From 664029f81e2e0542b2195badafa2099085c51f16 Mon Sep 17 00:00:00 2001 From: Rosanny Date: Wed, 4 Aug 2021 17:01:31 +0200 Subject: [PATCH 1/7] small updates --- .gitignore | 4 ++-- views/DE/404.pug | 4 ++-- views/DE/500.pug | 4 ++-- views/DE/account/newInformation.pug | 2 +- views/DE/account/updateInformation.pug | 18 +++++++++--------- views/DE/layout.pug | 12 ------------ 6 files changed, 16 insertions(+), 28 deletions(-) delete mode 100644 views/DE/layout.pug diff --git a/.gitignore b/.gitignore index 287d7f27..14e71094 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ +/built +/routes/cert /node_modules -sp-account-metadata.xml -.idea diff --git a/views/DE/404.pug b/views/DE/404.pug index 5a16f086..29a3cd86 100644 --- a/views/DE/404.pug +++ b/views/DE/404.pug @@ -21,8 +21,8 @@ html(lang="de") body div(class="container") div(class="center", align="center") - a(href="https://m4lab.hft-stuttgart.de") - img(src="https://transfer.hft-stuttgart.de/images/demo/m4lab_logo.jpg", class="img-responsive center-block", width="185", height="192") + a(href="/") + img(src="/images/demo/m4lab_logo.jpg", class="img-responsive center-block", width="185", height="192") br br p(class="h5") 404. The requested URL was not found. diff --git a/views/DE/500.pug b/views/DE/500.pug index aea0e76c..20dbfa9d 100644 --- a/views/DE/500.pug +++ b/views/DE/500.pug @@ -21,8 +21,8 @@ html(lang="de") body div(class="container") div(class="center", align="center") - a(href="https://m4lab.hft-stuttgart.de") - img(src="https://transfer.hft-stuttgart.de/images/demo/m4lab_logo.jpg", class="img-responsive center-block", width="185", height="192") + a(href="/") + img(src="/images/demo/m4lab_logo.jpg", class="img-responsive center-block", width="185", height="192") br br p(class="h5") 500. Unexpected Error :( diff --git a/views/DE/account/newInformation.pug b/views/DE/account/newInformation.pug index 543d456d..21788f6a 100644 --- a/views/DE/account/newInformation.pug +++ b/views/DE/account/newInformation.pug @@ -76,7 +76,7 @@ html(lang="de") label(for="logo", class="col-sm-2") Projektlogo div(class="col-sm-8") div(class="form-group row px-4") - - let defaultLogo = "https://m4lab.hft-stuttgart.de/img/footer/M4_LAB_LOGO_Graustufen.png" + - let defaultLogo = "/img/footer/M4_LAB_LOGO_Graustufen.png" img(src=defaultLogo, width="100" height="100") div(class="form-group row px-3") input#logo(name="logo", class="form-control-file", type="file") diff --git a/views/DE/account/updateInformation.pug b/views/DE/account/updateInformation.pug index f8318ee0..58cd8a42 100644 --- a/views/DE/account/updateInformation.pug +++ b/views/DE/account/updateInformation.pug @@ -85,7 +85,7 @@ html(lang="de") li Klicken Sie hier, um Ihre index.html in GitLab zu öffnen. li Bearbeiten Sie ihre Datei. li Um die Änderungen zu speichern und auf ihrer Seite sofort zu übernehmen, klicken Sie auf Commit changes - img(src="https://transfer.hft-stuttgart.de/img/help/save_file.png", class="img-fluid", style="border: 1px solid gray;", alt="index.html") + img(src="/img/help/save_file.png", class="img-fluid", style="border: 1px solid gray;", alt="index.html") li Sobald Sie Änderungen an Ihrer index.html vornehmen, wird Ihre Website veröffentlicht. div(class="card-header") div(class="card-title") @@ -95,21 +95,21 @@ html(lang="de") li Klicken Sie settings.js, um Ihre settings.js in GitLab zu öffnen. li Bearbeiten Sie ihre Datei. li Hier sehen Sie die Standardwerde für Soziale Netzwerke und persönliche Webseiten eines Teilnehmers sowie den Standardavatar. Es wird empfohlen, diese Werte nicht zu ändern, aber Sie können weitere Soziale Netzwerke hinzufügen. - img(src="https://transfer.hft-stuttgart.de/img/help/default_settings.png", class="img-fluid", style="border: 1px solid gray;") + img(src="/img/help/default_settings.png", class="img-fluid", style="border: 1px solid gray;") li Diese Schalter kontrollieren, welche Teile der gitlab-Seite angezeigt werden sollen. Wenn Sie also beispielsweise nur eine einzige Seite haben, benötigen Sie kein Menü und können den Wert für 'menu' auf OFF stellen. - img(src="https://transfer.hft-stuttgart.de/img/help/switches.png", class="img-fluid", style="border: 1px solid gray;") + img(src="/img/help/switches.png", class="img-fluid", style="border: 1px solid gray;") li Hier ändern Sie das Projektlogo. Das Logo wird am oberen Rand der Seite mittig angezeigt. Wenn der Schalter für 'project logo' auf OFF steht, wird es nicht angezeigt. - img(src="https://transfer.hft-stuttgart.de/img/help/pr_logo.png", class="img-fluid", style="border: 1px solid gray;") + img(src="/img/help/pr_logo.png", class="img-fluid", style="border: 1px solid gray;") li Hier ändern Sie das Menü Ihrer gitlab-Seite. Ein Menü kann entweder auf einen Unterordner/ template verweisen oder aber auf einen externen Link, z.B. eine Demo. Sie können Menüeinträge hinzufügen oder entfernen. Das Menü wird mit dem Schalter 'OFF' verborgen. Vergessen Sie nicht den Schrägstrich am Ende eines Menülinks, wenn dieser auf einen Ordner zeigt. - img(src="https://transfer.hft-stuttgart.de/img/help/menu.png", class="img-fluid", style="border: 1px solid gray;") + img(src="/img/help/menu.png", class="img-fluid", style="border: 1px solid gray;") li Hier ändern Sie die Teilnehmenden. Sie können die Standardwerte für Soziale Netzwerke (diese beinhalten die HFT-Kanäle) oder Ihr eigenen Profile verwenden. Sie können auf Ihre persönliche Webseite verlinken. Sie können soziale Netzwerke hinzufügen oder entfernen. Sie können auch einen persönlichen Avatar oder den Standard-Avatar (DEFAULT.avatar) verwenden. - img(src="https://transfer.hft-stuttgart.de/img/help/partic.png", class="img-fluid", style="border: 1px solid gray;") + img(src="/img/help/partic.png", class="img-fluid", style="border: 1px solid gray;") li Hier ist ein Beispiel mit zwei Teilnehmenden: - img(src="https://transfer.hft-stuttgart.de/img/help/partic2.png", class="img-fluid", style="border: 1px solid gray;") + img(src="/img/help/partic2.png", class="img-fluid", style="border: 1px solid gray;") li Hier ändern Sie die Fußzeilenlogos z.B. zu denen von Projektpartnern. Wenn Sie das Logo nicht mit einer externen Webseite verlinken wollen, verwenden Sie EMPTY_LINK als Wert für href. Der Titel title wird bei Mouse-Hover über dem Logo erscheinen. - img(src="https://transfer.hft-stuttgart.de/img/help/f_logos.png", class="img-fluid", style="border: 1px solid gray;") + img(src="/img/help/f_logos.png", class="img-fluid", style="border: 1px solid gray;") li Klicken Sie anschließend auf Commit changes, um die Änderungen zu speichern. - img(src="https://transfer.hft-stuttgart.de/img/help/edit_settings_generic.png", class="img-fluid", style="border: 1px solid gray;") + img(src="/img/help/edit_settings_generic.png", class="img-fluid", style="border: 1px solid gray;") hr div(class="mx-4") diff --git a/views/DE/layout.pug b/views/DE/layout.pug deleted file mode 100644 index 32d27e01..00000000 --- a/views/DE/layout.pug +++ /dev/null @@ -1,12 +0,0 @@ -doctype html -html - head - title PassportJS SAML example - block links - link(rel='stylesheet', href='bower_components/bootstrap/dist/css/bootstrap.css') - body - div.container - block content - script(src='bower_components/jquery/dist/jquery.min.js') - script(src='bower_components/bootstrap/dist/js/bootstrap.min.js') - block scripts -- GitLab From 1ed80da676f73366ae91c6e26adda7a515818cab Mon Sep 17 00:00:00 2001 From: Rosanny Date: Wed, 4 Aug 2021 17:03:24 +0200 Subject: [PATCH 2/7] unit test in TypeScript --- __tests__/{gitlab.unit.test.js => gitlab.unit.test.ts} | 2 +- __tests__/{method.unit.test.js => method.unit.test.ts} | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename __tests__/{gitlab.unit.test.js => gitlab.unit.test.ts} (95%) rename __tests__/{method.unit.test.js => method.unit.test.ts} (97%) diff --git a/__tests__/gitlab.unit.test.js b/__tests__/gitlab.unit.test.ts similarity index 95% rename from __tests__/gitlab.unit.test.js rename to __tests__/gitlab.unit.test.ts index 057f020d..c1e5ad91 100644 --- a/__tests__/gitlab.unit.test.js +++ b/__tests__/gitlab.unit.test.ts @@ -1,4 +1,4 @@ -const gitlab = require('../functions/gitlab') +import gitlab from '../functions/gitlab' //const axios = require('axios') //jest.mock('axios') diff --git a/__tests__/method.unit.test.js b/__tests__/method.unit.test.ts similarity index 97% rename from __tests__/method.unit.test.js rename to __tests__/method.unit.test.ts index 1673830d..2a11d132 100644 --- a/__tests__/method.unit.test.js +++ b/__tests__/method.unit.test.ts @@ -1,4 +1,4 @@ -const methods = require('../functions/methods') +import methods from '../functions/methods' describe("DB methohds test", () => { @@ -49,4 +49,4 @@ describe("DB methohds test", () => { expect(user).toBeNull() }) -}) +}) \ No newline at end of file -- GitLab From 0cd83c72cb762da64ea48375ca0af6c0c3973b62 Mon Sep 17 00:00:00 2001 From: Rosanny Date: Wed, 4 Aug 2021 17:04:00 +0200 Subject: [PATCH 3/7] updating dependencies --- package-lock.json | 1290 ++++++++++++++++++++++++++------------------- package.json | 33 +- 2 files changed, 766 insertions(+), 557 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2b7642f6..b2830afb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,28 +15,46 @@ "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 +69,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 +150,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 +226,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 +339,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 +528,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 +848,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 +891,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 +1007,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 +1173,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 +1350,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 +1364,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", @@ -1419,11 +1640,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 +1842,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 +2210,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", @@ -2061,6 +2264,12 @@ "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", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -2074,12 +2283,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 +2313,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 +2514,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 +2526,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 +2546,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 +2590,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 +3042,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 +3123,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 +3459,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 +3471,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 +3542,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 +3603,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 +4899,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 +4932,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 +4950,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 +5004,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 +5086,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 +5106,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,14 +5169,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", @@ -5232,14 +5284,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 +5335,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 +5347,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", @@ -5915,11 +5967,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": { @@ -6213,14 +6265,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,9 +7110,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==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, "node_modules/sqlstring": { "version": "2.3.1", @@ -7469,6 +7513,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 +7598,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 +7631,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", @@ -7930,14 +8027,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 +8174,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 +8195,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 +8259,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 +8332,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 +8435,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 +8576,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 +8839,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 +8882,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 +8998,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 +9161,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 +9288,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": { @@ -9215,11 +9514,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 +9671,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 +9962,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", @@ -9720,6 +10004,12 @@ "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", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -9730,11 +10020,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 +10046,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 +10197,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 +10206,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 +10223,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 +10258,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 +10596,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 +10648,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 +10896,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 +10961,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 +11004,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 +12001,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 +12028,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 +12043,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 +12084,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 +12144,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 +12156,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,11 +12208,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", @@ -12147,11 +12306,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 +12347,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", @@ -12652,11 +12814,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" } }, @@ -12912,11 +13074,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,9 +13751,9 @@ } }, "sprintf-js": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", - "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, "sqlstring": { "version": "2.3.1", @@ -13896,6 +14053,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 +14110,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 +14133,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", @@ -14247,11 +14436,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 +14553,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 78d2bb41..4604e051 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,9 @@ "url": "https://transfer.hft-stuttgart.de/gitlab/m4lab_tv1/user-account.git" }, "scripts": { - "start": "nodemon app.js", + "start": "nodemon app.ts", + "build": "tsc -build", + "clean": "tsc -build --clean", "test": "jest" }, "dependencies": { @@ -26,17 +28,15 @@ "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", @@ -48,7 +48,26 @@ "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" -- GitLab From 36450a274a0a1cb8628858320ed43b9ba8b38ba4 Mon Sep 17 00:00:00 2001 From: Rosanny Date: Wed, 4 Aug 2021 17:05:46 +0200 Subject: [PATCH 4/7] migrating to TypeScript --- app.js | 82 --- app.ts | 93 ++++ classes/{project.js => project.ts} | 25 +- classes/repo.js | 9 - classes/repo.ts | 9 + classes/user.js | 83 --- classes/user.ts | 97 ++++ classes/website.js | 9 - classes/website.ts | 9 + config/{config.js => config.ts} | 8 +- config/{const.js => const.ts} | 2 +- config/{dbconn.js => dbconn.ts} | 10 +- config/{dbconn2.js => dbconn2.ts} | 10 +- config/mailer.js | 39 -- config/mailer.ts | 40 ++ functions/{gitlab.js => gitlab.ts} | 114 ++--- functions/{helpers.js => helpers.ts} | 4 +- functions/{methods.js => methods.ts} | 127 +++-- public/js/jquery-ui/i18n/datepicker-de.js | 37 -- routes/account.js | 568 --------------------- routes/account.ts | 596 ++++++++++++++++++++++ routes/public.js | 296 ----------- routes/public.ts | 292 +++++++++++ tsconfig.json | 11 + 24 files changed, 1285 insertions(+), 1285 deletions(-) delete mode 100644 app.js create mode 100644 app.ts rename classes/{project.js => project.ts} (63%) delete mode 100644 classes/repo.js create mode 100644 classes/repo.ts delete mode 100644 classes/user.js create mode 100644 classes/user.ts delete mode 100644 classes/website.js create mode 100644 classes/website.ts rename config/{config.js => config.ts} (94%) rename config/{const.js => const.ts} (98%) rename config/{dbconn.js => dbconn.ts} (91%) rename config/{dbconn2.js => dbconn2.ts} (91%) delete mode 100644 config/mailer.js create mode 100644 config/mailer.ts rename functions/{gitlab.js => gitlab.ts} (58%) rename functions/{helpers.js => helpers.ts} (69%) rename functions/{methods.js => methods.ts} (56%) delete mode 100644 public/js/jquery-ui/i18n/datepicker-de.js delete mode 100644 routes/account.js create mode 100644 routes/account.ts delete mode 100644 routes/public.js create mode 100644 routes/public.ts create mode 100644 tsconfig.json diff --git a/app.js b/app.js deleted file mode 100644 index b5aac0bc..00000000 --- a/app.js +++ /dev/null @@ -1,82 +0,0 @@ -const express = require('express'); -const http = require('http'); -const path = require('path'); -const passport = require('passport'); -const morgan = require('morgan'); -const cookieParser = require('cookie-parser'); -const bodyParser = require('body-parser'); -const session = require('express-session'); -const errorhandler = require('errorhandler'); -const flash = require('express-flash-2'); -const fileUpload = require('express-fileupload'); -const helmet = require('helmet'); -const compression = require('compression'); -const methodOverride = require('method-override'); - -var env = process.env.NODE_ENV || 'testing'; -const config = require('./config/config')[env]; -const lang = 'DE'; - -var app = express(); - -app.set('port', config.app.port); -app.set('views', __dirname + '/views'); -app.set('view engine', 'pug'); - -// enable files upload -app.use(fileUpload({ - createParentPath: true, - limits: { - fileSize: 1000000 // 1 MB max. file size - } -})); - -app.use(methodOverride('_method')); -app.use(helmet()); -app.use(compression()); -app.use(morgan('combined')); -app.use(cookieParser()); -app.use(bodyParser.json()); -app.use(bodyParser.urlencoded({extended: false})); -app.use(express.static(path.join(__dirname, 'public'))); -app.use((req, res, next) => { - next(); -}); - -app.use(session( - { - resave: true, - saveUninitialized: true, - secret: config.app.sessionSecret - } -)); -app.use(flash()); -app.use(passport.initialize()); -app.use(passport.session()); - -// caching disabled for every route -// NOTE: Works in Firefox and Opera. Does not work in Edge -app.use(function(req, res, next) { - res.set('Cache-Control', 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0'); - next(); -}); - -require('./routes/account')(app, config, passport, lang); -require('./routes/public')(app, config, lang); - -// Handle 404 -app.use(function (req, res) { - res.status(404).render(lang+'/404') -}) - -// Handle 500 - any server error -app.use(function (err, req, res, next) { - console.error(err.stack) - res.status(500).render(lang+'/500', { - error: err - }) -}) - -app.listen(app.get('port'), function () { - console.log('Express server listening on port ' + app.get('port')); -}); \ No newline at end of file diff --git a/app.ts b/app.ts new file mode 100644 index 00000000..89a8a359 --- /dev/null +++ b/app.ts @@ -0,0 +1,93 @@ +import express from 'express'; +import path from 'path'; +import passport from 'passport'; +import morgan from 'morgan'; +import cookieParser from 'cookie-parser'; +import bodyParser from 'body-parser'; +import session from 'express-session'; +import flash from 'express-flash-2'; +import fileUpload from 'express-fileupload'; +import helmet from 'helmet'; +import compression from 'compression'; +import methodOverride from 'method-override'; +import dotenv from 'dotenv' + +dotenv.config(); + +var env = process.env.NODE_ENV || 'testing'; +const config = require('./config/config')[env]; +const lang = 'DE'; + +var app = express(); +app.set('port', config.app.port); +app.set('views', path.join( __dirname + '/views')); +app.set('view engine', 'pug'); + +// enable files upload +app.use(fileUpload({ + createParentPath: true, + limits: { + fileSize: 1000000 // 1 MB max. file size + } +})); +app.use(methodOverride('_method')); +app.use( + helmet.contentSecurityPolicy({ + useDefaults: true, + directives: { + "font-src": ["'self'", "https://use.fontawesome.com"], + "img-src": ["'self'", "https://transfer.hft-stuttgart.de"], + "script-src": ["'self'", "https://code.jquery.com/jquery-3.3.1.min.js", "https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js", + "https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js", "https://unpkg.com/bootstrap-show-password@1.2.1/dist/bootstrap-show-password.min.js"], + "style-src": ["'self'", "https://use.fontawesome.com/releases/v5.8.2/css/all.css"], + "frame-src": ["'self'"] + }, + reportOnly: true, + }) +); + +app.use(compression()); +app.use(morgan('combined')); +app.use(cookieParser(config.app.sessionSecret)); +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({extended: false})); +app.use(express.static(path.join(__dirname, 'public'))); +app.use((req, res, next) => { + next(); +}); + +app.use(session({ + resave: true, + saveUninitialized: true, + secret: config.app.sessionSecret +})); +app.use(flash()); +app.use(passport.initialize()); +app.use(passport.session()); + +// caching disabled for every route +// NOTE: Works in Firefox and Opera. Does not work in Edge +app.use(function(req, res, next) { + res.set('Cache-Control', 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0'); + next(); +}); + +require('./routes/public')(app, config, lang); +require('./routes/account')(app, config, passport, lang); + +// Handle 404 +app.use(function (req:any, res:any) { + res.status(404).render(lang+'/404') +}) + +// Handle 500 - any server error +app.use(function (err:any, req:any, res:any, next:any) { + console.error(err.stack) + res.status(500).render(lang+'/500', { + error: err + }) +}) + +app.listen(app.get('port'), function () { + console.log('Express server listening on port ' + app.get('port')); +}); \ No newline at end of file diff --git a/classes/project.js b/classes/project.ts similarity index 63% rename from classes/project.js rename to classes/project.ts index 85dafab3..045e86a7 100644 --- a/classes/project.js +++ b/classes/project.ts @@ -1,9 +1,16 @@ class Project { - constructor(ownerGitlabId, id, name, desc, logo, path) { + ownerGitlabId:number + name:string + desc:string + id?:number + logo?:string + path?:string + + constructor(ownerGitlabId:number, name:string, desc:string, id?:number, logo?:string, path?:string) { this.ownerGitlabId = ownerGitlabId - this.id = id this.name = name this.desc = desc + this.id = id this.logo = logo this.path = path } @@ -28,24 +35,24 @@ class Project { return this.path } // setter - setOwnerGitlabId(newOwnerGitlabId){ + setOwnerGitlabId(newOwnerGitlabId:number){ this.ownerGitlabId = newOwnerGitlabId } - setId(newId) { + setId(newId:number) { this.id = newId } - setName(newName) { + setName(newName:string) { this.name = newName } - setDesc(newDesc) { + setDesc(newDesc:string) { this.desc = newDesc } - setLogo(newLogoUrl) { + setLogo(newLogoUrl:string) { this.logo = newLogoUrl } - setPath(newPath) { + setPath(newPath:string) { this.path = newPath } } -module.exports = Project \ No newline at end of file +export = Project \ No newline at end of file diff --git a/classes/repo.js b/classes/repo.js deleted file mode 100644 index c99ac66f..00000000 --- a/classes/repo.js +++ /dev/null @@ -1,9 +0,0 @@ -const Project = require("./project"); - -class Repo extends Project { - constructor(ownerGitlabId, id, name, desc, logo, path) { - super(ownerGitlabId, id, name, desc, logo, path) - } -} - -module.exports = Repo \ No newline at end of file diff --git a/classes/repo.ts b/classes/repo.ts new file mode 100644 index 00000000..b41a8fe9 --- /dev/null +++ b/classes/repo.ts @@ -0,0 +1,9 @@ +import Project from "./project" + +class Repo extends Project { + constructor(ownerGitlabId:number, name:string, desc:string, id?:number, logo?:string, path?:string) { + super(ownerGitlabId, name, desc, id, logo, path) + } +} + +export = Repo \ No newline at end of file diff --git a/classes/user.js b/classes/user.js deleted file mode 100644 index 94f07edd..00000000 --- a/classes/user.js +++ /dev/null @@ -1,83 +0,0 @@ -class User { - constructor(id, email, salutation, title, firstName, lastName, industry, organisation, speciality, is_m4lab_idp, gitlabUserId, verificationStatus) { - this.id = id - this.email = email - this.salutation = salutation - this.title = title - this.firstName = firstName - this.lastName = lastName - this.industry = industry - this.organisation = organisation - this.speciality = speciality - this.is_m4lab_idp = is_m4lab_idp // 1 or 0 - this.gitlabUserId = gitlabUserId - this.verificationStatus = verificationStatus - } - - // getter - getId() { - return this.id - } - getEmail() { - return this.email - } - getFullName() { - return this.firstName+' '+this.lastName - } - getIdpStatus() { - return this.is_m4lab_idp - } - getGitlabUserId() { - return this.gitlabUserId - } - getVerificationStatus() { - return this.verificationStatus - } - // setter - setEmail(email) { - this.email = email - } - setSalutation(salutation) { - this.salutation = salutation - } - setTitle(title) { - this.title = title - } - setFirstName(firstName) { - this.firstName = firstName - } - setLastName(lastName) { - this.lastName = lastName - } - setIndustry(industry) { - this.industry = industry - } - setOrganisation(organisation) { - this.organisation = organisation - } - setSpeciality(speciality) { - this.speciality = speciality - } - setM4lab_idp(m4lab_idp) { - this.m4lab_idp = m4lab_idp - } - setGitlabUserId(newGitlabUserId) { - this.gitlabUserId = newGitlabUserId - } - setVerificationStatus(verificationStatus) { - this.verificationStatus = verificationStatus - } - - updateProfile(newSalutation, newTitle, newFirstname, newLastname, newEmail, newOrganisation, newIndustry, newSpeciality) { - this.salutation = newSalutation - this.title = newTitle - this.firstName = newFirstname - this.lastName = newLastname - this.email = newEmail - this.organisation = newOrganisation - this.industry = newIndustry - this.speciality = newSpeciality - } -} - -module.exports = User \ No newline at end of file diff --git a/classes/user.ts b/classes/user.ts new file mode 100644 index 00000000..3b26a694 --- /dev/null +++ b/classes/user.ts @@ -0,0 +1,97 @@ +class User { + id:number + email:string + salutation:string // should be enum + title:string // should be enum + firstName:string + lastName:string + industry:string + organisation:string + speciality:string + is_m4lab_idp:number // 1 or 0 + verificationStatus:number // 1 or 0 - // should be boolean + gitlabUserId?:number + + constructor(id:number, email:string, salutation:string, title:string, firstName:string, lastName:string, industry:string, organisation:string, + speciality:string, is_m4lab_idp:number, verificationStatus:number, gitlabUserId?:number) { + this.id = id + this.email = email + this.salutation = salutation + this.title = title + this.firstName = firstName + this.lastName = lastName + this.industry = industry + this.organisation = organisation + this.speciality = speciality + this.is_m4lab_idp = is_m4lab_idp + this.verificationStatus = verificationStatus + this.gitlabUserId = gitlabUserId + } + + // getter + getId() { + return this.id + } + getEmail() { + return this.email + } + getFullName() { + return this.firstName+' '+this.lastName + } + getIdpStatus() { + return this.is_m4lab_idp + } + getVerificationStatus() { + return this.verificationStatus + } + getGitlabUserId() { + return this.gitlabUserId + } + // setter + setEmail(email:string) { + this.email = email + } + setSalutation(salutation:string) { + this.salutation = salutation + } + setTitle(title:string) { + this.title = title + } + setFirstName(firstName:string) { + this.firstName = firstName + } + setLastName(lastName:string) { + this.lastName = lastName + } + setIndustry(industry:string) { + this.industry = industry + } + setOrganisation(organisation:string) { + this.organisation = organisation + } + setSpeciality(speciality:string) { + this.speciality = speciality + } + setM4lab_idp(m4lab_idp:number) { + this.is_m4lab_idp = m4lab_idp + } + setVerificationStatus(verificationStatus:number) { + this.verificationStatus = verificationStatus + } + setGitlabUserId(newGitlabUserId:number) { + this.gitlabUserId = newGitlabUserId + } + + updateProfile(newSalutation:string, newTitle:string, newFirstname:string, newLastname:string, newEmail:string, newOrganisation:string, newIndustry:string, newSpeciality:string) { + this.salutation = newSalutation + this.title = newTitle + this.firstName = newFirstname + this.lastName = newLastname + this.email = newEmail + this.organisation = newOrganisation + this.industry = newIndustry + this.speciality = newSpeciality + } +} + +export = User \ No newline at end of file diff --git a/classes/website.js b/classes/website.js deleted file mode 100644 index 1d05c400..00000000 --- a/classes/website.js +++ /dev/null @@ -1,9 +0,0 @@ -const Project = require("./project"); - -class Website extends Project { - constructor(ownerGitlabId, id, name, desc, logo, path) { - super(ownerGitlabId, id, name, desc, logo, path) - } -} - -module.exports = Website \ No newline at end of file diff --git a/classes/website.ts b/classes/website.ts new file mode 100644 index 00000000..bd64140d --- /dev/null +++ b/classes/website.ts @@ -0,0 +1,9 @@ +import Project from "./project" + +class Website extends Project { + constructor(ownerGitlabId:number, name:string, desc:string, id?:number, logo?:string, path?:string) { + super(ownerGitlabId, name, desc, id, logo, path) + } +} + +export = Website \ No newline at end of file diff --git a/config/config.js b/config/config.ts similarity index 94% rename from config/config.js rename to config/config.ts index e4bb457c..47558a5d 100644 --- a/config/config.js +++ b/config/config.ts @@ -1,4 +1,4 @@ -module.exports = { +export = { development: { app: { name: 'User Account Management', @@ -28,7 +28,7 @@ module.exports = { host: 'mailhost', // hostname secureConnection: false, // TLS requires secureConnection to be false port: 587, // port for secure SMTP - TLS: true, // sets requireTLS + TLS: true, authUser: 'mailuser', authPass: 'mailpass', tlsCiphers: 'SSLv3', @@ -67,7 +67,7 @@ module.exports = { host: 'mailhost', // hostname secureConnection: false, // TLS requires secureConnection to be false port: 587, // port for secure SMTP - TLS: true, // sets requireTLS + TLS: true, authUser: 'mailuser', authPass: 'mailpass', tlsCiphers: 'SSLv3', @@ -77,4 +77,4 @@ module.exports = { token_readWriteProjects: 'token-goes-here' } } -} +} \ No newline at end of file diff --git a/config/const.js b/config/const.ts similarity index 98% rename from config/const.js rename to config/const.ts index dcbb821a..302d0177 100644 --- a/config/const.js +++ b/config/const.ts @@ -1,4 +1,4 @@ -module.exports = { +export = { mailSignature: 'Mit den besten Grüßen,
das Transferportal-Team der HFT Stuttgart

' + 'Transferportal der Hochschule für Technik Stuttgart
' + diff --git a/config/dbconn.js b/config/dbconn.ts similarity index 91% rename from config/dbconn.js rename to config/dbconn.ts index 67003295..d918ce7c 100644 --- a/config/dbconn.js +++ b/config/dbconn.ts @@ -1,6 +1,6 @@ -const mysql = require('mysql') +import mysql from 'mysql' -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.ts similarity index 91% rename from config/dbconn2.js rename to config/dbconn2.ts index abbd0a01..c13c40f1 100644 --- a/config/dbconn2.js +++ b/config/dbconn2.ts @@ -1,6 +1,6 @@ -const mysql = require('mysql2') +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/mailer.js b/config/mailer.js deleted file mode 100644 index d7c6faf0..00000000 --- a/config/mailer.js +++ /dev/null @@ -1,39 +0,0 @@ -const nodemailer = require('nodemailer'); -const nodemailerNTLMAuth = require('nodemailer-ntlm-auth'); - - -var env = process.env.NODE_ENV || 'testing'; -const config = require('./config')[env] - -var smtpTransport = nodemailer.createTransport({ - host: config.mailer.host, - secure: config.mailer.secureConnection, - port: config.mailer.port, - requireTLS: config.mailer.TLS, - auth: { - type: 'custom', - method: 'NTLM', - user: config.mailer.authUser, - pass: config.mailer.authPass, - options: { - domain: 'ad' - } - }, - customAuth:{ - NTLM: nodemailerNTLMAuth - } -}); - -var mailOptions = { - to: "", - from: config.mailer.from, - subject: "", - text: "" -}; - -var mailer = { - transport: smtpTransport, - options: mailOptions -} - -module.exports = mailer diff --git a/config/mailer.ts b/config/mailer.ts new file mode 100644 index 00000000..18f25191 --- /dev/null +++ b/config/mailer.ts @@ -0,0 +1,40 @@ +const nodemailer = require('nodemailer') +const nodemailerNTLMAuth = require('nodemailer-ntlm-auth') + +var env = process.env.NODE_ENV || 'testing' +const config = require('./config')[env] + +var smtpTransporter = nodemailer.createTransport({ + host: config.mailer.host, + secure: config.mailer.secureConnection, + port: config.mailer.port, + requireTLS: config.mailer.TLS, + auth: { + type: 'custom', + method: 'NTLM', + user: config.mailer.authUser, + pass: config.mailer.authPass, + options: { + domain: 'ad' + } + }, + customAuth:{ + NTLM: nodemailerNTLMAuth + } +}); + +var mailOptions:any = { + to: "", + cc: "", + from: config.mailer.from, + subject: "", + text: "", + html: "" +} + +var mailer:any = { + transporter: smtpTransporter, + options: mailOptions +} + +export = mailer \ No newline at end of file diff --git a/functions/gitlab.js b/functions/gitlab.ts similarity index 58% rename from functions/gitlab.js rename to functions/gitlab.ts index 62ff3650..5924afd1 100644 --- a/functions/gitlab.js +++ b/functions/gitlab.ts @@ -1,13 +1,12 @@ +import axios from 'axios' +import fs from 'fs' +import formData from 'form-data' + var env = process.env.NODE_ENV || 'testing' const config = require('../config/config')[env] -const axios = require('axios') -const fs = require('fs') -var formData = require('form-data') var gitlab = { - // todo: GraphQL currentUser - - getUserByEmail: async function(email) { + getUserByEmail: async function(email:string) { return axios({ method: 'get', url: 'https://transfer.hft-stuttgart.de/gitlab/api/v4/users?search='+email, @@ -15,9 +14,12 @@ var gitlab = { 'Authorization': 'Bearer '+config.gitlab.token_readWriteProjects} }) .then(res => res.data[0]) - .catch(err => console.error(err)) + .catch(function(err){ + console.error(err) + return null + }) }, - createNewPages: async function(newPagesData, newLogoFile, template) { + createNewPages: async function(newPagesData:any, newLogoFile:string, template:any) { let data = new formData() data.append('avatar', fs.createReadStream(newLogoFile)) @@ -32,16 +34,15 @@ var gitlab = { }, data: data }) - .then(res => res = { - error: false, - data: res.data - }) - .catch(err => res = { - error: true, - data: err.response.data + .then(res => res.data) + .catch(function(err) { + console.error("ERR Status: "+err.response.status) + console.error("ERR Name: "+err.response.data.message.name) + console.error("ERR Path: "+err.response.data.message.path) + return err.response }) }, - updateProject: async function(updatedProjectData, newLogoFile){ + updateProject: async function(updatedProjectData:any, newLogoFile:string){ let data = new formData() if (newLogoFile) { data.append('avatar', fs.createReadStream(newLogoFile)) @@ -57,16 +58,16 @@ var gitlab = { }, data : data }) - .then(res => res = { - error: false, - data: res.data - }) - .catch(err => res = { - error: true, - data: err.response.data + //.then(res => res.data[0]) + .then(res => res.data) + .catch(function(err){ + console.error("ERR Status: "+err.response.status) + console.error("ERR Name: "+err.response.data.message.name) + console.error("ERR Path: "+err.response.data.message.path) + return err.response }) }, - deleteProjectById: function(projectId){ + deleteProjectById: function(projectId:number){ // https://docs.gitlab.com/ee/api/projects.html#delete-project return axios({ method: 'delete', @@ -75,16 +76,15 @@ var gitlab = { 'Authorization': 'Bearer '+config.gitlab.token_readWriteProjects } }) - .then(res => res = { - error: false, - data: res.data - }) - .catch(err => res = { - error: true, - data: err.response.data + .then(res => true) + .catch(function(err) { + console.error("ERR Status: "+err.response.status) + console.error("ERR Name: "+err.response.data.message.name) + console.error("ERR Path: "+err.response.data.message.path) + return false }) }, - getUserProjects: async function(gitlabUserId) { + getUserProjects: async function(gitlabUserId:number) { return axios({ method: 'get', url: 'https://transfer.hft-stuttgart.de/gitlab/api/v4/users/'+gitlabUserId+'/projects?owned=true&visibility=public', @@ -93,9 +93,12 @@ var gitlab = { } }) .then(res => res.data) - .catch(err => console.error(err)) + .catch(function(err) { + console.error(err) + return null + }) }, - getProjectById: async function(projectId) { + getProjectById: async function(projectId:number) { return axios({ method: 'get', url: 'https://transfer.hft-stuttgart.de/gitlab/api/v4/projects/'+projectId, @@ -104,45 +107,22 @@ var gitlab = { } }) .then(res => res.data) - .catch(err => console.error(err.response.status)) + .catch(function(err) { + console.error(err) + return null + }) }, - getProjectPipelineLatestStatus: async function(projectId) { + getProjectPipelineLatestStatus: async function(projectId:number) { return axios({ method: 'get', url: 'https://transfer.hft-stuttgart.de/gitlab/api/v4/projects/'+projectId+'/pipelines' }) .then(res => res.data[0].status) - .catch(err => console.error(err)) - }, - // - // test GraphQL - getGraphqlTest: function(callback) { - axios({ - url: 'https://gitlab.com/api/graphql', - method: 'get', - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer '+config.gitlab.token_readWriteProjects - }, - data: { - query: `{ - currentUser { - id - username - } - }` - /* query: `{ - projects { - nodes { - id - } - } - }` */ - } - }).then((result) => { - console.log(JSON.stringify(result.data)) - }); + .catch(function(err) { + console.error(err) + return null + }) } } -module.exports = gitlab \ No newline at end of file +export = gitlab \ No newline at end of file diff --git a/functions/helpers.js b/functions/helpers.ts similarity index 69% rename from functions/helpers.js rename to functions/helpers.ts index 4645aec7..1c3451fc 100644 --- a/functions/helpers.js +++ b/functions/helpers.ts @@ -1,5 +1,5 @@ var helpers = { - stringToArray: function (input){ + stringToArray: function (input:string){ if(input != null){ return input.split(','); }else{ @@ -8,4 +8,4 @@ var helpers = { } }; -module.exports = helpers; \ No newline at end of file +export = helpers; \ No newline at end of file diff --git a/functions/methods.js b/functions/methods.ts similarity index 56% rename from functions/methods.js rename to functions/methods.ts index 0037a7e1..16143b85 100644 --- a/functions/methods.js +++ b/functions/methods.ts @@ -1,57 +1,55 @@ -const dbconn_OBSOLETE = require('../config/dbconn') // DO NOT USE THIS FOR NEW FUNCTIONS -const dbconn = require('../config/dbconn2') +import dbconn_OBSOLETE = require('../config/dbconn') // DO NOT USE THIS FOR NEW FUNCTIONS +import dbconn = require('../config/dbconn2') 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_OBSOLETE.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_OBSOLETE.user.query('INSERT INTO user SET ?', data.profile, function (err:any, results:any, fields:any) { if (err) { return dbconn_OBSOLETE.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_OBSOLETE.user.query('INSERT INTO credential SET ?', credentialData, function (err:any, results:any, fields:any) { if (err) { return dbconn_OBSOLETE.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_OBSOLETE.user.query('INSERT INTO user_project_role SET ?', projectRoleData, function (err:any, results:any, fields:any) { if (err) { return dbconn_OBSOLETE.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_OBSOLETE.user.query('INSERT INTO verification SET ?', verificationData, function (err:any, results:any, fields:any) { if (err) { return dbconn_OBSOLETE.user.rollback(function() { throw err }); } // COMMIT - dbconn_OBSOLETE.user.commit(function(err) { + dbconn_OBSOLETE.user.commit(function(err:any) { if (err) { return dbconn_OBSOLETE.user.rollback(function() { throw err @@ -65,9 +63,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 +75,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 +87,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 +99,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 +112,38 @@ 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) - }) + 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 }, - 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) - }); + 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 }, - 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) { + addUserProjectRole_OBSOLETE: function(data:any, callback:any) { + /* + dbconn_OBSOLETE.user.query('INSERT INTO user_project_role SET ?', data, function (err:any, results:any, fields:any){ if (err) throw err - callback(rows, err) - }); - }, - addUserProjectRole: function(data, callback) { - dbconn_OBSOLETE.user.query('INSERT INTO user_project_role SET ?', data, function (err, results, fields){ + callback(err) + }) */ + 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 +153,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,21 +167,21 @@ var methods = { } return null }, - verifyUserAccount: function(userData, callback) { - dbconn_OBSOLETE.user.beginTransaction(function(err) { // START TRANSACTION + verifyUserAccount: function(userData:any, callback:any) { + dbconn_OBSOLETE.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_OBSOLETE.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 }) } // delete verification token - dbconn_OBSOLETE.user.query('DELETE FROM verification WHERE user_id = '+userData.id, function (err, rows, fields) { + dbconn_OBSOLETE.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 }) } // COMMIT - dbconn_OBSOLETE.user.commit(function(err) { + dbconn_OBSOLETE.user.commit(function(err:any) { if (err) { return dbconn_OBSOLETE.user.rollback(function() { throw err }) } @@ -203,9 +192,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 +206,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/public/js/jquery-ui/i18n/datepicker-de.js b/public/js/jquery-ui/i18n/datepicker-de.js deleted file mode 100644 index e2e61d27..00000000 --- a/public/js/jquery-ui/i18n/datepicker-de.js +++ /dev/null @@ -1,37 +0,0 @@ -/* German initialisation for the jQuery UI date picker plugin. */ -/* Written by Milian Wolff (mail@milianw.de). */ -( function( factory ) { - if ( typeof define === "function" && define.amd ) { - - // AMD. Register as an anonymous module. - define( [ "../widgets/datepicker" ], factory ); - } else { - - // Browser globals - factory( jQuery.datepicker ); - } -}( function( datepicker ) { - -datepicker.regional.de = { - closeText: "Schließen", - prevText: "<Zurück", - nextText: "Vor>", - currentText: "Heute", - monthNames: [ "Januar","Februar","März","April","Mai","Juni", - "Juli","August","September","Oktober","November","Dezember" ], - monthNamesShort: [ "Jan","Feb","Mär","Apr","Mai","Jun", - "Jul","Aug","Sep","Okt","Nov","Dez" ], - dayNames: [ "Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag" ], - dayNamesShort: [ "So","Mo","Di","Mi","Do","Fr","Sa" ], - dayNamesMin: [ "So","Mo","Di","Mi","Do","Fr","Sa" ], - weekHeader: "KW", - dateFormat: "dd.mm.yy", - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: "" }; -datepicker.setDefaults( datepicker.regional.de ); - -return datepicker.regional.de; - -} ) ); \ No newline at end of file diff --git a/routes/account.js b/routes/account.js deleted file mode 100644 index 0f3b2fc7..00000000 --- a/routes/account.js +++ /dev/null @@ -1,568 +0,0 @@ -const fs = require('fs') -const SamlStrategy = require('passport-saml').Strategy -const dbconn = require('../config/dbconn') -const methods = require('../functions/methods') -const gitlab = require('../functions/gitlab') -const constants = require('../config/const') -// pwd encryption -const bcrypt = require('bcryptjs'); -const saltRounds = 10; -const salt = 64; // salt length -// forgot pwd -const async = require('async') -const crypto = require('crypto') -const mailer = require('../config/mailer') -const logoDir = 'public/upload/' -const defaultLogo = 'public/default/logo.png' -const tpGitlabURL = 'https://transfer.hft-stuttgart.de/gitlab/' -const tpGitlabPagesURL = 'https://transfer.hft-stuttgart.de/pages/' - -const portalUser = require('../classes/user') -const projectInformation = require('../classes/website') -const projectRepo = require('../classes/repo') - -module.exports = function (app, config, passport, lang) { - - // =========== PASSPORT ======= - passport.serializeUser(function (user, done) { - done(null, user); - }); - - passport.deserializeUser(function (user, done) { - 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: null, - - // Service Provider private key - decryptionPvk: fs.readFileSync(__dirname + '/cert/key.pem', 'utf8'), - // Service Provider Certificate - privateCert: 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, done) { - 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, res) { - res.redirect('/account/'); - } - ); - - // to generate Service Provider's XML metadata - app.get('/saml/metadata', - function(req, res) { - 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) { - 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, null, user.verificationStatus - ) - - let userGitlabId = await methods.getGitlabId(loggedInUser.id) - if (userGitlabId) { - loggedInUser.setGitlabUserId(userGitlabId) - } - return loggedInUser - } - } - - app.get('/', async function (req, res) { - 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, res) { - 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, uri) { - req.logout(); - - if ( req.session ) { - req.session.destroy((err) => { - if(err) { - return console.log(err); - } - }); - } - - return res.redirect(uri); - }); - }); - - app.get('/profile', async function (req, res) { - if ( !req.isAuthenticated() ) { - res.redirect('/login') - } else { - let loggedInUser = await getLoggedInUserData(req.user.email) - if(loggedInUser.getVerificationStatus() != 1) { - res.redirect('/account/') - } else { - res.render(lang+'/account/profile', { - user: loggedInUser - }) - } - } - }) - - app.get('/services', async function(req, res){ - if( !req.isAuthenticated() ) { - res.redirect('/login') - } else { - let loggedInUser = await getLoggedInUserData(req.user.email) - 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" }) - } - - for (project in userProjects) { - if (userProjects[project].tag_list.includes('website')) { - let page = { - projectInformation: new projectInformation(loggedInUser.getGitlabUserId(), userProjects[project].id, userProjects[project].name, - userProjects[project].description, 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].id, userProjects[project].name, - userProjects[project].description, 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} - // RS: update to await? - methods.addGitlabUser(gitlabActivationData, function(err){ - if(err) { - res.status(500).render(lang+'/500', { error: err }) - } else { - res.redirect('/account/services') - } - }) - } - } - } - } - }) - - app.get('/security', async function (req, res) { - if ( !req.isAuthenticated() ) { - res.redirect('/login') - } else { - let loggedInUser = await getLoggedInUserData(req.user.email) - if(loggedInUser.getVerificationStatus() == 1 && loggedInUser.getIdpStatus() == 1) { - res.render(lang+'/account/security', { - user: loggedInUser - }) - } else { - res.redirect('/account/') - } - } - }) - - app.post('/updateProfile', async function (req, res) { - var 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, - } - - if ( !req.isAuthenticated() ) { - res.redirect('/login') - } else { - let loggedInUser = await getLoggedInUserData(req.user.email) - if (userData.email) { - dbconn.user.query('UPDATE user SET ? WHERE email = "' +userData.email+'"', userData, function (err, rows, fields) { - if (err) { - 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('/changePwd', async function (req, res) { - if( !req.isAuthenticated() ) { - res.redirect('/login') - } else { - let loggedInUser = await getLoggedInUserData(req.user.email) - - var currPwd = req.body.inputCurrPwd - var newPwd = req.body.inputNewPwd - var retypePwd = req.body.inputConfirm - - // update - get userId from loggedInUser - dbconn.user.query('SELECT password FROM credential WHERE user_id='+loggedInUser.getId(), function (err, rows, fields) { - if (err) { - console.error(err) - res.status(500).render(lang+'/500', { error: err }) - } - var 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, function(err, hash) { - var credentialData = { - password: hash, - user_id: userId - } - methods.updateCredential(credentialData, function(err){ - if (err) { - res.flash('error', "Datenbankfehler: Passwort kann nicht geändert werden.") - throw err - } else { - res.flash('success', "Passwort aktualisiert!") - mailer.options.to = req.user.email - mailer.options.subject = constants.updatePasswordMailSubject - mailer.options.html = constants.updatePasswordMailContent+'
'+constants.mailSignature+'
' - mailer.transport.sendMail(mailer.options, function(err) { - if (err) { console.log(err) } - }); - } - res.redirect('/account/security') - }) - }); - }); - } - } - }) - }) - } - }); - - app.get('/resendVerificationEmail', async function(req, res){ - 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 = '
Lieber Nutzer,

' + - '

vielen Dank für Ihre Anmeldung am Transferportal der HFT Stuttgart.
' + - 'Um Ihre Anmeldung zu bestätigen, klicken Sie bitte diesen Link: ' + config.app.host + '/verifyAccount?token=' + token + - '

' + - 'Ohne Bestätigung Ihres Kontos müssen wir Ihr Konto leider nach 7 Tagen löschen.


' + constants.mailSignature + - '
'; - mailer.options.to = loggedInUser.email; - mailer.options.subject = emailSubject; - mailer.options.html = emailContent; - mailer.transport.sendMail(mailer.options, function(err) { - if (err) { - console.log('cannot send email') - throw err - } - }) - res.send(true) - } - } - } - }) - - // ============= NEW GITLAB PAGES =========================== - - app.get('/newInformation', async function(req, res){ - if ( !req.isAuthenticated() ) { - res.redirect('/login') - } else { - let loggedInUser = await getLoggedInUserData(req.user.email) - 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, res) { - if( !req.isAuthenticated() ) { - res.redirect('/login') - } else { - let loggedInUser = await getLoggedInUserData(req.user.email) - - 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(), null, projectName, projectDesc, null, null) - let newLogoFile = defaultLogo - - if (req.files) { newLogoFile = req.files.logo } - - async.waterfall([ - function(callback){ // upload logo - if (!req.files) { - callback(null, newLogoFile) - } else { - newLogoFile.mv(logoDir + newLogoFile.name, function(err) { - newLogoFile = logoDir+newLogoFile.name - callback(err, newLogoFile) - }) - } - }, - async function(newLogoFile){ // create a new GitLab Page - let newPages = await gitlab.createNewPages(newInformation, newLogoFile, projectTemplate) - if (newPages.error) { - 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 { - let newPagesData = newPages.data - - 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.flash("success", "Your website will be published AFTER you complete your website by following the provided guideline below."+ - "\r\n Your website URL: "+tpGitlabPagesURL+newPagesData.path_with_namespace+"/home/") */ - res.redirect('/account/updateInformation?id='+newPagesData.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, res){ - if( !req.isAuthenticated() ) { - res.redirect('/login') - } else { - let loggedInUser = await getLoggedInUserData(req.user.email) - - 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(), req.query.id, project.name, project.description, - 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, res){ - if( !req.isAuthenticated() ) { - res.redirect('/login') - } else { - let loggedInUser = await getLoggedInUserData(req.user.email) - - 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(), req.query.id, projectName, projectDesc, null, null) - let newLogoFile - - async.waterfall([ - function(callback){ // upload logo - if(!req.files) { - callback(null, newLogoFile) - } else { - newLogoFile = req.files.logo - newLogoFile.mv(logoDir + newLogoFile.name, function(err) { - newLogoFile = logoDir + newLogoFile.name - callback(err, newLogoFile) - }) - } - }, - async function(newLogoFile, callback){ // update gitlab page - let updatedPages = await gitlab.updateProject(updatedInformation, newLogoFile) - let pagesData = updatedPages.data - if (updatedPages.error) { - if(pagesData.message.name == "has already been taken") { - res.flash("error", "Der Projektname 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(pagesData.avatar_url) - updatedInformation.setPath(pagesData.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, res){ - console.log("delete project") - - if( !req.isAuthenticated() ) { - res.redirect('/login') - } else { - let loggedInUser = await getLoggedInUserData(req.user.email) - 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 { - // delete project - let project = await gitlab.deleteProjectById(projectId) - if (project.error) { - res.flash("error", "Project cannot be deleted. Please try again.") - } - } - } - res.redirect('/account/services') - } - }) - -} \ No newline at end of file diff --git a/routes/account.ts b/routes/account.ts new file mode 100644 index 00000000..da1b2fb9 --- /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 + privateCert: 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, rows, fields) { + if (err) { + console.error(err) + res.status(500).render(lang+'/500', { error: err }) + } + var 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+'
'+constants.mailSignature+'
' + 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 = '
Lieber Nutzer,

' + + '

vielen Dank für Ihre Anmeldung am Transferportal der HFT Stuttgart.
' + + 'Um Ihre Anmeldung zu bestätigen, klicken Sie bitte diesen Link: ' + config.app.host + '/verifyAccount?token=' + token + + '

' + + 'Ohne Bestätigung Ihres Kontos müssen wir Ihr Konto leider nach 7 Tagen löschen.


' + constants.mailSignature + + '
'; + 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 diff --git a/routes/public.js b/routes/public.js deleted file mode 100644 index e6cd132a..00000000 --- a/routes/public.js +++ /dev/null @@ -1,296 +0,0 @@ -const methods = require('../functions/methods') -const async = require('async') -const mailer = require('../config/mailer') -const constants = require('../config/const') -// pwd encryption -const crypto = require('crypto') -const bcrypt = require('bcryptjs') -const saltRounds = 10 -const salt = 64 - -module.exports = function (app, config, lang) { - - // ================== NEW USERS REGISTRATION ====================== - - app.get('/registration', function(req, res) { - res.render(lang+'/account/registration') - }) - app.post('/registration', function(req, res) { - // user data - var curDate = new Date() - var 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, - createdDate: curDate.toISOString().slice(0,10) - } - - var userEmail = userData.email - var pos = userEmail.indexOf('@') - var emailLength = userEmail.length - var emailDomain = userEmail.slice(pos, emailLength); - - if ( emailDomain.toLowerCase() == "@hft-stuttgart.de") { - res.flash('error', "Fehlgeschlagen: HFT-Account") - res.redirect('/account/registration') - } else { - let token - async.waterfall([ - function(done) { - crypto.randomBytes(20, function(err, buf) { - token = buf.toString('hex'); - done(err, token); - }); - }, - // encrypt password - function(token, done) { - bcrypt.genSalt(saltRounds, function(err, salt) { - bcrypt.hash(req.body.inputPassword, salt, function(err, hash) { - var newAccount = { - profile: userData, - password: hash, - verificationToken: token - } - done(err, newAccount) - }); - }); - }, - // save data - function(newAccount, err) { - methods.registerNewUser(newAccount, function(err){ - if (err) { - res.flash('error', "Fehlgeschlagen") - } - else { - // send email - var emailSubject = "Bitte bestätigen Sie Ihr M4_LAB Benutzerkonto" - var emailContent = '
Lieber Nutzer,

' + - '

vielen Dank für Ihre Anmeldung am Transferportal der HFT Stuttgart.
' + - 'Um Ihre Anmeldung zu bestätigen, klicken Sie bitte diesen Link ' + - '

' + - 'Ohne Bestätigung Ihres Kontos müssen wir Ihr Konto leider nach 7 Tagen löschen.


' + constants.mailSignature + - '
'; - mailer.options.to = req.body.inputEmail; - mailer.options.subject = emailSubject; - mailer.options.html = emailContent; - mailer.transport.sendMail(mailer.options, function(err) { - if (err) { - console.error('cannot send email') - throw err - } - }) - // user feedback - res.flash('success', 'Vielen Dank für Ihre Registrierung!'+'\r\n\r\n'+ - 'Wir haben Ihnen eine E-Mail an Ihre verwendete Adresse gesendet. Diese enthält einen Link zur Bestätigung Ihres Accounts.'+'\r\n'+ - 'Wenn Sie die Mail nicht in ihrem Postfach vorfinden, prüfen Sie bitte auch Ihren Spam-Ordner.') - } - res.redirect('/account/registration') - }) - } - ]) - } - }) - - // =================== USERS VERIFICATION ========================= - - app.get("/verifyAccount", async function(req, res){ - let userId = await methods.getUserIdByVerificationToken(req.query.token) - if (!userId) { - // no user found - res.render(lang+'/account/verification', { - status: null - }) - } else { - // a user found, verify the account - let userData = { - id: userId, - verificationStatus: 1 - } - methods.verifyUserAccount(userData, async function(err){ - if (err) { - console.log("Error: "+err) - res.render(lang+'/account/verification', { - status: false - }); - } else { - // send welcome email after successful account verification - let userEmail = await methods.getUserEmailById(userId) - if (!userEmail) { - res.render(lang+'/account/verification', { - status: false - }) - } else { - // send email - var emailSubject = "Herzlich willkommen" - var emailContent = '
Lieber Nutzer,

' + - '

herzlich willkommen beim Transferportal der HFT Stuttgart!
' + - 'Sie können nun alle Dienste des Portals nutzen.


' + constants.mailSignature; - mailer.options.to = userEmail - mailer.options.subject = emailSubject - mailer.options.html = emailContent - mailer.transport.sendMail(mailer.options, function(err) { - if (err) { - console.log('cannot send email') - throw err - } - }) - - res.render(lang+'/account/verification', { - status: true - }) - } - } - }) - } - }) - - // ==================== FORGOT PASSWORD =========================== - - app.get('/forgotPwd', function (req, res) { - res.render(lang+'/account/forgotPwd', { - user: req.user - }) - }) - app.post('/forgotPwd', function(req, res) { - let emailAddress = req.body.inputEmail - async.waterfall([ - function(done) { - crypto.randomBytes(20, function(err, buf) { - var token = buf.toString('hex') - done(err, token) - }) - }, - async function(token) { - let user = await methods.checkUserEmail(emailAddress) - if (!user) { - console.log('no user found') - } else { - var emailSubject = "Ihre Passwort-Anfrage an das Transferportal der HFT Stuttgart"; - var emailContent = '

Lieber Nutzer,

' + - '

wir haben Ihre Anfrage zur Erneuerung Ihres Passwortes erhalten. Falls Sie diese Anfrage nicht gesendet haben, ignorieren Sie bitte diese E-Mail.

' + - 'Sie können Ihr Passwort mit dem Klick auf diesen Link ändern: '+config.app.host+'/reset/' + token + '
' + - 'Dieser Link ist aus Sicherheitsgründen nur für 1 Stunde gültig.

' + constants.mailSignature + '
' - - var credentialData = { - user_id: user.id, - resetPasswordToken: token, - resetPasswordExpires: Date.now() + 3600000 // 1 hour - } - methods.updateCredential(credentialData, function(err) { - if (err) { console.error(err) } - }) - - // send email - mailer.options.to = emailAddress - mailer.options.subject = emailSubject - mailer.options.html = emailContent - mailer.transport.sendMail(mailer.options, function(err) { - if (err) { console.error(err) } - }) - } - } - ], function(err) { - if (err) { - res.flash('error', 'Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut.') - } - else { - res.flash('success', 'Wenn Ihre E-Mail-Adresse registriert ist, wurde eine E-Mail mit dem weiteren Vorgehen an ' + emailAddress + ' versendet.') - } - res.redirect('/account/forgotPwd') - }) - }) - - // reset - app.get('/reset/:token', async function(req, res) { - let user = await methods.getUserByToken(req.params.token) - if (!user) { - res.flash('error', 'Der Schlüssel zum zurücksetzen des Passworts ist ungültig oder abgelaufen.') - res.redirect('/account/forgotPwd') - } else { - res.render(lang+'/account/reset') - } - }) - app.post('/reset/:token', async function(req, res) { - var newPwd = req.body.inputNewPwd - - let user = await methods.getUserByToken(req.params.token) - if (!user) { - res.flash('error', "User not found.") - res.redirect('/login') - } else { - // encrypt password - bcrypt.genSalt(saltRounds, function(err, salt) { - bcrypt.hash(newPwd, salt, function(err, hash) { - var credentialData = { - password: hash, - user_id: user.user_id - } - // update password - methods.updateCredential(credentialData, function(err){ - if (err) { - res.flash('error', "Datenbankfehler: Passwort kann nicht geändert werden.") - throw err - } else { - res.flash('success', "Passwort aktualisiert!") - - // send notifiaction email - mailer.options.to = user.email - mailer.options.subject = constants.updatePasswordMailSubject - mailer.options.html = constants.updatePasswordMailContent+'
'+constants.mailSignature+'
' - mailer.transport.sendMail(mailer.options, function(err) { - if (err) { console.log(err) } - }) - - res.redirect('/login') - } - }) - }); - }); - } - - }) - - // ======================= CONTACT FORM =========================== - - app.get('/contact', function (req, res) { - res.render(lang+'/account/contact', { - user: req.user - }) - }) - app.post('/contact', function(req, res, next) { - //methods.currentDate(); - let emailAddress = req.body.inputEmail; - let supportAddress = "support-transfer@hft-stuttgart.de"; - let inputName = req.body.name; - let inputContent = req.body.message; - let emailContent = "Es wurde eine Anfrage an das Transferportal gestellt: \n\n NAME: " + inputName + "\n NACHRICHT:\n "+ inputContent; - let emailSubject = "Ihre Anfrage an das Transferportal"; - async.waterfall([ - function(done) { - // send email - mailer.options.to = supportAddress; - mailer.options.cc = emailAddress; - mailer.options.subject = emailSubject; - mailer.options.text = emailContent; - mailer.transport.sendMail(mailer.options, function(err) { - done(err, 'done'); - }); - } - ], function(err) { - if (err) { - console.error(err) - res.flash('error', 'Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut.'); - } - else { - res.flash('success', 'Vielen Dank für Ihre Anfrage. Wir melden uns baldmöglichst bei Ihnen. Eine Kopie Ihrer Anfrage wurde an ' + emailAddress + ' versandt.'); - } - res.redirect('/account/contact') - }) - }) - -} \ No newline at end of file diff --git a/routes/public.ts b/routes/public.ts new file mode 100644 index 00000000..a5c7bd13 --- /dev/null +++ b/routes/public.ts @@ -0,0 +1,292 @@ +import async from 'async' +import bcrypt from 'bcryptjs' +import methods from '../functions/methods' +import mailer from '../config/mailer' +import constants from '../config/const' + +const saltRounds:number = 10 +const salt:number = 64 + +export = function (app:any, config:any, lang:string) { + + // ================== NEW USERS REGISTRATION ====================== + app.get('/registration', function(req:any, res:any) { + res.render(lang+'/account/registration') + }) + app.post('/registration', function(req:any, res:any) { + // user data + var curDate:Date = new Date() + var userData:any = { + 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, + createdDate: curDate.toISOString().slice(0,10) + } + + var userEmail:any = userData.email + var pos:number = userEmail.indexOf('@') + var emailLength:number = userEmail.length + var emailDomain:any = userEmail.slice(pos, emailLength); + + if ( emailDomain.toLowerCase() == "@hft-stuttgart.de") { + res.flash('error', "Fehlgeschlagen: HFT-Account") + res.redirect('/account/registration') + } else { + async.waterfall([ + function(done:any) { + // generate token + let token:string = ''; + let randomChars:string = 'abcdefghijklmnopqrstuvwxyz0123456789'; + for ( let i = 0; i<40; i++ ) { + token += randomChars.charAt(Math.floor(Math.random() * randomChars.length)); + } + // encrypt password + bcrypt.genSalt(saltRounds, function(err, salt) { + bcrypt.hash(req.body.inputPassword, salt, function(err:any, hash:any) { + var newAccount:any = { + profile: userData, + password: hash, + verificationToken: token + } + done(err, newAccount) + }); + }); + }, + // save data + function(newAccount:any, err:any) { + methods.registerNewUser(newAccount, function(err:any){ + if (err) { + res.flash('error', "Fehlgeschlagen") + } + else { + // send email + var emailSubject = "Bitte bestätigen Sie Ihr M4_LAB Benutzerkonto" + var emailContent = '
Lieber Nutzer,

' + + '

vielen Dank für Ihre Anmeldung am Transferportal der HFT Stuttgart.
' + + 'Um Ihre Anmeldung zu bestätigen, klicken Sie bitte diesen Link ' + + '

' + + 'Ohne Bestätigung Ihres Kontos müssen wir Ihr Konto leider nach 7 Tagen löschen.


' + constants.mailSignature + + '
'; + mailer.options.to = req.body.inputEmail; + mailer.options.subject = emailSubject; + mailer.options.html = emailContent; + mailer.transporter.sendMail(mailer.options, function(err:any) { + if (err) { + console.error('Cannot send email. [Error] '+err) + throw err + } + }) + // user feedback + res.flash('success', 'Vielen Dank für Ihre Registrierung!'+'\r\n\r\n'+ + 'Wir haben Ihnen eine E-Mail an Ihre verwendete Adresse gesendet. Diese enthält einen Link zur Bestätigung Ihres Accounts.'+'\r\n'+ + 'Wenn Sie die Mail nicht in ihrem Postfach vorfinden, prüfen Sie bitte auch Ihren Spam-Ordner.') + } + res.redirect('/account/registration') + }) + } + ]) + } + }) + + // =================== USERS VERIFICATION ========================= + + app.get("/verifyAccount", async function(req:any, res:any){ + let userId:number = await methods.getUserIdByVerificationToken(req.query.token) + if (!userId) { + // no user found + res.render(lang+'/account/verification', { + status: null + }) + } else { + // a user found, verify the account + let userData:any = { + id: userId, + verificationStatus: 1 + } + methods.verifyUserAccount(userData, async function(err:any){ + if (err) { + console.log("Error: "+err) + res.render(lang+'/account/verification', { + status: false + }); + } else { + // send welcome email after successful account verification + let userEmail:string = await methods.getUserEmailById(userId) + if (!userEmail) { + res.render(lang+'/account/verification', { + status: false + }) + } else { + // send email + var emailSubject = "Herzlich willkommen" + var emailContent = '
Lieber Nutzer,

' + + '

herzlich willkommen beim Transferportal der HFT Stuttgart!
' + + 'Sie können nun alle Dienste des Portals nutzen.


' + constants.mailSignature; + mailer.options.to = userEmail + mailer.options.subject = emailSubject + mailer.options.html = emailContent + mailer.transporter.sendMail(mailer.options, function(err:any) { + if (err) { + console.log('cannot send email') + throw err + } + }) + + res.render(lang+'/account/verification', { + status: true + }) + } + } + }) + } + }) + + // ==================== FORGOT PASSWORD =========================== + + app.get('/forgotPwd', function (req:any, res:any) { + res.render(lang+'/account/forgotPwd', { + user: req.user + }) + }) + app.post('/forgotPwd', function(req:any, res:any) { + let emailAddress = req.body.inputEmail + async.waterfall([ + async function(done:any) { + let user = await methods.checkUserEmail(emailAddress) + if (!user) { + console.log('No user found: '+emailAddress) + } else { + // generate token + let token:string = ''; + let randomChars:string = 'abcdefghijklmnopqrstuvwxyz0123456789'; + for ( let i = 0; i<40; i++ ) { + token += randomChars.charAt(Math.floor(Math.random() * randomChars.length)); + } + + var emailSubject = "Ihre Passwort-Anfrage an das Transferportal der HFT Stuttgart"; + var emailContent = '

Lieber Nutzer,

' + + '

wir haben Ihre Anfrage zur Erneuerung Ihres Passwortes erhalten. Falls Sie diese Anfrage nicht gesendet haben, ignorieren Sie bitte diese E-Mail.

' + + 'Sie können Ihr Passwort mit dem Klick auf diesen Link ändern: '+config.app.host+'/reset/' + token + '
' + + 'Dieser Link ist aus Sicherheitsgründen nur für 1 Stunde gültig.

' + constants.mailSignature + '
' + + var credentialData = { + user_id: user.id, + resetPasswordToken: token, + resetPasswordExpires: Date.now() + 3600000 // 1 hour + } + let result = await methods.updateCredential(credentialData) + if (!result) { + console.log('failed to update credential') + } else { + // send email + mailer.options.to = emailAddress + mailer.options.subject = emailSubject + mailer.options.html = emailContent + mailer.transporter.sendMail(mailer.options, function(err:any) { + if (err) { console.error(err) } + }) + } + } + done(null) + } + ], function(err:any) { + if (err) { + res.flash('error', 'Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut.') + } + else { + res.flash('success', 'Wenn Ihre E-Mail-Adresse registriert ist, wurde eine E-Mail mit dem weiteren Vorgehen an ' + emailAddress + ' versendet.') + } + res.redirect('/account/forgotPwd') + }) + }) + + // reset + app.get('/reset/:token', async function(req:any, res:any) { + let user = await methods.getUserByToken(req.params.token) + if (!user) { + res.flash('error', 'Der Schlüssel zum zurücksetzen des Passworts ist ungültig oder abgelaufen.') + res.redirect('/account/forgotPwd') + } else { + res.render(lang+'/account/reset') + } + }) + app.post('/reset/:token', async function(req:any, res:any) { + var newPwd = req.body.inputNewPwd + + var user = await methods.getUserByToken(req.params.token) + if (!user) { + res.flash('error', "User not found.") + res.redirect('/login') + } else { + // encrypt password + bcrypt.genSalt(saltRounds, function(err, salt) { + bcrypt.hash(newPwd, salt, async function(err:any, hash) { + var credentialData = { + password: hash, + user_id: user.user_id + } + // update password + 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 = user.email + mailer.options.subject = constants.updatePasswordMailSubject + mailer.options.html = constants.updatePasswordMailContent+'
'+constants.mailSignature+'
' + mailer.transporter.sendMail(mailer.options, function(err:any) { + if (err) { console.log(err) } + }) + } + res.redirect('/login') + }); + }); + } + + }) + + // ======================= CONTACT FORM =========================== + app.get('/contact', function (req:any, res:any) { + res.render(lang+'/account/contact', { + user: req.user + }) + }) + app.post('/contact', function(req:any, res:any, next:any) { + //methods.currentDate(); + let emailAddress = req.body.inputEmail; + let supportAddress = "support-transfer@hft-stuttgart.de"; + let inputName = req.body.name; + let inputContent = req.body.message; + let emailContent = "Es wurde eine Anfrage an das Transferportal gestellt: \n\n NAME: " + inputName + "\n NACHRICHT:\n "+ inputContent; + let emailSubject = "Ihre Anfrage an das Transferportal"; + async.waterfall([ + function(done:any) { + // send email + mailer.options.to = supportAddress; + mailer.options.cc = emailAddress; + mailer.options.subject = emailSubject; + mailer.options.text = emailContent; + mailer.transporter.sendMail(mailer.options, function(err:any) { + done(err, 'done'); + }); + } + ], function(err:any) { + if (err) { + console.error(err) + res.flash('error', 'Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut.'); + } + else { + res.flash('success', 'Vielen Dank für Ihre Anfrage. Wir melden uns baldmöglichst bei Ihnen. Eine Kopie Ihrer Anfrage wurde an ' + emailAddress + ' versandt.'); + } + res.redirect('/account/contact') + }) + }) + +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..1519fee7 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "target": "es6", + "module": "commonjs", + "rootDir": "./", + "outDir": "./built", + "esModuleInterop": true, + "strict": true, + "allowJs": true + } +} \ No newline at end of file -- GitLab From 7acf92feede641210fdc24134e1ec522b166a57e Mon Sep 17 00:00:00 2001 From: Rosanny Date: Wed, 4 Aug 2021 17:06:10 +0200 Subject: [PATCH 5/7] update yml config --- .gitlab-ci.yml | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0d650171..f0013cb5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,13 +1,21 @@ deploy-testing: stage: deploy script: - - cat $configfiledev > ./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 $configfiledev > ./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: - testing -- GitLab From 5b85506f14b1152f0809563a4cf3b4265ae261e8 Mon Sep 17 00:00:00 2001 From: Rosanny Date: Wed, 4 Aug 2021 15:16:11 +0000 Subject: [PATCH 6/7] updating yml config (cherry picked from commit 7afdce02f952d8e407b5eb26809ec9878102a915) --- .gitlab-ci.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f0013cb5..d11d9bcd 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,12 +4,12 @@ deploy-testing: - 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 + - 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 $configfiledev > ./built/config/config.js - cat $cert > ./built/routes/cert/cert.pem - cat $certidp > ./built/routes/cert/cert_idp.pem -- GitLab From 0858e1d4fe32b5d2cf1298fb9f2edbf612ade491 Mon Sep 17 00:00:00 2001 From: Rosanny Date: Wed, 4 Aug 2021 21:39:59 +0200 Subject: [PATCH 7/7] fixing bug MLAB-539 --- routes/public.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/routes/public.ts b/routes/public.ts index a5c7bd13..43b28e8a 100644 --- a/routes/public.ts +++ b/routes/public.ts @@ -92,6 +92,17 @@ export = function (app:any, config:any, lang:string) { ]) } }) + // to check whether or not an account is already exist + app.get('/email/:email', async function(req:any, res:any) { + let user = await methods.checkUserEmail(req.params.email) + if (!user) { + console.log('No user found: '+req.params.email) + res.send(true) + } else { + console.log('User found: '+req.params.email) + res.send(false) + } + }) // =================== USERS VERIFICATION ========================= -- GitLab