From a15d496c531c3983d065ec9475787e00151d2521 Mon Sep 17 00:00:00 2001 From: Alice Gaudon Date: Sun, 14 Jun 2020 21:47:18 +0200 Subject: [PATCH] Use formidable instead of multer --- package.json | 5 ++- src/Application.ts | 6 --- src/Controller.ts | 3 -- src/auth/AuthComponent.ts | 10 +++++ src/components/CsrfProtectionComponent.ts | 2 +- src/components/ExpressAppComponent.ts | 49 ++++++++++++++--------- src/components/LogRequestsComponent.ts | 1 - src/types/Express.d.ts | 2 + yarn.lock | 25 ++++++++---- 9 files changed, 64 insertions(+), 39 deletions(-) diff --git a/package.json b/package.json index 1b26e1c..c3258af 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wms-core", - "version": "0.7.12", + "version": "0.8.2", "description": "Node web framework", "repository": "git@gitlab.com:ArisuOngaku/wms-core.git", "author": "Alice Gaudon ", @@ -22,6 +22,7 @@ "@types/connect-redis": "^0.0.13", "@types/cookie": "^0.3.3", "@types/cookie-parser": "^1.4.2", + "@types/formidable": "^1.0.31", "@types/geoip-lite": "^1.1.31", "@types/jest": "^25.2.1", "@types/mjml": "^4.0.4", @@ -34,7 +35,6 @@ "dependencies": { "@types/express": "^4.17.6", "@types/express-session": "^1.17.0", - "@types/multer": "^1.4.3", "@types/mysql": "^2.15.10", "@types/nodemailer": "^6.4.0", "@types/nunjucks": "^3.1.3", @@ -48,6 +48,7 @@ "cookie-parser": "^1.4.5", "express": "^4.17.1", "express-session": "^1.17.1", + "formidable": "^1.2.2", "geoip-lite": "^1.4.2", "mjml": "^4.6.2", "mysql": "^2.18.1", diff --git a/src/Application.ts b/src/Application.ts index 43640f8..1b723aa 100644 --- a/src/Application.ts +++ b/src/Application.ts @@ -170,12 +170,6 @@ export default abstract class Application { }); } - public setupRequestParsingMiddlewares(router: Router) { - for (const controller of this.controllers) { - controller.setupRequestParsingMiddlewares(router); - } - } - public getWebSocketListeners(): { [p: string]: WebSocketListener } { return this.webSocketListeners; } diff --git a/src/Controller.ts b/src/Controller.ts index a47c2a8..bed86e3 100644 --- a/src/Controller.ts +++ b/src/Controller.ts @@ -39,9 +39,6 @@ export default abstract class Controller { return []; } - public setupRequestParsingMiddlewares(router: Router): void { - } - public hasGlobalHandlers(): boolean { return this.getGlobalHandlers().length > 0; } diff --git a/src/auth/AuthComponent.ts b/src/auth/AuthComponent.ts index a28895e..1df2bd4 100644 --- a/src/auth/AuthComponent.ts +++ b/src/auth/AuthComponent.ts @@ -24,6 +24,16 @@ export default class AuthComponent extends ApplicationComponent { } } +export const REQUIRE_REQUEST_AUTH_MIDDLEWARE = async (req: Request, res: Response, next: NextFunction): Promise => { + if (!await req.authGuard.isAuthenticatedViaRequest(req)) { + req.flash('error', `You must be logged in to access ${req.url}.`); + res.redirect(Controller.route('auth') || '/'); + return; + } + + req.models.user = await req.authGuard.getUserForRequest(req); + next(); +}; export const REQUIRE_AUTH_MIDDLEWARE = async (req: Request, res: Response, next: NextFunction): Promise => { if (await req.authGuard.isAuthenticatedViaRequest(req)) { diff --git a/src/components/CsrfProtectionComponent.ts b/src/components/CsrfProtectionComponent.ts index 5db4074..94aa260 100644 --- a/src/components/CsrfProtectionComponent.ts +++ b/src/components/CsrfProtectionComponent.ts @@ -17,7 +17,7 @@ export default class CsrfProtectionComponent extends ApplicationComponent return req.session!.csrf; }; - if (!['GET', 'HEAD', 'OPTIONS'].find(s => s === req.method)) { + if (!['GET', 'HEAD', 'OPTIONS'].find(s => s === req.method) && !req.authGuard.isAuthenticatedViaRequest(req)) { if (req.session.csrf === undefined) { throw new InvalidCsrfTokenError(req.baseUrl, `You weren't assigned any CSRF token.`); } else if (req.body.csrf === undefined) { diff --git a/src/components/ExpressAppComponent.ts b/src/components/ExpressAppComponent.ts index 3c1b495..6e32adf 100644 --- a/src/components/ExpressAppComponent.ts +++ b/src/components/ExpressAppComponent.ts @@ -1,8 +1,8 @@ import ApplicationComponent from "../ApplicationComponent"; -import express, {Express, NextFunction, Request, Response, Router} from "express"; +import express, {Express, RequestHandler, Router} from "express"; import Logger from "../Logger"; import {Server} from "http"; -import {MulterError} from "multer"; +import {IncomingForm} from "formidable"; import {FileError, ValidationBag} from "../db/Validator"; export default class ExpressAppComponent extends ApplicationComponent { @@ -19,22 +19,6 @@ export default class ExpressAppComponent extends ApplicationComponent { Logger.info(`Web server running on localhost:${this.port}.`); }); - this.app?.setupRequestParsingMiddlewares(router); - - // Multer error handler - router.use((err: any, req: Request, res: Response, next: NextFunction) => { - if (err instanceof MulterError) { - const bag = new ValidationBag(); - const validationError = new FileError(err.message); - validationError.thingName = err.field; - bag.addMessage(validationError); - req.flash('validation', bag.getMessages()); - res.redirectBack(); - } else { - next(err); - } - }); - router.use(express.json()); router.use(express.urlencoded({ extended: true, @@ -57,4 +41,31 @@ export default class ExpressAppComponent extends ApplicationComponent { if (!this.server) throw 'Server was not initialized.'; return this.server; } -} \ No newline at end of file +} + +export const FILE_UPLOAD_MIDDLEWARE: (formFactory: () => IncomingForm, defaultField: string) => RequestHandler = (formFactory: () => IncomingForm, defaultField: string) => { + return async (req, res, next) => { + const form = formFactory(); + try { + await new Promise((resolve, reject) => { + form.parse(req, (err, fields, files) => { + if (err) { + reject(err); + return; + } + req.body = fields; + req.files = files; + resolve(); + }); + }); + } catch (e) { + const bag = new ValidationBag(); + const fileError = new FileError(e); + fileError.thingName = defaultField; + bag.addMessage(fileError); + next(bag); + return; + } + next(); + }; +}; diff --git a/src/components/LogRequestsComponent.ts b/src/components/LogRequestsComponent.ts index e4285db..7ea9ea9 100644 --- a/src/components/LogRequestsComponent.ts +++ b/src/components/LogRequestsComponent.ts @@ -34,7 +34,6 @@ export default class LogRequestsComponent extends ApplicationComponent { query: req.query, params: req.params, body: req.body, - file: req.file, files: req.files, cookies: req.cookies, sessionId: req.sessionID, diff --git a/src/types/Express.d.ts b/src/types/Express.d.ts index 564c153..f75ccb9 100644 --- a/src/types/Express.d.ts +++ b/src/types/Express.d.ts @@ -1,6 +1,7 @@ import {Environment} from "nunjucks"; import Model from "../db/Model"; import AuthGuard from "../auth/AuthGuard"; +import {Files} from "formidable"; declare global { namespace Express { @@ -9,6 +10,7 @@ declare global { models: { [p: string]: Model | null }; modelCollections: { [p: string]: Model[] | null }; authGuard: AuthGuard; + files: Files; flash(): { [key: string]: string[] }; diff --git a/yarn.lock b/yarn.lock index 83479d6..3871fbb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -557,6 +557,11 @@ resolved "https://registry.toot.party/@types%2fcookie/-/cookie-0.3.3.tgz#85bc74ba782fb7aa3a514d11767832b0e3bc6803" integrity sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow== +"@types/events@*": + version "3.0.0" + resolved "https://registry.toot.party/@types%2fevents/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" + integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== + "@types/express-serve-static-core@*": version "4.17.7" resolved "https://registry.toot.party/@types%2fexpress-serve-static-core/-/express-serve-static-core-4.17.7.tgz#dfe61f870eb549dc6d7e12050901847c7d7e915b" @@ -584,6 +589,14 @@ "@types/qs" "*" "@types/serve-static" "*" +"@types/formidable@^1.0.31": + version "1.0.31" + resolved "https://registry.toot.party/@types%2fformidable/-/formidable-1.0.31.tgz#274f9dc2d0a1a9ce1feef48c24ca0859e7ec947b" + integrity sha512-dIhM5t8lRP0oWe2HF8MuPvdd1TpPTjhDMAqemcq6oIZQCBQTovhBAdTQ5L5veJB4pdQChadmHuxtB0YzqvfU3Q== + dependencies: + "@types/events" "*" + "@types/node" "*" + "@types/geoip-lite@^1.1.31": version "1.1.31" resolved "https://registry.toot.party/@types%2fgeoip-lite/-/geoip-lite-1.1.31.tgz#0063e47916ea982fa913a8c825f429e66b59ad10" @@ -641,13 +654,6 @@ resolved "https://registry.toot.party/@types%2fmjml/-/mjml-4.0.4.tgz#af6075d29f64d47186d76125504daf544dfb2b42" integrity sha512-4PhI6iZ1zGXZ9X9W0bbmI7mS2xdxITURueqSWJ/cTeS5+tbAtOUDG1ww/fPbfcffWwR4NeOjyNcZiczafH/yfw== -"@types/multer@^1.4.3": - version "1.4.3" - resolved "https://registry.toot.party/@types%2fmulter/-/multer-1.4.3.tgz#bdff74b334c38a8ee1de9fbedb5d1d3dbc377422" - integrity sha512-tWsKbF5LYtXrJ7eOfI0aLBgEv9B7fnJe1JRXTj5+Z6EMfX0yHVsRFsNGnKyN8Bs0gtDv+JR37xAqsPnALyVTqg== - dependencies: - "@types/express" "*" - "@types/mysql@^2.15.10": version "2.15.13" resolved "https://registry.toot.party/@types%2fmysql/-/mysql-2.15.13.tgz#153dc2e2f8dffd39f7bba556c2679f14bdbecde1" @@ -2115,6 +2121,11 @@ form-data@~2.3.2: combined-stream "^1.0.6" mime-types "^2.1.12" +formidable@^1.2.2: + version "1.2.2" + resolved "https://registry.toot.party/formidable/-/formidable-1.2.2.tgz#bf69aea2972982675f00865342b982986f6b8dd9" + integrity sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q== + forwarded@~0.1.2: version "0.1.2" resolved "https://registry.toot.party/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"