diff --git a/app/api/nextcloud/files/content/route.ts b/app/api/nextcloud/files/content/route.ts index 16bb356b..e4301dce 100644 --- a/app/api/nextcloud/files/content/route.ts +++ b/app/api/nextcloud/files/content/route.ts @@ -42,33 +42,53 @@ const createWebDAVClient = async (userId: string) => { export async function GET(request: Request) { try { + const { searchParams } = new URL(request.url); + const path = searchParams.get('path'); + + if (!path) { + return NextResponse.json({ error: 'Path parameter is required' }, { status: 400 }); + } + const session = await getServerSession(authOptions); - if (!session?.user?.id) { + if (!session?.user) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } - const { searchParams } = new URL(request.url); - const id = searchParams.get('id'); - const path = searchParams.get('path'); - - if (!id && !path) { - return NextResponse.json({ error: 'File ID or path is required' }, { status: 400 }); - } - - const { client } = await createWebDAVClient(session.user.id); + const nextcloudUrl = process.env.NEXTCLOUD_URL; + const username = `cube-${session.user.id}`; - try { - // Use either id or path to fetch the file content - const filePath = id || path; - const content = await client.getFileContents(filePath, { format: 'text' }); - console.log('Raw file content:', content); - return NextResponse.json({ content }); - } catch (error) { - console.error('Error fetching file content:', error); - return NextResponse.json({ error: 'Failed to fetch file content' }, { status: 500 }); + // Get credentials without logging + const credentials = await prisma.webDAVCredentials.findUnique({ + where: { userId: session.user.id } + }); + + if (!credentials) { + return NextResponse.json({ error: 'Nextcloud credentials not found' }, { status: 404 }); } + + // Make request without logging sensitive information + const response = await fetch(`${nextcloudUrl}/remote.php/dav${path}`, { + method: 'GET', + headers: { + 'Authorization': `Basic ${Buffer.from(`${username}:${credentials.password}`).toString('base64')}`, + }, + }); + + if (!response.ok) { + return NextResponse.json({ error: 'Failed to fetch file content' }, { status: response.status }); + } + + const content = await response.text(); + + // For VCF files, don't log the content + if (path.endsWith('.vcf')) { + return NextResponse.json({ content }); + } + + return NextResponse.json({ content }); } catch (error) { - console.error('Error in GET request:', error); + // Log error without sensitive information + console.error('Error fetching file content:', error instanceof Error ? error.message : 'Unknown error'); return NextResponse.json({ error: 'Internal server error' }, { status: 500 }); } } \ No newline at end of file diff --git a/app/api/nextcloud/files/route.ts b/app/api/nextcloud/files/route.ts index 90eba367..b6f89ccd 100644 --- a/app/api/nextcloud/files/route.ts +++ b/app/api/nextcloud/files/route.ts @@ -42,48 +42,88 @@ const createWebDAVClient = async (userId: string) => { export async function GET(request: Request) { try { + const { searchParams } = new URL(request.url); + const folder = searchParams.get('folder'); + + if (!folder) { + return NextResponse.json({ error: 'Folder parameter is required' }, { status: 400 }); + } + const session = await getServerSession(authOptions); - if (!session?.user?.id) { + if (!session?.user) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } - const { searchParams } = new URL(request.url); - const folder = searchParams.get('folder') || 'Notes'; - - const { client, username } = await createWebDAVClient(session.user.id); + const nextcloudUrl = process.env.NEXTCLOUD_URL; + const username = `cube-${session.user.id}`; - try { - const path = `/files/${username}/Private/${folder}`; - console.log('Fetching contents from path:', path); - - const files = await client.getDirectoryContents(path); - console.log('Raw files response:', JSON.stringify(files, null, 2)); + // Get credentials without logging + const credentials = await prisma.webDAVCredentials.findUnique({ + where: { userId: session.user.id } + }); - // Return all files for the Contacts folder - if (folder === 'Contacts') { - return NextResponse.json(files); - } - - // For other folders, filter markdown files - const markdownFiles = files - .filter((file: any) => file.basename.endsWith('.md')) - .map((file: any) => ({ - id: file.filename, - title: file.basename.replace('.md', ''), - lastModified: new Date(file.lastmod).toISOString(), - size: file.size, - type: 'file', - mime: file.mime, - etag: file.etag - })); - - return NextResponse.json(markdownFiles); - } catch (error) { - console.error('Error listing directory contents:', error); - return NextResponse.json({ error: 'Failed to list directory contents' }, { status: 500 }); + if (!credentials) { + return NextResponse.json({ error: 'Nextcloud credentials not found' }, { status: 404 }); } + + const path = `/files/${username}/Private/${folder}`; + + // Make request without logging sensitive information + const response = await fetch(`${nextcloudUrl}/remote.php/dav${path}`, { + method: 'PROPFIND', + headers: { + 'Authorization': `Basic ${Buffer.from(`${username}:${credentials.password}`).toString('base64')}`, + 'Depth': '1', + 'Content-Type': 'application/xml', + }, + body: '', + }); + + if (!response.ok) { + return NextResponse.json({ error: 'Failed to fetch files' }, { status: response.status }); + } + + const text = await response.text(); + const parser = new DOMParser(); + const xmlDoc = parser.parseFromString(text, 'text/xml'); + + const files: any[] = []; + const responses = xmlDoc.getElementsByTagName('d:response'); + + for (let i = 0; i < responses.length; i++) { + const response = responses[i]; + const href = response.getElementsByTagName('d:href')[0]?.textContent; + const propstat = response.getElementsByTagName('d:propstat')[0]; + + if (href && propstat) { + const prop = propstat.getElementsByTagName('d:prop')[0]; + if (prop) { + const type = prop.getElementsByTagName('d:resourcetype')[0]; + const lastmod = prop.getElementsByTagName('d:getlastmodified')[0]?.textContent; + const size = prop.getElementsByTagName('d:getcontentlength')[0]?.textContent; + const mime = prop.getElementsByTagName('d:getcontenttype')[0]?.textContent; + const etag = prop.getElementsByTagName('d:getetag')[0]?.textContent; + + if (type && !type.getElementsByTagName('d:collection').length) { + const filename = href.split('/').pop() || ''; + files.push({ + filename: href, + basename: filename, + lastmod, + size, + type: 'file', + etag, + mime + }); + } + } + } + } + + return NextResponse.json(files); } catch (error) { - console.error('Error fetching files:', error); + // Log error without sensitive information + console.error('Error fetching files:', error instanceof Error ? error.message : 'Unknown error'); return NextResponse.json({ error: 'Internal server error' }, { status: 500 }); } }