diff --git a/src/command/refreshCommand.ts b/src/command/refreshCommand.ts index bd7beea..e0404c8 100644 --- a/src/command/refreshCommand.ts +++ b/src/command/refreshCommand.ts @@ -3,6 +3,6 @@ export interface CreateRefreshCommand { } export interface DeleteRefreshCommand { - id: number; + token: string; userId: number; } diff --git a/src/command/refreshCommandHandler.ts b/src/command/refreshCommandHandler.ts index 5c6289c..8f7d674 100644 --- a/src/command/refreshCommandHandler.ts +++ b/src/command/refreshCommandHandler.ts @@ -2,9 +2,10 @@ import { dataSource } from "../data-source"; import { refresh } from "../entity/refresh"; import InternalException from "../exceptions/internalException"; import { JWTHelper } from "../helpers/jwtHelper"; +import { StringHelper } from "../helpers/stringHelper"; import UserService from "../service/userService"; import { JWTRefresh } from "../type/jwtTypes"; -import { CreateRefreshCommand } from "./refreshCommand"; +import { CreateRefreshCommand, DeleteRefreshCommand } from "./refreshCommand"; import ms from "ms"; export default abstract class RefreshCommandHandler { @@ -14,10 +15,11 @@ export default abstract class RefreshCommandHandler { * @returns {Promise} */ static async create(createRefresh: CreateRefreshCommand): Promise { - let createRefreshToken: JWTRefresh = { - userId: createRefresh.userId, - }; - const refreshToken = await JWTHelper.create(createRefreshToken); + // let createRefreshToken: JWTRefresh = { + // userId: createRefresh.userId, + // }; + // const refreshToken = await JWTHelper.create(createRefreshToken); + const refreshToken = StringHelper.random(32); return await dataSource .createQueryBuilder() @@ -26,7 +28,7 @@ export default abstract class RefreshCommandHandler { .values({ token: refreshToken, user: await UserService.getById(createRefresh.userId), - expiry: ms(process.env.REFRESH_EXPIRATION), + expiry: new Date(Date.now() + ms(process.env.REFRESH_EXPIRATION)), }) .execute() .then((result) => { @@ -36,4 +38,23 @@ export default abstract class RefreshCommandHandler { throw new InternalException("Failed saving refresh token"); }); } + + /** + * @description delete refresh by user and token + * @param DeleteRefreshCommand + * @returns {Promise} + */ + static async deleteByToken(deleteRefresh: DeleteRefreshCommand): Promise { + return await dataSource + .createQueryBuilder() + .delete() + .from(refresh) + .where("refresh.token = :token", { token: deleteRefresh.token }) + .andWhere("refresh.userId = :userId", { userId: deleteRefresh.userId }) + .execute() + .then((res) => {}) + .catch((err) => { + throw new InternalException("failed refresh removal"); + }); + } } diff --git a/src/controller/authController.ts b/src/controller/authController.ts index e4f25aa..2990b5c 100644 --- a/src/controller/authController.ts +++ b/src/controller/authController.ts @@ -1,6 +1,6 @@ import { Request, Response } from "express"; import { JWTHelper } from "../helpers/jwtHelper"; -import { JWTToken } from "../type/jwtTypes"; +import { JWTData, JWTToken } from "../type/jwtTypes"; import InternalException from "../exceptions/internalException"; import RefreshCommandHandler from "../command/refreshCommandHandler"; import { CreateRefreshCommand } from "../command/refreshCommand"; @@ -10,6 +10,8 @@ import UnauthorizedRequestException from "../exceptions/unauthorizedRequestExcep import QRCode from "qrcode"; import { CreateUserCommand } from "../command/userCommand"; import UserCommandHandler from "../command/userCommandHandler"; +import RefreshService from "../service/refreshService"; +import BadRequestException from "../exceptions/badRequestException"; /** * @description Check authentication status by token @@ -80,6 +82,51 @@ export async function logout(req: Request, res: Response): Promise {} export async function refresh(req: Request, res: Response): Promise { let token = req.body.token; let refresh = req.body.refresh; + + const tokenUser = await JWTHelper.decode(token); + if (typeof tokenUser == "string" || !tokenUser) { + throw new InternalException("process failed"); + } + + let tokenUserId = (tokenUser as JWTToken).userId; + + let { user } = await RefreshService.getByToken(refresh); + + if (tokenUserId != user.id) { + throw new UnauthorizedRequestException("user not identified with token and refresh"); + } + + let { id, username } = await UserService.getById(tokenUserId); + + let jwtData: JWTToken = { + userId: id, + username: username, + rights: [], + }; + + let accessToken: string; + let refreshToken: string; + + JWTHelper.create(jwtData) + .then((result) => { + accessToken = result; + }) + .catch((err) => { + console.log(err); + throw new InternalException("Failed accessToken creation"); + }); + + let refreshCommand: CreateRefreshCommand = { + userId: id, + }; + refreshToken = await RefreshCommandHandler.create(refreshCommand); + + await RefreshCommandHandler.deleteByToken(refresh); + + res.json({ + accessToken, + refreshToken, + }); } /** diff --git a/src/service/refreshService.ts b/src/service/refreshService.ts new file mode 100644 index 0000000..d18541c --- /dev/null +++ b/src/service/refreshService.ts @@ -0,0 +1,26 @@ +import { dataSource } from "../data-source"; +import { refresh } from "../entity/refresh"; +import InternalException from "../exceptions/internalException"; + +export default abstract class RefreshService { + /** + * @description get refresh by token + * @param token string + * @returns {Promise} + */ + static async getByToken(token: string): Promise { + return await dataSource + .getRepository(refresh) + .createQueryBuilder("refresh") + .leftJoinAndSelect("refresh.user", "user") + .where("refresh.token = :token", { token: token }) + .andWhere("refresh.expiry >= :expiry", { expiry: new Date() }) + .getOneOrFail() + .then((res) => { + return res; + }) + .catch((err) => { + throw new InternalException("refresh not found"); + }); + } +}