diff --git a/oas/user.yaml b/oas/user.yaml index c8c282d..7d9d225 100644 --- a/oas/user.yaml +++ b/oas/user.yaml @@ -43,7 +43,7 @@ 500: $ref: 'oas.yaml#/components/responses/500' put: - summary: TODO change user details + summary: change user details description: 'Auth: basic, levels: read, write, maintain, admin' tags: - /user @@ -85,7 +85,7 @@ 500: $ref: 'oas.yaml#/components/responses/500' delete: - summary: TODO delete user + summary: delete user description: 'Auth: basic, levels: read, write, maintain, admin' tags: - /user @@ -94,12 +94,8 @@ responses: 200: $ref: 'oas.yaml#/components/responses/Ok' - 400: - $ref: 'oas.yaml#/components/responses/400' 401: $ref: 'oas.yaml#/components/responses/401' - 403: - $ref: 'oas.yaml#/components/responses/403' 500: $ref: 'oas.yaml#/components/responses/500' /user/{name}: @@ -128,7 +124,7 @@ 500: $ref: 'oas.yaml#/components/responses/500' put: - summary: TODO change user details + summary: change user details description: 'Auth: basic, levels: admin' tags: - /user @@ -158,7 +154,7 @@ 500: $ref: 'oas.yaml#/components/responses/500' delete: - summary: TODO delete user + summary: delete user description: 'Auth: basic, levels: admin' tags: - /user @@ -167,8 +163,6 @@ responses: 200: $ref: 'oas.yaml#/components/responses/Ok' - 400: - $ref: 'oas.yaml#/components/responses/400' 401: $ref: 'oas.yaml#/components/responses/401' 403: @@ -179,7 +173,7 @@ $ref: 'oas.yaml#/components/responses/500' /user/key: get: - summary: TODO get API key for the user + summary: get API key for the user description: 'Auth: basic, levels: read, write, maintain, dev, admin' tags: - /user diff --git a/package-lock.json b/package-lock.json index 5249707..9b82ecb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -98,6 +98,15 @@ "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-3.0.0.tgz", "integrity": "sha512-nohgNyv+1ViVcubKBh0+XiNJ3dO8nYu///9aJ4cgSqv70gBL+94SNy/iC2NLzKPT2Zt/QavrOkBVbZRLZmw6NQ==" }, + "@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==", + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, "@types/bson": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.2.tgz", @@ -111,6 +120,39 @@ "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" }, + "@types/connect": { + "version": "3.4.33", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz", + "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==", + "requires": { + "@types/node": "*" + } + }, + "@types/express": { + "version": "4.17.6", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.6.tgz", + "integrity": "sha512-n/mr9tZI83kd4azlPG5y997C/M4DNABK9yErhFM6hKdym4kkmd9j0vtsJyjFIwfRBxtrxZtAfGZCNRIBMFLK5w==", + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "*", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.5.tgz", + "integrity": "sha512-578YH5Lt88AKoADy0b2jQGwJtrBxezXtVe/MBqWXKZpqx91SnC0pVkVCcxcytz3lWW+cHBYDi3Ysh0WXc+rAYw==", + "requires": { + "@types/node": "*", + "@types/range-parser": "*" + } + }, + "@types/mime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.1.tgz", + "integrity": "sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==" + }, "@types/mocha": { "version": "5.2.7", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", @@ -139,6 +181,25 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-13.1.6.tgz", "integrity": "sha512-Jg1F+bmxcpENHP23sVKkNuU3uaxPnsBMW0cLjleiikFKomJQbsn0Cqk2yDvQArqzZN6ABfBkZ0To7pQ8sLdWDg==" }, + "@types/qs": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.1.tgz", + "integrity": "sha512-lhbQXx9HKZAPgBkISrBcmAcMpZsmpe/Cd/hY7LGZS5OfkySUBItnPZHgQPssWYUET8elF+yCFBbP1Q0RZPTdaw==" + }, + "@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==" + }, + "@types/serve-static": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.3.tgz", + "integrity": "sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g==", + "requires": { + "@types/express-serve-static-core": "*", + "@types/mime": "*" + } + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -745,9 +806,9 @@ } }, "es-abstract": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.0.tgz", - "integrity": "sha512-yYkE07YF+6SIBmg1MsJ9dlub5L48Ek7X0qz+c/CPCHS9EBXfESorzng4cJQjJW5/pB6vDF41u7F8vUhLVDqIug==", + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", "dev": true, "requires": { "es-to-primitive": "^1.2.1", @@ -1299,12 +1360,12 @@ "dev": true }, "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", "dev": true, "requires": { - "chalk": "^2.0.1" + "chalk": "^2.4.2" } }, "lowercase-keys": { @@ -1393,9 +1454,9 @@ } }, "mocha": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.0.0.tgz", - "integrity": "sha512-CirsOPbO3jU86YKjjMzFLcXIb5YiGLUrjrXFHoJ3e2z9vWiaZVCZQ2+gtRGMPWF+nFhN6AWwLM/juzAQ6KRkbA==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.2.tgz", + "integrity": "sha512-o96kdRKMKI3E8U0bjnfqW4QMk12MwZ4mhdBTf+B5a1q9+aq2HRnj+3ZdJu0B/ZhJeK78MgYuv6L8d/rA5AeBJA==", "dev": true, "requires": { "ansi-colors": "3.2.3", @@ -1409,9 +1470,9 @@ "growl": "1.10.5", "he": "1.2.0", "js-yaml": "3.13.1", - "log-symbols": "2.2.0", + "log-symbols": "3.0.0", "minimatch": "3.0.4", - "mkdirp": "0.5.1", + "mkdirp": "0.5.5", "ms": "2.1.1", "node-environment-flags": "1.0.6", "object.assign": "4.1.0", @@ -1419,8 +1480,8 @@ "supports-color": "6.0.0", "which": "1.3.1", "wide-align": "1.1.3", - "yargs": "13.3.0", - "yargs-parser": "13.1.1", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", "yargs-unparser": "1.6.0" }, "dependencies": { @@ -1469,21 +1530,6 @@ "path-is-absolute": "^1.0.0" } }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", @@ -1709,9 +1755,9 @@ "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==" }, "p-limit": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", - "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -2132,24 +2178,46 @@ "strip-ansi": "^4.0.0" } }, - "string.prototype.trimleft": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", - "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", "dev": true, "requires": { "define-properties": "^1.1.3", - "function-bind": "^1.1.1" + "es-abstract": "^1.17.5" + } + }, + "string.prototype.trimleft": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", + "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimstart": "^1.0.0" } }, "string.prototype.trimright": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", - "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", + "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", "dev": true, "requires": { "define-properties": "^1.1.3", - "function-bind": "^1.1.1" + "es-abstract": "^1.17.5", + "string.prototype.trimend": "^1.0.0" + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" } }, "string_decoder": { @@ -2582,9 +2650,9 @@ "dev": true }, "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", "dev": true, "requires": { "cliui": "^5.0.0", @@ -2596,7 +2664,7 @@ "string-width": "^3.0.0", "which-module": "^2.0.0", "y18n": "^4.0.0", - "yargs-parser": "^13.1.1" + "yargs-parser": "^13.1.2" }, "dependencies": { "ansi-regex": { @@ -2628,21 +2696,13 @@ } }, "yargs-parser": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", - "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", "dev": true, "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" - }, - "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - } } }, "yargs-unparser": { diff --git a/package.json b/package.json index adc9874..3bc1031 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@apidevtools/json-schema-ref-parser": "^8.0.0", "@hapi/joi": "^17.1.1", "@types/bcrypt": "^3.0.0", + "@types/express": "^4.17.6", "@types/mocha": "^5.2.7", "@types/mongoose": "^5.7.12", "@types/node": "^13.1.6", @@ -35,7 +36,7 @@ "typescript": "^3.7.4" }, "devDependencies": { - "mocha": "^7.0.0", + "mocha": "^7.1.2", "should": "^13.2.3", "supertest": "^4.0.2" } diff --git a/src/routes/user.spec.ts b/src/routes/user.spec.ts index 60f5b4d..8148d2c 100644 --- a/src/routes/user.spec.ts +++ b/src/routes/user.spec.ts @@ -236,6 +236,16 @@ describe('/user', () => { }); }); }); + it('rejects a username which is in the special names', done => { + TestHelper.request(server, done, { + method: 'post', + url: '/user/new', + auth: {basic: 'admin'}, + httpStatus: 400, default: false, + req: {email: 'j.doe@bosch.com', name: 'passreset', pass: 'Abc123!#', level: 'read', location: 'Rng', device_name: 'Alpha II'}, + res: {status: 'Username already taken'} + }); + }); it('rejects invalid user details', done => { TestHelper.request(server, done, { method: 'put', @@ -304,6 +314,73 @@ describe('/user', () => { }); }); + describe('DELETE /user/{name}', () => { + it('deletes own user details', done => { + TestHelper.request(server, done, { + method: 'delete', + url: '/user', + auth: {basic: 'janedoe'}, + httpStatus: 200 + }).end((err, res) => { + if (err) return done (err); + should(res.body).be.eql({status: 'OK'}); + UserModel.find({name: 'janedoe'}).lean().exec( 'find', (err, data) => { + if (err) return done(err); + should(data).have.lengthOf(0); + done(); + }); + }); + }); + it('deletes other user details for admin', done => { + TestHelper.request(server, done, { + method: 'delete', + url: '/user/janedoe', + auth: {basic: 'admin'}, + httpStatus: 200 + }).end((err, res) => { + if (err) return done (err); + should(res.body).be.eql({status: 'OK'}); + UserModel.find({name: 'janedoe'}).lean().exec( 'find', (err, data) => { + if (err) return done(err); + should(data).have.lengthOf(0); + done(); + }); + }); + }); + it('rejects requests from non-admins for another user', done => { + TestHelper.request(server, done, { + method: 'delete', + url: '/user/admin', + auth: {basic: 'janedoe'}, + httpStatus: 403 + }); + }); + it('rejects requests from a user API key', done => { + TestHelper.request(server, done, { + method: 'delete', + url: '/user', + auth: {key: 'janedoe'}, + httpStatus: 401 + }); + }); + it('rejects requests from an admin API key', done => { + TestHelper.request(server, done, { + method: 'delete', + url: '/user/janedoe', + auth: {key: 'admin'}, + httpStatus: 401 + }); + }); + it('returns 404 for an unknown user', done => { + TestHelper.request(server, done, { + method: 'delete', + url: '/user/unknown', + auth: {basic: 'admin'}, + httpStatus: 404 + }); + }); + }); + describe('POST /user/new', () => { it('returns the added user data', done => { TestHelper.request(server, done, { @@ -365,6 +442,16 @@ describe('/user', () => { }); }); }); + it('rejects a username which is in the special names', done => { + TestHelper.request(server, done, { + method: 'post', + url: '/user/new', + auth: {basic: 'admin'}, + httpStatus: 400, default: false, + req: {email: 'j.doe@bosch.com', name: 'passreset', pass: 'Abc123!#', level: 'read', location: 'Rng', device_name: 'Alpha II'}, + res: {status: 'Username already taken'} + }); + }); it('rejects invalid user details', done => { TestHelper.request(server, done, { method: 'post', diff --git a/src/routes/user.ts b/src/routes/user.ts index 26f21cc..f4326ea 100644 --- a/src/routes/user.ts +++ b/src/routes/user.ts @@ -36,7 +36,7 @@ router.get('/user:username([/](?!key|new).?*|/?)', (req, res, next) => { // thi }); router.put('/user:username([/](?!key|new).?*|/?)', (req, res, next) => { // this path matches /user, /user/ and /user/xxx, but not /user/key or user/new - console.log(req.authDetails); + req.params.username = req.params[0]; if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'basic')) return; let username = req.authDetails.username; if (req.params.username !== undefined) { @@ -44,8 +44,6 @@ router.put('/user:username([/](?!key|new).?*|/?)', (req, res, next) => { // thi username = req.params.username; } const {error, value: user} = UserValidate.input(req.body, 'change' + (req.authDetails.level === 'admin'? 'admin' : '')); - console.log(error); - console.log(user); if(error !== undefined) { res.status(400).json({status: 'Invalid body format'}); return; @@ -59,7 +57,7 @@ router.put('/user:username([/](?!key|new).?*|/?)', (req, res, next) => { // thi if (user.hasOwnProperty('name') && user.name !== username) { UserModel.find({name: user.name}).lean().exec( (err, data:any) => { if (err) next(err); - if (data.length > 0) { + if (data.length > 0 || UserValidate.isSpecialName(user.name)) { res.status(400).json({status: 'Username already taken'}); return; } @@ -88,6 +86,26 @@ router.put('/user:username([/](?!key|new).?*|/?)', (req, res, next) => { // thi } }); +router.delete('/user:username([/](?!key|new).?*|/?)', (req, res, next) => { // this path matches /user, /user/ and /user/xxx, but not /user/key or user/new. See https://forbeslindesay.github.io/express-route-tester/ for the generated regex + req.params.username = req.params[0]; + if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'basic')) return; + let username = req.authDetails.username; + if (req.params.username !== undefined) { + if (!req.auth(res, ['admin'], 'basic')) return; + username = req.params.username; + } + + UserModel.findOneAndDelete({name: username}).lean().exec( (err, data:any) => { + if (err) next(err); + if (data) { + res.json({status: 'OK'}) + } + else { + res.status(404).json({status: 'Not found'}); + } + }); +}); + router.get('/user/key', (req, res, next) => { console.log('hmm'); if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'basic')) return; @@ -111,7 +129,7 @@ router.post('/user/new', (req, res, next) => { // check that user does not already exist UserModel.find({name: user.name}).lean().exec( (err, data:any) => { if (err) next(err); - if (data.length > 0) { + if (data.length > 0 || UserValidate.isSpecialName(user.name)) { res.status(400).json({status: 'Username already taken'}); return; } diff --git a/src/routes/validate/user.ts b/src/routes/validate/user.ts index 68f743d..4f563c6 100644 --- a/src/routes/validate/user.ts +++ b/src/routes/validate/user.ts @@ -25,6 +25,8 @@ export default class UserValidate { // validate input for user .allow('') }; + private static specialUsernames = ['admin', 'user', 'key', 'new', 'passreset']; // names a user cannot take + static input (data, param) { if (param === 'new') { return joi.object({ @@ -71,4 +73,8 @@ export default class UserValidate { // validate input for user }).validate(data, {stripUnknown: true}) return error !== undefined? null : value; } + + static isSpecialName (name) { // true if name belongs to special names + return this.specialUsernames.indexOf(name) > -1; + } }