diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 0d65017186a6f34b98e10cb9cc077ac8940cb3ec..0e8c8e765377ec459fd84b493242bd136681e905 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -17,15 +17,23 @@ deploy-testing:
 deploy-master:    
   stage: deploy
   script:
-    - cat $configfileprod > ./config/config.js
-    - cat $cert > ./routes/cert/cert.pem
-    - cat $certidp > ./routes/cert/cert_idp.pem
-    - cat $key > ./routes/cert/key.pem
-    - npm install
+    - npm run clean
+    - npm run build
+    - rm -rf ./built/public/default
+    - rm -rf ./built/routes/cert
+    - rm -rf ./built/views
+    - cp -R ./public/default ./built/public
+    - cp -R ./routes/cert ./built/routes
+    - cp -R ./views ./built
+    - cat $configfileprod > ./built/config/config.js
+    - cat $cert > ./built/routes/cert/cert.pem
+    - cat $certidp > ./built/routes/cert/cert_idp.pem
+    - cat $key > ./built/routes/cert/key.pem
     - "pm2 delete --silent account || :"
-    - pm2 start ./app.js --name=account
+    - pm2 start ./built/app.js --name=account
     - pm2 save
+
   tags: 
     - production
   only: 
-    - master
\ No newline at end of file
+    - master
diff --git a/config/dbconn.js b/config/dbconn.js
index 670032958e099606b5558a39b94cc6492eb155e4..c13c40f11c2c3994791d75c866c5cfc6d210e1d7 100644
--- a/config/dbconn.js
+++ b/config/dbconn.js
@@ -1,6 +1,6 @@
-const mysql = require('mysql')
+import mysql from 'mysql2'
 
-var env = process.env.NODE_ENV || 'testing';
+var env = process.env.NODE_ENV || 'testing'
 const config = require('./config')[env]
 
 // ==== USER ACOOUNT DB CONNECTION ====
@@ -14,7 +14,7 @@ var userConnection = mysql.createConnection({
 })
 
 userConnection.connect(function(err) {
-    if (err) throw err;
+    if (err) throw err
 })
 userConnection.query('USE '+config.database.dbUser)
 
@@ -52,7 +52,7 @@ var projectConnection = mysql.createConnection({
 })
 
 projectConnection.connect(function(err) {
-    if (err) throw err;
+    if (err) throw err
 })
 projectConnection.query('USE '+config.database.dbProject)
 
@@ -61,4 +61,4 @@ var connection = {
     project: projectConnection
 }
 
-module.exports = connection
\ No newline at end of file
+export = connection
\ No newline at end of file
diff --git a/config/dbconn2.js b/config/dbconn2.js
deleted file mode 100644
index abbd0a012666e0d1f86b03512759cd438cd2d8fe..0000000000000000000000000000000000000000
--- a/config/dbconn2.js
+++ /dev/null
@@ -1,64 +0,0 @@
-const mysql = require('mysql2')
-
-var env = process.env.NODE_ENV || 'testing';
-const config = require('./config')[env]
-
-// ==== USER ACOOUNT DB CONNECTION ====
-var userConnection = mysql.createConnection({
-    host: config.database.host,
-    user: config.database.user,
-    password: config.database.password,
-    port: config.database.port,
-    database: config.database.dbUser,
-    multipleStatements: true
-})
-
-userConnection.connect(function(err) {
-    if (err) throw err;
-})
-userConnection.query('USE '+config.database.dbUser)
-
-// ALTERNATIVE approach: close db connection manually after every query
-/*
-var dbconn = function dbconn(query, values, next) {
-    var connection = mysql.createConnection({
-        host: config.database.host,
-        user: config.database.user,
-        password: config.database.password,
-        port: config.database.port,
-        database: config.database.db
-    })
-    connection.connect(function(err) {
-        if (err) throw err;
-    })
-    connection.query(query, values, function(err) {
-        connection.end(); // close the connection
-        if (err) {
-            throw err;
-        }
-        // Execute the callback
-        next.apply(this, arguments);
-    });
-}
-*/
-
-// ==== PROJECT DB CONNECTION ====
-var projectConnection = mysql.createConnection({
-    host: config.database.host_project,
-    user: config.database.user,
-    password: config.database.password,
-    port: config.database.port,
-    database: config.database.dbProject
-})
-
-projectConnection.connect(function(err) {
-    if (err) throw err;
-})
-projectConnection.query('USE '+config.database.dbProject)
-
-var connection = {
-    user: userConnection,
-    project: projectConnection
-}
-
-module.exports = connection
\ No newline at end of file
diff --git a/functions/methods.js b/functions/methods.js
index 0037a7e143bab55cee0d9d48b71263818af86b5a..cebfcb2179d5dcd9dc70e591708c6bd69300523c 100644
--- a/functions/methods.js
+++ b/functions/methods.js
@@ -1,59 +1,56 @@
-const dbconn_OBSOLETE = require('../config/dbconn') // DO NOT USE THIS FOR NEW FUNCTIONS
-const dbconn = require('../config/dbconn2')
+import dbconn = require('../config/dbconn')
 
 var methods = {
     // ===================== user db =====================
-    registerNewUser: function(data, callback) {
-        dbconn_OBSOLETE.user.beginTransaction(function(err) { // START TRANSACTION
-            if (err) {
-                throw err
-            }
+    registerNewUser: function(data:any, callback:any) {
+        dbconn.user.beginTransaction(function(err:any) { // START TRANSACTION
+            if (err) { throw err }
             // insert profile
-            dbconn_OBSOLETE.user.query('INSERT INTO user SET ?', data.profile, function (err, results, fields) {
+            dbconn.user.query('INSERT INTO user SET ?', data.profile, function (err:any, results:any, fields:any) {
                 if (err) {
-                  return dbconn_OBSOLETE.user.rollback(function() {
+                  return dbconn.user.rollback(function() {
                     throw err
                   });
                 }
-                var newUserId = results.insertId
+                let newUserId:number = results.insertId
                 // set password
-                var credentialData = {
+                var credentialData:any = {
                     user_id: newUserId,
                     password: data.password
                 }
-                dbconn_OBSOLETE.user.query('INSERT INTO credential SET ?', credentialData, function (err, results, fields) {
+                dbconn.user.query('INSERT INTO credential SET ?', credentialData, function (err:any, results:any, fields:any) {
                     if (err) {
-                        return dbconn_OBSOLETE.user.rollback(function() {
+                        return dbconn.user.rollback(function() {
                             throw err
                         });
                     }
                     // set default user-project-role
-                    var projectRoleData = {
+                    var projectRoleData:any = {
                         project_id: 1,  //M4_LAB
                         role_id: 2,     // USER
                         user_id: newUserId
                     }
-                    dbconn_OBSOLETE.user.query('INSERT INTO user_project_role SET ?', projectRoleData, function (err, results, fields) {
+                    dbconn.user.query('INSERT INTO user_project_role SET ?', projectRoleData, function (err:any, results:any, fields:any) {
                         if (err) {
-                            return dbconn_OBSOLETE.user.rollback(function() {
+                            return dbconn.user.rollback(function() {
                                 throw err
                             });
                         }
                         // MLAB-129: INSERT verification token
-                        let verificationData = {
+                        let verificationData:any = {
                             user_id: newUserId,
                             token: data.verificationToken
                         }
-                        dbconn_OBSOLETE.user.query('INSERT INTO verification SET ?', verificationData, function (err, results, fields) {
+                        dbconn.user.query('INSERT INTO verification SET ?', verificationData, function (err:any, results:any, fields:any) {
                             if (err) {
-                                return dbconn_OBSOLETE.user.rollback(function() {
+                                return dbconn.user.rollback(function() {
                                     throw err
                                 });
                             }
                             // COMMIT
-                            dbconn_OBSOLETE.user.commit(function(err) {
+                            dbconn.user.commit(function(err:any) {
                                 if (err) {
-                                    return dbconn_OBSOLETE.user.rollback(function() {
+                                    return dbconn.user.rollback(function() {
                                         throw err
                                     })
                                 }
@@ -65,9 +62,9 @@ var methods = {
             callback(err)
         })
     },
-    getUserByEmail: async function(email) {
+    getUserByEmail: async function(email:any) {
         try {
-            let rows = await dbconn.user.promise().query('SELECT id, verificationStatus, salutation, title, firstname, lastname, industry, organisation, speciality, m4lab_idp FROM user WHERE email = "' +email+'"')
+            let rows:any = await dbconn.user.promise().query('SELECT id, verificationStatus, salutation, title, firstname, lastname, industry, organisation, speciality, m4lab_idp FROM user WHERE email = "' +email+'"')
             if (rows[0][0]) {
                 return rows[0][0]
             }
@@ -77,9 +74,9 @@ var methods = {
         }
         return null
     },
-    getUserEmailById: async function(userId) {
+    getUserEmailById: async function(userId:number) {
         try {
-            let rows = await dbconn.user.promise().query('SELECT email FROM user WHERE id = ' +userId)
+            let rows:any = await dbconn.user.promise().query('SELECT email FROM user WHERE id = ' +userId)
             if (rows[0][0]) {
                 return rows[0][0].email
             }
@@ -89,9 +86,9 @@ var methods = {
         }
         return null
     },
-    checkUserEmail: async function(email) {
+    checkUserEmail: async function(email:any) {
         try {
-            let rows = await dbconn.user.promise().query('SELECT id, email FROM user WHERE email = "' +email+'"')
+            let rows:any = await dbconn.user.promise().query('SELECT id, email FROM user WHERE email = "' +email+'"')
             if (rows[0][0]) {
                 return rows[0][0]
             }
@@ -101,9 +98,9 @@ var methods = {
         }
         return null
     },
-    getUserByToken: async function(token) {
+    getUserByToken: async function(token:any) {
         try {
-            let rows = await dbconn.user.promise().query('SELECT t1.user_id, t2.email FROM userdb.credential AS t1 INNER JOIN userdb.user AS t2 ON t1.user_id = t2.id AND t1.resetPasswordToken = "'
+            let rows:any = await dbconn.user.promise().query('SELECT t1.user_id, t2.email FROM userdb.credential AS t1 INNER JOIN userdb.user AS t2 ON t1.user_id = t2.id AND t1.resetPasswordToken = "'
                 +token+'" and resetPasswordExpires > '+Date.now())
             if (rows[0][0]) {
                 return rows[0][0]
@@ -114,47 +111,33 @@ var methods = {
         }
         return null
     },
-	updateUserById: function(userData, callback) {
-		dbconn_OBSOLETE.user.query('UPDATE user SET ? WHERE id = ' +userData.id, userData, function (err, rows, fields) {
-            if (err) throw err
-            callback(err)
-        })
-    },
-    updateCredential: function(data, callback) {
-        dbconn_OBSOLETE.user.query('UPDATE credential SET ? WHERE user_id = ' +data.user_id, data, function (err, rows, fields) {
-            if (err) throw err
-            callback(err)
-        })
-    },
-    getUserIdByEmail_OBSOLETE: function(email, callback) {
-        let userId
-        dbconn_OBSOLETE.user.query('SELECT id FROM user WHERE email = "' +email+'"', function (err, rows, fields) {
-            if (err) {
-                throw err
-            }
-            else {
-                if ( rows.length > 0) {
-                    userId = rows[0].id
-                }
-            }
-            callback(userId, err)
-        });
+    updateUserById: async function(userId:number, userData:any) {
+        try {
+            let result:any = await dbconn.user.promise().query('UPDATE user SET ? WHERE id = ' +userId, userData)
+            return result
+        } catch (err) {
+            console.error(err)
+        }
+        return null
     },
-    getUserProjectRole_OBSOLETE: function(userId, callback) {
-        dbconn_OBSOLETE.user.query('SELECT project_id, role_id FROM user_project_role WHERE user_id = "' +userId+'"', function (err, rows, fields) {
-            if (err) throw err
-            callback(rows, err)
-        });
+    updateCredential: async function(data:any) {
+        try {
+            let result:any = await dbconn.user.promise().query('UPDATE credential SET ? WHERE user_id = ' +data.user_id, data)
+            return result
+        } catch (err) {
+            console.error(err)
+        }
+        return null
     },
-    addUserProjectRole: function(data, callback) {
-        dbconn_OBSOLETE.user.query('INSERT INTO user_project_role SET ?', data, function (err, results, fields){
+    addUserProjectRole_OBSOLETE: function(data:any, callback:any) {
+        dbconn.user.query('INSERT INTO user_project_role SET ?', data, function (err:any){
             if (err) throw err
             callback(err)
         })
     },
-    getVerificationTokenByUserId: async function(userId) {
+    getVerificationTokenByUserId: async function(userId:number) {
         try {
-            let rows = await dbconn.user.promise().query('SELECT token FROM verification WHERE user_id = "' +userId+'"')
+            let rows:any = await dbconn.user.promise().query('SELECT token FROM verification WHERE user_id = "' +userId+'"')
             if (rows[0][0]) {
                 return rows[0][0].token
             }
@@ -164,9 +147,9 @@ var methods = {
         }
         return null
     },
-    getUserIdByVerificationToken: async function(token) {
+    getUserIdByVerificationToken: async function(token:any) {
         try {
-            let rows = await dbconn.user.promise().query('SELECT user_id FROM verification WHERE token = "' +token+'"')
+            let rows:any = await dbconn.user.promise().query('SELECT user_id FROM verification WHERE token = "' +token+'"')
             if (rows[0][0]) {
                 return rows[0][0].user_id
             }
@@ -178,23 +161,23 @@ var methods = {
         }
         return null
     },
-    verifyUserAccount: function(userData, callback) {
-        dbconn_OBSOLETE.user.beginTransaction(function(err) { // START TRANSACTION
+    verifyUserAccount: function(userData:any, callback:any) {
+        dbconn.user.beginTransaction(function(err:any) { // START TRANSACTION
             if (err) { throw err }
             // update user status
-            dbconn_OBSOLETE.user.query('UPDATE user SET ? WHERE id =' +userData.id, userData, function (err, rows, fields) {
+            dbconn.user.query('UPDATE user SET ? WHERE id =' +userData.id, userData, function (err:any, rows:any, fields:any) {
                 if (err) {
-                    return dbconn_OBSOLETE.user.rollback(function() { throw err })
+                    return dbconn.user.rollback(function() { throw err })
                 }
                 // delete verification token
-                dbconn_OBSOLETE.user.query('DELETE FROM verification WHERE user_id = '+userData.id, function (err, rows, fields) {
+                dbconn.user.query('DELETE FROM verification WHERE user_id = '+userData.id, function (err:any, rows:any, fields:any) {
                     if (err) {
-                        return dbconn_OBSOLETE.user.rollback(function() { throw err })
+                        return dbconn.user.rollback(function() { throw err })
                     }
                     // COMMIT
-                    dbconn_OBSOLETE.user.commit(function(err) {
+                    dbconn.user.commit(function(err:any) {
                         if (err) {
-                            return dbconn_OBSOLETE.user.rollback(function() { throw err })
+                            return dbconn.user.rollback(function() { throw err })
                         }
                     })
                 })
@@ -203,9 +186,9 @@ var methods = {
         })
     },
     /* ===== GitLab ===== */
-    getGitlabId: async function(userId) {
+    getGitlabId: async function(userId:number) {
         try {
-            let rows = await dbconn.user.promise().query('SELECT gu.gitlab_userId FROM user_gitlab gu, user u WHERE u.id = "' +userId+'" and gu.user_id = u.id')
+            let rows:any = await dbconn.user.promise().query('SELECT gu.gitlab_userId FROM user_gitlab gu, user u WHERE u.id = "' +userId+'" and gu.user_id = u.id')
             if (rows[0][0]) {
                 return rows[0][0].gitlab_userId
             } else {
@@ -217,12 +200,12 @@ var methods = {
             return err
         }
     },
-    addGitlabUser: function(data, callback){
-        dbconn_OBSOLETE.user.query('INSERT INTO user_gitlab SET ?', data, function (err) {
+    addGitlabUser: function(data:any, callback:any){
+        dbconn.user.query('INSERT INTO user_gitlab SET ?', data, function (err:any) {
             if (err) throw err
             callback(err)
         })
     }
 };
 
-module.exports = methods;
\ No newline at end of file
+export = methods
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 2b7642f6f140ab83974872e34c32167647dc95ae..817a7b40ebff26202cb6a43a0401c3abcec58c0d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,28 +15,45 @@
         "body-parser": "^1.19.0",
         "compression": "^1.7.4",
         "cookie-parser": "1.4.3",
-        "crypto": "^1.0.1",
-        "errorhandler": "1.4.3",
+        "dotenv": "^9.0.2",
         "express": "^4.17.1",
         "express-fileupload": "^1.1.6",
         "express-flash-2": "^1.0.1",
         "express-session": "^1.17.0",
         "form-data": "^3.0.0",
         "fs": "0.0.1-security",
-        "helmet": "^3.23.3",
-        "i18n": "^0.8.5",
-        "jest": "^26.6.3",
+        "helmet": "^4.6.0",
+        "jest": "^26.5.0",
         "method-override": "^3.0.0",
         "morgan": "^1.9.1",
-        "mysql": "^2.17.1",
         "mysql2": "^2.2.5",
         "nodemailer": "^6.3.1",
+        "nodemailer-ntlm-auth": "^1.0.1",
         "passport": "0.3.2",
         "passport-saml": "^2.1.0",
         "pug": "^3.0.2"
       },
       "devDependencies": {
-        "nodemon": "^2.0.1"
+        "@types/async": "^3.2.6",
+        "@types/bcryptjs": "^2.4.2",
+        "@types/compression": "^1.7.0",
+        "@types/cookie-parser": "^1.4.2",
+        "@types/express": "^4.17.11",
+        "@types/express-fileupload": "^1.1.6",
+        "@types/express-flash-2": "^1.0.6",
+        "@types/express-session": "^1.17.0",
+        "@types/jest": "^26.0.23",
+        "@types/method-override": "^0.0.31",
+        "@types/morgan": "^1.9.2",
+        "@types/mysql": "^2.15.18",
+        "@types/node": "^15.0.2",
+        "@types/nodemailer": "^6.4.1",
+        "@types/passport": "^1.0.6",
+        "@types/passport-strategy": "^0.2.35",
+        "@types/xml2js": "^0.4.8",
+        "nodemon": "^2.0.1",
+        "ts-node": "^9.1.1",
+        "typescript": "^4.2.4"
       },
       "engines": {
         "node": ">= 4.0.0"
@@ -51,9 +68,9 @@
       }
     },
     "node_modules/@babel/compat-data": {
-      "version": "7.14.0",
-      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.0.tgz",
-      "integrity": "sha512-vu9V3uMM/1o5Hl5OekMUowo3FqXLJSw+s+66nt0fSWVWTtmosdzn45JHOB3cPtZoe6CTBDzvSw0RdOY85Q37+Q=="
+      "version": "7.14.4",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.4.tgz",
+      "integrity": "sha512-i2wXrWQNkH6JplJQGn3Rd2I4Pij8GdHkXwHMxm+zV5YG/Jci+bCNrWZEWC4o+umiDkRrRs4dVzH3X4GP7vyjQQ=="
     },
     "node_modules/@babel/core": {
       "version": "7.14.3",
@@ -132,13 +149,13 @@
       }
     },
     "node_modules/@babel/helper-compilation-targets": {
-      "version": "7.13.16",
-      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.16.tgz",
-      "integrity": "sha512-3gmkYIrpqsLlieFwjkGgLaSHmhnvlAYzZLlYVjlW+QwI+1zE17kGxuJGmIqDQdYp56XdmGeD+Bswx0UTyG18xA==",
+      "version": "7.14.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.14.4.tgz",
+      "integrity": "sha512-JgdzOYZ/qGaKTVkn5qEDV/SXAh8KcyUVkCoSWGN8T3bwrgd6m+/dJa2kVGi6RJYJgEYPBdZ84BZp9dUjNWkBaA==",
       "dependencies": {
-        "@babel/compat-data": "^7.13.15",
+        "@babel/compat-data": "^7.14.4",
         "@babel/helper-validator-option": "^7.12.17",
-        "browserslist": "^4.14.5",
+        "browserslist": "^4.16.6",
         "semver": "^6.3.0"
       },
       "peerDependencies": {
@@ -208,14 +225,14 @@
       "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ=="
     },
     "node_modules/@babel/helper-replace-supers": {
-      "version": "7.14.3",
-      "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.14.3.tgz",
-      "integrity": "sha512-Rlh8qEWZSTfdz+tgNV/N4gz1a0TMNwCUcENhMjHTHKp3LseYH5Jha0NSlyTQWMnjbYcwFt+bqAMqSLHVXkQ6UA==",
+      "version": "7.14.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.14.4.tgz",
+      "integrity": "sha512-zZ7uHCWlxfEAAOVDYQpEf/uyi1dmeC7fX4nCf2iz9drnCwi1zvwXL3HwWWNXUQEJ1k23yVn3VbddiI9iJEXaTQ==",
       "dependencies": {
         "@babel/helper-member-expression-to-functions": "^7.13.12",
         "@babel/helper-optimise-call-expression": "^7.12.13",
         "@babel/traverse": "^7.14.2",
-        "@babel/types": "^7.14.2"
+        "@babel/types": "^7.14.4"
       }
     },
     "node_modules/@babel/helper-simple-access": {
@@ -321,9 +338,9 @@
       }
     },
     "node_modules/@babel/parser": {
-      "version": "7.14.3",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.3.tgz",
-      "integrity": "sha512-7MpZDIfI7sUC5zWo2+foJ50CSI5lcqDehZ0lVgIhSi4bFEk94fLAKlF3Q0nzSQQ+ca0lm+O6G9ztKVBeu8PMRQ==",
+      "version": "7.14.4",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.4.tgz",
+      "integrity": "sha512-ArliyUsWDUqEGfWcmzpGUzNfLxTdTp6WU4IuP6QFSp9gGfWS6boxFCkJSJ/L4+RG8z/FnIU3WxCk6hPL9SSWeA==",
       "bin": {
         "parser": "bin/babel-parser.js"
       },
@@ -510,9 +527,9 @@
       "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
     },
     "node_modules/@babel/types": {
-      "version": "7.14.2",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.2.tgz",
-      "integrity": "sha512-SdjAG/3DikRHpUOjxZgnkbR11xUlyDMUFJdvnIgZEE16mqmY0BINMmc4//JMJglEmn6i7sq6p+mGrFWyZ98EEw==",
+      "version": "7.14.4",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.4.tgz",
+      "integrity": "sha512-lCj4aIs0xUefJFQnwwQv2Bxg7Omd6bgquZ6LGC+gGMh6/s5qDVfjuCMlDmYQ15SLsWHd9n+X3E75lKIhl5Lkiw==",
       "dependencies": {
         "@babel/helper-validator-identifier": "^7.14.0",
         "to-fast-properties": "^2.0.0"
@@ -830,6 +847,12 @@
         "node": ">= 6"
       }
     },
+    "node_modules/@types/async": {
+      "version": "3.2.6",
+      "resolved": "https://registry.npmjs.org/@types/async/-/async-3.2.6.tgz",
+      "integrity": "sha512-ZkrXnZLC1mc4b9QLKaSrsxV4oxTRs10OI2kgSApT8G0v1jrmqppSHUVQ15kLorzsFBTjvf7OKF4kAibuuNQ+xA==",
+      "dev": true
+    },
     "node_modules/@types/babel__core": {
       "version": "7.1.14",
       "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.14.tgz",
@@ -867,6 +890,100 @@
         "@babel/types": "^7.3.0"
       }
     },
+    "node_modules/@types/bcryptjs": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.2.tgz",
+      "integrity": "sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==",
+      "dev": true
+    },
+    "node_modules/@types/body-parser": {
+      "version": "1.19.0",
+      "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz",
+      "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/connect": "*",
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/compression": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.0.tgz",
+      "integrity": "sha512-3LzWUM+3k3XdWOUk/RO+uSjv7YWOatYq2QADJntK1pjkk4DfVP0KrIEPDnXRJxAAGKe0VpIPRmlINLDuCedZWw==",
+      "dev": true,
+      "dependencies": {
+        "@types/express": "*"
+      }
+    },
+    "node_modules/@types/connect": {
+      "version": "3.4.34",
+      "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz",
+      "integrity": "sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/cookie-parser": {
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.2.tgz",
+      "integrity": "sha512-uwcY8m6SDQqciHsqcKDGbo10GdasYsPCYkH3hVegj9qAah6pX5HivOnOuI3WYmyQMnOATV39zv/Ybs0bC/6iVg==",
+      "dev": true,
+      "dependencies": {
+        "@types/express": "*"
+      }
+    },
+    "node_modules/@types/express": {
+      "version": "4.17.12",
+      "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.12.tgz",
+      "integrity": "sha512-pTYas6FrP15B1Oa0bkN5tQMNqOcVXa9j4FTFtO8DWI9kppKib+6NJtfTOOLcwxuuYvcX2+dVG6et1SxW/Kc17Q==",
+      "dev": true,
+      "dependencies": {
+        "@types/body-parser": "*",
+        "@types/express-serve-static-core": "^4.17.18",
+        "@types/qs": "*",
+        "@types/serve-static": "*"
+      }
+    },
+    "node_modules/@types/express-fileupload": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/@types/express-fileupload/-/express-fileupload-1.1.6.tgz",
+      "integrity": "sha512-8z92PCVgvWvG1TpxucRU9oRz3hZc5cUz+CkeDe4XwVmg2DJDdd/7QASMsJzIo+9Pbfp7LfTEWSeEFUJZBohv9g==",
+      "dev": true,
+      "dependencies": {
+        "@types/express": "*"
+      }
+    },
+    "node_modules/@types/express-flash-2": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/@types/express-flash-2/-/express-flash-2-1.0.6.tgz",
+      "integrity": "sha512-8YE6SDUxIIrsAKJL65nfUYtgO356QcT889GaXrwS0em7VYgbz6ShPdLUBOMDu8ihZrqidp5Qz2bNnWCCP4rZMw==",
+      "dev": true,
+      "dependencies": {
+        "@types/express": "*"
+      }
+    },
+    "node_modules/@types/express-serve-static-core": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.21.tgz",
+      "integrity": "sha512-gwCiEZqW6f7EoR8TTEfalyEhb1zA5jQJnRngr97+3pzMaO1RKoI1w2bw07TK72renMUVWcWS5mLI6rk1NqN0nA==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*",
+        "@types/qs": "*",
+        "@types/range-parser": "*"
+      }
+    },
+    "node_modules/@types/express-session": {
+      "version": "1.17.0",
+      "resolved": "https://registry.npmjs.org/@types/express-session/-/express-session-1.17.0.tgz",
+      "integrity": "sha512-OQEHeBFE1UhChVIBhRh9qElHUvTp4BzKKHxMDkGHT7WuYk5eL93hPG7D8YAIkoBSbhNEY0RjreF15zn+U0eLjA==",
+      "dev": true,
+      "dependencies": {
+        "@types/express": "*",
+        "@types/node": "*"
+      }
+    },
     "node_modules/@types/graceful-fs": {
       "version": "4.1.5",
       "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz",
@@ -889,33 +1006,135 @@
       }
     },
     "node_modules/@types/istanbul-reports": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
-      "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz",
+      "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==",
       "dependencies": {
         "@types/istanbul-lib-report": "*"
       }
     },
+    "node_modules/@types/jest": {
+      "version": "26.0.23",
+      "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.23.tgz",
+      "integrity": "sha512-ZHLmWMJ9jJ9PTiT58juykZpL7KjwJywFN3Rr2pTSkyQfydf/rk22yS7W8p5DaVUMQ2BQC7oYiU3FjbTM/mYrOA==",
+      "dev": true,
+      "dependencies": {
+        "jest-diff": "^26.0.0",
+        "pretty-format": "^26.0.0"
+      }
+    },
+    "node_modules/@types/method-override": {
+      "version": "0.0.31",
+      "resolved": "https://registry.npmjs.org/@types/method-override/-/method-override-0.0.31.tgz",
+      "integrity": "sha512-aLA4MGzjYjBHGpr5TgAdPRyX97Jd+xlWN2wa6PbsjKYeoUKPsxVDFRSTjI3YG4MvGg3ZJkdMxjAXZfujU9qEPw==",
+      "dev": true,
+      "dependencies": {
+        "@types/express": "*"
+      }
+    },
+    "node_modules/@types/mime": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
+      "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==",
+      "dev": true
+    },
+    "node_modules/@types/morgan": {
+      "version": "1.9.2",
+      "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.2.tgz",
+      "integrity": "sha512-edtGMEdit146JwwIeyQeHHg9yID4WSolQPxpEorHmN3KuytuCHyn2ELNr5Uxy8SerniFbbkmgKMrGM933am5BQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/mysql": {
+      "version": "2.15.18",
+      "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.18.tgz",
+      "integrity": "sha512-JW74Nh3P/RDAnaP8uXe1qmRpoFBO84SiWvWoSju/F5+2S1kVBi1FbbDoqK/sTZrCCxySaOJnRATvWD+bLcJjAg==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
     "node_modules/@types/node": {
-      "version": "15.6.1",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-15.6.1.tgz",
-      "integrity": "sha512-7EIraBEyRHEe7CH+Fm1XvgqU6uwZN8Q7jppJGcqjROMT29qhAuuOxYB1uEY5UMYQKEmA5D+5tBnhdaPXSsLONA=="
+      "version": "15.12.2",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz",
+      "integrity": "sha512-zjQ69G564OCIWIOHSXyQEEDpdpGl+G348RAKY0XXy9Z5kU9Vzv1GMNnkar/ZJ8dzXB3COzD9Mo9NtRZ4xfgUww=="
+    },
+    "node_modules/@types/nodemailer": {
+      "version": "6.4.2",
+      "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.2.tgz",
+      "integrity": "sha512-yhsqg5Xbr8aWdwjFS3QjkniW5/tLpWXtOYQcJdo9qE3DolBxsKzgRCQrteaMY0hos8MklJNSEsMqDpZynGzMNg==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*"
+      }
     },
     "node_modules/@types/normalize-package-data": {
       "version": "2.4.0",
       "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
       "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA=="
     },
+    "node_modules/@types/passport": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.6.tgz",
+      "integrity": "sha512-9oKfrJXuAxvyxdrtMCxKkHgmd6DMO8NDOLvMJ1LvIWd6/xP+i81PAkpTaEca7VhJX9S009RciwZL/j6dsLsHrA==",
+      "dev": true,
+      "dependencies": {
+        "@types/express": "*"
+      }
+    },
+    "node_modules/@types/passport-strategy": {
+      "version": "0.2.35",
+      "resolved": "https://registry.npmjs.org/@types/passport-strategy/-/passport-strategy-0.2.35.tgz",
+      "integrity": "sha512-o5D19Jy2XPFoX2rKApykY15et3Apgax00RRLf0RUotPDUsYrQa7x4howLYr9El2mlUApHmCMv5CZ1IXqKFQ2+g==",
+      "dev": true,
+      "dependencies": {
+        "@types/express": "*",
+        "@types/passport": "*"
+      }
+    },
     "node_modules/@types/prettier": {
       "version": "2.2.3",
       "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.3.tgz",
       "integrity": "sha512-PijRCG/K3s3w1We6ynUKdxEc5AcuuH3NBmMDP8uvKVp6X43UY7NQlTzczakXP3DJR0F4dfNQIGjU2cUeRYs2AA=="
     },
+    "node_modules/@types/qs": {
+      "version": "6.9.6",
+      "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.6.tgz",
+      "integrity": "sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA==",
+      "dev": true
+    },
+    "node_modules/@types/range-parser": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz",
+      "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==",
+      "dev": true
+    },
+    "node_modules/@types/serve-static": {
+      "version": "1.13.9",
+      "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.9.tgz",
+      "integrity": "sha512-ZFqF6qa48XsPdjXV5Gsz0Zqmux2PerNd3a/ktL45mHpa19cuMi/cL8tcxdAx497yRh+QtYPuofjT9oWw9P7nkA==",
+      "dev": true,
+      "dependencies": {
+        "@types/mime": "^1",
+        "@types/node": "*"
+      }
+    },
     "node_modules/@types/stack-utils": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz",
       "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw=="
     },
+    "node_modules/@types/xml2js": {
+      "version": "0.4.8",
+      "resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.8.tgz",
+      "integrity": "sha512-EyvT83ezOdec7BhDaEcsklWy7RSIdi6CNe95tmOAK0yx/Lm30C9K75snT3fYayK59ApC2oyW+rcHErdG05FHJA==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
     "node_modules/@types/yargs": {
       "version": "15.0.13",
       "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz",
@@ -953,9 +1172,9 @@
       }
     },
     "node_modules/acorn": {
-      "version": "8.2.4",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.2.4.tgz",
-      "integrity": "sha512-Ibt84YwBDDA890eDiDCEqcbwvHlBvzzDkU2cGBBDDI1QWT12jTiXIOn2CIw5KK4i6N5Z2HUxwYjzriDyqaqqZg==",
+      "version": "8.3.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.3.0.tgz",
+      "integrity": "sha512-tqPKHZ5CaBJw0Xmy0ZZvLs1qTV+BNFSyvn77ASXkpBNfIRk8ev26fKrD9iLGwGA9zedPao52GSHzq8lyZG0NUw==",
       "bin": {
         "acorn": "bin/acorn"
       },
@@ -1130,6 +1349,12 @@
         "node": ">= 8"
       }
     },
+    "node_modules/arg": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+      "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+      "devOptional": true
+    },
     "node_modules/argparse": {
       "version": "1.0.10",
       "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@@ -1138,11 +1363,6 @@
         "sprintf-js": "~1.0.2"
       }
     },
-    "node_modules/argparse/node_modules/sprintf-js": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
-      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
-    },
     "node_modules/arr-diff": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
@@ -1382,14 +1602,6 @@
       "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
       "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms="
     },
-    "node_modules/bignumber.js": {
-      "version": "9.0.0",
-      "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz",
-      "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==",
-      "engines": {
-        "node": "*"
-      }
-    },
     "node_modules/binary-extensions": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
@@ -1419,11 +1631,6 @@
         "node": ">= 0.8"
       }
     },
-    "node_modules/bowser": {
-      "version": "2.9.0",
-      "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.9.0.tgz",
-      "integrity": "sha512-2ld76tuLBNFekRgmJfT2+3j5MIrP6bFict8WAIT3beq+srz1gcKNAdNKMqHqauQt63NmAa88HfP1/Ypa9Er3HA=="
-    },
     "node_modules/boxen": {
       "version": "4.2.0",
       "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz",
@@ -1626,15 +1833,10 @@
         "node": ">=6"
       }
     },
-    "node_modules/camelize": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz",
-      "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs="
-    },
     "node_modules/caniuse-lite": {
-      "version": "1.0.30001230",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001230.tgz",
-      "integrity": "sha512-5yBd5nWCBS+jWKTcHOzXwo5xzcj4ePE/yjtkZyUV1BTUmrBaA9MRGC+e7mxnqXSA90CmCA8L3eKLaSUkt099IQ==",
+      "version": "1.0.30001235",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001235.tgz",
+      "integrity": "sha512-zWEwIVqnzPkSAXOUlQnPW2oKoYb2aLQ4Q5ejdjBcnH63rfypaW34CxaeBn1VMya2XaEU3P/R2qHpWyj+l0BT1A==",
       "funding": {
         "type": "opencollective",
         "url": "https://opencollective.com/browserslist"
@@ -1999,14 +2201,6 @@
         "node": ">= 0.6"
       }
     },
-    "node_modules/content-security-policy-builder": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/content-security-policy-builder/-/content-security-policy-builder-2.1.0.tgz",
-      "integrity": "sha512-/MtLWhJVvJNkA9dVLAp6fg9LxD2gfI6R2Fi1hPmfjYXSahJJzcfvoeDOxSyp4NvxMuwWv3WMssE9o31DoULHrQ==",
-      "engines": {
-        "node": ">=4.0.0"
-      }
-    },
     "node_modules/content-type": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
@@ -2056,10 +2250,11 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/core-util-is": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
-      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+    "node_modules/create-require": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+      "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
+      "devOptional": true
     },
     "node_modules/cross-spawn": {
       "version": "7.0.3",
@@ -2074,12 +2269,6 @@
         "node": ">= 8"
       }
     },
-    "node_modules/crypto": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz",
-      "integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==",
-      "deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in."
-    },
     "node_modules/crypto-random-string": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
@@ -2110,11 +2299,6 @@
       "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz",
       "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg=="
     },
-    "node_modules/dasherize": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/dasherize/-/dasherize-2.0.0.tgz",
-      "integrity": "sha1-bYCcnNDPe7iVLYD8hPoT1H3bEwg="
-    },
     "node_modules/data-urls": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz",
@@ -2316,14 +2500,6 @@
         "node": ">=8"
       }
     },
-    "node_modules/dont-sniff-mimetype": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/dont-sniff-mimetype/-/dont-sniff-mimetype-1.1.0.tgz",
-      "integrity": "sha512-ZjI4zqTaxveH2/tTlzS1wFp+7ncxNZaIEWYg3lzZRHkKf5zPT/MnEG6WL0BhHMJUabkh8GeU5NL5j+rEUCb7Ug==",
-      "engines": {
-        "node": ">=4.0.0"
-      }
-    },
     "node_modules/dot-prop": {
       "version": "5.3.0",
       "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
@@ -2336,6 +2512,14 @@
         "node": ">=8"
       }
     },
+    "node_modules/dotenv": {
+      "version": "9.0.2",
+      "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-9.0.2.tgz",
+      "integrity": "sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==",
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/duplexer3": {
       "version": "0.1.4",
       "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
@@ -2348,9 +2532,9 @@
       "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
     },
     "node_modules/electron-to-chromium": {
-      "version": "1.3.741",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.741.tgz",
-      "integrity": "sha512-4i3T0cwnHo1O4Mnp9JniEco8bZiXoqbm3PhW5hv7uu8YLg35iajYrRnNyKFaN8/8SSTskU2hYqVTeYVPceSpUA=="
+      "version": "1.3.749",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.749.tgz",
+      "integrity": "sha512-F+v2zxZgw/fMwPz/VUGIggG4ZndDsYy0vlpthi3tjmDZlcfbhN5mYW0evXUsBr2sUtuDANFtle410A9u/sd/4A=="
     },
     "node_modules/emittery": {
       "version": "0.7.2",
@@ -2392,18 +2576,6 @@
         "is-arrayish": "^0.2.1"
       }
     },
-    "node_modules/errorhandler": {
-      "version": "1.4.3",
-      "resolved": "https://registry.npmjs.org/errorhandler/-/errorhandler-1.4.3.tgz",
-      "integrity": "sha1-t7cO2PNZ6duICS8tIMD4MUIK2D8=",
-      "dependencies": {
-        "accepts": "~1.3.0",
-        "escape-html": "~1.0.3"
-      },
-      "engines": {
-        "node": ">= 0.8"
-      }
-    },
     "node_modules/escalade": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
@@ -2856,14 +3028,6 @@
         "bser": "2.1.1"
       }
     },
-    "node_modules/feature-policy": {
-      "version": "0.3.0",
-      "resolved": "https://registry.npmjs.org/feature-policy/-/feature-policy-0.3.0.tgz",
-      "integrity": "sha512-ZtijOTFN7TzCujt1fnNhfWPFPSHeZkesff9AXZj+UEjYBynWNUIYpC87Ve4wHzyexQsImicLu7WsC2LHq7/xrQ==",
-      "engines": {
-        "node": ">=4.0.0"
-      }
-    },
     "node_modules/fill-range": {
       "version": "7.0.1",
       "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@@ -2945,9 +3109,9 @@
       }
     },
     "node_modules/forwarded": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
-      "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=",
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+      "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
       "engines": {
         "node": ">= 0.6"
       }
@@ -3281,62 +3445,11 @@
       }
     },
     "node_modules/helmet": {
-      "version": "3.23.3",
-      "resolved": "https://registry.npmjs.org/helmet/-/helmet-3.23.3.tgz",
-      "integrity": "sha512-U3MeYdzPJQhtvqAVBPntVgAvNSOJyagwZwyKsFdyRa8TV3pOKVFljalPOCxbw5Wwf2kncGhmP0qHjyazIdNdSA==",
-      "dependencies": {
-        "depd": "2.0.0",
-        "dont-sniff-mimetype": "1.1.0",
-        "feature-policy": "0.3.0",
-        "helmet-crossdomain": "0.4.0",
-        "helmet-csp": "2.10.0",
-        "hide-powered-by": "1.1.0",
-        "hpkp": "2.0.0",
-        "hsts": "2.2.0",
-        "nocache": "2.1.0",
-        "referrer-policy": "1.2.0",
-        "x-xss-protection": "1.3.0"
-      },
-      "engines": {
-        "node": ">=4.0.0"
-      }
-    },
-    "node_modules/helmet-crossdomain": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/helmet-crossdomain/-/helmet-crossdomain-0.4.0.tgz",
-      "integrity": "sha512-AB4DTykRw3HCOxovD1nPR16hllrVImeFp5VBV9/twj66lJ2nU75DP8FPL0/Jp4jj79JhTfG+pFI2MD02kWJ+fA==",
-      "engines": {
-        "node": ">=4.0.0"
-      }
-    },
-    "node_modules/helmet-csp": {
-      "version": "2.10.0",
-      "resolved": "https://registry.npmjs.org/helmet-csp/-/helmet-csp-2.10.0.tgz",
-      "integrity": "sha512-Rz953ZNEFk8sT2XvewXkYN0Ho4GEZdjAZy4stjiEQV3eN7GDxg1QKmYggH7otDyIA7uGA6XnUMVSgeJwbR5X+w==",
-      "dependencies": {
-        "bowser": "2.9.0",
-        "camelize": "1.0.0",
-        "content-security-policy-builder": "2.1.0",
-        "dasherize": "2.0.0"
-      },
-      "engines": {
-        "node": ">=4.0.0"
-      }
-    },
-    "node_modules/helmet/node_modules/depd": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
-      "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
-      "engines": {
-        "node": ">= 0.8"
-      }
-    },
-    "node_modules/hide-powered-by": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/hide-powered-by/-/hide-powered-by-1.1.0.tgz",
-      "integrity": "sha512-Io1zA2yOA1YJslkr+AJlWSf2yWFkKjvkcL9Ni1XSUqnGLr/qRQe2UI3Cn/J9MsJht7yEVCe0SscY1HgVMujbgg==",
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/helmet/-/helmet-4.6.0.tgz",
+      "integrity": "sha512-HVqALKZlR95ROkrnesdhbbZJFi/rIVSoNq6f3jA/9u6MIbTsPh3xZwihjeI5+DO/2sOV6HMHooXcEOuwskHpTg==",
       "engines": {
-        "node": ">=4.0.0"
+        "node": ">=10.0.0"
       }
     },
     "node_modules/hosted-git-info": {
@@ -3344,30 +3457,6 @@
       "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
       "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw=="
     },
-    "node_modules/hpkp": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/hpkp/-/hpkp-2.0.0.tgz",
-      "integrity": "sha1-EOFCJk52IVpdMMROxD3mTe5tFnI="
-    },
-    "node_modules/hsts": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/hsts/-/hsts-2.2.0.tgz",
-      "integrity": "sha512-ToaTnQ2TbJkochoVcdXYm4HOCliNozlviNsg+X2XQLQvZNI/kCHR9rZxVYpJB3UPcHz80PgxRyWQ7PdU1r+VBQ==",
-      "dependencies": {
-        "depd": "2.0.0"
-      },
-      "engines": {
-        "node": ">=4.0.0"
-      }
-    },
-    "node_modules/hsts/node_modules/depd": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
-      "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
-      "engines": {
-        "node": ">= 0.8"
-      }
-    },
     "node_modules/html-encoding-sniffer": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz",
@@ -3439,6 +3528,26 @@
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
       "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
     },
+    "node_modules/httpntlm": {
+      "version": "1.7.6",
+      "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.7.6.tgz",
+      "integrity": "sha1-aZHoNSg2AH1nEBuD247Q+RX5BtA=",
+      "dependencies": {
+        "httpreq": ">=0.4.22",
+        "underscore": "~1.7.0"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/httpreq": {
+      "version": "0.4.24",
+      "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-0.4.24.tgz",
+      "integrity": "sha1-QzX/2CzZaWaKOUZckprGHWOTYn8=",
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
     "node_modules/https-proxy-agent": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
@@ -3480,22 +3589,6 @@
         "node": ">=8.12.0"
       }
     },
-    "node_modules/i18n": {
-      "version": "0.8.6",
-      "resolved": "https://registry.npmjs.org/i18n/-/i18n-0.8.6.tgz",
-      "integrity": "sha512-aMsJq8i1XXrb+BBsgmJBwak9mr69zPEIAUPb6c5yw2G/O4k1Q52lBxL+agZdQDN/RGf1ylQzrCswsOOgIiC1FA==",
-      "dependencies": {
-        "debug": "*",
-        "make-plural": "^6.0.1",
-        "math-interval-parser": "^2.0.1",
-        "messageformat": "^2.3.0",
-        "mustache": "*",
-        "sprintf-js": "^1.1.2"
-      },
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
     "node_modules/iconv-lite": {
       "version": "0.4.24",
       "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -4792,10 +4885,11 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/make-plural": {
-      "version": "6.2.2",
-      "resolved": "https://registry.npmjs.org/make-plural/-/make-plural-6.2.2.tgz",
-      "integrity": "sha512-8iTuFioatnTTmb/YJjywkVIHLjcwkFD9Ms0JpxjEm9Mo8eQYkh1z+55dwv4yc1jQ8ftVBxWQbihvZL1DfzGGWA=="
+    "node_modules/make-error": {
+      "version": "1.3.6",
+      "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+      "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+      "devOptional": true
     },
     "node_modules/makeerror": {
       "version": "1.0.11",
@@ -4824,14 +4918,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/math-interval-parser": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/math-interval-parser/-/math-interval-parser-2.0.1.tgz",
-      "integrity": "sha512-VmlAmb0UJwlvMyx8iPhXUDnVW1F9IrGEd9CIOmv+XL8AErCUUuozoDMrgImvnYt2A+53qVX/tPW6YJurMKYsvA==",
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
     "node_modules/media-typer": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@@ -4850,38 +4936,6 @@
       "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
       "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="
     },
-    "node_modules/messageformat": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/messageformat/-/messageformat-2.3.0.tgz",
-      "integrity": "sha512-uTzvsv0lTeQxYI2y1NPa1lItL5VRI8Gb93Y2K2ue5gBPyrbJxfDi/EYWxh2PKv5yO42AJeeqblS9MJSh/IEk4w==",
-      "deprecated": "Package renamed as '@messageformat/core', see messageformat.github.io for more details. 'messageformat' will eventually provide a polyfill for Intl.MessageFormat, once it's been defined by Unicode & ECMA.",
-      "dependencies": {
-        "make-plural": "^4.3.0",
-        "messageformat-formatters": "^2.0.1",
-        "messageformat-parser": "^4.1.2"
-      }
-    },
-    "node_modules/messageformat-formatters": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/messageformat-formatters/-/messageformat-formatters-2.0.1.tgz",
-      "integrity": "sha512-E/lQRXhtHwGuiQjI7qxkLp8AHbMD5r2217XNe/SREbBlSawe0lOqsFb7rflZJmlQFSULNLIqlcjjsCPlB3m3Mg=="
-    },
-    "node_modules/messageformat-parser": {
-      "version": "4.1.3",
-      "resolved": "https://registry.npmjs.org/messageformat-parser/-/messageformat-parser-4.1.3.tgz",
-      "integrity": "sha512-2fU3XDCanRqeOCkn7R5zW5VQHWf+T3hH65SzuqRvjatBK7r4uyFa5mEX+k6F9Bd04LVM5G4/BHBTUJsOdW7uyg=="
-    },
-    "node_modules/messageformat/node_modules/make-plural": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/make-plural/-/make-plural-4.3.0.tgz",
-      "integrity": "sha512-xTYd4JVHpSCW+aqDof6w/MebaMVNTVYBZhbB/vi513xXdiPT92JMVCo0Jq8W2UZnzYRFeVbQiQ+I25l13JuKvA==",
-      "bin": {
-        "make-plural": "bin/make-plural"
-      },
-      "optionalDependencies": {
-        "minimist": "^1.2.0"
-      }
-    },
     "node_modules/method-override": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/method-override/-/method-override-3.0.0.tgz",
@@ -4936,19 +4990,19 @@
       }
     },
     "node_modules/mime-db": {
-      "version": "1.47.0",
-      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz",
-      "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==",
+      "version": "1.48.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz",
+      "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==",
       "engines": {
         "node": ">= 0.6"
       }
     },
     "node_modules/mime-types": {
-      "version": "2.1.30",
-      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz",
-      "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==",
+      "version": "2.1.31",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz",
+      "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==",
       "dependencies": {
-        "mime-db": "1.47.0"
+        "mime-db": "1.48.0"
       },
       "engines": {
         "node": ">= 0.6"
@@ -5018,7 +5072,7 @@
       "dependencies": {
         "browser-stdout": "1.3.0",
         "commander": "2.9.0",
-        "debug": "2.6.8",
+        "debug": "2.6.9",
         "diff": "3.5.0",
         "escape-string-regexp": "1.0.5",
         "glob": "7.1.1",
@@ -5038,14 +5092,6 @@
         "npm": ">= 1.4.x"
       }
     },
-    "node_modules/mocha/node_modules/debug": {
-      "version": "2.6.8",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
-      "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
-      "dependencies": {
-        "ms": "2.0.0"
-      }
-    },
     "node_modules/mocha/node_modules/glob": {
       "version": "7.1.1",
       "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz",
@@ -5109,28 +5155,6 @@
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
       "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
     },
-    "node_modules/mustache": {
-      "version": "4.2.0",
-      "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz",
-      "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==",
-      "bin": {
-        "mustache": "bin/mustache"
-      }
-    },
-    "node_modules/mysql": {
-      "version": "2.18.1",
-      "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz",
-      "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==",
-      "dependencies": {
-        "bignumber.js": "9.0.0",
-        "readable-stream": "2.3.7",
-        "safe-buffer": "5.1.2",
-        "sqlstring": "2.3.1"
-      },
-      "engines": {
-        "node": ">= 0.6"
-      }
-    },
     "node_modules/mysql2": {
       "version": "2.2.5",
       "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.2.5.tgz",
@@ -5232,14 +5256,6 @@
       "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
       "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
     },
-    "node_modules/nocache": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/nocache/-/nocache-2.1.0.tgz",
-      "integrity": "sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q==",
-      "engines": {
-        "node": ">=4.0.0"
-      }
-    },
     "node_modules/node-forge": {
       "version": "0.10.0",
       "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
@@ -5291,9 +5307,9 @@
       }
     },
     "node_modules/node-releases": {
-      "version": "1.1.72",
-      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.72.tgz",
-      "integrity": "sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw=="
+      "version": "1.1.73",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz",
+      "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg=="
     },
     "node_modules/nodemailer": {
       "version": "6.6.1",
@@ -5303,6 +5319,14 @@
         "node": ">=6.0.0"
       }
     },
+    "node_modules/nodemailer-ntlm-auth": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/nodemailer-ntlm-auth/-/nodemailer-ntlm-auth-1.0.1.tgz",
+      "integrity": "sha512-nQK3NHGpyVU0CcGfpq2rzM3Xg/ZLYOwBGfIAz+oxW3Jhaj3opPC6eLXuei0doK5++Hm0zjl/PH+y7ZCc8sDFtg==",
+      "dependencies": {
+        "httpntlm": "1.7.6"
+      }
+    },
     "node_modules/nodemon": {
       "version": "2.0.7",
       "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.7.tgz",
@@ -5889,11 +5913,6 @@
         "node": ">= 10"
       }
     },
-    "node_modules/process-nextick-args": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
-      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
-    },
     "node_modules/promise": {
       "version": "7.3.1",
       "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
@@ -5915,11 +5934,11 @@
       }
     },
     "node_modules/proxy-addr": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
-      "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
+      "version": "2.0.7",
+      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+      "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
       "dependencies": {
-        "forwarded": "~0.1.2",
+        "forwarded": "0.2.0",
         "ipaddr.js": "1.9.1"
       },
       "engines": {
@@ -6187,20 +6206,6 @@
         "node": ">=8"
       }
     },
-    "node_modules/readable-stream": {
-      "version": "2.3.7",
-      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
-      "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
-      "dependencies": {
-        "core-util-is": "~1.0.0",
-        "inherits": "~2.0.3",
-        "isarray": "~1.0.0",
-        "process-nextick-args": "~2.0.0",
-        "safe-buffer": "~5.1.1",
-        "string_decoder": "~1.1.1",
-        "util-deprecate": "~1.0.1"
-      }
-    },
     "node_modules/readdirp": {
       "version": "3.5.0",
       "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
@@ -6213,14 +6218,6 @@
         "node": ">=8.10.0"
       }
     },
-    "node_modules/referrer-policy": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/referrer-policy/-/referrer-policy-1.2.0.tgz",
-      "integrity": "sha512-LgQJIuS6nAy1Jd88DCQRemyE3mS+ispwlqMk3b0yjZ257fI1v9c+/p6SD5gP5FGyXUIgrNOAfmyioHwZtYv2VA==",
-      "engines": {
-        "node": ">=4.0.0"
-      }
-    },
     "node_modules/regex-not": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
@@ -7066,17 +7063,9 @@
       }
     },
     "node_modules/sprintf-js": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
-      "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug=="
-    },
-    "node_modules/sqlstring": {
-      "version": "2.3.1",
-      "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz",
-      "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A=",
-      "engines": {
-        "node": ">= 0.6"
-      }
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
     },
     "node_modules/stack-utils": {
       "version": "2.0.3",
@@ -7201,14 +7190,6 @@
         "node": ">=0.8.0"
       }
     },
-    "node_modules/string_decoder": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
-      "dependencies": {
-        "safe-buffer": "~5.1.0"
-      }
-    },
     "node_modules/string-length": {
       "version": "4.0.2",
       "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
@@ -7469,6 +7450,41 @@
         "node": ">=8"
       }
     },
+    "node_modules/ts-node": {
+      "version": "9.1.1",
+      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz",
+      "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==",
+      "devOptional": true,
+      "dependencies": {
+        "arg": "^4.1.0",
+        "create-require": "^1.1.0",
+        "diff": "^4.0.1",
+        "make-error": "^1.1.1",
+        "source-map-support": "^0.5.17",
+        "yn": "3.1.1"
+      },
+      "bin": {
+        "ts-node": "dist/bin.js",
+        "ts-node-script": "dist/bin-script.js",
+        "ts-node-transpile-only": "dist/bin-transpile.js",
+        "ts-script": "dist/bin-script-deprecated.js"
+      },
+      "engines": {
+        "node": ">=10.0.0"
+      },
+      "peerDependencies": {
+        "typescript": ">=2.7"
+      }
+    },
+    "node_modules/ts-node/node_modules/diff": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+      "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+      "devOptional": true,
+      "engines": {
+        "node": ">=0.3.1"
+      }
+    },
     "node_modules/type-check": {
       "version": "0.3.2",
       "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
@@ -7519,6 +7535,19 @@
         "is-typedarray": "^1.0.0"
       }
     },
+    "node_modules/typescript": {
+      "version": "4.3.2",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz",
+      "integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==",
+      "devOptional": true,
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=4.2.0"
+      }
+    },
     "node_modules/uid-safe": {
       "version": "2.1.5",
       "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
@@ -7539,6 +7568,11 @@
         "debug": "^2.2.0"
       }
     },
+    "node_modules/underscore": {
+      "version": "1.13.1",
+      "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz",
+      "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk="
+    },
     "node_modules/union-value": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
@@ -7699,11 +7733,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/util-deprecate": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
-      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
-    },
     "node_modules/utils-merge": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
@@ -7930,14 +7959,6 @@
         }
       }
     },
-    "node_modules/x-xss-protection": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/x-xss-protection/-/x-xss-protection-1.3.0.tgz",
-      "integrity": "sha512-kpyBI9TlVipZO4diReZMAHWtS0MMa/7Kgx8hwG/EuZLiA6sg4Ah/4TRdASHhRRN3boobzcYgFRUFSgHRge6Qhg==",
-      "engines": {
-        "node": ">=4.0.0"
-      }
-    },
     "node_modules/xdg-basedir": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz",
@@ -8085,6 +8106,15 @@
       "engines": {
         "node": ">=6"
       }
+    },
+    "node_modules/yn": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+      "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+      "devOptional": true,
+      "engines": {
+        "node": ">=6"
+      }
     }
   },
   "dependencies": {
@@ -8097,9 +8127,9 @@
       }
     },
     "@babel/compat-data": {
-      "version": "7.14.0",
-      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.0.tgz",
-      "integrity": "sha512-vu9V3uMM/1o5Hl5OekMUowo3FqXLJSw+s+66nt0fSWVWTtmosdzn45JHOB3cPtZoe6CTBDzvSw0RdOY85Q37+Q=="
+      "version": "7.14.4",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.4.tgz",
+      "integrity": "sha512-i2wXrWQNkH6JplJQGn3Rd2I4Pij8GdHkXwHMxm+zV5YG/Jci+bCNrWZEWC4o+umiDkRrRs4dVzH3X4GP7vyjQQ=="
     },
     "@babel/core": {
       "version": "7.14.3",
@@ -8161,13 +8191,13 @@
       }
     },
     "@babel/helper-compilation-targets": {
-      "version": "7.13.16",
-      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.16.tgz",
-      "integrity": "sha512-3gmkYIrpqsLlieFwjkGgLaSHmhnvlAYzZLlYVjlW+QwI+1zE17kGxuJGmIqDQdYp56XdmGeD+Bswx0UTyG18xA==",
+      "version": "7.14.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.14.4.tgz",
+      "integrity": "sha512-JgdzOYZ/qGaKTVkn5qEDV/SXAh8KcyUVkCoSWGN8T3bwrgd6m+/dJa2kVGi6RJYJgEYPBdZ84BZp9dUjNWkBaA==",
       "requires": {
-        "@babel/compat-data": "^7.13.15",
+        "@babel/compat-data": "^7.14.4",
         "@babel/helper-validator-option": "^7.12.17",
-        "browserslist": "^4.14.5",
+        "browserslist": "^4.16.6",
         "semver": "^6.3.0"
       }
     },
@@ -8234,14 +8264,14 @@
       "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ=="
     },
     "@babel/helper-replace-supers": {
-      "version": "7.14.3",
-      "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.14.3.tgz",
-      "integrity": "sha512-Rlh8qEWZSTfdz+tgNV/N4gz1a0TMNwCUcENhMjHTHKp3LseYH5Jha0NSlyTQWMnjbYcwFt+bqAMqSLHVXkQ6UA==",
+      "version": "7.14.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.14.4.tgz",
+      "integrity": "sha512-zZ7uHCWlxfEAAOVDYQpEf/uyi1dmeC7fX4nCf2iz9drnCwi1zvwXL3HwWWNXUQEJ1k23yVn3VbddiI9iJEXaTQ==",
       "requires": {
         "@babel/helper-member-expression-to-functions": "^7.13.12",
         "@babel/helper-optimise-call-expression": "^7.12.13",
         "@babel/traverse": "^7.14.2",
-        "@babel/types": "^7.14.2"
+        "@babel/types": "^7.14.4"
       }
     },
     "@babel/helper-simple-access": {
@@ -8337,9 +8367,9 @@
       }
     },
     "@babel/parser": {
-      "version": "7.14.3",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.3.tgz",
-      "integrity": "sha512-7MpZDIfI7sUC5zWo2+foJ50CSI5lcqDehZ0lVgIhSi4bFEk94fLAKlF3Q0nzSQQ+ca0lm+O6G9ztKVBeu8PMRQ=="
+      "version": "7.14.4",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.4.tgz",
+      "integrity": "sha512-ArliyUsWDUqEGfWcmzpGUzNfLxTdTp6WU4IuP6QFSp9gGfWS6boxFCkJSJ/L4+RG8z/FnIU3WxCk6hPL9SSWeA=="
     },
     "@babel/plugin-syntax-async-generators": {
       "version": "7.8.4",
@@ -8478,9 +8508,9 @@
       }
     },
     "@babel/types": {
-      "version": "7.14.2",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.2.tgz",
-      "integrity": "sha512-SdjAG/3DikRHpUOjxZgnkbR11xUlyDMUFJdvnIgZEE16mqmY0BINMmc4//JMJglEmn6i7sq6p+mGrFWyZ98EEw==",
+      "version": "7.14.4",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.4.tgz",
+      "integrity": "sha512-lCj4aIs0xUefJFQnwwQv2Bxg7Omd6bgquZ6LGC+gGMh6/s5qDVfjuCMlDmYQ15SLsWHd9n+X3E75lKIhl5Lkiw==",
       "requires": {
         "@babel/helper-validator-identifier": "^7.14.0",
         "to-fast-properties": "^2.0.0"
@@ -8741,6 +8771,12 @@
       "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
       "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw=="
     },
+    "@types/async": {
+      "version": "3.2.6",
+      "resolved": "https://registry.npmjs.org/@types/async/-/async-3.2.6.tgz",
+      "integrity": "sha512-ZkrXnZLC1mc4b9QLKaSrsxV4oxTRs10OI2kgSApT8G0v1jrmqppSHUVQ15kLorzsFBTjvf7OKF4kAibuuNQ+xA==",
+      "dev": true
+    },
     "@types/babel__core": {
       "version": "7.1.14",
       "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.14.tgz",
@@ -8778,6 +8814,100 @@
         "@babel/types": "^7.3.0"
       }
     },
+    "@types/bcryptjs": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.2.tgz",
+      "integrity": "sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==",
+      "dev": true
+    },
+    "@types/body-parser": {
+      "version": "1.19.0",
+      "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz",
+      "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==",
+      "dev": true,
+      "requires": {
+        "@types/connect": "*",
+        "@types/node": "*"
+      }
+    },
+    "@types/compression": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.0.tgz",
+      "integrity": "sha512-3LzWUM+3k3XdWOUk/RO+uSjv7YWOatYq2QADJntK1pjkk4DfVP0KrIEPDnXRJxAAGKe0VpIPRmlINLDuCedZWw==",
+      "dev": true,
+      "requires": {
+        "@types/express": "*"
+      }
+    },
+    "@types/connect": {
+      "version": "3.4.34",
+      "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz",
+      "integrity": "sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==",
+      "dev": true,
+      "requires": {
+        "@types/node": "*"
+      }
+    },
+    "@types/cookie-parser": {
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.2.tgz",
+      "integrity": "sha512-uwcY8m6SDQqciHsqcKDGbo10GdasYsPCYkH3hVegj9qAah6pX5HivOnOuI3WYmyQMnOATV39zv/Ybs0bC/6iVg==",
+      "dev": true,
+      "requires": {
+        "@types/express": "*"
+      }
+    },
+    "@types/express": {
+      "version": "4.17.12",
+      "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.12.tgz",
+      "integrity": "sha512-pTYas6FrP15B1Oa0bkN5tQMNqOcVXa9j4FTFtO8DWI9kppKib+6NJtfTOOLcwxuuYvcX2+dVG6et1SxW/Kc17Q==",
+      "dev": true,
+      "requires": {
+        "@types/body-parser": "*",
+        "@types/express-serve-static-core": "^4.17.18",
+        "@types/qs": "*",
+        "@types/serve-static": "*"
+      }
+    },
+    "@types/express-fileupload": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/@types/express-fileupload/-/express-fileupload-1.1.6.tgz",
+      "integrity": "sha512-8z92PCVgvWvG1TpxucRU9oRz3hZc5cUz+CkeDe4XwVmg2DJDdd/7QASMsJzIo+9Pbfp7LfTEWSeEFUJZBohv9g==",
+      "dev": true,
+      "requires": {
+        "@types/express": "*"
+      }
+    },
+    "@types/express-flash-2": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/@types/express-flash-2/-/express-flash-2-1.0.6.tgz",
+      "integrity": "sha512-8YE6SDUxIIrsAKJL65nfUYtgO356QcT889GaXrwS0em7VYgbz6ShPdLUBOMDu8ihZrqidp5Qz2bNnWCCP4rZMw==",
+      "dev": true,
+      "requires": {
+        "@types/express": "*"
+      }
+    },
+    "@types/express-serve-static-core": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.21.tgz",
+      "integrity": "sha512-gwCiEZqW6f7EoR8TTEfalyEhb1zA5jQJnRngr97+3pzMaO1RKoI1w2bw07TK72renMUVWcWS5mLI6rk1NqN0nA==",
+      "dev": true,
+      "requires": {
+        "@types/node": "*",
+        "@types/qs": "*",
+        "@types/range-parser": "*"
+      }
+    },
+    "@types/express-session": {
+      "version": "1.17.0",
+      "resolved": "https://registry.npmjs.org/@types/express-session/-/express-session-1.17.0.tgz",
+      "integrity": "sha512-OQEHeBFE1UhChVIBhRh9qElHUvTp4BzKKHxMDkGHT7WuYk5eL93hPG7D8YAIkoBSbhNEY0RjreF15zn+U0eLjA==",
+      "dev": true,
+      "requires": {
+        "@types/express": "*",
+        "@types/node": "*"
+      }
+    },
     "@types/graceful-fs": {
       "version": "4.1.5",
       "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz",
@@ -8800,33 +8930,135 @@
       }
     },
     "@types/istanbul-reports": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
-      "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz",
+      "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==",
       "requires": {
         "@types/istanbul-lib-report": "*"
       }
     },
+    "@types/jest": {
+      "version": "26.0.23",
+      "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.23.tgz",
+      "integrity": "sha512-ZHLmWMJ9jJ9PTiT58juykZpL7KjwJywFN3Rr2pTSkyQfydf/rk22yS7W8p5DaVUMQ2BQC7oYiU3FjbTM/mYrOA==",
+      "dev": true,
+      "requires": {
+        "jest-diff": "^26.0.0",
+        "pretty-format": "^26.0.0"
+      }
+    },
+    "@types/method-override": {
+      "version": "0.0.31",
+      "resolved": "https://registry.npmjs.org/@types/method-override/-/method-override-0.0.31.tgz",
+      "integrity": "sha512-aLA4MGzjYjBHGpr5TgAdPRyX97Jd+xlWN2wa6PbsjKYeoUKPsxVDFRSTjI3YG4MvGg3ZJkdMxjAXZfujU9qEPw==",
+      "dev": true,
+      "requires": {
+        "@types/express": "*"
+      }
+    },
+    "@types/mime": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
+      "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==",
+      "dev": true
+    },
+    "@types/morgan": {
+      "version": "1.9.2",
+      "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.2.tgz",
+      "integrity": "sha512-edtGMEdit146JwwIeyQeHHg9yID4WSolQPxpEorHmN3KuytuCHyn2ELNr5Uxy8SerniFbbkmgKMrGM933am5BQ==",
+      "dev": true,
+      "requires": {
+        "@types/node": "*"
+      }
+    },
+    "@types/mysql": {
+      "version": "2.15.18",
+      "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.18.tgz",
+      "integrity": "sha512-JW74Nh3P/RDAnaP8uXe1qmRpoFBO84SiWvWoSju/F5+2S1kVBi1FbbDoqK/sTZrCCxySaOJnRATvWD+bLcJjAg==",
+      "dev": true,
+      "requires": {
+        "@types/node": "*"
+      }
+    },
     "@types/node": {
-      "version": "15.6.1",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-15.6.1.tgz",
-      "integrity": "sha512-7EIraBEyRHEe7CH+Fm1XvgqU6uwZN8Q7jppJGcqjROMT29qhAuuOxYB1uEY5UMYQKEmA5D+5tBnhdaPXSsLONA=="
+      "version": "15.12.2",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz",
+      "integrity": "sha512-zjQ69G564OCIWIOHSXyQEEDpdpGl+G348RAKY0XXy9Z5kU9Vzv1GMNnkar/ZJ8dzXB3COzD9Mo9NtRZ4xfgUww=="
+    },
+    "@types/nodemailer": {
+      "version": "6.4.2",
+      "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.2.tgz",
+      "integrity": "sha512-yhsqg5Xbr8aWdwjFS3QjkniW5/tLpWXtOYQcJdo9qE3DolBxsKzgRCQrteaMY0hos8MklJNSEsMqDpZynGzMNg==",
+      "dev": true,
+      "requires": {
+        "@types/node": "*"
+      }
     },
     "@types/normalize-package-data": {
       "version": "2.4.0",
       "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
       "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA=="
     },
+    "@types/passport": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.6.tgz",
+      "integrity": "sha512-9oKfrJXuAxvyxdrtMCxKkHgmd6DMO8NDOLvMJ1LvIWd6/xP+i81PAkpTaEca7VhJX9S009RciwZL/j6dsLsHrA==",
+      "dev": true,
+      "requires": {
+        "@types/express": "*"
+      }
+    },
+    "@types/passport-strategy": {
+      "version": "0.2.35",
+      "resolved": "https://registry.npmjs.org/@types/passport-strategy/-/passport-strategy-0.2.35.tgz",
+      "integrity": "sha512-o5D19Jy2XPFoX2rKApykY15et3Apgax00RRLf0RUotPDUsYrQa7x4howLYr9El2mlUApHmCMv5CZ1IXqKFQ2+g==",
+      "dev": true,
+      "requires": {
+        "@types/express": "*",
+        "@types/passport": "*"
+      }
+    },
     "@types/prettier": {
       "version": "2.2.3",
       "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.3.tgz",
       "integrity": "sha512-PijRCG/K3s3w1We6ynUKdxEc5AcuuH3NBmMDP8uvKVp6X43UY7NQlTzczakXP3DJR0F4dfNQIGjU2cUeRYs2AA=="
     },
+    "@types/qs": {
+      "version": "6.9.6",
+      "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.6.tgz",
+      "integrity": "sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA==",
+      "dev": true
+    },
+    "@types/range-parser": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz",
+      "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==",
+      "dev": true
+    },
+    "@types/serve-static": {
+      "version": "1.13.9",
+      "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.9.tgz",
+      "integrity": "sha512-ZFqF6qa48XsPdjXV5Gsz0Zqmux2PerNd3a/ktL45mHpa19cuMi/cL8tcxdAx497yRh+QtYPuofjT9oWw9P7nkA==",
+      "dev": true,
+      "requires": {
+        "@types/mime": "^1",
+        "@types/node": "*"
+      }
+    },
     "@types/stack-utils": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz",
       "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw=="
     },
+    "@types/xml2js": {
+      "version": "0.4.8",
+      "resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.8.tgz",
+      "integrity": "sha512-EyvT83ezOdec7BhDaEcsklWy7RSIdi6CNe95tmOAK0yx/Lm30C9K75snT3fYayK59ApC2oyW+rcHErdG05FHJA==",
+      "dev": true,
+      "requires": {
+        "@types/node": "*"
+      }
+    },
     "@types/yargs": {
       "version": "15.0.13",
       "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz",
@@ -8861,9 +9093,9 @@
       }
     },
     "acorn": {
-      "version": "8.2.4",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.2.4.tgz",
-      "integrity": "sha512-Ibt84YwBDDA890eDiDCEqcbwvHlBvzzDkU2cGBBDDI1QWT12jTiXIOn2CIw5KK4i6N5Z2HUxwYjzriDyqaqqZg=="
+      "version": "8.3.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.3.0.tgz",
+      "integrity": "sha512-tqPKHZ5CaBJw0Xmy0ZZvLs1qTV+BNFSyvn77ASXkpBNfIRk8ev26fKrD9iLGwGA9zedPao52GSHzq8lyZG0NUw=="
     },
     "acorn-globals": {
       "version": "6.0.0",
@@ -8988,19 +9220,18 @@
         "picomatch": "^2.0.4"
       }
     },
+    "arg": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+      "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+      "devOptional": true
+    },
     "argparse": {
       "version": "1.0.10",
       "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
       "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
       "requires": {
         "sprintf-js": "~1.0.2"
-      },
-      "dependencies": {
-        "sprintf-js": {
-          "version": "1.0.3",
-          "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
-          "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
-        }
       }
     },
     "arr-diff": {
@@ -9187,11 +9418,6 @@
       "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
       "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms="
     },
-    "bignumber.js": {
-      "version": "9.0.0",
-      "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz",
-      "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A=="
-    },
     "binary-extensions": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
@@ -9215,11 +9441,6 @@
         "type-is": "~1.6.17"
       }
     },
-    "bowser": {
-      "version": "2.9.0",
-      "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.9.0.tgz",
-      "integrity": "sha512-2ld76tuLBNFekRgmJfT2+3j5MIrP6bFict8WAIT3beq+srz1gcKNAdNKMqHqauQt63NmAa88HfP1/Ypa9Er3HA=="
-    },
     "boxen": {
       "version": "4.2.0",
       "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz",
@@ -9377,15 +9598,10 @@
       "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
       "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
     },
-    "camelize": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz",
-      "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs="
-    },
     "caniuse-lite": {
-      "version": "1.0.30001230",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001230.tgz",
-      "integrity": "sha512-5yBd5nWCBS+jWKTcHOzXwo5xzcj4ePE/yjtkZyUV1BTUmrBaA9MRGC+e7mxnqXSA90CmCA8L3eKLaSUkt099IQ=="
+      "version": "1.0.30001235",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001235.tgz",
+      "integrity": "sha512-zWEwIVqnzPkSAXOUlQnPW2oKoYb2aLQ4Q5ejdjBcnH63rfypaW34CxaeBn1VMya2XaEU3P/R2qHpWyj+l0BT1A=="
     },
     "capture-exit": {
       "version": "2.0.0",
@@ -9673,11 +9889,6 @@
         "safe-buffer": "5.1.2"
       }
     },
-    "content-security-policy-builder": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/content-security-policy-builder/-/content-security-policy-builder-2.1.0.tgz",
-      "integrity": "sha512-/MtLWhJVvJNkA9dVLAp6fg9LxD2gfI6R2Fi1hPmfjYXSahJJzcfvoeDOxSyp4NvxMuwWv3WMssE9o31DoULHrQ=="
-    },
     "content-type": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
@@ -9715,10 +9926,11 @@
       "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
       "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40="
     },
-    "core-util-is": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
-      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+    "create-require": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+      "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
+      "devOptional": true
     },
     "cross-spawn": {
       "version": "7.0.3",
@@ -9730,11 +9942,6 @@
         "which": "^2.0.1"
       }
     },
-    "crypto": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz",
-      "integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig=="
-    },
     "crypto-random-string": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
@@ -9761,11 +9968,6 @@
         }
       }
     },
-    "dasherize": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/dasherize/-/dasherize-2.0.0.tgz",
-      "integrity": "sha1-bYCcnNDPe7iVLYD8hPoT1H3bEwg="
-    },
     "data-urls": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz",
@@ -9917,11 +10119,6 @@
         }
       }
     },
-    "dont-sniff-mimetype": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/dont-sniff-mimetype/-/dont-sniff-mimetype-1.1.0.tgz",
-      "integrity": "sha512-ZjI4zqTaxveH2/tTlzS1wFp+7ncxNZaIEWYg3lzZRHkKf5zPT/MnEG6WL0BhHMJUabkh8GeU5NL5j+rEUCb7Ug=="
-    },
     "dot-prop": {
       "version": "5.3.0",
       "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
@@ -9931,6 +10128,11 @@
         "is-obj": "^2.0.0"
       }
     },
+    "dotenv": {
+      "version": "9.0.2",
+      "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-9.0.2.tgz",
+      "integrity": "sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg=="
+    },
     "duplexer3": {
       "version": "0.1.4",
       "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
@@ -9943,9 +10145,9 @@
       "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
     },
     "electron-to-chromium": {
-      "version": "1.3.741",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.741.tgz",
-      "integrity": "sha512-4i3T0cwnHo1O4Mnp9JniEco8bZiXoqbm3PhW5hv7uu8YLg35iajYrRnNyKFaN8/8SSTskU2hYqVTeYVPceSpUA=="
+      "version": "1.3.749",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.749.tgz",
+      "integrity": "sha512-F+v2zxZgw/fMwPz/VUGIggG4ZndDsYy0vlpthi3tjmDZlcfbhN5mYW0evXUsBr2sUtuDANFtle410A9u/sd/4A=="
     },
     "emittery": {
       "version": "0.7.2",
@@ -9978,15 +10180,6 @@
         "is-arrayish": "^0.2.1"
       }
     },
-    "errorhandler": {
-      "version": "1.4.3",
-      "resolved": "https://registry.npmjs.org/errorhandler/-/errorhandler-1.4.3.tgz",
-      "integrity": "sha1-t7cO2PNZ6duICS8tIMD4MUIK2D8=",
-      "requires": {
-        "accepts": "~1.3.0",
-        "escape-html": "~1.0.3"
-      }
-    },
     "escalade": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
@@ -10325,11 +10518,6 @@
         "bser": "2.1.1"
       }
     },
-    "feature-policy": {
-      "version": "0.3.0",
-      "resolved": "https://registry.npmjs.org/feature-policy/-/feature-policy-0.3.0.tgz",
-      "integrity": "sha512-ZtijOTFN7TzCujt1fnNhfWPFPSHeZkesff9AXZj+UEjYBynWNUIYpC87Ve4wHzyexQsImicLu7WsC2LHq7/xrQ=="
-    },
     "fill-range": {
       "version": "7.0.1",
       "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@@ -10382,9 +10570,9 @@
       }
     },
     "forwarded": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
-      "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+      "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
     },
     "fragment-cache": {
       "version": "0.2.1",
@@ -10630,76 +10818,15 @@
       "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0="
     },
     "helmet": {
-      "version": "3.23.3",
-      "resolved": "https://registry.npmjs.org/helmet/-/helmet-3.23.3.tgz",
-      "integrity": "sha512-U3MeYdzPJQhtvqAVBPntVgAvNSOJyagwZwyKsFdyRa8TV3pOKVFljalPOCxbw5Wwf2kncGhmP0qHjyazIdNdSA==",
-      "requires": {
-        "depd": "2.0.0",
-        "dont-sniff-mimetype": "1.1.0",
-        "feature-policy": "0.3.0",
-        "helmet-crossdomain": "0.4.0",
-        "helmet-csp": "2.10.0",
-        "hide-powered-by": "1.1.0",
-        "hpkp": "2.0.0",
-        "hsts": "2.2.0",
-        "nocache": "2.1.0",
-        "referrer-policy": "1.2.0",
-        "x-xss-protection": "1.3.0"
-      },
-      "dependencies": {
-        "depd": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
-          "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
-        }
-      }
-    },
-    "helmet-crossdomain": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/helmet-crossdomain/-/helmet-crossdomain-0.4.0.tgz",
-      "integrity": "sha512-AB4DTykRw3HCOxovD1nPR16hllrVImeFp5VBV9/twj66lJ2nU75DP8FPL0/Jp4jj79JhTfG+pFI2MD02kWJ+fA=="
-    },
-    "helmet-csp": {
-      "version": "2.10.0",
-      "resolved": "https://registry.npmjs.org/helmet-csp/-/helmet-csp-2.10.0.tgz",
-      "integrity": "sha512-Rz953ZNEFk8sT2XvewXkYN0Ho4GEZdjAZy4stjiEQV3eN7GDxg1QKmYggH7otDyIA7uGA6XnUMVSgeJwbR5X+w==",
-      "requires": {
-        "bowser": "2.9.0",
-        "camelize": "1.0.0",
-        "content-security-policy-builder": "2.1.0",
-        "dasherize": "2.0.0"
-      }
-    },
-    "hide-powered-by": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/hide-powered-by/-/hide-powered-by-1.1.0.tgz",
-      "integrity": "sha512-Io1zA2yOA1YJslkr+AJlWSf2yWFkKjvkcL9Ni1XSUqnGLr/qRQe2UI3Cn/J9MsJht7yEVCe0SscY1HgVMujbgg=="
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/helmet/-/helmet-4.6.0.tgz",
+      "integrity": "sha512-HVqALKZlR95ROkrnesdhbbZJFi/rIVSoNq6f3jA/9u6MIbTsPh3xZwihjeI5+DO/2sOV6HMHooXcEOuwskHpTg=="
     },
     "hosted-git-info": {
       "version": "2.8.9",
       "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
       "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw=="
     },
-    "hpkp": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/hpkp/-/hpkp-2.0.0.tgz",
-      "integrity": "sha1-EOFCJk52IVpdMMROxD3mTe5tFnI="
-    },
-    "hsts": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/hsts/-/hsts-2.2.0.tgz",
-      "integrity": "sha512-ToaTnQ2TbJkochoVcdXYm4HOCliNozlviNsg+X2XQLQvZNI/kCHR9rZxVYpJB3UPcHz80PgxRyWQ7PdU1r+VBQ==",
-      "requires": {
-        "depd": "2.0.0"
-      },
-      "dependencies": {
-        "depd": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
-          "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
-        }
-      }
-    },
     "html-encoding-sniffer": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz",
@@ -10756,6 +10883,20 @@
         }
       }
     },
+    "httpntlm": {
+      "version": "1.7.6",
+      "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.7.6.tgz",
+      "integrity": "sha1-aZHoNSg2AH1nEBuD247Q+RX5BtA=",
+      "requires": {
+        "httpreq": ">=0.4.22",
+        "underscore": "~1.7.0"
+      }
+    },
+    "httpreq": {
+      "version": "0.4.24",
+      "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-0.4.24.tgz",
+      "integrity": "sha1-QzX/2CzZaWaKOUZckprGHWOTYn8="
+    },
     "https-proxy-agent": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
@@ -10785,19 +10926,6 @@
       "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz",
       "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw=="
     },
-    "i18n": {
-      "version": "0.8.6",
-      "resolved": "https://registry.npmjs.org/i18n/-/i18n-0.8.6.tgz",
-      "integrity": "sha512-aMsJq8i1XXrb+BBsgmJBwak9mr69zPEIAUPb6c5yw2G/O4k1Q52lBxL+agZdQDN/RGf1ylQzrCswsOOgIiC1FA==",
-      "requires": {
-        "debug": "*",
-        "make-plural": "^6.0.1",
-        "math-interval-parser": "^2.0.1",
-        "messageformat": "^2.3.0",
-        "mustache": "*",
-        "sprintf-js": "^1.1.2"
-      }
-    },
     "iconv-lite": {
       "version": "0.4.24",
       "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -11795,10 +11923,11 @@
         "semver": "^6.0.0"
       }
     },
-    "make-plural": {
-      "version": "6.2.2",
-      "resolved": "https://registry.npmjs.org/make-plural/-/make-plural-6.2.2.tgz",
-      "integrity": "sha512-8iTuFioatnTTmb/YJjywkVIHLjcwkFD9Ms0JpxjEm9Mo8eQYkh1z+55dwv4yc1jQ8ftVBxWQbihvZL1DfzGGWA=="
+    "make-error": {
+      "version": "1.3.6",
+      "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+      "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+      "devOptional": true
     },
     "makeerror": {
       "version": "1.0.11",
@@ -11821,11 +11950,6 @@
         "object-visit": "^1.0.0"
       }
     },
-    "math-interval-parser": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/math-interval-parser/-/math-interval-parser-2.0.1.tgz",
-      "integrity": "sha512-VmlAmb0UJwlvMyx8iPhXUDnVW1F9IrGEd9CIOmv+XL8AErCUUuozoDMrgImvnYt2A+53qVX/tPW6YJurMKYsvA=="
-    },
     "media-typer": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@@ -11841,36 +11965,6 @@
       "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
       "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="
     },
-    "messageformat": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/messageformat/-/messageformat-2.3.0.tgz",
-      "integrity": "sha512-uTzvsv0lTeQxYI2y1NPa1lItL5VRI8Gb93Y2K2ue5gBPyrbJxfDi/EYWxh2PKv5yO42AJeeqblS9MJSh/IEk4w==",
-      "requires": {
-        "make-plural": "^4.3.0",
-        "messageformat-formatters": "^2.0.1",
-        "messageformat-parser": "^4.1.2"
-      },
-      "dependencies": {
-        "make-plural": {
-          "version": "4.3.0",
-          "resolved": "https://registry.npmjs.org/make-plural/-/make-plural-4.3.0.tgz",
-          "integrity": "sha512-xTYd4JVHpSCW+aqDof6w/MebaMVNTVYBZhbB/vi513xXdiPT92JMVCo0Jq8W2UZnzYRFeVbQiQ+I25l13JuKvA==",
-          "requires": {
-            "minimist": "^1.2.0"
-          }
-        }
-      }
-    },
-    "messageformat-formatters": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/messageformat-formatters/-/messageformat-formatters-2.0.1.tgz",
-      "integrity": "sha512-E/lQRXhtHwGuiQjI7qxkLp8AHbMD5r2217XNe/SREbBlSawe0lOqsFb7rflZJmlQFSULNLIqlcjjsCPlB3m3Mg=="
-    },
-    "messageformat-parser": {
-      "version": "4.1.3",
-      "resolved": "https://registry.npmjs.org/messageformat-parser/-/messageformat-parser-4.1.3.tgz",
-      "integrity": "sha512-2fU3XDCanRqeOCkn7R5zW5VQHWf+T3hH65SzuqRvjatBK7r4uyFa5mEX+k6F9Bd04LVM5G4/BHBTUJsOdW7uyg=="
-    },
     "method-override": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/method-override/-/method-override-3.0.0.tgz",
@@ -11912,16 +12006,16 @@
       "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
     },
     "mime-db": {
-      "version": "1.47.0",
-      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz",
-      "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw=="
+      "version": "1.48.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz",
+      "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ=="
     },
     "mime-types": {
-      "version": "2.1.30",
-      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz",
-      "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==",
+      "version": "2.1.31",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz",
+      "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==",
       "requires": {
-        "mime-db": "1.47.0"
+        "mime-db": "1.48.0"
       }
     },
     "mimic-fn": {
@@ -11972,7 +12066,7 @@
       "requires": {
         "browser-stdout": "1.3.0",
         "commander": "2.9.0",
-        "debug": "2.6.8",
+        "debug": "2.6.9",
         "diff": "3.5.0",
         "escape-string-regexp": "1.0.5",
         "glob": "7.1.1",
@@ -11984,14 +12078,6 @@
         "supports-color": "3.1.2"
       },
       "dependencies": {
-        "debug": {
-          "version": "2.6.8",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
-          "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
-          "requires": {
-            "ms": "2.0.0"
-          }
-        },
         "glob": {
           "version": "7.1.1",
           "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz",
@@ -12044,22 +12130,6 @@
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
       "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
     },
-    "mustache": {
-      "version": "4.2.0",
-      "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz",
-      "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ=="
-    },
-    "mysql": {
-      "version": "2.18.1",
-      "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz",
-      "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==",
-      "requires": {
-        "bignumber.js": "9.0.0",
-        "readable-stream": "2.3.7",
-        "safe-buffer": "5.1.2",
-        "sqlstring": "2.3.1"
-      }
-    },
     "mysql2": {
       "version": "2.2.5",
       "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.2.5.tgz",
@@ -12147,11 +12217,6 @@
       "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
       "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
     },
-    "nocache": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/nocache/-/nocache-2.1.0.tgz",
-      "integrity": "sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q=="
-    },
     "node-forge": {
       "version": "0.10.0",
       "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
@@ -12193,15 +12258,23 @@
       }
     },
     "node-releases": {
-      "version": "1.1.72",
-      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.72.tgz",
-      "integrity": "sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw=="
+      "version": "1.1.73",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz",
+      "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg=="
     },
     "nodemailer": {
       "version": "6.6.1",
       "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.6.1.tgz",
       "integrity": "sha512-1xzFN3gqv+/qJ6YRyxBxfTYstLNt0FCtZaFRvf4Sg9wxNGWbwFmGXVpfSi6ThGK6aRxAo+KjHtYSW8NvCsNSAg=="
     },
+    "nodemailer-ntlm-auth": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/nodemailer-ntlm-auth/-/nodemailer-ntlm-auth-1.0.1.tgz",
+      "integrity": "sha512-nQK3NHGpyVU0CcGfpq2rzM3Xg/ZLYOwBGfIAz+oxW3Jhaj3opPC6eLXuei0doK5++Hm0zjl/PH+y7ZCc8sDFtg==",
+      "requires": {
+        "httpntlm": "1.7.6"
+      }
+    },
     "nodemon": {
       "version": "2.0.7",
       "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.7.tgz",
@@ -12629,11 +12702,6 @@
         "react-is": "^17.0.1"
       }
     },
-    "process-nextick-args": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
-      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
-    },
     "promise": {
       "version": "7.3.1",
       "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
@@ -12652,11 +12720,11 @@
       }
     },
     "proxy-addr": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
-      "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
+      "version": "2.0.7",
+      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+      "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
       "requires": {
-        "forwarded": "~0.1.2",
+        "forwarded": "0.2.0",
         "ipaddr.js": "1.9.1"
       }
     },
@@ -12889,20 +12957,6 @@
         }
       }
     },
-    "readable-stream": {
-      "version": "2.3.7",
-      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
-      "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
-      "requires": {
-        "core-util-is": "~1.0.0",
-        "inherits": "~2.0.3",
-        "isarray": "~1.0.0",
-        "process-nextick-args": "~2.0.0",
-        "safe-buffer": "~5.1.1",
-        "string_decoder": "~1.1.1",
-        "util-deprecate": "~1.0.1"
-      }
-    },
     "readdirp": {
       "version": "3.5.0",
       "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
@@ -12912,11 +12966,6 @@
         "picomatch": "^2.2.1"
       }
     },
-    "referrer-policy": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/referrer-policy/-/referrer-policy-1.2.0.tgz",
-      "integrity": "sha512-LgQJIuS6nAy1Jd88DCQRemyE3mS+ispwlqMk3b0yjZ257fI1v9c+/p6SD5gP5FGyXUIgrNOAfmyioHwZtYv2VA=="
-    },
     "regex-not": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
@@ -13594,14 +13643,9 @@
       }
     },
     "sprintf-js": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
-      "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug=="
-    },
-    "sqlstring": {
-      "version": "2.3.1",
-      "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz",
-      "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A="
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
     },
     "stack-utils": {
       "version": "2.0.3",
@@ -13698,14 +13742,6 @@
       "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
       "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
     },
-    "string_decoder": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
-      "requires": {
-        "safe-buffer": "~5.1.0"
-      }
-    },
     "string-length": {
       "version": "4.0.2",
       "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
@@ -13896,6 +13932,28 @@
         "punycode": "^2.1.1"
       }
     },
+    "ts-node": {
+      "version": "9.1.1",
+      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz",
+      "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==",
+      "devOptional": true,
+      "requires": {
+        "arg": "^4.1.0",
+        "create-require": "^1.1.0",
+        "diff": "^4.0.1",
+        "make-error": "^1.1.1",
+        "source-map-support": "^0.5.17",
+        "yn": "3.1.1"
+      },
+      "dependencies": {
+        "diff": {
+          "version": "4.0.2",
+          "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+          "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+          "devOptional": true
+        }
+      }
+    },
     "type-check": {
       "version": "0.3.2",
       "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
@@ -13931,6 +13989,12 @@
         "is-typedarray": "^1.0.0"
       }
     },
+    "typescript": {
+      "version": "4.3.2",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz",
+      "integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==",
+      "devOptional": true
+    },
     "uid-safe": {
       "version": "2.1.5",
       "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
@@ -13948,6 +14012,10 @@
         "debug": "^2.2.0"
       }
     },
+    "underscore": {
+      "version": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz",
+      "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk="
+    },
     "union-value": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
@@ -14073,11 +14141,6 @@
       "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
       "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
     },
-    "util-deprecate": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
-      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
-    },
     "utils-merge": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
@@ -14247,11 +14310,6 @@
       "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==",
       "requires": {}
     },
-    "x-xss-protection": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/x-xss-protection/-/x-xss-protection-1.3.0.tgz",
-      "integrity": "sha512-kpyBI9TlVipZO4diReZMAHWtS0MMa/7Kgx8hwG/EuZLiA6sg4Ah/4TRdASHhRRN3boobzcYgFRUFSgHRge6Qhg=="
-    },
     "xdg-basedir": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz",
@@ -14369,6 +14427,12 @@
         "camelcase": "^5.0.0",
         "decamelize": "^1.2.0"
       }
+    },
+    "yn": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+      "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+      "devOptional": true
     }
   }
 }
diff --git a/package.json b/package.json
index 78d2bb4106093f642e5e0f22d0ce5d86178b5cdf..26db24d81b6feb495ccf58c03ea6fa5992b32707 100644
--- a/package.json
+++ b/package.json
@@ -39,7 +39,6 @@
     "jest": "^26.6.3",
     "method-override": "^3.0.0",
     "morgan": "^1.9.1",
-    "mysql": "^2.17.1",
     "mysql2": "^2.2.5",
     "nodemailer": "^6.3.1",
     "nodemailer-ntlm-auth": "^1.0.1",
diff --git a/routes/account.ts b/routes/account.ts
new file mode 100644
index 0000000000000000000000000000000000000000..68c3ca613a942c9b1d8f75e072b07d0f4377d7c8
--- /dev/null
+++ b/routes/account.ts
@@ -0,0 +1,596 @@
+import fs from 'fs'
+import async from 'async'
+import bcrypt from 'bcryptjs'
+import * as passportSaml from 'passport-saml'
+import dbconn from '../config/dbconn'
+import methods from '../functions/methods'
+import gitlab from '../functions/gitlab'
+import constants from '../config/const'
+import mailer from '../config/mailer'
+import portalUser from '../classes/user'
+import projectInformation from '../classes/website'
+import projectRepo from '../classes/repo'
+
+const SamlStrategy = passportSaml.Strategy
+const saltRounds = 10;
+const salt = 64; // salt length
+const logoDir = 'public/upload/'
+const defaultLogo:any = 'public/default/logo.png'
+
+export = function (app:any, config:any, passport:any, lang:string) {
+
+  // =========== PASSPORT =======
+  passport.serializeUser(function (user:any, done:any) {
+    done(null, user);
+  });
+
+  passport.deserializeUser(function (user:any, done:any) {
+    done(null, user);
+  });
+
+  var samlStrategy = new SamlStrategy({
+      // URL that goes from the Identity Provider -> Service Provider
+      callbackUrl: config.passport.saml.path,
+      // Base address to call logout requests
+      logoutUrl: config.passport.saml.logoutUrl,
+      
+      entryPoint: config.passport.saml.entryPoint,
+      issuer: config.passport.saml.issuer,
+      identifierFormat: undefined,
+      
+      // Service Provider private key
+      decryptionPvk: fs.readFileSync(__dirname + '/cert/key.pem', 'utf8'),
+      // Service Provider Certificate
+      privateKey: fs.readFileSync(__dirname + '/cert/key.pem', 'utf8'),
+      // Identity Provider's public key
+      cert: fs.readFileSync(__dirname + '/cert/cert_idp.pem', 'utf8'),
+      
+      validateInResponseTo: false,
+      disableRequestedAuthnContext: true
+  },
+  function (profile:any, done:any) {
+    return done(null, {
+      id: profile.nameID,
+      idFormat: profile.nameIDFormat,
+      email: profile.email,
+      firstName: profile.givenName,
+      lastName: profile.sn
+    });
+  });
+  
+  passport.use(samlStrategy);
+
+  // ============= SAML ==============
+  app.post(config.passport.saml.path,
+    passport.authenticate(config.passport.strategy,
+      {
+        failureRedirect: '/account/',
+        failureFlash: true
+      }),
+    function (req:any, res:any) {
+      res.redirect('/account/');
+    }
+  );
+
+  // to generate Service Provider's XML metadata
+  app.get('/saml/metadata',
+    function(req:any, res:any) {
+      res.type('application/xml');
+      var spMetadata = samlStrategy.generateServiceProviderMetadata(fs.readFileSync(__dirname + '/cert/cert.pem', 'utf8'));
+      res.status(200).send(spMetadata);
+    }
+  );
+
+  // ======== APP ROUTES - ACCOUNT ====================
+
+  async function getLoggedInUserData(email:string) {
+    let user = await methods.getUserByEmail(email)
+    if (!user) {
+      console.log('no user found')
+      return null
+    } else {
+      let loggedInUser = new portalUser(
+        user.id, email, user.salutation, user.title, user.firstname, user.lastname, user.industry, user.organisation, user.speciality, user.m4lab_idp, user.verificationStatus
+      )
+      
+      let userGitlabId = await methods.getGitlabId(loggedInUser.id)
+      if (userGitlabId) {
+        loggedInUser.setGitlabUserId(userGitlabId)
+      }
+      return loggedInUser
+    }
+  }
+
+  app.get('/', async function (req:any, res:any) {
+    if ( !req.isAuthenticated() ) {
+      res.redirect('/login')
+    } else {
+      let loggedInUser = await getLoggedInUserData(req.user.email)
+      
+      res.render(lang+'/account/home', {
+        user: loggedInUser
+      });
+    }
+  });
+
+  app.get('/login',
+    passport.authenticate(config.passport.strategy, {
+      successRedirect: '/',
+      failureRedirect: '/login'
+    })
+  )
+
+  app.get('/logout', function (req:any, res:any) {
+    if (req.user == null) {
+      return res.redirect('/');
+    }
+
+    req.user.nameID = req.user.id;
+    req.user.nameIDFormat = req.user.idFormat;
+    return samlStrategy.logout(req, function(err:any, uri:any) {
+      req.logout();
+
+      if ( req.session ) {
+        req.session.destroy((err:any) => {
+          if(err) {
+              return console.log(err);
+          }
+        });
+      }
+
+      return res.redirect(uri);
+    });
+  });
+
+  app.get('/profile', async function (req:any, res:any) {
+    if ( !req.isAuthenticated() ) {
+      res.redirect('/login')
+    } else {
+      let loggedInUser = await getLoggedInUserData(req.user.email)
+      if (!loggedInUser) { // null user
+        res.redirect('/account/')
+      } else {
+        if(loggedInUser.getVerificationStatus() != 1) {
+          res.redirect('/account/')
+        } else {
+          res.render(lang+'/account/profile', {
+            user: loggedInUser
+          })
+        }
+      }
+      
+    }
+  })
+
+  app.get('/services', async function(req:any, res:any){
+    if( !req.isAuthenticated() ) {
+      res.redirect('/login')
+    } else {
+      let loggedInUser = await getLoggedInUserData(req.user.email)
+      if (!loggedInUser) { // null user
+        res.redirect('/account/')
+      } else {
+        if(loggedInUser.getVerificationStatus() != 1) { // unverified users
+          res.redirect('/account/')
+        } else {
+          let gitlabReposArr = []
+          let gitlabPagesArr = []
+  
+          if(loggedInUser.getGitlabUserId()) { // for users who have activated their gitlab account
+            let userProjects = await gitlab.getUserProjects(loggedInUser.getGitlabUserId()!)
+            if (!userProjects) {
+              console.error("something went wrong")
+              res.status(500).render(lang+'/500', { error: "something went wrong" })
+            }
+            
+            let project:any
+            for (project in userProjects) {
+              if (userProjects[project].tag_list.includes('website')) {
+                let page = {
+                  projectInformation: new projectInformation(loggedInUser.getGitlabUserId()!, userProjects[project].name, userProjects[project].description,
+                    userProjects[project].id, userProjects[project].avatar_url, userProjects[project].path_with_namespace),
+                  pipelineStatus: await gitlab.getProjectPipelineLatestStatus(userProjects[project].id)
+                }
+                gitlabPagesArr.push(page)
+              } else {
+                let repo = new projectRepo(loggedInUser.getGitlabUserId()!, userProjects[project].name, userProjects[project].description,
+                  userProjects[project].id, userProjects[project].avatar_url, userProjects[project].path_with_namespace)
+                gitlabReposArr.push(repo)
+              }
+            }
+  
+            res.render(lang+'/account/services', {
+              user: loggedInUser,
+              gitlabRepos: gitlabReposArr,
+              gitlabPages: gitlabPagesArr
+            })
+          } else { // for users who have not activated their gitlab account yet
+            let gitlabUser = await gitlab.getUserByEmail(loggedInUser.getEmail())
+            if (!gitlabUser) {
+              res.render(lang+'/account/services', {
+                user: loggedInUser,
+                gitlabRepos: null,
+                gitlabPages: null
+              })
+            } else {
+              let gitlabActivationData = {
+                user_id: loggedInUser.getId(),
+                gitlab_userId: gitlabUser.id}
+
+              methods.addGitlabUser(gitlabActivationData, function(err:any){
+                if(err) {
+                  res.status(500).render(lang+'/500', { error: err })
+                } else {
+                  res.redirect('/account/services')
+                }
+              })
+            }
+          }
+        }
+      }
+    }
+  })
+
+  app.get('/security', async function (req:any, res:any) {
+    if ( !req.isAuthenticated() ) {
+      res.redirect('/login')
+    } else {
+      let loggedInUser = await getLoggedInUserData(req.user.email)
+      if (!loggedInUser) { // null user
+        res.redirect('/account/')
+      } else {
+        if(loggedInUser.getVerificationStatus() == 1 && loggedInUser.getIdpStatus() == 1) {
+          res.render(lang+'/account/security', {
+            user: loggedInUser
+          })
+        } else {
+          res.redirect('/account/')
+        }
+      }
+    }
+  })
+
+  app.post('/updateProfile', async function (req:any, res:any) {
+    if ( !req.isAuthenticated() ) {
+      res.redirect('/login')
+    } else {
+      let loggedInUser = await getLoggedInUserData(req.user.email)
+      if (!loggedInUser) { // null user
+        res.redirect('/account/')
+      } else {
+        let userData = {
+          salutation: req.body.inputSalutation,
+          title: req.body.inputTitle,
+          firstname: req.body.inputFirstname,
+          lastname: req.body.inputLastname,
+          email: req.body.inputEmail,
+          organisation: req.body.inputOrganisation,
+          industry: req.body.inputIndustry,
+          speciality: req.body.inputSpeciality,
+        }
+        let result = await methods.updateUserById(loggedInUser.getId(), userData)
+        if (!result) {
+          res.flash('error', "Failed")
+        } else {
+          loggedInUser.updateProfile(userData.salutation, userData.title, userData.firstname, userData.lastname, userData.email,
+            userData.organisation, userData.industry, userData.speciality)
+          res.flash('success', 'Ihr Benutzerprofil wurde aktualisiert!')
+        }
+        res.redirect('/account/profile')
+      }
+      
+    }
+  });
+
+  app.post('/account/changePwd', async function (req:any, res:any) {
+    if( !req.isAuthenticated() ) {
+      res.redirect('/login')
+    } else {
+      let loggedInUser = await getLoggedInUserData(req.user.email)
+
+      if (!loggedInUser) { // null user
+        res.redirect('/account/')
+      } else {
+        let currPwd = req.body.inputCurrPwd
+        let newPwd = req.body.inputNewPwd
+        let retypePwd = req.body.inputConfirm
+
+        dbconn.user.query('SELECT password FROM credential WHERE user_id='+loggedInUser.getId(), function (err:any, rows:any) {
+          if (err) {
+            console.error(err)
+            res.status(500).render(lang+'/500', { error: err })
+          }
+          let userPwd = rows[0].password
+
+          // check if the password is correct
+          bcrypt.compare(currPwd, userPwd, function(err, isMatch) {
+            if (err) {
+              console.error(err)
+              res.status(500).render(lang+'/500', { error: err })
+            } else if (!isMatch) {
+              res.flash('error', "Das Passwort ist leider falsch. Bitte überprüfen Sie Ihre Eingabe.")
+              res.redirect('/account/security')
+            } else {
+              if ( newPwd != retypePwd ) {
+                res.flash('error', 'Passwörter stimmen nicht überein. Bitte stellen Sie sicher, dass Sie das Passwort beide Male genau gleich eingeben.')
+                res.redirect('/account/security')
+              } else {
+                // update password
+                bcrypt.genSalt(saltRounds, function(err, salt) {
+                  bcrypt.hash(newPwd, salt, async function(err, hash) {
+                    var credentialData = {
+                      password: hash,
+                      user_id: loggedInUser!.getId()
+                    }
+                
+                    let result = await methods.updateCredential(credentialData)
+                    if (!result) {
+                      console.log('Failed to reset password')
+                      res.flash('error', "Datenbankfehler: Passwort kann nicht geändert werden.")
+                    } else {
+                      res.flash('success', "Passwort aktualisiert!")
+                      // send notifiaction email
+                      mailer.options.to = loggedInUser!.getEmail()
+                      mailer.options.subject = constants.updatePasswordMailSubject
+                      mailer.options.html = constants.updatePasswordMailContent+'<div>'+constants.mailSignature+'</div>'
+                      mailer.transporter.sendMail(mailer.options, function(err:any) {
+                        if (err) { console.log(err) }
+                      })
+                    }
+                    res.redirect('/account/security')
+
+                  });
+                });
+              }
+            }
+          })
+        })
+      }
+    }
+  });
+  
+  app.get('/resendVerificationEmail', async function(req:any, res:any){
+    if (!req.isAuthenticated) {
+      res.redirect('/login')
+    } else {
+      let loggedInUser = await getLoggedInUserData(req.user.email)
+      if (!loggedInUser) {
+        res.redirect('/login')
+      } else {
+        let token = await methods.getVerificationTokenByUserId(loggedInUser.id)
+        if (!token) {
+          res.send(false)
+        } else {
+          // send email
+          var emailSubject = "Bitte bestätigen Sie Ihr M4_LAB Benutzerkonto"
+          var emailContent = '<div>Lieber Nutzer,<br/><br/>' +
+            '<p>vielen Dank für Ihre Anmeldung am Transferportal der HFT Stuttgart. <br/>' +
+            'Um Ihre Anmeldung zu bestätigen, klicken Sie bitte diesen Link: ' + config.app.host + '/verifyAccount?token=' + token +
+            '<br/><br/>' +
+            'Ohne Bestätigung Ihres Kontos müssen wir Ihr Konto leider nach 7 Tagen löschen.</p><br/>' + constants.mailSignature +
+            '</div>';
+          mailer.options.to = loggedInUser.email;
+          mailer.options.subject = emailSubject;
+          mailer.options.html = emailContent;
+          mailer.transport.sendMail(mailer.options, function(err:any) {
+            if (err) {
+              console.log('cannot send email')
+              throw err
+            }
+          })
+          res.send(true)
+        }
+      }
+    }
+  })
+
+  // ============= NEW GITLAB PAGES ===========================
+  
+  app.get('/newInformation', async function(req:any, res:any){
+    if ( !req.isAuthenticated() ) {
+      res.redirect('/login')
+    } else {
+      let loggedInUser = await getLoggedInUserData(req.user.email)
+      if (!loggedInUser) {
+        res.redirect('/login')
+      } else {
+        let gitlabUser = await gitlab.getUserByEmail(loggedInUser.getEmail())
+        if (!gitlabUser) { // no user found
+          res.redirect('/account/services')
+        } else {
+          res.render(lang+'/account/newInformation', {
+            user: loggedInUser,
+            gitlabUsername: gitlabUser.username
+          })
+        }
+      }
+    }
+  })
+  app.post('/newInformation', async function(req:any, res:any) {
+    if( !req.isAuthenticated() ) {
+      res.redirect('/login')
+    } else {
+      let loggedInUser = await getLoggedInUserData(req.user.email)
+      if (!loggedInUser) {
+        res.redirect('/login')
+      } else {
+        if (!req.body.name && !req.body.description) {
+          res.flash('error', 'Bitte geben Sie die benötigten Daten ein')
+          res.redirect('/account/newInformation')
+        } else {
+          let projectName = req.body.name.toLowerCase().replace(/\s/g, '-')
+          let projectDesc = req.body.description
+          let projectTemplate = req.body.template
+          let newInformation = new projectInformation(loggedInUser.getGitlabUserId()!, projectName, projectDesc)
+          let newLogoFile = defaultLogo
+            
+          if (req.files) { newLogoFile = req.files.logo }
+  
+          async.waterfall([
+            function(callback:any){ // upload logo
+              if (!req.files) {
+                callback(null, newLogoFile)
+              } else {
+                newLogoFile.mv(logoDir + newLogoFile.name, function(err:any) {
+                  newLogoFile = logoDir+newLogoFile.name
+                  callback(err, newLogoFile)
+                })
+              }
+            },
+            async function(newLogoFile:any){ // create a new GitLab Page
+              let newPages = await gitlab.createNewPages(newInformation, newLogoFile, projectTemplate)
+              if (newPages.status) {
+                if(newPages.data.message.name == "has already been taken") {
+                  res.flash("error", "Der Projektname '"+newInformation.getName()+"' ist bereits vergeben, bitte wählen Sie einen anderen Namen.")
+                } else {
+                  res.flash("error", "Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut. ")
+                }
+                res.redirect('/account/newInformation')
+              } else {
+                res.flash("success", "Ihre Webseite wurde erstellt, aber noch nicht veröffentlicht. Um Ihre Webseite endgültig zu veröffentlichen, "+
+                  "schließen Sie die Einrichtung gemäß unten stehender Anleitung ab.")
+                res.redirect('/account/updateInformation?id='+newPages.id)
+              }
+            }
+          ], function (err) {
+            if(err) console.log(err)
+            // remove logo
+            if (req.files) {
+              fs.unlink(newLogoFile, (err) => {
+                if(err) console.log(err)
+              })
+            }
+          })
+        }
+      }
+    }
+  })
+
+  app.get('/updateInformation', async function(req:any, res:any){
+    if( !req.isAuthenticated() ) {
+      res.redirect('/login')
+    } else {
+      let loggedInUser = await getLoggedInUserData(req.user.email)
+
+      if (!loggedInUser) {
+        res.redirect('/login')
+      } else {
+        if(!req.query.id) {
+          res.redirect('/account/services')
+        } else {
+          let project = await gitlab.getProjectById(req.query.id)
+          if (!project) {
+            console.log(" ========= Error or no project found")
+            res.redirect('/account/services')
+          } else if (!project.owner) {
+            console.log(" ========= Project cannot be accessed, since it does not have an owner")
+            res.redirect('/account/services')
+          } else if (project.owner.id != loggedInUser.getGitlabUserId()) {
+            console.log(" ========= Access denied: Not your project")
+            res.redirect('/account/services')
+          } else {
+            let curInformation = new projectInformation(loggedInUser.getGitlabUserId()!, project.name, project.description,
+              req.query.id, project.avatar_url, project.path_with_namespace)
+            
+            res.render(lang+'/account/updateInformation', {
+              user: loggedInUser,
+              information: curInformation
+            })
+          }
+        }
+      }
+    }
+  })
+  // update a website
+  app.post('/updateInformation', async function(req:any, res:any){
+    if( !req.isAuthenticated() ) {
+      res.redirect('/login')
+    } else {
+      let loggedInUser = await getLoggedInUserData(req.user.email)
+
+      if (!loggedInUser) {
+        res.redirect('/login')
+      } else {
+        if (!req.body.name && !req.body.description) {
+          res.flash('error', 'Bitte geben Sie die benötigten Daten ein')
+          res.redirect('/account/updateInformation')
+        } else {
+          let projectName = req.body.name.toLowerCase().replace(/\s/g, '-')
+          let projectDesc = req.body.description
+          let updatedInformation = new projectInformation(loggedInUser.getGitlabUserId()!, projectName, projectDesc, req.query.id)
+          let newLogoFile:any
+  
+          async.waterfall([
+            function(callback:any){ // upload logo
+              if(!req.files) {
+                callback(null, newLogoFile)
+              } else {
+                newLogoFile = req.files.logo
+                newLogoFile.mv(logoDir + newLogoFile.name, function(err:any) {
+                  newLogoFile = logoDir + newLogoFile.name
+                  callback(err, newLogoFile)
+                })
+              }
+            },
+            async function(newLogoFile:any){ // update gitlab page
+              let updatedPages = await gitlab.updateProject(updatedInformation, newLogoFile)
+              
+              if (updatedPages.status) {
+                if(updatedPages.data.message.name == "has already been taken") {
+                  res.flash("error", "Der Projektname '"+projectName+"' ist bereits vergeben, bitte wählen Sie einen anderen Namen.")
+                } else {
+                  res.flash("error", "Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut. ")
+                }
+              } else {
+                updatedInformation.setLogo(updatedPages.avatar_url)
+                updatedInformation.setPath(updatedPages.path)
+                res.flash("success", "Ihre Website wurde aktualisiert")
+              }
+
+              res.redirect('/account/updateInformation?id='+updatedInformation.getId())
+            }
+          ], function (err) {
+            if(err) console.log(err)
+            if(newLogoFile){ // remove logo
+              fs.unlink(newLogoFile, (err) => {
+                if(err) console.log(err)
+              })
+            }
+          })
+        }
+      }
+    }
+  })
+
+  app.delete('/deleteProject', async function(req:any, res:any){
+    if( !req.isAuthenticated() ) {
+      res.redirect('/login')
+    } else {
+      let loggedInUser = await getLoggedInUserData(req.user.email)
+      if (!loggedInUser) {
+        res.redirect('/login')
+      } else {
+        let projectId = req.body.id
+
+        if (projectId) {
+          // check if the owner is valid
+          let project = await gitlab.getProjectById(projectId)
+          if (!project) {
+            console.log(" ========= Error or no project found")
+          } else if (!project.owner) {
+            console.log(" ========= Project cannot be accessed, since it does not have an owner")
+          } else if (project.owner.id != loggedInUser.getGitlabUserId()) {
+            console.log(" ========= Access denied: Not your project")
+          } else {
+            let isDeleted = await gitlab.deleteProjectById(projectId)
+            if (!isDeleted) {
+              res.flash("error", "Project cannot be deleted. Please try again.")
+            }
+          }
+        }
+        res.redirect('/account/services')
+      }
+    }
+  })
+
+}
\ No newline at end of file