@intlayer/backend 3.0.3 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. package/dist/cjs/controllers/dictionary.controller.cjs +91 -18
  2. package/dist/cjs/controllers/dictionary.controller.cjs.map +1 -1
  3. package/dist/cjs/controllers/organization.controller.cjs +140 -12
  4. package/dist/cjs/controllers/organization.controller.cjs.map +1 -1
  5. package/dist/cjs/controllers/project.controller.cjs +181 -31
  6. package/dist/cjs/controllers/project.controller.cjs.map +1 -1
  7. package/dist/cjs/controllers/projectAccessKey.controller.cjs +61 -10
  8. package/dist/cjs/controllers/projectAccessKey.controller.cjs.map +1 -1
  9. package/dist/cjs/controllers/sessionAuth.controller.cjs +291 -62
  10. package/dist/cjs/controllers/sessionAuth.controller.cjs.map +1 -1
  11. package/dist/cjs/controllers/stripe.controller.cjs +84 -0
  12. package/dist/cjs/controllers/stripe.controller.cjs.map +1 -0
  13. package/dist/cjs/controllers/user.controller.cjs +49 -20
  14. package/dist/cjs/controllers/user.controller.cjs.map +1 -1
  15. package/dist/cjs/emails/SubscriptionPaymentCancellation.cjs +182 -0
  16. package/dist/cjs/emails/SubscriptionPaymentCancellation.cjs.map +1 -0
  17. package/dist/cjs/emails/SubscriptionPaymentError.cjs +182 -0
  18. package/dist/cjs/emails/SubscriptionPaymentError.cjs.map +1 -0
  19. package/dist/cjs/emails/SubscriptionPaymentSuccess.cjs +188 -0
  20. package/dist/cjs/emails/SubscriptionPaymentSuccess.cjs.map +1 -0
  21. package/dist/cjs/export.cjs.map +1 -1
  22. package/dist/cjs/index.cjs +16 -5
  23. package/dist/cjs/index.cjs.map +1 -1
  24. package/dist/cjs/middlewares/oAuth2.middleware.cjs +10 -0
  25. package/dist/cjs/middlewares/oAuth2.middleware.cjs.map +1 -1
  26. package/dist/cjs/middlewares/sessionAuth.middleware.cjs +50 -10
  27. package/dist/cjs/middlewares/sessionAuth.middleware.cjs.map +1 -1
  28. package/dist/cjs/routes/dictionary.routes.cjs +2 -62
  29. package/dist/cjs/routes/dictionary.routes.cjs.map +1 -1
  30. package/dist/cjs/routes/organization.routes.cjs +1 -25
  31. package/dist/cjs/routes/organization.routes.cjs.map +1 -1
  32. package/dist/cjs/routes/project.routes.cjs +10 -85
  33. package/dist/cjs/routes/project.routes.cjs.map +1 -1
  34. package/dist/cjs/routes/sessionAuth.routes.cjs +26 -25
  35. package/dist/cjs/routes/sessionAuth.routes.cjs.map +1 -1
  36. package/dist/cjs/routes/stripe.routes.cjs +42 -0
  37. package/dist/cjs/routes/stripe.routes.cjs.map +1 -0
  38. package/dist/cjs/routes/user.routes.cjs +6 -27
  39. package/dist/cjs/routes/user.routes.cjs.map +1 -1
  40. package/dist/cjs/schemas/organization.schema.cjs +5 -0
  41. package/dist/cjs/schemas/organization.schema.cjs.map +1 -1
  42. package/dist/cjs/{middlewares/admin.middleware.cjs → schemas/plans.schema.cjs} +32 -20
  43. package/dist/cjs/schemas/plans.schema.cjs.map +1 -0
  44. package/dist/cjs/schemas/project.schema.cjs +14 -1
  45. package/dist/cjs/schemas/project.schema.cjs.map +1 -1
  46. package/dist/cjs/schemas/user.schema.cjs +5 -1
  47. package/dist/cjs/schemas/user.schema.cjs.map +1 -1
  48. package/dist/cjs/services/dictionary.service.cjs.map +1 -1
  49. package/dist/cjs/services/email.service.cjs +113 -43
  50. package/dist/cjs/services/email.service.cjs.map +1 -1
  51. package/dist/cjs/services/oAuth2.service.cjs +16 -8
  52. package/dist/cjs/services/oAuth2.service.cjs.map +1 -1
  53. package/dist/cjs/services/organization.service.cjs +63 -8
  54. package/dist/cjs/services/organization.service.cjs.map +1 -1
  55. package/dist/cjs/services/project.service.cjs +9 -5
  56. package/dist/cjs/services/project.service.cjs.map +1 -1
  57. package/dist/cjs/services/projectAccessKey.service.cjs +42 -10
  58. package/dist/cjs/services/projectAccessKey.service.cjs.map +1 -1
  59. package/dist/cjs/services/sessionAuth.service.cjs +9 -11
  60. package/dist/cjs/services/sessionAuth.service.cjs.map +1 -1
  61. package/dist/cjs/services/subscription.service.cjs +201 -0
  62. package/dist/cjs/services/subscription.service.cjs.map +1 -0
  63. package/dist/cjs/services/user.service.cjs +1 -3
  64. package/dist/cjs/services/user.service.cjs.map +1 -1
  65. package/dist/cjs/types/dictionary.types.cjs.map +1 -1
  66. package/dist/cjs/types/organization.types.cjs.map +1 -1
  67. package/dist/cjs/types/plan.types.cjs +17 -0
  68. package/dist/cjs/types/plan.types.cjs.map +1 -0
  69. package/dist/cjs/types/project.types.cjs.map +1 -1
  70. package/dist/cjs/types/session.types.cjs.map +1 -1
  71. package/dist/cjs/types/user.types.cjs.map +1 -1
  72. package/dist/cjs/utils/errors/ErrorHandler.cjs +29 -9
  73. package/dist/cjs/utils/errors/ErrorHandler.cjs.map +1 -1
  74. package/dist/cjs/utils/errors/ErrorsClass.cjs +17 -3
  75. package/dist/cjs/utils/errors/ErrorsClass.cjs.map +1 -1
  76. package/dist/cjs/utils/errors/errorCodes.cjs +321 -9
  77. package/dist/cjs/utils/errors/errorCodes.cjs.map +1 -1
  78. package/dist/cjs/utils/mapper/organization.cjs.map +1 -1
  79. package/dist/cjs/utils/mapper/project.cjs +19 -3
  80. package/dist/cjs/utils/mapper/project.cjs.map +1 -1
  81. package/dist/cjs/utils/mapper/user.cjs.map +1 -1
  82. package/dist/cjs/utils/plan.cjs +75 -0
  83. package/dist/cjs/utils/plan.cjs.map +1 -0
  84. package/dist/cjs/utils/responseData.cjs +8 -0
  85. package/dist/cjs/utils/responseData.cjs.map +1 -1
  86. package/dist/cjs/webhooks/stripe.webhook.cjs +133 -0
  87. package/dist/cjs/webhooks/stripe.webhook.cjs.map +1 -0
  88. package/dist/esm/controllers/dictionary.controller.mjs +91 -18
  89. package/dist/esm/controllers/dictionary.controller.mjs.map +1 -1
  90. package/dist/esm/controllers/organization.controller.mjs +140 -12
  91. package/dist/esm/controllers/organization.controller.mjs.map +1 -1
  92. package/dist/esm/controllers/project.controller.mjs +181 -31
  93. package/dist/esm/controllers/project.controller.mjs.map +1 -1
  94. package/dist/esm/controllers/projectAccessKey.controller.mjs +61 -10
  95. package/dist/esm/controllers/projectAccessKey.controller.mjs.map +1 -1
  96. package/dist/esm/controllers/sessionAuth.controller.mjs +287 -61
  97. package/dist/esm/controllers/sessionAuth.controller.mjs.map +1 -1
  98. package/dist/esm/controllers/stripe.controller.mjs +60 -0
  99. package/dist/esm/controllers/stripe.controller.mjs.map +1 -0
  100. package/dist/esm/controllers/user.controller.mjs +49 -20
  101. package/dist/esm/controllers/user.controller.mjs.map +1 -1
  102. package/dist/esm/emails/SubscriptionPaymentCancellation.mjs +168 -0
  103. package/dist/esm/emails/SubscriptionPaymentCancellation.mjs.map +1 -0
  104. package/dist/esm/emails/SubscriptionPaymentError.mjs +168 -0
  105. package/dist/esm/emails/SubscriptionPaymentError.mjs.map +1 -0
  106. package/dist/esm/emails/SubscriptionPaymentSuccess.mjs +174 -0
  107. package/dist/esm/emails/SubscriptionPaymentSuccess.mjs.map +1 -0
  108. package/dist/esm/export.mjs.map +1 -1
  109. package/dist/esm/index.mjs +19 -7
  110. package/dist/esm/index.mjs.map +1 -1
  111. package/dist/esm/middlewares/oAuth2.middleware.mjs +10 -0
  112. package/dist/esm/middlewares/oAuth2.middleware.mjs.map +1 -1
  113. package/dist/esm/middlewares/sessionAuth.middleware.mjs +49 -9
  114. package/dist/esm/middlewares/sessionAuth.middleware.mjs.map +1 -1
  115. package/dist/esm/routes/dictionary.routes.mjs +2 -62
  116. package/dist/esm/routes/dictionary.routes.mjs.map +1 -1
  117. package/dist/esm/routes/organization.routes.mjs +1 -25
  118. package/dist/esm/routes/organization.routes.mjs.map +1 -1
  119. package/dist/esm/routes/project.routes.mjs +10 -85
  120. package/dist/esm/routes/project.routes.mjs.map +1 -1
  121. package/dist/esm/routes/sessionAuth.routes.mjs +29 -26
  122. package/dist/esm/routes/sessionAuth.routes.mjs.map +1 -1
  123. package/dist/esm/routes/stripe.routes.mjs +17 -0
  124. package/dist/esm/routes/stripe.routes.mjs.map +1 -0
  125. package/dist/esm/routes/user.routes.mjs +6 -27
  126. package/dist/esm/routes/user.routes.mjs.map +1 -1
  127. package/dist/esm/schemas/organization.schema.mjs +5 -0
  128. package/dist/esm/schemas/organization.schema.mjs.map +1 -1
  129. package/dist/esm/schemas/plans.schema.mjs +32 -0
  130. package/dist/esm/schemas/plans.schema.mjs.map +1 -0
  131. package/dist/esm/schemas/project.schema.mjs +13 -1
  132. package/dist/esm/schemas/project.schema.mjs.map +1 -1
  133. package/dist/esm/schemas/user.schema.mjs +5 -1
  134. package/dist/esm/schemas/user.schema.mjs.map +1 -1
  135. package/dist/esm/services/dictionary.service.mjs.map +1 -1
  136. package/dist/esm/services/email.service.mjs +125 -43
  137. package/dist/esm/services/email.service.mjs.map +1 -1
  138. package/dist/esm/services/oAuth2.service.mjs +16 -8
  139. package/dist/esm/services/oAuth2.service.mjs.map +1 -1
  140. package/dist/esm/services/organization.service.mjs +58 -7
  141. package/dist/esm/services/organization.service.mjs.map +1 -1
  142. package/dist/esm/services/project.service.mjs +9 -5
  143. package/dist/esm/services/project.service.mjs.map +1 -1
  144. package/dist/esm/services/projectAccessKey.service.mjs +42 -10
  145. package/dist/esm/services/projectAccessKey.service.mjs.map +1 -1
  146. package/dist/esm/services/sessionAuth.service.mjs +9 -10
  147. package/dist/esm/services/sessionAuth.service.mjs.map +1 -1
  148. package/dist/esm/services/subscription.service.mjs +178 -0
  149. package/dist/esm/services/subscription.service.mjs.map +1 -0
  150. package/dist/esm/services/user.service.mjs +1 -3
  151. package/dist/esm/services/user.service.mjs.map +1 -1
  152. package/dist/esm/types/plan.types.mjs +1 -0
  153. package/dist/esm/types/plan.types.mjs.map +1 -0
  154. package/dist/esm/utils/errors/ErrorHandler.mjs +29 -9
  155. package/dist/esm/utils/errors/ErrorHandler.mjs.map +1 -1
  156. package/dist/esm/utils/errors/ErrorsClass.mjs +17 -3
  157. package/dist/esm/utils/errors/ErrorsClass.mjs.map +1 -1
  158. package/dist/esm/utils/errors/errorCodes.mjs +321 -9
  159. package/dist/esm/utils/errors/errorCodes.mjs.map +1 -1
  160. package/dist/esm/utils/mapper/organization.mjs.map +1 -1
  161. package/dist/esm/utils/mapper/project.mjs +17 -2
  162. package/dist/esm/utils/mapper/project.mjs.map +1 -1
  163. package/dist/esm/utils/mapper/user.mjs.map +1 -1
  164. package/dist/esm/utils/plan.mjs +50 -0
  165. package/dist/esm/utils/plan.mjs.map +1 -0
  166. package/dist/esm/utils/responseData.mjs +8 -0
  167. package/dist/esm/utils/responseData.mjs.map +1 -1
  168. package/dist/esm/webhooks/stripe.webhook.mjs +113 -0
  169. package/dist/esm/webhooks/stripe.webhook.mjs.map +1 -0
  170. package/dist/types/controllers/dictionary.controller.d.ts.map +1 -1
  171. package/dist/types/controllers/organization.controller.d.ts.map +1 -1
  172. package/dist/types/controllers/project.controller.d.ts +9 -7
  173. package/dist/types/controllers/project.controller.d.ts.map +1 -1
  174. package/dist/types/controllers/projectAccessKey.controller.d.ts.map +1 -1
  175. package/dist/types/controllers/sessionAuth.controller.d.ts +28 -9
  176. package/dist/types/controllers/sessionAuth.controller.d.ts.map +1 -1
  177. package/dist/types/controllers/stripe.controller.d.ts +17 -0
  178. package/dist/types/controllers/stripe.controller.d.ts.map +1 -0
  179. package/dist/types/controllers/user.controller.d.ts.map +1 -1
  180. package/dist/types/emails/SubscriptionPaymentCancellation.d.ts +20 -0
  181. package/dist/types/emails/SubscriptionPaymentCancellation.d.ts.map +1 -0
  182. package/dist/types/emails/SubscriptionPaymentError.d.ts +20 -0
  183. package/dist/types/emails/SubscriptionPaymentError.d.ts.map +1 -0
  184. package/dist/types/emails/SubscriptionPaymentSuccess.d.ts +20 -0
  185. package/dist/types/emails/SubscriptionPaymentSuccess.d.ts.map +1 -0
  186. package/dist/types/export.d.ts +2 -0
  187. package/dist/types/export.d.ts.map +1 -1
  188. package/dist/types/index.d.ts.map +1 -1
  189. package/dist/types/middlewares/oAuth2.middleware.d.ts.map +1 -1
  190. package/dist/types/middlewares/sessionAuth.middleware.d.ts +13 -7
  191. package/dist/types/middlewares/sessionAuth.middleware.d.ts.map +1 -1
  192. package/dist/types/models/dictionary.model.d.ts +1 -1
  193. package/dist/types/models/oAuth2.model.d.ts +1 -1
  194. package/dist/types/models/organization.model.d.ts +2 -1
  195. package/dist/types/models/organization.model.d.ts.map +1 -1
  196. package/dist/types/models/plan.moddel.d.ts +11 -0
  197. package/dist/types/models/plan.moddel.d.ts.map +1 -0
  198. package/dist/types/models/project.model.d.ts +1 -1
  199. package/dist/types/routes/dictionary.routes.d.ts.map +1 -1
  200. package/dist/types/routes/organization.routes.d.ts.map +1 -1
  201. package/dist/types/routes/project.routes.d.ts.map +1 -1
  202. package/dist/types/routes/sessionAuth.routes.d.ts +15 -2
  203. package/dist/types/routes/sessionAuth.routes.d.ts.map +1 -1
  204. package/dist/types/routes/stripe.routes.d.ts +10 -0
  205. package/dist/types/routes/stripe.routes.d.ts.map +1 -0
  206. package/dist/types/routes/user.routes.d.ts.map +1 -1
  207. package/dist/types/schemas/dictionary.schema.d.ts +2 -2
  208. package/dist/types/schemas/oAuth2.schema.d.ts +2 -2
  209. package/dist/types/schemas/organization.schema.d.ts +3 -2
  210. package/dist/types/schemas/organization.schema.d.ts.map +1 -1
  211. package/dist/types/schemas/plans.schema.d.ts +16 -0
  212. package/dist/types/schemas/plans.schema.d.ts.map +1 -0
  213. package/dist/types/schemas/project.schema.d.ts +12 -3
  214. package/dist/types/schemas/project.schema.d.ts.map +1 -1
  215. package/dist/types/schemas/user.schema.d.ts +2 -2
  216. package/dist/types/schemas/user.schema.d.ts.map +1 -1
  217. package/dist/types/services/dictionary.service.d.ts +9 -9
  218. package/dist/types/services/dictionary.service.d.ts.map +1 -1
  219. package/dist/types/services/email.service.d.ts +33 -4
  220. package/dist/types/services/email.service.d.ts.map +1 -1
  221. package/dist/types/services/oAuth2.service.d.ts +7 -5
  222. package/dist/types/services/oAuth2.service.d.ts.map +1 -1
  223. package/dist/types/services/organization.service.d.ts +27 -6
  224. package/dist/types/services/organization.service.d.ts.map +1 -1
  225. package/dist/types/services/plans.service.d.ts +35 -0
  226. package/dist/types/services/plans.service.d.ts.map +1 -0
  227. package/dist/types/services/project.service.d.ts +6 -6
  228. package/dist/types/services/project.service.d.ts.map +1 -1
  229. package/dist/types/services/projectAccessKey.service.d.ts +4 -4
  230. package/dist/types/services/projectAccessKey.service.d.ts.map +1 -1
  231. package/dist/types/services/sessionAuth.service.d.ts +9 -16
  232. package/dist/types/services/sessionAuth.service.d.ts.map +1 -1
  233. package/dist/types/services/subscription.service.d.ts +22 -0
  234. package/dist/types/services/subscription.service.d.ts.map +1 -0
  235. package/dist/types/services/user.service.d.ts +11 -19
  236. package/dist/types/services/user.service.d.ts.map +1 -1
  237. package/dist/types/types/dictionary.types.d.ts +2 -2
  238. package/dist/types/types/dictionary.types.d.ts.map +1 -1
  239. package/dist/types/types/organization.types.d.ts +4 -2
  240. package/dist/types/types/organization.types.d.ts.map +1 -1
  241. package/dist/types/types/plan.types.d.ts +18 -0
  242. package/dist/types/types/plan.types.d.ts.map +1 -0
  243. package/dist/types/types/project.types.d.ts +13 -2
  244. package/dist/types/types/project.types.d.ts.map +1 -1
  245. package/dist/types/types/session.types.d.ts +6 -6
  246. package/dist/types/types/session.types.d.ts.map +1 -1
  247. package/dist/types/types/user.types.d.ts +2 -1
  248. package/dist/types/types/user.types.d.ts.map +1 -1
  249. package/dist/types/utils/errors/ErrorHandler.d.ts +5 -3
  250. package/dist/types/utils/errors/ErrorHandler.d.ts.map +1 -1
  251. package/dist/types/utils/errors/ErrorsClass.d.ts +4 -1
  252. package/dist/types/utils/errors/ErrorsClass.d.ts.map +1 -1
  253. package/dist/types/utils/errors/errorCodes.d.ts +313 -1
  254. package/dist/types/utils/errors/errorCodes.d.ts.map +1 -1
  255. package/dist/types/utils/mapper/organization.d.ts +1 -1
  256. package/dist/types/utils/mapper/organization.d.ts.map +1 -1
  257. package/dist/types/utils/mapper/project.d.ts +10 -1
  258. package/dist/types/utils/mapper/project.d.ts.map +1 -1
  259. package/dist/types/utils/mapper/user.d.ts +1 -1
  260. package/dist/types/utils/mapper/user.d.ts.map +1 -1
  261. package/dist/types/utils/plan.d.ts +17 -0
  262. package/dist/types/utils/plan.d.ts.map +1 -0
  263. package/dist/types/utils/responseData.d.ts +13 -2
  264. package/dist/types/utils/responseData.d.ts.map +1 -1
  265. package/dist/types/webhooks/stripe.d.ts +3 -0
  266. package/dist/types/webhooks/stripe.d.ts.map +1 -0
  267. package/dist/types/webhooks/stripe.webhook.d.ts +3 -0
  268. package/dist/types/webhooks/stripe.webhook.d.ts.map +1 -0
  269. package/package.json +27 -24
  270. package/dist/cjs/middlewares/admin.middleware.cjs.map +0 -1
  271. package/dist/esm/middlewares/admin.middleware.mjs +0 -20
  272. package/dist/esm/middlewares/admin.middleware.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/services/oAuth2.service.ts"],"sourcesContent":["import { randomBytes } from 'crypto';\nimport { OAuth2AccessTokenModel } from '@models/oAuth2.model';\nimport { ProjectModel } from '@models/project.model';\nimport { GenericError } from '@utils/errors';\nimport { getTokenExpireAt } from '@utils/oAuth2';\nimport { Client, User, Token as OAuth2Token, Callback } from 'oauth2-server';\nimport { Token } from '../schemas/oAuth2.schema';\nimport { getOrganizationById } from './organization.service';\nimport { getUserById } from './user.service';\nimport { Organization } from '@/types/organization.types';\nimport { OAuth2Access, Project } from '@/types/project.types';\n\n/**\n * Function to generate client credentials\n *\n * @returns The client id and client secret\n */\nexport const generateClientCredentials = (): {\n clientId: string;\n clientSecret: string;\n} => {\n const clientId = randomBytes(16).toString('hex'); // Generate a 16 character hexadecimal string\n const clientSecret = randomBytes(32).toString('hex'); // Generate a 32 character hexadecimal string\n\n return { clientId, clientSecret };\n};\n\n/**\n * Method to get the client and the project\n *\n * @param clientId - The client id\n * @param clientSecret - The client secret\n * @returns The an object containing the client and the project or false if not found\n */\nexport const getClientAndProjectByClientId = async (\n clientId: string\n): Promise<\n { client: Client; oAuth2Access: OAuth2Access; project: Project } | false\n> => {\n const project = await ProjectModel.findOne({\n 'oAuth2Access.clientId': clientId,\n });\n\n if (!project) {\n return false;\n }\n\n const oAuth2Access = project.oAuth2Access.find(\n (access) => access.clientId === clientId\n );\n\n if (!oAuth2Access) {\n return false;\n }\n\n const formattedClient: Client = {\n id: oAuth2Access.clientId,\n clientId,\n clientSecret: oAuth2Access.clientSecret,\n grants: ['client_credentials'],\n };\n\n return { client: formattedClient, oAuth2Access, project };\n};\n\n/**\n * Get the client and verify that the client secret is correct\n *\n * @param clientId - The client id\n * @param clientSecret - The client secret\n * @returns The client or false if not found\n */\nexport const getClient = async (\n clientId: string,\n clientSecret: string\n): Promise<Client | false> => {\n const result = await getClientAndProjectByClientId(clientId);\n\n if (!result) {\n return false;\n }\n\n const { client } = result;\n\n if (!client || client.clientSecret !== clientSecret) {\n return false;\n }\n\n return client;\n};\n\n/**\n * Format an OAuth2Token\n *\n * @param token\n * @param client\n * @param user\n * @param project\n * @param organization\n * @returns\n */\nexport const formatOAuth2Token = (\n token: Token,\n client: Client,\n user: User,\n project: Project,\n organization: Organization\n): OAuth2Token => {\n const { clientId, userId, ...restToken } = token;\n\n if (String(userId) !== String(user._id)) {\n throw new GenericError('USER_ID_MISMATCH');\n }\n\n const formattedToken: OAuth2Token = {\n ...restToken,\n client,\n user,\n organization,\n project,\n accessToken: token.accessToken,\n accessTokenExpiresAt: token.accessTokenExpiresAt ?? new Date('999-99-99'),\n };\n\n return formattedToken;\n};\n\n/**\n * Format a auth token for the database\n *\n * @param token - The oAuth2 token to format\n * @param clientId - The client ID\n * @param userId - The user ID\n * @returns\n */\nexport const formatDBToken = (\n token: OAuth2Token,\n clientId: Client['id'],\n userId: User['_id']\n): Token => {\n const formattedToken: Token = {\n clientId: clientId,\n userId: userId,\n accessToken: token.accessToken,\n expiresIn: token.accessTokenExpiresAt ?? getTokenExpireAt(),\n };\n\n return formattedToken;\n};\n\n/**\n * Method to save the token\n *\n * @param token - The token\n * @param client - The client\n * @param user - The user\n * @returns The saved token or false if not saved\n */\nexport const saveToken = async (\n token: OAuth2Token,\n client: Client,\n user: User\n): Promise<OAuth2Token | false> => {\n const formattedAccessToken: Token = formatDBToken(token, client.id, user._id);\n\n const result = await OAuth2AccessTokenModel.create(formattedAccessToken);\n\n if (!result) {\n return false;\n }\n\n const result2 = await getClientAndProjectByClientId(result.clientId);\n\n if (!result2) {\n return false;\n }\n\n const { project } = result2;\n\n const organization = await getOrganizationById(project.organizationId);\n\n if (!organization) {\n return false;\n }\n\n const formattedResult = formatOAuth2Token(\n formattedAccessToken,\n client,\n user,\n project,\n organization\n );\n return formattedResult;\n};\n\n/**\n * Method to get the access token\n *\n * @param accessToken - The access token\n * @returns The access token or false if not found\n */\nexport const getAccessToken = async (\n accessToken: string\n): Promise<OAuth2Token | false> => {\n const token = await OAuth2AccessTokenModel.findOne({\n accessToken,\n });\n\n if (!token) {\n return false;\n }\n\n const { userId, clientId } = token;\n\n const user = await getUserById(userId);\n\n if (!user) {\n return false;\n }\n\n const result = await getClientAndProjectByClientId(clientId);\n\n if (!result) {\n return false;\n }\n\n const { client, project } = result;\n\n const organization = await getOrganizationById(project.organizationId);\n\n if (!organization) {\n return false;\n }\n\n const formattedAccessToken = formatOAuth2Token(\n token,\n client,\n user,\n project,\n organization\n );\n\n return formattedAccessToken;\n};\n\n/**\n * Method to get the user from the client\n *\n * @param client - The client\n * @returns The user or false if not found\n */\nexport const getUserFromClient = async (\n client: Client\n): Promise<User | false> => {\n const response = await getClientAndProjectByClientId(client.id);\n\n if (!response) {\n return false;\n }\n\n const { userId } = response.oAuth2Access;\n\n if (!userId) {\n return false;\n }\n\n const user: User = getUserById(userId);\n\n return user;\n};\n\n/**\n * Method to verify the permissions (grants)\n *\n * @param token - The token\n * @param scope - The scope\n * @returns True if the token has the required scope, false otherwise\n */\nexport const verifyScope = async (\n _token: OAuth2Token,\n _scope: string,\n _callback?: Callback<boolean> | undefined\n): Promise<boolean> => {\n // Implement the verification of scopes if necessary\n return true;\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/services/oAuth2.service.ts"],"sourcesContent":["import { randomBytes } from 'crypto';\nimport { OAuth2AccessTokenModel } from '@models/oAuth2.model';\nimport { ProjectModel } from '@models/project.model';\nimport { GenericError } from '@utils/errors';\nimport { getTokenExpireAt } from '@utils/oAuth2';\nimport { Client, User, Token as OAuth2Token, Callback } from 'oauth2-server';\nimport { Token } from '../schemas/oAuth2.schema';\nimport { getOrganizationById } from './organization.service';\nimport { getUserById } from './user.service';\nimport { UserDocument } from '@/export';\nimport { Organization } from '@/types/organization.types';\nimport { OAuth2Access, Project, ProjectDocument } from '@/types/project.types';\n\n/**\n * Function to generate client credentials\n *\n * @returns The client id and client secret\n */\nexport const generateClientCredentials = (): {\n clientId: string;\n clientSecret: string;\n} => {\n const clientId = randomBytes(16).toString('hex'); // Generate a 16 character hexadecimal string\n const clientSecret = randomBytes(32).toString('hex'); // Generate a 32 character hexadecimal string\n\n return { clientId, clientSecret };\n};\n\n/**\n * Method to get the client and the project\n *\n * @param clientId - The client id\n * @param clientSecret - The client secret\n * @returns The an object containing the client, the rights and the project or false if not found\n */\nexport const getClientAndProjectByClientId = async (\n clientId: string\n): Promise<\n | {\n client: Client;\n oAuth2Access: OAuth2Access;\n project: ProjectDocument;\n rights: Token['rights'];\n }\n | false\n> => {\n const project = await ProjectModel.findOne({\n 'oAuth2Access.clientId': clientId,\n });\n\n if (!project) {\n return false;\n }\n\n const oAuth2Access = project.oAuth2Access.find(\n (access) => access.clientId === clientId\n );\n\n if (!oAuth2Access) {\n return false;\n }\n\n const formattedClient: Client = {\n id: oAuth2Access.clientId,\n clientId,\n clientSecret: oAuth2Access.clientSecret,\n grants: ['client_credentials'],\n };\n\n return {\n client: formattedClient,\n oAuth2Access,\n rights: oAuth2Access.rights,\n project,\n };\n};\n\n/**\n * Get the client and verify that the client secret is correct\n *\n * @param clientId - The client id\n * @param clientSecret - The client secret\n * @returns The client or false if not found\n */\nexport const getClient = async (\n clientId: string,\n clientSecret: string\n): Promise<Client | false> => {\n const result = await getClientAndProjectByClientId(clientId);\n\n if (!result) {\n return false;\n }\n\n const { client } = result;\n\n if (!client || client.clientSecret !== clientSecret) {\n return false;\n }\n\n return client;\n};\n\n/**\n * Format an OAuth2Token\n *\n * @param token\n * @param client\n * @param user\n * @param project\n * @param organization\n * @returns\n */\nexport const formatOAuth2Token = (\n token: Token,\n client: Client,\n user: User,\n project: Project,\n organization: Organization,\n rights: Token['rights']\n): OAuth2Token => {\n const { clientId, userId, ...restToken } = token;\n\n if (String(userId) !== String(user._id)) {\n throw new GenericError('USER_ID_MISMATCH');\n }\n\n const formattedToken: OAuth2Token = {\n ...restToken,\n client,\n user,\n organization,\n project,\n accessToken: token.accessToken,\n accessTokenExpiresAt: token.accessTokenExpiresAt ?? new Date('999-99-99'),\n rights,\n };\n\n return formattedToken;\n};\n\n/**\n * Format a auth token for the database\n *\n * @param token - The oAuth2 token to format\n * @param clientId - The client ID\n * @param userId - The user ID\n * @returns\n */\nexport const formatDBToken = (\n token: OAuth2Token,\n clientId: Client['id'],\n userId: User['_id']\n): Token => {\n const formattedToken: Token = {\n clientId: clientId,\n userId: userId,\n accessToken: token.accessToken,\n expiresIn: token.accessTokenExpiresAt ?? getTokenExpireAt(),\n };\n\n return formattedToken;\n};\n\n/**\n * Method to save the token\n *\n * @param token - The token\n * @param client - The client\n * @param user - The user\n * @returns The saved token or false if not saved\n */\nexport const saveToken = async (\n token: OAuth2Token,\n client: Client,\n user: User\n): Promise<OAuth2Token | false> => {\n const formattedAccessToken: Token = formatDBToken(token, client.id, user._id);\n\n const result = await OAuth2AccessTokenModel.create(formattedAccessToken);\n\n if (!result) {\n return false;\n }\n\n const result2 = await getClientAndProjectByClientId(result.clientId);\n\n if (!result2) {\n return false;\n }\n\n const { project } = result2;\n\n const organization = await getOrganizationById(project.organizationId);\n\n if (!organization) {\n return false;\n }\n\n const formattedResult = formatOAuth2Token(\n formattedAccessToken,\n client,\n user,\n project,\n organization,\n token.rights\n );\n return formattedResult;\n};\n\n/**\n * Method to get the access token\n *\n * @param accessToken - The access token\n * @returns The access token or false if not found\n */\nexport const getAccessToken = async (\n accessToken: string\n): Promise<OAuth2Token | false> => {\n const token = await OAuth2AccessTokenModel.findOne({\n accessToken,\n });\n\n if (!token) {\n return false;\n }\n\n const { userId, clientId } = token;\n\n const user = await getUserById(userId);\n\n if (!user) {\n return false;\n }\n\n const result = await getClientAndProjectByClientId(clientId);\n\n if (!result) {\n return false;\n }\n\n const { client, project, rights } = result;\n\n const organization = await getOrganizationById(project.organizationId);\n\n if (!organization) {\n return false;\n }\n\n const formattedAccessToken = formatOAuth2Token(\n token,\n client,\n user,\n project,\n organization,\n rights\n );\n\n return formattedAccessToken;\n};\n\n/**\n * Method to get the user from the client\n *\n * @param client - The client\n * @returns The user or false if not found\n */\nexport const getUserFromClient = async (\n client: Client\n): Promise<UserDocument | false> => {\n const response = await getClientAndProjectByClientId(client.id);\n\n if (!response) {\n return false;\n }\n\n const { userId } = response.oAuth2Access;\n\n if (!userId) {\n return false;\n }\n\n const user = await getUserById(userId);\n\n return user ?? false;\n};\n\n/**\n * Method to verify the permissions (grants)\n *\n * @param token - The token\n * @param scope - The scope\n * @returns True if the token has the required scope, false otherwise\n */\nexport const verifyScope = async (\n _token: OAuth2Token,\n _scope: string,\n _callback?: Callback<boolean> | undefined\n): Promise<boolean> => {\n // Implement the verification of scopes if necessary\n return true;\n};\n"],"mappings":"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","names":[]}
@@ -13,6 +13,12 @@ const getOrganizationById = async (organizationId) => {
13
13
  }
14
14
  return organization;
15
15
  };
16
+ const getOrganizationsByOwner = async (userId) => {
17
+ const organization = await OrganizationModel.find({
18
+ creatorId: userId
19
+ });
20
+ return organization;
21
+ };
16
22
  const countOrganizations = async (filters) => {
17
23
  const result = await OrganizationModel.countDocuments(filters);
18
24
  if (typeof result === "undefined") {
@@ -25,12 +31,22 @@ const createOrganization = async (organization, userId) => {
25
31
  if (Object.keys(errors).length > 0) {
26
32
  throw new GenericError("ORGANIZATION_INVALID_FIELDS", { errors });
27
33
  }
28
- return await OrganizationModel.create({
29
- creatorId: userId,
30
- membersIds: [userId],
31
- adminsIds: [userId],
32
- ...organization
33
- });
34
+ try {
35
+ const result = await OrganizationModel.create({
36
+ creatorId: userId,
37
+ membersIds: [userId],
38
+ adminsIds: [userId],
39
+ plan: {
40
+ name: "FREE",
41
+ statue: "ACTIVE",
42
+ creatorId: userId
43
+ },
44
+ ...organization
45
+ });
46
+ return result;
47
+ } catch (error) {
48
+ throw new GenericError("ORGANIZATION_CREATION_FAILED", { error });
49
+ }
34
50
  };
35
51
  const updateOrganizationById = async (organizationId, organization) => {
36
52
  const updatedKeys = Object.keys(organization);
@@ -57,12 +73,47 @@ const deleteOrganizationById = async (organizationId) => {
57
73
  }
58
74
  return organization;
59
75
  };
76
+ const saveStripeCustomerId = async (organization, customerId) => {
77
+ if (!organization) {
78
+ return null;
79
+ }
80
+ await OrganizationModel.updateOne(
81
+ { _id: organization._id },
82
+ { $set: { plan: { customerId } } }
83
+ );
84
+ };
85
+ const updatePlan = async (organization, plan) => {
86
+ const updateOrganizationResult = await OrganizationModel.updateOne(
87
+ { _id: organization._id },
88
+ { $set: { plan: { ...organization.plan, ...plan } } },
89
+ { new: true }
90
+ );
91
+ if (updateOrganizationResult.matchedCount === 0) {
92
+ throw new GenericError("ORGANIZATION_UPDATE_FAILED", {
93
+ organizationId: organization._id
94
+ });
95
+ }
96
+ const updatedOrganization = await getOrganizationById(organization._id);
97
+ return updatedOrganization;
98
+ };
99
+ const getOrganizationByCustomerId = async (customerId) => {
100
+ const organization = await OrganizationModel.findOne({
101
+ plan: {
102
+ customerId
103
+ }
104
+ });
105
+ return organization;
106
+ };
60
107
  export {
61
108
  countOrganizations,
62
109
  createOrganization,
63
110
  deleteOrganizationById,
64
111
  findOrganizations,
112
+ getOrganizationByCustomerId,
65
113
  getOrganizationById,
66
- updateOrganizationById
114
+ getOrganizationsByOwner,
115
+ saveStripeCustomerId,
116
+ updateOrganizationById,
117
+ updatePlan
67
118
  };
68
119
  //# sourceMappingURL=organization.service.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/services/organization.service.ts"],"sourcesContent":["import { OrganizationModel } from '@models/organization.model';\nimport { GenericError } from '@utils/errors';\nimport type { OrganizationFilters } from '@utils/filtersAndPagination/getOrganizationFiltersAndPagination';\nimport {\n type OrganizationFields,\n validateOrganization,\n} from '@utils/validation/validateOrganization';\nimport type { ObjectId } from 'mongoose';\nimport type {\n Organization,\n OrganizationCreationData,\n} from '@/types/organization.types';\n\n/**\n * Finds organizations based on filters and pagination options.\n * @param filters - MongoDB filter query.\n * @param skip - Number of documents to skip.\n * @param limit - Number of documents to limit.\n * @returns List of organizations matching the filters.\n */\nexport const findOrganizations = async (\n filters: OrganizationFilters,\n skip: number,\n limit: number\n): Promise<Organization[]> => {\n return await OrganizationModel.find(filters).skip(skip).limit(limit);\n};\n\n/**\n * Finds an organization by its ID.\n * @param organizationId - The ID of the organization to find.\n * @returns The organization matching the ID.\n */\nexport const getOrganizationById = async (\n organizationId: ObjectId | string\n): Promise<Organization> => {\n const organization = await OrganizationModel.findById(organizationId);\n\n if (!organization) {\n throw new GenericError('ORGANIZATION_NOT_FOUND', { organizationId });\n }\n\n return organization;\n};\n\n/**\n * Counts the total number of organizations that match the filters.\n * @param filters - MongoDB filter query.\n * @returns Total number of organizations.\n */\nexport const countOrganizations = async (\n filters: OrganizationFilters\n): Promise<number> => {\n const result = await OrganizationModel.countDocuments(filters);\n\n if (typeof result === 'undefined') {\n throw new GenericError('ORGANIZATION_COUNT_FAILED', { filters });\n }\n\n return result;\n};\n\n/**\n * Creates a new organization in the database.\n * @param organization - The organization data to create.\n * @returns The created organization.\n */\nexport const createOrganization = async (\n organization: OrganizationCreationData,\n userId: string | ObjectId\n): Promise<Organization> => {\n const errors = validateOrganization(organization, ['name']);\n\n if (Object.keys(errors).length > 0) {\n throw new GenericError('ORGANIZATION_INVALID_FIELDS', { errors });\n }\n\n return await OrganizationModel.create({\n creatorId: userId,\n membersIds: [userId],\n adminsIds: [userId],\n ...organization,\n });\n};\n\n/**\n * Updates an existing organization in the database by its ID.\n * @param organizationId - The ID of the organization to update.\n * @param organization - The updated organization data.\n * @returns The updated organization.\n */\nexport const updateOrganizationById = async (\n organizationId: ObjectId | string,\n organization: Partial<Organization>\n): Promise<Organization> => {\n const updatedKeys = Object.keys(organization) as OrganizationFields;\n const errors = validateOrganization(organization, updatedKeys);\n\n if (Object.keys(errors).length > 0) {\n throw new GenericError('ORGANIZATION_INVALID_FIELDS', {\n organizationId,\n errors,\n });\n }\n\n const result = await OrganizationModel.updateOne(\n { _id: organizationId },\n organization\n );\n\n if (result.matchedCount === 0) {\n throw new GenericError('ORGANIZATION_UPDATE_FAILED', { organizationId });\n }\n\n return await getOrganizationById(organizationId);\n};\n\n/**\n * Deletes an organization from the database by its ID.\n * @param organizationId - The ID of the organization to delete.\n * @returns The result of the deletion operation.\n */\nexport const deleteOrganizationById = async (\n organizationId: ObjectId | string\n): Promise<Organization> => {\n const organization =\n await OrganizationModel.findByIdAndDelete(organizationId);\n\n if (!organization) {\n throw new GenericError('ORGANIZATION_NOT_FOUND', { organizationId });\n }\n\n return organization;\n};\n"],"mappings":"AAAA,SAAS,yBAAyB;AAClC,SAAS,oBAAoB;AAE7B;AAAA,EAEE;AAAA,OACK;AAcA,MAAM,oBAAoB,OAC/B,SACA,MACA,UAC4B;AAC5B,SAAO,MAAM,kBAAkB,KAAK,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,KAAK;AACrE;AAOO,MAAM,sBAAsB,OACjC,mBAC0B;AAC1B,QAAM,eAAe,MAAM,kBAAkB,SAAS,cAAc;AAEpE,MAAI,CAAC,cAAc;AACjB,UAAM,IAAI,aAAa,0BAA0B,EAAE,eAAe,CAAC;AAAA,EACrE;AAEA,SAAO;AACT;AAOO,MAAM,qBAAqB,OAChC,YACoB;AACpB,QAAM,SAAS,MAAM,kBAAkB,eAAe,OAAO;AAE7D,MAAI,OAAO,WAAW,aAAa;AACjC,UAAM,IAAI,aAAa,6BAA6B,EAAE,QAAQ,CAAC;AAAA,EACjE;AAEA,SAAO;AACT;AAOO,MAAM,qBAAqB,OAChC,cACA,WAC0B;AAC1B,QAAM,SAAS,qBAAqB,cAAc,CAAC,MAAM,CAAC;AAE1D,MAAI,OAAO,KAAK,MAAM,EAAE,SAAS,GAAG;AAClC,UAAM,IAAI,aAAa,+BAA+B,EAAE,OAAO,CAAC;AAAA,EAClE;AAEA,SAAO,MAAM,kBAAkB,OAAO;AAAA,IACpC,WAAW;AAAA,IACX,YAAY,CAAC,MAAM;AAAA,IACnB,WAAW,CAAC,MAAM;AAAA,IAClB,GAAG;AAAA,EACL,CAAC;AACH;AAQO,MAAM,yBAAyB,OACpC,gBACA,iBAC0B;AAC1B,QAAM,cAAc,OAAO,KAAK,YAAY;AAC5C,QAAM,SAAS,qBAAqB,cAAc,WAAW;AAE7D,MAAI,OAAO,KAAK,MAAM,EAAE,SAAS,GAAG;AAClC,UAAM,IAAI,aAAa,+BAA+B;AAAA,MACpD;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,SAAS,MAAM,kBAAkB;AAAA,IACrC,EAAE,KAAK,eAAe;AAAA,IACtB;AAAA,EACF;AAEA,MAAI,OAAO,iBAAiB,GAAG;AAC7B,UAAM,IAAI,aAAa,8BAA8B,EAAE,eAAe,CAAC;AAAA,EACzE;AAEA,SAAO,MAAM,oBAAoB,cAAc;AACjD;AAOO,MAAM,yBAAyB,OACpC,mBAC0B;AAC1B,QAAM,eACJ,MAAM,kBAAkB,kBAAkB,cAAc;AAE1D,MAAI,CAAC,cAAc;AACjB,UAAM,IAAI,aAAa,0BAA0B,EAAE,eAAe,CAAC;AAAA,EACrE;AAEA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../../../src/services/organization.service.ts"],"sourcesContent":["import { OrganizationModel } from '@models/organization.model';\nimport { GenericError } from '@utils/errors';\nimport type { OrganizationFilters } from '@utils/filtersAndPagination/getOrganizationFiltersAndPagination';\nimport {\n type OrganizationFields,\n validateOrganization,\n} from '@utils/validation/validateOrganization';\nimport type { ObjectId } from 'mongoose';\nimport type {\n Organization,\n OrganizationCreationData,\n OrganizationDocument,\n} from '@/types/organization.types';\nimport type { Plan } from '@/types/plan.types';\n\n/**\n * Finds organizations based on filters and pagination options.\n * @param filters - MongoDB filter query.\n * @param skip - Number of documents to skip.\n * @param limit - Number of documents to limit.\n * @returns List of organizations matching the filters.\n */\nexport const findOrganizations = async (\n filters: OrganizationFilters,\n skip: number,\n limit: number\n): Promise<OrganizationDocument[]> => {\n return await OrganizationModel.find(filters).skip(skip).limit(limit);\n};\n\n/**\n * Finds an organization by its ID.\n * @param organizationId - The ID of the organization to find.\n * @returns The organization matching the ID.\n */\nexport const getOrganizationById = async (\n organizationId: ObjectId | string\n): Promise<OrganizationDocument> => {\n const organization = await OrganizationModel.findById(organizationId);\n\n if (!organization) {\n throw new GenericError('ORGANIZATION_NOT_FOUND', { organizationId });\n }\n\n return organization;\n};\n\n/**\n * Retrieves an organization by its owner.\n * @param userId - The ID of the user to find the organization.\n * @returns The organizations matching the user ID.\n */\nexport const getOrganizationsByOwner = async (\n userId: string | ObjectId\n): Promise<OrganizationDocument[] | null> => {\n const organization = await OrganizationModel.find({\n creatorId: userId,\n });\n\n return organization;\n};\n\n/**\n * Counts the total number of organizations that match the filters.\n * @param filters - MongoDB filter query.\n * @returns Total number of organizations.\n */\nexport const countOrganizations = async (\n filters: OrganizationFilters\n): Promise<number> => {\n const result = await OrganizationModel.countDocuments(filters);\n\n if (typeof result === 'undefined') {\n throw new GenericError('ORGANIZATION_COUNT_FAILED', { filters });\n }\n\n return result;\n};\n\n/**\n * Creates a new organization in the database.\n * @param organization - The organization data to create.\n * @returns The created organization.\n */\nexport const createOrganization = async (\n organization: OrganizationCreationData,\n userId: string | ObjectId\n): Promise<OrganizationDocument> => {\n const errors = validateOrganization(organization, ['name']);\n\n if (Object.keys(errors).length > 0) {\n throw new GenericError('ORGANIZATION_INVALID_FIELDS', { errors });\n }\n\n try {\n const result = await OrganizationModel.create({\n creatorId: userId,\n membersIds: [userId],\n adminsIds: [userId],\n plan: {\n name: 'FREE',\n statue: 'ACTIVE',\n creatorId: userId,\n },\n ...organization,\n });\n\n return result;\n } catch (error) {\n throw new GenericError('ORGANIZATION_CREATION_FAILED', { error });\n }\n};\n\n/**\n * Updates an existing organization in the database by its ID.\n * @param organizationId - The ID of the organization to update.\n * @param organization - The updated organization data.\n * @returns The updated organization.\n */\nexport const updateOrganizationById = async (\n organizationId: ObjectId | string,\n organization: Partial<Organization>\n): Promise<OrganizationDocument> => {\n const updatedKeys = Object.keys(organization) as OrganizationFields;\n const errors = validateOrganization(organization, updatedKeys);\n\n if (Object.keys(errors).length > 0) {\n throw new GenericError('ORGANIZATION_INVALID_FIELDS', {\n organizationId,\n errors,\n });\n }\n\n const result = await OrganizationModel.updateOne(\n { _id: organizationId },\n organization\n );\n\n if (result.matchedCount === 0) {\n throw new GenericError('ORGANIZATION_UPDATE_FAILED', { organizationId });\n }\n\n return await getOrganizationById(organizationId);\n};\n\n/**\n * Deletes an organization from the database by its ID.\n * @param organizationId - The ID of the organization to delete.\n * @returns The result of the deletion operation.\n */\nexport const deleteOrganizationById = async (\n organizationId: ObjectId | string\n): Promise<OrganizationDocument> => {\n const organization =\n await OrganizationModel.findByIdAndDelete(organizationId);\n\n if (!organization) {\n throw new GenericError('ORGANIZATION_NOT_FOUND', { organizationId });\n }\n\n return organization;\n};\n\nexport const saveStripeCustomerId = async (\n organization: Organization,\n customerId: string\n) => {\n if (!organization) {\n return null;\n }\n\n await OrganizationModel.updateOne(\n { _id: organization._id },\n { $set: { plan: { customerId } } }\n );\n};\n\n/**\n * Updates an existing plan in the database by its ID.\n * @param planId - The ID of the plan to update.\n * @param plan - The updated plan data.\n * @returns The updated plan.\n */\nexport const updatePlan = async (\n organization: Organization,\n plan: Partial<Plan>\n): Promise<OrganizationDocument | null> => {\n const updateOrganizationResult = await OrganizationModel.updateOne(\n { _id: organization._id },\n { $set: { plan: { ...organization.plan, ...plan } } },\n { new: true }\n );\n\n if (updateOrganizationResult.matchedCount === 0) {\n throw new GenericError('ORGANIZATION_UPDATE_FAILED', {\n organizationId: organization._id,\n });\n }\n\n const updatedOrganization = await getOrganizationById(organization._id);\n\n return updatedOrganization;\n};\n\n/**\n * Retrieves an organization by its customer ID.\n * @param customerId - The ID of the customer to find the organization.\n * @returns The organizations matching the customer ID.\n */\nexport const getOrganizationByCustomerId = async (\n customerId: string\n): Promise<OrganizationDocument | null> => {\n const organization = await OrganizationModel.findOne({\n plan: {\n customerId,\n },\n });\n\n return organization;\n};\n"],"mappings":"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","names":[]}
@@ -3,13 +3,11 @@ import { GenericError } from './../utils/errors/index.mjs';
3
3
  import {
4
4
  validateProject
5
5
  } from './../utils/validation/validateProject.mjs';
6
- const findProjects = async (filters, skip = 0, limit = 100) => {
7
- return await ProjectModel.find(filters).skip(skip).limit(limit);
8
- };
6
+ const findProjects = async (filters, skip = 0, limit = 100) => await ProjectModel.find(filters).skip(skip).limit(limit);
9
7
  const getProjectById = async (projectId) => {
10
8
  const project = await ProjectModel.findById(projectId);
11
9
  if (!project) {
12
- throw new GenericError("PROJECT_NOT_FOUND", { projectId });
10
+ throw new GenericError("PROJECT_NOT_DEFINED", { projectId });
13
11
  }
14
12
  return project;
15
13
  };
@@ -21,6 +19,9 @@ const countProjects = async (filters) => {
21
19
  return result;
22
20
  };
23
21
  const createProject = async (project) => {
22
+ if (project.oAuth2Access) {
23
+ delete project.oAuth2Access;
24
+ }
24
25
  const errors = await validateProject(project, ["name"]);
25
26
  if (Object.keys(errors).length > 0) {
26
27
  throw new GenericError("PROJECT_INVALID_FIELDS", { errors });
@@ -28,6 +29,9 @@ const createProject = async (project) => {
28
29
  return await ProjectModel.create(project);
29
30
  };
30
31
  const updateProjectById = async (projectId, project) => {
32
+ if (project.oAuth2Access) {
33
+ delete project.oAuth2Access;
34
+ }
31
35
  const updatedKeys = Object.keys(project);
32
36
  const errors = validateProject(project, updatedKeys);
33
37
  if (Object.keys(errors).length > 0) {
@@ -45,7 +49,7 @@ const updateProjectById = async (projectId, project) => {
45
49
  const deleteProjectById = async (projectId) => {
46
50
  const project = await ProjectModel.findByIdAndDelete(projectId);
47
51
  if (!project) {
48
- throw new GenericError("PROJECT_NOT_FOUND", { projectId });
52
+ throw new GenericError("PROJECT_NOT_DEFINED", { projectId });
49
53
  }
50
54
  return project;
51
55
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/services/project.service.ts"],"sourcesContent":["import { ProjectModel } from '@models/project.model';\nimport { GenericError } from '@utils/errors';\nimport type { ProjectFilters } from '@utils/filtersAndPagination/getProjectFiltersAndPagination';\nimport {\n type ProjectFields,\n validateProject,\n} from '@utils/validation/validateProject';\nimport type { ObjectId } from 'mongoose';\nimport type { Project, ProjectData } from '@/types/project.types';\n\n/**\n * Finds projects based on filters and pagination options.\n * @param filters - MongoDB filter query.\n * @param skip - Number of documents to skip.\n * @param limit - Number of documents to limit.\n * @returns List of projects matching the filters.\n */\nexport const findProjects = async (\n filters: ProjectFilters,\n skip = 0,\n limit = 100\n): Promise<Project[]> => {\n return await ProjectModel.find(filters).skip(skip).limit(limit);\n};\n\n/**\n * Finds a project by its ID.\n * @param projectId - The ID of the project to find.\n * @returns The project matching the ID.\n */\nexport const getProjectById = async (\n projectId: string | ObjectId\n): Promise<Project> => {\n const project = await ProjectModel.findById(projectId);\n\n if (!project) {\n throw new GenericError('PROJECT_NOT_FOUND', { projectId });\n }\n\n return project;\n};\n\n/**\n * Counts the total number of projects that match the filters.\n * @param filters - MongoDB filter query.\n * @returns Total number of projects.\n */\nexport const countProjects = async (\n filters: ProjectFilters\n): Promise<number> => {\n const result = await ProjectModel.countDocuments(filters);\n\n if (typeof result === 'undefined') {\n throw new GenericError('PROJECT_COUNT_FAILED', { filters });\n }\n\n return result;\n};\n\n/**\n * Creates a new project in the database.\n * @param project - The project data to create.\n * @returns The created project.\n */\nexport const createProject = async (project: ProjectData): Promise<Project> => {\n const errors = await validateProject(project, ['name']);\n\n if (Object.keys(errors).length > 0) {\n throw new GenericError('PROJECT_INVALID_FIELDS', { errors });\n }\n\n return await ProjectModel.create(project);\n};\n\n/**\n * Updates an existing project in the database by its ID.\n * @param projectId - The ID of the project to update.\n * @param project - The updated project data.\n * @returns The updated project.\n */\nexport const updateProjectById = async (\n projectId: string | ObjectId,\n project: Partial<Project>\n): Promise<Project> => {\n const updatedKeys = Object.keys(project) as ProjectFields;\n const errors = validateProject(project, updatedKeys);\n\n if (Object.keys(errors).length > 0) {\n throw new GenericError('PROJECT_INVALID_FIELDS', {\n projectId,\n errors,\n });\n }\n\n const result = await ProjectModel.updateOne({ _id: projectId }, project);\n\n if (result.matchedCount === 0) {\n throw new GenericError('PROJECT_UPDATE_FAILED', { projectId });\n }\n\n return await getProjectById(projectId);\n};\n\n/**\n * Deletes a project from the database by its ID.\n * @param projectId - The ID of the project to delete.\n * @returns The result of the deletion operation.\n */\nexport const deleteProjectById = async (\n projectId: string | ObjectId\n): Promise<Project> => {\n const project = await ProjectModel.findByIdAndDelete(projectId);\n\n if (!project) {\n throw new GenericError('PROJECT_NOT_FOUND', { projectId });\n }\n\n return project;\n};\n"],"mappings":"AAAA,SAAS,oBAAoB;AAC7B,SAAS,oBAAoB;AAE7B;AAAA,EAEE;AAAA,OACK;AAWA,MAAM,eAAe,OAC1B,SACA,OAAO,GACP,QAAQ,QACe;AACvB,SAAO,MAAM,aAAa,KAAK,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,KAAK;AAChE;AAOO,MAAM,iBAAiB,OAC5B,cACqB;AACrB,QAAM,UAAU,MAAM,aAAa,SAAS,SAAS;AAErD,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,aAAa,qBAAqB,EAAE,UAAU,CAAC;AAAA,EAC3D;AAEA,SAAO;AACT;AAOO,MAAM,gBAAgB,OAC3B,YACoB;AACpB,QAAM,SAAS,MAAM,aAAa,eAAe,OAAO;AAExD,MAAI,OAAO,WAAW,aAAa;AACjC,UAAM,IAAI,aAAa,wBAAwB,EAAE,QAAQ,CAAC;AAAA,EAC5D;AAEA,SAAO;AACT;AAOO,MAAM,gBAAgB,OAAO,YAA2C;AAC7E,QAAM,SAAS,MAAM,gBAAgB,SAAS,CAAC,MAAM,CAAC;AAEtD,MAAI,OAAO,KAAK,MAAM,EAAE,SAAS,GAAG;AAClC,UAAM,IAAI,aAAa,0BAA0B,EAAE,OAAO,CAAC;AAAA,EAC7D;AAEA,SAAO,MAAM,aAAa,OAAO,OAAO;AAC1C;AAQO,MAAM,oBAAoB,OAC/B,WACA,YACqB;AACrB,QAAM,cAAc,OAAO,KAAK,OAAO;AACvC,QAAM,SAAS,gBAAgB,SAAS,WAAW;AAEnD,MAAI,OAAO,KAAK,MAAM,EAAE,SAAS,GAAG;AAClC,UAAM,IAAI,aAAa,0BAA0B;AAAA,MAC/C;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,SAAS,MAAM,aAAa,UAAU,EAAE,KAAK,UAAU,GAAG,OAAO;AAEvE,MAAI,OAAO,iBAAiB,GAAG;AAC7B,UAAM,IAAI,aAAa,yBAAyB,EAAE,UAAU,CAAC;AAAA,EAC/D;AAEA,SAAO,MAAM,eAAe,SAAS;AACvC;AAOO,MAAM,oBAAoB,OAC/B,cACqB;AACrB,QAAM,UAAU,MAAM,aAAa,kBAAkB,SAAS;AAE9D,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,aAAa,qBAAqB,EAAE,UAAU,CAAC;AAAA,EAC3D;AAEA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../../../src/services/project.service.ts"],"sourcesContent":["import { ProjectModel } from '@models/project.model';\nimport { GenericError } from '@utils/errors';\nimport type { ProjectFilters } from '@utils/filtersAndPagination/getProjectFiltersAndPagination';\nimport {\n type ProjectFields,\n validateProject,\n} from '@utils/validation/validateProject';\nimport type { ObjectId } from 'mongoose';\nimport type {\n Project,\n ProjectData,\n ProjectDocument,\n} from '@/types/project.types';\n\n/**\n * Finds projects based on filters and pagination options.\n * @param filters - MongoDB filter query.\n * @param skip - Number of documents to skip.\n * @param limit - Number of documents to limit.\n * @returns List of projects matching the filters.\n */\nexport const findProjects = async (\n filters: ProjectFilters,\n skip = 0,\n limit = 100\n): Promise<ProjectDocument[]> =>\n await ProjectModel.find(filters).skip(skip).limit(limit);\n\n/**\n * Finds a project by its ID.\n * @param projectId - The ID of the project to find.\n * @returns The project matching the ID.\n */\nexport const getProjectById = async (\n projectId: string | ObjectId\n): Promise<ProjectDocument> => {\n const project = await ProjectModel.findById(projectId);\n\n if (!project) {\n throw new GenericError('PROJECT_NOT_DEFINED', { projectId });\n }\n\n return project;\n};\n\n/**\n * Counts the total number of projects that match the filters.\n * @param filters - MongoDB filter query.\n * @returns Total number of projects.\n */\nexport const countProjects = async (\n filters: ProjectFilters\n): Promise<number> => {\n const result = await ProjectModel.countDocuments(filters);\n\n if (typeof result === 'undefined') {\n throw new GenericError('PROJECT_COUNT_FAILED', { filters });\n }\n\n return result;\n};\n\n/**\n * Creates a new project in the database.\n * @param project - The project data to create.\n * @returns The created project.\n */\nexport const createProject = async (\n project: ProjectData\n): Promise<ProjectDocument> => {\n if ((project as Partial<Project>).oAuth2Access) {\n delete (project as Partial<Project>).oAuth2Access;\n }\n\n const errors = await validateProject(project, ['name']);\n\n if (Object.keys(errors).length > 0) {\n throw new GenericError('PROJECT_INVALID_FIELDS', { errors });\n }\n\n return await ProjectModel.create(project);\n};\n\n/**\n * Updates an existing project in the database by its ID.\n * @param projectId - The ID of the project to update.\n * @param project - The updated project data.\n * @returns The updated project.\n */\nexport const updateProjectById = async (\n projectId: string | ObjectId,\n project: Partial<Project>\n): Promise<ProjectDocument> => {\n if (project.oAuth2Access) {\n delete project.oAuth2Access;\n }\n\n const updatedKeys = Object.keys(project) as ProjectFields;\n\n const errors = validateProject(project, updatedKeys);\n\n if (Object.keys(errors).length > 0) {\n throw new GenericError('PROJECT_INVALID_FIELDS', {\n projectId,\n errors,\n });\n }\n\n const result = await ProjectModel.updateOne({ _id: projectId }, project);\n\n if (result.matchedCount === 0) {\n throw new GenericError('PROJECT_UPDATE_FAILED', { projectId });\n }\n\n return await getProjectById(projectId);\n};\n\n/**\n * Deletes a project from the database by its ID.\n * @param projectId - The ID of the project to delete.\n * @returns The result of the deletion operation.\n */\nexport const deleteProjectById = async (\n projectId: string | ObjectId\n): Promise<ProjectDocument> => {\n const project = await ProjectModel.findByIdAndDelete(projectId);\n\n if (!project) {\n throw new GenericError('PROJECT_NOT_DEFINED', { projectId });\n }\n\n return project;\n};\n"],"mappings":"AAAA,SAAS,oBAAoB;AAC7B,SAAS,oBAAoB;AAE7B;AAAA,EAEE;AAAA,OACK;AAeA,MAAM,eAAe,OAC1B,SACA,OAAO,GACP,QAAQ,QAER,MAAM,aAAa,KAAK,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,KAAK;AAOlD,MAAM,iBAAiB,OAC5B,cAC6B;AAC7B,QAAM,UAAU,MAAM,aAAa,SAAS,SAAS;AAErD,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,aAAa,uBAAuB,EAAE,UAAU,CAAC;AAAA,EAC7D;AAEA,SAAO;AACT;AAOO,MAAM,gBAAgB,OAC3B,YACoB;AACpB,QAAM,SAAS,MAAM,aAAa,eAAe,OAAO;AAExD,MAAI,OAAO,WAAW,aAAa;AACjC,UAAM,IAAI,aAAa,wBAAwB,EAAE,QAAQ,CAAC;AAAA,EAC5D;AAEA,SAAO;AACT;AAOO,MAAM,gBAAgB,OAC3B,YAC6B;AAC7B,MAAK,QAA6B,cAAc;AAC9C,WAAQ,QAA6B;AAAA,EACvC;AAEA,QAAM,SAAS,MAAM,gBAAgB,SAAS,CAAC,MAAM,CAAC;AAEtD,MAAI,OAAO,KAAK,MAAM,EAAE,SAAS,GAAG;AAClC,UAAM,IAAI,aAAa,0BAA0B,EAAE,OAAO,CAAC;AAAA,EAC7D;AAEA,SAAO,MAAM,aAAa,OAAO,OAAO;AAC1C;AAQO,MAAM,oBAAoB,OAC/B,WACA,YAC6B;AAC7B,MAAI,QAAQ,cAAc;AACxB,WAAO,QAAQ;AAAA,EACjB;AAEA,QAAM,cAAc,OAAO,KAAK,OAAO;AAEvC,QAAM,SAAS,gBAAgB,SAAS,WAAW;AAEnD,MAAI,OAAO,KAAK,MAAM,EAAE,SAAS,GAAG;AAClC,UAAM,IAAI,aAAa,0BAA0B;AAAA,MAC/C;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,SAAS,MAAM,aAAa,UAAU,EAAE,KAAK,UAAU,GAAG,OAAO;AAEvE,MAAI,OAAO,iBAAiB,GAAG;AAC7B,UAAM,IAAI,aAAa,yBAAyB,EAAE,UAAU,CAAC;AAAA,EAC/D;AAEA,SAAO,MAAM,eAAe,SAAS;AACvC;AAOO,MAAM,oBAAoB,OAC/B,cAC6B;AAC7B,QAAM,UAAU,MAAM,aAAa,kBAAkB,SAAS;AAE9D,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,aAAa,uBAAuB,EAAE,UAAU,CAAC;AAAA,EAC7D;AAEA,SAAO;AACT;","names":[]}
@@ -2,14 +2,20 @@ import { ProjectModel } from './../models/project.model.mjs';
2
2
  import { GenericError } from './../utils/errors/index.mjs';
3
3
  import { generateClientCredentials } from './oAuth2.service.mjs';
4
4
  import { getProjectById } from './project.service.mjs';
5
- const addNewAccessKey = async (accessKeyData, projectId, user) => {
5
+ const addNewAccessKey = async (accessKeyData, projectId, user, organizationRights, projectRights, dictionaryRights) => {
6
6
  const { clientId, clientSecret } = generateClientCredentials();
7
7
  const newAccessKey = {
8
8
  ...accessKeyData,
9
9
  clientId,
10
10
  clientSecret,
11
11
  userId: user._id,
12
- accessToken: []
12
+ accessToken: [],
13
+ rights: restrictAccessKeyRights(
14
+ accessKeyData,
15
+ organizationRights,
16
+ projectRights,
17
+ dictionaryRights
18
+ )
13
19
  };
14
20
  const result = await ProjectModel.updateOne(
15
21
  { _id: projectId },
@@ -35,9 +41,9 @@ const addNewAccessKey = async (accessKeyData, projectId, user) => {
35
41
  }
36
42
  return newAccessKeyId;
37
43
  };
38
- const deleteAccessKey = async (clientId, project) => {
44
+ const deleteAccessKey = async (clientId, project, userId) => {
39
45
  const projectAccess = project.oAuth2Access.find(
40
- (access) => access.clientId === clientId
46
+ (access) => access.clientId === clientId && String(access.userId) === String(userId)
41
47
  );
42
48
  if (!projectAccess) {
43
49
  throw new GenericError("ACCESS_KEY_NOT_FOUND", {
@@ -46,7 +52,10 @@ const deleteAccessKey = async (clientId, project) => {
46
52
  });
47
53
  }
48
54
  const result = await ProjectModel.updateOne(
49
- { "oAuth2Access.clientId": clientId },
55
+ {
56
+ "oAuth2Access.clientId": clientId,
57
+ "oAuth2Access.userId": String(userId)
58
+ },
50
59
  { $pull: { oAuth2Access: { clientId } } }
51
60
  );
52
61
  if (result.modifiedCount === 0) {
@@ -57,15 +66,17 @@ const deleteAccessKey = async (clientId, project) => {
57
66
  }
58
67
  return projectAccess;
59
68
  };
60
- const refreshAccessKey = async (clientId, projectId) => {
69
+ const refreshAccessKey = async (clientId, projectId, userId) => {
61
70
  const project = await ProjectModel.findOne({
62
71
  _id: projectId,
63
- "oAuth2Access.clientId": clientId
72
+ "oAuth2Access.clientId": clientId,
73
+ "oAuth2Access.userId": String(userId)
64
74
  });
65
75
  if (!project) {
66
76
  throw new GenericError("PROJECT_NOT_FOUND", {
67
77
  clientId,
68
- projectId
78
+ projectId,
79
+ userId
69
80
  });
70
81
  }
71
82
  const projectAccess = project.oAuth2Access.find(
@@ -79,7 +90,10 @@ const refreshAccessKey = async (clientId, projectId) => {
79
90
  }
80
91
  const { clientSecret } = generateClientCredentials();
81
92
  const result = await ProjectModel.updateOne(
82
- { "oAuth2Access.clientId": clientId },
93
+ {
94
+ "oAuth2Access.clientId": clientId,
95
+ "oAuth2Access.userId": String(userId)
96
+ },
83
97
  {
84
98
  $set: {
85
99
  "oAuth2Access.$.clientId": projectAccess.clientId,
@@ -100,11 +114,29 @@ const refreshAccessKey = async (clientId, projectId) => {
100
114
  if (!newAccessKeyId) {
101
115
  throw new GenericError("ACCESS_KEY_CREATION_FAILED", {
102
116
  accessKeyData: updatedProject.oAuth2Access,
103
- projectId
117
+ projectId,
118
+ userId
104
119
  });
105
120
  }
106
121
  return newAccessKeyId;
107
122
  };
123
+ const restrictRights = (givenRights, userRights) => {
124
+ const restrictedRights = {};
125
+ for (const key in givenRights) {
126
+ if (Object.prototype.hasOwnProperty.call(givenRights, key)) {
127
+ restrictedRights[key] = givenRights[key] && userRights[key];
128
+ }
129
+ }
130
+ return restrictedRights;
131
+ };
132
+ const restrictAccessKeyRights = (accessKey, organizationsRights, projectRights, dictionaryRights) => ({
133
+ dictionary: restrictRights(accessKey.rights.dictionary, dictionaryRights),
134
+ project: restrictRights(accessKey.rights.project, projectRights),
135
+ organization: restrictRights(
136
+ accessKey.rights.organization,
137
+ organizationsRights
138
+ )
139
+ });
108
140
  export {
109
141
  addNewAccessKey,
110
142
  deleteAccessKey,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/services/projectAccessKey.service.ts"],"sourcesContent":["import { ProjectModel } from '@models/project.model';\nimport { GenericError } from '@utils/errors';\nimport type { ObjectId } from 'mongoose';\nimport { generateClientCredentials } from './oAuth2.service';\nimport { getProjectById } from './project.service';\nimport type {\n AccessKeyData,\n OAuth2Access,\n OAuth2AccessData,\n Project,\n} from '@/types/project.types';\nimport { User } from '@/types/user.types';\n\n/**\n * Adds a new access key to a project.\n *\n * @param accessKeyData - The access key data.\n * @param projectId - The ID of the project to add the access key to.\n * @param user - The user adding the access key.\n * @returns The new access key.\n *\n */\nexport const addNewAccessKey = async (\n accessKeyData: AccessKeyData,\n projectId: string | ObjectId,\n user: User\n): Promise<OAuth2Access> => {\n const { clientId, clientSecret } = generateClientCredentials();\n\n const newAccessKey: OAuth2AccessData = {\n ...accessKeyData,\n clientId,\n clientSecret,\n userId: user._id,\n accessToken: [],\n };\n\n const result = await ProjectModel.updateOne(\n { _id: projectId },\n { $push: { oAuth2Access: newAccessKey } }\n );\n\n if (result.modifiedCount === 0) {\n throw new GenericError('ACCESS_KEY_CREATION_FAILED', {\n accessKeyData,\n projectId,\n userId: user._id,\n });\n }\n\n const updatedProject = await getProjectById(projectId);\n\n const newAccessKeyId = updatedProject.oAuth2Access.find(\n (access) => access.clientId === clientId\n );\n\n if (!newAccessKeyId) {\n throw new GenericError('ACCESS_KEY_CREATION_FAILED', {\n accessKeyData,\n projectId,\n userId: user._id,\n });\n }\n\n return newAccessKeyId;\n};\n\nexport const deleteAccessKey = async (\n clientId: string | ObjectId,\n project: Project\n) => {\n const projectAccess = project.oAuth2Access.find(\n (access) => access.clientId === clientId\n );\n\n if (!projectAccess) {\n throw new GenericError('ACCESS_KEY_NOT_FOUND', {\n clientId,\n projectId: project._id,\n });\n }\n\n const result = await ProjectModel.updateOne(\n { 'oAuth2Access.clientId': clientId },\n { $pull: { oAuth2Access: { clientId } } }\n );\n\n if (result.modifiedCount === 0) {\n throw new GenericError('ACCESS_KEY_DELETION_FAILED', {\n clientId,\n projectId: project._id,\n });\n }\n\n return projectAccess;\n};\n\nexport const refreshAccessKey = async (\n clientId: string | ObjectId,\n projectId: string | ObjectId\n): Promise<OAuth2Access> => {\n const project = await ProjectModel.findOne({\n _id: projectId,\n 'oAuth2Access.clientId': clientId,\n });\n\n if (!project) {\n throw new GenericError('PROJECT_NOT_FOUND', {\n clientId,\n projectId,\n });\n }\n\n const projectAccess = project.oAuth2Access.find(\n (access) => access.clientId === clientId\n );\n\n if (!projectAccess) {\n throw new GenericError('ACCESS_KEY_NOT_FOUND', {\n clientId,\n projectId: project._id,\n });\n }\n\n const { clientSecret } = generateClientCredentials();\n\n const result = await ProjectModel.updateOne(\n { 'oAuth2Access.clientId': clientId },\n {\n $set: {\n 'oAuth2Access.$.clientId': projectAccess.clientId,\n 'oAuth2Access.$.clientSecret': clientSecret,\n },\n }\n );\n\n if (result.modifiedCount === 0) {\n throw new GenericError('ACCESS_KEy_UPDATE_FAILED', {\n clientId,\n projectId,\n });\n }\n\n const updatedProject = await getProjectById(projectId);\n\n const newAccessKeyId = updatedProject.oAuth2Access.find(\n (access) => access.clientId === projectAccess.clientId\n );\n\n if (!newAccessKeyId) {\n throw new GenericError('ACCESS_KEY_CREATION_FAILED', {\n accessKeyData: updatedProject.oAuth2Access,\n projectId,\n });\n }\n\n return newAccessKeyId;\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/services/projectAccessKey.service.ts"],"sourcesContent":["import { ProjectModel } from '@models/project.model';\nimport { GenericError } from '@utils/errors';\nimport type { ObjectId } from 'mongoose';\nimport { generateClientCredentials } from './oAuth2.service';\nimport { getProjectById } from './project.service';\nimport type {\n AccessKeyData,\n OAuth2Access,\n OAuth2AccessData,\n Project,\n Rights,\n TokenRights,\n} from '@/types/project.types';\nimport { User } from '@/types/user.types';\n\n/**\n * Adds a new access key to a project.\n *\n * @param accessKeyData - The access key data.\n * @param projectId - The ID of the project to add the access key to.\n * @param user - The user adding the access key.\n * @returns The new access key.\n *\n */\nexport const addNewAccessKey = async (\n accessKeyData: AccessKeyData,\n projectId: string | ObjectId,\n user: User,\n organizationRights: Rights,\n projectRights: Rights,\n dictionaryRights: Rights\n): Promise<OAuth2Access> => {\n const { clientId, clientSecret } = generateClientCredentials();\n\n const newAccessKey: OAuth2AccessData = {\n ...accessKeyData,\n clientId,\n clientSecret,\n userId: user._id,\n accessToken: [],\n rights: restrictAccessKeyRights(\n accessKeyData,\n organizationRights,\n projectRights,\n dictionaryRights\n ),\n };\n\n const result = await ProjectModel.updateOne(\n { _id: projectId },\n { $push: { oAuth2Access: newAccessKey } }\n );\n\n if (result.modifiedCount === 0) {\n throw new GenericError('ACCESS_KEY_CREATION_FAILED', {\n accessKeyData,\n projectId,\n userId: user._id,\n });\n }\n\n const updatedProject = await getProjectById(projectId);\n\n const newAccessKeyId = updatedProject.oAuth2Access.find(\n (access) => access.clientId === clientId\n );\n\n if (!newAccessKeyId) {\n throw new GenericError('ACCESS_KEY_CREATION_FAILED', {\n accessKeyData,\n projectId,\n userId: user._id,\n });\n }\n\n return newAccessKeyId;\n};\n\nexport const deleteAccessKey = async (\n clientId: string | ObjectId,\n project: Project,\n userId: string | ObjectId\n) => {\n const projectAccess = project.oAuth2Access.find(\n (access) =>\n access.clientId === clientId && String(access.userId) === String(userId)\n );\n\n if (!projectAccess) {\n throw new GenericError('ACCESS_KEY_NOT_FOUND', {\n clientId,\n projectId: project._id,\n });\n }\n\n const result = await ProjectModel.updateOne(\n {\n 'oAuth2Access.clientId': clientId,\n 'oAuth2Access.userId': String(userId),\n },\n { $pull: { oAuth2Access: { clientId } } }\n );\n\n if (result.modifiedCount === 0) {\n throw new GenericError('ACCESS_KEY_DELETION_FAILED', {\n clientId,\n projectId: project._id,\n });\n }\n\n return projectAccess;\n};\n\nexport const refreshAccessKey = async (\n clientId: string | ObjectId,\n projectId: string | ObjectId,\n userId: string | ObjectId\n): Promise<OAuth2Access> => {\n const project = await ProjectModel.findOne({\n _id: projectId,\n 'oAuth2Access.clientId': clientId,\n 'oAuth2Access.userId': String(userId),\n });\n\n if (!project) {\n throw new GenericError('PROJECT_NOT_FOUND', {\n clientId,\n projectId,\n userId,\n });\n }\n\n const projectAccess = project.oAuth2Access.find(\n (access) => access.clientId === clientId\n );\n\n if (!projectAccess) {\n throw new GenericError('ACCESS_KEY_NOT_FOUND', {\n clientId,\n projectId: project._id,\n });\n }\n\n const { clientSecret } = generateClientCredentials();\n\n const result = await ProjectModel.updateOne(\n {\n 'oAuth2Access.clientId': clientId,\n 'oAuth2Access.userId': String(userId),\n },\n {\n $set: {\n 'oAuth2Access.$.clientId': projectAccess.clientId,\n 'oAuth2Access.$.clientSecret': clientSecret,\n },\n }\n );\n\n if (result.modifiedCount === 0) {\n throw new GenericError('ACCESS_KEy_UPDATE_FAILED', {\n clientId,\n projectId,\n });\n }\n\n const updatedProject = await getProjectById(projectId);\n\n const newAccessKeyId = updatedProject.oAuth2Access.find(\n (access) => access.clientId === projectAccess.clientId\n );\n\n if (!newAccessKeyId) {\n throw new GenericError('ACCESS_KEY_CREATION_FAILED', {\n accessKeyData: updatedProject.oAuth2Access,\n projectId,\n userId,\n });\n }\n\n return newAccessKeyId;\n};\n\nconst restrictRights = (givenRights: Rights, userRights: Rights): Rights => {\n const restrictedRights: Rights = {} as Rights;\n\n for (const key in givenRights) {\n if (Object.prototype.hasOwnProperty.call(givenRights, key)) {\n restrictedRights[key as keyof Rights] =\n givenRights[key as keyof Rights] && userRights[key as keyof Rights];\n }\n }\n\n return restrictedRights;\n};\n\nconst restrictAccessKeyRights = (\n accessKey: AccessKeyData,\n organizationsRights: Rights,\n projectRights: Rights,\n dictionaryRights: Rights\n): TokenRights => ({\n dictionary: restrictRights(accessKey.rights.dictionary, dictionaryRights),\n project: restrictRights(accessKey.rights.project, projectRights),\n organization: restrictRights(\n accessKey.rights.organization,\n organizationsRights\n ),\n});\n"],"mappings":"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","names":[]}
@@ -1,3 +1,4 @@
1
+ import crypto from "crypto";
1
2
  import { logger } from './../logger/index.mjs';
2
3
  import {
3
4
  Cookies,
@@ -113,11 +114,6 @@ const clearProjectAuth = (res) => {
113
114
  res.locals.project = null;
114
115
  res.cookie(Cookies.JWT_PROJECT, "", getClearCookieOptions());
115
116
  };
116
- const activateUser = async (userId, secret) => {
117
- return await updateUserProvider(userId, "email", {
118
- secret
119
- });
120
- };
121
117
  const generateSecret = (length) => {
122
118
  const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
123
119
  return Array.from(
@@ -139,7 +135,13 @@ const resetUserPassword = async (userId, secret, newPassword) => {
139
135
  if (!emailAndPasswordProvider) {
140
136
  throw new GenericError("USER_PROVIDER_NOT_FOUND", { userId });
141
137
  }
142
- if (emailAndPasswordProvider.secret !== secret) {
138
+ if (!emailAndPasswordProvider.secret) {
139
+ throw new GenericError("USER_PROVIDER_SECRET_NOT_DEFINED", { userId });
140
+ }
141
+ if (!crypto.timingSafeEqual(
142
+ Buffer.from(emailAndPasswordProvider.secret),
143
+ Buffer.from(secret)
144
+ )) {
143
145
  throw new GenericError("USER_PROVIDER_SECRET_NOT_VALID", { userId });
144
146
  }
145
147
  const updatedUser = await updateUserProvider(userId, "email", {
@@ -289,13 +291,11 @@ const hashUserPassword = async (userWithPasswordNotHashed) => {
289
291
  });
290
292
  return { ...user, provider: userProvider };
291
293
  };
292
- const changeUserPassword = async (userId, oldPassword, newPassword) => {
294
+ const changeUserPassword = async (userId, newPassword) => {
293
295
  const user = await getUserById(userId);
294
296
  if (!user) {
295
297
  throw new GenericError("USER_NOT_FOUND", { userId });
296
298
  }
297
- const { email } = user;
298
- await testUserPassword(email, oldPassword);
299
299
  const updatedUser = await updateUserProvider(userId, "email", {
300
300
  passwordHash: await hash(newPassword, await genSalt())
301
301
  });
@@ -312,7 +312,6 @@ const resetPassword = async (userId, password) => {
312
312
  return updatedUser;
313
313
  };
314
314
  export {
315
- activateUser,
316
315
  addSession,
317
316
  addUserProvider,
318
317
  changeUserPassword,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/services/sessionAuth.service.ts"],"sourcesContent":["import { logger } from '@logger';\nimport { ResponseWithInformation } from '@middlewares/sessionAuth.middleware';\nimport {\n Cookies,\n getClearCookieOptions,\n getCookieOptions,\n MAX_AGE,\n} from '@utils/cookies';\nimport { GenericError } from '@utils/errors';\nimport { mapUserToAPI } from '@utils/mapper/user';\nimport { hash, genSalt, compare } from 'bcrypt';\nimport type { Response } from 'express';\n// @ts-ignore express-intlayer not build yet\nimport { t } from 'express-intlayer';\nimport jwt from 'jsonwebtoken';\nimport type { Document, ObjectId } from 'mongoose';\nimport { v4 as uuidv4 } from 'uuid';\n// eslint-disable-next-line import/no-cycle\nimport { getUserByEmail, getUserById, updateUserById } from './user.service';\nimport type { Organization } from '@/types/organization.types';\nimport type { Project } from '@/types/project.types';\nimport type {\n SessionProviders,\n EmailPasswordSessionProvider,\n GoogleSessionProvider,\n GithubSessionProvider,\n Session,\n} from '@/types/session.types';\nimport type { User, UserWithPasswordNotHashed } from '@/types/user.types';\n\n/**\n * Adds a session to a user or updates the existing one.\n * @param user - User object.\n * @returns Updated user object.\n */\nexport const addSession = async (user: User): Promise<User> => {\n const userSessionToken = uuidv4();\n\n const session: Session = {\n sessionToken: userSessionToken,\n expires: new Date(Date.now() + MAX_AGE),\n };\n\n const updatedUser: User = await updateUserById(user._id, { session });\n\n return updatedUser;\n};\n\nexport const removeSession = async (user: User): Promise<User> => {\n const session = undefined;\n\n const updatedUser: User = await updateUserById(user._id, { session });\n\n return updatedUser;\n};\n\n/**\n * Set user auth locals object\n * @param res - Express response object.\n * @param user - User object.\n */\nexport const setUserAuth = async (res: Response, user: User) => {\n const formattedUser = mapUserToAPI(user);\n\n const userToken = jwt.sign(formattedUser, process.env.JWT_TOKEN_SECRET!, {\n expiresIn: MAX_AGE,\n });\n\n if (!userToken) {\n throw new GenericError('JWT_TOKEN_CREATION_FAILED_USER', { user });\n }\n\n const cookieOptions = getCookieOptions();\n\n res.cookie(Cookies.JWT_USER, userToken, cookieOptions);\n\n const userWithSession = await addSession(user);\n\n const userSessionToken = userWithSession.session?.sessionToken;\n\n res.cookie(Cookies.JWT_AUTH, userSessionToken, cookieOptions);\n\n res.locals.user = user;\n logger.info(\n `User logged in - User: Name: ${user.name}, id: ${String(user._id)}`\n );\n};\n\n/**\n * Clears the JWT auth cookies and user locals object.\n * @param res - Express response object.\n */\nexport const clearUserAuth = async (res: ResponseWithInformation) => {\n const { user } = res.locals;\n const cookiesOptions = getClearCookieOptions();\n\n if (user) {\n await removeSession(user);\n }\n\n res.cookie(Cookies.JWT_AUTH, '', cookiesOptions);\n res.cookie(Cookies.JWT_USER, '', cookiesOptions);\n\n res.locals.user = null;\n res.locals.authType = null;\n};\n\n/**\n *\n * @param res\n * @param organization\n * @returns\n */\nexport const setOrganizationAuth = (\n res: ResponseWithInformation,\n organization: Organization\n) => {\n const organizationData = {\n _id: organization._id,\n name: organization.name,\n };\n\n const organizationToken = jwt.sign(\n organizationData,\n process.env.JWT_TOKEN_SECRET!,\n {\n expiresIn: MAX_AGE,\n }\n );\n\n if (!organizationToken) {\n throw new GenericError('JWT_TOKEN_CREATION_FAILED_ORGANIZATION', {\n organization,\n });\n }\n\n res.cookie(Cookies.JWT_ORGANIZATION, organizationToken, getCookieOptions());\n\n res.locals.organization = organization;\n};\n\n/**\n * Clears the JWT organization cookies and organization locals object.\n * @param res - Express response object.\n */\nexport const clearOrganizationAuth = (res: ResponseWithInformation) => {\n res.locals.organization = null;\n\n res.cookie(Cookies.JWT_ORGANIZATION, '', getClearCookieOptions());\n};\n\n/**\n * Set project auth locals object\n * @param res - Express response object.\n * @param project - Project object.\n */\nexport const setProjectAuth = (\n res: ResponseWithInformation,\n project: Project\n) => {\n const { organization } = res.locals;\n const projectData = {\n _id: project._id,\n name: project.name,\n };\n\n const projectToken = jwt.sign(projectData, process.env.JWT_TOKEN_SECRET!, {\n expiresIn: MAX_AGE,\n });\n\n if (!projectToken) {\n throw new GenericError('JWT_TOKEN_CREATION_FAILED_PROJECT', {\n project,\n });\n }\n\n res.cookie(Cookies.JWT_PROJECT, projectToken, getCookieOptions());\n\n if (!organization) {\n throw new GenericError('ORGANIZATION_NOT_FOUND', {\n project,\n });\n }\n\n if (\n // if the project is not in the organization's projects\n String(organization._id) !== String(project.organizationId)\n ) {\n throw new GenericError('JWT_TOKEN_ORGANIZATION_MISMATCH_PROJECT', {\n project,\n });\n }\n\n res.locals.project = project;\n};\n\n/**\n * Clears the JWT project cookies and project locals object.\n * @param res - Express response object.\n */\nexport const clearProjectAuth = (res: Response) => {\n res.locals.project = null;\n\n res.cookie(Cookies.JWT_PROJECT, '', getClearCookieOptions());\n};\n\n/**\n * Activates a user by setting the emailValidated flag to true.\n * @param user - The user object.\n * @returns\n */\nexport const activateUser = async (\n userId: string | ObjectId,\n secret: string\n): Promise<User> => {\n return await updateUserProvider(userId, 'email', {\n secret,\n });\n};\n\n/**\n * Generates a random secret string of a specified length.\n * @param length - The length of the secret.\n * @returns The generated secret string.\n */\nexport const generateSecret = (length: number): string => {\n const characters =\n 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\n return Array.from({ length }, () =>\n characters.charAt(Math.floor(Math.random() * characters.length))\n ).join('');\n};\n\n/**\n * Handles a password reset request for a user.\n * @param email - The user's email.\n * @param organization - The organization associated with the user.\n * @returns The user object or null if no user was found.\n */\nexport const requestPasswordReset = async (\n email: string\n): Promise<User | null> => {\n const user = await getUserByEmail(email);\n\n if (!user) {\n throw new GenericError('USER_NOT_FOUND', { email });\n }\n\n return updateUserProvider(user._id as unknown as string, 'email', {\n secret: generateSecret(35),\n });\n};\n\n/**\n * Resets a user's password.\n * @param userId - The ID of the user.\n * @param secret - The secret token associated with the user.\n * @param newPassword - The new password to set.\n * @returns The updated user or null if the reset failed.\n */\nexport const resetUserPassword = async (\n userId: string | ObjectId,\n secret: string,\n newPassword: string\n): Promise<User> => {\n const emailAndPasswordProvider = await getUserProvider(userId, 'email');\n\n if (!emailAndPasswordProvider) {\n throw new GenericError('USER_PROVIDER_NOT_FOUND', { userId });\n }\n\n if (emailAndPasswordProvider.secret !== secret) {\n throw new GenericError('USER_PROVIDER_SECRET_NOT_VALID', { userId });\n }\n\n const updatedUser: User = await updateUserProvider(userId, 'email', {\n passwordHash: await hash(newPassword, await genSalt()),\n secret,\n });\n\n return updatedUser;\n};\n\ntype UserProvider<T extends SessionProviders['provider']> = T extends 'email'\n ? EmailPasswordSessionProvider\n : T extends 'google'\n ? GoogleSessionProvider\n : T extends 'github'\n ? GithubSessionProvider\n : SessionProviders;\n\n/**\n * Gets a user's provider.\n * @param userId - The ID of the user.\n * @param provider - The provider to get.\n * @returns The user's provider.\n */\nexport const getUserProvider = async <T extends SessionProviders['provider']>(\n userId: string | ObjectId,\n provider: T,\n providerAccountId?: string\n): Promise<UserProvider<T> | null> => {\n const user = await getUserById(userId);\n\n if (!user) {\n throw new GenericError('USER_NOT_FOUND', { userId });\n }\n\n const userProvider = user.provider?.find(\n (providerEl) =>\n (providerEl.provider === provider && !providerAccountId) ||\n (providerAccountId &&\n (providerEl as GithubSessionProvider).providerAccountId ===\n providerAccountId)\n );\n\n return (userProvider as UserProvider<T>) ?? null;\n};\n\n/**\n * Formats the given fields of a user's provider.\n * @param provider - The provider to update.\n * @param user - The user object.\n * @param providerUpdate - The updates to apply to the provider.\n * @returns The updated user provider.\n */\nexport const formatUserProviderUpdate = <\n T extends SessionProviders['provider'],\n>(\n provider: T,\n user: Partial<User>,\n providerUpdate: Partial<UserProvider<T>>\n): User['provider'] => {\n const userProvider: SessionProviders[] = (\n user.provider as unknown as Document\n ).toObject();\n const userProviderToUpdate = userProvider?.find(\n (providerEl) => providerEl.provider === provider\n );\n\n let updatedProvider: User['provider'];\n\n if (userProviderToUpdate) {\n const otherProviders =\n user.provider?.filter((p) => p.provider !== provider) ?? [];\n\n updatedProvider = [\n ...otherProviders,\n { ...userProviderToUpdate, ...providerUpdate, provider },\n ];\n } else {\n updatedProvider = [\n ...(user.provider ?? []),\n { ...providerUpdate, provider } as SessionProviders,\n ];\n }\n\n return updatedProvider;\n};\n\n/**\n * Updates the given fields of a user's provider.\n * @param userId - The ID of the user.\n * @param provider - The provider to update.\n * @param providerUpdate - The updates to apply to the provider.\n * @returns The updated user.\n */\nexport const updateUserProvider = async <\n T extends SessionProviders['provider'],\n>(\n userId: string | ObjectId,\n provider: T,\n providerUpdate: Partial<UserProvider<T>>\n): Promise<User> => {\n const user = await getUserById(userId);\n\n if (!user) {\n throw new GenericError('USER_NOT_FOUND', { userId });\n }\n\n const formattedProviderToUpdate = formatUserProviderUpdate(\n provider,\n user,\n providerUpdate\n );\n\n const updatedUser: User = await updateUserById(userId, {\n provider: formattedProviderToUpdate,\n });\n\n logger.info(\n `User provider updated - User: Name: ${updatedUser.name}, id: ${String(updatedUser._id)} - Provider: ${provider}`\n );\n\n return updatedUser;\n};\n\n/**\n * Updates the given fields of a user's provider.\n * @param userId - The ID of the user.\n * @param provider - The updates to apply to the provider.\n * @returns The updated user.\n */\nexport const addUserProvider = async (\n userId: string | ObjectId,\n provider: SessionProviders\n): Promise<User> => {\n const user = await getUserById(userId);\n\n if (!user) {\n throw new GenericError('USER_NOT_FOUND', { userId });\n }\n\n const existingProvider = await getUserProvider(userId, provider.provider);\n\n if (existingProvider) {\n throw new GenericError('USER_PROVIDER_ALREADY_EXISTS', {\n userId,\n provider,\n });\n }\n\n const updatedProvider = [...(user.provider ?? []), provider];\n\n const updatedUser = await updateUserById(userId, {\n provider: updatedProvider,\n });\n\n logger.info(\n `User provider added - User: Name: ${updatedUser.name}, id: ${String(updatedUser._id)} - Provider: ${provider.provider}`\n );\n\n return updatedUser;\n};\n\n/**\n * Removes a user's provider.\n * @param userId - The ID of the user.\n * @param provider - The provider to remove.\n * @returns The updated user.\n */\nexport const removeUserProvider = async (\n userId: string | ObjectId,\n provider: SessionProviders['provider'],\n providerAccountId?: string\n) => {\n const user = await getUserById(userId);\n\n if (!user) {\n throw new GenericError('USER_NOT_FOUND', { userId });\n }\n\n const existingProvider = await getUserProvider(\n userId,\n provider,\n providerAccountId\n );\n\n if (!existingProvider) {\n throw new GenericError('USER_PROVIDER_NOT_FOUND', {\n userId,\n provider,\n });\n }\n\n const updatedProvider = user.provider?.filter(\n (p) =>\n p.provider !== provider &&\n (!providerAccountId ||\n (providerAccountId &&\n (p as GithubSessionProvider).providerAccountId !== providerAccountId))\n );\n\n return await updateUserById(userId, {\n provider: updatedProvider,\n });\n};\n\ntype TestUserPasswordResult = { user: User | null; error?: string };\n\n/**\n * Logs in a user.\n * @param email - The user's email.\n * @param password - The user's password.\n * @returns The user object.\n */\nexport const testUserPassword = async (\n email: string,\n password: string\n): Promise<TestUserPasswordResult> => {\n const user = await getUserByEmail(email);\n\n if (!user) {\n const errorMessages = {\n en: `User not found - ${email}`,\n fr: `Utilisateur non trouvé - ${email}`,\n es: `Usuario no encontrado - ${email}`,\n };\n\n return { user: null, error: t(errorMessages) };\n }\n\n const userEmailPasswordProvider = user.provider?.find(\n (provider) => provider.provider === 'email'\n );\n\n if (!userEmailPasswordProvider?.passwordHash) {\n const errorMessages = {\n en: `User request to login but no password defined: ${user.email}`,\n fr: `Demande de connexion d'utilisateur mais pas de mot de passe défini : ${user.email}`,\n es: `Solicitud de inicio de sesión de usuario pero no se define la contraseña : ${user.email}`,\n };\n\n return { user: null, error: t(errorMessages) };\n }\n\n const isMatch = await compare(\n password,\n userEmailPasswordProvider.passwordHash\n );\n\n if (!isMatch) {\n const errorMessages = {\n en: `Incorrect email or password: ${email}`,\n fr: `Email ou mot de passe incorrect : ${email}`,\n es: `Correo electrónico o contraseña incorrecta : ${email}`,\n };\n\n logger.error(errorMessages.en);\n\n // Await a random time to prevent brute force attacks\n const randomNumber = Math.floor(Math.random() * 1000) + 1000;\n await new Promise((resolve) => setTimeout(resolve, randomNumber));\n\n return { user: null, error: t(errorMessages) };\n }\n\n return { user };\n};\n\n/**\n * Hashes a user's password.\n * @param userWithPasswordNotHashed - The user object with password not hashed.\n * @returns The user object with hashed password.\n */\nexport const hashUserPassword = async (\n userWithPasswordNotHashed: UserWithPasswordNotHashed\n): Promise<Partial<User>> => {\n const { password, ...user } = userWithPasswordNotHashed;\n\n if (!password) {\n throw new GenericError('USER_PASSWORD_NOT_DEFINED', { user });\n }\n\n const userProvider = formatUserProviderUpdate('email', user, {\n passwordHash: await hash(password, await genSalt()),\n secret: generateSecret(35),\n });\n\n return { ...user, provider: userProvider };\n};\n\n/**\n * Changes a user's password.\n * @param userId - The ID of the user.\n * @param oldPassword - The user's old password.\n * @param newPassword - The user's new password.\n * @returns The updated user or null if the password change failed.\n */\nexport const changeUserPassword = async (\n userId: string | ObjectId,\n oldPassword: string,\n newPassword: string\n) => {\n const user = await getUserById(userId);\n\n if (!user) {\n throw new GenericError('USER_NOT_FOUND', { userId });\n }\n\n const { email } = user;\n\n await testUserPassword(email, oldPassword);\n\n const updatedUser: User = await updateUserProvider(userId, 'email', {\n passwordHash: await hash(newPassword, await genSalt()),\n });\n\n return updatedUser;\n};\n\n/**\n * Resets a user's password.\n * @param userId - The ID of the user.\n * @param secret - The secret token associated with the user.\n * @param newPassword - The new password to set.\n * @returns The updated user or null if the reset failed.\n */\nexport const resetPassword = async (userId: string, password: string) => {\n const user = await getUserById(userId);\n\n if (!user) {\n throw new GenericError('USER_NOT_FOUND', { userId });\n }\n\n const updatedUser: User = await updateUserProvider(userId, 'email', {\n passwordHash: await hash(password, await genSalt()),\n });\n\n return updatedUser;\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/services/sessionAuth.service.ts"],"sourcesContent":["import crypto from 'crypto';\nimport { logger } from '@logger';\nimport { ResponseWithInformation } from '@middlewares/sessionAuth.middleware';\nimport {\n Cookies,\n getClearCookieOptions,\n getCookieOptions,\n MAX_AGE,\n} from '@utils/cookies';\nimport { GenericError } from '@utils/errors';\nimport { mapUserToAPI } from '@utils/mapper/user';\nimport { hash, genSalt, compare } from 'bcrypt';\nimport type { Response } from 'express';\n// @ts-ignore express-intlayer not build yet\nimport { t } from 'express-intlayer';\nimport jwt from 'jsonwebtoken';\nimport type { Document, ObjectId } from 'mongoose';\nimport { v4 as uuidv4 } from 'uuid';\n// eslint-disable-next-line import/no-cycle\nimport { getUserByEmail, getUserById, updateUserById } from './user.service';\nimport type { Organization } from '@/types/organization.types';\nimport type { Project } from '@/types/project.types';\nimport type {\n SessionProviders,\n EmailPasswordSessionProvider,\n GoogleSessionProvider,\n GithubSessionProvider,\n Session,\n} from '@/types/session.types';\nimport type {\n User,\n UserDocument,\n UserWithPasswordNotHashed,\n} from '@/types/user.types';\n\n/**\n * Adds a session to a user or updates the existing one.\n * @param user - User object.\n * @returns Updated user object.\n */\nexport const addSession = async (user: User): Promise<UserDocument> => {\n const userSessionToken = uuidv4();\n\n const session: Session = {\n sessionToken: userSessionToken,\n expires: new Date(Date.now() + MAX_AGE),\n };\n\n const updatedUser: UserDocument = await updateUserById(user._id, { session });\n\n return updatedUser;\n};\n\nexport const removeSession = async (user: User): Promise<UserDocument> => {\n const session = undefined;\n\n const updatedUser: UserDocument = await updateUserById(user._id, { session });\n\n return updatedUser;\n};\n\n/**\n * Set user auth locals object\n * @param res - Express response object.\n * @param user - User object.\n */\nexport const setUserAuth = async (res: Response, user: User) => {\n const formattedUser = mapUserToAPI(user);\n\n const userToken = jwt.sign(formattedUser, process.env.JWT_TOKEN_SECRET!, {\n expiresIn: MAX_AGE,\n });\n\n if (!userToken) {\n throw new GenericError('JWT_TOKEN_CREATION_FAILED_USER', { user });\n }\n\n const cookieOptions = getCookieOptions();\n\n res.cookie(Cookies.JWT_USER, userToken, cookieOptions);\n\n const userWithSession: UserDocument = await addSession(user);\n\n const userSessionToken = userWithSession.session?.sessionToken;\n\n res.cookie(Cookies.JWT_AUTH, userSessionToken, cookieOptions);\n\n res.locals.user = user;\n logger.info(\n `User logged in - User: Name: ${user.name}, id: ${String(user._id)}`\n );\n};\n\n/**\n * Clears the JWT auth cookies and user locals object.\n * @param res - Express response object.\n */\nexport const clearUserAuth = async (res: ResponseWithInformation) => {\n const { user } = res.locals;\n const cookiesOptions = getClearCookieOptions();\n\n if (user) {\n await removeSession(user);\n }\n\n res.cookie(Cookies.JWT_AUTH, '', cookiesOptions);\n res.cookie(Cookies.JWT_USER, '', cookiesOptions);\n\n res.locals.user = null;\n res.locals.authType = null;\n};\n\n/**\n *\n * @param res\n * @param organization\n * @returns\n */\nexport const setOrganizationAuth = (\n res: ResponseWithInformation,\n organization: Organization\n) => {\n const organizationData = {\n _id: organization._id,\n name: organization.name,\n };\n\n const organizationToken = jwt.sign(\n organizationData,\n process.env.JWT_TOKEN_SECRET!,\n {\n expiresIn: MAX_AGE,\n }\n );\n\n if (!organizationToken) {\n throw new GenericError('JWT_TOKEN_CREATION_FAILED_ORGANIZATION', {\n organization,\n });\n }\n\n res.cookie(Cookies.JWT_ORGANIZATION, organizationToken, getCookieOptions());\n\n res.locals.organization = organization;\n};\n\n/**\n * Clears the JWT organization cookies and organization locals object.\n * @param res - Express response object.\n */\nexport const clearOrganizationAuth = (res: ResponseWithInformation) => {\n res.locals.organization = null;\n\n res.cookie(Cookies.JWT_ORGANIZATION, '', getClearCookieOptions());\n};\n\n/**\n * Set project auth locals object\n * @param res - Express response object.\n * @param project - Project object.\n */\nexport const setProjectAuth = (\n res: ResponseWithInformation,\n project: Project\n) => {\n const { organization } = res.locals;\n const projectData = {\n _id: project._id,\n name: project.name,\n };\n\n const projectToken = jwt.sign(projectData, process.env.JWT_TOKEN_SECRET!, {\n expiresIn: MAX_AGE,\n });\n\n if (!projectToken) {\n throw new GenericError('JWT_TOKEN_CREATION_FAILED_PROJECT', {\n project,\n });\n }\n\n res.cookie(Cookies.JWT_PROJECT, projectToken, getCookieOptions());\n\n if (!organization) {\n throw new GenericError('ORGANIZATION_NOT_FOUND', {\n project,\n });\n }\n\n if (\n // if the project is not in the organization's projects\n String(organization._id) !== String(project.organizationId)\n ) {\n throw new GenericError('JWT_TOKEN_ORGANIZATION_MISMATCH_PROJECT', {\n project,\n });\n }\n\n res.locals.project = project;\n};\n\n/**\n * Clears the JWT project cookies and project locals object.\n * @param res - Express response object.\n */\nexport const clearProjectAuth = (res: Response) => {\n res.locals.project = null;\n\n res.cookie(Cookies.JWT_PROJECT, '', getClearCookieOptions());\n};\n\n/**\n * Generates a random secret string of a specified length.\n * @param length - The length of the secret.\n * @returns The generated secret string.\n */\nexport const generateSecret = (length: number): string => {\n const characters =\n 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\n return Array.from({ length }, () =>\n characters.charAt(Math.floor(Math.random() * characters.length))\n ).join('');\n};\n\n/**\n * Handles a password reset request for a user.\n * @param email - The user's email.\n * @param organization - The organization associated with the user.\n * @returns The user object or null if no user was found.\n */\nexport const requestPasswordReset = async (\n email: string\n): Promise<User | null> => {\n const user = await getUserByEmail(email);\n\n if (!user) {\n throw new GenericError('USER_NOT_FOUND', { email });\n }\n\n return updateUserProvider(user._id as unknown as string, 'email', {\n secret: generateSecret(35),\n });\n};\n\n/**\n * Resets a user's password.\n * @param userId - The ID of the user.\n * @param secret - The secret token associated with the user.\n * @param newPassword - The new password to set.\n * @returns The updated user or null if the reset failed.\n */\nexport const resetUserPassword = async (\n userId: string | ObjectId,\n secret: string,\n newPassword: string\n): Promise<User> => {\n const emailAndPasswordProvider = await getUserProvider(userId, 'email');\n\n if (!emailAndPasswordProvider) {\n throw new GenericError('USER_PROVIDER_NOT_FOUND', { userId });\n }\n\n if (!emailAndPasswordProvider.secret) {\n throw new GenericError('USER_PROVIDER_SECRET_NOT_DEFINED', { userId });\n }\n\n if (\n !crypto.timingSafeEqual(\n Buffer.from(emailAndPasswordProvider.secret),\n Buffer.from(secret)\n )\n ) {\n throw new GenericError('USER_PROVIDER_SECRET_NOT_VALID', { userId });\n }\n\n const updatedUser: User = await updateUserProvider(userId, 'email', {\n passwordHash: await hash(newPassword, await genSalt()),\n secret,\n });\n\n return updatedUser;\n};\n\ntype UserProvider<T extends SessionProviders['provider']> = T extends 'email'\n ? EmailPasswordSessionProvider\n : T extends 'google'\n ? GoogleSessionProvider\n : T extends 'github'\n ? GithubSessionProvider\n : SessionProviders;\n\n/**\n * Gets a user's provider.\n * @param userId - The ID of the user.\n * @param provider - The provider to get.\n * @returns The user's provider.\n */\nexport const getUserProvider = async <T extends SessionProviders['provider']>(\n userId: string | ObjectId,\n provider: T,\n providerAccountId?: string\n): Promise<UserProvider<T> | null> => {\n const user = await getUserById(userId);\n\n if (!user) {\n throw new GenericError('USER_NOT_FOUND', { userId });\n }\n\n const userProvider = user.provider?.find(\n (providerEl) =>\n (providerEl.provider === provider && !providerAccountId) ||\n (providerAccountId &&\n (providerEl as GithubSessionProvider).providerAccountId ===\n providerAccountId)\n );\n\n return (userProvider as UserProvider<T>) ?? null;\n};\n\n/**\n * Formats the given fields of a user's provider.\n * @param provider - The provider to update.\n * @param user - The user object.\n * @param providerUpdate - The updates to apply to the provider.\n * @returns The updated user provider.\n */\nexport const formatUserProviderUpdate = <\n T extends SessionProviders['provider'],\n>(\n provider: T,\n user: Partial<User>,\n providerUpdate: Partial<UserProvider<T>>\n): User['provider'] => {\n const userProvider: SessionProviders[] = (\n user.provider as unknown as Document\n ).toObject();\n const userProviderToUpdate = userProvider?.find(\n (providerEl) => providerEl.provider === provider\n );\n\n let updatedProvider: User['provider'];\n\n if (userProviderToUpdate) {\n const otherProviders =\n user.provider?.filter((p) => p.provider !== provider) ?? [];\n\n updatedProvider = [\n ...otherProviders,\n { ...userProviderToUpdate, ...providerUpdate, provider },\n ];\n } else {\n updatedProvider = [\n ...(user.provider ?? []),\n { ...providerUpdate, provider } as SessionProviders,\n ];\n }\n\n return updatedProvider;\n};\n\n/**\n * Updates the given fields of a user's provider.\n * @param userId - The ID of the user.\n * @param provider - The provider to update.\n * @param providerUpdate - The updates to apply to the provider.\n * @returns The updated user.\n */\nexport const updateUserProvider = async <\n T extends SessionProviders['provider'],\n>(\n userId: string | ObjectId,\n provider: T,\n providerUpdate: Partial<UserProvider<T>>\n): Promise<UserDocument> => {\n const user = await getUserById(userId);\n\n if (!user) {\n throw new GenericError('USER_NOT_FOUND', { userId });\n }\n\n const formattedProviderToUpdate = formatUserProviderUpdate(\n provider,\n user,\n providerUpdate\n );\n\n const updatedUser: UserDocument = await updateUserById(userId, {\n provider: formattedProviderToUpdate,\n });\n\n logger.info(\n `User provider updated - User: Name: ${updatedUser.name}, id: ${String(updatedUser._id)} - Provider: ${provider}`\n );\n\n return updatedUser;\n};\n\n/**\n * Updates the given fields of a user's provider.\n * @param userId - The ID of the user.\n * @param provider - The updates to apply to the provider.\n * @returns The updated user.\n */\nexport const addUserProvider = async (\n userId: string | ObjectId,\n provider: SessionProviders\n): Promise<UserDocument> => {\n const user = await getUserById(userId);\n\n if (!user) {\n throw new GenericError('USER_NOT_FOUND', { userId });\n }\n\n const existingProvider = await getUserProvider(userId, provider.provider);\n\n if (existingProvider) {\n throw new GenericError('USER_PROVIDER_ALREADY_EXISTS', {\n userId,\n provider,\n });\n }\n\n const updatedProvider = [...(user.provider ?? []), provider];\n\n const updatedUser = await updateUserById(userId, {\n provider: updatedProvider,\n });\n\n logger.info(\n `User provider added - User: Name: ${updatedUser.name}, id: ${String(updatedUser._id)} - Provider: ${provider.provider}`\n );\n\n return updatedUser;\n};\n\n/**\n * Removes a user's provider.\n * @param userId - The ID of the user.\n * @param provider - The provider to remove.\n * @returns The updated user.\n */\nexport const removeUserProvider = async (\n userId: string | ObjectId,\n provider: SessionProviders['provider'],\n providerAccountId?: string\n) => {\n const user = await getUserById(userId);\n\n if (!user) {\n throw new GenericError('USER_NOT_FOUND', { userId });\n }\n\n const existingProvider = await getUserProvider(\n userId,\n provider,\n providerAccountId\n );\n\n if (!existingProvider) {\n throw new GenericError('USER_PROVIDER_NOT_FOUND', {\n userId,\n provider,\n });\n }\n\n const updatedProvider = user.provider?.filter(\n (p) =>\n p.provider !== provider &&\n (!providerAccountId ||\n (providerAccountId &&\n (p as GithubSessionProvider).providerAccountId !== providerAccountId))\n );\n\n return await updateUserById(userId, {\n provider: updatedProvider,\n });\n};\n\ntype TestUserPasswordResult = { user: User | null; error?: string };\n\n/**\n * Logs in a user.\n * @param email - The user's email.\n * @param password - The user's password.\n * @returns The user object.\n */\nexport const testUserPassword = async (\n email: string,\n password: string\n): Promise<TestUserPasswordResult> => {\n const user = await getUserByEmail(email);\n\n if (!user) {\n const errorMessages = {\n en: `User not found - ${email}`,\n fr: `Utilisateur non trouvé - ${email}`,\n es: `Usuario no encontrado - ${email}`,\n };\n\n return { user: null, error: t(errorMessages) };\n }\n\n const userEmailPasswordProvider = user.provider?.find(\n (provider) => provider.provider === 'email'\n );\n\n if (!userEmailPasswordProvider?.passwordHash) {\n const errorMessages = {\n en: `User request to login but no password defined: ${user.email}`,\n fr: `Demande de connexion d'utilisateur mais pas de mot de passe défini : ${user.email}`,\n es: `Solicitud de inicio de sesión de usuario pero no se define la contraseña : ${user.email}`,\n };\n\n return { user: null, error: t(errorMessages) };\n }\n\n const isMatch = await compare(\n password,\n userEmailPasswordProvider.passwordHash\n );\n\n if (!isMatch) {\n const errorMessages = {\n en: `Incorrect email or password: ${email}`,\n fr: `Email ou mot de passe incorrect : ${email}`,\n es: `Correo electrónico o contraseña incorrecta : ${email}`,\n };\n\n logger.error(errorMessages.en);\n\n // Await a random time to prevent brute force attacks\n const randomNumber = Math.floor(Math.random() * 1000) + 1000;\n await new Promise((resolve) => setTimeout(resolve, randomNumber));\n\n return { user: null, error: t(errorMessages) };\n }\n\n return { user };\n};\n\n/**\n * Hashes a user's password.\n * @param userWithPasswordNotHashed - The user object with password not hashed.\n * @returns The user object with hashed password.\n */\nexport const hashUserPassword = async (\n userWithPasswordNotHashed: UserWithPasswordNotHashed\n): Promise<Partial<UserDocument>> => {\n const { password, ...user } = userWithPasswordNotHashed;\n\n if (!password) {\n throw new GenericError('USER_PASSWORD_NOT_DEFINED', { user });\n }\n\n const userProvider = formatUserProviderUpdate('email', user, {\n passwordHash: await hash(password, await genSalt()),\n secret: generateSecret(35),\n });\n\n return { ...user, provider: userProvider };\n};\n\n/**\n * Changes a user's password.\n * @param userId - The ID of the user.\n * @param newPassword - The user's new password.\n * @returns The updated user or null if the password change failed.\n */\nexport const changeUserPassword = async (\n userId: string | ObjectId,\n newPassword: string\n) => {\n const user = await getUserById(userId);\n\n if (!user) {\n throw new GenericError('USER_NOT_FOUND', { userId });\n }\n\n const updatedUser: User = await updateUserProvider(userId, 'email', {\n passwordHash: await hash(newPassword, await genSalt()),\n });\n\n return updatedUser;\n};\n\n/**\n * Resets a user's password.\n * @param userId - The ID of the user.\n * @param secret - The secret token associated with the user.\n * @param newPassword - The new password to set.\n * @returns The updated user or null if the reset failed.\n */\nexport const resetPassword = async (userId: string, password: string) => {\n const user = await getUserById(userId);\n\n if (!user) {\n throw new GenericError('USER_NOT_FOUND', { userId });\n }\n\n const updatedUser: UserDocument = await updateUserProvider(userId, 'email', {\n passwordHash: await hash(password, await genSalt()),\n });\n\n return updatedUser;\n};\n"],"mappings":"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","names":[]}