@sonicjs-cms/core 2.11.0 → 2.12.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/{app-Ozl9agJG.d.cts → app-COElO4Rm.d.cts} +6 -1
- package/dist/{app-Ozl9agJG.d.ts → app-COElO4Rm.d.ts} +6 -1
- package/dist/{chunk-BUU2US2Z.js → chunk-6R6LAUR7.js} +3 -3
- package/dist/{chunk-BUU2US2Z.js.map → chunk-6R6LAUR7.js.map} +1 -1
- package/dist/{chunk-JJS7JZCH.js → chunk-76TX6XND.js} +4 -2
- package/dist/chunk-76TX6XND.js.map +1 -0
- package/dist/{chunk-DE5YTNCD.cjs → chunk-AG3SIPP7.cjs} +9 -2
- package/dist/chunk-AG3SIPP7.cjs.map +1 -0
- package/dist/{chunk-74XCYEI7.js → chunk-BWZBKLOC.js} +3 -3
- package/dist/{chunk-74XCYEI7.js.map → chunk-BWZBKLOC.js.map} +1 -1
- package/dist/{chunk-NMLFKXWW.js → chunk-H3XXBAMO.js} +15 -2
- package/dist/chunk-H3XXBAMO.js.map +1 -0
- package/dist/{chunk-LTKV7AE5.cjs → chunk-H4NHRZ6Y.cjs} +4 -2
- package/dist/chunk-H4NHRZ6Y.cjs.map +1 -0
- package/dist/{chunk-GKRGDJGG.js → chunk-HXIYYE57.js} +6 -6
- package/dist/{chunk-GKRGDJGG.js.map → chunk-HXIYYE57.js.map} +1 -1
- package/dist/{chunk-6BVLPACH.cjs → chunk-I6FFGQIT.cjs} +15 -2
- package/dist/chunk-I6FFGQIT.cjs.map +1 -0
- package/dist/{chunk-JTQBNSZX.js → chunk-NDFHQOPP.js} +4176 -3805
- package/dist/chunk-NDFHQOPP.js.map +1 -0
- package/dist/{chunk-LFAQUR7P.cjs → chunk-NZWFCUDA.cjs} +26 -2
- package/dist/chunk-NZWFCUDA.cjs.map +1 -0
- package/dist/{chunk-3G7XX4UI.cjs → chunk-RBXFXT7H.cjs} +9 -9
- package/dist/{chunk-3G7XX4UI.cjs.map → chunk-RBXFXT7H.cjs.map} +1 -1
- package/dist/{chunk-QLPFENZ2.cjs → chunk-RXNLGINR.cjs} +3 -3
- package/dist/{chunk-QLPFENZ2.cjs.map → chunk-RXNLGINR.cjs.map} +1 -1
- package/dist/{chunk-VJCLJH3X.js → chunk-TBJY2FF7.js} +26 -2
- package/dist/chunk-TBJY2FF7.js.map +1 -0
- package/dist/{chunk-H55AYIRI.js → chunk-U3ZMGBVC.js} +9 -2
- package/dist/chunk-U3ZMGBVC.js.map +1 -0
- package/dist/{chunk-B2ASV5RD.cjs → chunk-VHNTCB2X.cjs} +10 -10
- package/dist/{chunk-B2ASV5RD.cjs.map → chunk-VHNTCB2X.cjs.map} +1 -1
- package/dist/{chunk-ASAEJ4B7.cjs → chunk-ZV6ZCJ74.cjs} +4376 -4001
- package/dist/chunk-ZV6ZCJ74.cjs.map +1 -0
- package/dist/index.cjs +1828 -170
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +53 -5
- package/dist/index.d.ts +53 -5
- package/dist/index.js +1656 -13
- package/dist/index.js.map +1 -1
- package/dist/middleware.cjs +29 -29
- package/dist/middleware.d.cts +1 -1
- package/dist/middleware.d.ts +1 -1
- package/dist/middleware.js +3 -3
- package/dist/migrations-USSEHJC7.js +4 -0
- package/dist/{migrations-UFVJTPVT.js.map → migrations-USSEHJC7.js.map} +1 -1
- package/dist/migrations-ZE6IZNLB.cjs +13 -0
- package/dist/{migrations-VNYOSUNE.cjs.map → migrations-ZE6IZNLB.cjs.map} +1 -1
- package/dist/{plugin-bootstrap-DXBAYaqM.d.ts → plugin-bootstrap-CZ1GDum7.d.ts} +802 -1
- package/dist/{plugin-bootstrap-DCXpeQVb.d.cts → plugin-bootstrap-DVGLQrcO.d.cts} +802 -1
- package/dist/routes.cjs +30 -30
- package/dist/routes.d.cts +1 -1
- package/dist/routes.d.ts +1 -1
- package/dist/routes.js +7 -7
- package/dist/services.cjs +39 -39
- package/dist/services.d.cts +1 -1
- package/dist/services.d.ts +1 -1
- package/dist/services.js +3 -3
- package/dist/templates.cjs +19 -19
- package/dist/templates.js +2 -2
- package/dist/utils.cjs +11 -11
- package/dist/utils.js +1 -1
- package/migrations/034_security_audit_plugin.sql +27 -0
- package/package.json +1 -1
- package/dist/chunk-6BVLPACH.cjs.map +0 -1
- package/dist/chunk-ASAEJ4B7.cjs.map +0 -1
- package/dist/chunk-DE5YTNCD.cjs.map +0 -1
- package/dist/chunk-H55AYIRI.js.map +0 -1
- package/dist/chunk-JJS7JZCH.js.map +0 -1
- package/dist/chunk-JTQBNSZX.js.map +0 -1
- package/dist/chunk-LFAQUR7P.cjs.map +0 -1
- package/dist/chunk-LTKV7AE5.cjs.map +0 -1
- package/dist/chunk-NMLFKXWW.js.map +0 -1
- package/dist/chunk-VJCLJH3X.js.map +0 -1
- package/dist/migrations-UFVJTPVT.js +0 -4
- package/dist/migrations-VNYOSUNE.cjs +0 -13
package/dist/index.cjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
var
|
|
7
|
-
var
|
|
8
|
-
var
|
|
9
|
-
var
|
|
3
|
+
var chunkZV6ZCJ74_cjs = require('./chunk-ZV6ZCJ74.cjs');
|
|
4
|
+
var chunkNZWFCUDA_cjs = require('./chunk-NZWFCUDA.cjs');
|
|
5
|
+
var chunkVHNTCB2X_cjs = require('./chunk-VHNTCB2X.cjs');
|
|
6
|
+
var chunkI6FFGQIT_cjs = require('./chunk-I6FFGQIT.cjs');
|
|
7
|
+
var chunkAG3SIPP7_cjs = require('./chunk-AG3SIPP7.cjs');
|
|
8
|
+
var chunkRBXFXT7H_cjs = require('./chunk-RBXFXT7H.cjs');
|
|
9
|
+
var chunkH4NHRZ6Y_cjs = require('./chunk-H4NHRZ6Y.cjs');
|
|
10
10
|
var chunk56GUBLJE_cjs = require('./chunk-56GUBLJE.cjs');
|
|
11
11
|
var chunk6FHNRRJ3_cjs = require('./chunk-6FHNRRJ3.cjs');
|
|
12
|
-
var
|
|
12
|
+
var chunkRXNLGINR_cjs = require('./chunk-RXNLGINR.cjs');
|
|
13
13
|
require('./chunk-P3XDZL6Q.cjs');
|
|
14
14
|
var chunkRCQ2HIQD_cjs = require('./chunk-RCQ2HIQD.cjs');
|
|
15
15
|
var chunkMNWKYY5E_cjs = require('./chunk-MNWKYY5E.cjs');
|
|
@@ -235,7 +235,7 @@ var DatabaseToolsService = class {
|
|
|
235
235
|
};
|
|
236
236
|
|
|
237
237
|
// src/templates/pages/admin-database-table.template.ts
|
|
238
|
-
|
|
238
|
+
chunkH4NHRZ6Y_cjs.init_admin_layout_catalyst_template();
|
|
239
239
|
function renderDatabaseTablePage(data) {
|
|
240
240
|
const totalPages = Math.ceil(data.totalRows / data.pageSize);
|
|
241
241
|
const startRow = (data.currentPage - 1) * data.pageSize + 1;
|
|
@@ -484,7 +484,7 @@ function renderDatabaseTablePage(data) {
|
|
|
484
484
|
user: data.user,
|
|
485
485
|
content: pageContent
|
|
486
486
|
};
|
|
487
|
-
return
|
|
487
|
+
return chunkH4NHRZ6Y_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
488
488
|
}
|
|
489
489
|
function generatePageNumbers(currentPage, totalPages) {
|
|
490
490
|
const pages = [];
|
|
@@ -559,7 +559,7 @@ function formatCellValue(value) {
|
|
|
559
559
|
// src/plugins/core-plugins/database-tools-plugin/admin-routes.ts
|
|
560
560
|
function createDatabaseToolsAdminRoutes() {
|
|
561
561
|
const router3 = new hono.Hono();
|
|
562
|
-
router3.use("*",
|
|
562
|
+
router3.use("*", chunkVHNTCB2X_cjs.requireAuth());
|
|
563
563
|
router3.get("/api/stats", async (c) => {
|
|
564
564
|
try {
|
|
565
565
|
const user = c.get("user");
|
|
@@ -1776,7 +1776,7 @@ function createOTPLoginPlugin() {
|
|
|
1776
1776
|
console.warn("Failed to parse OTP plugin settings, using defaults");
|
|
1777
1777
|
}
|
|
1778
1778
|
}
|
|
1779
|
-
const settingsService = new
|
|
1779
|
+
const settingsService = new chunkNZWFCUDA_cjs.SettingsService(db);
|
|
1780
1780
|
const generalSettings = await settingsService.getGeneralSettings();
|
|
1781
1781
|
const siteName = generalSettings.siteName;
|
|
1782
1782
|
const canRequest = await otpService.checkRateLimit(normalizedEmail, settings);
|
|
@@ -1926,7 +1926,7 @@ function createOTPLoginPlugin() {
|
|
|
1926
1926
|
error: "Account is deactivated"
|
|
1927
1927
|
}, 403);
|
|
1928
1928
|
}
|
|
1929
|
-
const token = await
|
|
1929
|
+
const token = await chunkVHNTCB2X_cjs.AuthManager.generateToken(user.id, user.email, user.role, c.env.JWT_SECRET);
|
|
1930
1930
|
cookie.setCookie(c, "auth_token", token, {
|
|
1931
1931
|
httpOnly: true,
|
|
1932
1932
|
secure: true,
|
|
@@ -2396,13 +2396,13 @@ function createOAuthProvidersPlugin() {
|
|
|
2396
2396
|
if (!user || !user.is_active) {
|
|
2397
2397
|
return c.redirect("/auth/login?error=Account is deactivated");
|
|
2398
2398
|
}
|
|
2399
|
-
const jwt2 = await
|
|
2399
|
+
const jwt2 = await chunkVHNTCB2X_cjs.AuthManager.generateToken(
|
|
2400
2400
|
user.id,
|
|
2401
2401
|
user.email,
|
|
2402
2402
|
user.role,
|
|
2403
2403
|
c.env.JWT_SECRET
|
|
2404
2404
|
);
|
|
2405
|
-
|
|
2405
|
+
chunkVHNTCB2X_cjs.AuthManager.setAuthCookie(c, jwt2, { sameSite: "Lax" });
|
|
2406
2406
|
return c.redirect("/admin");
|
|
2407
2407
|
}
|
|
2408
2408
|
const existingUser = await oauthService.findUserByEmail(profile.email);
|
|
@@ -2419,13 +2419,13 @@ function createOAuthProvidersPlugin() {
|
|
|
2419
2419
|
tokenExpiresAt: tokenExpiresAt ?? void 0,
|
|
2420
2420
|
profileData: JSON.stringify(profile)
|
|
2421
2421
|
});
|
|
2422
|
-
const jwt2 = await
|
|
2422
|
+
const jwt2 = await chunkVHNTCB2X_cjs.AuthManager.generateToken(
|
|
2423
2423
|
existingUser.id,
|
|
2424
2424
|
existingUser.email,
|
|
2425
2425
|
existingUser.role,
|
|
2426
2426
|
c.env.JWT_SECRET
|
|
2427
2427
|
);
|
|
2428
|
-
|
|
2428
|
+
chunkVHNTCB2X_cjs.AuthManager.setAuthCookie(c, jwt2, { sameSite: "Lax" });
|
|
2429
2429
|
return c.redirect("/admin");
|
|
2430
2430
|
}
|
|
2431
2431
|
const newUserId = await oauthService.createUserFromOAuth(profile);
|
|
@@ -2438,13 +2438,13 @@ function createOAuthProvidersPlugin() {
|
|
|
2438
2438
|
tokenExpiresAt: tokenExpiresAt ?? void 0,
|
|
2439
2439
|
profileData: JSON.stringify(profile)
|
|
2440
2440
|
});
|
|
2441
|
-
const jwt = await
|
|
2441
|
+
const jwt = await chunkVHNTCB2X_cjs.AuthManager.generateToken(
|
|
2442
2442
|
newUserId,
|
|
2443
2443
|
profile.email.toLowerCase(),
|
|
2444
2444
|
"viewer",
|
|
2445
2445
|
c.env.JWT_SECRET
|
|
2446
2446
|
);
|
|
2447
|
-
|
|
2447
|
+
chunkVHNTCB2X_cjs.AuthManager.setAuthCookie(c, jwt, { sameSite: "Lax" });
|
|
2448
2448
|
return c.redirect("/admin");
|
|
2449
2449
|
} catch (error) {
|
|
2450
2450
|
console.error("OAuth callback error:", error);
|
|
@@ -4126,7 +4126,7 @@ function renderSettingsPage(data) {
|
|
|
4126
4126
|
}, 30000);
|
|
4127
4127
|
</script>
|
|
4128
4128
|
`;
|
|
4129
|
-
return
|
|
4129
|
+
return chunkH4NHRZ6Y_cjs.renderAdminLayout({
|
|
4130
4130
|
title: "AI Search Settings",
|
|
4131
4131
|
pageTitle: "AI Search Settings",
|
|
4132
4132
|
currentPath: "/admin/plugins/ai-search/settings",
|
|
@@ -4137,7 +4137,7 @@ function renderSettingsPage(data) {
|
|
|
4137
4137
|
|
|
4138
4138
|
// src/plugins/core-plugins/ai-search-plugin/routes/admin.ts
|
|
4139
4139
|
var adminRoutes = new hono.Hono();
|
|
4140
|
-
adminRoutes.use("*",
|
|
4140
|
+
adminRoutes.use("*", chunkVHNTCB2X_cjs.requireAuth());
|
|
4141
4141
|
adminRoutes.get("/", async (c) => {
|
|
4142
4142
|
try {
|
|
4143
4143
|
const user = c.get("user");
|
|
@@ -4538,13 +4538,13 @@ function createMagicLinkAuthPlugin() {
|
|
|
4538
4538
|
SET used = 1, used_at = ?
|
|
4539
4539
|
WHERE id = ?
|
|
4540
4540
|
`).bind(Date.now(), magicLink.id).run();
|
|
4541
|
-
const jwtToken = await
|
|
4541
|
+
const jwtToken = await chunkVHNTCB2X_cjs.AuthManager.generateToken(
|
|
4542
4542
|
user.id,
|
|
4543
4543
|
user.email,
|
|
4544
4544
|
user.role,
|
|
4545
4545
|
c.env.JWT_SECRET
|
|
4546
4546
|
);
|
|
4547
|
-
|
|
4547
|
+
chunkVHNTCB2X_cjs.AuthManager.setAuthCookie(c, jwtToken);
|
|
4548
4548
|
await db.prepare(`
|
|
4549
4549
|
UPDATE users SET last_login_at = ? WHERE id = ?
|
|
4550
4550
|
`).bind(Date.now(), user.id).run();
|
|
@@ -4689,6 +4689,1636 @@ function renderMagicLinkEmail(magicLink, expiryMinutes) {
|
|
|
4689
4689
|
}
|
|
4690
4690
|
createMagicLinkAuthPlugin();
|
|
4691
4691
|
|
|
4692
|
+
// src/plugins/core-plugins/security-audit-plugin/types.ts
|
|
4693
|
+
var DEFAULT_SETTINGS2 = {
|
|
4694
|
+
retention: {
|
|
4695
|
+
daysToKeep: 90,
|
|
4696
|
+
maxEvents: 1e5,
|
|
4697
|
+
autoPurge: true
|
|
4698
|
+
},
|
|
4699
|
+
bruteForce: {
|
|
4700
|
+
enabled: true,
|
|
4701
|
+
maxFailedAttemptsPerIP: 10,
|
|
4702
|
+
maxFailedAttemptsPerEmail: 5,
|
|
4703
|
+
windowMinutes: 15,
|
|
4704
|
+
lockoutDurationMinutes: 30,
|
|
4705
|
+
alertThreshold: 20
|
|
4706
|
+
},
|
|
4707
|
+
logging: {
|
|
4708
|
+
logSuccessfulLogins: true,
|
|
4709
|
+
logLogouts: true,
|
|
4710
|
+
logRegistrations: true,
|
|
4711
|
+
logPasswordResets: true,
|
|
4712
|
+
logPermissionDenied: true
|
|
4713
|
+
}
|
|
4714
|
+
};
|
|
4715
|
+
|
|
4716
|
+
// src/plugins/core-plugins/security-audit-plugin/services/security-audit-service.ts
|
|
4717
|
+
var SecurityAuditService = class {
|
|
4718
|
+
constructor(db, settings = DEFAULT_SETTINGS2) {
|
|
4719
|
+
this.db = db;
|
|
4720
|
+
this.settings = settings;
|
|
4721
|
+
}
|
|
4722
|
+
async logEvent(event) {
|
|
4723
|
+
const id = crypto.randomUUID();
|
|
4724
|
+
const now = Date.now();
|
|
4725
|
+
await this.db.prepare(`
|
|
4726
|
+
INSERT INTO security_events (id, event_type, severity, user_id, email, ip_address, user_agent, country_code, request_path, request_method, details, fingerprint, blocked, created_at)
|
|
4727
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
4728
|
+
`).bind(
|
|
4729
|
+
id,
|
|
4730
|
+
event.eventType,
|
|
4731
|
+
event.severity || "info",
|
|
4732
|
+
event.userId || null,
|
|
4733
|
+
event.email || null,
|
|
4734
|
+
event.ipAddress || null,
|
|
4735
|
+
event.userAgent || null,
|
|
4736
|
+
event.countryCode || null,
|
|
4737
|
+
event.requestPath || null,
|
|
4738
|
+
event.requestMethod || null,
|
|
4739
|
+
event.details ? JSON.stringify(event.details) : null,
|
|
4740
|
+
event.fingerprint || null,
|
|
4741
|
+
event.blocked ? 1 : 0,
|
|
4742
|
+
now
|
|
4743
|
+
).run();
|
|
4744
|
+
return id;
|
|
4745
|
+
}
|
|
4746
|
+
async getEvents(filters = {}) {
|
|
4747
|
+
const conditions = [];
|
|
4748
|
+
const params = [];
|
|
4749
|
+
if (filters.eventType) {
|
|
4750
|
+
if (Array.isArray(filters.eventType)) {
|
|
4751
|
+
conditions.push(`event_type IN (${filters.eventType.map(() => "?").join(",")})`);
|
|
4752
|
+
params.push(...filters.eventType);
|
|
4753
|
+
} else {
|
|
4754
|
+
conditions.push("event_type = ?");
|
|
4755
|
+
params.push(filters.eventType);
|
|
4756
|
+
}
|
|
4757
|
+
}
|
|
4758
|
+
if (filters.severity) {
|
|
4759
|
+
if (Array.isArray(filters.severity)) {
|
|
4760
|
+
conditions.push(`severity IN (${filters.severity.map(() => "?").join(",")})`);
|
|
4761
|
+
params.push(...filters.severity);
|
|
4762
|
+
} else {
|
|
4763
|
+
conditions.push("severity = ?");
|
|
4764
|
+
params.push(filters.severity);
|
|
4765
|
+
}
|
|
4766
|
+
}
|
|
4767
|
+
if (filters.email) {
|
|
4768
|
+
conditions.push("email LIKE ?");
|
|
4769
|
+
params.push(`%${filters.email}%`);
|
|
4770
|
+
}
|
|
4771
|
+
if (filters.ipAddress) {
|
|
4772
|
+
conditions.push("ip_address LIKE ?");
|
|
4773
|
+
params.push(`%${filters.ipAddress}%`);
|
|
4774
|
+
}
|
|
4775
|
+
if (filters.search) {
|
|
4776
|
+
conditions.push("(email LIKE ? OR ip_address LIKE ? OR details LIKE ?)");
|
|
4777
|
+
params.push(`%${filters.search}%`, `%${filters.search}%`, `%${filters.search}%`);
|
|
4778
|
+
}
|
|
4779
|
+
if (filters.startDate) {
|
|
4780
|
+
conditions.push("created_at >= ?");
|
|
4781
|
+
params.push(filters.startDate);
|
|
4782
|
+
}
|
|
4783
|
+
if (filters.endDate) {
|
|
4784
|
+
conditions.push("created_at <= ?");
|
|
4785
|
+
params.push(filters.endDate);
|
|
4786
|
+
}
|
|
4787
|
+
if (filters.blocked !== void 0) {
|
|
4788
|
+
conditions.push("blocked = ?");
|
|
4789
|
+
params.push(filters.blocked ? 1 : 0);
|
|
4790
|
+
}
|
|
4791
|
+
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
4792
|
+
const sortBy = filters.sortBy || "created_at";
|
|
4793
|
+
const sortOrder = filters.sortOrder || "desc";
|
|
4794
|
+
const page = filters.page || 1;
|
|
4795
|
+
const limit = filters.limit || 50;
|
|
4796
|
+
const offset = (page - 1) * limit;
|
|
4797
|
+
const countResult = await this.db.prepare(
|
|
4798
|
+
`SELECT COUNT(*) as count FROM security_events ${where}`
|
|
4799
|
+
).bind(...params).first();
|
|
4800
|
+
const total = countResult?.count || 0;
|
|
4801
|
+
const results = await this.db.prepare(
|
|
4802
|
+
`SELECT * FROM security_events ${where} ORDER BY ${sortBy} ${sortOrder} LIMIT ? OFFSET ?`
|
|
4803
|
+
).bind(...params, limit, offset).all();
|
|
4804
|
+
const events = (results.results || []).map((row) => ({
|
|
4805
|
+
id: row.id,
|
|
4806
|
+
eventType: row.event_type,
|
|
4807
|
+
severity: row.severity,
|
|
4808
|
+
userId: row.user_id,
|
|
4809
|
+
email: row.email,
|
|
4810
|
+
ipAddress: row.ip_address,
|
|
4811
|
+
userAgent: row.user_agent,
|
|
4812
|
+
countryCode: row.country_code,
|
|
4813
|
+
requestPath: row.request_path,
|
|
4814
|
+
requestMethod: row.request_method,
|
|
4815
|
+
details: row.details ? JSON.parse(row.details) : null,
|
|
4816
|
+
fingerprint: row.fingerprint,
|
|
4817
|
+
blocked: !!row.blocked,
|
|
4818
|
+
createdAt: row.created_at
|
|
4819
|
+
}));
|
|
4820
|
+
return { events, total };
|
|
4821
|
+
}
|
|
4822
|
+
async getEvent(id) {
|
|
4823
|
+
const row = await this.db.prepare(
|
|
4824
|
+
"SELECT * FROM security_events WHERE id = ?"
|
|
4825
|
+
).bind(id).first();
|
|
4826
|
+
if (!row) return null;
|
|
4827
|
+
return {
|
|
4828
|
+
id: row.id,
|
|
4829
|
+
eventType: row.event_type,
|
|
4830
|
+
severity: row.severity,
|
|
4831
|
+
userId: row.user_id,
|
|
4832
|
+
email: row.email,
|
|
4833
|
+
ipAddress: row.ip_address,
|
|
4834
|
+
userAgent: row.user_agent,
|
|
4835
|
+
countryCode: row.country_code,
|
|
4836
|
+
requestPath: row.request_path,
|
|
4837
|
+
requestMethod: row.request_method,
|
|
4838
|
+
details: row.details ? JSON.parse(row.details) : null,
|
|
4839
|
+
fingerprint: row.fingerprint,
|
|
4840
|
+
blocked: !!row.blocked,
|
|
4841
|
+
createdAt: row.created_at
|
|
4842
|
+
};
|
|
4843
|
+
}
|
|
4844
|
+
async getStats() {
|
|
4845
|
+
const now = Date.now();
|
|
4846
|
+
const h24 = now - 24 * 60 * 60 * 1e3;
|
|
4847
|
+
const h48 = now - 48 * 60 * 60 * 1e3;
|
|
4848
|
+
const totalResult = await this.db.prepare(
|
|
4849
|
+
"SELECT COUNT(*) as count FROM security_events"
|
|
4850
|
+
).first();
|
|
4851
|
+
const failed24hResult = await this.db.prepare(
|
|
4852
|
+
"SELECT COUNT(*) as count FROM security_events WHERE event_type = 'login_failure' AND created_at >= ?"
|
|
4853
|
+
).bind(h24).first();
|
|
4854
|
+
const failedPrior24hResult = await this.db.prepare(
|
|
4855
|
+
"SELECT COUNT(*) as count FROM security_events WHERE event_type = 'login_failure' AND created_at >= ? AND created_at < ?"
|
|
4856
|
+
).bind(h48, h24).first();
|
|
4857
|
+
const failed24h = failed24hResult?.count || 0;
|
|
4858
|
+
const failedPrior24h = failedPrior24hResult?.count || 0;
|
|
4859
|
+
const trend = failedPrior24h > 0 ? Math.round((failed24h - failedPrior24h) / failedPrior24h * 100) : failed24h > 0 ? 100 : 0;
|
|
4860
|
+
const lockoutWindow = now - this.settings.bruteForce.lockoutDurationMinutes * 60 * 1e3;
|
|
4861
|
+
const lockoutsResult = await this.db.prepare(
|
|
4862
|
+
"SELECT COUNT(DISTINCT ip_address) as count FROM security_events WHERE event_type = 'account_lockout' AND created_at >= ?"
|
|
4863
|
+
).bind(lockoutWindow).first();
|
|
4864
|
+
const windowStart = now - this.settings.bruteForce.windowMinutes * 60 * 1e3;
|
|
4865
|
+
const flaggedResult = await this.db.prepare(
|
|
4866
|
+
`SELECT COUNT(*) as count FROM (
|
|
4867
|
+
SELECT ip_address FROM security_events
|
|
4868
|
+
WHERE event_type = 'login_failure' AND created_at >= ?
|
|
4869
|
+
GROUP BY ip_address HAVING COUNT(*) >= ?
|
|
4870
|
+
)`
|
|
4871
|
+
).bind(windowStart, this.settings.bruteForce.maxFailedAttemptsPerIP).first();
|
|
4872
|
+
const typeResults = await this.db.prepare(
|
|
4873
|
+
"SELECT event_type, COUNT(*) as count FROM security_events WHERE created_at >= ? GROUP BY event_type"
|
|
4874
|
+
).bind(h24).all();
|
|
4875
|
+
const eventsByType = {};
|
|
4876
|
+
for (const row of typeResults.results || []) {
|
|
4877
|
+
eventsByType[row.event_type] = row.count;
|
|
4878
|
+
}
|
|
4879
|
+
const severityResults = await this.db.prepare(
|
|
4880
|
+
"SELECT severity, COUNT(*) as count FROM security_events WHERE created_at >= ? GROUP BY severity"
|
|
4881
|
+
).bind(h24).all();
|
|
4882
|
+
const eventsBySeverity = {};
|
|
4883
|
+
for (const row of severityResults.results || []) {
|
|
4884
|
+
eventsBySeverity[row.severity] = row.count;
|
|
4885
|
+
}
|
|
4886
|
+
return {
|
|
4887
|
+
totalEvents: totalResult?.count || 0,
|
|
4888
|
+
failedLogins24h: failed24h,
|
|
4889
|
+
failedLoginsTrend: trend,
|
|
4890
|
+
activeLockouts: lockoutsResult?.count || 0,
|
|
4891
|
+
flaggedIPs: flaggedResult?.count || 0,
|
|
4892
|
+
eventsByType,
|
|
4893
|
+
eventsBySeverity
|
|
4894
|
+
};
|
|
4895
|
+
}
|
|
4896
|
+
async getTopIPs(limit = 10) {
|
|
4897
|
+
const now = Date.now();
|
|
4898
|
+
const h24 = now - 24 * 60 * 60 * 1e3;
|
|
4899
|
+
const results = await this.db.prepare(`
|
|
4900
|
+
SELECT
|
|
4901
|
+
ip_address,
|
|
4902
|
+
country_code,
|
|
4903
|
+
COUNT(*) as failed_attempts,
|
|
4904
|
+
MAX(created_at) as last_seen
|
|
4905
|
+
FROM security_events
|
|
4906
|
+
WHERE event_type = 'login_failure' AND created_at >= ?
|
|
4907
|
+
GROUP BY ip_address
|
|
4908
|
+
ORDER BY failed_attempts DESC
|
|
4909
|
+
LIMIT ?
|
|
4910
|
+
`).bind(h24, limit).all();
|
|
4911
|
+
const lockoutWindow = now - this.settings.bruteForce.lockoutDurationMinutes * 60 * 1e3;
|
|
4912
|
+
const lockoutResults = await this.db.prepare(
|
|
4913
|
+
"SELECT DISTINCT ip_address FROM security_events WHERE event_type = 'account_lockout' AND created_at >= ?"
|
|
4914
|
+
).bind(lockoutWindow).all();
|
|
4915
|
+
const lockedIPs = new Set((lockoutResults.results || []).map((r) => r.ip_address));
|
|
4916
|
+
return (results.results || []).map((row) => ({
|
|
4917
|
+
ipAddress: row.ip_address,
|
|
4918
|
+
countryCode: row.country_code,
|
|
4919
|
+
failedAttempts: row.failed_attempts,
|
|
4920
|
+
lastSeen: row.last_seen,
|
|
4921
|
+
locked: lockedIPs.has(row.ip_address)
|
|
4922
|
+
}));
|
|
4923
|
+
}
|
|
4924
|
+
async getHourlyTrend(hours = 24) {
|
|
4925
|
+
const now = Date.now();
|
|
4926
|
+
const start = now - hours * 60 * 60 * 1e3;
|
|
4927
|
+
const buckets = [];
|
|
4928
|
+
for (let i = 0; i < hours; i++) {
|
|
4929
|
+
const bucketStart = start + i * 60 * 60 * 1e3;
|
|
4930
|
+
const date = new Date(bucketStart);
|
|
4931
|
+
buckets.push({
|
|
4932
|
+
hour: `${date.getUTCHours().toString().padStart(2, "0")}:00`,
|
|
4933
|
+
count: 0
|
|
4934
|
+
});
|
|
4935
|
+
}
|
|
4936
|
+
const results = await this.db.prepare(`
|
|
4937
|
+
SELECT
|
|
4938
|
+
CAST((created_at - ?) / 3600000 AS INTEGER) as bucket,
|
|
4939
|
+
COUNT(*) as count
|
|
4940
|
+
FROM security_events
|
|
4941
|
+
WHERE event_type = 'login_failure' AND created_at >= ?
|
|
4942
|
+
GROUP BY bucket
|
|
4943
|
+
ORDER BY bucket
|
|
4944
|
+
`).bind(start, start).all();
|
|
4945
|
+
for (const row of results.results || []) {
|
|
4946
|
+
const idx = row.bucket;
|
|
4947
|
+
if (idx >= 0 && idx < buckets.length) {
|
|
4948
|
+
buckets[idx].count = row.count;
|
|
4949
|
+
}
|
|
4950
|
+
}
|
|
4951
|
+
return buckets;
|
|
4952
|
+
}
|
|
4953
|
+
async purgeOldEvents(daysToKeep) {
|
|
4954
|
+
const days = daysToKeep || this.settings.retention.daysToKeep;
|
|
4955
|
+
const cutoff = Date.now() - days * 24 * 60 * 60 * 1e3;
|
|
4956
|
+
const result = await this.db.prepare(
|
|
4957
|
+
"DELETE FROM security_events WHERE created_at < ?"
|
|
4958
|
+
).bind(cutoff).run();
|
|
4959
|
+
return result.meta?.changes || 0;
|
|
4960
|
+
}
|
|
4961
|
+
async getRecentCriticalEvents(limit = 20) {
|
|
4962
|
+
const results = await this.db.prepare(
|
|
4963
|
+
"SELECT * FROM security_events WHERE severity = 'critical' ORDER BY created_at DESC LIMIT ?"
|
|
4964
|
+
).bind(limit).all();
|
|
4965
|
+
return (results.results || []).map((row) => ({
|
|
4966
|
+
id: row.id,
|
|
4967
|
+
eventType: row.event_type,
|
|
4968
|
+
severity: row.severity,
|
|
4969
|
+
userId: row.user_id,
|
|
4970
|
+
email: row.email,
|
|
4971
|
+
ipAddress: row.ip_address,
|
|
4972
|
+
userAgent: row.user_agent,
|
|
4973
|
+
countryCode: row.country_code,
|
|
4974
|
+
requestPath: row.request_path,
|
|
4975
|
+
requestMethod: row.request_method,
|
|
4976
|
+
details: row.details ? JSON.parse(row.details) : null,
|
|
4977
|
+
fingerprint: row.fingerprint,
|
|
4978
|
+
blocked: !!row.blocked,
|
|
4979
|
+
createdAt: row.created_at
|
|
4980
|
+
}));
|
|
4981
|
+
}
|
|
4982
|
+
};
|
|
4983
|
+
|
|
4984
|
+
// src/plugins/core-plugins/security-audit-plugin/components/dashboard-page.ts
|
|
4985
|
+
chunkH4NHRZ6Y_cjs.init_admin_layout_catalyst_template();
|
|
4986
|
+
function formatTimestamp(ts) {
|
|
4987
|
+
const date = new Date(ts);
|
|
4988
|
+
const now = Date.now();
|
|
4989
|
+
const diff = now - ts;
|
|
4990
|
+
if (diff < 6e4) return "just now";
|
|
4991
|
+
if (diff < 36e5) return `${Math.floor(diff / 6e4)}m ago`;
|
|
4992
|
+
if (diff < 864e5) return `${Math.floor(diff / 36e5)}h ago`;
|
|
4993
|
+
return date.toLocaleDateString("en-US", { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" });
|
|
4994
|
+
}
|
|
4995
|
+
function severityBadge(severity) {
|
|
4996
|
+
const colors = {
|
|
4997
|
+
info: "bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400",
|
|
4998
|
+
warning: "bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-400",
|
|
4999
|
+
critical: "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400"
|
|
5000
|
+
};
|
|
5001
|
+
return `<span class="inline-flex items-center rounded-md px-2 py-1 text-xs font-medium ${colors[severity] || colors.info}">${severity}</span>`;
|
|
5002
|
+
}
|
|
5003
|
+
function eventTypeBadge(type) {
|
|
5004
|
+
const labels = {
|
|
5005
|
+
login_success: "Login OK",
|
|
5006
|
+
login_failure: "Login Failed",
|
|
5007
|
+
registration: "Registration",
|
|
5008
|
+
account_lockout: "Lockout",
|
|
5009
|
+
suspicious_activity: "Suspicious",
|
|
5010
|
+
logout: "Logout",
|
|
5011
|
+
password_reset_request: "Password Reset",
|
|
5012
|
+
permission_denied: "Access Denied"
|
|
5013
|
+
};
|
|
5014
|
+
return labels[type] || type;
|
|
5015
|
+
}
|
|
5016
|
+
function trendArrow(trend) {
|
|
5017
|
+
if (trend > 0) return `<span class="text-red-500">+${trend}%</span>`;
|
|
5018
|
+
if (trend < 0) return `<span class="text-emerald-500">${trend}%</span>`;
|
|
5019
|
+
return `<span class="text-zinc-400">0%</span>`;
|
|
5020
|
+
}
|
|
5021
|
+
function renderBarChart(data) {
|
|
5022
|
+
if (data.length === 0) return '<p class="text-zinc-500 text-sm">No data available</p>';
|
|
5023
|
+
const max = Math.max(...data.map((d) => d.count), 1);
|
|
5024
|
+
const bars = data.map((d) => {
|
|
5025
|
+
const height = Math.max(d.count / max * 100, 2);
|
|
5026
|
+
const color = d.count === 0 ? "bg-zinc-200 dark:bg-zinc-700" : d.count >= max * 0.75 ? "bg-red-500" : d.count >= max * 0.5 ? "bg-amber-500" : "bg-cyan-500";
|
|
5027
|
+
return `
|
|
5028
|
+
<div class="flex flex-col items-center flex-1 min-w-0 group relative">
|
|
5029
|
+
<div class="w-full flex flex-col items-center justify-end" style="height: 120px">
|
|
5030
|
+
<div class="absolute bottom-8 hidden group-hover:block bg-zinc-900 text-white text-xs rounded px-2 py-1 whitespace-nowrap z-10">
|
|
5031
|
+
${d.hour}: ${d.count} failed
|
|
5032
|
+
</div>
|
|
5033
|
+
<div class="${color} w-full max-w-[12px] rounded-t transition-all" style="height: ${height}%"></div>
|
|
5034
|
+
</div>
|
|
5035
|
+
<span class="text-[9px] text-zinc-400 mt-1 ${data.length > 12 ? "hidden sm:block" : ""}">${d.hour}</span>
|
|
5036
|
+
</div>
|
|
5037
|
+
`;
|
|
5038
|
+
}).join("");
|
|
5039
|
+
return `<div class="flex items-end gap-px">${bars}</div>`;
|
|
5040
|
+
}
|
|
5041
|
+
function renderSecurityDashboard(data) {
|
|
5042
|
+
const { stats, topIPs, hourlyTrend, recentCritical, user, version, dynamicMenuItems } = data;
|
|
5043
|
+
const content2 = `
|
|
5044
|
+
<div>
|
|
5045
|
+
<div class="sm:flex sm:items-center sm:justify-between mb-6">
|
|
5046
|
+
<div class="sm:flex-auto">
|
|
5047
|
+
<h1 class="text-2xl/8 font-semibold text-zinc-950 dark:text-white sm:text-xl/8">Security Dashboard</h1>
|
|
5048
|
+
<p class="mt-2 text-sm/6 text-zinc-500 dark:text-zinc-400">
|
|
5049
|
+
Monitor login attempts, brute-force detection, and security events.
|
|
5050
|
+
</p>
|
|
5051
|
+
</div>
|
|
5052
|
+
<div class="mt-4 sm:mt-0 sm:ml-16 flex gap-x-2">
|
|
5053
|
+
<a href="/admin/plugins/security-audit/events"
|
|
5054
|
+
class="inline-flex items-center justify-center rounded-lg bg-white dark:bg-zinc-800 px-3.5 py-2.5 text-sm font-semibold text-zinc-950 dark:text-white hover:bg-zinc-50 dark:hover:bg-zinc-700 ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 transition-colors shadow-sm">
|
|
5055
|
+
View Event Log
|
|
5056
|
+
</a>
|
|
5057
|
+
<a href="/api/security-audit/export?format=csv"
|
|
5058
|
+
class="inline-flex items-center justify-center rounded-lg bg-zinc-950 dark:bg-white px-3.5 py-2.5 text-sm font-semibold text-white dark:text-zinc-950 hover:bg-zinc-800 dark:hover:bg-zinc-100 transition-colors shadow-sm">
|
|
5059
|
+
Export CSV
|
|
5060
|
+
</a>
|
|
5061
|
+
</div>
|
|
5062
|
+
</div>
|
|
5063
|
+
|
|
5064
|
+
<!-- Summary Cards -->
|
|
5065
|
+
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4 mb-6">
|
|
5066
|
+
<div class="rounded-xl bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl p-5 ring-1 ring-zinc-950/5 dark:ring-white/10 shadow-sm">
|
|
5067
|
+
<p class="text-sm font-medium text-zinc-500 dark:text-zinc-400">Total Events</p>
|
|
5068
|
+
<p class="mt-2 text-3xl font-bold text-zinc-950 dark:text-white">${stats.totalEvents.toLocaleString()}</p>
|
|
5069
|
+
</div>
|
|
5070
|
+
<div class="rounded-xl bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl p-5 ring-1 ring-zinc-950/5 dark:ring-white/10 shadow-sm">
|
|
5071
|
+
<p class="text-sm font-medium text-zinc-500 dark:text-zinc-400">Failed Logins (24h)</p>
|
|
5072
|
+
<p class="mt-2 text-3xl font-bold text-zinc-950 dark:text-white">
|
|
5073
|
+
${stats.failedLogins24h}
|
|
5074
|
+
<span class="ml-2 text-sm font-normal">${trendArrow(stats.failedLoginsTrend)}</span>
|
|
5075
|
+
</p>
|
|
5076
|
+
</div>
|
|
5077
|
+
<div class="rounded-xl bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl p-5 ring-1 ring-zinc-950/5 dark:ring-white/10 shadow-sm">
|
|
5078
|
+
<p class="text-sm font-medium text-zinc-500 dark:text-zinc-400">Active Lockouts</p>
|
|
5079
|
+
<p class="mt-2 text-3xl font-bold ${stats.activeLockouts > 0 ? "text-red-600 dark:text-red-400" : "text-zinc-950 dark:text-white"}">${stats.activeLockouts}</p>
|
|
5080
|
+
</div>
|
|
5081
|
+
<div class="rounded-xl bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl p-5 ring-1 ring-zinc-950/5 dark:ring-white/10 shadow-sm">
|
|
5082
|
+
<p class="text-sm font-medium text-zinc-500 dark:text-zinc-400">Flagged IPs</p>
|
|
5083
|
+
<p class="mt-2 text-3xl font-bold ${stats.flaggedIPs > 0 ? "text-amber-600 dark:text-amber-400" : "text-zinc-950 dark:text-white"}">${stats.flaggedIPs}</p>
|
|
5084
|
+
</div>
|
|
5085
|
+
</div>
|
|
5086
|
+
|
|
5087
|
+
<!-- Charts Row -->
|
|
5088
|
+
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
|
|
5089
|
+
<!-- Failed Login Trend -->
|
|
5090
|
+
<div class="rounded-xl bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl p-5 ring-1 ring-zinc-950/5 dark:ring-white/10 shadow-sm">
|
|
5091
|
+
<h2 class="text-sm font-semibold text-zinc-950 dark:text-white mb-4">Failed Login Attempts (24h)</h2>
|
|
5092
|
+
${renderBarChart(hourlyTrend)}
|
|
5093
|
+
</div>
|
|
5094
|
+
|
|
5095
|
+
<!-- Events by Type -->
|
|
5096
|
+
<div class="rounded-xl bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl p-5 ring-1 ring-zinc-950/5 dark:ring-white/10 shadow-sm">
|
|
5097
|
+
<h2 class="text-sm font-semibold text-zinc-950 dark:text-white mb-4">Events by Type (24h)</h2>
|
|
5098
|
+
<div class="space-y-3">
|
|
5099
|
+
${Object.entries(stats.eventsByType).length === 0 ? '<p class="text-zinc-500 text-sm">No events in the last 24 hours</p>' : Object.entries(stats.eventsByType).sort(([, a], [, b]) => b - a).map(([type, count]) => {
|
|
5100
|
+
const total = Object.values(stats.eventsByType).reduce((s, v) => s + v, 0);
|
|
5101
|
+
const pct = total > 0 ? Math.round(count / total * 100) : 0;
|
|
5102
|
+
return `
|
|
5103
|
+
<div>
|
|
5104
|
+
<div class="flex justify-between text-sm mb-1">
|
|
5105
|
+
<span class="text-zinc-600 dark:text-zinc-300">${eventTypeBadge(type)}</span>
|
|
5106
|
+
<span class="text-zinc-500 dark:text-zinc-400">${count}</span>
|
|
5107
|
+
</div>
|
|
5108
|
+
<div class="w-full bg-zinc-100 dark:bg-zinc-800 rounded-full h-1.5">
|
|
5109
|
+
<div class="h-1.5 rounded-full ${type === "login_failure" ? "bg-red-500" : type === "login_success" ? "bg-emerald-500" : "bg-cyan-500"}" style="width: ${pct}%"></div>
|
|
5110
|
+
</div>
|
|
5111
|
+
</div>
|
|
5112
|
+
`;
|
|
5113
|
+
}).join("")}
|
|
5114
|
+
</div>
|
|
5115
|
+
</div>
|
|
5116
|
+
</div>
|
|
5117
|
+
|
|
5118
|
+
<!-- Top IPs and Recent Critical -->
|
|
5119
|
+
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
5120
|
+
<!-- Top IPs -->
|
|
5121
|
+
<div class="rounded-xl bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl ring-1 ring-zinc-950/5 dark:ring-white/10 shadow-sm overflow-hidden">
|
|
5122
|
+
<div class="p-5 border-b border-zinc-100 dark:border-zinc-800">
|
|
5123
|
+
<h2 class="text-sm font-semibold text-zinc-950 dark:text-white">Top IPs by Failed Logins (24h)</h2>
|
|
5124
|
+
</div>
|
|
5125
|
+
${topIPs.length === 0 ? '<div class="p-5"><p class="text-zinc-500 text-sm">No failed login attempts</p></div>' : `<table class="min-w-full">
|
|
5126
|
+
<thead>
|
|
5127
|
+
<tr class="border-b border-zinc-100 dark:border-zinc-800">
|
|
5128
|
+
<th class="px-5 py-3 text-left text-xs font-medium text-zinc-500 uppercase">IP Address</th>
|
|
5129
|
+
<th class="px-5 py-3 text-left text-xs font-medium text-zinc-500 uppercase">Country</th>
|
|
5130
|
+
<th class="px-5 py-3 text-right text-xs font-medium text-zinc-500 uppercase">Attempts</th>
|
|
5131
|
+
<th class="px-5 py-3 text-right text-xs font-medium text-zinc-500 uppercase">Status</th>
|
|
5132
|
+
</tr>
|
|
5133
|
+
</thead>
|
|
5134
|
+
<tbody>
|
|
5135
|
+
${topIPs.map((ip) => `
|
|
5136
|
+
<tr class="border-b border-zinc-50 dark:border-zinc-800/50 hover:bg-zinc-50 dark:hover:bg-zinc-800/50">
|
|
5137
|
+
<td class="px-5 py-3 text-sm font-mono text-zinc-900 dark:text-zinc-100">${ip.ipAddress}</td>
|
|
5138
|
+
<td class="px-5 py-3 text-sm text-zinc-600 dark:text-zinc-400">${ip.countryCode || "-"}</td>
|
|
5139
|
+
<td class="px-5 py-3 text-sm text-right font-semibold ${ip.failedAttempts >= 10 ? "text-red-600 dark:text-red-400" : "text-zinc-900 dark:text-zinc-100"}">${ip.failedAttempts}</td>
|
|
5140
|
+
<td class="px-5 py-3 text-sm text-right">
|
|
5141
|
+
${ip.locked ? '<span class="inline-flex items-center rounded-md bg-red-100 dark:bg-red-900/30 px-2 py-1 text-xs font-medium text-red-700 dark:text-red-400">Locked</span>' : '<span class="inline-flex items-center rounded-md bg-emerald-100 dark:bg-emerald-900/30 px-2 py-1 text-xs font-medium text-emerald-700 dark:text-emerald-400">Active</span>'}
|
|
5142
|
+
</td>
|
|
5143
|
+
</tr>
|
|
5144
|
+
`).join("")}
|
|
5145
|
+
</tbody>
|
|
5146
|
+
</table>`}
|
|
5147
|
+
</div>
|
|
5148
|
+
|
|
5149
|
+
<!-- Recent Critical Events -->
|
|
5150
|
+
<div class="rounded-xl bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl ring-1 ring-zinc-950/5 dark:ring-white/10 shadow-sm overflow-hidden">
|
|
5151
|
+
<div class="p-5 border-b border-zinc-100 dark:border-zinc-800">
|
|
5152
|
+
<h2 class="text-sm font-semibold text-zinc-950 dark:text-white">Recent Critical Events</h2>
|
|
5153
|
+
</div>
|
|
5154
|
+
${recentCritical.length === 0 ? '<div class="p-5"><p class="text-zinc-500 text-sm">No critical events</p></div>' : `<div class="divide-y divide-zinc-100 dark:divide-zinc-800">
|
|
5155
|
+
${recentCritical.slice(0, 10).map((event) => `
|
|
5156
|
+
<div class="px-5 py-3 hover:bg-zinc-50 dark:hover:bg-zinc-800/50">
|
|
5157
|
+
<div class="flex items-center justify-between">
|
|
5158
|
+
<div class="flex items-center gap-2">
|
|
5159
|
+
${severityBadge(event.severity)}
|
|
5160
|
+
<span class="text-sm font-medium text-zinc-900 dark:text-zinc-100">${eventTypeBadge(event.eventType)}</span>
|
|
5161
|
+
</div>
|
|
5162
|
+
<span class="text-xs text-zinc-400">${formatTimestamp(event.createdAt)}</span>
|
|
5163
|
+
</div>
|
|
5164
|
+
<div class="mt-1 text-xs text-zinc-500 dark:text-zinc-400">
|
|
5165
|
+
${event.ipAddress ? `IP: ${event.ipAddress}` : ""}
|
|
5166
|
+
${event.email ? ` | ${event.email}` : ""}
|
|
5167
|
+
</div>
|
|
5168
|
+
</div>
|
|
5169
|
+
`).join("")}
|
|
5170
|
+
</div>`}
|
|
5171
|
+
</div>
|
|
5172
|
+
</div>
|
|
5173
|
+
</div>
|
|
5174
|
+
`;
|
|
5175
|
+
const layoutData = {
|
|
5176
|
+
title: "Security Dashboard",
|
|
5177
|
+
pageTitle: "Security Dashboard",
|
|
5178
|
+
currentPath: "/admin/plugins/security-audit",
|
|
5179
|
+
user,
|
|
5180
|
+
content: content2,
|
|
5181
|
+
version,
|
|
5182
|
+
dynamicMenuItems
|
|
5183
|
+
};
|
|
5184
|
+
return chunkH4NHRZ6Y_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
5185
|
+
}
|
|
5186
|
+
|
|
5187
|
+
// src/plugins/core-plugins/security-audit-plugin/components/event-log-page.ts
|
|
5188
|
+
chunkH4NHRZ6Y_cjs.init_admin_layout_catalyst_template();
|
|
5189
|
+
function formatTimestamp2(ts) {
|
|
5190
|
+
const date = new Date(ts);
|
|
5191
|
+
return date.toLocaleDateString("en-US", {
|
|
5192
|
+
month: "short",
|
|
5193
|
+
day: "numeric",
|
|
5194
|
+
year: "numeric",
|
|
5195
|
+
hour: "2-digit",
|
|
5196
|
+
minute: "2-digit",
|
|
5197
|
+
second: "2-digit"
|
|
5198
|
+
});
|
|
5199
|
+
}
|
|
5200
|
+
function severityBadge2(severity) {
|
|
5201
|
+
const colors = {
|
|
5202
|
+
info: "bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400",
|
|
5203
|
+
warning: "bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-400",
|
|
5204
|
+
critical: "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400"
|
|
5205
|
+
};
|
|
5206
|
+
return `<span class="inline-flex items-center rounded-md px-2 py-1 text-xs font-medium ${colors[severity] || colors.info}">${severity}</span>`;
|
|
5207
|
+
}
|
|
5208
|
+
function eventTypeBadge2(type) {
|
|
5209
|
+
const colors = {
|
|
5210
|
+
login_success: "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400",
|
|
5211
|
+
login_failure: "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400",
|
|
5212
|
+
registration: "bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400",
|
|
5213
|
+
account_lockout: "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400",
|
|
5214
|
+
suspicious_activity: "bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-400",
|
|
5215
|
+
logout: "bg-zinc-100 text-zinc-700 dark:bg-zinc-800 dark:text-zinc-400",
|
|
5216
|
+
password_reset_request: "bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-400",
|
|
5217
|
+
permission_denied: "bg-orange-100 text-orange-700 dark:bg-orange-900/30 dark:text-orange-400"
|
|
5218
|
+
};
|
|
5219
|
+
const labels = {
|
|
5220
|
+
login_success: "Login OK",
|
|
5221
|
+
login_failure: "Login Failed",
|
|
5222
|
+
registration: "Registration",
|
|
5223
|
+
account_lockout: "Lockout",
|
|
5224
|
+
suspicious_activity: "Suspicious",
|
|
5225
|
+
logout: "Logout",
|
|
5226
|
+
password_reset_request: "Password Reset",
|
|
5227
|
+
permission_denied: "Access Denied"
|
|
5228
|
+
};
|
|
5229
|
+
const color = colors[type] || "bg-zinc-100 text-zinc-700 dark:bg-zinc-800 dark:text-zinc-400";
|
|
5230
|
+
return `<span class="inline-flex items-center rounded-md px-2 py-1 text-xs font-medium ${color}">${labels[type] || type}</span>`;
|
|
5231
|
+
}
|
|
5232
|
+
function buildFilterUrl(filters, overrides = {}) {
|
|
5233
|
+
const params = new URLSearchParams();
|
|
5234
|
+
if (filters.eventType && !overrides.type) params.set("type", String(filters.eventType));
|
|
5235
|
+
if (filters.severity && !overrides.severity) params.set("severity", String(filters.severity));
|
|
5236
|
+
if (filters.email && !overrides.email) params.set("email", filters.email);
|
|
5237
|
+
if (filters.ipAddress && !overrides.ip) params.set("ip", filters.ipAddress);
|
|
5238
|
+
if (filters.search && !overrides.search) params.set("search", filters.search);
|
|
5239
|
+
for (const [key, value] of Object.entries(overrides)) {
|
|
5240
|
+
if (value) params.set(key, value);
|
|
5241
|
+
}
|
|
5242
|
+
const qs = params.toString();
|
|
5243
|
+
return `/admin/plugins/security-audit/events${qs ? "?" + qs : ""}`;
|
|
5244
|
+
}
|
|
5245
|
+
function renderEventLogPage(data) {
|
|
5246
|
+
const { events, pagination, filters, user, version, dynamicMenuItems } = data;
|
|
5247
|
+
const content2 = `
|
|
5248
|
+
<div>
|
|
5249
|
+
<div class="sm:flex sm:items-center sm:justify-between mb-6">
|
|
5250
|
+
<div class="sm:flex-auto">
|
|
5251
|
+
<h1 class="text-2xl/8 font-semibold text-zinc-950 dark:text-white sm:text-xl/8">Security Event Log</h1>
|
|
5252
|
+
<p class="mt-2 text-sm/6 text-zinc-500 dark:text-zinc-400">
|
|
5253
|
+
Browse and filter all security events. Showing ${pagination.startItem}-${pagination.endItem} of ${pagination.totalItems}.
|
|
5254
|
+
</p>
|
|
5255
|
+
</div>
|
|
5256
|
+
<div class="mt-4 sm:mt-0 sm:ml-16 flex gap-x-2">
|
|
5257
|
+
<a href="/admin/plugins/security-audit"
|
|
5258
|
+
class="inline-flex items-center justify-center rounded-lg bg-white dark:bg-zinc-800 px-3.5 py-2.5 text-sm font-semibold text-zinc-950 dark:text-white hover:bg-zinc-50 dark:hover:bg-zinc-700 ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 transition-colors shadow-sm">
|
|
5259
|
+
Dashboard
|
|
5260
|
+
</a>
|
|
5261
|
+
</div>
|
|
5262
|
+
</div>
|
|
5263
|
+
|
|
5264
|
+
<!-- Filters -->
|
|
5265
|
+
<div class="rounded-xl bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl p-5 ring-1 ring-zinc-950/5 dark:ring-white/10 shadow-sm mb-6">
|
|
5266
|
+
<form method="GET" action="/admin/plugins/security-audit/events" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-4">
|
|
5267
|
+
<div>
|
|
5268
|
+
<label class="block text-xs font-medium text-zinc-500 dark:text-zinc-400 mb-1">Event Type</label>
|
|
5269
|
+
<select name="type" class="w-full rounded-lg border-0 bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-900 dark:text-white ring-1 ring-inset ring-zinc-300 dark:ring-zinc-700 focus:ring-2 focus:ring-cyan-500">
|
|
5270
|
+
<option value="">All Types</option>
|
|
5271
|
+
<option value="login_success" ${filters.eventType === "login_success" ? "selected" : ""}>Login Success</option>
|
|
5272
|
+
<option value="login_failure" ${filters.eventType === "login_failure" ? "selected" : ""}>Login Failure</option>
|
|
5273
|
+
<option value="registration" ${filters.eventType === "registration" ? "selected" : ""}>Registration</option>
|
|
5274
|
+
<option value="account_lockout" ${filters.eventType === "account_lockout" ? "selected" : ""}>Account Lockout</option>
|
|
5275
|
+
<option value="suspicious_activity" ${filters.eventType === "suspicious_activity" ? "selected" : ""}>Suspicious Activity</option>
|
|
5276
|
+
<option value="logout" ${filters.eventType === "logout" ? "selected" : ""}>Logout</option>
|
|
5277
|
+
</select>
|
|
5278
|
+
</div>
|
|
5279
|
+
<div>
|
|
5280
|
+
<label class="block text-xs font-medium text-zinc-500 dark:text-zinc-400 mb-1">Severity</label>
|
|
5281
|
+
<select name="severity" class="w-full rounded-lg border-0 bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-900 dark:text-white ring-1 ring-inset ring-zinc-300 dark:ring-zinc-700 focus:ring-2 focus:ring-cyan-500">
|
|
5282
|
+
<option value="">All Severities</option>
|
|
5283
|
+
<option value="info" ${filters.severity === "info" ? "selected" : ""}>Info</option>
|
|
5284
|
+
<option value="warning" ${filters.severity === "warning" ? "selected" : ""}>Warning</option>
|
|
5285
|
+
<option value="critical" ${filters.severity === "critical" ? "selected" : ""}>Critical</option>
|
|
5286
|
+
</select>
|
|
5287
|
+
</div>
|
|
5288
|
+
<div>
|
|
5289
|
+
<label class="block text-xs font-medium text-zinc-500 dark:text-zinc-400 mb-1">Email</label>
|
|
5290
|
+
<input type="text" name="email" value="${filters.email || ""}" placeholder="Filter by email"
|
|
5291
|
+
class="w-full rounded-lg border-0 bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-900 dark:text-white ring-1 ring-inset ring-zinc-300 dark:ring-zinc-700 focus:ring-2 focus:ring-cyan-500 placeholder:text-zinc-400">
|
|
5292
|
+
</div>
|
|
5293
|
+
<div>
|
|
5294
|
+
<label class="block text-xs font-medium text-zinc-500 dark:text-zinc-400 mb-1">IP Address</label>
|
|
5295
|
+
<input type="text" name="ip" value="${filters.ipAddress || ""}" placeholder="Filter by IP"
|
|
5296
|
+
class="w-full rounded-lg border-0 bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-900 dark:text-white ring-1 ring-inset ring-zinc-300 dark:ring-zinc-700 focus:ring-2 focus:ring-cyan-500 placeholder:text-zinc-400">
|
|
5297
|
+
</div>
|
|
5298
|
+
<div class="flex items-end gap-2">
|
|
5299
|
+
<button type="submit"
|
|
5300
|
+
class="flex-1 rounded-lg bg-cyan-600 px-3 py-2 text-sm font-semibold text-white hover:bg-cyan-500 transition-colors shadow-sm">
|
|
5301
|
+
Filter
|
|
5302
|
+
</button>
|
|
5303
|
+
<a href="/admin/plugins/security-audit/events"
|
|
5304
|
+
class="rounded-lg bg-zinc-100 dark:bg-zinc-800 px-3 py-2 text-sm font-medium text-zinc-600 dark:text-zinc-400 hover:bg-zinc-200 dark:hover:bg-zinc-700 transition-colors">
|
|
5305
|
+
Clear
|
|
5306
|
+
</a>
|
|
5307
|
+
</div>
|
|
5308
|
+
</form>
|
|
5309
|
+
</div>
|
|
5310
|
+
|
|
5311
|
+
<!-- Events Table -->
|
|
5312
|
+
<div class="rounded-xl bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl ring-1 ring-zinc-950/5 dark:ring-white/10 shadow-sm overflow-hidden">
|
|
5313
|
+
${events.length === 0 ? `<div class="p-12 text-center">
|
|
5314
|
+
<svg class="mx-auto h-12 w-12 text-zinc-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
5315
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"/>
|
|
5316
|
+
</svg>
|
|
5317
|
+
<h3 class="mt-2 text-sm font-semibold text-zinc-900 dark:text-white">No events found</h3>
|
|
5318
|
+
<p class="mt-1 text-sm text-zinc-500">No security events match your current filters.</p>
|
|
5319
|
+
</div>` : `<div class="overflow-x-auto">
|
|
5320
|
+
<table class="min-w-full divide-y divide-zinc-200 dark:divide-zinc-800">
|
|
5321
|
+
<thead>
|
|
5322
|
+
<tr>
|
|
5323
|
+
<th class="px-4 py-3 text-left text-xs font-medium text-zinc-500 uppercase tracking-wider">Time</th>
|
|
5324
|
+
<th class="px-4 py-3 text-left text-xs font-medium text-zinc-500 uppercase tracking-wider">Type</th>
|
|
5325
|
+
<th class="px-4 py-3 text-left text-xs font-medium text-zinc-500 uppercase tracking-wider">Severity</th>
|
|
5326
|
+
<th class="px-4 py-3 text-left text-xs font-medium text-zinc-500 uppercase tracking-wider">Email</th>
|
|
5327
|
+
<th class="px-4 py-3 text-left text-xs font-medium text-zinc-500 uppercase tracking-wider">IP Address</th>
|
|
5328
|
+
<th class="px-4 py-3 text-left text-xs font-medium text-zinc-500 uppercase tracking-wider">Country</th>
|
|
5329
|
+
<th class="px-4 py-3 text-left text-xs font-medium text-zinc-500 uppercase tracking-wider">Status</th>
|
|
5330
|
+
</tr>
|
|
5331
|
+
</thead>
|
|
5332
|
+
<tbody class="divide-y divide-zinc-100 dark:divide-zinc-800">
|
|
5333
|
+
${events.map((event) => `
|
|
5334
|
+
<tr class="hover:bg-zinc-50 dark:hover:bg-zinc-800/50 cursor-pointer" onclick="this.querySelector('.event-details').classList.toggle('hidden')">
|
|
5335
|
+
<td class="px-4 py-3 text-sm text-zinc-600 dark:text-zinc-300 whitespace-nowrap">${formatTimestamp2(event.createdAt)}</td>
|
|
5336
|
+
<td class="px-4 py-3">${eventTypeBadge2(event.eventType)}</td>
|
|
5337
|
+
<td class="px-4 py-3">${severityBadge2(event.severity)}</td>
|
|
5338
|
+
<td class="px-4 py-3 text-sm text-zinc-600 dark:text-zinc-300 max-w-[200px] truncate">${event.email || "-"}</td>
|
|
5339
|
+
<td class="px-4 py-3 text-sm font-mono text-zinc-600 dark:text-zinc-300">${event.ipAddress || "-"}</td>
|
|
5340
|
+
<td class="px-4 py-3 text-sm text-zinc-600 dark:text-zinc-300">${event.countryCode || "-"}</td>
|
|
5341
|
+
<td class="px-4 py-3">
|
|
5342
|
+
${event.blocked ? '<span class="inline-flex items-center rounded-md bg-red-100 dark:bg-red-900/30 px-2 py-1 text-xs font-medium text-red-700 dark:text-red-400">Blocked</span>' : '<span class="inline-flex items-center rounded-md bg-emerald-100 dark:bg-emerald-900/30 px-2 py-1 text-xs font-medium text-emerald-700 dark:text-emerald-400">Allowed</span>'}
|
|
5343
|
+
</td>
|
|
5344
|
+
</tr>
|
|
5345
|
+
<tr class="event-details hidden">
|
|
5346
|
+
<td colspan="7" class="px-4 py-3 bg-zinc-50 dark:bg-zinc-800/30">
|
|
5347
|
+
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 text-xs">
|
|
5348
|
+
<div><span class="font-medium text-zinc-500">Event ID:</span> <span class="text-zinc-700 dark:text-zinc-300 font-mono">${event.id.substring(0, 8)}...</span></div>
|
|
5349
|
+
<div><span class="font-medium text-zinc-500">User Agent:</span> <span class="text-zinc-700 dark:text-zinc-300 truncate block max-w-[300px]">${event.userAgent || "-"}</span></div>
|
|
5350
|
+
<div><span class="font-medium text-zinc-500">Path:</span> <span class="text-zinc-700 dark:text-zinc-300">${event.requestPath || "-"}</span></div>
|
|
5351
|
+
<div><span class="font-medium text-zinc-500">Fingerprint:</span> <span class="text-zinc-700 dark:text-zinc-300 font-mono">${event.fingerprint || "-"}</span></div>
|
|
5352
|
+
${event.details ? `<div class="col-span-full"><span class="font-medium text-zinc-500">Details:</span> <pre class="text-zinc-700 dark:text-zinc-300 mt-1 bg-zinc-100 dark:bg-zinc-900 rounded p-2 overflow-x-auto">${JSON.stringify(event.details, null, 2)}</pre></div>` : ""}
|
|
5353
|
+
</div>
|
|
5354
|
+
</td>
|
|
5355
|
+
</tr>
|
|
5356
|
+
`).join("")}
|
|
5357
|
+
</tbody>
|
|
5358
|
+
</table>
|
|
5359
|
+
</div>`}
|
|
5360
|
+
|
|
5361
|
+
<!-- Pagination -->
|
|
5362
|
+
${pagination.totalPages > 1 ? `
|
|
5363
|
+
<div class="flex items-center justify-between border-t border-zinc-200 dark:border-zinc-800 px-4 py-3">
|
|
5364
|
+
<div class="text-sm text-zinc-500">
|
|
5365
|
+
Page ${pagination.currentPage} of ${pagination.totalPages}
|
|
5366
|
+
</div>
|
|
5367
|
+
<div class="flex gap-1">
|
|
5368
|
+
${pagination.currentPage > 1 ? `
|
|
5369
|
+
<a href="${buildFilterUrl(filters, { page: String(pagination.currentPage - 1) })}"
|
|
5370
|
+
class="rounded-lg px-3 py-1.5 text-sm font-medium text-zinc-600 dark:text-zinc-300 hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors">
|
|
5371
|
+
Previous
|
|
5372
|
+
</a>
|
|
5373
|
+
` : ""}
|
|
5374
|
+
${pagination.currentPage < pagination.totalPages ? `
|
|
5375
|
+
<a href="${buildFilterUrl(filters, { page: String(pagination.currentPage + 1) })}"
|
|
5376
|
+
class="rounded-lg px-3 py-1.5 text-sm font-medium text-zinc-600 dark:text-zinc-300 hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors">
|
|
5377
|
+
Next
|
|
5378
|
+
</a>
|
|
5379
|
+
` : ""}
|
|
5380
|
+
</div>
|
|
5381
|
+
</div>
|
|
5382
|
+
` : ""}
|
|
5383
|
+
</div>
|
|
5384
|
+
</div>
|
|
5385
|
+
`;
|
|
5386
|
+
const layoutData = {
|
|
5387
|
+
title: "Security Event Log",
|
|
5388
|
+
pageTitle: "Security Event Log",
|
|
5389
|
+
currentPath: "/admin/plugins/security-audit/events",
|
|
5390
|
+
user,
|
|
5391
|
+
content: content2,
|
|
5392
|
+
version,
|
|
5393
|
+
dynamicMenuItems
|
|
5394
|
+
};
|
|
5395
|
+
return chunkH4NHRZ6Y_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
5396
|
+
}
|
|
5397
|
+
|
|
5398
|
+
// src/plugins/core-plugins/security-audit-plugin/components/settings-page.ts
|
|
5399
|
+
chunkH4NHRZ6Y_cjs.init_admin_layout_catalyst_template();
|
|
5400
|
+
function renderSecuritySettingsPage(data) {
|
|
5401
|
+
const { settings, user, version, message, dynamicMenuItems } = data;
|
|
5402
|
+
const content2 = `
|
|
5403
|
+
<div>
|
|
5404
|
+
<div class="sm:flex sm:items-center sm:justify-between mb-6">
|
|
5405
|
+
<div class="sm:flex-auto">
|
|
5406
|
+
<h1 class="text-2xl/8 font-semibold text-zinc-950 dark:text-white sm:text-xl/8">Security Audit Settings</h1>
|
|
5407
|
+
<p class="mt-2 text-sm/6 text-zinc-500 dark:text-zinc-400">
|
|
5408
|
+
Configure brute-force detection thresholds, event logging, and data retention.
|
|
5409
|
+
</p>
|
|
5410
|
+
</div>
|
|
5411
|
+
<div class="mt-4 sm:mt-0 sm:ml-16 flex gap-x-2">
|
|
5412
|
+
<a href="/admin/plugins/security-audit"
|
|
5413
|
+
class="inline-flex items-center justify-center rounded-lg bg-white dark:bg-zinc-800 px-3.5 py-2.5 text-sm font-semibold text-zinc-950 dark:text-white hover:bg-zinc-50 dark:hover:bg-zinc-700 ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 transition-colors shadow-sm">
|
|
5414
|
+
Dashboard
|
|
5415
|
+
</a>
|
|
5416
|
+
</div>
|
|
5417
|
+
</div>
|
|
5418
|
+
|
|
5419
|
+
${message ? `
|
|
5420
|
+
<div class="mb-6 rounded-lg bg-emerald-50 dark:bg-emerald-900/20 p-4 ring-1 ring-emerald-200 dark:ring-emerald-800">
|
|
5421
|
+
<p class="text-sm text-emerald-800 dark:text-emerald-300">${message}</p>
|
|
5422
|
+
</div>
|
|
5423
|
+
` : ""}
|
|
5424
|
+
|
|
5425
|
+
<form method="POST" action="/admin/plugins/security-audit/settings"
|
|
5426
|
+
class="space-y-6"
|
|
5427
|
+
hx-post="/admin/plugins/security-audit/settings"
|
|
5428
|
+
hx-swap="none"
|
|
5429
|
+
hx-on::after-request="if(event.detail.successful) { window.showNotification && window.showNotification('Settings saved', 'success'); } else { window.showNotification && window.showNotification('Failed to save', 'error'); }">
|
|
5430
|
+
|
|
5431
|
+
<!-- Brute Force Detection -->
|
|
5432
|
+
<div class="rounded-xl bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl p-6 ring-1 ring-zinc-950/5 dark:ring-white/10 shadow-sm">
|
|
5433
|
+
<h2 class="text-base font-semibold text-zinc-950 dark:text-white mb-4">Brute-Force Detection</h2>
|
|
5434
|
+
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
5435
|
+
<div>
|
|
5436
|
+
<label class="flex items-center gap-2 mb-4">
|
|
5437
|
+
<input type="checkbox" name="bruteForce.enabled" value="true" ${settings.bruteForce.enabled ? "checked" : ""}
|
|
5438
|
+
class="rounded border-zinc-300 text-cyan-600 focus:ring-cyan-500">
|
|
5439
|
+
<span class="text-sm font-medium text-zinc-700 dark:text-zinc-300">Enable brute-force detection</span>
|
|
5440
|
+
</label>
|
|
5441
|
+
</div>
|
|
5442
|
+
<div></div><div></div>
|
|
5443
|
+
<div>
|
|
5444
|
+
<label class="block text-xs font-medium text-zinc-500 dark:text-zinc-400 mb-1">Max Failed Attempts per IP</label>
|
|
5445
|
+
<input type="number" name="bruteForce.maxFailedAttemptsPerIP" value="${settings.bruteForce.maxFailedAttemptsPerIP}" min="1" max="100"
|
|
5446
|
+
class="w-full rounded-lg border-0 bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-900 dark:text-white ring-1 ring-inset ring-zinc-300 dark:ring-zinc-700 focus:ring-2 focus:ring-cyan-500">
|
|
5447
|
+
</div>
|
|
5448
|
+
<div>
|
|
5449
|
+
<label class="block text-xs font-medium text-zinc-500 dark:text-zinc-400 mb-1">Max Failed Attempts per Email</label>
|
|
5450
|
+
<input type="number" name="bruteForce.maxFailedAttemptsPerEmail" value="${settings.bruteForce.maxFailedAttemptsPerEmail}" min="1" max="100"
|
|
5451
|
+
class="w-full rounded-lg border-0 bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-900 dark:text-white ring-1 ring-inset ring-zinc-300 dark:ring-zinc-700 focus:ring-2 focus:ring-cyan-500">
|
|
5452
|
+
</div>
|
|
5453
|
+
<div>
|
|
5454
|
+
<label class="block text-xs font-medium text-zinc-500 dark:text-zinc-400 mb-1">Window (minutes)</label>
|
|
5455
|
+
<input type="number" name="bruteForce.windowMinutes" value="${settings.bruteForce.windowMinutes}" min="1" max="1440"
|
|
5456
|
+
class="w-full rounded-lg border-0 bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-900 dark:text-white ring-1 ring-inset ring-zinc-300 dark:ring-zinc-700 focus:ring-2 focus:ring-cyan-500">
|
|
5457
|
+
</div>
|
|
5458
|
+
<div>
|
|
5459
|
+
<label class="block text-xs font-medium text-zinc-500 dark:text-zinc-400 mb-1">Lockout Duration (minutes)</label>
|
|
5460
|
+
<input type="number" name="bruteForce.lockoutDurationMinutes" value="${settings.bruteForce.lockoutDurationMinutes}" min="1" max="1440"
|
|
5461
|
+
class="w-full rounded-lg border-0 bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-900 dark:text-white ring-1 ring-inset ring-zinc-300 dark:ring-zinc-700 focus:ring-2 focus:ring-cyan-500">
|
|
5462
|
+
</div>
|
|
5463
|
+
<div>
|
|
5464
|
+
<label class="block text-xs font-medium text-zinc-500 dark:text-zinc-400 mb-1">Alert Threshold</label>
|
|
5465
|
+
<input type="number" name="bruteForce.alertThreshold" value="${settings.bruteForce.alertThreshold}" min="1" max="1000"
|
|
5466
|
+
class="w-full rounded-lg border-0 bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-900 dark:text-white ring-1 ring-inset ring-zinc-300 dark:ring-zinc-700 focus:ring-2 focus:ring-cyan-500">
|
|
5467
|
+
<p class="mt-1 text-xs text-zinc-400">Events above this count trigger critical severity</p>
|
|
5468
|
+
</div>
|
|
5469
|
+
</div>
|
|
5470
|
+
</div>
|
|
5471
|
+
|
|
5472
|
+
<!-- Event Logging -->
|
|
5473
|
+
<div class="rounded-xl bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl p-6 ring-1 ring-zinc-950/5 dark:ring-white/10 shadow-sm">
|
|
5474
|
+
<h2 class="text-base font-semibold text-zinc-950 dark:text-white mb-4">Event Logging</h2>
|
|
5475
|
+
<div class="space-y-3">
|
|
5476
|
+
<label class="flex items-center gap-2">
|
|
5477
|
+
<input type="checkbox" name="logging.logSuccessfulLogins" value="true" ${settings.logging.logSuccessfulLogins ? "checked" : ""}
|
|
5478
|
+
class="rounded border-zinc-300 text-cyan-600 focus:ring-cyan-500">
|
|
5479
|
+
<span class="text-sm text-zinc-700 dark:text-zinc-300">Log successful logins</span>
|
|
5480
|
+
</label>
|
|
5481
|
+
<label class="flex items-center gap-2">
|
|
5482
|
+
<input type="checkbox" name="logging.logLogouts" value="true" ${settings.logging.logLogouts ? "checked" : ""}
|
|
5483
|
+
class="rounded border-zinc-300 text-cyan-600 focus:ring-cyan-500">
|
|
5484
|
+
<span class="text-sm text-zinc-700 dark:text-zinc-300">Log logouts</span>
|
|
5485
|
+
</label>
|
|
5486
|
+
<label class="flex items-center gap-2">
|
|
5487
|
+
<input type="checkbox" name="logging.logRegistrations" value="true" ${settings.logging.logRegistrations ? "checked" : ""}
|
|
5488
|
+
class="rounded border-zinc-300 text-cyan-600 focus:ring-cyan-500">
|
|
5489
|
+
<span class="text-sm text-zinc-700 dark:text-zinc-300">Log registrations</span>
|
|
5490
|
+
</label>
|
|
5491
|
+
<label class="flex items-center gap-2">
|
|
5492
|
+
<input type="checkbox" name="logging.logPasswordResets" value="true" ${settings.logging.logPasswordResets ? "checked" : ""}
|
|
5493
|
+
class="rounded border-zinc-300 text-cyan-600 focus:ring-cyan-500">
|
|
5494
|
+
<span class="text-sm text-zinc-700 dark:text-zinc-300">Log password resets</span>
|
|
5495
|
+
</label>
|
|
5496
|
+
<label class="flex items-center gap-2">
|
|
5497
|
+
<input type="checkbox" name="logging.logPermissionDenied" value="true" ${settings.logging.logPermissionDenied ? "checked" : ""}
|
|
5498
|
+
class="rounded border-zinc-300 text-cyan-600 focus:ring-cyan-500">
|
|
5499
|
+
<span class="text-sm text-zinc-700 dark:text-zinc-300">Log permission denied events</span>
|
|
5500
|
+
</label>
|
|
5501
|
+
</div>
|
|
5502
|
+
</div>
|
|
5503
|
+
|
|
5504
|
+
<!-- Data Retention -->
|
|
5505
|
+
<div class="rounded-xl bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl p-6 ring-1 ring-zinc-950/5 dark:ring-white/10 shadow-sm">
|
|
5506
|
+
<h2 class="text-base font-semibold text-zinc-950 dark:text-white mb-4">Data Retention</h2>
|
|
5507
|
+
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
|
5508
|
+
<div>
|
|
5509
|
+
<label class="block text-xs font-medium text-zinc-500 dark:text-zinc-400 mb-1">Days to Keep</label>
|
|
5510
|
+
<input type="number" name="retention.daysToKeep" value="${settings.retention.daysToKeep}" min="1" max="365"
|
|
5511
|
+
class="w-full rounded-lg border-0 bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-900 dark:text-white ring-1 ring-inset ring-zinc-300 dark:ring-zinc-700 focus:ring-2 focus:ring-cyan-500">
|
|
5512
|
+
</div>
|
|
5513
|
+
<div>
|
|
5514
|
+
<label class="block text-xs font-medium text-zinc-500 dark:text-zinc-400 mb-1">Max Events</label>
|
|
5515
|
+
<input type="number" name="retention.maxEvents" value="${settings.retention.maxEvents}" min="1000" max="1000000"
|
|
5516
|
+
class="w-full rounded-lg border-0 bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-900 dark:text-white ring-1 ring-inset ring-zinc-300 dark:ring-zinc-700 focus:ring-2 focus:ring-cyan-500">
|
|
5517
|
+
</div>
|
|
5518
|
+
<div>
|
|
5519
|
+
<label class="flex items-center gap-2 mt-5">
|
|
5520
|
+
<input type="checkbox" name="retention.autoPurge" value="true" ${settings.retention.autoPurge ? "checked" : ""}
|
|
5521
|
+
class="rounded border-zinc-300 text-cyan-600 focus:ring-cyan-500">
|
|
5522
|
+
<span class="text-sm text-zinc-700 dark:text-zinc-300">Auto-purge old events</span>
|
|
5523
|
+
</label>
|
|
5524
|
+
</div>
|
|
5525
|
+
</div>
|
|
5526
|
+
</div>
|
|
5527
|
+
|
|
5528
|
+
<!-- Actions -->
|
|
5529
|
+
<div class="flex items-center justify-between">
|
|
5530
|
+
<button type="button"
|
|
5531
|
+
onclick="if(confirm('Purge events older than retention period?')) fetch('/api/security-audit/events/purge', {method:'POST',headers:{'Content-Type':'application/json'}}).then(r=>r.json()).then(d=>window.showNotification && window.showNotification('Purged '+d.deleted+' events','success'))"
|
|
5532
|
+
class="rounded-lg bg-red-50 dark:bg-red-900/20 px-4 py-2.5 text-sm font-medium text-red-700 dark:text-red-400 hover:bg-red-100 dark:hover:bg-red-900/40 ring-1 ring-red-200 dark:ring-red-800 transition-colors">
|
|
5533
|
+
Purge Old Events
|
|
5534
|
+
</button>
|
|
5535
|
+
<button type="submit"
|
|
5536
|
+
class="rounded-lg bg-cyan-600 px-6 py-2.5 text-sm font-semibold text-white hover:bg-cyan-500 transition-colors shadow-sm">
|
|
5537
|
+
Save Settings
|
|
5538
|
+
</button>
|
|
5539
|
+
</div>
|
|
5540
|
+
</form>
|
|
5541
|
+
</div>
|
|
5542
|
+
`;
|
|
5543
|
+
const layoutData = {
|
|
5544
|
+
title: "Security Audit Settings",
|
|
5545
|
+
pageTitle: "Security Audit Settings",
|
|
5546
|
+
currentPath: "/admin/plugins/security-audit/settings",
|
|
5547
|
+
user,
|
|
5548
|
+
content: content2,
|
|
5549
|
+
version,
|
|
5550
|
+
dynamicMenuItems
|
|
5551
|
+
};
|
|
5552
|
+
return chunkH4NHRZ6Y_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
5553
|
+
}
|
|
5554
|
+
|
|
5555
|
+
// src/plugins/core-plugins/security-audit-plugin/routes/admin.ts
|
|
5556
|
+
var adminRoutes2 = new hono.Hono();
|
|
5557
|
+
adminRoutes2.use("*", chunkVHNTCB2X_cjs.requireAuth());
|
|
5558
|
+
adminRoutes2.use("*", async (c, next) => {
|
|
5559
|
+
const user = c.get("user");
|
|
5560
|
+
if (user?.role !== "admin") {
|
|
5561
|
+
return c.text("Access denied", 403);
|
|
5562
|
+
}
|
|
5563
|
+
return next();
|
|
5564
|
+
});
|
|
5565
|
+
async function getSettings(db) {
|
|
5566
|
+
try {
|
|
5567
|
+
const pluginService = new chunkI6FFGQIT_cjs.PluginService(db);
|
|
5568
|
+
const plugin2 = await pluginService.getPlugin("security-audit");
|
|
5569
|
+
if (plugin2?.settings) {
|
|
5570
|
+
const settings = typeof plugin2.settings === "string" ? JSON.parse(plugin2.settings) : plugin2.settings;
|
|
5571
|
+
return { ...DEFAULT_SETTINGS2, ...settings };
|
|
5572
|
+
}
|
|
5573
|
+
} catch {
|
|
5574
|
+
}
|
|
5575
|
+
return DEFAULT_SETTINGS2;
|
|
5576
|
+
}
|
|
5577
|
+
adminRoutes2.get("/", async (c) => {
|
|
5578
|
+
const db = c.env.DB;
|
|
5579
|
+
const user = c.get("user");
|
|
5580
|
+
const settings = await getSettings(db);
|
|
5581
|
+
const service = new SecurityAuditService(db, settings);
|
|
5582
|
+
const [stats, topIPs, hourlyTrend, recentCritical] = await Promise.all([
|
|
5583
|
+
service.getStats(),
|
|
5584
|
+
service.getTopIPs(10),
|
|
5585
|
+
service.getHourlyTrend(24),
|
|
5586
|
+
service.getRecentCriticalEvents(20)
|
|
5587
|
+
]);
|
|
5588
|
+
const pageData = {
|
|
5589
|
+
stats,
|
|
5590
|
+
topIPs,
|
|
5591
|
+
hourlyTrend,
|
|
5592
|
+
recentCritical,
|
|
5593
|
+
user: user ? { name: user.email, email: user.email, role: user.role } : void 0,
|
|
5594
|
+
version: c.get("appVersion"),
|
|
5595
|
+
dynamicMenuItems: c.get("pluginMenuItems")
|
|
5596
|
+
};
|
|
5597
|
+
return c.html(renderSecurityDashboard(pageData));
|
|
5598
|
+
});
|
|
5599
|
+
adminRoutes2.get("/events", async (c) => {
|
|
5600
|
+
const db = c.env.DB;
|
|
5601
|
+
const user = c.get("user");
|
|
5602
|
+
const settings = await getSettings(db);
|
|
5603
|
+
const service = new SecurityAuditService(db, settings);
|
|
5604
|
+
const page = parseInt(c.req.query("page") || "1");
|
|
5605
|
+
const limit = 50;
|
|
5606
|
+
const filters = {
|
|
5607
|
+
eventType: c.req.query("type") || void 0,
|
|
5608
|
+
severity: c.req.query("severity") || void 0,
|
|
5609
|
+
email: c.req.query("email") || void 0,
|
|
5610
|
+
ipAddress: c.req.query("ip") || void 0,
|
|
5611
|
+
search: c.req.query("search") || void 0,
|
|
5612
|
+
page,
|
|
5613
|
+
limit
|
|
5614
|
+
};
|
|
5615
|
+
const { events, total } = await service.getEvents(filters);
|
|
5616
|
+
const totalPages = Math.ceil(total / limit);
|
|
5617
|
+
const pageData = {
|
|
5618
|
+
events,
|
|
5619
|
+
pagination: {
|
|
5620
|
+
currentPage: page,
|
|
5621
|
+
totalPages,
|
|
5622
|
+
totalItems: total,
|
|
5623
|
+
itemsPerPage: limit,
|
|
5624
|
+
startItem: total === 0 ? 0 : (page - 1) * limit + 1,
|
|
5625
|
+
endItem: Math.min(page * limit, total)
|
|
5626
|
+
},
|
|
5627
|
+
filters,
|
|
5628
|
+
user: user ? { name: user.email, email: user.email, role: user.role } : void 0,
|
|
5629
|
+
version: c.get("appVersion"),
|
|
5630
|
+
dynamicMenuItems: c.get("pluginMenuItems")
|
|
5631
|
+
};
|
|
5632
|
+
return c.html(renderEventLogPage(pageData));
|
|
5633
|
+
});
|
|
5634
|
+
adminRoutes2.get("/settings", async (c) => {
|
|
5635
|
+
const db = c.env.DB;
|
|
5636
|
+
const user = c.get("user");
|
|
5637
|
+
const settings = await getSettings(db);
|
|
5638
|
+
const pageData = {
|
|
5639
|
+
settings,
|
|
5640
|
+
user: user ? { name: user.email, email: user.email, role: user.role } : void 0,
|
|
5641
|
+
version: c.get("appVersion"),
|
|
5642
|
+
message: c.req.query("message") || void 0,
|
|
5643
|
+
dynamicMenuItems: c.get("pluginMenuItems")
|
|
5644
|
+
};
|
|
5645
|
+
return c.html(renderSecuritySettingsPage(pageData));
|
|
5646
|
+
});
|
|
5647
|
+
adminRoutes2.post("/settings", async (c) => {
|
|
5648
|
+
const db = c.env.DB;
|
|
5649
|
+
const body = await c.req.parseBody();
|
|
5650
|
+
const settings = {
|
|
5651
|
+
bruteForce: {
|
|
5652
|
+
enabled: body["bruteForce.enabled"] === "true",
|
|
5653
|
+
maxFailedAttemptsPerIP: parseInt(body["bruteForce.maxFailedAttemptsPerIP"]) || 10,
|
|
5654
|
+
maxFailedAttemptsPerEmail: parseInt(body["bruteForce.maxFailedAttemptsPerEmail"]) || 5,
|
|
5655
|
+
windowMinutes: parseInt(body["bruteForce.windowMinutes"]) || 15,
|
|
5656
|
+
lockoutDurationMinutes: parseInt(body["bruteForce.lockoutDurationMinutes"]) || 30,
|
|
5657
|
+
alertThreshold: parseInt(body["bruteForce.alertThreshold"]) || 20
|
|
5658
|
+
},
|
|
5659
|
+
logging: {
|
|
5660
|
+
logSuccessfulLogins: body["logging.logSuccessfulLogins"] === "true",
|
|
5661
|
+
logLogouts: body["logging.logLogouts"] === "true",
|
|
5662
|
+
logRegistrations: body["logging.logRegistrations"] === "true",
|
|
5663
|
+
logPasswordResets: body["logging.logPasswordResets"] === "true",
|
|
5664
|
+
logPermissionDenied: body["logging.logPermissionDenied"] === "true"
|
|
5665
|
+
},
|
|
5666
|
+
retention: {
|
|
5667
|
+
daysToKeep: parseInt(body["retention.daysToKeep"]) || 90,
|
|
5668
|
+
maxEvents: parseInt(body["retention.maxEvents"]) || 1e5,
|
|
5669
|
+
autoPurge: body["retention.autoPurge"] === "true"
|
|
5670
|
+
}
|
|
5671
|
+
};
|
|
5672
|
+
const pluginService = new chunkI6FFGQIT_cjs.PluginService(db);
|
|
5673
|
+
await pluginService.updatePluginSettings("security-audit", settings);
|
|
5674
|
+
if (c.req.header("HX-Request")) {
|
|
5675
|
+
return c.json({ success: true });
|
|
5676
|
+
}
|
|
5677
|
+
return c.redirect("/admin/plugins/security-audit/settings?message=Settings saved successfully");
|
|
5678
|
+
});
|
|
5679
|
+
|
|
5680
|
+
// src/plugins/core-plugins/security-audit-plugin/services/brute-force-detector.ts
|
|
5681
|
+
var KV_PREFIX = "security:bf:";
|
|
5682
|
+
var LOCK_PREFIX = "security:locked:";
|
|
5683
|
+
var BruteForceDetector = class {
|
|
5684
|
+
constructor(kv, settings) {
|
|
5685
|
+
this.kv = kv;
|
|
5686
|
+
this.settings = settings || DEFAULT_SETTINGS2.bruteForce;
|
|
5687
|
+
}
|
|
5688
|
+
settings;
|
|
5689
|
+
async recordFailedAttempt(ip, email) {
|
|
5690
|
+
if (!this.settings.enabled) {
|
|
5691
|
+
return { ipCount: 0, emailCount: 0, shouldLockIP: false, shouldLockEmail: false, isSuspicious: false };
|
|
5692
|
+
}
|
|
5693
|
+
const windowMs = this.settings.windowMinutes * 60 * 1e3;
|
|
5694
|
+
const ipKey = `${KV_PREFIX}ip:${ip}`;
|
|
5695
|
+
const ipCount = await this.incrementCounter(ipKey, windowMs);
|
|
5696
|
+
const emailKey = `${KV_PREFIX}email:${email}`;
|
|
5697
|
+
const emailCount = await this.incrementCounter(emailKey, windowMs);
|
|
5698
|
+
const ipEmailsKey = `${KV_PREFIX}ip-emails:${ip}`;
|
|
5699
|
+
await this.addToSet(ipEmailsKey, email, windowMs);
|
|
5700
|
+
const emailsFromIP = await this.getSetSize(ipEmailsKey);
|
|
5701
|
+
const isSuspicious = emailsFromIP >= 5;
|
|
5702
|
+
const shouldLockIP = ipCount >= this.settings.maxFailedAttemptsPerIP;
|
|
5703
|
+
const shouldLockEmail = emailCount >= this.settings.maxFailedAttemptsPerEmail;
|
|
5704
|
+
return { ipCount, emailCount, shouldLockIP, shouldLockEmail, isSuspicious };
|
|
5705
|
+
}
|
|
5706
|
+
async isLocked(ip, email) {
|
|
5707
|
+
if (!this.settings.enabled) {
|
|
5708
|
+
return { locked: false };
|
|
5709
|
+
}
|
|
5710
|
+
const ipLocked = await this.kv.get(`${LOCK_PREFIX}ip:${ip}`);
|
|
5711
|
+
if (ipLocked) {
|
|
5712
|
+
return { locked: true, reason: "IP address temporarily locked due to excessive failed login attempts" };
|
|
5713
|
+
}
|
|
5714
|
+
const emailLocked = await this.kv.get(`${LOCK_PREFIX}email:${email}`);
|
|
5715
|
+
if (emailLocked) {
|
|
5716
|
+
return { locked: true, reason: "Account temporarily locked due to excessive failed login attempts" };
|
|
5717
|
+
}
|
|
5718
|
+
return { locked: false };
|
|
5719
|
+
}
|
|
5720
|
+
async lockIP(ip) {
|
|
5721
|
+
const ttl = this.settings.lockoutDurationMinutes * 60;
|
|
5722
|
+
await this.kv.put(`${LOCK_PREFIX}ip:${ip}`, JSON.stringify({
|
|
5723
|
+
lockedAt: Date.now(),
|
|
5724
|
+
reason: "brute_force_ip"
|
|
5725
|
+
}), { expirationTtl: ttl });
|
|
5726
|
+
}
|
|
5727
|
+
async lockEmail(email) {
|
|
5728
|
+
const ttl = this.settings.lockoutDurationMinutes * 60;
|
|
5729
|
+
await this.kv.put(`${LOCK_PREFIX}email:${email}`, JSON.stringify({
|
|
5730
|
+
lockedAt: Date.now(),
|
|
5731
|
+
reason: "brute_force_email"
|
|
5732
|
+
}), { expirationTtl: ttl });
|
|
5733
|
+
}
|
|
5734
|
+
async unlockIP(ip) {
|
|
5735
|
+
await this.kv.delete(`${LOCK_PREFIX}ip:${ip}`);
|
|
5736
|
+
}
|
|
5737
|
+
async unlockEmail(email) {
|
|
5738
|
+
await this.kv.delete(`${LOCK_PREFIX}email:${email}`);
|
|
5739
|
+
}
|
|
5740
|
+
async getActiveLockouts() {
|
|
5741
|
+
const ipLocks = await this.kv.list({ prefix: `${LOCK_PREFIX}ip:` });
|
|
5742
|
+
const emailLocks = await this.kv.list({ prefix: `${LOCK_PREFIX}email:` });
|
|
5743
|
+
const lockouts = [];
|
|
5744
|
+
for (const key of ipLocks.keys) {
|
|
5745
|
+
const data = await this.kv.get(key.name);
|
|
5746
|
+
if (data) {
|
|
5747
|
+
const parsed = JSON.parse(data);
|
|
5748
|
+
lockouts.push({
|
|
5749
|
+
key: key.name,
|
|
5750
|
+
type: "ip",
|
|
5751
|
+
value: key.name.replace(`${LOCK_PREFIX}ip:`, ""),
|
|
5752
|
+
lockedAt: parsed.lockedAt
|
|
5753
|
+
});
|
|
5754
|
+
}
|
|
5755
|
+
}
|
|
5756
|
+
for (const key of emailLocks.keys) {
|
|
5757
|
+
const data = await this.kv.get(key.name);
|
|
5758
|
+
if (data) {
|
|
5759
|
+
const parsed = JSON.parse(data);
|
|
5760
|
+
lockouts.push({
|
|
5761
|
+
key: key.name,
|
|
5762
|
+
type: "email",
|
|
5763
|
+
value: key.name.replace(`${LOCK_PREFIX}email:`, ""),
|
|
5764
|
+
lockedAt: parsed.lockedAt
|
|
5765
|
+
});
|
|
5766
|
+
}
|
|
5767
|
+
}
|
|
5768
|
+
return lockouts;
|
|
5769
|
+
}
|
|
5770
|
+
async releaseLockout(key) {
|
|
5771
|
+
await this.kv.delete(key);
|
|
5772
|
+
}
|
|
5773
|
+
isAboveAlertThreshold(count) {
|
|
5774
|
+
return count >= this.settings.alertThreshold;
|
|
5775
|
+
}
|
|
5776
|
+
async incrementCounter(key, windowMs) {
|
|
5777
|
+
const existing = await this.kv.get(key);
|
|
5778
|
+
const now = Date.now();
|
|
5779
|
+
let entries = [];
|
|
5780
|
+
if (existing) {
|
|
5781
|
+
try {
|
|
5782
|
+
entries = JSON.parse(existing);
|
|
5783
|
+
} catch {
|
|
5784
|
+
entries = [];
|
|
5785
|
+
}
|
|
5786
|
+
}
|
|
5787
|
+
const cutoff = now - windowMs;
|
|
5788
|
+
entries = entries.filter((ts) => ts > cutoff);
|
|
5789
|
+
entries.push(now);
|
|
5790
|
+
const ttlSeconds = Math.ceil(windowMs / 1e3);
|
|
5791
|
+
await this.kv.put(key, JSON.stringify(entries), { expirationTtl: ttlSeconds });
|
|
5792
|
+
return entries.length;
|
|
5793
|
+
}
|
|
5794
|
+
async addToSet(key, value, windowMs) {
|
|
5795
|
+
const existing = await this.kv.get(key);
|
|
5796
|
+
let set = {};
|
|
5797
|
+
const now = Date.now();
|
|
5798
|
+
const cutoff = now - windowMs;
|
|
5799
|
+
if (existing) {
|
|
5800
|
+
try {
|
|
5801
|
+
set = JSON.parse(existing);
|
|
5802
|
+
} catch {
|
|
5803
|
+
set = {};
|
|
5804
|
+
}
|
|
5805
|
+
}
|
|
5806
|
+
for (const [k, ts] of Object.entries(set)) {
|
|
5807
|
+
if (ts < cutoff) delete set[k];
|
|
5808
|
+
}
|
|
5809
|
+
set[value] = now;
|
|
5810
|
+
const ttlSeconds = Math.ceil(windowMs / 1e3);
|
|
5811
|
+
await this.kv.put(key, JSON.stringify(set), { expirationTtl: ttlSeconds });
|
|
5812
|
+
}
|
|
5813
|
+
async getSetSize(key) {
|
|
5814
|
+
const existing = await this.kv.get(key);
|
|
5815
|
+
if (!existing) return 0;
|
|
5816
|
+
try {
|
|
5817
|
+
const set = JSON.parse(existing);
|
|
5818
|
+
return Object.keys(set).length;
|
|
5819
|
+
} catch {
|
|
5820
|
+
return 0;
|
|
5821
|
+
}
|
|
5822
|
+
}
|
|
5823
|
+
};
|
|
5824
|
+
|
|
5825
|
+
// src/plugins/core-plugins/security-audit-plugin/routes/api.ts
|
|
5826
|
+
var apiRoutes2 = new hono.Hono();
|
|
5827
|
+
apiRoutes2.use("*", chunkVHNTCB2X_cjs.requireAuth());
|
|
5828
|
+
apiRoutes2.use("*", async (c, next) => {
|
|
5829
|
+
const user = c.get("user");
|
|
5830
|
+
if (user?.role !== "admin") {
|
|
5831
|
+
return c.json({ error: "Access denied" }, 403);
|
|
5832
|
+
}
|
|
5833
|
+
return next();
|
|
5834
|
+
});
|
|
5835
|
+
async function getSettings2(db) {
|
|
5836
|
+
try {
|
|
5837
|
+
const pluginService = new chunkI6FFGQIT_cjs.PluginService(db);
|
|
5838
|
+
const plugin2 = await pluginService.getPlugin("security-audit");
|
|
5839
|
+
if (plugin2?.settings) {
|
|
5840
|
+
const settings = typeof plugin2.settings === "string" ? JSON.parse(plugin2.settings) : plugin2.settings;
|
|
5841
|
+
return { ...DEFAULT_SETTINGS2, ...settings };
|
|
5842
|
+
}
|
|
5843
|
+
} catch {
|
|
5844
|
+
}
|
|
5845
|
+
return DEFAULT_SETTINGS2;
|
|
5846
|
+
}
|
|
5847
|
+
apiRoutes2.get("/events", async (c) => {
|
|
5848
|
+
const db = c.env.DB;
|
|
5849
|
+
const settings = await getSettings2(db);
|
|
5850
|
+
const service = new SecurityAuditService(db, settings);
|
|
5851
|
+
const filters = {
|
|
5852
|
+
eventType: c.req.query("type"),
|
|
5853
|
+
severity: c.req.query("severity"),
|
|
5854
|
+
email: c.req.query("email") || void 0,
|
|
5855
|
+
ipAddress: c.req.query("ip") || void 0,
|
|
5856
|
+
search: c.req.query("search") || void 0,
|
|
5857
|
+
startDate: c.req.query("start") ? parseInt(c.req.query("start")) : void 0,
|
|
5858
|
+
endDate: c.req.query("end") ? parseInt(c.req.query("end")) : void 0,
|
|
5859
|
+
page: c.req.query("page") ? parseInt(c.req.query("page")) : 1,
|
|
5860
|
+
limit: c.req.query("limit") ? Math.min(parseInt(c.req.query("limit")), 100) : 50,
|
|
5861
|
+
sortBy: c.req.query("sortBy") || "created_at",
|
|
5862
|
+
sortOrder: c.req.query("sortOrder") || "desc"
|
|
5863
|
+
};
|
|
5864
|
+
const result = await service.getEvents(filters);
|
|
5865
|
+
return c.json(result);
|
|
5866
|
+
});
|
|
5867
|
+
apiRoutes2.get("/events/:id", async (c) => {
|
|
5868
|
+
const db = c.env.DB;
|
|
5869
|
+
const settings = await getSettings2(db);
|
|
5870
|
+
const service = new SecurityAuditService(db, settings);
|
|
5871
|
+
const event = await service.getEvent(c.req.param("id"));
|
|
5872
|
+
if (!event) {
|
|
5873
|
+
return c.json({ error: "Event not found" }, 404);
|
|
5874
|
+
}
|
|
5875
|
+
return c.json(event);
|
|
5876
|
+
});
|
|
5877
|
+
apiRoutes2.get("/stats", async (c) => {
|
|
5878
|
+
const db = c.env.DB;
|
|
5879
|
+
const settings = await getSettings2(db);
|
|
5880
|
+
const service = new SecurityAuditService(db, settings);
|
|
5881
|
+
const stats = await service.getStats();
|
|
5882
|
+
return c.json(stats);
|
|
5883
|
+
});
|
|
5884
|
+
apiRoutes2.get("/stats/ips", async (c) => {
|
|
5885
|
+
const db = c.env.DB;
|
|
5886
|
+
const settings = await getSettings2(db);
|
|
5887
|
+
const service = new SecurityAuditService(db, settings);
|
|
5888
|
+
const limit = c.req.query("limit") ? parseInt(c.req.query("limit")) : 10;
|
|
5889
|
+
const ips = await service.getTopIPs(limit);
|
|
5890
|
+
return c.json(ips);
|
|
5891
|
+
});
|
|
5892
|
+
apiRoutes2.get("/stats/trend", async (c) => {
|
|
5893
|
+
const db = c.env.DB;
|
|
5894
|
+
const settings = await getSettings2(db);
|
|
5895
|
+
const service = new SecurityAuditService(db, settings);
|
|
5896
|
+
const hours = c.req.query("hours") ? parseInt(c.req.query("hours")) : 24;
|
|
5897
|
+
const trend = await service.getHourlyTrend(hours);
|
|
5898
|
+
return c.json(trend);
|
|
5899
|
+
});
|
|
5900
|
+
apiRoutes2.get("/lockouts", async (c) => {
|
|
5901
|
+
const kv = c.env.CACHE_KV;
|
|
5902
|
+
const db = c.env.DB;
|
|
5903
|
+
const settings = await getSettings2(db);
|
|
5904
|
+
const detector = new BruteForceDetector(kv, settings.bruteForce);
|
|
5905
|
+
const lockouts = await detector.getActiveLockouts();
|
|
5906
|
+
return c.json(lockouts);
|
|
5907
|
+
});
|
|
5908
|
+
apiRoutes2.delete("/lockouts/:key", async (c) => {
|
|
5909
|
+
const kv = c.env.CACHE_KV;
|
|
5910
|
+
const key = decodeURIComponent(c.req.param("key"));
|
|
5911
|
+
const db = c.env.DB;
|
|
5912
|
+
const settings = await getSettings2(db);
|
|
5913
|
+
const detector = new BruteForceDetector(kv, settings.bruteForce);
|
|
5914
|
+
await detector.releaseLockout(key);
|
|
5915
|
+
return c.json({ success: true });
|
|
5916
|
+
});
|
|
5917
|
+
apiRoutes2.post("/events/purge", async (c) => {
|
|
5918
|
+
const db = c.env.DB;
|
|
5919
|
+
const settings = await getSettings2(db);
|
|
5920
|
+
const service = new SecurityAuditService(db, settings);
|
|
5921
|
+
const body = await c.req.json().catch(() => ({}));
|
|
5922
|
+
const deleted = await service.purgeOldEvents(body.daysToKeep);
|
|
5923
|
+
return c.json({ success: true, deleted });
|
|
5924
|
+
});
|
|
5925
|
+
apiRoutes2.get("/export", async (c) => {
|
|
5926
|
+
const db = c.env.DB;
|
|
5927
|
+
const settings = await getSettings2(db);
|
|
5928
|
+
const service = new SecurityAuditService(db, settings);
|
|
5929
|
+
const format = c.req.query("format") || "json";
|
|
5930
|
+
const filters = {
|
|
5931
|
+
eventType: c.req.query("type"),
|
|
5932
|
+
severity: c.req.query("severity"),
|
|
5933
|
+
startDate: c.req.query("start") ? parseInt(c.req.query("start")) : void 0,
|
|
5934
|
+
endDate: c.req.query("end") ? parseInt(c.req.query("end")) : void 0,
|
|
5935
|
+
limit: 1e4,
|
|
5936
|
+
page: 1
|
|
5937
|
+
};
|
|
5938
|
+
const { events } = await service.getEvents(filters);
|
|
5939
|
+
if (format === "csv") {
|
|
5940
|
+
const headers = ["id", "event_type", "severity", "email", "ip_address", "country_code", "blocked", "created_at"];
|
|
5941
|
+
const csvRows = [headers.join(",")];
|
|
5942
|
+
for (const event of events) {
|
|
5943
|
+
csvRows.push([
|
|
5944
|
+
event.id,
|
|
5945
|
+
event.eventType,
|
|
5946
|
+
event.severity,
|
|
5947
|
+
event.email || "",
|
|
5948
|
+
event.ipAddress || "",
|
|
5949
|
+
event.countryCode || "",
|
|
5950
|
+
event.blocked ? "1" : "0",
|
|
5951
|
+
new Date(event.createdAt).toISOString()
|
|
5952
|
+
].map((v) => `"${String(v).replace(/"/g, '""')}"`).join(","));
|
|
5953
|
+
}
|
|
5954
|
+
return new Response(csvRows.join("\n"), {
|
|
5955
|
+
headers: {
|
|
5956
|
+
"Content-Type": "text/csv",
|
|
5957
|
+
"Content-Disposition": `attachment; filename="security-events-${Date.now()}.csv"`
|
|
5958
|
+
}
|
|
5959
|
+
});
|
|
5960
|
+
}
|
|
5961
|
+
return c.json(events);
|
|
5962
|
+
});
|
|
5963
|
+
|
|
5964
|
+
// src/plugins/core-plugins/security-audit-plugin/middleware/audit-middleware.ts
|
|
5965
|
+
function extractRequestInfo(c) {
|
|
5966
|
+
const ip = c.req.header("cf-connecting-ip") || c.req.header("x-forwarded-for")?.split(",")[0]?.trim() || "unknown";
|
|
5967
|
+
const userAgent = c.req.header("user-agent") || "unknown";
|
|
5968
|
+
const countryCode = c.req.header("cf-ipcountry") || null;
|
|
5969
|
+
const path = new URL(c.req.url).pathname;
|
|
5970
|
+
const method = c.req.method;
|
|
5971
|
+
return { ip, userAgent, countryCode, path, method };
|
|
5972
|
+
}
|
|
5973
|
+
function generateFingerprint(ip, userAgent) {
|
|
5974
|
+
const str = `${ip}:${userAgent}`;
|
|
5975
|
+
let hash = 0;
|
|
5976
|
+
for (let i = 0; i < str.length; i++) {
|
|
5977
|
+
const char = str.charCodeAt(i);
|
|
5978
|
+
hash = (hash << 5) - hash + char;
|
|
5979
|
+
hash |= 0;
|
|
5980
|
+
}
|
|
5981
|
+
return Math.abs(hash).toString(36);
|
|
5982
|
+
}
|
|
5983
|
+
async function getPluginSettings(db) {
|
|
5984
|
+
try {
|
|
5985
|
+
const pluginService = new chunkI6FFGQIT_cjs.PluginService(db);
|
|
5986
|
+
const plugin2 = await pluginService.getPlugin("security-audit");
|
|
5987
|
+
if (plugin2?.settings) {
|
|
5988
|
+
const settings = typeof plugin2.settings === "string" ? JSON.parse(plugin2.settings) : plugin2.settings;
|
|
5989
|
+
return { ...DEFAULT_SETTINGS2, ...settings };
|
|
5990
|
+
}
|
|
5991
|
+
} catch {
|
|
5992
|
+
}
|
|
5993
|
+
return DEFAULT_SETTINGS2;
|
|
5994
|
+
}
|
|
5995
|
+
async function isPluginActive2(db) {
|
|
5996
|
+
try {
|
|
5997
|
+
const result = await db.prepare(
|
|
5998
|
+
"SELECT status FROM plugins WHERE id = 'security-audit'"
|
|
5999
|
+
).first();
|
|
6000
|
+
return result?.status === "active";
|
|
6001
|
+
} catch {
|
|
6002
|
+
return false;
|
|
6003
|
+
}
|
|
6004
|
+
}
|
|
6005
|
+
function securityAuditMiddleware() {
|
|
6006
|
+
return async (c, next) => {
|
|
6007
|
+
const path = new URL(c.req.url).pathname;
|
|
6008
|
+
if (!path.startsWith("/auth/")) {
|
|
6009
|
+
return next();
|
|
6010
|
+
}
|
|
6011
|
+
const db = c.env.DB;
|
|
6012
|
+
if (!await isPluginActive2(db)) {
|
|
6013
|
+
return next();
|
|
6014
|
+
}
|
|
6015
|
+
const settings = await getPluginSettings(db);
|
|
6016
|
+
const { ip, userAgent, countryCode, method } = extractRequestInfo(c);
|
|
6017
|
+
const fingerprint = generateFingerprint(ip, userAgent);
|
|
6018
|
+
const isLoginPost = (path === "/auth/login" || path === "/auth/login/form") && method === "POST";
|
|
6019
|
+
let preExtractedEmail = "";
|
|
6020
|
+
if (isLoginPost) {
|
|
6021
|
+
try {
|
|
6022
|
+
if (path === "/auth/login/form") {
|
|
6023
|
+
const clonedReq = c.req.raw.clone();
|
|
6024
|
+
const formData = await clonedReq.formData();
|
|
6025
|
+
preExtractedEmail = (formData.get("email") || "").toLowerCase();
|
|
6026
|
+
} else {
|
|
6027
|
+
const body = await c.req.json();
|
|
6028
|
+
preExtractedEmail = body?.email?.toLowerCase() || "";
|
|
6029
|
+
}
|
|
6030
|
+
} catch {
|
|
6031
|
+
}
|
|
6032
|
+
if (preExtractedEmail && settings.bruteForce.enabled) {
|
|
6033
|
+
const detector = new BruteForceDetector(c.env.CACHE_KV, settings.bruteForce);
|
|
6034
|
+
const lockStatus = await detector.isLocked(ip, preExtractedEmail);
|
|
6035
|
+
if (lockStatus.locked) {
|
|
6036
|
+
const service = new SecurityAuditService(db, settings);
|
|
6037
|
+
const logPromise2 = service.logEvent({
|
|
6038
|
+
eventType: "login_failure",
|
|
6039
|
+
severity: "warning",
|
|
6040
|
+
email: preExtractedEmail,
|
|
6041
|
+
ipAddress: ip,
|
|
6042
|
+
userAgent,
|
|
6043
|
+
countryCode: countryCode || void 0,
|
|
6044
|
+
requestPath: path,
|
|
6045
|
+
requestMethod: method,
|
|
6046
|
+
fingerprint,
|
|
6047
|
+
blocked: true,
|
|
6048
|
+
details: { reason: lockStatus.reason }
|
|
6049
|
+
});
|
|
6050
|
+
if (c.executionCtx?.waitUntil) {
|
|
6051
|
+
c.executionCtx.waitUntil(logPromise2);
|
|
6052
|
+
}
|
|
6053
|
+
return c.json({
|
|
6054
|
+
error: lockStatus.reason || "Too many failed attempts. Please try again later."
|
|
6055
|
+
}, 429);
|
|
6056
|
+
}
|
|
6057
|
+
}
|
|
6058
|
+
}
|
|
6059
|
+
await next();
|
|
6060
|
+
const logPromise = logAuthEvent(c, db, settings, ip, userAgent, countryCode, fingerprint, path, method, preExtractedEmail);
|
|
6061
|
+
if (c.executionCtx?.waitUntil) {
|
|
6062
|
+
c.executionCtx.waitUntil(logPromise);
|
|
6063
|
+
}
|
|
6064
|
+
};
|
|
6065
|
+
}
|
|
6066
|
+
async function logAuthEvent(c, db, settings, ip, userAgent, countryCode, fingerprint, path, method, preExtractedEmail = "") {
|
|
6067
|
+
try {
|
|
6068
|
+
const service = new SecurityAuditService(db, settings);
|
|
6069
|
+
const status = c.res.status;
|
|
6070
|
+
const isLoginPost = (path === "/auth/login" || path === "/auth/login/form") && method === "POST";
|
|
6071
|
+
const isFormLogin = path === "/auth/login/form";
|
|
6072
|
+
if (isLoginPost) {
|
|
6073
|
+
let loginSucceeded;
|
|
6074
|
+
if (isFormLogin) {
|
|
6075
|
+
const hxRedirect = c.res.headers.get("HX-Redirect");
|
|
6076
|
+
const setCookieHeader = c.res.headers.get("set-cookie") || "";
|
|
6077
|
+
loginSucceeded = !!(hxRedirect?.includes("/admin") || setCookieHeader.includes("auth_token"));
|
|
6078
|
+
} else {
|
|
6079
|
+
loginSucceeded = status === 200;
|
|
6080
|
+
}
|
|
6081
|
+
if (loginSucceeded) {
|
|
6082
|
+
if (!settings.logging.logSuccessfulLogins) return;
|
|
6083
|
+
let email = preExtractedEmail;
|
|
6084
|
+
let userId = "";
|
|
6085
|
+
if (!isFormLogin) {
|
|
6086
|
+
try {
|
|
6087
|
+
const cloned = c.res.clone();
|
|
6088
|
+
const body = await cloned.json();
|
|
6089
|
+
email = body?.user?.email || email;
|
|
6090
|
+
userId = body?.user?.id || "";
|
|
6091
|
+
} catch {
|
|
6092
|
+
}
|
|
6093
|
+
}
|
|
6094
|
+
await service.logEvent({
|
|
6095
|
+
eventType: "login_success",
|
|
6096
|
+
severity: "info",
|
|
6097
|
+
userId: userId || void 0,
|
|
6098
|
+
email: email || void 0,
|
|
6099
|
+
ipAddress: ip,
|
|
6100
|
+
userAgent,
|
|
6101
|
+
countryCode: countryCode || void 0,
|
|
6102
|
+
requestPath: path,
|
|
6103
|
+
requestMethod: method,
|
|
6104
|
+
fingerprint
|
|
6105
|
+
});
|
|
6106
|
+
} else {
|
|
6107
|
+
const email = preExtractedEmail;
|
|
6108
|
+
await service.logEvent({
|
|
6109
|
+
eventType: "login_failure",
|
|
6110
|
+
severity: "warning",
|
|
6111
|
+
email: email || void 0,
|
|
6112
|
+
ipAddress: ip,
|
|
6113
|
+
userAgent,
|
|
6114
|
+
countryCode: countryCode || void 0,
|
|
6115
|
+
requestPath: path,
|
|
6116
|
+
requestMethod: method,
|
|
6117
|
+
fingerprint,
|
|
6118
|
+
details: { statusCode: status }
|
|
6119
|
+
});
|
|
6120
|
+
if (email && settings.bruteForce.enabled) {
|
|
6121
|
+
const detector = new BruteForceDetector(c.env.CACHE_KV, settings.bruteForce);
|
|
6122
|
+
const result = await detector.recordFailedAttempt(ip, email);
|
|
6123
|
+
if (result.shouldLockIP) {
|
|
6124
|
+
await detector.lockIP(ip);
|
|
6125
|
+
await service.logEvent({
|
|
6126
|
+
eventType: "account_lockout",
|
|
6127
|
+
severity: "critical",
|
|
6128
|
+
email,
|
|
6129
|
+
ipAddress: ip,
|
|
6130
|
+
userAgent,
|
|
6131
|
+
countryCode: countryCode || void 0,
|
|
6132
|
+
requestPath: path,
|
|
6133
|
+
requestMethod: method,
|
|
6134
|
+
fingerprint,
|
|
6135
|
+
details: { reason: "brute_force_ip", attemptCount: result.ipCount }
|
|
6136
|
+
});
|
|
6137
|
+
}
|
|
6138
|
+
if (result.shouldLockEmail) {
|
|
6139
|
+
await detector.lockEmail(email);
|
|
6140
|
+
await service.logEvent({
|
|
6141
|
+
eventType: "account_lockout",
|
|
6142
|
+
severity: "critical",
|
|
6143
|
+
email,
|
|
6144
|
+
ipAddress: ip,
|
|
6145
|
+
userAgent,
|
|
6146
|
+
countryCode: countryCode || void 0,
|
|
6147
|
+
requestPath: path,
|
|
6148
|
+
requestMethod: method,
|
|
6149
|
+
fingerprint,
|
|
6150
|
+
details: { reason: "brute_force_email", attemptCount: result.emailCount }
|
|
6151
|
+
});
|
|
6152
|
+
}
|
|
6153
|
+
if (result.isSuspicious) {
|
|
6154
|
+
await service.logEvent({
|
|
6155
|
+
eventType: "suspicious_activity",
|
|
6156
|
+
severity: "critical",
|
|
6157
|
+
ipAddress: ip,
|
|
6158
|
+
userAgent,
|
|
6159
|
+
countryCode: countryCode || void 0,
|
|
6160
|
+
requestPath: path,
|
|
6161
|
+
requestMethod: method,
|
|
6162
|
+
fingerprint,
|
|
6163
|
+
details: { reason: "multiple_emails_from_ip", ipCount: result.ipCount }
|
|
6164
|
+
});
|
|
6165
|
+
}
|
|
6166
|
+
}
|
|
6167
|
+
}
|
|
6168
|
+
}
|
|
6169
|
+
if (path === "/auth/register" && method === "POST" && settings.logging.logRegistrations) {
|
|
6170
|
+
if (status === 201 || status === 200) {
|
|
6171
|
+
let email = "";
|
|
6172
|
+
let userId = "";
|
|
6173
|
+
try {
|
|
6174
|
+
const cloned = c.res.clone();
|
|
6175
|
+
const body = await cloned.json();
|
|
6176
|
+
email = body?.user?.email || "";
|
|
6177
|
+
userId = body?.user?.id || "";
|
|
6178
|
+
} catch {
|
|
6179
|
+
}
|
|
6180
|
+
await service.logEvent({
|
|
6181
|
+
eventType: "registration",
|
|
6182
|
+
severity: "info",
|
|
6183
|
+
userId: userId || void 0,
|
|
6184
|
+
email: email || void 0,
|
|
6185
|
+
ipAddress: ip,
|
|
6186
|
+
userAgent,
|
|
6187
|
+
countryCode: countryCode || void 0,
|
|
6188
|
+
requestPath: path,
|
|
6189
|
+
requestMethod: method,
|
|
6190
|
+
fingerprint
|
|
6191
|
+
});
|
|
6192
|
+
}
|
|
6193
|
+
}
|
|
6194
|
+
if (path === "/auth/logout" && settings.logging.logLogouts) {
|
|
6195
|
+
const user = c.get("user");
|
|
6196
|
+
await service.logEvent({
|
|
6197
|
+
eventType: "logout",
|
|
6198
|
+
severity: "info",
|
|
6199
|
+
userId: user?.userId,
|
|
6200
|
+
email: user?.email,
|
|
6201
|
+
ipAddress: ip,
|
|
6202
|
+
userAgent,
|
|
6203
|
+
countryCode: countryCode || void 0,
|
|
6204
|
+
requestPath: path,
|
|
6205
|
+
requestMethod: method,
|
|
6206
|
+
fingerprint
|
|
6207
|
+
});
|
|
6208
|
+
}
|
|
6209
|
+
} catch (error) {
|
|
6210
|
+
console.error("[SecurityAudit] Error logging auth event:", error);
|
|
6211
|
+
}
|
|
6212
|
+
}
|
|
6213
|
+
|
|
6214
|
+
// src/plugins/core-plugins/security-audit-plugin/index.ts
|
|
6215
|
+
function createSecurityAuditPlugin() {
|
|
6216
|
+
const builder = chunk6FHNRRJ3_cjs.PluginBuilder.create({
|
|
6217
|
+
name: "security-audit",
|
|
6218
|
+
version: "1.0.0-beta.1",
|
|
6219
|
+
description: "Security event logging, brute-force detection, and analytics dashboard"
|
|
6220
|
+
});
|
|
6221
|
+
builder.metadata({
|
|
6222
|
+
author: { name: "SonicJS Team" },
|
|
6223
|
+
license: "MIT"
|
|
6224
|
+
});
|
|
6225
|
+
builder.addRoute("/admin/plugins/security-audit", adminRoutes2, {
|
|
6226
|
+
description: "Security audit dashboard and admin pages",
|
|
6227
|
+
requiresAuth: true,
|
|
6228
|
+
priority: 50
|
|
6229
|
+
});
|
|
6230
|
+
builder.addRoute("/api/security-audit", apiRoutes2, {
|
|
6231
|
+
description: "Security audit API endpoints",
|
|
6232
|
+
requiresAuth: true,
|
|
6233
|
+
priority: 50
|
|
6234
|
+
});
|
|
6235
|
+
builder.addMenuItem("Security", "/admin/plugins/security-audit", {
|
|
6236
|
+
icon: `<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"/></svg>`,
|
|
6237
|
+
order: 85
|
|
6238
|
+
});
|
|
6239
|
+
builder.lifecycle({
|
|
6240
|
+
install: async (context) => {
|
|
6241
|
+
console.log("[SecurityAudit] Plugin installed");
|
|
6242
|
+
},
|
|
6243
|
+
activate: async (context) => {
|
|
6244
|
+
console.log("[SecurityAudit] Plugin activated");
|
|
6245
|
+
},
|
|
6246
|
+
deactivate: async (context) => {
|
|
6247
|
+
console.log("[SecurityAudit] Plugin deactivated");
|
|
6248
|
+
},
|
|
6249
|
+
uninstall: async (context) => {
|
|
6250
|
+
console.log("[SecurityAudit] Plugin uninstalled");
|
|
6251
|
+
}
|
|
6252
|
+
});
|
|
6253
|
+
return builder.build();
|
|
6254
|
+
}
|
|
6255
|
+
var securityAuditPlugin = createSecurityAuditPlugin();
|
|
6256
|
+
|
|
6257
|
+
// src/middleware/plugin-menu.ts
|
|
6258
|
+
var MENU_PLUGINS = [
|
|
6259
|
+
securityAuditPlugin
|
|
6260
|
+
];
|
|
6261
|
+
var MARKER = "<!-- DYNAMIC_PLUGIN_MENU -->";
|
|
6262
|
+
function renderMenuItem(item, currentPath) {
|
|
6263
|
+
const isActive = currentPath === item.path || currentPath.startsWith(item.path);
|
|
6264
|
+
const fallbackIcon = `<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"/></svg>`;
|
|
6265
|
+
return `
|
|
6266
|
+
<span class="relative">
|
|
6267
|
+
${isActive ? '<span class="absolute inset-y-2 -left-4 w-0.5 rounded-full bg-cyan-500 dark:bg-cyan-400"></span>' : ""}
|
|
6268
|
+
<a
|
|
6269
|
+
href="${item.path}"
|
|
6270
|
+
class="flex w-full items-center gap-3 rounded-lg px-2 py-2.5 text-left text-sm/5 font-medium ${isActive ? "text-zinc-950 dark:text-white" : "text-zinc-950 hover:bg-zinc-950/5 dark:text-white dark:hover:bg-white/5"}"
|
|
6271
|
+
${isActive ? 'data-current="true"' : ""}
|
|
6272
|
+
>
|
|
6273
|
+
<span class="shrink-0 ${isActive ? "fill-zinc-950 dark:fill-white" : "fill-zinc-500 dark:fill-zinc-400"}">
|
|
6274
|
+
${item.icon || fallbackIcon}
|
|
6275
|
+
</span>
|
|
6276
|
+
<span class="truncate">${item.label}</span>
|
|
6277
|
+
</a>
|
|
6278
|
+
</span>`;
|
|
6279
|
+
}
|
|
6280
|
+
function pluginMenuMiddleware() {
|
|
6281
|
+
return async (c, next) => {
|
|
6282
|
+
const path = new URL(c.req.url).pathname;
|
|
6283
|
+
if (!path.startsWith("/admin")) {
|
|
6284
|
+
return next();
|
|
6285
|
+
}
|
|
6286
|
+
let activeMenuItems = [];
|
|
6287
|
+
try {
|
|
6288
|
+
const db = c.env.DB;
|
|
6289
|
+
const pluginNames = MENU_PLUGINS.map((p) => p.name);
|
|
6290
|
+
if (pluginNames.length > 0) {
|
|
6291
|
+
const placeholders = pluginNames.map(() => "?").join(",");
|
|
6292
|
+
const result = await db.prepare(
|
|
6293
|
+
`SELECT name FROM plugins WHERE name IN (${placeholders}) AND status = 'active'`
|
|
6294
|
+
).bind(...pluginNames).all();
|
|
6295
|
+
const activeNames = new Set((result.results || []).map((r) => r.name));
|
|
6296
|
+
for (const plugin2 of MENU_PLUGINS) {
|
|
6297
|
+
if (activeNames.has(plugin2.name) && plugin2.menuItems) {
|
|
6298
|
+
activeMenuItems.push(...plugin2.menuItems);
|
|
6299
|
+
}
|
|
6300
|
+
}
|
|
6301
|
+
activeMenuItems.sort((a, b) => (a.order || 0) - (b.order || 0));
|
|
6302
|
+
}
|
|
6303
|
+
} catch {
|
|
6304
|
+
}
|
|
6305
|
+
c.set("pluginMenuItems", activeMenuItems.map((m) => ({ label: m.label, path: m.path, icon: m.icon || "" })));
|
|
6306
|
+
await next();
|
|
6307
|
+
if (activeMenuItems.length > 0 && c.res.headers.get("content-type")?.includes("text/html")) {
|
|
6308
|
+
const status = c.res.status;
|
|
6309
|
+
const headers = new Headers(c.res.headers);
|
|
6310
|
+
const html = await c.res.text();
|
|
6311
|
+
if (html.includes(MARKER)) {
|
|
6312
|
+
const renderedItems = activeMenuItems.map((item) => renderMenuItem(item, path)).join("");
|
|
6313
|
+
const newHtml = html.split(MARKER).join(renderedItems);
|
|
6314
|
+
c.res = new Response(newHtml, { status, headers });
|
|
6315
|
+
} else {
|
|
6316
|
+
c.res = new Response(html, { status, headers });
|
|
6317
|
+
}
|
|
6318
|
+
}
|
|
6319
|
+
};
|
|
6320
|
+
}
|
|
6321
|
+
|
|
4692
6322
|
// src/plugins/cache/services/cache-config.ts
|
|
4693
6323
|
var CACHE_CONFIGS = {
|
|
4694
6324
|
// Content (high read, low write)
|
|
@@ -5651,7 +7281,7 @@ async function warmNamespace(namespace, entries) {
|
|
|
5651
7281
|
}
|
|
5652
7282
|
|
|
5653
7283
|
// src/templates/pages/admin-cache.template.ts
|
|
5654
|
-
|
|
7284
|
+
chunkH4NHRZ6Y_cjs.init_admin_layout_catalyst_template();
|
|
5655
7285
|
function renderCacheDashboard(data) {
|
|
5656
7286
|
const pageContent = `
|
|
5657
7287
|
<div class="space-y-6">
|
|
@@ -5830,7 +7460,7 @@ function renderCacheDashboard(data) {
|
|
|
5830
7460
|
</script>
|
|
5831
7461
|
|
|
5832
7462
|
<!-- Confirmation Dialogs -->
|
|
5833
|
-
${
|
|
7463
|
+
${chunkZV6ZCJ74_cjs.renderConfirmationDialog({
|
|
5834
7464
|
id: "clear-all-cache-confirm",
|
|
5835
7465
|
title: "Clear All Cache",
|
|
5836
7466
|
message: "Are you sure you want to clear all cache entries? This cannot be undone.",
|
|
@@ -5841,7 +7471,7 @@ function renderCacheDashboard(data) {
|
|
|
5841
7471
|
onConfirm: "performClearAllCaches()"
|
|
5842
7472
|
})}
|
|
5843
7473
|
|
|
5844
|
-
${
|
|
7474
|
+
${chunkZV6ZCJ74_cjs.renderConfirmationDialog({
|
|
5845
7475
|
id: "clear-namespace-cache-confirm",
|
|
5846
7476
|
title: "Clear Namespace Cache",
|
|
5847
7477
|
message: "Clear cache for this namespace?",
|
|
@@ -5852,7 +7482,7 @@ function renderCacheDashboard(data) {
|
|
|
5852
7482
|
onConfirm: "performClearNamespaceCache()"
|
|
5853
7483
|
})}
|
|
5854
7484
|
|
|
5855
|
-
${
|
|
7485
|
+
${chunkZV6ZCJ74_cjs.getConfirmationDialogScript()}
|
|
5856
7486
|
`;
|
|
5857
7487
|
const layoutData = {
|
|
5858
7488
|
title: "Cache System",
|
|
@@ -5862,7 +7492,7 @@ function renderCacheDashboard(data) {
|
|
|
5862
7492
|
version: data.version,
|
|
5863
7493
|
content: pageContent
|
|
5864
7494
|
};
|
|
5865
|
-
return
|
|
7495
|
+
return chunkH4NHRZ6Y_cjs.renderAdminLayoutCatalyst(layoutData);
|
|
5866
7496
|
}
|
|
5867
7497
|
function renderStatCard(label, value, color, icon, colorOverride) {
|
|
5868
7498
|
const finalColor = colorOverride || color;
|
|
@@ -6538,14 +8168,14 @@ var faviconSvg = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
|
6538
8168
|
// src/app.ts
|
|
6539
8169
|
function createSonicJSApp(config = {}) {
|
|
6540
8170
|
const app2 = new hono.Hono();
|
|
6541
|
-
const appVersion = config.version ||
|
|
8171
|
+
const appVersion = config.version || chunkRXNLGINR_cjs.getCoreVersion();
|
|
6542
8172
|
const appName = config.name || "SonicJS AI";
|
|
6543
8173
|
app2.use("*", async (c, next) => {
|
|
6544
8174
|
c.set("appVersion", appVersion);
|
|
6545
8175
|
await next();
|
|
6546
8176
|
});
|
|
6547
|
-
app2.use("*",
|
|
6548
|
-
app2.use("*",
|
|
8177
|
+
app2.use("*", chunkVHNTCB2X_cjs.metricsMiddleware());
|
|
8178
|
+
app2.use("*", chunkVHNTCB2X_cjs.bootstrapMiddleware(config));
|
|
6549
8179
|
if (config.middleware?.beforeAuth) {
|
|
6550
8180
|
for (const middleware of config.middleware.beforeAuth) {
|
|
6551
8181
|
app2.use("*", middleware);
|
|
@@ -6554,28 +8184,35 @@ function createSonicJSApp(config = {}) {
|
|
|
6554
8184
|
app2.use("*", async (_c, next) => {
|
|
6555
8185
|
await next();
|
|
6556
8186
|
});
|
|
6557
|
-
app2.use("*",
|
|
6558
|
-
app2.use("*",
|
|
8187
|
+
app2.use("*", chunkVHNTCB2X_cjs.securityHeadersMiddleware());
|
|
8188
|
+
app2.use("*", chunkVHNTCB2X_cjs.csrfProtection());
|
|
6559
8189
|
if (config.middleware?.afterAuth) {
|
|
6560
8190
|
for (const middleware of config.middleware.afterAuth) {
|
|
6561
8191
|
app2.use("*", middleware);
|
|
6562
8192
|
}
|
|
6563
8193
|
}
|
|
6564
|
-
app2.
|
|
6565
|
-
app2.route("/api
|
|
6566
|
-
app2.route("/api/
|
|
6567
|
-
app2.route("/
|
|
6568
|
-
app2.route("/admin/
|
|
6569
|
-
app2.route("/admin/
|
|
6570
|
-
app2.route("/admin/
|
|
6571
|
-
app2.route("/admin/
|
|
6572
|
-
app2.route("/
|
|
6573
|
-
app2.route("/
|
|
6574
|
-
app2.route("/
|
|
8194
|
+
app2.use("/admin/*", pluginMenuMiddleware());
|
|
8195
|
+
app2.route("/api", chunkZV6ZCJ74_cjs.api_default);
|
|
8196
|
+
app2.route("/api/media", chunkZV6ZCJ74_cjs.api_media_default);
|
|
8197
|
+
app2.route("/api/system", chunkZV6ZCJ74_cjs.api_system_default);
|
|
8198
|
+
app2.route("/admin/api", chunkZV6ZCJ74_cjs.admin_api_default);
|
|
8199
|
+
app2.route("/admin/dashboard", chunkZV6ZCJ74_cjs.router);
|
|
8200
|
+
app2.route("/admin/collections", chunkZV6ZCJ74_cjs.adminCollectionsRoutes);
|
|
8201
|
+
app2.route("/admin/forms", chunkZV6ZCJ74_cjs.adminFormsRoutes);
|
|
8202
|
+
app2.route("/admin/settings", chunkZV6ZCJ74_cjs.adminSettingsRoutes);
|
|
8203
|
+
app2.route("/forms", chunkZV6ZCJ74_cjs.public_forms_default);
|
|
8204
|
+
app2.route("/api/forms", chunkZV6ZCJ74_cjs.public_forms_default);
|
|
8205
|
+
app2.route("/admin/api-reference", chunkZV6ZCJ74_cjs.router2);
|
|
6575
8206
|
app2.route("/admin/database-tools", createDatabaseToolsAdminRoutes());
|
|
6576
8207
|
app2.route("/admin/seed-data", createSeedDataAdminRoutes());
|
|
6577
|
-
app2.route("/admin/content",
|
|
6578
|
-
app2.route("/admin/media",
|
|
8208
|
+
app2.route("/admin/content", chunkZV6ZCJ74_cjs.admin_content_default);
|
|
8209
|
+
app2.route("/admin/media", chunkZV6ZCJ74_cjs.adminMediaRoutes);
|
|
8210
|
+
app2.use("/auth/*", securityAuditMiddleware());
|
|
8211
|
+
if (securityAuditPlugin.routes && securityAuditPlugin.routes.length > 0) {
|
|
8212
|
+
for (const route of securityAuditPlugin.routes) {
|
|
8213
|
+
app2.route(route.path, route.handler);
|
|
8214
|
+
}
|
|
8215
|
+
}
|
|
6579
8216
|
if (aiSearchPlugin.routes && aiSearchPlugin.routes.length > 0) {
|
|
6580
8217
|
for (const route of aiSearchPlugin.routes) {
|
|
6581
8218
|
app2.route(route.path, route.handler);
|
|
@@ -6587,16 +8224,21 @@ function createSonicJSApp(config = {}) {
|
|
|
6587
8224
|
app2.route(route.path, route.handler);
|
|
6588
8225
|
}
|
|
6589
8226
|
}
|
|
8227
|
+
if (chunkZV6ZCJ74_cjs.userProfilesPlugin.routes && chunkZV6ZCJ74_cjs.userProfilesPlugin.routes.length > 0) {
|
|
8228
|
+
for (const route of chunkZV6ZCJ74_cjs.userProfilesPlugin.routes) {
|
|
8229
|
+
app2.route(route.path, route.handler);
|
|
8230
|
+
}
|
|
8231
|
+
}
|
|
6590
8232
|
if (otpLoginPlugin.routes && otpLoginPlugin.routes.length > 0) {
|
|
6591
8233
|
for (const route of otpLoginPlugin.routes) {
|
|
6592
8234
|
app2.route(route.path, route.handler);
|
|
6593
8235
|
}
|
|
6594
8236
|
}
|
|
6595
|
-
app2.route("/admin/plugins",
|
|
6596
|
-
app2.route("/admin/logs",
|
|
6597
|
-
app2.route("/admin",
|
|
6598
|
-
app2.route("/auth",
|
|
6599
|
-
app2.route("/",
|
|
8237
|
+
app2.route("/admin/plugins", chunkZV6ZCJ74_cjs.adminPluginRoutes);
|
|
8238
|
+
app2.route("/admin/logs", chunkZV6ZCJ74_cjs.adminLogsRoutes);
|
|
8239
|
+
app2.route("/admin", chunkZV6ZCJ74_cjs.userRoutes);
|
|
8240
|
+
app2.route("/auth", chunkZV6ZCJ74_cjs.auth_default);
|
|
8241
|
+
app2.route("/", chunkZV6ZCJ74_cjs.test_cleanup_default);
|
|
6600
8242
|
if (emailPlugin.routes && emailPlugin.routes.length > 0) {
|
|
6601
8243
|
for (const route of emailPlugin.routes) {
|
|
6602
8244
|
app2.route(route.path, route.handler);
|
|
@@ -6659,7 +8301,7 @@ function createSonicJSApp(config = {}) {
|
|
|
6659
8301
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
6660
8302
|
});
|
|
6661
8303
|
});
|
|
6662
|
-
|
|
8304
|
+
chunkNZWFCUDA_cjs.setAppInstance(app2);
|
|
6663
8305
|
app2.notFound((c) => {
|
|
6664
8306
|
return c.json({ error: "Not Found", status: 404 }, 404);
|
|
6665
8307
|
});
|
|
@@ -6676,447 +8318,463 @@ function setupCoreRoutes(_app) {
|
|
|
6676
8318
|
console.warn("setupCoreRoutes is deprecated. Use createSonicJSApp() instead.");
|
|
6677
8319
|
}
|
|
6678
8320
|
function createDb(d1$1) {
|
|
6679
|
-
return d1.drizzle(d1$1, { schema:
|
|
8321
|
+
return d1.drizzle(d1$1, { schema: chunkNZWFCUDA_cjs.schema_exports });
|
|
6680
8322
|
}
|
|
6681
8323
|
|
|
6682
8324
|
// src/index.ts
|
|
6683
|
-
var VERSION =
|
|
8325
|
+
var VERSION = chunkRXNLGINR_cjs.package_default.version;
|
|
6684
8326
|
|
|
6685
8327
|
Object.defineProperty(exports, "ROUTES_INFO", {
|
|
6686
8328
|
enumerable: true,
|
|
6687
|
-
get: function () { return
|
|
8329
|
+
get: function () { return chunkZV6ZCJ74_cjs.ROUTES_INFO; }
|
|
6688
8330
|
});
|
|
6689
8331
|
Object.defineProperty(exports, "adminApiRoutes", {
|
|
6690
8332
|
enumerable: true,
|
|
6691
|
-
get: function () { return
|
|
8333
|
+
get: function () { return chunkZV6ZCJ74_cjs.admin_api_default; }
|
|
6692
8334
|
});
|
|
6693
8335
|
Object.defineProperty(exports, "adminCheckboxRoutes", {
|
|
6694
8336
|
enumerable: true,
|
|
6695
|
-
get: function () { return
|
|
8337
|
+
get: function () { return chunkZV6ZCJ74_cjs.adminCheckboxRoutes; }
|
|
6696
8338
|
});
|
|
6697
8339
|
Object.defineProperty(exports, "adminCodeExamplesRoutes", {
|
|
6698
8340
|
enumerable: true,
|
|
6699
|
-
get: function () { return
|
|
8341
|
+
get: function () { return chunkZV6ZCJ74_cjs.admin_code_examples_default; }
|
|
6700
8342
|
});
|
|
6701
8343
|
Object.defineProperty(exports, "adminCollectionsRoutes", {
|
|
6702
8344
|
enumerable: true,
|
|
6703
|
-
get: function () { return
|
|
8345
|
+
get: function () { return chunkZV6ZCJ74_cjs.adminCollectionsRoutes; }
|
|
6704
8346
|
});
|
|
6705
8347
|
Object.defineProperty(exports, "adminContentRoutes", {
|
|
6706
8348
|
enumerable: true,
|
|
6707
|
-
get: function () { return
|
|
8349
|
+
get: function () { return chunkZV6ZCJ74_cjs.admin_content_default; }
|
|
6708
8350
|
});
|
|
6709
8351
|
Object.defineProperty(exports, "adminDashboardRoutes", {
|
|
6710
8352
|
enumerable: true,
|
|
6711
|
-
get: function () { return
|
|
8353
|
+
get: function () { return chunkZV6ZCJ74_cjs.router; }
|
|
6712
8354
|
});
|
|
6713
8355
|
Object.defineProperty(exports, "adminDesignRoutes", {
|
|
6714
8356
|
enumerable: true,
|
|
6715
|
-
get: function () { return
|
|
8357
|
+
get: function () { return chunkZV6ZCJ74_cjs.adminDesignRoutes; }
|
|
6716
8358
|
});
|
|
6717
8359
|
Object.defineProperty(exports, "adminLogsRoutes", {
|
|
6718
8360
|
enumerable: true,
|
|
6719
|
-
get: function () { return
|
|
8361
|
+
get: function () { return chunkZV6ZCJ74_cjs.adminLogsRoutes; }
|
|
6720
8362
|
});
|
|
6721
8363
|
Object.defineProperty(exports, "adminMediaRoutes", {
|
|
6722
8364
|
enumerable: true,
|
|
6723
|
-
get: function () { return
|
|
8365
|
+
get: function () { return chunkZV6ZCJ74_cjs.adminMediaRoutes; }
|
|
6724
8366
|
});
|
|
6725
8367
|
Object.defineProperty(exports, "adminPluginRoutes", {
|
|
6726
8368
|
enumerable: true,
|
|
6727
|
-
get: function () { return
|
|
8369
|
+
get: function () { return chunkZV6ZCJ74_cjs.adminPluginRoutes; }
|
|
6728
8370
|
});
|
|
6729
8371
|
Object.defineProperty(exports, "adminSettingsRoutes", {
|
|
6730
8372
|
enumerable: true,
|
|
6731
|
-
get: function () { return
|
|
8373
|
+
get: function () { return chunkZV6ZCJ74_cjs.adminSettingsRoutes; }
|
|
6732
8374
|
});
|
|
6733
8375
|
Object.defineProperty(exports, "adminTestimonialsRoutes", {
|
|
6734
8376
|
enumerable: true,
|
|
6735
|
-
get: function () { return
|
|
8377
|
+
get: function () { return chunkZV6ZCJ74_cjs.admin_testimonials_default; }
|
|
6736
8378
|
});
|
|
6737
8379
|
Object.defineProperty(exports, "adminUsersRoutes", {
|
|
6738
8380
|
enumerable: true,
|
|
6739
|
-
get: function () { return
|
|
8381
|
+
get: function () { return chunkZV6ZCJ74_cjs.userRoutes; }
|
|
6740
8382
|
});
|
|
6741
8383
|
Object.defineProperty(exports, "apiContentCrudRoutes", {
|
|
6742
8384
|
enumerable: true,
|
|
6743
|
-
get: function () { return
|
|
8385
|
+
get: function () { return chunkZV6ZCJ74_cjs.api_content_crud_default; }
|
|
6744
8386
|
});
|
|
6745
8387
|
Object.defineProperty(exports, "apiMediaRoutes", {
|
|
6746
8388
|
enumerable: true,
|
|
6747
|
-
get: function () { return
|
|
8389
|
+
get: function () { return chunkZV6ZCJ74_cjs.api_media_default; }
|
|
6748
8390
|
});
|
|
6749
8391
|
Object.defineProperty(exports, "apiRoutes", {
|
|
6750
8392
|
enumerable: true,
|
|
6751
|
-
get: function () { return
|
|
8393
|
+
get: function () { return chunkZV6ZCJ74_cjs.api_default; }
|
|
6752
8394
|
});
|
|
6753
8395
|
Object.defineProperty(exports, "apiSystemRoutes", {
|
|
6754
8396
|
enumerable: true,
|
|
6755
|
-
get: function () { return
|
|
8397
|
+
get: function () { return chunkZV6ZCJ74_cjs.api_system_default; }
|
|
6756
8398
|
});
|
|
6757
8399
|
Object.defineProperty(exports, "authRoutes", {
|
|
6758
8400
|
enumerable: true,
|
|
6759
|
-
get: function () { return
|
|
8401
|
+
get: function () { return chunkZV6ZCJ74_cjs.auth_default; }
|
|
8402
|
+
});
|
|
8403
|
+
Object.defineProperty(exports, "createUserProfilesPlugin", {
|
|
8404
|
+
enumerable: true,
|
|
8405
|
+
get: function () { return chunkZV6ZCJ74_cjs.createUserProfilesPlugin; }
|
|
8406
|
+
});
|
|
8407
|
+
Object.defineProperty(exports, "defineUserProfile", {
|
|
8408
|
+
enumerable: true,
|
|
8409
|
+
get: function () { return chunkZV6ZCJ74_cjs.defineUserProfile; }
|
|
8410
|
+
});
|
|
8411
|
+
Object.defineProperty(exports, "getUserProfileConfig", {
|
|
8412
|
+
enumerable: true,
|
|
8413
|
+
get: function () { return chunkZV6ZCJ74_cjs.getUserProfileConfig; }
|
|
8414
|
+
});
|
|
8415
|
+
Object.defineProperty(exports, "userProfilesPlugin", {
|
|
8416
|
+
enumerable: true,
|
|
8417
|
+
get: function () { return chunkZV6ZCJ74_cjs.userProfilesPlugin; }
|
|
6760
8418
|
});
|
|
6761
8419
|
Object.defineProperty(exports, "Logger", {
|
|
6762
8420
|
enumerable: true,
|
|
6763
|
-
get: function () { return
|
|
8421
|
+
get: function () { return chunkNZWFCUDA_cjs.Logger; }
|
|
6764
8422
|
});
|
|
6765
8423
|
Object.defineProperty(exports, "apiTokens", {
|
|
6766
8424
|
enumerable: true,
|
|
6767
|
-
get: function () { return
|
|
8425
|
+
get: function () { return chunkNZWFCUDA_cjs.apiTokens; }
|
|
6768
8426
|
});
|
|
6769
8427
|
Object.defineProperty(exports, "collections", {
|
|
6770
8428
|
enumerable: true,
|
|
6771
|
-
get: function () { return
|
|
8429
|
+
get: function () { return chunkNZWFCUDA_cjs.collections; }
|
|
6772
8430
|
});
|
|
6773
8431
|
Object.defineProperty(exports, "content", {
|
|
6774
8432
|
enumerable: true,
|
|
6775
|
-
get: function () { return
|
|
8433
|
+
get: function () { return chunkNZWFCUDA_cjs.content; }
|
|
6776
8434
|
});
|
|
6777
8435
|
Object.defineProperty(exports, "contentVersions", {
|
|
6778
8436
|
enumerable: true,
|
|
6779
|
-
get: function () { return
|
|
8437
|
+
get: function () { return chunkNZWFCUDA_cjs.contentVersions; }
|
|
6780
8438
|
});
|
|
6781
8439
|
Object.defineProperty(exports, "getLogger", {
|
|
6782
8440
|
enumerable: true,
|
|
6783
|
-
get: function () { return
|
|
8441
|
+
get: function () { return chunkNZWFCUDA_cjs.getLogger; }
|
|
6784
8442
|
});
|
|
6785
8443
|
Object.defineProperty(exports, "initLogger", {
|
|
6786
8444
|
enumerable: true,
|
|
6787
|
-
get: function () { return
|
|
8445
|
+
get: function () { return chunkNZWFCUDA_cjs.initLogger; }
|
|
6788
8446
|
});
|
|
6789
8447
|
Object.defineProperty(exports, "insertCollectionSchema", {
|
|
6790
8448
|
enumerable: true,
|
|
6791
|
-
get: function () { return
|
|
8449
|
+
get: function () { return chunkNZWFCUDA_cjs.insertCollectionSchema; }
|
|
6792
8450
|
});
|
|
6793
8451
|
Object.defineProperty(exports, "insertContentSchema", {
|
|
6794
8452
|
enumerable: true,
|
|
6795
|
-
get: function () { return
|
|
8453
|
+
get: function () { return chunkNZWFCUDA_cjs.insertContentSchema; }
|
|
6796
8454
|
});
|
|
6797
8455
|
Object.defineProperty(exports, "insertLogConfigSchema", {
|
|
6798
8456
|
enumerable: true,
|
|
6799
|
-
get: function () { return
|
|
8457
|
+
get: function () { return chunkNZWFCUDA_cjs.insertLogConfigSchema; }
|
|
6800
8458
|
});
|
|
6801
8459
|
Object.defineProperty(exports, "insertMediaSchema", {
|
|
6802
8460
|
enumerable: true,
|
|
6803
|
-
get: function () { return
|
|
8461
|
+
get: function () { return chunkNZWFCUDA_cjs.insertMediaSchema; }
|
|
6804
8462
|
});
|
|
6805
8463
|
Object.defineProperty(exports, "insertPluginActivityLogSchema", {
|
|
6806
8464
|
enumerable: true,
|
|
6807
|
-
get: function () { return
|
|
8465
|
+
get: function () { return chunkNZWFCUDA_cjs.insertPluginActivityLogSchema; }
|
|
6808
8466
|
});
|
|
6809
8467
|
Object.defineProperty(exports, "insertPluginAssetSchema", {
|
|
6810
8468
|
enumerable: true,
|
|
6811
|
-
get: function () { return
|
|
8469
|
+
get: function () { return chunkNZWFCUDA_cjs.insertPluginAssetSchema; }
|
|
6812
8470
|
});
|
|
6813
8471
|
Object.defineProperty(exports, "insertPluginHookSchema", {
|
|
6814
8472
|
enumerable: true,
|
|
6815
|
-
get: function () { return
|
|
8473
|
+
get: function () { return chunkNZWFCUDA_cjs.insertPluginHookSchema; }
|
|
6816
8474
|
});
|
|
6817
8475
|
Object.defineProperty(exports, "insertPluginRouteSchema", {
|
|
6818
8476
|
enumerable: true,
|
|
6819
|
-
get: function () { return
|
|
8477
|
+
get: function () { return chunkNZWFCUDA_cjs.insertPluginRouteSchema; }
|
|
6820
8478
|
});
|
|
6821
8479
|
Object.defineProperty(exports, "insertPluginSchema", {
|
|
6822
8480
|
enumerable: true,
|
|
6823
|
-
get: function () { return
|
|
8481
|
+
get: function () { return chunkNZWFCUDA_cjs.insertPluginSchema; }
|
|
6824
8482
|
});
|
|
6825
8483
|
Object.defineProperty(exports, "insertSystemLogSchema", {
|
|
6826
8484
|
enumerable: true,
|
|
6827
|
-
get: function () { return
|
|
8485
|
+
get: function () { return chunkNZWFCUDA_cjs.insertSystemLogSchema; }
|
|
6828
8486
|
});
|
|
6829
8487
|
Object.defineProperty(exports, "insertUserSchema", {
|
|
6830
8488
|
enumerable: true,
|
|
6831
|
-
get: function () { return
|
|
8489
|
+
get: function () { return chunkNZWFCUDA_cjs.insertUserSchema; }
|
|
6832
8490
|
});
|
|
6833
8491
|
Object.defineProperty(exports, "insertWorkflowHistorySchema", {
|
|
6834
8492
|
enumerable: true,
|
|
6835
|
-
get: function () { return
|
|
8493
|
+
get: function () { return chunkNZWFCUDA_cjs.insertWorkflowHistorySchema; }
|
|
6836
8494
|
});
|
|
6837
8495
|
Object.defineProperty(exports, "logConfig", {
|
|
6838
8496
|
enumerable: true,
|
|
6839
|
-
get: function () { return
|
|
8497
|
+
get: function () { return chunkNZWFCUDA_cjs.logConfig; }
|
|
6840
8498
|
});
|
|
6841
8499
|
Object.defineProperty(exports, "media", {
|
|
6842
8500
|
enumerable: true,
|
|
6843
|
-
get: function () { return
|
|
8501
|
+
get: function () { return chunkNZWFCUDA_cjs.media; }
|
|
6844
8502
|
});
|
|
6845
8503
|
Object.defineProperty(exports, "pluginActivityLog", {
|
|
6846
8504
|
enumerable: true,
|
|
6847
|
-
get: function () { return
|
|
8505
|
+
get: function () { return chunkNZWFCUDA_cjs.pluginActivityLog; }
|
|
6848
8506
|
});
|
|
6849
8507
|
Object.defineProperty(exports, "pluginAssets", {
|
|
6850
8508
|
enumerable: true,
|
|
6851
|
-
get: function () { return
|
|
8509
|
+
get: function () { return chunkNZWFCUDA_cjs.pluginAssets; }
|
|
6852
8510
|
});
|
|
6853
8511
|
Object.defineProperty(exports, "pluginHooks", {
|
|
6854
8512
|
enumerable: true,
|
|
6855
|
-
get: function () { return
|
|
8513
|
+
get: function () { return chunkNZWFCUDA_cjs.pluginHooks; }
|
|
6856
8514
|
});
|
|
6857
8515
|
Object.defineProperty(exports, "pluginRoutes", {
|
|
6858
8516
|
enumerable: true,
|
|
6859
|
-
get: function () { return
|
|
8517
|
+
get: function () { return chunkNZWFCUDA_cjs.pluginRoutes; }
|
|
6860
8518
|
});
|
|
6861
8519
|
Object.defineProperty(exports, "plugins", {
|
|
6862
8520
|
enumerable: true,
|
|
6863
|
-
get: function () { return
|
|
8521
|
+
get: function () { return chunkNZWFCUDA_cjs.plugins; }
|
|
6864
8522
|
});
|
|
6865
8523
|
Object.defineProperty(exports, "selectCollectionSchema", {
|
|
6866
8524
|
enumerable: true,
|
|
6867
|
-
get: function () { return
|
|
8525
|
+
get: function () { return chunkNZWFCUDA_cjs.selectCollectionSchema; }
|
|
6868
8526
|
});
|
|
6869
8527
|
Object.defineProperty(exports, "selectContentSchema", {
|
|
6870
8528
|
enumerable: true,
|
|
6871
|
-
get: function () { return
|
|
8529
|
+
get: function () { return chunkNZWFCUDA_cjs.selectContentSchema; }
|
|
6872
8530
|
});
|
|
6873
8531
|
Object.defineProperty(exports, "selectLogConfigSchema", {
|
|
6874
8532
|
enumerable: true,
|
|
6875
|
-
get: function () { return
|
|
8533
|
+
get: function () { return chunkNZWFCUDA_cjs.selectLogConfigSchema; }
|
|
6876
8534
|
});
|
|
6877
8535
|
Object.defineProperty(exports, "selectMediaSchema", {
|
|
6878
8536
|
enumerable: true,
|
|
6879
|
-
get: function () { return
|
|
8537
|
+
get: function () { return chunkNZWFCUDA_cjs.selectMediaSchema; }
|
|
6880
8538
|
});
|
|
6881
8539
|
Object.defineProperty(exports, "selectPluginActivityLogSchema", {
|
|
6882
8540
|
enumerable: true,
|
|
6883
|
-
get: function () { return
|
|
8541
|
+
get: function () { return chunkNZWFCUDA_cjs.selectPluginActivityLogSchema; }
|
|
6884
8542
|
});
|
|
6885
8543
|
Object.defineProperty(exports, "selectPluginAssetSchema", {
|
|
6886
8544
|
enumerable: true,
|
|
6887
|
-
get: function () { return
|
|
8545
|
+
get: function () { return chunkNZWFCUDA_cjs.selectPluginAssetSchema; }
|
|
6888
8546
|
});
|
|
6889
8547
|
Object.defineProperty(exports, "selectPluginHookSchema", {
|
|
6890
8548
|
enumerable: true,
|
|
6891
|
-
get: function () { return
|
|
8549
|
+
get: function () { return chunkNZWFCUDA_cjs.selectPluginHookSchema; }
|
|
6892
8550
|
});
|
|
6893
8551
|
Object.defineProperty(exports, "selectPluginRouteSchema", {
|
|
6894
8552
|
enumerable: true,
|
|
6895
|
-
get: function () { return
|
|
8553
|
+
get: function () { return chunkNZWFCUDA_cjs.selectPluginRouteSchema; }
|
|
6896
8554
|
});
|
|
6897
8555
|
Object.defineProperty(exports, "selectPluginSchema", {
|
|
6898
8556
|
enumerable: true,
|
|
6899
|
-
get: function () { return
|
|
8557
|
+
get: function () { return chunkNZWFCUDA_cjs.selectPluginSchema; }
|
|
6900
8558
|
});
|
|
6901
8559
|
Object.defineProperty(exports, "selectSystemLogSchema", {
|
|
6902
8560
|
enumerable: true,
|
|
6903
|
-
get: function () { return
|
|
8561
|
+
get: function () { return chunkNZWFCUDA_cjs.selectSystemLogSchema; }
|
|
6904
8562
|
});
|
|
6905
8563
|
Object.defineProperty(exports, "selectUserSchema", {
|
|
6906
8564
|
enumerable: true,
|
|
6907
|
-
get: function () { return
|
|
8565
|
+
get: function () { return chunkNZWFCUDA_cjs.selectUserSchema; }
|
|
6908
8566
|
});
|
|
6909
8567
|
Object.defineProperty(exports, "selectWorkflowHistorySchema", {
|
|
6910
8568
|
enumerable: true,
|
|
6911
|
-
get: function () { return
|
|
8569
|
+
get: function () { return chunkNZWFCUDA_cjs.selectWorkflowHistorySchema; }
|
|
6912
8570
|
});
|
|
6913
8571
|
Object.defineProperty(exports, "systemLogs", {
|
|
6914
8572
|
enumerable: true,
|
|
6915
|
-
get: function () { return
|
|
8573
|
+
get: function () { return chunkNZWFCUDA_cjs.systemLogs; }
|
|
6916
8574
|
});
|
|
6917
8575
|
Object.defineProperty(exports, "users", {
|
|
6918
8576
|
enumerable: true,
|
|
6919
|
-
get: function () { return
|
|
8577
|
+
get: function () { return chunkNZWFCUDA_cjs.users; }
|
|
6920
8578
|
});
|
|
6921
8579
|
Object.defineProperty(exports, "workflowHistory", {
|
|
6922
8580
|
enumerable: true,
|
|
6923
|
-
get: function () { return
|
|
8581
|
+
get: function () { return chunkNZWFCUDA_cjs.workflowHistory; }
|
|
6924
8582
|
});
|
|
6925
8583
|
Object.defineProperty(exports, "AuthManager", {
|
|
6926
8584
|
enumerable: true,
|
|
6927
|
-
get: function () { return
|
|
8585
|
+
get: function () { return chunkVHNTCB2X_cjs.AuthManager; }
|
|
6928
8586
|
});
|
|
6929
8587
|
Object.defineProperty(exports, "PermissionManager", {
|
|
6930
8588
|
enumerable: true,
|
|
6931
|
-
get: function () { return
|
|
8589
|
+
get: function () { return chunkVHNTCB2X_cjs.PermissionManager; }
|
|
6932
8590
|
});
|
|
6933
8591
|
Object.defineProperty(exports, "bootstrapMiddleware", {
|
|
6934
8592
|
enumerable: true,
|
|
6935
|
-
get: function () { return
|
|
8593
|
+
get: function () { return chunkVHNTCB2X_cjs.bootstrapMiddleware; }
|
|
6936
8594
|
});
|
|
6937
8595
|
Object.defineProperty(exports, "cacheHeaders", {
|
|
6938
8596
|
enumerable: true,
|
|
6939
|
-
get: function () { return
|
|
8597
|
+
get: function () { return chunkVHNTCB2X_cjs.cacheHeaders; }
|
|
6940
8598
|
});
|
|
6941
8599
|
Object.defineProperty(exports, "compressionMiddleware", {
|
|
6942
8600
|
enumerable: true,
|
|
6943
|
-
get: function () { return
|
|
8601
|
+
get: function () { return chunkVHNTCB2X_cjs.compressionMiddleware; }
|
|
6944
8602
|
});
|
|
6945
8603
|
Object.defineProperty(exports, "detailedLoggingMiddleware", {
|
|
6946
8604
|
enumerable: true,
|
|
6947
|
-
get: function () { return
|
|
8605
|
+
get: function () { return chunkVHNTCB2X_cjs.detailedLoggingMiddleware; }
|
|
6948
8606
|
});
|
|
6949
8607
|
Object.defineProperty(exports, "getActivePlugins", {
|
|
6950
8608
|
enumerable: true,
|
|
6951
|
-
get: function () { return
|
|
8609
|
+
get: function () { return chunkVHNTCB2X_cjs.getActivePlugins; }
|
|
6952
8610
|
});
|
|
6953
8611
|
Object.defineProperty(exports, "isPluginActive", {
|
|
6954
8612
|
enumerable: true,
|
|
6955
|
-
get: function () { return
|
|
8613
|
+
get: function () { return chunkVHNTCB2X_cjs.isPluginActive; }
|
|
6956
8614
|
});
|
|
6957
8615
|
Object.defineProperty(exports, "logActivity", {
|
|
6958
8616
|
enumerable: true,
|
|
6959
|
-
get: function () { return
|
|
8617
|
+
get: function () { return chunkVHNTCB2X_cjs.logActivity; }
|
|
6960
8618
|
});
|
|
6961
8619
|
Object.defineProperty(exports, "loggingMiddleware", {
|
|
6962
8620
|
enumerable: true,
|
|
6963
|
-
get: function () { return
|
|
8621
|
+
get: function () { return chunkVHNTCB2X_cjs.loggingMiddleware; }
|
|
6964
8622
|
});
|
|
6965
8623
|
Object.defineProperty(exports, "optionalAuth", {
|
|
6966
8624
|
enumerable: true,
|
|
6967
|
-
get: function () { return
|
|
8625
|
+
get: function () { return chunkVHNTCB2X_cjs.optionalAuth; }
|
|
6968
8626
|
});
|
|
6969
8627
|
Object.defineProperty(exports, "performanceLoggingMiddleware", {
|
|
6970
8628
|
enumerable: true,
|
|
6971
|
-
get: function () { return
|
|
8629
|
+
get: function () { return chunkVHNTCB2X_cjs.performanceLoggingMiddleware; }
|
|
6972
8630
|
});
|
|
6973
8631
|
Object.defineProperty(exports, "requireActivePlugin", {
|
|
6974
8632
|
enumerable: true,
|
|
6975
|
-
get: function () { return
|
|
8633
|
+
get: function () { return chunkVHNTCB2X_cjs.requireActivePlugin; }
|
|
6976
8634
|
});
|
|
6977
8635
|
Object.defineProperty(exports, "requireActivePlugins", {
|
|
6978
8636
|
enumerable: true,
|
|
6979
|
-
get: function () { return
|
|
8637
|
+
get: function () { return chunkVHNTCB2X_cjs.requireActivePlugins; }
|
|
6980
8638
|
});
|
|
6981
8639
|
Object.defineProperty(exports, "requireAnyPermission", {
|
|
6982
8640
|
enumerable: true,
|
|
6983
|
-
get: function () { return
|
|
8641
|
+
get: function () { return chunkVHNTCB2X_cjs.requireAnyPermission; }
|
|
6984
8642
|
});
|
|
6985
8643
|
Object.defineProperty(exports, "requireAuth", {
|
|
6986
8644
|
enumerable: true,
|
|
6987
|
-
get: function () { return
|
|
8645
|
+
get: function () { return chunkVHNTCB2X_cjs.requireAuth; }
|
|
6988
8646
|
});
|
|
6989
8647
|
Object.defineProperty(exports, "requirePermission", {
|
|
6990
8648
|
enumerable: true,
|
|
6991
|
-
get: function () { return
|
|
8649
|
+
get: function () { return chunkVHNTCB2X_cjs.requirePermission; }
|
|
6992
8650
|
});
|
|
6993
8651
|
Object.defineProperty(exports, "requireRole", {
|
|
6994
8652
|
enumerable: true,
|
|
6995
|
-
get: function () { return
|
|
8653
|
+
get: function () { return chunkVHNTCB2X_cjs.requireRole; }
|
|
6996
8654
|
});
|
|
6997
8655
|
Object.defineProperty(exports, "securityHeaders", {
|
|
6998
8656
|
enumerable: true,
|
|
6999
|
-
get: function () { return
|
|
8657
|
+
get: function () { return chunkVHNTCB2X_cjs.securityHeadersMiddleware; }
|
|
7000
8658
|
});
|
|
7001
8659
|
Object.defineProperty(exports, "securityLoggingMiddleware", {
|
|
7002
8660
|
enumerable: true,
|
|
7003
|
-
get: function () { return
|
|
8661
|
+
get: function () { return chunkVHNTCB2X_cjs.securityLoggingMiddleware; }
|
|
7004
8662
|
});
|
|
7005
8663
|
Object.defineProperty(exports, "PluginBootstrapService", {
|
|
7006
8664
|
enumerable: true,
|
|
7007
|
-
get: function () { return
|
|
8665
|
+
get: function () { return chunkI6FFGQIT_cjs.PluginBootstrapService; }
|
|
7008
8666
|
});
|
|
7009
8667
|
Object.defineProperty(exports, "PluginServiceClass", {
|
|
7010
8668
|
enumerable: true,
|
|
7011
|
-
get: function () { return
|
|
8669
|
+
get: function () { return chunkI6FFGQIT_cjs.PluginService; }
|
|
7012
8670
|
});
|
|
7013
8671
|
Object.defineProperty(exports, "backfillFormSubmissions", {
|
|
7014
8672
|
enumerable: true,
|
|
7015
|
-
get: function () { return
|
|
8673
|
+
get: function () { return chunkI6FFGQIT_cjs.backfillFormSubmissions; }
|
|
7016
8674
|
});
|
|
7017
8675
|
Object.defineProperty(exports, "cleanupRemovedCollections", {
|
|
7018
8676
|
enumerable: true,
|
|
7019
|
-
get: function () { return
|
|
8677
|
+
get: function () { return chunkI6FFGQIT_cjs.cleanupRemovedCollections; }
|
|
7020
8678
|
});
|
|
7021
8679
|
Object.defineProperty(exports, "createContentFromSubmission", {
|
|
7022
8680
|
enumerable: true,
|
|
7023
|
-
get: function () { return
|
|
8681
|
+
get: function () { return chunkI6FFGQIT_cjs.createContentFromSubmission; }
|
|
7024
8682
|
});
|
|
7025
8683
|
Object.defineProperty(exports, "deriveCollectionSchemaFromFormio", {
|
|
7026
8684
|
enumerable: true,
|
|
7027
|
-
get: function () { return
|
|
8685
|
+
get: function () { return chunkI6FFGQIT_cjs.deriveCollectionSchemaFromFormio; }
|
|
7028
8686
|
});
|
|
7029
8687
|
Object.defineProperty(exports, "deriveSubmissionTitle", {
|
|
7030
8688
|
enumerable: true,
|
|
7031
|
-
get: function () { return
|
|
8689
|
+
get: function () { return chunkI6FFGQIT_cjs.deriveSubmissionTitle; }
|
|
7032
8690
|
});
|
|
7033
8691
|
Object.defineProperty(exports, "fullCollectionSync", {
|
|
7034
8692
|
enumerable: true,
|
|
7035
|
-
get: function () { return
|
|
8693
|
+
get: function () { return chunkI6FFGQIT_cjs.fullCollectionSync; }
|
|
7036
8694
|
});
|
|
7037
8695
|
Object.defineProperty(exports, "getAvailableCollectionNames", {
|
|
7038
8696
|
enumerable: true,
|
|
7039
|
-
get: function () { return
|
|
8697
|
+
get: function () { return chunkI6FFGQIT_cjs.getAvailableCollectionNames; }
|
|
7040
8698
|
});
|
|
7041
8699
|
Object.defineProperty(exports, "getManagedCollections", {
|
|
7042
8700
|
enumerable: true,
|
|
7043
|
-
get: function () { return
|
|
8701
|
+
get: function () { return chunkI6FFGQIT_cjs.getManagedCollections; }
|
|
7044
8702
|
});
|
|
7045
8703
|
Object.defineProperty(exports, "isCollectionManaged", {
|
|
7046
8704
|
enumerable: true,
|
|
7047
|
-
get: function () { return
|
|
8705
|
+
get: function () { return chunkI6FFGQIT_cjs.isCollectionManaged; }
|
|
7048
8706
|
});
|
|
7049
8707
|
Object.defineProperty(exports, "loadCollectionConfig", {
|
|
7050
8708
|
enumerable: true,
|
|
7051
|
-
get: function () { return
|
|
8709
|
+
get: function () { return chunkI6FFGQIT_cjs.loadCollectionConfig; }
|
|
7052
8710
|
});
|
|
7053
8711
|
Object.defineProperty(exports, "loadCollectionConfigs", {
|
|
7054
8712
|
enumerable: true,
|
|
7055
|
-
get: function () { return
|
|
8713
|
+
get: function () { return chunkI6FFGQIT_cjs.loadCollectionConfigs; }
|
|
7056
8714
|
});
|
|
7057
8715
|
Object.defineProperty(exports, "mapFormStatusToContentStatus", {
|
|
7058
8716
|
enumerable: true,
|
|
7059
|
-
get: function () { return
|
|
8717
|
+
get: function () { return chunkI6FFGQIT_cjs.mapFormStatusToContentStatus; }
|
|
7060
8718
|
});
|
|
7061
8719
|
Object.defineProperty(exports, "registerCollections", {
|
|
7062
8720
|
enumerable: true,
|
|
7063
|
-
get: function () { return
|
|
8721
|
+
get: function () { return chunkI6FFGQIT_cjs.registerCollections; }
|
|
7064
8722
|
});
|
|
7065
8723
|
Object.defineProperty(exports, "syncAllFormCollections", {
|
|
7066
8724
|
enumerable: true,
|
|
7067
|
-
get: function () { return
|
|
8725
|
+
get: function () { return chunkI6FFGQIT_cjs.syncAllFormCollections; }
|
|
7068
8726
|
});
|
|
7069
8727
|
Object.defineProperty(exports, "syncCollection", {
|
|
7070
8728
|
enumerable: true,
|
|
7071
|
-
get: function () { return
|
|
8729
|
+
get: function () { return chunkI6FFGQIT_cjs.syncCollection; }
|
|
7072
8730
|
});
|
|
7073
8731
|
Object.defineProperty(exports, "syncCollections", {
|
|
7074
8732
|
enumerable: true,
|
|
7075
|
-
get: function () { return
|
|
8733
|
+
get: function () { return chunkI6FFGQIT_cjs.syncCollections; }
|
|
7076
8734
|
});
|
|
7077
8735
|
Object.defineProperty(exports, "syncFormCollection", {
|
|
7078
8736
|
enumerable: true,
|
|
7079
|
-
get: function () { return
|
|
8737
|
+
get: function () { return chunkI6FFGQIT_cjs.syncFormCollection; }
|
|
7080
8738
|
});
|
|
7081
8739
|
Object.defineProperty(exports, "validateCollectionConfig", {
|
|
7082
8740
|
enumerable: true,
|
|
7083
|
-
get: function () { return
|
|
8741
|
+
get: function () { return chunkI6FFGQIT_cjs.validateCollectionConfig; }
|
|
7084
8742
|
});
|
|
7085
8743
|
Object.defineProperty(exports, "MigrationService", {
|
|
7086
8744
|
enumerable: true,
|
|
7087
|
-
get: function () { return
|
|
8745
|
+
get: function () { return chunkAG3SIPP7_cjs.MigrationService; }
|
|
7088
8746
|
});
|
|
7089
8747
|
Object.defineProperty(exports, "renderFilterBar", {
|
|
7090
8748
|
enumerable: true,
|
|
7091
|
-
get: function () { return
|
|
8749
|
+
get: function () { return chunkRBXFXT7H_cjs.renderFilterBar; }
|
|
7092
8750
|
});
|
|
7093
8751
|
Object.defineProperty(exports, "getConfirmationDialogScript", {
|
|
7094
8752
|
enumerable: true,
|
|
7095
|
-
get: function () { return
|
|
8753
|
+
get: function () { return chunkH4NHRZ6Y_cjs.getConfirmationDialogScript; }
|
|
7096
8754
|
});
|
|
7097
8755
|
Object.defineProperty(exports, "renderAlert", {
|
|
7098
8756
|
enumerable: true,
|
|
7099
|
-
get: function () { return
|
|
8757
|
+
get: function () { return chunkH4NHRZ6Y_cjs.renderAlert; }
|
|
7100
8758
|
});
|
|
7101
8759
|
Object.defineProperty(exports, "renderConfirmationDialog", {
|
|
7102
8760
|
enumerable: true,
|
|
7103
|
-
get: function () { return
|
|
8761
|
+
get: function () { return chunkH4NHRZ6Y_cjs.renderConfirmationDialog; }
|
|
7104
8762
|
});
|
|
7105
8763
|
Object.defineProperty(exports, "renderForm", {
|
|
7106
8764
|
enumerable: true,
|
|
7107
|
-
get: function () { return
|
|
8765
|
+
get: function () { return chunkH4NHRZ6Y_cjs.renderForm; }
|
|
7108
8766
|
});
|
|
7109
8767
|
Object.defineProperty(exports, "renderFormField", {
|
|
7110
8768
|
enumerable: true,
|
|
7111
|
-
get: function () { return
|
|
8769
|
+
get: function () { return chunkH4NHRZ6Y_cjs.renderFormField; }
|
|
7112
8770
|
});
|
|
7113
8771
|
Object.defineProperty(exports, "renderPagination", {
|
|
7114
8772
|
enumerable: true,
|
|
7115
|
-
get: function () { return
|
|
8773
|
+
get: function () { return chunkH4NHRZ6Y_cjs.renderPagination; }
|
|
7116
8774
|
});
|
|
7117
8775
|
Object.defineProperty(exports, "renderTable", {
|
|
7118
8776
|
enumerable: true,
|
|
7119
|
-
get: function () { return
|
|
8777
|
+
get: function () { return chunkH4NHRZ6Y_cjs.renderTable; }
|
|
7120
8778
|
});
|
|
7121
8779
|
Object.defineProperty(exports, "HookSystemImpl", {
|
|
7122
8780
|
enumerable: true,
|
|
@@ -7152,31 +8810,31 @@ Object.defineProperty(exports, "PluginHelpers", {
|
|
|
7152
8810
|
});
|
|
7153
8811
|
Object.defineProperty(exports, "QueryFilterBuilder", {
|
|
7154
8812
|
enumerable: true,
|
|
7155
|
-
get: function () { return
|
|
8813
|
+
get: function () { return chunkRXNLGINR_cjs.QueryFilterBuilder; }
|
|
7156
8814
|
});
|
|
7157
8815
|
Object.defineProperty(exports, "SONICJS_VERSION", {
|
|
7158
8816
|
enumerable: true,
|
|
7159
|
-
get: function () { return
|
|
8817
|
+
get: function () { return chunkRXNLGINR_cjs.SONICJS_VERSION; }
|
|
7160
8818
|
});
|
|
7161
8819
|
Object.defineProperty(exports, "TemplateRenderer", {
|
|
7162
8820
|
enumerable: true,
|
|
7163
|
-
get: function () { return
|
|
8821
|
+
get: function () { return chunkRXNLGINR_cjs.TemplateRenderer; }
|
|
7164
8822
|
});
|
|
7165
8823
|
Object.defineProperty(exports, "buildQuery", {
|
|
7166
8824
|
enumerable: true,
|
|
7167
|
-
get: function () { return
|
|
8825
|
+
get: function () { return chunkRXNLGINR_cjs.buildQuery; }
|
|
7168
8826
|
});
|
|
7169
8827
|
Object.defineProperty(exports, "getCoreVersion", {
|
|
7170
8828
|
enumerable: true,
|
|
7171
|
-
get: function () { return
|
|
8829
|
+
get: function () { return chunkRXNLGINR_cjs.getCoreVersion; }
|
|
7172
8830
|
});
|
|
7173
8831
|
Object.defineProperty(exports, "renderTemplate", {
|
|
7174
8832
|
enumerable: true,
|
|
7175
|
-
get: function () { return
|
|
8833
|
+
get: function () { return chunkRXNLGINR_cjs.renderTemplate; }
|
|
7176
8834
|
});
|
|
7177
8835
|
Object.defineProperty(exports, "templateRenderer", {
|
|
7178
8836
|
enumerable: true,
|
|
7179
|
-
get: function () { return
|
|
8837
|
+
get: function () { return chunkRXNLGINR_cjs.templateRenderer; }
|
|
7180
8838
|
});
|
|
7181
8839
|
Object.defineProperty(exports, "metricsTracker", {
|
|
7182
8840
|
enumerable: true,
|