@sonicjs-cms/core 2.4.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-CPXAVWCU.js → chunk-3YUHXWSG.js} +278 -3
- package/dist/chunk-3YUHXWSG.js.map +1 -0
- package/dist/chunk-AI2JJIJX.cjs +211 -0
- package/dist/chunk-AI2JJIJX.cjs.map +1 -0
- package/dist/{chunk-VNCYCH3H.js → chunk-BHNDALCA.js} +56 -4
- package/dist/chunk-BHNDALCA.js.map +1 -0
- package/dist/{chunk-2MI3LZFH.cjs → chunk-I4V3VZWF.cjs} +46 -2
- package/dist/chunk-I4V3VZWF.cjs.map +1 -0
- package/dist/{chunk-DTLB6UIH.cjs → chunk-LWG2MWDA.cjs} +280 -2
- package/dist/chunk-LWG2MWDA.cjs.map +1 -0
- package/dist/{chunk-FT6NBHNX.js → chunk-OJZ45OJD.js} +507 -275
- package/dist/chunk-OJZ45OJD.js.map +1 -0
- package/dist/chunk-QDBNW7KQ.js +209 -0
- package/dist/chunk-QDBNW7KQ.js.map +1 -0
- package/dist/{chunk-DXM575E2.js → chunk-TJTWRO4G.js} +5 -5
- package/dist/chunk-TJTWRO4G.js.map +1 -0
- package/dist/{chunk-A4SVOGG6.cjs → chunk-UAQL2VWX.cjs} +591 -360
- package/dist/chunk-UAQL2VWX.cjs.map +1 -0
- package/dist/{chunk-D2NLCPO2.js → chunk-VEL7QRYI.js} +46 -2
- package/dist/chunk-VEL7QRYI.js.map +1 -0
- package/dist/{chunk-7I5INVNR.cjs → chunk-YYV3XQOQ.cjs} +6 -6
- package/dist/chunk-YYV3XQOQ.cjs.map +1 -0
- package/dist/{chunk-FYEDK7K7.cjs → chunk-ZWV3EBZ7.cjs} +58 -3
- package/dist/chunk-ZWV3EBZ7.cjs.map +1 -0
- package/dist/{collection-config-FLlGtsh9.d.cts → collection-config-B6gMPunn.d.cts} +9 -1
- package/dist/{collection-config-FLlGtsh9.d.ts → collection-config-B6gMPunn.d.ts} +9 -1
- package/dist/index.cjs +90 -87
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +12 -9
- package/dist/index.js.map +1 -1
- package/dist/middleware.cjs +23 -23
- package/dist/middleware.js +2 -2
- package/dist/migrations-NIEUFG44.cjs +13 -0
- package/dist/{migrations-32QAYLWJ.cjs.map → migrations-NIEUFG44.cjs.map} +1 -1
- package/dist/migrations-TGZKJKV4.js +4 -0
- package/dist/{migrations-57ZHBQ4X.js.map → migrations-TGZKJKV4.js.map} +1 -1
- package/dist/{plugin-bootstrap-C0E3jdz-.d.cts → plugin-bootstrap-SHsdjE6X.d.cts} +1 -1
- package/dist/{plugin-bootstrap-CDh0JHtW.d.ts → plugin-bootstrap-dYhD9fQR.d.ts} +1 -1
- package/dist/plugin-manager-Baa6xXqB.d.ts +328 -0
- package/dist/plugin-manager-vBal9Zip.d.cts +328 -0
- package/dist/plugins.cjs +20 -7
- package/dist/plugins.d.cts +53 -310
- package/dist/plugins.d.ts +53 -310
- package/dist/plugins.js +2 -1
- package/dist/routes.cjs +25 -24
- package/dist/routes.js +5 -4
- package/dist/services.cjs +2 -2
- package/dist/services.d.cts +2 -2
- package/dist/services.d.ts +2 -2
- package/dist/services.js +1 -1
- package/dist/types.d.cts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/utils.cjs +23 -11
- package/dist/utils.d.cts +38 -1
- package/dist/utils.d.ts +38 -1
- package/dist/utils.js +1 -1
- package/migrations/027_fix_slug_field_type.sql +18 -0
- package/migrations/028_fix_slug_field_type_in_schemas.sql +30 -0
- package/package.json +2 -1
- package/dist/chunk-2MI3LZFH.cjs.map +0 -1
- package/dist/chunk-7I5INVNR.cjs.map +0 -1
- package/dist/chunk-A4SVOGG6.cjs.map +0 -1
- package/dist/chunk-CPXAVWCU.js.map +0 -1
- package/dist/chunk-D2NLCPO2.js.map +0 -1
- package/dist/chunk-DTLB6UIH.cjs.map +0 -1
- package/dist/chunk-DXM575E2.js.map +0 -1
- package/dist/chunk-FT6NBHNX.js.map +0 -1
- package/dist/chunk-FYEDK7K7.cjs.map +0 -1
- package/dist/chunk-VNCYCH3H.js.map +0 -1
- package/dist/migrations-32QAYLWJ.cjs +0 -13
- package/dist/migrations-57ZHBQ4X.js +0 -4
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PluginBuilder } from './chunk-QDBNW7KQ.js';
|
|
1
2
|
import { HOOKS } from './chunk-LOUJRBXV.js';
|
|
2
3
|
import { __commonJS, __toESM } from './chunk-V4OQ3NZ2.js';
|
|
3
4
|
import { z } from 'zod';
|
|
@@ -3081,6 +3082,280 @@ var PluginManager = class {
|
|
|
3081
3082
|
}
|
|
3082
3083
|
};
|
|
3083
3084
|
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3085
|
+
// src/plugins/core-plugins/turnstile-plugin/manifest.json
|
|
3086
|
+
var manifest_default = {
|
|
3087
|
+
id: "turnstile",
|
|
3088
|
+
name: "Cloudflare Turnstile",
|
|
3089
|
+
description: "CAPTCHA-free bot protection using Cloudflare Turnstile. Provides reusable verification for any form.",
|
|
3090
|
+
version: "1.0.0",
|
|
3091
|
+
author: "SonicJS",
|
|
3092
|
+
category: "security",
|
|
3093
|
+
icon: "shield-check",
|
|
3094
|
+
homepage: "https://developers.cloudflare.com/turnstile/",
|
|
3095
|
+
repository: "https://github.com/sonicjs/sonicjs",
|
|
3096
|
+
license: "MIT",
|
|
3097
|
+
permissions: ["settings:write", "admin:access"],
|
|
3098
|
+
dependencies: [],
|
|
3099
|
+
configSchema: {
|
|
3100
|
+
siteKey: {
|
|
3101
|
+
type: "string",
|
|
3102
|
+
label: "Site Key",
|
|
3103
|
+
description: "Your Cloudflare Turnstile site key (public)",
|
|
3104
|
+
required: true
|
|
3105
|
+
},
|
|
3106
|
+
secretKey: {
|
|
3107
|
+
type: "string",
|
|
3108
|
+
label: "Secret Key",
|
|
3109
|
+
description: "Your Cloudflare Turnstile secret key (private)",
|
|
3110
|
+
required: true,
|
|
3111
|
+
sensitive: true
|
|
3112
|
+
},
|
|
3113
|
+
theme: {
|
|
3114
|
+
type: "select",
|
|
3115
|
+
label: "Widget Theme",
|
|
3116
|
+
description: "Visual theme for the Turnstile widget",
|
|
3117
|
+
default: "auto",
|
|
3118
|
+
options: [
|
|
3119
|
+
{ value: "light", label: "Light" },
|
|
3120
|
+
{ value: "dark", label: "Dark" },
|
|
3121
|
+
{ value: "auto", label: "Auto" }
|
|
3122
|
+
]
|
|
3123
|
+
},
|
|
3124
|
+
size: {
|
|
3125
|
+
type: "select",
|
|
3126
|
+
label: "Widget Size",
|
|
3127
|
+
description: "Size of the Turnstile widget",
|
|
3128
|
+
default: "normal",
|
|
3129
|
+
options: [
|
|
3130
|
+
{ value: "normal", label: "Normal" },
|
|
3131
|
+
{ value: "compact", label: "Compact" }
|
|
3132
|
+
]
|
|
3133
|
+
},
|
|
3134
|
+
mode: {
|
|
3135
|
+
type: "select",
|
|
3136
|
+
label: "Widget Mode",
|
|
3137
|
+
description: "Managed: Adaptive challenge. Non-Interactive: Always visible, minimal friction. Invisible: No visible widget",
|
|
3138
|
+
default: "managed",
|
|
3139
|
+
options: [
|
|
3140
|
+
{ value: "managed", label: "Managed (Recommended)" },
|
|
3141
|
+
{ value: "non-interactive", label: "Non-Interactive" },
|
|
3142
|
+
{ value: "invisible", label: "Invisible" }
|
|
3143
|
+
]
|
|
3144
|
+
},
|
|
3145
|
+
appearance: {
|
|
3146
|
+
type: "select",
|
|
3147
|
+
label: "Appearance",
|
|
3148
|
+
description: "When the Turnstile challenge is executed. Always: Verifies immediately. Execute: Challenge on form submit. Interaction Only: Only after user interaction",
|
|
3149
|
+
default: "always",
|
|
3150
|
+
options: [
|
|
3151
|
+
{ value: "always", label: "Always" },
|
|
3152
|
+
{ value: "execute", label: "Execute" },
|
|
3153
|
+
{ value: "interaction-only", label: "Interaction Only" }
|
|
3154
|
+
]
|
|
3155
|
+
},
|
|
3156
|
+
preClearance: {
|
|
3157
|
+
type: "boolean",
|
|
3158
|
+
label: "Enable Pre-clearance",
|
|
3159
|
+
description: "Issue a clearance cookie that bypasses Cloudflare Firewall Rules (as if the user passed a challenge on your proxied site)",
|
|
3160
|
+
default: false
|
|
3161
|
+
},
|
|
3162
|
+
preClearanceLevel: {
|
|
3163
|
+
type: "select",
|
|
3164
|
+
label: "Pre-clearance Level",
|
|
3165
|
+
description: "Controls which Cloudflare Firewall Rules the clearance cookie bypasses. Only applies if Pre-clearance is enabled",
|
|
3166
|
+
default: "managed",
|
|
3167
|
+
options: [
|
|
3168
|
+
{ value: "interactive", label: "Interactive - Bypasses Interactive, Managed & JS Challenge Rules" },
|
|
3169
|
+
{ value: "managed", label: "Managed - Bypasses Managed & JS Challenge Rules" },
|
|
3170
|
+
{ value: "non-interactive", label: "Non-interactive - Bypasses JS Challenge Rules only" }
|
|
3171
|
+
]
|
|
3172
|
+
},
|
|
3173
|
+
enabled: {
|
|
3174
|
+
type: "boolean",
|
|
3175
|
+
label: "Enable Turnstile",
|
|
3176
|
+
description: "Enable or disable Turnstile verification globally",
|
|
3177
|
+
default: true
|
|
3178
|
+
}
|
|
3179
|
+
},
|
|
3180
|
+
adminMenu: {
|
|
3181
|
+
label: "Turnstile",
|
|
3182
|
+
icon: "shield-check",
|
|
3183
|
+
href: "/admin/plugins/turnstile/settings",
|
|
3184
|
+
parentId: "plugins",
|
|
3185
|
+
order: 100
|
|
3186
|
+
}
|
|
3187
|
+
};
|
|
3188
|
+
|
|
3189
|
+
// src/plugins/core-plugins/turnstile-plugin/services/turnstile.ts
|
|
3190
|
+
var TurnstileService = class {
|
|
3191
|
+
db;
|
|
3192
|
+
VERIFY_URL = "https://challenges.cloudflare.com/turnstile/v0/siteverify";
|
|
3193
|
+
constructor(db) {
|
|
3194
|
+
this.db = db;
|
|
3195
|
+
}
|
|
3196
|
+
/**
|
|
3197
|
+
* Get Turnstile settings from database
|
|
3198
|
+
*/
|
|
3199
|
+
async getSettings() {
|
|
3200
|
+
try {
|
|
3201
|
+
const plugin = await this.db.prepare(`SELECT settings FROM plugins WHERE id = ? LIMIT 1`).bind(manifest_default.id).first();
|
|
3202
|
+
if (!plugin || !plugin.settings) {
|
|
3203
|
+
return null;
|
|
3204
|
+
}
|
|
3205
|
+
return JSON.parse(plugin.settings);
|
|
3206
|
+
} catch (error) {
|
|
3207
|
+
console.error("Error getting Turnstile settings:", error);
|
|
3208
|
+
return null;
|
|
3209
|
+
}
|
|
3210
|
+
}
|
|
3211
|
+
/**
|
|
3212
|
+
* Verify a Turnstile token with Cloudflare
|
|
3213
|
+
*/
|
|
3214
|
+
async verifyToken(token, remoteIp) {
|
|
3215
|
+
try {
|
|
3216
|
+
const settings = await this.getSettings();
|
|
3217
|
+
if (!settings) {
|
|
3218
|
+
return { success: false, error: "Turnstile not configured" };
|
|
3219
|
+
}
|
|
3220
|
+
if (!settings.enabled) {
|
|
3221
|
+
return { success: true };
|
|
3222
|
+
}
|
|
3223
|
+
if (!settings.secretKey) {
|
|
3224
|
+
return { success: false, error: "Turnstile secret key not configured" };
|
|
3225
|
+
}
|
|
3226
|
+
const formData = new FormData();
|
|
3227
|
+
formData.append("secret", settings.secretKey);
|
|
3228
|
+
formData.append("response", token);
|
|
3229
|
+
if (remoteIp) {
|
|
3230
|
+
formData.append("remoteip", remoteIp);
|
|
3231
|
+
}
|
|
3232
|
+
const response = await fetch(this.VERIFY_URL, {
|
|
3233
|
+
method: "POST",
|
|
3234
|
+
body: formData
|
|
3235
|
+
});
|
|
3236
|
+
if (!response.ok) {
|
|
3237
|
+
return { success: false, error: "Turnstile verification request failed" };
|
|
3238
|
+
}
|
|
3239
|
+
const result = await response.json();
|
|
3240
|
+
if (!result.success) {
|
|
3241
|
+
const errorCode = result["error-codes"]?.[0] || "unknown-error";
|
|
3242
|
+
return { success: false, error: `Turnstile verification failed: ${errorCode}` };
|
|
3243
|
+
}
|
|
3244
|
+
return { success: true };
|
|
3245
|
+
} catch (error) {
|
|
3246
|
+
console.error("Error verifying Turnstile token:", error);
|
|
3247
|
+
return { success: false, error: "Turnstile verification error" };
|
|
3248
|
+
}
|
|
3249
|
+
}
|
|
3250
|
+
/**
|
|
3251
|
+
* Save Turnstile settings to database
|
|
3252
|
+
*/
|
|
3253
|
+
async saveSettings(settings) {
|
|
3254
|
+
try {
|
|
3255
|
+
await this.db.prepare(`UPDATE plugins SET settings = ?, updated_at = ? WHERE id = ?`).bind(JSON.stringify(settings), Date.now(), manifest_default.id).run();
|
|
3256
|
+
console.log("Turnstile settings saved successfully");
|
|
3257
|
+
} catch (error) {
|
|
3258
|
+
console.error("Error saving Turnstile settings:", error);
|
|
3259
|
+
throw new Error("Failed to save Turnstile settings");
|
|
3260
|
+
}
|
|
3261
|
+
}
|
|
3262
|
+
/**
|
|
3263
|
+
* Check if Turnstile is enabled
|
|
3264
|
+
*/
|
|
3265
|
+
async isEnabled() {
|
|
3266
|
+
const settings = await this.getSettings();
|
|
3267
|
+
return settings?.enabled === true && !!settings.siteKey && !!settings.secretKey;
|
|
3268
|
+
}
|
|
3269
|
+
};
|
|
3270
|
+
|
|
3271
|
+
// src/plugins/core-plugins/turnstile-plugin/middleware/verify.ts
|
|
3272
|
+
async function verifyTurnstile(c, next) {
|
|
3273
|
+
const db = c.get("db") || c.env?.DB;
|
|
3274
|
+
if (!db) {
|
|
3275
|
+
console.error("Turnstile middleware: Database not available");
|
|
3276
|
+
return c.json({ error: "Database not available" }, 500);
|
|
3277
|
+
}
|
|
3278
|
+
const turnstileService = new TurnstileService(db);
|
|
3279
|
+
const isEnabled = await turnstileService.isEnabled();
|
|
3280
|
+
if (!isEnabled) {
|
|
3281
|
+
return next();
|
|
3282
|
+
}
|
|
3283
|
+
let token;
|
|
3284
|
+
let body;
|
|
3285
|
+
if (c.req.method === "POST") {
|
|
3286
|
+
const contentType = c.req.header("content-type") || "";
|
|
3287
|
+
if (contentType.includes("application/json")) {
|
|
3288
|
+
body = await c.req.json();
|
|
3289
|
+
token = body["cf-turnstile-response"] || body["turnstile-token"];
|
|
3290
|
+
c.set("requestBody", body);
|
|
3291
|
+
} else if (contentType.includes("application/x-www-form-urlencoded") || contentType.includes("multipart/form-data")) {
|
|
3292
|
+
const formData = await c.req.formData();
|
|
3293
|
+
token = formData.get("cf-turnstile-response")?.toString() || formData.get("turnstile-token")?.toString();
|
|
3294
|
+
}
|
|
3295
|
+
}
|
|
3296
|
+
if (!token) {
|
|
3297
|
+
return c.json({
|
|
3298
|
+
error: "Turnstile token missing",
|
|
3299
|
+
message: "Please complete the verification challenge"
|
|
3300
|
+
}, 400);
|
|
3301
|
+
}
|
|
3302
|
+
const remoteIp = c.req.header("cf-connecting-ip") || c.req.header("x-forwarded-for");
|
|
3303
|
+
const result = await turnstileService.verifyToken(token, remoteIp);
|
|
3304
|
+
if (!result.success) {
|
|
3305
|
+
return c.json({
|
|
3306
|
+
error: "Turnstile verification failed",
|
|
3307
|
+
message: result.error || "Verification failed. Please try again."
|
|
3308
|
+
}, 403);
|
|
3309
|
+
}
|
|
3310
|
+
return next();
|
|
3311
|
+
}
|
|
3312
|
+
function createTurnstileMiddleware(options) {
|
|
3313
|
+
return async (c, next) => {
|
|
3314
|
+
const db = c.get("db") || c.env?.DB;
|
|
3315
|
+
if (!db) {
|
|
3316
|
+
return options?.onError?.(c, "Database not available") || c.json({ error: "Database not available" }, 500);
|
|
3317
|
+
}
|
|
3318
|
+
const turnstileService = new TurnstileService(db);
|
|
3319
|
+
const isEnabled = await turnstileService.isEnabled();
|
|
3320
|
+
if (!isEnabled) {
|
|
3321
|
+
return next();
|
|
3322
|
+
}
|
|
3323
|
+
let token;
|
|
3324
|
+
const contentType = c.req.header("content-type") || "";
|
|
3325
|
+
if (contentType.includes("application/json")) {
|
|
3326
|
+
const body = await c.req.json();
|
|
3327
|
+
token = body["cf-turnstile-response"] || body["turnstile-token"];
|
|
3328
|
+
c.set("requestBody", body);
|
|
3329
|
+
} else if (contentType.includes("application/x-www-form-urlencoded") || contentType.includes("multipart/form-data")) {
|
|
3330
|
+
const formData = await c.req.formData();
|
|
3331
|
+
token = formData.get("cf-turnstile-response")?.toString() || formData.get("turnstile-token")?.toString();
|
|
3332
|
+
}
|
|
3333
|
+
if (!token) {
|
|
3334
|
+
return options?.onMissing?.(c) || c.json({ error: "Turnstile token missing" }, 400);
|
|
3335
|
+
}
|
|
3336
|
+
const remoteIp = c.req.header("cf-connecting-ip") || c.req.header("x-forwarded-for");
|
|
3337
|
+
const result = await turnstileService.verifyToken(token, remoteIp);
|
|
3338
|
+
if (!result.success) {
|
|
3339
|
+
return options?.onError?.(c, result.error || "Verification failed") || c.json({ error: "Turnstile verification failed", message: result.error }, 403);
|
|
3340
|
+
}
|
|
3341
|
+
return next();
|
|
3342
|
+
};
|
|
3343
|
+
}
|
|
3344
|
+
|
|
3345
|
+
// src/plugins/core-plugins/turnstile-plugin/index.ts
|
|
3346
|
+
new PluginBuilder({
|
|
3347
|
+
name: manifest_default.name,
|
|
3348
|
+
version: manifest_default.version,
|
|
3349
|
+
description: manifest_default.description,
|
|
3350
|
+
author: { name: manifest_default.author }
|
|
3351
|
+
}).metadata({
|
|
3352
|
+
description: manifest_default.description,
|
|
3353
|
+
author: { name: manifest_default.author }
|
|
3354
|
+
}).addService("turnstile", TurnstileService).addSingleMiddleware("verifyTurnstile", verifyTurnstile, {
|
|
3355
|
+
description: "Verify Cloudflare Turnstile token",
|
|
3356
|
+
global: false
|
|
3357
|
+
}).build();
|
|
3358
|
+
|
|
3359
|
+
export { HookSystemImpl, HookUtils, PluginManager, PluginRegistryImpl, PluginValidator, ScopedHookSystem, TurnstileService, createTurnstileMiddleware, verifyTurnstile };
|
|
3360
|
+
//# sourceMappingURL=chunk-3YUHXWSG.js.map
|
|
3361
|
+
//# sourceMappingURL=chunk-3YUHXWSG.js.map
|