mirror of
https://github.com/zadam/trilium.git
synced 2025-01-31 11:32:30 +08:00
limit max imported file size to 250 MiB, #3108
This commit is contained in:
parent
7f566178d3
commit
b2a63afc28
5 changed files with 578 additions and 254 deletions
761
package-lock.json
generated
761
package-lock.json
generated
File diff suppressed because it is too large
Load diff
18
package.json
18
package.json
|
@ -28,7 +28,7 @@
|
||||||
"@electron/remote": "2.0.8",
|
"@electron/remote": "2.0.8",
|
||||||
"@excalidraw/excalidraw": "0.12.0",
|
"@excalidraw/excalidraw": "0.12.0",
|
||||||
"archiver": "5.3.1",
|
"archiver": "5.3.1",
|
||||||
"async-mutex": "0.3.2",
|
"async-mutex": "0.4.0",
|
||||||
"axios": "0.27.2",
|
"axios": "0.27.2",
|
||||||
"better-sqlite3": "7.4.5",
|
"better-sqlite3": "7.4.5",
|
||||||
"chokidar": "3.5.3",
|
"chokidar": "3.5.3",
|
||||||
|
@ -37,7 +37,7 @@
|
||||||
"compression": "^1.7.4",
|
"compression": "^1.7.4",
|
||||||
"cookie-parser": "1.4.6",
|
"cookie-parser": "1.4.6",
|
||||||
"csurf": "1.11.0",
|
"csurf": "1.11.0",
|
||||||
"dayjs": "1.11.4",
|
"dayjs": "1.11.5",
|
||||||
"dayjs-plugin-utc": "^0.1.2",
|
"dayjs-plugin-utc": "^0.1.2",
|
||||||
"ejs": "3.1.8",
|
"ejs": "3.1.8",
|
||||||
"electron-debug": "3.2.0",
|
"electron-debug": "3.2.0",
|
||||||
|
@ -45,16 +45,16 @@
|
||||||
"electron-window-state": "5.0.3",
|
"electron-window-state": "5.0.3",
|
||||||
"express": "4.18.1",
|
"express": "4.18.1",
|
||||||
"express-partial-content": "1.0.2",
|
"express-partial-content": "1.0.2",
|
||||||
"express-rate-limit": "6.5.1",
|
"express-rate-limit": "6.5.2",
|
||||||
"express-session": "1.17.3",
|
"express-session": "1.17.3",
|
||||||
"fs-extra": "10.1.0",
|
"fs-extra": "10.1.0",
|
||||||
"helmet": "5.1.1",
|
"helmet": "6.0.0",
|
||||||
"html": "1.0.0",
|
"html": "1.0.0",
|
||||||
"html2plaintext": "2.1.4",
|
"html2plaintext": "2.1.4",
|
||||||
"http-proxy-agent": "5.0.0",
|
"http-proxy-agent": "5.0.0",
|
||||||
"https-proxy-agent": "5.0.1",
|
"https-proxy-agent": "5.0.1",
|
||||||
"image-type": "4.1.0",
|
"image-type": "4.1.0",
|
||||||
"ini": "3.0.0",
|
"ini": "3.0.1",
|
||||||
"is-animated": "2.0.2",
|
"is-animated": "2.0.2",
|
||||||
"is-svg": "4.3.2",
|
"is-svg": "4.3.2",
|
||||||
"jimp": "0.16.1",
|
"jimp": "0.16.1",
|
||||||
|
@ -89,15 +89,15 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"electron": "16.2.8",
|
"electron": "16.2.8",
|
||||||
"electron-builder": "23.1.0",
|
"electron-builder": "23.3.3",
|
||||||
"electron-packager": "15.5.1",
|
"electron-packager": "16.0.0",
|
||||||
"electron-rebuild": "3.2.8",
|
"electron-rebuild": "3.2.9",
|
||||||
"esm": "3.2.25",
|
"esm": "3.2.25",
|
||||||
"jasmine": "4.3.0",
|
"jasmine": "4.3.0",
|
||||||
"jsdoc": "3.6.11",
|
"jsdoc": "3.6.11",
|
||||||
"lorem-ipsum": "2.0.8",
|
"lorem-ipsum": "2.0.8",
|
||||||
"rcedit": "3.0.1",
|
"rcedit": "3.0.1",
|
||||||
"webpack": "5.73.0",
|
"webpack": "5.74.0",
|
||||||
"webpack-cli": "4.10.0"
|
"webpack-cli": "4.10.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
|
|
|
@ -32,6 +32,9 @@ export async function uploadFiles(parentNoteId, files, options) {
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
timeout: 60 * 60 * 1000,
|
timeout: 60 * 60 * 1000,
|
||||||
|
error: function(xhr) {
|
||||||
|
toastService.showError("Import failed: " + xhr.responseText);
|
||||||
|
},
|
||||||
contentType: false, // NEEDED, DON'T REMOVE THIS
|
contentType: false, // NEEDED, DON'T REMOVE THIS
|
||||||
processData: false, // NEEDED, DON'T REMOVE THIS
|
processData: false, // NEEDED, DON'T REMOVE THIS
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -215,7 +215,7 @@ function update(req) {
|
||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
for (const key in partialRequests) {
|
for (const key in partialRequests) {
|
||||||
if (Date.now() - partialRequests[key].createdAt > 5 * 60 * 1000) {
|
if (Date.now() - partialRequests[key].createdAt > 20 * 60 * 1000) {
|
||||||
log.info(`Cleaning up unfinished partial requests for ${key}`);
|
log.info(`Cleaning up unfinished partial requests for ${key}`);
|
||||||
|
|
||||||
delete partialRequests[key];
|
delete partialRequests[key];
|
||||||
|
|
|
@ -4,14 +4,7 @@ const setupRoute = require('./setup');
|
||||||
const loginRoute = require('./login');
|
const loginRoute = require('./login');
|
||||||
const indexRoute = require('./index');
|
const indexRoute = require('./index');
|
||||||
const utils = require('../services/utils');
|
const utils = require('../services/utils');
|
||||||
const multer = require('multer')({
|
const multer = require('multer');
|
||||||
fileFilter: (req, file, cb) => {
|
|
||||||
// UTF-8 file names are not well decoded by multer/busboy, so we handle the conversion on our side.
|
|
||||||
// See https://github.com/expressjs/multer/pull/1102.
|
|
||||||
file.originalname = Buffer.from(file.originalname, "latin1").toString("utf-8");
|
|
||||||
cb(null, true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// API routes
|
// API routes
|
||||||
const treeApiRoute = require('./api/tree');
|
const treeApiRoute = require('./api/tree');
|
||||||
|
@ -201,8 +194,33 @@ function route(method, path, middleware, routeHandler, resultHandler, transactio
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MAX_ALLOWED_FILE_SIZE_MB = 250;
|
||||||
|
|
||||||
const GET = 'get', POST = 'post', PUT = 'put', PATCH = 'patch', DELETE = 'delete';
|
const GET = 'get', POST = 'post', PUT = 'put', PATCH = 'patch', DELETE = 'delete';
|
||||||
const uploadMiddleware = multer.single('upload');
|
const uploadMiddleware = multer({
|
||||||
|
fileFilter: (req, file, cb) => {
|
||||||
|
// UTF-8 file names are not well decoded by multer/busboy, so we handle the conversion on our side.
|
||||||
|
// See https://github.com/expressjs/multer/pull/1102.
|
||||||
|
file.originalname = Buffer.from(file.originalname, "latin1").toString("utf-8");
|
||||||
|
cb(null, true);
|
||||||
|
},
|
||||||
|
limits: {
|
||||||
|
fileSize: MAX_ALLOWED_FILE_SIZE_MB * 1024 * 1024
|
||||||
|
}
|
||||||
|
}).single('upload');
|
||||||
|
|
||||||
|
const uploadMiddlewareWithErrorHandling = function (req, res, next) {
|
||||||
|
uploadMiddleware(req, res, function (err) {
|
||||||
|
if (err?.code === 'LIMIT_FILE_SIZE') {
|
||||||
|
res.setHeader("Content-Type", "text/plain")
|
||||||
|
.status(400)
|
||||||
|
.send(`Cannot upload file because it excceeded max allowed file size of ${MAX_ALLOWED_FILE_SIZE_MB} MiB`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
function register(app) {
|
function register(app) {
|
||||||
route(GET, '/', [auth.checkAuth, csrfMiddleware], indexRoute.index);
|
route(GET, '/', [auth.checkAuth, csrfMiddleware], indexRoute.index);
|
||||||
|
@ -260,9 +278,9 @@ function register(app) {
|
||||||
apiRoute(PUT, '/api/notes/:noteId/clone-after/:afterBranchId', cloningApiRoute.cloneNoteAfter);
|
apiRoute(PUT, '/api/notes/:noteId/clone-after/:afterBranchId', cloningApiRoute.cloneNoteAfter);
|
||||||
|
|
||||||
route(GET, '/api/notes/:branchId/export/:type/:format/:version/:taskId', [auth.checkApiAuthOrElectron], exportRoute.exportBranch);
|
route(GET, '/api/notes/:branchId/export/:type/:format/:version/:taskId', [auth.checkApiAuthOrElectron], exportRoute.exportBranch);
|
||||||
route(POST, '/api/notes/:parentNoteId/import', [auth.checkApiAuthOrElectron, uploadMiddleware, csrfMiddleware], importRoute.importToBranch, apiResultHandler);
|
route(POST, '/api/notes/:parentNoteId/import', [auth.checkApiAuthOrElectron, uploadMiddlewareWithErrorHandling, csrfMiddleware], importRoute.importToBranch, apiResultHandler);
|
||||||
|
|
||||||
route(PUT, '/api/notes/:noteId/file', [auth.checkApiAuthOrElectron, uploadMiddleware, csrfMiddleware],
|
route(PUT, '/api/notes/:noteId/file', [auth.checkApiAuthOrElectron, uploadMiddlewareWithErrorHandling, csrfMiddleware],
|
||||||
filesRoute.updateFile, apiResultHandler);
|
filesRoute.updateFile, apiResultHandler);
|
||||||
|
|
||||||
route(GET, '/api/notes/:noteId/open', [auth.checkApiAuthOrElectron], filesRoute.openFile);
|
route(GET, '/api/notes/:noteId/open', [auth.checkApiAuthOrElectron], filesRoute.openFile);
|
||||||
|
@ -301,10 +319,10 @@ function register(app) {
|
||||||
apiRoute(POST, '/api/special-notes/search-note', specialNotesRoute.createSearchNote);
|
apiRoute(POST, '/api/special-notes/search-note', specialNotesRoute.createSearchNote);
|
||||||
apiRoute(POST, '/api/special-notes/save-search-note', specialNotesRoute.saveSearchNote);
|
apiRoute(POST, '/api/special-notes/save-search-note', specialNotesRoute.saveSearchNote);
|
||||||
|
|
||||||
// :filename is not used by trilium, but instead used for "save as" to assign a human readable filename
|
// :filename is not used by trilium, but instead used for "save as" to assign a human-readable filename
|
||||||
route(GET, '/api/images/:noteId/:filename', [auth.checkApiAuthOrElectron], imageRoute.returnImage);
|
route(GET, '/api/images/:noteId/:filename', [auth.checkApiAuthOrElectron], imageRoute.returnImage);
|
||||||
route(POST, '/api/images', [auth.checkApiAuthOrElectron, uploadMiddleware, csrfMiddleware], imageRoute.uploadImage, apiResultHandler);
|
route(POST, '/api/images', [auth.checkApiAuthOrElectron, uploadMiddlewareWithErrorHandling, csrfMiddleware], imageRoute.uploadImage, apiResultHandler);
|
||||||
route(PUT, '/api/images/:noteId', [auth.checkApiAuthOrElectron, uploadMiddleware, csrfMiddleware], imageRoute.updateImage, apiResultHandler);
|
route(PUT, '/api/images/:noteId', [auth.checkApiAuthOrElectron, uploadMiddlewareWithErrorHandling, csrfMiddleware], imageRoute.updateImage, apiResultHandler);
|
||||||
|
|
||||||
apiRoute(GET, '/api/recent-changes/:ancestorNoteId', recentChangesApiRoute.getRecentChanges);
|
apiRoute(GET, '/api/recent-changes/:ancestorNoteId', recentChangesApiRoute.getRecentChanges);
|
||||||
|
|
||||||
|
@ -366,7 +384,7 @@ function register(app) {
|
||||||
|
|
||||||
// no CSRF since this is called from android app
|
// no CSRF since this is called from android app
|
||||||
route(POST, '/api/sender/login', [], loginApiRoute.token, apiResultHandler);
|
route(POST, '/api/sender/login', [], loginApiRoute.token, apiResultHandler);
|
||||||
route(POST, '/api/sender/image', [auth.checkEtapiToken, uploadMiddleware], senderRoute.uploadImage, apiResultHandler);
|
route(POST, '/api/sender/image', [auth.checkEtapiToken, uploadMiddlewareWithErrorHandling], senderRoute.uploadImage, apiResultHandler);
|
||||||
route(POST, '/api/sender/note', [auth.checkEtapiToken], senderRoute.saveNote, apiResultHandler);
|
route(POST, '/api/sender/note', [auth.checkEtapiToken], senderRoute.saveNote, apiResultHandler);
|
||||||
|
|
||||||
apiRoute(GET, '/api/quick-search/:searchString', searchRoute.quickSearch);
|
apiRoute(GET, '/api/quick-search/:searchString', searchRoute.quickSearch);
|
||||||
|
|
Loading…
Reference in a new issue