From 8505d9279b0855990619008b38094d17a0be2aeb Mon Sep 17 00:00:00 2001 From: Flam3rboy <34555296+Flam3rboy@users.noreply.github.com> Date: Tue, 2 Feb 2021 00:51:00 +0100 Subject: [PATCH] :art: Body Parser error --- {src/locales => locales}/de/auth.json | 0 {src/locales => locales}/de/common.json | 0 {src/locales => locales}/en/auth.json | 0 {src/locales => locales}/en/common.json | 0 package-lock.json | Bin 68756 -> 70983 bytes package.json | 7 +++-- src/Server.ts | 36 ++++++++++++++++-------- src/index.ts | 3 ++ src/middlewares/Authentication.ts | 2 +- src/middlewares/BodyParser.ts | 17 +++++++++++ src/middlewares/GlobalRateLimit.ts | 8 +++--- src/test/mongo_test.ts | 7 ++--- src/util/String.ts | 20 +++++++++++-- src/util/instanceOf.ts | 6 ++-- 14 files changed, 77 insertions(+), 29 deletions(-) rename {src/locales => locales}/de/auth.json (100%) rename {src/locales => locales}/de/common.json (100%) rename {src/locales => locales}/en/auth.json (100%) rename {src/locales => locales}/en/common.json (100%) create mode 100644 src/middlewares/BodyParser.ts diff --git a/src/locales/de/auth.json b/locales/de/auth.json similarity index 100% rename from src/locales/de/auth.json rename to locales/de/auth.json diff --git a/src/locales/de/common.json b/locales/de/common.json similarity index 100% rename from src/locales/de/common.json rename to locales/de/common.json diff --git a/src/locales/en/auth.json b/locales/en/auth.json similarity index 100% rename from src/locales/en/auth.json rename to locales/en/auth.json diff --git a/src/locales/en/common.json b/locales/en/common.json similarity index 100% rename from src/locales/en/common.json rename to locales/en/common.json diff --git a/package-lock.json b/package-lock.json index b365af4b26ac87f86373f9f5445227a6b3139c7c..3d022326b7810cdbc12f84ddf1065b408d316a21 100644 GIT binary patch delta 1518 zcmaKsO^@3|7{|3D+jh62($d|ur7tuo5{EQvJC5T7u~lOycH)g=JBghasiltX*m3OG zYddkWw5Syoe1JhzZ~=)EoEGK6Hvno|*CdJpcbZ zpMDL3-?{T6*B8`?509#wsXUagfmwaIk(FJ7Eo!hEAACXSNaW z-DX1UbDY-77eo%~cWaCzRMa}wL|t7sahtWNfxr@ONfiZ7s0yQUop#5q(5U-W78;or zQZHvJ<)L9(jhvZaKDsfW%wyMK7xP+7eto4%0}q3v4LYMF(p*^ITA;v&|YraU-%=&o%bV zp*-p}Ggzb6r96cV0%otTs(GUAjf<%Py^rC;I>z_moI54xsfFnROl0#aWBFER>a@U9 z`O2HV>kY@jAZ_{)>W9&hndJJ~+S-G~t!qENb1Is*W$;LhgD)Q=8`@F6q&$wmi^mB7 zf3qsl6N(CP(N*P?o^?|~Wjb!djd`mBH6@K9N-U(40b6Wvuu_|}G8Lt~J8tn)!<2F| zt?hXv0r~y9xl1$zedTU7c`OnKR|xQm!=XK{P3{Grn3NTrrCZY+KYx+)MGK z<<9hsLU)Q5Oqw*D1uOHbNk2W8Z7Y%%-A0xpc{9>>Eou7B7>mjo@aT{8i_6BJXI2lF zf{jlute`;Hg5&1V<|Y1dl#ad;-Lu#o^c4;_J0*2)!Xf!?0 z$&4nc6hULXip*eCYbm=mJWgy709hla8ap2x3%XZP>E zapd>I%UOCp(i0#b++27M$V=eopAhi-XYYZ7&7{P;wo5Zbbc_b*UZ@2&*%3p##t#b> zHKXEorC$kiDI)Y|ojNDYg%&YI3-~NWh5asSGlbOUjb@qNZ(xX~+p}!1XJnf|s{|)E`|zI**71~ea^A@bp<;&qvhm>?fR3I zTa}g>EX^n+4`9lWvP`OnRx~U&YqS< X) { - super({ ...opts, errorHandler: false }); + // @ts-ignore + super({ ...opts, errorHandler: false, jsonBody: false }); } async start() { @@ -31,20 +35,28 @@ export class DiscordServer extends Server { this.app.use(GlobalRateLimit); this.app.use(Authentication); - const namespaces = await fs.readdir(__dirname + "/locales/de/"); + this.app.use(BodyParser({ inflate: true })); + const languages = await fs.readdir(__dirname + "/../locales/"); + const namespaces = await fs.readdir(__dirname + "/../locales/en/"); const ns = namespaces.filter((x) => x.endsWith(".json")).map((x) => x.slice(0, x.length - 5)); - i18next.use(i18nextMiddleware.LanguageDetector).init({ - preload: ["en", "de"], - fallbackLng: "en", - ns, - backend: { - loadPath: "locales/{{lng}}/{{ns}}.json", - }, - }); + await i18next + .use(i18nextBackend) + .use(i18nextMiddleware.LanguageDetector) + .init({ + preload: languages, + // debug: true, + fallbackLng: "en", + ns, + backend: { + loadPath: __dirname + "/../locales/{{lng}}/{{ns}}.json", + }, + load: "all", + }); this.app.use(i18nextMiddleware.handle(i18next, {})); this.routes = await this.registerRoutes(__dirname + "/routes/"); + this.app.use(ErrorHandler); const indexHTML = await fs.readFile(__dirname + "/../client_test/index.html"); this.app.get("*", (req, res) => { diff --git a/src/index.ts b/src/index.ts index 9299221c..f4be661d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,3 +6,6 @@ import { DiscordServer } from "./Server"; const server = new DiscordServer({ port: 3000 }); server.start().catch(console.error); + +// @ts-ignore +global.server = server; diff --git a/src/middlewares/Authentication.ts b/src/middlewares/Authentication.ts index 5a1241f3..8fbae122 100644 --- a/src/middlewares/Authentication.ts +++ b/src/middlewares/Authentication.ts @@ -19,7 +19,7 @@ export function Authentication(req: Request, res: Response, next: NextFunction) if (NO_AUTHORIZATION_ROUTES.includes(req.url)) return next(); if (!req.headers.authorization) return next(new HTTPError("Missing Authorization Header", 401)); - return jwt.verify(req.headers.authorization, Config.get().server.jwtSecret, JWTOptions, (err, decoded: any) => { + return jwt.verify(req.headers.authorization, Config.get().security.jwtSecret, JWTOptions, (err, decoded: any) => { if (err || !decoded) return next(new HTTPError("Invalid Token", 401)); req.token = decoded; diff --git a/src/middlewares/BodyParser.ts b/src/middlewares/BodyParser.ts new file mode 100644 index 00000000..b0ff699d --- /dev/null +++ b/src/middlewares/BodyParser.ts @@ -0,0 +1,17 @@ +import bodyParser, { OptionsJson } from "body-parser"; +import { NextFunction, Request, Response } from "express"; +import { HTTPError } from "lambert-server"; + +export function BodyParser(opts?: OptionsJson) { + const jsonParser = bodyParser.json(opts); + + return (req: Request, res: Response, next: NextFunction) => { + jsonParser(req, res, (err) => { + if (err) { + // TODO: different errors for body parser (request size limit, wrong body type, invalid body, ...) + return next(new HTTPError("Invalid Body", 400)); + } + next(); + }); + }; +} diff --git a/src/middlewares/GlobalRateLimit.ts b/src/middlewares/GlobalRateLimit.ts index 5c5f690a..8fbfbd5c 100644 --- a/src/middlewares/GlobalRateLimit.ts +++ b/src/middlewares/GlobalRateLimit.ts @@ -3,16 +3,16 @@ import Config from "../util/Config"; import db from "../util/Database"; export async function GlobalRateLimit(req: Request, res: Response, next: NextFunction) { - if (!Config.get().server.ipRateLimit.enabled) return next(); + if (!Config.get().limits.rate.ip.enabled) return next(); const ip = getIpAdress(req); let limit = (await db.data.ratelimit.global[ip].get()) || { start: Date.now(), count: 0 }; - if (limit.start < Date.now() - Config.get().server.ipRateLimit.timespan) { + if (limit.start < Date.now() - Config.get().limits.rate.ip.timespan) { limit.start = Date.now(); limit.count = 0; } - if (limit.count > Config.get().server.ipRateLimit.count) { + if (limit.count > Config.get().limits.rate.ip.count) { const timespan = Date.now() - limit.start; return res @@ -37,7 +37,7 @@ export async function GlobalRateLimit(req: Request, res: Response, next: NextFun } export function getIpAdress(req: Request): string { - const { forwadedFor } = Config.get().server; + const { forwadedFor } = Config.get().security; const ip = forwadedFor ? req.headers[forwadedFor] : req.ip; return ip.replaceAll(".", "_").replaceAll(":", "_"); } diff --git a/src/test/mongo_test.ts b/src/test/mongo_test.ts index ad290198..d6906402 100644 --- a/src/test/mongo_test.ts +++ b/src/test/mongo_test.ts @@ -1,4 +1,6 @@ import mongoose from "mongoose"; +import { Long } from "mongodb"; +import { Snowflake } from "../util/Snowflake"; async function main() { const conn = await mongoose.createConnection( @@ -9,10 +11,7 @@ async function main() { } ); console.log("connected"); - const result = await conn - .collection("users") - .find({ $or: [{ email: "samuel.scheit@gmail.com" }, { phone: "samuel.scheit@gmail.com" }] }) - .toArray(); + const result = await conn.collection("users").insertOne({ test: Long.fromString(Snowflake.generate().toString()) }); // .project(undefined) console.log(result); diff --git a/src/util/String.ts b/src/util/String.ts index e7f014eb..fa93f1b7 100644 --- a/src/util/String.ts +++ b/src/util/String.ts @@ -1,6 +1,20 @@ -export const WHITE_SPACE = /\s\s+/g; +import { Request } from "express"; +import { FieldError, FieldErrors } from "./instanceOf"; + +export const DOUBLE_WHITE_SPACE = /\s\s+/g; export const SPECIAL_CHAR = /[@#`:\r\n\t\f\v\p{C}]/gu; -export function trim(str: string) { - return str.replace(SPECIAL_CHAR, "").replace(WHITE_SPACE, " ").trim(); +export function trimSpecial(str: string) { + return str.replace(SPECIAL_CHAR, "").replace(DOUBLE_WHITE_SPACE, " ").trim(); +} + +export function checkLength(str: string, min: number, max: number, key: string, req: Request) { + if (str.length < min || str.length > max) { + throw FieldErrors({ + [key]: { + code: "BASE_TYPE_BAD_LENGTH", + message: req.t("common:field.BASE_TYPE_BAD_LENGTH", { length: `${min} - ${max}` }), + }, + }); + } } diff --git a/src/util/instanceOf.ts b/src/util/instanceOf.ts index 341374b7..5035e4c9 100644 --- a/src/util/instanceOf.ts +++ b/src/util/instanceOf.ts @@ -95,7 +95,7 @@ export function instanceOf( return true; throw new FieldError("BASE_TYPE_CHOICES", t("common:field.BASE_TYPE_CHOICES", { types: type.types })); case Email: - if ((type).check()) return true; + if (new Email(value).check()) return true; throw new FieldError("EMAIL_TYPE_INVALID_EMAIL", t("common:field.EMAIL_TYPE_INVALID_EMAIL")); case Date: value = new Date(value); @@ -143,13 +143,13 @@ export function instanceOf( let newKey = key; const OPTIONAL = key.startsWith(OPTIONAL_PREFIX); if (OPTIONAL) newKey = newKey.slice(OPTIONAL_PREFIX.length); - errors[key] = {}; + errors[newKey] = {}; return ( instanceOf(type[key], value[newKey], { path: `${path}.${newKey}`, optional: OPTIONAL, - errors: errors[key], + errors: errors[newKey], t, ref: { key: newKey, obj: value }, }) === true