diff --git a/src/jwtcreator.ts b/src/jwtcreator.ts new file mode 100644 index 0000000..d32d231 --- /dev/null +++ b/src/jwtcreator.ts @@ -0,0 +1,85 @@ +import { IsBoolean, IsEmail, IsInt, IsNotEmpty, IsOptional, IsString, IsUUID } from 'class-validator'; +import * as jsonwebtoken from "jsonwebtoken"; +import { config } from './config'; +import { User } from './models/entities/User'; + +export class JwtCreator { + public static createRefresh(user: User, expiry_timestamp?: number) { + if (!expiry_timestamp) { expiry_timestamp = Math.floor(Date.now() / 1000) + 10 * 36000; } + return jsonwebtoken.sign({ + refreshtokencount: user.refreshTokenCount, + userid: user.id, + exp: expiry_timestamp + }, config.jwt_secret) + } + + public static createAccess(user: User, expiry_timestamp?: number) { + if (!expiry_timestamp) { expiry_timestamp = Math.floor(Date.now() / 1000) + 10 * 36000; } + return jsonwebtoken.sign({ + userdetails: new JwtUser(user), + exp: expiry_timestamp + }, config.jwt_secret) + } +} + +class JwtUser { + @IsInt() + id: number; + + @IsUUID(4) + uuid: string; + + @IsOptional() + @IsEmail() + email?: string; + + @IsOptional() + @IsString() + username?: string; + + @IsString() + @IsNotEmpty() + firstname: string; + + @IsString() + @IsOptional() + middlename?: string; + + @IsString() + @IsNotEmpty() + lastname: string; + + permissions: string[]; + + @IsBoolean() + enabled: boolean; + + @IsInt() + @IsNotEmpty() + refreshTokenCount?: number; + + @IsString() + @IsOptional() + profilePic?: string; + + public constructor(user: User) { + this.id = user.id; + this.firstname = user.firstname; + this.middlename = user.middlename; + this.lastname = user.lastname; + this.username = user.username; + this.email = user.email; + this.refreshTokenCount = user.refreshTokenCount; + this.uuid = user.uuid; + this.profilePic = user.profilePic; + this.permissions = this.getPermissions(user); + } + + public getPermissions(user: User): string[] { + let returnPermissions: string[] = new Array(); + for (let permission of user.permissions) { + returnPermissions.push(permission.toString()); + } + return returnPermissions; + } +} \ No newline at end of file diff --git a/src/models/actions/CreateAuth.ts b/src/models/actions/CreateAuth.ts index b31bee6..a29f28a 100644 --- a/src/models/actions/CreateAuth.ts +++ b/src/models/actions/CreateAuth.ts @@ -1,10 +1,9 @@ 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 { JwtCreator } from '../../JwtCreator'; import { User } from '../entities/User'; import { Auth } from '../responses/ResponseAuth'; @@ -26,34 +25,24 @@ export class CreateAuth { throw new UsernameOrEmailNeededError(); } if (!this.password) { - throw new PasswordNeededError() + throw new PasswordNeededError(); } - const found_users = await getConnectionManager().get().getRepository(User).find({ relations: ['groups', 'permissions'], where: [{ username: this.username }, { email: this.email }] }); - if (found_users.length === 0) { - throw new UserNotFoundError() - } else { - const found_user = found_users[0] - if (await argon2.verify(found_user.password, this.password + found_user.uuid)) { - const timestamp_accesstoken_expiry = Math.floor(Date.now() / 1000) + 5 * 60 - found_user.permissions = found_user.permissions || [] - delete found_user.password; - newAuth.access_token = jsonwebtoken.sign({ - userdetails: found_user, - exp: timestamp_accesstoken_expiry - }, config.jwt_secret) - 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 - }, config.jwt_secret) - newAuth.refresh_token_expires_at = timestamp_refresh_expiry - } else { - throw new InvalidCredentialsError() - } + const found_user = await getConnectionManager().get().getRepository(User).findOne({ relations: ['groups', 'permissions'], where: [{ username: this.username }, { email: this.email }] }); + if (!found_user) { + throw new UserNotFoundError(); } + if (!(await argon2.verify(found_user.password, this.password + found_user.uuid))) { + throw new InvalidCredentialsError(); + } + + //Create the access token + const timestamp_accesstoken_expiry = Math.floor(Date.now() / 1000) + 5 * 60 + newAuth.access_token = JwtCreator.createAccess(found_user, timestamp_accesstoken_expiry); + newAuth.access_token_expires_at = timestamp_accesstoken_expiry + //Create the refresh token + const timestamp_refresh_expiry = Math.floor(Date.now() / 1000) + 10 * 36000 + newAuth.refresh_token = JwtCreator.createRefresh(found_user, timestamp_refresh_expiry); + newAuth.refresh_token_expires_at = timestamp_refresh_expiry return newAuth; } } \ No newline at end of file diff --git a/src/models/actions/RefreshAuth.ts b/src/models/actions/RefreshAuth.ts index afd22fe..757dea3 100644 --- a/src/models/actions/RefreshAuth.ts +++ b/src/models/actions/RefreshAuth.ts @@ -3,6 +3,7 @@ import * as jsonwebtoken from 'jsonwebtoken'; import { getConnectionManager } from 'typeorm'; import { config } from '../../config'; import { IllegalJWTError, JwtNotProvidedError, RefreshTokenCountInvalidError, UserNotFoundError } from '../../errors/AuthError'; +import { JwtCreator } from "../../JwtCreator"; import { User } from '../entities/User'; import { Auth } from '../responses/ResponseAuth'; @@ -29,24 +30,14 @@ export class RefreshAuth { if (found_user.refreshTokenCount !== decoded["refreshtokencount"]) { throw new RefreshTokenCountInvalidError() } - found_user.permissions = found_user.permissions || [] - delete found_user.password; + //Create the auth token 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 - }, config.jwt_secret) + newAuth.access_token = JwtCreator.createAccess(found_user, timestamp_accesstoken_expiry); newAuth.access_token_expires_at = timestamp_accesstoken_expiry - // + //Create the refresh token 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 - }, config.jwt_secret) - newAuth.refresh_token_expires_at = timestamp_refresh_expiry - + newAuth.refresh_token = JwtCreator.createRefresh(found_user, timestamp_refresh_expiry); + newAuth.refresh_token_expires_at = timestamp_refresh_expiry; return newAuth; } } \ No newline at end of file