@revealui/security 0.2.4 → 0.2.5
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/audit-UF7PIYBU.js +21 -0
- package/dist/audit-UF7PIYBU.js.map +1 -0
- package/dist/chunk-Q5KAPSST.js +429 -0
- package/dist/chunk-Q5KAPSST.js.map +1 -0
- package/dist/index.d.ts +149 -1
- package/dist/index.js +199 -370
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AuditReportGenerator,
|
|
3
|
+
AuditSystem,
|
|
4
|
+
AuditTrail,
|
|
5
|
+
InMemoryAuditStorage,
|
|
6
|
+
audit,
|
|
7
|
+
createAuditMiddleware,
|
|
8
|
+
signAuditEntry,
|
|
9
|
+
verifyAuditEntry
|
|
10
|
+
} from "./chunk-Q5KAPSST.js";
|
|
11
|
+
export {
|
|
12
|
+
AuditReportGenerator,
|
|
13
|
+
AuditSystem,
|
|
14
|
+
AuditTrail,
|
|
15
|
+
InMemoryAuditStorage,
|
|
16
|
+
audit,
|
|
17
|
+
createAuditMiddleware,
|
|
18
|
+
signAuditEntry,
|
|
19
|
+
verifyAuditEntry
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=audit-UF7PIYBU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
// src/audit.ts
|
|
2
|
+
var AuditSystem = class {
|
|
3
|
+
storage;
|
|
4
|
+
filters = [];
|
|
5
|
+
constructor(storage) {
|
|
6
|
+
this.storage = storage;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Replace the backing storage (e.g. swap InMemory for Postgres at startup).
|
|
10
|
+
* Events already written to the old storage are NOT migrated.
|
|
11
|
+
*/
|
|
12
|
+
setStorage(storage) {
|
|
13
|
+
this.storage = storage;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Log audit event
|
|
17
|
+
*/
|
|
18
|
+
async log(event) {
|
|
19
|
+
const fullEvent = {
|
|
20
|
+
...event,
|
|
21
|
+
id: crypto.randomUUID(),
|
|
22
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
23
|
+
};
|
|
24
|
+
const shouldLog = this.filters.every((filter) => filter(fullEvent));
|
|
25
|
+
if (!shouldLog) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
await this.storage.write(fullEvent);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Log authentication event
|
|
32
|
+
*/
|
|
33
|
+
async logAuth(type, actorId, result, metadata) {
|
|
34
|
+
await this.log({
|
|
35
|
+
type,
|
|
36
|
+
severity: result === "failure" ? "medium" : "low",
|
|
37
|
+
actor: {
|
|
38
|
+
id: actorId,
|
|
39
|
+
type: "user"
|
|
40
|
+
},
|
|
41
|
+
action: type.replace("auth.", ""),
|
|
42
|
+
result,
|
|
43
|
+
metadata
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Log data access event
|
|
48
|
+
*/
|
|
49
|
+
async logDataAccess(action, actorId, resourceType, resourceId, result, changes) {
|
|
50
|
+
await this.log({
|
|
51
|
+
type: `data.${action}`,
|
|
52
|
+
severity: action === "delete" ? "high" : "medium",
|
|
53
|
+
actor: {
|
|
54
|
+
id: actorId,
|
|
55
|
+
type: "user"
|
|
56
|
+
},
|
|
57
|
+
resource: {
|
|
58
|
+
type: resourceType,
|
|
59
|
+
id: resourceId
|
|
60
|
+
},
|
|
61
|
+
action,
|
|
62
|
+
result,
|
|
63
|
+
changes
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Log permission change
|
|
68
|
+
*/
|
|
69
|
+
async logPermissionChange(action, actorId, targetUserId, permission, result) {
|
|
70
|
+
await this.log({
|
|
71
|
+
type: `permission.${action}`,
|
|
72
|
+
severity: "high",
|
|
73
|
+
actor: {
|
|
74
|
+
id: actorId,
|
|
75
|
+
type: "user"
|
|
76
|
+
},
|
|
77
|
+
resource: {
|
|
78
|
+
type: "user",
|
|
79
|
+
id: targetUserId
|
|
80
|
+
},
|
|
81
|
+
action,
|
|
82
|
+
result,
|
|
83
|
+
metadata: {
|
|
84
|
+
permission
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Log security event
|
|
90
|
+
*/
|
|
91
|
+
async logSecurityEvent(type, severity, actorId, message, metadata) {
|
|
92
|
+
await this.log({
|
|
93
|
+
type: `security.${type}`,
|
|
94
|
+
severity,
|
|
95
|
+
actor: {
|
|
96
|
+
id: actorId,
|
|
97
|
+
type: "user"
|
|
98
|
+
},
|
|
99
|
+
action: type,
|
|
100
|
+
result: "failure",
|
|
101
|
+
message,
|
|
102
|
+
metadata
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Log GDPR event
|
|
107
|
+
*/
|
|
108
|
+
async logGDPREvent(type, actorId, result, metadata) {
|
|
109
|
+
await this.log({
|
|
110
|
+
type: `gdpr.${type}`,
|
|
111
|
+
severity: "high",
|
|
112
|
+
actor: {
|
|
113
|
+
id: actorId,
|
|
114
|
+
type: "user"
|
|
115
|
+
},
|
|
116
|
+
action: type,
|
|
117
|
+
result,
|
|
118
|
+
metadata
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Query audit logs
|
|
123
|
+
*/
|
|
124
|
+
async query(query) {
|
|
125
|
+
return this.storage.query(query);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Count audit logs
|
|
129
|
+
*/
|
|
130
|
+
async count(query) {
|
|
131
|
+
return this.storage.count(query);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Add filter
|
|
135
|
+
*/
|
|
136
|
+
addFilter(filter) {
|
|
137
|
+
this.filters.push(filter);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Remove filter
|
|
141
|
+
*/
|
|
142
|
+
removeFilter(filter) {
|
|
143
|
+
const index = this.filters.indexOf(filter);
|
|
144
|
+
if (index > -1) {
|
|
145
|
+
this.filters.splice(index, 1);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
var InMemoryAuditStorage = class {
|
|
150
|
+
events = [];
|
|
151
|
+
maxEvents;
|
|
152
|
+
constructor(maxEvents = 1e4) {
|
|
153
|
+
this.maxEvents = maxEvents;
|
|
154
|
+
}
|
|
155
|
+
async write(event) {
|
|
156
|
+
this.events.push(event);
|
|
157
|
+
if (this.events.length > this.maxEvents) {
|
|
158
|
+
this.events.shift();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
async query(query) {
|
|
162
|
+
let results = [...this.events];
|
|
163
|
+
if (query.types && query.types.length > 0) {
|
|
164
|
+
results = results.filter((e) => query.types?.includes(e.type));
|
|
165
|
+
}
|
|
166
|
+
if (query.actorId) {
|
|
167
|
+
results = results.filter((e) => e.actor.id === query.actorId);
|
|
168
|
+
}
|
|
169
|
+
if (query.resourceType) {
|
|
170
|
+
results = results.filter((e) => e.resource?.type === query.resourceType);
|
|
171
|
+
}
|
|
172
|
+
if (query.resourceId) {
|
|
173
|
+
results = results.filter((e) => e.resource?.id === query.resourceId);
|
|
174
|
+
}
|
|
175
|
+
if (query.startDate) {
|
|
176
|
+
const startDate = query.startDate;
|
|
177
|
+
results = results.filter((e) => new Date(e.timestamp) >= startDate);
|
|
178
|
+
}
|
|
179
|
+
if (query.endDate) {
|
|
180
|
+
const endDate = query.endDate;
|
|
181
|
+
results = results.filter((e) => new Date(e.timestamp) <= endDate);
|
|
182
|
+
}
|
|
183
|
+
if (query.severity && query.severity.length > 0) {
|
|
184
|
+
results = results.filter((e) => query.severity?.includes(e.severity));
|
|
185
|
+
}
|
|
186
|
+
if (query.result && query.result.length > 0) {
|
|
187
|
+
results = results.filter((e) => query.result?.includes(e.result));
|
|
188
|
+
}
|
|
189
|
+
results.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
|
|
190
|
+
const offset = query.offset || 0;
|
|
191
|
+
const limit = query.limit || 100;
|
|
192
|
+
return results.slice(offset, offset + limit);
|
|
193
|
+
}
|
|
194
|
+
async count(query) {
|
|
195
|
+
const results = await this.query({ ...query, limit: void 0, offset: void 0 });
|
|
196
|
+
return results.length;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Clear all events
|
|
200
|
+
*/
|
|
201
|
+
clear() {
|
|
202
|
+
this.events = [];
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Get all events
|
|
206
|
+
*/
|
|
207
|
+
getAll() {
|
|
208
|
+
return [...this.events];
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
function AuditTrail(type, action, options) {
|
|
212
|
+
return (_target, _propertyKey, descriptor) => {
|
|
213
|
+
const originalMethod = descriptor.value;
|
|
214
|
+
descriptor.value = async function(...args) {
|
|
215
|
+
const actorId = this.user?.id || "system";
|
|
216
|
+
const before = options?.captureChanges ? args[0] : void 0;
|
|
217
|
+
let result = "success";
|
|
218
|
+
let error;
|
|
219
|
+
try {
|
|
220
|
+
const returnValue = await originalMethod.apply(this, args);
|
|
221
|
+
if (this.audit) {
|
|
222
|
+
await this.audit.log({
|
|
223
|
+
type,
|
|
224
|
+
severity: options?.severity || "medium",
|
|
225
|
+
actor: {
|
|
226
|
+
id: actorId,
|
|
227
|
+
type: "user"
|
|
228
|
+
},
|
|
229
|
+
resource: options?.resourceType ? {
|
|
230
|
+
type: options.resourceType,
|
|
231
|
+
id: args[0]?.id || "unknown"
|
|
232
|
+
} : void 0,
|
|
233
|
+
action,
|
|
234
|
+
result,
|
|
235
|
+
changes: options?.captureChanges ? {
|
|
236
|
+
before,
|
|
237
|
+
after: returnValue
|
|
238
|
+
} : void 0
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
return returnValue;
|
|
242
|
+
} catch (err) {
|
|
243
|
+
result = "failure";
|
|
244
|
+
error = err;
|
|
245
|
+
if (this.audit) {
|
|
246
|
+
await this.audit.log({
|
|
247
|
+
type,
|
|
248
|
+
severity: "high",
|
|
249
|
+
actor: {
|
|
250
|
+
id: actorId,
|
|
251
|
+
type: "user"
|
|
252
|
+
},
|
|
253
|
+
resource: options?.resourceType ? {
|
|
254
|
+
type: options.resourceType,
|
|
255
|
+
id: args[0]?.id || "unknown"
|
|
256
|
+
} : void 0,
|
|
257
|
+
action,
|
|
258
|
+
result,
|
|
259
|
+
message: error.message
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
throw error;
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
return descriptor;
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
function createAuditMiddleware(audit2, getUser) {
|
|
269
|
+
return async (request, next) => {
|
|
270
|
+
const user = getUser(request);
|
|
271
|
+
const startTime = Date.now();
|
|
272
|
+
try {
|
|
273
|
+
const response = await next();
|
|
274
|
+
await audit2.log({
|
|
275
|
+
type: "data.read",
|
|
276
|
+
severity: "low",
|
|
277
|
+
actor: {
|
|
278
|
+
id: user.id,
|
|
279
|
+
type: "user",
|
|
280
|
+
ip: user.ip,
|
|
281
|
+
userAgent: user.userAgent
|
|
282
|
+
},
|
|
283
|
+
action: request.method,
|
|
284
|
+
result: "success",
|
|
285
|
+
metadata: {
|
|
286
|
+
path: request.url,
|
|
287
|
+
duration: Date.now() - startTime,
|
|
288
|
+
status: response.status
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
return response;
|
|
292
|
+
} catch (error) {
|
|
293
|
+
await audit2.log({
|
|
294
|
+
type: "data.read",
|
|
295
|
+
severity: "medium",
|
|
296
|
+
actor: {
|
|
297
|
+
id: user.id,
|
|
298
|
+
type: "user",
|
|
299
|
+
ip: user.ip,
|
|
300
|
+
userAgent: user.userAgent
|
|
301
|
+
},
|
|
302
|
+
action: request.method,
|
|
303
|
+
result: "failure",
|
|
304
|
+
message: error instanceof Error ? error.message : "Unknown error",
|
|
305
|
+
metadata: {
|
|
306
|
+
path: request.url,
|
|
307
|
+
duration: Date.now() - startTime
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
throw error;
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
var AuditReportGenerator = class {
|
|
315
|
+
constructor(audit2) {
|
|
316
|
+
this.audit = audit2;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Generate security report
|
|
320
|
+
*/
|
|
321
|
+
async generateSecurityReport(startDate, endDate) {
|
|
322
|
+
const allEvents = await this.audit.query({
|
|
323
|
+
startDate,
|
|
324
|
+
endDate
|
|
325
|
+
});
|
|
326
|
+
const securityViolations = allEvents.filter((e) => e.type.startsWith("security.")).length;
|
|
327
|
+
const failedLogins = allEvents.filter((e) => e.type === "auth.failed_login").length;
|
|
328
|
+
const permissionChanges = allEvents.filter((e) => e.type.startsWith("permission.")).length;
|
|
329
|
+
const dataExports = allEvents.filter((e) => e.type === "data.export").length;
|
|
330
|
+
const criticalEvents = allEvents.filter((e) => e.severity === "critical");
|
|
331
|
+
return {
|
|
332
|
+
totalEvents: allEvents.length,
|
|
333
|
+
securityViolations,
|
|
334
|
+
failedLogins,
|
|
335
|
+
permissionChanges,
|
|
336
|
+
dataExports,
|
|
337
|
+
criticalEvents
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Generate user activity report
|
|
342
|
+
*/
|
|
343
|
+
async generateUserActivityReport(userId, startDate, endDate) {
|
|
344
|
+
const events = await this.audit.query({
|
|
345
|
+
actorId: userId,
|
|
346
|
+
startDate,
|
|
347
|
+
endDate
|
|
348
|
+
});
|
|
349
|
+
const actionsByType = events.reduce(
|
|
350
|
+
(acc, event) => {
|
|
351
|
+
acc[event.type] = (acc[event.type] || 0) + 1;
|
|
352
|
+
return acc;
|
|
353
|
+
},
|
|
354
|
+
{}
|
|
355
|
+
);
|
|
356
|
+
const failedActions = events.filter((e) => e.result === "failure").length;
|
|
357
|
+
return {
|
|
358
|
+
totalActions: events.length,
|
|
359
|
+
actionsByType,
|
|
360
|
+
failedActions,
|
|
361
|
+
recentActions: events.slice(0, 10)
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Generate compliance report
|
|
366
|
+
*/
|
|
367
|
+
async generateComplianceReport(startDate, endDate) {
|
|
368
|
+
const events = await this.audit.query({
|
|
369
|
+
startDate,
|
|
370
|
+
endDate
|
|
371
|
+
});
|
|
372
|
+
const dataAccesses = events.filter((e) => e.type === "data.read").length;
|
|
373
|
+
const dataModifications = events.filter(
|
|
374
|
+
(e) => e.type === "data.update" || e.type === "data.create"
|
|
375
|
+
).length;
|
|
376
|
+
const dataDeletions = events.filter((e) => e.type === "data.delete").length;
|
|
377
|
+
const gdprRequests = events.filter((e) => e.type.startsWith("gdpr.")).length;
|
|
378
|
+
const auditTrailComplete = this.checkAuditTrailContinuity(events);
|
|
379
|
+
return {
|
|
380
|
+
dataAccesses,
|
|
381
|
+
dataModifications,
|
|
382
|
+
dataDeletions,
|
|
383
|
+
gdprRequests,
|
|
384
|
+
auditTrailComplete
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Check audit trail continuity
|
|
389
|
+
*/
|
|
390
|
+
checkAuditTrailContinuity(events) {
|
|
391
|
+
if (events.length === 0) return true;
|
|
392
|
+
const sorted = events.sort(
|
|
393
|
+
(a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
|
|
394
|
+
);
|
|
395
|
+
return sorted.length > 0;
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
async function signAuditEntry(entry, secret) {
|
|
399
|
+
const { createHmac } = await import("crypto");
|
|
400
|
+
const canonical = JSON.stringify({
|
|
401
|
+
timestamp: entry.timestamp,
|
|
402
|
+
eventType: entry.eventType,
|
|
403
|
+
severity: entry.severity,
|
|
404
|
+
agentId: entry.agentId,
|
|
405
|
+
payload: entry.payload
|
|
406
|
+
});
|
|
407
|
+
return createHmac("sha256", secret).update(canonical).digest("hex");
|
|
408
|
+
}
|
|
409
|
+
async function verifyAuditEntry(entry, signature, secret) {
|
|
410
|
+
const { timingSafeEqual } = await import("crypto");
|
|
411
|
+
const expected = await signAuditEntry(entry, secret);
|
|
412
|
+
if (expected.length !== signature.length) {
|
|
413
|
+
return false;
|
|
414
|
+
}
|
|
415
|
+
return timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
|
|
416
|
+
}
|
|
417
|
+
var audit = new AuditSystem(new InMemoryAuditStorage());
|
|
418
|
+
|
|
419
|
+
export {
|
|
420
|
+
AuditSystem,
|
|
421
|
+
InMemoryAuditStorage,
|
|
422
|
+
AuditTrail,
|
|
423
|
+
createAuditMiddleware,
|
|
424
|
+
AuditReportGenerator,
|
|
425
|
+
signAuditEntry,
|
|
426
|
+
verifyAuditEntry,
|
|
427
|
+
audit
|
|
428
|
+
};
|
|
429
|
+
//# sourceMappingURL=chunk-Q5KAPSST.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/audit.ts"],"sourcesContent":["/**\n * Audit Logging System\n *\n * Track security-relevant events and user actions for compliance\n */\n\nexport type AuditEventType =\n | 'auth.login'\n | 'auth.logout'\n | 'auth.failed_login'\n | 'auth.password_change'\n | 'auth.password_reset'\n | 'auth.mfa_enabled'\n | 'auth.mfa_disabled'\n | 'user.create'\n | 'user.update'\n | 'user.delete'\n | 'user.view'\n | 'data.create'\n | 'data.read'\n | 'data.update'\n | 'data.delete'\n | 'data.export'\n | 'permission.grant'\n | 'permission.revoke'\n | 'role.assign'\n | 'role.remove'\n | 'config.change'\n | 'security.violation'\n | 'security.alert'\n | 'gdpr.consent'\n | 'gdpr.data_request'\n | 'gdpr.data_deletion'\n | `data.${string}`\n | `permission.${string}`\n | `security.${string}`\n | `gdpr.${string}`;\n\nexport type AuditSeverity = 'low' | 'medium' | 'high' | 'critical';\n\nexport interface AuditEvent {\n id: string;\n timestamp: string;\n type: AuditEventType;\n severity: AuditSeverity;\n actor: {\n id: string;\n type: 'user' | 'system' | 'api';\n ip?: string;\n userAgent?: string;\n };\n resource?: {\n type: string;\n id: string;\n name?: string;\n };\n action: string;\n result: 'success' | 'failure' | 'partial';\n changes?: {\n before?: Record<string, unknown>;\n after?: Record<string, unknown>;\n };\n metadata?: Record<string, unknown>;\n message?: string;\n}\n\nexport interface AuditQuery {\n types?: AuditEventType[];\n actorId?: string;\n resourceType?: string;\n resourceId?: string;\n startDate?: Date;\n endDate?: Date;\n severity?: AuditSeverity[];\n result?: ('success' | 'failure' | 'partial')[];\n limit?: number;\n offset?: number;\n}\n\nexport interface AuditStorage {\n write(event: AuditEvent): Promise<void>;\n query(query: AuditQuery): Promise<AuditEvent[]>;\n count(query: AuditQuery): Promise<number>;\n}\n\n/**\n * Audit logging system\n */\nexport class AuditSystem {\n private storage: AuditStorage;\n private filters: Array<(event: AuditEvent) => boolean> = [];\n\n constructor(storage: AuditStorage) {\n this.storage = storage;\n }\n\n /**\n * Replace the backing storage (e.g. swap InMemory for Postgres at startup).\n * Events already written to the old storage are NOT migrated.\n */\n setStorage(storage: AuditStorage): void {\n this.storage = storage;\n }\n\n /**\n * Log audit event\n */\n async log(event: Omit<AuditEvent, 'id' | 'timestamp'>): Promise<void> {\n const fullEvent: AuditEvent = {\n ...event,\n id: crypto.randomUUID(),\n timestamp: new Date().toISOString(),\n };\n\n // Apply filters\n const shouldLog = this.filters.every((filter) => filter(fullEvent));\n\n if (!shouldLog) {\n return;\n }\n\n await this.storage.write(fullEvent);\n }\n\n /**\n * Log authentication event\n */\n async logAuth(\n type: Extract<\n AuditEventType,\n 'auth.login' | 'auth.logout' | 'auth.failed_login' | 'auth.password_change'\n >,\n actorId: string,\n result: 'success' | 'failure',\n metadata?: Record<string, unknown>,\n ): Promise<void> {\n await this.log({\n type,\n severity: result === 'failure' ? 'medium' : 'low',\n actor: {\n id: actorId,\n type: 'user',\n },\n action: (type as string).replace('auth.', ''),\n result,\n metadata,\n });\n }\n\n /**\n * Log data access event\n */\n async logDataAccess(\n action: 'create' | 'read' | 'update' | 'delete',\n actorId: string,\n resourceType: string,\n resourceId: string,\n result: 'success' | 'failure',\n changes?: { before?: Record<string, unknown>; after?: Record<string, unknown> },\n ): Promise<void> {\n await this.log({\n type: `data.${action}` as AuditEventType,\n severity: action === 'delete' ? 'high' : 'medium',\n actor: {\n id: actorId,\n type: 'user',\n },\n resource: {\n type: resourceType,\n id: resourceId,\n },\n action,\n result,\n changes,\n });\n }\n\n /**\n * Log permission change\n */\n async logPermissionChange(\n action: 'grant' | 'revoke',\n actorId: string,\n targetUserId: string,\n permission: string,\n result: 'success' | 'failure',\n ): Promise<void> {\n await this.log({\n type: `permission.${action}` as AuditEventType,\n severity: 'high',\n actor: {\n id: actorId,\n type: 'user',\n },\n resource: {\n type: 'user',\n id: targetUserId,\n },\n action,\n result,\n metadata: {\n permission,\n },\n });\n }\n\n /**\n * Log security event\n */\n async logSecurityEvent(\n type: 'violation' | 'alert',\n severity: AuditSeverity,\n actorId: string,\n message: string,\n metadata?: Record<string, unknown>,\n ): Promise<void> {\n await this.log({\n type: `security.${type}` as AuditEventType,\n severity,\n actor: {\n id: actorId,\n type: 'user',\n },\n action: type,\n result: 'failure',\n message,\n metadata,\n });\n }\n\n /**\n * Log GDPR event\n */\n async logGDPREvent(\n type: 'consent' | 'data_request' | 'data_deletion',\n actorId: string,\n result: 'success' | 'failure',\n metadata?: Record<string, unknown>,\n ): Promise<void> {\n await this.log({\n type: `gdpr.${type}` as AuditEventType,\n severity: 'high',\n actor: {\n id: actorId,\n type: 'user',\n },\n action: type,\n result,\n metadata,\n });\n }\n\n /**\n * Query audit logs\n */\n async query(query: AuditQuery): Promise<AuditEvent[]> {\n return this.storage.query(query);\n }\n\n /**\n * Count audit logs\n */\n async count(query: AuditQuery): Promise<number> {\n return this.storage.count(query);\n }\n\n /**\n * Add filter\n */\n addFilter(filter: (event: AuditEvent) => boolean): void {\n this.filters.push(filter);\n }\n\n /**\n * Remove filter\n */\n removeFilter(filter: (event: AuditEvent) => boolean): void {\n const index = this.filters.indexOf(filter);\n if (index > -1) {\n this.filters.splice(index, 1);\n }\n }\n}\n\n/**\n * In-memory audit storage (for development)\n */\nexport class InMemoryAuditStorage implements AuditStorage {\n private events: AuditEvent[] = [];\n private maxEvents: number;\n\n constructor(maxEvents: number = 10000) {\n this.maxEvents = maxEvents;\n }\n\n async write(event: AuditEvent): Promise<void> {\n this.events.push(event);\n\n // Trim old events\n if (this.events.length > this.maxEvents) {\n this.events.shift();\n }\n }\n\n async query(query: AuditQuery): Promise<AuditEvent[]> {\n let results = [...this.events];\n\n // Filter by type\n if (query.types && query.types.length > 0) {\n results = results.filter((e) => query.types?.includes(e.type));\n }\n\n // Filter by actor\n if (query.actorId) {\n results = results.filter((e) => e.actor.id === query.actorId);\n }\n\n // Filter by resource\n if (query.resourceType) {\n results = results.filter((e) => e.resource?.type === query.resourceType);\n }\n\n if (query.resourceId) {\n results = results.filter((e) => e.resource?.id === query.resourceId);\n }\n\n // Filter by date range\n if (query.startDate) {\n const startDate = query.startDate;\n results = results.filter((e) => new Date(e.timestamp) >= startDate);\n }\n\n if (query.endDate) {\n const endDate = query.endDate;\n results = results.filter((e) => new Date(e.timestamp) <= endDate);\n }\n\n // Filter by severity\n if (query.severity && query.severity.length > 0) {\n results = results.filter((e) => query.severity?.includes(e.severity));\n }\n\n // Filter by result\n if (query.result && query.result.length > 0) {\n results = results.filter((e) => query.result?.includes(e.result));\n }\n\n // Sort by timestamp (newest first)\n results.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());\n\n // Apply pagination\n const offset = query.offset || 0;\n const limit = query.limit || 100;\n\n return results.slice(offset, offset + limit);\n }\n\n async count(query: AuditQuery): Promise<number> {\n const results = await this.query({ ...query, limit: undefined, offset: undefined });\n return results.length;\n }\n\n /**\n * Clear all events\n */\n clear(): void {\n this.events = [];\n }\n\n /**\n * Get all events\n */\n getAll(): AuditEvent[] {\n return [...this.events];\n }\n}\n\n/**\n * Audit trail decorator\n */\nexport function AuditTrail(\n type: AuditEventType,\n action: string,\n options?: {\n severity?: AuditSeverity;\n captureChanges?: boolean;\n resourceType?: string;\n },\n) {\n return (_target: object, _propertyKey: string, descriptor: PropertyDescriptor) => {\n const originalMethod = descriptor.value;\n\n descriptor.value = async function (\n this: { user?: { id?: string }; audit?: AuditSystem },\n ...args: unknown[]\n ) {\n const actorId = this.user?.id || 'system';\n const before = options?.captureChanges ? args[0] : undefined;\n\n let result: 'success' | 'failure' | 'partial' = 'success';\n let error: Error | undefined;\n\n try {\n const returnValue = await originalMethod.apply(this, args);\n\n // Log audit event\n if (this.audit) {\n await this.audit.log({\n type,\n severity: options?.severity || 'medium',\n actor: {\n id: actorId,\n type: 'user',\n },\n resource: options?.resourceType\n ? {\n type: options.resourceType,\n id: (args[0] as { id?: string })?.id || 'unknown',\n }\n : undefined,\n action,\n result,\n changes: options?.captureChanges\n ? {\n before: before as Record<string, unknown> | undefined,\n after: returnValue as Record<string, unknown> | undefined,\n }\n : undefined,\n });\n }\n\n return returnValue;\n } catch (err) {\n result = 'failure';\n error = err as Error;\n\n // Log failure\n if (this.audit) {\n await this.audit.log({\n type,\n severity: 'high',\n actor: {\n id: actorId,\n type: 'user',\n },\n resource: options?.resourceType\n ? {\n type: options.resourceType,\n id: (args[0] as { id?: string })?.id || 'unknown',\n }\n : undefined,\n action,\n result,\n message: error.message,\n });\n }\n\n throw error;\n }\n };\n\n return descriptor;\n };\n}\n\n/**\n * Audit middleware\n */\nexport function createAuditMiddleware<TRequest = unknown, TResponse = unknown>(\n audit: AuditSystem,\n getUser: (request: TRequest) => { id: string; ip?: string; userAgent?: string },\n) {\n return async (\n request: TRequest & { method: string; url: string },\n next: () => Promise<TResponse & { status?: number }>,\n ) => {\n const user = getUser(request);\n const startTime = Date.now();\n\n try {\n const response = await next();\n\n // Log successful request\n await audit.log({\n type: 'data.read',\n severity: 'low',\n actor: {\n id: user.id,\n type: 'user',\n ip: user.ip,\n userAgent: user.userAgent,\n },\n action: request.method,\n result: 'success',\n metadata: {\n path: request.url,\n duration: Date.now() - startTime,\n status: response.status,\n },\n });\n\n return response;\n } catch (error) {\n // Log failed request\n await audit.log({\n type: 'data.read',\n severity: 'medium',\n actor: {\n id: user.id,\n type: 'user',\n ip: user.ip,\n userAgent: user.userAgent,\n },\n action: request.method,\n result: 'failure',\n message: error instanceof Error ? error.message : 'Unknown error',\n metadata: {\n path: request.url,\n duration: Date.now() - startTime,\n },\n });\n\n throw error;\n }\n };\n}\n\n/**\n * Audit report generator\n */\nexport class AuditReportGenerator {\n constructor(private audit: AuditSystem) {}\n\n /**\n * Generate security report\n */\n async generateSecurityReport(\n startDate: Date,\n endDate: Date,\n ): Promise<{\n totalEvents: number;\n securityViolations: number;\n failedLogins: number;\n permissionChanges: number;\n dataExports: number;\n criticalEvents: AuditEvent[];\n }> {\n const allEvents = await this.audit.query({\n startDate,\n endDate,\n });\n\n const securityViolations = allEvents.filter((e) => e.type.startsWith('security.')).length;\n\n const failedLogins = allEvents.filter((e) => e.type === 'auth.failed_login').length;\n\n const permissionChanges = allEvents.filter((e) => e.type.startsWith('permission.')).length;\n\n const dataExports = allEvents.filter((e) => e.type === 'data.export').length;\n\n const criticalEvents = allEvents.filter((e) => e.severity === 'critical');\n\n return {\n totalEvents: allEvents.length,\n securityViolations,\n failedLogins,\n permissionChanges,\n dataExports,\n criticalEvents,\n };\n }\n\n /**\n * Generate user activity report\n */\n async generateUserActivityReport(\n userId: string,\n startDate: Date,\n endDate: Date,\n ): Promise<{\n totalActions: number;\n actionsByType: Record<string, number>;\n failedActions: number;\n recentActions: AuditEvent[];\n }> {\n const events = await this.audit.query({\n actorId: userId,\n startDate,\n endDate,\n });\n\n const actionsByType = events.reduce(\n (acc, event) => {\n acc[event.type] = (acc[event.type] || 0) + 1;\n return acc;\n },\n {} as Record<string, number>,\n );\n\n const failedActions = events.filter((e) => e.result === 'failure').length;\n\n return {\n totalActions: events.length,\n actionsByType,\n failedActions,\n recentActions: events.slice(0, 10),\n };\n }\n\n /**\n * Generate compliance report\n */\n async generateComplianceReport(\n startDate: Date,\n endDate: Date,\n ): Promise<{\n dataAccesses: number;\n dataModifications: number;\n dataDeletions: number;\n gdprRequests: number;\n auditTrailComplete: boolean;\n }> {\n const events = await this.audit.query({\n startDate,\n endDate,\n });\n\n const dataAccesses = events.filter((e) => e.type === 'data.read').length;\n\n const dataModifications = events.filter(\n (e) => e.type === 'data.update' || e.type === 'data.create',\n ).length;\n\n const dataDeletions = events.filter((e) => e.type === 'data.delete').length;\n\n const gdprRequests = events.filter((e) => e.type.startsWith('gdpr.')).length;\n\n // Check if audit trail is complete (no gaps)\n const auditTrailComplete = this.checkAuditTrailContinuity(events);\n\n return {\n dataAccesses,\n dataModifications,\n dataDeletions,\n gdprRequests,\n auditTrailComplete,\n };\n }\n\n /**\n * Check audit trail continuity\n */\n private checkAuditTrailContinuity(events: AuditEvent[]): boolean {\n if (events.length === 0) return true;\n\n // Sort by timestamp\n const sorted = events.sort(\n (a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime(),\n );\n\n // Check for gaps (simplified - just check if we have events)\n return sorted.length > 0;\n }\n}\n\n// =============================================================================\n// Audit Log Integrity — HMAC-SHA256 Signing\n// =============================================================================\n\n/** Fields included in the HMAC signature for tamper detection. */\ninterface SignableFields {\n timestamp: string;\n eventType: string;\n severity: string;\n agentId: string;\n payload: unknown;\n}\n\n/**\n * Compute an HMAC-SHA256 signature over the canonical fields of an audit entry.\n *\n * The signature covers `timestamp`, `eventType`, `severity`, `agentId`, and\n * `payload` — the immutable core of every audit record. Changing any of\n * these fields after signing will cause verification to fail.\n *\n * @param entry - The audit entry fields to sign\n * @param secret - The HMAC secret key\n * @returns Hex-encoded HMAC-SHA256 signature\n */\nexport async function signAuditEntry(entry: SignableFields, secret: string): Promise<string> {\n const { createHmac } = await import('node:crypto');\n const canonical = JSON.stringify({\n timestamp: entry.timestamp,\n eventType: entry.eventType,\n severity: entry.severity,\n agentId: entry.agentId,\n payload: entry.payload,\n });\n return createHmac('sha256', secret).update(canonical).digest('hex');\n}\n\n/**\n * Verify an HMAC-SHA256 signature against the canonical fields of an audit entry.\n *\n * Uses timing-safe comparison to prevent timing attacks.\n *\n * @param entry - The audit entry fields to verify\n * @param signature - The hex-encoded HMAC-SHA256 signature to verify\n * @param secret - The HMAC secret key\n * @returns True if the signature is valid\n */\nexport async function verifyAuditEntry(\n entry: SignableFields,\n signature: string,\n secret: string,\n): Promise<boolean> {\n const { timingSafeEqual } = await import('node:crypto');\n const expected = await signAuditEntry(entry, secret);\n\n // Lengths must match for timingSafeEqual\n if (expected.length !== signature.length) {\n return false;\n }\n\n return timingSafeEqual(Buffer.from(expected), Buffer.from(signature));\n}\n\n/**\n * Global audit system\n */\nexport const audit = new AuditSystem(new InMemoryAuditStorage());\n"],"mappings":"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","names":["audit"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -54,6 +54,11 @@ declare class AuditSystem {
|
|
|
54
54
|
private storage;
|
|
55
55
|
private filters;
|
|
56
56
|
constructor(storage: AuditStorage);
|
|
57
|
+
/**
|
|
58
|
+
* Replace the backing storage (e.g. swap InMemory for Postgres at startup).
|
|
59
|
+
* Events already written to the old storage are NOT migrated.
|
|
60
|
+
*/
|
|
61
|
+
setStorage(storage: AuditStorage): void;
|
|
57
62
|
/**
|
|
58
63
|
* Log audit event
|
|
59
64
|
*/
|
|
@@ -181,11 +186,154 @@ declare class AuditReportGenerator {
|
|
|
181
186
|
*/
|
|
182
187
|
private checkAuditTrailContinuity;
|
|
183
188
|
}
|
|
189
|
+
/** Fields included in the HMAC signature for tamper detection. */
|
|
190
|
+
interface SignableFields {
|
|
191
|
+
timestamp: string;
|
|
192
|
+
eventType: string;
|
|
193
|
+
severity: string;
|
|
194
|
+
agentId: string;
|
|
195
|
+
payload: unknown;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Compute an HMAC-SHA256 signature over the canonical fields of an audit entry.
|
|
199
|
+
*
|
|
200
|
+
* The signature covers `timestamp`, `eventType`, `severity`, `agentId`, and
|
|
201
|
+
* `payload` — the immutable core of every audit record. Changing any of
|
|
202
|
+
* these fields after signing will cause verification to fail.
|
|
203
|
+
*
|
|
204
|
+
* @param entry - The audit entry fields to sign
|
|
205
|
+
* @param secret - The HMAC secret key
|
|
206
|
+
* @returns Hex-encoded HMAC-SHA256 signature
|
|
207
|
+
*/
|
|
208
|
+
declare function signAuditEntry(entry: SignableFields, secret: string): Promise<string>;
|
|
209
|
+
/**
|
|
210
|
+
* Verify an HMAC-SHA256 signature against the canonical fields of an audit entry.
|
|
211
|
+
*
|
|
212
|
+
* Uses timing-safe comparison to prevent timing attacks.
|
|
213
|
+
*
|
|
214
|
+
* @param entry - The audit entry fields to verify
|
|
215
|
+
* @param signature - The hex-encoded HMAC-SHA256 signature to verify
|
|
216
|
+
* @param secret - The HMAC secret key
|
|
217
|
+
* @returns True if the signature is valid
|
|
218
|
+
*/
|
|
219
|
+
declare function verifyAuditEntry(entry: SignableFields, signature: string, secret: string): Promise<boolean>;
|
|
184
220
|
/**
|
|
185
221
|
* Global audit system
|
|
186
222
|
*/
|
|
187
223
|
declare const audit: AuditSystem;
|
|
188
224
|
|
|
225
|
+
/**
|
|
226
|
+
* Security Alerting Service
|
|
227
|
+
*
|
|
228
|
+
* Evaluates audit events against configurable threshold rules and
|
|
229
|
+
* dispatches alerts through pluggable handlers (logging, audit trail,
|
|
230
|
+
* webhook / SIEM integration).
|
|
231
|
+
*/
|
|
232
|
+
|
|
233
|
+
/** A security alert produced when a threshold is breached. */
|
|
234
|
+
interface SecurityAlert {
|
|
235
|
+
/** Alert rule that triggered (e.g. 'failedLogins', 'accountLockout'). */
|
|
236
|
+
type: string;
|
|
237
|
+
/** Severity of the alert. */
|
|
238
|
+
severity: AuditSeverity;
|
|
239
|
+
/** Human-readable description. */
|
|
240
|
+
message: string;
|
|
241
|
+
/** Contextual data attached to the alert. */
|
|
242
|
+
context: Record<string, unknown>;
|
|
243
|
+
/** When the alert was raised (ISO-8601). */
|
|
244
|
+
timestamp: string;
|
|
245
|
+
}
|
|
246
|
+
/** Handler that receives dispatched security alerts. */
|
|
247
|
+
interface AlertHandler {
|
|
248
|
+
/** Process a single alert. */
|
|
249
|
+
handle(alert: SecurityAlert): Promise<void>;
|
|
250
|
+
}
|
|
251
|
+
/** Configuration for a single threshold rule. */
|
|
252
|
+
interface ThresholdRule {
|
|
253
|
+
/** Maximum event count before an alert fires. */
|
|
254
|
+
maxCount: number;
|
|
255
|
+
/** Sliding window duration in milliseconds. */
|
|
256
|
+
windowMs: number;
|
|
257
|
+
/** Severity assigned to alerts from this rule. */
|
|
258
|
+
severity: AuditSeverity;
|
|
259
|
+
/** Human-readable message template — `{count}` is replaced at runtime. */
|
|
260
|
+
messageTemplate: string;
|
|
261
|
+
}
|
|
262
|
+
/** Top-level configuration for the alerting service. */
|
|
263
|
+
interface AlertingConfig {
|
|
264
|
+
/** Threshold rules keyed by rule name. */
|
|
265
|
+
thresholds: Record<string, ThresholdRule>;
|
|
266
|
+
/** Handlers that receive dispatched alerts. */
|
|
267
|
+
handlers: AlertHandler[];
|
|
268
|
+
}
|
|
269
|
+
/** Default threshold rules aligned with SOC2 6.2 requirements. */
|
|
270
|
+
declare const DEFAULT_THRESHOLDS: Record<string, ThresholdRule>;
|
|
271
|
+
/**
|
|
272
|
+
* Logs alerts to the structured security logger.
|
|
273
|
+
*/
|
|
274
|
+
declare class LogAlertHandler implements AlertHandler {
|
|
275
|
+
/** Write alert details to the configured security logger. */
|
|
276
|
+
handle(alert: SecurityAlert): Promise<void>;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Writes alerts as critical audit events into the audit log.
|
|
280
|
+
*/
|
|
281
|
+
declare class AuditAlertHandler implements AlertHandler {
|
|
282
|
+
/** Record the alert in the audit trail with severity 'critical'. */
|
|
283
|
+
handle(alert: SecurityAlert): Promise<void>;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* POSTs alerts to a configurable webhook URL for SIEM integration.
|
|
287
|
+
*/
|
|
288
|
+
declare class WebhookAlertHandler implements AlertHandler {
|
|
289
|
+
private url;
|
|
290
|
+
private headers;
|
|
291
|
+
/**
|
|
292
|
+
* Create a webhook alert handler.
|
|
293
|
+
*
|
|
294
|
+
* @param url - The webhook endpoint URL
|
|
295
|
+
* @param headers - Additional HTTP headers (e.g. authorization)
|
|
296
|
+
*/
|
|
297
|
+
constructor(url: string, headers?: Record<string, string>);
|
|
298
|
+
/** POST the alert payload to the configured webhook URL. */
|
|
299
|
+
handle(alert: SecurityAlert): Promise<void>;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Evaluates audit events against threshold rules and dispatches alerts.
|
|
303
|
+
*
|
|
304
|
+
* Maintains an in-memory sliding window per rule/group key. When the
|
|
305
|
+
* event count within the window exceeds the threshold, an alert is
|
|
306
|
+
* dispatched to all configured handlers.
|
|
307
|
+
*/
|
|
308
|
+
declare class SecurityAlertService {
|
|
309
|
+
private config;
|
|
310
|
+
private windows;
|
|
311
|
+
/**
|
|
312
|
+
* Create a new SecurityAlertService.
|
|
313
|
+
*
|
|
314
|
+
* @param config - Alerting configuration with thresholds and handlers
|
|
315
|
+
*/
|
|
316
|
+
constructor(config: AlertingConfig);
|
|
317
|
+
/**
|
|
318
|
+
* Evaluate a single audit event against all threshold rules.
|
|
319
|
+
* If a threshold is breached, dispatches alerts to all handlers.
|
|
320
|
+
*
|
|
321
|
+
* @param event - The audit event to evaluate
|
|
322
|
+
* @returns The alert that was dispatched, or null if no threshold was breached
|
|
323
|
+
*/
|
|
324
|
+
evaluateEvent(event: AuditEvent): Promise<SecurityAlert | null>;
|
|
325
|
+
/**
|
|
326
|
+
* Clear all sliding window state. Useful for testing.
|
|
327
|
+
*/
|
|
328
|
+
reset(): void;
|
|
329
|
+
/**
|
|
330
|
+
* Dispatch an alert to all configured handlers.
|
|
331
|
+
* Errors in individual handlers are logged but do not prevent
|
|
332
|
+
* other handlers from receiving the alert.
|
|
333
|
+
*/
|
|
334
|
+
private dispatchAlert;
|
|
335
|
+
}
|
|
336
|
+
|
|
189
337
|
/**
|
|
190
338
|
* Authentication Utilities
|
|
191
339
|
*
|
|
@@ -1356,4 +1504,4 @@ interface SecurityLogger {
|
|
|
1356
1504
|
*/
|
|
1357
1505
|
declare function configureSecurityLogger(logger: SecurityLogger): void;
|
|
1358
1506
|
|
|
1359
|
-
export { type AuditEvent, type AuditEventType, type AuditQuery, AuditReportGenerator, type AuditSeverity, type AuditStorage, AuditSystem, AuditTrail, type AuthorizationContext, AuthorizationSystem, type BreachStorage, type CORSConfig, CORSManager, CORSPresets, CommonRoles, ConsentManager, type ConsentRecord, type ConsentType, type ContentSecurityPolicyConfig, type CookieConsentConfig, CookieConsentManager, DataAnonymization, type DataBreach, DataBreachManager, type DataCategory, type DataDeletionRequest, DataDeletionSystem, DataExportSystem, DataMasking, type DataProcessingPurpose, type EncryptedData, type EncryptionConfig, EncryptionSystem, EnvelopeEncryption, FieldEncryption, type GDPRStorage, type HSTSConfig, InMemoryAuditStorage, InMemoryBreachStorage, InMemoryGDPRStorage, KeyRotationManager, OAuthClient, type OAuthConfig, OAuthProviders, PasswordHasher, type Permission, PermissionBuilder, PermissionCache, type PermissionsPolicyConfig, type PersonalDataExport, type Policy, PolicyBuilder, type PolicyCondition, PrivacyPolicyManager, type ReferrerPolicyValue, RequirePermission, RequireRole, type Role, SecurityHeaders, type SecurityHeadersConfig, type SecurityLogger, SecurityPresets, TokenGenerator, TwoFactorAuth, type User, audit, authorization, canAccessResource, checkAttributeAccess, configureSecurityLogger, cookieConsentManager, createAuditMiddleware, createAuthorizationMiddleware, createConsentManager, createDataBreachManager, createDataDeletionSystem, createSecurityMiddleware, dataExportSystem, encryption, permissionCache, privacyPolicyManager, setRateLimitHeaders };
|
|
1507
|
+
export { type AlertHandler, type AlertingConfig, AuditAlertHandler, type AuditEvent, type AuditEventType, type AuditQuery, AuditReportGenerator, type AuditSeverity, type AuditStorage, AuditSystem, AuditTrail, type AuthorizationContext, AuthorizationSystem, type BreachStorage, type CORSConfig, CORSManager, CORSPresets, CommonRoles, ConsentManager, type ConsentRecord, type ConsentType, type ContentSecurityPolicyConfig, type CookieConsentConfig, CookieConsentManager, DEFAULT_THRESHOLDS, DataAnonymization, type DataBreach, DataBreachManager, type DataCategory, type DataDeletionRequest, DataDeletionSystem, DataExportSystem, DataMasking, type DataProcessingPurpose, type EncryptedData, type EncryptionConfig, EncryptionSystem, EnvelopeEncryption, FieldEncryption, type GDPRStorage, type HSTSConfig, InMemoryAuditStorage, InMemoryBreachStorage, InMemoryGDPRStorage, KeyRotationManager, LogAlertHandler, OAuthClient, type OAuthConfig, OAuthProviders, PasswordHasher, type Permission, PermissionBuilder, PermissionCache, type PermissionsPolicyConfig, type PersonalDataExport, type Policy, PolicyBuilder, type PolicyCondition, PrivacyPolicyManager, type ReferrerPolicyValue, RequirePermission, RequireRole, type Role, type SecurityAlert, SecurityAlertService, SecurityHeaders, type SecurityHeadersConfig, type SecurityLogger, SecurityPresets, type ThresholdRule, TokenGenerator, TwoFactorAuth, type User, WebhookAlertHandler, audit, authorization, canAccessResource, checkAttributeAccess, configureSecurityLogger, cookieConsentManager, createAuditMiddleware, createAuthorizationMiddleware, createConsentManager, createDataBreachManager, createDataDeletionSystem, createSecurityMiddleware, dataExportSystem, encryption, permissionCache, privacyPolicyManager, setRateLimitHeaders, signAuditEntry, verifyAuditEntry };
|