From 02bf17d559b9c7a35b59cbf243fb0729bdde58f4 Mon Sep 17 00:00:00 2001 From: Mateiadrielrafael Date: Mon, 12 Aug 2019 21:12:56 +0300 Subject: [PATCH] typescript(lunargame/api): added eslint Signed-off-by: prescientmoon --- typescript/lunargame/api/.eslintrc.json | 25 + typescript/lunargame/api/.prettierrc.json | 2 +- .../lunargame/api/.vscode/settings.json | 4 +- .../api/db/migrations/create_account.js | 4 +- typescript/lunargame/api/package-lock.json | 821 +++++++++++++++++- typescript/lunargame/api/package.json | 11 +- .../lang/arrays/helpers/randomElement.test.ts | 11 +- .../api/src/modules/auth/constants.ts | 4 + .../auth/helpers/checkPassword.test.ts | 20 + .../src/modules/auth/helpers/checkPassword.ts | 21 + .../auth/helpers/encryptPassword.test.ts | 22 + .../modules/auth/helpers/encryptPassword.ts | 24 + .../modules/auth/middleware/isAuthorized.ts | 13 + .../auth/middleware/isUnauthorized.test.ts | 28 + .../modules/auth/middleware/isUnauthorized.ts | 13 + .../modules/auth/middleware/loggedIn.test.ts | 28 + .../auth/queries/createAccount.test.ts | 32 + .../src/modules/auth/queries/createAccount.ts | 15 + .../auth/queries/getPasswordByEmail.test.ts | 16 + .../auth/queries/getPasswordByEmail.ts | 26 + .../src/modules/auth/routes/authRoute.test.ts | 91 +- .../api/src/modules/auth/routes/authRoute.ts | 74 +- .../api/src/modules/auth/schemas/LoginBody.ts | 10 +- .../src/modules/auth/schemas/SignupBody.ts | 10 + .../src/modules/auth/schemas/authFields.ts | 4 +- .../api/src/modules/auth/types/Account.ts | 32 + .../modules/auth/types/LoginReponseBody.ts | 6 + .../modules/auth/types/passwordEncryption.ts | 4 + .../api/test/seeds/01_create-account.ts | 21 + .../lunargame/api/test/utils/loggedInAgent.ts | 7 +- 30 files changed, 1345 insertions(+), 54 deletions(-) create mode 100644 typescript/lunargame/api/.eslintrc.json create mode 100644 typescript/lunargame/api/src/modules/auth/constants.ts create mode 100644 typescript/lunargame/api/src/modules/auth/helpers/checkPassword.test.ts create mode 100644 typescript/lunargame/api/src/modules/auth/helpers/checkPassword.ts create mode 100644 typescript/lunargame/api/src/modules/auth/helpers/encryptPassword.test.ts create mode 100644 typescript/lunargame/api/src/modules/auth/helpers/encryptPassword.ts create mode 100644 typescript/lunargame/api/src/modules/auth/middleware/isAuthorized.ts create mode 100644 typescript/lunargame/api/src/modules/auth/middleware/isUnauthorized.test.ts create mode 100644 typescript/lunargame/api/src/modules/auth/middleware/isUnauthorized.ts create mode 100644 typescript/lunargame/api/src/modules/auth/middleware/loggedIn.test.ts create mode 100644 typescript/lunargame/api/src/modules/auth/queries/createAccount.test.ts create mode 100644 typescript/lunargame/api/src/modules/auth/queries/createAccount.ts create mode 100644 typescript/lunargame/api/src/modules/auth/queries/getPasswordByEmail.test.ts create mode 100644 typescript/lunargame/api/src/modules/auth/queries/getPasswordByEmail.ts create mode 100644 typescript/lunargame/api/src/modules/auth/schemas/SignupBody.ts create mode 100644 typescript/lunargame/api/src/modules/auth/types/Account.ts create mode 100644 typescript/lunargame/api/src/modules/auth/types/LoginReponseBody.ts create mode 100644 typescript/lunargame/api/src/modules/auth/types/passwordEncryption.ts create mode 100644 typescript/lunargame/api/test/seeds/01_create-account.ts diff --git a/typescript/lunargame/api/.eslintrc.json b/typescript/lunargame/api/.eslintrc.json new file mode 100644 index 0000000..aa811e8 --- /dev/null +++ b/typescript/lunargame/api/.eslintrc.json @@ -0,0 +1,25 @@ +{ + "parser": "@typescript-eslint/parser", + "env": { + "es6": true, + "node": true, + "jest": true + }, + "extends": [ + "plugin:@typescript-eslint/recommended", + "prettier/@typescript-eslint", + "plugin:prettier/recommended" + ], + "globals": { + "Atomics": "readonly", + "SharedArrayBuffer": "readonly" + }, + "parserOptions": { + "ecmaVersion": 2018, + "sourceType": "module" + }, + "rules": { + "@typescript-eslint/explicit-function-return-type": 0, + "@typescript-eslint/no-object-literal-type-assertion": 0 + } +} diff --git a/typescript/lunargame/api/.prettierrc.json b/typescript/lunargame/api/.prettierrc.json index 92a9ef9..ee615b2 100644 --- a/typescript/lunargame/api/.prettierrc.json +++ b/typescript/lunargame/api/.prettierrc.json @@ -1,7 +1,7 @@ { "trailingComma": "none", "singleQuote": true, - "printWidth": 80, + "printWidth": 100, "tabWidth": 4, "semi": false } diff --git a/typescript/lunargame/api/.vscode/settings.json b/typescript/lunargame/api/.vscode/settings.json index 3277f6b..9651954 100644 --- a/typescript/lunargame/api/.vscode/settings.json +++ b/typescript/lunargame/api/.vscode/settings.json @@ -2,5 +2,7 @@ "eslint.enable": true, "editor.formatOnSave": true, "prettier.eslintIntegration": true, - "explorer.autoReveal": false + "explorer.autoReveal": false, + "eslint.autoFixOnSave": true, + "eslint.validate": ["javascript", { "language": "typescript", "autoFix": true }] } diff --git a/typescript/lunargame/api/db/migrations/create_account.js b/typescript/lunargame/api/db/migrations/create_account.js index 61201d0..907d288 100644 --- a/typescript/lunargame/api/db/migrations/create_account.js +++ b/typescript/lunargame/api/db/migrations/create_account.js @@ -16,8 +16,8 @@ exports.up = knex => { // the password of the user table.text('password').notNullable() - // the password encription - table.text('password_encription').notNullable() + // the password encryption + table.text('passwordEncryption').notNullable() }) } diff --git a/typescript/lunargame/api/package-lock.json b/typescript/lunargame/api/package-lock.json index 4de6711..9b22713 100644 --- a/typescript/lunargame/api/package-lock.json +++ b/typescript/lunargame/api/package-lock.json @@ -231,6 +231,47 @@ "minimist": "^1.2.0" } }, + "@hapi/address": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.0.0.tgz", + "integrity": "sha512-mV6T0IYqb0xL1UALPFplXYQmR0twnXG0M6jUswpquqT2sD12BOiCiLy3EvMp/Fy7s3DZElC4/aPjEjo2jeZpvw==" + }, + "@hapi/hoek": { + "version": "6.2.4", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-6.2.4.tgz", + "integrity": "sha512-HOJ20Kc93DkDVvjwHyHawPwPkX44sIrbXazAUDiUXaY2R9JwQGo2PhFfnQtdrsIe4igjG2fPgMra7NYw7qhy0A==" + }, + "@hapi/joi": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-15.1.0.tgz", + "integrity": "sha512-n6kaRQO8S+kepUTbXL9O/UOL788Odqs38/VOfoCrATDtTvyfiO3fgjlSRaNkHabpTLgM7qru9ifqXlXbXk8SeQ==", + "requires": { + "@hapi/address": "2.x.x", + "@hapi/hoek": "6.x.x", + "@hapi/marker": "1.x.x", + "@hapi/topo": "3.x.x" + } + }, + "@hapi/marker": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@hapi/marker/-/marker-1.0.0.tgz", + "integrity": "sha512-JOfdekTXnJexfE8PyhZFyHvHjt81rBFSAbTIRAhF2vv/2Y1JzoKsGqxH/GpZJoF7aEfYok8JVcAHmSz1gkBieA==" + }, + "@hapi/topo": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.3.tgz", + "integrity": "sha512-JmS9/vQK6dcUYn7wc2YZTqzIKubAQcJKu2KCKAru6es482U5RT5fP1EXCPtlXpiK7PR0On/kpQKI4fRKkzpZBQ==", + "requires": { + "@hapi/hoek": "8.x.x" + }, + "dependencies": { + "@hapi/hoek": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.2.0.tgz", + "integrity": "sha512-pR2ZgiP562aiaQvQ98WgfqfTrm+xG+7hwHRPEiYZ+7U1OHAAb4OVZJIalCP03bMqYSioQzflzVTVrybSwDBn1Q==" + } + } + }, "@jest/console": { "version": "24.7.1", "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.7.1.tgz", @@ -592,6 +633,12 @@ "@types/node": "*" } }, + "@types/eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", + "dev": true + }, "@types/express": { "version": "4.17.0", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.0.tgz", @@ -613,6 +660,12 @@ "@types/range-parser": "*" } }, + "@types/faker": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/faker/-/faker-4.1.5.tgz", + "integrity": "sha512-YSDqoBEWYGdNk53xSkkb6REaUaVSlIjxIAGjj/nbLzlZOit7kUU+nA2zC2qQkIVO4MQ+3zl4Sz7aw+kbpHHHUQ==", + "dev": true + }, "@types/form-data": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-2.2.1.tgz", @@ -621,6 +674,14 @@ "@types/node": "*" } }, + "@types/hapi__joi": { + "version": "15.0.3", + "resolved": "https://registry.npmjs.org/@types/hapi__joi/-/hapi__joi-15.0.3.tgz", + "integrity": "sha512-kncvQstpAQSjQ+J+tL2oYerjOEepv+yJHKM/JD/NmFZyDcy3rYOBcMJhdHRDjBxuSZu3ipGECszhgtmug9VSuw==", + "requires": { + "@types/hapi__joi": "*" + } + }, "@types/http-assert": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/@types/http-assert/-/http-assert-1.4.1.tgz", @@ -673,6 +734,12 @@ "integrity": "sha512-6gAT/UkIzYb7zZulAbcof3lFxpiD5EI6xBeTvkL1wYN12pnFQ+y/+xl9BvnVgxkmaIDN89xWhGZLD9CvuOtZ9g==", "dev": true }, + "@types/json-schema": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.3.tgz", + "integrity": "sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A==", + "dev": true + }, "@types/keygrip": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/keygrip/-/keygrip-1.0.1.tgz", @@ -750,15 +817,6 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.10.tgz", "integrity": "sha512-LcsGbPomWsad6wmMNv7nBLw7YYYyfdYcz6xryKYQhx89c3XXan+8Q6AJ43G5XDIaklaVkK3mE4fCb0SBvMiPSQ==" }, - "@types/nodemailer": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.2.0.tgz", - "integrity": "sha512-WGGEk/BGRLuYF3gyoTwbtKg5tCexZzb5lkTsis2k7GkAzlg4x2299/SC6Ssdj3X/5TzT1BHVc8zcFg/7KSzBLw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, "@types/range-parser": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", @@ -831,6 +889,60 @@ "integrity": "sha512-SOhuU4wNBxhhTHxYaiG5NY4HBhDIDnJF60GU+2LqHAdKKer86//e4yg69aENCtQ04n0ovz+tq2YPME5t5yp4pw==", "dev": true }, + "@typescript-eslint/eslint-plugin": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.13.0.tgz", + "integrity": "sha512-WQHCozMnuNADiqMtsNzp96FNox5sOVpU8Xt4meaT4em8lOG1SrOv92/mUbEHQVh90sldKSfcOc/I0FOb/14G1g==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "1.13.0", + "eslint-utils": "^1.3.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^2.0.1", + "tsutils": "^3.7.0" + } + }, + "@typescript-eslint/experimental-utils": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-1.13.0.tgz", + "integrity": "sha512-zmpS6SyqG4ZF64ffaJ6uah6tWWWgZ8m+c54XXgwFtUv0jNz8aJAVx8chMCvnk7yl6xwn8d+d96+tWp7fXzTuDg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/typescript-estree": "1.13.0", + "eslint-scope": "^4.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-1.13.0.tgz", + "integrity": "sha512-ITMBs52PCPgLb2nGPoeT4iU3HdQZHcPaZVw+7CsFagRJHUhyeTgorEwHXhFf3e7Evzi8oujKNpHc8TONth8AdQ==", + "dev": true, + "requires": { + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "1.13.0", + "@typescript-eslint/typescript-estree": "1.13.0", + "eslint-visitor-keys": "^1.0.0" + } + }, + "@typescript-eslint/typescript-estree": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-1.13.0.tgz", + "integrity": "sha512-b5rCmd2e6DCC6tCTN9GSUAuxdYwCM/k/2wdjHGrIRGPSJotWMCe/dGpi66u42bhuh8q3QBzqM4TMA1GUUCJvdw==", + "dev": true, + "requires": { + "lodash.unescape": "4.0.1", + "semver": "5.5.0" + }, + "dependencies": { + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true + } + } + }, "abab": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz", @@ -876,6 +988,12 @@ } } }, + "acorn-jsx": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz", + "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==", + "dev": true + }, "acorn-walk": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", @@ -970,6 +1088,15 @@ "integrity": "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==", "dev": true }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, "arr-diff": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", @@ -1378,6 +1505,12 @@ "supports-color": "^5.3.0" } }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, "chokidar": { "version": "2.1.6", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz", @@ -1437,6 +1570,21 @@ "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", "dev": true }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, "cliui": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", @@ -1841,6 +1989,15 @@ "integrity": "sha512-xLqpez+Zj9GKSnPWS0WZw1igGocZ+uua8+y+5dDNTT934N3QuY1sp2LkHzwiaYQGz60hMq0pjAshdeXm5VUOEw==", "dev": true }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, "domexception": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", @@ -1884,6 +2041,12 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", @@ -1964,12 +2127,227 @@ } } }, + "eslint": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.1.0.tgz", + "integrity": "sha512-QhrbdRD7ofuV09IuE2ySWBz0FyXCq0rriLTZXZqaWSI79CVtHVRdkFuFTViiqzZhkCgfOh9USpriuGN2gIpZDQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.3.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^6.0.0", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^6.4.1", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "eslint-scope": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "glob-parent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz", + "integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "strip-json-comments": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", + "dev": true + } + } + }, + "eslint-config-prettier": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.0.0.tgz", + "integrity": "sha512-vDrcCFE3+2ixNT5H83g28bO/uYAwibJxerXPj+E7op4qzBCsAV36QfvdAyVOoNxKAH2Os/e01T/2x++V0LPukA==", + "dev": true, + "requires": { + "get-stdin": "^6.0.0" + } + }, + "eslint-plugin-prettier": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.0.tgz", + "integrity": "sha512-XWX2yVuwVNLOUhQijAkXz+rMPPoCr7WFiAl8ig6I7Xn+pPVhDhzg4DxHpmbeb0iqjO9UronEA3Tb09ChnFVHHA==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.0.tgz", + "integrity": "sha512-7ehnzPaP5IIEh1r1tkjuIrxqhNkzUJa9z3R92tLJdZIVdWaczEhr3EbhGtsMrVxi1KeR8qA7Off6SWc5WNQqyQ==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.0.0" + } + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "dev": true + }, + "espree": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.0.0.tgz", + "integrity": "sha512-lJvCS6YbCn3ImT3yKkPe0+tJ+mH6ljhGNjHQH9mRtiO6gjhVAOhVXW1yjnwqGwTkK3bGbye+hb00nFNmu0l/1Q==", + "dev": true, + "requires": { + "acorn": "^6.0.7", + "acorn-jsx": "^5.0.0", + "eslint-visitor-keys": "^1.0.0" + }, + "dependencies": { + "acorn": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", + "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==", + "dev": true + } + } + }, "esprima": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", "dev": true }, + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "dev": true, + "requires": { + "estraverse": "^4.0.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, "estraverse": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", @@ -2095,6 +2473,17 @@ } } }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, "extglob": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", @@ -2159,11 +2548,23 @@ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, + "faker": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/faker/-/faker-4.1.0.tgz", + "integrity": "sha1-HkW7vsxndLPBlfrSg1EJxtdIzD8=", + "dev": true + }, "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", @@ -2184,6 +2585,24 @@ "bser": "^2.0.0" } }, + "figures": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.0.0.tgz", + "integrity": "sha512-HKri+WoWoUgr83pehn/SIgLOMZ9nAWC6dcGj26RY2R4F50u4+RTUz0RCrUlOV3nKRAICW1UGzyb+kcX2qK1S/g==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -2242,6 +2661,23 @@ "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==" }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", + "dev": true + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -2857,6 +3293,12 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "gauge": { "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", @@ -2916,6 +3358,12 @@ "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", "dev": true }, + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + }, "get-stream": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", @@ -3231,6 +3679,12 @@ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, "ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", @@ -3246,6 +3700,24 @@ "minimatch": "^3.0.4" } }, + "import-fresh": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", + "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, "import-lazy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", @@ -3293,6 +3765,76 @@ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, + "inquirer": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.1.tgz", + "integrity": "sha512-uxNHBeQhRXIoHWTSNYUFhQVrHYFThIt6IVo2fFmSe8aBwdR3/w6b58hJpiL/fMukFkvGzjg+hSxFtwvVmKZmXw==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^2.4.2", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^4.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-escapes": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.2.1.tgz", + "integrity": "sha512-Cg3ymMAdN10wOk/VYfLV7KCQyv7EDirJ64500sU7n9UlmioEtDuU5Gd+hj73hXSU/ex7tHJSssmyftDdkMLO8Q==", + "dev": true, + "requires": { + "type-fest": "^0.5.2" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "string-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.1.0.tgz", + "integrity": "sha512-NrX+1dVVh+6Y9dnQ19pR0pP4FiEIlUvdTGn8pw6CKTNq5sgib2nIhmUNT5TAmhWmvKr3WcxBcP3E8nWezuipuQ==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^5.2.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, "interpret": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", @@ -3513,6 +4055,12 @@ "isobject": "^3.0.1" } }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, "is-redirect": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", @@ -4258,12 +4806,39 @@ "topo": "3.x.x" } }, + "joi-extract-type": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/joi-extract-type/-/joi-extract-type-15.0.0.tgz", + "integrity": "sha512-WY56yOyub9HKMyPruZ4CaL99GXHJbjdgAs1Eyt6u1GBuiLt//WMErQvPsiCSCVAZtGAKW0t+vjvdWxOnozwjCw==", + "requires": { + "@hapi/joi": ">=15", + "@types/hapi__joi": ">=15" + } + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "dependencies": { + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + } + } + }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", @@ -4325,6 +4900,12 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -4609,6 +5190,12 @@ "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", "dev": true }, + "lodash.unescape": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz", + "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=", + "dev": true + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -4843,6 +5430,12 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, "nan": { "version": "2.14.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", @@ -4956,11 +5549,6 @@ } } }, - "nodemailer": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.2.1.tgz", - "integrity": "sha512-TagB7iuIi9uyNgHExo8lUDq3VK5/B0BpbkcjIgNvxbtVrjNqq0DwAOTuzALPVkK76kMhTSzIgHqg8X1uklVs6g==" - }, "nodemon": { "version": "1.19.1", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.19.1.tgz", @@ -5163,6 +5751,15 @@ "wrappy": "1" } }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, "only": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/only/-/only-0.0.2.tgz", @@ -5354,6 +5951,15 @@ "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, "parse-filepath": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", @@ -5603,6 +6209,21 @@ "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", "dev": true }, + "prettier": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz", + "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, "pretty-format": { "version": "24.8.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.8.0.tgz", @@ -5628,6 +6249,12 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, "prompts": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.2.1.tgz", @@ -5790,6 +6417,12 @@ "safe-regex": "^1.1.0" } }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, "registry-auth-token": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", @@ -5928,6 +6561,16 @@ "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", @@ -5948,6 +6591,24 @@ "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", "dev": true }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, + "rxjs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", + "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -6114,6 +6775,17 @@ "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", "dev": true }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + } + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -6307,6 +6979,12 @@ "extend-shallow": "^3.0.0" } }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, "sqlite3": { "version": "4.0.9", "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.0.9.tgz", @@ -6465,6 +7143,70 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, + "table": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.5.tgz", + "integrity": "sha512-oGa2Hl7CQjfoaogtrOHEJroOcYILTx7BZWLGsJIlzoWmB2zmguhNfPJZsWPKYek/MgCxfco54gEi31d1uN2hFA==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, "tar": { "version": "4.4.10", "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.10.tgz", @@ -6514,6 +7256,12 @@ "require-main-filename": "^2.0.0" } }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "throat": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", @@ -6536,6 +7284,15 @@ "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", "dev": true }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, "tmpl": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", @@ -6680,6 +7437,21 @@ "yn": "^3.0.0" } }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true + }, + "tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -6702,6 +7474,12 @@ "prelude-ls": "~1.1.2" } }, + "type-fest": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.5.2.tgz", + "integrity": "sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==", + "dev": true + }, "type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -6905,6 +7683,12 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" }, + "v8-compile-cache": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", + "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", + "dev": true + }, "v8flags": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.3.tgz", @@ -7079,6 +7863,15 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, "write-file-atomic": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", diff --git a/typescript/lunargame/api/package.json b/typescript/lunargame/api/package.json index fe68fc1..14d4e0b 100644 --- a/typescript/lunargame/api/package.json +++ b/typescript/lunargame/api/package.json @@ -12,6 +12,7 @@ "devDependencies": { "@types/bcryptjs": "^2.4.2", "@types/dotenv": "^6.1.1", + "@types/faker": "^4.1.5", "@types/jest": "^24.0.17", "@types/joi": "^14.3.3", "@types/koa": "^2.0.49", @@ -20,12 +21,18 @@ "@types/koa-session": "^5.10.1", "@types/koa__cors": "^2.2.3", "@types/node": "^12.0.10", - "@types/nodemailer": "^6.2.0", "@types/supertest": "^2.0.8", "@types/uuid": "^3.4.5", + "@typescript-eslint/eslint-plugin": "^1.13.0", + "@typescript-eslint/parser": "^1.13.0", "cross-env": "^5.2.0", + "eslint": "^6.1.0", + "eslint-config-prettier": "^6.0.0", + "eslint-plugin-prettier": "^3.1.0", + "faker": "^4.1.0", "jest": "^24.8.0", "nodemon": "^1.19.1", + "prettier": "^1.18.2", "sqlite3": "^4.0.9", "ts-jest": "^24.0.2", "ts-node": "^8.3.0", @@ -37,13 +44,13 @@ "bcryptjs": "^2.4.3", "dotenv": "^8.0.0", "joi": "^14.3.1", + "joi-extract-type": "^15.0.0", "knex": "^0.18.1", "koa": "^2.7.0", "koa-bodyparser": "^4.2.1", "koa-router": "^7.4.0", "koa-session": "^5.12.0", "koa-session-knex-store": "^1.1.2", - "nodemailer": "^6.2.1", "pg": "^7.11.0", "supertest": "^4.0.2", "uuid": "^3.3.2" diff --git a/typescript/lunargame/api/src/common/lang/arrays/helpers/randomElement.test.ts b/typescript/lunargame/api/src/common/lang/arrays/helpers/randomElement.test.ts index 243a62d..84f1c6e 100644 --- a/typescript/lunargame/api/src/common/lang/arrays/helpers/randomElement.test.ts +++ b/typescript/lunargame/api/src/common/lang/arrays/helpers/randomElement.test.ts @@ -8,15 +8,8 @@ describe('The randomElement function', () => { }) test('should throw an error when passing an empty array', () => { - let error: Error | undefined - - try { + expect(() => { randomElement([]) - } catch (catchedError) { - // - error = catchedError - } - - expect(error).toBeTruthy() + }).toThrow() }) }) diff --git a/typescript/lunargame/api/src/modules/auth/constants.ts b/typescript/lunargame/api/src/modules/auth/constants.ts new file mode 100644 index 0000000..35f5919 --- /dev/null +++ b/typescript/lunargame/api/src/modules/auth/constants.ts @@ -0,0 +1,4 @@ +import { passwordEncryption } from './types/passwordEncryption' + +// i made a separate constant to prevent duplication +export const defaultEncryptionMethod: passwordEncryption = 'bcrypt' diff --git a/typescript/lunargame/api/src/modules/auth/helpers/checkPassword.test.ts b/typescript/lunargame/api/src/modules/auth/helpers/checkPassword.test.ts new file mode 100644 index 0000000..24ddc61 --- /dev/null +++ b/typescript/lunargame/api/src/modules/auth/helpers/checkPassword.test.ts @@ -0,0 +1,20 @@ +import { checkPassword } from './checkPassword' +import { passwordEncryption } from '../types/passwordEncryption' + +describe('The checkPassword helper', () => { + const pass = 'this is a test password' + + test("should throw an error if the encryption method doesn't exist", () => { + expect(() => { + checkPassword(pass, pass, '12212' as passwordEncryption) + }).toThrow() + }) + + test('should return true if the password matches the hash and the encryption = plain', () => { + expect(checkPassword(pass, pass, 'plain')).toBe(true) + }) + + test('shoud return false if the password is wrong and the encryption = plain', () => { + expect(checkPassword(pass, pass + 'something', 'plain')).toBe(false) + }) +}) diff --git a/typescript/lunargame/api/src/modules/auth/helpers/checkPassword.ts b/typescript/lunargame/api/src/modules/auth/helpers/checkPassword.ts new file mode 100644 index 0000000..bd85788 --- /dev/null +++ b/typescript/lunargame/api/src/modules/auth/helpers/checkPassword.ts @@ -0,0 +1,21 @@ +import { passwordEncryption } from '../types/passwordEncryption' +import { HttpError } from '../../network/classes/HttpError' + +/** + * Comparesa apssword with it's hash + * + * @param hash The hash of the password + * @param password The actual password + * @param encryption The encription of the password + */ +export const checkPassword = ( + hash: string, + password: string, + encryption: passwordEncryption = 'plain' +) => { + if (encryption === 'plain') { + return hash === password + } else { + throw new HttpError(400, `Encription ${encryption} doesn't exist`) + } +} diff --git a/typescript/lunargame/api/src/modules/auth/helpers/encryptPassword.test.ts b/typescript/lunargame/api/src/modules/auth/helpers/encryptPassword.test.ts new file mode 100644 index 0000000..c53cea4 --- /dev/null +++ b/typescript/lunargame/api/src/modules/auth/helpers/encryptPassword.test.ts @@ -0,0 +1,22 @@ +import { internet } from 'faker' +import { encryptPassword } from './encryptPassword' +import { compare } from 'bcryptjs' + +describe('The encryptPassword helper', () => { + test("should return the same password if the method is 'plain'", async () => { + const password = internet.password() + const hash = await encryptPassword(password, 'plain') + + expect(hash).toBe(password) + }) + + test("should return a mactching hash if the method is 'bcrypt'", async () => { + const password = internet.password() + + // the amount of rounds is small because this is just a test + const hash = await encryptPassword(password, 'bcrypt', 3) + const match = await compare(password, hash) + + expect(match).toBe(true) + }) +}) diff --git a/typescript/lunargame/api/src/modules/auth/helpers/encryptPassword.ts b/typescript/lunargame/api/src/modules/auth/helpers/encryptPassword.ts new file mode 100644 index 0000000..1832c5c --- /dev/null +++ b/typescript/lunargame/api/src/modules/auth/helpers/encryptPassword.ts @@ -0,0 +1,24 @@ +import { passwordEncryption } from '../types/passwordEncryption' +import { genSalt, hash } from 'bcryptjs' + +/** + * Encypts a string + * + * @param password The password to encrypt + * @param method The method to encrypt the password with + * @param rounds The salting rounds (for bcrypt only) + */ +export const encryptPassword = async ( + password: string, + method: passwordEncryption, + rounds = 10 +) => { + if (method === 'bcrypt') { + const salt = await genSalt(rounds) + const result = await hash(password, salt) + + return result + } else { + return password + } +} diff --git a/typescript/lunargame/api/src/modules/auth/middleware/isAuthorized.ts b/typescript/lunargame/api/src/modules/auth/middleware/isAuthorized.ts new file mode 100644 index 0000000..497cf3d --- /dev/null +++ b/typescript/lunargame/api/src/modules/auth/middleware/isAuthorized.ts @@ -0,0 +1,13 @@ +import { Middleware } from 'koa' +import { HttpError } from '../../network/classes/HttpError' + +/** + * Middlware wich throws an error if the user isn't logged in + */ +export const isAuthorized = (): Middleware => (context, next) => { + if (context.session.uid !== undefined) { + return next() + } else { + throw new HttpError(401) + } +} diff --git a/typescript/lunargame/api/src/modules/auth/middleware/isUnauthorized.test.ts b/typescript/lunargame/api/src/modules/auth/middleware/isUnauthorized.test.ts new file mode 100644 index 0000000..f332c5d --- /dev/null +++ b/typescript/lunargame/api/src/modules/auth/middleware/isUnauthorized.test.ts @@ -0,0 +1,28 @@ +import { Context } from 'koa' +import { isUnauthorized } from './isUnauthorized' + +describe('The isUnauthorized middleware', () => { + const fakeNext = () => async () => {} + + test('should throw an error if the user is logged in', () => { + const fakeContext = ({ + session: { + uid: 7 + } + } as unknown) as Context + + expect(() => isUnauthorized()(fakeContext, fakeNext())).toThrow() + }) + + test("should call next if the user isn't logged in", () => { + const fakeContext = { + session: {} + } as Context + + const next = jest.fn(fakeNext()) + + isUnauthorized()(fakeContext, next) + + expect(next).toBeCalled() + }) +}) diff --git a/typescript/lunargame/api/src/modules/auth/middleware/isUnauthorized.ts b/typescript/lunargame/api/src/modules/auth/middleware/isUnauthorized.ts new file mode 100644 index 0000000..17d3021 --- /dev/null +++ b/typescript/lunargame/api/src/modules/auth/middleware/isUnauthorized.ts @@ -0,0 +1,13 @@ +import { Middleware } from 'koa' +import { HttpError } from '../../network/classes/HttpError' + +/** + * Middleware wich throws an error if the user is logged in + */ +export const isUnauthorized = (): Middleware => (context, next) => { + if (context.session.uid === undefined) { + return next() + } else { + throw new HttpError(401) + } +} diff --git a/typescript/lunargame/api/src/modules/auth/middleware/loggedIn.test.ts b/typescript/lunargame/api/src/modules/auth/middleware/loggedIn.test.ts new file mode 100644 index 0000000..f9caf0f --- /dev/null +++ b/typescript/lunargame/api/src/modules/auth/middleware/loggedIn.test.ts @@ -0,0 +1,28 @@ +import { isAuthorized } from './isAuthorized' +import { Context } from 'koa' + +describe('The isAuthorized middleware', () => { + const fakeNext = () => async () => {} + + test("should throw an error if the user isn't logged in", () => { + const fakeContext = { + session: {} + } as Context + + expect(() => isAuthorized()(fakeContext, fakeNext())).toThrow() + }) + + test('should call next if the user is logged in', () => { + const fakeContext = ({ + session: { + uid: Math.random() + } + } as unknown) as Context + + const next = jest.fn(fakeNext()) + + isAuthorized()(fakeContext, next) + + expect(next).toBeCalled() + }) +}) diff --git a/typescript/lunargame/api/src/modules/auth/queries/createAccount.test.ts b/typescript/lunargame/api/src/modules/auth/queries/createAccount.test.ts new file mode 100644 index 0000000..b01f409 --- /dev/null +++ b/typescript/lunargame/api/src/modules/auth/queries/createAccount.test.ts @@ -0,0 +1,32 @@ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ +import { name, random, internet } from 'faker' +import { createAccount } from './createAccount' +import { connection } from '../../db/connection' +import { SignupBody } from '../schemas/SignupBody' + +describe('The createAccount query', () => { + test('should return the id of the account and add it to the db', async () => { + const email = internet.email() + const username = name.firstName() + const password = random.alphaNumeric(10) + + const result = await createAccount({ + email, + name: username, + password, + passwordEncryption: 'plain' + }) + + const account = await connection + .from('account') + .select>(['email', 'name', 'password']) + .where({ + id: result + }) + .first() + + expect(account.name).toBe(username) + expect(account.email).toBe(email) + expect(account.password).toBe(password) + }) +}) diff --git a/typescript/lunargame/api/src/modules/auth/queries/createAccount.ts b/typescript/lunargame/api/src/modules/auth/queries/createAccount.ts new file mode 100644 index 0000000..5fa70c2 --- /dev/null +++ b/typescript/lunargame/api/src/modules/auth/queries/createAccount.ts @@ -0,0 +1,15 @@ +import { connection } from '../../db/connection' +import { DbAccount } from '../types/Account' + +/** + * Saves a new user into the db + * + * @param user The user object to insert + */ +export const createAccount = async (user: DbAccount): Promise => { + const result = await connection.from('account').insert({ + ...user + }) + + return result[0] +} diff --git a/typescript/lunargame/api/src/modules/auth/queries/getPasswordByEmail.test.ts b/typescript/lunargame/api/src/modules/auth/queries/getPasswordByEmail.test.ts new file mode 100644 index 0000000..bac6ed2 --- /dev/null +++ b/typescript/lunargame/api/src/modules/auth/queries/getPasswordByEmail.test.ts @@ -0,0 +1,16 @@ +import { getPasswordByEmail } from './getPasswordByEmail' +import { mockAccounts } from '../../../../test/seeds/01_create-account' +import { connection } from '../../db/connection' + +describe('The getPasswordByName query', () => { + test('should return the correct password & encryption for a mock account', async () => { + await connection.seed.run() + + for (const account of mockAccounts) { + const result = await getPasswordByEmail(account.email) + + expect(result.password).toBe(account.password) + expect(result.passwordEncryption).toBe(account.passwordEncryption) + } + }) +}) diff --git a/typescript/lunargame/api/src/modules/auth/queries/getPasswordByEmail.ts b/typescript/lunargame/api/src/modules/auth/queries/getPasswordByEmail.ts new file mode 100644 index 0000000..0d9ed7e --- /dev/null +++ b/typescript/lunargame/api/src/modules/auth/queries/getPasswordByEmail.ts @@ -0,0 +1,26 @@ +import { connection } from '../../db/connection' +import { passwordEncryption } from '../types/passwordEncryption' + +/** + * The result of the getPasswordByName query + */ +export interface PasswordByEmailResult { + password: string + passwordEncryption: passwordEncryption + id: number +} + +/** + * Gets the password, passwordEncryption and id of an account from it's email + * + * @param email The email of the account + */ +export const getPasswordByEmail = (email: string): Promise => { + return connection + .from('account') + .select('password', 'passwordEncryption', 'id') + .where({ + email + }) + .first() +} diff --git a/typescript/lunargame/api/src/modules/auth/routes/authRoute.test.ts b/typescript/lunargame/api/src/modules/auth/routes/authRoute.test.ts index 5a68404..99a8126 100644 --- a/typescript/lunargame/api/src/modules/auth/routes/authRoute.test.ts +++ b/typescript/lunargame/api/src/modules/auth/routes/authRoute.test.ts @@ -1,26 +1,95 @@ import supertest from 'supertest' import { app } from '../../../server' import { loggedInAgent } from '../../../../test/utils/loggedInAgent' +import { mockAccounts } from '../../../../test/seeds/01_create-account' +import { random, internet } from 'faker' +import { LoginReponseBody } from '../types/LoginReponseBody' +import { defaultEncryptionMethod } from '../constants' describe('The /auth route', () => { + // used to make requests let request = supertest(app.callback()) - test('should return undefined if the user was not logged in', async () => { - const res = await request.get('/auth') + describe(`The POST method on the /login subroute`, () => { + test('should throw an error if the password field is empty', async () => { + const response = await request.post('/auth/login').send({ + name: mockAccounts[0].name + }) - expect(res.body.uid).toBe(undefined) + expect(response.status).not.toBe(200) + }) + + test('should throw an error if the name field is empty', async () => { + const response = await request.post('/auth/login').send({ + password: mockAccounts[0].password + }) + + expect(response.status).not.toBe(200) + }) + + test('should throw an error if the password is wrong', async () => { + const response = await request.post('/auth/login').send({ + name: mockAccounts[0].name, + password: mockAccounts[0].password + 'something' + }) + + expect(response.status).not.toBe(200) + }) + + test('should work just fine when the password is correct', async () => { + for (const account of mockAccounts) { + const response = await request.post('/auth/login').send({ + email: account.email, + password: account.password + }) + + // i'm making a separate constant for vsc to help me + const body: LoginReponseBody = response.body + + expect(response.status).toBe(200) + expect(body.uid).not.toBe(undefined) + expect(body.encryption).toBe(account.passwordEncryption) + } + }) }) - test.only('should return the uid form the session while logged in', async () => { - const uid = 7 + describe(`The GET method on the / subroute`, () => { + test('should return undefined if the user was not logged in', async () => { + const res = await request.get('/auth') - const [agent, cookie] = await loggedInAgent( - supertest.agent(app.callback()), - uid - ) + expect(res.body.uid).toBe(undefined) + }) - const res = await agent.get('/auth').set('cookie', cookie) + test('should return the uid form the session while logged in', async () => { + const [agent, cookie] = await loggedInAgent(supertest.agent(app.callback()), { + email: mockAccounts[0].email, + password: mockAccounts[0].password + }) - expect(res.body.uid).toBe(uid) + const response = await agent.get('/auth').set('cookie', cookie) + + expect(response.body.uid).not.toBe(undefined) + }) + }) + + describe('The POST method on the /signup subroute', () => { + test('should return the email name and the encrytion', async () => { + const username = random.alphaNumeric(7) + const password = random.alphaNumeric(5) + const email = internet.email() + + const response = await request.post('/auth/signup').send({ + name: username, + email, + password + }) + + // i'm making a separate constant for vsc to help me + const body: LoginReponseBody = response.body + + expect(response.status).toBe(200) + expect(body.uid).not.toBe(undefined) + expect(body.encryption).toBe(defaultEncryptionMethod) + }) }) }) diff --git a/typescript/lunargame/api/src/modules/auth/routes/authRoute.ts b/typescript/lunargame/api/src/modules/auth/routes/authRoute.ts index cc193dc..555403f 100644 --- a/typescript/lunargame/api/src/modules/auth/routes/authRoute.ts +++ b/typescript/lunargame/api/src/modules/auth/routes/authRoute.ts @@ -1,4 +1,14 @@ import Router from 'koa-router' +import { validate } from '../../../common/validation/middleware/validate' +import { getPasswordByEmail } from '../queries/getPasswordByEmail' +import { HttpError } from '../../network/classes/HttpError' +import { checkPassword } from '../helpers/checkPassword' +import { SignupBodySchema } from '../schemas/SignupBody' +import { encryptPassword } from '../helpers/encryptPassword' +import { createAccount } from '../queries/createAccount' +import { defaultEncryptionMethod } from '../constants' +import { LoginBodySchema } from '../schemas/LoginBody' +import { isUnauthorized } from '../middleware/isUnauthorized' const router = new Router() @@ -10,11 +20,65 @@ router.get('/', (context, next) => { return next() }) -router.post('/login', (context, next) => { - context.session.uid = context.request.body.uid - context.body = {} +router.post( + '/login', + isUnauthorized(), + validate(LoginBodySchema, 'body'), + async (context, next) => { + const { email, password } = context.request.body - return next() -}) + const passwordData = await getPasswordByEmail(email) + + // in case the user doesnt exist + if (!passwordData) { + throw new HttpError(400) + } + + const match = checkPassword( + passwordData.password, + password, + passwordData.passwordEncryption + ) + + if (!match) { + throw new HttpError(400, 'wrong password') + } + + context.session.uid = passwordData.id + + context.body = { + encryption: passwordData.passwordEncryption, + uid: passwordData.id + } + + return next() + } +) + +router.post( + '/signup', + isUnauthorized(), + validate(SignupBodySchema, 'body'), + async (context, next) => { + const { email, name, password } = context.request.body + + // encript the password (bcrypt by default) + const encryptedPassword = await encryptPassword(password, defaultEncryptionMethod, 10) + + const uid = await createAccount({ + email, + name, + password: encryptedPassword, + passwordEncryption: defaultEncryptionMethod + }) + + context.body = { + uid, + encryption: defaultEncryptionMethod + } + + return next() + } +) export default router diff --git a/typescript/lunargame/api/src/modules/auth/schemas/LoginBody.ts b/typescript/lunargame/api/src/modules/auth/schemas/LoginBody.ts index c06ae04..e464ffe 100644 --- a/typescript/lunargame/api/src/modules/auth/schemas/LoginBody.ts +++ b/typescript/lunargame/api/src/modules/auth/schemas/LoginBody.ts @@ -1,7 +1,9 @@ -import Joi from 'joi' -import { name, password } from './authFields' +import Joi from '@hapi/joi' +import { email, password } from './authFields' export const LoginBodySchema = Joi.object({ - name, + email, password -}) +}).required() + +export type LoginBody = Joi.extractType diff --git a/typescript/lunargame/api/src/modules/auth/schemas/SignupBody.ts b/typescript/lunargame/api/src/modules/auth/schemas/SignupBody.ts new file mode 100644 index 0000000..c4259de --- /dev/null +++ b/typescript/lunargame/api/src/modules/auth/schemas/SignupBody.ts @@ -0,0 +1,10 @@ +import Joi from '@hapi/joi' +import { email, name, password } from './authFields' + +export const SignupBodySchema = Joi.object({ + name, + password, + email +}).required() + +export type SignupBody = Joi.extractType diff --git a/typescript/lunargame/api/src/modules/auth/schemas/authFields.ts b/typescript/lunargame/api/src/modules/auth/schemas/authFields.ts index 52c32e4..c399f99 100644 --- a/typescript/lunargame/api/src/modules/auth/schemas/authFields.ts +++ b/typescript/lunargame/api/src/modules/auth/schemas/authFields.ts @@ -1,10 +1,8 @@ import Joi from 'joi' export const name = Joi.string() - .alphanum() .min(3) .max(30) - .lowercase() .required() export const email = Joi.string() @@ -15,6 +13,6 @@ export const email = Joi.string() export const password = Joi.string() .min(3) - .max(50) + .max(20) .alphanum() .required() diff --git a/typescript/lunargame/api/src/modules/auth/types/Account.ts b/typescript/lunargame/api/src/modules/auth/types/Account.ts new file mode 100644 index 0000000..f2ca84a --- /dev/null +++ b/typescript/lunargame/api/src/modules/auth/types/Account.ts @@ -0,0 +1,32 @@ +import { passwordEncryption } from './passwordEncryption' + +/** + * The data about an account wich needs to be inserted into the db + */ +export interface DbAccount { + name: string + email: string + password: string + passwordEncryption: passwordEncryption +} + +/** + * The data about an account wich actually gets stored into the db + */ +export interface FullDbAccount extends DbAccount { + id: number +} + +/** + * The data everyone can get about an account + */ +export interface AccountPublicData { + name: string +} + +/** + * The data only the owner of the account has acces to + */ +export interface AccountPrivateData extends AccountPublicData { + email: string +} diff --git a/typescript/lunargame/api/src/modules/auth/types/LoginReponseBody.ts b/typescript/lunargame/api/src/modules/auth/types/LoginReponseBody.ts new file mode 100644 index 0000000..4484762 --- /dev/null +++ b/typescript/lunargame/api/src/modules/auth/types/LoginReponseBody.ts @@ -0,0 +1,6 @@ +import { passwordEncryption } from './passwordEncryption' + +export interface LoginReponseBody { + uid: number + encryption: passwordEncryption +} diff --git a/typescript/lunargame/api/src/modules/auth/types/passwordEncryption.ts b/typescript/lunargame/api/src/modules/auth/types/passwordEncryption.ts new file mode 100644 index 0000000..7995a9f --- /dev/null +++ b/typescript/lunargame/api/src/modules/auth/types/passwordEncryption.ts @@ -0,0 +1,4 @@ +/** + * All modes a password can be encrypted in + */ +export type passwordEncryption = 'plain' | 'bcrypt' diff --git a/typescript/lunargame/api/test/seeds/01_create-account.ts b/typescript/lunargame/api/test/seeds/01_create-account.ts new file mode 100644 index 0000000..a9ff035 --- /dev/null +++ b/typescript/lunargame/api/test/seeds/01_create-account.ts @@ -0,0 +1,21 @@ +import * as Knex from 'knex' +import { DbAccount } from '../../src/modules/auth/types/Account' + +const tableName = 'account' + +export const mockAccounts: DbAccount[] = [ + { + name: 'Adriel', + email: 'rafaeladriel11@gmail.com', + password: '1234', + passwordEncryption: 'plain' + } +] + +export async function seed(knex: Knex): Promise { + return knex(tableName) + .del() + .then(() => { + return knex(tableName).insert(mockAccounts) + }) +} diff --git a/typescript/lunargame/api/test/utils/loggedInAgent.ts b/typescript/lunargame/api/test/utils/loggedInAgent.ts index 34fe56f..c5dae29 100644 --- a/typescript/lunargame/api/test/utils/loggedInAgent.ts +++ b/typescript/lunargame/api/test/utils/loggedInAgent.ts @@ -1,4 +1,6 @@ import supertest from 'supertest' +import 'joi-extract-type' +import { LoginBody } from '../../src/modules/auth/schemas/LoginBody' /** * Helper to get a supertest agent wich is logged in @@ -8,10 +10,11 @@ import supertest from 'supertest' */ export const loggedInAgent = async ( agent: supertest.SuperTest, - uid: number + { email, password }: LoginBody ) => { const response = await agent.post('/auth/login').send({ - uid + email, + password }) // the cookie to send back