expressjs -> nextjs
This commit is contained in:
80
nextjs/app/%5Fshare/[filename]/route.js
Normal file
80
nextjs/app/%5Fshare/[filename]/route.js
Normal file
@@ -0,0 +1,80 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { Readable } from 'node:stream';
|
||||
|
||||
import { NextResponse } from 'next/server';
|
||||
|
||||
import { shareDir } from '@/src/lib/config.js';
|
||||
import { get, logEvent, run, runCleanupIfNeeded } from '@/src/lib/db.js';
|
||||
import { getRequestMeta } from '@/src/lib/security.js';
|
||||
|
||||
export const runtime = 'nodejs';
|
||||
export const dynamic = 'force-dynamic';
|
||||
|
||||
function safeFilename(value) {
|
||||
const fileName = String(value || '');
|
||||
if (!fileName) {
|
||||
return '';
|
||||
}
|
||||
if (fileName.includes('/') || fileName.includes('\\') || fileName.includes('..')) {
|
||||
return '';
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
|
||||
function contentDisposition(filename) {
|
||||
const fallback = String(filename || 'download')
|
||||
.replace(/[\r\n]/g, ' ')
|
||||
.replace(/[\\"]/g, '_')
|
||||
.replace(/[^ -~]/g, '_');
|
||||
const encoded = encodeURIComponent(filename || 'download');
|
||||
return `attachment; filename="${fallback}"; filename*=UTF-8''${encoded}`;
|
||||
}
|
||||
|
||||
export async function GET(request, { params }) {
|
||||
await runCleanupIfNeeded();
|
||||
|
||||
const resolvedParams = await params;
|
||||
const fileName = safeFilename(resolvedParams.filename);
|
||||
if (!fileName) {
|
||||
return new NextResponse('Ungültiger Dateiname', { status: 400 });
|
||||
}
|
||||
|
||||
const row = await get('SELECT id, original_name, stored_path FROM uploads WHERE stored_name = ?', [fileName]);
|
||||
|
||||
let filePath;
|
||||
let downloadName;
|
||||
|
||||
if (row) {
|
||||
filePath = row.stored_path;
|
||||
downloadName = row.original_name || fileName;
|
||||
|
||||
const requestMeta = await getRequestMeta();
|
||||
run('UPDATE uploads SET downloads = downloads + 1 WHERE id = ?', [row.id]).catch(() => undefined);
|
||||
logEvent('download', null, { name: fileName, original: downloadName }, requestMeta).catch(() => undefined);
|
||||
} else {
|
||||
filePath = path.join(shareDir, fileName);
|
||||
downloadName = fileName;
|
||||
}
|
||||
|
||||
let fileStat;
|
||||
try {
|
||||
fileStat = await fs.promises.stat(filePath);
|
||||
} catch {
|
||||
return new NextResponse('Datei nicht gefunden', { status: 404 });
|
||||
}
|
||||
|
||||
const fileStream = fs.createReadStream(filePath);
|
||||
const webStream = Readable.toWeb(fileStream);
|
||||
|
||||
return new NextResponse(webStream, {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/octet-stream',
|
||||
'Content-Length': String(fileStat.size),
|
||||
'Content-Disposition': contentDisposition(downloadName),
|
||||
'Cache-Control': 'private, no-store',
|
||||
'X-Content-Type-Options': 'nosniff',
|
||||
},
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user