Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,20 @@ const startServer = async () => {

let origin;
if (corsConfig.allow_origin === true) {
origin = corsConfig.whitelist;
if (corsConfig.whitelist && corsConfig.whitelist.length > 0) {
origin = corsConfig.whitelist;
} else {
origin = false;
logger.warn(
'CORS allow_origin is true but whitelist is empty. Blocking all CORS requests for security.'
);
}
} else if (corsConfig.allow_origin === false) {
origin = false;
} else if (corsConfig.allow_origin === 'specific') {
origin = corsConfig.whitelist;
} else {
origin = corsConfig.allow_origin; // fallback for other values
origin = corsConfig.allow_origin;
}

const corsOptions = {
Expand Down
9 changes: 9 additions & 0 deletions config/paths.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,12 @@ export const getSecurePath = requestPath => {

return fullPath;
};

export const isLocalUrl = urlPath => {
try {
const url = new URL(urlPath, 'https://localhost');
return url.origin === 'https://localhost';
} catch {
return false;
}
};
22 changes: 19 additions & 3 deletions routes/fileServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { join, basename, extname, resolve } from 'path';
import { Op } from 'sequelize';
import auth from 'basic-auth';
import escapeHtml from 'escape-html';
import { SERVED_DIR, getSecurePath } from '../config/paths.js';
import { SERVED_DIR, getSecurePath, isLocalUrl } from '../config/paths.js';
import {
authenticateDownloads,
authenticateUploads,
Expand Down Expand Up @@ -228,6 +228,12 @@ router.get('*splat', authenticateDownloads, async (req, res) => {
const redirectPath = req.originalUrl.endsWith('/')
? req.originalUrl
: `${req.originalUrl}/`;

if (!isLocalUrl(redirectPath)) {
logger.warn('Rejected potentially unsafe redirect', { path: redirectPath });
return res.status(400).send('Invalid redirect path');
}

return res.redirect(301, redirectPath);
}
return handleDirectoryListing(req, res, fullPath, requestPath);
Expand Down Expand Up @@ -1085,12 +1091,22 @@ router.post('*splat', (req, res, next) => {
res.status(200).send('Authenticated');
});
} else if (req.query.action === 'create-folder') {
// Redirect to new endpoint
const newPath = `${req.path}/folders`;

if (!isLocalUrl(newPath)) {
logger.warn('Rejected potentially unsafe redirect', { path: newPath });
return res.status(400).send('Invalid redirect path');
}

return res.redirect(307, newPath);
} else if (req.query.action === 'search') {
// Redirect to new endpoint
const newPath = `${req.path}/search`;

if (!isLocalUrl(newPath)) {
logger.warn('Rejected potentially unsafe redirect', { path: newPath });
return res.status(400).send('Invalid redirect path');
}

return res.redirect(307, newPath);
}
return next();
Expand Down