diff options
author | Flam3rboy <34555296+Flam3rboy@users.noreply.github.com> | 2021-09-17 23:42:40 +0200 |
---|---|---|
committer | Flam3rboy <34555296+Flam3rboy@users.noreply.github.com> | 2021-09-17 23:42:40 +0200 |
commit | c20f4b4ef539a44c8e091815c5603acbf0fa8d04 (patch) | |
tree | 49e32c077cec3734d939ec4d4bb26980239f593a /api/src/util | |
parent | :bug: fix vanity url (diff) | |
download | server-c20f4b4ef539a44c8e091815c5603acbf0fa8d04.tar.xz |
:bug: fix body parse treating null not as undefined (except for icons/avatars)
Diffstat (limited to 'api/src/util')
-rw-r--r-- | api/src/util/route.ts | 45 |
1 files changed, 36 insertions, 9 deletions
diff --git a/api/src/util/route.ts b/api/src/util/route.ts index 6cd8f622..678ca64c 100644 --- a/api/src/util/route.ts +++ b/api/src/util/route.ts @@ -43,10 +43,37 @@ export interface RouteOptions { }; } +// Normalizer is introduced to workaround https://github.com/ajv-validator/ajv/issues/1287 +// this removes null values as ajv doesn't treat them as undefined +// normalizeBody allows to handle circular structures without issues +// taken from https://github.com/serverless/serverless/blob/master/lib/classes/ConfigSchemaHandler/index.js#L30 (MIT license) +const normalizeBody = (body: any = {}) => { + const normalizedObjectsSet = new WeakSet(); + const normalizeObject = (object: any) => { + if (normalizedObjectsSet.has(object)) return; + normalizedObjectsSet.add(object); + if (Array.isArray(object)) { + for (const [index, value] of object.entries()) { + if (typeof value === "object") normalizeObject(value); + } + } else { + for (const [key, value] of Object.entries(object)) { + if (value == null) { + if (key === "icon" || key === "avatar" || key === "banner" || key === "splash") continue; + delete object[key]; + } else if (typeof value === "object") { + normalizeObject(value); + } + } + } + }; + normalizeObject(body); + return body; +}; + export function route(opts: RouteOptions) { - var validate: AnyValidateFunction<any>; + var validate: AnyValidateFunction<any> | undefined; if (opts.body) { - // @ts-ignore validate = ajv.getSchema(opts.body); if (!validate) throw new Error(`Body schema ${opts.body} not found`); } @@ -60,14 +87,14 @@ export function route(opts: RouteOptions) { if (!permission.has(required)) { throw DiscordApiErrors.MISSING_PERMISSIONS.withParams(opts.permission as string); } + } - if (validate) { - const valid = validate(req.body); - if (!valid) { - const fields: Record<string, { code?: string; message: string }> = {}; - validate.errors?.forEach((x) => (fields[x.instancePath] = { code: x.keyword, message: x.message || "" })); - throw FieldErrors(fields); - } + if (validate) { + const valid = validate(normalizeBody(req.body)); + if (!valid) { + const fields: Record<string, { code?: string; message: string }> = {}; + validate.errors?.forEach((x) => (fields[x.instancePath.slice(1)] = { code: x.keyword, message: x.message || "" })); + throw FieldErrors(fields); } } next(); |