@vitnode/core 1.2.0-canary.23 → 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 +3 -1
- 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/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/data-table.d.ts.map +1 -1
- package/dist/src/components/table/data-table.js +2 -7
- 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 +39 -5
- 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 +2 -1
- package/dist/src/lib/fetcher/core.d.ts.map +1 -1
- package/dist/src/lib/fetcher/core.js +2 -2
- package/dist/src/lib/fetcher-client.d.ts +2 -1
- package/dist/src/lib/fetcher-client.d.ts.map +1 -1
- package/dist/src/lib/fetcher-client.js +3 -2
- package/dist/src/lib/fetcher.d.ts +2 -1
- package/dist/src/lib/fetcher.d.ts.map +1 -1
- package/dist/src/lib/fetcher.js +2 -1
- 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/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/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/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 +8 -4
- 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 +39 -22
- package/src/app_admin/core/debug/page.tsx +43 -0
- package/src/app_admin/core/users/page.tsx +6 -1
- package/src/locales/en.json +35 -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"}
|