@revealui/security 0.0.1-pre.1 → 0.2.1

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,2429 @@
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
+ Authorization: `Bearer ${accessToken}`
855
476
  }
856
- const decrypted = await this.decrypt(encrypted.data);
857
- if (!decrypted.success || decrypted.data !== testData) {
858
- throw new Error("Health check decryption failed");
477
+ });
478
+ if (!response.ok) {
479
+ let detail = "";
480
+ try {
481
+ const body = await response.text();
482
+ detail = `: ${response.status} ${body.slice(0, 200)}`;
483
+ } catch {
484
+ detail = `: ${response.status}`;
859
485
  }
860
- } catch (error) {
861
- throw new Error(
862
- `EncryptionService health check failed: ${error instanceof Error ? error.message : "Unknown error"}`
863
- );
486
+ throw new Error(`Failed to fetch user info${detail}`);
864
487
  }
488
+ return response.json();
865
489
  }
866
490
  };
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()
491
+ var PH_ITERATIONS = 1e5;
492
+ var PH_KEY_LENGTH = 64;
493
+ var PH_DIGEST = "sha512";
494
+ async function hashPassword(password) {
495
+ const { pbkdf2, randomBytes: rb } = await import("crypto");
496
+ const salt = rb(16).toString("hex");
497
+ return new Promise((resolve, reject) => {
498
+ pbkdf2(password, salt, PH_ITERATIONS, PH_KEY_LENGTH, PH_DIGEST, (err, derivedKey) => {
499
+ if (err) reject(err);
500
+ else resolve(`${salt}:${derivedKey.toString("hex")}`);
501
+ });
967
502
  });
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
503
+ }
504
+ async function verifyPassword(password, storedHash) {
505
+ const { pbkdf2, timingSafeEqual: tse } = await import("crypto");
506
+ const [salt, hash] = storedHash.split(":");
507
+ if (!(salt && hash)) {
508
+ return false;
509
+ }
510
+ return new Promise((resolve, reject) => {
511
+ pbkdf2(password, salt, PH_ITERATIONS, PH_KEY_LENGTH, PH_DIGEST, (err, derivedKey) => {
512
+ if (err) reject(err);
513
+ else {
514
+ const derived = Buffer.from(derivedKey.toString("hex"), "utf-8");
515
+ const expected = Buffer.from(hash, "utf-8");
516
+ if (derived.length !== expected.length) {
517
+ resolve(false);
518
+ } else {
519
+ resolve(tse(derived, expected));
520
+ }
521
+ }
982
522
  });
983
- }
523
+ });
524
+ }
525
+ var PasswordHasher = {
526
+ hash: hashPassword,
527
+ verify: verifyPassword
984
528
  };
985
- var getSecurityEvents = () => [...events];
986
- var getSecurityAlerts = () => [...alerts];
987
- var getSecurityMetrics = () => calculateSecurityMetrics(events);
988
- var clearSecurityData = () => {
989
- events = [];
990
- alerts = [];
991
- };
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
529
+ function base32Encode(buffer) {
530
+ const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
531
+ let result = "";
532
+ let bits = 0;
533
+ let value = 0;
534
+ for (const byte of buffer) {
535
+ if (byte === void 0) continue;
536
+ value = value << 8 | byte;
537
+ bits += 8;
538
+ while (bits >= 5) {
539
+ result += alphabet[value >>> bits - 5 & 31];
540
+ bits -= 5;
1000
541
  }
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);
542
+ }
543
+ if (bits > 0) {
544
+ result += alphabet[value << 5 - bits & 31];
545
+ }
546
+ return result;
547
+ }
548
+ function totpHmac(key, message) {
549
+ const hmacDigest = createHmac("sha1", key).update(message).digest();
550
+ return new Uint8Array(hmacDigest);
551
+ }
552
+ function generateSecret() {
553
+ const crypto2 = globalThis.crypto;
554
+ if (!crypto2) {
555
+ throw new Error("Crypto API not available");
556
+ }
557
+ const buffer = new Uint8Array(20);
558
+ crypto2.getRandomValues(buffer);
559
+ return base32Encode(buffer);
560
+ }
561
+ function generateCode(secret, timestamp) {
562
+ const time = Math.floor((timestamp || Date.now()) / 3e4);
563
+ const hmacDigest = totpHmac(secret, time.toString());
564
+ const offset = hmacDigest[hmacDigest.length - 1] & 15;
565
+ const b0 = hmacDigest[offset] & 127;
566
+ const b1 = hmacDigest[offset + 1] & 255;
567
+ const b2 = hmacDigest[offset + 2] & 255;
568
+ const b3 = hmacDigest[offset + 3] & 255;
569
+ const code = (b0 << 24 | b1 << 16 | b2 << 8 | b3) % 1e6;
570
+ return code.toString().padStart(6, "0");
571
+ }
572
+ function verifyCode(secret, code, window = 1) {
573
+ const timestamp = Date.now();
574
+ for (let i = -window; i <= window; i++) {
575
+ const testTime = timestamp + i * 3e4;
576
+ const testCode = generateCode(secret, testTime);
577
+ if (testCode.length === code.length && timingSafeEqual(Buffer.from(testCode), Buffer.from(code))) {
578
+ return true;
579
+ }
580
+ }
581
+ return false;
582
+ }
583
+ var TwoFactorAuth = {
584
+ generateSecret,
585
+ generateCode,
586
+ verifyCode
1009
587
  };
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
588
+
589
+ // src/authorization.ts
590
+ var AuthorizationSystem = class {
591
+ roles = /* @__PURE__ */ new Map();
592
+ policies = /* @__PURE__ */ new Map();
593
+ /**
594
+ * Register role
595
+ */
596
+ registerRole(role) {
597
+ this.roles.set(role.id, role);
598
+ }
599
+ /**
600
+ * Get role
601
+ */
602
+ getRole(roleId) {
603
+ return this.roles.get(roleId);
604
+ }
605
+ /**
606
+ * Register policy
607
+ */
608
+ registerPolicy(policy) {
609
+ this.policies.set(policy.id, policy);
610
+ }
611
+ /**
612
+ * Check if user has permission (RBAC)
613
+ */
614
+ hasPermission(userRoles, resource, action) {
615
+ const permissions = this.getUserPermissions(userRoles);
616
+ return permissions.some(
617
+ (permission) => this.matchesResource(permission.resource, resource) && this.matchesAction(permission.action, action)
618
+ );
619
+ }
620
+ /**
621
+ * Check access with policies (ABAC)
622
+ */
623
+ checkAccess(context, resource, action) {
624
+ if (this.hasPermission(context.user.roles, resource, action)) {
625
+ return { allowed: true };
1020
626
  }
1021
- };
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);
627
+ const applicablePolicies = this.getApplicablePolicies(resource, action, context);
628
+ applicablePolicies.sort((a, b) => (b.priority || 0) - (a.priority || 0));
629
+ for (const policy of applicablePolicies) {
630
+ if (this.evaluateConditions(policy.conditions || [], context)) {
631
+ return {
632
+ allowed: policy.effect === "allow",
633
+ reason: policy.effect === "deny" ? `Denied by policy: ${policy.name}` : void 0
634
+ };
635
+ }
636
+ }
637
+ return { allowed: false, reason: "No matching policy" };
638
+ }
639
+ /**
640
+ * Get all permissions for roles
641
+ */
642
+ getUserPermissions(roleIds) {
643
+ const permissions = [];
644
+ const visited = /* @__PURE__ */ new Set();
645
+ const addRolePermissions = (roleId) => {
646
+ if (visited.has(roleId)) return;
647
+ visited.add(roleId);
648
+ const role = this.roles.get(roleId);
649
+ if (!role) return;
650
+ permissions.push(...role.permissions);
651
+ if (role.inherits) {
652
+ role.inherits.forEach((inheritedRoleId) => {
653
+ addRolePermissions(inheritedRoleId);
654
+ });
655
+ }
656
+ };
657
+ roleIds.forEach(addRolePermissions);
658
+ return permissions;
659
+ }
660
+ /**
661
+ * Get applicable policies
662
+ */
663
+ getApplicablePolicies(resource, action, _context) {
664
+ return Array.from(this.policies.values()).filter((policy) => {
665
+ const resourceMatches = policy.resources.some((r) => this.matchesResource(r, resource));
666
+ const actionMatches = policy.actions.some((a) => this.matchesAction(a, action));
667
+ return resourceMatches && actionMatches;
668
+ });
669
+ }
670
+ /**
671
+ * Match resource pattern
672
+ */
673
+ matchesResource(pattern, resource) {
674
+ if (pattern === "*") return true;
675
+ if (pattern === resource) return true;
676
+ const regex = new RegExp(
677
+ `^${pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".")}$`
678
+ );
679
+ return regex.test(resource);
680
+ }
681
+ /**
682
+ * Match action pattern
683
+ */
684
+ matchesAction(pattern, action) {
685
+ if (pattern === "*") return true;
686
+ if (pattern === action) return true;
687
+ const regex = new RegExp(
688
+ `^${pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".")}$`
689
+ );
690
+ return regex.test(action);
691
+ }
692
+ /**
693
+ * Evaluate policy conditions
694
+ */
695
+ evaluateConditions(conditions, context) {
696
+ return conditions.every((condition) => {
697
+ const value = this.getContextValue(condition.field, context);
698
+ return this.evaluateCondition(condition, value);
699
+ });
700
+ }
701
+ /**
702
+ * Get value from context
703
+ */
704
+ getContextValue(field, context) {
705
+ const parts = field.split(".");
706
+ let value = context;
707
+ for (const part of parts) {
708
+ if (value && typeof value === "object" && part in value) {
709
+ value = value[part];
710
+ } else {
711
+ return void 0;
712
+ }
713
+ }
714
+ return value;
715
+ }
716
+ /**
717
+ * Evaluate single condition
718
+ */
719
+ evaluateCondition(condition, value) {
720
+ switch (condition.operator) {
721
+ case "eq":
722
+ return value === condition.value;
723
+ case "ne":
724
+ return value !== condition.value;
725
+ case "gt":
726
+ return typeof value === "number" && value > condition.value;
727
+ case "gte":
728
+ return typeof value === "number" && value >= condition.value;
729
+ case "lt":
730
+ return typeof value === "number" && value < condition.value;
731
+ case "lte":
732
+ return typeof value === "number" && value <= condition.value;
733
+ case "in":
734
+ return Array.isArray(condition.value) && condition.value.includes(value);
735
+ case "contains":
736
+ return typeof value === "string" && typeof condition.value === "string" && value.includes(condition.value);
737
+ default:
738
+ return false;
739
+ }
740
+ }
741
+ /**
742
+ * Check if user owns resource
743
+ */
744
+ ownsResource(userId, resource) {
745
+ return resource.owner === userId;
746
+ }
747
+ /**
748
+ * Clear all roles and policies
749
+ */
750
+ clear() {
751
+ this.roles.clear();
752
+ this.policies.clear();
753
+ }
1029
754
  };
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
755
+ var authorization = new AuthorizationSystem();
756
+ var CommonRoles = {
757
+ owner: {
758
+ id: "owner",
759
+ name: "Owner",
760
+ description: "Full control \u2014 inherits admin",
761
+ permissions: [{ resource: "*", action: "*" }],
762
+ inherits: ["admin"]
763
+ },
764
+ admin: {
765
+ id: "admin",
766
+ name: "Administrator",
767
+ description: "Full system access",
768
+ permissions: [{ resource: "*", action: "*" }]
769
+ },
770
+ editor: {
771
+ id: "editor",
772
+ name: "Editor",
773
+ description: "Can read and modify content",
774
+ permissions: [
775
+ { resource: "content", action: "read" },
776
+ { resource: "content", action: "create" },
777
+ { resource: "content", action: "update" },
778
+ { resource: "profile", action: "read" },
779
+ { resource: "profile", action: "update" },
780
+ { resource: "sites", action: "read" },
781
+ { resource: "marketplace", action: "read" }
782
+ ]
783
+ },
784
+ viewer: {
785
+ id: "viewer",
786
+ name: "Viewer",
787
+ description: "Read-only access",
788
+ permissions: [
789
+ { resource: "content", action: "read" },
790
+ { resource: "profile", action: "read" },
791
+ { resource: "sites", action: "read" },
792
+ { resource: "public", action: "read" }
793
+ ]
794
+ },
795
+ agent: {
796
+ id: "agent",
797
+ name: "AI Agent",
798
+ description: "Can execute tasks and read content",
799
+ permissions: [
800
+ { resource: "tasks", action: "create" },
801
+ { resource: "tasks", action: "read" },
802
+ { resource: "content", action: "read" },
803
+ { resource: "rag", action: "read" },
804
+ { resource: "rag", action: "create" }
805
+ ]
806
+ },
807
+ contributor: {
808
+ id: "contributor",
809
+ name: "Contributor",
810
+ description: "Can suggest changes \u2014 create drafts but not publish or delete",
811
+ permissions: [
812
+ { resource: "content", action: "read" },
813
+ { resource: "content", action: "create" },
814
+ { resource: "profile", action: "read" },
815
+ { resource: "profile", action: "update" }
816
+ ]
817
+ }
818
+ };
819
+ var PermissionBuilder = class {
820
+ permission = {};
821
+ resource(resource) {
822
+ this.permission.resource = resource;
823
+ return this;
824
+ }
825
+ action(action) {
826
+ this.permission.action = action;
827
+ return this;
828
+ }
829
+ conditions(conditions) {
830
+ this.permission.conditions = conditions;
831
+ return this;
832
+ }
833
+ build() {
834
+ if (!(this.permission.resource && this.permission.action)) {
835
+ throw new Error("Resource and action are required");
1040
836
  }
1041
- };
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);
837
+ return this.permission;
838
+ }
1049
839
  };
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
840
+ var PolicyBuilder = class {
841
+ policy = {
842
+ effect: "allow",
843
+ resources: [],
844
+ actions: [],
845
+ conditions: []
846
+ };
847
+ id(id) {
848
+ this.policy.id = id;
849
+ return this;
850
+ }
851
+ name(name) {
852
+ this.policy.name = name;
853
+ return this;
854
+ }
855
+ allow() {
856
+ this.policy.effect = "allow";
857
+ return this;
858
+ }
859
+ deny() {
860
+ this.policy.effect = "deny";
861
+ return this;
862
+ }
863
+ resources(...resources) {
864
+ this.policy.resources = resources;
865
+ return this;
866
+ }
867
+ actions(...actions) {
868
+ this.policy.actions = actions;
869
+ return this;
870
+ }
871
+ condition(field, operator, value) {
872
+ if (!this.policy.conditions) {
873
+ this.policy.conditions = [];
874
+ }
875
+ this.policy.conditions.push({ field, operator, value });
876
+ return this;
877
+ }
878
+ priority(priority) {
879
+ this.policy.priority = priority;
880
+ return this;
881
+ }
882
+ build() {
883
+ if (!(this.policy.id && this.policy.name)) {
884
+ throw new Error("ID and name are required");
885
+ }
886
+ return this.policy;
887
+ }
1075
888
  };
1076
-
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 };
889
+ function RequirePermission(resource, action) {
890
+ return (_target, _propertyKey, descriptor) => {
891
+ const originalMethod = descriptor.value;
892
+ descriptor.value = function(...args) {
893
+ const userRoles = this.user?.roles || [];
894
+ if (!authorization.hasPermission(userRoles, resource, action)) {
895
+ throw new Error(`Permission denied: ${resource}:${action}`);
896
+ }
897
+ return originalMethod.apply(this, args);
898
+ };
899
+ return descriptor;
900
+ };
1082
901
  }
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)
1087
- };
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;
902
+ function RequireRole(requiredRole) {
903
+ return (_target, _propertyKey, descriptor) => {
904
+ const originalMethod = descriptor.value;
905
+ descriptor.value = function(...args) {
906
+ const userRoles = this.user?.roles || [];
907
+ if (!userRoles.includes(requiredRole)) {
908
+ throw new Error(`Role required: ${requiredRole}`);
909
+ }
910
+ return originalMethod.apply(this, args);
911
+ };
912
+ return descriptor;
913
+ };
1111
914
  }
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;
915
+ function createAuthorizationMiddleware(getUser, resource, action) {
916
+ return (request, next) => {
917
+ const user = getUser(request);
918
+ if (!authorization.hasPermission(user.roles, resource, action)) {
919
+ throw new Error(`Permission denied: ${resource}:${action}`);
1125
920
  }
921
+ return next();
1126
922
  };
1127
923
  }
924
+ function canAccessResource(userId, userRoles, resource, action) {
925
+ if (authorization.hasPermission(userRoles, resource.type, action)) {
926
+ return true;
927
+ }
928
+ if (authorization.ownsResource(userId, resource)) {
929
+ return true;
930
+ }
931
+ return false;
932
+ }
933
+ function checkAttributeAccess(context, resource, action, requiredAttributes) {
934
+ const { allowed } = authorization.checkAccess(context, resource, action);
935
+ if (!allowed) {
936
+ return false;
937
+ }
938
+ if (requiredAttributes) {
939
+ const userAttributes = context.user.attributes || {};
940
+ return Object.entries(requiredAttributes).every(
941
+ ([key, value]) => userAttributes[key] === value
942
+ );
943
+ }
944
+ return true;
945
+ }
946
+ var PermissionCache = class {
947
+ cache = /* @__PURE__ */ new Map();
948
+ ttl;
949
+ maxEntries;
950
+ constructor(ttl = 3e5, maxEntries = 1e4) {
951
+ this.ttl = ttl;
952
+ this.maxEntries = maxEntries;
953
+ }
954
+ /**
955
+ * Get cached permission
956
+ */
957
+ get(userId, resource, action) {
958
+ const key = this.getCacheKey(userId, resource, action);
959
+ const cached = this.cache.get(key);
960
+ if (!cached) {
961
+ return void 0;
962
+ }
963
+ if (Date.now() > cached.expiresAt) {
964
+ this.cache.delete(key);
965
+ return void 0;
966
+ }
967
+ return cached.allowed;
968
+ }
969
+ /**
970
+ * Set cached permission
971
+ */
972
+ set(userId, resource, action, allowed) {
973
+ const key = this.getCacheKey(userId, resource, action);
974
+ if (this.cache.size >= this.maxEntries) {
975
+ const now = Date.now();
976
+ for (const [k, v] of this.cache) {
977
+ if (now > v.expiresAt) this.cache.delete(k);
978
+ }
979
+ if (this.cache.size >= this.maxEntries) {
980
+ const excess = this.cache.size - this.maxEntries + 1;
981
+ const keys = this.cache.keys();
982
+ for (let i = 0; i < excess; i++) {
983
+ const next = keys.next();
984
+ if (!next.done) this.cache.delete(next.value);
985
+ }
986
+ }
987
+ }
988
+ this.cache.set(key, {
989
+ allowed,
990
+ expiresAt: Date.now() + this.ttl
991
+ });
992
+ }
993
+ /**
994
+ * Clear cache for user
995
+ */
996
+ clearUser(userId) {
997
+ for (const key of this.cache.keys()) {
998
+ if (key.startsWith(`${userId}:`)) {
999
+ this.cache.delete(key);
1000
+ }
1001
+ }
1002
+ }
1003
+ /**
1004
+ * Clear all cache
1005
+ */
1006
+ clear() {
1007
+ this.cache.clear();
1008
+ }
1009
+ /**
1010
+ * Get cache key
1011
+ */
1012
+ getCacheKey(userId, resource, action) {
1013
+ return `${userId}:${resource}:${action}`;
1014
+ }
1015
+ };
1016
+ var permissionCache = new PermissionCache();
1128
1017
 
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)
1018
+ // src/encryption.ts
1019
+ var DEFAULT_CONFIG = {
1020
+ algorithm: "AES-GCM",
1021
+ keySize: 256,
1022
+ ivSize: 12
1134
1023
  };
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
- })
1024
+ var EncryptionSystem = class {
1025
+ config;
1026
+ keys = /* @__PURE__ */ new Map();
1027
+ constructor(config = {}) {
1028
+ this.config = { ...DEFAULT_CONFIG, ...config };
1029
+ }
1030
+ /**
1031
+ * Generate encryption key
1032
+ */
1033
+ async generateKey(keyId) {
1034
+ const crypto2 = globalThis.crypto;
1035
+ if (!crypto2) {
1036
+ throw new Error("Crypto API not available");
1037
+ }
1038
+ const key = await crypto2.subtle.generateKey(
1039
+ {
1040
+ name: this.config.algorithm,
1041
+ length: this.config.keySize
1042
+ },
1043
+ this.config.extractable ?? false,
1044
+ // non-extractable by default — prevents key exfiltration
1045
+ ["encrypt", "decrypt"]
1046
+ );
1047
+ if (keyId) {
1048
+ this.keys.set(keyId, key);
1049
+ }
1050
+ return key;
1051
+ }
1052
+ /**
1053
+ * Import key from raw data
1054
+ */
1055
+ async importKey(keyData, keyId) {
1056
+ const crypto2 = globalThis.crypto;
1057
+ if (!crypto2) {
1058
+ throw new Error("Crypto API not available");
1059
+ }
1060
+ const key = await crypto2.subtle.importKey(
1061
+ "raw",
1062
+ keyData,
1063
+ {
1064
+ name: this.config.algorithm,
1065
+ length: this.config.keySize
1066
+ },
1067
+ this.config.extractable ?? false,
1068
+ // non-extractable by default — prevents key exfiltration
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
+ }
1144
1252
  };
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))
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");
1151
1272
  }
1152
- };
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
+ });
1428
+ }
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
1455
+ };
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("");
1153
1459
  }
1154
1460
  function generateUUID() {
1155
- if (typeof crypto !== "undefined" && crypto.randomUUID) {
1156
- return crypto.randomUUID();
1461
+ const crypto2 = globalThis.crypto;
1462
+ if (!crypto2) {
1463
+ throw new Error("Crypto API not available");
1157
1464
  }
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);
1162
- });
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/logger.ts
1485
+ var securityLogger = console;
1486
+ function configureSecurityLogger(logger) {
1487
+ securityLogger = logger;
1488
+ }
1489
+ function getSecurityLogger() {
1490
+ return securityLogger;
1491
+ }
1492
+
1493
+ // src/gdpr.ts
1494
+ var ConsentManager = class {
1495
+ storage;
1496
+ consentVersion = "1.0.0";
1497
+ constructor(storage) {
1498
+ this.storage = storage;
1499
+ }
1500
+ /**
1501
+ * Grant consent
1502
+ */
1503
+ async grantConsent(userId, type, source = "explicit", expiresIn) {
1504
+ const consent = {
1505
+ id: crypto.randomUUID(),
1506
+ userId,
1507
+ type,
1508
+ granted: true,
1509
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1510
+ expiresAt: expiresIn ? new Date(Date.now() + expiresIn).toISOString() : void 0,
1511
+ source,
1512
+ version: this.consentVersion
1513
+ };
1514
+ await this.storage.setConsent(userId, type, consent);
1515
+ return consent;
1516
+ }
1517
+ /**
1518
+ * Revoke consent
1519
+ */
1520
+ async revokeConsent(userId, type) {
1521
+ const existing = await this.storage.getConsent(userId, type);
1522
+ if (existing) {
1523
+ existing.granted = false;
1524
+ existing.timestamp = (/* @__PURE__ */ new Date()).toISOString();
1525
+ await this.storage.setConsent(userId, type, existing);
1526
+ }
1527
+ }
1528
+ /**
1529
+ * Check if consent is granted
1530
+ */
1531
+ async hasConsent(userId, type) {
1532
+ const consent = await this.storage.getConsent(userId, type);
1533
+ if (!consent?.granted) {
1534
+ return false;
1535
+ }
1536
+ if (consent.expiresAt && new Date(consent.expiresAt) < /* @__PURE__ */ new Date()) {
1537
+ return false;
1538
+ }
1539
+ return true;
1540
+ }
1541
+ /**
1542
+ * Get all consents for user
1543
+ */
1544
+ async getUserConsents(userId) {
1545
+ return this.storage.getConsentsByUser(userId);
1546
+ }
1547
+ /**
1548
+ * Update consent version
1549
+ */
1550
+ setConsentVersion(version) {
1551
+ this.consentVersion = version;
1552
+ }
1553
+ /**
1554
+ * Check if consent needs renewal
1555
+ */
1556
+ async needsRenewal(userId, type, maxAge) {
1557
+ const consent = await this.storage.getConsent(userId, type);
1558
+ if (!consent?.granted) {
1559
+ return true;
1560
+ }
1561
+ const age = Date.now() - new Date(consent.timestamp).getTime();
1562
+ return age >= maxAge;
1563
+ }
1564
+ /**
1565
+ * Get consent statistics
1566
+ */
1567
+ async getStatistics() {
1568
+ const consents = await this.storage.getAllConsents();
1569
+ const now = /* @__PURE__ */ new Date();
1570
+ const granted = consents.filter((c) => c.granted).length;
1571
+ const revoked = consents.filter((c) => !c.granted).length;
1572
+ const expired = consents.filter((c) => c.expiresAt && new Date(c.expiresAt) < now).length;
1573
+ const byType = consents.reduce(
1574
+ (acc, c) => {
1575
+ acc[c.type] = (acc[c.type] || 0) + 1;
1576
+ return acc;
1577
+ },
1578
+ {}
1579
+ );
1580
+ return {
1581
+ total: consents.length,
1582
+ granted,
1583
+ revoked,
1584
+ expired,
1585
+ byType
1586
+ };
1587
+ }
1588
+ };
1589
+ function escapeCsvField(value) {
1590
+ let safe = /^[=+\-@\t\r]/.test(value) ? `'${value}` : value;
1591
+ safe = safe.replace(/"/g, '""');
1592
+ return `"${safe}"`;
1163
1593
  }
1164
- var SessionRepository = class {
1165
- constructor(payload) {
1166
- this.payload = payload;
1167
- void this.payload;
1594
+ var DataExportSystem = class {
1595
+ /**
1596
+ * Export user data
1597
+ */
1598
+ async exportUserData(userId, getUserData, format = "json") {
1599
+ const data = await getUserData(userId);
1600
+ const exportData = {
1601
+ userId,
1602
+ exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
1603
+ data: {
1604
+ profile: data.profile,
1605
+ activities: data.activities,
1606
+ consents: data.consents,
1607
+ dataProcessing: []
1608
+ },
1609
+ format
1610
+ };
1611
+ return exportData;
1168
1612
  }
1169
- sessions = /* @__PURE__ */ new Map();
1170
- createSessionId() {
1613
+ /**
1614
+ * Format export as JSON
1615
+ */
1616
+ formatAsJSON(exportData) {
1617
+ return JSON.stringify(exportData, null, 2);
1618
+ }
1619
+ /**
1620
+ * Format export as CSV
1621
+ */
1622
+ formatAsCSV(exportData) {
1623
+ const lines = [];
1624
+ lines.push("Type,Key,Value");
1625
+ Object.entries(exportData.data.profile).forEach(([key, value]) => {
1626
+ lines.push(`Profile,${escapeCsvField(key)},${escapeCsvField(String(value))}`);
1627
+ });
1628
+ exportData.data.activities.forEach((activity, index) => {
1629
+ Object.entries(activity).forEach(([key, value]) => {
1630
+ lines.push(`Activity ${index + 1},${escapeCsvField(key)},${escapeCsvField(String(value))}`);
1631
+ });
1632
+ });
1633
+ return lines.join("\n");
1634
+ }
1635
+ /**
1636
+ * Create download link
1637
+ */
1638
+ createDownloadLink(content, _filename, mimeType) {
1639
+ const blob = new Blob([content], { type: mimeType });
1640
+ return URL.createObjectURL(blob);
1641
+ }
1642
+ };
1643
+ var DataDeletionSystem = class {
1644
+ storage;
1645
+ constructor(storage) {
1646
+ this.storage = storage;
1647
+ }
1648
+ /**
1649
+ * Request data deletion
1650
+ */
1651
+ async requestDeletion(userId, dataCategories, reason) {
1652
+ const request = {
1653
+ id: crypto.randomUUID(),
1654
+ userId,
1655
+ requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
1656
+ status: "pending",
1657
+ dataCategories,
1658
+ reason
1659
+ };
1660
+ await this.storage.setDeletionRequest(request);
1661
+ return request;
1662
+ }
1663
+ /**
1664
+ * Process deletion request
1665
+ */
1666
+ async processDeletion(requestId, deleteData) {
1667
+ const request = await this.storage.getDeletionRequest(requestId);
1668
+ if (!request) {
1669
+ throw new Error("Deletion request not found");
1670
+ }
1671
+ request.status = "processing";
1672
+ await this.storage.setDeletionRequest(request);
1171
1673
  try {
1172
- return generateUUID();
1173
- } catch {
1174
- return `session_${Date.now().toString(36)}`;
1674
+ const result = await deleteData(request.userId, request.dataCategories);
1675
+ request.status = "completed";
1676
+ request.processedAt = (/* @__PURE__ */ new Date()).toISOString();
1677
+ request.deletedData = result.deleted;
1678
+ request.retainedData = result.retained;
1679
+ await this.storage.setDeletionRequest(request);
1680
+ } catch (error) {
1681
+ request.status = "failed";
1682
+ await this.storage.setDeletionRequest(request);
1683
+ throw error;
1175
1684
  }
1176
1685
  }
1177
- createToken() {
1178
- try {
1179
- return `token_${generateUUID()}`;
1180
- } catch {
1181
- return `token_${Date.now().toString(36)}`;
1182
- }
1686
+ /**
1687
+ * Get deletion request
1688
+ */
1689
+ async getRequest(requestId) {
1690
+ return this.storage.getDeletionRequest(requestId);
1691
+ }
1692
+ /**
1693
+ * Get user deletion requests
1694
+ */
1695
+ async getUserRequests(userId) {
1696
+ return this.storage.getDeletionRequestsByUser(userId);
1697
+ }
1698
+ /**
1699
+ * Check if data can be deleted
1700
+ */
1701
+ canDelete(_dataCategory, legalBasis) {
1702
+ if (legalBasis === "legal_obligation" || legalBasis === "vital_interest") {
1703
+ return false;
1704
+ }
1705
+ return true;
1706
+ }
1707
+ /**
1708
+ * Calculate retention period
1709
+ */
1710
+ calculateRetentionEnd(createdAt, retentionPeriod) {
1711
+ return new Date(createdAt.getTime() + retentionPeriod * 24 * 60 * 60 * 1e3);
1712
+ }
1713
+ /**
1714
+ * Check if data should be deleted (retention period expired)
1715
+ */
1716
+ shouldDelete(createdAt, retentionPeriod) {
1717
+ const retentionEnd = this.calculateRetentionEnd(createdAt, retentionPeriod);
1718
+ return /* @__PURE__ */ new Date() > retentionEnd;
1719
+ }
1720
+ };
1721
+ function hashValue(value) {
1722
+ const digest = createHash("sha256").update(value).digest("hex");
1723
+ return `hash_${digest}`;
1724
+ }
1725
+ function anonymizeUser(user) {
1726
+ return {
1727
+ ...user,
1728
+ email: hashValue(user.email),
1729
+ name: "Anonymous User",
1730
+ phone: void 0,
1731
+ address: void 0,
1732
+ ip: void 0
1733
+ };
1734
+ }
1735
+ function pseudonymize(value, key) {
1736
+ const hmac = createHmac2("sha256", key).update(value).digest("hex");
1737
+ return `pseudo_${hmac.substring(0, 16)}`;
1738
+ }
1739
+ function anonymizeDataset(data, sensitiveFields) {
1740
+ return data.map((item) => {
1741
+ const anonymized = { ...item };
1742
+ sensitiveFields.forEach((field) => {
1743
+ if (field in anonymized && typeof anonymized[field] === "string") {
1744
+ anonymized[field] = hashValue(anonymized[field]);
1745
+ }
1746
+ });
1747
+ return anonymized;
1748
+ });
1749
+ }
1750
+ function checkKAnonymity(data, quasiIdentifiers, k) {
1751
+ const groups = /* @__PURE__ */ new Map();
1752
+ data.forEach((item) => {
1753
+ const key = quasiIdentifiers.map((field) => String(item[field])).join("|");
1754
+ groups.set(key, (groups.get(key) || 0) + 1);
1755
+ });
1756
+ return Array.from(groups.values()).every((count) => count >= k);
1757
+ }
1758
+ var DataAnonymization = {
1759
+ anonymizeUser,
1760
+ pseudonymize,
1761
+ hashValue,
1762
+ anonymizeDataset,
1763
+ checkKAnonymity
1764
+ };
1765
+ var PrivacyPolicyManager = class {
1766
+ policies = /* @__PURE__ */ new Map();
1767
+ currentVersion = "1.0.0";
1768
+ /**
1769
+ * Add policy version
1770
+ */
1771
+ addPolicy(version, content, effectiveDate) {
1772
+ this.policies.set(version, { version, content, effectiveDate });
1773
+ this.currentVersion = version;
1774
+ }
1775
+ /**
1776
+ * Get current policy
1777
+ */
1778
+ getCurrentPolicy() {
1779
+ return this.policies.get(this.currentVersion);
1780
+ }
1781
+ /**
1782
+ * Get policy by version
1783
+ */
1784
+ getPolicy(version) {
1785
+ return this.policies.get(version);
1786
+ }
1787
+ /**
1788
+ * Check if user accepted current policy
1789
+ */
1790
+ hasAcceptedCurrent(userAcceptedVersion) {
1791
+ return userAcceptedVersion === this.currentVersion;
1183
1792
  }
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 };
1793
+ /**
1794
+ * Get all versions
1795
+ */
1796
+ getAllVersions() {
1797
+ return Array.from(this.policies.keys());
1266
1798
  }
1267
1799
  };
1268
- var SessionService = class {
1269
- repository = null;
1270
- constructor(repository) {
1271
- if (repository) {
1272
- this.repository = repository;
1273
- }
1800
+ var CookieConsentManager = class {
1801
+ config = {
1802
+ necessary: true,
1803
+ functional: false,
1804
+ analytics: false,
1805
+ marketing: false
1806
+ };
1807
+ /**
1808
+ * Set consent configuration
1809
+ */
1810
+ setConsent(config) {
1811
+ this.config = { ...this.config, ...config };
1812
+ this.saveToStorage();
1274
1813
  }
1275
- async getRepository() {
1276
- if (!this.repository) {
1277
- const payload = await getPayloadClient2();
1278
- this.repository = new SessionRepository(payload);
1279
- }
1280
- return this.repository;
1814
+ /**
1815
+ * Get consent configuration
1816
+ */
1817
+ getConsent() {
1818
+ return { ...this.config };
1281
1819
  }
1282
1820
  /**
1283
- * Creates a new session for a user.
1821
+ * Check if specific consent is granted
1284
1822
  */
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;
1823
+ hasConsent(type) {
1824
+ return this.config[type];
1310
1825
  }
1311
1826
  /**
1312
- * Validates a session by ID, checks for expiration, and deletes if expired.
1827
+ * Save to storage
1313
1828
  */
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
- };
1829
+ saveToStorage() {
1830
+ if (typeof localStorage !== "undefined") {
1831
+ localStorage.setItem("cookie-consent", JSON.stringify(this.config));
1375
1832
  }
1376
1833
  }
1377
1834
  /**
1378
- * Invalidates (deletes) a session by ID.
1835
+ * Load from storage
1379
1836
  */
1380
- async invalidateSession(sessionId) {
1381
- try {
1382
- const repository = await this.getRepository();
1383
- const result = await repository.delete(sessionId);
1384
- if (!result.success) {
1837
+ loadFromStorage() {
1838
+ if (typeof localStorage !== "undefined") {
1839
+ const stored = localStorage.getItem("cookie-consent");
1840
+ if (stored) {
1385
1841
  try {
1386
- const payload = await getPayloadClient2();
1387
- payload.logger.error("Session invalidation failed", {
1388
- errors: result.errors
1389
- });
1842
+ const parsed = JSON.parse(stored);
1843
+ if (typeof parsed === "object" && parsed !== null) {
1844
+ this.config = {
1845
+ necessary: true,
1846
+ // always required
1847
+ analytics: typeof parsed.analytics === "boolean" ? parsed.analytics : false,
1848
+ marketing: typeof parsed.marketing === "boolean" ? parsed.marketing : false,
1849
+ functional: typeof parsed.functional === "boolean" ? parsed.functional : true
1850
+ };
1851
+ }
1390
1852
  } catch {
1391
- devLogger3.error("Session invalidation failed", {
1392
- errors: result.errors
1393
- });
1394
1853
  }
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
1854
  }
1405
- return {
1406
- success: false,
1407
- errors: [
1408
- {
1409
- message: "Session invalidation failed",
1410
- path: "invalidateSession"
1411
- }
1412
- ]
1413
- };
1414
1855
  }
1415
1856
  }
1416
1857
  /**
1417
- * Invalidates (deletes) all sessions for a user by userId.
1858
+ * Clear consent
1418
1859
  */
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
- };
1860
+ clearConsent() {
1861
+ this.config = {
1862
+ necessary: true,
1863
+ functional: false,
1864
+ analytics: false,
1865
+ marketing: false
1866
+ };
1867
+ if (typeof localStorage !== "undefined") {
1868
+ localStorage.removeItem("cookie-consent");
1455
1869
  }
1456
1870
  }
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
- }
1469
- }
1470
- return result;
1871
+ };
1872
+ var DataBreachManager = class {
1873
+ storage;
1874
+ constructor(storage) {
1875
+ this.storage = storage;
1471
1876
  }
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
- }
1877
+ /**
1878
+ * Report data breach
1879
+ */
1880
+ async reportBreach(breach) {
1881
+ const fullBreach = {
1882
+ ...breach,
1883
+ id: crypto.randomUUID(),
1884
+ detectedAt: (/* @__PURE__ */ new Date()).toISOString(),
1885
+ status: "detected"
1886
+ };
1887
+ await this.storage.setBreach(fullBreach);
1888
+ if (fullBreach.severity === "critical") {
1889
+ await this.notifyAuthorities(fullBreach);
1486
1890
  }
1487
- return result;
1891
+ return fullBreach;
1488
1892
  }
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;
1893
+ /**
1894
+ * Notify authorities (required within 72 hours under GDPR)
1895
+ */
1896
+ async notifyAuthorities(breach) {
1897
+ await this.storage.updateBreach(breach.id, {
1898
+ reportedAt: (/* @__PURE__ */ new Date()).toISOString(),
1899
+ status: "notified"
1900
+ });
1901
+ getSecurityLogger().info("Breach reported to authorities", { breachId: breach.id });
1503
1902
  }
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
- }
1903
+ /**
1904
+ * Notify affected users
1905
+ */
1906
+ async notifyAffectedUsers(breachId, notifyFn) {
1907
+ const breach = await this.storage.getBreach(breachId);
1908
+ if (!breach) {
1909
+ throw new Error("Breach not found");
1516
1910
  }
1517
- return result;
1911
+ for (const userId of breach.affectedUsers) {
1912
+ await notifyFn(userId, breach);
1913
+ }
1914
+ }
1915
+ /**
1916
+ * Check if breach notification is required
1917
+ */
1918
+ requiresNotification(breach) {
1919
+ return breach.severity === "high" || breach.severity === "critical" || breach.dataCategories.includes("sensitive") || breach.dataCategories.includes("financial");
1920
+ }
1921
+ /**
1922
+ * Get breach
1923
+ */
1924
+ async getBreach(id) {
1925
+ return this.storage.getBreach(id);
1926
+ }
1927
+ /**
1928
+ * Get all breaches
1929
+ */
1930
+ async getAllBreaches() {
1931
+ return this.storage.getAllBreaches();
1518
1932
  }
1519
1933
  };
1520
- var sessionService = new SessionService();
1934
+ function createConsentManager(storage) {
1935
+ return new ConsentManager(storage);
1936
+ }
1937
+ function createDataDeletionSystem(storage) {
1938
+ return new DataDeletionSystem(storage);
1939
+ }
1940
+ var dataExportSystem = new DataExportSystem();
1941
+ var privacyPolicyManager = new PrivacyPolicyManager();
1942
+ var cookieConsentManager = new CookieConsentManager();
1943
+ function createDataBreachManager(storage) {
1944
+ return new DataBreachManager(storage);
1945
+ }
1521
1946
 
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;
1947
+ // src/gdpr-storage.ts
1948
+ var InMemoryBreachStorage = class {
1949
+ breaches = /* @__PURE__ */ new Map();
1950
+ async setBreach(breach) {
1951
+ this.breaches.set(breach.id, breach);
1952
+ }
1953
+ async getBreach(id) {
1954
+ return this.breaches.get(id);
1955
+ }
1956
+ async getAllBreaches() {
1957
+ return Array.from(this.breaches.values());
1958
+ }
1959
+ async updateBreach(id, updates) {
1960
+ const existing = this.breaches.get(id);
1961
+ if (existing) {
1962
+ this.breaches.set(id, { ...existing, ...updates });
1532
1963
  }
1533
1964
  }
1534
1965
  };
1535
- var ErrorCode = {
1536
- TOKEN_INVALID: "TOKEN_INVALID",
1537
- TOKEN_EXPIRED: "TOKEN_EXPIRED",
1538
- AUTHENTICATION_ERROR: "AUTHENTICATION_ERROR",
1539
- INTERNAL_ERROR: "INTERNAL_ERROR"
1966
+ var InMemoryGDPRStorage = class {
1967
+ consents = /* @__PURE__ */ new Map();
1968
+ deletionRequests = /* @__PURE__ */ new Map();
1969
+ // ── Consent Records ──────────────────────────────────────────────
1970
+ async setConsent(userId, type, record) {
1971
+ this.consents.set(`${userId}:${type}`, record);
1972
+ }
1973
+ async getConsent(userId, type) {
1974
+ return this.consents.get(`${userId}:${type}`);
1975
+ }
1976
+ async getConsentsByUser(userId) {
1977
+ return Array.from(this.consents.values()).filter((c) => c.userId === userId);
1978
+ }
1979
+ async getAllConsents() {
1980
+ return Array.from(this.consents.values());
1981
+ }
1982
+ // ── Deletion Requests ────────────────────────────────────────────
1983
+ async setDeletionRequest(request) {
1984
+ this.deletionRequests.set(request.id, request);
1985
+ }
1986
+ async getDeletionRequest(requestId) {
1987
+ return this.deletionRequests.get(requestId);
1988
+ }
1989
+ async getDeletionRequestsByUser(userId) {
1990
+ return Array.from(this.deletionRequests.values()).filter((r) => r.userId === userId);
1991
+ }
1540
1992
  };
1541
- var TokenService = class extends InfrastructureService2 {
1542
- constructor(payload) {
1543
- super(payload, "TokenService");
1544
- this.payload = payload;
1993
+
1994
+ // src/headers.ts
1995
+ var SecurityHeaders = class {
1996
+ config;
1997
+ constructor(config = {}) {
1998
+ this.config = config;
1545
1999
  }
1546
2000
  /**
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
2001
+ * Get all security headers
1551
2002
  */
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
- );
2003
+ getHeaders() {
2004
+ const headers = {};
2005
+ if (this.config.contentSecurityPolicy) {
2006
+ headers["Content-Security-Policy"] = this.buildCSP(this.config.contentSecurityPolicy);
2007
+ }
2008
+ if (this.config.strictTransportSecurity) {
2009
+ headers["Strict-Transport-Security"] = this.buildHSTS(this.config.strictTransportSecurity);
2010
+ }
2011
+ if (this.config.xFrameOptions) {
2012
+ headers["X-Frame-Options"] = this.config.xFrameOptions;
2013
+ }
2014
+ if (this.config.xContentTypeOptions !== false) {
2015
+ headers["X-Content-Type-Options"] = "nosniff";
2016
+ }
2017
+ if (this.config.referrerPolicy) {
2018
+ headers["Referrer-Policy"] = this.config.referrerPolicy;
1584
2019
  }
2020
+ if (this.config.permissionsPolicy) {
2021
+ headers["Permissions-Policy"] = this.buildPermissionsPolicy(this.config.permissionsPolicy);
2022
+ }
2023
+ if (this.config.crossOriginEmbedderPolicy) {
2024
+ headers["Cross-Origin-Embedder-Policy"] = this.config.crossOriginEmbedderPolicy;
2025
+ }
2026
+ if (this.config.crossOriginOpenerPolicy) {
2027
+ headers["Cross-Origin-Opener-Policy"] = this.config.crossOriginOpenerPolicy;
2028
+ }
2029
+ if (this.config.crossOriginResourcePolicy) {
2030
+ headers["Cross-Origin-Resource-Policy"] = this.config.crossOriginResourcePolicy;
2031
+ }
2032
+ return headers;
1585
2033
  }
1586
2034
  /**
1587
- * Verify user by ID using PayloadCMS native functionality
1588
- * @param userId User ID to verify
1589
- * @returns User data if exists
2035
+ * Build Content Security Policy header
1590
2036
  */
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
- );
2037
+ buildCSP(config) {
2038
+ if (typeof config === "string") {
2039
+ return config;
2040
+ }
2041
+ const directives = [];
2042
+ const addDirective = (name, values) => {
2043
+ if (values && values.length > 0) {
2044
+ directives.push(`${name} ${values.join(" ")}`);
2045
+ }
2046
+ };
2047
+ addDirective("default-src", config.defaultSrc);
2048
+ addDirective("script-src", config.scriptSrc);
2049
+ addDirective("style-src", config.styleSrc);
2050
+ addDirective("img-src", config.imgSrc);
2051
+ addDirective("font-src", config.fontSrc);
2052
+ addDirective("connect-src", config.connectSrc);
2053
+ addDirective("frame-src", config.frameSrc);
2054
+ addDirective("object-src", config.objectSrc);
2055
+ addDirective("media-src", config.mediaSrc);
2056
+ addDirective("worker-src", config.workerSrc);
2057
+ addDirective("child-src", config.childSrc);
2058
+ addDirective("form-action", config.formAction);
2059
+ addDirective("frame-ancestors", config.frameAncestors);
2060
+ addDirective("base-uri", config.baseUri);
2061
+ addDirective("manifest-src", config.manifestSrc);
2062
+ if (config.upgradeInsecureRequests) {
2063
+ directives.push("upgrade-insecure-requests");
2064
+ }
2065
+ if (config.blockAllMixedContent) {
2066
+ directives.push("block-all-mixed-content");
2067
+ }
2068
+ if (config.reportUri) {
2069
+ directives.push(`report-uri ${config.reportUri}`);
1618
2070
  }
2071
+ if (config.reportTo) {
2072
+ directives.push(`report-to ${config.reportTo}`);
2073
+ }
2074
+ return directives.join("; ");
1619
2075
  }
1620
2076
  /**
1621
- * Generate password reset token using PayloadCMS native functionality
1622
- * @param email User email address
1623
- * @returns Password reset token
2077
+ * Build HSTS header
1624
2078
  */
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
- );
2079
+ buildHSTS(config) {
2080
+ if (config === true) {
2081
+ return "max-age=31536000; includeSubDomains";
1652
2082
  }
2083
+ if (config === false) {
2084
+ return "";
2085
+ }
2086
+ const parts = [`max-age=${config.maxAge}`];
2087
+ if (config.includeSubDomains) {
2088
+ parts.push("includeSubDomains");
2089
+ }
2090
+ if (config.preload) {
2091
+ parts.push("preload");
2092
+ }
2093
+ return parts.join("; ");
1653
2094
  }
1654
2095
  /**
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.
2096
+ * Build Permissions-Policy header
1662
2097
  */
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
- );
2098
+ buildPermissionsPolicy(config) {
2099
+ if (typeof config === "string") {
2100
+ return config;
1693
2101
  }
2102
+ const policies = [];
2103
+ Object.entries(config).forEach(([feature, origins]) => {
2104
+ if (!origins || origins.length === 0) {
2105
+ policies.push(`${feature}=()`);
2106
+ } else if (origins.includes("*")) {
2107
+ policies.push(`${feature}=*`);
2108
+ } else {
2109
+ const originsList = origins.map((o) => `"${o}"`).join(" ");
2110
+ policies.push(`${feature}=(${originsList})`);
2111
+ }
2112
+ });
2113
+ return policies.join(", ");
1694
2114
  }
1695
2115
  /**
1696
- * Verify email using PayloadCMS native functionality
1697
- * @param token Email verification token
1698
- * @returns Verification success status
2116
+ * Apply headers to response
1699
2117
  */
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
- );
2118
+ applyHeaders(response) {
2119
+ const headers = this.getHeaders();
2120
+ Object.entries(headers).forEach(([name, value]) => {
2121
+ response.headers.set(name, value);
2122
+ });
2123
+ return response;
2124
+ }
2125
+ };
2126
+ var CORSManager = class {
2127
+ config;
2128
+ constructor(config = {}) {
2129
+ this.config = {
2130
+ origin: config.origin ?? [],
2131
+ methods: config.methods || ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"],
2132
+ allowedHeaders: config.allowedHeaders || ["Content-Type", "Authorization"],
2133
+ exposedHeaders: config.exposedHeaders || [],
2134
+ credentials: config.credentials ?? false,
2135
+ maxAge: config.maxAge || 86400,
2136
+ preflightContinue: config.preflightContinue ?? false,
2137
+ optionsSuccessStatus: config.optionsSuccessStatus || 204
2138
+ };
2139
+ }
2140
+ /**
2141
+ * Check if origin is allowed
2142
+ */
2143
+ isOriginAllowed(origin) {
2144
+ const { origin: allowedOrigin } = this.config;
2145
+ if (allowedOrigin === "*") {
2146
+ return true;
2147
+ }
2148
+ if (typeof allowedOrigin === "function") {
2149
+ return allowedOrigin(origin);
2150
+ }
2151
+ if (typeof allowedOrigin === "string") {
2152
+ return origin === allowedOrigin;
1725
2153
  }
2154
+ if (Array.isArray(allowedOrigin)) {
2155
+ return allowedOrigin.includes(origin);
2156
+ }
2157
+ return false;
1726
2158
  }
1727
2159
  /**
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.
2160
+ * Get CORS headers
1735
2161
  */
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
- );
2162
+ getCORSHeaders(origin) {
2163
+ const headers = {};
2164
+ if (this.config.origin !== "*") {
2165
+ headers.Vary = "Origin";
1766
2166
  }
2167
+ if (!this.isOriginAllowed(origin)) {
2168
+ return headers;
2169
+ }
2170
+ headers["Access-Control-Allow-Origin"] = this.config.origin === "*" ? "*" : origin;
2171
+ if (this.config.credentials && this.config.origin !== "*") {
2172
+ headers["Access-Control-Allow-Credentials"] = "true";
2173
+ }
2174
+ if (this.config.exposedHeaders.length > 0) {
2175
+ headers["Access-Control-Expose-Headers"] = this.config.exposedHeaders.join(", ");
2176
+ }
2177
+ return headers;
1767
2178
  }
1768
2179
  /**
1769
- * @inheritdoc
2180
+ * Get preflight headers
1770
2181
  */
1771
- onInitialize() {
1772
- this.logger.info("TokenService initialized with PayloadCMS native auth", {
1773
- serviceName: this.serviceName
1774
- });
2182
+ getPreflightHeaders(origin) {
2183
+ const headers = this.getCORSHeaders(origin);
2184
+ if (!this.isOriginAllowed(origin)) {
2185
+ return headers;
2186
+ }
2187
+ headers["Access-Control-Allow-Methods"] = this.config.methods.join(", ");
2188
+ headers["Access-Control-Allow-Headers"] = this.config.allowedHeaders.join(", ");
2189
+ headers["Access-Control-Max-Age"] = this.config.maxAge.toString();
2190
+ return headers;
2191
+ }
2192
+ /**
2193
+ * Handle CORS request
2194
+ */
2195
+ handleRequest(request) {
2196
+ const origin = request.headers.get("Origin");
2197
+ if (!origin) {
2198
+ return null;
2199
+ }
2200
+ if (request.method === "OPTIONS") {
2201
+ return this.handlePreflight(request, origin);
2202
+ }
2203
+ return null;
1775
2204
  }
1776
2205
  /**
1777
- * @inheritdoc
2206
+ * Handle preflight request
1778
2207
  */
1779
- onCleanup() {
1780
- this.logger.info("TokenService cleaned up", {
1781
- serviceName: this.serviceName
2208
+ handlePreflight(_request, origin) {
2209
+ if (!this.isOriginAllowed(origin)) {
2210
+ return new Response(null, { status: 403 });
2211
+ }
2212
+ const headers = this.getPreflightHeaders(origin);
2213
+ return new Response(null, {
2214
+ status: this.config.optionsSuccessStatus,
2215
+ headers
1782
2216
  });
1783
2217
  }
1784
2218
  /**
1785
- * @inheritdoc
2219
+ * Apply CORS headers to response
1786
2220
  */
1787
- onHealthCheck() {
1788
- this.logger.debug("TokenService health check passed", {
1789
- serviceName: this.serviceName
2221
+ applyHeaders(response, origin) {
2222
+ if (!this.isOriginAllowed(origin)) {
2223
+ return response;
2224
+ }
2225
+ const headers = this.getCORSHeaders(origin);
2226
+ Object.entries(headers).forEach(([name, value]) => {
2227
+ response.headers.set(name, value);
1790
2228
  });
2229
+ return response;
2230
+ }
2231
+ };
2232
+ var SecurityPresets = {
2233
+ /**
2234
+ * Strict security (recommended for production)
2235
+ */
2236
+ strict: () => ({
2237
+ contentSecurityPolicy: {
2238
+ defaultSrc: ["'self'"],
2239
+ scriptSrc: ["'self'"],
2240
+ styleSrc: ["'self'", "'unsafe-inline'"],
2241
+ imgSrc: ["'self'", "data:", "https:"],
2242
+ fontSrc: ["'self'", "data:"],
2243
+ connectSrc: ["'self'"],
2244
+ frameSrc: ["'none'"],
2245
+ objectSrc: ["'none'"],
2246
+ baseUri: ["'self'"],
2247
+ formAction: ["'self'"],
2248
+ frameAncestors: ["'none'"],
2249
+ upgradeInsecureRequests: true
2250
+ },
2251
+ strictTransportSecurity: {
2252
+ maxAge: 31536e3,
2253
+ includeSubDomains: true,
2254
+ preload: true
2255
+ },
2256
+ xFrameOptions: "DENY",
2257
+ xContentTypeOptions: true,
2258
+ referrerPolicy: "strict-origin-when-cross-origin",
2259
+ crossOriginEmbedderPolicy: "require-corp",
2260
+ crossOriginOpenerPolicy: "same-origin",
2261
+ crossOriginResourcePolicy: "same-origin"
2262
+ }),
2263
+ /**
2264
+ * Moderate security (balanced)
2265
+ */
2266
+ moderate: () => ({
2267
+ contentSecurityPolicy: {
2268
+ defaultSrc: ["'self'"],
2269
+ scriptSrc: ["'self'", "'unsafe-inline'"],
2270
+ styleSrc: ["'self'", "'unsafe-inline'"],
2271
+ imgSrc: ["'self'", "data:", "https:"],
2272
+ fontSrc: ["'self'", "data:", "https:"],
2273
+ connectSrc: ["'self'", "https:"],
2274
+ frameAncestors: ["'self'"]
2275
+ },
2276
+ strictTransportSecurity: {
2277
+ maxAge: 31536e3,
2278
+ includeSubDomains: true
2279
+ },
2280
+ xFrameOptions: "SAMEORIGIN",
2281
+ xContentTypeOptions: true,
2282
+ referrerPolicy: "origin-when-cross-origin"
2283
+ }),
2284
+ /**
2285
+ * Development (permissive)
2286
+ */
2287
+ development: () => ({
2288
+ xContentTypeOptions: true,
2289
+ referrerPolicy: "no-referrer-when-downgrade"
2290
+ })
2291
+ };
2292
+ var CORSPresets = {
2293
+ /**
2294
+ * Strict CORS (same origin only)
2295
+ */
2296
+ strict: () => ({
2297
+ origin: [],
2298
+ methods: ["GET", "POST", "PUT", "DELETE"],
2299
+ allowedHeaders: ["Content-Type", "Authorization"],
2300
+ credentials: true,
2301
+ maxAge: 86400
2302
+ }),
2303
+ /**
2304
+ * Moderate CORS (specific origins)
2305
+ */
2306
+ moderate: (allowedOrigins) => ({
2307
+ origin: allowedOrigins,
2308
+ methods: ["GET", "POST", "PUT", "DELETE", "PATCH"],
2309
+ allowedHeaders: ["Content-Type", "Authorization", "X-Requested-With"],
2310
+ exposedHeaders: ["X-Total-Count"],
2311
+ credentials: true,
2312
+ maxAge: 86400
2313
+ }),
2314
+ /**
2315
+ * Permissive CORS (all origins) — development only.
2316
+ * Logs a warning if used when NODE_ENV === 'production'.
2317
+ */
2318
+ permissive: () => {
2319
+ if (process.env.NODE_ENV === "production") {
2320
+ getSecurityLogger().warn(
2321
+ "[SecurityPresets] CORS permissive preset used in production \u2014 this allows all origins. Use moderate() with explicit origins instead."
2322
+ );
2323
+ }
2324
+ return {
2325
+ origin: "*",
2326
+ methods: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"],
2327
+ allowedHeaders: ["*"],
2328
+ credentials: false,
2329
+ maxAge: 86400
2330
+ };
2331
+ },
2332
+ /**
2333
+ * API CORS (public read-only APIs) — credentials disabled.
2334
+ * Logs a warning if used when NODE_ENV === 'production'.
2335
+ */
2336
+ api: () => {
2337
+ if (process.env.NODE_ENV === "production") {
2338
+ getSecurityLogger().warn(
2339
+ '[SecurityPresets] CORS api preset uses origin:"*". For production, pass explicit origins to moderate() instead.'
2340
+ );
2341
+ }
2342
+ return {
2343
+ origin: "*",
2344
+ methods: ["GET", "POST", "PUT", "DELETE", "PATCH"],
2345
+ allowedHeaders: ["Content-Type", "Authorization", "X-API-Key"],
2346
+ exposedHeaders: ["X-RateLimit-Limit", "X-RateLimit-Remaining", "X-RateLimit-Reset"],
2347
+ credentials: false,
2348
+ maxAge: 86400
2349
+ };
1791
2350
  }
1792
2351
  };
1793
- function createTokenService(payload) {
1794
- return new TokenService(payload);
2352
+ function createSecurityMiddleware(securityConfig, corsConfig) {
2353
+ const security = new SecurityHeaders(securityConfig);
2354
+ const cors = new CORSManager(corsConfig);
2355
+ return async (request, next) => {
2356
+ const origin = request.headers.get("Origin");
2357
+ if (origin && request.method === "OPTIONS") {
2358
+ const preflightResponse = cors.handleRequest(request);
2359
+ if (preflightResponse) {
2360
+ return preflightResponse;
2361
+ }
2362
+ }
2363
+ const response = await next();
2364
+ security.applyHeaders(response);
2365
+ if (origin) {
2366
+ cors.applyHeaders(response, origin);
2367
+ }
2368
+ return response;
2369
+ };
2370
+ }
2371
+ function setRateLimitHeaders(response, limit, remaining, reset) {
2372
+ response.headers.set("X-RateLimit-Limit", limit.toString());
2373
+ response.headers.set("X-RateLimit-Remaining", remaining.toString());
2374
+ response.headers.set("X-RateLimit-Reset", reset.toString());
1795
2375
  }
1796
2376
  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
2377
+ AuditReportGenerator,
2378
+ AuditSystem,
2379
+ AuditTrail,
2380
+ AuthorizationSystem,
2381
+ CORSManager,
2382
+ CORSPresets,
2383
+ CommonRoles,
2384
+ ConsentManager,
2385
+ CookieConsentManager,
2386
+ DataAnonymization,
2387
+ DataBreachManager,
2388
+ DataDeletionSystem,
2389
+ DataExportSystem,
2390
+ DataMasking,
2391
+ EncryptionSystem,
2392
+ EnvelopeEncryption,
2393
+ FieldEncryption,
2394
+ InMemoryAuditStorage,
2395
+ InMemoryBreachStorage,
2396
+ InMemoryGDPRStorage,
2397
+ KeyRotationManager,
2398
+ OAuthClient,
2399
+ OAuthProviders,
2400
+ PasswordHasher,
2401
+ PermissionBuilder,
2402
+ PermissionCache,
2403
+ PolicyBuilder,
2404
+ PrivacyPolicyManager,
2405
+ RequirePermission,
2406
+ RequireRole,
2407
+ SecurityHeaders,
2408
+ SecurityPresets,
2409
+ TokenGenerator,
2410
+ TwoFactorAuth,
2411
+ audit,
2412
+ authorization,
2413
+ canAccessResource,
2414
+ checkAttributeAccess,
2415
+ configureSecurityLogger,
2416
+ cookieConsentManager,
2417
+ createAuditMiddleware,
2418
+ createAuthorizationMiddleware,
2419
+ createConsentManager,
2420
+ createDataBreachManager,
2421
+ createDataDeletionSystem,
2422
+ createSecurityMiddleware,
2423
+ dataExportSystem,
2424
+ encryption,
2425
+ permissionCache,
2426
+ privacyPolicyManager,
2427
+ setRateLimitHeaders
1840
2428
  };
1841
2429
  //# sourceMappingURL=index.js.map