@revealui/security 0.0.1-pre.0 → 0.2.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/index.js CHANGED
@@ -1,1841 +1,2434 @@
1
- // src/SecurityValidation.ts
2
- import { z } from "zod";
3
- var EnvironmentSchema = z.object({
4
- PAYLOAD_SECRET: z.string().min(32, "PAYLOAD_SECRET must be at least 32 characters"),
5
- MCP_ENCRYPTION_KEY: z.string().min(64, "MCP_ENCRYPTION_KEY must be at least 64 characters"),
6
- TURSO_URL: z.string().url().optional(),
7
- TURSO_AUTH_TOKEN: z.string().optional(),
8
- SUPPORT_EMAIL: z.string().email().optional()
9
- });
10
- var RATE_LIMITS = {
11
- CHAT: { windowMs: 60 * 1e3, maxRequests: 10 },
12
- // 10 requests per minute
13
- CONTENT: { windowMs: 60 * 1e3, maxRequests: 5 },
14
- // 5 requests per minute
15
- CONTACT: { windowMs: 15 * 60 * 1e3, maxRequests: 3 },
16
- // 3 requests per 15 minutes
17
- RECOMMENDATIONS: { windowMs: 60 * 1e3, maxRequests: 20 }
18
- // 20 requests per minute
19
- };
20
- var rateLimitStore = /* @__PURE__ */ new Map();
21
- async function validateEnvironment() {
22
- const validation = EnvironmentSchema.safeParse(process.env);
23
- if (!validation.success) {
24
- const errors = validation.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join(", ");
25
- throw new Error(`Environment validation failed: ${errors}`);
26
- }
27
- }
28
- async function checkRateLimit(key, config) {
29
- const now = Date.now();
30
- for (const [k, v] of rateLimitStore.entries()) {
31
- if (v.resetTime < now) {
32
- rateLimitStore.delete(k);
33
- }
34
- }
35
- const entry = rateLimitStore.get(key);
36
- if (!entry || entry.resetTime < now) {
37
- rateLimitStore.set(key, { count: 1, resetTime: now + config.windowMs });
38
- return {
39
- allowed: true,
40
- remaining: config.maxRequests - 1,
41
- resetTime: now + config.windowMs
42
- };
43
- }
44
- if (entry.count >= config.maxRequests) {
45
- return {
46
- allowed: false,
47
- remaining: 0,
48
- resetTime: entry.resetTime
49
- };
1
+ // src/audit.ts
2
+ var AuditSystem = class {
3
+ storage;
4
+ filters = [];
5
+ constructor(storage) {
6
+ this.storage = storage;
50
7
  }
51
- entry.count++;
52
- rateLimitStore.set(key, entry);
53
- return {
54
- allowed: true,
55
- remaining: config.maxRequests - entry.count,
56
- resetTime: entry.resetTime
57
- };
58
- }
59
- function generateRateLimitKey(userId, action) {
60
- return `rate_limit:${action}:${userId}`;
61
- }
62
- function generateIPRateLimitKey(ip, action) {
63
- return `rate_limit:${action}:ip:${ip}`;
64
- }
65
- async function validateCSRFToken(token, sessionToken) {
66
- return token === sessionToken && token.length > 0;
67
- }
68
- function sanitizeInput(input) {
69
- return input.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "").replace(/on\w+\s*=\s*["'][^"']*["']/gi, "").replace(/javascript:/gi, "").trim();
70
- }
71
- function validateAndSanitizeInput(input, schema) {
72
- try {
73
- const validation = schema.safeParse(input);
74
- if (!validation.success) {
75
- return {
76
- success: false,
77
- error: validation.error.issues.map((i) => i.message).join(", ")
78
- };
79
- }
80
- const sanitized = sanitizeObject(validation.data);
81
- return {
82
- success: true,
83
- data: sanitized
84
- };
85
- } catch (error) {
86
- return {
87
- success: false,
88
- error: error instanceof Error ? error.message : "Validation failed"
8
+ /**
9
+ * Log audit event
10
+ */
11
+ async log(event) {
12
+ const fullEvent = {
13
+ ...event,
14
+ id: crypto.randomUUID(),
15
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
89
16
  };
90
- }
91
- }
92
- function sanitizeObject(obj) {
93
- if (typeof obj === "string") {
94
- return sanitizeInput(obj);
95
- }
96
- if (Array.isArray(obj)) {
97
- return obj.map(sanitizeObject);
98
- }
99
- if (obj && typeof obj === "object") {
100
- const sanitized = {};
101
- for (const [key, value] of Object.entries(obj)) {
102
- sanitized[key] = sanitizeObject(value);
17
+ const shouldLog = this.filters.every((filter) => filter(fullEvent));
18
+ if (!shouldLog) {
19
+ return;
103
20
  }
104
- return sanitized;
105
- }
106
- return obj;
107
- }
108
- var SECURITY_HEADERS = {
109
- "X-Content-Type-Options": "nosniff",
110
- "X-Frame-Options": "DENY",
111
- "X-XSS-Protection": "1; mode=block",
112
- "Referrer-Policy": "strict-origin-when-cross-origin",
113
- "Permissions-Policy": "camera=(), microphone=(), geolocation=()"
114
- };
115
- function logSecurityEvent(event, details, severity = "medium") {
116
- console.log(`[SECURITY-${severity.toUpperCase()}] ${event}:`, {
117
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
118
- severity,
119
- ...details
120
- });
121
- }
122
-
123
- // src/RateLimiterService.ts
124
- var devLogger = {
125
- debug: (...args) => console.debug("[security]", ...args),
126
- info: (...args) => console.log("[security]", ...args),
127
- warn: (...args) => console.warn("[security]", ...args),
128
- error: (...args) => console.error("[security]", ...args),
129
- forService: (_name) => ({
130
- debug: (...args) => console.debug("[security]", ...args),
131
- info: (...args) => console.log("[security]", ...args),
132
- warn: (...args) => console.warn("[security]", ...args),
133
- error: (...args) => console.error("[security]", ...args)
134
- })
135
- };
136
- var RateLimiterService = class {
137
- config;
138
- inMemoryStore = /* @__PURE__ */ new Map();
139
- cleanupInterval = null;
140
- constructor(config) {
141
- this.config = {
142
- windowMs: config.windowMs ?? 15 * 60 * 1e3,
143
- // 15 minutes
144
- maxRequests: config.maxRequests ?? 100,
145
- skipSuccessfulRequests: config.skipSuccessfulRequests ?? false,
146
- skipFailedRequests: config.skipFailedRequests ?? false,
147
- standardHeaders: config.standardHeaders ?? true,
148
- legacyHeaders: config.legacyHeaders ?? false
149
- };
150
- this.startCleanupInterval();
151
- }
152
- setPayload(_payload) {
21
+ await this.storage.write(fullEvent);
153
22
  }
154
23
  /**
155
- * Check rate limit using token bucket algorithm
24
+ * Log authentication event
156
25
  */
157
- checkTokenBucket(key, tokens = 1, capacity = 10, refillRate = 1, refillTime = 100) {
158
- try {
159
- const now = Date.now();
160
- const bucketKey = `rate_limit:token_bucket:${key}`;
161
- const current = this.inMemoryStore.get(bucketKey);
162
- let currentTokens = capacity;
163
- let lastRefill = now;
164
- if (current) {
165
- currentTokens = current.count;
166
- lastRefill = current.lastRequestTime;
167
- }
168
- const timePassed = now - lastRefill;
169
- const refillAmount = Math.floor(timePassed / refillTime) * refillRate;
170
- currentTokens = Math.min(capacity, currentTokens + refillAmount);
171
- if (currentTokens >= tokens) {
172
- currentTokens = currentTokens - tokens;
173
- this.inMemoryStore.set(bucketKey, {
174
- count: currentTokens,
175
- resetTime: now + refillTime,
176
- lastRequestTime: now
177
- });
178
- devLogger.debug("Rate limit check", {
179
- key,
180
- algorithm: "token_bucket",
181
- allowed: true,
182
- remaining: currentTokens,
183
- resetTime: now + refillTime,
184
- tokens,
185
- capacity,
186
- refillRate
187
- });
188
- return {
189
- allowed: true,
190
- remaining: currentTokens,
191
- resetTime: now + refillTime
192
- };
193
- }
194
- const resetTime = lastRefill + refillTime;
195
- devLogger.warn("Rate limit blocked", {
196
- key,
197
- algorithm: "token_bucket",
198
- remaining: currentTokens,
199
- resetTime,
200
- tokens
201
- });
202
- return {
203
- allowed: false,
204
- remaining: currentTokens,
205
- resetTime,
206
- retryAfter: Math.ceil((resetTime - now) / 1e3)
207
- };
208
- } catch (error) {
209
- devLogger.error("Rate limiter error", error instanceof Error ? error : void 0, {
210
- key,
211
- algorithm: "token_bucket",
212
- error: error instanceof Error ? error.message : "Unknown error"
213
- });
214
- return {
215
- allowed: true,
216
- remaining: capacity,
217
- resetTime: Date.now() + refillTime
218
- };
219
- }
26
+ async logAuth(type, actorId, result, metadata) {
27
+ await this.log({
28
+ type,
29
+ severity: result === "failure" ? "medium" : "low",
30
+ actor: {
31
+ id: actorId,
32
+ type: "user"
33
+ },
34
+ action: type.replace("auth.", ""),
35
+ result,
36
+ metadata
37
+ });
220
38
  }
221
39
  /**
222
- * Check rate limit using sliding window algorithm
40
+ * Log data access event
223
41
  */
224
- checkSlidingWindow(key, windowMs = this.config.windowMs, maxRequests = this.config.maxRequests) {
225
- try {
226
- const now = Date.now();
227
- const windowKey = `rate_limit:sliding_window:${key}`;
228
- const current = this.inMemoryStore.get(windowKey);
229
- let requests = [];
230
- if (current) {
231
- requests = [current.count];
232
- }
233
- const windowStart = now - windowMs;
234
- requests = requests.filter((timestamp) => timestamp >= windowStart);
235
- if (requests.length < maxRequests) {
236
- requests.push(now);
237
- this.inMemoryStore.set(windowKey, {
238
- count: requests.length,
239
- resetTime: now + windowMs,
240
- lastRequestTime: now
241
- });
242
- devLogger.debug("Rate limit check", {
243
- key,
244
- algorithm: "sliding_window",
245
- allowed: true,
246
- remaining: maxRequests - requests.length,
247
- resetTime: now + windowMs
248
- });
249
- return {
250
- allowed: true,
251
- remaining: maxRequests - requests.length,
252
- resetTime: now + windowMs
253
- };
254
- }
255
- const oldest = Math.min(...requests);
256
- const resetTime = oldest + windowMs;
257
- devLogger.warn("Rate limit blocked", {
258
- key,
259
- algorithm: "sliding_window",
260
- remaining: 0,
261
- resetTime
262
- });
263
- return {
264
- allowed: false,
265
- remaining: 0,
266
- resetTime,
267
- retryAfter: Math.ceil((resetTime - now) / 1e3)
268
- };
269
- } catch (error) {
270
- devLogger.error("Rate limiter error", error instanceof Error ? error : void 0, {
271
- key,
272
- algorithm: "sliding_window",
273
- error: error instanceof Error ? error.message : "Unknown error"
274
- });
275
- return {
276
- allowed: true,
277
- remaining: maxRequests,
278
- resetTime: Date.now() + windowMs
279
- };
280
- }
42
+ async logDataAccess(action, actorId, resourceType, resourceId, result, changes) {
43
+ await this.log({
44
+ type: `data.${action}`,
45
+ severity: action === "delete" ? "high" : "medium",
46
+ actor: {
47
+ id: actorId,
48
+ type: "user"
49
+ },
50
+ resource: {
51
+ type: resourceType,
52
+ id: resourceId
53
+ },
54
+ action,
55
+ result,
56
+ changes
57
+ });
281
58
  }
282
59
  /**
283
- * Check rate limit using leaky bucket algorithm
60
+ * Log permission change
284
61
  */
285
- checkLeakyBucket(key, capacity = 10, leakRate = 1, leakTime = 100) {
286
- try {
287
- const now = Date.now();
288
- const bucketKey = `rate_limit:leaky_bucket:${key}`;
289
- const current = this.inMemoryStore.get(bucketKey);
290
- let currentLevel = 0;
291
- let lastLeak = now;
292
- if (current) {
293
- currentLevel = current.count;
294
- lastLeak = current.lastRequestTime;
295
- }
296
- const timePassed = now - lastLeak;
297
- const leakAmount = Math.floor(timePassed / leakTime) * leakRate;
298
- currentLevel = Math.max(0, currentLevel - leakAmount);
299
- if (currentLevel < capacity) {
300
- currentLevel++;
301
- this.inMemoryStore.set(bucketKey, {
302
- count: currentLevel,
303
- resetTime: now + leakTime,
304
- lastRequestTime: now
305
- });
306
- devLogger.debug("Rate limit check", {
307
- key,
308
- algorithm: "leaky_bucket",
309
- allowed: true,
310
- remaining: capacity - currentLevel,
311
- resetTime: now + leakTime
312
- });
313
- return {
314
- allowed: true,
315
- remaining: capacity - currentLevel,
316
- resetTime: now + leakTime
317
- };
62
+ async logPermissionChange(action, actorId, targetUserId, permission, result) {
63
+ await this.log({
64
+ type: `permission.${action}`,
65
+ severity: "high",
66
+ actor: {
67
+ id: actorId,
68
+ type: "user"
69
+ },
70
+ resource: {
71
+ type: "user",
72
+ id: targetUserId
73
+ },
74
+ action,
75
+ result,
76
+ metadata: {
77
+ permission
318
78
  }
319
- const resetTime = lastLeak + leakTime;
320
- devLogger.warn("Rate limit blocked", {
321
- key,
322
- algorithm: "leaky_bucket",
323
- remaining: 0,
324
- resetTime
325
- });
326
- return {
327
- allowed: false,
328
- remaining: 0,
329
- resetTime,
330
- retryAfter: Math.ceil((resetTime - now) / 1e3)
331
- };
332
- } catch (error) {
333
- devLogger.error("Rate limiter error", error instanceof Error ? error : void 0, {
334
- key,
335
- algorithm: "leaky_bucket",
336
- error: error instanceof Error ? error.message : "Unknown error"
337
- });
338
- return {
339
- allowed: true,
340
- remaining: capacity,
341
- resetTime: Date.now() + leakTime
342
- };
343
- }
79
+ });
344
80
  }
345
81
  /**
346
- * Reset rate limit for a key
82
+ * Log security event
347
83
  */
348
- resetRateLimit(key) {
349
- const patterns = [
350
- `rate_limit:token_bucket:${key}`,
351
- `rate_limit:sliding_window:${key}`,
352
- `rate_limit:leaky_bucket:${key}`
353
- ];
354
- for (const pattern of patterns) {
355
- this.inMemoryStore.delete(pattern);
356
- }
357
- devLogger.debug("Rate limit reset", { key });
84
+ async logSecurityEvent(type, severity, actorId, message, metadata) {
85
+ await this.log({
86
+ type: `security.${type}`,
87
+ severity,
88
+ actor: {
89
+ id: actorId,
90
+ type: "user"
91
+ },
92
+ action: type,
93
+ result: "failure",
94
+ message,
95
+ metadata
96
+ });
358
97
  }
359
98
  /**
360
- * Get current rate limit state
99
+ * Log GDPR event
361
100
  */
362
- getRateLimitState(key) {
363
- const patterns = [
364
- `rate_limit:token_bucket:${key}`,
365
- `rate_limit:sliding_window:${key}`,
366
- `rate_limit:leaky_bucket:${key}`
367
- ];
368
- for (const pattern of patterns) {
369
- const state = this.inMemoryStore.get(pattern);
370
- if (state) {
371
- return state;
372
- }
373
- }
374
- return null;
101
+ async logGDPREvent(type, actorId, result, metadata) {
102
+ await this.log({
103
+ type: `gdpr.${type}`,
104
+ severity: "high",
105
+ actor: {
106
+ id: actorId,
107
+ type: "user"
108
+ },
109
+ action: type,
110
+ result,
111
+ metadata
112
+ });
375
113
  }
376
114
  /**
377
- * Update rate limit state
115
+ * Query audit logs
378
116
  */
379
- updateRateLimitState(key, state) {
380
- this.inMemoryStore.set(key, state);
117
+ async query(query) {
118
+ return this.storage.query(query);
381
119
  }
382
120
  /**
383
- * Get rate limiter statistics
121
+ * Count audit logs
384
122
  */
385
- getStats() {
386
- return {
387
- totalKeys: this.inMemoryStore.size,
388
- memoryUsage: this.inMemoryStore.size
389
- };
123
+ async count(query) {
124
+ return this.storage.count(query);
390
125
  }
391
126
  /**
392
- * Clean up expired entries
127
+ * Add filter
393
128
  */
394
- cleanup() {
395
- const now = Date.now();
396
- const maxAge = 24 * 60 * 60 * 1e3;
397
- for (const [key, state] of this.inMemoryStore.entries()) {
398
- if (now - state.lastRequestTime > maxAge) {
399
- this.inMemoryStore.delete(key);
400
- }
401
- }
402
- devLogger.debug("Cleaned up expired rate limit entries", {
403
- remaining: this.inMemoryStore.size
404
- });
129
+ addFilter(filter) {
130
+ this.filters.push(filter);
405
131
  }
406
132
  /**
407
- * Start cleanup interval
133
+ * Remove filter
408
134
  */
409
- startCleanupInterval() {
410
- if (this.cleanupInterval) {
411
- clearInterval(this.cleanupInterval);
135
+ removeFilter(filter) {
136
+ const index = this.filters.indexOf(filter);
137
+ if (index > -1) {
138
+ this.filters.splice(index, 1);
412
139
  }
413
- this.cleanupInterval = setInterval(
414
- () => {
415
- this.cleanup();
416
- },
417
- 60 * 60 * 1e3
418
- );
140
+ }
141
+ };
142
+ var InMemoryAuditStorage = class {
143
+ events = [];
144
+ maxEvents;
145
+ constructor(maxEvents = 1e4) {
146
+ this.maxEvents = maxEvents;
147
+ }
148
+ async write(event) {
149
+ this.events.push(event);
150
+ if (this.events.length > this.maxEvents) {
151
+ this.events.shift();
152
+ }
153
+ }
154
+ async query(query) {
155
+ let results = [...this.events];
156
+ if (query.types && query.types.length > 0) {
157
+ results = results.filter((e) => query.types?.includes(e.type));
158
+ }
159
+ if (query.actorId) {
160
+ results = results.filter((e) => e.actor.id === query.actorId);
161
+ }
162
+ if (query.resourceType) {
163
+ results = results.filter((e) => e.resource?.type === query.resourceType);
164
+ }
165
+ if (query.resourceId) {
166
+ results = results.filter((e) => e.resource?.id === query.resourceId);
167
+ }
168
+ if (query.startDate) {
169
+ const startDate = query.startDate;
170
+ results = results.filter((e) => new Date(e.timestamp) >= startDate);
171
+ }
172
+ if (query.endDate) {
173
+ const endDate = query.endDate;
174
+ results = results.filter((e) => new Date(e.timestamp) <= endDate);
175
+ }
176
+ if (query.severity && query.severity.length > 0) {
177
+ results = results.filter((e) => query.severity?.includes(e.severity));
178
+ }
179
+ if (query.result && query.result.length > 0) {
180
+ results = results.filter((e) => query.result?.includes(e.result));
181
+ }
182
+ results.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
183
+ const offset = query.offset || 0;
184
+ const limit = query.limit || 100;
185
+ return results.slice(offset, offset + limit);
186
+ }
187
+ async count(query) {
188
+ const results = await this.query({ ...query, limit: void 0, offset: void 0 });
189
+ return results.length;
419
190
  }
420
191
  /**
421
- * Stop cleanup interval
192
+ * Clear all events
422
193
  */
423
- stopCleanupInterval() {
424
- if (this.cleanupInterval) {
425
- clearInterval(this.cleanupInterval);
426
- this.cleanupInterval = null;
427
- }
194
+ clear() {
195
+ this.events = [];
428
196
  }
429
197
  /**
430
- * Dispose of the service
198
+ * Get all events
431
199
  */
432
- dispose() {
433
- this.stopCleanupInterval();
434
- this.inMemoryStore.clear();
200
+ getAll() {
201
+ return [...this.events];
435
202
  }
436
203
  };
437
- var getRateLimiterService = (config) => {
438
- return new RateLimiterService(config ?? {});
439
- };
440
-
441
- // src/RateLimitingService.ts
442
- import { headers } from "next/headers";
443
- var RATE_LIMITS2 = { default: { limit: 100, windowMs: 6e4 } };
444
- var generateRateLimitKey2 = (id) => `rate:${id}`;
445
- var generateIPRateLimitKey2 = (ip) => `rate:ip:${ip}`;
446
- async function checkRateLimit2(_key, _limit, _windowMs) {
447
- return { allowed: true, remaining: _limit, resetTime: Date.now() + _windowMs };
448
- }
449
- async function withRateLimit(action, config) {
450
- return async (...args) => {
451
- const headersList = await headers();
452
- const ip = headersList.get("x-forwarded-for") ?? headersList.get("x-real-ip") ?? "unknown";
453
- const key = config.customKey ?? (config.userId ? generateRateLimitKey2(config.userId) : generateIPRateLimitKey2(ip));
454
- const rateLimitResult = await checkRateLimit2(
455
- key,
456
- RATE_LIMITS2[config.type].limit,
457
- RATE_LIMITS2[config.type].windowMs
458
- );
459
- if (!rateLimitResult.allowed) {
460
- throw new Error(
461
- `Rate limit exceeded. Try again in ${Math.ceil((rateLimitResult.resetTime - Date.now()) / 1e3)} seconds.`
462
- );
463
- }
464
- return await action(...args);
465
- };
466
- }
467
- function RateLimited(type, userId) {
204
+ function AuditTrail(type, action, options) {
468
205
  return (_target, _propertyKey, descriptor) => {
469
206
  const originalMethod = descriptor.value;
470
207
  descriptor.value = async function(...args) {
471
- const headersList = await headers();
472
- const ip = headersList.get("x-forwarded-for") ?? headersList.get("x-real-ip") ?? "unknown";
473
- const key = userId ? generateRateLimitKey2(userId) : generateIPRateLimitKey2(ip);
474
- const rateLimitResult = await checkRateLimit2(
475
- key,
476
- RATE_LIMITS2[type].limit,
477
- RATE_LIMITS2[type].windowMs
478
- );
479
- if (!rateLimitResult.allowed) {
480
- throw new Error(
481
- `Rate limit exceeded. Try again in ${Math.ceil((rateLimitResult.resetTime - Date.now()) / 1e3)} seconds.`
482
- );
208
+ const actorId = this.user?.id || "system";
209
+ const before = options?.captureChanges ? args[0] : void 0;
210
+ let result = "success";
211
+ let error;
212
+ try {
213
+ const returnValue = await originalMethod.apply(this, args);
214
+ if (this.audit) {
215
+ await this.audit.log({
216
+ type,
217
+ severity: options?.severity || "medium",
218
+ actor: {
219
+ id: actorId,
220
+ type: "user"
221
+ },
222
+ resource: options?.resourceType ? {
223
+ type: options.resourceType,
224
+ id: args[0]?.id || "unknown"
225
+ } : void 0,
226
+ action,
227
+ result,
228
+ changes: options?.captureChanges ? {
229
+ before,
230
+ after: returnValue
231
+ } : void 0
232
+ });
233
+ }
234
+ return returnValue;
235
+ } catch (err) {
236
+ result = "failure";
237
+ error = err;
238
+ if (this.audit) {
239
+ await this.audit.log({
240
+ type,
241
+ severity: "high",
242
+ actor: {
243
+ id: actorId,
244
+ type: "user"
245
+ },
246
+ resource: options?.resourceType ? {
247
+ type: options.resourceType,
248
+ id: args[0]?.id || "unknown"
249
+ } : void 0,
250
+ action,
251
+ result,
252
+ message: error.message
253
+ });
254
+ }
255
+ throw error;
483
256
  }
484
- return await originalMethod.apply(this, args);
485
257
  };
486
258
  return descriptor;
487
259
  };
488
260
  }
489
- async function getClientIP() {
490
- const headersList = await headers();
491
- return headersList.get("x-forwarded-for") ?? headersList.get("x-real-ip") ?? "unknown";
492
- }
493
- async function isTrustedSource() {
494
- const headersList = await headers();
495
- const userAgent = headersList.get("user-agent") || "";
496
- const origin = headersList.get("origin") || "";
497
- const botPatterns = [/bot/i, /crawler/i, /spider/i, /scraper/i, /curl/i, /wget/i];
498
- const isBot = botPatterns.some((pattern) => pattern.test(userAgent));
499
- const trustedOrigins = [
500
- process.env.NEXT_PUBLIC_APP_URL,
501
- "http://localhost:3000",
502
- "https://localhost:3000"
503
- ].filter(Boolean);
504
- const isTrustedOrigin = trustedOrigins.includes(origin);
505
- return !isBot && isTrustedOrigin;
506
- }
507
- async function checkUserRateLimit(userId, action, customConfig) {
508
- const config = { ...RATE_LIMITS2[action], ...customConfig };
509
- const key = generateRateLimitKey2(userId);
510
- return await checkRateLimit2(key, config.limit, config.windowMs);
511
- }
512
- async function checkAnonymousRateLimit(action, customConfig) {
513
- const ip = await getClientIP();
514
- const config = { ...RATE_LIMITS2[action], ...customConfig };
515
- const key = generateIPRateLimitKey2(ip);
516
- return await checkRateLimit2(key, config.limit, config.windowMs);
517
- }
518
-
519
- // src/CSRFService.ts
520
- import { createHmac, randomBytes } from "crypto";
521
- var CSRFService = class {
522
- constructor(payload, options = {}) {
523
- this.payload = payload;
524
- this.options = {
525
- algorithm: options.algorithm ?? "sha256",
526
- encoding: options.encoding ?? "hex",
527
- tokenLength: options.tokenLength ?? 32,
528
- tokenExpiry: options.tokenExpiry ?? 24 * 60 * 60 * 1e3
529
- // 24 hours
530
- };
531
- }
532
- options;
533
- async generateCsrfToken(sessionId) {
261
+ function createAuditMiddleware(audit2, getUser) {
262
+ return async (request, next) => {
263
+ const user = getUser(request);
264
+ const startTime = Date.now();
534
265
  try {
535
- const token = randomBytes(this.options.tokenLength);
536
- const hmac = createHmac(this.options.algorithm, process.env.PAYLOAD_SECRET ?? "");
537
- hmac.update(sessionId);
538
- hmac.update(token);
539
- const signature = hmac.digest(this.options.encoding);
540
- const csrfToken = `${token.toString(this.options.encoding)}.${signature}`;
541
- this.payload.logger.debug("CSRF token generated successfully");
542
- return csrfToken;
266
+ const response = await next();
267
+ await audit2.log({
268
+ type: "data.read",
269
+ severity: "low",
270
+ actor: {
271
+ id: user.id,
272
+ type: "user",
273
+ ip: user.ip,
274
+ userAgent: user.userAgent
275
+ },
276
+ action: request.method,
277
+ result: "success",
278
+ metadata: {
279
+ path: request.url,
280
+ duration: Date.now() - startTime,
281
+ status: response.status
282
+ }
283
+ });
284
+ return response;
543
285
  } catch (error) {
544
- this.payload.logger.error("Failed to generate CSRF token", error);
286
+ await audit2.log({
287
+ type: "data.read",
288
+ severity: "medium",
289
+ actor: {
290
+ id: user.id,
291
+ type: "user",
292
+ ip: user.ip,
293
+ userAgent: user.userAgent
294
+ },
295
+ action: request.method,
296
+ result: "failure",
297
+ message: error instanceof Error ? error.message : "Unknown error",
298
+ metadata: {
299
+ path: request.url,
300
+ duration: Date.now() - startTime
301
+ }
302
+ });
545
303
  throw error;
546
304
  }
547
- }
548
- async validateCsrfToken(token, sessionId) {
549
- try {
550
- const [tokenPart, signature] = token.split(".");
551
- if (!tokenPart || !signature) {
552
- this.payload.logger.warn("Invalid CSRF token format");
553
- return false;
554
- }
555
- const hmac = createHmac(this.options.algorithm, process.env.PAYLOAD_SECRET ?? "");
556
- hmac.update(sessionId);
557
- hmac.update(Buffer.from(tokenPart, this.options.encoding));
558
- const expectedSignature = hmac.digest(this.options.encoding);
559
- const isValid = signature === expectedSignature;
560
- if (isValid) {
561
- this.payload.logger.debug("CSRF token validated successfully");
562
- } else {
563
- this.payload.logger.warn("CSRF token validation failed");
564
- }
565
- return isValid;
566
- } catch (error) {
567
- this.payload.logger.error("Failed to validate CSRF token", error);
568
- return false;
569
- }
570
- }
571
- };
572
-
573
- // src/EncryptionService.ts
574
- import { InfrastructureService } from "@revealui/core";
575
- import {
576
- createCipheriv,
577
- createDecipheriv,
578
- randomBytes as randomBytes2,
579
- scrypt as scryptCallback
580
- } from "crypto";
581
- import { promisify } from "util";
582
- var scryptAsync = promisify(scryptCallback);
583
- function isAuthenticatedCipher(cipher) {
584
- return typeof cipher.getAuthTag === "function";
585
- }
586
- function isAuthenticatedDecipher(decipher) {
587
- return typeof decipher.setAuthTag === "function";
305
+ };
588
306
  }
589
- var EncryptionService = class extends InfrastructureService {
590
- options;
591
- constructor(payload, options = {}) {
592
- super(payload, "EncryptionService");
593
- this.options = {
594
- algorithm: options.algorithm ?? "aes-256-gcm",
595
- keyLength: options.keyLength ?? 32,
596
- saltLength: options.saltLength ?? 16,
597
- ivLength: options.ivLength ?? 12,
598
- iterations: options.iterations ?? 1e5,
599
- encoding: options.encoding ?? "hex"
600
- };
307
+ var AuditReportGenerator = class {
308
+ constructor(audit2) {
309
+ this.audit = audit2;
601
310
  }
602
311
  /**
603
- * Encrypts data using the configured algorithm with comprehensive error handling.
312
+ * Generate security report
604
313
  */
605
- async encrypt(data, customOptions) {
606
- return this.executeInfrastructureOperation(async () => {
607
- if (typeof data !== "string" || data.length === 0) {
608
- throw new Error("Data to encrypt must be a non-empty string");
609
- }
610
- const effectiveOptions = { ...this.options, ...customOptions };
611
- this.logger.debug("Starting data encryption", {
612
- algorithm: effectiveOptions.algorithm,
613
- dataLength: data.length,
614
- serviceName: this.serviceName,
615
- operation: "encrypt"
616
- });
617
- const salt = randomBytes2(effectiveOptions.saltLength);
618
- const iv = randomBytes2(effectiveOptions.ivLength);
619
- const key = await this.deriveKey(salt, effectiveOptions);
620
- const cipher = createCipheriv(effectiveOptions.algorithm, key, iv);
621
- const encrypted = Buffer.concat([cipher.update(data, "utf8"), cipher.final()]);
622
- if (isAuthenticatedCipher(cipher) !== true) {
623
- throw new Error("Cipher does not support authentication");
624
- }
625
- const authTag = cipher.getAuthTag();
626
- const result = {
627
- data: encrypted.toString(effectiveOptions.encoding),
628
- metadata: {
629
- algorithm: effectiveOptions.algorithm,
630
- iv: iv.toString(effectiveOptions.encoding),
631
- authTag: authTag.toString(effectiveOptions.encoding),
632
- salt: salt.toString(effectiveOptions.encoding)
633
- }
634
- };
635
- this.logger.debug("Data encrypted successfully", {
636
- algorithm: effectiveOptions.algorithm,
637
- originalLength: data.length,
638
- encryptedLength: result.data.length,
639
- serviceName: this.serviceName
640
- });
641
- return result;
642
- }, "encrypt");
314
+ async generateSecurityReport(startDate, endDate) {
315
+ const allEvents = await this.audit.query({
316
+ startDate,
317
+ endDate
318
+ });
319
+ const securityViolations = allEvents.filter((e) => e.type.startsWith("security.")).length;
320
+ const failedLogins = allEvents.filter((e) => e.type === "auth.failed_login").length;
321
+ const permissionChanges = allEvents.filter((e) => e.type.startsWith("permission.")).length;
322
+ const dataExports = allEvents.filter((e) => e.type === "data.export").length;
323
+ const criticalEvents = allEvents.filter((e) => e.severity === "critical");
324
+ return {
325
+ totalEvents: allEvents.length,
326
+ securityViolations,
327
+ failedLogins,
328
+ permissionChanges,
329
+ dataExports,
330
+ criticalEvents
331
+ };
643
332
  }
644
333
  /**
645
- * Decrypts data using the metadata provided with comprehensive validation.
334
+ * Generate user activity report
646
335
  */
647
- async decrypt(encryptedData) {
648
- return this.executeInfrastructureOperation(async () => {
649
- if (!encryptedData || !encryptedData.data || !encryptedData.metadata) {
650
- throw new Error("Invalid encrypted data structure");
651
- }
652
- const { data, metadata } = encryptedData;
653
- const requiredFields = ["algorithm", "iv", "authTag", "salt"];
654
- for (const field of requiredFields) {
655
- const fieldValue = metadata[field];
656
- if (fieldValue === void 0 || fieldValue === null || fieldValue === "") {
657
- throw new Error(`Missing required encryption metadata field: ${field}`);
658
- }
659
- }
660
- this.logger.debug("Starting data decryption", {
661
- algorithm: metadata.algorithm,
662
- encryptedLength: data.length,
663
- serviceName: this.serviceName,
664
- operation: "decrypt"
665
- });
666
- const key = await this.deriveKey(Buffer.from(metadata.salt, this.options.encoding), {
667
- ...this.options,
668
- algorithm: metadata.algorithm
669
- });
670
- const decipher = createDecipheriv(
671
- metadata.algorithm,
672
- key,
673
- Buffer.from(metadata.iv, this.options.encoding)
674
- );
675
- if (isAuthenticatedDecipher(decipher) !== true) {
676
- throw new Error("Decipher does not support authentication");
677
- }
678
- decipher.setAuthTag(Buffer.from(metadata.authTag, this.options.encoding));
679
- const decrypted = Buffer.concat([
680
- decipher.update(Buffer.from(data, this.options.encoding)),
681
- decipher.final()
682
- ]);
683
- const result = decrypted.toString("utf8");
684
- this.logger.debug("Data decrypted successfully", {
685
- algorithm: metadata.algorithm,
686
- encryptedLength: data.length,
687
- decryptedLength: result.length,
688
- serviceName: this.serviceName
689
- });
690
- return result;
691
- }, "decrypt");
336
+ async generateUserActivityReport(userId, startDate, endDate) {
337
+ const events = await this.audit.query({
338
+ actorId: userId,
339
+ startDate,
340
+ endDate
341
+ });
342
+ const actionsByType = events.reduce(
343
+ (acc, event) => {
344
+ acc[event.type] = (acc[event.type] || 0) + 1;
345
+ return acc;
346
+ },
347
+ {}
348
+ );
349
+ const failedActions = events.filter((e) => e.result === "failure").length;
350
+ return {
351
+ totalActions: events.length,
352
+ actionsByType,
353
+ failedActions,
354
+ recentActions: events.slice(0, 10)
355
+ };
692
356
  }
693
357
  /**
694
- * Encrypts multiple data items in batch with optimized processing.
358
+ * Generate compliance report
695
359
  */
696
- async encryptBatch(dataItems, customOptions) {
697
- return this.executeInfrastructureOperation(async () => {
698
- if (!Array.isArray(dataItems) || dataItems.length === 0) {
699
- throw new Error("Data items array must contain at least one item");
700
- }
701
- this.logger.info("Starting batch encryption", {
702
- itemCount: dataItems.length,
703
- serviceName: this.serviceName,
704
- operation: "encryptBatch"
705
- });
706
- const successful = [];
707
- const failed = [];
708
- const encryptionPromises = dataItems.map(async (data) => {
709
- try {
710
- const result = await this.encrypt(data, customOptions);
711
- if (result.success && result.data) {
712
- successful.push(result.data);
713
- } else {
714
- failed.push({
715
- data,
716
- error: result.error ?? "Unknown encryption error"
717
- });
718
- }
719
- } catch (error) {
720
- failed.push({
721
- data,
722
- error: error instanceof Error ? error.message : "Unknown encryption error"
723
- });
724
- }
725
- });
726
- await Promise.allSettled(encryptionPromises);
727
- this.logger.info("Batch encryption completed", {
728
- totalItems: dataItems.length,
729
- successful: successful.length,
730
- failed: failed.length,
731
- serviceName: this.serviceName
732
- });
733
- return { successful, failed };
734
- }, "encryptBatch");
360
+ async generateComplianceReport(startDate, endDate) {
361
+ const events = await this.audit.query({
362
+ startDate,
363
+ endDate
364
+ });
365
+ const dataAccesses = events.filter((e) => e.type === "data.read").length;
366
+ const dataModifications = events.filter(
367
+ (e) => e.type === "data.update" || e.type === "data.create"
368
+ ).length;
369
+ const dataDeletions = events.filter((e) => e.type === "data.delete").length;
370
+ const gdprRequests = events.filter((e) => e.type.startsWith("gdpr.")).length;
371
+ const auditTrailComplete = this.checkAuditTrailContinuity(events);
372
+ return {
373
+ dataAccesses,
374
+ dataModifications,
375
+ dataDeletions,
376
+ gdprRequests,
377
+ auditTrailComplete
378
+ };
735
379
  }
736
380
  /**
737
- * Generates cryptographically secure random data.
381
+ * Check audit trail continuity
738
382
  */
739
- async generateRandomData(length = 32, encoding = "hex") {
740
- return this.executeInfrastructureOperation(async () => {
741
- if (length <= 0 || length > 1024) {
742
- throw new Error("Random data length must be between 1 and 1024 bytes");
743
- }
744
- this.logger.debug("Generating random data", {
745
- length,
746
- encoding,
747
- serviceName: this.serviceName,
748
- operation: "generateRandomData"
749
- });
750
- const randomData = randomBytes2(length);
751
- const result = randomData.toString(encoding);
752
- this.logger.debug("Random data generated successfully", {
753
- length,
754
- encoding,
755
- outputLength: result.length,
756
- serviceName: this.serviceName
757
- });
758
- return result;
759
- }, "generateRandomData");
383
+ checkAuditTrailContinuity(events) {
384
+ if (events.length === 0) return true;
385
+ const sorted = events.sort(
386
+ (a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
387
+ );
388
+ return sorted.length > 0;
760
389
  }
761
- /**
762
- * Validates the integrity of encrypted data by attempting decryption.
763
- */
764
- async validateEncryptedData(encryptedData) {
765
- return this.executeInfrastructureOperation(async () => {
766
- if (!encryptedData) {
767
- throw new Error("Encrypted data is required");
768
- }
769
- this.logger.debug("Validating encrypted data integrity", {
770
- algorithm: encryptedData.metadata.algorithm,
771
- serviceName: this.serviceName,
772
- operation: "validateEncryptedData"
773
- });
774
- try {
775
- const decryptResult = await this.decrypt(encryptedData);
776
- const valid = decryptResult.success && !!decryptResult.data;
777
- this.logger.debug("Encrypted data validation completed", {
778
- valid,
779
- serviceName: this.serviceName
780
- });
781
- return valid ? { valid, error: void 0 } : {
782
- valid,
783
- error: decryptResult.error ?? "Decryption failed"
784
- };
785
- } catch (error) {
786
- const errorMessage = error instanceof Error ? error.message : "Unknown validation error";
787
- this.logger.debug("Encrypted data validation failed", {
788
- error: errorMessage,
789
- serviceName: this.serviceName
790
- });
791
- return { valid: false, error: errorMessage };
792
- }
793
- }, "validateEncryptedData");
390
+ };
391
+ var audit = new AuditSystem(new InMemoryAuditStorage());
392
+
393
+ // src/auth.ts
394
+ import { createHmac, timingSafeEqual } from "crypto";
395
+ var OAuthProviders = {
396
+ google: {
397
+ authorizationUrl: "https://accounts.google.com/o/oauth2/v2/auth",
398
+ tokenUrl: "https://oauth2.googleapis.com/token",
399
+ userInfoUrl: "https://www.googleapis.com/oauth2/v2/userinfo",
400
+ scope: ["openid", "email", "profile"]
401
+ },
402
+ github: {
403
+ authorizationUrl: "https://github.com/login/oauth/authorize",
404
+ tokenUrl: "https://github.com/login/oauth/access_token",
405
+ userInfoUrl: "https://api.github.com/user",
406
+ scope: ["user:email"]
407
+ },
408
+ microsoft: {
409
+ authorizationUrl: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
410
+ tokenUrl: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
411
+ userInfoUrl: "https://graph.microsoft.com/v1.0/me",
412
+ scope: ["openid", "email", "profile"]
794
413
  }
795
- /**
796
- * Derives encryption key from password and salt using PBKDF2.
797
- * @private
798
- */
799
- async deriveKey(salt, options = {}) {
800
- const effectiveOptions = { ...this.options, ...options };
801
- const secret = process.env.PAYLOAD_SECRET;
802
- if (!secret || secret === "") {
803
- throw new Error("PAYLOAD_SECRET environment variable is required for encryption");
804
- }
805
- return scryptAsync(secret, salt, effectiveOptions.keyLength);
414
+ };
415
+ var OAuthClient = class {
416
+ config;
417
+ constructor(config) {
418
+ this.config = {
419
+ ...OAuthProviders[config.provider],
420
+ ...config
421
+ };
806
422
  }
807
423
  /**
808
- * @inheritdoc
424
+ * Get authorization URL
809
425
  */
810
- async onInitialize() {
811
- this.logger.info("Initializing EncryptionService", {
812
- algorithm: this.options.algorithm,
813
- keyLength: this.options.keyLength,
814
- serviceName: this.serviceName
426
+ getAuthorizationUrl(state) {
427
+ const params = new URLSearchParams({
428
+ client_id: this.config.clientId,
429
+ redirect_uri: this.config.redirectUri,
430
+ response_type: "code",
431
+ scope: (this.config.scope || []).join(" ")
815
432
  });
816
- if (!process.env.PAYLOAD_SECRET) {
817
- throw new Error("PAYLOAD_SECRET environment variable is required for EncryptionService");
818
- }
819
- try {
820
- const testData = "encryption-test-data";
821
- const encrypted = await this.encrypt(testData);
822
- if (!encrypted.success || !encrypted.data) {
823
- throw new Error("Encryption test failed");
824
- }
825
- const decrypted = await this.decrypt(encrypted.data);
826
- if (!decrypted.success || decrypted.data !== testData) {
827
- throw new Error("Decryption test failed");
828
- }
829
- this.logger.debug("EncryptionService initialization test passed", {
830
- serviceName: this.serviceName
831
- });
832
- } catch (error) {
833
- throw new Error(
834
- `EncryptionService initialization failed: ${error instanceof Error ? error.message : "Unknown error"}`
835
- );
433
+ if (state) {
434
+ params.append("state", state);
836
435
  }
436
+ return `${this.config.authorizationUrl}?${params.toString()}`;
837
437
  }
838
438
  /**
839
- * @inheritdoc
439
+ * Exchange code for token
840
440
  */
841
- async onCleanup() {
842
- this.logger.info("Cleaning up EncryptionService", {
843
- serviceName: this.serviceName
441
+ async exchangeCodeForToken(code) {
442
+ if (!this.config.tokenUrl) throw new Error("tokenUrl is required for OAuth");
443
+ const response = await fetch(this.config.tokenUrl, {
444
+ method: "POST",
445
+ headers: {
446
+ "Content-Type": "application/x-www-form-urlencoded"
447
+ },
448
+ body: new URLSearchParams({
449
+ client_id: this.config.clientId,
450
+ client_secret: this.config.clientSecret,
451
+ code,
452
+ grant_type: "authorization_code",
453
+ redirect_uri: this.config.redirectUri
454
+ })
844
455
  });
456
+ if (!response.ok) {
457
+ let detail = "";
458
+ try {
459
+ const body = await response.text();
460
+ detail = `: ${response.status} ${body.slice(0, 200)}`;
461
+ } catch {
462
+ detail = `: ${response.status}`;
463
+ }
464
+ throw new Error(`Failed to exchange code for token${detail}`);
465
+ }
466
+ return response.json();
845
467
  }
846
468
  /**
847
- * @inheritdoc
469
+ * Get user info
848
470
  */
849
- async onHealthCheck() {
850
- try {
851
- const testData = "health-check-data";
852
- const encrypted = await this.encrypt(testData);
853
- if (!encrypted.success || !encrypted.data) {
854
- throw new Error("Health check encryption failed");
471
+ async getUserInfo(accessToken) {
472
+ if (!this.config.userInfoUrl) throw new Error("userInfoUrl is required for OAuth");
473
+ const response = await fetch(this.config.userInfoUrl, {
474
+ headers: {
475
+ // biome-ignore lint/style/useNamingConvention: HTTP header convention
476
+ Authorization: `Bearer ${accessToken}`
855
477
  }
856
- const decrypted = await this.decrypt(encrypted.data);
857
- if (!decrypted.success || decrypted.data !== testData) {
858
- throw new Error("Health check decryption failed");
478
+ });
479
+ if (!response.ok) {
480
+ let detail = "";
481
+ try {
482
+ const body = await response.text();
483
+ detail = `: ${response.status} ${body.slice(0, 200)}`;
484
+ } catch {
485
+ detail = `: ${response.status}`;
859
486
  }
860
- } catch (error) {
861
- throw new Error(
862
- `EncryptionService health check failed: ${error instanceof Error ? error.message : "Unknown error"}`
863
- );
487
+ throw new Error(`Failed to fetch user info${detail}`);
864
488
  }
489
+ return response.json();
865
490
  }
866
491
  };
867
-
868
- // src/SecurityMonitoringService.ts
869
- var devLogger2 = {
870
- info: (...args) => console.log("[security]", ...args),
871
- warn: (...args) => console.warn("[security]", ...args),
872
- error: (...args) => console.error("[security]", ...args)
873
- };
874
- var createSecurityEvent = (type, severity, message, options) => {
875
- const baseEvent = {
876
- id: crypto.randomUUID(),
877
- type,
878
- severity,
879
- message,
880
- timestamp: /* @__PURE__ */ new Date(),
881
- ...options?.metadata ? { metadata: options.metadata } : {},
882
- ...options?.userId !== void 0 ? { userId: options.userId } : {},
883
- ...options?.ipAddress !== void 0 ? { ipAddress: options.ipAddress } : {},
884
- ...options?.userAgent !== void 0 ? { userAgent: options.userAgent } : {}
885
- };
886
- return baseEvent;
887
- };
888
- var calculateSecurityMetrics = (events2) => {
889
- if (events2.length === 0) {
890
- return {
891
- totalEvents: 0,
892
- eventsByType: {},
893
- eventsBySeverity: {},
894
- averageResponseTime: 0
895
- };
896
- }
897
- const eventsByType = events2.reduce((acc, event) => {
898
- acc[event.type] = (acc[event.type] || 0) + 1;
899
- return acc;
900
- }, {});
901
- const eventsBySeverity = events2.reduce((acc, event) => {
902
- acc[event.severity] = (acc[event.severity] || 0) + 1;
903
- return acc;
904
- }, {});
905
- const lastEventTime = events2.length > 0 ? new Date(Math.max(...events2.map((e) => e.timestamp.getTime()))) : void 0;
906
- return {
907
- totalEvents: events2.length,
908
- eventsByType,
909
- eventsBySeverity,
910
- averageResponseTime: 0,
911
- // Would be calculated from actual response times
912
- ...lastEventTime !== void 0 ? { lastEventTime } : {}
913
- };
914
- };
915
- var shouldTriggerAlert = (event, thresholds) => {
916
- const now = /* @__PURE__ */ new Date();
917
- const timeWindowStart = new Date(now.getTime() - thresholds.timeWindowMs);
918
- const recentEvents = events.filter(
919
- (event2) => event2.timestamp >= timeWindowStart && event2.timestamp <= now
920
- );
921
- const criticalCount = recentEvents.filter((e) => e.severity === "critical").length;
922
- const highCount = recentEvents.filter((e) => e.severity === "high").length;
923
- const mediumCount = recentEvents.filter((e) => e.severity === "medium").length;
924
- if (criticalCount >= thresholds.criticalCount) return true;
925
- if (highCount >= thresholds.highCount) return true;
926
- if (mediumCount >= thresholds.mediumCount) return true;
927
- if (event.severity === "critical") return true;
928
- return false;
929
- };
930
- var createSecurityAlert = (event, alertType = "threshold_exceeded") => ({
931
- id: crypto.randomUUID(),
932
- type: alertType,
933
- severity: event.severity,
934
- message: `Security alert: ${event.message}`,
935
- timestamp: /* @__PURE__ */ new Date(),
936
- metadata: {
937
- originalEventId: event.id,
938
- originalEventType: event.type,
939
- ...event.metadata
940
- }
941
- });
942
- var filterEvents = (events2, criteria) => {
943
- return events2.filter((event) => {
944
- if (criteria.type && event.type !== criteria.type) return false;
945
- if (criteria.severity && event.severity !== criteria.severity) return false;
946
- if (criteria.userId && event.userId !== criteria.userId) return false;
947
- if (criteria.timeRange) {
948
- const eventTime = event.timestamp.getTime();
949
- const startTime = criteria.timeRange.start.getTime();
950
- const endTime = criteria.timeRange.end.getTime();
951
- if (eventTime < startTime || eventTime > endTime) return false;
952
- }
953
- return true;
954
- });
955
- };
956
- var events = [];
957
- var alerts = [];
958
- var addSecurityEvent = (event) => {
959
- events.push(event);
960
- devLogger2.info("Security event recorded", {
961
- eventId: event.id,
962
- type: event.type,
963
- severity: event.severity,
964
- message: event.message,
965
- userId: event.userId,
966
- timestamp: event.timestamp.toISOString()
492
+ var PH_ITERATIONS = 1e5;
493
+ var PH_KEY_LENGTH = 64;
494
+ var PH_DIGEST = "sha512";
495
+ async function hashPassword(password) {
496
+ const { pbkdf2, randomBytes: rb } = await import("crypto");
497
+ const salt = rb(16).toString("hex");
498
+ return new Promise((resolve, reject) => {
499
+ pbkdf2(password, salt, PH_ITERATIONS, PH_KEY_LENGTH, PH_DIGEST, (err, derivedKey) => {
500
+ if (err) reject(err);
501
+ else resolve(`${salt}:${derivedKey.toString("hex")}`);
502
+ });
967
503
  });
968
- if (shouldTriggerAlert(event, {
969
- criticalCount: 1,
970
- highCount: 5,
971
- mediumCount: 10,
972
- timeWindowMs: 6e4
973
- // 1 minute
974
- })) {
975
- const alert = createSecurityAlert(event);
976
- alerts.push(alert);
977
- devLogger2.warn("Security alert triggered", {
978
- alertId: alert.id,
979
- eventId: event.id,
980
- severity: alert.severity,
981
- message: alert.message
504
+ }
505
+ async function verifyPassword(password, storedHash) {
506
+ const { pbkdf2, timingSafeEqual: tse } = await import("crypto");
507
+ const [salt, hash] = storedHash.split(":");
508
+ if (!(salt && hash)) {
509
+ return false;
510
+ }
511
+ return new Promise((resolve, reject) => {
512
+ pbkdf2(password, salt, PH_ITERATIONS, PH_KEY_LENGTH, PH_DIGEST, (err, derivedKey) => {
513
+ if (err) reject(err);
514
+ else {
515
+ const derived = Buffer.from(derivedKey.toString("hex"), "utf-8");
516
+ const expected = Buffer.from(hash, "utf-8");
517
+ if (derived.length !== expected.length) {
518
+ resolve(false);
519
+ } else {
520
+ resolve(tse(derived, expected));
521
+ }
522
+ }
982
523
  });
983
- }
524
+ });
525
+ }
526
+ var PasswordHasher = {
527
+ hash: hashPassword,
528
+ verify: verifyPassword
984
529
  };
985
- var getSecurityEvents = () => [...events];
986
- var getSecurityAlerts = () => [...alerts];
987
- var getSecurityMetrics = () => calculateSecurityMetrics(events);
988
- var clearSecurityData = () => {
989
- events = [];
990
- alerts = [];
530
+ function base32Encode(buffer) {
531
+ const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
532
+ let result = "";
533
+ let bits = 0;
534
+ let value = 0;
535
+ for (const byte of buffer) {
536
+ if (byte === void 0) continue;
537
+ value = value << 8 | byte;
538
+ bits += 8;
539
+ while (bits >= 5) {
540
+ result += alphabet[value >>> bits - 5 & 31];
541
+ bits -= 5;
542
+ }
543
+ }
544
+ if (bits > 0) {
545
+ result += alphabet[value << 5 - bits & 31];
546
+ }
547
+ return result;
548
+ }
549
+ function totpHmac(key, message) {
550
+ const hmacDigest = createHmac("sha1", key).update(message).digest();
551
+ return new Uint8Array(hmacDigest);
552
+ }
553
+ function generateSecret() {
554
+ const crypto2 = globalThis.crypto;
555
+ if (!crypto2) {
556
+ throw new Error("Crypto API not available");
557
+ }
558
+ const buffer = new Uint8Array(20);
559
+ crypto2.getRandomValues(buffer);
560
+ return base32Encode(buffer);
561
+ }
562
+ function generateCode(secret, timestamp) {
563
+ const time = Math.floor((timestamp || Date.now()) / 3e4);
564
+ const hmacDigest = totpHmac(secret, time.toString());
565
+ const offset = hmacDigest[hmacDigest.length - 1] & 15;
566
+ const b0 = hmacDigest[offset] & 127;
567
+ const b1 = hmacDigest[offset + 1] & 255;
568
+ const b2 = hmacDigest[offset + 2] & 255;
569
+ const b3 = hmacDigest[offset + 3] & 255;
570
+ const code = (b0 << 24 | b1 << 16 | b2 << 8 | b3) % 1e6;
571
+ return code.toString().padStart(6, "0");
572
+ }
573
+ function verifyCode(secret, code, window = 1) {
574
+ const timestamp = Date.now();
575
+ for (let i = -window; i <= window; i++) {
576
+ const testTime = timestamp + i * 3e4;
577
+ const testCode = generateCode(secret, testTime);
578
+ if (testCode.length === code.length && timingSafeEqual(Buffer.from(testCode), Buffer.from(code))) {
579
+ return true;
580
+ }
581
+ }
582
+ return false;
583
+ }
584
+ var TwoFactorAuth = {
585
+ generateSecret,
586
+ generateCode,
587
+ verifyCode
991
588
  };
992
- var logAuthenticationEvent = (userId, success, options) => {
993
- const eventOptions = {
994
- userId,
995
- ...options?.ipAddress !== void 0 ? { ipAddress: options.ipAddress } : {},
996
- ...options?.userAgent !== void 0 ? { userAgent: options.userAgent } : {},
997
- metadata: {
998
- success,
999
- ...options?.metadata
589
+
590
+ // src/authorization.ts
591
+ var AuthorizationSystem = class {
592
+ roles = /* @__PURE__ */ new Map();
593
+ policies = /* @__PURE__ */ new Map();
594
+ /**
595
+ * Register role
596
+ */
597
+ registerRole(role) {
598
+ this.roles.set(role.id, role);
599
+ }
600
+ /**
601
+ * Get role
602
+ */
603
+ getRole(roleId) {
604
+ return this.roles.get(roleId);
605
+ }
606
+ /**
607
+ * Register policy
608
+ */
609
+ registerPolicy(policy) {
610
+ this.policies.set(policy.id, policy);
611
+ }
612
+ /**
613
+ * Check if user has permission (RBAC)
614
+ */
615
+ hasPermission(userRoles, resource, action) {
616
+ const permissions = this.getUserPermissions(userRoles);
617
+ return permissions.some(
618
+ (permission) => this.matchesResource(permission.resource, resource) && this.matchesAction(permission.action, action)
619
+ );
620
+ }
621
+ /**
622
+ * Check access with policies (ABAC)
623
+ */
624
+ checkAccess(context, resource, action) {
625
+ if (this.hasPermission(context.user.roles, resource, action)) {
626
+ return { allowed: true };
1000
627
  }
1001
- };
1002
- const event = createSecurityEvent(
1003
- "authentication",
1004
- success ? "low" : "high",
1005
- `Authentication ${success ? "successful" : "failed"} for user ${userId}`,
1006
- eventOptions
1007
- );
1008
- addSecurityEvent(event);
628
+ const applicablePolicies = this.getApplicablePolicies(resource, action, context);
629
+ applicablePolicies.sort((a, b) => (b.priority || 0) - (a.priority || 0));
630
+ for (const policy of applicablePolicies) {
631
+ if (this.evaluateConditions(policy.conditions || [], context)) {
632
+ return {
633
+ allowed: policy.effect === "allow",
634
+ reason: policy.effect === "deny" ? `Denied by policy: ${policy.name}` : void 0
635
+ };
636
+ }
637
+ }
638
+ return { allowed: false, reason: "No matching policy" };
639
+ }
640
+ /**
641
+ * Get all permissions for roles
642
+ */
643
+ getUserPermissions(roleIds) {
644
+ const permissions = [];
645
+ const visited = /* @__PURE__ */ new Set();
646
+ const addRolePermissions = (roleId) => {
647
+ if (visited.has(roleId)) return;
648
+ visited.add(roleId);
649
+ const role = this.roles.get(roleId);
650
+ if (!role) return;
651
+ permissions.push(...role.permissions);
652
+ if (role.inherits) {
653
+ role.inherits.forEach((inheritedRoleId) => {
654
+ addRolePermissions(inheritedRoleId);
655
+ });
656
+ }
657
+ };
658
+ roleIds.forEach(addRolePermissions);
659
+ return permissions;
660
+ }
661
+ /**
662
+ * Get applicable policies
663
+ */
664
+ getApplicablePolicies(resource, action, _context) {
665
+ return Array.from(this.policies.values()).filter((policy) => {
666
+ const resourceMatches = policy.resources.some((r) => this.matchesResource(r, resource));
667
+ const actionMatches = policy.actions.some((a) => this.matchesAction(a, action));
668
+ return resourceMatches && actionMatches;
669
+ });
670
+ }
671
+ /**
672
+ * Match resource pattern
673
+ */
674
+ matchesResource(pattern, resource) {
675
+ if (pattern === "*") return true;
676
+ if (pattern === resource) return true;
677
+ const regex = new RegExp(
678
+ `^${pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".")}$`
679
+ );
680
+ return regex.test(resource);
681
+ }
682
+ /**
683
+ * Match action pattern
684
+ */
685
+ matchesAction(pattern, action) {
686
+ if (pattern === "*") return true;
687
+ if (pattern === action) return true;
688
+ const regex = new RegExp(
689
+ `^${pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".")}$`
690
+ );
691
+ return regex.test(action);
692
+ }
693
+ /**
694
+ * Evaluate policy conditions
695
+ */
696
+ evaluateConditions(conditions, context) {
697
+ return conditions.every((condition) => {
698
+ const value = this.getContextValue(condition.field, context);
699
+ return this.evaluateCondition(condition, value);
700
+ });
701
+ }
702
+ /**
703
+ * Get value from context
704
+ */
705
+ getContextValue(field, context) {
706
+ const parts = field.split(".");
707
+ let value = context;
708
+ for (const part of parts) {
709
+ if (value && typeof value === "object" && part in value) {
710
+ value = value[part];
711
+ } else {
712
+ return void 0;
713
+ }
714
+ }
715
+ return value;
716
+ }
717
+ /**
718
+ * Evaluate single condition
719
+ */
720
+ evaluateCondition(condition, value) {
721
+ switch (condition.operator) {
722
+ case "eq":
723
+ return value === condition.value;
724
+ case "ne":
725
+ return value !== condition.value;
726
+ case "gt":
727
+ return typeof value === "number" && value > condition.value;
728
+ case "gte":
729
+ return typeof value === "number" && value >= condition.value;
730
+ case "lt":
731
+ return typeof value === "number" && value < condition.value;
732
+ case "lte":
733
+ return typeof value === "number" && value <= condition.value;
734
+ case "in":
735
+ return Array.isArray(condition.value) && condition.value.includes(value);
736
+ case "contains":
737
+ return typeof value === "string" && typeof condition.value === "string" && value.includes(condition.value);
738
+ default:
739
+ return false;
740
+ }
741
+ }
742
+ /**
743
+ * Check if user owns resource
744
+ */
745
+ ownsResource(userId, resource) {
746
+ return resource.owner === userId;
747
+ }
748
+ /**
749
+ * Clear all roles and policies
750
+ */
751
+ clear() {
752
+ this.roles.clear();
753
+ this.policies.clear();
754
+ }
1009
755
  };
1010
- var logAuthorizationEvent = (userId, resource, action, granted, options) => {
1011
- const eventOptions = {
1012
- userId,
1013
- ...options?.ipAddress !== void 0 ? { ipAddress: options.ipAddress } : {},
1014
- ...options?.userAgent !== void 0 ? { userAgent: options.userAgent } : {},
1015
- metadata: {
1016
- resource,
1017
- action,
1018
- granted,
1019
- ...options?.metadata
756
+ var authorization = new AuthorizationSystem();
757
+ var CommonRoles = {
758
+ owner: {
759
+ id: "owner",
760
+ name: "Owner",
761
+ description: "Full control \u2014 inherits admin",
762
+ permissions: [{ resource: "*", action: "*" }],
763
+ inherits: ["admin"]
764
+ },
765
+ admin: {
766
+ id: "admin",
767
+ name: "Administrator",
768
+ description: "Full system access",
769
+ permissions: [{ resource: "*", action: "*" }]
770
+ },
771
+ editor: {
772
+ id: "editor",
773
+ name: "Editor",
774
+ description: "Can read and modify content",
775
+ permissions: [
776
+ { resource: "content", action: "read" },
777
+ { resource: "content", action: "create" },
778
+ { resource: "content", action: "update" },
779
+ { resource: "profile", action: "read" },
780
+ { resource: "profile", action: "update" },
781
+ { resource: "sites", action: "read" },
782
+ { resource: "marketplace", action: "read" }
783
+ ]
784
+ },
785
+ viewer: {
786
+ id: "viewer",
787
+ name: "Viewer",
788
+ description: "Read-only access",
789
+ permissions: [
790
+ { resource: "content", action: "read" },
791
+ { resource: "profile", action: "read" },
792
+ { resource: "sites", action: "read" },
793
+ { resource: "public", action: "read" }
794
+ ]
795
+ },
796
+ agent: {
797
+ id: "agent",
798
+ name: "AI Agent",
799
+ description: "Can execute tasks and read content",
800
+ permissions: [
801
+ { resource: "tasks", action: "create" },
802
+ { resource: "tasks", action: "read" },
803
+ { resource: "content", action: "read" },
804
+ { resource: "rag", action: "read" },
805
+ { resource: "rag", action: "create" }
806
+ ]
807
+ },
808
+ contributor: {
809
+ id: "contributor",
810
+ name: "Contributor",
811
+ description: "Can suggest changes \u2014 create drafts but not publish or delete",
812
+ permissions: [
813
+ { resource: "content", action: "read" },
814
+ { resource: "content", action: "create" },
815
+ { resource: "profile", action: "read" },
816
+ { resource: "profile", action: "update" }
817
+ ]
818
+ }
819
+ };
820
+ var PermissionBuilder = class {
821
+ permission = {};
822
+ resource(resource) {
823
+ this.permission.resource = resource;
824
+ return this;
825
+ }
826
+ action(action) {
827
+ this.permission.action = action;
828
+ return this;
829
+ }
830
+ conditions(conditions) {
831
+ this.permission.conditions = conditions;
832
+ return this;
833
+ }
834
+ build() {
835
+ if (!(this.permission.resource && this.permission.action)) {
836
+ throw new Error("Resource and action are required");
1020
837
  }
838
+ return this.permission;
839
+ }
840
+ };
841
+ var PolicyBuilder = class {
842
+ policy = {
843
+ effect: "allow",
844
+ resources: [],
845
+ actions: [],
846
+ conditions: []
1021
847
  };
1022
- const event = createSecurityEvent(
1023
- "authorization",
1024
- granted ? "low" : "medium",
1025
- `Authorization ${granted ? "granted" : "denied"} for user ${userId} on ${resource}:${action}`,
1026
- eventOptions
1027
- );
1028
- addSecurityEvent(event);
848
+ id(id) {
849
+ this.policy.id = id;
850
+ return this;
851
+ }
852
+ name(name) {
853
+ this.policy.name = name;
854
+ return this;
855
+ }
856
+ allow() {
857
+ this.policy.effect = "allow";
858
+ return this;
859
+ }
860
+ deny() {
861
+ this.policy.effect = "deny";
862
+ return this;
863
+ }
864
+ resources(...resources) {
865
+ this.policy.resources = resources;
866
+ return this;
867
+ }
868
+ actions(...actions) {
869
+ this.policy.actions = actions;
870
+ return this;
871
+ }
872
+ condition(field, operator, value) {
873
+ if (!this.policy.conditions) {
874
+ this.policy.conditions = [];
875
+ }
876
+ this.policy.conditions.push({ field, operator, value });
877
+ return this;
878
+ }
879
+ priority(priority) {
880
+ this.policy.priority = priority;
881
+ return this;
882
+ }
883
+ build() {
884
+ if (!(this.policy.id && this.policy.name)) {
885
+ throw new Error("ID and name are required");
886
+ }
887
+ return this.policy;
888
+ }
1029
889
  };
1030
- var logDataAccessEvent = (userId, collection, operation, recordId, options) => {
1031
- const eventOptions = {
1032
- userId,
1033
- ...options?.ipAddress !== void 0 ? { ipAddress: options.ipAddress } : {},
1034
- ...options?.userAgent !== void 0 ? { userAgent: options.userAgent } : {},
1035
- metadata: {
1036
- collection,
1037
- operation,
1038
- recordId,
1039
- ...options?.metadata
890
+ function RequirePermission(resource, action) {
891
+ return (_target, _propertyKey, descriptor) => {
892
+ const originalMethod = descriptor.value;
893
+ descriptor.value = function(...args) {
894
+ const userRoles = this.user?.roles || [];
895
+ if (!authorization.hasPermission(userRoles, resource, action)) {
896
+ throw new Error(`Permission denied: ${resource}:${action}`);
897
+ }
898
+ return originalMethod.apply(this, args);
899
+ };
900
+ return descriptor;
901
+ };
902
+ }
903
+ function RequireRole(requiredRole) {
904
+ return (_target, _propertyKey, descriptor) => {
905
+ const originalMethod = descriptor.value;
906
+ descriptor.value = function(...args) {
907
+ const userRoles = this.user?.roles || [];
908
+ if (!userRoles.includes(requiredRole)) {
909
+ throw new Error(`Role required: ${requiredRole}`);
910
+ }
911
+ return originalMethod.apply(this, args);
912
+ };
913
+ return descriptor;
914
+ };
915
+ }
916
+ function createAuthorizationMiddleware(getUser, resource, action) {
917
+ return (request, next) => {
918
+ const user = getUser(request);
919
+ if (!authorization.hasPermission(user.roles, resource, action)) {
920
+ throw new Error(`Permission denied: ${resource}:${action}`);
1040
921
  }
922
+ return next();
1041
923
  };
1042
- const event = createSecurityEvent(
1043
- "data_access",
1044
- operation === "delete" ? "medium" : "low",
1045
- `Data access: ${operation} on ${collection}${recordId ? ` (${recordId})` : ""} by user ${userId}`,
1046
- eventOptions
1047
- );
1048
- addSecurityEvent(event);
1049
- };
1050
- var getUserEvents = (userId) => filterEvents(events, { userId });
1051
- var getEventsBySeverity = (severity) => filterEvents(events, { severity });
1052
- var getEventsInTimeRange = (start, end) => filterEvents(events, { timeRange: { start, end } });
1053
- var SecurityMonitoringService = {
1054
- // Event management
1055
- addEvent: addSecurityEvent,
1056
- getEvents: getSecurityEvents,
1057
- getUserEvents,
1058
- getEventsBySeverity,
1059
- getEventsInTimeRange,
1060
- // Alert management
1061
- getAlerts: getSecurityAlerts,
1062
- // Metrics
1063
- getMetrics: getSecurityMetrics,
1064
- // Utility functions
1065
- logAuthenticationEvent,
1066
- logAuthorizationEvent,
1067
- logDataAccessEvent,
1068
- // Testing utilities
1069
- clearData: clearSecurityData,
1070
- // Pure functions for composition
1071
- createEvent: createSecurityEvent,
1072
- createAlert: createSecurityAlert,
1073
- filterEvents,
1074
- calculateMetrics: calculateSecurityMetrics
924
+ }
925
+ function canAccessResource(userId, userRoles, resource, action) {
926
+ if (authorization.hasPermission(userRoles, resource.type, action)) {
927
+ return true;
928
+ }
929
+ if (authorization.ownsResource(userId, resource)) {
930
+ return true;
931
+ }
932
+ return false;
933
+ }
934
+ function checkAttributeAccess(context, resource, action, requiredAttributes) {
935
+ const { allowed } = authorization.checkAccess(context, resource, action);
936
+ if (!allowed) {
937
+ return false;
938
+ }
939
+ if (requiredAttributes) {
940
+ const userAttributes = context.user.attributes || {};
941
+ return Object.entries(requiredAttributes).every(
942
+ ([key, value]) => userAttributes[key] === value
943
+ );
944
+ }
945
+ return true;
946
+ }
947
+ var PermissionCache = class {
948
+ cache = /* @__PURE__ */ new Map();
949
+ ttl;
950
+ maxEntries;
951
+ constructor(ttl = 3e5, maxEntries = 1e4) {
952
+ this.ttl = ttl;
953
+ this.maxEntries = maxEntries;
954
+ }
955
+ /**
956
+ * Get cached permission
957
+ */
958
+ get(userId, resource, action) {
959
+ const key = this.getCacheKey(userId, resource, action);
960
+ const cached = this.cache.get(key);
961
+ if (!cached) {
962
+ return void 0;
963
+ }
964
+ if (Date.now() > cached.expiresAt) {
965
+ this.cache.delete(key);
966
+ return void 0;
967
+ }
968
+ return cached.allowed;
969
+ }
970
+ /**
971
+ * Set cached permission
972
+ */
973
+ set(userId, resource, action, allowed) {
974
+ const key = this.getCacheKey(userId, resource, action);
975
+ if (this.cache.size >= this.maxEntries) {
976
+ const now = Date.now();
977
+ for (const [k, v] of this.cache) {
978
+ if (now > v.expiresAt) this.cache.delete(k);
979
+ }
980
+ if (this.cache.size >= this.maxEntries) {
981
+ const excess = this.cache.size - this.maxEntries + 1;
982
+ const keys = this.cache.keys();
983
+ for (let i = 0; i < excess; i++) {
984
+ const next = keys.next();
985
+ if (!next.done) this.cache.delete(next.value);
986
+ }
987
+ }
988
+ }
989
+ this.cache.set(key, {
990
+ allowed,
991
+ expiresAt: Date.now() + this.ttl
992
+ });
993
+ }
994
+ /**
995
+ * Clear cache for user
996
+ */
997
+ clearUser(userId) {
998
+ for (const key of this.cache.keys()) {
999
+ if (key.startsWith(`${userId}:`)) {
1000
+ this.cache.delete(key);
1001
+ }
1002
+ }
1003
+ }
1004
+ /**
1005
+ * Clear all cache
1006
+ */
1007
+ clear() {
1008
+ this.cache.clear();
1009
+ }
1010
+ /**
1011
+ * Get cache key
1012
+ */
1013
+ getCacheKey(userId, resource, action) {
1014
+ return `${userId}:${resource}:${action}`;
1015
+ }
1075
1016
  };
1017
+ var permissionCache = new PermissionCache();
1076
1018
 
1077
- // src/SecurityService.ts
1078
- import { NextResponse } from "next/server";
1079
- import { createHmac as createHmac2 } from "crypto";
1080
- async function getPayloadClient() {
1081
- return { logger: console };
1019
+ // src/encryption.ts
1020
+ var DEFAULT_CONFIG = {
1021
+ algorithm: "AES-GCM",
1022
+ keySize: 256,
1023
+ ivSize: 12
1024
+ };
1025
+ var EncryptionSystem = class {
1026
+ config;
1027
+ keys = /* @__PURE__ */ new Map();
1028
+ constructor(config = {}) {
1029
+ this.config = { ...DEFAULT_CONFIG, ...config };
1030
+ }
1031
+ /**
1032
+ * Generate encryption key
1033
+ */
1034
+ async generateKey(keyId) {
1035
+ const crypto2 = globalThis.crypto;
1036
+ if (!crypto2) {
1037
+ throw new Error("Crypto API not available");
1038
+ }
1039
+ const key = await crypto2.subtle.generateKey(
1040
+ {
1041
+ name: this.config.algorithm,
1042
+ length: this.config.keySize
1043
+ },
1044
+ this.config.extractable ?? false,
1045
+ // non-extractable by default — prevents key exfiltration
1046
+ ["encrypt", "decrypt"]
1047
+ );
1048
+ if (keyId) {
1049
+ this.keys.set(keyId, key);
1050
+ }
1051
+ return key;
1052
+ }
1053
+ /**
1054
+ * Import key from raw data
1055
+ */
1056
+ async importKey(keyData, keyId) {
1057
+ const crypto2 = globalThis.crypto;
1058
+ if (!crypto2) {
1059
+ throw new Error("Crypto API not available");
1060
+ }
1061
+ const key = await crypto2.subtle.importKey(
1062
+ "raw",
1063
+ keyData,
1064
+ {
1065
+ name: this.config.algorithm,
1066
+ length: this.config.keySize
1067
+ },
1068
+ true,
1069
+ ["encrypt", "decrypt"]
1070
+ );
1071
+ if (keyId) {
1072
+ this.keys.set(keyId, key);
1073
+ }
1074
+ return key;
1075
+ }
1076
+ /**
1077
+ * Export key to raw data
1078
+ */
1079
+ async exportKey(key) {
1080
+ const crypto2 = globalThis.crypto;
1081
+ if (!crypto2) {
1082
+ throw new Error("Crypto API not available");
1083
+ }
1084
+ return crypto2.subtle.exportKey("raw", key);
1085
+ }
1086
+ /**
1087
+ * Encrypt data
1088
+ */
1089
+ async encrypt(data, keyOrId) {
1090
+ const crypto2 = globalThis.crypto;
1091
+ if (!crypto2) {
1092
+ throw new Error("Crypto API not available");
1093
+ }
1094
+ const key = typeof keyOrId === "string" ? this.keys.get(keyOrId) : keyOrId;
1095
+ if (!key) {
1096
+ throw new Error("Key not found");
1097
+ }
1098
+ const iv = crypto2.getRandomValues(new Uint8Array(this.config.ivSize || 12));
1099
+ const encoder = new TextEncoder();
1100
+ const encodedData = encoder.encode(data);
1101
+ const encrypted = await crypto2.subtle.encrypt(
1102
+ {
1103
+ name: this.config.algorithm,
1104
+ iv
1105
+ },
1106
+ key,
1107
+ encodedData
1108
+ );
1109
+ const encryptedArray = new Uint8Array(encrypted);
1110
+ const ivArray = new Uint8Array(iv);
1111
+ return {
1112
+ data: this.arrayBufferToBase64(encryptedArray),
1113
+ iv: this.arrayBufferToBase64(ivArray),
1114
+ algorithm: this.config.algorithm
1115
+ };
1116
+ }
1117
+ /**
1118
+ * Decrypt data
1119
+ */
1120
+ async decrypt(encryptedData, keyOrId) {
1121
+ const crypto2 = globalThis.crypto;
1122
+ if (!crypto2) {
1123
+ throw new Error("Crypto API not available");
1124
+ }
1125
+ const key = typeof keyOrId === "string" ? this.keys.get(keyOrId) : keyOrId;
1126
+ if (!key) {
1127
+ throw new Error("Key not found");
1128
+ }
1129
+ const data = this.base64ToArrayBuffer(encryptedData.data);
1130
+ const iv = this.base64ToArrayBuffer(encryptedData.iv);
1131
+ const decrypted = await crypto2.subtle.decrypt(
1132
+ {
1133
+ name: encryptedData.algorithm,
1134
+ iv
1135
+ },
1136
+ key,
1137
+ data
1138
+ );
1139
+ const decoder = new TextDecoder();
1140
+ return decoder.decode(decrypted);
1141
+ }
1142
+ /**
1143
+ * Encrypt object
1144
+ */
1145
+ async encryptObject(obj, keyOrId) {
1146
+ const json = JSON.stringify(obj);
1147
+ return this.encrypt(json, keyOrId);
1148
+ }
1149
+ /**
1150
+ * Decrypt object
1151
+ */
1152
+ async decryptObject(encryptedData, keyOrId) {
1153
+ const json = await this.decrypt(encryptedData, keyOrId);
1154
+ return JSON.parse(json);
1155
+ }
1156
+ /**
1157
+ * Hash data
1158
+ */
1159
+ async hash(data, algorithm = "SHA-256") {
1160
+ const crypto2 = globalThis.crypto;
1161
+ if (!crypto2) {
1162
+ throw new Error("Crypto API not available");
1163
+ }
1164
+ const encoder = new TextEncoder();
1165
+ const encodedData = encoder.encode(data);
1166
+ const hashBuffer = await crypto2.subtle.digest(algorithm, encodedData);
1167
+ return this.arrayBufferToBase64(new Uint8Array(hashBuffer));
1168
+ }
1169
+ /**
1170
+ * Generate random bytes
1171
+ */
1172
+ randomBytes(length) {
1173
+ const crypto2 = globalThis.crypto;
1174
+ if (!crypto2) {
1175
+ throw new Error("Crypto API not available");
1176
+ }
1177
+ return crypto2.getRandomValues(new Uint8Array(length));
1178
+ }
1179
+ /**
1180
+ * Generate random string
1181
+ */
1182
+ randomString(length, charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") {
1183
+ const maxValid = 256 - 256 % charset.length;
1184
+ const result = [];
1185
+ while (result.length < length) {
1186
+ const bytes = this.randomBytes(length - result.length + 16);
1187
+ for (const byte of bytes) {
1188
+ if (byte < maxValid) {
1189
+ result.push(charset[byte % charset.length]);
1190
+ if (result.length === length) break;
1191
+ }
1192
+ }
1193
+ }
1194
+ return result.join("");
1195
+ }
1196
+ /**
1197
+ * Convert ArrayBuffer to base64
1198
+ */
1199
+ arrayBufferToBase64(buffer) {
1200
+ const bytes = Array.from(buffer);
1201
+ const binary = bytes.map((byte) => String.fromCharCode(byte)).join("");
1202
+ if (typeof btoa !== "undefined") {
1203
+ return btoa(binary);
1204
+ }
1205
+ if (typeof Buffer !== "undefined") {
1206
+ return Buffer.from(binary, "binary").toString("base64");
1207
+ }
1208
+ throw new Error("No base64 encoding available");
1209
+ }
1210
+ /**
1211
+ * Convert base64 to ArrayBuffer
1212
+ */
1213
+ base64ToArrayBuffer(base64) {
1214
+ let binary;
1215
+ if (typeof atob !== "undefined") {
1216
+ binary = atob(base64);
1217
+ } else if (typeof Buffer !== "undefined") {
1218
+ binary = Buffer.from(base64, "base64").toString("binary");
1219
+ } else {
1220
+ throw new Error("No base64 decoding available");
1221
+ }
1222
+ const bytes = new Uint8Array(binary.length);
1223
+ for (let i = 0; i < binary.length; i++) {
1224
+ bytes[i] = binary.charCodeAt(i);
1225
+ }
1226
+ return bytes;
1227
+ }
1228
+ /**
1229
+ * Store key
1230
+ */
1231
+ storeKey(keyId, key) {
1232
+ this.keys.set(keyId, key);
1233
+ }
1234
+ /**
1235
+ * Get key
1236
+ */
1237
+ getKey(keyId) {
1238
+ return this.keys.get(keyId);
1239
+ }
1240
+ /**
1241
+ * Remove key
1242
+ */
1243
+ removeKey(keyId) {
1244
+ this.keys.delete(keyId);
1245
+ }
1246
+ /**
1247
+ * Clear all keys
1248
+ */
1249
+ clearKeys() {
1250
+ this.keys.clear();
1251
+ }
1252
+ };
1253
+ var encryption = new EncryptionSystem();
1254
+ var FieldEncryption = class {
1255
+ encryption;
1256
+ key = null;
1257
+ constructor(encryption2) {
1258
+ this.encryption = encryption2;
1259
+ }
1260
+ /**
1261
+ * Initialize with key
1262
+ */
1263
+ async initialize(key) {
1264
+ this.key = key;
1265
+ }
1266
+ /**
1267
+ * Encrypt field
1268
+ */
1269
+ async encryptField(value) {
1270
+ if (!this.key) {
1271
+ throw new Error("Encryption not initialized");
1272
+ }
1273
+ const stringValue = typeof value === "string" ? value : JSON.stringify(value);
1274
+ return this.encryption.encrypt(stringValue, this.key);
1275
+ }
1276
+ /**
1277
+ * Decrypt field
1278
+ */
1279
+ async decryptField(encryptedData) {
1280
+ if (!this.key) {
1281
+ throw new Error("Encryption not initialized");
1282
+ }
1283
+ const decrypted = await this.encryption.decrypt(encryptedData, this.key);
1284
+ try {
1285
+ return JSON.parse(decrypted);
1286
+ } catch {
1287
+ return decrypted;
1288
+ }
1289
+ }
1290
+ /**
1291
+ * Encrypt object fields
1292
+ */
1293
+ async encryptFields(obj, fields) {
1294
+ const result = { ...obj };
1295
+ for (const field of fields) {
1296
+ if (field in result) {
1297
+ result[field] = await this.encryptField(result[field]);
1298
+ }
1299
+ }
1300
+ return result;
1301
+ }
1302
+ /**
1303
+ * Decrypt object fields
1304
+ */
1305
+ async decryptFields(obj, fields) {
1306
+ const result = { ...obj };
1307
+ for (const field of fields) {
1308
+ if (field in result && typeof result[field] === "object" && result[field] !== null) {
1309
+ const encryptedData = result[field];
1310
+ if ("data" in encryptedData && "iv" in encryptedData) {
1311
+ result[field] = await this.decryptField(encryptedData);
1312
+ }
1313
+ }
1314
+ }
1315
+ return result;
1316
+ }
1317
+ };
1318
+ var KeyRotationManager = class {
1319
+ encryption;
1320
+ currentKeyId;
1321
+ oldKeys = /* @__PURE__ */ new Map();
1322
+ keyCreationDates = /* @__PURE__ */ new Map();
1323
+ constructor(encryption2, initialKeyId) {
1324
+ this.encryption = encryption2;
1325
+ this.currentKeyId = initialKeyId;
1326
+ this.keyCreationDates.set(initialKeyId, /* @__PURE__ */ new Date());
1327
+ }
1328
+ /**
1329
+ * Rotate to new key
1330
+ */
1331
+ async rotate(newKeyId, newKey) {
1332
+ const oldKey = this.encryption.getKey(this.currentKeyId);
1333
+ if (oldKey) {
1334
+ this.oldKeys.set(this.currentKeyId, oldKey);
1335
+ }
1336
+ this.encryption.storeKey(newKeyId, newKey);
1337
+ this.currentKeyId = newKeyId;
1338
+ this.keyCreationDates.set(newKeyId, /* @__PURE__ */ new Date());
1339
+ }
1340
+ /**
1341
+ * Re-encrypt data with new key
1342
+ */
1343
+ async reencrypt(encryptedData, oldKeyId) {
1344
+ const oldKey = this.oldKeys.get(oldKeyId) || this.encryption.getKey(oldKeyId);
1345
+ const newKey = this.encryption.getKey(this.currentKeyId);
1346
+ if (!(oldKey && newKey)) {
1347
+ throw new Error("Keys not found");
1348
+ }
1349
+ const decrypted = await this.encryption.decrypt(encryptedData, oldKey);
1350
+ return this.encryption.encrypt(decrypted, newKey);
1351
+ }
1352
+ /**
1353
+ * Get current key ID
1354
+ */
1355
+ getCurrentKeyId() {
1356
+ return this.currentKeyId;
1357
+ }
1358
+ /**
1359
+ * Clean up old keys created before the specified date.
1360
+ * Never removes the current active key.
1361
+ */
1362
+ cleanupOldKeys(olderThan) {
1363
+ for (const [keyId, createdAt] of this.keyCreationDates.entries()) {
1364
+ if (keyId !== this.currentKeyId && createdAt < olderThan) {
1365
+ this.oldKeys.delete(keyId);
1366
+ this.encryption.removeKey(keyId);
1367
+ this.keyCreationDates.delete(keyId);
1368
+ }
1369
+ }
1370
+ }
1371
+ };
1372
+ var EnvelopeEncryption = class {
1373
+ encryption;
1374
+ masterKey;
1375
+ constructor(encryption2, masterKey) {
1376
+ this.encryption = encryption2;
1377
+ this.masterKey = masterKey;
1378
+ }
1379
+ /**
1380
+ * Encrypt with envelope encryption
1381
+ */
1382
+ async encrypt(data) {
1383
+ const dek = await this.encryption.generateKey();
1384
+ const encryptedData = await this.encryption.encrypt(data, dek);
1385
+ const dekRaw = await this.encryption.exportKey(dek);
1386
+ const dekBase64 = this.arrayBufferToBase64(new Uint8Array(dekRaw));
1387
+ const encryptedKey = await this.encryption.encrypt(dekBase64, this.masterKey);
1388
+ return { encryptedData, encryptedKey };
1389
+ }
1390
+ /**
1391
+ * Decrypt with envelope encryption
1392
+ */
1393
+ async decrypt(encryptedData, encryptedKey) {
1394
+ const dekBase64 = await this.encryption.decrypt(encryptedKey, this.masterKey);
1395
+ const dekRaw = this.base64ToArrayBuffer(dekBase64);
1396
+ const dek = await this.encryption.importKey(dekRaw.buffer);
1397
+ return this.encryption.decrypt(encryptedData, dek);
1398
+ }
1399
+ arrayBufferToBase64(buffer) {
1400
+ const bytes = Array.from(buffer);
1401
+ const binary = bytes.map((byte) => String.fromCharCode(byte)).join("");
1402
+ return typeof btoa !== "undefined" ? btoa(binary) : Buffer.from(binary, "binary").toString("base64");
1403
+ }
1404
+ base64ToArrayBuffer(base64) {
1405
+ const binary = typeof atob !== "undefined" ? atob(base64) : Buffer.from(base64, "base64").toString("binary");
1406
+ const bytes = new Uint8Array(binary.length);
1407
+ for (let i = 0; i < binary.length; i++) {
1408
+ bytes[i] = binary.charCodeAt(i);
1409
+ }
1410
+ return bytes;
1411
+ }
1412
+ };
1413
+ function maskEmail(email) {
1414
+ const [local, domain] = email.split("@");
1415
+ if (!(local && domain)) return email;
1416
+ const maskedLocal = local.length > 2 ? local[0] + "*".repeat(local.length - 2) + local[local.length - 1] : `${local[0]}*`;
1417
+ return `${maskedLocal}@${domain}`;
1418
+ }
1419
+ function maskPhone(phone) {
1420
+ const digits = phone.replace(/\D/g, "");
1421
+ if (digits.length < 4) return phone;
1422
+ const lastFour = digits.slice(-4);
1423
+ const masked = "*".repeat(digits.length - 4) + lastFour;
1424
+ return phone.replace(/\d/g, (char, index) => {
1425
+ const digitIndex = phone.slice(0, index + 1).replace(/\D/g, "").length - 1;
1426
+ return masked[digitIndex] || char;
1427
+ });
1082
1428
  }
1083
- var logger = {
1084
- info: (message, ...args) => console.log(`[SecurityService] ${message}`, ...args),
1085
- warn: (message, ...args) => console.warn(`[SecurityService] ${message}`, ...args),
1086
- error: (message, ...args) => console.error(`[SecurityService] ${message}`, ...args)
1429
+ function maskCreditCard(card) {
1430
+ const digits = card.replace(/\D/g, "");
1431
+ if (digits.length < 4) return card;
1432
+ const lastFour = digits.slice(-4);
1433
+ return `****-****-****-${lastFour}`;
1434
+ }
1435
+ function maskSSN(ssn) {
1436
+ const digits = ssn.replace(/\D/g, "");
1437
+ if (digits.length !== 9) return ssn;
1438
+ return `***-**-${digits.slice(-4)}`;
1439
+ }
1440
+ function maskString(str, keepChars = 1) {
1441
+ if (str.length <= keepChars * 2) {
1442
+ return "*".repeat(str.length);
1443
+ }
1444
+ const prefix = str.slice(0, keepChars);
1445
+ const suffix = str.slice(-keepChars);
1446
+ const masked = "*".repeat(str.length - keepChars * 2);
1447
+ return `${prefix}${masked}${suffix}`;
1448
+ }
1449
+ var DataMasking = {
1450
+ maskEmail,
1451
+ maskPhone,
1452
+ maskCreditCard,
1453
+ maskSSN,
1454
+ maskString
1087
1455
  };
1088
- async function securityMiddleware(req) {
1089
- const response = new NextResponse();
1090
- try {
1091
- const payload = await getPayloadClient();
1092
- payload.logger.info(`Security middleware started for ${req.method} ${req.url}`);
1093
- } catch {
1094
- logger.info(`Security middleware started for ${req.method} ${req.url}`);
1095
- }
1096
- response.headers.set("X-Content-Type-Options", "nosniff");
1097
- response.headers.set("X-Frame-Options", "DENY");
1098
- response.headers.set("X-XSS-Protection", "1; mode=block");
1099
- response.headers.set("Referrer-Policy", "strict-origin-when-cross-origin");
1100
- response.headers.set("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
1101
- const isApiRoute = req.nextUrl.pathname.startsWith("/api");
1102
- const csp = isApiRoute ? "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'" : "default-src 'self'";
1103
- response.headers.set("Content-Security-Policy", csp);
1104
- try {
1105
- const payload = await getPayloadClient();
1106
- payload.logger.info("Security middleware completed");
1107
- } catch {
1108
- logger.info("Security middleware completed");
1109
- }
1110
- return;
1456
+ function generateToken(length = 32) {
1457
+ const bytes = encryption.randomBytes(length);
1458
+ return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
1111
1459
  }
1112
- function createSecurity(config) {
1113
- return {
1114
- generateCsrfToken(sessionId) {
1115
- return createHmac2("sha256", config.csrfSecret).update(sessionId).digest("hex");
1116
- },
1117
- isTokenExpired(exp) {
1118
- return Date.now() / 1e3 > exp;
1119
- },
1120
- getAccessTokenExpiry() {
1121
- return config.tokenExpiry.access;
1122
- },
1123
- getRefreshTokenExpiry() {
1124
- return config.tokenExpiry.refresh;
1460
+ function generateUUID() {
1461
+ const crypto2 = globalThis.crypto;
1462
+ if (!crypto2) {
1463
+ throw new Error("Crypto API not available");
1464
+ }
1465
+ return crypto2.randomUUID();
1466
+ }
1467
+ function generateAPIKey(prefix = "sk") {
1468
+ const token = generateToken(32);
1469
+ return `${prefix}_${token}`;
1470
+ }
1471
+ function generateSessionID() {
1472
+ return generateToken(64);
1473
+ }
1474
+ var TokenGenerator = {
1475
+ generate: generateToken,
1476
+ generateUUID,
1477
+ generateAPIKey,
1478
+ generateSessionID
1479
+ };
1480
+
1481
+ // src/gdpr.ts
1482
+ import { createHash, createHmac as createHmac2 } from "crypto";
1483
+
1484
+ // src/gdpr-storage.ts
1485
+ var InMemoryBreachStorage = class {
1486
+ breaches = /* @__PURE__ */ new Map();
1487
+ async setBreach(breach) {
1488
+ this.breaches.set(breach.id, breach);
1489
+ }
1490
+ async getBreach(id) {
1491
+ return this.breaches.get(id);
1492
+ }
1493
+ async getAllBreaches() {
1494
+ return Array.from(this.breaches.values());
1495
+ }
1496
+ async updateBreach(id, updates) {
1497
+ const existing = this.breaches.get(id);
1498
+ if (existing) {
1499
+ this.breaches.set(id, { ...existing, ...updates });
1125
1500
  }
1126
- };
1501
+ }
1502
+ };
1503
+ var InMemoryGDPRStorage = class {
1504
+ consents = /* @__PURE__ */ new Map();
1505
+ deletionRequests = /* @__PURE__ */ new Map();
1506
+ // ── Consent Records ──────────────────────────────────────────────
1507
+ async setConsent(userId, type, record) {
1508
+ this.consents.set(`${userId}:${type}`, record);
1509
+ }
1510
+ async getConsent(userId, type) {
1511
+ return this.consents.get(`${userId}:${type}`);
1512
+ }
1513
+ async getConsentsByUser(userId) {
1514
+ return Array.from(this.consents.values()).filter((c) => c.userId === userId);
1515
+ }
1516
+ async getAllConsents() {
1517
+ return Array.from(this.consents.values());
1518
+ }
1519
+ // ── Deletion Requests ────────────────────────────────────────────
1520
+ async setDeletionRequest(request) {
1521
+ this.deletionRequests.set(request.id, request);
1522
+ }
1523
+ async getDeletionRequest(requestId) {
1524
+ return this.deletionRequests.get(requestId);
1525
+ }
1526
+ async getDeletionRequestsByUser(userId) {
1527
+ return Array.from(this.deletionRequests.values()).filter((r) => r.userId === userId);
1528
+ }
1529
+ };
1530
+
1531
+ // src/logger.ts
1532
+ var securityLogger = console;
1533
+ function configureSecurityLogger(logger) {
1534
+ securityLogger = logger;
1535
+ }
1536
+ function getSecurityLogger() {
1537
+ return securityLogger;
1127
1538
  }
1128
1539
 
1129
- // src/SessionService.ts
1130
- var logger2 = {
1131
- info: (message, ...args) => console.log(`[SessionService] ${message}`, ...args),
1132
- warn: (message, ...args) => console.warn(`[SessionService] ${message}`, ...args),
1133
- error: (message, ...args) => console.error(`[SessionService] ${message}`, ...args)
1540
+ // src/gdpr.ts
1541
+ var ConsentManager = class {
1542
+ storage;
1543
+ consentVersion = "1.0.0";
1544
+ constructor(storage) {
1545
+ this.storage = storage;
1546
+ }
1547
+ /**
1548
+ * Grant consent
1549
+ */
1550
+ async grantConsent(userId, type, source = "explicit", expiresIn) {
1551
+ const consent = {
1552
+ id: crypto.randomUUID(),
1553
+ userId,
1554
+ type,
1555
+ granted: true,
1556
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1557
+ expiresAt: expiresIn ? new Date(Date.now() + expiresIn).toISOString() : void 0,
1558
+ source,
1559
+ version: this.consentVersion
1560
+ };
1561
+ await this.storage.setConsent(userId, type, consent);
1562
+ return consent;
1563
+ }
1564
+ /**
1565
+ * Revoke consent
1566
+ */
1567
+ async revokeConsent(userId, type) {
1568
+ const existing = await this.storage.getConsent(userId, type);
1569
+ if (existing) {
1570
+ existing.granted = false;
1571
+ existing.timestamp = (/* @__PURE__ */ new Date()).toISOString();
1572
+ await this.storage.setConsent(userId, type, existing);
1573
+ }
1574
+ }
1575
+ /**
1576
+ * Check if consent is granted
1577
+ */
1578
+ async hasConsent(userId, type) {
1579
+ const consent = await this.storage.getConsent(userId, type);
1580
+ if (!consent?.granted) {
1581
+ return false;
1582
+ }
1583
+ if (consent.expiresAt && new Date(consent.expiresAt) < /* @__PURE__ */ new Date()) {
1584
+ return false;
1585
+ }
1586
+ return true;
1587
+ }
1588
+ /**
1589
+ * Get all consents for user
1590
+ */
1591
+ async getUserConsents(userId) {
1592
+ return this.storage.getConsentsByUser(userId);
1593
+ }
1594
+ /**
1595
+ * Update consent version
1596
+ */
1597
+ setConsentVersion(version) {
1598
+ this.consentVersion = version;
1599
+ }
1600
+ /**
1601
+ * Check if consent needs renewal
1602
+ */
1603
+ async needsRenewal(userId, type, maxAge) {
1604
+ const consent = await this.storage.getConsent(userId, type);
1605
+ if (!consent?.granted) {
1606
+ return true;
1607
+ }
1608
+ const age = Date.now() - new Date(consent.timestamp).getTime();
1609
+ return age >= maxAge;
1610
+ }
1611
+ /**
1612
+ * Get consent statistics
1613
+ */
1614
+ async getStatistics() {
1615
+ const consents = await this.storage.getAllConsents();
1616
+ const now = /* @__PURE__ */ new Date();
1617
+ const granted = consents.filter((c) => c.granted).length;
1618
+ const revoked = consents.filter((c) => !c.granted).length;
1619
+ const expired = consents.filter((c) => c.expiresAt && new Date(c.expiresAt) < now).length;
1620
+ const byType = consents.reduce(
1621
+ (acc, c) => {
1622
+ acc[c.type] = (acc[c.type] || 0) + 1;
1623
+ return acc;
1624
+ },
1625
+ {}
1626
+ );
1627
+ return {
1628
+ total: consents.length,
1629
+ granted,
1630
+ revoked,
1631
+ expired,
1632
+ byType
1633
+ };
1634
+ }
1134
1635
  };
1135
- var devLogger3 = {
1136
- info: (...args) => logger2.info(String(args[0]), ...args.slice(1)),
1137
- warn: (...args) => logger2.warn(String(args[0]), ...args.slice(1)),
1138
- error: (...args) => logger2.error(String(args[0]), ...args.slice(1)),
1139
- forService: (_name) => ({
1140
- info: (...args) => logger2.info(String(args[0]), ...args.slice(1)),
1141
- warn: (...args) => logger2.warn(String(args[0]), ...args.slice(1)),
1142
- error: (...args) => logger2.error(String(args[0]), ...args.slice(1))
1143
- })
1636
+ function escapeCsvField(value) {
1637
+ let safe = /^[=+\-@\t\r]/.test(value) ? `'${value}` : value;
1638
+ safe = safe.replace(/"/g, '""');
1639
+ return `"${safe}"`;
1640
+ }
1641
+ var DataExportSystem = class {
1642
+ /**
1643
+ * Export user data
1644
+ */
1645
+ async exportUserData(userId, getUserData, format = "json") {
1646
+ const data = await getUserData(userId);
1647
+ const exportData = {
1648
+ userId,
1649
+ exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
1650
+ data: {
1651
+ profile: data.profile,
1652
+ activities: data.activities,
1653
+ consents: data.consents,
1654
+ dataProcessing: []
1655
+ },
1656
+ format
1657
+ };
1658
+ return exportData;
1659
+ }
1660
+ /**
1661
+ * Format export as JSON
1662
+ */
1663
+ formatAsJSON(exportData) {
1664
+ return JSON.stringify(exportData, null, 2);
1665
+ }
1666
+ /**
1667
+ * Format export as CSV
1668
+ */
1669
+ formatAsCSV(exportData) {
1670
+ const lines = [];
1671
+ lines.push("Type,Key,Value");
1672
+ Object.entries(exportData.data.profile).forEach(([key, value]) => {
1673
+ lines.push(`Profile,${escapeCsvField(key)},${escapeCsvField(String(value))}`);
1674
+ });
1675
+ exportData.data.activities.forEach((activity, index) => {
1676
+ Object.entries(activity).forEach(([key, value]) => {
1677
+ lines.push(`Activity ${index + 1},${escapeCsvField(key)},${escapeCsvField(String(value))}`);
1678
+ });
1679
+ });
1680
+ return lines.join("\n");
1681
+ }
1682
+ /**
1683
+ * Create download link
1684
+ */
1685
+ createDownloadLink(content, _filename, mimeType) {
1686
+ const blob = new Blob([content], { type: mimeType });
1687
+ return URL.createObjectURL(blob);
1688
+ }
1144
1689
  };
1145
- async function getPayloadClient2() {
1146
- return {
1147
- logger: {
1148
- info: (...args) => logger2.info(String(args[0]), ...args.slice(1)),
1149
- warn: (...args) => logger2.warn(String(args[0]), ...args.slice(1)),
1150
- error: (...args) => logger2.error(String(args[0]), ...args.slice(1))
1690
+ var DataDeletionSystem = class {
1691
+ storage;
1692
+ constructor(storage) {
1693
+ this.storage = storage;
1694
+ }
1695
+ /**
1696
+ * Request data deletion
1697
+ */
1698
+ async requestDeletion(userId, dataCategories, reason) {
1699
+ const request = {
1700
+ id: crypto.randomUUID(),
1701
+ userId,
1702
+ requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
1703
+ status: "pending",
1704
+ dataCategories,
1705
+ reason
1706
+ };
1707
+ await this.storage.setDeletionRequest(request);
1708
+ return request;
1709
+ }
1710
+ /**
1711
+ * Process deletion request
1712
+ */
1713
+ async processDeletion(requestId, deleteData) {
1714
+ const request = await this.storage.getDeletionRequest(requestId);
1715
+ if (!request) {
1716
+ throw new Error("Deletion request not found");
1151
1717
  }
1718
+ request.status = "processing";
1719
+ await this.storage.setDeletionRequest(request);
1720
+ try {
1721
+ const result = await deleteData(request.userId, request.dataCategories);
1722
+ request.status = "completed";
1723
+ request.processedAt = (/* @__PURE__ */ new Date()).toISOString();
1724
+ request.deletedData = result.deleted;
1725
+ request.retainedData = result.retained;
1726
+ await this.storage.setDeletionRequest(request);
1727
+ } catch (error) {
1728
+ request.status = "failed";
1729
+ await this.storage.setDeletionRequest(request);
1730
+ throw error;
1731
+ }
1732
+ }
1733
+ /**
1734
+ * Get deletion request
1735
+ */
1736
+ async getRequest(requestId) {
1737
+ return this.storage.getDeletionRequest(requestId);
1738
+ }
1739
+ /**
1740
+ * Get user deletion requests
1741
+ */
1742
+ async getUserRequests(userId) {
1743
+ return this.storage.getDeletionRequestsByUser(userId);
1744
+ }
1745
+ /**
1746
+ * Check if data can be deleted
1747
+ */
1748
+ canDelete(_dataCategory, legalBasis) {
1749
+ if (legalBasis === "legal_obligation" || legalBasis === "vital_interest") {
1750
+ return false;
1751
+ }
1752
+ return true;
1753
+ }
1754
+ /**
1755
+ * Calculate retention period
1756
+ */
1757
+ calculateRetentionEnd(createdAt, retentionPeriod) {
1758
+ return new Date(createdAt.getTime() + retentionPeriod * 24 * 60 * 60 * 1e3);
1759
+ }
1760
+ /**
1761
+ * Check if data should be deleted (retention period expired)
1762
+ */
1763
+ shouldDelete(createdAt, retentionPeriod) {
1764
+ const retentionEnd = this.calculateRetentionEnd(createdAt, retentionPeriod);
1765
+ return /* @__PURE__ */ new Date() > retentionEnd;
1766
+ }
1767
+ };
1768
+ function hashValue(value) {
1769
+ const digest = createHash("sha256").update(value).digest("hex");
1770
+ return `hash_${digest}`;
1771
+ }
1772
+ function anonymizeUser(user) {
1773
+ return {
1774
+ ...user,
1775
+ email: hashValue(user.email),
1776
+ name: "Anonymous User",
1777
+ phone: void 0,
1778
+ address: void 0,
1779
+ ip: void 0
1152
1780
  };
1153
1781
  }
1154
- function generateUUID() {
1155
- if (typeof crypto !== "undefined" && crypto.randomUUID) {
1156
- return crypto.randomUUID();
1157
- }
1158
- return `xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`.replace(/[xy]/g, (c) => {
1159
- const r = Math.random() * 16 | 0;
1160
- const v = c === "x" ? r : r & 3 | 8;
1161
- return v.toString(16);
1782
+ function pseudonymize(value, key) {
1783
+ const hmac = createHmac2("sha256", key).update(value).digest("hex");
1784
+ return `pseudo_${hmac.substring(0, 16)}`;
1785
+ }
1786
+ function anonymizeDataset(data, sensitiveFields) {
1787
+ return data.map((item) => {
1788
+ const anonymized = { ...item };
1789
+ sensitiveFields.forEach((field) => {
1790
+ if (field in anonymized && typeof anonymized[field] === "string") {
1791
+ anonymized[field] = hashValue(anonymized[field]);
1792
+ }
1793
+ });
1794
+ return anonymized;
1795
+ });
1796
+ }
1797
+ function checkKAnonymity(data, quasiIdentifiers, k) {
1798
+ const groups = /* @__PURE__ */ new Map();
1799
+ data.forEach((item) => {
1800
+ const key = quasiIdentifiers.map((field) => String(item[field])).join("|");
1801
+ groups.set(key, (groups.get(key) || 0) + 1);
1162
1802
  });
1803
+ return Array.from(groups.values()).every((count) => count >= k);
1163
1804
  }
1164
- var SessionRepository = class {
1165
- constructor(payload) {
1166
- this.payload = payload;
1167
- void this.payload;
1805
+ var DataAnonymization = {
1806
+ anonymizeUser,
1807
+ pseudonymize,
1808
+ hashValue,
1809
+ anonymizeDataset,
1810
+ checkKAnonymity
1811
+ };
1812
+ var PrivacyPolicyManager = class {
1813
+ policies = /* @__PURE__ */ new Map();
1814
+ currentVersion = "1.0.0";
1815
+ /**
1816
+ * Add policy version
1817
+ */
1818
+ addPolicy(version, content, effectiveDate) {
1819
+ this.policies.set(version, { version, content, effectiveDate });
1820
+ this.currentVersion = version;
1168
1821
  }
1169
- sessions = /* @__PURE__ */ new Map();
1170
- createSessionId() {
1171
- try {
1172
- return generateUUID();
1173
- } catch {
1174
- return `session_${Date.now().toString(36)}`;
1175
- }
1822
+ /**
1823
+ * Get current policy
1824
+ */
1825
+ getCurrentPolicy() {
1826
+ return this.policies.get(this.currentVersion);
1176
1827
  }
1177
- createToken() {
1178
- try {
1179
- return `token_${generateUUID()}`;
1180
- } catch {
1181
- return `token_${Date.now().toString(36)}`;
1182
- }
1828
+ /**
1829
+ * Get policy by version
1830
+ */
1831
+ getPolicy(version) {
1832
+ return this.policies.get(version);
1183
1833
  }
1184
- async create(data) {
1185
- if (!data.userId) {
1186
- return {
1187
- success: false,
1188
- errors: [{ message: "userId is required", path: "create" }]
1189
- };
1190
- }
1191
- const now = /* @__PURE__ */ new Date();
1192
- const session = {
1193
- id: data.id ?? this.createSessionId(),
1194
- userId: data.userId,
1195
- token: data.token ?? this.createToken(),
1196
- expiresAt: data.expiresAt ? new Date(data.expiresAt) : new Date(now.getTime() + 1e3 * 60 * 60),
1197
- lastActiveAt: data.lastActiveAt ? new Date(data.lastActiveAt) : now,
1198
- isActive: data.isActive ?? true,
1199
- updatedAt: now,
1200
- createdAt: now,
1201
- ...data.device !== void 0 ? { device: data.device } : {}
1202
- };
1203
- this.sessions.set(session.id, session);
1204
- return { success: true, data: session };
1205
- }
1206
- async findById(id) {
1207
- const session = this.sessions.get(String(id));
1208
- if (!session) {
1209
- return {
1210
- success: false,
1211
- errors: [{ message: "Session not found", path: "findById" }]
1212
- };
1213
- }
1214
- return { success: true, data: session };
1215
- }
1216
- async delete(id) {
1217
- const key = String(id);
1218
- if (!this.sessions.has(key)) {
1219
- return {
1220
- success: false,
1221
- errors: [{ message: "Session not found", path: "delete" }]
1222
- };
1223
- }
1224
- this.sessions.delete(key);
1225
- return { success: true };
1226
- }
1227
- async revokeAllUserSessions(userId) {
1228
- let removed = false;
1229
- for (const [key, session] of this.sessions.entries()) {
1230
- if (session.userId === userId) {
1231
- this.sessions.delete(key);
1232
- removed = true;
1233
- }
1234
- }
1235
- if (!removed) {
1236
- return {
1237
- success: false,
1238
- errors: [{ message: "No sessions found for user", path: "revokeAllUserSessions" }]
1239
- };
1240
- }
1241
- return { success: true };
1242
- }
1243
- async findAll() {
1244
- return { success: true, data: Array.from(this.sessions.values()) };
1245
- }
1246
- async update(id, data) {
1247
- const existing = this.sessions.get(id);
1248
- if (!existing) {
1249
- return {
1250
- success: false,
1251
- errors: [{ message: "Session not found", path: "update" }]
1252
- };
1253
- }
1254
- const updated = {
1255
- ...existing,
1256
- ...data.userId !== void 0 ? { userId: data.userId } : {},
1257
- ...data.token !== void 0 ? { token: data.token } : {},
1258
- ...data.device !== void 0 ? { device: data.device } : {},
1259
- ...data.expiresAt !== void 0 ? { expiresAt: new Date(data.expiresAt) } : {},
1260
- ...data.lastActiveAt !== void 0 ? { lastActiveAt: new Date(data.lastActiveAt) } : {},
1261
- ...data.isActive !== void 0 ? { isActive: data.isActive } : {},
1262
- updatedAt: /* @__PURE__ */ new Date()
1263
- };
1264
- this.sessions.set(id, updated);
1265
- return { success: true, data: updated };
1834
+ /**
1835
+ * Check if user accepted current policy
1836
+ */
1837
+ hasAcceptedCurrent(userAcceptedVersion) {
1838
+ return userAcceptedVersion === this.currentVersion;
1839
+ }
1840
+ /**
1841
+ * Get all versions
1842
+ */
1843
+ getAllVersions() {
1844
+ return Array.from(this.policies.keys());
1266
1845
  }
1267
1846
  };
1268
- var SessionService = class {
1269
- repository = null;
1270
- constructor(repository) {
1271
- if (repository) {
1272
- this.repository = repository;
1273
- }
1847
+ var CookieConsentManager = class {
1848
+ config = {
1849
+ necessary: true,
1850
+ functional: false,
1851
+ analytics: false,
1852
+ marketing: false
1853
+ };
1854
+ /**
1855
+ * Set consent configuration
1856
+ */
1857
+ setConsent(config) {
1858
+ this.config = { ...this.config, ...config };
1859
+ this.saveToStorage();
1274
1860
  }
1275
- async getRepository() {
1276
- if (!this.repository) {
1277
- const payload = await getPayloadClient2();
1278
- this.repository = new SessionRepository(payload);
1279
- }
1280
- return this.repository;
1861
+ /**
1862
+ * Get consent configuration
1863
+ */
1864
+ getConsent() {
1865
+ return { ...this.config };
1281
1866
  }
1282
1867
  /**
1283
- * Creates a new session for a user.
1868
+ * Check if specific consent is granted
1284
1869
  */
1285
- async createSession(data) {
1286
- if (!data.userId || typeof data.userId !== "string") {
1287
- return {
1288
- success: false,
1289
- errors: [
1290
- {
1291
- message: "userId is required",
1292
- path: "userId"
1293
- }
1294
- ]
1295
- };
1296
- }
1297
- const repository = await this.getRepository();
1298
- const result = await repository.create(data);
1299
- if (!result.success) {
1300
- try {
1301
- const payload = await getPayloadClient2();
1302
- payload.logger.error("Failed to create session", {
1303
- errors: result.errors
1304
- });
1305
- } catch {
1306
- devLogger3.error("Failed to create session", { errors: result.errors });
1307
- }
1308
- }
1309
- return result;
1870
+ hasConsent(type) {
1871
+ return this.config[type];
1310
1872
  }
1311
1873
  /**
1312
- * Validates a session by ID, checks for expiration, and deletes if expired.
1874
+ * Save to storage
1313
1875
  */
1314
- async validateSession(sessionId) {
1315
- try {
1316
- const repository = await this.getRepository();
1317
- const result = await repository.findById(sessionId);
1318
- if (!result.success || !result.data) {
1319
- try {
1320
- const payload = await getPayloadClient2();
1321
- payload.logger.warn("Invalid session", { sessionId, errors: result.errors });
1322
- } catch {
1323
- devLogger3.warn("Invalid session", { sessionId, errors: result.errors });
1324
- }
1325
- return {
1326
- success: false,
1327
- errors: result.errors ?? [{ message: "Session not found", path: "validateSession" }]
1328
- };
1329
- }
1330
- const session = result.data;
1331
- if (session.expiresAt.getTime() < Date.now()) {
1332
- await repository.delete(sessionId);
1333
- try {
1334
- const payload = await getPayloadClient2();
1335
- payload.logger.info("Session expired and deleted", { sessionId });
1336
- } catch {
1337
- devLogger3.info("Session expired and deleted", { sessionId });
1338
- }
1339
- return {
1340
- success: false,
1341
- errors: [{ message: "Session expired", path: "validateSession" }]
1342
- };
1343
- }
1344
- const userResult = { success: true, data: { id: session.userId } };
1345
- if (!userResult.success || !userResult.data) {
1346
- try {
1347
- const payload = await getPayloadClient2();
1348
- payload.logger.error("User not found for session", {
1349
- sessionId,
1350
- userId: session.userId
1351
- });
1352
- } catch {
1353
- devLogger3.error("User not found for session", {
1354
- sessionId,
1355
- userId: session.userId
1356
- });
1357
- }
1358
- return {
1359
- success: false,
1360
- errors: [{ message: "User not found for session", path: "validateSession" }]
1361
- };
1362
- }
1363
- return { success: true, data: session };
1364
- } catch (error) {
1365
- try {
1366
- const payload = await getPayloadClient2();
1367
- payload.logger.error("Session validation failed", { error });
1368
- } catch {
1369
- devLogger3.error("Session validation failed", { error });
1370
- }
1371
- return {
1372
- success: false,
1373
- errors: [{ message: "Session validation failed", path: "validateSession" }]
1374
- };
1876
+ saveToStorage() {
1877
+ if (typeof localStorage !== "undefined") {
1878
+ localStorage.setItem("cookie-consent", JSON.stringify(this.config));
1375
1879
  }
1376
1880
  }
1377
1881
  /**
1378
- * Invalidates (deletes) a session by ID.
1882
+ * Load from storage
1379
1883
  */
1380
- async invalidateSession(sessionId) {
1381
- try {
1382
- const repository = await this.getRepository();
1383
- const result = await repository.delete(sessionId);
1384
- if (!result.success) {
1884
+ loadFromStorage() {
1885
+ if (typeof localStorage !== "undefined") {
1886
+ const stored = localStorage.getItem("cookie-consent");
1887
+ if (stored) {
1385
1888
  try {
1386
- const payload = await getPayloadClient2();
1387
- payload.logger.error("Session invalidation failed", {
1388
- errors: result.errors
1389
- });
1889
+ const parsed = JSON.parse(stored);
1890
+ if (typeof parsed === "object" && parsed !== null) {
1891
+ this.config = {
1892
+ necessary: true,
1893
+ // always required
1894
+ analytics: typeof parsed.analytics === "boolean" ? parsed.analytics : false,
1895
+ marketing: typeof parsed.marketing === "boolean" ? parsed.marketing : false,
1896
+ functional: typeof parsed.functional === "boolean" ? parsed.functional : true
1897
+ };
1898
+ }
1390
1899
  } catch {
1391
- devLogger3.error("Session invalidation failed", {
1392
- errors: result.errors
1393
- });
1394
1900
  }
1395
- return result;
1396
- }
1397
- return result;
1398
- } catch (error) {
1399
- try {
1400
- const payload = await getPayloadClient2();
1401
- payload.logger.error("Session invalidation failed", { error });
1402
- } catch {
1403
- devLogger3.error("Session invalidation failed", { error });
1404
1901
  }
1405
- return {
1406
- success: false,
1407
- errors: [
1408
- {
1409
- message: "Session invalidation failed",
1410
- path: "invalidateSession"
1411
- }
1412
- ]
1413
- };
1414
1902
  }
1415
1903
  }
1416
1904
  /**
1417
- * Invalidates (deletes) all sessions for a user by userId.
1905
+ * Clear consent
1418
1906
  */
1419
- async invalidateAllUserSessions(userId) {
1420
- try {
1421
- const repository = await this.getRepository();
1422
- const result = await repository.revokeAllUserSessions(userId);
1423
- if (!result.success) {
1424
- try {
1425
- const payload = await getPayloadClient2();
1426
- payload.logger.error("User sessions invalidation failed", {
1427
- errors: result.errors
1428
- });
1429
- } catch {
1430
- devLogger3.error("User sessions invalidation failed", {
1431
- errors: result.errors
1432
- });
1433
- }
1434
- return result;
1435
- }
1436
- return result;
1437
- } catch (error) {
1438
- try {
1439
- const payload = await getPayloadClient2();
1440
- payload.logger.error("User sessions invalidation failed", {
1441
- error
1442
- });
1443
- } catch {
1444
- devLogger3.error("User sessions invalidation failed", { error });
1445
- }
1446
- return {
1447
- success: false,
1448
- errors: [
1449
- {
1450
- message: "Failed to invalidate user sessions",
1451
- path: "invalidateAllUserSessions"
1452
- }
1453
- ]
1454
- };
1907
+ clearConsent() {
1908
+ this.config = {
1909
+ necessary: true,
1910
+ functional: false,
1911
+ analytics: false,
1912
+ marketing: false
1913
+ };
1914
+ if (typeof localStorage !== "undefined") {
1915
+ localStorage.removeItem("cookie-consent");
1455
1916
  }
1456
1917
  }
1457
- async getSessionById(id) {
1458
- const repository = await this.getRepository();
1459
- const result = await repository.findById(id);
1460
- if (!result.success) {
1461
- try {
1462
- const payload = await getPayloadClient2();
1463
- payload.logger.warn("Session not found", {
1464
- errors: result.errors
1465
- });
1466
- } catch {
1467
- devLogger3.warn("Session not found", { errors: result.errors });
1468
- }
1918
+ };
1919
+ var DataBreachManager = class {
1920
+ storage;
1921
+ constructor(storage) {
1922
+ if (storage) {
1923
+ this.storage = storage;
1924
+ } else {
1925
+ getSecurityLogger().warn(
1926
+ "DataBreachManager: using in-memory storage \u2014 breach records will be lost on restart. For production GDPR compliance, pass a database-backed BreachStorage."
1927
+ );
1928
+ this.storage = new InMemoryBreachStorage();
1469
1929
  }
1470
- return result;
1471
1930
  }
1472
- async getAllSessions() {
1473
- const repository = await this.getRepository();
1474
- const result = await repository.findAll();
1475
- if (!result.success) {
1476
- try {
1477
- const payload = await getPayloadClient2();
1478
- payload.logger.error("Failed to fetch sessions", {
1479
- errors: result.errors
1480
- });
1481
- } catch {
1482
- devLogger3.error("Failed to fetch sessions", {
1483
- errors: result.errors
1484
- });
1485
- }
1931
+ /**
1932
+ * Report data breach
1933
+ */
1934
+ async reportBreach(breach) {
1935
+ const fullBreach = {
1936
+ ...breach,
1937
+ id: crypto.randomUUID(),
1938
+ detectedAt: (/* @__PURE__ */ new Date()).toISOString(),
1939
+ status: "detected"
1940
+ };
1941
+ await this.storage.setBreach(fullBreach);
1942
+ if (fullBreach.severity === "critical") {
1943
+ await this.notifyAuthorities(fullBreach);
1486
1944
  }
1487
- return result;
1945
+ return fullBreach;
1488
1946
  }
1489
- async updateSession(id, data) {
1490
- const repository = await this.getRepository();
1491
- const result = await repository.update(id, data);
1492
- if (!result.success) {
1493
- try {
1494
- const payload = await getPayloadClient2();
1495
- payload.logger.error("Failed to update session", {
1496
- errors: result.errors
1497
- });
1498
- } catch {
1499
- devLogger3.error("Failed to update session", { errors: result.errors });
1500
- }
1501
- }
1502
- return result;
1947
+ /**
1948
+ * Notify authorities (required within 72 hours under GDPR)
1949
+ */
1950
+ async notifyAuthorities(breach) {
1951
+ await this.storage.updateBreach(breach.id, {
1952
+ reportedAt: (/* @__PURE__ */ new Date()).toISOString(),
1953
+ status: "notified"
1954
+ });
1955
+ getSecurityLogger().info("Breach reported to authorities", { breachId: breach.id });
1503
1956
  }
1504
- async deleteSession(id) {
1505
- const repository = await this.getRepository();
1506
- const result = await repository.delete(id);
1507
- if (!result.success) {
1508
- try {
1509
- const payload = await getPayloadClient2();
1510
- payload.logger.error("Failed to delete session", {
1511
- errors: result.errors
1512
- });
1513
- } catch {
1514
- devLogger3.error("Failed to delete session", { errors: result.errors });
1515
- }
1957
+ /**
1958
+ * Notify affected users
1959
+ */
1960
+ async notifyAffectedUsers(breachId, notifyFn) {
1961
+ const breach = await this.storage.getBreach(breachId);
1962
+ if (!breach) {
1963
+ throw new Error("Breach not found");
1516
1964
  }
1517
- return result;
1965
+ for (const userId of breach.affectedUsers) {
1966
+ await notifyFn(userId, breach);
1967
+ }
1968
+ }
1969
+ /**
1970
+ * Check if breach notification is required
1971
+ */
1972
+ requiresNotification(breach) {
1973
+ return breach.severity === "high" || breach.severity === "critical" || breach.dataCategories.includes("sensitive") || breach.dataCategories.includes("financial");
1974
+ }
1975
+ /**
1976
+ * Get breach
1977
+ */
1978
+ async getBreach(id) {
1979
+ return this.storage.getBreach(id);
1980
+ }
1981
+ /**
1982
+ * Get all breaches
1983
+ */
1984
+ async getAllBreaches() {
1985
+ return this.storage.getAllBreaches();
1518
1986
  }
1519
1987
  };
1520
- var sessionService = new SessionService();
1988
+ function createConsentManager(storage) {
1989
+ return new ConsentManager(storage);
1990
+ }
1991
+ function createDataDeletionSystem(storage) {
1992
+ return new DataDeletionSystem(storage);
1993
+ }
1994
+ var dataExportSystem = new DataExportSystem();
1995
+ var privacyPolicyManager = new PrivacyPolicyManager();
1996
+ var cookieConsentManager = new CookieConsentManager();
1997
+ function createDataBreachManager(storage) {
1998
+ return new DataBreachManager(storage);
1999
+ }
2000
+ var dataBreachManager = new DataBreachManager();
1521
2001
 
1522
- // src/TokenService.ts
1523
- import { InfrastructureService as InfrastructureService2 } from "@revealui/core";
1524
- var AppError = class extends Error {
1525
- constructor(code, message, cause) {
1526
- super(message);
1527
- this.code = code;
1528
- this.cause = cause;
1529
- this.name = "AppError";
1530
- if (cause) {
1531
- this.cause = cause;
1532
- }
2002
+ // src/headers.ts
2003
+ var SecurityHeaders = class {
2004
+ config;
2005
+ constructor(config = {}) {
2006
+ this.config = config;
1533
2007
  }
1534
- };
1535
- var ErrorCode = {
1536
- TOKEN_INVALID: "TOKEN_INVALID",
1537
- TOKEN_EXPIRED: "TOKEN_EXPIRED",
1538
- AUTHENTICATION_ERROR: "AUTHENTICATION_ERROR",
1539
- INTERNAL_ERROR: "INTERNAL_ERROR"
1540
- };
1541
- var TokenService = class extends InfrastructureService2 {
1542
- constructor(payload) {
1543
- super(payload, "TokenService");
1544
- this.payload = payload;
2008
+ /**
2009
+ * Get all security headers
2010
+ */
2011
+ getHeaders() {
2012
+ const headers = {};
2013
+ if (this.config.contentSecurityPolicy) {
2014
+ headers["Content-Security-Policy"] = this.buildCSP(this.config.contentSecurityPolicy);
2015
+ }
2016
+ if (this.config.strictTransportSecurity) {
2017
+ headers["Strict-Transport-Security"] = this.buildHSTS(this.config.strictTransportSecurity);
2018
+ }
2019
+ if (this.config.xFrameOptions) {
2020
+ headers["X-Frame-Options"] = this.config.xFrameOptions;
2021
+ }
2022
+ if (this.config.xContentTypeOptions !== false) {
2023
+ headers["X-Content-Type-Options"] = "nosniff";
2024
+ }
2025
+ if (this.config.referrerPolicy) {
2026
+ headers["Referrer-Policy"] = this.config.referrerPolicy;
2027
+ }
2028
+ if (this.config.permissionsPolicy) {
2029
+ headers["Permissions-Policy"] = this.buildPermissionsPolicy(this.config.permissionsPolicy);
2030
+ }
2031
+ if (this.config.crossOriginEmbedderPolicy) {
2032
+ headers["Cross-Origin-Embedder-Policy"] = this.config.crossOriginEmbedderPolicy;
2033
+ }
2034
+ if (this.config.crossOriginOpenerPolicy) {
2035
+ headers["Cross-Origin-Opener-Policy"] = this.config.crossOriginOpenerPolicy;
2036
+ }
2037
+ if (this.config.crossOriginResourcePolicy) {
2038
+ headers["Cross-Origin-Resource-Policy"] = this.config.crossOriginResourcePolicy;
2039
+ }
2040
+ return headers;
1545
2041
  }
1546
2042
  /**
1547
- * Authenticate user and generate access token using PayloadCMS native login
1548
- * @param credentials User login credentials
1549
- * @param req Optional PayloadRequest for context
1550
- * @returns Login result with user data and token
2043
+ * Build Content Security Policy header
1551
2044
  */
1552
- async login(credentials, req) {
1553
- try {
1554
- this.logger.debug("Attempting user login", {
1555
- email: credentials.email,
1556
- serviceName: this.serviceName,
1557
- operation: "login"
1558
- });
1559
- const result = await this.payload.login({
1560
- collection: "users",
1561
- data: {
1562
- email: credentials.email,
1563
- password: credentials.password
1564
- },
1565
- ...req && { req }
1566
- });
1567
- this.logger.info("User login successful", {
1568
- userId: result.user.id,
1569
- email: result.user.email,
1570
- serviceName: this.serviceName
1571
- });
1572
- return result;
1573
- } catch (error) {
1574
- this.logger.error("User login failed", {
1575
- email: credentials.email,
1576
- error: error instanceof Error ? error.message : "Unknown error",
1577
- serviceName: this.serviceName
1578
- });
1579
- throw new AppError(
1580
- ErrorCode.AUTHENTICATION_ERROR,
1581
- "Login failed",
1582
- error instanceof Error ? error : new Error(String(error))
1583
- );
2045
+ buildCSP(config) {
2046
+ if (typeof config === "string") {
2047
+ return config;
2048
+ }
2049
+ const directives = [];
2050
+ const addDirective = (name, values) => {
2051
+ if (values && values.length > 0) {
2052
+ directives.push(`${name} ${values.join(" ")}`);
2053
+ }
2054
+ };
2055
+ addDirective("default-src", config.defaultSrc);
2056
+ addDirective("script-src", config.scriptSrc);
2057
+ addDirective("style-src", config.styleSrc);
2058
+ addDirective("img-src", config.imgSrc);
2059
+ addDirective("font-src", config.fontSrc);
2060
+ addDirective("connect-src", config.connectSrc);
2061
+ addDirective("frame-src", config.frameSrc);
2062
+ addDirective("object-src", config.objectSrc);
2063
+ addDirective("media-src", config.mediaSrc);
2064
+ addDirective("worker-src", config.workerSrc);
2065
+ addDirective("child-src", config.childSrc);
2066
+ addDirective("form-action", config.formAction);
2067
+ addDirective("frame-ancestors", config.frameAncestors);
2068
+ addDirective("base-uri", config.baseUri);
2069
+ addDirective("manifest-src", config.manifestSrc);
2070
+ if (config.upgradeInsecureRequests) {
2071
+ directives.push("upgrade-insecure-requests");
1584
2072
  }
2073
+ if (config.blockAllMixedContent) {
2074
+ directives.push("block-all-mixed-content");
2075
+ }
2076
+ if (config.reportUri) {
2077
+ directives.push(`report-uri ${config.reportUri}`);
2078
+ }
2079
+ if (config.reportTo) {
2080
+ directives.push(`report-to ${config.reportTo}`);
2081
+ }
2082
+ return directives.join("; ");
1585
2083
  }
1586
2084
  /**
1587
- * Verify user by ID using PayloadCMS native functionality
1588
- * @param userId User ID to verify
1589
- * @returns User data if exists
2085
+ * Build HSTS header
1590
2086
  */
1591
- async verifyUser(userId) {
1592
- try {
1593
- this.logger.debug("Verifying user", {
1594
- userId,
1595
- serviceName: this.serviceName,
1596
- operation: "verifyUser"
1597
- });
1598
- const user = await this.payload.findByID({
1599
- collection: "users",
1600
- id: userId
1601
- });
1602
- this.logger.debug("User verification successful", {
1603
- userId: user.id,
1604
- serviceName: this.serviceName
1605
- });
1606
- return user;
1607
- } catch (error) {
1608
- this.logger.error("User verification failed", {
1609
- userId,
1610
- error: error instanceof Error ? error.message : "Unknown error",
1611
- serviceName: this.serviceName
1612
- });
1613
- throw new AppError(
1614
- ErrorCode.AUTHENTICATION_ERROR,
1615
- "User verification failed",
1616
- error instanceof Error ? error : new Error(String(error))
1617
- );
2087
+ buildHSTS(config) {
2088
+ if (config === true) {
2089
+ return "max-age=31536000; includeSubDomains";
2090
+ }
2091
+ if (config === false) {
2092
+ return "";
2093
+ }
2094
+ const parts = [`max-age=${config.maxAge}`];
2095
+ if (config.includeSubDomains) {
2096
+ parts.push("includeSubDomains");
1618
2097
  }
2098
+ if (config.preload) {
2099
+ parts.push("preload");
2100
+ }
2101
+ return parts.join("; ");
1619
2102
  }
1620
2103
  /**
1621
- * Generate password reset token using PayloadCMS native functionality
1622
- * @param email User email address
1623
- * @returns Password reset token
2104
+ * Build Permissions-Policy header
1624
2105
  */
1625
- async generatePasswordResetToken(email) {
1626
- try {
1627
- this.logger.debug("Generating password reset token", {
1628
- email,
1629
- serviceName: this.serviceName,
1630
- operation: "generatePasswordResetToken"
1631
- });
1632
- const token = await this.payload.forgotPassword({
1633
- collection: "users",
1634
- data: { email }
1635
- });
1636
- this.logger.info("Password reset token generated", {
1637
- email,
1638
- serviceName: this.serviceName
1639
- });
1640
- return token;
1641
- } catch (error) {
1642
- this.logger.error("Password reset token generation failed", {
1643
- email,
1644
- error: error instanceof Error ? error.message : "Unknown error",
1645
- serviceName: this.serviceName
1646
- });
1647
- throw new AppError(
1648
- ErrorCode.INTERNAL_ERROR,
1649
- "Failed to generate password reset token",
1650
- error instanceof Error ? error : new Error(String(error))
1651
- );
2106
+ buildPermissionsPolicy(config) {
2107
+ if (typeof config === "string") {
2108
+ return config;
1652
2109
  }
2110
+ const policies = [];
2111
+ Object.entries(config).forEach(([feature, origins]) => {
2112
+ if (!origins || origins.length === 0) {
2113
+ policies.push(`${feature}=()`);
2114
+ } else if (origins.includes("*")) {
2115
+ policies.push(`${feature}=*`);
2116
+ } else {
2117
+ const originsList = origins.map((o) => `"${o}"`).join(" ");
2118
+ policies.push(`${feature}=(${originsList})`);
2119
+ }
2120
+ });
2121
+ return policies.join(", ");
1653
2122
  }
1654
2123
  /**
1655
- * Reset user password using PayloadCMS native functionality
1656
- * @param token Password reset token
1657
- * @param newPassword New password
1658
- * @returns Reset result with user and new token
1659
- *
1660
- * NOTE: Uses overrideAccess: true as this is a system-level password reset operation
1661
- * that requires bypassing normal access control for security token validation.
2124
+ * Apply headers to response
1662
2125
  */
1663
- async resetPassword(token, newPassword) {
1664
- try {
1665
- this.logger.debug("Resetting password", {
1666
- serviceName: this.serviceName,
1667
- operation: "resetPassword"
1668
- });
1669
- const result = await this.payload.resetPassword({
1670
- collection: "users",
1671
- data: {
1672
- token,
1673
- password: newPassword
1674
- },
1675
- overrideAccess: true
1676
- // System-level operation for password reset flow
1677
- });
1678
- this.logger.info("Password reset successful", {
1679
- userId: result.user?.id,
1680
- serviceName: this.serviceName
1681
- });
1682
- return result;
1683
- } catch (error) {
1684
- this.logger.error("Password reset failed", {
1685
- error: error instanceof Error ? error.message : "Unknown error",
1686
- serviceName: this.serviceName
1687
- });
1688
- throw new AppError(
1689
- ErrorCode.AUTHENTICATION_ERROR,
1690
- "Password reset failed",
1691
- error instanceof Error ? error : new Error(String(error))
1692
- );
2126
+ applyHeaders(response) {
2127
+ const headers = this.getHeaders();
2128
+ Object.entries(headers).forEach(([name, value]) => {
2129
+ response.headers.set(name, value);
2130
+ });
2131
+ return response;
2132
+ }
2133
+ };
2134
+ var CORSManager = class {
2135
+ config;
2136
+ constructor(config = {}) {
2137
+ this.config = {
2138
+ origin: config.origin ?? [],
2139
+ methods: config.methods || ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"],
2140
+ allowedHeaders: config.allowedHeaders || ["Content-Type", "Authorization"],
2141
+ exposedHeaders: config.exposedHeaders || [],
2142
+ credentials: config.credentials ?? false,
2143
+ maxAge: config.maxAge || 86400,
2144
+ preflightContinue: config.preflightContinue ?? false,
2145
+ optionsSuccessStatus: config.optionsSuccessStatus || 204
2146
+ };
2147
+ }
2148
+ /**
2149
+ * Check if origin is allowed
2150
+ */
2151
+ isOriginAllowed(origin) {
2152
+ const { origin: allowedOrigin } = this.config;
2153
+ if (allowedOrigin === "*") {
2154
+ return true;
1693
2155
  }
2156
+ if (typeof allowedOrigin === "function") {
2157
+ return allowedOrigin(origin);
2158
+ }
2159
+ if (typeof allowedOrigin === "string") {
2160
+ return origin === allowedOrigin;
2161
+ }
2162
+ if (Array.isArray(allowedOrigin)) {
2163
+ return allowedOrigin.includes(origin);
2164
+ }
2165
+ return false;
1694
2166
  }
1695
2167
  /**
1696
- * Verify email using PayloadCMS native functionality
1697
- * @param token Email verification token
1698
- * @returns Verification success status
2168
+ * Get CORS headers
1699
2169
  */
1700
- async verifyEmail(token) {
1701
- try {
1702
- this.logger.debug("Verifying email", {
1703
- serviceName: this.serviceName,
1704
- operation: "verifyEmail"
1705
- });
1706
- const result = await this.payload.verifyEmail({
1707
- collection: "users",
1708
- token
1709
- });
1710
- this.logger.info("Email verification completed", {
1711
- success: result,
1712
- serviceName: this.serviceName
1713
- });
1714
- return result;
1715
- } catch (error) {
1716
- this.logger.error("Email verification failed", {
1717
- error: error instanceof Error ? error.message : "Unknown error",
1718
- serviceName: this.serviceName
1719
- });
1720
- throw new AppError(
1721
- ErrorCode.AUTHENTICATION_ERROR,
1722
- "Email verification failed",
1723
- error instanceof Error ? error : new Error(String(error))
1724
- );
2170
+ getCORSHeaders(origin) {
2171
+ const headers = {};
2172
+ if (this.isOriginAllowed(origin)) {
2173
+ headers["Access-Control-Allow-Origin"] = this.config.origin === "*" ? "*" : origin;
2174
+ }
2175
+ if (this.config.origin !== "*") {
2176
+ headers.Vary = "Origin";
2177
+ }
2178
+ if (this.config.credentials && this.config.origin !== "*") {
2179
+ headers["Access-Control-Allow-Credentials"] = "true";
1725
2180
  }
2181
+ if (this.config.exposedHeaders.length > 0) {
2182
+ headers["Access-Control-Expose-Headers"] = this.config.exposedHeaders.join(", ");
2183
+ }
2184
+ return headers;
1726
2185
  }
1727
2186
  /**
1728
- * Unlock user account using PayloadCMS native functionality
1729
- * @param email User email address
1730
- * @param password User password
1731
- * @returns Unlock success status
1732
- *
1733
- * NOTE: Uses overrideAccess: true as this is a system-level account unlock operation
1734
- * that requires bypassing normal access control for account recovery.
2187
+ * Get preflight headers
1735
2188
  */
1736
- async unlockUser(email, password) {
1737
- try {
1738
- this.logger.debug("Unlocking user account", {
1739
- email,
1740
- serviceName: this.serviceName,
1741
- operation: "unlockUser"
1742
- });
1743
- const result = await this.payload.unlock({
1744
- collection: "users",
1745
- data: { email, password },
1746
- overrideAccess: true
1747
- // System-level operation for account recovery
1748
- });
1749
- this.logger.info("User account unlock completed", {
1750
- email,
1751
- success: result,
1752
- serviceName: this.serviceName
1753
- });
1754
- return result;
1755
- } catch (error) {
1756
- this.logger.error("User account unlock failed", {
1757
- email,
1758
- error: error instanceof Error ? error.message : "Unknown error",
1759
- serviceName: this.serviceName
1760
- });
1761
- throw new AppError(
1762
- ErrorCode.AUTHENTICATION_ERROR,
1763
- "User account unlock failed",
1764
- error instanceof Error ? error : new Error(String(error))
1765
- );
2189
+ getPreflightHeaders(origin) {
2190
+ const headers = this.getCORSHeaders(origin);
2191
+ headers["Access-Control-Allow-Methods"] = this.config.methods.join(", ");
2192
+ headers["Access-Control-Allow-Headers"] = this.config.allowedHeaders.join(", ");
2193
+ headers["Access-Control-Max-Age"] = this.config.maxAge.toString();
2194
+ return headers;
2195
+ }
2196
+ /**
2197
+ * Handle CORS request
2198
+ */
2199
+ handleRequest(request) {
2200
+ const origin = request.headers.get("Origin");
2201
+ if (!origin) {
2202
+ return null;
2203
+ }
2204
+ if (request.method === "OPTIONS") {
2205
+ return this.handlePreflight(request, origin);
1766
2206
  }
2207
+ return null;
1767
2208
  }
1768
2209
  /**
1769
- * @inheritdoc
2210
+ * Handle preflight request
1770
2211
  */
1771
- onInitialize() {
1772
- this.logger.info("TokenService initialized with PayloadCMS native auth", {
1773
- serviceName: this.serviceName
2212
+ handlePreflight(_request, origin) {
2213
+ if (!this.isOriginAllowed(origin)) {
2214
+ return new Response(null, { status: 403 });
2215
+ }
2216
+ const headers = this.getPreflightHeaders(origin);
2217
+ return new Response(null, {
2218
+ status: this.config.optionsSuccessStatus,
2219
+ headers
1774
2220
  });
1775
2221
  }
1776
2222
  /**
1777
- * @inheritdoc
2223
+ * Apply CORS headers to response
1778
2224
  */
1779
- onCleanup() {
1780
- this.logger.info("TokenService cleaned up", {
1781
- serviceName: this.serviceName
2225
+ applyHeaders(response, origin) {
2226
+ if (!this.isOriginAllowed(origin)) {
2227
+ return response;
2228
+ }
2229
+ const headers = this.getCORSHeaders(origin);
2230
+ Object.entries(headers).forEach(([name, value]) => {
2231
+ response.headers.set(name, value);
1782
2232
  });
2233
+ return response;
1783
2234
  }
2235
+ };
2236
+ var SecurityPresets = {
1784
2237
  /**
1785
- * @inheritdoc
2238
+ * Strict security (recommended for production)
1786
2239
  */
1787
- onHealthCheck() {
1788
- this.logger.debug("TokenService health check passed", {
1789
- serviceName: this.serviceName
1790
- });
2240
+ strict: () => ({
2241
+ contentSecurityPolicy: {
2242
+ defaultSrc: ["'self'"],
2243
+ scriptSrc: ["'self'"],
2244
+ styleSrc: ["'self'", "'unsafe-inline'"],
2245
+ imgSrc: ["'self'", "data:", "https:"],
2246
+ fontSrc: ["'self'", "data:"],
2247
+ connectSrc: ["'self'"],
2248
+ frameSrc: ["'none'"],
2249
+ objectSrc: ["'none'"],
2250
+ baseUri: ["'self'"],
2251
+ formAction: ["'self'"],
2252
+ frameAncestors: ["'none'"],
2253
+ upgradeInsecureRequests: true
2254
+ },
2255
+ strictTransportSecurity: {
2256
+ maxAge: 31536e3,
2257
+ includeSubDomains: true,
2258
+ preload: true
2259
+ },
2260
+ xFrameOptions: "DENY",
2261
+ xContentTypeOptions: true,
2262
+ referrerPolicy: "strict-origin-when-cross-origin",
2263
+ crossOriginEmbedderPolicy: "require-corp",
2264
+ crossOriginOpenerPolicy: "same-origin",
2265
+ crossOriginResourcePolicy: "same-origin"
2266
+ }),
2267
+ /**
2268
+ * Moderate security (balanced)
2269
+ */
2270
+ moderate: () => ({
2271
+ contentSecurityPolicy: {
2272
+ defaultSrc: ["'self'"],
2273
+ scriptSrc: ["'self'", "'unsafe-inline'"],
2274
+ styleSrc: ["'self'", "'unsafe-inline'"],
2275
+ imgSrc: ["'self'", "data:", "https:"],
2276
+ fontSrc: ["'self'", "data:", "https:"],
2277
+ connectSrc: ["'self'", "https:"],
2278
+ frameAncestors: ["'self'"]
2279
+ },
2280
+ strictTransportSecurity: {
2281
+ maxAge: 31536e3,
2282
+ includeSubDomains: true
2283
+ },
2284
+ xFrameOptions: "SAMEORIGIN",
2285
+ xContentTypeOptions: true,
2286
+ referrerPolicy: "origin-when-cross-origin"
2287
+ }),
2288
+ /**
2289
+ * Development (permissive)
2290
+ */
2291
+ development: () => ({
2292
+ xContentTypeOptions: true,
2293
+ referrerPolicy: "no-referrer-when-downgrade"
2294
+ })
2295
+ };
2296
+ var CORSPresets = {
2297
+ /**
2298
+ * Strict CORS (same origin only)
2299
+ */
2300
+ strict: () => ({
2301
+ origin: [],
2302
+ methods: ["GET", "POST", "PUT", "DELETE"],
2303
+ allowedHeaders: ["Content-Type", "Authorization"],
2304
+ credentials: true,
2305
+ maxAge: 86400
2306
+ }),
2307
+ /**
2308
+ * Moderate CORS (specific origins)
2309
+ */
2310
+ moderate: (allowedOrigins) => ({
2311
+ origin: allowedOrigins,
2312
+ methods: ["GET", "POST", "PUT", "DELETE", "PATCH"],
2313
+ allowedHeaders: ["Content-Type", "Authorization", "X-Requested-With"],
2314
+ exposedHeaders: ["X-Total-Count"],
2315
+ credentials: true,
2316
+ maxAge: 86400
2317
+ }),
2318
+ /**
2319
+ * Permissive CORS (all origins) — development only.
2320
+ * Logs a warning if used when NODE_ENV === 'production'.
2321
+ */
2322
+ permissive: () => {
2323
+ if (process.env.NODE_ENV === "production") {
2324
+ getSecurityLogger().warn(
2325
+ "[SecurityPresets] CORS permissive preset used in production \u2014 this allows all origins. Use moderate() with explicit origins instead."
2326
+ );
2327
+ }
2328
+ return {
2329
+ origin: "*",
2330
+ methods: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"],
2331
+ allowedHeaders: ["*"],
2332
+ credentials: false,
2333
+ maxAge: 86400
2334
+ };
2335
+ },
2336
+ /**
2337
+ * API CORS (public read-only APIs) — credentials disabled.
2338
+ * Logs a warning if used when NODE_ENV === 'production'.
2339
+ */
2340
+ api: () => {
2341
+ if (process.env.NODE_ENV === "production") {
2342
+ getSecurityLogger().warn(
2343
+ '[SecurityPresets] CORS api preset uses origin:"*". For production, pass explicit origins to moderate() instead.'
2344
+ );
2345
+ }
2346
+ return {
2347
+ origin: "*",
2348
+ methods: ["GET", "POST", "PUT", "DELETE", "PATCH"],
2349
+ allowedHeaders: ["Content-Type", "Authorization", "X-API-Key"],
2350
+ exposedHeaders: ["X-RateLimit-Limit", "X-RateLimit-Remaining", "X-RateLimit-Reset"],
2351
+ credentials: false,
2352
+ maxAge: 86400
2353
+ };
1791
2354
  }
1792
2355
  };
1793
- function createTokenService(payload) {
1794
- return new TokenService(payload);
2356
+ function createSecurityMiddleware(securityConfig, corsConfig) {
2357
+ const security = new SecurityHeaders(securityConfig);
2358
+ const cors = new CORSManager(corsConfig);
2359
+ return async (request, next) => {
2360
+ const origin = request.headers.get("Origin");
2361
+ if (origin && request.method === "OPTIONS") {
2362
+ const preflightResponse = cors.handleRequest(request);
2363
+ if (preflightResponse) {
2364
+ return preflightResponse;
2365
+ }
2366
+ }
2367
+ const response = await next();
2368
+ security.applyHeaders(response);
2369
+ if (origin) {
2370
+ cors.applyHeaders(response, origin);
2371
+ }
2372
+ return response;
2373
+ };
2374
+ }
2375
+ function setRateLimitHeaders(response, limit, remaining, reset) {
2376
+ response.headers.set("X-RateLimit-Limit", limit.toString());
2377
+ response.headers.set("X-RateLimit-Remaining", remaining.toString());
2378
+ response.headers.set("X-RateLimit-Reset", reset.toString());
1795
2379
  }
1796
2380
  export {
1797
- CSRFService,
1798
- EncryptionService,
1799
- RATE_LIMITS,
1800
- RateLimited,
1801
- RateLimiterService,
1802
- SECURITY_HEADERS,
1803
- SecurityMonitoringService,
1804
- SessionService,
1805
- TokenService,
1806
- addSecurityEvent,
1807
- calculateSecurityMetrics,
1808
- checkAnonymousRateLimit,
1809
- checkRateLimit,
1810
- checkUserRateLimit,
1811
- clearSecurityData,
1812
- createSecurity,
1813
- createSecurityAlert,
1814
- createSecurityEvent,
1815
- createTokenService,
1816
- filterEvents,
1817
- generateIPRateLimitKey,
1818
- generateRateLimitKey,
1819
- getClientIP,
1820
- getEventsBySeverity,
1821
- getEventsInTimeRange,
1822
- getRateLimiterService,
1823
- getSecurityAlerts,
1824
- getSecurityEvents,
1825
- getSecurityMetrics,
1826
- getUserEvents,
1827
- isTrustedSource,
1828
- logAuthenticationEvent,
1829
- logAuthorizationEvent,
1830
- logDataAccessEvent,
1831
- logSecurityEvent,
1832
- sanitizeInput,
1833
- securityMiddleware,
1834
- sessionService,
1835
- shouldTriggerAlert,
1836
- validateAndSanitizeInput,
1837
- validateCSRFToken,
1838
- validateEnvironment,
1839
- withRateLimit
2381
+ AuditReportGenerator,
2382
+ AuditSystem,
2383
+ AuditTrail,
2384
+ AuthorizationSystem,
2385
+ CORSManager,
2386
+ CORSPresets,
2387
+ CommonRoles,
2388
+ ConsentManager,
2389
+ CookieConsentManager,
2390
+ DataAnonymization,
2391
+ DataBreachManager,
2392
+ DataDeletionSystem,
2393
+ DataExportSystem,
2394
+ DataMasking,
2395
+ EncryptionSystem,
2396
+ EnvelopeEncryption,
2397
+ FieldEncryption,
2398
+ InMemoryAuditStorage,
2399
+ InMemoryBreachStorage,
2400
+ InMemoryGDPRStorage,
2401
+ KeyRotationManager,
2402
+ OAuthClient,
2403
+ OAuthProviders,
2404
+ PasswordHasher,
2405
+ PermissionBuilder,
2406
+ PermissionCache,
2407
+ PolicyBuilder,
2408
+ PrivacyPolicyManager,
2409
+ RequirePermission,
2410
+ RequireRole,
2411
+ SecurityHeaders,
2412
+ SecurityPresets,
2413
+ TokenGenerator,
2414
+ TwoFactorAuth,
2415
+ audit,
2416
+ authorization,
2417
+ canAccessResource,
2418
+ checkAttributeAccess,
2419
+ configureSecurityLogger,
2420
+ cookieConsentManager,
2421
+ createAuditMiddleware,
2422
+ createAuthorizationMiddleware,
2423
+ createConsentManager,
2424
+ createDataBreachManager,
2425
+ createDataDeletionSystem,
2426
+ createSecurityMiddleware,
2427
+ dataBreachManager,
2428
+ dataExportSystem,
2429
+ encryption,
2430
+ permissionCache,
2431
+ privacyPolicyManager,
2432
+ setRateLimitHeaders
1840
2433
  };
1841
2434
  //# sourceMappingURL=index.js.map