hazo_auth 1.4.2 → 1.6.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 (320) hide show
  1. package/SETUP_CHECKLIST.md +708 -0
  2. package/dist/app/api/hazo_auth/change_password/route.d.ts +8 -0
  3. package/dist/app/api/hazo_auth/change_password/route.d.ts.map +1 -0
  4. package/dist/app/api/hazo_auth/change_password/route.js +98 -0
  5. package/dist/app/api/hazo_auth/forgot_password/route.d.ts +8 -0
  6. package/dist/app/api/hazo_auth/forgot_password/route.d.ts.map +1 -0
  7. package/dist/app/api/hazo_auth/forgot_password/route.js +78 -0
  8. package/dist/app/api/hazo_auth/get_auth/route.d.ts +10 -0
  9. package/dist/app/api/hazo_auth/get_auth/route.d.ts.map +1 -0
  10. package/dist/app/api/hazo_auth/get_auth/route.js +63 -0
  11. package/dist/app/api/hazo_auth/invalidate_cache/route.d.ts +14 -0
  12. package/dist/app/api/hazo_auth/invalidate_cache/route.d.ts.map +1 -0
  13. package/dist/app/api/hazo_auth/invalidate_cache/route.js +96 -0
  14. package/dist/app/api/hazo_auth/library_photos/route.d.ts +13 -0
  15. package/dist/app/api/hazo_auth/library_photos/route.d.ts.map +1 -0
  16. package/dist/app/api/hazo_auth/library_photos/route.js +55 -0
  17. package/dist/app/api/hazo_auth/login/route.d.ts +12 -0
  18. package/dist/app/api/hazo_auth/login/route.d.ts.map +1 -0
  19. package/dist/app/api/hazo_auth/login/route.js +140 -0
  20. package/dist/app/api/hazo_auth/logout/route.d.ts +8 -0
  21. package/dist/app/api/hazo_auth/logout/route.d.ts.map +1 -0
  22. package/dist/app/api/hazo_auth/logout/route.js +71 -0
  23. package/dist/app/api/hazo_auth/me/route.d.ts +3 -0
  24. package/dist/app/api/hazo_auth/me/route.d.ts.map +1 -0
  25. package/dist/app/api/hazo_auth/me/route.js +34 -0
  26. package/dist/app/api/hazo_auth/profile_picture/[filename]/route.d.ts +7 -0
  27. package/dist/app/api/hazo_auth/profile_picture/[filename]/route.d.ts.map +1 -0
  28. package/dist/app/api/hazo_auth/profile_picture/[filename]/route.js +43 -0
  29. package/dist/app/api/hazo_auth/register/route.d.ts +9 -0
  30. package/dist/app/api/hazo_auth/register/route.d.ts.map +1 -0
  31. package/dist/app/api/hazo_auth/register/route.js +80 -0
  32. package/dist/app/api/hazo_auth/remove_profile_picture/route.d.ts +8 -0
  33. package/dist/app/api/hazo_auth/remove_profile_picture/route.d.ts.map +1 -0
  34. package/dist/app/api/hazo_auth/remove_profile_picture/route.js +64 -0
  35. package/dist/app/api/hazo_auth/resend_verification/route.d.ts +8 -0
  36. package/dist/app/api/hazo_auth/resend_verification/route.d.ts.map +1 -0
  37. package/dist/app/api/hazo_auth/resend_verification/route.js +79 -0
  38. package/dist/app/api/hazo_auth/reset_password/route.d.ts +8 -0
  39. package/dist/app/api/hazo_auth/reset_password/route.d.ts.map +1 -0
  40. package/dist/app/api/hazo_auth/reset_password/route.js +76 -0
  41. package/dist/app/api/hazo_auth/update_user/route.d.ts +9 -0
  42. package/dist/app/api/hazo_auth/update_user/route.d.ts.map +1 -0
  43. package/dist/app/api/hazo_auth/update_user/route.js +95 -0
  44. package/dist/app/api/hazo_auth/upload_profile_picture/route.d.ts +9 -0
  45. package/dist/app/api/hazo_auth/upload_profile_picture/route.d.ts.map +1 -0
  46. package/dist/app/api/hazo_auth/upload_profile_picture/route.js +204 -0
  47. package/dist/app/api/hazo_auth/validate_reset_token/route.d.ts +6 -0
  48. package/dist/app/api/hazo_auth/validate_reset_token/route.d.ts.map +1 -0
  49. package/dist/app/api/hazo_auth/validate_reset_token/route.js +58 -0
  50. package/dist/app/api/hazo_auth/verify_email/route.d.ts +11 -0
  51. package/dist/app/api/hazo_auth/verify_email/route.d.ts.map +1 -0
  52. package/dist/app/api/hazo_auth/verify_email/route.js +63 -0
  53. package/dist/cli/generate.d.ts +2 -0
  54. package/dist/cli/generate.d.ts.map +1 -0
  55. package/dist/cli/generate.js +117 -0
  56. package/dist/cli/index.d.ts +3 -0
  57. package/dist/cli/index.d.ts.map +1 -0
  58. package/dist/cli/index.js +120 -0
  59. package/dist/cli/validate.d.ts +15 -0
  60. package/dist/cli/validate.d.ts.map +1 -0
  61. package/dist/cli/validate.js +509 -0
  62. package/dist/components/ui/card.d.ts +9 -0
  63. package/dist/components/ui/card.d.ts.map +1 -0
  64. package/dist/components/ui/card.js +45 -0
  65. package/dist/hooks/use-mobile.d.ts.map +1 -1
  66. package/dist/hooks/use-mobile.js +17 -3
  67. package/dist/server/routes/change_password.d.ts +2 -0
  68. package/dist/server/routes/change_password.d.ts.map +1 -0
  69. package/dist/server/routes/change_password.js +2 -0
  70. package/dist/server/routes/forgot_password.d.ts +2 -0
  71. package/dist/server/routes/forgot_password.d.ts.map +1 -0
  72. package/dist/server/routes/forgot_password.js +2 -0
  73. package/dist/server/routes/get_auth.d.ts +2 -0
  74. package/dist/server/routes/get_auth.d.ts.map +1 -0
  75. package/dist/server/routes/get_auth.js +2 -0
  76. package/dist/server/routes/index.d.ts +18 -0
  77. package/dist/server/routes/index.d.ts.map +1 -0
  78. package/dist/server/routes/index.js +24 -0
  79. package/dist/server/routes/invalidate_cache.d.ts +2 -0
  80. package/dist/server/routes/invalidate_cache.d.ts.map +1 -0
  81. package/dist/server/routes/invalidate_cache.js +2 -0
  82. package/dist/server/routes/library_photos.d.ts +2 -0
  83. package/dist/server/routes/library_photos.d.ts.map +1 -0
  84. package/dist/server/routes/library_photos.js +2 -0
  85. package/dist/server/routes/login.d.ts +2 -0
  86. package/dist/server/routes/login.d.ts.map +1 -0
  87. package/dist/server/routes/login.js +2 -0
  88. package/dist/server/routes/logout.d.ts +2 -0
  89. package/dist/server/routes/logout.d.ts.map +1 -0
  90. package/dist/server/routes/logout.js +2 -0
  91. package/dist/server/routes/me.d.ts +2 -0
  92. package/dist/server/routes/me.d.ts.map +1 -0
  93. package/dist/server/routes/me.js +2 -0
  94. package/dist/server/routes/profile_picture_filename.d.ts +2 -0
  95. package/dist/server/routes/profile_picture_filename.d.ts.map +1 -0
  96. package/dist/server/routes/profile_picture_filename.js +3 -0
  97. package/dist/server/routes/register.d.ts +2 -0
  98. package/dist/server/routes/register.d.ts.map +1 -0
  99. package/dist/server/routes/register.js +2 -0
  100. package/dist/server/routes/remove_profile_picture.d.ts +2 -0
  101. package/dist/server/routes/remove_profile_picture.d.ts.map +1 -0
  102. package/dist/server/routes/remove_profile_picture.js +2 -0
  103. package/dist/server/routes/resend_verification.d.ts +2 -0
  104. package/dist/server/routes/resend_verification.d.ts.map +1 -0
  105. package/dist/server/routes/resend_verification.js +2 -0
  106. package/dist/server/routes/reset_password.d.ts +2 -0
  107. package/dist/server/routes/reset_password.d.ts.map +1 -0
  108. package/dist/server/routes/reset_password.js +2 -0
  109. package/dist/server/routes/update_user.d.ts +2 -0
  110. package/dist/server/routes/update_user.d.ts.map +1 -0
  111. package/dist/server/routes/update_user.js +2 -0
  112. package/dist/server/routes/upload_profile_picture.d.ts +2 -0
  113. package/dist/server/routes/upload_profile_picture.d.ts.map +1 -0
  114. package/dist/server/routes/upload_profile_picture.js +2 -0
  115. package/dist/server/routes/validate_reset_token.d.ts +2 -0
  116. package/dist/server/routes/validate_reset_token.d.ts.map +1 -0
  117. package/dist/server/routes/validate_reset_token.js +2 -0
  118. package/dist/server/routes/verify_email.d.ts +2 -0
  119. package/dist/server/routes/verify_email.d.ts.map +1 -0
  120. package/dist/server/routes/verify_email.js +2 -0
  121. package/package.json +12 -17
  122. package/components.json +0 -22
  123. package/instrumentation.ts +0 -32
  124. package/migrations/001_add_token_type_to_refresh_tokens.sql +0 -14
  125. package/migrations/002_add_name_to_hazo_users.sql +0 -7
  126. package/migrations/003_add_url_on_logon_to_hazo_users.sql +0 -8
  127. package/next.config.mjs +0 -67
  128. package/postcss.config.mjs +0 -8
  129. package/public/file.svg +0 -1
  130. package/public/globe.svg +0 -1
  131. package/public/next.svg +0 -1
  132. package/public/vercel.svg +0 -1
  133. package/public/window.svg +0 -1
  134. package/scripts/apply_migration.ts +0 -118
  135. package/scripts/init_users.ts +0 -378
  136. package/src/app/api/hazo_auth/auth/upload_profile_picture/route.ts +0 -268
  137. package/src/app/api/hazo_auth/change_password/route.ts +0 -132
  138. package/src/app/api/hazo_auth/forgot_password/route.ts +0 -107
  139. package/src/app/api/hazo_auth/get_auth/route.ts +0 -89
  140. package/src/app/api/hazo_auth/invalidate_cache/route.ts +0 -139
  141. package/src/app/api/hazo_auth/library_photos/route.ts +0 -73
  142. package/src/app/api/hazo_auth/login/route.ts +0 -181
  143. package/src/app/api/hazo_auth/logout/route.ts +0 -89
  144. package/src/app/api/hazo_auth/me/route.ts +0 -47
  145. package/src/app/api/hazo_auth/profile_picture/[filename]/route.ts +0 -67
  146. package/src/app/api/hazo_auth/register/route.ts +0 -109
  147. package/src/app/api/hazo_auth/remove_profile_picture/route.ts +0 -86
  148. package/src/app/api/hazo_auth/resend_verification/route.ts +0 -108
  149. package/src/app/api/hazo_auth/reset_password/route.ts +0 -107
  150. package/src/app/api/hazo_auth/update_user/route.ts +0 -126
  151. package/src/app/api/hazo_auth/upload_profile_picture/route.ts +0 -268
  152. package/src/app/api/hazo_auth/user_management/permissions/route.ts +0 -367
  153. package/src/app/api/hazo_auth/user_management/roles/route.ts +0 -442
  154. package/src/app/api/hazo_auth/user_management/users/roles/route.ts +0 -367
  155. package/src/app/api/hazo_auth/user_management/users/route.ts +0 -239
  156. package/src/app/api/hazo_auth/validate_reset_token/route.ts +0 -83
  157. package/src/app/api/hazo_auth/verify_email/route.ts +0 -88
  158. package/src/app/api/migrations/apply/route.ts +0 -91
  159. package/src/app/favicon.ico +0 -0
  160. package/src/app/fonts/GeistMonoVF.woff +0 -0
  161. package/src/app/fonts/GeistVF.woff +0 -0
  162. package/src/app/globals.css +0 -89
  163. package/src/app/hazo_auth/forgot_password/forgot_password_page_client.tsx +0 -60
  164. package/src/app/hazo_auth/forgot_password/page.tsx +0 -24
  165. package/src/app/hazo_auth/login/login_page_client.tsx +0 -86
  166. package/src/app/hazo_auth/login/page.tsx +0 -38
  167. package/src/app/hazo_auth/my_settings/my_settings_page_client.tsx +0 -120
  168. package/src/app/hazo_auth/my_settings/page.tsx +0 -40
  169. package/src/app/hazo_auth/register/page.tsx +0 -36
  170. package/src/app/hazo_auth/register/register_page_client.tsx +0 -81
  171. package/src/app/hazo_auth/reset_password/page.tsx +0 -29
  172. package/src/app/hazo_auth/reset_password/reset_password_page_client.tsx +0 -81
  173. package/src/app/hazo_auth/user_management/page.tsx +0 -14
  174. package/src/app/hazo_auth/user_management/user_management_page_client.tsx +0 -16
  175. package/src/app/hazo_auth/verify_email/page.tsx +0 -24
  176. package/src/app/hazo_auth/verify_email/verify_email_page_client.tsx +0 -60
  177. package/src/app/hazo_connect/api/sqlite/data/route.ts +0 -203
  178. package/src/app/hazo_connect/api/sqlite/schema/route.ts +0 -45
  179. package/src/app/hazo_connect/api/sqlite/tables/route.ts +0 -36
  180. package/src/app/hazo_connect/sqlite_admin/page.tsx +0 -51
  181. package/src/app/hazo_connect/sqlite_admin/sqlite-admin-client.tsx +0 -984
  182. package/src/app/layout.tsx +0 -43
  183. package/src/app/page.tsx +0 -170
  184. package/src/components/index.ts +0 -7
  185. package/src/components/layouts/email_verification/config/email_verification_field_config.ts +0 -86
  186. package/src/components/layouts/email_verification/hooks/use_email_verification.ts +0 -297
  187. package/src/components/layouts/email_verification/index.tsx +0 -297
  188. package/src/components/layouts/forgot_password/config/forgot_password_field_config.ts +0 -58
  189. package/src/components/layouts/forgot_password/hooks/use_forgot_password_form.ts +0 -179
  190. package/src/components/layouts/forgot_password/index.tsx +0 -168
  191. package/src/components/layouts/index.ts +0 -26
  192. package/src/components/layouts/login/config/login_field_config.ts +0 -67
  193. package/src/components/layouts/login/hooks/use_login_form.ts +0 -286
  194. package/src/components/layouts/login/index.tsx +0 -252
  195. package/src/components/layouts/my_settings/components/editable_field.tsx +0 -177
  196. package/src/components/layouts/my_settings/components/password_change_dialog.tsx +0 -301
  197. package/src/components/layouts/my_settings/components/profile_picture_dialog.tsx +0 -385
  198. package/src/components/layouts/my_settings/components/profile_picture_display.tsx +0 -66
  199. package/src/components/layouts/my_settings/components/profile_picture_gravatar_tab.tsx +0 -143
  200. package/src/components/layouts/my_settings/components/profile_picture_library_tab.tsx +0 -311
  201. package/src/components/layouts/my_settings/components/profile_picture_upload_tab.tsx +0 -341
  202. package/src/components/layouts/my_settings/config/my_settings_field_config.ts +0 -61
  203. package/src/components/layouts/my_settings/hooks/use_my_settings.ts +0 -458
  204. package/src/components/layouts/my_settings/index.tsx +0 -351
  205. package/src/components/layouts/register/config/register_field_config.ts +0 -101
  206. package/src/components/layouts/register/hooks/use_register_form.ts +0 -275
  207. package/src/components/layouts/register/index.tsx +0 -226
  208. package/src/components/layouts/reset_password/config/reset_password_field_config.ts +0 -86
  209. package/src/components/layouts/reset_password/hooks/use_reset_password_form.ts +0 -276
  210. package/src/components/layouts/reset_password/index.tsx +0 -294
  211. package/src/components/layouts/shared/components/already_logged_in_guard.tsx +0 -95
  212. package/src/components/layouts/shared/components/auth_page_shell.tsx +0 -36
  213. package/src/components/layouts/shared/components/field_error_message.tsx +0 -29
  214. package/src/components/layouts/shared/components/form_action_buttons.tsx +0 -64
  215. package/src/components/layouts/shared/components/form_field_wrapper.tsx +0 -44
  216. package/src/components/layouts/shared/components/form_header.tsx +0 -36
  217. package/src/components/layouts/shared/components/logout_button.tsx +0 -76
  218. package/src/components/layouts/shared/components/password_field.tsx +0 -72
  219. package/src/components/layouts/shared/components/profile_pic_menu.tsx +0 -321
  220. package/src/components/layouts/shared/components/profile_pic_menu_wrapper.tsx +0 -40
  221. package/src/components/layouts/shared/components/sidebar_layout_wrapper.tsx +0 -214
  222. package/src/components/layouts/shared/components/standalone_layout_wrapper.tsx +0 -53
  223. package/src/components/layouts/shared/components/two_column_auth_layout.tsx +0 -44
  224. package/src/components/layouts/shared/components/unauthorized_guard.tsx +0 -78
  225. package/src/components/layouts/shared/components/visual_panel.tsx +0 -41
  226. package/src/components/layouts/shared/config/layout_customization.ts +0 -95
  227. package/src/components/layouts/shared/data/layout_data_client.ts +0 -19
  228. package/src/components/layouts/shared/hooks/use_auth_status.ts +0 -103
  229. package/src/components/layouts/shared/hooks/use_hazo_auth.ts +0 -158
  230. package/src/components/layouts/shared/index.ts +0 -34
  231. package/src/components/layouts/shared/utils/ip_address.ts +0 -37
  232. package/src/components/layouts/shared/utils/validation.ts +0 -66
  233. package/src/components/layouts/user_management/components/roles_matrix.tsx +0 -607
  234. package/src/components/layouts/user_management/index.tsx +0 -1295
  235. package/src/components/ui/alert-dialog.tsx +0 -141
  236. package/src/components/ui/avatar.tsx +0 -50
  237. package/src/components/ui/button.tsx +0 -57
  238. package/src/components/ui/checkbox.tsx +0 -30
  239. package/src/components/ui/dialog.tsx +0 -122
  240. package/src/components/ui/dropdown-menu.tsx +0 -201
  241. package/src/components/ui/hazo_ui_tooltip.tsx +0 -67
  242. package/src/components/ui/index.ts +0 -22
  243. package/src/components/ui/input.tsx +0 -22
  244. package/src/components/ui/label.tsx +0 -26
  245. package/src/components/ui/separator.tsx +0 -31
  246. package/src/components/ui/sheet.tsx +0 -139
  247. package/src/components/ui/sidebar.tsx +0 -773
  248. package/src/components/ui/skeleton.tsx +0 -15
  249. package/src/components/ui/sonner.tsx +0 -31
  250. package/src/components/ui/switch.tsx +0 -29
  251. package/src/components/ui/table.tsx +0 -120
  252. package/src/components/ui/tabs.tsx +0 -55
  253. package/src/components/ui/tooltip.tsx +0 -32
  254. package/src/components/ui/vertical-tabs.tsx +0 -59
  255. package/src/hooks/use-mobile.tsx +0 -19
  256. package/src/index.ts +0 -7
  257. package/src/lib/already_logged_in_config.server.ts +0 -46
  258. package/src/lib/app_logger.ts +0 -24
  259. package/src/lib/auth/auth_cache.ts +0 -220
  260. package/src/lib/auth/auth_rate_limiter.ts +0 -121
  261. package/src/lib/auth/auth_types.ts +0 -65
  262. package/src/lib/auth/auth_utils.server.ts +0 -196
  263. package/src/lib/auth/hazo_get_auth.server.ts +0 -333
  264. package/src/lib/auth/index.ts +0 -23
  265. package/src/lib/auth/server_auth.ts +0 -88
  266. package/src/lib/auth_utility_config.server.ts +0 -136
  267. package/src/lib/config/config_loader.server.ts +0 -164
  268. package/src/lib/email_verification_config.server.ts +0 -32
  269. package/src/lib/file_types_config.server.ts +0 -25
  270. package/src/lib/forgot_password_config.server.ts +0 -32
  271. package/src/lib/hazo_connect_instance.server.ts +0 -101
  272. package/src/lib/hazo_connect_setup.server.ts +0 -194
  273. package/src/lib/hazo_connect_setup.ts +0 -54
  274. package/src/lib/index.ts +0 -44
  275. package/src/lib/login_config.server.ts +0 -71
  276. package/src/lib/messages_config.server.ts +0 -45
  277. package/src/lib/migrations/apply_migration.ts +0 -105
  278. package/src/lib/my_settings_config.server.ts +0 -135
  279. package/src/lib/password_requirements_config.server.ts +0 -39
  280. package/src/lib/profile_pic_menu_config.server.ts +0 -138
  281. package/src/lib/profile_picture_config.server.ts +0 -56
  282. package/src/lib/register_config.server.ts +0 -73
  283. package/src/lib/reset_password_config.server.ts +0 -75
  284. package/src/lib/services/email_service.ts +0 -581
  285. package/src/lib/services/email_verification_service.ts +0 -270
  286. package/src/lib/services/index.ts +0 -15
  287. package/src/lib/services/login_service.ts +0 -134
  288. package/src/lib/services/password_change_service.ts +0 -154
  289. package/src/lib/services/password_reset_service.ts +0 -405
  290. package/src/lib/services/profile_picture_remove_service.ts +0 -120
  291. package/src/lib/services/profile_picture_service.ts +0 -215
  292. package/src/lib/services/profile_picture_source_mapper.ts +0 -62
  293. package/src/lib/services/registration_service.ts +0 -184
  294. package/src/lib/services/token_service.ts +0 -240
  295. package/src/lib/services/user_profiles_service.ts +0 -143
  296. package/src/lib/services/user_update_service.ts +0 -141
  297. package/src/lib/ui_shell_config.server.ts +0 -73
  298. package/src/lib/ui_sizes_config.server.ts +0 -37
  299. package/src/lib/user_fields_config.server.ts +0 -31
  300. package/src/lib/user_management_config.server.ts +0 -39
  301. package/src/lib/utils/api_route_helpers.ts +0 -60
  302. package/src/lib/utils/error_sanitizer.ts +0 -75
  303. package/src/lib/utils.ts +0 -11
  304. package/src/middleware.ts +0 -94
  305. package/src/routes/index.ts +0 -34
  306. package/src/server/config/config_loader.ts +0 -496
  307. package/src/server/index.ts +0 -38
  308. package/src/server/logging/logger_service.ts +0 -56
  309. package/src/server/routes/root_router.ts +0 -16
  310. package/src/server/server.ts +0 -28
  311. package/src/server/types/app_types.ts +0 -74
  312. package/src/server/types/express.d.ts +0 -16
  313. package/src/stories/email_verification_layout.stories.tsx +0 -137
  314. package/src/stories/forgot_password_layout.stories.tsx +0 -85
  315. package/src/stories/login_layout.stories.tsx +0 -85
  316. package/src/stories/project_overview.stories.tsx +0 -33
  317. package/src/stories/register_layout.stories.tsx +0 -107
  318. package/tailwind.config.ts +0 -77
  319. package/tsconfig.build.json +0 -36
  320. package/tsconfig.json +0 -28
@@ -1,121 +0,0 @@
1
- // file_description: Simple in-memory rate limiter for hazo_get_auth API endpoint
2
- // section: types
3
-
4
- /**
5
- * Rate limit entry structure
6
- */
7
- type RateLimitEntry = {
8
- count: number;
9
- window_start: number; // Unix timestamp in milliseconds
10
- };
11
-
12
- /**
13
- * Simple in-memory rate limiter
14
- * Tracks request counts per key within a time window
15
- */
16
- class RateLimiter {
17
- private limits: Map<string, RateLimitEntry>;
18
- private window_ms: number; // 1 minute = 60000ms
19
-
20
- constructor() {
21
- this.limits = new Map();
22
- this.window_ms = 60 * 1000; // 1 minute window
23
- }
24
-
25
- /**
26
- * Checks if a request should be allowed
27
- * @param key - Rate limit key (e.g., "user:123" or "ip:192.168.1.1")
28
- * @param max_requests - Maximum requests allowed per window
29
- * @returns true if allowed, false if rate limited
30
- */
31
- check(key: string, max_requests: number): boolean {
32
- const now = Date.now();
33
- const entry = this.limits.get(key);
34
-
35
- if (!entry) {
36
- // First request for this key
37
- this.limits.set(key, {
38
- count: 1,
39
- window_start: now,
40
- });
41
- return true;
42
- }
43
-
44
- // Check if window has expired
45
- if (now - entry.window_start >= this.window_ms) {
46
- // Reset window
47
- this.limits.set(key, {
48
- count: 1,
49
- window_start: now,
50
- });
51
- return true;
52
- }
53
-
54
- // Check if limit exceeded
55
- if (entry.count >= max_requests) {
56
- return false;
57
- }
58
-
59
- // Increment count
60
- entry.count++;
61
- return true;
62
- }
63
-
64
- /**
65
- * Cleans up old entries (call periodically to prevent memory leak)
66
- * Removes entries older than 2 windows
67
- */
68
- cleanup(): void {
69
- const now = Date.now();
70
- const cutoff = now - 2 * this.window_ms;
71
-
72
- const keys_to_delete: string[] = [];
73
- for (const [key, entry] of this.limits.entries()) {
74
- if (entry.window_start < cutoff) {
75
- keys_to_delete.push(key);
76
- }
77
- }
78
-
79
- for (const key of keys_to_delete) {
80
- this.limits.delete(key);
81
- }
82
- }
83
-
84
- /**
85
- * Gets rate limit statistics
86
- * @returns Object with current limit entries count
87
- */
88
- get_stats(): { active_limits: number } {
89
- return {
90
- active_limits: this.limits.size,
91
- };
92
- }
93
- }
94
-
95
- // section: singleton
96
- // Global rate limiter instance
97
- let rate_limiter_instance: RateLimiter | null = null;
98
-
99
- /**
100
- * Gets or creates the global rate limiter instance
101
- * @returns Rate limiter instance
102
- */
103
- export function get_rate_limiter(): RateLimiter {
104
- if (!rate_limiter_instance) {
105
- rate_limiter_instance = new RateLimiter();
106
-
107
- // Cleanup old entries every 5 minutes
108
- setInterval(() => {
109
- rate_limiter_instance?.cleanup();
110
- }, 5 * 60 * 1000);
111
- }
112
- return rate_limiter_instance;
113
- }
114
-
115
- /**
116
- * Resets the global rate limiter instance (useful for testing)
117
- */
118
- export function reset_rate_limiter(): void {
119
- rate_limiter_instance = null;
120
- }
121
-
@@ -1,65 +0,0 @@
1
- // file_description: Type definitions and error classes for hazo_get_auth utility
2
- // section: types
3
-
4
- /**
5
- * User data structure returned by hazo_get_auth
6
- */
7
- export type HazoAuthUser = {
8
- id: string;
9
- name: string | null;
10
- email_address: string;
11
- is_active: boolean;
12
- profile_picture_url: string | null;
13
- };
14
-
15
- /**
16
- * Result type for hazo_get_auth function
17
- * Returns authenticated state with user data and permissions, or unauthenticated state
18
- */
19
- export type HazoAuthResult =
20
- | {
21
- authenticated: true;
22
- user: HazoAuthUser;
23
- permissions: string[];
24
- permission_ok: boolean;
25
- missing_permissions?: string[];
26
- }
27
- | {
28
- authenticated: false;
29
- user: null;
30
- permissions: [];
31
- permission_ok: false;
32
- };
33
-
34
- /**
35
- * Options for hazo_get_auth function
36
- */
37
- export type HazoAuthOptions = {
38
- /**
39
- * Array of required permissions to check
40
- * If provided, permission_ok will be set based on whether user has all required permissions
41
- */
42
- required_permissions?: string[];
43
- /**
44
- * If true, throws PermissionError when user lacks required permissions
45
- * If false (default), returns permission_ok: false without throwing
46
- */
47
- strict?: boolean;
48
- };
49
-
50
- /**
51
- * Custom error class for permission denials
52
- * Includes technical and user-friendly error messages
53
- */
54
- export class PermissionError extends Error {
55
- constructor(
56
- public missing_permissions: string[],
57
- public user_permissions: string[],
58
- public required_permissions: string[],
59
- public user_friendly_message?: string,
60
- ) {
61
- super(`Missing permissions: ${missing_permissions.join(", ")}`);
62
- this.name = "PermissionError";
63
- }
64
- }
65
-
@@ -1,196 +0,0 @@
1
- // file_description: server-side authentication utilities for checking login status in API routes
2
- // section: imports
3
- import { NextRequest, NextResponse } from "next/server";
4
- import { get_hazo_connect_instance } from "../hazo_connect_instance.server";
5
- import { createCrudService } from "hazo_connect/server";
6
- import { map_db_source_to_ui } from "../services/profile_picture_source_mapper";
7
-
8
- // section: types
9
- export type AuthUser = {
10
- authenticated: true;
11
- user_id: string;
12
- email: string;
13
- name?: string;
14
- email_verified: boolean;
15
- is_active: boolean;
16
- last_logon?: string;
17
- profile_picture_url?: string;
18
- profile_source?: "upload" | "library" | "gravatar" | "custom";
19
- };
20
-
21
- export type AuthResult =
22
- | AuthUser
23
- | { authenticated: false };
24
-
25
- // section: helpers
26
- /**
27
- * Clears authentication cookies from response
28
- * @param response - NextResponse object to clear cookies from
29
- * @returns The response with cleared cookies
30
- */
31
- function clear_auth_cookies(response: NextResponse): NextResponse {
32
- response.cookies.set("hazo_auth_user_email", "", {
33
- expires: new Date(0),
34
- path: "/",
35
- });
36
- response.cookies.set("hazo_auth_user_id", "", {
37
- expires: new Date(0),
38
- path: "/",
39
- });
40
- return response;
41
- }
42
-
43
- // section: functions
44
- /**
45
- * Checks if a user is authenticated from request cookies
46
- * Validates user exists, is active, and cookies match
47
- * @param request - NextRequest object
48
- * @returns AuthResult with user info or authenticated: false
49
- */
50
- export async function get_authenticated_user(request: NextRequest): Promise<AuthResult> {
51
- const user_id = request.cookies.get("hazo_auth_user_id")?.value;
52
- const user_email = request.cookies.get("hazo_auth_user_email")?.value;
53
-
54
- if (!user_id || !user_email) {
55
- return { authenticated: false };
56
- }
57
-
58
- try {
59
- const hazoConnect = get_hazo_connect_instance();
60
- const users_service = createCrudService(hazoConnect, "hazo_users");
61
-
62
- const users = await users_service.findBy({
63
- id: user_id,
64
- email_address: user_email,
65
- });
66
-
67
- if (!Array.isArray(users) || users.length === 0) {
68
- return { authenticated: false };
69
- }
70
-
71
- const user = users[0];
72
-
73
- // Check if user is active
74
- if (user.is_active === false) {
75
- return { authenticated: false };
76
- }
77
-
78
- // Map database profile_source to UI representation
79
- const profile_source_db = user.profile_source as string | null | undefined;
80
- const profile_source_ui = profile_source_db ? map_db_source_to_ui(profile_source_db) : undefined;
81
-
82
- return {
83
- authenticated: true,
84
- user_id: user.id as string,
85
- email: user.email_address as string,
86
- name: (user.name as string | null | undefined) || undefined,
87
- email_verified: user.email_verified === true,
88
- is_active: user.is_active === true,
89
- last_logon: (user.last_logon as string | null | undefined) || undefined,
90
- profile_picture_url: (user.profile_picture_url as string | null | undefined) || undefined,
91
- profile_source: profile_source_ui,
92
- };
93
- } catch (error) {
94
- return { authenticated: false };
95
- }
96
- }
97
-
98
- /**
99
- * Checks if user is authenticated (simple boolean check)
100
- * @param request - NextRequest object
101
- * @returns true if authenticated, false otherwise
102
- */
103
- export async function is_authenticated(request: NextRequest): Promise<boolean> {
104
- const result = await get_authenticated_user(request);
105
- return result.authenticated;
106
- }
107
-
108
- /**
109
- * Requires authentication - throws error if not authenticated
110
- * Use in API routes that require authentication
111
- * @param request - NextRequest object
112
- * @returns AuthUser (never returns authenticated: false, throws instead)
113
- * @throws Error if not authenticated
114
- */
115
- export async function require_auth(request: NextRequest): Promise<AuthUser> {
116
- const result = await get_authenticated_user(request);
117
-
118
- if (!result.authenticated) {
119
- throw new Error("Authentication required");
120
- }
121
-
122
- return result;
123
- }
124
-
125
- /**
126
- * Gets authenticated user and returns response with cleared cookies if invalid
127
- * Useful for /api/auth/me endpoint that needs to clear cookies on invalid auth
128
- * @param request - NextRequest object
129
- * @returns Object with auth_result and response (with cleared cookies if invalid)
130
- */
131
- export async function get_authenticated_user_with_response(request: NextRequest): Promise<{
132
- auth_result: AuthResult;
133
- response?: NextResponse;
134
- }> {
135
- const user_id = request.cookies.get("hazo_auth_user_id")?.value;
136
- const user_email = request.cookies.get("hazo_auth_user_email")?.value;
137
-
138
- if (!user_id || !user_email) {
139
- return { auth_result: { authenticated: false } };
140
- }
141
-
142
- try {
143
- const hazoConnect = get_hazo_connect_instance();
144
- const users_service = createCrudService(hazoConnect, "hazo_users");
145
-
146
- const users = await users_service.findBy({
147
- id: user_id,
148
- email_address: user_email,
149
- });
150
-
151
- if (!Array.isArray(users) || users.length === 0) {
152
- // User not found - clear cookies
153
- const response = NextResponse.json(
154
- { authenticated: false },
155
- { status: 200 }
156
- );
157
- clear_auth_cookies(response);
158
- return { auth_result: { authenticated: false }, response };
159
- }
160
-
161
- const user = users[0];
162
-
163
- // Check if user is still active
164
- if (user.is_active === false) {
165
- // User is inactive - clear cookies
166
- const response = NextResponse.json(
167
- { authenticated: false },
168
- { status: 200 }
169
- );
170
- clear_auth_cookies(response);
171
- return { auth_result: { authenticated: false }, response };
172
- }
173
-
174
- // Map database profile_source to UI representation
175
- const profile_source_db = user.profile_source as string | null | undefined;
176
- const profile_source_ui = profile_source_db ? map_db_source_to_ui(profile_source_db) : undefined;
177
-
178
- return {
179
- auth_result: {
180
- authenticated: true,
181
- user_id: user.id as string,
182
- email: user.email_address as string,
183
- name: (user.name as string | null | undefined) || undefined,
184
- email_verified: user.email_verified === true,
185
- is_active: user.is_active === true,
186
- last_logon: (user.last_logon as string | null | undefined) || undefined,
187
- profile_picture_url: (user.profile_picture_url as string | null | undefined) || undefined,
188
- profile_source: profile_source_ui,
189
- },
190
- };
191
- } catch (error) {
192
- // On error, assume not authenticated
193
- return { auth_result: { authenticated: false } };
194
- }
195
- }
196
-
@@ -1,333 +0,0 @@
1
- // file_description: server-side implementation of hazo_get_auth utility for API routes
2
- // section: imports
3
- import { NextRequest } from "next/server";
4
- import { get_hazo_connect_instance } from "../hazo_connect_instance.server";
5
- import { createCrudService } from "hazo_connect/server";
6
- import { create_app_logger } from "../app_logger";
7
- import { get_filename, get_line_number } from "../utils/api_route_helpers";
8
- import type { HazoAuthResult, HazoAuthUser, HazoAuthOptions } from "./auth_types";
9
- import { PermissionError } from "./auth_types";
10
- import { get_auth_cache } from "./auth_cache";
11
- import { get_rate_limiter } from "./auth_rate_limiter";
12
- import { get_auth_utility_config } from "../auth_utility_config.server";
13
-
14
- // section: helpers
15
-
16
- /**
17
- * Gets client IP address from request
18
- * @param request - NextRequest object
19
- * @returns IP address string
20
- */
21
- function get_client_ip(request: NextRequest): string {
22
- const forwarded = request.headers.get("x-forwarded-for");
23
- if (forwarded) {
24
- return forwarded.split(",")[0].trim();
25
- }
26
- const real_ip = request.headers.get("x-real-ip");
27
- if (real_ip) {
28
- return real_ip;
29
- }
30
- return "unknown";
31
- }
32
-
33
- /**
34
- * Fetches user data and permissions from database
35
- * @param user_id - User ID
36
- * @returns Object with user, permissions, and role_ids
37
- */
38
- async function fetch_user_data_from_db(user_id: string): Promise<{
39
- user: HazoAuthUser;
40
- permissions: string[];
41
- role_ids: number[];
42
- }> {
43
- const hazoConnect = get_hazo_connect_instance();
44
- const users_service = createCrudService(hazoConnect, "hazo_users");
45
- const user_roles_service = createCrudService(hazoConnect, "hazo_user_roles");
46
- const role_permissions_service = createCrudService(
47
- hazoConnect,
48
- "hazo_role_permissions",
49
- );
50
- const permissions_service = createCrudService(
51
- hazoConnect,
52
- "hazo_permissions",
53
- );
54
-
55
- // Fetch user
56
- const users = await users_service.findBy({ id: user_id });
57
- if (!Array.isArray(users) || users.length === 0) {
58
- throw new Error("User not found");
59
- }
60
-
61
- const user_db = users[0];
62
-
63
- // Check if user is active
64
- if (user_db.is_active === false) {
65
- throw new Error("User is inactive");
66
- }
67
-
68
- // Build user object
69
- const user: HazoAuthUser = {
70
- id: user_db.id as string,
71
- name: (user_db.name as string | null) || null,
72
- email_address: user_db.email_address as string,
73
- is_active: user_db.is_active === true,
74
- profile_picture_url:
75
- (user_db.profile_picture_url as string | null) || null,
76
- };
77
-
78
- // Fetch user roles
79
- const user_roles = await user_roles_service.findBy({ user_id });
80
- const role_ids: number[] = [];
81
- if (Array.isArray(user_roles)) {
82
- for (const ur of user_roles) {
83
- const role_id = ur.role_id as number | undefined;
84
- if (role_id !== undefined) {
85
- role_ids.push(role_id);
86
- }
87
- }
88
- }
89
-
90
- // Fetch role permissions
91
- const permissions_set = new Set<string>();
92
- if (role_ids.length > 0) {
93
- const role_permissions = await role_permissions_service.findBy({});
94
- if (Array.isArray(role_permissions)) {
95
- // Filter role_permissions for user's roles
96
- const user_role_permissions = role_permissions.filter((rp) =>
97
- role_ids.includes(rp.role_id as number),
98
- );
99
-
100
- // Get permission IDs
101
- const permission_ids = new Set<number>();
102
- for (const rp of user_role_permissions) {
103
- const perm_id = rp.permission_id as number | undefined;
104
- if (perm_id !== undefined) {
105
- permission_ids.add(perm_id);
106
- }
107
- }
108
-
109
- // Fetch permission names
110
- if (permission_ids.size > 0) {
111
- const permissions = await permissions_service.findBy({});
112
- if (Array.isArray(permissions)) {
113
- for (const perm of permissions) {
114
- const perm_id = perm.id as number | undefined;
115
- if (perm_id !== undefined && permission_ids.has(perm_id)) {
116
- const perm_name = perm.permission_name as string | undefined;
117
- if (perm_name) {
118
- permissions_set.add(perm_name);
119
- }
120
- }
121
- }
122
- }
123
- }
124
- }
125
- }
126
-
127
- const permissions = Array.from(permissions_set);
128
-
129
- return { user, permissions, role_ids };
130
- }
131
-
132
- /**
133
- * Checks if user has required permissions
134
- * @param user_permissions - User's permissions
135
- * @param required_permissions - Required permissions
136
- * @returns Object with permission_ok and missing_permissions
137
- */
138
- function check_permissions(
139
- user_permissions: string[],
140
- required_permissions: string[],
141
- ): { permission_ok: boolean; missing_permissions: string[] } {
142
- const user_perms_set = new Set(user_permissions);
143
- const missing = required_permissions.filter(
144
- (perm) => !user_perms_set.has(perm),
145
- );
146
-
147
- return {
148
- permission_ok: missing.length === 0,
149
- missing_permissions: missing,
150
- };
151
- }
152
-
153
- /**
154
- * Gets user-friendly error message for missing permissions
155
- * @param missing_permissions - Array of missing permission names
156
- * @param config - Auth utility config
157
- * @returns User-friendly message or undefined
158
- */
159
- function get_friendly_error_message(
160
- missing_permissions: string[],
161
- config: ReturnType<typeof get_auth_utility_config>,
162
- ): string | undefined {
163
- if (!config.enable_friendly_error_messages) {
164
- return undefined;
165
- }
166
-
167
- // Try to get messages for each missing permission
168
- const messages: string[] = [];
169
- for (const perm of missing_permissions) {
170
- const message = config.permission_error_messages.get(perm);
171
- if (message) {
172
- messages.push(message);
173
- }
174
- }
175
-
176
- if (messages.length > 0) {
177
- return messages.join(". ");
178
- }
179
-
180
- // Default message if no specific mapping
181
- return "You don't have the required permissions to perform this action. Please contact your administrator.";
182
- }
183
-
184
- // section: main_function
185
-
186
- /**
187
- * Main hazo_get_auth function for server-side use in API routes
188
- * Returns user details, permissions, and checks required permissions
189
- * @param request - NextRequest object
190
- * @param options - Optional parameters for permission checking
191
- * @returns HazoAuthResult with user data and permissions
192
- * @throws PermissionError if strict mode and permissions are missing
193
- */
194
- export async function hazo_get_auth(
195
- request: NextRequest,
196
- options?: HazoAuthOptions,
197
- ): Promise<HazoAuthResult> {
198
- const logger = create_app_logger();
199
- const config = get_auth_utility_config();
200
- const cache = get_auth_cache(
201
- config.cache_max_users,
202
- config.cache_ttl_minutes,
203
- config.cache_max_age_minutes,
204
- );
205
- const rate_limiter = get_rate_limiter();
206
-
207
- // Fast path: Check for authentication cookies
208
- const user_id = request.cookies.get("hazo_auth_user_id")?.value;
209
- const user_email = request.cookies.get("hazo_auth_user_email")?.value;
210
-
211
- if (!user_id || !user_email) {
212
- // Unauthenticated - check rate limit by IP
213
- const client_ip = get_client_ip(request);
214
- const ip_key = `ip:${client_ip}`;
215
- if (!rate_limiter.check(ip_key, config.rate_limit_per_ip)) {
216
- logger.warn("auth_utility_rate_limit_exceeded_ip", {
217
- filename: get_filename(),
218
- line_number: get_line_number(),
219
- ip: client_ip,
220
- });
221
- throw new Error("Rate limit exceeded. Please try again later.");
222
- }
223
-
224
- return {
225
- authenticated: false,
226
- user: null,
227
- permissions: [],
228
- permission_ok: false,
229
- };
230
- }
231
-
232
- // Authenticated - check rate limit by user
233
- const user_key = `user:${user_id}`;
234
- if (!rate_limiter.check(user_key, config.rate_limit_per_user)) {
235
- logger.warn("auth_utility_rate_limit_exceeded_user", {
236
- filename: get_filename(),
237
- line_number: get_line_number(),
238
- user_id,
239
- });
240
- throw new Error("Rate limit exceeded. Please try again later.");
241
- }
242
-
243
- // Check cache
244
- let cached_entry = cache.get(user_id);
245
- let user: HazoAuthUser;
246
- let permissions: string[];
247
- let role_ids: number[];
248
-
249
- if (cached_entry) {
250
- // Cache hit
251
- user = cached_entry.user;
252
- permissions = cached_entry.permissions;
253
- role_ids = cached_entry.role_ids;
254
- } else {
255
- // Cache miss - fetch from database
256
- try {
257
- const user_data = await fetch_user_data_from_db(user_id);
258
- user = user_data.user;
259
- permissions = user_data.permissions;
260
- role_ids = user_data.role_ids;
261
-
262
- // Update cache
263
- cache.set(user_id, user, permissions, role_ids);
264
- } catch (error) {
265
- const error_message =
266
- error instanceof Error ? error.message : "Unknown error";
267
- logger.error("auth_utility_fetch_user_failed", {
268
- filename: get_filename(),
269
- line_number: get_line_number(),
270
- user_id,
271
- error: error_message,
272
- });
273
-
274
- return {
275
- authenticated: false,
276
- user: null,
277
- permissions: [],
278
- permission_ok: false,
279
- };
280
- }
281
- }
282
-
283
- // Check permissions if required
284
- let permission_ok = true;
285
- let missing_permissions: string[] | undefined;
286
-
287
- if (options?.required_permissions && options.required_permissions.length > 0) {
288
- const check_result = check_permissions(
289
- permissions,
290
- options.required_permissions,
291
- );
292
- permission_ok = check_result.permission_ok;
293
- missing_permissions = check_result.missing_permissions;
294
-
295
- // Log permission denial if enabled
296
- if (!permission_ok && config.log_permission_denials) {
297
- const client_ip = get_client_ip(request);
298
- logger.warn("auth_utility_permission_denied", {
299
- filename: get_filename(),
300
- line_number: get_line_number(),
301
- user_id,
302
- requested_permissions: options.required_permissions,
303
- missing_permissions,
304
- user_permissions: permissions,
305
- ip: client_ip,
306
- });
307
- }
308
-
309
- // Throw error if strict mode
310
- if (!permission_ok && options.strict) {
311
- const friendly_message = get_friendly_error_message(
312
- missing_permissions,
313
- config,
314
- );
315
-
316
- throw new PermissionError(
317
- missing_permissions,
318
- permissions,
319
- options.required_permissions,
320
- friendly_message,
321
- );
322
- }
323
- }
324
-
325
- return {
326
- authenticated: true,
327
- user,
328
- permissions,
329
- permission_ok,
330
- missing_permissions,
331
- };
332
- }
333
-