From c013a1847a62ac25e2bb73d71a66df964e39f08a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Minelli?= <michael@minelli.me> Date: Fri, 30 Jun 2023 23:01:38 +0200 Subject: [PATCH] Add Dojo validator --- ExpressAPI/src/helpers/DojoValidators.ts | 106 +++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 ExpressAPI/src/helpers/DojoValidators.ts diff --git a/ExpressAPI/src/helpers/DojoValidators.ts b/ExpressAPI/src/helpers/DojoValidators.ts new file mode 100644 index 0000000..aae3e1a --- /dev/null +++ b/ExpressAPI/src/helpers/DojoValidators.ts @@ -0,0 +1,106 @@ +import ApiRequest from '../models/ApiRequest'; +import Config from '../config/Config'; +import GitlabHelper from './GitlabHelper'; +import { StatusCodes } from 'http-status-codes'; +import { CustomValidator, ErrorMessage, FieldMessageFactory, Meta } from 'express-validator/src/base'; +import { BailOptions, ValidationChain } from 'express-validator/src/chain'; + + +declare type DojoMeta = Meta & { + req: ApiRequest +}; + +declare type DojoCustomValidator = (input: any, meta: DojoMeta) => any; + + +class DojoValidators { + private static _instance: DojoValidators; + + private constructor() { } + + public static get instance(): DojoValidators { + if ( !DojoValidators._instance ) { + DojoValidators._instance = new DojoValidators(); + } + + return DojoValidators._instance; + } + + private toValidatorSchemaOptions(arg: { errorMessage?: FieldMessageFactory | ErrorMessage, negated?: boolean, bail?: boolean | BailOptions, if?: DojoCustomValidator | ValidationChain, options?: DojoCustomValidator }) { + // This is a hack to make the types work with req arg as ApiRequest instead of Request + return arg as unknown as { errorMessage?: FieldMessageFactory | ErrorMessage, negated?: boolean, bail?: boolean | BailOptions, if?: CustomValidator | ValidationChain, options?: CustomValidator }; + } + + private getParamValue(req: ApiRequest, path: string): any { + return 'body' in req && path in req.body ? req.body[path] : req.query[path]; + } + + readonly nullSanitizer = this.toValidatorSchemaOptions({ + options: (value, { + req, + location, + path + }) => { + try { + return value == 'null' || value == 'undefined' || value == '' ? null : value; + } catch ( e ) { + return value; + } + } + }); + + readonly arraySanitizer = this.toValidatorSchemaOptions({ + options: (value, { + req, + location, + path + }) => { + try { + return JSON.parse(value); + } catch ( e ) { + return value; + } + } + }); + + readonly templateUrlValidator = this.toValidatorSchemaOptions({ + bail : true, + errorMessage: 'Template doesn\'t exist or you don\'t have access to it', + options : (value, { + req, + location, + path + }) => { + return new Promise((resolve, reject) => { + const template = this.getParamValue(req, path); + if ( template ) { + GitlabHelper.checkTemplateAccess(template, req).then((templateAccess) => { + templateAccess !== StatusCodes.OK ? reject() : resolve(true); + }); + } + resolve(true); + }); + } + }); + + readonly templateUrlSanitizer = this.toValidatorSchemaOptions({ + options: (value, { + req, + location, + path + }) => { + try { + const template = this.getParamValue(req, path); + if ( template ) { + return `${ Config.gitlab.urls[0].replace(/^([a-z]{3,5}:\/{2})?(.*)/, `$1${ Config.gitlab.account.username }:${ Config.gitlab.account.token }@$2`) }${ template }.git`; + } + } catch ( e ) { } + + return value; + } + }); + +} + + +export default DojoValidators.instance; \ No newline at end of file -- GitLab