@vitnode/core 1.2.0-canary.60 → 1.2.0-canary.62
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/get-config.js +15 -0
- package/dist/scripts/plugin.js +188 -0
- package/dist/scripts/prepare-database.js +177 -0
- package/dist/scripts/prepare-plugins-files.js +134 -0
- package/dist/scripts/run-interactive-shell-command.js +21 -0
- package/dist/scripts/scripts.js +39 -13
- package/dist/scripts/shared/file-utils.js +203 -0
- package/dist/src/api/adapters/sso/discord.js +1 -77
- package/dist/src/api/adapters/sso/facebook.js +1 -76
- package/dist/src/api/adapters/sso/google.js +1 -87
- package/dist/src/api/config.js +1 -67
- package/dist/src/api/lib/check-plugin-id.js +1 -43
- package/dist/src/api/lib/cron.js +1 -22
- package/dist/src/api/lib/logger-middleware.js +1 -35
- package/dist/src/api/lib/module.js +1 -22
- package/dist/src/api/lib/plugin.js +1 -22
- package/dist/src/api/lib/route.js +1 -27
- package/dist/src/api/lib/with-pagination.js +1 -83
- package/dist/src/api/middlewares/captcha.middleware.js +1 -63
- package/dist/src/api/middlewares/cron-auth.middleware.js +1 -19
- package/dist/src/api/middlewares/global.middleware.js +1 -93
- package/dist/src/api/middlewares/rate-limiter.middleware.js +1 -32
- package/dist/src/api/models/device.js +1 -61
- package/dist/src/api/models/email.js +1 -76
- package/dist/src/api/models/password.js +1 -36
- package/dist/src/api/models/session-admin.js +1 -106
- package/dist/src/api/models/session.js +1 -85
- package/dist/src/api/models/sso.js +1 -120
- package/dist/src/api/models/user/get-user-by-id.js +1 -19
- package/dist/src/api/models/user/sign-in-with-passwords.js +1 -22
- package/dist/src/api/models/user/sign-up.js +1 -73
- package/dist/src/api/models/user.js +1 -8
- package/dist/src/api/modules/admin/admin.module.js +1 -19
- package/dist/src/api/modules/admin/advanced/advanced.admin.module.js +1 -11
- package/dist/src/api/modules/admin/advanced/cron/cron.admin.module.js +1 -12
- package/dist/src/api/modules/admin/advanced/cron/routes/get.route.js +1 -66
- package/dist/src/api/modules/admin/advanced/cron/routes/run.route.js +1 -95
- package/dist/src/api/modules/admin/debug/debug.admin.module.js +1 -10
- package/dist/src/api/modules/admin/debug/routes/logs.route.js +1 -94
- package/dist/src/api/modules/admin/routes/session.route.js +1 -47
- package/dist/src/api/modules/admin/users/routes/list.route.js +1 -79
- package/dist/src/api/modules/admin/users/routes/users.route.js +1 -84
- package/dist/src/api/modules/admin/users/users.admin.module.js +1 -10
- package/dist/src/api/modules/cron/cron/clean.cron.js +1 -24
- package/dist/src/api/modules/cron/cron.module.js +1 -14
- package/dist/src/api/modules/cron/helpers/process-cron-jobs.d.ts.map +1 -1
- package/dist/src/api/modules/cron/helpers/process-cron-jobs.js +1 -76
- package/dist/src/api/modules/cron/routes/cron.route.js +1 -101
- package/dist/src/api/modules/middleware/middleware.module.js +1 -10
- package/dist/src/api/modules/middleware/route.js +1 -49
- package/dist/src/api/modules/users/avatar-color.js +1 -43
- package/dist/src/api/modules/users/routes/change-password.route.js +1 -58
- package/dist/src/api/modules/users/routes/reset-passowrd.route.js +1 -91
- package/dist/src/api/modules/users/routes/session.route.js +1 -46
- package/dist/src/api/modules/users/routes/sign-in.route.js +1 -71
- package/dist/src/api/modules/users/routes/sign-out.route.js +1 -43
- package/dist/src/api/modules/users/routes/sign-up.route.js +1 -77
- package/dist/src/api/modules/users/routes/test.route.js +1 -33
- package/dist/src/api/modules/users/sso/routes/callback.route.js +1 -52
- package/dist/src/api/modules/users/sso/routes/create-url.route.js +1 -36
- package/dist/src/api/modules/users/sso/sso.module.js +1 -12
- package/dist/src/api/modules/users/users.module.js +1 -26
- package/dist/src/api/plugin.js +1 -15
- package/dist/src/app/login/page.js +1 -16
- package/dist/src/app/login/reset-password/page.js +1 -18
- package/dist/src/app/login/sso/[providerId]/page.js +1 -10
- package/dist/src/app/register/page.js +1 -16
- package/dist/src/app_admin/core/advanced/cron/page.js +1 -42
- package/dist/src/app_admin/core/debug/page.js +1 -45
- package/dist/src/app_admin/core/page.js +1 -5
- package/dist/src/app_admin/core/test/page.js +1 -5
- package/dist/src/app_admin/core/users/page.js +1 -38
- package/dist/src/components/avatar.js +1 -14
- package/dist/src/components/confirm-action/confirm-action-alert-dialog.js +1 -42
- package/dist/src/components/confirm-action/content.js +1 -31
- package/dist/src/components/date-format.js +1 -41
- package/dist/src/components/form/auto-form.js +1 -103
- package/dist/src/components/form/common/desc.js +1 -9
- package/dist/src/components/form/common/label.js +1 -18
- package/dist/src/components/form/fields/checkbox.js +1 -37
- package/dist/src/components/form/fields/combobox-async.js +1 -123
- package/dist/src/components/form/fields/combobox.js +1 -87
- package/dist/src/components/form/fields/input.js +1 -39
- package/dist/src/components/form/fields/radio-group.js +1 -50
- package/dist/src/components/form/fields/select.js +1 -58
- package/dist/src/components/form/fields/switch.js +1 -36
- package/dist/src/components/form/fields/textarea.js +1 -36
- package/dist/src/components/i18n-provider.js +1 -43
- package/dist/src/components/logo-vitnode.js +1 -119
- package/dist/src/components/switchers/langs/language-switcher.js +1 -47
- package/dist/src/components/switchers/themes/theme-switcher.js +1 -28
- package/dist/src/components/table/content.js +1 -81
- package/dist/src/components/table/data-table.js +1 -68
- package/dist/src/components/table/order-table-head.js +1 -50
- package/dist/src/components/table/pagination.js +1 -122
- package/dist/src/components/tiptap/extension.js +1 -33
- package/dist/src/components/tiptap/toolbar/actions/alignment-action.js +1 -91
- package/dist/src/components/tiptap/toolbar/actions/bold-action.js +1 -39
- package/dist/src/components/tiptap/toolbar/actions/headings-action.js +1 -93
- package/dist/src/components/tiptap/toolbar/actions/italic-action.js +1 -38
- package/dist/src/components/tiptap/toolbar/actions/list-action.js +1 -61
- package/dist/src/components/tiptap/toolbar/actions/text-format-more/text-format-more.js +1 -59
- package/dist/src/components/tiptap/toolbar/actions/underline-action.js +1 -38
- package/dist/src/components/tiptap/toolbar/actions/undo-redo-actions.js +1 -63
- package/dist/src/components/tiptap/toolbar/actions/utils/tooltip-shortcut.js +1 -11
- package/dist/src/components/tiptap/toolbar/tiptap-toolbar.js +1 -55
- package/dist/src/components/tiptap/toolbar/use-toolbar-editor.js +1 -5
- package/dist/src/components/ui/accordion.js +1 -46
- package/dist/src/components/ui/alert-dialog.js +1 -123
- package/dist/src/components/ui/alert.js +1 -39
- package/dist/src/components/ui/badge.js +1 -28
- package/dist/src/components/ui/button-client.js +1 -57
- package/dist/src/components/ui/button.js +1 -32
- package/dist/src/components/ui/card.js +1 -52
- package/dist/src/components/ui/checkbox.js +1 -20
- package/dist/src/components/ui/collapsible.js +1 -22
- package/dist/src/components/ui/command.js +1 -98
- package/dist/src/components/ui/context-menu.js +1 -140
- package/dist/src/components/ui/dialog.js +1 -189
- package/dist/src/components/ui/drawer.js +1 -83
- package/dist/src/components/ui/dropdown-menu.js +1 -141
- package/dist/src/components/ui/editor-content.js +1 -10
- package/dist/src/components/ui/editor.js +1 -35
- package/dist/src/components/ui/form.js +1 -148
- package/dist/src/components/ui/header-content.js +1 -30
- package/dist/src/components/ui/hover-card.js +1 -29
- package/dist/src/components/ui/input-otp.js +1 -48
- package/dist/src/components/ui/input.js +1 -11
- package/dist/src/components/ui/label.js +1 -12
- package/dist/src/components/ui/loader.js +1 -16
- package/dist/src/components/ui/menubar.js +1 -151
- package/dist/src/components/ui/navigation-menu.js +1 -82
- package/dist/src/components/ui/popover.js +1 -35
- package/dist/src/components/ui/progress.js +1 -19
- package/dist/src/components/ui/radio-group.js +1 -27
- package/dist/src/components/ui/scroll-area.js +1 -33
- package/dist/src/components/ui/select.js +1 -113
- package/dist/src/components/ui/separator.js +1 -14
- package/dist/src/components/ui/sheet.js +1 -92
- package/dist/src/components/ui/sidebar.js +1 -433
- package/dist/src/components/ui/skeleton.js +1 -10
- package/dist/src/components/ui/slider.js +1 -50
- package/dist/src/components/ui/sonner.js +1 -26
- package/dist/src/components/ui/switch.js +1 -16
- package/dist/src/components/ui/table.js +1 -63
- package/dist/src/components/ui/tabs.js +1 -33
- package/dist/src/components/ui/textarea.js +1 -10
- package/dist/src/components/ui/toggle-group.js +1 -45
- package/dist/src/components/ui/toggle.js +1 -34
- package/dist/src/components/ui/tooltip.js +1 -57
- package/dist/src/config.js +1 -4
- package/dist/src/database/admins.js +1 -74
- package/dist/src/database/cron.js +1 -22
- package/dist/src/database/languages.js +1 -52
- package/dist/src/database/logs.js +1 -34
- package/dist/src/database/moderators.js +1 -37
- package/dist/src/database/roles.js +1 -13
- package/dist/src/database/sessions.js +1 -60
- package/dist/src/database/users.js +1 -145
- package/dist/src/drizzle.config.js +1 -67
- package/dist/src/emails/default-template.js +1 -99
- package/dist/src/emails/reset-password.js +1 -132
- package/dist/src/emails/ui/button.js +1 -36
- package/dist/src/emails/ui/card.js +1 -39
- package/dist/src/hooks/use-before-unload.js +1 -30
- package/dist/src/hooks/use-captcha.js +1 -122
- package/dist/src/hooks/use-mobile.js +1 -16
- package/dist/src/lib/api/get-middleware-api.js +1 -13
- package/dist/src/lib/api/get-next-cron-run-date.js +1 -14
- package/dist/src/lib/api/get-next-cron-run-date.test.js +1 -55
- package/dist/src/lib/api/get-session-admin-api.js +1 -19
- package/dist/src/lib/api/get-session-api.js +1 -14
- package/dist/src/lib/api/should-cron-job-run.js +1 -16
- package/dist/src/lib/api/should-cron-job-run.test.js +1 -213
- package/dist/src/lib/api/validate-cron-schedule.d.ts +2 -0
- package/dist/src/lib/api/validate-cron-schedule.d.ts.map +1 -0
- package/dist/src/lib/api/validate-cron-schedule.js +1 -0
- package/dist/src/lib/api/validate-cron-schedule.test.d.ts +2 -0
- package/dist/src/lib/api/validate-cron-schedule.test.d.ts.map +1 -0
- package/dist/src/lib/api/validate-cron-schedule.test.js +1 -0
- package/dist/src/lib/colors.js +1 -140
- package/dist/src/lib/colors.test.js +1 -173
- package/dist/src/lib/config.js +1 -14
- package/dist/src/lib/ctrl-or-command-character.js +1 -5
- package/dist/src/lib/fetcher/cookie-from-string-to-object.js +1 -12
- package/dist/src/lib/fetcher/cookie-from-string-to-object.test.js +1 -78
- package/dist/src/lib/fetcher/core.js +3 -48
- package/dist/src/lib/fetcher/helpers-server.js +1 -18
- package/dist/src/lib/fetcher/helpers.js +1 -16
- package/dist/src/lib/fetcher/helpers.test.js +1 -37
- package/dist/src/lib/fetcher/types.js +1 -1
- package/dist/src/lib/fetcher-client.js +1 -17
- package/dist/src/lib/fetcher.js +1 -33
- package/dist/src/lib/helpers/auto-form.js +1 -98
- package/dist/src/lib/helpers/auto-form.test.js +1 -336
- package/dist/src/lib/navigation.js +1 -11
- package/dist/src/lib/plugin.js +1 -3
- package/dist/src/lib/special-characters.js +1 -4
- package/dist/src/lib/special-characters.test.js +1 -56
- package/dist/src/lib/utils.js +1 -5
- package/dist/src/locales/en.json +308 -0
- package/dist/src/tests/setup.js +1 -6
- package/dist/src/views/admin/layouts/admin-layout.js +1 -73
- package/dist/src/views/admin/layouts/sidebar/nav/item.js +1 -98
- package/dist/src/views/admin/layouts/sidebar/nav/nav.js +1 -60
- package/dist/src/views/admin/layouts/sidebar/sidebar.js +1 -28
- package/dist/src/views/admin/layouts/sidebar/sign-out.js +1 -14
- package/dist/src/views/admin/layouts/user-bar/client.js +1 -69
- package/dist/src/views/admin/layouts/user-bar/user-bar.js +1 -32
- package/dist/src/views/admin/sign-in/sign-in-admin-view.js +1 -27
- package/dist/src/views/admin/views/core/advanced/cron/cron-table-view.js +1 -97
- package/dist/src/views/admin/views/core/advanced/cron/run-action/mutation-api.js +1 -23
- package/dist/src/views/admin/views/core/advanced/cron/run-action/run-action.js +1 -38
- package/dist/src/views/admin/views/core/dashboard/dashboard-admin-view.js +1 -44
- package/dist/src/views/admin/views/core/debug/actions/clear-cache/clear-cache.js +1 -35
- package/dist/src/views/admin/views/core/debug/actions/clear-cache/mutation-api.js +1 -5
- package/dist/src/views/admin/views/core/debug/system-logs/actions/more/content.js +1 -281
- package/dist/src/views/admin/views/core/debug/system-logs/actions/more/more.js +1 -67
- package/dist/src/views/admin/views/core/debug/system-logs/badges/badge-status.js +1 -14
- package/dist/src/views/admin/views/core/debug/system-logs/badges/badge-type-log.js +1 -30
- package/dist/src/views/admin/views/core/debug/system-logs/system-logs-view.js +1 -96
- package/dist/src/views/admin/views/core/test.js +1 -161
- package/dist/src/views/admin/views/core/users/users-admin-view.js +1 -89
- package/dist/src/views/auth/password-reset/change-password-form/form.js +1 -48
- package/dist/src/views/auth/password-reset/change-password-form/mutation-api.js +1 -22
- package/dist/src/views/auth/password-reset/change-password-form/use-form.js +1 -36
- package/dist/src/views/auth/password-reset/form/form.js +1 -104
- package/dist/src/views/auth/password-reset/form/mutation-api.js +1 -21
- package/dist/src/views/auth/password-reset/form/use-form.js +1 -33
- package/dist/src/views/auth/password-reset/password-reset-view.js +1 -37
- package/dist/src/views/auth/sign-in/form/form.js +1 -64
- package/dist/src/views/auth/sign-in/form/mutation-api.js +1 -33
- package/dist/src/views/auth/sign-in/form/use-form.js +1 -38
- package/dist/src/views/auth/sign-in/sign-in-view.js +1 -61
- package/dist/src/views/auth/sign-up/components/password-input.js +1 -96
- package/dist/src/views/auth/sign-up/email-confirmation-view.js +1 -55
- package/dist/src/views/auth/sign-up/form/form.js +1 -89
- package/dist/src/views/auth/sign-up/form/mutation-api.js +1 -30
- package/dist/src/views/auth/sign-up/form/use-form.js +1 -70
- package/dist/src/views/auth/sign-up/sign-up-view.js +1 -65
- package/dist/src/views/auth/sign-up/wrapper.js +1 -22
- package/dist/src/views/auth/sso/buttons/client.js +1 -22
- package/dist/src/views/auth/sso/buttons/mutation-api.js +1 -24
- package/dist/src/views/auth/sso/buttons/sso-buttons.js +1 -56
- package/dist/src/views/auth/sso/callback/callback-sso-view.js +1 -32
- package/dist/src/views/auth/sso/callback/client/client.js +1 -68
- package/dist/src/views/auth/sso/callback/client/mutation-api.js +1 -32
- package/dist/src/views/error/back-button.js +1 -14
- package/dist/src/views/error/error-view.js +1 -58
- package/dist/src/views/error/global-error-view.js +1 -50
- package/dist/src/views/layouts/provider.js +1 -44
- package/dist/src/views/layouts/root-layout.js +1 -25
- package/dist/src/views/layouts/theme/header/header.js +1 -38
- package/dist/src/views/layouts/theme/header/user/auth/auth.js +1 -33
- package/dist/src/views/layouts/theme/header/user/auth/client.js +1 -47
- package/dist/src/views/layouts/theme/header/user/auth/log-out-mutation-api.js +1 -27
- package/dist/src/views/layouts/theme/header/user/user.js +1 -32
- package/dist/src/views/layouts/theme/layout.js +1 -16
- package/dist/src/vitnode.config.js +1 -42
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/tsup.config.js +18 -0
- package/dist/vitest.config.d.ts.map +1 -1
- package/dist/vitest.config.js +49 -0
- package/eslint.config.mjs +2 -0
- package/package.json +6 -10
- package/dist/src/api/adapters/cron/node-cron.adapter.d.ts +0 -3
- package/dist/src/api/adapters/cron/node-cron.adapter.d.ts.map +0 -1
- package/dist/src/api/adapters/cron/node-cron.adapter.js +0 -11
- package/dist/src/api/adapters/email/nodemailer.d.ts +0 -10
- package/dist/src/api/adapters/email/nodemailer.d.ts.map +0 -1
- package/dist/src/api/adapters/email/nodemailer.js +0 -30
- package/dist/src/api/adapters/email/resend.d.ts +0 -6
- package/dist/src/api/adapters/email/resend.d.ts.map +0 -1
- package/dist/src/api/adapters/email/resend.js +0 -21
package/dist/src/api/config.js
CHANGED
|
@@ -1,67 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { cors } from "hono/cors";
|
|
3
|
-
import { csrf } from "hono/csrf";
|
|
4
|
-
import { HTTPException } from "hono/http-exception";
|
|
5
|
-
import { newBuildPluginApiCore } from "./plugin.js";
|
|
6
|
-
import { CONFIG_PLUGIN } from "../config.js";
|
|
7
|
-
import { globalAdminMiddleware, globalMiddleware } from "./middlewares/global.middleware.js";
|
|
8
|
-
import { rateLimiterMiddleware } from "./middlewares/rate-limiter.middleware.js";
|
|
9
|
-
export function VitNodeAPI({ app, cors: corsOptions, csrf: csrfOptions, vitNodeApiConfig }) {
|
|
10
|
-
app.doc("/swagger/doc", {
|
|
11
|
-
openapi: "3.0.0",
|
|
12
|
-
info: {
|
|
13
|
-
version: CONFIG_PLUGIN.version,
|
|
14
|
-
title: "VitNode API"
|
|
15
|
-
}
|
|
16
|
-
});
|
|
17
|
-
app.use(cors(corsOptions));
|
|
18
|
-
app.use(csrf(csrfOptions));
|
|
19
|
-
app.use("*", rateLimiterMiddleware(vitNodeApiConfig.rateLimiter));
|
|
20
|
-
app.get("/swagger", swaggerUI({
|
|
21
|
-
url: "/api/swagger/doc"
|
|
22
|
-
}));
|
|
23
|
-
app.use("*", globalMiddleware({
|
|
24
|
-
pathToMessages: vitNodeApiConfig.pathToMessages,
|
|
25
|
-
email: vitNodeApiConfig.email,
|
|
26
|
-
metadata: vitNodeApiConfig.metadata,
|
|
27
|
-
authorization: vitNodeApiConfig.authorization,
|
|
28
|
-
dbProvider: vitNodeApiConfig.dbProvider,
|
|
29
|
-
captcha: vitNodeApiConfig.captcha,
|
|
30
|
-
plugins: [
|
|
31
|
-
newBuildPluginApiCore,
|
|
32
|
-
...vitNodeApiConfig.plugins
|
|
33
|
-
]
|
|
34
|
-
}));
|
|
35
|
-
app.use(async (c, next)=>{
|
|
36
|
-
if (c.req.path.includes("/admin/")) {
|
|
37
|
-
return await globalAdminMiddleware()(c, next);
|
|
38
|
-
}
|
|
39
|
-
return next();
|
|
40
|
-
});
|
|
41
|
-
if (vitNodeApiConfig.cronAdapter) {
|
|
42
|
-
vitNodeApiConfig.cronAdapter.schedule();
|
|
43
|
-
}
|
|
44
|
-
[
|
|
45
|
-
newBuildPluginApiCore,
|
|
46
|
-
...vitNodeApiConfig.plugins
|
|
47
|
-
].map((root)=>{
|
|
48
|
-
app.route(`/${root.pluginId}`, root.hono);
|
|
49
|
-
});
|
|
50
|
-
app.onError(async (error, c)=>{
|
|
51
|
-
if (error instanceof HTTPException) {
|
|
52
|
-
return error.getResponse();
|
|
53
|
-
}
|
|
54
|
-
const errorMessage = error?.message ?? "Unknown error";
|
|
55
|
-
try {
|
|
56
|
-
const logger = c.get("log");
|
|
57
|
-
if (logger) {
|
|
58
|
-
await logger.error(`Unhandled error: ${errorMessage}`);
|
|
59
|
-
}
|
|
60
|
-
} catch {
|
|
61
|
-
/* empty */ }
|
|
62
|
-
return new Response(process.env.NODE_ENV === "development" ? errorMessage : "Internal Server Error", {
|
|
63
|
-
status: 500
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
return app;
|
|
67
|
-
}
|
|
1
|
+
import{swaggerUI}from"@hono/swagger-ui";import{cors}from"hono/cors";import{csrf}from"hono/csrf";import{HTTPException}from"hono/http-exception";import{newBuildPluginApiCore}from"./plugin.js";import{CONFIG_PLUGIN}from"../config.js";import{globalAdminMiddleware,globalMiddleware}from"./middlewares/global.middleware.js";import{rateLimiterMiddleware}from"./middlewares/rate-limiter.middleware.js";export function VitNodeAPI({app,cors:corsOptions,csrf:csrfOptions,vitNodeApiConfig}){app.doc("/swagger/doc",{openapi:"3.0.0",info:{version:CONFIG_PLUGIN.version,title:"VitNode API"}});app.use(cors(corsOptions));app.use(csrf(csrfOptions));app.use("*",rateLimiterMiddleware(vitNodeApiConfig.rateLimiter));app.get("/swagger",swaggerUI({url:"/api/swagger/doc"}));app.use("*",globalMiddleware({pathToMessages:vitNodeApiConfig.pathToMessages,email:vitNodeApiConfig.email,metadata:vitNodeApiConfig.metadata,authorization:vitNodeApiConfig.authorization,dbProvider:vitNodeApiConfig.dbProvider,captcha:vitNodeApiConfig.captcha,plugins:[newBuildPluginApiCore,...vitNodeApiConfig.plugins]}));app.use(async(c,next)=>{if(c.req.path.includes("/admin/")){return await globalAdminMiddleware()(c,next)}return next()});if(vitNodeApiConfig.cronAdapter){vitNodeApiConfig.cronAdapter.schedule()}[newBuildPluginApiCore,...vitNodeApiConfig.plugins].map(root=>{app.route(`/${root.pluginId}`,root.hono)});app.onError(async(error,c)=>{if(error instanceof HTTPException){return error.getResponse()}const errorMessage=error?.message??"Unknown error";try{const logger=c.get("log");if(logger){await logger.error(`Unhandled error: ${errorMessage}`)}}catch{}return new Response(process.env.NODE_ENV==="development"?errorMessage:"Internal Server Error",{status:500})});return app}
|
|
@@ -1,43 +1 @@
|
|
|
1
|
-
import { existsSync,
|
|
2
|
-
import { join, resolve } from "node:path";
|
|
3
|
-
import { CONFIG } from "../../lib/config.js";
|
|
4
|
-
export const checkPluginId = (pluginName)=>{
|
|
5
|
-
if (!CONFIG.node_development) return null;
|
|
6
|
-
const findMonorepoRoot = (startPath)=>{
|
|
7
|
-
let currentPath = startPath;
|
|
8
|
-
while(currentPath !== resolve(currentPath, "..")){
|
|
9
|
-
const turboConfigPath = join(currentPath, "turbo.json");
|
|
10
|
-
if (existsSync(turboConfigPath)) {
|
|
11
|
-
return currentPath;
|
|
12
|
-
}
|
|
13
|
-
currentPath = resolve(currentPath, "..");
|
|
14
|
-
}
|
|
15
|
-
return null;
|
|
16
|
-
};
|
|
17
|
-
const findPluginPath = (pluginName)=>{
|
|
18
|
-
const cwd = process.cwd();
|
|
19
|
-
const monorepoRoot = findMonorepoRoot(cwd);
|
|
20
|
-
// Check in current working directory first
|
|
21
|
-
const cwdPluginPath = join(cwd, "node_modules", pluginName, "package.json");
|
|
22
|
-
if (existsSync(cwdPluginPath)) {
|
|
23
|
-
return cwdPluginPath;
|
|
24
|
-
}
|
|
25
|
-
// Check in monorepo root if it exists and is different from cwd
|
|
26
|
-
if (monorepoRoot && monorepoRoot !== cwd) {
|
|
27
|
-
const rootPluginPath = join(monorepoRoot, "node_modules", pluginName, "package.json");
|
|
28
|
-
if (existsSync(rootPluginPath)) {
|
|
29
|
-
return rootPluginPath;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return null;
|
|
33
|
-
};
|
|
34
|
-
const path = findPluginPath(pluginName);
|
|
35
|
-
if (!path) {
|
|
36
|
-
throw new Error(`package.json file not found for plugin "${pluginName}". Please ensure you are using the correct plugin name as specified in its package.json.`);
|
|
37
|
-
}
|
|
38
|
-
const content = JSON.parse(readFileSync(path, "utf-8"));
|
|
39
|
-
if (content.name !== pluginName) {
|
|
40
|
-
throw new Error(`The plugin name in package.json (${content.name}) does not match the requested plugin name (${pluginName}). Please check the plugin name.`);
|
|
41
|
-
}
|
|
42
|
-
return content;
|
|
43
|
-
};
|
|
1
|
+
import{existsSync,readFileSync}from"node:fs";import{join,resolve}from"node:path";import{CONFIG}from"../../lib/config.js";export const checkPluginId=pluginName=>{if(!CONFIG.node_development)return null;const findMonorepoRoot=startPath=>{let currentPath=startPath;while(currentPath!==resolve(currentPath,"..")){const turboConfigPath=join(currentPath,"turbo.json");if(existsSync(turboConfigPath)){return currentPath}currentPath=resolve(currentPath,"..")}return null};const findPluginPath=pluginName=>{const cwd=process.cwd();const monorepoRoot=findMonorepoRoot(cwd);const cwdPluginPath=join(cwd,"node_modules",pluginName,"package.json");if(existsSync(cwdPluginPath)){return cwdPluginPath}if(monorepoRoot&&monorepoRoot!==cwd){const rootPluginPath=join(monorepoRoot,"node_modules",pluginName,"package.json");if(existsSync(rootPluginPath)){return rootPluginPath}}return null};const path=findPluginPath(pluginName);if(!path){throw new Error(`package.json file not found for plugin "${pluginName}". Please ensure you are using the correct plugin name as specified in its package.json.`)}const content=JSON.parse(readFileSync(path,"utf-8"));if(content.name!==pluginName){throw new Error(`The plugin name in package.json (${content.name}) does not match the requested plugin name (${pluginName}). Please check the plugin name.`)}return content};
|
package/dist/src/api/lib/cron.js
CHANGED
|
@@ -1,22 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
export function buildCron({ name, schedule, handler, description }) {
|
|
3
|
-
return {
|
|
4
|
-
name,
|
|
5
|
-
schedule,
|
|
6
|
-
handler,
|
|
7
|
-
description
|
|
8
|
-
};
|
|
9
|
-
}
|
|
10
|
-
export const handleCronJobs = async ()=>{
|
|
11
|
-
const url = new URL("/api/@vitnode/core/cron", CONFIG.api.origin);
|
|
12
|
-
const headers = {
|
|
13
|
-
"Content-Type": "application/json"
|
|
14
|
-
};
|
|
15
|
-
if (CONFIG.cronJobSecret) {
|
|
16
|
-
headers.authorization = `Bearer ${CONFIG.cronJobSecret}`;
|
|
17
|
-
}
|
|
18
|
-
await fetch(url.toString(), {
|
|
19
|
-
method: "POST",
|
|
20
|
-
headers
|
|
21
|
-
});
|
|
22
|
-
};
|
|
1
|
+
import{CONFIG}from"../../lib/config.js";export function buildCron({name,schedule,handler,description}){return{name,schedule,handler,description}}export const handleCronJobs=async()=>{const url=new URL("/api/@vitnode/core/cron",CONFIG.api.origin);const headers={"Content-Type":"application/json"};if(CONFIG.cronJobSecret){headers.authorization=`Bearer ${CONFIG.cronJobSecret}`}await fetch(url.toString(),{method:"POST",headers})};
|
|
@@ -1,35 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export const loggerMiddleware = (c)=>{
|
|
3
|
-
const logToDbAndConsole = async (content, type)=>{
|
|
4
|
-
const pluginId = c.get("plugin")?.id ?? "core";
|
|
5
|
-
const ipAddress = c.get("ipAddress");
|
|
6
|
-
await c.get("db").insert(core_logs).values({
|
|
7
|
-
pluginId,
|
|
8
|
-
type,
|
|
9
|
-
content,
|
|
10
|
-
ipAddress,
|
|
11
|
-
method: c.req.method.toUpperCase(),
|
|
12
|
-
path: c.req.path,
|
|
13
|
-
userAgent: c.req.header("User-Agent"),
|
|
14
|
-
statusCode: c.res.status,
|
|
15
|
-
userId: c.get("user")?.id
|
|
16
|
-
});
|
|
17
|
-
const loggers = {
|
|
18
|
-
debug: (msg)=>console.debug(`\x1b[34m[VitNode]\x1b[0m \x1b[38;5;208mDebug (${pluginId})\x1b[0m: ${msg}`),
|
|
19
|
-
error: (msg)=>console.error(`\x1b[34m[VitNode]\x1b[0m \x1b[31mError (${pluginId})\x1b[0m: ${msg}`),
|
|
20
|
-
warn: (msg)=>console.warn(`\x1b[34m[VitNode]\x1b[0m \x1b[33mWarning (${pluginId})\x1b[0m: ${msg}`)
|
|
21
|
-
};
|
|
22
|
-
(loggers[type] ?? loggers.debug)(content);
|
|
23
|
-
};
|
|
24
|
-
return {
|
|
25
|
-
debug: async (content)=>{
|
|
26
|
-
await logToDbAndConsole(content, "debug");
|
|
27
|
-
},
|
|
28
|
-
error: async (content)=>{
|
|
29
|
-
await logToDbAndConsole(content, "error");
|
|
30
|
-
},
|
|
31
|
-
warn: async (content)=>{
|
|
32
|
-
await logToDbAndConsole(content, "warn");
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
};
|
|
1
|
+
import{core_logs}from"../../database/logs.js";export const loggerMiddleware=c=>{const logToDbAndConsole=async(content,type)=>{const pluginId=c.get("plugin")?.id??"core";const ipAddress=c.get("ipAddress");await c.get("db").insert(core_logs).values({pluginId,type,content,ipAddress,method:c.req.method.toUpperCase(),path:c.req.path,userAgent:c.req.header("User-Agent"),statusCode:c.res.status,userId:c.get("user")?.id});const loggers={debug:msg=>console.debug(`\x1b[34m[VitNode]\x1b[0m \x1b[38;5;208mDebug (${pluginId})\x1b[0m: ${msg}`),error:msg=>console.error(`\x1b[34m[VitNode]\x1b[0m \x1b[31mError (${pluginId})\x1b[0m: ${msg}`),warn:msg=>console.warn(`\x1b[34m[VitNode]\x1b[0m \x1b[33mWarning (${pluginId})\x1b[0m: ${msg}`)};(loggers[type]??loggers.debug)(content)};return{debug:async content=>{await logToDbAndConsole(content,"debug")},error:async content=>{await logToDbAndConsole(content,"error")},warn:async content=>{await logToDbAndConsole(content,"warn")}}};
|
|
@@ -1,22 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
export function buildModule({ routes, pluginId, name, modules, cronJobs = [] }) {
|
|
3
|
-
const hono = new OpenAPIHono();
|
|
4
|
-
if (routes) {
|
|
5
|
-
routes.forEach(({ handler, route })=>{
|
|
6
|
-
hono.openapi(route, handler);
|
|
7
|
-
});
|
|
8
|
-
}
|
|
9
|
-
if (modules) {
|
|
10
|
-
modules.forEach((module)=>{
|
|
11
|
-
hono.route(`/${module.name}`, module.hono);
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
return {
|
|
15
|
-
routes,
|
|
16
|
-
pluginId,
|
|
17
|
-
hono,
|
|
18
|
-
name,
|
|
19
|
-
modules,
|
|
20
|
-
cronJobs
|
|
21
|
-
};
|
|
22
|
-
}
|
|
1
|
+
import{OpenAPIHono}from"@hono/zod-openapi";export function buildModule({routes,pluginId,name,modules,cronJobs=[]}){const hono=new OpenAPIHono;if(routes){routes.forEach(({handler,route})=>{hono.openapi(route,handler)})}if(modules){modules.forEach(module=>{hono.route(`/${module.name}`,module.hono)})}return{routes,pluginId,hono,name,modules,cronJobs}}
|
|
@@ -1,22 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { checkPluginId } from "./check-plugin-id.js";
|
|
3
|
-
export function buildApiPlugin({ pluginId, modules = [] }) {
|
|
4
|
-
// Run for checking if the plugin is valid
|
|
5
|
-
checkPluginId(pluginId);
|
|
6
|
-
const hono = new OpenAPIHono();
|
|
7
|
-
const cronJobs = [];
|
|
8
|
-
modules.forEach((handler)=>{
|
|
9
|
-
hono.route(`/${handler.name}`, handler.hono);
|
|
10
|
-
handler.cronJobs?.forEach((cron)=>{
|
|
11
|
-
cronJobs.push({
|
|
12
|
-
...cron,
|
|
13
|
-
module: handler.name
|
|
14
|
-
});
|
|
15
|
-
});
|
|
16
|
-
});
|
|
17
|
-
return {
|
|
18
|
-
pluginId,
|
|
19
|
-
hono,
|
|
20
|
-
cronJobs
|
|
21
|
-
};
|
|
22
|
-
}
|
|
1
|
+
import{OpenAPIHono}from"@hono/zod-openapi";import{checkPluginId}from"./check-plugin-id.js";export function buildApiPlugin({pluginId,modules=[]}){checkPluginId(pluginId);const hono=new OpenAPIHono;const cronJobs=[];modules.forEach(handler=>{hono.route(`/${handler.name}`,handler.hono);handler.cronJobs?.forEach(cron=>{cronJobs.push({...cron,module:handler.name})})});return{pluginId,hono,cronJobs}}
|
|
@@ -1,27 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { captchaMiddleware } from "../middlewares/captcha.middleware.js";
|
|
3
|
-
import { pluginMiddleware } from "../middlewares/global.middleware.js";
|
|
4
|
-
export const buildRoute = ({ route, handler, pluginId })=>{
|
|
5
|
-
const pluginTag = pluginId.split(/[-_]/).map((word)=>word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
6
|
-
const tags = [
|
|
7
|
-
pluginTag,
|
|
8
|
-
...route.tags ?? []
|
|
9
|
-
];
|
|
10
|
-
return {
|
|
11
|
-
route: createRouteHono({
|
|
12
|
-
tags,
|
|
13
|
-
middleware: [
|
|
14
|
-
pluginMiddleware(pluginId),
|
|
15
|
-
...route.withCaptcha ? [
|
|
16
|
-
captchaMiddleware()
|
|
17
|
-
] : [],
|
|
18
|
-
...Array.isArray(route.middleware) ? route.middleware : route.middleware ? [
|
|
19
|
-
route.middleware
|
|
20
|
-
] : []
|
|
21
|
-
],
|
|
22
|
-
...route
|
|
23
|
-
}),
|
|
24
|
-
handler: handler,
|
|
25
|
-
pluginId
|
|
26
|
-
};
|
|
27
|
-
};
|
|
1
|
+
import{createRoute as createRouteHono}from"@hono/zod-openapi";import{captchaMiddleware}from"../middlewares/captcha.middleware.js";import{pluginMiddleware}from"../middlewares/global.middleware.js";export const buildRoute=({route,handler,pluginId})=>{const pluginTag=pluginId.split(/[-_]/).map(word=>word.charAt(0).toUpperCase()+word.slice(1)).join(" ");const tags=[pluginTag,...route.tags??[]];return{route:createRouteHono({tags,middleware:[pluginMiddleware(pluginId),...route.withCaptcha?[captchaMiddleware()]:[],...Array.isArray(route.middleware)?route.middleware:route.middleware?[route.middleware]:[]],...route}),handler:handler,pluginId}};
|
|
@@ -1,83 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { and, asc, count, desc, gt, lt } from "drizzle-orm";
|
|
3
|
-
function parsePaginationParams(params) {
|
|
4
|
-
const cursor = params.query.cursor ? parseInt(params.query.cursor, 10) : undefined;
|
|
5
|
-
const first = params.query.first ? Math.min(parseInt(params.query.first, 10), 100) : undefined;
|
|
6
|
-
const last = params.query.last ? Math.min(parseInt(params.query.last, 10), 100) : undefined;
|
|
7
|
-
if (first !== undefined && last !== undefined) {
|
|
8
|
-
throw new Error("Cannot specify both first and last");
|
|
9
|
-
}
|
|
10
|
-
if (first !== undefined && first < 0) {
|
|
11
|
-
throw new Error("first must be positive");
|
|
12
|
-
}
|
|
13
|
-
if (last !== undefined && last < 0) {
|
|
14
|
-
throw new Error("last must be positive");
|
|
15
|
-
}
|
|
16
|
-
return {
|
|
17
|
-
cursor,
|
|
18
|
-
first,
|
|
19
|
-
last
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
function getOrderFn(isForward, order) {
|
|
23
|
-
if (isForward) {
|
|
24
|
-
return order === "asc" ? asc : desc;
|
|
25
|
-
}
|
|
26
|
-
return order === "asc" ? desc : asc;
|
|
27
|
-
}
|
|
28
|
-
function buildWhereWithCursor(baseWhere, cursor, isForward, order, table, primaryCursor) {
|
|
29
|
-
if (!cursor) return baseWhere;
|
|
30
|
-
const cursorFilter = isForward && order === "asc" || !isForward && order === "desc" ? gt : lt;
|
|
31
|
-
const cursorWhere = cursorFilter(table[primaryCursor.name], cursor);
|
|
32
|
-
return baseWhere ? and(baseWhere, cursorWhere) : cursorWhere;
|
|
33
|
-
}
|
|
34
|
-
async function fetchTotalCount(c, table, where) {
|
|
35
|
-
const [{ count: totalCount }] = await c.get("db").select({
|
|
36
|
-
count: count()
|
|
37
|
-
}).from(table).where(where);
|
|
38
|
-
return totalCount;
|
|
39
|
-
}
|
|
40
|
-
export async function withPagination({ query, table, params, where: whereFromParams, primaryCursor, orderBy: orderByFromParams, c }) {
|
|
41
|
-
const { cursor, first, last } = parsePaginationParams(params);
|
|
42
|
-
const isForward = last === undefined;
|
|
43
|
-
const orderFn = getOrderFn(isForward, orderByFromParams.order);
|
|
44
|
-
const orderBy = orderFn(table[orderByFromParams.column.name]);
|
|
45
|
-
const where = buildWhereWithCursor(whereFromParams, cursor, isForward, orderByFromParams.order, table, primaryCursor);
|
|
46
|
-
const totalCount = await fetchTotalCount(c, table, whereFromParams);
|
|
47
|
-
const limit = (first ?? last ?? 50) + 1;
|
|
48
|
-
const edges = await query({
|
|
49
|
-
limit,
|
|
50
|
-
where,
|
|
51
|
-
orderBy
|
|
52
|
-
});
|
|
53
|
-
const requested = first ?? last ?? edges.length;
|
|
54
|
-
const hasMore = edges.length > requested;
|
|
55
|
-
const slicedEdges = edges.slice(0, requested);
|
|
56
|
-
const finalEdges = isForward ? slicedEdges : slicedEdges.reverse();
|
|
57
|
-
const startCursor = finalEdges[0]?.[primaryCursor.name] ?? null;
|
|
58
|
-
const endCursor = finalEdges.at(-1)?.[primaryCursor.name] ?? null;
|
|
59
|
-
return {
|
|
60
|
-
pageInfo: {
|
|
61
|
-
totalCount,
|
|
62
|
-
count: finalEdges.length,
|
|
63
|
-
hasNextPage: isForward ? hasMore : !!cursor,
|
|
64
|
-
hasPreviousPage: isForward ? !!cursor : hasMore,
|
|
65
|
-
startCursor,
|
|
66
|
-
endCursor
|
|
67
|
-
},
|
|
68
|
-
edges: finalEdges
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
export const zodPaginationPageInfo = z.object({
|
|
72
|
-
totalCount: z.number(),
|
|
73
|
-
count: z.number(),
|
|
74
|
-
hasNextPage: z.boolean(),
|
|
75
|
-
hasPreviousPage: z.boolean(),
|
|
76
|
-
startCursor: z.number().nullable(),
|
|
77
|
-
endCursor: z.number().nullable()
|
|
78
|
-
});
|
|
79
|
-
export const zodPaginationQuery = z.object({
|
|
80
|
-
cursor: z.string().optional(),
|
|
81
|
-
first: z.string().optional(),
|
|
82
|
-
last: z.string().optional()
|
|
83
|
-
});
|
|
1
|
+
import{z}from"@hono/zod-openapi";import{and,asc,count,desc,gt,lt}from"drizzle-orm";function parsePaginationParams(params){const cursor=params.query.cursor?parseInt(params.query.cursor,10):undefined;const first=params.query.first?Math.min(parseInt(params.query.first,10),100):undefined;const last=params.query.last?Math.min(parseInt(params.query.last,10),100):undefined;if(first!==undefined&&last!==undefined){throw new Error("Cannot specify both first and last")}if(first!==undefined&&first<0){throw new Error("first must be positive")}if(last!==undefined&&last<0){throw new Error("last must be positive")}return{cursor,first,last}}function getOrderFn(isForward,order){if(isForward){return order==="asc"?asc:desc}return order==="asc"?desc:asc}function buildWhereWithCursor(baseWhere,cursor,isForward,order,table,primaryCursor){if(!cursor)return baseWhere;const cursorFilter=isForward&&order==="asc"||!isForward&&order==="desc"?gt:lt;const cursorWhere=cursorFilter(table[primaryCursor.name],cursor);return baseWhere?and(baseWhere,cursorWhere):cursorWhere}async function fetchTotalCount(c,table,where){const[{count:totalCount}]=await c.get("db").select({count:count()}).from(table).where(where);return totalCount}export async function withPagination({query,table,params,where:whereFromParams,primaryCursor,orderBy:orderByFromParams,c}){const{cursor,first,last}=parsePaginationParams(params);const isForward=last===undefined;const orderFn=getOrderFn(isForward,orderByFromParams.order);const orderBy=orderFn(table[orderByFromParams.column.name]);const where=buildWhereWithCursor(whereFromParams,cursor,isForward,orderByFromParams.order,table,primaryCursor);const totalCount=await fetchTotalCount(c,table,whereFromParams);const limit=(first??last??50)+1;const edges=await query({limit,where,orderBy});const requested=first??last??edges.length;const hasMore=edges.length>requested;const slicedEdges=edges.slice(0,requested);const finalEdges=isForward?slicedEdges:slicedEdges.reverse();const startCursor=finalEdges[0]?.[primaryCursor.name]??null;const endCursor=finalEdges.at(-1)?.[primaryCursor.name]??null;return{pageInfo:{totalCount,count:finalEdges.length,hasNextPage:isForward?hasMore:!!cursor,hasPreviousPage:isForward?!!cursor:hasMore,startCursor,endCursor},edges:finalEdges}}export const zodPaginationPageInfo=z.object({totalCount:z.number(),count:z.number(),hasNextPage:z.boolean(),hasPreviousPage:z.boolean(),startCursor:z.number().nullable(),endCursor:z.number().nullable()});export const zodPaginationQuery=z.object({cursor:z.string().optional(),first:z.string().optional(),last:z.string().optional()});
|
|
@@ -1,63 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
const getResFromReCaptcha = async ({ token, userIp, captchaConfig })=>{
|
|
3
|
-
if (captchaConfig.type === "cloudflare_turnstile") {
|
|
4
|
-
const res = await fetch("https://challenges.cloudflare.com/turnstile/v0/siteverify", {
|
|
5
|
-
method: "POST",
|
|
6
|
-
body: JSON.stringify({
|
|
7
|
-
secret: captchaConfig.secretKey,
|
|
8
|
-
response: token,
|
|
9
|
-
remoteip: userIp
|
|
10
|
-
}),
|
|
11
|
-
headers: {
|
|
12
|
-
"Content-Type": "application/json"
|
|
13
|
-
}
|
|
14
|
-
});
|
|
15
|
-
const data = await res.json();
|
|
16
|
-
return {
|
|
17
|
-
success: data.success,
|
|
18
|
-
score: data.success ? 1 : 0,
|
|
19
|
-
"error-codes": data["error-codes"]
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
if (captchaConfig.type === "recaptcha_v3") {
|
|
23
|
-
const res = await fetch(`https://www.google.com/recaptcha/api/siteverify?secret=${captchaConfig.secretKey}&response=${token}&remoteip=${userIp}`, {
|
|
24
|
-
method: "POST"
|
|
25
|
-
});
|
|
26
|
-
const data = await res.json();
|
|
27
|
-
return {
|
|
28
|
-
success: data.success,
|
|
29
|
-
score: data.score ?? 0,
|
|
30
|
-
"error-codes": data["error-codes"]
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
return {
|
|
34
|
-
success: false,
|
|
35
|
-
score: 0
|
|
36
|
-
};
|
|
37
|
-
};
|
|
38
|
-
export const captchaMiddleware = ()=>{
|
|
39
|
-
return async (c, next)=>{
|
|
40
|
-
const token = c.req.header("x-vitnode-captcha-token");
|
|
41
|
-
const captchaConfig = c.get("core").captcha;
|
|
42
|
-
if (!captchaConfig) {
|
|
43
|
-
await next();
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
if (!token) {
|
|
47
|
-
throw new HTTPException(400, {
|
|
48
|
-
message: "Captcha token is required"
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
const res = await getResFromReCaptcha({
|
|
52
|
-
token,
|
|
53
|
-
userIp: c.get("ipAddress"),
|
|
54
|
-
captchaConfig
|
|
55
|
-
});
|
|
56
|
-
if (!res.success || res.score < 0.5) {
|
|
57
|
-
throw new HTTPException(400, {
|
|
58
|
-
message: "Captcha validation failed"
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
await next();
|
|
62
|
-
};
|
|
63
|
-
};
|
|
1
|
+
import{HTTPException}from"hono/http-exception";const getResFromReCaptcha=async({token,userIp,captchaConfig})=>{if(captchaConfig.type==="cloudflare_turnstile"){const res=await fetch("https://challenges.cloudflare.com/turnstile/v0/siteverify",{method:"POST",body:JSON.stringify({secret:captchaConfig.secretKey,response:token,remoteip:userIp}),headers:{"Content-Type":"application/json"}});const data=await res.json();return{success:data.success,score:data.success?1:0,"error-codes":data["error-codes"]}}if(captchaConfig.type==="recaptcha_v3"){const res=await fetch(`https://www.google.com/recaptcha/api/siteverify?secret=${captchaConfig.secretKey}&response=${token}&remoteip=${userIp}`,{method:"POST"});const data=await res.json();return{success:data.success,score:data.score??0,"error-codes":data["error-codes"]}}return{success:false,score:0}};export const captchaMiddleware=()=>{return async(c,next)=>{const token=c.req.header("x-vitnode-captcha-token");const captchaConfig=c.get("core").captcha;if(!captchaConfig){await next();return}if(!token){throw new HTTPException(400,{message:"Captcha token is required"})}const res=await getResFromReCaptcha({token,userIp:c.get("ipAddress"),captchaConfig});if(!res.success||res.score<.5){throw new HTTPException(400,{message:"Captcha validation failed"})}await next()}};
|
|
@@ -1,19 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
export const cronAuthMiddleware = ()=>{
|
|
3
|
-
return async (c, next)=>{
|
|
4
|
-
const cronSecret = c.get("core").cronSecret;
|
|
5
|
-
if (!cronSecret) {
|
|
6
|
-
throw new HTTPException(403, {
|
|
7
|
-
message: "Cron access not configured"
|
|
8
|
-
});
|
|
9
|
-
}
|
|
10
|
-
const authHeader = c.req.header("authorization");
|
|
11
|
-
const providedSecret = authHeader?.replace("Bearer ", "");
|
|
12
|
-
if (providedSecret !== cronSecret) {
|
|
13
|
-
throw new HTTPException(403, {
|
|
14
|
-
message: "Invalid cron authorization"
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
await next();
|
|
18
|
-
};
|
|
19
|
-
};
|
|
1
|
+
import{HTTPException}from"hono/http-exception";export const cronAuthMiddleware=()=>{return async(c,next)=>{const cronSecret=c.get("core").cronSecret;if(!cronSecret){throw new HTTPException(403,{message:"Cron access not configured"})}const authHeader=c.req.header("authorization");const providedSecret=authHeader?.replace("Bearer ","");if(providedSecret!==cronSecret){throw new HTTPException(403,{message:"Invalid cron authorization"})}await next()}};
|
|
@@ -1,93 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { EmailModel } from "../models/email.js";
|
|
3
|
-
import { SessionModel } from "../models/session.js";
|
|
4
|
-
import { SessionAdminModel } from "../models/session-admin.js";
|
|
5
|
-
import { CONFIG } from "../../lib/config.js";
|
|
6
|
-
import { loggerMiddleware } from "../lib/logger-middleware.js";
|
|
7
|
-
export const globalMiddleware = ({ authorization, metadata, email, dbProvider, captcha, plugins, pathToMessages })=>{
|
|
8
|
-
const pluginsMetadata = plugins.map((plugin)=>({
|
|
9
|
-
id: plugin.pluginId
|
|
10
|
-
}));
|
|
11
|
-
const cronMetadata = plugins.flatMap((plugin)=>plugin.cronJobs.map((cronJob)=>({
|
|
12
|
-
pluginId: plugin.pluginId,
|
|
13
|
-
module: cronJob.module,
|
|
14
|
-
name: cronJob.name,
|
|
15
|
-
schedule: cronJob.schedule,
|
|
16
|
-
handler: cronJob.handler,
|
|
17
|
-
description: cronJob.description
|
|
18
|
-
})));
|
|
19
|
-
const ipHeaderKeys = [
|
|
20
|
-
"x-forwarded-for",
|
|
21
|
-
"x-real-ip",
|
|
22
|
-
"cf-connecting-ip",
|
|
23
|
-
"x-client-ip",
|
|
24
|
-
"x-forwarded",
|
|
25
|
-
"x-cluster-client-ip",
|
|
26
|
-
"forwarded-for",
|
|
27
|
-
"forwarded",
|
|
28
|
-
"via",
|
|
29
|
-
"remote-addr",
|
|
30
|
-
"client-ip",
|
|
31
|
-
"ip",
|
|
32
|
-
"x-ip",
|
|
33
|
-
"true-client-ip",
|
|
34
|
-
"fastly-client-ip",
|
|
35
|
-
"x-fastly-client-ip"
|
|
36
|
-
];
|
|
37
|
-
return async (c, next)=>{
|
|
38
|
-
let ipAddress;
|
|
39
|
-
// Optimize: Try both header methods in a single loop
|
|
40
|
-
for (const key of ipHeaderKeys){
|
|
41
|
-
ipAddress = c.req.header(key);
|
|
42
|
-
if (ipAddress) break;
|
|
43
|
-
ipAddress = c.req.raw.headers.get(key) ?? undefined;
|
|
44
|
-
if (ipAddress) break;
|
|
45
|
-
}
|
|
46
|
-
// Fallback to localhost if nothing found
|
|
47
|
-
c.set("ipAddress", ipAddress ?? "127.0.0.1");
|
|
48
|
-
c.set("db", dbProvider);
|
|
49
|
-
c.set("email", new EmailModel(c));
|
|
50
|
-
c.set("core", {
|
|
51
|
-
pathToMessages,
|
|
52
|
-
metadata,
|
|
53
|
-
email,
|
|
54
|
-
authorization: {
|
|
55
|
-
cookieName: authorization?.cookieName ?? "vitnode_auth",
|
|
56
|
-
cookie_expires: authorization?.cookieExpires ?? 1000 * 60 * 60 * 24 * 90,
|
|
57
|
-
ssoAdapters: authorization?.ssoAdapters ?? [],
|
|
58
|
-
deviceCookieName: authorization?.deviceCookieName ?? "vitnode_device",
|
|
59
|
-
deviceCookieExpires: authorization?.deviceCookieExpires ?? 1000 * 60 * 60 * 24 * 365,
|
|
60
|
-
adminCookieName: authorization?.adminCookieName ?? "vitnode_auth_admin",
|
|
61
|
-
adminCookieExpires: authorization?.adminCookieExpires ?? 1000 * 60 * 60 * 24 * 1,
|
|
62
|
-
cookieSecure: authorization?.cookieSecure ?? true
|
|
63
|
-
},
|
|
64
|
-
captcha,
|
|
65
|
-
cronSecret: CONFIG.cronJobSecret,
|
|
66
|
-
plugins: pluginsMetadata,
|
|
67
|
-
cron: cronMetadata
|
|
68
|
-
});
|
|
69
|
-
const user = await new SessionModel(c).getUser();
|
|
70
|
-
c.set("user", user);
|
|
71
|
-
c.set("admin", null);
|
|
72
|
-
c.set("log", loggerMiddleware(c));
|
|
73
|
-
await next();
|
|
74
|
-
};
|
|
75
|
-
};
|
|
76
|
-
export const pluginMiddleware = (pluginId)=>{
|
|
77
|
-
return async (c, next)=>{
|
|
78
|
-
c.set("plugin", {
|
|
79
|
-
id: pluginId
|
|
80
|
-
});
|
|
81
|
-
await next();
|
|
82
|
-
};
|
|
83
|
-
};
|
|
84
|
-
export const globalAdminMiddleware = ()=>{
|
|
85
|
-
return async (c, next)=>{
|
|
86
|
-
const user = await new SessionAdminModel(c).getUser();
|
|
87
|
-
if (!user) throw new HTTPException(403);
|
|
88
|
-
c.set("admin", {
|
|
89
|
-
user
|
|
90
|
-
});
|
|
91
|
-
await next();
|
|
92
|
-
};
|
|
93
|
-
};
|
|
1
|
+
import{HTTPException}from"hono/http-exception";import{EmailModel}from"../models/email.js";import{SessionModel}from"../models/session.js";import{SessionAdminModel}from"../models/session-admin.js";import{CONFIG}from"../../lib/config.js";import{loggerMiddleware}from"../lib/logger-middleware.js";export const globalMiddleware=({authorization,metadata,email,dbProvider,captcha,plugins,pathToMessages})=>{const pluginsMetadata=plugins.map(plugin=>({id:plugin.pluginId}));const cronMetadata=plugins.flatMap(plugin=>plugin.cronJobs.map(cronJob=>({pluginId:plugin.pluginId,module:cronJob.module,name:cronJob.name,schedule:cronJob.schedule,handler:cronJob.handler,description:cronJob.description})));const ipHeaderKeys=["x-forwarded-for","x-real-ip","cf-connecting-ip","x-client-ip","x-forwarded","x-cluster-client-ip","forwarded-for","forwarded","via","remote-addr","client-ip","ip","x-ip","true-client-ip","fastly-client-ip","x-fastly-client-ip"];return async(c,next)=>{let ipAddress;for(const key of ipHeaderKeys){ipAddress=c.req.header(key);if(ipAddress)break;ipAddress=c.req.raw.headers.get(key)??undefined;if(ipAddress)break}c.set("ipAddress",ipAddress??"127.0.0.1");c.set("db",dbProvider);c.set("email",new EmailModel(c));c.set("core",{pathToMessages,metadata,email,authorization:{cookieName:authorization?.cookieName??"vitnode_auth",cookie_expires:authorization?.cookieExpires??1e3*60*60*24*90,ssoAdapters:authorization?.ssoAdapters??[],deviceCookieName:authorization?.deviceCookieName??"vitnode_device",deviceCookieExpires:authorization?.deviceCookieExpires??1e3*60*60*24*365,adminCookieName:authorization?.adminCookieName??"vitnode_auth_admin",adminCookieExpires:authorization?.adminCookieExpires??1e3*60*60*24*1,cookieSecure:authorization?.cookieSecure??true},captcha,cronSecret:CONFIG.cronJobSecret,plugins:pluginsMetadata,cron:cronMetadata});const user=await new SessionModel(c).getUser();c.set("user",user);c.set("admin",null);c.set("log",loggerMiddleware(c));await next()}};export const pluginMiddleware=pluginId=>{return async(c,next)=>{c.set("plugin",{id:pluginId});await next()}};export const globalAdminMiddleware=()=>{return async(c,next)=>{const user=await new SessionAdminModel(c).getUser();if(!user)throw new HTTPException(403);c.set("admin",{user});await next()}};
|
|
@@ -1,32 +1 @@
|
|
|
1
|
-
import { RateLimiterMemory }
|
|
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: options?.points ?? 80,
|
|
8
|
-
duration: options?.duration ?? 60,
|
|
9
|
-
...options
|
|
10
|
-
});
|
|
11
|
-
};
|
|
12
|
-
export const rateLimiterMiddleware = (options)=>{
|
|
13
|
-
if (CONFIG.node_development) {
|
|
14
|
-
// In development, we disable the rate limiter for easier testing
|
|
15
|
-
return async (_c, next)=>{
|
|
16
|
-
await next();
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
const rateLimiter = createRateLimiter({
|
|
20
|
-
...options,
|
|
21
|
-
keyPrefix: "vitnode-api-rate-limiter"
|
|
22
|
-
});
|
|
23
|
-
return async (c, next)=>{
|
|
24
|
-
const key = c.get("ipAddress");
|
|
25
|
-
try {
|
|
26
|
-
await rateLimiter.consume(key);
|
|
27
|
-
} catch {
|
|
28
|
-
return c.text("Too Many Requests", 429);
|
|
29
|
-
}
|
|
30
|
-
await next();
|
|
31
|
-
};
|
|
32
|
-
};
|
|
1
|
+
import{RateLimiterMemory}from"rate-limiter-flexible";import{CONFIG}from"../../lib/config.js";const createRateLimiter=({keyPrefix,...options})=>{return new RateLimiterMemory({keyPrefix,points:options?.points??80,duration:options?.duration??60,...options})};export const rateLimiterMiddleware=options=>{if(CONFIG.node_development){return async(_c,next)=>{await next()}}const rateLimiter=createRateLimiter({...options,keyPrefix:"vitnode-api-rate-limiter"});return async(c,next)=>{const key=c.get("ipAddress");try{await rateLimiter.consume(key)}catch{return c.text("Too Many Requests",429)}await next()}};
|
|
@@ -1,61 +1 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getCookie, setCookie } from "hono/cookie";
|
|
3
|
-
import { randomBytes } from "node:crypto";
|
|
4
|
-
import { core_sessions_known_devices } from "../../database/sessions.js";
|
|
5
|
-
import { CONFIG } from "../../lib/config.js";
|
|
6
|
-
export class DeviceModel {
|
|
7
|
-
constructor(c){
|
|
8
|
-
this.c = c;
|
|
9
|
-
}
|
|
10
|
-
c;
|
|
11
|
-
async createDevice() {
|
|
12
|
-
const publicId = randomBytes(16).toString("hex");
|
|
13
|
-
const [device] = await this.c.get("db").insert(core_sessions_known_devices).values({
|
|
14
|
-
publicId,
|
|
15
|
-
ipAddress: this.c.get("ipAddress"),
|
|
16
|
-
userAgent: this.getUserAgent()
|
|
17
|
-
}).returning({
|
|
18
|
-
id: core_sessions_known_devices.id
|
|
19
|
-
});
|
|
20
|
-
this.setCookieDevice(publicId);
|
|
21
|
-
return {
|
|
22
|
-
id: device.id,
|
|
23
|
-
publicId
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
getUserAgent() {
|
|
27
|
-
return this.c.req.header("User-Agent") ?? "node";
|
|
28
|
-
}
|
|
29
|
-
setCookieDevice(publicDeviceId) {
|
|
30
|
-
setCookie(this.c, this.c.get("core").authorization.deviceCookieName, publicDeviceId, {
|
|
31
|
-
httpOnly: true,
|
|
32
|
-
secure: this.c.get("core").authorization.cookieSecure,
|
|
33
|
-
path: "/",
|
|
34
|
-
domain: CONFIG.web.hostname,
|
|
35
|
-
expires: new Date(Date.now() + this.c.get("core").authorization.deviceCookieExpires)
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
async getDeviceId() {
|
|
39
|
-
const deviceIdFromCookie = getCookie(this.c, this.c.get("core").authorization.deviceCookieName);
|
|
40
|
-
try {
|
|
41
|
-
if (deviceIdFromCookie) {
|
|
42
|
-
const [device] = await this.c.get("db").select({
|
|
43
|
-
id: core_sessions_known_devices.id
|
|
44
|
-
}).from(core_sessions_known_devices).where(eq(core_sessions_known_devices.publicId, deviceIdFromCookie));
|
|
45
|
-
if (!device) {
|
|
46
|
-
return await this.createDevice();
|
|
47
|
-
}
|
|
48
|
-
await this.c.get("db").update(core_sessions_known_devices).set({
|
|
49
|
-
ipAddress: this.c.get("ipAddress"),
|
|
50
|
-
userAgent: this.getUserAgent()
|
|
51
|
-
}).where(eq(core_sessions_known_devices.publicId, deviceIdFromCookie));
|
|
52
|
-
return {
|
|
53
|
-
id: device.id,
|
|
54
|
-
publicId: deviceIdFromCookie
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
} catch {
|
|
58
|
-
/* empty */ }
|
|
59
|
-
return await this.createDevice();
|
|
60
|
-
}
|
|
61
|
-
}
|
|
1
|
+
import{eq}from"drizzle-orm";import{getCookie,setCookie}from"hono/cookie";import{randomBytes}from"node:crypto";import{core_sessions_known_devices}from"../../database/sessions.js";import{CONFIG}from"../../lib/config.js";export class DeviceModel{constructor(c){this.c=c}c;async createDevice(){const publicId=randomBytes(16).toString("hex");const[device]=await this.c.get("db").insert(core_sessions_known_devices).values({publicId,ipAddress:this.c.get("ipAddress"),userAgent:this.getUserAgent()}).returning({id:core_sessions_known_devices.id});this.setCookieDevice(publicId);return{id:device.id,publicId}}getUserAgent(){return this.c.req.header("User-Agent")??"node"}setCookieDevice(publicDeviceId){setCookie(this.c,this.c.get("core").authorization.deviceCookieName,publicDeviceId,{httpOnly:true,secure:this.c.get("core").authorization.cookieSecure,path:"/",domain:CONFIG.web.hostname,expires:new Date(Date.now()+this.c.get("core").authorization.deviceCookieExpires)})}async getDeviceId(){const deviceIdFromCookie=getCookie(this.c,this.c.get("core").authorization.deviceCookieName);try{if(deviceIdFromCookie){const[device]=await this.c.get("db").select({id:core_sessions_known_devices.id}).from(core_sessions_known_devices).where(eq(core_sessions_known_devices.publicId,deviceIdFromCookie));if(!device){return await this.createDevice()}await this.c.get("db").update(core_sessions_known_devices).set({ipAddress:this.c.get("ipAddress"),userAgent:this.getUserAgent()}).where(eq(core_sessions_known_devices.publicId,deviceIdFromCookie));return{id:device.id,publicId:deviceIdFromCookie}}}catch{}return await this.createDevice()}}
|