From 1f3b31267598e1b9e97cf8bed542def68bfd99f6 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Fri, 4 Dec 2020 21:38:34 +0100 Subject: [PATCH 01/47] =?UTF-8?q?=F0=9F=9A=A7=20basic=20JWTAuth=20Middlewa?= =?UTF-8?q?re?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref #12 --- src/app.ts | 11 ++++++----- src/middlewares/jwtauth.ts | 33 ++++++++++++++++++--------------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/app.ts b/src/app.ts index 9e15de1..e54f0ac 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,17 +1,18 @@ -import "reflect-metadata"; -import * as dotenvSafe from "dotenv-safe"; -import { createExpressServer } from "routing-controllers"; import consola from "consola"; -import loaders from "./loaders/index"; +import * as dotenvSafe from "dotenv-safe"; +import "reflect-metadata"; +import { createExpressServer } from "routing-controllers"; import authchecker from "./authchecker"; +import loaders from "./loaders/index"; import { ErrorHandler } from './middlewares/ErrorHandler'; +import { JWTAuth } from './middlewares/JWTAuth'; dotenvSafe.config(); const PORT = process.env.APP_PORT || 4010; const app = createExpressServer({ authorizationChecker: authchecker, - middlewares: [ErrorHandler], + middlewares: [ErrorHandler, JWTAuth], development: process.env.NODE_ENV === "production", cors: true, routePrefix: "/api", diff --git a/src/middlewares/jwtauth.ts b/src/middlewares/jwtauth.ts index 81c28c3..bdb423b 100644 --- a/src/middlewares/jwtauth.ts +++ b/src/middlewares/jwtauth.ts @@ -1,17 +1,20 @@ -import { Request, Response, NextFunction } from "express"; -// import bodyParser from 'body-parser'; -// import cors from 'cors'; import * as jwt from "jsonwebtoken"; +import { + ExpressMiddlewareInterface, Middleware +} from "routing-controllers"; -export default (req: Request, res: Response, next: NextFunction) => { - const token = req.headers["auth"]; - try { - const jwtPayload = jwt.verify(token, "secretjwtsecret"); - // const jwtPayload = jwt.verify(token, process.env.JWT_SECRET); - res.locals.jwtPayload = jwtPayload; - } catch (error) { - console.log(error); - return res.status(401).send(); - } - next(); -}; +@Middleware({ type: "before" }) +export class JWTAuth implements ExpressMiddlewareInterface { + use(request: any, response: any, next?: (err?: any) => any): any { + const token = request.headers["auth"]; + try { + const jwtPayload = jwt.verify(token, "secretjwtsecret"); + // const jwtPayload = jwt.verify(token, process.env.JWT_SECRET); + response.locals.jwtPayload = jwtPayload; + } catch (error) { + console.log(error); + return response.status(401).send(); + } + next(); + } +} From b9bbdee82654b5cea26fdd97b38df2c0829ec1e6 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Fri, 4 Dec 2020 22:17:03 +0100 Subject: [PATCH 02/47] =?UTF-8?q?=F0=9F=9A=A7=20basic=20AuthErrors=20?= =?UTF-8?q?=F0=9F=94=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref #12 --- src/errors/AuthError.ts | 68 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 src/errors/AuthError.ts diff --git a/src/errors/AuthError.ts b/src/errors/AuthError.ts new file mode 100644 index 0000000..24ded8a --- /dev/null +++ b/src/errors/AuthError.ts @@ -0,0 +1,68 @@ +import { IsString } from 'class-validator'; +import { ForbiddenError, NotAcceptableError, UnauthorizedError } from 'routing-controllers'; + +/** + * Error to throw when a jwt is expired + */ +export class ExpiredJWTError extends UnauthorizedError { + @IsString() + name = "ExpiredJWTError" + + @IsString() + message = "your provided jwt is expired" +} + +/** + * Error to throw when a jwt could not be parsed + */ +export class IllegalJWTError extends UnauthorizedError { + @IsString() + name = "IllegalJWTError" + + @IsString() + message = "your provided jwt could not be parsed" +} + +/** + * Error to throw when provided credentials are invalid + */ +export class InvalidCredentialsError extends UnauthorizedError { + @IsString() + name = "InvalidCredentialsError" + + @IsString() + message = "your provided credentials are invalid" +} + +/** + * Error to throw when a jwt does not have permission for this route/ action + */ +export class NoPermissionError extends ForbiddenError { + @IsString() + name = "NoPermissionError" + + @IsString() + message = "your provided jwt does not have permission for this route/ action" +} + +/** + * Error to thow when no username and no email is set + */ +export class UsernameOrEmailNeededError extends NotAcceptableError { + @IsString() + name = "UsernameOrEmailNeededError" + + @IsString() + message = "Auth needs to have email or username set! \n You provided neither." +} + +/** + * Error to thow when no password is provided + */ +export class PasswordNeededError extends NotAcceptableError { + @IsString() + name = "PasswordNeededError" + + @IsString() + message = "no password is provided - you need to provide it" +} \ No newline at end of file From b0a24c6a74d9a20a4ec5c562ece6baa3811cd00a Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Fri, 4 Dec 2020 22:18:40 +0100 Subject: [PATCH 03/47] basic Auth model ref #12 --- src/models/entities/Auth.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/models/entities/Auth.ts diff --git a/src/models/entities/Auth.ts b/src/models/entities/Auth.ts new file mode 100644 index 0000000..75ed27c --- /dev/null +++ b/src/models/entities/Auth.ts @@ -0,0 +1,21 @@ +/** + * Defines a auth object +*/ +export class Auth { + /** + * access_token - JWT shortterm access token + */ + access_token: string; + /** + * refresh_token - longterm refresh token (used for requesting new access tokens) + */ + refresh_token: string; + /** + * access_token_expires_at - unix timestamp of access token expiry + */ + access_token_expires_at: number; + /** + * refresh_token_expires_at - unix timestamp of access token expiry + */ + refresh_token_expires_at: number; +} From f251b7acdbc8e277971cf97cfe619f441ac0362a Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Fri, 4 Dec 2020 22:18:54 +0100 Subject: [PATCH 04/47] authchecker - use new custom Errors ref #12 --- src/authchecker.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/authchecker.ts b/src/authchecker.ts index 9b62dfa..f32ec75 100644 --- a/src/authchecker.ts +++ b/src/authchecker.ts @@ -1,5 +1,6 @@ import * as jwt from "jsonwebtoken"; -import { Action, HttpError } from "routing-controllers"; +import { Action } from "routing-controllers"; +import { IllegalJWTError, NoPermissionError } from './errors/AuthError'; // ----------- const sampletoken = jwt.sign({ "permissions": { @@ -22,7 +23,7 @@ const authchecker = async (action: Action, permissions: string | string[]) => { try { jwtPayload = jwt.verify(provided_token, process.env.JWT_SECRET || "secretjwtsecret"); } catch (error) { - throw new HttpError(401, "jwt_illegal") + throw new IllegalJWTError() } if (jwtPayload.permissions) { action.response.local = {} @@ -34,11 +35,11 @@ const authchecker = async (action: Action, permissions: string | string[]) => { if (actual_accesslevel_for_permission.includes(permission_access_level)) { return true; } else { - throw new HttpError(403, "no") + throw new NoPermissionError() } }); } else { - throw new HttpError(403, "no") + throw new NoPermissionError() } // try { From a7afcf4cd1ab60f856c299eaeace7fe5f3ec3b14 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Fri, 4 Dec 2020 22:19:55 +0100 Subject: [PATCH 05/47] CreateAuth model ref #12 --- src/models/creation/CreateAuth.ts | 36 +++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/models/creation/CreateAuth.ts diff --git a/src/models/creation/CreateAuth.ts b/src/models/creation/CreateAuth.ts new file mode 100644 index 0000000..7f20dbe --- /dev/null +++ b/src/models/creation/CreateAuth.ts @@ -0,0 +1,36 @@ +import { IsEmail, IsOptional, IsString } from 'class-validator'; +import { PasswordNeededError } from '../../errors/AuthError'; +import { UsernameOrEmailNeededError } from '../../errors/UserErrors'; +import { Auth } from '../entities/Auth'; + +export class CreateAuth { + @IsOptional() + @IsString() + username?: string; + @IsString() + password: string; + @IsEmail() + @IsString() + email?: string; + + public async toAuth(): Promise { + let newAuth: Auth = new Auth(); + + if (this.email === undefined && this.username === undefined) { + throw new UsernameOrEmailNeededError(); + } + if (!this.password) { + throw new PasswordNeededError() + } + // const found = await getConnectionManager().get().getRepository(UserGroup).find({ id: g }); + + // TODO: jwt creation + return + newAuth.access_token = "" + newAuth.refresh_token = "" + newAuth.access_token_expires_at = 1587349200 + newAuth.refresh_token_expires_at = 1587349200 + + console.log(newAuth) + return newAuth; + } +} \ No newline at end of file From c5c3058f3d20aa898bd67c02baa3d995321e0ab5 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Fri, 4 Dec 2020 22:28:17 +0100 Subject: [PATCH 06/47] clean up jwtauth ref #12 --- src/middlewares/jwtauth.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/middlewares/jwtauth.ts b/src/middlewares/jwtauth.ts index bdb423b..3f77265 100644 --- a/src/middlewares/jwtauth.ts +++ b/src/middlewares/jwtauth.ts @@ -1,9 +1,9 @@ import * as jwt from "jsonwebtoken"; import { - ExpressMiddlewareInterface, Middleware + ExpressMiddlewareInterface } from "routing-controllers"; -@Middleware({ type: "before" }) +// @Middleware({ type: "before" }) export class JWTAuth implements ExpressMiddlewareInterface { use(request: any, response: any, next?: (err?: any) => any): any { const token = request.headers["auth"]; From c4b7ece974fe548e68415b49fc8cce913ef6cd92 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Fri, 4 Dec 2020 22:34:03 +0100 Subject: [PATCH 07/47] class-validator on Auth model ref #12 --- src/models/entities/Auth.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/models/entities/Auth.ts b/src/models/entities/Auth.ts index 75ed27c..39a16ef 100644 --- a/src/models/entities/Auth.ts +++ b/src/models/entities/Auth.ts @@ -1,3 +1,5 @@ +import { IsInt, IsString } from 'class-validator'; + /** * Defines a auth object */ @@ -5,17 +7,21 @@ export class Auth { /** * access_token - JWT shortterm access token */ + @IsString() access_token: string; /** * refresh_token - longterm refresh token (used for requesting new access tokens) */ + @IsString() refresh_token: string; /** * access_token_expires_at - unix timestamp of access token expiry */ + @IsInt() access_token_expires_at: number; /** * refresh_token_expires_at - unix timestamp of access token expiry */ + @IsInt() refresh_token_expires_at: number; } From 6cb01090d0f640d25728495f0a80c756ee43e985 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Fri, 4 Dec 2020 22:43:41 +0100 Subject: [PATCH 08/47] working on AuthController + CreateAuth ref #12 --- src/controllers/AuthController.ts | 26 ++++++++++++++++++++++++++ src/models/creation/CreateAuth.ts | 7 +++++-- 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 src/controllers/AuthController.ts diff --git a/src/controllers/AuthController.ts b/src/controllers/AuthController.ts new file mode 100644 index 0000000..8a39093 --- /dev/null +++ b/src/controllers/AuthController.ts @@ -0,0 +1,26 @@ +import { Body, JsonController, Post } from 'routing-controllers'; +import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; +import { InvalidCredentialsError } from '../errors/AuthError'; +import { UserNotFoundError } from '../errors/UserErrors'; +import { CreateAuth } from '../models/creation/CreateAuth'; + +@JsonController('/auth') +export class AuthController { + constructor() { + } + + @Post("/login") + @ResponseSchema(InvalidCredentialsError) + @ResponseSchema(UserNotFoundError) + @OpenAPI({ description: 'Create a new access token object' }) + async post(@Body({ validate: true }) createAuth: CreateAuth) { + let auth; + try { + auth = await createAuth.toAuth(); + console.log(auth); + } catch (error) { + return error; + } + return auth + } +} diff --git a/src/models/creation/CreateAuth.ts b/src/models/creation/CreateAuth.ts index 7f20dbe..4e28229 100644 --- a/src/models/creation/CreateAuth.ts +++ b/src/models/creation/CreateAuth.ts @@ -1,7 +1,9 @@ import { IsEmail, IsOptional, IsString } from 'class-validator'; +import { getConnectionManager } from 'typeorm'; import { PasswordNeededError } from '../../errors/AuthError'; import { UsernameOrEmailNeededError } from '../../errors/UserErrors'; import { Auth } from '../entities/Auth'; +import { User } from '../entities/User'; export class CreateAuth { @IsOptional() @@ -22,9 +24,10 @@ export class CreateAuth { if (!this.password) { throw new PasswordNeededError() } - // const found = await getConnectionManager().get().getRepository(UserGroup).find({ id: g }); + const found = await getConnectionManager().get().getRepository(User).find({ where: [{ username: this.username }, { email: this.email }] }); + console.log(found); - // TODO: jwt creation + return + // TODO: jwt creation newAuth.access_token = "" newAuth.refresh_token = "" newAuth.access_token_expires_at = 1587349200 From d803704eeebc5d5a188cb9fd5c9afd6882579fd3 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Fri, 4 Dec 2020 23:02:23 +0100 Subject: [PATCH 09/47] UserNotFoundError ref #12 --- src/errors/AuthError.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/errors/AuthError.ts b/src/errors/AuthError.ts index 24ded8a..a0de93a 100644 --- a/src/errors/AuthError.ts +++ b/src/errors/AuthError.ts @@ -1,5 +1,5 @@ import { IsString } from 'class-validator'; -import { ForbiddenError, NotAcceptableError, UnauthorizedError } from 'routing-controllers'; +import { ForbiddenError, NotAcceptableError, NotFoundError, UnauthorizedError } from 'routing-controllers'; /** * Error to throw when a jwt is expired @@ -65,4 +65,15 @@ export class PasswordNeededError extends NotAcceptableError { @IsString() message = "no password is provided - you need to provide it" +} + +/** + * Error to thow when no user could be found for provided credential + */ +export class UserNotFoundError extends NotFoundError { + @IsString() + name = "UserNotFoundError" + + @IsString() + message = "no user could be found for provided credential" } \ No newline at end of file From 6244c969afac300183339aaf0dac77d213947d2b Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Fri, 4 Dec 2020 23:03:10 +0100 Subject: [PATCH 10/47] integrate UserNotFoundError ref #12 --- src/models/creation/CreateAuth.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/models/creation/CreateAuth.ts b/src/models/creation/CreateAuth.ts index 4e28229..5e7cd9f 100644 --- a/src/models/creation/CreateAuth.ts +++ b/src/models/creation/CreateAuth.ts @@ -1,6 +1,6 @@ import { IsEmail, IsOptional, IsString } from 'class-validator'; import { getConnectionManager } from 'typeorm'; -import { PasswordNeededError } from '../../errors/AuthError'; +import { PasswordNeededError, UserNotFoundError } from '../../errors/AuthError'; import { UsernameOrEmailNeededError } from '../../errors/UserErrors'; import { Auth } from '../entities/Auth'; import { User } from '../entities/User'; @@ -24,8 +24,11 @@ export class CreateAuth { if (!this.password) { throw new PasswordNeededError() } - const found = await getConnectionManager().get().getRepository(User).find({ where: [{ username: this.username }, { email: this.email }] }); - console.log(found); + const found_users = await getConnectionManager().get().getRepository(User).find({ where: [{ username: this.username }, { email: this.email }] }); + console.log(found_users); + if (found_users.length === 0) { + throw new UserNotFoundError() + } else { // TODO: jwt creation newAuth.access_token = "" @@ -33,7 +36,8 @@ export class CreateAuth { newAuth.access_token_expires_at = 1587349200 newAuth.refresh_token_expires_at = 1587349200 - console.log(newAuth) + console.log(newAuth) + } return newAuth; } } \ No newline at end of file From 6ae0c1b95526530968198ebf78b10ab1e71a8caa Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Fri, 4 Dec 2020 23:03:24 +0100 Subject: [PATCH 11/47] first jwt generation ref #12 --- src/models/creation/CreateAuth.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/models/creation/CreateAuth.ts b/src/models/creation/CreateAuth.ts index 5e7cd9f..a1a8884 100644 --- a/src/models/creation/CreateAuth.ts +++ b/src/models/creation/CreateAuth.ts @@ -1,4 +1,5 @@ import { IsEmail, IsOptional, IsString } from 'class-validator'; +import * as jsonwebtoken from 'jsonwebtoken'; import { getConnectionManager } from 'typeorm'; import { PasswordNeededError, UserNotFoundError } from '../../errors/AuthError'; import { UsernameOrEmailNeededError } from '../../errors/UserErrors'; @@ -29,12 +30,14 @@ export class CreateAuth { if (found_users.length === 0) { throw new UserNotFoundError() } else { + const found_user = found_users[0] + const token = jsonwebtoken.sign(found_user, "sec") - // TODO: jwt creation - newAuth.access_token = "" - newAuth.refresh_token = "" - newAuth.access_token_expires_at = 1587349200 - newAuth.refresh_token_expires_at = 1587349200 + // TODO: jwt creation + newAuth.access_token = token + newAuth.refresh_token = token + newAuth.access_token_expires_at = 1587349200 + newAuth.refresh_token_expires_at = 1587349200 console.log(newAuth) } From b8bc39d691d10c13e60dc7bd3709d413dcf8b8b6 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Sat, 5 Dec 2020 11:14:06 +0100 Subject: [PATCH 12/47] =?UTF-8?q?=F0=9F=9A=A7=20User=20-=20mark=20columns?= =?UTF-8?q?=20as=20unique?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref #11 #12 --- src/models/entities/User.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/models/entities/User.ts b/src/models/entities/User.ts index 1d2065e..8e29e27 100644 --- a/src/models/entities/User.ts +++ b/src/models/entities/User.ts @@ -19,14 +19,14 @@ export class User { /** * uuid */ - @Column() + @Column({ unique: true }) @IsUUID(4) uuid: string; /** * user email */ - @Column({ nullable: true }) + @Column({ nullable: true, unique: true }) @IsEmail() email?: string; @@ -41,7 +41,7 @@ export class User { /** * username */ - @Column({ nullable: true }) + @Column({ nullable: true, unique: true }) @IsString() username?: string; @@ -109,7 +109,7 @@ export class User { /** * profilepic */ - @Column({ nullable: true }) + @Column({ nullable: true, unique: true }) @IsString() @IsOptional() profilePic?: string; From d46ad5954676e73ab3c77f2d84c87b22088f4e71 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Sat, 5 Dec 2020 11:14:26 +0100 Subject: [PATCH 13/47] =?UTF-8?q?=F0=9F=9A=A7=20CreateAuth=20now=20returns?= =?UTF-8?q?=20a=20sample=20jwt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref #12 --- src/models/creation/CreateAuth.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/models/creation/CreateAuth.ts b/src/models/creation/CreateAuth.ts index a1a8884..b2c9727 100644 --- a/src/models/creation/CreateAuth.ts +++ b/src/models/creation/CreateAuth.ts @@ -12,6 +12,7 @@ export class CreateAuth { username?: string; @IsString() password: string; + @IsOptional() @IsEmail() @IsString() email?: string; @@ -26,20 +27,17 @@ export class CreateAuth { throw new PasswordNeededError() } const found_users = await getConnectionManager().get().getRepository(User).find({ where: [{ username: this.username }, { email: this.email }] }); - console.log(found_users); if (found_users.length === 0) { throw new UserNotFoundError() } else { const found_user = found_users[0] - const token = jsonwebtoken.sign(found_user, "sec") - - // TODO: jwt creation + // TODO: proper jwt creation + const token = jsonwebtoken.sign({}, "securekey") newAuth.access_token = token newAuth.refresh_token = token newAuth.access_token_expires_at = 1587349200 newAuth.refresh_token_expires_at = 1587349200 - console.log(newAuth) } return newAuth; } From bd0c7ce04213a297cf13f85ac63de34785796306 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Sat, 5 Dec 2020 11:18:12 +0100 Subject: [PATCH 14/47] =?UTF-8?q?=F0=9F=9A=A7=20CreateAuth=20-=20credentia?= =?UTF-8?q?l=20validation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref #12 --- src/models/creation/CreateAuth.ts | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/models/creation/CreateAuth.ts b/src/models/creation/CreateAuth.ts index b2c9727..564d6f5 100644 --- a/src/models/creation/CreateAuth.ts +++ b/src/models/creation/CreateAuth.ts @@ -1,7 +1,8 @@ +import * as argon2 from "argon2"; import { IsEmail, IsOptional, IsString } from 'class-validator'; import * as jsonwebtoken from 'jsonwebtoken'; import { getConnectionManager } from 'typeorm'; -import { PasswordNeededError, UserNotFoundError } from '../../errors/AuthError'; +import { InvalidCredentialsError, PasswordNeededError, UserNotFoundError } from '../../errors/AuthError'; import { UsernameOrEmailNeededError } from '../../errors/UserErrors'; import { Auth } from '../entities/Auth'; import { User } from '../entities/User'; @@ -31,12 +32,23 @@ export class CreateAuth { throw new UserNotFoundError() } else { const found_user = found_users[0] - // TODO: proper jwt creation - const token = jsonwebtoken.sign({}, "securekey") - newAuth.access_token = token - newAuth.refresh_token = token - newAuth.access_token_expires_at = 1587349200 - newAuth.refresh_token_expires_at = 1587349200 + console.log(found_user.password); + // try { + if (await argon2.verify(found_user.password, this.password + found_user.uuid)) { + // password match + // TODO: proper jwt creation + const token = jsonwebtoken.sign({}, "securekey") + newAuth.access_token = token + newAuth.refresh_token = token + newAuth.access_token_expires_at = 1587349200 + newAuth.refresh_token_expires_at = 1587349200 + } else { + // password did not match + throw new InvalidCredentialsError() + } + // } catch (err) { + // // internal failure + // } } return newAuth; From 2a1b65f4249defb535f8464cf5ec3a63e4dd44bb Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Sat, 5 Dec 2020 11:22:45 +0100 Subject: [PATCH 15/47] =?UTF-8?q?=F0=9F=9A=A7AuthController=20-=20add=20al?= =?UTF-8?q?l=20Error=20response=20schemas=20to=20post?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref #12 --- src/controllers/AuthController.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/controllers/AuthController.ts b/src/controllers/AuthController.ts index 8a39093..afa677b 100644 --- a/src/controllers/AuthController.ts +++ b/src/controllers/AuthController.ts @@ -1,6 +1,6 @@ import { Body, JsonController, Post } from 'routing-controllers'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; -import { InvalidCredentialsError } from '../errors/AuthError'; +import { InvalidCredentialsError, PasswordNeededError, UsernameOrEmailNeededError } from '../errors/AuthError'; import { UserNotFoundError } from '../errors/UserErrors'; import { CreateAuth } from '../models/creation/CreateAuth'; @@ -12,6 +12,9 @@ export class AuthController { @Post("/login") @ResponseSchema(InvalidCredentialsError) @ResponseSchema(UserNotFoundError) + @ResponseSchema(UsernameOrEmailNeededError) + @ResponseSchema(PasswordNeededError) + @ResponseSchema(InvalidCredentialsError) @OpenAPI({ description: 'Create a new access token object' }) async post(@Body({ validate: true }) createAuth: CreateAuth) { let auth; From 1850dd542d564e91cf55ac9fcdf7902091969163 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Sat, 5 Dec 2020 11:22:59 +0100 Subject: [PATCH 16/47] =?UTF-8?q?=F0=9F=A7=B9=20clean=20up=20CreateAuth?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref #12 --- src/models/creation/CreateAuth.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/models/creation/CreateAuth.ts b/src/models/creation/CreateAuth.ts index 564d6f5..0ba27af 100644 --- a/src/models/creation/CreateAuth.ts +++ b/src/models/creation/CreateAuth.ts @@ -33,9 +33,7 @@ export class CreateAuth { } else { const found_user = found_users[0] console.log(found_user.password); - // try { if (await argon2.verify(found_user.password, this.password + found_user.uuid)) { - // password match // TODO: proper jwt creation const token = jsonwebtoken.sign({}, "securekey") newAuth.access_token = token @@ -43,13 +41,8 @@ export class CreateAuth { newAuth.access_token_expires_at = 1587349200 newAuth.refresh_token_expires_at = 1587349200 } else { - // password did not match throw new InvalidCredentialsError() } - // } catch (err) { - // // internal failure - // } - } return newAuth; } From d23ed002b24ee29b1bfca98b7f5b3eb3ce47c2db Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Sat, 5 Dec 2020 12:28:06 +0100 Subject: [PATCH 17/47] =?UTF-8?q?=F0=9F=9A=A7=20JwtNotProvidedError?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref #12 --- src/errors/AuthError.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/errors/AuthError.ts b/src/errors/AuthError.ts index a0de93a..cdaa870 100644 --- a/src/errors/AuthError.ts +++ b/src/errors/AuthError.ts @@ -76,4 +76,15 @@ export class UserNotFoundError extends NotFoundError { @IsString() message = "no user could be found for provided credential" +} + +/** + * Error to thow when no jwt token was provided + */ +export class JwtNotProvidedError extends NotAcceptableError { + @IsString() + name = "JwtNotProvidedError" + + @IsString() + message = "no jwt token was provided" } \ No newline at end of file From 28c2b862f0a070323ea7eb1d2c0a53c71979e46f Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Sat, 5 Dec 2020 12:28:43 +0100 Subject: [PATCH 18/47] =?UTF-8?q?=F0=9F=9A=A7=20AuthController=20with=20mu?= =?UTF-8?q?ltiple=20endpoints?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref #12 --- src/controllers/AuthController.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/controllers/AuthController.ts b/src/controllers/AuthController.ts index afa677b..d14e574 100644 --- a/src/controllers/AuthController.ts +++ b/src/controllers/AuthController.ts @@ -3,6 +3,7 @@ import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { InvalidCredentialsError, PasswordNeededError, UsernameOrEmailNeededError } from '../errors/AuthError'; import { UserNotFoundError } from '../errors/UserErrors'; import { CreateAuth } from '../models/creation/CreateAuth'; +import { RefreshAuth } from '../models/creation/RefreshAuth'; @JsonController('/auth') export class AuthController { @@ -16,7 +17,7 @@ export class AuthController { @ResponseSchema(PasswordNeededError) @ResponseSchema(InvalidCredentialsError) @OpenAPI({ description: 'Create a new access token object' }) - async post(@Body({ validate: true }) createAuth: CreateAuth) { + async login(@Body({ validate: true }) createAuth: CreateAuth) { let auth; try { auth = await createAuth.toAuth(); @@ -26,4 +27,19 @@ export class AuthController { } return auth } + + @Post("/refresh") + @ResponseSchema(InvalidCredentialsError) + @ResponseSchema(UserNotFoundError) + @OpenAPI({ description: 'refresh a access token' }) + async refresh(@Body({ validate: true }) refreshAuth: RefreshAuth) { + let auth; + try { + auth = await refreshAuth.toAuth(); + console.log(auth); + } catch (error) { + return error; + } + return auth + } } From c33097f7738da74cbd50f3cedd15e1ae173a7e3e Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Sat, 5 Dec 2020 12:28:59 +0100 Subject: [PATCH 19/47] first accesstoken generation ref #12 --- src/models/creation/CreateAuth.ts | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/models/creation/CreateAuth.ts b/src/models/creation/CreateAuth.ts index 0ba27af..4580869 100644 --- a/src/models/creation/CreateAuth.ts +++ b/src/models/creation/CreateAuth.ts @@ -32,14 +32,22 @@ export class CreateAuth { throw new UserNotFoundError() } else { const found_user = found_users[0] - console.log(found_user.password); if (await argon2.verify(found_user.password, this.password + found_user.uuid)) { // TODO: proper jwt creation - const token = jsonwebtoken.sign({}, "securekey") - newAuth.access_token = token - newAuth.refresh_token = token - newAuth.access_token_expires_at = 1587349200 - newAuth.refresh_token_expires_at = 1587349200 + const timestamp_accesstoken_expiry = Math.floor(Date.now() / 1000) + 5 * 60 + newAuth.access_token = jsonwebtoken.sign({ + refreshtokencount: 5, + userdetails: {}, + exp: timestamp_accesstoken_expiry + }, "securekey") + const timestamp_refresh_expiry = Math.floor(Date.now() / 1000) + 10 * 36000 + newAuth.refresh_token = jsonwebtoken.sign({ + refreshtokencount: 5, + userdetails: {}, + exp: timestamp_refresh_expiry + }, "securekey") + newAuth.access_token_expires_at = timestamp_accesstoken_expiry + newAuth.refresh_token_expires_at = timestamp_refresh_expiry } else { throw new InvalidCredentialsError() } From a0fe8c0017d4f594d57e0d3c00305077874f5aa0 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Sat, 5 Dec 2020 12:34:07 +0100 Subject: [PATCH 20/47] =?UTF-8?q?=F0=9F=9A=A7=20CreateAuth=20-=20basic=20j?= =?UTF-8?q?wt=20creation=20with=20user=20details?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref #12 --- src/models/creation/CreateAuth.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/models/creation/CreateAuth.ts b/src/models/creation/CreateAuth.ts index 4580869..f21c026 100644 --- a/src/models/creation/CreateAuth.ts +++ b/src/models/creation/CreateAuth.ts @@ -33,20 +33,20 @@ export class CreateAuth { } else { const found_user = found_users[0] if (await argon2.verify(found_user.password, this.password + found_user.uuid)) { - // TODO: proper jwt creation const timestamp_accesstoken_expiry = Math.floor(Date.now() / 1000) + 5 * 60 + delete found_user.password; newAuth.access_token = jsonwebtoken.sign({ - refreshtokencount: 5, - userdetails: {}, + userdetails: found_user, exp: timestamp_accesstoken_expiry }, "securekey") + newAuth.access_token_expires_at = timestamp_accesstoken_expiry + // const timestamp_refresh_expiry = Math.floor(Date.now() / 1000) + 10 * 36000 newAuth.refresh_token = jsonwebtoken.sign({ refreshtokencount: 5, - userdetails: {}, + userid: found_user.id, exp: timestamp_refresh_expiry }, "securekey") - newAuth.access_token_expires_at = timestamp_accesstoken_expiry newAuth.refresh_token_expires_at = timestamp_refresh_expiry } else { throw new InvalidCredentialsError() From 2f902755c47af829ae3eb6447a5cabe3c0017cf4 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Sat, 5 Dec 2020 12:55:38 +0100 Subject: [PATCH 21/47] =?UTF-8?q?=F0=9F=9A=A7=20starting=20work=20on=20Ref?= =?UTF-8?q?reshAuth?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref #12 --- src/models/creation/RefreshAuth.ts | 36 ++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/models/creation/RefreshAuth.ts diff --git a/src/models/creation/RefreshAuth.ts b/src/models/creation/RefreshAuth.ts new file mode 100644 index 0000000..16233c4 --- /dev/null +++ b/src/models/creation/RefreshAuth.ts @@ -0,0 +1,36 @@ +import { IsString } from 'class-validator'; +import * as jsonwebtoken from 'jsonwebtoken'; +import { getConnectionManager } from 'typeorm'; +import { IllegalJWTError, JwtNotProvidedError, UserNotFoundError } from '../../errors/AuthError'; +import { Auth } from '../entities/Auth'; +import { User } from '../entities/User'; + +export class RefreshAuth { + @IsString() + token: string; + + public async toAuth(): Promise { + let newAuth: Auth = new Auth(); + if (!this.token || this.token === undefined) { + throw new JwtNotProvidedError() + } + let decoded + try { + decoded = jsonwebtoken.verify(this.token, 'securekey') + } catch (error) { + throw new IllegalJWTError() + } + const found_users = await getConnectionManager().get().getRepository(User).findOne({ id: decoded["userid"], refreshTokenCount: decoded["refreshtokencount"] }); + if (!found_users) { + throw new UserNotFoundError() + } else { + const found_user = found_users[0] + delete found_user.password; + newAuth.access_token = "ja" + newAuth.access_token_expires_at = 5555555 + newAuth.refresh_token = "ja" + newAuth.refresh_token_expires_at = 555555 + } + return newAuth; + } +} \ No newline at end of file From 093f6f5f789d58d54f325fcf02fbd1ab3cf09a95 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Sat, 5 Dec 2020 12:59:02 +0100 Subject: [PATCH 22/47] =?UTF-8?q?=F0=9F=9A=A7=20UserNotFoundOrRefreshToken?= =?UTF-8?q?CountInvalidError?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref #12 --- src/errors/AuthError.ts | 11 +++++++++++ src/models/creation/RefreshAuth.ts | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/errors/AuthError.ts b/src/errors/AuthError.ts index cdaa870..e95670d 100644 --- a/src/errors/AuthError.ts +++ b/src/errors/AuthError.ts @@ -87,4 +87,15 @@ export class JwtNotProvidedError extends NotAcceptableError { @IsString() message = "no jwt token was provided" +} + +/** + * Error to thow when user was not found or refresh token count was invalid + */ +export class UserNotFoundOrRefreshTokenCountInvalidError extends NotAcceptableError { + @IsString() + name = "UserNotFoundOrRefreshTokenCountInvalidError" + + @IsString() + message = "user was not found or refresh token count was invalid" } \ No newline at end of file diff --git a/src/models/creation/RefreshAuth.ts b/src/models/creation/RefreshAuth.ts index 16233c4..97e5e4e 100644 --- a/src/models/creation/RefreshAuth.ts +++ b/src/models/creation/RefreshAuth.ts @@ -1,7 +1,7 @@ import { IsString } from 'class-validator'; import * as jsonwebtoken from 'jsonwebtoken'; import { getConnectionManager } from 'typeorm'; -import { IllegalJWTError, JwtNotProvidedError, UserNotFoundError } from '../../errors/AuthError'; +import { IllegalJWTError, JwtNotProvidedError, UserNotFoundOrRefreshTokenCountInvalidError } from '../../errors/AuthError'; import { Auth } from '../entities/Auth'; import { User } from '../entities/User'; @@ -22,7 +22,7 @@ export class RefreshAuth { } const found_users = await getConnectionManager().get().getRepository(User).findOne({ id: decoded["userid"], refreshTokenCount: decoded["refreshtokencount"] }); if (!found_users) { - throw new UserNotFoundError() + throw new UserNotFoundOrRefreshTokenCountInvalidError() } else { const found_user = found_users[0] delete found_user.password; From c0c95056bf0401de0c77032928547c13982c932c Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Sat, 5 Dec 2020 13:06:58 +0100 Subject: [PATCH 23/47] better errors ref #12 --- src/errors/AuthError.ts | 11 +++++++++++ src/models/creation/RefreshAuth.ts | 12 +++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/errors/AuthError.ts b/src/errors/AuthError.ts index e95670d..a03ff24 100644 --- a/src/errors/AuthError.ts +++ b/src/errors/AuthError.ts @@ -98,4 +98,15 @@ export class UserNotFoundOrRefreshTokenCountInvalidError extends NotAcceptableEr @IsString() message = "user was not found or refresh token count was invalid" +} + +/** + * Error to thow when refresh token count was invalid + */ +export class RefreshTokenCountInvalidError extends NotAcceptableError { + @IsString() + name = "RefreshTokenCountInvalidError" + + @IsString() + message = "refresh token count was invalid" } \ No newline at end of file diff --git a/src/models/creation/RefreshAuth.ts b/src/models/creation/RefreshAuth.ts index 97e5e4e..f9010ce 100644 --- a/src/models/creation/RefreshAuth.ts +++ b/src/models/creation/RefreshAuth.ts @@ -1,7 +1,7 @@ import { IsString } from 'class-validator'; import * as jsonwebtoken from 'jsonwebtoken'; import { getConnectionManager } from 'typeorm'; -import { IllegalJWTError, JwtNotProvidedError, UserNotFoundOrRefreshTokenCountInvalidError } from '../../errors/AuthError'; +import { IllegalJWTError, JwtNotProvidedError, RefreshTokenCountInvalidError, UserNotFoundError } from '../../errors/AuthError'; import { Auth } from '../entities/Auth'; import { User } from '../entities/User'; @@ -20,16 +20,18 @@ export class RefreshAuth { } catch (error) { throw new IllegalJWTError() } - const found_users = await getConnectionManager().get().getRepository(User).findOne({ id: decoded["userid"], refreshTokenCount: decoded["refreshtokencount"] }); - if (!found_users) { - throw new UserNotFoundOrRefreshTokenCountInvalidError() - } else { const found_user = found_users[0] delete found_user.password; newAuth.access_token = "ja" newAuth.access_token_expires_at = 5555555 newAuth.refresh_token = "ja" newAuth.refresh_token_expires_at = 555555 + const found_user = await getConnectionManager().get().getRepository(User).findOne({ id: decoded["userid"] }); + if (!found_user) { + throw new UserNotFoundError() + } + if (found_user.refreshTokenCount !== decoded["refreshtokencount"]) { + throw new RefreshTokenCountInvalidError() } return newAuth; } From 82f31185a1aaba1cb3d4e3812ff65ef62d042e4c Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Sat, 5 Dec 2020 13:07:18 +0100 Subject: [PATCH 24/47] =?UTF-8?q?=F0=9F=9A=A7=20CreateAuth=20-=20use=20pro?= =?UTF-8?q?per=20refreshTokenCount?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref #12 --- src/models/creation/CreateAuth.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/creation/CreateAuth.ts b/src/models/creation/CreateAuth.ts index f21c026..5642375 100644 --- a/src/models/creation/CreateAuth.ts +++ b/src/models/creation/CreateAuth.ts @@ -43,7 +43,7 @@ export class CreateAuth { // const timestamp_refresh_expiry = Math.floor(Date.now() / 1000) + 10 * 36000 newAuth.refresh_token = jsonwebtoken.sign({ - refreshtokencount: 5, + refreshtokencount: found_user.refreshTokenCount, userid: found_user.id, exp: timestamp_refresh_expiry }, "securekey") From 126799dab98a8866be2e3f3812b7a76a50d0812d Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Sat, 5 Dec 2020 13:07:33 +0100 Subject: [PATCH 25/47] basic RefreshAuth checking ref #12 --- src/models/creation/RefreshAuth.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/models/creation/RefreshAuth.ts b/src/models/creation/RefreshAuth.ts index f9010ce..96721ab 100644 --- a/src/models/creation/RefreshAuth.ts +++ b/src/models/creation/RefreshAuth.ts @@ -20,12 +20,7 @@ export class RefreshAuth { } catch (error) { throw new IllegalJWTError() } - const found_user = found_users[0] - delete found_user.password; - newAuth.access_token = "ja" - newAuth.access_token_expires_at = 5555555 - newAuth.refresh_token = "ja" - newAuth.refresh_token_expires_at = 555555 + console.log(decoded["userid"]); const found_user = await getConnectionManager().get().getRepository(User).findOne({ id: decoded["userid"] }); if (!found_user) { throw new UserNotFoundError() @@ -33,6 +28,13 @@ export class RefreshAuth { if (found_user.refreshTokenCount !== decoded["refreshtokencount"]) { throw new RefreshTokenCountInvalidError() } + console.log(found_user); + // delete found_user.password; + newAuth.access_token = "ja" + newAuth.access_token_expires_at = 5555555 + newAuth.refresh_token = "ja" + newAuth.refresh_token_expires_at = 555555 + return newAuth; } } \ No newline at end of file From 51addd4a31e63bdaab64b422f35432571af7da23 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Sat, 5 Dec 2020 13:12:47 +0100 Subject: [PATCH 26/47] =?UTF-8?q?=F0=9F=9A=A7=20RefreshAuth=20-=20refresh?= =?UTF-8?q?=20tokens=20now=20working=20=E2=9C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref #12 --- src/models/creation/RefreshAuth.ts | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/models/creation/RefreshAuth.ts b/src/models/creation/RefreshAuth.ts index 96721ab..ab947e6 100644 --- a/src/models/creation/RefreshAuth.ts +++ b/src/models/creation/RefreshAuth.ts @@ -20,7 +20,6 @@ export class RefreshAuth { } catch (error) { throw new IllegalJWTError() } - console.log(decoded["userid"]); const found_user = await getConnectionManager().get().getRepository(User).findOne({ id: decoded["userid"] }); if (!found_user) { throw new UserNotFoundError() @@ -28,12 +27,22 @@ export class RefreshAuth { if (found_user.refreshTokenCount !== decoded["refreshtokencount"]) { throw new RefreshTokenCountInvalidError() } - console.log(found_user); - // delete found_user.password; - newAuth.access_token = "ja" - newAuth.access_token_expires_at = 5555555 - newAuth.refresh_token = "ja" - newAuth.refresh_token_expires_at = 555555 + delete found_user.password; + const timestamp_accesstoken_expiry = Math.floor(Date.now() / 1000) + 5 * 60 + delete found_user.password; + newAuth.access_token = jsonwebtoken.sign({ + userdetails: found_user, + exp: timestamp_accesstoken_expiry + }, "securekey") + newAuth.access_token_expires_at = timestamp_accesstoken_expiry + // + const timestamp_refresh_expiry = Math.floor(Date.now() / 1000) + 10 * 36000 + newAuth.refresh_token = jsonwebtoken.sign({ + refreshtokencount: found_user.refreshTokenCount, + userid: found_user.id, + exp: timestamp_refresh_expiry + }, "securekey") + newAuth.refresh_token_expires_at = timestamp_refresh_expiry return newAuth; } From e5f65d0b801934c0ac3a5d898aa7d8fdee4a35c4 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Sat, 5 Dec 2020 13:30:22 +0100 Subject: [PATCH 27/47] note on refreshtokencount checking ref #12 --- src/middlewares/jwtauth.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/middlewares/jwtauth.ts b/src/middlewares/jwtauth.ts index 3f77265..f83e0cf 100644 --- a/src/middlewares/jwtauth.ts +++ b/src/middlewares/jwtauth.ts @@ -3,11 +3,15 @@ import { ExpressMiddlewareInterface } from "routing-controllers"; -// @Middleware({ type: "before" }) export class JWTAuth implements ExpressMiddlewareInterface { use(request: any, response: any, next?: (err?: any) => any): any { const token = request.headers["auth"]; try { + /** + TODO: idk if we should always check the db if refreshtokencount is valid? + seems like a lot of db overhead + at the same time it's basically our only option to support proper logouts + */ const jwtPayload = jwt.verify(token, "secretjwtsecret"); // const jwtPayload = jwt.verify(token, process.env.JWT_SECRET); response.locals.jwtPayload = jwtPayload; From 0d21497c2fd42602d253067d6f6d42fe7cfee5b5 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Sat, 5 Dec 2020 13:31:46 +0100 Subject: [PATCH 28/47] =?UTF-8?q?=F0=9F=9A=A7=20AuthController=20-=20add?= =?UTF-8?q?=20proper=20response=20schemas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controllers/AuthController.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/controllers/AuthController.ts b/src/controllers/AuthController.ts index d14e574..2264ba5 100644 --- a/src/controllers/AuthController.ts +++ b/src/controllers/AuthController.ts @@ -1,6 +1,6 @@ import { Body, JsonController, Post } from 'routing-controllers'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; -import { InvalidCredentialsError, PasswordNeededError, UsernameOrEmailNeededError } from '../errors/AuthError'; +import { IllegalJWTError, InvalidCredentialsError, JwtNotProvidedError, PasswordNeededError, RefreshTokenCountInvalidError, UsernameOrEmailNeededError } from '../errors/AuthError'; import { UserNotFoundError } from '../errors/UserErrors'; import { CreateAuth } from '../models/creation/CreateAuth'; import { RefreshAuth } from '../models/creation/RefreshAuth'; @@ -29,8 +29,10 @@ export class AuthController { } @Post("/refresh") - @ResponseSchema(InvalidCredentialsError) + @ResponseSchema(JwtNotProvidedError) + @ResponseSchema(IllegalJWTError) @ResponseSchema(UserNotFoundError) + @ResponseSchema(RefreshTokenCountInvalidError) @OpenAPI({ description: 'refresh a access token' }) async refresh(@Body({ validate: true }) refreshAuth: RefreshAuth) { let auth; From 675717f8ca495898e87fb73dca12249065301fb0 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Sat, 5 Dec 2020 13:38:59 +0100 Subject: [PATCH 29/47] =?UTF-8?q?=F0=9F=9A=A7=20starting=20work=20on=20Log?= =?UTF-8?q?outHandler?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref #12 --- src/controllers/AuthController.ts | 19 +++++++++++++++++ src/models/creation/HandleLogout.ts | 33 +++++++++++++++++++++++++++++ src/models/entities/Logout.ts | 17 +++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 src/models/creation/HandleLogout.ts create mode 100644 src/models/entities/Logout.ts diff --git a/src/controllers/AuthController.ts b/src/controllers/AuthController.ts index 2264ba5..90d1c57 100644 --- a/src/controllers/AuthController.ts +++ b/src/controllers/AuthController.ts @@ -3,6 +3,7 @@ import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { IllegalJWTError, InvalidCredentialsError, JwtNotProvidedError, PasswordNeededError, RefreshTokenCountInvalidError, UsernameOrEmailNeededError } from '../errors/AuthError'; import { UserNotFoundError } from '../errors/UserErrors'; import { CreateAuth } from '../models/creation/CreateAuth'; +import { HandleLogout } from '../models/creation/HandleLogout'; import { RefreshAuth } from '../models/creation/RefreshAuth'; @JsonController('/auth') @@ -28,6 +29,24 @@ export class AuthController { return auth } + @Post("/logout") + @ResponseSchema(InvalidCredentialsError) + @ResponseSchema(UserNotFoundError) + @ResponseSchema(UsernameOrEmailNeededError) + @ResponseSchema(PasswordNeededError) + @ResponseSchema(InvalidCredentialsError) + @OpenAPI({ description: 'Create a new access token object' }) + async logout(@Body({ validate: true }) handleLogout: HandleLogout) { + let logout; + try { + logout = await handleLogout.logout() + console.log(logout); + } catch (error) { + return error; + } + return logout + } + @Post("/refresh") @ResponseSchema(JwtNotProvidedError) @ResponseSchema(IllegalJWTError) diff --git a/src/models/creation/HandleLogout.ts b/src/models/creation/HandleLogout.ts new file mode 100644 index 0000000..5404f9b --- /dev/null +++ b/src/models/creation/HandleLogout.ts @@ -0,0 +1,33 @@ +import { IsString } from 'class-validator'; +import * as jsonwebtoken from 'jsonwebtoken'; +import { IllegalJWTError, JwtNotProvidedError } from '../../errors/AuthError'; +import { Logout } from '../entities/Logout'; + +export class HandleLogout { + @IsString() + token: string; + + public async logout(): Promise { + let logout: Logout = new Logout(); + if (!this.token || this.token === undefined) { + throw new JwtNotProvidedError() + } + let decoded + try { + decoded = jsonwebtoken.verify(this.token, 'securekey') + } catch (error) { + throw new IllegalJWTError() + } + logout.access_token = this.token + logout.timestamp = Math.floor(Date.now() / 1000) + // const found_user = await getConnectionManager().get().getRepository(User).findOne({ id: decoded["userid"] }); + // if (!found_user) { + // throw new UserNotFoundError() + // } + // if (found_user.refreshTokenCount !== decoded["refreshtokencount"]) { + // throw new RefreshTokenCountInvalidError() + // } + // TODO: increment refreshtokencount WHERE userid===userid && refreshtokencount===refreshtokencount + return logout; + } +} \ No newline at end of file diff --git a/src/models/entities/Logout.ts b/src/models/entities/Logout.ts new file mode 100644 index 0000000..d24d95f --- /dev/null +++ b/src/models/entities/Logout.ts @@ -0,0 +1,17 @@ +import { IsString } from 'class-validator'; + +/** + * Defines a Logout object +*/ +export class Logout { + /** + * access_token - JWT shortterm access token + */ + @IsString() + access_token: string; + /** + * timestamp of logout + */ + @IsString() + timestamp: number; +} From 8c229dba82ebad03a22231ac821d985a49b45611 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Sat, 5 Dec 2020 13:40:59 +0100 Subject: [PATCH 30/47] add response schemas to AuthController --- src/controllers/AuthController.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/controllers/AuthController.ts b/src/controllers/AuthController.ts index 90d1c57..e8d81cc 100644 --- a/src/controllers/AuthController.ts +++ b/src/controllers/AuthController.ts @@ -5,6 +5,8 @@ import { UserNotFoundError } from '../errors/UserErrors'; import { CreateAuth } from '../models/creation/CreateAuth'; import { HandleLogout } from '../models/creation/HandleLogout'; import { RefreshAuth } from '../models/creation/RefreshAuth'; +import { Auth } from '../models/entities/Auth'; +import { Logout } from '../models/entities/Logout'; @JsonController('/auth') export class AuthController { @@ -12,6 +14,7 @@ export class AuthController { } @Post("/login") + @ResponseSchema(Auth) @ResponseSchema(InvalidCredentialsError) @ResponseSchema(UserNotFoundError) @ResponseSchema(UsernameOrEmailNeededError) @@ -30,6 +33,7 @@ export class AuthController { } @Post("/logout") + @ResponseSchema(Logout) @ResponseSchema(InvalidCredentialsError) @ResponseSchema(UserNotFoundError) @ResponseSchema(UsernameOrEmailNeededError) @@ -48,6 +52,7 @@ export class AuthController { } @Post("/refresh") + @ResponseSchema(Auth) @ResponseSchema(JwtNotProvidedError) @ResponseSchema(IllegalJWTError) @ResponseSchema(UserNotFoundError) From 13d568ba3f9a3c1035a2dd48509bee2567bd06f3 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sat, 5 Dec 2020 17:20:18 +0100 Subject: [PATCH 31/47] implemented refreshcount increase ref #12 --- src/models/creation/HandleLogout.ts | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/models/creation/HandleLogout.ts b/src/models/creation/HandleLogout.ts index 5404f9b..f1527f3 100644 --- a/src/models/creation/HandleLogout.ts +++ b/src/models/creation/HandleLogout.ts @@ -1,7 +1,9 @@ import { IsString } from 'class-validator'; import * as jsonwebtoken from 'jsonwebtoken'; -import { IllegalJWTError, JwtNotProvidedError } from '../../errors/AuthError'; +import { getConnectionManager } from 'typeorm'; +import { IllegalJWTError, JwtNotProvidedError, RefreshTokenCountInvalidError, UserNotFoundError } from '../../errors/AuthError'; import { Logout } from '../entities/Logout'; +import { User } from '../entities/User'; export class HandleLogout { @IsString() @@ -12,7 +14,7 @@ export class HandleLogout { if (!this.token || this.token === undefined) { throw new JwtNotProvidedError() } - let decoded + let decoded; try { decoded = jsonwebtoken.verify(this.token, 'securekey') } catch (error) { @@ -20,14 +22,15 @@ export class HandleLogout { } logout.access_token = this.token logout.timestamp = Math.floor(Date.now() / 1000) - // const found_user = await getConnectionManager().get().getRepository(User).findOne({ id: decoded["userid"] }); - // if (!found_user) { - // throw new UserNotFoundError() - // } - // if (found_user.refreshTokenCount !== decoded["refreshtokencount"]) { - // throw new RefreshTokenCountInvalidError() - // } - // TODO: increment refreshtokencount WHERE userid===userid && refreshtokencount===refreshtokencount + let found_user: User = await getConnectionManager().get().getRepository(User).findOne({ id: decoded["userid"] }); + if (!found_user) { + throw new UserNotFoundError() + } + if (found_user.refreshTokenCount !== decoded["refreshtokencount"]) { + throw new RefreshTokenCountInvalidError() + } + found_user.refreshTokenCount++; + getConnectionManager().get().getRepository(User).update({ id: found_user.id }, found_user) return logout; } } \ No newline at end of file From 7e4ce00c30acd4eaa188fdee524cee1c19948faf Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sat, 5 Dec 2020 17:20:39 +0100 Subject: [PATCH 32/47] added await (async stuff und so) ref #12 --- src/models/creation/HandleLogout.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/creation/HandleLogout.ts b/src/models/creation/HandleLogout.ts index f1527f3..d1ee7b8 100644 --- a/src/models/creation/HandleLogout.ts +++ b/src/models/creation/HandleLogout.ts @@ -30,7 +30,7 @@ export class HandleLogout { throw new RefreshTokenCountInvalidError() } found_user.refreshTokenCount++; - getConnectionManager().get().getRepository(User).update({ id: found_user.id }, found_user) + await getConnectionManager().get().getRepository(User).update({ id: found_user.id }, found_user) return logout; } } \ No newline at end of file From e5b605cc55715e92885ddb1fefe930b79449c430 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Sat, 5 Dec 2020 17:25:57 +0100 Subject: [PATCH 33/47] =?UTF-8?q?=F0=9F=A7=B9=20cleanups?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controllers/AuthController.ts | 4 ++-- src/models/creation/CreateAuth.ts | 2 +- src/models/creation/HandleLogout.ts | 3 +-- src/models/creation/RefreshAuth.ts | 2 +- src/models/{entities => responses}/Auth.ts | 0 src/models/{entities => responses}/Logout.ts | 5 ----- 6 files changed, 5 insertions(+), 11 deletions(-) rename src/models/{entities => responses}/Auth.ts (100%) rename src/models/{entities => responses}/Logout.ts (64%) diff --git a/src/controllers/AuthController.ts b/src/controllers/AuthController.ts index e8d81cc..4e5ced1 100644 --- a/src/controllers/AuthController.ts +++ b/src/controllers/AuthController.ts @@ -5,8 +5,8 @@ import { UserNotFoundError } from '../errors/UserErrors'; import { CreateAuth } from '../models/creation/CreateAuth'; import { HandleLogout } from '../models/creation/HandleLogout'; import { RefreshAuth } from '../models/creation/RefreshAuth'; -import { Auth } from '../models/entities/Auth'; -import { Logout } from '../models/entities/Logout'; +import { Auth } from '../models/responses/Auth'; +import { Logout } from '../models/responses/Logout'; @JsonController('/auth') export class AuthController { diff --git a/src/models/creation/CreateAuth.ts b/src/models/creation/CreateAuth.ts index 5642375..140f9ef 100644 --- a/src/models/creation/CreateAuth.ts +++ b/src/models/creation/CreateAuth.ts @@ -4,8 +4,8 @@ import * as jsonwebtoken from 'jsonwebtoken'; import { getConnectionManager } from 'typeorm'; import { InvalidCredentialsError, PasswordNeededError, UserNotFoundError } from '../../errors/AuthError'; import { UsernameOrEmailNeededError } from '../../errors/UserErrors'; -import { Auth } from '../entities/Auth'; import { User } from '../entities/User'; +import { Auth } from '../responses/Auth'; export class CreateAuth { @IsOptional() diff --git a/src/models/creation/HandleLogout.ts b/src/models/creation/HandleLogout.ts index d1ee7b8..c50edd0 100644 --- a/src/models/creation/HandleLogout.ts +++ b/src/models/creation/HandleLogout.ts @@ -2,8 +2,8 @@ import { IsString } from 'class-validator'; import * as jsonwebtoken from 'jsonwebtoken'; import { getConnectionManager } from 'typeorm'; import { IllegalJWTError, JwtNotProvidedError, RefreshTokenCountInvalidError, UserNotFoundError } from '../../errors/AuthError'; -import { Logout } from '../entities/Logout'; import { User } from '../entities/User'; +import { Logout } from '../responses/Logout'; export class HandleLogout { @IsString() @@ -20,7 +20,6 @@ export class HandleLogout { } catch (error) { throw new IllegalJWTError() } - logout.access_token = this.token logout.timestamp = Math.floor(Date.now() / 1000) let found_user: User = await getConnectionManager().get().getRepository(User).findOne({ id: decoded["userid"] }); if (!found_user) { diff --git a/src/models/creation/RefreshAuth.ts b/src/models/creation/RefreshAuth.ts index ab947e6..66e27f8 100644 --- a/src/models/creation/RefreshAuth.ts +++ b/src/models/creation/RefreshAuth.ts @@ -2,8 +2,8 @@ import { IsString } from 'class-validator'; import * as jsonwebtoken from 'jsonwebtoken'; import { getConnectionManager } from 'typeorm'; import { IllegalJWTError, JwtNotProvidedError, RefreshTokenCountInvalidError, UserNotFoundError } from '../../errors/AuthError'; -import { Auth } from '../entities/Auth'; import { User } from '../entities/User'; +import { Auth } from '../responses/Auth'; export class RefreshAuth { @IsString() diff --git a/src/models/entities/Auth.ts b/src/models/responses/Auth.ts similarity index 100% rename from src/models/entities/Auth.ts rename to src/models/responses/Auth.ts diff --git a/src/models/entities/Logout.ts b/src/models/responses/Logout.ts similarity index 64% rename from src/models/entities/Logout.ts rename to src/models/responses/Logout.ts index d24d95f..f0c109d 100644 --- a/src/models/entities/Logout.ts +++ b/src/models/responses/Logout.ts @@ -4,11 +4,6 @@ import { IsString } from 'class-validator'; * Defines a Logout object */ export class Logout { - /** - * access_token - JWT shortterm access token - */ - @IsString() - access_token: string; /** * timestamp of logout */ From 5a4a6cdcefd96ddc413232841af8b596580d941f Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sat, 5 Dec 2020 17:47:32 +0100 Subject: [PATCH 34/47] Added basic openapi security scheme for the bearer auth header ref #12 --- src/loaders/openapi.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/loaders/openapi.ts b/src/loaders/openapi.ts index 9a0ff85..fe0c77a 100644 --- a/src/loaders/openapi.ts +++ b/src/loaders/openapi.ts @@ -1,8 +1,8 @@ +import { validationMetadatasToSchemas } from "class-validator-jsonschema"; import { Application } from "express"; -import * as swaggerUiExpress from "swagger-ui-express"; import { getMetadataArgsStorage } from "routing-controllers"; import { routingControllersToSpec } from "routing-controllers-openapi"; -import { validationMetadatasToSchemas } from "class-validator-jsonschema"; +import * as swaggerUiExpress from "swagger-ui-express"; export default async (app: Application) => { const storage = getMetadataArgsStorage(); @@ -17,6 +17,13 @@ export default async (app: Application) => { { components: { schemas, + "securitySchemes": { + "AuthToken": { + "type": "http", + "scheme": "bearer", + "bearerFormat": "JWT" + } + } }, info: { description: "The the backend API for the LfK! runner system.", From 76e19ca28dc183f698049080b62e88f9feddf036 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Sat, 5 Dec 2020 17:59:43 +0100 Subject: [PATCH 35/47] implement proper jwt checking in authchecker ref #12 --- src/app.ts | 3 +-- src/authchecker.ts | 13 ++++++++++--- src/errors/AuthError.ts | 11 +++++++++++ src/middlewares/jwtauth.ts | 24 ------------------------ 4 files changed, 22 insertions(+), 29 deletions(-) delete mode 100644 src/middlewares/jwtauth.ts diff --git a/src/app.ts b/src/app.ts index e54f0ac..e19d313 100644 --- a/src/app.ts +++ b/src/app.ts @@ -5,14 +5,13 @@ import { createExpressServer } from "routing-controllers"; import authchecker from "./authchecker"; import loaders from "./loaders/index"; import { ErrorHandler } from './middlewares/ErrorHandler'; -import { JWTAuth } from './middlewares/JWTAuth'; dotenvSafe.config(); const PORT = process.env.APP_PORT || 4010; const app = createExpressServer({ authorizationChecker: authchecker, - middlewares: [ErrorHandler, JWTAuth], + middlewares: [ErrorHandler], development: process.env.NODE_ENV === "production", cors: true, routePrefix: "/api", diff --git a/src/authchecker.ts b/src/authchecker.ts index f32ec75..4264130 100644 --- a/src/authchecker.ts +++ b/src/authchecker.ts @@ -1,13 +1,15 @@ import * as jwt from "jsonwebtoken"; import { Action } from "routing-controllers"; -import { IllegalJWTError, NoPermissionError } from './errors/AuthError'; +import { getConnectionManager } from 'typeorm'; +import { IllegalJWTError, NoPermissionError, UserNonexistantOrRefreshtokenInvalidError } from './errors/AuthError'; +import { User } from './models/entities/User'; // ----------- const sampletoken = jwt.sign({ "permissions": { "TRACKS": ["read", "update", "delete", "add"] // "TRACKS": [] } -}, process.env.JWT_SECRET || "secretjwtsecret") +}, "securekey") console.log(`sampletoken: ${sampletoken}`); // ----------- const authchecker = async (action: Action, permissions: string | string[]) => { @@ -21,10 +23,15 @@ const authchecker = async (action: Action, permissions: string | string[]) => { const provided_token = action.request.query["auth"]; let jwtPayload = undefined try { - jwtPayload = jwt.verify(provided_token, process.env.JWT_SECRET || "secretjwtsecret"); + jwtPayload = jwt.verify(provided_token, "securekey"); } catch (error) { + console.log(error); throw new IllegalJWTError() } + const count = await getConnectionManager().get().getRepository(User).count({ id: jwtPayload["userdetails"]["id"], refreshTokenCount: jwtPayload["userdetails"]["refreshTokenCount"] }) + if (count !== 1) { + throw new UserNonexistantOrRefreshtokenInvalidError() + } if (jwtPayload.permissions) { action.response.local = {} action.response.local.jwtPayload = jwtPayload.permissions diff --git a/src/errors/AuthError.ts b/src/errors/AuthError.ts index a03ff24..2c2ce5b 100644 --- a/src/errors/AuthError.ts +++ b/src/errors/AuthError.ts @@ -23,6 +23,17 @@ export class IllegalJWTError extends UnauthorizedError { message = "your provided jwt could not be parsed" } +/** + * Error to throw when user is nonexistant or refreshtoken is invalid + */ +export class UserNonexistantOrRefreshtokenInvalidError extends UnauthorizedError { + @IsString() + name = "UserNonexistantOrRefreshtokenInvalidError" + + @IsString() + message = "user is nonexistant or refreshtoken is invalid" +} + /** * Error to throw when provided credentials are invalid */ diff --git a/src/middlewares/jwtauth.ts b/src/middlewares/jwtauth.ts deleted file mode 100644 index f83e0cf..0000000 --- a/src/middlewares/jwtauth.ts +++ /dev/null @@ -1,24 +0,0 @@ -import * as jwt from "jsonwebtoken"; -import { - ExpressMiddlewareInterface -} from "routing-controllers"; - -export class JWTAuth implements ExpressMiddlewareInterface { - use(request: any, response: any, next?: (err?: any) => any): any { - const token = request.headers["auth"]; - try { - /** - TODO: idk if we should always check the db if refreshtokencount is valid? - seems like a lot of db overhead - at the same time it's basically our only option to support proper logouts - */ - const jwtPayload = jwt.verify(token, "secretjwtsecret"); - // const jwtPayload = jwt.verify(token, process.env.JWT_SECRET); - response.locals.jwtPayload = jwtPayload; - } catch (error) { - console.log(error); - return response.status(401).send(); - } - next(); - } -} From 740d7f10f5ede09846d5a4d3a482bf750cb13698 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Sat, 5 Dec 2020 18:02:49 +0100 Subject: [PATCH 36/47] remove routes/v1/test --- src/routes/v1/test.ts | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 src/routes/v1/test.ts diff --git a/src/routes/v1/test.ts b/src/routes/v1/test.ts deleted file mode 100644 index 7f000f5..0000000 --- a/src/routes/v1/test.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Router } from "express"; -import jwtauth from "../../middlewares/jwtauth"; - -const router = Router(); - -router.use("*", jwtauth, async (req, res, next) => { - return res.send("ok"); -}); - -export default router; From 5c259484ee5a4063bcf71bd847413014ec848a00 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Sat, 5 Dec 2020 18:02:57 +0100 Subject: [PATCH 37/47] remove sampletoken generation --- src/authchecker.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/authchecker.ts b/src/authchecker.ts index 4264130..f61f35f 100644 --- a/src/authchecker.ts +++ b/src/authchecker.ts @@ -4,14 +4,6 @@ import { getConnectionManager } from 'typeorm'; import { IllegalJWTError, NoPermissionError, UserNonexistantOrRefreshtokenInvalidError } from './errors/AuthError'; import { User } from './models/entities/User'; // ----------- -const sampletoken = jwt.sign({ - "permissions": { - "TRACKS": ["read", "update", "delete", "add"] - // "TRACKS": [] - } -}, "securekey") -console.log(`sampletoken: ${sampletoken}`); -// ----------- const authchecker = async (action: Action, permissions: string | string[]) => { let required_permissions = undefined if (typeof permissions === "string") { From 0e924449d60c994c29b95abba675309e31c04383 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sat, 5 Dec 2020 18:45:47 +0100 Subject: [PATCH 38/47] Cleanup: Renamed the creation folder to the more fitting "actions" ref #11 #13 --- src/controllers/AuthController.ts | 6 ++--- src/controllers/RunnerController.ts | 2 +- .../RunnerOrganisationController.ts | 2 +- src/controllers/RunnerTeamController.ts | 2 +- src/controllers/TrackController.ts | 2 +- src/controllers/UserController.ts | 2 +- src/controllers/UserGroupController.ts | 2 +- .../{creation => actions}/CreateAddress.ts | 0 .../{creation => actions}/CreateAuth.ts | 0 .../CreateGroupContact.ts | 0 .../CreateParticipant.ts | 0 .../{creation => actions}/CreateRunner.ts | 0 .../CreateRunnerGroup.ts | 0 .../CreateRunnerOrganisation.ts | 0 .../{creation => actions}/CreateRunnerTeam.ts | 0 .../{creation => actions}/CreateTrack.ts | 0 .../{creation => actions}/CreateUser.ts | 0 .../{creation => actions}/CreateUserGroup.ts | 0 .../{creation => actions}/HandleLogout.ts | 0 .../{creation => actions}/RefreshAuth.ts | 0 src/tests.ts | 23 +++++++++++++++++++ 21 files changed, 32 insertions(+), 9 deletions(-) rename src/models/{creation => actions}/CreateAddress.ts (100%) rename src/models/{creation => actions}/CreateAuth.ts (100%) rename src/models/{creation => actions}/CreateGroupContact.ts (100%) rename src/models/{creation => actions}/CreateParticipant.ts (100%) rename src/models/{creation => actions}/CreateRunner.ts (100%) rename src/models/{creation => actions}/CreateRunnerGroup.ts (100%) rename src/models/{creation => actions}/CreateRunnerOrganisation.ts (100%) rename src/models/{creation => actions}/CreateRunnerTeam.ts (100%) rename src/models/{creation => actions}/CreateTrack.ts (100%) rename src/models/{creation => actions}/CreateUser.ts (100%) rename src/models/{creation => actions}/CreateUserGroup.ts (100%) rename src/models/{creation => actions}/HandleLogout.ts (100%) rename src/models/{creation => actions}/RefreshAuth.ts (100%) create mode 100644 src/tests.ts diff --git a/src/controllers/AuthController.ts b/src/controllers/AuthController.ts index 4e5ced1..d5320a3 100644 --- a/src/controllers/AuthController.ts +++ b/src/controllers/AuthController.ts @@ -2,9 +2,9 @@ import { Body, JsonController, Post } from 'routing-controllers'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { IllegalJWTError, InvalidCredentialsError, JwtNotProvidedError, PasswordNeededError, RefreshTokenCountInvalidError, UsernameOrEmailNeededError } from '../errors/AuthError'; import { UserNotFoundError } from '../errors/UserErrors'; -import { CreateAuth } from '../models/creation/CreateAuth'; -import { HandleLogout } from '../models/creation/HandleLogout'; -import { RefreshAuth } from '../models/creation/RefreshAuth'; +import { CreateAuth } from '../models/actions/CreateAuth'; +import { HandleLogout } from '../models/actions/HandleLogout'; +import { RefreshAuth } from '../models/actions/RefreshAuth'; import { Auth } from '../models/responses/Auth'; import { Logout } from '../models/responses/Logout'; diff --git a/src/controllers/RunnerController.ts b/src/controllers/RunnerController.ts index 6508f67..8293f36 100644 --- a/src/controllers/RunnerController.ts +++ b/src/controllers/RunnerController.ts @@ -3,7 +3,7 @@ import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { getConnectionManager, Repository } from 'typeorm'; import { EntityFromBody, EntityFromParam } from 'typeorm-routing-controllers-extensions'; import { RunnerGroupNeededError, RunnerGroupNotFoundError, RunnerIdsNotMatchingError, RunnerNotFoundError, RunnerOnlyOneGroupAllowedError } from '../errors/RunnerErrors'; -import { CreateRunner } from '../models/creation/CreateRunner'; +import { CreateRunner } from '../models/actions/CreateRunner'; import { Runner } from '../models/entities/Runner'; import { ResponseRunner } from '../models/responses/ResponseRunner'; diff --git a/src/controllers/RunnerOrganisationController.ts b/src/controllers/RunnerOrganisationController.ts index 8cfef6a..1a598e5 100644 --- a/src/controllers/RunnerOrganisationController.ts +++ b/src/controllers/RunnerOrganisationController.ts @@ -3,7 +3,7 @@ import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { getConnectionManager, Repository } from 'typeorm'; import { EntityFromBody, EntityFromParam } from 'typeorm-routing-controllers-extensions'; import { RunnerOrganisationHasRunnersError, RunnerOrganisationHasTeamsError, RunnerOrganisationIdsNotMatchingError, RunnerOrganisationNotFoundError } from '../errors/RunnerOrganisationErrors'; -import { CreateRunnerOrganisation } from '../models/creation/CreateRunnerOrganisation'; +import { CreateRunnerOrganisation } from '../models/actions/CreateRunnerOrganisation'; import { RunnerOrganisation } from '../models/entities/RunnerOrganisation'; import { ResponseRunnerOrganisation } from '../models/responses/ResponseRunnerOrganisation'; import { RunnerController } from './RunnerController'; diff --git a/src/controllers/RunnerTeamController.ts b/src/controllers/RunnerTeamController.ts index 1b7627d..7b0a841 100644 --- a/src/controllers/RunnerTeamController.ts +++ b/src/controllers/RunnerTeamController.ts @@ -3,7 +3,7 @@ import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { getConnectionManager, Repository } from 'typeorm'; import { EntityFromBody, EntityFromParam } from 'typeorm-routing-controllers-extensions'; import { RunnerTeamHasRunnersError, RunnerTeamIdsNotMatchingError, RunnerTeamNotFoundError } from '../errors/RunnerTeamErrors'; -import { CreateRunnerTeam } from '../models/creation/CreateRunnerTeam'; +import { CreateRunnerTeam } from '../models/actions/CreateRunnerTeam'; import { RunnerTeam } from '../models/entities/RunnerTeam'; import { ResponseRunnerTeam } from '../models/responses/ResponseRunnerTeam'; import { RunnerController } from './RunnerController'; diff --git a/src/controllers/TrackController.ts b/src/controllers/TrackController.ts index 02370fc..149b837 100644 --- a/src/controllers/TrackController.ts +++ b/src/controllers/TrackController.ts @@ -3,7 +3,7 @@ import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { getConnectionManager, Repository } from 'typeorm'; import { EntityFromBody, EntityFromParam } from 'typeorm-routing-controllers-extensions'; import { TrackIdsNotMatchingError, TrackNotFoundError } from "../errors/TrackErrors"; -import { CreateTrack } from '../models/creation/CreateTrack'; +import { CreateTrack } from '../models/actions/CreateTrack'; import { Track } from '../models/entities/Track'; import { ResponseTrack } from '../models/responses/ResponseTrack'; diff --git a/src/controllers/UserController.ts b/src/controllers/UserController.ts index 01e743e..8c2f2ea 100644 --- a/src/controllers/UserController.ts +++ b/src/controllers/UserController.ts @@ -3,7 +3,7 @@ import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { getConnectionManager, Repository } from 'typeorm'; import { EntityFromBody, EntityFromParam } from 'typeorm-routing-controllers-extensions'; import { UserGroupNotFoundError, UserIdsNotMatchingError, UserNotFoundError } from '../errors/UserErrors'; -import { CreateUser } from '../models/creation/CreateUser'; +import { CreateUser } from '../models/actions/CreateUser'; import { User } from '../models/entities/User'; diff --git a/src/controllers/UserGroupController.ts b/src/controllers/UserGroupController.ts index c937f36..70e3c5a 100644 --- a/src/controllers/UserGroupController.ts +++ b/src/controllers/UserGroupController.ts @@ -3,7 +3,7 @@ import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { getConnectionManager, Repository } from 'typeorm'; import { EntityFromBody, EntityFromParam } from 'typeorm-routing-controllers-extensions'; import { UserGroupIdsNotMatchingError, UserGroupNotFoundError } from '../errors/UserGroupErrors'; -import { CreateUserGroup } from '../models/creation/CreateUserGroup'; +import { CreateUserGroup } from '../models/actions/CreateUserGroup'; import { UserGroup } from '../models/entities/UserGroup'; diff --git a/src/models/creation/CreateAddress.ts b/src/models/actions/CreateAddress.ts similarity index 100% rename from src/models/creation/CreateAddress.ts rename to src/models/actions/CreateAddress.ts diff --git a/src/models/creation/CreateAuth.ts b/src/models/actions/CreateAuth.ts similarity index 100% rename from src/models/creation/CreateAuth.ts rename to src/models/actions/CreateAuth.ts diff --git a/src/models/creation/CreateGroupContact.ts b/src/models/actions/CreateGroupContact.ts similarity index 100% rename from src/models/creation/CreateGroupContact.ts rename to src/models/actions/CreateGroupContact.ts diff --git a/src/models/creation/CreateParticipant.ts b/src/models/actions/CreateParticipant.ts similarity index 100% rename from src/models/creation/CreateParticipant.ts rename to src/models/actions/CreateParticipant.ts diff --git a/src/models/creation/CreateRunner.ts b/src/models/actions/CreateRunner.ts similarity index 100% rename from src/models/creation/CreateRunner.ts rename to src/models/actions/CreateRunner.ts diff --git a/src/models/creation/CreateRunnerGroup.ts b/src/models/actions/CreateRunnerGroup.ts similarity index 100% rename from src/models/creation/CreateRunnerGroup.ts rename to src/models/actions/CreateRunnerGroup.ts diff --git a/src/models/creation/CreateRunnerOrganisation.ts b/src/models/actions/CreateRunnerOrganisation.ts similarity index 100% rename from src/models/creation/CreateRunnerOrganisation.ts rename to src/models/actions/CreateRunnerOrganisation.ts diff --git a/src/models/creation/CreateRunnerTeam.ts b/src/models/actions/CreateRunnerTeam.ts similarity index 100% rename from src/models/creation/CreateRunnerTeam.ts rename to src/models/actions/CreateRunnerTeam.ts diff --git a/src/models/creation/CreateTrack.ts b/src/models/actions/CreateTrack.ts similarity index 100% rename from src/models/creation/CreateTrack.ts rename to src/models/actions/CreateTrack.ts diff --git a/src/models/creation/CreateUser.ts b/src/models/actions/CreateUser.ts similarity index 100% rename from src/models/creation/CreateUser.ts rename to src/models/actions/CreateUser.ts diff --git a/src/models/creation/CreateUserGroup.ts b/src/models/actions/CreateUserGroup.ts similarity index 100% rename from src/models/creation/CreateUserGroup.ts rename to src/models/actions/CreateUserGroup.ts diff --git a/src/models/creation/HandleLogout.ts b/src/models/actions/HandleLogout.ts similarity index 100% rename from src/models/creation/HandleLogout.ts rename to src/models/actions/HandleLogout.ts diff --git a/src/models/creation/RefreshAuth.ts b/src/models/actions/RefreshAuth.ts similarity index 100% rename from src/models/creation/RefreshAuth.ts rename to src/models/actions/RefreshAuth.ts diff --git a/src/tests.ts b/src/tests.ts new file mode 100644 index 0000000..bf43e1e --- /dev/null +++ b/src/tests.ts @@ -0,0 +1,23 @@ +import * as dotenvSafe from "dotenv-safe"; +import "reflect-metadata"; +import { createExpressServer } from "routing-controllers"; +import authchecker from "./authchecker"; +import loaders from "./loaders/index"; +import { ErrorHandler } from './middlewares/ErrorHandler'; + +dotenvSafe.config(); +const PORT = process.env.APP_PORT || 4010; + +const app = createExpressServer({ + authorizationChecker: authchecker, + middlewares: [ErrorHandler], + development: process.env.NODE_ENV === "production", + cors: true, + routePrefix: "/api", + controllers: [__dirname + "/controllers/*.ts"], +}); + +async function main() { + await loaders(app); +} +main(); From 61e7ae4f86e0453c0efa15f151271d674ea0a44d Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sat, 5 Dec 2020 18:49:13 +0100 Subject: [PATCH 39/47] Cleanup: Renamed Responses to represent their response nature ref #11 #13 #14 --- src/controllers/AuthController.ts | 4 ++-- src/models/actions/CreateAuth.ts | 2 +- src/models/actions/HandleLogout.ts | 2 +- src/models/actions/RefreshAuth.ts | 2 +- src/models/responses/{Auth.ts => ResponseAuth.ts} | 0 src/models/responses/{Logout.ts => ResponseLogout.ts} | 0 6 files changed, 5 insertions(+), 5 deletions(-) rename src/models/responses/{Auth.ts => ResponseAuth.ts} (100%) rename src/models/responses/{Logout.ts => ResponseLogout.ts} (100%) diff --git a/src/controllers/AuthController.ts b/src/controllers/AuthController.ts index d5320a3..435f3ca 100644 --- a/src/controllers/AuthController.ts +++ b/src/controllers/AuthController.ts @@ -5,8 +5,8 @@ import { UserNotFoundError } from '../errors/UserErrors'; import { CreateAuth } from '../models/actions/CreateAuth'; import { HandleLogout } from '../models/actions/HandleLogout'; import { RefreshAuth } from '../models/actions/RefreshAuth'; -import { Auth } from '../models/responses/Auth'; -import { Logout } from '../models/responses/Logout'; +import { Auth } from '../models/responses/ResponseAuth'; +import { Logout } from '../models/responses/ResponseLogout'; @JsonController('/auth') export class AuthController { diff --git a/src/models/actions/CreateAuth.ts b/src/models/actions/CreateAuth.ts index 140f9ef..bf8584c 100644 --- a/src/models/actions/CreateAuth.ts +++ b/src/models/actions/CreateAuth.ts @@ -5,7 +5,7 @@ import { getConnectionManager } from 'typeorm'; import { InvalidCredentialsError, PasswordNeededError, UserNotFoundError } from '../../errors/AuthError'; import { UsernameOrEmailNeededError } from '../../errors/UserErrors'; import { User } from '../entities/User'; -import { Auth } from '../responses/Auth'; +import { Auth } from '../responses/ResponseAuth'; export class CreateAuth { @IsOptional() diff --git a/src/models/actions/HandleLogout.ts b/src/models/actions/HandleLogout.ts index c50edd0..7b68d91 100644 --- a/src/models/actions/HandleLogout.ts +++ b/src/models/actions/HandleLogout.ts @@ -3,7 +3,7 @@ import * as jsonwebtoken from 'jsonwebtoken'; import { getConnectionManager } from 'typeorm'; import { IllegalJWTError, JwtNotProvidedError, RefreshTokenCountInvalidError, UserNotFoundError } from '../../errors/AuthError'; import { User } from '../entities/User'; -import { Logout } from '../responses/Logout'; +import { Logout } from '../responses/ResponseLogout'; export class HandleLogout { @IsString() diff --git a/src/models/actions/RefreshAuth.ts b/src/models/actions/RefreshAuth.ts index 66e27f8..6e61a75 100644 --- a/src/models/actions/RefreshAuth.ts +++ b/src/models/actions/RefreshAuth.ts @@ -3,7 +3,7 @@ import * as jsonwebtoken from 'jsonwebtoken'; import { getConnectionManager } from 'typeorm'; import { IllegalJWTError, JwtNotProvidedError, RefreshTokenCountInvalidError, UserNotFoundError } from '../../errors/AuthError'; import { User } from '../entities/User'; -import { Auth } from '../responses/Auth'; +import { Auth } from '../responses/ResponseAuth'; export class RefreshAuth { @IsString() diff --git a/src/models/responses/Auth.ts b/src/models/responses/ResponseAuth.ts similarity index 100% rename from src/models/responses/Auth.ts rename to src/models/responses/ResponseAuth.ts diff --git a/src/models/responses/Logout.ts b/src/models/responses/ResponseLogout.ts similarity index 100% rename from src/models/responses/Logout.ts rename to src/models/responses/ResponseLogout.ts From 21ad622c10712ae36fb0c5e1519fc3ecba6341ae Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sat, 5 Dec 2020 18:49:59 +0100 Subject: [PATCH 40/47] Removed console logs ref #11 --- src/controllers/AuthController.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/controllers/AuthController.ts b/src/controllers/AuthController.ts index 435f3ca..00380cb 100644 --- a/src/controllers/AuthController.ts +++ b/src/controllers/AuthController.ts @@ -25,7 +25,6 @@ export class AuthController { let auth; try { auth = await createAuth.toAuth(); - console.log(auth); } catch (error) { return error; } @@ -44,7 +43,6 @@ export class AuthController { let logout; try { logout = await handleLogout.logout() - console.log(logout); } catch (error) { return error; } @@ -62,7 +60,6 @@ export class AuthController { let auth; try { auth = await refreshAuth.toAuth(); - console.log(auth); } catch (error) { return error; } From 1ae466a6f4618ca41beaffb64a673a5a66ca4901 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sat, 5 Dec 2020 19:01:30 +0100 Subject: [PATCH 41/47] Error cleanup #11 #13 #14 --- src/controllers/RunnerController.ts | 4 ++-- src/controllers/UserController.ts | 3 ++- src/errors/AddressErrors.ts | 6 ++++++ src/errors/AuthError.ts | 20 ++++++++++---------- src/errors/GroupContactErrors.ts | 6 ++++++ src/errors/RunnerErrors.ts | 20 +++----------------- src/errors/RunnerGroupErrors.ts | 14 ++++++++++++++ src/errors/RunnerOrganisationErrors.ts | 3 +++ src/errors/UserErrors.ts | 10 ---------- src/models/actions/CreateRunner.ts | 2 +- src/models/actions/CreateUser.ts | 3 ++- 11 files changed, 49 insertions(+), 42 deletions(-) create mode 100644 src/errors/RunnerGroupErrors.ts diff --git a/src/controllers/RunnerController.ts b/src/controllers/RunnerController.ts index 8293f36..acee2eb 100644 --- a/src/controllers/RunnerController.ts +++ b/src/controllers/RunnerController.ts @@ -2,7 +2,8 @@ import { Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, Query import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { getConnectionManager, Repository } from 'typeorm'; import { EntityFromBody, EntityFromParam } from 'typeorm-routing-controllers-extensions'; -import { RunnerGroupNeededError, RunnerGroupNotFoundError, RunnerIdsNotMatchingError, RunnerNotFoundError, RunnerOnlyOneGroupAllowedError } from '../errors/RunnerErrors'; +import { RunnerGroupNeededError, RunnerIdsNotMatchingError, RunnerNotFoundError } from '../errors/RunnerErrors'; +import { RunnerGroupNotFoundError } from '../errors/RunnerGroupErrors'; import { CreateRunner } from '../models/actions/CreateRunner'; import { Runner } from '../models/entities/Runner'; import { ResponseRunner } from '../models/responses/ResponseRunner'; @@ -43,7 +44,6 @@ export class RunnerController { @Post() @ResponseSchema(ResponseRunner) - @ResponseSchema(RunnerOnlyOneGroupAllowedError) @ResponseSchema(RunnerGroupNeededError) @ResponseSchema(RunnerGroupNotFoundError) @OpenAPI({ description: 'Create a new runner object (id will be generated automagicly).' }) diff --git a/src/controllers/UserController.ts b/src/controllers/UserController.ts index 8c2f2ea..f833f54 100644 --- a/src/controllers/UserController.ts +++ b/src/controllers/UserController.ts @@ -2,7 +2,8 @@ import { Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put } from import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { getConnectionManager, Repository } from 'typeorm'; import { EntityFromBody, EntityFromParam } from 'typeorm-routing-controllers-extensions'; -import { UserGroupNotFoundError, UserIdsNotMatchingError, UserNotFoundError } from '../errors/UserErrors'; +import { UserIdsNotMatchingError, UserNotFoundError } from '../errors/UserErrors'; +import { UserGroupNotFoundError } from '../errors/UserGroupErrors'; import { CreateUser } from '../models/actions/CreateUser'; import { User } from '../models/entities/User'; diff --git a/src/errors/AddressErrors.ts b/src/errors/AddressErrors.ts index c7ae8af..18cf624 100644 --- a/src/errors/AddressErrors.ts +++ b/src/errors/AddressErrors.ts @@ -1,6 +1,9 @@ import { IsString } from 'class-validator'; import { NotAcceptableError, NotFoundError } from 'routing-controllers'; +/** + * Error to throw, when to provided address doesn't belong to the accepted types. + */ export class AddressWrongTypeError extends NotAcceptableError { @IsString() name = "AddressWrongTypeError" @@ -9,6 +12,9 @@ export class AddressWrongTypeError extends NotAcceptableError { message = "The address must be an existing adress's id. \n You provided a object of another type." } +/** + * Error to throw, when a non-existant address get's loaded. + */ export class AddressNotFoundError extends NotFoundError { @IsString() name = "AddressNotFoundError" diff --git a/src/errors/AuthError.ts b/src/errors/AuthError.ts index 2c2ce5b..ebd5c00 100644 --- a/src/errors/AuthError.ts +++ b/src/errors/AuthError.ts @@ -2,7 +2,7 @@ import { IsString } from 'class-validator'; import { ForbiddenError, NotAcceptableError, NotFoundError, UnauthorizedError } from 'routing-controllers'; /** - * Error to throw when a jwt is expired + * Error to throw when a jwt is expired. */ export class ExpiredJWTError extends UnauthorizedError { @IsString() @@ -13,7 +13,7 @@ export class ExpiredJWTError extends UnauthorizedError { } /** - * Error to throw when a jwt could not be parsed + * Error to throw when a jwt could not be parsed. */ export class IllegalJWTError extends UnauthorizedError { @IsString() @@ -24,7 +24,7 @@ export class IllegalJWTError extends UnauthorizedError { } /** - * Error to throw when user is nonexistant or refreshtoken is invalid + * Error to throw when user is nonexistant or refreshtoken is invalid. */ export class UserNonexistantOrRefreshtokenInvalidError extends UnauthorizedError { @IsString() @@ -35,7 +35,7 @@ export class UserNonexistantOrRefreshtokenInvalidError extends UnauthorizedError } /** - * Error to throw when provided credentials are invalid + * Error to throw when provided credentials are invalid. */ export class InvalidCredentialsError extends UnauthorizedError { @IsString() @@ -46,7 +46,7 @@ export class InvalidCredentialsError extends UnauthorizedError { } /** - * Error to throw when a jwt does not have permission for this route/ action + * Error to throw when a jwt does not have permission for this route/action. */ export class NoPermissionError extends ForbiddenError { @IsString() @@ -57,7 +57,7 @@ export class NoPermissionError extends ForbiddenError { } /** - * Error to thow when no username and no email is set + * Error to throw when no username and no email is set. */ export class UsernameOrEmailNeededError extends NotAcceptableError { @IsString() @@ -68,7 +68,7 @@ export class UsernameOrEmailNeededError extends NotAcceptableError { } /** - * Error to thow when no password is provided + * Error to throw when no password is provided. */ export class PasswordNeededError extends NotAcceptableError { @IsString() @@ -79,7 +79,7 @@ export class PasswordNeededError extends NotAcceptableError { } /** - * Error to thow when no user could be found for provided credential + * Error to throw when no user could be found mating the provided credential. */ export class UserNotFoundError extends NotFoundError { @IsString() @@ -90,7 +90,7 @@ export class UserNotFoundError extends NotFoundError { } /** - * Error to thow when no jwt token was provided + * Error to throw when no jwt token was provided (but one had to be). */ export class JwtNotProvidedError extends NotAcceptableError { @IsString() @@ -101,7 +101,7 @@ export class JwtNotProvidedError extends NotAcceptableError { } /** - * Error to thow when user was not found or refresh token count was invalid + * Error to throw when user was not found or refresh token count was invalid. */ export class UserNotFoundOrRefreshTokenCountInvalidError extends NotAcceptableError { @IsString() diff --git a/src/errors/GroupContactErrors.ts b/src/errors/GroupContactErrors.ts index c5bf9c7..7dc19e8 100644 --- a/src/errors/GroupContactErrors.ts +++ b/src/errors/GroupContactErrors.ts @@ -1,6 +1,9 @@ import { IsString } from 'class-validator'; import { NotAcceptableError, NotFoundError } from 'routing-controllers'; +/** + * Error to throw, when a provided groupContact doesn't belong to the accepted types. + */ export class GroupContactWrongTypeError extends NotAcceptableError { @IsString() name = "GroupContactWrongTypeError" @@ -9,6 +12,9 @@ export class GroupContactWrongTypeError extends NotAcceptableError { message = "The groupContact must be an existing groupContact's id. \n You provided a object of another type." } +/** + * Error to throw, when a non-existant groupContact get's loaded. + */ export class GroupContactNotFoundError extends NotFoundError { @IsString() name = "GroupContactNotFoundError" diff --git a/src/errors/RunnerErrors.ts b/src/errors/RunnerErrors.ts index 8250d17..06dc78f 100644 --- a/src/errors/RunnerErrors.ts +++ b/src/errors/RunnerErrors.ts @@ -26,27 +26,13 @@ export class RunnerIdsNotMatchingError extends NotAcceptableError { message = "The id's don't match!! \n And if you wanted to change a runner's id: This isn't allowed" } -export class RunnerOnlyOneGroupAllowedError extends NotAcceptableError { - @IsString() - name = "RunnerOnlyOneGroupAllowedError" - - @IsString() - message = "Runner's can only be part of one group (team or organisiation)! \n You provided an id for both." -} - +/** + * Error to throw when a runner is missing his group association. + */ export class RunnerGroupNeededError extends NotAcceptableError { @IsString() name = "RunnerGroupNeededError" @IsString() message = "Runner's need to be part of one group (team or organisiation)! \n You provided neither." -} - - -export class RunnerGroupNotFoundError extends NotFoundError { - @IsString() - name = "RunnerGroupNotFoundError" - - @IsString() - message = "The group you provided couldn't be located in the system. \n Please check your request." } \ No newline at end of file diff --git a/src/errors/RunnerGroupErrors.ts b/src/errors/RunnerGroupErrors.ts new file mode 100644 index 0000000..ed9624c --- /dev/null +++ b/src/errors/RunnerGroupErrors.ts @@ -0,0 +1,14 @@ +import { IsString } from 'class-validator'; +import { NotFoundError } from 'routing-controllers'; + +/** + * Error to throw when a runner group couldn't be found. + * Implemented this ways to work with the json-schema conversion for openapi. + */ +export class RunnerGroupNotFoundError extends NotFoundError { + @IsString() + name = "RunnerGroupNotFoundError" + + @IsString() + message = "RunnerGroup not found!" +} \ No newline at end of file diff --git a/src/errors/RunnerOrganisationErrors.ts b/src/errors/RunnerOrganisationErrors.ts index 65736b1..040befb 100644 --- a/src/errors/RunnerOrganisationErrors.ts +++ b/src/errors/RunnerOrganisationErrors.ts @@ -50,6 +50,9 @@ export class RunnerOrganisationHasTeamsError extends NotAcceptableError { message = "This organisation still has teams associated with it. \n If you want to delete this organisation with all it's runners and teams ass `?force` to your query." } +/** + * Error to throw, when a provided runnerOrganisation doesn't belong to the accepted types. + */ export class RunnerOrganisationWrongTypeError extends NotAcceptableError { @IsString() name = "RunnerOrganisationWrongTypeError" diff --git a/src/errors/UserErrors.ts b/src/errors/UserErrors.ts index 4c9e98b..cfceff1 100644 --- a/src/errors/UserErrors.ts +++ b/src/errors/UserErrors.ts @@ -1,16 +1,6 @@ import { IsString } from 'class-validator'; import { NotAcceptableError, NotFoundError } from 'routing-controllers'; -/** - * Error to throw when a usergroup couldn't be found. - */ -export class UserGroupNotFoundError extends NotFoundError { - @IsString() - name = "UserGroupNotFoundError" - - @IsString() - message = "User Group not found!" -} /** * Error to throw when no username or email is set diff --git a/src/models/actions/CreateRunner.ts b/src/models/actions/CreateRunner.ts index 4e5f3e9..f3611ce 100644 --- a/src/models/actions/CreateRunner.ts +++ b/src/models/actions/CreateRunner.ts @@ -1,6 +1,6 @@ import { IsInt } from 'class-validator'; import { getConnectionManager } from 'typeorm'; -import { RunnerGroupNotFoundError } from '../../errors/RunnerErrors'; +import { RunnerGroupNotFoundError } from '../../errors/RunnerGroupErrors'; import { RunnerOrganisationWrongTypeError } from '../../errors/RunnerOrganisationErrors'; import { RunnerTeamNeedsParentError } from '../../errors/RunnerTeamErrors'; import { Runner } from '../entities/Runner'; diff --git a/src/models/actions/CreateUser.ts b/src/models/actions/CreateUser.ts index fb7841a..ff6771a 100644 --- a/src/models/actions/CreateUser.ts +++ b/src/models/actions/CreateUser.ts @@ -2,7 +2,8 @@ import * as argon2 from "argon2"; import { IsEmail, IsOptional, IsPhoneNumber, IsString } from 'class-validator'; import { getConnectionManager } from 'typeorm'; import * as uuid from 'uuid'; -import { UserGroupNotFoundError, UsernameOrEmailNeededError } from '../../errors/UserErrors'; +import { UsernameOrEmailNeededError } from '../../errors/UserErrors'; +import { UserGroupNotFoundError } from '../../errors/UserGroupErrors'; import { User } from '../entities/User'; import { UserGroup } from '../entities/UserGroup'; From 33b3bcb8c2eaec3dd9d92a2f92d1e561920b97a9 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sat, 5 Dec 2020 19:01:30 +0100 Subject: [PATCH 42/47] Error cleanup #11 #13 #14 --- src/controllers/RunnerController.ts | 4 ++-- src/controllers/UserController.ts | 3 ++- src/errors/AddressErrors.ts | 6 ++++++ src/errors/AuthError.ts | 22 +++++++++++----------- src/errors/GroupContactErrors.ts | 6 ++++++ src/errors/RunnerErrors.ts | 20 +++----------------- src/errors/RunnerGroupErrors.ts | 14 ++++++++++++++ src/errors/RunnerOrganisationErrors.ts | 3 +++ src/errors/UserErrors.ts | 10 ---------- src/models/actions/CreateRunner.ts | 2 +- src/models/actions/CreateUser.ts | 3 ++- 11 files changed, 50 insertions(+), 43 deletions(-) create mode 100644 src/errors/RunnerGroupErrors.ts diff --git a/src/controllers/RunnerController.ts b/src/controllers/RunnerController.ts index 8293f36..acee2eb 100644 --- a/src/controllers/RunnerController.ts +++ b/src/controllers/RunnerController.ts @@ -2,7 +2,8 @@ import { Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, Query import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { getConnectionManager, Repository } from 'typeorm'; import { EntityFromBody, EntityFromParam } from 'typeorm-routing-controllers-extensions'; -import { RunnerGroupNeededError, RunnerGroupNotFoundError, RunnerIdsNotMatchingError, RunnerNotFoundError, RunnerOnlyOneGroupAllowedError } from '../errors/RunnerErrors'; +import { RunnerGroupNeededError, RunnerIdsNotMatchingError, RunnerNotFoundError } from '../errors/RunnerErrors'; +import { RunnerGroupNotFoundError } from '../errors/RunnerGroupErrors'; import { CreateRunner } from '../models/actions/CreateRunner'; import { Runner } from '../models/entities/Runner'; import { ResponseRunner } from '../models/responses/ResponseRunner'; @@ -43,7 +44,6 @@ export class RunnerController { @Post() @ResponseSchema(ResponseRunner) - @ResponseSchema(RunnerOnlyOneGroupAllowedError) @ResponseSchema(RunnerGroupNeededError) @ResponseSchema(RunnerGroupNotFoundError) @OpenAPI({ description: 'Create a new runner object (id will be generated automagicly).' }) diff --git a/src/controllers/UserController.ts b/src/controllers/UserController.ts index 8c2f2ea..f833f54 100644 --- a/src/controllers/UserController.ts +++ b/src/controllers/UserController.ts @@ -2,7 +2,8 @@ import { Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put } from import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { getConnectionManager, Repository } from 'typeorm'; import { EntityFromBody, EntityFromParam } from 'typeorm-routing-controllers-extensions'; -import { UserGroupNotFoundError, UserIdsNotMatchingError, UserNotFoundError } from '../errors/UserErrors'; +import { UserIdsNotMatchingError, UserNotFoundError } from '../errors/UserErrors'; +import { UserGroupNotFoundError } from '../errors/UserGroupErrors'; import { CreateUser } from '../models/actions/CreateUser'; import { User } from '../models/entities/User'; diff --git a/src/errors/AddressErrors.ts b/src/errors/AddressErrors.ts index c7ae8af..18cf624 100644 --- a/src/errors/AddressErrors.ts +++ b/src/errors/AddressErrors.ts @@ -1,6 +1,9 @@ import { IsString } from 'class-validator'; import { NotAcceptableError, NotFoundError } from 'routing-controllers'; +/** + * Error to throw, when to provided address doesn't belong to the accepted types. + */ export class AddressWrongTypeError extends NotAcceptableError { @IsString() name = "AddressWrongTypeError" @@ -9,6 +12,9 @@ export class AddressWrongTypeError extends NotAcceptableError { message = "The address must be an existing adress's id. \n You provided a object of another type." } +/** + * Error to throw, when a non-existant address get's loaded. + */ export class AddressNotFoundError extends NotFoundError { @IsString() name = "AddressNotFoundError" diff --git a/src/errors/AuthError.ts b/src/errors/AuthError.ts index 2c2ce5b..7687371 100644 --- a/src/errors/AuthError.ts +++ b/src/errors/AuthError.ts @@ -2,7 +2,7 @@ import { IsString } from 'class-validator'; import { ForbiddenError, NotAcceptableError, NotFoundError, UnauthorizedError } from 'routing-controllers'; /** - * Error to throw when a jwt is expired + * Error to throw when a jwt is expired. */ export class ExpiredJWTError extends UnauthorizedError { @IsString() @@ -13,7 +13,7 @@ export class ExpiredJWTError extends UnauthorizedError { } /** - * Error to throw when a jwt could not be parsed + * Error to throw when a jwt could not be parsed. */ export class IllegalJWTError extends UnauthorizedError { @IsString() @@ -24,7 +24,7 @@ export class IllegalJWTError extends UnauthorizedError { } /** - * Error to throw when user is nonexistant or refreshtoken is invalid + * Error to throw when user is nonexistant or refreshtoken is invalid. */ export class UserNonexistantOrRefreshtokenInvalidError extends UnauthorizedError { @IsString() @@ -35,7 +35,7 @@ export class UserNonexistantOrRefreshtokenInvalidError extends UnauthorizedError } /** - * Error to throw when provided credentials are invalid + * Error to throw when provided credentials are invalid. */ export class InvalidCredentialsError extends UnauthorizedError { @IsString() @@ -46,7 +46,7 @@ export class InvalidCredentialsError extends UnauthorizedError { } /** - * Error to throw when a jwt does not have permission for this route/ action + * Error to throw when a jwt does not have permission for this route/action. */ export class NoPermissionError extends ForbiddenError { @IsString() @@ -57,7 +57,7 @@ export class NoPermissionError extends ForbiddenError { } /** - * Error to thow when no username and no email is set + * Error to throw when no username and no email is set. */ export class UsernameOrEmailNeededError extends NotAcceptableError { @IsString() @@ -68,7 +68,7 @@ export class UsernameOrEmailNeededError extends NotAcceptableError { } /** - * Error to thow when no password is provided + * Error to throw when no password is provided. */ export class PasswordNeededError extends NotAcceptableError { @IsString() @@ -79,7 +79,7 @@ export class PasswordNeededError extends NotAcceptableError { } /** - * Error to thow when no user could be found for provided credential + * Error to throw when no user could be found mating the provided credential. */ export class UserNotFoundError extends NotFoundError { @IsString() @@ -90,7 +90,7 @@ export class UserNotFoundError extends NotFoundError { } /** - * Error to thow when no jwt token was provided + * Error to throw when no jwt token was provided (but one had to be). */ export class JwtNotProvidedError extends NotAcceptableError { @IsString() @@ -101,7 +101,7 @@ export class JwtNotProvidedError extends NotAcceptableError { } /** - * Error to thow when user was not found or refresh token count was invalid + * Error to throw when user was not found or refresh token count was invalid. */ export class UserNotFoundOrRefreshTokenCountInvalidError extends NotAcceptableError { @IsString() @@ -112,7 +112,7 @@ export class UserNotFoundOrRefreshTokenCountInvalidError extends NotAcceptableEr } /** - * Error to thow when refresh token count was invalid + * Error to throw when refresh token count was invalid */ export class RefreshTokenCountInvalidError extends NotAcceptableError { @IsString() diff --git a/src/errors/GroupContactErrors.ts b/src/errors/GroupContactErrors.ts index c5bf9c7..7dc19e8 100644 --- a/src/errors/GroupContactErrors.ts +++ b/src/errors/GroupContactErrors.ts @@ -1,6 +1,9 @@ import { IsString } from 'class-validator'; import { NotAcceptableError, NotFoundError } from 'routing-controllers'; +/** + * Error to throw, when a provided groupContact doesn't belong to the accepted types. + */ export class GroupContactWrongTypeError extends NotAcceptableError { @IsString() name = "GroupContactWrongTypeError" @@ -9,6 +12,9 @@ export class GroupContactWrongTypeError extends NotAcceptableError { message = "The groupContact must be an existing groupContact's id. \n You provided a object of another type." } +/** + * Error to throw, when a non-existant groupContact get's loaded. + */ export class GroupContactNotFoundError extends NotFoundError { @IsString() name = "GroupContactNotFoundError" diff --git a/src/errors/RunnerErrors.ts b/src/errors/RunnerErrors.ts index 8250d17..06dc78f 100644 --- a/src/errors/RunnerErrors.ts +++ b/src/errors/RunnerErrors.ts @@ -26,27 +26,13 @@ export class RunnerIdsNotMatchingError extends NotAcceptableError { message = "The id's don't match!! \n And if you wanted to change a runner's id: This isn't allowed" } -export class RunnerOnlyOneGroupAllowedError extends NotAcceptableError { - @IsString() - name = "RunnerOnlyOneGroupAllowedError" - - @IsString() - message = "Runner's can only be part of one group (team or organisiation)! \n You provided an id for both." -} - +/** + * Error to throw when a runner is missing his group association. + */ export class RunnerGroupNeededError extends NotAcceptableError { @IsString() name = "RunnerGroupNeededError" @IsString() message = "Runner's need to be part of one group (team or organisiation)! \n You provided neither." -} - - -export class RunnerGroupNotFoundError extends NotFoundError { - @IsString() - name = "RunnerGroupNotFoundError" - - @IsString() - message = "The group you provided couldn't be located in the system. \n Please check your request." } \ No newline at end of file diff --git a/src/errors/RunnerGroupErrors.ts b/src/errors/RunnerGroupErrors.ts new file mode 100644 index 0000000..ed9624c --- /dev/null +++ b/src/errors/RunnerGroupErrors.ts @@ -0,0 +1,14 @@ +import { IsString } from 'class-validator'; +import { NotFoundError } from 'routing-controllers'; + +/** + * Error to throw when a runner group couldn't be found. + * Implemented this ways to work with the json-schema conversion for openapi. + */ +export class RunnerGroupNotFoundError extends NotFoundError { + @IsString() + name = "RunnerGroupNotFoundError" + + @IsString() + message = "RunnerGroup not found!" +} \ No newline at end of file diff --git a/src/errors/RunnerOrganisationErrors.ts b/src/errors/RunnerOrganisationErrors.ts index 65736b1..040befb 100644 --- a/src/errors/RunnerOrganisationErrors.ts +++ b/src/errors/RunnerOrganisationErrors.ts @@ -50,6 +50,9 @@ export class RunnerOrganisationHasTeamsError extends NotAcceptableError { message = "This organisation still has teams associated with it. \n If you want to delete this organisation with all it's runners and teams ass `?force` to your query." } +/** + * Error to throw, when a provided runnerOrganisation doesn't belong to the accepted types. + */ export class RunnerOrganisationWrongTypeError extends NotAcceptableError { @IsString() name = "RunnerOrganisationWrongTypeError" diff --git a/src/errors/UserErrors.ts b/src/errors/UserErrors.ts index 4c9e98b..cfceff1 100644 --- a/src/errors/UserErrors.ts +++ b/src/errors/UserErrors.ts @@ -1,16 +1,6 @@ import { IsString } from 'class-validator'; import { NotAcceptableError, NotFoundError } from 'routing-controllers'; -/** - * Error to throw when a usergroup couldn't be found. - */ -export class UserGroupNotFoundError extends NotFoundError { - @IsString() - name = "UserGroupNotFoundError" - - @IsString() - message = "User Group not found!" -} /** * Error to throw when no username or email is set diff --git a/src/models/actions/CreateRunner.ts b/src/models/actions/CreateRunner.ts index 4e5f3e9..f3611ce 100644 --- a/src/models/actions/CreateRunner.ts +++ b/src/models/actions/CreateRunner.ts @@ -1,6 +1,6 @@ import { IsInt } from 'class-validator'; import { getConnectionManager } from 'typeorm'; -import { RunnerGroupNotFoundError } from '../../errors/RunnerErrors'; +import { RunnerGroupNotFoundError } from '../../errors/RunnerGroupErrors'; import { RunnerOrganisationWrongTypeError } from '../../errors/RunnerOrganisationErrors'; import { RunnerTeamNeedsParentError } from '../../errors/RunnerTeamErrors'; import { Runner } from '../entities/Runner'; diff --git a/src/models/actions/CreateUser.ts b/src/models/actions/CreateUser.ts index fb7841a..ff6771a 100644 --- a/src/models/actions/CreateUser.ts +++ b/src/models/actions/CreateUser.ts @@ -2,7 +2,8 @@ import * as argon2 from "argon2"; import { IsEmail, IsOptional, IsPhoneNumber, IsString } from 'class-validator'; import { getConnectionManager } from 'typeorm'; import * as uuid from 'uuid'; -import { UserGroupNotFoundError, UsernameOrEmailNeededError } from '../../errors/UserErrors'; +import { UsernameOrEmailNeededError } from '../../errors/UserErrors'; +import { UserGroupNotFoundError } from '../../errors/UserGroupErrors'; import { User } from '../entities/User'; import { UserGroup } from '../entities/UserGroup'; From f58a715c45ae5e8ea95041816d78991498461b94 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sat, 5 Dec 2020 19:09:08 +0100 Subject: [PATCH 43/47] Cleaned up the loaders ref #11 --- src/loaders/database.ts | 3 +++ src/loaders/express.ts | 6 ++++-- src/loaders/index.ts | 7 +++++-- src/loaders/openapi.ts | 7 +++++++ 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/loaders/database.ts b/src/loaders/database.ts index b8e9607..ee331ae 100644 --- a/src/loaders/database.ts +++ b/src/loaders/database.ts @@ -1,5 +1,8 @@ import { createConnection } from "typeorm"; +/** + * Loader for the database that creates the database connection and initializes the database tabels. + */ export default async () => { const connection = await createConnection(); connection.synchronize(); diff --git a/src/loaders/express.ts b/src/loaders/express.ts index 787497a..32a28cd 100644 --- a/src/loaders/express.ts +++ b/src/loaders/express.ts @@ -1,7 +1,9 @@ import { Application } from "express"; -import bodyParser from 'body-parser'; -import cors from 'cors'; +/** + * Loader for express related configurations. + * Currently only enables the proxy trust. + */ export default async (app: Application) => { app.enable('trust proxy'); return app; diff --git a/src/loaders/index.ts b/src/loaders/index.ts index 704ea47..802a732 100644 --- a/src/loaders/index.ts +++ b/src/loaders/index.ts @@ -1,8 +1,11 @@ +import { Application } from "express"; +import databaseLoader from "./database"; import expressLoader from "./express"; import openapiLoader from "./openapi"; -import databaseLoader from "./database"; -import { Application } from "express"; +/** + * Index Loader that executes the other loaders in the right order. + */ export default async (app: Application) => { await databaseLoader(); await openapiLoader(app); diff --git a/src/loaders/openapi.ts b/src/loaders/openapi.ts index fe0c77a..9c270ed 100644 --- a/src/loaders/openapi.ts +++ b/src/loaders/openapi.ts @@ -4,11 +4,16 @@ import { getMetadataArgsStorage } from "routing-controllers"; import { routingControllersToSpec } from "routing-controllers-openapi"; import * as swaggerUiExpress from "swagger-ui-express"; +/** + * Loader for everything openapi related - from creating the schema to serving it via a static route. + */ export default async (app: Application) => { const storage = getMetadataArgsStorage(); const schemas = validationMetadatasToSchemas({ refPointerPrefix: "#/components/schemas/", }); + + //Spec creation based on the previously created schemas const spec = routingControllersToSpec( storage, { @@ -32,6 +37,8 @@ export default async (app: Application) => { }, } ); + + //Options for swaggerUiExpress const options = { explorer: true, }; From 1fb09e577c539d8261afe4cc4a2cfae88b8f866b Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sat, 5 Dec 2020 19:14:04 +0100 Subject: [PATCH 44/47] Cleaned up up the middlewares ref #11 --- src/middlewares/ErrorHandler.ts | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/middlewares/ErrorHandler.ts b/src/middlewares/ErrorHandler.ts index 7f45073..40c1ff6 100644 --- a/src/middlewares/ErrorHandler.ts +++ b/src/middlewares/ErrorHandler.ts @@ -1,20 +1,14 @@ -import { - Middleware, - ExpressErrorMiddlewareInterface -} from "routing-controllers"; +import { ExpressErrorMiddlewareInterface, Middleware } from "routing-controllers"; +/** + * Our Error handling middlware that returns our custom httperrors to the user + */ @Middleware({ type: "after" }) export class ErrorHandler implements ExpressErrorMiddlewareInterface { - public error( - error: any, - request: any, - response: any, - next: (err: any) => any - ) { + public error(error: any, request: any, response: any, next: (err: any) => any) { if (response.headersSent) { return; } - response.json(error); } } From ad6c9e72111f91f432b66bc67001ef8ceea499dc Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sat, 5 Dec 2020 19:15:56 +0100 Subject: [PATCH 45/47] Removed garbage file --- src/tests.ts | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 src/tests.ts diff --git a/src/tests.ts b/src/tests.ts deleted file mode 100644 index bf43e1e..0000000 --- a/src/tests.ts +++ /dev/null @@ -1,23 +0,0 @@ -import * as dotenvSafe from "dotenv-safe"; -import "reflect-metadata"; -import { createExpressServer } from "routing-controllers"; -import authchecker from "./authchecker"; -import loaders from "./loaders/index"; -import { ErrorHandler } from './middlewares/ErrorHandler'; - -dotenvSafe.config(); -const PORT = process.env.APP_PORT || 4010; - -const app = createExpressServer({ - authorizationChecker: authchecker, - middlewares: [ErrorHandler], - development: process.env.NODE_ENV === "production", - cors: true, - routePrefix: "/api", - controllers: [__dirname + "/controllers/*.ts"], -}); - -async function main() { - await loaders(app); -} -main(); From 5103e8a6e5db8a3484eae5710f8f4f7712cb8b14 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sat, 5 Dec 2020 20:01:06 +0100 Subject: [PATCH 46/47] Updated folders in the readme --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 077f888..f974523 100644 --- a/README.md +++ b/README.md @@ -53,9 +53,11 @@ docker-compose up --build ## File Structure -- src/models/\* - database models (typeorm entities) +- src/models/entities\* - database models (typeorm entities) +- src/models/actions\* - actions models +- src/models/responses\* - response models - src/controllers/\* - routing-controllers - src/loaders/\* - loaders for the different init steps of the api server -- src/routes/\* - express routes for everything we don't do via routing-controllers (shouldn't be much) - src/middlewares/\* - express middlewares (mainly auth r/n) - src/errors/* - our custom (http) errors +- src/routes/\* - express routes for everything we don't do via routing-controllers (depreciated) \ No newline at end of file From 99d8a0360f3cdb18444a07ba4f3b5f8cd4bb98d0 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Sun, 6 Dec 2020 10:29:56 +0100 Subject: [PATCH 47/47] =?UTF-8?q?=F0=9F=9A=9A=20basic=20move=20to=20config?= =?UTF-8?q?.ts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref #18 --- src/app.ts | 11 ++++------- src/authchecker.ts | 5 +++-- src/config.ts | 7 +++++++ src/models/creation/CreateAuth.ts | 5 +++-- src/models/creation/HandleLogout.ts | 3 ++- src/models/creation/RefreshAuth.ts | 7 ++++--- 6 files changed, 23 insertions(+), 15 deletions(-) create mode 100644 src/config.ts diff --git a/src/app.ts b/src/app.ts index e19d313..fd3dc8e 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,18 +1,15 @@ import consola from "consola"; -import * as dotenvSafe from "dotenv-safe"; import "reflect-metadata"; import { createExpressServer } from "routing-controllers"; import authchecker from "./authchecker"; +import { config } from './config'; import loaders from "./loaders/index"; import { ErrorHandler } from './middlewares/ErrorHandler'; -dotenvSafe.config(); -const PORT = process.env.APP_PORT || 4010; - const app = createExpressServer({ authorizationChecker: authchecker, middlewares: [ErrorHandler], - development: process.env.NODE_ENV === "production", + development: config.development, cors: true, routePrefix: "/api", controllers: [__dirname + "/controllers/*.ts"], @@ -20,9 +17,9 @@ const app = createExpressServer({ async function main() { await loaders(app); - app.listen(PORT, () => { + app.listen(config.internal_port, () => { consola.success( - `⚡️[server]: Server is running at http://localhost:${PORT}` + `⚡️[server]: Server is running at http://localhost:${config.internal_port}` ); }); } diff --git a/src/authchecker.ts b/src/authchecker.ts index f61f35f..869e0da 100644 --- a/src/authchecker.ts +++ b/src/authchecker.ts @@ -1,6 +1,7 @@ import * as jwt from "jsonwebtoken"; import { Action } from "routing-controllers"; import { getConnectionManager } from 'typeorm'; +import { config } from './config'; import { IllegalJWTError, NoPermissionError, UserNonexistantOrRefreshtokenInvalidError } from './errors/AuthError'; import { User } from './models/entities/User'; // ----------- @@ -15,7 +16,7 @@ const authchecker = async (action: Action, permissions: string | string[]) => { const provided_token = action.request.query["auth"]; let jwtPayload = undefined try { - jwtPayload = jwt.verify(provided_token, "securekey"); + jwtPayload = jwt.verify(provided_token, config.jwt_secret); } catch (error) { console.log(error); throw new IllegalJWTError() @@ -42,7 +43,7 @@ const authchecker = async (action: Action, permissions: string | string[]) => { } // try { - jwt.verify(provided_token, process.env.JWT_SECRET || "secretjwtsecret"); + jwt.verify(provided_token, config.jwt_secret); return true } catch (error) { return false diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 0000000..5f54ce3 --- /dev/null +++ b/src/config.ts @@ -0,0 +1,7 @@ +import * as dotenvSafe from "dotenv-safe"; +dotenvSafe.config(); +export const config = { + internal_port: process.env.APP_PORT || 4010, + development: process.env.NODE_ENV === "production", + jwt_secret: process.env.JWT_SECRET || "secretjwtsecret" +} \ No newline at end of file diff --git a/src/models/creation/CreateAuth.ts b/src/models/creation/CreateAuth.ts index 140f9ef..42a0d5d 100644 --- a/src/models/creation/CreateAuth.ts +++ b/src/models/creation/CreateAuth.ts @@ -2,6 +2,7 @@ import * as argon2 from "argon2"; import { IsEmail, IsOptional, IsString } from 'class-validator'; import * as jsonwebtoken from 'jsonwebtoken'; import { getConnectionManager } from 'typeorm'; +import { config } from '../../config'; import { InvalidCredentialsError, PasswordNeededError, UserNotFoundError } from '../../errors/AuthError'; import { UsernameOrEmailNeededError } from '../../errors/UserErrors'; import { User } from '../entities/User'; @@ -38,7 +39,7 @@ export class CreateAuth { newAuth.access_token = jsonwebtoken.sign({ userdetails: found_user, exp: timestamp_accesstoken_expiry - }, "securekey") + }, config.jwt_secret) newAuth.access_token_expires_at = timestamp_accesstoken_expiry // const timestamp_refresh_expiry = Math.floor(Date.now() / 1000) + 10 * 36000 @@ -46,7 +47,7 @@ export class CreateAuth { refreshtokencount: found_user.refreshTokenCount, userid: found_user.id, exp: timestamp_refresh_expiry - }, "securekey") + }, config.jwt_secret) newAuth.refresh_token_expires_at = timestamp_refresh_expiry } else { throw new InvalidCredentialsError() diff --git a/src/models/creation/HandleLogout.ts b/src/models/creation/HandleLogout.ts index c50edd0..4b23d5f 100644 --- a/src/models/creation/HandleLogout.ts +++ b/src/models/creation/HandleLogout.ts @@ -1,6 +1,7 @@ import { IsString } from 'class-validator'; import * as jsonwebtoken from 'jsonwebtoken'; import { getConnectionManager } from 'typeorm'; +import { config } from '../../config'; import { IllegalJWTError, JwtNotProvidedError, RefreshTokenCountInvalidError, UserNotFoundError } from '../../errors/AuthError'; import { User } from '../entities/User'; import { Logout } from '../responses/Logout'; @@ -16,7 +17,7 @@ export class HandleLogout { } let decoded; try { - decoded = jsonwebtoken.verify(this.token, 'securekey') + decoded = jsonwebtoken.verify(this.token, config.jwt_secret) } catch (error) { throw new IllegalJWTError() } diff --git a/src/models/creation/RefreshAuth.ts b/src/models/creation/RefreshAuth.ts index 66e27f8..96bbc8d 100644 --- a/src/models/creation/RefreshAuth.ts +++ b/src/models/creation/RefreshAuth.ts @@ -1,6 +1,7 @@ import { IsString } from 'class-validator'; import * as jsonwebtoken from 'jsonwebtoken'; import { getConnectionManager } from 'typeorm'; +import { config } from '../../config'; import { IllegalJWTError, JwtNotProvidedError, RefreshTokenCountInvalidError, UserNotFoundError } from '../../errors/AuthError'; import { User } from '../entities/User'; import { Auth } from '../responses/Auth'; @@ -16,7 +17,7 @@ export class RefreshAuth { } let decoded try { - decoded = jsonwebtoken.verify(this.token, 'securekey') + decoded = jsonwebtoken.verify(this.token, config.jwt_secret) } catch (error) { throw new IllegalJWTError() } @@ -33,7 +34,7 @@ export class RefreshAuth { newAuth.access_token = jsonwebtoken.sign({ userdetails: found_user, exp: timestamp_accesstoken_expiry - }, "securekey") + }, config.jwt_secret) newAuth.access_token_expires_at = timestamp_accesstoken_expiry // const timestamp_refresh_expiry = Math.floor(Date.now() / 1000) + 10 * 36000 @@ -41,7 +42,7 @@ export class RefreshAuth { refreshtokencount: found_user.refreshTokenCount, userid: found_user.id, exp: timestamp_refresh_expiry - }, "securekey") + }, config.jwt_secret) newAuth.refresh_token_expires_at = timestamp_refresh_expiry return newAuth;