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