@vitnode/core 1.2.0-canary.22 → 1.2.0-canary.24

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 (190) hide show
  1. package/dist/scripts/plugin.d.ts.map +1 -1
  2. package/dist/scripts/scripts.js +2 -9
  3. package/dist/scripts/shared/file-utils.d.ts.map +1 -1
  4. package/dist/src/api/{plugins → adapters}/email/nodemailer.d.ts +1 -1
  5. package/dist/src/api/adapters/email/nodemailer.d.ts.map +1 -0
  6. package/dist/src/api/{plugins → adapters}/email/nodemailer.js +1 -1
  7. package/dist/src/api/{plugins → adapters}/email/resend.d.ts +1 -1
  8. package/dist/src/api/adapters/email/resend.d.ts.map +1 -0
  9. package/dist/src/api/{plugins → adapters}/email/resend.js +1 -1
  10. package/dist/src/api/adapters/sso/discord.d.ts.map +1 -0
  11. package/dist/src/api/adapters/sso/facebook.d.ts.map +1 -0
  12. package/dist/src/api/adapters/sso/google.d.ts.map +1 -0
  13. package/dist/src/api/config.d.ts.map +1 -1
  14. package/dist/src/api/config.js +6 -5
  15. package/dist/src/api/lib/logger-middleware.d.ts +8 -0
  16. package/dist/src/api/lib/logger-middleware.d.ts.map +1 -0
  17. package/dist/src/api/lib/logger-middleware.js +30 -0
  18. package/dist/src/api/lib/route.d.ts +1 -1
  19. package/dist/src/api/lib/route.d.ts.map +1 -1
  20. package/dist/src/api/lib/route.js +1 -1
  21. package/dist/src/api/middlewares/{global/global.d.ts → global.middleware.d.ts} +10 -8
  22. package/dist/src/api/middlewares/global.middleware.d.ts.map +1 -0
  23. package/dist/src/api/middlewares/global.middleware.js +86 -0
  24. package/dist/src/api/middlewares/rate-limiter.middleware.d.ts +4 -0
  25. package/dist/src/api/middlewares/rate-limiter.middleware.d.ts.map +1 -0
  26. package/dist/src/api/middlewares/rate-limiter.middleware.js +26 -0
  27. package/dist/src/api/models/device.d.ts +4 -1
  28. package/dist/src/api/models/device.d.ts.map +1 -1
  29. package/dist/src/api/models/device.js +21 -14
  30. package/dist/src/api/models/email.d.ts +1 -2
  31. package/dist/src/api/models/email.d.ts.map +1 -1
  32. package/dist/src/api/models/email.js +9 -16
  33. package/dist/src/api/models/password.d.ts.map +1 -1
  34. package/dist/src/api/models/password.js +8 -1
  35. package/dist/src/api/models/session-admin.d.ts +1 -1
  36. package/dist/src/api/models/session-admin.d.ts.map +1 -1
  37. package/dist/src/api/models/session-admin.js +40 -16
  38. package/dist/src/api/models/session.d.ts +1 -1
  39. package/dist/src/api/models/session.d.ts.map +1 -1
  40. package/dist/src/api/models/session.js +28 -12
  41. package/dist/src/api/models/sso.js +1 -1
  42. package/dist/src/api/models/user/sign-up.d.ts +1 -1
  43. package/dist/src/api/models/user/sign-up.d.ts.map +1 -1
  44. package/dist/src/api/models/user/sign-up.js +2 -3
  45. package/dist/src/api/models/user.d.ts +1 -1
  46. package/dist/src/api/models/user.d.ts.map +1 -1
  47. package/dist/src/api/modules/admin/admin.module.d.ts +161 -8
  48. package/dist/src/api/modules/admin/admin.module.d.ts.map +1 -1
  49. package/dist/src/api/modules/admin/admin.module.js +3 -1
  50. package/dist/src/api/modules/admin/debug/debug.admin.module.d.ts +159 -0
  51. package/dist/src/api/modules/admin/debug/debug.admin.module.d.ts.map +1 -0
  52. package/dist/src/api/modules/admin/debug/debug.admin.module.js +10 -0
  53. package/dist/src/api/modules/admin/debug/routes/logs.route.d.ts +160 -0
  54. package/dist/src/api/modules/admin/debug/routes/logs.route.d.ts.map +1 -0
  55. package/dist/src/api/modules/admin/debug/routes/logs.route.js +70 -0
  56. package/dist/src/api/modules/admin/routes/session.route.d.ts +1 -5
  57. package/dist/src/api/modules/admin/routes/session.route.d.ts.map +1 -1
  58. package/dist/src/api/modules/admin/routes/session.route.js +0 -4
  59. package/dist/src/api/modules/admin/users/routes/list.route.d.ts +1 -1
  60. package/dist/src/api/modules/admin/users/routes/users.route.d.ts +1 -1
  61. package/dist/src/api/modules/admin/users/users.admin.module.d.ts +1 -1
  62. package/dist/src/api/modules/middleware/middleware.module.d.ts +1 -1
  63. package/dist/src/api/modules/middleware/route.d.ts +1 -1
  64. package/dist/src/api/modules/middleware/route.d.ts.map +1 -1
  65. package/dist/src/api/modules/middleware/route.js +2 -4
  66. package/dist/src/api/modules/users/routes/session.route.d.ts +1 -1
  67. package/dist/src/api/modules/users/routes/sign-in.route.d.ts +1 -1
  68. package/dist/src/api/modules/users/routes/sign-out.route.d.ts +1 -1
  69. package/dist/src/api/modules/users/routes/sign-up.route.d.ts +1 -1
  70. package/dist/src/api/modules/users/routes/test.route.d.ts +1 -1
  71. package/dist/src/api/modules/users/routes/test.route.d.ts.map +1 -1
  72. package/dist/src/api/modules/users/routes/test.route.js +8 -0
  73. package/dist/src/api/modules/users/sso/routes/callback.route.d.ts +1 -1
  74. package/dist/src/api/modules/users/sso/routes/create-url.route.d.ts +1 -1
  75. package/dist/src/api/modules/users/sso/sso.module.d.ts +2 -2
  76. package/dist/src/api/modules/users/users.module.d.ts +7 -7
  77. package/dist/src/app_admin/core/debug/page.d.ts +11 -0
  78. package/dist/src/app_admin/core/debug/page.d.ts.map +1 -0
  79. package/dist/src/app_admin/core/debug/page.js +44 -0
  80. package/dist/src/app_admin/core/users/page.d.ts +4 -1
  81. package/dist/src/app_admin/core/users/page.d.ts.map +1 -1
  82. package/dist/src/app_admin/core/users/page.js +4 -2
  83. package/dist/src/components/confirm-action/confirm-action-alert-dialog.d.ts +15 -0
  84. package/dist/src/components/confirm-action/confirm-action-alert-dialog.d.ts.map +1 -0
  85. package/dist/src/components/confirm-action/confirm-action-alert-dialog.js +41 -0
  86. package/dist/src/components/confirm-action/content.d.ts +7 -0
  87. package/dist/src/components/confirm-action/content.d.ts.map +1 -0
  88. package/dist/src/components/confirm-action/content.js +31 -0
  89. package/dist/src/components/date-format.d.ts +2 -1
  90. package/dist/src/components/date-format.d.ts.map +1 -1
  91. package/dist/src/components/date-format.js +4 -1
  92. package/dist/src/components/form/auto-form.js +1 -1
  93. package/dist/src/components/form/fields/combobox-async.d.ts +21 -0
  94. package/dist/src/components/form/fields/combobox-async.d.ts.map +1 -0
  95. package/dist/src/components/form/fields/combobox-async.js +115 -0
  96. package/dist/src/components/form/fields/combobox.d.ts +2 -1
  97. package/dist/src/components/form/fields/combobox.d.ts.map +1 -1
  98. package/dist/src/components/form/fields/combobox.js +4 -5
  99. package/dist/src/components/switchers/langs/language-swietcher.d.ts +5 -0
  100. package/dist/src/components/switchers/langs/language-swietcher.d.ts.map +1 -0
  101. package/dist/src/components/switchers/langs/language-swietcher.js +45 -0
  102. package/dist/src/components/switchers/themes/theme-switcher.d.ts.map +1 -0
  103. package/dist/src/components/switchers/{theme-switcher.js → themes/theme-switcher.js} +1 -1
  104. package/dist/src/components/table/content.js +1 -1
  105. package/dist/src/components/table/data-table.d.ts.map +1 -1
  106. package/dist/src/components/table/data-table.js +2 -7
  107. package/dist/src/components/table/pagination.js +3 -3
  108. package/dist/src/components/ui/alert-dialog.d.ts +7 -2
  109. package/dist/src/components/ui/alert-dialog.d.ts.map +1 -1
  110. package/dist/src/components/ui/alert-dialog.js +41 -7
  111. package/dist/src/components/ui/dialog.d.ts.map +1 -1
  112. package/dist/src/components/ui/dialog.js +1 -1
  113. package/dist/src/database/logs.d.ts +116 -0
  114. package/dist/src/database/logs.d.ts.map +1 -0
  115. package/dist/src/database/logs.js +18 -0
  116. package/dist/src/database/sessions.d.ts +19 -0
  117. package/dist/src/database/sessions.d.ts.map +1 -1
  118. package/dist/src/database/sessions.js +3 -0
  119. package/dist/src/lib/fetcher/core.d.ts +16 -0
  120. package/dist/src/lib/fetcher/core.d.ts.map +1 -0
  121. package/dist/src/lib/fetcher/core.js +39 -0
  122. package/dist/src/lib/fetcher/helpers-server.d.ts +3 -0
  123. package/dist/src/lib/fetcher/helpers-server.d.ts.map +1 -0
  124. package/dist/src/lib/fetcher/helpers-server.js +18 -0
  125. package/dist/src/lib/fetcher/helpers.d.ts +0 -1
  126. package/dist/src/lib/fetcher/helpers.d.ts.map +1 -1
  127. package/dist/src/lib/fetcher/helpers.js +0 -17
  128. package/dist/src/lib/fetcher-client.d.ts +9 -0
  129. package/dist/src/lib/fetcher-client.d.ts.map +1 -0
  130. package/dist/src/lib/fetcher-client.js +12 -0
  131. package/dist/src/lib/fetcher.d.ts +3 -1
  132. package/dist/src/lib/fetcher.d.ts.map +1 -1
  133. package/dist/src/lib/fetcher.js +15 -33
  134. package/dist/src/lib/helpers/auto-form.d.ts.map +1 -1
  135. package/dist/src/lib/helpers/auto-form.js +28 -16
  136. package/dist/src/lib/helpers/auto-form.test.js +49 -0
  137. package/dist/src/views/admin/layouts/admin-layout.d.ts.map +1 -1
  138. package/dist/src/views/admin/layouts/admin-layout.js +5 -1
  139. package/dist/src/views/admin/layouts/sidebar/nav/item.d.ts.map +1 -1
  140. package/dist/src/views/admin/layouts/sidebar/nav/item.js +24 -3
  141. package/dist/src/views/admin/layouts/user-bar/client.d.ts.map +1 -1
  142. package/dist/src/views/admin/layouts/user-bar/client.js +26 -18
  143. package/dist/src/views/admin/views/core/dashboard/dashboard-admin-view.js +1 -1
  144. package/dist/src/views/admin/views/core/debug/actions/clear-cache/clear-cache.d.ts +2 -0
  145. package/dist/src/views/admin/views/core/debug/actions/clear-cache/clear-cache.d.ts.map +1 -0
  146. package/dist/src/views/admin/views/core/debug/actions/clear-cache/clear-cache.js +35 -0
  147. package/dist/src/views/admin/views/core/debug/actions/clear-cache/mutation-api.d.ts +2 -0
  148. package/dist/src/views/admin/views/core/debug/actions/clear-cache/mutation-api.d.ts.map +1 -0
  149. package/dist/src/views/admin/views/core/debug/actions/clear-cache/mutation-api.js +5 -0
  150. package/dist/src/views/admin/views/core/debug/debug-admin-view.d.ts +4 -0
  151. package/dist/src/views/admin/views/core/debug/debug-admin-view.d.ts.map +1 -0
  152. package/dist/src/views/admin/views/core/debug/debug-admin-view.js +110 -0
  153. package/dist/src/views/admin/views/core/test.d.ts.map +1 -1
  154. package/dist/src/views/admin/views/core/test.js +108 -103
  155. package/dist/src/views/auth/sso/buttons/sso-buttons.d.ts +1 -1
  156. package/dist/src/views/auth/sso/buttons/sso-buttons.d.ts.map +1 -1
  157. package/dist/src/views/auth/sso/buttons/sso-buttons.js +5 -2
  158. package/dist/src/views/layouts/theme/header/header.d.ts +4 -1
  159. package/dist/src/views/layouts/theme/header/header.d.ts.map +1 -1
  160. package/dist/src/views/layouts/theme/header/header.js +30 -23
  161. package/dist/src/views/layouts/theme/layout.d.ts +3 -1
  162. package/dist/src/views/layouts/theme/layout.d.ts.map +1 -1
  163. package/dist/src/views/layouts/theme/layout.js +4 -3
  164. package/dist/src/vitnode.config.d.ts +11 -5
  165. package/dist/src/vitnode.config.d.ts.map +1 -1
  166. package/dist/src/vitnode.config.js +2 -1
  167. package/dist/tsconfig.tsbuildinfo +1 -1
  168. package/package.json +40 -22
  169. package/src/app_admin/core/debug/page.tsx +43 -0
  170. package/src/app_admin/core/users/page.tsx +7 -2
  171. package/src/locales/en.json +37 -1
  172. package/src/vitnode.config.ts +16 -6
  173. package/dist/src/api/lib/get-user-ip.d.ts +0 -3
  174. package/dist/src/api/lib/get-user-ip.d.ts.map +0 -1
  175. package/dist/src/api/lib/get-user-ip.js +0 -8
  176. package/dist/src/api/middlewares/global/global.d.ts.map +0 -1
  177. package/dist/src/api/middlewares/global/global.js +0 -47
  178. package/dist/src/api/plugins/email/nodemailer.d.ts.map +0 -1
  179. package/dist/src/api/plugins/email/resend.d.ts.map +0 -1
  180. package/dist/src/api/plugins/sso/discord.d.ts.map +0 -1
  181. package/dist/src/api/plugins/sso/facebook.d.ts.map +0 -1
  182. package/dist/src/api/plugins/sso/google.d.ts.map +0 -1
  183. package/dist/src/components/switchers/theme-switcher.d.ts.map +0 -1
  184. /package/dist/src/api/{plugins → adapters}/sso/discord.d.ts +0 -0
  185. /package/dist/src/api/{plugins → adapters}/sso/discord.js +0 -0
  186. /package/dist/src/api/{plugins → adapters}/sso/facebook.d.ts +0 -0
  187. /package/dist/src/api/{plugins → adapters}/sso/facebook.js +0 -0
  188. /package/dist/src/api/{plugins → adapters}/sso/google.d.ts +0 -0
  189. /package/dist/src/api/{plugins → adapters}/sso/google.js +0 -0
  190. /package/dist/src/components/switchers/{theme-switcher.d.ts → themes/theme-switcher.d.ts} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../src/api/lib/route.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAInE,OAAO,EACL,KAAK,UAAU,EAEhB,MAAM,8BAA8B,CAAC;AAEtC,KAAK,WAAW,CAAC,CAAC,SAAS,MAAM,IAC/B,CAAC,SAAS,GAAG,MAAM,IAAI,KAAK,MAAM,KAAK,IAAI,MAAM,IAAI,EAAE,GACnD,GAAG,IAAI,KAAK,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,EAAE,GACvC,CAAC,CAAC;AAER,KAAK,YAAY,CAAC,CAAC,SAAS,WAAW,IAAI,CACzC,CAAC,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,KAC1C,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;AAEjC,eAAO,MAAM,UAAU,GACrB,MAAM,SAAS,MAAM,EACrB,CAAC,SAAS,MAAM,EAChB,CAAC,SAAS,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,GAAG;IACpC,IAAI,EAAE,CAAC,CAAC;CACT,EACD,CAAC,SAAS,YAAY,CAAC,CAAC,GAAG;IAAE,IAAI,EAAE,CAAC,CAAA;CAAE,CAAC,EACvC,+BAIC;IACD,OAAO,EAAE,CAAC,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,CAAC,CAAC;CACV,KAAG;IACF,OAAO,EAAE,CAAC,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,CAAC,GAAG;QACT,cAAc,EAAE,MAAM,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;KAC9C,CAAC;CA2BH,CAAC;AAEF,MAAM,WAAW,KAAK,CACpB,MAAM,SAAS,MAAM,GAAG,MAAM,EAC9B,CAAC,SAAS,WAAW,GAAG,WAAW,EACnC,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC;IAE3C,OAAO,EAAE,CAAC,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,CAAC,CAAC;CACV"}
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../src/api/lib/route.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAInE,OAAO,EACL,KAAK,UAAU,EAEhB,MAAM,kCAAkC,CAAC;AAE1C,KAAK,WAAW,CAAC,CAAC,SAAS,MAAM,IAC/B,CAAC,SAAS,GAAG,MAAM,IAAI,KAAK,MAAM,KAAK,IAAI,MAAM,IAAI,EAAE,GACnD,GAAG,IAAI,KAAK,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,EAAE,GACvC,CAAC,CAAC;AAER,KAAK,YAAY,CAAC,CAAC,SAAS,WAAW,IAAI,CACzC,CAAC,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,KAC1C,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;AAEjC,eAAO,MAAM,UAAU,GACrB,MAAM,SAAS,MAAM,EACrB,CAAC,SAAS,MAAM,EAChB,CAAC,SAAS,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,GAAG;IACpC,IAAI,EAAE,CAAC,CAAC;CACT,EACD,CAAC,SAAS,YAAY,CAAC,CAAC,GAAG;IAAE,IAAI,EAAE,CAAC,CAAA;CAAE,CAAC,EACvC,+BAIC;IACD,OAAO,EAAE,CAAC,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,CAAC,CAAC;CACV,KAAG;IACF,OAAO,EAAE,CAAC,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,CAAC,GAAG;QACT,cAAc,EAAE,MAAM,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;KAC9C,CAAC;CA2BH,CAAC;AAEF,MAAM,WAAW,KAAK,CACpB,MAAM,SAAS,MAAM,GAAG,MAAM,EAC9B,CAAC,SAAS,WAAW,GAAG,WAAW,EACnC,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC;IAE3C,OAAO,EAAE,CAAC,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,CAAC,CAAC;CACV"}
@@ -1,5 +1,5 @@
1
1
  import { createRoute as createRouteHono } from "@hono/zod-openapi";
2
- import { pluginMiddleware } from "../middlewares/global/global.js";
2
+ import { pluginMiddleware } from "../middlewares/global.middleware.js";
3
3
  export const buildRoute = ({ route, handler, pluginId })=>{
4
4
  const pluginTag = pluginId.split(/[-_]/).map((word)=>word.charAt(0).toUpperCase() + word.slice(1)).join(' ');
5
5
  const tags = [
@@ -1,7 +1,8 @@
1
1
  import type { Context, Env, Next } from 'hono';
2
- import type { EmailApiPlugin } from '../../../api/models/email';
3
- import type { VitNodeApiConfig, VitNodeConfig } from '../../../vitnode.config';
4
- import type { SSOApiPlugin } from '../../models/sso';
2
+ import type { EmailApiPlugin } from '../../api/models/email';
3
+ import type { VitNodeApiConfig, VitNodeConfig } from '../../vitnode.config';
4
+ import type { SSOApiPlugin } from '../models/sso';
5
+ import { type LoggerMiddlewareType } from '../lib/logger-middleware';
5
6
  export interface EnvVitNode extends Env {
6
7
  Variables: EnvVariablesVitNode;
7
8
  }
@@ -29,16 +30,17 @@ interface EnvVariablesVitNode {
29
30
  cookieSecure: boolean;
30
31
  deviceCookieExpires: number;
31
32
  deviceCookieName: string;
32
- ssoPlugins: SSOApiPlugin[];
33
+ ssoProviders: SSOApiPlugin[];
33
34
  };
34
- emailProvider?: EmailApiPlugin;
35
+ emailAdapter?: EmailApiPlugin;
35
36
  metadata: {
36
37
  shortTitle?: string;
37
38
  title: string;
38
39
  };
39
40
  };
40
41
  db: Pick<VitNodeApiConfig, 'dbProvider'>['dbProvider'];
41
- deviceId: number;
42
+ ipAddress: string;
43
+ log: LoggerMiddlewareType;
42
44
  plugin: {
43
45
  id: string;
44
46
  };
@@ -59,8 +61,8 @@ declare module 'hono' {
59
61
  interface ContextVariableMap extends EnvVariablesVitNode {
60
62
  }
61
63
  }
62
- export declare const globalMiddleware: ({ authorization, metadata, emailProvider, dbProvider, }: Pick<VitNodeApiConfig, "authorization" | "dbProvider" | "emailProvider"> & Pick<VitNodeConfig, "metadata">) => (c: Context, next: Next) => Promise<void>;
64
+ export declare const globalMiddleware: ({ authorization, metadata, emailAdapter, dbProvider, }: Pick<VitNodeApiConfig, "authorization" | "dbProvider" | "emailAdapter"> & Pick<VitNodeConfig, "metadata">) => (c: Context, next: Next) => Promise<void>;
63
65
  export declare const pluginMiddleware: (pluginId: string) => (c: Context, next: Next) => Promise<void>;
64
66
  export declare const globalAdminMiddleware: () => (c: Context, next: Next) => Promise<void>;
65
67
  export {};
66
- //# sourceMappingURL=global.d.ts.map
68
+ //# sourceMappingURL=global.middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"global.middleware.d.ts","sourceRoot":"","sources":["../../../../src/api/middlewares/global.middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAI/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAKxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,0BAA0B,CAAC;AAElC,MAAM,WAAW,UAAW,SAAQ,GAAG;IACrC,SAAS,EAAE,mBAAmB,CAAC;CAChC;AAED,UAAU,mBAAmB;IAC3B,KAAK,EAAE,IAAI,GAAG;QACZ,IAAI,EAAE;YACJ,WAAW,EAAE,MAAM,CAAC;YACpB,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAC;YACtB,SAAS,EAAE,IAAI,CAAC;YAChB,KAAK,EAAE,MAAM,CAAC;YACd,aAAa,EAAE,OAAO,CAAC;YACvB,EAAE,EAAE,MAAM,CAAC;YACX,IAAI,EAAE,MAAM,CAAC;YACb,QAAQ,EAAE,MAAM,CAAC;YACjB,UAAU,EAAE,OAAO,CAAC;YACpB,MAAM,EAAE,MAAM,CAAC;SAChB,CAAC;KACH,CAAC;IACF,IAAI,EAAE;QACJ,aAAa,EAAE;YACb,kBAAkB,EAAE,MAAM,CAAC;YAC3B,eAAe,EAAE,MAAM,CAAC;YACxB,cAAc,EAAE,MAAM,CAAC;YACvB,UAAU,EAAE,MAAM,CAAC;YACnB,YAAY,EAAE,OAAO,CAAC;YACtB,mBAAmB,EAAE,MAAM,CAAC;YAC5B,gBAAgB,EAAE,MAAM,CAAC;YACzB,YAAY,EAAE,YAAY,EAAE,CAAC;SAC9B,CAAC;QACF,YAAY,CAAC,EAAE,cAAc,CAAC;QAC9B,QAAQ,EAAE;YACR,UAAU,CAAC,EAAE,MAAM,CAAC;YACpB,KAAK,EAAE,MAAM,CAAC;SACf,CAAC;KACH,CAAC;IACF,EAAE,EAAE,IAAI,CAAC,gBAAgB,EAAE,YAAY,CAAC,CAAC,YAAY,CAAC,CAAC;IACvD,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,oBAAoB,CAAC;IAC1B,MAAM,EAAE;QACN,EAAE,EAAE,MAAM,CAAC;KACZ,CAAC;IACF,IAAI,EAAE,IAAI,GAAG;QACX,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAC;QACtB,SAAS,EAAE,IAAI,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,aAAa,EAAE,OAAO,CAAC;QACvB,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,OAAO,CAAC;QACpB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED,OAAO,QAAQ,MAAM,CAAC;IAEpB,UAAU,kBAAmB,SAAQ,mBAAmB;KAAG;CAC5D;AAED,eAAO,MAAM,gBAAgB,GAAI,wDAK9B,IAAI,CAAC,gBAAgB,EAAE,eAAe,GAAG,YAAY,GAAG,cAAc,CAAC,GACxE,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,MACjB,GAAG,OAAO,EAAE,MAAM,IAAI,kBAwErC,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,UAAU,MAAM,MACjC,GAAG,OAAO,EAAE,MAAM,IAAI,kBAMrC,CAAC;AAEF,eAAO,MAAM,qBAAqB,SAClB,GAAG,OAAO,EAAE,MAAM,IAAI,kBASrC,CAAC"}
@@ -0,0 +1,86 @@
1
+ import { HTTPException } from "hono/http-exception";
2
+ import { SessionModel } from "../models/session.js";
3
+ import { SessionAdminModel } from "../models/session-admin.js";
4
+ import { loggerMiddleware } from "../lib/logger-middleware.js";
5
+ export const globalMiddleware = ({ authorization, metadata, emailAdapter, dbProvider })=>{
6
+ return async (c, next)=>{
7
+ // Collect possible IP header keys in order of trust/preference
8
+ const ipHeaderKeys = [
9
+ 'x-forwarded-for',
10
+ 'x-real-ip',
11
+ 'cf-connecting-ip',
12
+ 'x-client-ip',
13
+ 'x-forwarded',
14
+ 'x-cluster-client-ip',
15
+ 'forwarded-for',
16
+ 'forwarded',
17
+ 'via',
18
+ 'remote-addr',
19
+ 'client-ip',
20
+ 'ip',
21
+ 'x-ip',
22
+ 'true-client-ip',
23
+ 'fastly-client-ip',
24
+ 'x-fastly-client-ip'
25
+ ];
26
+ let ipAddress;
27
+ // Try to get IP from Hono's request header method first
28
+ for (const key of ipHeaderKeys){
29
+ const value = c.req.header(key);
30
+ if (value) {
31
+ ipAddress = value;
32
+ break;
33
+ }
34
+ }
35
+ // If not found, try raw headers (for edge runtimes, etc.)
36
+ if (!ipAddress) {
37
+ for (const key of ipHeaderKeys){
38
+ const value = c.req.raw.headers.get(key);
39
+ if (value) {
40
+ ipAddress = value;
41
+ break;
42
+ }
43
+ }
44
+ }
45
+ // Fallback to localhost if nothing found
46
+ c.set('ipAddress', ipAddress ?? '127.0.0.1');
47
+ c.set('db', dbProvider);
48
+ c.set('core', {
49
+ metadata,
50
+ emailAdapter,
51
+ authorization: {
52
+ cookieName: authorization?.cookieName ?? 'vitnode_auth',
53
+ cookie_expires: authorization?.cookieExpires ?? 1000 * 60 * 60 * 24 * 90,
54
+ ssoProviders: authorization?.ssoProviders ?? [],
55
+ deviceCookieName: authorization?.deviceCookieName ?? 'vitnode_device',
56
+ deviceCookieExpires: authorization?.deviceCookieExpires ?? 1000 * 60 * 60 * 24 * 365,
57
+ adminCookieName: authorization?.adminCookieName ?? 'vitnode_auth_admin',
58
+ adminCookieExpires: authorization?.adminCookieExpires ?? 1000 * 60 * 60 * 24 * 1,
59
+ cookieSecure: authorization?.cookieSecure ?? true
60
+ }
61
+ });
62
+ const user = await new SessionModel(c).getUser();
63
+ c.set('user', user);
64
+ c.set('admin', null);
65
+ c.set('log', loggerMiddleware(c));
66
+ await next();
67
+ };
68
+ };
69
+ export const pluginMiddleware = (pluginId)=>{
70
+ return async (c, next)=>{
71
+ c.set('plugin', {
72
+ id: pluginId
73
+ });
74
+ await next();
75
+ };
76
+ };
77
+ export const globalAdminMiddleware = ()=>{
78
+ return async (c, next)=>{
79
+ const user = await new SessionAdminModel(c).getUser();
80
+ if (!user) throw new HTTPException(403);
81
+ c.set('admin', {
82
+ user
83
+ });
84
+ await next();
85
+ };
86
+ };
@@ -0,0 +1,4 @@
1
+ import type { Context, Next } from 'hono';
2
+ import { type IRateLimiterOptions } from 'rate-limiter-flexible';
3
+ export declare const rateLimiterMiddleware: (options?: Omit<IRateLimiterOptions, "keyPrefix">) => (c: Context, next: Next) => Promise<(Response & import("hono").TypedResponse<"Too Many Requests", 429, "text">) | undefined>;
4
+ //# sourceMappingURL=rate-limiter.middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limiter.middleware.d.ts","sourceRoot":"","sources":["../../../../src/api/middlewares/rate-limiter.middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE1C,OAAO,EACL,KAAK,mBAAmB,EAGzB,MAAM,uBAAuB,CAAC;AAoB/B,eAAO,MAAM,qBAAqB,GAChC,UAAU,IAAI,CAAC,mBAAmB,EAAE,WAAW,CAAC,MAOlC,GAAG,OAAO,EAAE,MAAM,IAAI,qGAWrC,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { RateLimiterMemory } from "rate-limiter-flexible";
2
+ import { CONFIG } from "../../lib/config.js";
3
+ const createRateLimiter = ({ keyPrefix, ...options })=>{
4
+ // TODO: Add support for Redis or other storage options
5
+ return new RateLimiterMemory({
6
+ keyPrefix,
7
+ points: CONFIG.node_development ? 120 : options?.points ?? 80,
8
+ duration: options?.duration ?? 60,
9
+ ...options
10
+ });
11
+ };
12
+ export const rateLimiterMiddleware = (options)=>{
13
+ const rateLimiter = createRateLimiter({
14
+ ...options,
15
+ keyPrefix: 'vitnode-api-rate-limiter'
16
+ });
17
+ return async (c, next)=>{
18
+ const key = c.get('ipAddress');
19
+ try {
20
+ await rateLimiter.consume(key);
21
+ await next();
22
+ } catch {
23
+ return c.text('Too Many Requests', 429);
24
+ }
25
+ };
26
+ };
@@ -5,6 +5,9 @@ export declare class DeviceModel {
5
5
  private createDevice;
6
6
  private getUserAgent;
7
7
  private setCookieDevice;
8
- getDeviceId(): Promise<number>;
8
+ getDeviceId(): Promise<{
9
+ id: number;
10
+ publicId: string;
11
+ }>;
9
12
  }
10
13
  //# sourceMappingURL=device.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../../../../src/api/models/device.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAUpC,qBAAa,WAAW;gBACV,CAAC,EAAE,OAAO;IAGtB,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC;YAEhB,YAAY;IAe1B,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,eAAe;IAiBjB,WAAW;CAoClB"}
1
+ {"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../../../../src/api/models/device.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AASpC,qBAAa,WAAW;gBACV,CAAC,EAAE,OAAO;IAGtB,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC;YAEhB,YAAY;IAkB1B,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,eAAe;IAiBjB,WAAW;;;;CAwClB"}
@@ -1,28 +1,33 @@
1
+ import { randomBytes } from "crypto";
1
2
  import { eq } from "drizzle-orm";
2
3
  import { getCookie, setCookie } from "hono/cookie";
3
4
  import { core_sessions_known_devices } from "../../database/sessions.js";
4
5
  import { CONFIG } from "../../lib/config.js";
5
- import { getUserIp } from "../lib/get-user-ip.js";
6
6
  export class DeviceModel {
7
7
  constructor(c){
8
8
  this.c = c;
9
9
  }
10
10
  c;
11
11
  async createDevice() {
12
+ const publicId = randomBytes(16).toString('hex');
12
13
  const [device] = await this.c.get('db').insert(core_sessions_known_devices).values({
13
- ipAddress: getUserIp(this.c),
14
+ publicId,
15
+ ipAddress: this.c.get('ipAddress'),
14
16
  userAgent: this.getUserAgent()
15
17
  }).returning({
16
18
  id: core_sessions_known_devices.id
17
19
  });
18
- this.setCookieDevice(device.id);
19
- return device.id;
20
+ this.setCookieDevice(publicId);
21
+ return {
22
+ id: device.id,
23
+ publicId
24
+ };
20
25
  }
21
26
  getUserAgent() {
22
27
  return this.c.req.header('User-Agent') ?? 'node';
23
28
  }
24
- setCookieDevice(deviceId) {
25
- setCookie(this.c, this.c.get('core').authorization.deviceCookieName, deviceId.toString(), {
29
+ setCookieDevice(publicDeviceId) {
30
+ setCookie(this.c, this.c.get('core').authorization.deviceCookieName, publicDeviceId, {
26
31
  httpOnly: true,
27
32
  secure: this.c.get('core').authorization.cookieSecure,
28
33
  path: '/',
@@ -31,24 +36,26 @@ export class DeviceModel {
31
36
  });
32
37
  }
33
38
  async getDeviceId() {
34
- const deviceIdFromCookie = Number(getCookie(this.c, this.c.get('core').authorization.deviceCookieName));
39
+ const deviceIdFromCookie = getCookie(this.c, this.c.get('core').authorization.deviceCookieName);
35
40
  try {
36
41
  if (deviceIdFromCookie) {
37
42
  const [device] = await this.c.get('db').select({
38
43
  id: core_sessions_known_devices.id
39
- }).from(core_sessions_known_devices).where(eq(core_sessions_known_devices.id, deviceIdFromCookie));
44
+ }).from(core_sessions_known_devices).where(eq(core_sessions_known_devices.publicId, deviceIdFromCookie));
40
45
  if (!device) {
41
46
  return await this.createDevice();
42
47
  }
43
48
  await this.c.get('db').update(core_sessions_known_devices).set({
44
- ipAddress: getUserIp(this.c),
49
+ ipAddress: this.c.get('ipAddress'),
45
50
  userAgent: this.getUserAgent()
46
- }).where(eq(core_sessions_known_devices.id, deviceIdFromCookie));
47
- return device.id;
51
+ }).where(eq(core_sessions_known_devices.publicId, deviceIdFromCookie));
52
+ return {
53
+ id: device.id,
54
+ publicId: deviceIdFromCookie
55
+ };
48
56
  }
49
- } catch (_) {
50
- return await this.createDevice();
51
- }
57
+ } catch {
58
+ /* empty */ }
52
59
  return await this.createDevice();
53
60
  }
54
61
  }
@@ -11,12 +11,11 @@ export interface EmailApiPlugin {
11
11
  export declare class EmailModel {
12
12
  constructor(c: Context);
13
13
  protected readonly c: Context;
14
- isAvailable(): boolean;
15
14
  send(args: {
16
15
  html: string;
17
16
  replyTo?: string;
18
17
  subject: string;
19
18
  to: string;
20
- }): Promise<void>;
19
+ }): void;
21
20
  }
22
21
  //# sourceMappingURL=email.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"email.d.ts","sourceRoot":"","sources":["../../../../src/api/models/email.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,MAAM,CAAC;AAIxD,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,CAAC,IAAI,EAAE;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,kBAAkB,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;QACjD,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,EAAE,EAAE,MAAM,CAAC;KACZ,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACrB;AAED,qBAAa,UAAU;gBACT,CAAC,EAAE,OAAO;IAItB,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC;IAE9B,WAAW;IAIL,IAAI,CAAC,IAAI,EAAE;QACf,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,EAAE,EAAE,MAAM,CAAC;KACZ;CAqBF"}
1
+ {"version":3,"file":"email.d.ts","sourceRoot":"","sources":["../../../../src/api/models/email.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,MAAM,CAAC;AAIxD,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,CAAC,IAAI,EAAE;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,kBAAkB,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;QACjD,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,EAAE,EAAE,MAAM,CAAC;KACZ,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACrB;AAED,qBAAa,UAAU;gBACT,CAAC,EAAE,OAAO;IAItB,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC;IAE9B,IAAI,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE;CAuB3E"}
@@ -4,27 +4,20 @@ export class EmailModel {
4
4
  this.c = c;
5
5
  }
6
6
  c;
7
- isAvailable() {
8
- return !!this.c.get('core').emailProvider;
9
- }
10
- async send(args) {
7
+ send(args) {
11
8
  const core = this.c.get('core');
12
- const provider = core.emailProvider;
9
+ const provider = core.emailAdapter;
13
10
  if (!provider) {
14
11
  throw new HTTPException(500, {
15
12
  message: 'Email provider not found'
16
13
  });
17
14
  }
18
- try {
19
- await provider.sendEmail({
20
- ...args,
21
- metadata: core.metadata
22
- });
23
- } catch (e) {
24
- const error = e;
25
- throw new HTTPException(500, {
26
- message: error.message
27
- });
28
- }
15
+ void provider.sendEmail({
16
+ ...args,
17
+ metadata: core.metadata
18
+ }).catch((err)=>{
19
+ const error = err instanceof Error ? err : new Error('Unknown error from email provider');
20
+ this.c.get('log').error(`Failed to send email: ${error.message}`);
21
+ });
29
22
  }
30
23
  }
@@ -1 +1 @@
1
- {"version":3,"file":"password.d.ts","sourceRoot":"","sources":["../../../../src/api/models/password.ts"],"names":[],"mappings":"AAEA,qBAAa,aAAa;IAClB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAYlD,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CASvE"}
1
+ {"version":3,"file":"password.d.ts","sourceRoot":"","sources":["../../../../src/api/models/password.ts"],"names":[],"mappings":"AAEA,qBAAa,aAAa;IAClB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAYlD,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAkBvE"}
@@ -12,9 +12,16 @@ export class PasswordModel {
12
12
  async verifyPassword(password, hash) {
13
13
  return new Promise((resolve, reject)=>{
14
14
  const [salt, key] = hash.split(':');
15
+ const keyBuffer = Buffer.from(key, 'hex');
15
16
  crypto.scrypt(password, salt, 64, (err, derivedKey)=>{
16
17
  if (err) reject(err);
17
- resolve(key == derivedKey.toString('hex'));
18
+ if (keyBuffer.length !== derivedKey.length) {
19
+ crypto.timingSafeEqual(derivedKey, derivedKey);
20
+ resolve(false);
21
+ } else {
22
+ const areEqual = crypto.timingSafeEqual(keyBuffer, derivedKey);
23
+ resolve(areEqual);
24
+ }
18
25
  });
19
26
  });
20
27
  }
@@ -2,10 +2,10 @@ import type { Context } from 'hono';
2
2
  export declare class SessionAdminModel {
3
3
  constructor(c: Context);
4
4
  protected readonly c: Context;
5
+ private hashToken;
5
6
  checkIfUserIsAdmin(userId: number): Promise<boolean>;
6
7
  createSessionByUserId(userId: number): Promise<{
7
8
  token: string;
8
- deviceId: number;
9
9
  }>;
10
10
  deleteSession(): Promise<void>;
11
11
  getUser(): Promise<{
@@ -1 +1 @@
1
- {"version":3,"file":"session-admin.d.ts","sourceRoot":"","sources":["../../../../src/api/models/session-admin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAWpC,qBAAa,iBAAiB;gBAChB,CAAC,EAAE,OAAO;IAGtB,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC;IAExB,kBAAkB,CAAC,MAAM,EAAE,MAAM;IAmBjC,qBAAqB,CAAC,MAAM,EAAE,MAAM;;;;IAsCpC,aAAa;IAgBb,OAAO;;;;;;;;;;;;CAgCd"}
1
+ {"version":3,"file":"session-admin.d.ts","sourceRoot":"","sources":["../../../../src/api/models/session-admin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAYpC,qBAAa,iBAAiB;gBAChB,CAAC,EAAE,OAAO;IAGtB,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC;YAEhB,SAAS;IASjB,kBAAkB,CAAC,MAAM,EAAE,MAAM;IAmBjC,qBAAqB,CAAC,MAAM,EAAE,MAAM;;;IAwCpC,aAAa;IAoBb,OAAO;;;;;;;;;;;;CAiDd"}
@@ -1,14 +1,22 @@
1
- import { and, eq, gt, or } from "drizzle-orm";
1
+ import { and, eq, gt, or } from "drizzle-orm"; // Removed 'or' as it's safer not to use it here
2
2
  import { deleteCookie, getCookie, setCookie } from "hono/cookie";
3
3
  import { HTTPException } from "hono/http-exception";
4
4
  import { core_admin_permissions, core_admin_sessions } from "../../database/admins.js";
5
5
  import { CONFIG } from "../../lib/config.js";
6
+ import { DeviceModel } from "./device.js";
6
7
  import { UserModel } from "./user.js";
7
8
  export class SessionAdminModel {
8
9
  constructor(c){
9
10
  this.c = c;
10
11
  }
11
12
  c;
13
+ async hashToken(token) {
14
+ const encoder = new TextEncoder();
15
+ const data = encoder.encode(token);
16
+ const hashBuffer = await crypto.subtle.digest('SHA-256', data);
17
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
18
+ return hashArray.map((b)=>b.toString(16).padStart(2, '0')).join('');
19
+ }
12
20
  async checkIfUserIsAdmin(userId) {
13
21
  const user = await new UserModel().getUserById({
14
22
  id: userId,
@@ -20,54 +28,70 @@ export class SessionAdminModel {
20
28
  }
21
29
  async createSessionByUserId(userId) {
22
30
  const isAdmin = await this.checkIfUserIsAdmin(userId);
23
- if (!isAdmin) throw new HTTPException(403);
24
- // Generate secure random bytes using Web Crypto API
31
+ if (!isAdmin) {
32
+ throw new HTTPException(403, {
33
+ message: 'Forbidden'
34
+ });
35
+ }
25
36
  const randomBytes = new Uint8Array(64);
26
37
  crypto.getRandomValues(randomBytes);
27
38
  const token = Array.from(randomBytes).map((b)=>b.toString(16).padStart(2, '0')).join('');
28
- const deviceId = this.c.get('deviceId');
39
+ const hashedToken = await this.hashToken(token);
40
+ const device = await new DeviceModel(this.c).getDeviceId();
29
41
  await this.c.get('db').insert(core_admin_sessions).values({
30
- token,
42
+ token: hashedToken,
31
43
  userId,
32
44
  expiresAt: new Date(Date.now() + this.c.get('core').authorization.adminCookieExpires),
33
- deviceId
45
+ deviceId: device.id
34
46
  });
35
47
  setCookie(this.c, this.c.get('core').authorization.adminCookieName, token, {
36
48
  httpOnly: true,
37
49
  secure: this.c.get('core').authorization.cookieSecure,
38
- path: '/admin',
50
+ path: '/',
39
51
  expires: new Date(Date.now() + this.c.get('core').authorization.adminCookieExpires),
40
52
  domain: CONFIG.frontend.hostname
41
53
  });
42
54
  return {
43
- token,
44
- deviceId
55
+ token
45
56
  };
46
57
  }
47
58
  async deleteSession() {
48
59
  const token = getCookie(this.c, this.c.get('core').authorization.adminCookieName);
49
60
  if (!token) return;
50
- await this.c.get('db').delete(core_admin_sessions).where(eq(core_admin_sessions.token, token));
61
+ const hashedToken = await this.hashToken(token);
62
+ await this.c.get('db').delete(core_admin_sessions).where(eq(core_admin_sessions.token, hashedToken));
51
63
  deleteCookie(this.c, this.c.get('core').authorization.adminCookieName, {
52
- path: '/admin'
64
+ path: '/',
65
+ domain: CONFIG.frontend.hostname
53
66
  });
54
67
  }
55
68
  async getUser() {
56
69
  const { authorization } = this.c.get('core');
57
70
  const token = getCookie(this.c, authorization.adminCookieName);
58
71
  if (!token) return null;
59
- const deviceId = this.c.get('deviceId');
60
- if (!deviceId) return null;
72
+ const device = await new DeviceModel(this.c).getDeviceId();
73
+ if (!device) return null;
74
+ const hashedToken = await this.hashToken(token);
61
75
  const [session] = await this.c.get('db').select({
62
- token: core_admin_sessions.token,
63
76
  userId: core_admin_sessions.userId
64
- }).from(core_admin_sessions).where(and(eq(core_admin_sessions.token, token), eq(core_admin_sessions.deviceId, deviceId), gt(core_admin_sessions.expiresAt, new Date()))).limit(1);
65
- if (!session) return null;
77
+ }).from(core_admin_sessions).where(and(eq(core_admin_sessions.token, hashedToken), eq(core_admin_sessions.deviceId, device.id), gt(core_admin_sessions.expiresAt, new Date()))).limit(1);
78
+ if (!session) {
79
+ deleteCookie(this.c, this.c.get('core').authorization.adminCookieName, {
80
+ path: '/',
81
+ domain: CONFIG.frontend.hostname
82
+ });
83
+ return null;
84
+ }
66
85
  const user = await new UserModel().getUserById({
67
86
  id: session.userId,
68
87
  c: this.c
69
88
  });
70
89
  if (!user) return null;
90
+ const isStillAdmin = await this.checkIfUserIsAdmin(user.id);
91
+ if (!isStillAdmin) {
92
+ await this.deleteSession();
93
+ return null;
94
+ }
71
95
  return user;
72
96
  }
73
97
  }
@@ -2,9 +2,9 @@ import type { Context } from 'hono';
2
2
  export declare class SessionModel {
3
3
  constructor(c: Context);
4
4
  protected readonly c: Context;
5
+ private hashToken;
5
6
  createSessionByUserId(userId: number): Promise<{
6
7
  token: string;
7
- deviceId: number;
8
8
  }>;
9
9
  deleteSession(): Promise<void>;
10
10
  getUser(): Promise<{
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../../src/api/models/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAUpC,qBAAa,YAAY;gBACX,CAAC,EAAE,OAAO;IAGtB,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC;IAExB,qBAAqB,CAAC,MAAM,EAAE,MAAM;;;;IAqCpC,aAAa;IAcb,OAAO;;;;;;;;;;;;CAoCd"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../../src/api/models/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAWpC,qBAAa,YAAY;gBACX,CAAC,EAAE,OAAO;IAGtB,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC;YAEhB,SAAS;IASjB,qBAAqB,CAAC,MAAM,EAAE,MAAM;;;IAsCpC,aAAa;IA8Bb,OAAO;;;;;;;;;;;;CA0Cd"}
@@ -2,23 +2,32 @@ import { and, eq, gt } from "drizzle-orm";
2
2
  import { deleteCookie, getCookie, setCookie } from "hono/cookie";
3
3
  import { core_sessions } from "../../database/sessions.js";
4
4
  import { CONFIG } from "../../lib/config.js";
5
+ import { DeviceModel } from "./device.js";
5
6
  import { UserModel } from "./user.js";
6
7
  export class SessionModel {
7
8
  constructor(c){
8
9
  this.c = c;
9
10
  }
10
11
  c;
12
+ async hashToken(token) {
13
+ const encoder = new TextEncoder();
14
+ const data = encoder.encode(token);
15
+ const hashBuffer = await crypto.subtle.digest('SHA-256', data);
16
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
17
+ return hashArray.map((b)=>b.toString(16).padStart(2, '0')).join('');
18
+ }
11
19
  async createSessionByUserId(userId) {
12
20
  // Generate secure random bytes using Web Crypto API
13
21
  const randomBytes = new Uint8Array(64);
14
22
  crypto.getRandomValues(randomBytes);
15
23
  const token = Array.from(randomBytes).map((b)=>b.toString(16).padStart(2, '0')).join('');
16
- const deviceId = this.c.get('deviceId');
24
+ const device = await new DeviceModel(this.c).getDeviceId();
25
+ const hashedToken = await this.hashToken(token);
17
26
  await this.c.get('db').insert(core_sessions).values({
18
- token,
27
+ token: hashedToken,
19
28
  userId,
20
29
  expiresAt: new Date(Date.now() + this.c.get('core').authorization.cookie_expires),
21
- deviceId
30
+ deviceId: device.id
22
31
  });
23
32
  setCookie(this.c, this.c.get('core').authorization.cookieName, token, {
24
33
  httpOnly: true,
@@ -28,26 +37,33 @@ export class SessionModel {
28
37
  domain: CONFIG.frontend.hostname
29
38
  });
30
39
  return {
31
- token,
32
- deviceId
40
+ token
33
41
  };
34
42
  }
35
43
  async deleteSession() {
36
44
  const token = getCookie(this.c, this.c.get('core').authorization.cookieName);
37
- if (!token) return;
38
- await this.c.get('db').delete(core_sessions).where(eq(core_sessions.token, token));
45
+ const device = await new DeviceModel(this.c).getDeviceId();
46
+ // Ensure both token and deviceId exist before proceeding
47
+ if (!token || !device.id) {
48
+ deleteCookie(this.c, this.c.get('core').authorization.cookieName);
49
+ return;
50
+ }
51
+ const hashedToken = await this.hashToken(token);
52
+ await this.c.get('db').delete(core_sessions)// Harden the query to ensure a user can only delete their own device's session
53
+ .where(and(eq(core_sessions.token, hashedToken), eq(core_sessions.deviceId, device.id)));
39
54
  deleteCookie(this.c, this.c.get('core').authorization.cookieName);
40
55
  }
41
56
  async getUser() {
42
57
  const token = getCookie(this.c, this.c.get('core').authorization.cookieName);
43
58
  if (!token) return null;
44
- const deviceId = this.c.get('deviceId');
45
- if (!deviceId) return null;
59
+ const device = await new DeviceModel(this.c).getDeviceId();
60
+ if (!device) return null;
61
+ const hashedToken = await this.hashToken(token);
46
62
  const [session] = await this.c.get('db').select({
47
- token: core_sessions.token,
48
63
  userId: core_sessions.userId
49
- }).from(core_sessions).where(and(eq(core_sessions.token, token), eq(core_sessions.deviceId, deviceId), gt(core_sessions.expiresAt, new Date()))).limit(1);
50
- if (!session || session.token !== token) {
64
+ }).from(core_sessions).where(and(eq(core_sessions.token, hashedToken), eq(core_sessions.deviceId, device.id), gt(core_sessions.expiresAt, new Date()))).limit(1);
65
+ if (!session) {
66
+ deleteCookie(this.c, this.c.get('core').authorization.cookieName);
51
67
  return null;
52
68
  }
53
69
  const user = await new UserModel().getUserById({
@@ -10,7 +10,7 @@ export const getRedirectUri = (code)=>new URL(`${CONFIG.frontend.href}login/sso/
10
10
  export class SSOModel {
11
11
  constructor(c){
12
12
  this.c = c;
13
- this.plugins = c.get('core').authorization.ssoPlugins;
13
+ this.plugins = c.get('core').authorization.ssoProviders;
14
14
  }
15
15
  c;
16
16
  plugins;
@@ -5,6 +5,7 @@ export declare const signUp: ({ email, name, newsletter, hashedPassword, }: {
5
5
  name: string;
6
6
  newsletter?: boolean;
7
7
  }, c: Context) => Promise<{
8
+ ipAddress: string;
8
9
  id: number;
9
10
  name: string;
10
11
  createdAt: Date;
@@ -16,6 +17,5 @@ export declare const signUp: ({ email, name, newsletter, hashedPassword, }: {
16
17
  emailVerified: boolean;
17
18
  roleId: number;
18
19
  birthday: Date | null;
19
- ipAddress: string;
20
20
  }>;
21
21
  //# sourceMappingURL=sign-up.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sign-up.d.ts","sourceRoot":"","sources":["../../../../../src/api/models/user/sign-up.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAkEpC,eAAO,MAAM,MAAM,GACjB,8CAKG;IACD,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,EACD,GAAG,OAAO;;;;;;;;;;;;;EAwDX,CAAC"}
1
+ {"version":3,"file":"sign-up.d.ts","sourceRoot":"","sources":["../../../../../src/api/models/user/sign-up.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAiEpC,eAAO,MAAM,MAAM,GACjB,8CAKG;IACD,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,EACD,GAAG,OAAO;;;;;;;;;;;;;EAwDX,CAAC"}