@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.
- package/dist/scripts/plugin.d.ts.map +1 -1
- package/dist/scripts/scripts.js +2 -9
- package/dist/scripts/shared/file-utils.d.ts.map +1 -1
- package/dist/src/api/{plugins → adapters}/email/nodemailer.d.ts +1 -1
- package/dist/src/api/adapters/email/nodemailer.d.ts.map +1 -0
- package/dist/src/api/{plugins → adapters}/email/nodemailer.js +1 -1
- package/dist/src/api/{plugins → adapters}/email/resend.d.ts +1 -1
- package/dist/src/api/adapters/email/resend.d.ts.map +1 -0
- package/dist/src/api/{plugins → adapters}/email/resend.js +1 -1
- package/dist/src/api/adapters/sso/discord.d.ts.map +1 -0
- package/dist/src/api/adapters/sso/facebook.d.ts.map +1 -0
- package/dist/src/api/adapters/sso/google.d.ts.map +1 -0
- package/dist/src/api/config.d.ts.map +1 -1
- package/dist/src/api/config.js +6 -5
- package/dist/src/api/lib/logger-middleware.d.ts +8 -0
- package/dist/src/api/lib/logger-middleware.d.ts.map +1 -0
- package/dist/src/api/lib/logger-middleware.js +30 -0
- package/dist/src/api/lib/route.d.ts +1 -1
- package/dist/src/api/lib/route.d.ts.map +1 -1
- package/dist/src/api/lib/route.js +1 -1
- package/dist/src/api/middlewares/{global/global.d.ts → global.middleware.d.ts} +10 -8
- package/dist/src/api/middlewares/global.middleware.d.ts.map +1 -0
- package/dist/src/api/middlewares/global.middleware.js +86 -0
- package/dist/src/api/middlewares/rate-limiter.middleware.d.ts +4 -0
- package/dist/src/api/middlewares/rate-limiter.middleware.d.ts.map +1 -0
- package/dist/src/api/middlewares/rate-limiter.middleware.js +26 -0
- package/dist/src/api/models/device.d.ts +4 -1
- package/dist/src/api/models/device.d.ts.map +1 -1
- package/dist/src/api/models/device.js +21 -14
- package/dist/src/api/models/email.d.ts +1 -2
- package/dist/src/api/models/email.d.ts.map +1 -1
- package/dist/src/api/models/email.js +9 -16
- package/dist/src/api/models/password.d.ts.map +1 -1
- package/dist/src/api/models/password.js +8 -1
- package/dist/src/api/models/session-admin.d.ts +1 -1
- package/dist/src/api/models/session-admin.d.ts.map +1 -1
- package/dist/src/api/models/session-admin.js +40 -16
- package/dist/src/api/models/session.d.ts +1 -1
- package/dist/src/api/models/session.d.ts.map +1 -1
- package/dist/src/api/models/session.js +28 -12
- package/dist/src/api/models/sso.js +1 -1
- package/dist/src/api/models/user/sign-up.d.ts +1 -1
- package/dist/src/api/models/user/sign-up.d.ts.map +1 -1
- package/dist/src/api/models/user/sign-up.js +2 -3
- package/dist/src/api/models/user.d.ts +1 -1
- package/dist/src/api/models/user.d.ts.map +1 -1
- package/dist/src/api/modules/admin/admin.module.d.ts +161 -8
- package/dist/src/api/modules/admin/admin.module.d.ts.map +1 -1
- package/dist/src/api/modules/admin/admin.module.js +3 -1
- package/dist/src/api/modules/admin/debug/debug.admin.module.d.ts +159 -0
- package/dist/src/api/modules/admin/debug/debug.admin.module.d.ts.map +1 -0
- package/dist/src/api/modules/admin/debug/debug.admin.module.js +10 -0
- package/dist/src/api/modules/admin/debug/routes/logs.route.d.ts +160 -0
- package/dist/src/api/modules/admin/debug/routes/logs.route.d.ts.map +1 -0
- package/dist/src/api/modules/admin/debug/routes/logs.route.js +70 -0
- package/dist/src/api/modules/admin/routes/session.route.d.ts +1 -5
- package/dist/src/api/modules/admin/routes/session.route.d.ts.map +1 -1
- package/dist/src/api/modules/admin/routes/session.route.js +0 -4
- package/dist/src/api/modules/admin/users/routes/list.route.d.ts +1 -1
- package/dist/src/api/modules/admin/users/routes/users.route.d.ts +1 -1
- package/dist/src/api/modules/admin/users/users.admin.module.d.ts +1 -1
- package/dist/src/api/modules/middleware/middleware.module.d.ts +1 -1
- package/dist/src/api/modules/middleware/route.d.ts +1 -1
- package/dist/src/api/modules/middleware/route.d.ts.map +1 -1
- package/dist/src/api/modules/middleware/route.js +2 -4
- package/dist/src/api/modules/users/routes/session.route.d.ts +1 -1
- package/dist/src/api/modules/users/routes/sign-in.route.d.ts +1 -1
- package/dist/src/api/modules/users/routes/sign-out.route.d.ts +1 -1
- package/dist/src/api/modules/users/routes/sign-up.route.d.ts +1 -1
- package/dist/src/api/modules/users/routes/test.route.d.ts +1 -1
- package/dist/src/api/modules/users/routes/test.route.d.ts.map +1 -1
- package/dist/src/api/modules/users/routes/test.route.js +8 -0
- package/dist/src/api/modules/users/sso/routes/callback.route.d.ts +1 -1
- package/dist/src/api/modules/users/sso/routes/create-url.route.d.ts +1 -1
- package/dist/src/api/modules/users/sso/sso.module.d.ts +2 -2
- package/dist/src/api/modules/users/users.module.d.ts +7 -7
- package/dist/src/app_admin/core/debug/page.d.ts +11 -0
- package/dist/src/app_admin/core/debug/page.d.ts.map +1 -0
- package/dist/src/app_admin/core/debug/page.js +44 -0
- package/dist/src/app_admin/core/users/page.d.ts +4 -1
- package/dist/src/app_admin/core/users/page.d.ts.map +1 -1
- package/dist/src/app_admin/core/users/page.js +4 -2
- package/dist/src/components/confirm-action/confirm-action-alert-dialog.d.ts +15 -0
- package/dist/src/components/confirm-action/confirm-action-alert-dialog.d.ts.map +1 -0
- package/dist/src/components/confirm-action/confirm-action-alert-dialog.js +41 -0
- package/dist/src/components/confirm-action/content.d.ts +7 -0
- package/dist/src/components/confirm-action/content.d.ts.map +1 -0
- package/dist/src/components/confirm-action/content.js +31 -0
- package/dist/src/components/date-format.d.ts +2 -1
- package/dist/src/components/date-format.d.ts.map +1 -1
- package/dist/src/components/date-format.js +4 -1
- package/dist/src/components/form/auto-form.js +1 -1
- package/dist/src/components/form/fields/combobox-async.d.ts +21 -0
- package/dist/src/components/form/fields/combobox-async.d.ts.map +1 -0
- package/dist/src/components/form/fields/combobox-async.js +115 -0
- package/dist/src/components/form/fields/combobox.d.ts +2 -1
- package/dist/src/components/form/fields/combobox.d.ts.map +1 -1
- package/dist/src/components/form/fields/combobox.js +4 -5
- package/dist/src/components/switchers/langs/language-swietcher.d.ts +5 -0
- package/dist/src/components/switchers/langs/language-swietcher.d.ts.map +1 -0
- package/dist/src/components/switchers/langs/language-swietcher.js +45 -0
- package/dist/src/components/switchers/themes/theme-switcher.d.ts.map +1 -0
- package/dist/src/components/switchers/{theme-switcher.js → themes/theme-switcher.js} +1 -1
- package/dist/src/components/table/content.js +1 -1
- package/dist/src/components/table/data-table.d.ts.map +1 -1
- package/dist/src/components/table/data-table.js +2 -7
- package/dist/src/components/table/pagination.js +3 -3
- package/dist/src/components/ui/alert-dialog.d.ts +7 -2
- package/dist/src/components/ui/alert-dialog.d.ts.map +1 -1
- package/dist/src/components/ui/alert-dialog.js +41 -7
- package/dist/src/components/ui/dialog.d.ts.map +1 -1
- package/dist/src/components/ui/dialog.js +1 -1
- package/dist/src/database/logs.d.ts +116 -0
- package/dist/src/database/logs.d.ts.map +1 -0
- package/dist/src/database/logs.js +18 -0
- package/dist/src/database/sessions.d.ts +19 -0
- package/dist/src/database/sessions.d.ts.map +1 -1
- package/dist/src/database/sessions.js +3 -0
- package/dist/src/lib/fetcher/core.d.ts +16 -0
- package/dist/src/lib/fetcher/core.d.ts.map +1 -0
- package/dist/src/lib/fetcher/core.js +39 -0
- package/dist/src/lib/fetcher/helpers-server.d.ts +3 -0
- package/dist/src/lib/fetcher/helpers-server.d.ts.map +1 -0
- package/dist/src/lib/fetcher/helpers-server.js +18 -0
- package/dist/src/lib/fetcher/helpers.d.ts +0 -1
- package/dist/src/lib/fetcher/helpers.d.ts.map +1 -1
- package/dist/src/lib/fetcher/helpers.js +0 -17
- package/dist/src/lib/fetcher-client.d.ts +9 -0
- package/dist/src/lib/fetcher-client.d.ts.map +1 -0
- package/dist/src/lib/fetcher-client.js +12 -0
- package/dist/src/lib/fetcher.d.ts +3 -1
- package/dist/src/lib/fetcher.d.ts.map +1 -1
- package/dist/src/lib/fetcher.js +15 -33
- package/dist/src/lib/helpers/auto-form.d.ts.map +1 -1
- package/dist/src/lib/helpers/auto-form.js +28 -16
- package/dist/src/lib/helpers/auto-form.test.js +49 -0
- package/dist/src/views/admin/layouts/admin-layout.d.ts.map +1 -1
- package/dist/src/views/admin/layouts/admin-layout.js +5 -1
- package/dist/src/views/admin/layouts/sidebar/nav/item.d.ts.map +1 -1
- package/dist/src/views/admin/layouts/sidebar/nav/item.js +24 -3
- package/dist/src/views/admin/layouts/user-bar/client.d.ts.map +1 -1
- package/dist/src/views/admin/layouts/user-bar/client.js +26 -18
- package/dist/src/views/admin/views/core/dashboard/dashboard-admin-view.js +1 -1
- package/dist/src/views/admin/views/core/debug/actions/clear-cache/clear-cache.d.ts +2 -0
- package/dist/src/views/admin/views/core/debug/actions/clear-cache/clear-cache.d.ts.map +1 -0
- package/dist/src/views/admin/views/core/debug/actions/clear-cache/clear-cache.js +35 -0
- package/dist/src/views/admin/views/core/debug/actions/clear-cache/mutation-api.d.ts +2 -0
- package/dist/src/views/admin/views/core/debug/actions/clear-cache/mutation-api.d.ts.map +1 -0
- package/dist/src/views/admin/views/core/debug/actions/clear-cache/mutation-api.js +5 -0
- package/dist/src/views/admin/views/core/debug/debug-admin-view.d.ts +4 -0
- package/dist/src/views/admin/views/core/debug/debug-admin-view.d.ts.map +1 -0
- package/dist/src/views/admin/views/core/debug/debug-admin-view.js +110 -0
- package/dist/src/views/admin/views/core/test.d.ts.map +1 -1
- package/dist/src/views/admin/views/core/test.js +108 -103
- package/dist/src/views/auth/sso/buttons/sso-buttons.d.ts +1 -1
- package/dist/src/views/auth/sso/buttons/sso-buttons.d.ts.map +1 -1
- package/dist/src/views/auth/sso/buttons/sso-buttons.js +5 -2
- package/dist/src/views/layouts/theme/header/header.d.ts +4 -1
- package/dist/src/views/layouts/theme/header/header.d.ts.map +1 -1
- package/dist/src/views/layouts/theme/header/header.js +30 -23
- package/dist/src/views/layouts/theme/layout.d.ts +3 -1
- package/dist/src/views/layouts/theme/layout.d.ts.map +1 -1
- package/dist/src/views/layouts/theme/layout.js +4 -3
- package/dist/src/vitnode.config.d.ts +11 -5
- package/dist/src/vitnode.config.d.ts.map +1 -1
- package/dist/src/vitnode.config.js +2 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +40 -22
- package/src/app_admin/core/debug/page.tsx +43 -0
- package/src/app_admin/core/users/page.tsx +7 -2
- package/src/locales/en.json +37 -1
- package/src/vitnode.config.ts +16 -6
- package/dist/src/api/lib/get-user-ip.d.ts +0 -3
- package/dist/src/api/lib/get-user-ip.d.ts.map +0 -1
- package/dist/src/api/lib/get-user-ip.js +0 -8
- package/dist/src/api/middlewares/global/global.d.ts.map +0 -1
- package/dist/src/api/middlewares/global/global.js +0 -47
- package/dist/src/api/plugins/email/nodemailer.d.ts.map +0 -1
- package/dist/src/api/plugins/email/resend.d.ts.map +0 -1
- package/dist/src/api/plugins/sso/discord.d.ts.map +0 -1
- package/dist/src/api/plugins/sso/facebook.d.ts.map +0 -1
- package/dist/src/api/plugins/sso/google.d.ts.map +0 -1
- package/dist/src/components/switchers/theme-switcher.d.ts.map +0 -1
- /package/dist/src/api/{plugins → adapters}/sso/discord.d.ts +0 -0
- /package/dist/src/api/{plugins → adapters}/sso/discord.js +0 -0
- /package/dist/src/api/{plugins → adapters}/sso/facebook.d.ts +0 -0
- /package/dist/src/api/{plugins → adapters}/sso/facebook.js +0 -0
- /package/dist/src/api/{plugins → adapters}/sso/google.d.ts +0 -0
- /package/dist/src/api/{plugins → adapters}/sso/google.js +0 -0
- /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,
|
|
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
|
|
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 '
|
|
3
|
-
import type { VitNodeApiConfig, VitNodeConfig } from '
|
|
4
|
-
import type { SSOApiPlugin } from '
|
|
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
|
-
|
|
33
|
+
ssoProviders: SSOApiPlugin[];
|
|
33
34
|
};
|
|
34
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
+
};
|
|
@@ -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;
|
|
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
|
-
|
|
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(
|
|
19
|
-
return
|
|
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(
|
|
25
|
-
setCookie(this.c, this.c.get('core').authorization.deviceCookieName,
|
|
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 =
|
|
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.
|
|
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:
|
|
49
|
+
ipAddress: this.c.get('ipAddress'),
|
|
45
50
|
userAgent: this.getUserAgent()
|
|
46
|
-
}).where(eq(core_sessions_known_devices.
|
|
47
|
-
return
|
|
51
|
+
}).where(eq(core_sessions_known_devices.publicId, deviceIdFromCookie));
|
|
52
|
+
return {
|
|
53
|
+
id: device.id,
|
|
54
|
+
publicId: deviceIdFromCookie
|
|
55
|
+
};
|
|
48
56
|
}
|
|
49
|
-
} catch
|
|
50
|
-
|
|
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
|
-
}):
|
|
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,
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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;
|
|
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
|
-
|
|
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;
|
|
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)
|
|
24
|
-
|
|
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
|
|
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: '/
|
|
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.
|
|
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: '/
|
|
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
|
|
60
|
-
if (!
|
|
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,
|
|
65
|
-
if (!session)
|
|
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;
|
|
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
|
|
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
|
-
|
|
38
|
-
|
|
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
|
|
45
|
-
if (!
|
|
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,
|
|
50
|
-
if (!session
|
|
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.
|
|
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;
|
|
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"}
|