diff --git a/package-lock.json b/package-lock.json index 4d08cfe..275ca3a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1509,6 +1509,12 @@ "@types/node": "*" } }, + "@types/cors": { + "version": "2.8.12", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", + "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", + "dev": true + }, "@types/event-stream": { "version": "3.3.34", "resolved": "https://registry.npmjs.org/@types/event-stream/-/event-stream-3.3.34.tgz", @@ -1546,6 +1552,15 @@ "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", "dev": true }, + "@types/jsonwebtoken": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.6.tgz", + "integrity": "sha512-+P3O/xC7nzVizIi5VbF34YtqSonFsdnbXBnWUCYRiKOi1f9gA4sEFvXkrGr/QVV23IbMYvcoerI7nnhDUiWXRQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -1588,6 +1603,12 @@ "@types/node": "*" } }, + "@types/uuid": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.3.tgz", + "integrity": "sha512-0LbEEx1zxrYB3pgpd1M5lEhLcXjKJnYghvhTRgaBeUivLHMDM1TzF3IJ6hXU2+8uA4Xz+5BA63mtZo5DjVT8iA==", + "dev": true + }, "@typescript-eslint/eslint-plugin": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.1.0.tgz", @@ -2038,6 +2059,11 @@ "node-releases": "^1.1.76" } }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -2365,6 +2391,15 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -2509,6 +2544,14 @@ "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", "dev": true }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -3676,6 +3719,42 @@ "minimist": "^1.2.5" } }, + "jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + } + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "keyv": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", @@ -3736,12 +3815,47 @@ "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", "dev": true }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, "logform": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/logform/-/logform-2.3.0.tgz", @@ -4041,6 +4155,11 @@ "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", "dev": true }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, "object-inspect": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", diff --git a/package.json b/package.json index 7c572a8..e48bf11 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "module-4": "nodemon --exec babel-node ./src/module-3/index.ts --extensions .ts", + "dev": "nodemon --exec babel-node ./src/module-3/index.ts --extensions .ts", "lint": "eslint . --ext .ts" }, "author": "", @@ -14,12 +14,14 @@ "@types/event-stream": "^3.3.34", "@types/node": "^16.10.1", "bunyan": "^1.8.15", + "cors": "^2.8.5", "csvtojson": "^2.0.10", "dotenv": "^10.0.0", "event-stream": "^4.0.1", "express": "^4.17.1", "express-joi-validation": "^5.0.0", "joi": "^17.4.2", + "jsonwebtoken": "^8.5.1", "morgan": "^1.10.0", "pg": "^8.7.1", "pg-hstore": "^2.3.4", @@ -35,8 +37,11 @@ "@babel/preset-env": "^7.15.6", "@babel/preset-typescript": "^7.15.0", "@types/bunyan": "^1.8.8", + "@types/cors": "^2.8.12", "@types/express": "^4.17.13", + "@types/jsonwebtoken": "^8.5.6", "@types/morgan": "^1.9.3", + "@types/uuid": "^8.3.3", "@typescript-eslint/eslint-plugin": "^5.1.0", "@typescript-eslint/parser": "^5.1.0", "babel-eslint": "^10.1.0", diff --git a/src/module-3/controllers/auth.ts b/src/module-3/controllers/auth.ts new file mode 100644 index 0000000..5c7cb72 --- /dev/null +++ b/src/module-3/controllers/auth.ts @@ -0,0 +1,55 @@ +import express, { Request, Response } from "express"; +import { createValidator } from "express-joi-validation"; +import { log, logger } from "../middlewares/loggers"; +import * as AuthService from "../services/auth"; +import { UserAuthModel } from "../types"; +import { + loginValidationSchema, + updTokenValidationSchema +} from "./validation/auth"; + +const validator = createValidator(); +const router = express.Router(); + +router.post( + "/login", + [validator.body(loginValidationSchema), log(AuthService.verify)], + async (req: Request, res: Response) => { + try { + const { login, password }: UserAuthModel = req.body; + const token = (await AuthService.verify(login, password)) ?? {}; + + if (!token) { + return res.status(403).send({ + success: false, + message: "Bad username / password combination. Please try again." + }); + } + + res.status(200).send(token); + } catch (e) { + logger.setError(e); + res.status(500).send(e.message); + } + } +); + +router.post( + "/token", + [validator.body(updTokenValidationSchema), log(AuthService.refreshToken)], + async (req: Request, res: Response) => { + const data = req.body; + + try { + const token = await AuthService.refreshToken(data); + if (!token) { + return res.status(404).send("Invalid request"); + } + res.status(200).json(token); + } catch (e) { + logger.setError(e); + } + } +); + +export default router; diff --git a/src/module-3/controllers/groups.ts b/src/module-3/controllers/groups.ts index a8e8ea9..c0f0a92 100644 --- a/src/module-3/controllers/groups.ts +++ b/src/module-3/controllers/groups.ts @@ -1,6 +1,7 @@ import express from "express"; import { createValidator } from "express-joi-validation"; -import { log, logger } from "../loggers"; +import { checkToken } from "../middlewares/auth"; +import { log, logger } from "../middlewares/loggers"; import * as GroupsService from "../services/groups"; import { Errors, GroupModel } from "../types"; import { isNull } from "./utils"; @@ -11,7 +12,7 @@ const router = express.Router(); /* Get all groups */ -router.get("/", log(GroupsService.findAll), async (req, res) => { +router.get("/", [checkToken, log(GroupsService.findAll)], async (req, res) => { try { const groups = await GroupsService.findAll(); res.status(200).send(groups); @@ -23,7 +24,7 @@ router.get("/", log(GroupsService.findAll), async (req, res) => { /* Find group by id */ -router.get("/:id", log(GroupsService.find), async (req, res) => { +router.get("/:id", [checkToken, log(GroupsService.find)], async (req, res) => { try { const id = req.params.id; const group = await GroupsService.find(id); @@ -42,7 +43,11 @@ router.get("/:id", log(GroupsService.find), async (req, res) => { router.post( "/", - [log(GroupsService.create), validator.body(groupValidationSchema)], + [ + log(GroupsService.create), + validator.body(groupValidationSchema), + checkToken + ], async (req, res) => { try { const body: GroupModel = req.body; @@ -61,26 +66,34 @@ router.post( /* Delete group */ -router.delete("/:id", log(GroupsService.remove), async (req, res) => { - try { - const id = req.params.id; - const isSuccess = await GroupsService.remove(id); - if (isNull(isSuccess)) { - const err = "Something wrong"; - logger.setError(err); - return res.status(404).send(err); +router.delete( + "/:id", + [checkToken, log(GroupsService.remove)], + async (req, res) => { + try { + const id = req.params.id; + const isSuccess = await GroupsService.remove(id); + if (isNull(isSuccess)) { + const err = "Something wrong"; + logger.setError(err); + return res.status(404).send(err); + } + res.redirect("/api/groups"); + } catch (e) { + res.status(500).send(e.message); } - res.redirect("/api/groups"); - } catch (e) { - res.status(500).send(e.message); } -}); +); /* Update group */ router.put( "/:id", - [log(GroupsService.update), validator.body(groupValidationSchema)], + [ + log(GroupsService.update), + checkToken, + validator.body(groupValidationSchema) + ], async ({ params: { id }, body }, res) => { try { const status = await GroupsService.update(id, body); diff --git a/src/module-3/controllers/user-groups.ts b/src/module-3/controllers/user-groups.ts index 67ca29b..f8ff188 100644 --- a/src/module-3/controllers/user-groups.ts +++ b/src/module-3/controllers/user-groups.ts @@ -1,6 +1,7 @@ import express from "express"; import { createValidator } from "express-joi-validation"; -import { log, logger } from "../loggers"; +import { checkToken } from "../middlewares/auth"; +import { log, logger } from "../middlewares/loggers"; import { AddUsersToGroupModel } from "../services/types"; import * as UserGroupsService from "../services/user-groups"; import userGroupValidationSchema from "./validation/user-groups"; @@ -10,15 +11,19 @@ const router = express.Router(); /* Get user-groups list */ -router.get("/", log(UserGroupsService.findAll), async (req, res) => { - try { - const userGroups = await UserGroupsService.findAll(); - res.status(200).send(userGroups); - } catch (e) { - logger.setError(e); - res.status(500).send(e.message); +router.get( + "/", + [checkToken, log(UserGroupsService.findAll)], + async (req, res) => { + try { + const userGroups = await UserGroupsService.findAll(); + res.status(200).send(userGroups); + } catch (e) { + logger.setError(e); + res.status(500).send(e.message); + } } -}); +); /* Add user to any group by id*/ @@ -26,7 +31,8 @@ router.post( "/", [ log(UserGroupsService.addUsersToGroup), - validator.body(userGroupValidationSchema) + validator.body(userGroupValidationSchema), + checkToken ], async (req, res) => { try { diff --git a/src/module-3/controllers/users.ts b/src/module-3/controllers/users.ts index 459d94b..ed822f5 100644 --- a/src/module-3/controllers/users.ts +++ b/src/module-3/controllers/users.ts @@ -1,6 +1,7 @@ import express from "express"; import { createValidator } from "express-joi-validation"; -import { log, logger } from "../loggers"; +import { checkToken } from "../middlewares/auth"; +import { log, logger } from "../middlewares/loggers"; import * as UsersService from "../services/users"; import { UserModel } from "../types"; import { isNull } from "./utils"; @@ -11,26 +12,22 @@ const router = express.Router(); /* Get users list */ -router.get( - "/", - log(UsersService.getAutoSuggestUsers), - async ({ body }, res) => { - try { - const users = await UsersService.getAutoSuggestUsers( - body.loginSubstring, - body.limit - ); - res.status(200).send(users); - } catch (e) { - logger.setError(e); - res.status(500).send(e.message); - } +router.get("/", checkToken, async ({ body }, res) => { + try { + const users = await UsersService.getAutoSuggestUsers( + body.loginSubstring, + body.limit + ); + res.status(200).send(users); + } catch (e) { + logger.setError(e); + res.status(500).send(e.message); } -); +}); /* Find user by id */ -router.get("/:id", log(UsersService.find), async (req, res) => { +router.get("/:id", [checkToken, log(UsersService.find)], async (req, res) => { try { const id = req.params.id; const user = await UsersService.find(id); @@ -49,7 +46,7 @@ router.get("/:id", log(UsersService.find), async (req, res) => { router.post( "/", - [log(UsersService.create), validator.body(userValidationSchema)], + [log(UsersService.create), checkToken, validator.body(userValidationSchema)], async (req, res) => { try { const body: UserModel = req.body; @@ -68,26 +65,30 @@ router.post( /* Delete user */ -router.delete("/:id", log(UsersService.remove), async (req, res) => { - try { - const id = req.params.id; - const isSuccess = await UsersService.remove(id); - if (isNull(isSuccess)) { - const err = "User with this id is not found"; - logger.setError(err); - return res.status(404).send(err); +router.delete( + "/:id", + [checkToken, log(UsersService.remove)], + async (req, res) => { + try { + const id = req.params.id; + const isSuccess = await UsersService.remove(id); + if (isNull(isSuccess)) { + const err = "User with this id is not found"; + logger.setError(err); + return res.status(404).send(err); + } + res.redirect("/api/users"); + } catch (e) { + res.status(500).send(e.message); } - res.redirect("/api/users"); - } catch (e) { - res.status(500).send(e.message); } -}); +); /* Update user */ router.put( "/:id", - [log(UsersService.update), validator.body(userValidationSchema)], + [log(UsersService.update), checkToken, validator.body(userValidationSchema)], async (req, res) => { try { const id = req.params.id; diff --git a/src/module-3/controllers/validation/auth.ts b/src/module-3/controllers/validation/auth.ts new file mode 100644 index 0000000..de1eb9a --- /dev/null +++ b/src/module-3/controllers/validation/auth.ts @@ -0,0 +1,12 @@ +import joi from "joi"; + +export const loginValidationSchema = joi.object().keys({ + login: joi.string().alphanum().min(3).max(10).required(), + password: joi.string().alphanum().required() +}); + +export const updTokenValidationSchema = joi.object().keys({ + login: joi.string().alphanum().min(3).max(10).required(), + password: joi.string().alphanum().required(), + refreshToken: joi.string().required() +}); diff --git a/src/module-3/data-access/index.ts b/src/module-3/data-access/index.ts index 0271528..234a793 100644 --- a/src/module-3/data-access/index.ts +++ b/src/module-3/data-access/index.ts @@ -9,6 +9,15 @@ if (!process.env.DB_URL) { const DB_URL = process.env.DB_URL; +export const tokenList = {}; + +export const JWT_DATA = { + refreshTokenSecret: process.env.JWT_REFRESH_TOKEN_SECRET, + accessTokenSecret: process.env.JWT_ACCESS_TOKEN_SECRET, + refreshTokenExp: Number(process.env.JWT_REFRESH_TOKEN_EXP), + accessTokenExp: Number(process.env.JWT_ACCESS_TOKEN_EXP) +}; + export default new Sequelize(DB_URL, { pool: { max: 5, diff --git a/src/module-3/index.ts b/src/module-3/index.ts index f769679..6d12a0e 100644 --- a/src/module-3/index.ts +++ b/src/module-3/index.ts @@ -1,19 +1,18 @@ +import cors from "cors"; import express from "express"; +import authRouter from "./controllers/auth"; import groupsRouter from "./controllers/groups"; import userGroupsRouter from "./controllers/user-groups"; import usersRouter from "./controllers/users"; import db from "./data-access"; -import { - errorLoggerMiddleware, - initHandlers, - mainLoggerMiddleware -} from "./loggers"; +import { errorsLogger, initHandlers, mainLogger } from "./middlewares/loggers"; const app = express(); initHandlers(); -app.use(errorLoggerMiddleware); +app.use(cors()); +app.use(errorsLogger); app.listen(3000, () => db @@ -25,7 +24,8 @@ app.listen(3000, () => ) .then(() => app.use(express.json())) .then(() => { - app.use(mainLoggerMiddleware); + app.use(mainLogger); + app.use("/api/auth", authRouter); app.use("/api/groups", groupsRouter); app.use("/api/users", usersRouter); app.use("/api/user-groups", userGroupsRouter); diff --git a/src/module-3/middlewares/auth.ts b/src/module-3/middlewares/auth.ts new file mode 100644 index 0000000..aef1abe --- /dev/null +++ b/src/module-3/middlewares/auth.ts @@ -0,0 +1,21 @@ +import { NextFunction, Request, Response } from "express"; +import jwt from "jsonwebtoken"; +import { JWT_DATA } from "../data-access"; + +export const checkToken = (req: Request, res: Response, next: NextFunction) => { + const token = req.headers["x-access-token"] as string; + + if (!token) { + return res + .status(403) + .send({ success: false, message: "No token provided" }); + } + + jwt.verify(token, JWT_DATA.accessTokenSecret, (err: Error, decoded) => { + if (err) { + return res.json({ success: false, message: "Failed to auth token." }); + } + + next(); + }); +}; diff --git a/src/module-3/loggers.ts b/src/module-3/middlewares/loggers.ts similarity index 91% rename from src/module-3/loggers.ts rename to src/module-3/middlewares/loggers.ts index 61d4b95..fd124e9 100644 --- a/src/module-3/loggers.ts +++ b/src/module-3/middlewares/loggers.ts @@ -48,14 +48,14 @@ const winstonLogger = winston.createLogger({ exitOnError: false }); -export const errorLoggerMiddleware = morgan("tiny", { +export const errorsLogger = morgan("tiny", { stream: { write: (message) => winstonLogger.error(message) }, skip: (req, res) => res.statusCode !== 500 }); -export const mainLoggerMiddleware = ( +export const mainLogger = ( req: Request, res: Response, next: NextFunction diff --git a/src/module-3/services/auth.ts b/src/module-3/services/auth.ts new file mode 100644 index 0000000..9819cb7 --- /dev/null +++ b/src/module-3/services/auth.ts @@ -0,0 +1,64 @@ +import { Request } from "express"; +import jwt from "jsonwebtoken"; +import { JWT_DATA, tokenList } from "../data-access"; +import User from "../models/user"; +import { UserModel } from "../types"; + +export const verify = async ( + login: UserModel["login"], + password: UserModel["password"] +) => { + const user = await User.findOne({ + where: { + login, + password, + isDeleted: false + } + }); + + if (!user) { + return; + } + + const payload = { + sub: user.get("id"), + login: user.get("login") + }; + + const token = jwt.sign(payload, JWT_DATA.accessTokenSecret, { + expiresIn: JWT_DATA.accessTokenExp + }); + + const refreshToken = jwt.sign(payload, JWT_DATA.refreshTokenSecret, { + expiresIn: JWT_DATA.refreshTokenExp + }); + + const response = { + token, + refreshToken + }; + + tokenList[refreshToken] = response; + + return response; +}; + +export const refreshToken = async (body: Request["body"]) => { + if (body.refreshToken && body.refreshToken in tokenList) { + const payload = { + sub: body.id, + login: body.login + }; + const token = jwt.sign(payload, JWT_DATA.accessTokenSecret, { + expiresIn: JWT_DATA.accessTokenExp + }); + + const response = { token }; + // update the token in the list + tokenList[body.refreshToken].token = token; + + return response; + } + + return; +}; diff --git a/src/module-3/types.ts b/src/module-3/types.ts index 0a22483..a35498f 100644 --- a/src/module-3/types.ts +++ b/src/module-3/types.ts @@ -12,6 +12,8 @@ export interface UserModel extends BaseUser { age: number; } +export type UserAuthModel = Pick; + export type Permissions = | "READ" | "WRITE"