mcp-wordpress 2.2.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +503 -0
- package/dist/client/api.d.ts +90 -0
- package/dist/client/api.d.ts.map +1 -1
- package/dist/client/api.js +90 -0
- package/dist/client/api.js.map +1 -1
- package/dist/security/AISecurityScanner.d.ts +175 -0
- package/dist/security/AISecurityScanner.d.ts.map +1 -0
- package/dist/security/AISecurityScanner.js +645 -0
- package/dist/security/AISecurityScanner.js.map +1 -0
- package/dist/security/AutomatedRemediation.d.ts +145 -0
- package/dist/security/AutomatedRemediation.d.ts.map +1 -0
- package/dist/security/AutomatedRemediation.js +535 -0
- package/dist/security/AutomatedRemediation.js.map +1 -0
- package/dist/security/SecurityCIPipeline.d.ts +213 -0
- package/dist/security/SecurityCIPipeline.d.ts.map +1 -0
- package/dist/security/SecurityCIPipeline.js +684 -0
- package/dist/security/SecurityCIPipeline.js.map +1 -0
- package/dist/security/SecurityConfigManager.d.ts +294 -0
- package/dist/security/SecurityConfigManager.d.ts.map +1 -0
- package/dist/security/SecurityConfigManager.js +553 -0
- package/dist/security/SecurityConfigManager.js.map +1 -0
- package/dist/security/SecurityMonitoring.d.ts +245 -0
- package/dist/security/SecurityMonitoring.d.ts.map +1 -0
- package/dist/security/SecurityMonitoring.js +596 -0
- package/dist/security/SecurityMonitoring.js.map +1 -0
- package/dist/security/SecurityReviewer.d.ts +168 -0
- package/dist/security/SecurityReviewer.d.ts.map +1 -0
- package/dist/security/SecurityReviewer.js +683 -0
- package/dist/security/SecurityReviewer.js.map +1 -0
- package/dist/security/index.d.ts +182 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +189 -0
- package/dist/security/index.js.map +1 -0
- package/dist/tools/media.d.ts +43 -4
- package/dist/tools/media.d.ts.map +1 -1
- package/dist/tools/media.js +43 -4
- package/dist/tools/media.js.map +1 -1
- package/dist/tools/posts.d.ts +225 -4
- package/dist/tools/posts.d.ts.map +1 -1
- package/dist/tools/posts.js +225 -4
- package/dist/tools/posts.js.map +1 -1
- package/docs/DOCKER_PUBLISHING_TROUBLESHOOTING.md +233 -0
- package/docs/PUBLISHING-TROUBLESHOOTING.md +227 -0
- package/docs/api/README.md +53 -11
- package/docs/api/openapi.json +10 -10
- package/docs/api/summary.json +1 -1
- package/docs/api/tools/wp_create_post.md +9 -3
- package/docs/api/tools/wp_delete_post.md +2 -3
- package/docs/api/tools/wp_get_current_user.md +7 -1
- package/docs/api/tools/wp_get_post.md +2 -3
- package/docs/api/tools/wp_get_post_revisions.md +1 -1
- package/docs/api/tools/wp_list_posts.md +10 -3
- package/docs/api/tools/wp_list_users.md +8 -1
- package/docs/api/tools/wp_search_site.md +8 -1
- package/docs/api/tools/wp_test_auth.md +8 -1
- package/docs/api/tools/wp_update_post.md +2 -3
- package/docs/examples/docker-production.md +801 -0
- package/docs/examples/multi-site-setup.md +575 -0
- package/docs/examples/single-site-setup.md +390 -0
- package/docs/examples/use-case-workflows.md +469 -0
- package/package.json +11 -3
- package/src/client/api.ts +90 -0
- package/src/security/AISecurityScanner.ts +780 -0
- package/src/security/AutomatedRemediation.ts +665 -0
- package/src/security/SecurityCIPipeline.ts +969 -0
- package/src/security/SecurityConfigManager.ts +829 -0
- package/src/security/SecurityMonitoring.ts +841 -0
- package/src/security/SecurityReviewer.ts +855 -0
- package/src/security/index.ts +249 -0
- package/src/tools/media.ts +43 -4
- package/src/tools/posts.ts +225 -4
|
@@ -0,0 +1,841 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security Monitoring and Alerting System
|
|
3
|
+
* Provides real-time security monitoring, threat detection, and incident response
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { EventEmitter } from "events";
|
|
7
|
+
import { SecurityUtils } from "./SecurityConfig";
|
|
8
|
+
|
|
9
|
+
export interface SecurityEvent {
|
|
10
|
+
id: string;
|
|
11
|
+
timestamp: Date;
|
|
12
|
+
type: "authentication" | "authorization" | "input-validation" | "data-access" | "system" | "anomaly";
|
|
13
|
+
severity: "critical" | "high" | "medium" | "low";
|
|
14
|
+
source: string;
|
|
15
|
+
details: {
|
|
16
|
+
userId?: string;
|
|
17
|
+
sessionId?: string;
|
|
18
|
+
ipAddress?: string;
|
|
19
|
+
userAgent?: string;
|
|
20
|
+
endpoint?: string;
|
|
21
|
+
method?: string;
|
|
22
|
+
payload?: any;
|
|
23
|
+
error?: string;
|
|
24
|
+
metadata?: Record<string, any>;
|
|
25
|
+
};
|
|
26
|
+
description: string;
|
|
27
|
+
riskScore: number;
|
|
28
|
+
handled: boolean;
|
|
29
|
+
actions: SecurityAction[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface SecurityAction {
|
|
33
|
+
id: string;
|
|
34
|
+
type: "block" | "throttle" | "alert" | "log" | "investigate" | "escalate";
|
|
35
|
+
timestamp: Date;
|
|
36
|
+
automated: boolean;
|
|
37
|
+
result: "success" | "failure" | "pending";
|
|
38
|
+
details: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface SecurityAlert {
|
|
42
|
+
id: string;
|
|
43
|
+
eventId: string;
|
|
44
|
+
timestamp: Date;
|
|
45
|
+
severity: "critical" | "high" | "medium" | "low";
|
|
46
|
+
title: string;
|
|
47
|
+
description: string;
|
|
48
|
+
category: string;
|
|
49
|
+
affectedSystems: string[];
|
|
50
|
+
indicators: {
|
|
51
|
+
type: string;
|
|
52
|
+
value: string;
|
|
53
|
+
confidence: number;
|
|
54
|
+
}[];
|
|
55
|
+
recommendations: string[];
|
|
56
|
+
status: "new" | "investigating" | "resolved" | "false-positive";
|
|
57
|
+
assignee?: string;
|
|
58
|
+
resolution?: {
|
|
59
|
+
timestamp: Date;
|
|
60
|
+
action: string;
|
|
61
|
+
details: string;
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
interface ThreatIntelligence {
|
|
66
|
+
id: string;
|
|
67
|
+
type: "ip" | "domain" | "hash" | "pattern" | "signature";
|
|
68
|
+
value: string;
|
|
69
|
+
confidence: number;
|
|
70
|
+
severity: "critical" | "high" | "medium" | "low";
|
|
71
|
+
source: string;
|
|
72
|
+
description: string;
|
|
73
|
+
indicators: string[];
|
|
74
|
+
lastSeen: Date;
|
|
75
|
+
expiry?: Date;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
interface SecurityMetrics {
|
|
79
|
+
timestamp: Date;
|
|
80
|
+
events: {
|
|
81
|
+
total: number;
|
|
82
|
+
byType: Record<string, number>;
|
|
83
|
+
bySeverity: Record<string, number>;
|
|
84
|
+
};
|
|
85
|
+
threats: {
|
|
86
|
+
blocked: number;
|
|
87
|
+
detected: number;
|
|
88
|
+
investigated: number;
|
|
89
|
+
};
|
|
90
|
+
alerts: {
|
|
91
|
+
new: number;
|
|
92
|
+
resolved: number;
|
|
93
|
+
falsePositives: number;
|
|
94
|
+
};
|
|
95
|
+
performance: {
|
|
96
|
+
responseTime: number;
|
|
97
|
+
detectionRate: number;
|
|
98
|
+
falsePositiveRate: number;
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
interface AnomalyPattern {
|
|
103
|
+
id: string;
|
|
104
|
+
type: "traffic" | "authentication" | "access" | "behavior";
|
|
105
|
+
pattern: string;
|
|
106
|
+
threshold: number;
|
|
107
|
+
timeWindow: number;
|
|
108
|
+
description: string;
|
|
109
|
+
enabled: boolean;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Real-time Security Monitor
|
|
114
|
+
*/
|
|
115
|
+
export class SecurityMonitor extends EventEmitter {
|
|
116
|
+
private events: SecurityEvent[] = [];
|
|
117
|
+
private alerts: SecurityAlert[] = [];
|
|
118
|
+
private threatIntel: Map<string, ThreatIntelligence> = new Map();
|
|
119
|
+
private anomalyPatterns: AnomalyPattern[] = [];
|
|
120
|
+
private metrics: SecurityMetrics[] = [];
|
|
121
|
+
private isMonitoring = false;
|
|
122
|
+
private metricsInterval?: NodeJS.Timeout | undefined;
|
|
123
|
+
|
|
124
|
+
constructor() {
|
|
125
|
+
super();
|
|
126
|
+
this.initializeAnomalyPatterns();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Start security monitoring
|
|
131
|
+
*/
|
|
132
|
+
start(): void {
|
|
133
|
+
if (this.isMonitoring) {
|
|
134
|
+
console.warn("[Security Monitor] Already monitoring");
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
this.isMonitoring = true;
|
|
139
|
+
console.log("[Security Monitor] Starting security monitoring");
|
|
140
|
+
|
|
141
|
+
// Start metrics collection
|
|
142
|
+
this.metricsInterval = setInterval(() => {
|
|
143
|
+
this.collectMetrics();
|
|
144
|
+
}, 60000); // Every minute
|
|
145
|
+
|
|
146
|
+
this.emit("monitoring-started");
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Stop security monitoring
|
|
151
|
+
*/
|
|
152
|
+
stop(): void {
|
|
153
|
+
if (!this.isMonitoring) {
|
|
154
|
+
console.warn("[Security Monitor] Not currently monitoring");
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
this.isMonitoring = false;
|
|
159
|
+
|
|
160
|
+
if (this.metricsInterval) {
|
|
161
|
+
clearInterval(this.metricsInterval);
|
|
162
|
+
this.metricsInterval = undefined;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
console.log("[Security Monitor] Stopped security monitoring");
|
|
166
|
+
this.emit("monitoring-stopped");
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Log security event
|
|
171
|
+
*/
|
|
172
|
+
async logSecurityEvent(
|
|
173
|
+
eventData: Omit<SecurityEvent, "id" | "timestamp" | "handled" | "actions">,
|
|
174
|
+
): Promise<SecurityEvent> {
|
|
175
|
+
const event: SecurityEvent = {
|
|
176
|
+
...eventData,
|
|
177
|
+
id: SecurityUtils.generateSecureToken(16),
|
|
178
|
+
timestamp: new Date(),
|
|
179
|
+
handled: false,
|
|
180
|
+
actions: [],
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
this.events.push(event);
|
|
184
|
+
|
|
185
|
+
// Process event in real-time
|
|
186
|
+
await this.processSecurityEvent(event);
|
|
187
|
+
|
|
188
|
+
// Check for anomalies
|
|
189
|
+
await this.checkForAnomalies(event);
|
|
190
|
+
|
|
191
|
+
// Emit event for real-time processing
|
|
192
|
+
this.emit("security-event", event);
|
|
193
|
+
|
|
194
|
+
console.log(`[Security Monitor] Logged ${event.severity} event: ${event.type} - ${event.description}`);
|
|
195
|
+
|
|
196
|
+
return event;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Process security event and take automated actions
|
|
201
|
+
*/
|
|
202
|
+
private async processSecurityEvent(event: SecurityEvent): Promise<void> {
|
|
203
|
+
const actions: SecurityAction[] = [];
|
|
204
|
+
|
|
205
|
+
// High-severity events get immediate attention
|
|
206
|
+
if (event.severity === "critical" || event.severity === "high") {
|
|
207
|
+
actions.push(await this.createAction("alert", event, true));
|
|
208
|
+
|
|
209
|
+
if (event.type === "authentication" && event.details.ipAddress) {
|
|
210
|
+
// Consider blocking suspicious IPs
|
|
211
|
+
const suspiciousActivity = await this.checkSuspiciousActivity(event.details.ipAddress);
|
|
212
|
+
if (suspiciousActivity) {
|
|
213
|
+
actions.push(await this.createAction("block", event, true));
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Rate limiting for authentication events
|
|
219
|
+
if (event.type === "authentication" && event.details.userId) {
|
|
220
|
+
const failedAttempts = await this.getFailedAuthAttempts(event.details.userId);
|
|
221
|
+
if (failedAttempts > 5) {
|
|
222
|
+
actions.push(await this.createAction("throttle", event, true));
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Check against threat intelligence
|
|
227
|
+
if (event.details.ipAddress) {
|
|
228
|
+
const threat = this.threatIntel.get(event.details.ipAddress);
|
|
229
|
+
if (threat) {
|
|
230
|
+
actions.push(await this.createAction("block", event, true));
|
|
231
|
+
actions.push(await this.createAction("alert", event, true));
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
event.actions = actions;
|
|
236
|
+
event.handled = actions.length > 0;
|
|
237
|
+
|
|
238
|
+
// Create alert if necessary
|
|
239
|
+
if (event.severity === "critical" || (event.severity === "high" && event.riskScore > 7)) {
|
|
240
|
+
await this.createAlert(event);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Create security action
|
|
246
|
+
*/
|
|
247
|
+
private async createAction(
|
|
248
|
+
type: SecurityAction["type"],
|
|
249
|
+
event: SecurityEvent,
|
|
250
|
+
automated: boolean,
|
|
251
|
+
): Promise<SecurityAction> {
|
|
252
|
+
const action: SecurityAction = {
|
|
253
|
+
id: SecurityUtils.generateSecureToken(12),
|
|
254
|
+
type,
|
|
255
|
+
timestamp: new Date(),
|
|
256
|
+
automated,
|
|
257
|
+
result: "pending",
|
|
258
|
+
details: `${type} action triggered for ${event.type} event`,
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
try {
|
|
262
|
+
// Execute the action
|
|
263
|
+
switch (type) {
|
|
264
|
+
case "block":
|
|
265
|
+
await this.executeBlockAction(event);
|
|
266
|
+
break;
|
|
267
|
+
case "throttle":
|
|
268
|
+
await this.executeThrottleAction(event);
|
|
269
|
+
break;
|
|
270
|
+
case "alert":
|
|
271
|
+
await this.executeAlertAction(event);
|
|
272
|
+
break;
|
|
273
|
+
case "log":
|
|
274
|
+
await this.executeLogAction(event);
|
|
275
|
+
break;
|
|
276
|
+
default:
|
|
277
|
+
console.log(`[Security Monitor] Action ${type} queued for manual processing`);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
action.result = "success";
|
|
281
|
+
action.details += " - executed successfully";
|
|
282
|
+
} catch (error) {
|
|
283
|
+
action.result = "failure";
|
|
284
|
+
action.details += ` - failed: ${error instanceof Error ? error.message : String(error)}`;
|
|
285
|
+
console.error(`[Security Monitor] Action ${type} failed:`, error);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return action;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Execute block action
|
|
293
|
+
*/
|
|
294
|
+
private async executeBlockAction(event: SecurityEvent): Promise<void> {
|
|
295
|
+
if (event.details.ipAddress) {
|
|
296
|
+
console.log(`[Security Monitor] Blocking IP: ${event.details.ipAddress}`);
|
|
297
|
+
// In a real implementation, this would interface with firewall/load balancer
|
|
298
|
+
this.emit("ip-blocked", { ip: event.details.ipAddress, reason: event.description });
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Execute throttle action
|
|
304
|
+
*/
|
|
305
|
+
private async executeThrottleAction(event: SecurityEvent): Promise<void> {
|
|
306
|
+
if (event.details.userId) {
|
|
307
|
+
console.log(`[Security Monitor] Throttling user: ${event.details.userId}`);
|
|
308
|
+
// In a real implementation, this would apply rate limiting
|
|
309
|
+
this.emit("user-throttled", { userId: event.details.userId, reason: event.description });
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Execute alert action
|
|
315
|
+
*/
|
|
316
|
+
private async executeAlertAction(event: SecurityEvent): Promise<void> {
|
|
317
|
+
console.log(`[Security Monitor] Alert triggered for event: ${event.id}`);
|
|
318
|
+
this.emit("security-alert", event);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Execute log action
|
|
323
|
+
*/
|
|
324
|
+
private async executeLogAction(event: SecurityEvent): Promise<void> {
|
|
325
|
+
console.log(`[Security Monitor] Enhanced logging for event: ${event.id}`);
|
|
326
|
+
// Additional detailed logging would go here
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Create security alert
|
|
331
|
+
*/
|
|
332
|
+
private async createAlert(event: SecurityEvent): Promise<SecurityAlert> {
|
|
333
|
+
const alert: SecurityAlert = {
|
|
334
|
+
id: SecurityUtils.generateSecureToken(16),
|
|
335
|
+
eventId: event.id,
|
|
336
|
+
timestamp: new Date(),
|
|
337
|
+
severity: event.severity,
|
|
338
|
+
title: `Security Alert: ${event.type}`,
|
|
339
|
+
description: event.description,
|
|
340
|
+
category: event.type,
|
|
341
|
+
affectedSystems: [event.source],
|
|
342
|
+
indicators: this.extractIndicators(event),
|
|
343
|
+
recommendations: this.generateRecommendations(event),
|
|
344
|
+
status: "new",
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
this.alerts.push(alert);
|
|
348
|
+
|
|
349
|
+
console.log(`[Security Monitor] Created ${alert.severity} alert: ${alert.title}`);
|
|
350
|
+
this.emit("alert-created", alert);
|
|
351
|
+
|
|
352
|
+
return alert;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Extract indicators from security event
|
|
357
|
+
*/
|
|
358
|
+
private extractIndicators(event: SecurityEvent): SecurityAlert["indicators"] {
|
|
359
|
+
const indicators: SecurityAlert["indicators"] = [];
|
|
360
|
+
|
|
361
|
+
if (event.details.ipAddress) {
|
|
362
|
+
indicators.push({
|
|
363
|
+
type: "ip-address",
|
|
364
|
+
value: event.details.ipAddress,
|
|
365
|
+
confidence: 0.8,
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
if (event.details.userAgent) {
|
|
370
|
+
indicators.push({
|
|
371
|
+
type: "user-agent",
|
|
372
|
+
value: event.details.userAgent,
|
|
373
|
+
confidence: 0.6,
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (event.details.endpoint) {
|
|
378
|
+
indicators.push({
|
|
379
|
+
type: "endpoint",
|
|
380
|
+
value: event.details.endpoint,
|
|
381
|
+
confidence: 0.7,
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
return indicators;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Generate recommendations for event
|
|
390
|
+
*/
|
|
391
|
+
private generateRecommendations(event: SecurityEvent): string[] {
|
|
392
|
+
const recommendations: string[] = [];
|
|
393
|
+
|
|
394
|
+
switch (event.type) {
|
|
395
|
+
case "authentication":
|
|
396
|
+
recommendations.push("Review authentication logs for patterns");
|
|
397
|
+
recommendations.push("Consider implementing multi-factor authentication");
|
|
398
|
+
if (event.severity === "high" || event.severity === "critical") {
|
|
399
|
+
recommendations.push("Temporarily block suspicious IP addresses");
|
|
400
|
+
}
|
|
401
|
+
break;
|
|
402
|
+
|
|
403
|
+
case "authorization":
|
|
404
|
+
recommendations.push("Review user permissions and access controls");
|
|
405
|
+
recommendations.push("Audit privilege escalation attempts");
|
|
406
|
+
break;
|
|
407
|
+
|
|
408
|
+
case "input-validation":
|
|
409
|
+
recommendations.push("Review input validation rules");
|
|
410
|
+
recommendations.push("Update WAF rules if applicable");
|
|
411
|
+
break;
|
|
412
|
+
|
|
413
|
+
case "data-access":
|
|
414
|
+
recommendations.push("Review data access patterns");
|
|
415
|
+
recommendations.push("Implement data loss prevention measures");
|
|
416
|
+
break;
|
|
417
|
+
|
|
418
|
+
case "system":
|
|
419
|
+
recommendations.push("Check system integrity");
|
|
420
|
+
recommendations.push("Review system logs for correlating events");
|
|
421
|
+
break;
|
|
422
|
+
|
|
423
|
+
case "anomaly":
|
|
424
|
+
recommendations.push("Investigate unusual patterns");
|
|
425
|
+
recommendations.push("Tune anomaly detection thresholds");
|
|
426
|
+
break;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
return recommendations;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Check for suspicious activity from IP
|
|
434
|
+
*/
|
|
435
|
+
private async checkSuspiciousActivity(ipAddress: string): Promise<boolean> {
|
|
436
|
+
const recentEvents = this.events.filter(
|
|
437
|
+
(event) => event.details.ipAddress === ipAddress && event.timestamp.getTime() > Date.now() - 3600000, // Last hour
|
|
438
|
+
);
|
|
439
|
+
|
|
440
|
+
// Multiple failed authentication attempts
|
|
441
|
+
const failedAuth = recentEvents.filter((event) => event.type === "authentication" && event.severity === "high");
|
|
442
|
+
|
|
443
|
+
if (failedAuth.length > 5) {
|
|
444
|
+
return true;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// Multiple different user attempts from same IP
|
|
448
|
+
const userIds = new Set(recentEvents.map((event) => event.details.userId).filter(Boolean));
|
|
449
|
+
if (userIds.size > 10) {
|
|
450
|
+
return true;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
return false;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Get failed authentication attempts for user
|
|
458
|
+
*/
|
|
459
|
+
private async getFailedAuthAttempts(userId: string): Promise<number> {
|
|
460
|
+
const recentEvents = this.events.filter(
|
|
461
|
+
(event) =>
|
|
462
|
+
event.type === "authentication" &&
|
|
463
|
+
event.details.userId === userId &&
|
|
464
|
+
event.severity === "high" &&
|
|
465
|
+
event.timestamp.getTime() > Date.now() - 900000, // Last 15 minutes
|
|
466
|
+
);
|
|
467
|
+
|
|
468
|
+
return recentEvents.length;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Check for anomalies
|
|
473
|
+
*/
|
|
474
|
+
private async checkForAnomalies(event: SecurityEvent): Promise<void> {
|
|
475
|
+
for (const pattern of this.anomalyPatterns) {
|
|
476
|
+
if (!pattern.enabled) continue;
|
|
477
|
+
|
|
478
|
+
if (await this.matchesAnomalyPattern(event, pattern)) {
|
|
479
|
+
await this.logSecurityEvent({
|
|
480
|
+
type: "anomaly",
|
|
481
|
+
severity: "medium",
|
|
482
|
+
source: "anomaly-detection",
|
|
483
|
+
description: `Anomaly detected: ${pattern.description}`,
|
|
484
|
+
riskScore: 5,
|
|
485
|
+
details: {
|
|
486
|
+
metadata: { pattern: pattern.pattern, patternId: pattern.id, originalEvent: event.id },
|
|
487
|
+
},
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Check if event matches anomaly pattern
|
|
495
|
+
*/
|
|
496
|
+
private async matchesAnomalyPattern(event: SecurityEvent, pattern: AnomalyPattern): Promise<boolean> {
|
|
497
|
+
// Simplified pattern matching - in practice this would be more sophisticated
|
|
498
|
+
const timeWindow = Date.now() - pattern.timeWindow;
|
|
499
|
+
const relatedEvents = this.events.filter((e) => e.timestamp.getTime() > timeWindow && e.type === event.type);
|
|
500
|
+
|
|
501
|
+
switch (pattern.type) {
|
|
502
|
+
case "traffic":
|
|
503
|
+
return relatedEvents.length > pattern.threshold;
|
|
504
|
+
|
|
505
|
+
case "authentication":
|
|
506
|
+
return event.type === "authentication" && relatedEvents.length > pattern.threshold;
|
|
507
|
+
|
|
508
|
+
case "access":
|
|
509
|
+
return event.type === "data-access" && relatedEvents.length > pattern.threshold;
|
|
510
|
+
|
|
511
|
+
case "behavior":
|
|
512
|
+
// Check for unusual user behavior patterns
|
|
513
|
+
if (event.details.userId) {
|
|
514
|
+
const userEvents = relatedEvents.filter((e) => e.details.userId === event.details.userId);
|
|
515
|
+
return userEvents.length > pattern.threshold;
|
|
516
|
+
}
|
|
517
|
+
return false;
|
|
518
|
+
|
|
519
|
+
default:
|
|
520
|
+
return false;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Initialize default anomaly patterns
|
|
526
|
+
*/
|
|
527
|
+
private initializeAnomalyPatterns(): void {
|
|
528
|
+
this.anomalyPatterns = [
|
|
529
|
+
{
|
|
530
|
+
id: "high-auth-failures",
|
|
531
|
+
type: "authentication",
|
|
532
|
+
pattern: "failed-auth-attempts",
|
|
533
|
+
threshold: 10,
|
|
534
|
+
timeWindow: 300000, // 5 minutes
|
|
535
|
+
description: "High number of authentication failures",
|
|
536
|
+
enabled: true,
|
|
537
|
+
},
|
|
538
|
+
{
|
|
539
|
+
id: "unusual-access-pattern",
|
|
540
|
+
type: "access",
|
|
541
|
+
pattern: "data-access-spike",
|
|
542
|
+
threshold: 50,
|
|
543
|
+
timeWindow: 900000, // 15 minutes
|
|
544
|
+
description: "Unusual data access pattern",
|
|
545
|
+
enabled: true,
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
id: "traffic-spike",
|
|
549
|
+
type: "traffic",
|
|
550
|
+
pattern: "request-volume",
|
|
551
|
+
threshold: 100,
|
|
552
|
+
timeWindow: 300000, // 5 minutes
|
|
553
|
+
description: "Traffic volume spike",
|
|
554
|
+
enabled: true,
|
|
555
|
+
},
|
|
556
|
+
{
|
|
557
|
+
id: "user-behavior-anomaly",
|
|
558
|
+
type: "behavior",
|
|
559
|
+
pattern: "user-activity",
|
|
560
|
+
threshold: 20,
|
|
561
|
+
timeWindow: 3600000, // 1 hour
|
|
562
|
+
description: "Unusual user behavior pattern",
|
|
563
|
+
enabled: true,
|
|
564
|
+
},
|
|
565
|
+
];
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* Collect security metrics
|
|
570
|
+
*/
|
|
571
|
+
private collectMetrics(): void {
|
|
572
|
+
const now = new Date();
|
|
573
|
+
const hourAgo = new Date(now.getTime() - 3600000);
|
|
574
|
+
|
|
575
|
+
const recentEvents = this.events.filter((event) => event.timestamp > hourAgo);
|
|
576
|
+
const recentAlerts = this.alerts.filter((alert) => alert.timestamp > hourAgo);
|
|
577
|
+
|
|
578
|
+
const metrics: SecurityMetrics = {
|
|
579
|
+
timestamp: now,
|
|
580
|
+
events: {
|
|
581
|
+
total: recentEvents.length,
|
|
582
|
+
byType: this.groupBy(recentEvents, "type"),
|
|
583
|
+
bySeverity: this.groupBy(recentEvents, "severity"),
|
|
584
|
+
},
|
|
585
|
+
threats: {
|
|
586
|
+
blocked: recentEvents.filter((e) => e.actions.some((a) => a.type === "block")).length,
|
|
587
|
+
detected: recentEvents.filter((e) => e.riskScore > 5).length,
|
|
588
|
+
investigated: recentAlerts.filter((a) => a.status === "investigating").length,
|
|
589
|
+
},
|
|
590
|
+
alerts: {
|
|
591
|
+
new: recentAlerts.filter((a) => a.status === "new").length,
|
|
592
|
+
resolved: recentAlerts.filter((a) => a.status === "resolved").length,
|
|
593
|
+
falsePositives: recentAlerts.filter((a) => a.status === "false-positive").length,
|
|
594
|
+
},
|
|
595
|
+
performance: {
|
|
596
|
+
responseTime: this.calculateAverageResponseTime(recentEvents),
|
|
597
|
+
detectionRate: this.calculateDetectionRate(recentEvents),
|
|
598
|
+
falsePositiveRate: this.calculateFalsePositiveRate(recentAlerts),
|
|
599
|
+
},
|
|
600
|
+
};
|
|
601
|
+
|
|
602
|
+
this.metrics.push(metrics);
|
|
603
|
+
|
|
604
|
+
// Keep only last 24 hours of metrics
|
|
605
|
+
const dayAgo = new Date(now.getTime() - 86400000);
|
|
606
|
+
this.metrics = this.metrics.filter((m) => m.timestamp > dayAgo);
|
|
607
|
+
|
|
608
|
+
this.emit("metrics-collected", metrics);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* Group array by property
|
|
613
|
+
*/
|
|
614
|
+
private groupBy(array: any[], property: string): Record<string, number> {
|
|
615
|
+
return array.reduce((acc, item) => {
|
|
616
|
+
const key = item[property] || "unknown";
|
|
617
|
+
acc[key] = (acc[key] || 0) + 1;
|
|
618
|
+
return acc;
|
|
619
|
+
}, {});
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Calculate average response time for security events
|
|
624
|
+
*/
|
|
625
|
+
private calculateAverageResponseTime(events: SecurityEvent[]): number {
|
|
626
|
+
const handledEvents = events.filter((e) => e.handled && e.actions.length > 0);
|
|
627
|
+
if (handledEvents.length === 0) return 0;
|
|
628
|
+
|
|
629
|
+
const totalTime = handledEvents.reduce((sum, event) => {
|
|
630
|
+
const firstAction = event.actions[0];
|
|
631
|
+
if (firstAction) {
|
|
632
|
+
return sum + (firstAction.timestamp.getTime() - event.timestamp.getTime());
|
|
633
|
+
}
|
|
634
|
+
return sum;
|
|
635
|
+
}, 0);
|
|
636
|
+
|
|
637
|
+
return totalTime / handledEvents.length;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* Calculate detection rate
|
|
642
|
+
*/
|
|
643
|
+
private calculateDetectionRate(events: SecurityEvent[]): number {
|
|
644
|
+
const totalEvents = events.length;
|
|
645
|
+
if (totalEvents === 0) return 1;
|
|
646
|
+
|
|
647
|
+
const detectedEvents = events.filter((e) => e.handled || e.riskScore > 3).length;
|
|
648
|
+
return detectedEvents / totalEvents;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* Calculate false positive rate
|
|
653
|
+
*/
|
|
654
|
+
private calculateFalsePositiveRate(alerts: SecurityAlert[]): number {
|
|
655
|
+
const totalAlerts = alerts.length;
|
|
656
|
+
if (totalAlerts === 0) return 0;
|
|
657
|
+
|
|
658
|
+
const falsePositives = alerts.filter((a) => a.status === "false-positive").length;
|
|
659
|
+
return falsePositives / totalAlerts;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* Add threat intelligence
|
|
664
|
+
*/
|
|
665
|
+
addThreatIntelligence(threat: ThreatIntelligence): void {
|
|
666
|
+
this.threatIntel.set(threat.value, threat);
|
|
667
|
+
console.log(`[Security Monitor] Added threat intelligence: ${threat.type} - ${threat.value}`);
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* Remove threat intelligence
|
|
672
|
+
*/
|
|
673
|
+
removeThreatIntelligence(value: string): boolean {
|
|
674
|
+
const removed = this.threatIntel.delete(value);
|
|
675
|
+
if (removed) {
|
|
676
|
+
console.log(`[Security Monitor] Removed threat intelligence: ${value}`);
|
|
677
|
+
}
|
|
678
|
+
return removed;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
/**
|
|
682
|
+
* Update alert status
|
|
683
|
+
*/
|
|
684
|
+
updateAlertStatus(alertId: string, status: SecurityAlert["status"], assignee?: string): boolean {
|
|
685
|
+
const alert = this.alerts.find((a) => a.id === alertId);
|
|
686
|
+
if (!alert) {
|
|
687
|
+
return false;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
alert.status = status;
|
|
691
|
+
if (assignee) {
|
|
692
|
+
alert.assignee = assignee;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
if (status === "resolved") {
|
|
696
|
+
alert.resolution = {
|
|
697
|
+
timestamp: new Date(),
|
|
698
|
+
action: "manual-resolution",
|
|
699
|
+
details: "Alert marked as resolved",
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
console.log(`[Security Monitor] Updated alert ${alertId} status to ${status}`);
|
|
704
|
+
this.emit("alert-updated", alert);
|
|
705
|
+
return true;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
/**
|
|
709
|
+
* Get security events
|
|
710
|
+
*/
|
|
711
|
+
getEvents(
|
|
712
|
+
options: {
|
|
713
|
+
limit?: number;
|
|
714
|
+
offset?: number;
|
|
715
|
+
severity?: string;
|
|
716
|
+
type?: string;
|
|
717
|
+
since?: Date;
|
|
718
|
+
} = {},
|
|
719
|
+
): SecurityEvent[] {
|
|
720
|
+
let events = [...this.events];
|
|
721
|
+
|
|
722
|
+
if (options.since) {
|
|
723
|
+
events = events.filter((e) => e.timestamp >= options.since!);
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
if (options.severity) {
|
|
727
|
+
events = events.filter((e) => e.severity === options.severity);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
if (options.type) {
|
|
731
|
+
events = events.filter((e) => e.type === options.type);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
// Sort by timestamp (newest first)
|
|
735
|
+
events.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
|
|
736
|
+
|
|
737
|
+
if (options.offset) {
|
|
738
|
+
events = events.slice(options.offset);
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
if (options.limit) {
|
|
742
|
+
events = events.slice(0, options.limit);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
return events;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* Get security alerts
|
|
750
|
+
*/
|
|
751
|
+
getAlerts(
|
|
752
|
+
options: {
|
|
753
|
+
limit?: number;
|
|
754
|
+
offset?: number;
|
|
755
|
+
severity?: string;
|
|
756
|
+
status?: string;
|
|
757
|
+
since?: Date;
|
|
758
|
+
} = {},
|
|
759
|
+
): SecurityAlert[] {
|
|
760
|
+
let alerts = [...this.alerts];
|
|
761
|
+
|
|
762
|
+
if (options.since) {
|
|
763
|
+
alerts = alerts.filter((a) => a.timestamp >= options.since!);
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
if (options.severity) {
|
|
767
|
+
alerts = alerts.filter((a) => a.severity === options.severity);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
if (options.status) {
|
|
771
|
+
alerts = alerts.filter((a) => a.status === options.status);
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
// Sort by timestamp (newest first)
|
|
775
|
+
alerts.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
|
|
776
|
+
|
|
777
|
+
if (options.offset) {
|
|
778
|
+
alerts = alerts.slice(options.offset);
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
if (options.limit) {
|
|
782
|
+
alerts = alerts.slice(0, options.limit);
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
return alerts;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
/**
|
|
789
|
+
* Get security metrics
|
|
790
|
+
*/
|
|
791
|
+
getMetrics(
|
|
792
|
+
options: {
|
|
793
|
+
since?: Date;
|
|
794
|
+
until?: Date;
|
|
795
|
+
} = {},
|
|
796
|
+
): SecurityMetrics[] {
|
|
797
|
+
let metrics = [...this.metrics];
|
|
798
|
+
|
|
799
|
+
if (options.since) {
|
|
800
|
+
metrics = metrics.filter((m) => m.timestamp >= options.since!);
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
if (options.until) {
|
|
804
|
+
metrics = metrics.filter((m) => m.timestamp <= options.until!);
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
return metrics.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
/**
|
|
811
|
+
* Get system status
|
|
812
|
+
*/
|
|
813
|
+
getStatus(): {
|
|
814
|
+
monitoring: boolean;
|
|
815
|
+
eventsToday: number;
|
|
816
|
+
alertsOpen: number;
|
|
817
|
+
threatsBlocked: number;
|
|
818
|
+
systemHealth: "healthy" | "degraded" | "critical";
|
|
819
|
+
} {
|
|
820
|
+
const today = new Date();
|
|
821
|
+
today.setHours(0, 0, 0, 0);
|
|
822
|
+
|
|
823
|
+
const eventsToday = this.events.filter((e) => e.timestamp >= today).length;
|
|
824
|
+
const alertsOpen = this.alerts.filter((a) => a.status === "new" || a.status === "investigating").length;
|
|
825
|
+
const threatsBlocked = this.events.filter(
|
|
826
|
+
(e) => e.timestamp >= today && e.actions.some((a) => a.type === "block"),
|
|
827
|
+
).length;
|
|
828
|
+
|
|
829
|
+
let systemHealth: "healthy" | "degraded" | "critical" = "healthy";
|
|
830
|
+
if (alertsOpen > 10) systemHealth = "critical";
|
|
831
|
+
else if (alertsOpen > 5 || eventsToday > 100) systemHealth = "degraded";
|
|
832
|
+
|
|
833
|
+
return {
|
|
834
|
+
monitoring: this.isMonitoring,
|
|
835
|
+
eventsToday,
|
|
836
|
+
alertsOpen,
|
|
837
|
+
threatsBlocked,
|
|
838
|
+
systemHealth,
|
|
839
|
+
};
|
|
840
|
+
}
|
|
841
|
+
}
|