token-service.ts 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. import { config } from "#config";
  2. import jwt from "jsonwebtoken";
  3. // база данных
  4. import { selPool, updPool } from "#db";
  5. import { sql } from "slonik";
  6. // types
  7. import { TokenPayload } from "../types/token-playload-type.js";
  8. import type { Response } from "express";
  9. import { z } from "zod";
  10. import { v7 } from "uuid";
  11. import { logger } from "#plugins/logger.js";
  12. const JWT_ACCESS_SECRET = config.JWT_ACCESS_SECRET || "";
  13. const JWT_REFRESH_SECRET = config.JWT_REFRESH_SECRET || "";
  14. const ACCESS_TOKEN_LIFETIME_MINS = config.ACCESS_TOKEN_LIFETIME_MINS || 15;
  15. const REFRESH_TOKEN_LIFETIME_DAYS = config.REFRESH_TOKEN_LIFETIME_DAYS || 30;
  16. class TokenService {
  17. /**
  18. * генерирует пару токенов: accessToken и refreshToken
  19. * @param payload - данные, которые будут зашифрованы в токенах
  20. * @returns обьект с двумя свойствами: accessToken и refreshToken
  21. */
  22. generateTokens(payload: z.infer<typeof TokenPayload>): {
  23. accessToken: string;
  24. refreshToken: string;
  25. } {
  26. const accessToken = jwt.sign(payload, JWT_ACCESS_SECRET, {
  27. expiresIn: `${ACCESS_TOKEN_LIFETIME_MINS}m`,
  28. });
  29. const refreshToken = jwt.sign(payload, JWT_REFRESH_SECRET, {
  30. expiresIn: `${REFRESH_TOKEN_LIFETIME_DAYS}d`,
  31. });
  32. return {
  33. accessToken,
  34. refreshToken,
  35. };
  36. }
  37. /**
  38. * вставляет refreshToken в базу данных
  39. * @param userId - id пользователя
  40. * @param refreshToken - токен, который будет вставлен
  41. */
  42. async insertRefreshToken(userId: string, refreshToken: string) {
  43. const id = v7();
  44. await updPool.query(
  45. sql.unsafe`
  46. insert into usr.user_refresh_tokens
  47. (token_id, user_id, refresh_token)
  48. values
  49. (${id}, ${userId}, ${refreshToken})
  50. `,
  51. );
  52. }
  53. /**
  54. * обновляет refreshToken в базе данных
  55. * @param userId - id пользователя
  56. * @param oldRefreshToken - старый токен
  57. * @param newRefreshToken - новый токен
  58. */
  59. async updateRefreshToken(
  60. userId: string,
  61. oldRefreshToken: string,
  62. newRefreshToken: string,
  63. ) {
  64. await updPool.query(
  65. sql.unsafe`
  66. update
  67. usr.user_refresh_tokens
  68. set
  69. refresh_token = ${newRefreshToken}
  70. where
  71. user_id = ${userId} and
  72. refresh_token = ${oldRefreshToken}
  73. `,
  74. );
  75. }
  76. /**
  77. * удаляет refreshToken из базы данных
  78. * @param userId - id пользователя
  79. * @param refreshToken - токен, который будет удален
  80. */
  81. async removeToken(userId: string, refreshToken: string) {
  82. await updPool.query(sql.unsafe`
  83. delete from
  84. usr.user_refresh_tokens
  85. where
  86. user_id = ${userId} and refresh_token = ${refreshToken}
  87. `);
  88. }
  89. /**
  90. * удаляет все токены пользователя по его id
  91. * @param userId - id пользователя
  92. */
  93. async removeAllUserTokens(userId: string) {
  94. await updPool.query(sql.unsafe`
  95. delete from
  96. usr.user_refresh_tokens
  97. where
  98. user_id = ${userId}
  99. `);
  100. }
  101. /**
  102. * проверяет acess токен и возвращает данные из него
  103. * @param token - токен
  104. * @returns данные из токена
  105. */
  106. validateAccessToken(token: string) {
  107. const userData = jwt.verify(token, JWT_ACCESS_SECRET);
  108. return TokenPayload.parse(userData);
  109. }
  110. /**
  111. * проверяет refresh токен и возвращает данные из него
  112. * @param token - токен
  113. * @returns данные из токена
  114. */
  115. validateRefreshToken(token: string) {
  116. const userData = jwt.verify(token, JWT_REFRESH_SECRET);
  117. return TokenPayload.parse(userData);
  118. }
  119. /**
  120. * Проверяет, существует ли refresh токен в базе данных
  121. * @param userId - id пользователя
  122. * @param refreshToken - токен, который будет проверен
  123. * @returns true, если токен существует, false - иначе
  124. */
  125. async refreshTokenIsExist(
  126. userId: string,
  127. refreshToken: string,
  128. ): Promise<boolean> {
  129. const tokenIsExist = await selPool.exists(
  130. sql.unsafe`
  131. select
  132. user_id
  133. from
  134. usr.user_refresh_tokens
  135. where
  136. user_id = ${userId} and refresh_token = ${refreshToken}`,
  137. );
  138. return tokenIsExist;
  139. }
  140. /**
  141. * установить refresh токен в cookie
  142. * @param res - объект Response
  143. * @param token - токен
  144. */
  145. setRefreshTokenInCookie(res: Response, token: string) {
  146. logger.silly(`setRefreshTokenInCookie ${token}`);
  147. res.cookie("refreshToken", token, {
  148. maxAge: config.REFRESH_TOKEN_LIFETIME_DAYS * 24 * 60 * 60 * 1000,
  149. httpOnly: true, //запрет на изменение пользователем
  150. // secure: true, //после включения https
  151. sameSite: "lax", // TODO: Разбраться
  152. });
  153. }
  154. }
  155. export default new TokenService();