@nauth-toolkit/core 0.1.14 → 0.1.18

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 (623) hide show
  1. package/dist/adapters/database-columns.d.ts +70 -0
  2. package/dist/adapters/database-columns.d.ts.map +1 -1
  3. package/dist/adapters/database-columns.js +76 -2
  4. package/dist/adapters/database-columns.js.map +1 -1
  5. package/dist/adapters/express.adapter.d.ts +66 -0
  6. package/dist/adapters/express.adapter.d.ts.map +1 -1
  7. package/dist/adapters/express.adapter.js +80 -0
  8. package/dist/adapters/express.adapter.js.map +1 -1
  9. package/dist/adapters/fastify.adapter.d.ts +42 -0
  10. package/dist/adapters/fastify.adapter.d.ts.map +1 -1
  11. package/dist/adapters/fastify.adapter.js +86 -0
  12. package/dist/adapters/fastify.adapter.js.map +1 -1
  13. package/dist/adapters/index.d.ts +5 -0
  14. package/dist/adapters/index.d.ts.map +1 -1
  15. package/dist/adapters/index.js +9 -0
  16. package/dist/adapters/index.js.map +1 -1
  17. package/dist/adapters/storage.factory.d.ts +107 -0
  18. package/dist/adapters/storage.factory.d.ts.map +1 -1
  19. package/dist/adapters/storage.factory.js +114 -0
  20. package/dist/adapters/storage.factory.js.map +1 -1
  21. package/dist/adapters.d.ts +8 -0
  22. package/dist/adapters.d.ts.map +1 -1
  23. package/dist/adapters.js +8 -0
  24. package/dist/adapters.js.map +1 -1
  25. package/dist/bootstrap.d.ts +82 -0
  26. package/dist/bootstrap.d.ts.map +1 -1
  27. package/dist/bootstrap.js +106 -0
  28. package/dist/bootstrap.js.map +1 -1
  29. package/dist/dto/admin-set-password.dto.d.ts +90 -0
  30. package/dist/dto/admin-set-password.dto.d.ts.map +1 -1
  31. package/dist/dto/admin-set-password.dto.js +91 -0
  32. package/dist/dto/admin-set-password.dto.js.map +1 -1
  33. package/dist/dto/auth-challenge.dto.d.ts +170 -0
  34. package/dist/dto/auth-challenge.dto.d.ts.map +1 -1
  35. package/dist/dto/auth-challenge.dto.js +170 -0
  36. package/dist/dto/auth-challenge.dto.js.map +1 -1
  37. package/dist/dto/auth-response.dto.d.ts +196 -0
  38. package/dist/dto/auth-response.dto.d.ts.map +1 -1
  39. package/dist/dto/auth-response.dto.js +149 -0
  40. package/dist/dto/auth-response.dto.js.map +1 -1
  41. package/dist/dto/challenge-response.dto.d.ts +155 -0
  42. package/dist/dto/challenge-response.dto.d.ts.map +1 -1
  43. package/dist/dto/challenge-response.dto.js +8 -0
  44. package/dist/dto/challenge-response.dto.js.map +1 -1
  45. package/dist/dto/change-password-request.dto.d.ts +35 -0
  46. package/dist/dto/change-password-request.dto.d.ts.map +1 -1
  47. package/dist/dto/change-password-request.dto.js +35 -0
  48. package/dist/dto/change-password-request.dto.js.map +1 -1
  49. package/dist/dto/change-password-response.dto.d.ts +25 -0
  50. package/dist/dto/change-password-response.dto.d.ts.map +1 -1
  51. package/dist/dto/change-password-response.dto.js +25 -0
  52. package/dist/dto/change-password-response.dto.js.map +1 -1
  53. package/dist/dto/change-password.dto.d.ts +45 -0
  54. package/dist/dto/change-password.dto.d.ts.map +1 -1
  55. package/dist/dto/change-password.dto.js +45 -0
  56. package/dist/dto/change-password.dto.js.map +1 -1
  57. package/dist/dto/confirm-forgot-password.dto.d.ts +59 -0
  58. package/dist/dto/confirm-forgot-password.dto.d.ts.map +1 -1
  59. package/dist/dto/confirm-forgot-password.dto.js +59 -0
  60. package/dist/dto/confirm-forgot-password.dto.js.map +1 -1
  61. package/dist/dto/error-response.dto.d.ts +103 -0
  62. package/dist/dto/error-response.dto.d.ts.map +1 -1
  63. package/dist/dto/error-response.dto.js +103 -0
  64. package/dist/dto/error-response.dto.js.map +1 -1
  65. package/dist/dto/forgot-password.dto.d.ts +58 -0
  66. package/dist/dto/forgot-password.dto.d.ts.map +1 -1
  67. package/dist/dto/forgot-password.dto.js +58 -0
  68. package/dist/dto/forgot-password.dto.js.map +1 -1
  69. package/dist/dto/get-available-methods.dto.d.ts +37 -0
  70. package/dist/dto/get-available-methods.dto.d.ts.map +1 -1
  71. package/dist/dto/get-available-methods.dto.js +37 -0
  72. package/dist/dto/get-available-methods.dto.js.map +1 -1
  73. package/dist/dto/get-challenge-data-response.dto.d.ts +24 -0
  74. package/dist/dto/get-challenge-data-response.dto.d.ts.map +1 -1
  75. package/dist/dto/get-challenge-data-response.dto.js +24 -0
  76. package/dist/dto/get-challenge-data-response.dto.js.map +1 -1
  77. package/dist/dto/get-challenge-data.dto.d.ts +46 -0
  78. package/dist/dto/get-challenge-data.dto.d.ts.map +1 -1
  79. package/dist/dto/get-challenge-data.dto.js +46 -0
  80. package/dist/dto/get-challenge-data.dto.js.map +1 -1
  81. package/dist/dto/get-client-info.dto.d.ts +74 -0
  82. package/dist/dto/get-client-info.dto.d.ts.map +1 -1
  83. package/dist/dto/get-client-info.dto.js +74 -0
  84. package/dist/dto/get-client-info.dto.js.map +1 -1
  85. package/dist/dto/get-device-token-response.dto.d.ts +21 -0
  86. package/dist/dto/get-device-token-response.dto.d.ts.map +1 -1
  87. package/dist/dto/get-device-token-response.dto.js +21 -0
  88. package/dist/dto/get-device-token-response.dto.js.map +1 -1
  89. package/dist/dto/get-events-by-type.dto.d.ts +50 -0
  90. package/dist/dto/get-events-by-type.dto.d.ts.map +1 -1
  91. package/dist/dto/get-events-by-type.dto.js +50 -0
  92. package/dist/dto/get-events-by-type.dto.js.map +1 -1
  93. package/dist/dto/get-ip-address-response.dto.d.ts +20 -0
  94. package/dist/dto/get-ip-address-response.dto.d.ts.map +1 -1
  95. package/dist/dto/get-ip-address-response.dto.js +20 -0
  96. package/dist/dto/get-ip-address-response.dto.js.map +1 -1
  97. package/dist/dto/get-mfa-status.dto.d.ts +59 -0
  98. package/dist/dto/get-mfa-status.dto.d.ts.map +1 -1
  99. package/dist/dto/get-mfa-status.dto.js +59 -0
  100. package/dist/dto/get-mfa-status.dto.js.map +1 -1
  101. package/dist/dto/get-risk-assessment-history.dto.d.ts +28 -0
  102. package/dist/dto/get-risk-assessment-history.dto.d.ts.map +1 -1
  103. package/dist/dto/get-risk-assessment-history.dto.js +28 -0
  104. package/dist/dto/get-risk-assessment-history.dto.js.map +1 -1
  105. package/dist/dto/get-session-id-response.dto.d.ts +21 -0
  106. package/dist/dto/get-session-id-response.dto.d.ts.map +1 -1
  107. package/dist/dto/get-session-id-response.dto.js +21 -0
  108. package/dist/dto/get-session-id-response.dto.js.map +1 -1
  109. package/dist/dto/get-setup-data-response.dto.d.ts +27 -0
  110. package/dist/dto/get-setup-data-response.dto.d.ts.map +1 -1
  111. package/dist/dto/get-setup-data-response.dto.js +27 -0
  112. package/dist/dto/get-setup-data-response.dto.js.map +1 -1
  113. package/dist/dto/get-setup-data.dto.d.ts +51 -0
  114. package/dist/dto/get-setup-data.dto.d.ts.map +1 -1
  115. package/dist/dto/get-setup-data.dto.js +51 -0
  116. package/dist/dto/get-setup-data.dto.js.map +1 -1
  117. package/dist/dto/get-suspicious-activity.dto.d.ts +31 -0
  118. package/dist/dto/get-suspicious-activity.dto.d.ts.map +1 -1
  119. package/dist/dto/get-suspicious-activity.dto.js +31 -0
  120. package/dist/dto/get-suspicious-activity.dto.js.map +1 -1
  121. package/dist/dto/get-user-agent-response.dto.d.ts +19 -0
  122. package/dist/dto/get-user-agent-response.dto.d.ts.map +1 -1
  123. package/dist/dto/get-user-agent-response.dto.js +19 -0
  124. package/dist/dto/get-user-agent-response.dto.js.map +1 -1
  125. package/dist/dto/get-user-auth-history.dto.d.ts +64 -0
  126. package/dist/dto/get-user-auth-history.dto.d.ts.map +1 -1
  127. package/dist/dto/get-user-auth-history.dto.js +64 -0
  128. package/dist/dto/get-user-auth-history.dto.js.map +1 -1
  129. package/dist/dto/get-user-by-email.dto.d.ts +42 -0
  130. package/dist/dto/get-user-by-email.dto.d.ts.map +1 -1
  131. package/dist/dto/get-user-by-email.dto.js +42 -0
  132. package/dist/dto/get-user-by-email.dto.js.map +1 -1
  133. package/dist/dto/get-user-by-id.dto.d.ts +32 -0
  134. package/dist/dto/get-user-by-id.dto.d.ts.map +1 -1
  135. package/dist/dto/get-user-by-id.dto.js +32 -0
  136. package/dist/dto/get-user-by-id.dto.js.map +1 -1
  137. package/dist/dto/get-user-devices.dto.d.ts +34 -0
  138. package/dist/dto/get-user-devices.dto.d.ts.map +1 -1
  139. package/dist/dto/get-user-devices.dto.js +34 -0
  140. package/dist/dto/get-user-devices.dto.js.map +1 -1
  141. package/dist/dto/get-user-response.dto.d.ts +14 -0
  142. package/dist/dto/get-user-response.dto.d.ts.map +1 -1
  143. package/dist/dto/get-user-response.dto.js +15 -0
  144. package/dist/dto/get-user-response.dto.js.map +1 -1
  145. package/dist/dto/has-provider.dto.d.ts +33 -0
  146. package/dist/dto/has-provider.dto.d.ts.map +1 -1
  147. package/dist/dto/has-provider.dto.js +33 -0
  148. package/dist/dto/has-provider.dto.js.map +1 -1
  149. package/dist/dto/index.js +5 -0
  150. package/dist/dto/index.js.map +1 -1
  151. package/dist/dto/is-trusted-device-response.dto.d.ts +28 -0
  152. package/dist/dto/is-trusted-device-response.dto.d.ts.map +1 -1
  153. package/dist/dto/is-trusted-device-response.dto.js +28 -0
  154. package/dist/dto/is-trusted-device-response.dto.js.map +1 -1
  155. package/dist/dto/list-providers-response.dto.d.ts +19 -0
  156. package/dist/dto/list-providers-response.dto.d.ts.map +1 -1
  157. package/dist/dto/list-providers-response.dto.js +19 -0
  158. package/dist/dto/list-providers-response.dto.js.map +1 -1
  159. package/dist/dto/login.dto.d.ts +48 -0
  160. package/dist/dto/login.dto.d.ts.map +1 -1
  161. package/dist/dto/login.dto.js +50 -1
  162. package/dist/dto/login.dto.js.map +1 -1
  163. package/dist/dto/logout-all-response.dto.d.ts +20 -0
  164. package/dist/dto/logout-all-response.dto.d.ts.map +1 -1
  165. package/dist/dto/logout-all-response.dto.js +20 -0
  166. package/dist/dto/logout-all-response.dto.js.map +1 -1
  167. package/dist/dto/logout-all.dto.d.ts +42 -0
  168. package/dist/dto/logout-all.dto.d.ts.map +1 -1
  169. package/dist/dto/logout-all.dto.js +42 -0
  170. package/dist/dto/logout-all.dto.js.map +1 -1
  171. package/dist/dto/logout-response.dto.d.ts +21 -0
  172. package/dist/dto/logout-response.dto.d.ts.map +1 -1
  173. package/dist/dto/logout-response.dto.js +21 -0
  174. package/dist/dto/logout-response.dto.js.map +1 -1
  175. package/dist/dto/logout.dto.d.ts +45 -0
  176. package/dist/dto/logout.dto.d.ts.map +1 -1
  177. package/dist/dto/logout.dto.js +45 -0
  178. package/dist/dto/logout.dto.js.map +1 -1
  179. package/dist/dto/refresh-token.dto.d.ts +28 -0
  180. package/dist/dto/refresh-token.dto.d.ts.map +1 -1
  181. package/dist/dto/refresh-token.dto.js +28 -0
  182. package/dist/dto/refresh-token.dto.js.map +1 -1
  183. package/dist/dto/remove-devices.dto.d.ts +51 -0
  184. package/dist/dto/remove-devices.dto.d.ts.map +1 -1
  185. package/dist/dto/remove-devices.dto.js +51 -0
  186. package/dist/dto/remove-devices.dto.js.map +1 -1
  187. package/dist/dto/resend-code-response.dto.d.ts +28 -0
  188. package/dist/dto/resend-code-response.dto.d.ts.map +1 -1
  189. package/dist/dto/resend-code-response.dto.js +28 -0
  190. package/dist/dto/resend-code-response.dto.js.map +1 -1
  191. package/dist/dto/resend-code.dto.d.ts +37 -0
  192. package/dist/dto/resend-code.dto.d.ts.map +1 -1
  193. package/dist/dto/resend-code.dto.js +37 -0
  194. package/dist/dto/resend-code.dto.js.map +1 -1
  195. package/dist/dto/reset-password.dto.d.ts +74 -0
  196. package/dist/dto/reset-password.dto.d.ts.map +1 -1
  197. package/dist/dto/reset-password.dto.js +76 -1
  198. package/dist/dto/reset-password.dto.js.map +1 -1
  199. package/dist/dto/respond-challenge.dto.d.ts +147 -0
  200. package/dist/dto/respond-challenge.dto.d.ts.map +1 -1
  201. package/dist/dto/respond-challenge.dto.js +162 -0
  202. package/dist/dto/respond-challenge.dto.js.map +1 -1
  203. package/dist/dto/set-mfa-exemption.dto.d.ts +65 -0
  204. package/dist/dto/set-mfa-exemption.dto.d.ts.map +1 -1
  205. package/dist/dto/set-mfa-exemption.dto.js +65 -0
  206. package/dist/dto/set-mfa-exemption.dto.js.map +1 -1
  207. package/dist/dto/set-must-change-password-response.dto.d.ts +23 -0
  208. package/dist/dto/set-must-change-password-response.dto.d.ts.map +1 -1
  209. package/dist/dto/set-must-change-password-response.dto.js +23 -0
  210. package/dist/dto/set-must-change-password-response.dto.js.map +1 -1
  211. package/dist/dto/set-must-change-password.dto.d.ts +32 -0
  212. package/dist/dto/set-must-change-password.dto.d.ts.map +1 -1
  213. package/dist/dto/set-must-change-password.dto.js +32 -0
  214. package/dist/dto/set-must-change-password.dto.js.map +1 -1
  215. package/dist/dto/set-preferred-method.dto.d.ts +48 -0
  216. package/dist/dto/set-preferred-method.dto.d.ts.map +1 -1
  217. package/dist/dto/set-preferred-method.dto.js +48 -0
  218. package/dist/dto/set-preferred-method.dto.js.map +1 -1
  219. package/dist/dto/setup-mfa.dto.d.ts +62 -0
  220. package/dist/dto/setup-mfa.dto.d.ts.map +1 -1
  221. package/dist/dto/setup-mfa.dto.js +62 -0
  222. package/dist/dto/setup-mfa.dto.js.map +1 -1
  223. package/dist/dto/signup.dto.d.ts +92 -0
  224. package/dist/dto/signup.dto.d.ts.map +1 -1
  225. package/dist/dto/signup.dto.js +93 -0
  226. package/dist/dto/signup.dto.js.map +1 -1
  227. package/dist/dto/social-auth.dto.d.ts +234 -0
  228. package/dist/dto/social-auth.dto.d.ts.map +1 -1
  229. package/dist/dto/social-auth.dto.js +234 -0
  230. package/dist/dto/social-auth.dto.js.map +1 -1
  231. package/dist/dto/trust-device-response.dto.d.ts +26 -0
  232. package/dist/dto/trust-device-response.dto.d.ts.map +1 -1
  233. package/dist/dto/trust-device-response.dto.js +26 -0
  234. package/dist/dto/trust-device-response.dto.js.map +1 -1
  235. package/dist/dto/trust-device.dto.d.ts +9 -0
  236. package/dist/dto/trust-device.dto.d.ts.map +1 -1
  237. package/dist/dto/trust-device.dto.js +9 -0
  238. package/dist/dto/trust-device.dto.js.map +1 -1
  239. package/dist/dto/update-user-attributes-request.dto.d.ts +36 -0
  240. package/dist/dto/update-user-attributes-request.dto.d.ts.map +1 -1
  241. package/dist/dto/update-user-attributes-request.dto.js +36 -0
  242. package/dist/dto/update-user-attributes-request.dto.js.map +1 -1
  243. package/dist/dto/user-response.dto.d.ts +81 -0
  244. package/dist/dto/user-response.dto.d.ts.map +1 -1
  245. package/dist/dto/user-response.dto.js +84 -2
  246. package/dist/dto/user-response.dto.js.map +1 -1
  247. package/dist/dto/user-update.dto.d.ts +132 -0
  248. package/dist/dto/user-update.dto.d.ts.map +1 -1
  249. package/dist/dto/user-update.dto.js +133 -0
  250. package/dist/dto/user-update.dto.js.map +1 -1
  251. package/dist/dto/verify-email.dto.d.ts +171 -0
  252. package/dist/dto/verify-email.dto.d.ts.map +1 -1
  253. package/dist/dto/verify-email.dto.js +173 -1
  254. package/dist/dto/verify-email.dto.js.map +1 -1
  255. package/dist/dto/verify-mfa-code.dto.d.ts +65 -0
  256. package/dist/dto/verify-mfa-code.dto.d.ts.map +1 -1
  257. package/dist/dto/verify-mfa-code.dto.js +65 -0
  258. package/dist/dto/verify-mfa-code.dto.js.map +1 -1
  259. package/dist/dto/verify-phone-by-sub.dto.d.ts +49 -0
  260. package/dist/dto/verify-phone-by-sub.dto.d.ts.map +1 -1
  261. package/dist/dto/verify-phone-by-sub.dto.js +49 -0
  262. package/dist/dto/verify-phone-by-sub.dto.js.map +1 -1
  263. package/dist/dto/verify-phone.dto.d.ts +139 -0
  264. package/dist/dto/verify-phone.dto.d.ts.map +1 -1
  265. package/dist/dto/verify-phone.dto.js +142 -1
  266. package/dist/dto/verify-phone.dto.js.map +1 -1
  267. package/dist/dto.d.ts +10 -0
  268. package/dist/dto.d.ts.map +1 -1
  269. package/dist/dto.js +10 -0
  270. package/dist/dto.js.map +1 -1
  271. package/dist/entities/auth-audit.entity.d.ts +159 -0
  272. package/dist/entities/auth-audit.entity.d.ts.map +1 -1
  273. package/dist/entities/auth-audit.entity.js +166 -0
  274. package/dist/entities/auth-audit.entity.js.map +1 -1
  275. package/dist/entities/challenge-session.entity.d.ts +87 -0
  276. package/dist/entities/challenge-session.entity.d.ts.map +1 -1
  277. package/dist/entities/challenge-session.entity.js +87 -0
  278. package/dist/entities/challenge-session.entity.js.map +1 -1
  279. package/dist/entities/index.d.ts +18 -0
  280. package/dist/entities/index.d.ts.map +1 -1
  281. package/dist/entities/index.js +18 -0
  282. package/dist/entities/index.js.map +1 -1
  283. package/dist/entities/login-attempt.entity.d.ts +43 -0
  284. package/dist/entities/login-attempt.entity.d.ts.map +1 -1
  285. package/dist/entities/login-attempt.entity.js +43 -0
  286. package/dist/entities/login-attempt.entity.js.map +1 -1
  287. package/dist/entities/mfa-device.entity.d.ts +112 -0
  288. package/dist/entities/mfa-device.entity.d.ts.map +1 -1
  289. package/dist/entities/mfa-device.entity.js +112 -0
  290. package/dist/entities/mfa-device.entity.js.map +1 -1
  291. package/dist/entities/rate-limit.entity.d.ts +31 -0
  292. package/dist/entities/rate-limit.entity.d.ts.map +1 -1
  293. package/dist/entities/rate-limit.entity.js +31 -0
  294. package/dist/entities/rate-limit.entity.js.map +1 -1
  295. package/dist/entities/session.entity.d.ts +121 -0
  296. package/dist/entities/session.entity.d.ts.map +1 -1
  297. package/dist/entities/session.entity.js +121 -0
  298. package/dist/entities/session.entity.js.map +1 -1
  299. package/dist/entities/social-account.entity.d.ts +75 -0
  300. package/dist/entities/social-account.entity.d.ts.map +1 -1
  301. package/dist/entities/social-account.entity.js +75 -0
  302. package/dist/entities/social-account.entity.js.map +1 -1
  303. package/dist/entities/storage-lock.entity.d.ts +28 -0
  304. package/dist/entities/storage-lock.entity.d.ts.map +1 -1
  305. package/dist/entities/storage-lock.entity.js +28 -0
  306. package/dist/entities/storage-lock.entity.js.map +1 -1
  307. package/dist/entities/trusted-device.entity.d.ts +83 -0
  308. package/dist/entities/trusted-device.entity.d.ts.map +1 -1
  309. package/dist/entities/trusted-device.entity.js +83 -0
  310. package/dist/entities/trusted-device.entity.js.map +1 -1
  311. package/dist/entities/user.entity.d.ts +166 -0
  312. package/dist/entities/user.entity.d.ts.map +1 -1
  313. package/dist/entities/user.entity.js +166 -0
  314. package/dist/entities/user.entity.js.map +1 -1
  315. package/dist/entities/verification-token.entity.d.ts +102 -0
  316. package/dist/entities/verification-token.entity.d.ts.map +1 -1
  317. package/dist/entities/verification-token.entity.js +102 -0
  318. package/dist/entities/verification-token.entity.js.map +1 -1
  319. package/dist/entities.d.ts +8 -0
  320. package/dist/entities.d.ts.map +1 -1
  321. package/dist/entities.js +8 -0
  322. package/dist/entities.js.map +1 -1
  323. package/dist/enums/auth-audit-event-type.enum.d.ts +211 -0
  324. package/dist/enums/auth-audit-event-type.enum.d.ts.map +1 -1
  325. package/dist/enums/auth-audit-event-type.enum.js +244 -0
  326. package/dist/enums/auth-audit-event-type.enum.js.map +1 -1
  327. package/dist/enums/error-codes.enum.d.ts +296 -0
  328. package/dist/enums/error-codes.enum.d.ts.map +1 -1
  329. package/dist/enums/error-codes.enum.js +332 -0
  330. package/dist/enums/error-codes.enum.js.map +1 -1
  331. package/dist/enums/mfa-method.enum.d.ts +74 -0
  332. package/dist/enums/mfa-method.enum.d.ts.map +1 -1
  333. package/dist/enums/mfa-method.enum.js +64 -0
  334. package/dist/enums/mfa-method.enum.js.map +1 -1
  335. package/dist/enums/risk-factor.enum.d.ts +91 -0
  336. package/dist/enums/risk-factor.enum.d.ts.map +1 -1
  337. package/dist/enums/risk-factor.enum.js +97 -0
  338. package/dist/enums/risk-factor.enum.js.map +1 -1
  339. package/dist/exceptions/nauth.exception.d.ts +149 -0
  340. package/dist/exceptions/nauth.exception.d.ts.map +1 -1
  341. package/dist/exceptions/nauth.exception.js +159 -0
  342. package/dist/exceptions/nauth.exception.js.map +1 -1
  343. package/dist/handlers/auth.handler.d.ts +32 -0
  344. package/dist/handlers/auth.handler.d.ts.map +1 -1
  345. package/dist/handlers/auth.handler.js +47 -1
  346. package/dist/handlers/auth.handler.js.map +1 -1
  347. package/dist/handlers/client-info.handler.d.ts +25 -0
  348. package/dist/handlers/client-info.handler.d.ts.map +1 -1
  349. package/dist/handlers/client-info.handler.js +36 -2
  350. package/dist/handlers/client-info.handler.js.map +1 -1
  351. package/dist/handlers/csrf.handler.d.ts +32 -0
  352. package/dist/handlers/csrf.handler.d.ts.map +1 -1
  353. package/dist/handlers/csrf.handler.js +49 -1
  354. package/dist/handlers/csrf.handler.js.map +1 -1
  355. package/dist/handlers/token-delivery.handler.d.ts +16 -0
  356. package/dist/handlers/token-delivery.handler.d.ts.map +1 -1
  357. package/dist/handlers/token-delivery.handler.js +22 -1
  358. package/dist/handlers/token-delivery.handler.js.map +1 -1
  359. package/dist/index.d.ts +34 -0
  360. package/dist/index.d.ts.map +1 -1
  361. package/dist/index.js +67 -0
  362. package/dist/index.js.map +1 -1
  363. package/dist/interfaces/client-info.interface.d.ts +58 -0
  364. package/dist/interfaces/client-info.interface.d.ts.map +1 -1
  365. package/dist/interfaces/config.interface.d.ts +1780 -0
  366. package/dist/interfaces/config.interface.d.ts.map +1 -1
  367. package/dist/interfaces/config.interface.js +16 -0
  368. package/dist/interfaces/config.interface.js.map +1 -1
  369. package/dist/interfaces/entities.interface.d.ts +48 -0
  370. package/dist/interfaces/entities.interface.d.ts.map +1 -1
  371. package/dist/interfaces/entities.interface.js +8 -0
  372. package/dist/interfaces/entities.interface.js.map +1 -1
  373. package/dist/interfaces/index.js +5 -0
  374. package/dist/interfaces/index.js.map +1 -1
  375. package/dist/interfaces/logger.interface.d.ts +213 -0
  376. package/dist/interfaces/logger.interface.d.ts.map +1 -1
  377. package/dist/interfaces/logger.interface.js +35 -0
  378. package/dist/interfaces/logger.interface.js.map +1 -1
  379. package/dist/interfaces/mfa-provider.interface.d.ts +134 -0
  380. package/dist/interfaces/mfa-provider.interface.d.ts.map +1 -1
  381. package/dist/interfaces/oauth.interface.d.ts +110 -0
  382. package/dist/interfaces/oauth.interface.d.ts.map +1 -1
  383. package/dist/interfaces/provider.interface.d.ts +83 -0
  384. package/dist/interfaces/provider.interface.d.ts.map +1 -1
  385. package/dist/interfaces/sms-template.interface.d.ts +246 -0
  386. package/dist/interfaces/sms-template.interface.d.ts.map +1 -1
  387. package/dist/interfaces/sms-template.interface.js +26 -0
  388. package/dist/interfaces/sms-template.interface.js.map +1 -1
  389. package/dist/interfaces/social-auth-provider.interface.d.ts +115 -0
  390. package/dist/interfaces/social-auth-provider.interface.d.ts.map +1 -1
  391. package/dist/interfaces/storage-adapter.interface.d.ts +37 -0
  392. package/dist/interfaces/storage-adapter.interface.d.ts.map +1 -1
  393. package/dist/interfaces/template.interface.d.ts +351 -0
  394. package/dist/interfaces/template.interface.d.ts.map +1 -1
  395. package/dist/interfaces/template.interface.js +13 -0
  396. package/dist/interfaces/template.interface.js.map +1 -1
  397. package/dist/interfaces/token-verifier.interface.d.ts +101 -0
  398. package/dist/interfaces/token-verifier.interface.d.ts.map +1 -1
  399. package/dist/interfaces.d.ts +8 -0
  400. package/dist/interfaces.d.ts.map +1 -1
  401. package/dist/interfaces.js +8 -0
  402. package/dist/interfaces.js.map +1 -1
  403. package/dist/internal.d.ts +120 -0
  404. package/dist/internal.d.ts.map +1 -1
  405. package/dist/internal.js +138 -0
  406. package/dist/internal.js.map +1 -1
  407. package/dist/platform/interfaces.d.ts +187 -0
  408. package/dist/platform/interfaces.d.ts.map +1 -1
  409. package/dist/platform/interfaces.js +11 -0
  410. package/dist/platform/interfaces.js.map +1 -1
  411. package/dist/schemas/auth-config.schema.d.ts +62 -0
  412. package/dist/schemas/auth-config.schema.d.ts.map +1 -1
  413. package/dist/schemas/auth-config.schema.js +189 -9
  414. package/dist/schemas/auth-config.schema.js.map +1 -1
  415. package/dist/services/adaptive-mfa-decision.service.d.ts +144 -0
  416. package/dist/services/adaptive-mfa-decision.service.d.ts.map +1 -1
  417. package/dist/services/adaptive-mfa-decision.service.js +151 -5
  418. package/dist/services/adaptive-mfa-decision.service.js.map +1 -1
  419. package/dist/services/auth-audit.service.d.ts +195 -0
  420. package/dist/services/auth-audit.service.d.ts.map +1 -1
  421. package/dist/services/auth-audit.service.js +228 -1
  422. package/dist/services/auth-audit.service.js.map +1 -1
  423. package/dist/services/auth-challenge-helper.service.d.ts +144 -1
  424. package/dist/services/auth-challenge-helper.service.d.ts.map +1 -1
  425. package/dist/services/auth-challenge-helper.service.js +295 -16
  426. package/dist/services/auth-challenge-helper.service.js.map +1 -1
  427. package/dist/services/auth-flow-context-builder.service.d.ts +120 -1
  428. package/dist/services/auth-flow-context-builder.service.d.ts.map +1 -1
  429. package/dist/services/auth-flow-context-builder.service.js +184 -5
  430. package/dist/services/auth-flow-context-builder.service.js.map +1 -1
  431. package/dist/services/auth-flow-rules.d.ts +136 -0
  432. package/dist/services/auth-flow-rules.d.ts.map +1 -1
  433. package/dist/services/auth-flow-rules.js +137 -0
  434. package/dist/services/auth-flow-rules.js.map +1 -1
  435. package/dist/services/auth-flow-state-definitions.d.ts +40 -0
  436. package/dist/services/auth-flow-state-definitions.d.ts.map +1 -1
  437. package/dist/services/auth-flow-state-definitions.js +98 -0
  438. package/dist/services/auth-flow-state-definitions.js.map +1 -1
  439. package/dist/services/auth-flow-state-machine.service.d.ts +91 -0
  440. package/dist/services/auth-flow-state-machine.service.d.ts.map +1 -1
  441. package/dist/services/auth-flow-state-machine.service.js +102 -0
  442. package/dist/services/auth-flow-state-machine.service.js.map +1 -1
  443. package/dist/services/auth-flow-state-machine.types.d.ts +221 -0
  444. package/dist/services/auth-flow-state-machine.types.d.ts.map +1 -1
  445. package/dist/services/auth-flow-state-machine.types.js +47 -0
  446. package/dist/services/auth-flow-state-machine.types.js.map +1 -1
  447. package/dist/services/auth.service.d.ts +397 -1
  448. package/dist/services/auth.service.d.ts.map +1 -1
  449. package/dist/services/auth.service.js +943 -27
  450. package/dist/services/auth.service.js.map +1 -1
  451. package/dist/services/challenge.service.d.ts +255 -1
  452. package/dist/services/challenge.service.d.ts.map +1 -1
  453. package/dist/services/challenge.service.js +327 -3
  454. package/dist/services/challenge.service.js.map +1 -1
  455. package/dist/services/client-info.service.d.ts +143 -0
  456. package/dist/services/client-info.service.d.ts.map +1 -1
  457. package/dist/services/client-info.service.js +161 -0
  458. package/dist/services/client-info.service.js.map +1 -1
  459. package/dist/services/csrf.service.d.ts +15 -0
  460. package/dist/services/csrf.service.d.ts.map +1 -1
  461. package/dist/services/csrf.service.js +16 -0
  462. package/dist/services/csrf.service.js.map +1 -1
  463. package/dist/services/email-verification.service.d.ts +52 -0
  464. package/dist/services/email-verification.service.d.ts.map +1 -1
  465. package/dist/services/email-verification.service.js +152 -12
  466. package/dist/services/email-verification.service.js.map +1 -1
  467. package/dist/services/geo-location.service.d.ts +105 -0
  468. package/dist/services/geo-location.service.d.ts.map +1 -1
  469. package/dist/services/geo-location.service.js +188 -2
  470. package/dist/services/geo-location.service.js.map +1 -1
  471. package/dist/services/jwt.service.d.ts +257 -0
  472. package/dist/services/jwt.service.d.ts.map +1 -1
  473. package/dist/services/jwt.service.js +284 -1
  474. package/dist/services/jwt.service.js.map +1 -1
  475. package/dist/services/mfa-base.service.d.ts +179 -1
  476. package/dist/services/mfa-base.service.d.ts.map +1 -1
  477. package/dist/services/mfa-base.service.js +256 -2
  478. package/dist/services/mfa-base.service.js.map +1 -1
  479. package/dist/services/mfa.service.d.ts +304 -0
  480. package/dist/services/mfa.service.d.ts.map +1 -1
  481. package/dist/services/mfa.service.js +380 -0
  482. package/dist/services/mfa.service.js.map +1 -1
  483. package/dist/services/password-reset.service.d.ts +46 -0
  484. package/dist/services/password-reset.service.d.ts.map +1 -1
  485. package/dist/services/password-reset.service.js +79 -0
  486. package/dist/services/password-reset.service.js.map +1 -1
  487. package/dist/services/password.service.d.ts +139 -0
  488. package/dist/services/password.service.d.ts.map +1 -1
  489. package/dist/services/password.service.js +167 -9
  490. package/dist/services/password.service.js.map +1 -1
  491. package/dist/services/phone-verification.service.d.ts +75 -0
  492. package/dist/services/phone-verification.service.d.ts.map +1 -1
  493. package/dist/services/phone-verification.service.js +188 -6
  494. package/dist/services/phone-verification.service.js.map +1 -1
  495. package/dist/services/risk-detection.service.d.ts +198 -0
  496. package/dist/services/risk-detection.service.d.ts.map +1 -1
  497. package/dist/services/risk-detection.service.js +358 -11
  498. package/dist/services/risk-detection.service.js.map +1 -1
  499. package/dist/services/risk-scoring.service.d.ts +84 -0
  500. package/dist/services/risk-scoring.service.d.ts.map +1 -1
  501. package/dist/services/risk-scoring.service.js +87 -0
  502. package/dist/services/risk-scoring.service.js.map +1 -1
  503. package/dist/services/session.service.d.ts +204 -0
  504. package/dist/services/session.service.d.ts.map +1 -1
  505. package/dist/services/session.service.js +289 -4
  506. package/dist/services/session.service.js.map +1 -1
  507. package/dist/services/social-auth-base.service.d.ts +123 -1
  508. package/dist/services/social-auth-base.service.d.ts.map +1 -1
  509. package/dist/services/social-auth-base.service.js +155 -2
  510. package/dist/services/social-auth-base.service.js.map +1 -1
  511. package/dist/services/social-auth.service.d.ts +191 -0
  512. package/dist/services/social-auth.service.d.ts.map +1 -1
  513. package/dist/services/social-auth.service.js +215 -2
  514. package/dist/services/social-auth.service.js.map +1 -1
  515. package/dist/services/social-provider-registry.service.d.ts +86 -0
  516. package/dist/services/social-provider-registry.service.d.ts.map +1 -1
  517. package/dist/services/social-provider-registry.service.js +86 -0
  518. package/dist/services/social-provider-registry.service.js.map +1 -1
  519. package/dist/services/trusted-device.service.d.ts +105 -0
  520. package/dist/services/trusted-device.service.d.ts.map +1 -1
  521. package/dist/services/trusted-device.service.js +133 -4
  522. package/dist/services/trusted-device.service.js.map +1 -1
  523. package/dist/storage/account-lockout-storage.service.d.ts +35 -0
  524. package/dist/storage/account-lockout-storage.service.d.ts.map +1 -1
  525. package/dist/storage/account-lockout-storage.service.js +35 -0
  526. package/dist/storage/account-lockout-storage.service.js.map +1 -1
  527. package/dist/storage/memory-storage.adapter.d.ts +148 -0
  528. package/dist/storage/memory-storage.adapter.d.ts.map +1 -1
  529. package/dist/storage/memory-storage.adapter.js +201 -6
  530. package/dist/storage/memory-storage.adapter.js.map +1 -1
  531. package/dist/storage/rate-limit-storage.service.d.ts +3 -0
  532. package/dist/storage/rate-limit-storage.service.d.ts.map +1 -1
  533. package/dist/storage/rate-limit-storage.service.js +4 -0
  534. package/dist/storage/rate-limit-storage.service.js.map +1 -1
  535. package/dist/storage.d.ts +8 -0
  536. package/dist/storage.d.ts.map +1 -1
  537. package/dist/storage.js +8 -0
  538. package/dist/storage.js.map +1 -1
  539. package/dist/templates/html-template.engine.d.ts +110 -0
  540. package/dist/templates/html-template.engine.d.ts.map +1 -1
  541. package/dist/templates/html-template.engine.js +147 -0
  542. package/dist/templates/html-template.engine.js.map +1 -1
  543. package/dist/templates/index.d.ts +5 -0
  544. package/dist/templates/index.d.ts.map +1 -1
  545. package/dist/templates/index.js +5 -0
  546. package/dist/templates/index.js.map +1 -1
  547. package/dist/templates/sms-template.engine.d.ts +151 -0
  548. package/dist/templates/sms-template.engine.d.ts.map +1 -1
  549. package/dist/templates/sms-template.engine.js +171 -0
  550. package/dist/templates/sms-template.engine.js.map +1 -1
  551. package/dist/templates.d.ts +8 -0
  552. package/dist/templates.d.ts.map +1 -1
  553. package/dist/templates.js +8 -0
  554. package/dist/templates.js.map +1 -1
  555. package/dist/utils/common-passwords.d.ts +42 -0
  556. package/dist/utils/common-passwords.d.ts.map +1 -1
  557. package/dist/utils/common-passwords.js +88 -0
  558. package/dist/utils/common-passwords.js.map +1 -1
  559. package/dist/utils/context-storage.d.ts +129 -0
  560. package/dist/utils/context-storage.d.ts.map +1 -1
  561. package/dist/utils/context-storage.js +129 -0
  562. package/dist/utils/context-storage.js.map +1 -1
  563. package/dist/utils/cookie-names.util.d.ts +35 -0
  564. package/dist/utils/cookie-names.util.d.ts.map +1 -1
  565. package/dist/utils/cookie-names.util.js +37 -0
  566. package/dist/utils/cookie-names.util.js.map +1 -1
  567. package/dist/utils/cookies.util.d.ts +19 -0
  568. package/dist/utils/cookies.util.d.ts.map +1 -1
  569. package/dist/utils/cookies.util.js +30 -3
  570. package/dist/utils/cookies.util.js.map +1 -1
  571. package/dist/utils/index.d.ts +3 -0
  572. package/dist/utils/index.d.ts.map +1 -1
  573. package/dist/utils/index.js +4 -0
  574. package/dist/utils/index.js.map +1 -1
  575. package/dist/utils/ip-extractor.d.ts +88 -0
  576. package/dist/utils/ip-extractor.d.ts.map +1 -1
  577. package/dist/utils/ip-extractor.js +109 -16
  578. package/dist/utils/ip-extractor.js.map +1 -1
  579. package/dist/utils/nauth-logger.d.ts +70 -0
  580. package/dist/utils/nauth-logger.d.ts.map +1 -1
  581. package/dist/utils/nauth-logger.js +82 -4
  582. package/dist/utils/nauth-logger.js.map +1 -1
  583. package/dist/utils/pii-redactor.d.ts +70 -0
  584. package/dist/utils/pii-redactor.d.ts.map +1 -1
  585. package/dist/utils/pii-redactor.js +102 -0
  586. package/dist/utils/pii-redactor.js.map +1 -1
  587. package/dist/utils/setup/get-repositories.d.ts +16 -0
  588. package/dist/utils/setup/get-repositories.d.ts.map +1 -1
  589. package/dist/utils/setup/get-repositories.js +21 -0
  590. package/dist/utils/setup/get-repositories.js.map +1 -1
  591. package/dist/utils/setup/init-services.d.ts +40 -1
  592. package/dist/utils/setup/init-services.d.ts.map +1 -1
  593. package/dist/utils/setup/init-services.js +98 -0
  594. package/dist/utils/setup/init-services.js.map +1 -1
  595. package/dist/utils/setup/init-social.d.ts +27 -0
  596. package/dist/utils/setup/init-social.d.ts.map +1 -1
  597. package/dist/utils/setup/init-social.js +49 -0
  598. package/dist/utils/setup/init-social.js.map +1 -1
  599. package/dist/utils/setup/init-storage.d.ts +22 -0
  600. package/dist/utils/setup/init-storage.d.ts.map +1 -1
  601. package/dist/utils/setup/init-storage.js +36 -0
  602. package/dist/utils/setup/init-storage.js.map +1 -1
  603. package/dist/utils/setup/register-mfa.d.ts +22 -0
  604. package/dist/utils/setup/register-mfa.d.ts.map +1 -1
  605. package/dist/utils/setup/register-mfa.js +41 -0
  606. package/dist/utils/setup/register-mfa.js.map +1 -1
  607. package/dist/utils/setup/run-nauth-migrations.d.ts +7 -0
  608. package/dist/utils/setup/run-nauth-migrations.d.ts.map +1 -1
  609. package/dist/utils/setup/run-nauth-migrations.js +8 -0
  610. package/dist/utils/setup/run-nauth-migrations.js.map +1 -1
  611. package/dist/utils/token-delivery-policy.d.ts +17 -0
  612. package/dist/utils/token-delivery-policy.d.ts.map +1 -1
  613. package/dist/utils/token-delivery-policy.js +17 -0
  614. package/dist/utils/token-delivery-policy.js.map +1 -1
  615. package/dist/utils.d.ts +8 -0
  616. package/dist/utils.d.ts.map +1 -1
  617. package/dist/utils.js +8 -0
  618. package/dist/utils.js.map +1 -1
  619. package/dist/validators/template.validator.d.ts +80 -0
  620. package/dist/validators/template.validator.d.ts.map +1 -1
  621. package/dist/validators/template.validator.js +94 -0
  622. package/dist/validators/template.validator.js.map +1 -1
  623. package/package.json +7 -2
@@ -4,6 +4,31 @@ exports.RiskDetectionService = void 0;
4
4
  const typeorm_1 = require("typeorm");
5
5
  const auth_audit_event_type_enum_1 = require("../enums/auth-audit-event-type.enum");
6
6
  const risk_factor_enum_1 = require("../enums/risk-factor.enum");
7
+ /**
8
+ * Risk Detection Service
9
+ *
10
+ * Analyzes authentication attempts for risk factors by comparing current
11
+ * context against user's historical behavior (sessions and audit trail).
12
+ *
13
+ * **Risk Factors Detected:**
14
+ * - `new_device`: DeviceId never seen before (check sessions table)
15
+ * - `new_ip`: IP address never seen before (check sessions + audit)
16
+ * - `new_country`: Country never seen before (check sessions where ipCountry)
17
+ * - `impossible_travel`: Geographic distance impossible in time window
18
+ * - `suspicious_activity`: Recent failed attempts, token reuse, etc.
19
+ *
20
+ * **Design Notes:**
21
+ * - All queries use userId (internal integer ID) for optimal performance
22
+ * - Queries are optimized with COUNT and LIMIT 1 for existence checks
23
+ * - Non-blocking: Errors logged but don't throw (graceful degradation)
24
+ * - Impossible travel detection requires city-level geolocation (optional)
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * const riskFactors = await riskDetectionService.detectRiskFactors(user, clientInfo);
29
+ * // Returns: ['new_device', 'new_country']
30
+ * ```
31
+ */
7
32
  class RiskDetectionService {
8
33
  sessionRepository;
9
34
  auditRepository;
@@ -17,9 +42,35 @@ class RiskDetectionService {
17
42
  this.logger = logger;
18
43
  this.trustedDeviceService = trustedDeviceService;
19
44
  }
45
+ /**
46
+ * Detect risk factors for current authentication attempt
47
+ *
48
+ * Compares current context against user's historical behavior to identify
49
+ * potential security risks. Returns array of detected risk factor strings.
50
+ *
51
+ * **Double-Counting Prevention:**
52
+ * - If `new_country` is detected, `new_ip` is NOT checked (IP is source of country data)
53
+ * - If `impossible_travel` is detected (city change), `new_ip` is NOT checked
54
+ * - This prevents double-counting the same underlying risk (location change)
55
+ *
56
+ * @param user - User being authenticated
57
+ * @param clientInfo - Current request context (IP, device, location, etc.)
58
+ * @returns Array of detected risk factor strings
59
+ *
60
+ * @example
61
+ * ```typescript
62
+ * const factors = await riskDetectionService.detectRiskFactors(user, clientInfo);
63
+ * // Returns: ['new_device', 'new_country'] // new_ip excluded if new_country detected
64
+ * ```
65
+ */
20
66
  async detectRiskFactors(user, clientInfo) {
21
67
  const factors = [];
22
68
  try {
69
+ // ============================================================================
70
+ // Trigger Configuration
71
+ // ============================================================================
72
+ // Check which triggers are enabled in config
73
+ // Config uses string literals, but they match RiskFactor enum values
23
74
  const enabledTriggers = this.config.mfa?.adaptive?.triggers || [
24
75
  risk_factor_enum_1.RiskFactor.NEW_DEVICE,
25
76
  risk_factor_enum_1.RiskFactor.NEW_IP,
@@ -27,8 +78,14 @@ class RiskDetectionService {
27
78
  risk_factor_enum_1.RiskFactor.RECENT_PASSWORD_RESET,
28
79
  ];
29
80
  this.logger?.debug?.(`Risk detection started for user ${user.sub}: enabled_triggers=[${enabledTriggers.join(', ')}], has_device_token=${!!clientInfo.deviceToken}, ip=${clientInfo.ipAddress}, location=${clientInfo.ipCity}, ${clientInfo.ipCountry}`);
81
+ // ============================================================================
82
+ // Device Risk Detection
83
+ // ============================================================================
84
+ // Check new_device
30
85
  if (enabledTriggers.includes(risk_factor_enum_1.RiskFactor.NEW_DEVICE)) {
31
86
  if (clientInfo.deviceToken) {
87
+ // Device has a token - check if it's been seen before
88
+ // This is the most reliable method (cookie-based or header-based token)
32
89
  const isNew = await this.isNewDevice(user.id, clientInfo.deviceToken);
33
90
  if (isNew) {
34
91
  factors.push(risk_factor_enum_1.RiskFactor.NEW_DEVICE);
@@ -36,13 +93,24 @@ class RiskDetectionService {
36
93
  }
37
94
  }
38
95
  else {
96
+ // No deviceToken (incognito mode, cleared cookies, first login, etc.)
97
+ // Check if user has logged in before - if yes, missing token is suspicious
98
+ // This prevents false positives for legitimate first-time logins
39
99
  const hasPreviousSessions = await this.hasUserLoggedInBefore(user.id);
40
100
  if (hasPreviousSessions) {
101
+ // User has logged in before but no deviceToken - treat as new/unknown device
102
+ // This covers incognito mode, cleared cookies, and other scenarios where
103
+ // device identification is not available
41
104
  factors.push(risk_factor_enum_1.RiskFactor.NEW_DEVICE);
42
105
  this.logger?.debug?.(`Missing deviceToken for user ${user.sub} with previous sessions - treating as new_device`);
43
106
  }
44
107
  }
45
108
  }
109
+ // ============================================================================
110
+ // Location Risk Detection (with Double-Counting Prevention)
111
+ // ============================================================================
112
+ // Check new_country first (before new_ip to avoid double-counting)
113
+ // IP is the source of country/city data, so if country changed, IP definitely changed
46
114
  let newCountryDetected = false;
47
115
  if (enabledTriggers.includes(risk_factor_enum_1.RiskFactor.NEW_COUNTRY) && clientInfo.ipCountry) {
48
116
  const isNew = await this.isNewCountry(user.id, clientInfo.ipCountry);
@@ -52,6 +120,8 @@ class RiskDetectionService {
52
120
  this.logger?.debug?.(`New country detected for user ${user.sub}: ${clientInfo.ipCountry}`);
53
121
  }
54
122
  }
123
+ // Check impossible_travel (now works with country-only data too)
124
+ // This also indicates location change (city/country), so skip new_ip if detected
55
125
  let impossibleTravelDetected = false;
56
126
  if (enabledTriggers.includes(risk_factor_enum_1.RiskFactor.IMPOSSIBLE_TRAVEL) && clientInfo.ipCountry) {
57
127
  const isImpossible = await this.detectImpossibleTravel(user.id, clientInfo);
@@ -61,6 +131,13 @@ class RiskDetectionService {
61
131
  this.logger?.debug?.(`Impossible travel detected for user ${user.sub}: ${clientInfo.ipCity ?? 'unknown'}, ${clientInfo.ipCountry}`);
62
132
  }
63
133
  }
134
+ // ============================================================================
135
+ // Location Data Completeness Check
136
+ // ============================================================================
137
+ // Add risk factor if location data is incomplete (missing city or coordinates) when country exists
138
+ // AND user has previous logins (only relevant for returning users)
139
+ // This reduces confidence in risk assessment and warrants extra caution
140
+ // Only check if location-related triggers are enabled
64
141
  const locationTriggersEnabled = enabledTriggers.includes(risk_factor_enum_1.RiskFactor.NEW_COUNTRY) || enabledTriggers.includes(risk_factor_enum_1.RiskFactor.IMPOSSIBLE_TRAVEL);
65
142
  if (locationTriggersEnabled &&
66
143
  clientInfo.ipCountry &&
@@ -71,10 +148,17 @@ class RiskDetectionService {
71
148
  `city=${clientInfo.ipCity ?? 'missing'}, coordinates=${clientInfo.ipLatitude && clientInfo.ipLongitude ? 'available' : 'missing'}. ` +
72
149
  `Adding INCOMPLETE_LOCATION_DATA risk factor (+20 points) for reduced confidence in risk assessment.`);
73
150
  }
151
+ // ============================================================================
152
+ // IP Risk Detection (only if location unchanged)
153
+ // ============================================================================
154
+ // Check new_ip only if country/city hasn't changed
155
+ // IP is the source of location data, so if country/city changed, IP definitely changed
156
+ // Avoid double-counting the same risk factor
74
157
  if (enabledTriggers.includes(risk_factor_enum_1.RiskFactor.NEW_IP) &&
75
158
  clientInfo.ipAddress &&
76
159
  !newCountryDetected &&
77
160
  !impossibleTravelDetected) {
161
+ // Normalize IP address (remove port if present, e.g., "192.168.1.1:8080" -> "192.168.1.1")
78
162
  const normalizedIp = this.normalizeIpAddress(clientInfo.ipAddress);
79
163
  const isNew = await this.isNewIp(user.id, normalizedIp);
80
164
  if (isNew) {
@@ -82,6 +166,10 @@ class RiskDetectionService {
82
166
  this.logger?.debug?.(`New IP detected for user ${user.sub}: ${normalizedIp} (original: ${clientInfo.ipAddress})`);
83
167
  }
84
168
  }
169
+ // ============================================================================
170
+ // Behavioral Risk Detection
171
+ // ============================================================================
172
+ // Check suspicious_activity
85
173
  if (enabledTriggers.includes(risk_factor_enum_1.RiskFactor.SUSPICIOUS_ACTIVITY)) {
86
174
  const isSuspicious = await this.detectSuspiciousActivity(user.id);
87
175
  if (isSuspicious) {
@@ -89,6 +177,11 @@ class RiskDetectionService {
89
177
  this.logger?.debug?.(`Suspicious activity detected for user ${user.sub}`);
90
178
  }
91
179
  }
180
+ // ============================================================================
181
+ // Account Recovery Risk Detection
182
+ // ============================================================================
183
+ // Detect if the password was reset/changed after the last successful login.
184
+ // WHY: Many providers treat post-reset sign-in as higher risk and require step-up auth.
92
185
  if (enabledTriggers.includes(risk_factor_enum_1.RiskFactor.RECENT_PASSWORD_RESET) &&
93
186
  user.passwordChangedAt &&
94
187
  user.lastLoginAt &&
@@ -96,27 +189,47 @@ class RiskDetectionService {
96
189
  factors.push(risk_factor_enum_1.RiskFactor.RECENT_PASSWORD_RESET);
97
190
  this.logger?.debug?.(`Recent password reset detected for user ${user.sub}: passwordChangedAt=${user.passwordChangedAt.toISOString()}, lastLoginAt=${user.lastLoginAt.toISOString()}`);
98
191
  }
192
+ // ============================================================================
193
+ // Summary
194
+ // ============================================================================
99
195
  if (factors.length > 0) {
100
196
  this.logger?.debug?.(`Risk detection complete for user ${user.sub}: ${factors.length} factor(s) detected [${factors.join(', ')}]`);
101
197
  }
102
198
  }
103
199
  catch (error) {
200
+ // Non-blocking: Log error but don't throw
104
201
  const errorMessage = error instanceof Error ? error.message : 'Unknown error';
105
202
  this.logger?.error?.(`Risk detection failed for user ${user.sub}: ${errorMessage}`, { error, userId: user.id });
203
+ // Return empty array on error (graceful degradation)
106
204
  return [];
107
205
  }
108
206
  return factors;
109
207
  }
208
+ /**
209
+ * Check if device has been seen before
210
+ *
211
+ * Checks trusted devices first (if available), then sessions table.
212
+ * If device is trusted, it's not considered "new" even if no sessions exist yet.
213
+ *
214
+ * @param userId - Internal user ID (integer)
215
+ * @param deviceToken - Device token from client
216
+ * @returns True if device is new (never seen before and not trusted)
217
+ * @private
218
+ */
110
219
  async isNewDevice(userId, deviceToken) {
111
220
  try {
221
+ // First, check if device is trusted (if trusted device service is available)
222
+ // Trusted devices should not be flagged as "new" even if no sessions exist
112
223
  if (this.trustedDeviceService && typeof this.trustedDeviceService.isDeviceTrusted === 'function') {
113
224
  try {
114
225
  const isTrusted = await this.trustedDeviceService.isDeviceTrusted(deviceToken, userId);
115
226
  if (isTrusted) {
227
+ // Device is trusted - not a new device
116
228
  return false;
117
229
  }
118
230
  }
119
231
  catch (trustedError) {
232
+ // Non-blocking: If trusted device check fails, continue to session check
120
233
  const errorMessage = trustedError instanceof Error ? trustedError.message : 'Unknown error';
121
234
  this.logger?.warn?.(`Failed to check trusted device: ${errorMessage}`, {
122
235
  error: trustedError,
@@ -125,6 +238,8 @@ class RiskDetectionService {
125
238
  });
126
239
  }
127
240
  }
241
+ // Check if any session exists with this deviceId (short-circuit existence)
242
+ // Note: deviceToken is stored as deviceId in sessions
128
243
  const exists = await this.sessionRepository.findOne({
129
244
  select: ['id'],
130
245
  where: { userId, deviceId: deviceToken },
@@ -132,13 +247,26 @@ class RiskDetectionService {
132
247
  return !exists;
133
248
  }
134
249
  catch (error) {
250
+ // Non-blocking: Log and assume device is new (safer default)
135
251
  const errorMessage = error instanceof Error ? error.message : 'Unknown error';
136
252
  this.logger?.warn?.(`Failed to check device history: ${errorMessage}`, { error, userId, deviceToken });
137
- return true;
253
+ return true; // Assume new device on error (safer for security)
138
254
  }
139
255
  }
256
+ /**
257
+ * Check if user has logged in before (has any previous sessions)
258
+ *
259
+ * Used to determine if missing deviceToken should be treated as suspicious.
260
+ * If user has never logged in before, missing token is expected (first login).
261
+ * If user has logged in before, missing token is suspicious (incognito, cleared cookies, etc.).
262
+ *
263
+ * @param userId - Internal user ID (integer)
264
+ * @returns True if user has at least one previous session
265
+ * @private
266
+ */
140
267
  async hasUserLoggedInBefore(userId) {
141
268
  try {
269
+ // Check if any session exists for this user (short-circuit existence check)
142
270
  const exists = await this.sessionRepository.findOne({
143
271
  select: ['id'],
144
272
  where: { userId },
@@ -146,31 +274,64 @@ class RiskDetectionService {
146
274
  return !!exists;
147
275
  }
148
276
  catch (error) {
277
+ // Non-blocking: Log and assume user has logged in before (safer default)
149
278
  const errorMessage = error instanceof Error ? error.message : 'Unknown error';
150
279
  this.logger?.warn?.(`Failed to check user login history: ${errorMessage}`, { error, userId });
151
- return true;
280
+ return true; // Assume user has logged in before on error (safer for security)
152
281
  }
153
282
  }
283
+ /**
284
+ * Normalize IP address for consistent comparison
285
+ *
286
+ * Removes port numbers and normalizes IPv6 addresses.
287
+ * This ensures IPs like "192.168.1.1:8080" and "192.168.1.1" are treated as the same.
288
+ *
289
+ * @param ipAddress - IP address to normalize
290
+ * @returns Normalized IP address
291
+ * @private
292
+ */
154
293
  normalizeIpAddress(ipAddress) {
294
+ // Remove port if present (e.g., "192.168.1.1:8080" -> "192.168.1.1")
295
+ // Handle both IPv4 and IPv6 formats
155
296
  if (ipAddress.includes(':')) {
297
+ // Could be IPv6 or IPv4 with port
156
298
  if (ipAddress.startsWith('[')) {
299
+ // IPv6 with port: "[::1]:8080" -> "::1"
157
300
  const match = ipAddress.match(/^\[(.+)\]:\d+$/);
158
301
  if (match) {
159
302
  return match[1];
160
303
  }
161
304
  }
162
305
  else {
306
+ // IPv4 with port: "192.168.1.1:8080" -> "192.168.1.1"
163
307
  const parts = ipAddress.split(':');
164
308
  if (parts.length === 2 && /^\d+$/.test(parts[1])) {
309
+ // Second part is a port number
165
310
  return parts[0];
166
311
  }
312
+ // Otherwise it's likely IPv6 without brackets, return as-is
167
313
  }
168
314
  }
169
315
  return ipAddress;
170
316
  }
317
+ /**
318
+ * Check if IP address has been seen before
319
+ *
320
+ * Queries sessions table first (faster), then audit table for older data.
321
+ * Uses normalized IP addresses for consistent comparison.
322
+ *
323
+ * @param userId - Internal user ID (integer)
324
+ * @param ipAddress - IP address to check (should already be normalized)
325
+ * @returns True if IP is new (never seen before)
326
+ * @private
327
+ */
171
328
  async isNewIp(userId, ipAddress) {
172
329
  try {
330
+ // Normalize IP address before checking (in case it wasn't normalized upstream)
173
331
  const normalizedIp = this.normalizeIpAddress(ipAddress);
332
+ // Check sessions first (faster, more recent data) - existence only
333
+ // Note: We check both normalized and original IP to handle cases where
334
+ // old records might have stored IPs with ports
174
335
  const seenInSessions = (await this.sessionRepository.findOne({
175
336
  select: ['id'],
176
337
  where: { userId, ipAddress: normalizedIp },
@@ -181,8 +342,9 @@ class RiskDetectionService {
181
342
  where: { userId, ipAddress },
182
343
  })));
183
344
  if (seenInSessions) {
184
- return false;
345
+ return false; // IP seen in sessions
185
346
  }
347
+ // Check audit trail for older data (only if not found in sessions)
186
348
  const seenInAudit = (await this.auditRepository.findOne({
187
349
  select: ['id'],
188
350
  where: { userId, ipAddress: normalizedIp },
@@ -195,47 +357,119 @@ class RiskDetectionService {
195
357
  return !seenInAudit;
196
358
  }
197
359
  catch (error) {
360
+ // Non-blocking: Log and assume IP is new (safer default)
198
361
  const errorMessage = error instanceof Error ? error.message : 'Unknown error';
199
362
  this.logger?.warn?.(`Failed to check IP history: ${errorMessage}`, { error, userId, ipAddress });
200
- return true;
363
+ return true; // Assume new IP on error (safer for security)
201
364
  }
202
365
  }
366
+ /**
367
+ * Check if country has been seen before
368
+ *
369
+ * Queries sessions table for any past session from this country.
370
+ * **Optimization:** Uses 1-2 queries instead of 3 by checking country existence first
371
+ * (most likely to short-circuit), then verifying country data availability if needed.
372
+ *
373
+ * **Important:**
374
+ * - On first login (no previous sessions), returns false (no history to compare)
375
+ * - If sessions exist but none have ipCountry data (null), returns false (can't determine)
376
+ * - Only flags as new if we have sessions with country data AND none match
377
+ *
378
+ * @param userId - Internal user ID (integer)
379
+ * @param country - Country code to check (e.g., 'US', 'GB')
380
+ * @returns True if country is new (never seen before), false on first login, if no country data, or if country seen before
381
+ * @private
382
+ */
203
383
  async isNewCountry(userId, country) {
204
384
  try {
385
+ // ============================================================================
386
+ // Optimization: Check country existence first (most likely to short-circuit)
387
+ // ============================================================================
388
+ // This query checks if country exists in sessions with country data
389
+ // If it exists, we can return false immediately (1 query instead of 3)
205
390
  const countryExists = await this.sessionRepository.findOne({
206
391
  select: ['id'],
207
392
  where: { userId, ipCountry: country },
208
393
  });
394
+ // If country exists in any session, it's not new
209
395
  if (countryExists) {
210
396
  return false;
211
397
  }
398
+ // ============================================================================
399
+ // Country doesn't exist - verify we have country data to compare against
400
+ // ============================================================================
401
+ // Only check if we have sessions with country data (needed to make determination)
402
+ // If no country data exists, we can't determine if it's new (first login or no geo data)
212
403
  const hasAnyCountryData = await this.sessionRepository.findOne({
213
404
  select: ['id'],
214
405
  where: { userId, ipCountry: (0, typeorm_1.Not)((0, typeorm_1.IsNull)()) },
215
406
  });
407
+ // If we have sessions with country data but country doesn't exist, it's new
408
+ // If no sessions have country data, we can't determine (return false for safety)
216
409
  return !!hasAnyCountryData;
217
410
  }
218
411
  catch (error) {
412
+ // Non-blocking: Log and assume country is not new on error (safer default)
219
413
  const errorMessage = error instanceof Error ? error.message : 'Unknown error';
220
414
  this.logger?.warn?.(`Failed to check country history: ${errorMessage}`, { error, userId, country });
221
- return false;
415
+ return false; // Assume not new country on error (safer default)
222
416
  }
223
417
  }
418
+ /**
419
+ * Detect impossible travel
420
+ *
421
+ * Calculates if geographic distance between last location and current
422
+ * location is impossible given time elapsed.
423
+ *
424
+ * **Algorithm:**
425
+ * 1. Get last login location (ipCountry, ipCity, coordinates) and createdAt
426
+ * 2. Calculate distance using coordinates (Haversine) or heuristics (fallback)
427
+ * 3. Calculate max possible speed (distance / time)
428
+ * 4. If speed > threshold (default 900 km/h), flag as impossible
429
+ *
430
+ * **Edge Cases Handled:**
431
+ * - No previous location data → false (benefit of doubt)
432
+ * - Same location → false (not travel)
433
+ * - Missing city but country changed → true (suspicious, different country in short time)
434
+ * - Missing coordinates → use heuristic distance estimates
435
+ *
436
+ * @param userId - Internal user ID (integer)
437
+ * @param currentInfo - Current client info with location
438
+ * @returns True if travel is impossible
439
+ * @private
440
+ */
224
441
  async detectImpossibleTravel(userId, currentInfo) {
442
+ // Require at least country data to perform any checks
225
443
  if (!currentInfo.ipCountry) {
226
444
  this.logger?.debug?.(`Skipping impossible_travel check for user ${userId}: no country data available`);
227
445
  return false;
228
446
  }
229
447
  try {
448
+ // ============================================================================
449
+ // Find last known location from most recent login
450
+ // ============================================================================
451
+ // CRITICAL: We need the location from the PREVIOUS login, not token refreshes
452
+ // Check BOTH sessions and audit trail to ensure we get the most recent location:
453
+ // - Sessions: might be cleaned up or expired
454
+ // - Audit: permanent record of all logins
455
+ // Use the more recent of the two
456
+ // ============================================================================
457
+ // Find previous login location (exclude current login to avoid race conditions)
458
+ // ============================================================================
459
+ // SIMPLIFIED LOGIC: Just get the most recent login from EITHER sessions OR audits
460
+ // The current login hasn't been committed yet (we're in risk detection before session creation)
461
+ // So the "most recent" we find IS the previous login
462
+ // Check sessions (use createdAt for login-to-login comparison, not lastActivityAt)
230
463
  const lastSession = (await this.sessionRepository.findOne({
231
464
  where: {
232
465
  userId,
233
466
  ipCountry: (0, typeorm_1.Not)((0, typeorm_1.IsNull)()),
234
467
  },
235
468
  order: {
236
- createdAt: 'DESC',
469
+ createdAt: 'DESC', // Most recent first
237
470
  },
238
471
  }));
472
+ // Check audit trail for most recent login with location data
239
473
  const lastAuditLogin = (await this.auditRepository.findOne({
240
474
  where: {
241
475
  userId,
@@ -246,6 +480,12 @@ class RiskDetectionService {
246
480
  createdAt: 'DESC',
247
481
  },
248
482
  }));
483
+ // ============================================================================
484
+ // Debug Dumps (optional)
485
+ // ============================================================================
486
+ // WHY: These queries are expensive and should only run when a real NAuthLogger
487
+ // instance is wired (consumer provided a logger). Unit tests frequently use
488
+ // plain object mocks that do NOT implement `isEnabled()`.
249
489
  const loggerEnabled = typeof this.logger.isEnabled === 'function'
250
490
  ? this.logger.isEnabled()
251
491
  : false;
@@ -279,8 +519,10 @@ class RiskDetectionService {
279
519
  ageMinutes: ((Date.now() - a.createdAt.getTime()) / (1000 * 60)).toFixed(1),
280
520
  })))}`);
281
521
  }
522
+ // Determine which record is more recent and extract location data with coordinates
282
523
  let lastLocation = null;
283
524
  if (lastSession && lastAuditLogin) {
525
+ // Both exist - use the more recent one as the previous login
284
526
  const sessionTime = lastSession.createdAt;
285
527
  const auditTime = lastAuditLogin.createdAt;
286
528
  if (sessionTime > auditTime) {
@@ -326,8 +568,9 @@ class RiskDetectionService {
326
568
  }
327
569
  if (!lastLocation) {
328
570
  this.logger?.debug?.(`No previous location data found for user ${userId} (no sessions or audit records)`);
329
- return false;
571
+ return false; // No previous location data (benefit of doubt)
330
572
  }
573
+ // Debug logging to help diagnose issues
331
574
  const hasCoordinates = !!(lastLocation.latitude &&
332
575
  lastLocation.longitude &&
333
576
  currentInfo.ipLatitude &&
@@ -336,6 +579,7 @@ class RiskDetectionService {
336
579
  `last=[${lastLocation.city ?? 'unknown'}, ${lastLocation.country} @ ${lastLocation.time.toISOString()}], ` +
337
580
  `current=[${currentInfo.ipCity ?? 'unknown'}, ${currentInfo.ipCountry}], ` +
338
581
  `coordinates=${hasCoordinates ? 'available' : 'missing'}`);
582
+ // Same location → not travel (only if we have city data to compare)
339
583
  if (lastLocation.city &&
340
584
  currentInfo.ipCity &&
341
585
  lastLocation.country === currentInfo.ipCountry &&
@@ -343,12 +587,22 @@ class RiskDetectionService {
343
587
  this.logger?.debug?.(`Same location detected - no travel: user=${userId}, location=[${currentInfo.ipCity}, ${currentInfo.ipCountry}]`);
344
588
  return false;
345
589
  }
590
+ // Calculate time difference (hours)
591
+ // Risk detection runs BEFORE session creation, so we compare current time to previous login
592
+ // All times are in UTC (database stores timestamps in UTC)
346
593
  const now = new Date();
347
594
  const hoursSinceLastSeen = (now.getTime() - lastLocation.time.getTime()) / (1000 * 60 * 60);
348
595
  this.logger?.debug?.(`Time since last location: ${hoursSinceLastSeen.toFixed(2)} hours (${(hoursSinceLastSeen * 60).toFixed(1)} minutes). ` +
349
596
  `Previous login: ${lastLocation.time.toISOString()} (UTC), Current: ${now.toISOString()} (UTC)`);
597
+ // ============================================================================
598
+ // SPECIAL CASE: Country change with missing city data
599
+ // ============================================================================
600
+ // If city data is missing for either location but countries differ,
601
+ // apply conservative threshold for country-level changes
350
602
  if (lastLocation.country !== currentInfo.ipCountry) {
351
603
  if (!lastLocation.city || !currentInfo.ipCity) {
604
+ // Missing city data - use conservative threshold for country changes
605
+ // If country changed in < threshold hours, flag as suspicious (can't verify exact locations)
352
606
  const countryChangeThresholdHours = this.config.mfa?.adaptive?.countryChangeThreshold || 2;
353
607
  if (hoursSinceLastSeen < countryChangeThresholdHours) {
354
608
  this.logger?.warn?.(`Impossible travel detected (country change without city data): ` +
@@ -363,8 +617,12 @@ class RiskDetectionService {
363
617
  return false;
364
618
  }
365
619
  }
620
+ // ============================================================================
621
+ // NORMAL CASE: Calculate distance using coordinates or heuristics
622
+ // ============================================================================
366
623
  let distance;
367
624
  let distanceMethod = 'heuristic';
625
+ // Try to use actual coordinates for precise distance calculation
368
626
  if (hasCoordinates) {
369
627
  distance = this.calculateHaversineDistance(lastLocation.latitude, lastLocation.longitude, currentInfo.ipLatitude, currentInfo.ipLongitude);
370
628
  distanceMethod = 'haversine';
@@ -372,12 +630,14 @@ class RiskDetectionService {
372
630
  `(${lastLocation.latitude},${lastLocation.longitude} → ${currentInfo.ipLatitude},${currentInfo.ipLongitude})`);
373
631
  }
374
632
  else {
633
+ // Fallback to heuristic distance estimation
375
634
  distance = await this.calculateDistance(lastLocation.city, lastLocation.country, currentInfo.ipCity ?? null, currentInfo.ipCountry);
376
635
  this.logger?.debug?.(`Using heuristic distance estimation (coordinates unavailable): distance=${distance}km`);
377
636
  }
378
637
  if (distance === 0) {
379
- return false;
638
+ return false; // Same location (shouldn't happen, but safety check)
380
639
  }
640
+ // Max realistic speed: 900 km/h (commercial airliner speed)
381
641
  const maxTravelSpeed = this.config.mfa?.adaptive?.maxTravelSpeed || 900;
382
642
  const requiredSpeed = distance / hoursSinceLastSeen;
383
643
  this.logger?.debug?.(`Travel speed calculation (${distanceMethod}): distance=${distance.toFixed(0)}km, ` +
@@ -397,13 +657,32 @@ class RiskDetectionService {
397
657
  return isImpossible;
398
658
  }
399
659
  catch (error) {
660
+ // Non-blocking: Log and assume not impossible travel (safer default)
400
661
  const errorMessage = error instanceof Error ? error.message : 'Unknown error';
401
662
  this.logger?.warn?.(`Failed to detect impossible travel: ${errorMessage}`, { error, userId });
402
- return false;
663
+ return false; // Assume not impossible travel on error
403
664
  }
404
665
  }
666
+ /**
667
+ * Calculate distance between two points using Haversine formula
668
+ *
669
+ * Accurate distance calculation using geographic coordinates (latitude/longitude).
670
+ * This is the preferred method when coordinates are available.
671
+ *
672
+ * **Haversine Formula:**
673
+ * - Accounts for Earth's spherical shape
674
+ * - Returns great-circle distance in kilometers
675
+ * - Accuracy: ~0.5% for most distances
676
+ *
677
+ * @param lat1 - Latitude of first point (degrees)
678
+ * @param lon1 - Longitude of first point (degrees)
679
+ * @param lat2 - Latitude of second point (degrees)
680
+ * @param lon2 - Longitude of second point (degrees)
681
+ * @returns Distance in kilometers (accurate)
682
+ * @private
683
+ */
405
684
  calculateHaversineDistance(lat1, lon1, lat2, lon2) {
406
- const R = 6371;
685
+ const R = 6371; // Earth's radius in kilometers
407
686
  const dLat = this.toRadians(lat2 - lat1);
408
687
  const dLon = this.toRadians(lon2 - lon1);
409
688
  const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
@@ -412,28 +691,76 @@ class RiskDetectionService {
412
691
  const distance = R * c;
413
692
  return distance;
414
693
  }
694
+ /**
695
+ * Convert degrees to radians
696
+ *
697
+ * @param degrees - Angle in degrees
698
+ * @returns Angle in radians
699
+ * @private
700
+ */
415
701
  toRadians(degrees) {
416
702
  return degrees * (Math.PI / 180);
417
703
  }
704
+ /**
705
+ * Calculate distance between two cities (heuristic fallback)
706
+ *
707
+ * Heuristic-based implementation for estimating travel distance when
708
+ * precise coordinates are not available. Uses continent and regional
709
+ * groupings for realistic estimates.
710
+ *
711
+ * **Fallback approach:**
712
+ * - Same city: 0 km
713
+ * - Same country, different city: 500 km (average domestic travel)
714
+ * - Different country, same continent: 1,500 km (regional travel)
715
+ * - Different continent (intercontinental): 8,000 km (long-haul flight)
716
+ * - Missing city data: use country-level comparison
717
+ *
718
+ * @param city1 - First city name (nullable)
719
+ * @param country1 - First country code (ISO 2-letter)
720
+ * @param city2 - Second city name (nullable)
721
+ * @param country2 - Second country code (ISO 2-letter)
722
+ * @returns Distance in kilometers (estimated)
723
+ * @private
724
+ */
418
725
  async calculateDistance(city1, country1, city2, country2) {
726
+ // Same city and country → 0 km (only if both cities are known)
419
727
  if (city1 && city2 && city1 === city2 && country1 === country2) {
420
728
  return 0;
421
729
  }
730
+ // Same country → estimate 500 km (average domestic travel)
422
731
  if (country1 === country2) {
423
732
  return 500;
424
733
  }
734
+ // Different country - determine if same continent or intercontinental
425
735
  const continent1 = this.getContinent(country1);
426
736
  const continent2 = this.getContinent(country2);
427
737
  if (continent1 === continent2 && continent1 !== 'unknown') {
738
+ // Same continent, different country → estimate 1,500 km (regional travel)
739
+ // Examples: Paris-Berlin (880km), London-Rome (1,400km), Sydney-Auckland (2,160km)
428
740
  return 1500;
429
741
  }
742
+ // Different continent → estimate 8,000 km (intercontinental long-haul)
743
+ // Examples: NYC-London (5,570km), Tokyo-Sydney (7,800km), Auckland-Karachi (9,700km)
744
+ // Using 8,000km as realistic average for transcontinental flights
430
745
  return 8000;
431
746
  }
747
+ /**
748
+ * Get continent for a country code
749
+ *
750
+ * Maps ISO 2-letter country codes to continents for distance estimation.
751
+ * This is used to differentiate between regional and intercontinental travel.
752
+ *
753
+ * @param countryCode - ISO 2-letter country code
754
+ * @returns Continent name
755
+ * @private
756
+ */
432
757
  getContinent(countryCode) {
433
758
  const continentMap = {
759
+ // North America
434
760
  US: 'north_america',
435
761
  CA: 'north_america',
436
762
  MX: 'north_america',
763
+ // Europe
437
764
  GB: 'europe',
438
765
  FR: 'europe',
439
766
  DE: 'europe',
@@ -461,6 +788,7 @@ class RiskDetectionService {
461
788
  LT: 'europe',
462
789
  LV: 'europe',
463
790
  EE: 'europe',
791
+ // Asia
464
792
  CN: 'asia',
465
793
  JP: 'asia',
466
794
  IN: 'asia',
@@ -479,14 +807,17 @@ class RiskDetectionService {
479
807
  IL: 'asia',
480
808
  HK: 'asia',
481
809
  TW: 'asia',
810
+ // Oceania
482
811
  AU: 'oceania',
483
812
  NZ: 'oceania',
813
+ // South America
484
814
  BR: 'south_america',
485
815
  AR: 'south_america',
486
816
  CL: 'south_america',
487
817
  CO: 'south_america',
488
818
  PE: 'south_america',
489
819
  VE: 'south_america',
820
+ // Africa
490
821
  ZA: 'africa',
491
822
  EG: 'africa',
492
823
  NG: 'africa',
@@ -496,10 +827,24 @@ class RiskDetectionService {
496
827
  };
497
828
  return continentMap[countryCode.toUpperCase()] || 'unknown';
498
829
  }
830
+ /**
831
+ * Detect suspicious activity patterns
832
+ *
833
+ * Checks for:
834
+ * - Recent failed login attempts (last 1 hour)
835
+ * - Token reuse detected (SUSPICIOUS_ACTIVITY audit events)
836
+ * - Multiple MFA failures
837
+ * - Account lockout attempts
838
+ *
839
+ * @param userId - Internal user ID (integer)
840
+ * @returns True if suspicious activity detected
841
+ * @private
842
+ */
499
843
  async detectSuspiciousActivity(userId) {
500
844
  try {
501
845
  const windowHours = this.config.mfa?.adaptive?.suspiciousActivityWindow || 1;
502
846
  const oneHourAgo = new Date(Date.now() - windowHours * 60 * 60 * 1000);
847
+ // Check for recent suspicious audit events (existence only)
503
848
  const hasSuspicious = await this.auditRepository.findOne({
504
849
  select: ['id'],
505
850
  where: { userId, eventStatus: 'SUSPICIOUS', createdAt: (0, typeorm_1.MoreThan)(oneHourAgo) },
@@ -507,6 +852,7 @@ class RiskDetectionService {
507
852
  if (hasSuspicious) {
508
853
  return true;
509
854
  }
855
+ // Check for failed login attempts (3+ in last hour) using limited IDs
510
856
  const failedLogins = await this.auditRepository.find({
511
857
  select: ['id'],
512
858
  where: { userId, eventType: auth_audit_event_type_enum_1.AuthAuditEventType.LOGIN_FAILED, createdAt: (0, typeorm_1.MoreThan)(oneHourAgo) },
@@ -516,9 +862,10 @@ class RiskDetectionService {
516
862
  return failedLogins.length >= 3;
517
863
  }
518
864
  catch (error) {
865
+ // Non-blocking: Log and assume not suspicious (safer default)
519
866
  const errorMessage = error instanceof Error ? error.message : 'Unknown error';
520
867
  this.logger?.warn?.(`Failed to detect suspicious activity: ${errorMessage}`, { error, userId });
521
- return false;
868
+ return false; // Assume not suspicious on error
522
869
  }
523
870
  }
524
871
  }