diff --git a/docker-compose.yml b/docker-compose.yml index c2b5e30..4c0a81b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -79,7 +79,7 @@ services: labels: - "traefik.enable=true" - - "traefik.http.routers.express.rule=Host(`${SERVICE_FQDN}`) && PathPrefix(`/manage`)" + - "traefik.http.routers.express.rule=Host(`${SERVICE_FQDN}`) && (PathPrefix(`/manage`) || PathPrefix(`/_share`))" - "traefik.http.routers.express.entrypoints=websecure" - "traefik.http.routers.express.tls=true" - "traefik.http.routers.express.tls.certresolver=letsencrypt" @@ -87,7 +87,7 @@ services: - "traefik.http.services.express-svc.loadbalancer.server.port=3000" - "traefik.http.routers.express.priority=10" # Optional HTTP redirect - - "traefik.http.routers.express-http.rule=Host(`${SERVICE_FQDN}`) && PathPrefix(`/manage`)" + - "traefik.http.routers.express-http.rule=Host(`${SERVICE_FQDN}`) && (PathPrefix(`/manage`) || PathPrefix(`/_share`))" - "traefik.http.routers.express-http.entrypoints=web" - "traefik.http.routers.express-http.middlewares=express-https-redirect" - "traefik.http.middlewares.express-https-redirect.redirectscheme.scheme=https" diff --git a/expressjs/data/uploads.sqlite b/expressjs/data/uploads.sqlite new file mode 100644 index 0000000..0db78db Binary files /dev/null and b/expressjs/data/uploads.sqlite differ diff --git a/expressjs/src/server.js b/expressjs/src/server.js index 506b292..fe01e1e 100644 --- a/expressjs/src/server.js +++ b/expressjs/src/server.js @@ -257,12 +257,11 @@ function createRandomId() { function sanitizeBaseName(originalName) { const ext = path.extname(originalName || ''); const base = path.basename(originalName || 'datei', ext); + // Allow more characters but keep it safe for URLs and FS const cleaned = base - .replace(/\s+/g, '-') - .replace(/[^a-zA-Z0-9_-]/g, '') - .replace(/-+/g, '-') - .replace(/_+/g, '_') - .replace(/^[-_]+|[-_]+$/g, ''); + .replace(/[^\w\-. ]/g, '') // Allow words, dashes, dots, spaces + .trim() + .replace(/\s+/g, '-'); // Replace spaces with dashes for better URLs return cleaned || 'datei'; } @@ -318,45 +317,152 @@ function renderFileManagerPage(title, body) {
Seite nicht gefunden.
')); }); +// Add endpoint to serve files with correct headers +// NOTE: This must be mounted at root level or matching the path prefix handled by Traefik +app.get('/_share/:filename', async (req, res) => { + const filename = req.params.filename; + // Security check: ensure no path traversal + if (filename.includes('/') || filename.includes('\\') || filename.includes('..')) { + res.status(400).send('Invalid filename'); + return; + } + + const row = await get('SELECT original_name, stored_path FROM uploads WHERE stored_name = ?', [filename]); + + if (!row) { + // If not found in DB, check if it exists on disk (legacy or manual files) + const filePath = path.join(shareDir, filename); + if (fs.existsSync(filePath)) { + res.download(filePath, filename); // Fallback: download with stored name + return; + } + res.status(404).send('File not found'); + return; + } + + res.download(row.stored_path, row.original_name); +}); + const server = app.listen(port, () => { console.log(`Express server listening on ${port} with base path ${basePath}`); }); diff --git a/webserver.Dockerfile b/webserver.Dockerfile index 0ce3dc7..810b721 100644 --- a/webserver.Dockerfile +++ b/webserver.Dockerfile @@ -32,7 +32,13 @@ IndexOptions FancyIndexing FoldersFirst NameWidth=*\n\ # Force download for shared files RUN printf '\n# --- Force download in _share ---\n\