@sonicjs-cms/core 2.0.0 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-3NVJ6W27.cjs +1076 -0
- package/dist/chunk-3NVJ6W27.cjs.map +1 -0
- package/dist/chunk-4BJGEGX5.cjs +236 -0
- package/dist/chunk-4BJGEGX5.cjs.map +1 -0
- package/dist/{chunk-QUMBDPNJ.cjs → chunk-7G6XT62S.cjs} +4583 -540
- package/dist/chunk-7G6XT62S.cjs.map +1 -0
- package/dist/{chunk-ET5I4GBD.cjs → chunk-ALOS2CBJ.cjs} +194 -4
- package/dist/chunk-ALOS2CBJ.cjs.map +1 -0
- package/dist/{chunk-7N3HK7ZK.js → chunk-CDBVZEWR.js} +7 -904
- package/dist/chunk-CDBVZEWR.js.map +1 -0
- package/dist/{chunk-BITQ4MFX.js → chunk-EAELJXRV.js} +93 -115
- package/dist/chunk-EAELJXRV.js.map +1 -0
- package/dist/chunk-EGFHFM4N.cjs +76 -0
- package/dist/chunk-EGFHFM4N.cjs.map +1 -0
- package/dist/chunk-FICTAGD4.js +59 -0
- package/dist/chunk-FICTAGD4.js.map +1 -0
- package/dist/{chunk-FVMV5DKA.cjs → chunk-HJZOA2O5.cjs} +93 -115
- package/dist/chunk-HJZOA2O5.cjs.map +1 -0
- package/dist/{chunk-RNR4HA23.cjs → chunk-LEG4KNFP.cjs} +6 -945
- package/dist/chunk-LEG4KNFP.cjs.map +1 -0
- package/dist/chunk-LH4Z7QID.js +1030 -0
- package/dist/chunk-LH4Z7QID.js.map +1 -0
- package/dist/chunk-M6FPVS7E.js +214 -0
- package/dist/chunk-M6FPVS7E.js.map +1 -0
- package/dist/{chunk-P3VS4DV3.js → chunk-O46XKBFM.js} +193 -5
- package/dist/chunk-O46XKBFM.js.map +1 -0
- package/dist/chunk-P2PTTBO5.js +74 -0
- package/dist/chunk-P2PTTBO5.js.map +1 -0
- package/dist/chunk-RCQ2HIQD.cjs +61 -0
- package/dist/chunk-RCQ2HIQD.cjs.map +1 -0
- package/dist/{chunk-JETM2U2D.js → chunk-SGGHTIWV.js} +4414 -374
- package/dist/chunk-SGGHTIWV.js.map +1 -0
- package/dist/{chunk-RGCQSFKC.cjs → chunk-UL32L2KV.cjs} +9 -58
- package/dist/chunk-UL32L2KV.cjs.map +1 -0
- package/dist/{chunk-JIINOD2W.js → chunk-XJETEIRU.js} +8 -58
- package/dist/chunk-XJETEIRU.js.map +1 -0
- package/dist/index.cjs +241 -218
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +20 -15
- package/dist/index.js.map +1 -1
- package/dist/middleware.cjs +27 -22
- package/dist/middleware.js +3 -2
- package/dist/plugins.cjs +7 -7
- package/dist/plugins.js +1 -1
- package/dist/routes.cjs +36 -23
- package/dist/routes.js +7 -6
- package/dist/services.cjs +28 -28
- package/dist/services.js +2 -2
- package/dist/templates.cjs +24 -24
- package/dist/templates.js +2 -2
- package/dist/utils.cjs +20 -11
- package/dist/utils.js +2 -1
- package/package.json +2 -16
- package/dist/chunk-3MNMOLSA.js +0 -133
- package/dist/chunk-3MNMOLSA.js.map +0 -1
- package/dist/chunk-4XI3YBKU.cjs +0 -266
- package/dist/chunk-4XI3YBKU.cjs.map +0 -1
- package/dist/chunk-7N3HK7ZK.js.map +0 -1
- package/dist/chunk-AGOE25LF.cjs +0 -137
- package/dist/chunk-AGOE25LF.cjs.map +0 -1
- package/dist/chunk-BITQ4MFX.js.map +0 -1
- package/dist/chunk-BUKT6HP5.cjs +0 -776
- package/dist/chunk-BUKT6HP5.cjs.map +0 -1
- package/dist/chunk-ET5I4GBD.cjs.map +0 -1
- package/dist/chunk-FVMV5DKA.cjs.map +0 -1
- package/dist/chunk-JETM2U2D.js.map +0 -1
- package/dist/chunk-JIINOD2W.js.map +0 -1
- package/dist/chunk-LU6J53IX.js +0 -262
- package/dist/chunk-LU6J53IX.js.map +0 -1
- package/dist/chunk-P3VS4DV3.js.map +0 -1
- package/dist/chunk-QUMBDPNJ.cjs.map +0 -1
- package/dist/chunk-RGCQSFKC.cjs.map +0 -1
- package/dist/chunk-RNR4HA23.cjs.map +0 -1
- package/dist/chunk-WESS2U3K.js +0 -755
- package/dist/chunk-WESS2U3K.js.map +0 -1
package/dist/chunk-WESS2U3K.js
DELETED
|
@@ -1,755 +0,0 @@
|
|
|
1
|
-
import { getLogger, MigrationService, syncCollections, PluginBootstrapService } from './chunk-7N3HK7ZK.js';
|
|
2
|
-
import { sign, verify } from 'hono/jwt';
|
|
3
|
-
import { getCookie } from 'hono/cookie';
|
|
4
|
-
import { compress } from 'hono/compress';
|
|
5
|
-
|
|
6
|
-
var JWT_SECRET = "your-super-secret-jwt-key-change-in-production";
|
|
7
|
-
var AuthManager = class {
|
|
8
|
-
static async generateToken(userId, email, role) {
|
|
9
|
-
const payload = {
|
|
10
|
-
userId,
|
|
11
|
-
email,
|
|
12
|
-
role,
|
|
13
|
-
exp: Math.floor(Date.now() / 1e3) + 60 * 60 * 24,
|
|
14
|
-
// 24 hours
|
|
15
|
-
iat: Math.floor(Date.now() / 1e3)
|
|
16
|
-
};
|
|
17
|
-
return await sign(payload, JWT_SECRET);
|
|
18
|
-
}
|
|
19
|
-
static async verifyToken(token) {
|
|
20
|
-
try {
|
|
21
|
-
const payload = await verify(token, JWT_SECRET);
|
|
22
|
-
if (payload.exp < Math.floor(Date.now() / 1e3)) {
|
|
23
|
-
return null;
|
|
24
|
-
}
|
|
25
|
-
return payload;
|
|
26
|
-
} catch (error) {
|
|
27
|
-
console.error("Token verification failed:", error);
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
static async hashPassword(password) {
|
|
32
|
-
const encoder = new TextEncoder();
|
|
33
|
-
const data = encoder.encode(password + "salt-change-in-production");
|
|
34
|
-
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
|
35
|
-
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
36
|
-
return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
37
|
-
}
|
|
38
|
-
static async verifyPassword(password, hash) {
|
|
39
|
-
const passwordHash = await this.hashPassword(password);
|
|
40
|
-
return passwordHash === hash;
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
var requireAuth = () => {
|
|
44
|
-
return async (c, next) => {
|
|
45
|
-
try {
|
|
46
|
-
let token = c.req.header("Authorization")?.replace("Bearer ", "");
|
|
47
|
-
if (!token) {
|
|
48
|
-
token = getCookie(c, "auth_token");
|
|
49
|
-
}
|
|
50
|
-
if (!token) {
|
|
51
|
-
const acceptHeader = c.req.header("Accept") || "";
|
|
52
|
-
if (acceptHeader.includes("text/html")) {
|
|
53
|
-
return c.redirect("/auth/login?error=Please login to access the admin area");
|
|
54
|
-
}
|
|
55
|
-
return c.json({ error: "Authentication required" }, 401);
|
|
56
|
-
}
|
|
57
|
-
const kv = c.env?.KV;
|
|
58
|
-
let payload = null;
|
|
59
|
-
if (kv) {
|
|
60
|
-
const cacheKey = `auth:${token.substring(0, 20)}`;
|
|
61
|
-
const cached = await kv.get(cacheKey, "json");
|
|
62
|
-
if (cached) {
|
|
63
|
-
payload = cached;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
if (!payload) {
|
|
67
|
-
payload = await AuthManager.verifyToken(token);
|
|
68
|
-
if (payload && kv) {
|
|
69
|
-
const cacheKey = `auth:${token.substring(0, 20)}`;
|
|
70
|
-
await kv.put(cacheKey, JSON.stringify(payload), { expirationTtl: 300 });
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
if (!payload) {
|
|
74
|
-
const acceptHeader = c.req.header("Accept") || "";
|
|
75
|
-
if (acceptHeader.includes("text/html")) {
|
|
76
|
-
return c.redirect("/auth/login?error=Your session has expired, please login again");
|
|
77
|
-
}
|
|
78
|
-
return c.json({ error: "Invalid or expired token" }, 401);
|
|
79
|
-
}
|
|
80
|
-
c.set("user", payload);
|
|
81
|
-
return await next();
|
|
82
|
-
} catch (error) {
|
|
83
|
-
console.error("Auth middleware error:", error);
|
|
84
|
-
const acceptHeader = c.req.header("Accept") || "";
|
|
85
|
-
if (acceptHeader.includes("text/html")) {
|
|
86
|
-
return c.redirect("/auth/login?error=Authentication failed, please login again");
|
|
87
|
-
}
|
|
88
|
-
return c.json({ error: "Authentication failed" }, 401);
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
};
|
|
92
|
-
var requireRole = (requiredRole) => {
|
|
93
|
-
return async (c, next) => {
|
|
94
|
-
const user = c.get("user");
|
|
95
|
-
if (!user) {
|
|
96
|
-
const acceptHeader = c.req.header("Accept") || "";
|
|
97
|
-
if (acceptHeader.includes("text/html")) {
|
|
98
|
-
return c.redirect("/auth/login?error=Please login to access the admin area");
|
|
99
|
-
}
|
|
100
|
-
return c.json({ error: "Authentication required" }, 401);
|
|
101
|
-
}
|
|
102
|
-
const roles = Array.isArray(requiredRole) ? requiredRole : [requiredRole];
|
|
103
|
-
if (!roles.includes(user.role)) {
|
|
104
|
-
const acceptHeader = c.req.header("Accept") || "";
|
|
105
|
-
if (acceptHeader.includes("text/html")) {
|
|
106
|
-
return c.redirect("/auth/login?error=You do not have permission to access this area");
|
|
107
|
-
}
|
|
108
|
-
return c.json({ error: "Insufficient permissions" }, 403);
|
|
109
|
-
}
|
|
110
|
-
return await next();
|
|
111
|
-
};
|
|
112
|
-
};
|
|
113
|
-
var optionalAuth = () => {
|
|
114
|
-
return async (c, next) => {
|
|
115
|
-
try {
|
|
116
|
-
let token = c.req.header("Authorization")?.replace("Bearer ", "");
|
|
117
|
-
if (!token) {
|
|
118
|
-
token = getCookie(c, "auth_token");
|
|
119
|
-
}
|
|
120
|
-
if (token) {
|
|
121
|
-
const payload = await AuthManager.verifyToken(token);
|
|
122
|
-
if (payload) {
|
|
123
|
-
c.set("user", payload);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
return await next();
|
|
127
|
-
} catch (error) {
|
|
128
|
-
console.error("Optional auth error:", error);
|
|
129
|
-
return await next();
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
// src/middleware/logging.ts
|
|
135
|
-
function loggingMiddleware() {
|
|
136
|
-
return async (c, next) => {
|
|
137
|
-
const startTime = Date.now();
|
|
138
|
-
const requestId = crypto.randomUUID();
|
|
139
|
-
c.set("requestId", requestId);
|
|
140
|
-
c.set("startTime", startTime);
|
|
141
|
-
try {
|
|
142
|
-
const logger = getLogger(c.env.DB);
|
|
143
|
-
const user = c.get("user");
|
|
144
|
-
const method = c.req.method;
|
|
145
|
-
const url = c.req.url;
|
|
146
|
-
const userAgent = c.req.header("user-agent") || "";
|
|
147
|
-
const ipAddress = c.req.header("cf-connecting-ip") || c.req.header("x-forwarded-for") || c.req.header("x-real-ip") || "unknown";
|
|
148
|
-
await next();
|
|
149
|
-
const duration = Date.now() - startTime;
|
|
150
|
-
const status = c.res.status;
|
|
151
|
-
const skipLogging = url.includes("/admin/api/metrics");
|
|
152
|
-
if (!skipLogging) {
|
|
153
|
-
await logger.logRequest(method, url, status, duration, {
|
|
154
|
-
userId: user?.userId,
|
|
155
|
-
requestId,
|
|
156
|
-
ipAddress,
|
|
157
|
-
userAgent,
|
|
158
|
-
source: "http-middleware"
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
if (status >= 400) {
|
|
162
|
-
await logger.warn("api", `HTTP ${status} error for ${method} ${url}`, {
|
|
163
|
-
method,
|
|
164
|
-
url,
|
|
165
|
-
status,
|
|
166
|
-
duration,
|
|
167
|
-
userAgent,
|
|
168
|
-
userId: user?.userId
|
|
169
|
-
}, {
|
|
170
|
-
userId: user?.userId,
|
|
171
|
-
requestId,
|
|
172
|
-
ipAddress,
|
|
173
|
-
userAgent,
|
|
174
|
-
method,
|
|
175
|
-
url,
|
|
176
|
-
statusCode: status,
|
|
177
|
-
duration,
|
|
178
|
-
source: "http-middleware",
|
|
179
|
-
tags: ["http-error", `status-${status}`]
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
} catch (error) {
|
|
183
|
-
const duration = Date.now() - startTime;
|
|
184
|
-
try {
|
|
185
|
-
const logger = getLogger(c.env.DB);
|
|
186
|
-
const user = c.get("user");
|
|
187
|
-
await logger.error("api", `Unhandled error in ${c.req.method} ${c.req.url}`, error, {
|
|
188
|
-
userId: user?.userId,
|
|
189
|
-
requestId,
|
|
190
|
-
ipAddress: c.req.header("cf-connecting-ip") || "unknown",
|
|
191
|
-
userAgent: c.req.header("user-agent") || "",
|
|
192
|
-
method: c.req.method,
|
|
193
|
-
url: c.req.url,
|
|
194
|
-
duration,
|
|
195
|
-
source: "http-middleware",
|
|
196
|
-
tags: ["unhandled-error"]
|
|
197
|
-
});
|
|
198
|
-
} catch (logError) {
|
|
199
|
-
console.error("Failed to log error:", logError);
|
|
200
|
-
console.error("Original error:", error);
|
|
201
|
-
}
|
|
202
|
-
throw error;
|
|
203
|
-
}
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
function detailedLoggingMiddleware() {
|
|
207
|
-
return async (c, next) => {
|
|
208
|
-
const startTime = Date.now();
|
|
209
|
-
const requestId = crypto.randomUUID();
|
|
210
|
-
c.set("requestId", requestId);
|
|
211
|
-
c.set("startTime", startTime);
|
|
212
|
-
try {
|
|
213
|
-
const logger = getLogger(c.env.DB);
|
|
214
|
-
const user = c.get("user");
|
|
215
|
-
const method = c.req.method;
|
|
216
|
-
const url = c.req.url;
|
|
217
|
-
const userAgent = c.req.header("user-agent") || "";
|
|
218
|
-
const ipAddress = c.req.header("cf-connecting-ip") || c.req.header("x-forwarded-for") || c.req.header("x-real-ip") || "unknown";
|
|
219
|
-
const contentType = c.req.header("content-type") || "";
|
|
220
|
-
const contentLength = c.req.header("content-length") || "";
|
|
221
|
-
await logger.debug("api", `Starting ${method} ${url}`, {
|
|
222
|
-
method,
|
|
223
|
-
url,
|
|
224
|
-
userAgent,
|
|
225
|
-
contentType,
|
|
226
|
-
contentLength,
|
|
227
|
-
headers: Object.fromEntries(c.req.raw.headers.entries())
|
|
228
|
-
}, {
|
|
229
|
-
userId: user?.userId,
|
|
230
|
-
requestId,
|
|
231
|
-
ipAddress,
|
|
232
|
-
userAgent,
|
|
233
|
-
method,
|
|
234
|
-
url,
|
|
235
|
-
source: "detailed-middleware",
|
|
236
|
-
tags: ["request-start"]
|
|
237
|
-
});
|
|
238
|
-
await next();
|
|
239
|
-
const duration = Date.now() - startTime;
|
|
240
|
-
const status = c.res.status;
|
|
241
|
-
const responseHeaders = Object.fromEntries(c.res.headers.entries());
|
|
242
|
-
await logger.info("api", `Completed ${method} ${url} - ${status} (${duration}ms)`, {
|
|
243
|
-
method,
|
|
244
|
-
url,
|
|
245
|
-
status,
|
|
246
|
-
duration,
|
|
247
|
-
responseHeaders,
|
|
248
|
-
responseSize: c.res.headers.get("content-length")
|
|
249
|
-
}, {
|
|
250
|
-
userId: user?.userId,
|
|
251
|
-
requestId,
|
|
252
|
-
ipAddress,
|
|
253
|
-
userAgent,
|
|
254
|
-
method,
|
|
255
|
-
url,
|
|
256
|
-
statusCode: status,
|
|
257
|
-
duration,
|
|
258
|
-
source: "detailed-middleware",
|
|
259
|
-
tags: ["request-complete", `status-${Math.floor(status / 100)}xx`]
|
|
260
|
-
});
|
|
261
|
-
} catch (error) {
|
|
262
|
-
const duration = Date.now() - startTime;
|
|
263
|
-
try {
|
|
264
|
-
const logger = getLogger(c.env.DB);
|
|
265
|
-
const user = c.get("user");
|
|
266
|
-
await logger.error("api", `Request failed: ${c.req.method} ${c.req.url}`, error, {
|
|
267
|
-
userId: user?.userId,
|
|
268
|
-
requestId,
|
|
269
|
-
ipAddress: c.req.header("cf-connecting-ip") || "unknown",
|
|
270
|
-
userAgent: c.req.header("user-agent") || "",
|
|
271
|
-
method: c.req.method,
|
|
272
|
-
url: c.req.url,
|
|
273
|
-
duration,
|
|
274
|
-
source: "detailed-middleware",
|
|
275
|
-
tags: ["request-error"]
|
|
276
|
-
});
|
|
277
|
-
} catch (logError) {
|
|
278
|
-
console.error("Failed to log detailed error:", logError);
|
|
279
|
-
console.error("Original error:", error);
|
|
280
|
-
}
|
|
281
|
-
throw error;
|
|
282
|
-
}
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
function securityLoggingMiddleware() {
|
|
286
|
-
return async (c, next) => {
|
|
287
|
-
const startTime = Date.now();
|
|
288
|
-
const requestId = c.get("requestId") || crypto.randomUUID();
|
|
289
|
-
try {
|
|
290
|
-
const logger = getLogger(c.env.DB);
|
|
291
|
-
const user = c.get("user");
|
|
292
|
-
const method = c.req.method;
|
|
293
|
-
const url = c.req.url;
|
|
294
|
-
const ipAddress = c.req.header("cf-connecting-ip") || "unknown";
|
|
295
|
-
const userAgent = c.req.header("user-agent") || "";
|
|
296
|
-
const suspiciousPatterns = [
|
|
297
|
-
/script[^>]*>/i,
|
|
298
|
-
/javascript:/i,
|
|
299
|
-
/on\w+\s*=/i,
|
|
300
|
-
/\.\.\/\.\.\//,
|
|
301
|
-
/\/etc\/passwd/i,
|
|
302
|
-
/union\s+select/i,
|
|
303
|
-
/drop\s+table/i
|
|
304
|
-
];
|
|
305
|
-
const isSuspicious = suspiciousPatterns.some(
|
|
306
|
-
(pattern) => pattern.test(url) || pattern.test(userAgent)
|
|
307
|
-
);
|
|
308
|
-
if (isSuspicious) {
|
|
309
|
-
await logger.logSecurity("Suspicious request pattern detected", "medium", {
|
|
310
|
-
userId: user?.userId,
|
|
311
|
-
requestId,
|
|
312
|
-
ipAddress,
|
|
313
|
-
userAgent,
|
|
314
|
-
method,
|
|
315
|
-
url,
|
|
316
|
-
source: "security-middleware",
|
|
317
|
-
tags: ["suspicious-pattern"]
|
|
318
|
-
});
|
|
319
|
-
}
|
|
320
|
-
await next();
|
|
321
|
-
const duration = Date.now() - startTime;
|
|
322
|
-
const status = c.res.status;
|
|
323
|
-
if (url.includes("/auth/") && status === 401) {
|
|
324
|
-
await logger.logSecurity("Authentication failure", "low", {
|
|
325
|
-
userId: user?.userId,
|
|
326
|
-
requestId,
|
|
327
|
-
ipAddress,
|
|
328
|
-
userAgent,
|
|
329
|
-
method,
|
|
330
|
-
url,
|
|
331
|
-
statusCode: status,
|
|
332
|
-
duration,
|
|
333
|
-
source: "security-middleware",
|
|
334
|
-
tags: ["auth-failure"]
|
|
335
|
-
});
|
|
336
|
-
}
|
|
337
|
-
if (url.includes("/admin/") && status < 400 && !url.includes("/admin/api/metrics")) {
|
|
338
|
-
await logger.logSecurity("Admin area access", "low", {
|
|
339
|
-
userId: user?.userId,
|
|
340
|
-
requestId,
|
|
341
|
-
ipAddress,
|
|
342
|
-
userAgent,
|
|
343
|
-
method,
|
|
344
|
-
url,
|
|
345
|
-
statusCode: status,
|
|
346
|
-
duration,
|
|
347
|
-
source: "security-middleware",
|
|
348
|
-
tags: ["admin-access"]
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
} catch (error) {
|
|
352
|
-
try {
|
|
353
|
-
const logger = getLogger(c.env.DB);
|
|
354
|
-
await logger.error("security", "Security middleware error", error, {
|
|
355
|
-
requestId,
|
|
356
|
-
source: "security-middleware"
|
|
357
|
-
});
|
|
358
|
-
} catch (logError) {
|
|
359
|
-
console.error("Failed to log security error:", logError);
|
|
360
|
-
}
|
|
361
|
-
throw error;
|
|
362
|
-
}
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
|
-
function performanceLoggingMiddleware(slowThreshold = 1e3) {
|
|
366
|
-
return async (c, next) => {
|
|
367
|
-
const startTime = Date.now();
|
|
368
|
-
const requestId = c.get("requestId") || crypto.randomUUID();
|
|
369
|
-
await next();
|
|
370
|
-
const duration = Date.now() - startTime;
|
|
371
|
-
if (duration > slowThreshold) {
|
|
372
|
-
try {
|
|
373
|
-
const logger = getLogger(c.env.DB);
|
|
374
|
-
const user = c.get("user");
|
|
375
|
-
await logger.warn("system", `Slow request detected: ${c.req.method} ${c.req.url} took ${duration}ms`, {
|
|
376
|
-
method: c.req.method,
|
|
377
|
-
url: c.req.url,
|
|
378
|
-
duration,
|
|
379
|
-
threshold: slowThreshold
|
|
380
|
-
}, {
|
|
381
|
-
userId: user?.userId,
|
|
382
|
-
requestId,
|
|
383
|
-
method: c.req.method,
|
|
384
|
-
url: c.req.url,
|
|
385
|
-
duration,
|
|
386
|
-
source: "performance-middleware",
|
|
387
|
-
tags: ["slow-request", "performance"]
|
|
388
|
-
});
|
|
389
|
-
} catch (error) {
|
|
390
|
-
console.error("Failed to log slow request:", error);
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
};
|
|
394
|
-
}
|
|
395
|
-
var cacheHeaders = (maxAge = 60) => {
|
|
396
|
-
return async (c, next) => {
|
|
397
|
-
await next();
|
|
398
|
-
if (c.res.status === 200 && c.res.headers.get("Content-Type")?.includes("text/html")) {
|
|
399
|
-
c.res.headers.set("Cache-Control", `private, max-age=${maxAge}`);
|
|
400
|
-
}
|
|
401
|
-
};
|
|
402
|
-
};
|
|
403
|
-
var compressionMiddleware = compress();
|
|
404
|
-
var securityHeaders = () => {
|
|
405
|
-
return async (c, next) => {
|
|
406
|
-
await next();
|
|
407
|
-
c.res.headers.set("X-Content-Type-Options", "nosniff");
|
|
408
|
-
c.res.headers.set("X-Frame-Options", "SAMEORIGIN");
|
|
409
|
-
c.res.headers.set("X-XSS-Protection", "1; mode=block");
|
|
410
|
-
};
|
|
411
|
-
};
|
|
412
|
-
|
|
413
|
-
// src/middleware/permissions.ts
|
|
414
|
-
var PermissionManager = class _PermissionManager {
|
|
415
|
-
static permissionCache = /* @__PURE__ */ new Map();
|
|
416
|
-
static cacheExpiry = /* @__PURE__ */ new Map();
|
|
417
|
-
static CACHE_TTL = 5 * 60 * 1e3;
|
|
418
|
-
// 5 minutes
|
|
419
|
-
/**
|
|
420
|
-
* Get user permissions from database with caching
|
|
421
|
-
*/
|
|
422
|
-
static async getUserPermissions(db, userId) {
|
|
423
|
-
const cacheKey = `permissions:${userId}`;
|
|
424
|
-
const now = Date.now();
|
|
425
|
-
if (this.permissionCache.has(cacheKey)) {
|
|
426
|
-
const expiry = this.cacheExpiry.get(cacheKey) || 0;
|
|
427
|
-
if (now < expiry) {
|
|
428
|
-
return this.permissionCache.get(cacheKey);
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
const userStmt = db.prepare("SELECT id, role FROM users WHERE id = ? AND is_active = 1");
|
|
432
|
-
const user = await userStmt.bind(userId).first();
|
|
433
|
-
if (!user) {
|
|
434
|
-
throw new Error("User not found");
|
|
435
|
-
}
|
|
436
|
-
const rolePermStmt = db.prepare(`
|
|
437
|
-
SELECT p.name
|
|
438
|
-
FROM role_permissions rp
|
|
439
|
-
JOIN permissions p ON rp.permission_id = p.id
|
|
440
|
-
WHERE rp.role = ?
|
|
441
|
-
`);
|
|
442
|
-
const { results: rolePermissions } = await rolePermStmt.bind(user.role).all();
|
|
443
|
-
const rolePerms = (rolePermissions || []).map((row) => row.name);
|
|
444
|
-
const permissions = [...rolePerms];
|
|
445
|
-
const teamPermStmt = db.prepare(`
|
|
446
|
-
SELECT tm.team_id, tm.role, tm.permissions
|
|
447
|
-
FROM team_memberships tm
|
|
448
|
-
WHERE tm.user_id = ?
|
|
449
|
-
`);
|
|
450
|
-
const { results: teamMemberships } = await teamPermStmt.bind(userId).all();
|
|
451
|
-
const teamPermissions = {};
|
|
452
|
-
for (const membership of teamMemberships || []) {
|
|
453
|
-
const teamRole = membership.role;
|
|
454
|
-
const customPerms = membership.permissions ? JSON.parse(membership.permissions) : [];
|
|
455
|
-
const teamRolePerms = await rolePermStmt.bind(teamRole).all();
|
|
456
|
-
const teamRolePermissions = (teamRolePerms.results || []).map((row) => row.name);
|
|
457
|
-
teamPermissions[membership.team_id] = [...teamRolePermissions, ...customPerms];
|
|
458
|
-
}
|
|
459
|
-
const userPermissions = {
|
|
460
|
-
userId,
|
|
461
|
-
role: user.role,
|
|
462
|
-
permissions,
|
|
463
|
-
teamPermissions
|
|
464
|
-
};
|
|
465
|
-
this.permissionCache.set(cacheKey, userPermissions);
|
|
466
|
-
this.cacheExpiry.set(cacheKey, now + this.CACHE_TTL);
|
|
467
|
-
return userPermissions;
|
|
468
|
-
}
|
|
469
|
-
/**
|
|
470
|
-
* Check if user has a specific permission
|
|
471
|
-
*/
|
|
472
|
-
static async hasPermission(db, userId, permission, teamId) {
|
|
473
|
-
try {
|
|
474
|
-
console.log("hasPermission called with:", { userId, permission, teamId });
|
|
475
|
-
const userPerms = await this.getUserPermissions(db, userId);
|
|
476
|
-
console.log("User permissions result:", userPerms);
|
|
477
|
-
if (userPerms.permissions.includes(permission)) {
|
|
478
|
-
console.log("Permission found in global permissions");
|
|
479
|
-
return true;
|
|
480
|
-
}
|
|
481
|
-
if (teamId && userPerms.teamPermissions && userPerms.teamPermissions[teamId]) {
|
|
482
|
-
const hasTeamPermission = userPerms.teamPermissions[teamId].includes(permission);
|
|
483
|
-
console.log("Team permission check:", hasTeamPermission);
|
|
484
|
-
return hasTeamPermission;
|
|
485
|
-
}
|
|
486
|
-
console.log("Permission not found");
|
|
487
|
-
return false;
|
|
488
|
-
} catch (error) {
|
|
489
|
-
console.error("Permission check error:", error);
|
|
490
|
-
if (error instanceof Error && error.message === "User not found") {
|
|
491
|
-
return false;
|
|
492
|
-
}
|
|
493
|
-
throw error;
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
/**
|
|
497
|
-
* Clear permission cache for a user
|
|
498
|
-
*/
|
|
499
|
-
static clearUserCache(userId) {
|
|
500
|
-
const cacheKey = `permissions:${userId}`;
|
|
501
|
-
this.permissionCache.delete(cacheKey);
|
|
502
|
-
this.cacheExpiry.delete(cacheKey);
|
|
503
|
-
}
|
|
504
|
-
/**
|
|
505
|
-
* Clear all permission cache
|
|
506
|
-
*/
|
|
507
|
-
static clearAllCache() {
|
|
508
|
-
this.permissionCache.clear();
|
|
509
|
-
this.cacheExpiry.clear();
|
|
510
|
-
}
|
|
511
|
-
/**
|
|
512
|
-
* Clear all permission cache (alias for clearAllCache)
|
|
513
|
-
*/
|
|
514
|
-
static clearCache() {
|
|
515
|
-
this.clearAllCache();
|
|
516
|
-
}
|
|
517
|
-
/**
|
|
518
|
-
* Check multiple permissions at once
|
|
519
|
-
*/
|
|
520
|
-
static async checkMultiplePermissions(db, userId, permissions, teamId) {
|
|
521
|
-
const result = {};
|
|
522
|
-
for (const permission of permissions) {
|
|
523
|
-
result[permission] = await this.hasPermission(db, userId, permission, teamId);
|
|
524
|
-
}
|
|
525
|
-
return result;
|
|
526
|
-
}
|
|
527
|
-
/**
|
|
528
|
-
* Middleware factory to require specific permissions
|
|
529
|
-
*/
|
|
530
|
-
static requirePermissions(permissions, teamIdParam) {
|
|
531
|
-
return async (c, next) => {
|
|
532
|
-
const user = c.get("user");
|
|
533
|
-
if (!user) {
|
|
534
|
-
return c.json({ error: "Authentication required" }, 401);
|
|
535
|
-
}
|
|
536
|
-
const db = c.env.DB;
|
|
537
|
-
const teamId = teamIdParam ? c.req.param(teamIdParam) : void 0;
|
|
538
|
-
try {
|
|
539
|
-
for (const permission of permissions) {
|
|
540
|
-
const hasPermission = await _PermissionManager.hasPermission(db, user.userId, permission, teamId);
|
|
541
|
-
if (!hasPermission) {
|
|
542
|
-
return c.json({ error: `Permission denied: ${permission}` }, 403);
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
return await next();
|
|
546
|
-
} catch (error) {
|
|
547
|
-
console.error("Permission check error:", error);
|
|
548
|
-
return c.json({ error: "Permission check failed" }, 500);
|
|
549
|
-
}
|
|
550
|
-
};
|
|
551
|
-
}
|
|
552
|
-
/**
|
|
553
|
-
* Get all available permissions from database
|
|
554
|
-
*/
|
|
555
|
-
static async getAllPermissions(db) {
|
|
556
|
-
const stmt = db.prepare("SELECT * FROM permissions ORDER BY category, name");
|
|
557
|
-
const { results } = await stmt.all();
|
|
558
|
-
return (results || []).map((row) => ({
|
|
559
|
-
id: row.id,
|
|
560
|
-
name: row.name,
|
|
561
|
-
description: row.description,
|
|
562
|
-
category: row.category
|
|
563
|
-
}));
|
|
564
|
-
}
|
|
565
|
-
};
|
|
566
|
-
function requirePermission(permission, teamIdParam) {
|
|
567
|
-
return async (c, next) => {
|
|
568
|
-
const user = c.get("user");
|
|
569
|
-
if (!user) {
|
|
570
|
-
return c.json({ error: "Authentication required" }, 401);
|
|
571
|
-
}
|
|
572
|
-
const db = c.env.DB;
|
|
573
|
-
const teamId = teamIdParam ? c.req.param(teamIdParam) : void 0;
|
|
574
|
-
try {
|
|
575
|
-
const hasPermission = await PermissionManager.hasPermission(db, user.userId, permission, teamId);
|
|
576
|
-
if (!hasPermission) {
|
|
577
|
-
return c.json({ error: `Permission denied: ${permission}` }, 403);
|
|
578
|
-
}
|
|
579
|
-
return await next();
|
|
580
|
-
} catch (error) {
|
|
581
|
-
console.error("Permission check error:", error);
|
|
582
|
-
return c.json({ error: "Permission check failed" }, 500);
|
|
583
|
-
}
|
|
584
|
-
};
|
|
585
|
-
}
|
|
586
|
-
function requireAnyPermission(permissions, teamIdParam) {
|
|
587
|
-
return async (c, next) => {
|
|
588
|
-
const user = c.get("user");
|
|
589
|
-
if (!user) {
|
|
590
|
-
return c.json({ error: "Authentication required" }, 401);
|
|
591
|
-
}
|
|
592
|
-
const db = c.env.DB;
|
|
593
|
-
const teamId = teamIdParam ? c.req.param(teamIdParam) : void 0;
|
|
594
|
-
try {
|
|
595
|
-
for (const permission of permissions) {
|
|
596
|
-
const hasPermission = await PermissionManager.hasPermission(db, user.userId, permission, teamId);
|
|
597
|
-
if (hasPermission) {
|
|
598
|
-
await next();
|
|
599
|
-
return;
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
return c.json({ error: `Permission denied. Required one of: ${permissions.join(", ")}` }, 403);
|
|
603
|
-
} catch (error) {
|
|
604
|
-
console.error("Permission check error:", error);
|
|
605
|
-
return c.json({ error: "Permission check failed" }, 500);
|
|
606
|
-
}
|
|
607
|
-
};
|
|
608
|
-
}
|
|
609
|
-
async function logActivity(db, userId, action, resourceType, resourceId, details, ipAddress, userAgent) {
|
|
610
|
-
try {
|
|
611
|
-
const logStmt = db.prepare(`
|
|
612
|
-
INSERT INTO activity_logs (id, user_id, action, resource_type, resource_id, details, ip_address, user_agent, created_at)
|
|
613
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
614
|
-
`);
|
|
615
|
-
await logStmt.bind(
|
|
616
|
-
crypto.randomUUID(),
|
|
617
|
-
userId,
|
|
618
|
-
action,
|
|
619
|
-
resourceType || null,
|
|
620
|
-
resourceId || null,
|
|
621
|
-
details ? JSON.stringify(details) : null,
|
|
622
|
-
ipAddress || null,
|
|
623
|
-
userAgent || null,
|
|
624
|
-
Date.now()
|
|
625
|
-
).run();
|
|
626
|
-
} catch (error) {
|
|
627
|
-
console.error("Failed to log activity:", error);
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
// src/middleware/plugin-middleware.ts
|
|
632
|
-
function requireActivePlugin(pluginName) {
|
|
633
|
-
return async (c, next) => {
|
|
634
|
-
try {
|
|
635
|
-
const db = c.env.DB;
|
|
636
|
-
const plugin = await db.prepare(
|
|
637
|
-
"SELECT status FROM plugins WHERE name = ? AND status = ?"
|
|
638
|
-
).bind(pluginName, "active").first();
|
|
639
|
-
if (!plugin) {
|
|
640
|
-
return c.html(`
|
|
641
|
-
<div class="min-h-screen flex items-center justify-center bg-gray-900">
|
|
642
|
-
<div class="text-center">
|
|
643
|
-
<h1 class="text-4xl font-bold text-white mb-4">Feature Not Available</h1>
|
|
644
|
-
<p class="text-gray-300 mb-6">The ${pluginName} plugin is not currently active.</p>
|
|
645
|
-
<a href="/admin" class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-lg font-medium">
|
|
646
|
-
Return to Admin Dashboard
|
|
647
|
-
</a>
|
|
648
|
-
</div>
|
|
649
|
-
</div>
|
|
650
|
-
`, 404);
|
|
651
|
-
}
|
|
652
|
-
return await next();
|
|
653
|
-
} catch (error) {
|
|
654
|
-
console.error(`Error checking plugin status for ${pluginName}:`, error);
|
|
655
|
-
return await next();
|
|
656
|
-
}
|
|
657
|
-
};
|
|
658
|
-
}
|
|
659
|
-
function requireActivePlugins(pluginNames) {
|
|
660
|
-
return async (c, next) => {
|
|
661
|
-
try {
|
|
662
|
-
const db = c.env.DB;
|
|
663
|
-
for (const pluginName of pluginNames) {
|
|
664
|
-
const plugin = await db.prepare(
|
|
665
|
-
"SELECT status FROM plugins WHERE name = ? AND status = ?"
|
|
666
|
-
).bind(pluginName, "active").first();
|
|
667
|
-
if (!plugin) {
|
|
668
|
-
return c.html(`
|
|
669
|
-
<div class="min-h-screen flex items-center justify-center bg-gray-900">
|
|
670
|
-
<div class="text-center">
|
|
671
|
-
<h1 class="text-4xl font-bold text-white mb-4">Feature Not Available</h1>
|
|
672
|
-
<p class="text-gray-300 mb-6">Required plugin "${pluginName}" is not currently active.</p>
|
|
673
|
-
<a href="/admin" class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-lg font-medium">
|
|
674
|
-
Return to Admin Dashboard
|
|
675
|
-
</a>
|
|
676
|
-
</div>
|
|
677
|
-
</div>
|
|
678
|
-
`, 404);
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
return await next();
|
|
682
|
-
} catch (error) {
|
|
683
|
-
console.error(`Error checking plugin status for plugins:`, pluginNames, error);
|
|
684
|
-
return await next();
|
|
685
|
-
}
|
|
686
|
-
};
|
|
687
|
-
}
|
|
688
|
-
async function getActivePlugins(db) {
|
|
689
|
-
try {
|
|
690
|
-
const result = await db.prepare(
|
|
691
|
-
"SELECT name, display_name, icon, settings FROM plugins WHERE status = ? ORDER BY display_name"
|
|
692
|
-
).bind("active").all();
|
|
693
|
-
return result.results?.map((row) => ({
|
|
694
|
-
name: row.name,
|
|
695
|
-
display_name: row.display_name,
|
|
696
|
-
icon: row.icon,
|
|
697
|
-
settings: row.settings ? JSON.parse(row.settings) : null
|
|
698
|
-
})) || [];
|
|
699
|
-
} catch (error) {
|
|
700
|
-
console.error("Error fetching active plugins:", error);
|
|
701
|
-
return [];
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
async function isPluginActive(db, pluginName) {
|
|
705
|
-
try {
|
|
706
|
-
const result = await db.prepare(
|
|
707
|
-
"SELECT id FROM plugins WHERE name = ? AND status = ?"
|
|
708
|
-
).bind(pluginName, "active").first();
|
|
709
|
-
return !!result;
|
|
710
|
-
} catch (error) {
|
|
711
|
-
console.error(`Error checking if plugin ${pluginName} is active:`, error);
|
|
712
|
-
return false;
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
// src/middleware/bootstrap.ts
|
|
717
|
-
var bootstrapComplete = false;
|
|
718
|
-
function bootstrapMiddleware() {
|
|
719
|
-
return async (c, next) => {
|
|
720
|
-
if (bootstrapComplete) {
|
|
721
|
-
return next();
|
|
722
|
-
}
|
|
723
|
-
const path = c.req.path;
|
|
724
|
-
if (path.startsWith("/images/") || path.startsWith("/assets/") || path === "/health" || path.endsWith(".js") || path.endsWith(".css") || path.endsWith(".png") || path.endsWith(".jpg") || path.endsWith(".ico")) {
|
|
725
|
-
return next();
|
|
726
|
-
}
|
|
727
|
-
try {
|
|
728
|
-
console.log("[Bootstrap] Starting system initialization...");
|
|
729
|
-
console.log("[Bootstrap] Running database migrations...");
|
|
730
|
-
const migrationService = new MigrationService(c.env.DB);
|
|
731
|
-
await migrationService.runPendingMigrations();
|
|
732
|
-
console.log("[Bootstrap] Syncing collection configurations...");
|
|
733
|
-
try {
|
|
734
|
-
await syncCollections(c.env.DB);
|
|
735
|
-
} catch (error) {
|
|
736
|
-
console.error("[Bootstrap] Error syncing collections:", error);
|
|
737
|
-
}
|
|
738
|
-
console.log("[Bootstrap] Bootstrapping core plugins...");
|
|
739
|
-
const bootstrapService = new PluginBootstrapService(c.env.DB);
|
|
740
|
-
const needsBootstrap = await bootstrapService.isBootstrapNeeded();
|
|
741
|
-
if (needsBootstrap) {
|
|
742
|
-
await bootstrapService.bootstrapCorePlugins();
|
|
743
|
-
}
|
|
744
|
-
bootstrapComplete = true;
|
|
745
|
-
console.log("[Bootstrap] System initialization completed");
|
|
746
|
-
} catch (error) {
|
|
747
|
-
console.error("[Bootstrap] Error during system initialization:", error);
|
|
748
|
-
}
|
|
749
|
-
return next();
|
|
750
|
-
};
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
export { AuthManager, PermissionManager, bootstrapMiddleware, cacheHeaders, compressionMiddleware, detailedLoggingMiddleware, getActivePlugins, isPluginActive, logActivity, loggingMiddleware, optionalAuth, performanceLoggingMiddleware, requireActivePlugin, requireActivePlugins, requireAnyPermission, requireAuth, requirePermission, requireRole, securityHeaders, securityLoggingMiddleware };
|
|
754
|
-
//# sourceMappingURL=chunk-WESS2U3K.js.map
|
|
755
|
-
//# sourceMappingURL=chunk-WESS2U3K.js.map
|