@panguard-ai/threat-cloud 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audit-logger.d.ts +46 -0
- package/dist/audit-logger.d.ts.map +1 -0
- package/dist/audit-logger.js +105 -0
- package/dist/audit-logger.js.map +1 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +115 -0
- package/dist/cli.js.map +1 -0
- package/dist/correlation-engine.d.ts +41 -0
- package/dist/correlation-engine.d.ts.map +1 -0
- package/dist/correlation-engine.js +313 -0
- package/dist/correlation-engine.js.map +1 -0
- package/dist/database.d.ts +63 -0
- package/dist/database.d.ts.map +1 -0
- package/dist/database.js +444 -0
- package/dist/database.js.map +1 -0
- package/dist/feed-distributor.d.ts +36 -0
- package/dist/feed-distributor.d.ts.map +1 -0
- package/dist/feed-distributor.js +125 -0
- package/dist/feed-distributor.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/ioc-store.d.ts +83 -0
- package/dist/ioc-store.d.ts.map +1 -0
- package/dist/ioc-store.js +278 -0
- package/dist/ioc-store.js.map +1 -0
- package/dist/query-handlers.d.ts +40 -0
- package/dist/query-handlers.d.ts.map +1 -0
- package/dist/query-handlers.js +211 -0
- package/dist/query-handlers.js.map +1 -0
- package/dist/reputation-engine.d.ts +44 -0
- package/dist/reputation-engine.d.ts.map +1 -0
- package/dist/reputation-engine.js +169 -0
- package/dist/reputation-engine.js.map +1 -0
- package/dist/rule-generator.d.ts +47 -0
- package/dist/rule-generator.d.ts.map +1 -0
- package/dist/rule-generator.js +238 -0
- package/dist/rule-generator.js.map +1 -0
- package/dist/scheduler.d.ts +52 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +143 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/server.d.ts +99 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +809 -0
- package/dist/server.js.map +1 -0
- package/dist/sighting-store.d.ts +61 -0
- package/dist/sighting-store.d.ts.map +1 -0
- package/dist/sighting-store.js +191 -0
- package/dist/sighting-store.js.map +1 -0
- package/dist/types.d.ts +352 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +37 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Automatic Sigma Rule Generator
|
|
3
|
+
* 自動 Sigma 規則產生器
|
|
4
|
+
*
|
|
5
|
+
* Analyzes enriched threat events, detects recurring patterns,
|
|
6
|
+
* and generates Sigma detection rules automatically.
|
|
7
|
+
*
|
|
8
|
+
* @module @panguard-ai/threat-cloud/rule-generator
|
|
9
|
+
*/
|
|
10
|
+
import { createHash } from 'node:crypto';
|
|
11
|
+
/** MITRE technique → tactic mapping (simplified) */
|
|
12
|
+
const TECHNIQUE_TACTIC_MAP = {
|
|
13
|
+
T1110: 'credential_access',
|
|
14
|
+
T1021: 'lateral_movement',
|
|
15
|
+
T1046: 'discovery',
|
|
16
|
+
T1059: 'execution',
|
|
17
|
+
T1486: 'impact',
|
|
18
|
+
T1190: 'initial_access',
|
|
19
|
+
T1078: 'defense_evasion',
|
|
20
|
+
T1071: 'command_and_control',
|
|
21
|
+
T1048: 'exfiltration',
|
|
22
|
+
T1569: 'execution',
|
|
23
|
+
T1053: 'execution',
|
|
24
|
+
T1543: 'persistence',
|
|
25
|
+
T1547: 'persistence',
|
|
26
|
+
T1098: 'persistence',
|
|
27
|
+
T1027: 'defense_evasion',
|
|
28
|
+
T1070: 'defense_evasion',
|
|
29
|
+
T1562: 'defense_evasion',
|
|
30
|
+
T1018: 'discovery',
|
|
31
|
+
T1057: 'discovery',
|
|
32
|
+
T1082: 'discovery',
|
|
33
|
+
T1560: 'collection',
|
|
34
|
+
};
|
|
35
|
+
/** Severity mapping for pattern analysis */
|
|
36
|
+
const SEVERITY_ORDER = ['critical', 'high', 'medium', 'low'];
|
|
37
|
+
/** Default configuration */
|
|
38
|
+
const DEFAULT_CONFIG = {
|
|
39
|
+
minOccurrences: 10,
|
|
40
|
+
analysisWindowHours: 168, // 7 days
|
|
41
|
+
minDistinctIPs: 3,
|
|
42
|
+
};
|
|
43
|
+
export class RuleGenerator {
|
|
44
|
+
db;
|
|
45
|
+
config;
|
|
46
|
+
constructor(db, config) {
|
|
47
|
+
this.db = db;
|
|
48
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Analyze recent events and generate rules for recurring patterns.
|
|
52
|
+
* 分析近期事件並為反覆出現的模式產生規則
|
|
53
|
+
*/
|
|
54
|
+
generateRules() {
|
|
55
|
+
const startTime = Date.now();
|
|
56
|
+
const patterns = this.detectPatterns();
|
|
57
|
+
let rulesGenerated = 0;
|
|
58
|
+
let rulesUpdated = 0;
|
|
59
|
+
this.db.transaction(() => {
|
|
60
|
+
for (const pattern of patterns) {
|
|
61
|
+
const existing = this.db
|
|
62
|
+
.prepare('SELECT pattern_hash FROM generated_patterns WHERE pattern_hash = ?')
|
|
63
|
+
.get(pattern.patternHash);
|
|
64
|
+
if (existing) {
|
|
65
|
+
this.updatePattern(pattern);
|
|
66
|
+
rulesUpdated++;
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
this.createRuleFromPattern(pattern);
|
|
70
|
+
rulesGenerated++;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
})();
|
|
74
|
+
return {
|
|
75
|
+
patternsAnalyzed: patterns.length,
|
|
76
|
+
rulesGenerated,
|
|
77
|
+
rulesUpdated,
|
|
78
|
+
duration: Date.now() - startTime,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Detect recurring patterns in enriched threat events.
|
|
83
|
+
* 偵測豐富化威脅事件中的反覆模式
|
|
84
|
+
*/
|
|
85
|
+
detectPatterns() {
|
|
86
|
+
const sinceDate = new Date(Date.now() - this.config.analysisWindowHours * 60 * 60 * 1000).toISOString();
|
|
87
|
+
const rows = this.db
|
|
88
|
+
.prepare(`SELECT attack_type, mitre_techniques, attack_source_ip, region, severity, timestamp
|
|
89
|
+
FROM enriched_threats
|
|
90
|
+
WHERE received_at > ?
|
|
91
|
+
ORDER BY timestamp ASC`)
|
|
92
|
+
.all(sinceDate);
|
|
93
|
+
// Group by (attack_type, sorted mitre_techniques)
|
|
94
|
+
const grouped = new Map();
|
|
95
|
+
for (const row of rows) {
|
|
96
|
+
const techniques = JSON.parse(row.mitre_techniques).sort();
|
|
97
|
+
const key = `${row.attack_type}|${techniques.join(',')}`;
|
|
98
|
+
let group = grouped.get(key);
|
|
99
|
+
if (!group) {
|
|
100
|
+
group = {
|
|
101
|
+
attackType: row.attack_type,
|
|
102
|
+
techniques,
|
|
103
|
+
ips: new Set(),
|
|
104
|
+
regions: new Set(),
|
|
105
|
+
severityCounts: {},
|
|
106
|
+
occurrences: 0,
|
|
107
|
+
firstSeen: row.timestamp,
|
|
108
|
+
lastSeen: row.timestamp,
|
|
109
|
+
};
|
|
110
|
+
grouped.set(key, group);
|
|
111
|
+
}
|
|
112
|
+
group.ips.add(row.attack_source_ip);
|
|
113
|
+
group.regions.add(row.region);
|
|
114
|
+
group.severityCounts[row.severity] = (group.severityCounts[row.severity] ?? 0) + 1;
|
|
115
|
+
group.occurrences++;
|
|
116
|
+
if (row.timestamp > group.lastSeen)
|
|
117
|
+
group.lastSeen = row.timestamp;
|
|
118
|
+
}
|
|
119
|
+
// Filter by thresholds
|
|
120
|
+
const patterns = [];
|
|
121
|
+
for (const group of grouped.values()) {
|
|
122
|
+
if (group.occurrences >= this.config.minOccurrences &&
|
|
123
|
+
group.ips.size >= this.config.minDistinctIPs) {
|
|
124
|
+
const patternHash = createHash('sha256')
|
|
125
|
+
.update(group.attackType + group.techniques.join(','))
|
|
126
|
+
.digest('hex')
|
|
127
|
+
.slice(0, 16);
|
|
128
|
+
patterns.push({
|
|
129
|
+
attackType: group.attackType,
|
|
130
|
+
mitreTechniques: group.techniques,
|
|
131
|
+
patternHash,
|
|
132
|
+
occurrences: group.occurrences,
|
|
133
|
+
distinctIPs: group.ips.size,
|
|
134
|
+
regions: [...group.regions],
|
|
135
|
+
severityCounts: group.severityCounts,
|
|
136
|
+
firstSeen: group.firstSeen,
|
|
137
|
+
lastSeen: group.lastSeen,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return patterns;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Get all generated patterns.
|
|
145
|
+
* 取得所有已產生的模式
|
|
146
|
+
*/
|
|
147
|
+
getGeneratedPatterns() {
|
|
148
|
+
const rows = this.db
|
|
149
|
+
.prepare(`SELECT pattern_hash, attack_type, mitre_techniques, rule_id, occurrences, distinct_ips
|
|
150
|
+
FROM generated_patterns
|
|
151
|
+
ORDER BY occurrences DESC`)
|
|
152
|
+
.all();
|
|
153
|
+
return rows.map((r) => ({
|
|
154
|
+
patternHash: r.pattern_hash,
|
|
155
|
+
attackType: r.attack_type,
|
|
156
|
+
mitreTechniques: JSON.parse(r.mitre_techniques),
|
|
157
|
+
ruleId: r.rule_id,
|
|
158
|
+
occurrences: r.occurrences,
|
|
159
|
+
distinctIPs: r.distinct_ips,
|
|
160
|
+
}));
|
|
161
|
+
}
|
|
162
|
+
// -------------------------------------------------------------------------
|
|
163
|
+
// Private helpers / 私有輔助方法
|
|
164
|
+
// -------------------------------------------------------------------------
|
|
165
|
+
/** Create a new rule from a detected pattern */
|
|
166
|
+
createRuleFromPattern(pattern) {
|
|
167
|
+
const ruleId = `tc-auto-${pattern.patternHash}`;
|
|
168
|
+
const severity = this.pickMaxSeverity(pattern.severityCounts);
|
|
169
|
+
const sigmaYaml = this.generateSigmaYaml(pattern, ruleId, severity);
|
|
170
|
+
// Insert into rules table
|
|
171
|
+
this.db
|
|
172
|
+
.prepare(`INSERT INTO rules (rule_id, rule_content, published_at, source)
|
|
173
|
+
VALUES (?, ?, datetime('now'), 'threat-cloud-auto')
|
|
174
|
+
ON CONFLICT(rule_id) DO UPDATE SET
|
|
175
|
+
rule_content = excluded.rule_content,
|
|
176
|
+
published_at = excluded.published_at,
|
|
177
|
+
updated_at = datetime('now')`)
|
|
178
|
+
.run(ruleId, sigmaYaml);
|
|
179
|
+
// Insert into generated_patterns table
|
|
180
|
+
this.db
|
|
181
|
+
.prepare(`INSERT INTO generated_patterns
|
|
182
|
+
(pattern_hash, attack_type, mitre_techniques, rule_id, occurrences, distinct_ips, first_seen, last_seen)
|
|
183
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
184
|
+
.run(pattern.patternHash, pattern.attackType, JSON.stringify(pattern.mitreTechniques), ruleId, pattern.occurrences, pattern.distinctIPs, pattern.firstSeen, pattern.lastSeen);
|
|
185
|
+
}
|
|
186
|
+
/** Update an existing pattern's statistics */
|
|
187
|
+
updatePattern(pattern) {
|
|
188
|
+
this.db
|
|
189
|
+
.prepare(`UPDATE generated_patterns SET
|
|
190
|
+
occurrences = ?,
|
|
191
|
+
distinct_ips = ?,
|
|
192
|
+
last_seen = ?,
|
|
193
|
+
updated_at = datetime('now')
|
|
194
|
+
WHERE pattern_hash = ?`)
|
|
195
|
+
.run(pattern.occurrences, pattern.distinctIPs, pattern.lastSeen, pattern.patternHash);
|
|
196
|
+
// Also update the rule content
|
|
197
|
+
const ruleId = `tc-auto-${pattern.patternHash}`;
|
|
198
|
+
const severity = this.pickMaxSeverity(pattern.severityCounts);
|
|
199
|
+
const sigmaYaml = this.generateSigmaYaml(pattern, ruleId, severity);
|
|
200
|
+
this.db
|
|
201
|
+
.prepare(`UPDATE rules SET rule_content = ?, published_at = datetime('now'), updated_at = datetime('now')
|
|
202
|
+
WHERE rule_id = ?`)
|
|
203
|
+
.run(sigmaYaml, ruleId);
|
|
204
|
+
}
|
|
205
|
+
/** Generate Sigma YAML rule content */
|
|
206
|
+
generateSigmaYaml(pattern, ruleId, severity) {
|
|
207
|
+
const tags = pattern.mitreTechniques.map((t) => {
|
|
208
|
+
const tactic = TECHNIQUE_TACTIC_MAP[t] ?? 'unknown';
|
|
209
|
+
return ` - attack.${tactic}\n - attack.${t.toLowerCase()}`;
|
|
210
|
+
});
|
|
211
|
+
const regionList = pattern.regions.join(', ');
|
|
212
|
+
return [
|
|
213
|
+
`title: "Threat Cloud Auto: ${pattern.attackType} via ${pattern.mitreTechniques.join(', ')}"`,
|
|
214
|
+
`id: ${ruleId}`,
|
|
215
|
+
`status: experimental`,
|
|
216
|
+
`author: Panguard Threat Cloud (auto-generated)`,
|
|
217
|
+
`description: |`,
|
|
218
|
+
` Pattern observed ${pattern.occurrences} times from ${pattern.distinctIPs} distinct IPs across ${regionList}.`,
|
|
219
|
+
`date: ${new Date().toISOString().slice(0, 10)}`,
|
|
220
|
+
`detection:`,
|
|
221
|
+
` selection:`,
|
|
222
|
+
` EventType: ${pattern.attackType}`,
|
|
223
|
+
` condition: selection`,
|
|
224
|
+
`level: ${severity}`,
|
|
225
|
+
`tags:`,
|
|
226
|
+
...tags,
|
|
227
|
+
].join('\n');
|
|
228
|
+
}
|
|
229
|
+
/** Pick highest severity from counts */
|
|
230
|
+
pickMaxSeverity(severityCounts) {
|
|
231
|
+
for (const s of SEVERITY_ORDER) {
|
|
232
|
+
if (severityCounts[s] && severityCounts[s] > 0)
|
|
233
|
+
return s;
|
|
234
|
+
}
|
|
235
|
+
return 'medium';
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
//# sourceMappingURL=rule-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-generator.js","sourceRoot":"","sources":["../src/rule-generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Background Scheduler
|
|
3
|
+
* 背景排程器
|
|
4
|
+
*
|
|
5
|
+
* Manages periodic tasks: reputation recalculation, correlation scanning,
|
|
6
|
+
* rule generation, and data lifecycle cleanup.
|
|
7
|
+
*
|
|
8
|
+
* @module @panguard-ai/threat-cloud/scheduler
|
|
9
|
+
*/
|
|
10
|
+
import type Database from 'better-sqlite3';
|
|
11
|
+
import type { SchedulerConfig } from './types.js';
|
|
12
|
+
export declare class Scheduler {
|
|
13
|
+
private readonly db;
|
|
14
|
+
private readonly config;
|
|
15
|
+
private readonly reputation;
|
|
16
|
+
private readonly correlation;
|
|
17
|
+
private readonly ruleGen;
|
|
18
|
+
private readonly iocStore;
|
|
19
|
+
private timers;
|
|
20
|
+
private running;
|
|
21
|
+
constructor(db: Database.Database, config?: Partial<SchedulerConfig>);
|
|
22
|
+
/** Start all scheduled tasks / 啟動所有排程任務 */
|
|
23
|
+
start(): void;
|
|
24
|
+
/** Stop all scheduled tasks / 停止所有排程任務 */
|
|
25
|
+
stop(): void;
|
|
26
|
+
/** Check if scheduler is running */
|
|
27
|
+
isRunning(): boolean;
|
|
28
|
+
/** Run correlation scan manually */
|
|
29
|
+
runCorrelation(): {
|
|
30
|
+
newCampaigns: number;
|
|
31
|
+
eventsCorrelated: number;
|
|
32
|
+
};
|
|
33
|
+
/** Run reputation recalculation manually */
|
|
34
|
+
runReputation(): {
|
|
35
|
+
updated: number;
|
|
36
|
+
};
|
|
37
|
+
/** Run rule generation manually */
|
|
38
|
+
runRuleGeneration(): {
|
|
39
|
+
rulesGenerated: number;
|
|
40
|
+
rulesUpdated: number;
|
|
41
|
+
};
|
|
42
|
+
/** Run data lifecycle cleanup */
|
|
43
|
+
runLifecycle(): {
|
|
44
|
+
expired: number;
|
|
45
|
+
purged: number;
|
|
46
|
+
vacuumed: boolean;
|
|
47
|
+
auditPurged: number;
|
|
48
|
+
};
|
|
49
|
+
/** Run database backup / 執行資料庫備份 */
|
|
50
|
+
runBackup(backupDir: string, maxBackups?: number): string | null;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=scheduler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAK3C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAYlD,qBAAa,SAAS;IAUlB,OAAO,CAAC,QAAQ,CAAC,EAAE;IATrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAmB;IAC9C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAoB;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IACxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAW;IACpC,OAAO,CAAC,MAAM,CAA6C;IAC3D,OAAO,CAAC,OAAO,CAAS;gBAGL,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACtC,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC;IASnC,2CAA2C;IAC3C,KAAK,IAAI,IAAI;IAoBb,0CAA0C;IAC1C,IAAI,IAAI,IAAI;IAQZ,oCAAoC;IACpC,SAAS,IAAI,OAAO;IAIpB,oCAAoC;IACpC,cAAc,IAAI;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAE;IAKpE,4CAA4C;IAC5C,aAAa,IAAI;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE;IAKpC,mCAAmC;IACnC,iBAAiB,IAAI;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE;IAKrE,iCAAiC;IACjC,YAAY,IAAI;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE;IAwC3F,oCAAoC;IACpC,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,SAAK,GAAG,MAAM,GAAG,IAAI;CA4B7D"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Background Scheduler
|
|
3
|
+
* 背景排程器
|
|
4
|
+
*
|
|
5
|
+
* Manages periodic tasks: reputation recalculation, correlation scanning,
|
|
6
|
+
* rule generation, and data lifecycle cleanup.
|
|
7
|
+
*
|
|
8
|
+
* @module @panguard-ai/threat-cloud/scheduler
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, mkdirSync, readdirSync, unlinkSync } from 'node:fs';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
import { ReputationEngine } from './reputation-engine.js';
|
|
13
|
+
import { CorrelationEngine } from './correlation-engine.js';
|
|
14
|
+
import { RuleGenerator } from './rule-generator.js';
|
|
15
|
+
import { IoCStore } from './ioc-store.js';
|
|
16
|
+
/** Default scheduler configuration */
|
|
17
|
+
const DEFAULT_CONFIG = {
|
|
18
|
+
reputationIntervalMs: 60 * 60 * 1000, // 1 hour
|
|
19
|
+
correlationIntervalMs: 5 * 60 * 1000, // 5 minutes
|
|
20
|
+
ruleGenerationIntervalMs: 6 * 60 * 60 * 1000, // 6 hours
|
|
21
|
+
threatRetentionDays: 90,
|
|
22
|
+
iocRetentionDays: 365,
|
|
23
|
+
aggregationIntervalMs: 24 * 60 * 60 * 1000, // 24 hours
|
|
24
|
+
};
|
|
25
|
+
export class Scheduler {
|
|
26
|
+
db;
|
|
27
|
+
config;
|
|
28
|
+
reputation;
|
|
29
|
+
correlation;
|
|
30
|
+
ruleGen;
|
|
31
|
+
iocStore;
|
|
32
|
+
timers = [];
|
|
33
|
+
running = false;
|
|
34
|
+
constructor(db, config) {
|
|
35
|
+
this.db = db;
|
|
36
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
37
|
+
this.reputation = new ReputationEngine(db);
|
|
38
|
+
this.correlation = new CorrelationEngine(db);
|
|
39
|
+
this.ruleGen = new RuleGenerator(db);
|
|
40
|
+
this.iocStore = new IoCStore(db);
|
|
41
|
+
}
|
|
42
|
+
/** Start all scheduled tasks / 啟動所有排程任務 */
|
|
43
|
+
start() {
|
|
44
|
+
if (this.running)
|
|
45
|
+
return;
|
|
46
|
+
this.running = true;
|
|
47
|
+
// Run correlation immediately, then on interval
|
|
48
|
+
this.runCorrelation();
|
|
49
|
+
this.timers.push(setInterval(() => this.runCorrelation(), this.config.correlationIntervalMs));
|
|
50
|
+
// Reputation recalculation
|
|
51
|
+
this.timers.push(setInterval(() => this.runReputation(), this.config.reputationIntervalMs));
|
|
52
|
+
// Rule generation
|
|
53
|
+
this.timers.push(setInterval(() => this.runRuleGeneration(), this.config.ruleGenerationIntervalMs));
|
|
54
|
+
// Data lifecycle cleanup
|
|
55
|
+
this.timers.push(setInterval(() => this.runLifecycle(), this.config.aggregationIntervalMs));
|
|
56
|
+
}
|
|
57
|
+
/** Stop all scheduled tasks / 停止所有排程任務 */
|
|
58
|
+
stop() {
|
|
59
|
+
this.running = false;
|
|
60
|
+
for (const timer of this.timers) {
|
|
61
|
+
clearInterval(timer);
|
|
62
|
+
}
|
|
63
|
+
this.timers = [];
|
|
64
|
+
}
|
|
65
|
+
/** Check if scheduler is running */
|
|
66
|
+
isRunning() {
|
|
67
|
+
return this.running;
|
|
68
|
+
}
|
|
69
|
+
/** Run correlation scan manually */
|
|
70
|
+
runCorrelation() {
|
|
71
|
+
const result = this.correlation.scanForCampaigns();
|
|
72
|
+
return { newCampaigns: result.newCampaigns, eventsCorrelated: result.eventsCorrelated };
|
|
73
|
+
}
|
|
74
|
+
/** Run reputation recalculation manually */
|
|
75
|
+
runReputation() {
|
|
76
|
+
const result = this.reputation.recalculateAll();
|
|
77
|
+
return { updated: result.updated };
|
|
78
|
+
}
|
|
79
|
+
/** Run rule generation manually */
|
|
80
|
+
runRuleGeneration() {
|
|
81
|
+
const result = this.ruleGen.generateRules();
|
|
82
|
+
return { rulesGenerated: result.rulesGenerated, rulesUpdated: result.rulesUpdated };
|
|
83
|
+
}
|
|
84
|
+
/** Run data lifecycle cleanup */
|
|
85
|
+
runLifecycle() {
|
|
86
|
+
const expireCutoff = new Date(Date.now() - this.config.iocRetentionDays * 24 * 60 * 60 * 1000).toISOString();
|
|
87
|
+
const purgeCutoff = new Date(Date.now() - (this.config.iocRetentionDays + 30) * 24 * 60 * 60 * 1000).toISOString();
|
|
88
|
+
const expired = this.iocStore.expireStaleIoCs(expireCutoff);
|
|
89
|
+
const purged = this.iocStore.purgeExpiredIoCs(purgeCutoff);
|
|
90
|
+
// Purge old enriched threats
|
|
91
|
+
const threatCutoff = new Date(Date.now() - this.config.threatRetentionDays * 24 * 60 * 60 * 1000).toISOString();
|
|
92
|
+
this.db
|
|
93
|
+
.prepare('DELETE FROM enriched_threats WHERE received_at < ? AND campaign_id IS NULL')
|
|
94
|
+
.run(threatCutoff);
|
|
95
|
+
// Purge old audit log entries (180 days retention)
|
|
96
|
+
const auditCutoff = new Date(Date.now() - 180 * 24 * 60 * 60 * 1000).toISOString();
|
|
97
|
+
const auditResult = this.db
|
|
98
|
+
.prepare('DELETE FROM audit_log WHERE created_at < ?')
|
|
99
|
+
.run(auditCutoff);
|
|
100
|
+
const auditPurged = auditResult.changes;
|
|
101
|
+
// WAL checkpoint
|
|
102
|
+
let vacuumed = false;
|
|
103
|
+
try {
|
|
104
|
+
this.db.pragma('wal_checkpoint(PASSIVE)');
|
|
105
|
+
vacuumed = true;
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
/* ignore checkpoint errors */
|
|
109
|
+
}
|
|
110
|
+
return { expired, purged, vacuumed, auditPurged };
|
|
111
|
+
}
|
|
112
|
+
/** Run database backup / 執行資料庫備份 */
|
|
113
|
+
runBackup(backupDir, maxBackups = 30) {
|
|
114
|
+
try {
|
|
115
|
+
if (!existsSync(backupDir)) {
|
|
116
|
+
mkdirSync(backupDir, { recursive: true });
|
|
117
|
+
}
|
|
118
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
119
|
+
const dest = join(backupDir, `threat-cloud-${timestamp}.db`);
|
|
120
|
+
this.db.exec(`VACUUM INTO '${dest.replace(/'/g, "''")}'`);
|
|
121
|
+
// Rotate: remove oldest backups beyond maxBackups
|
|
122
|
+
const backups = readdirSync(backupDir)
|
|
123
|
+
.filter((f) => f.startsWith('threat-cloud-') && f.endsWith('.db'))
|
|
124
|
+
.sort();
|
|
125
|
+
while (backups.length > maxBackups) {
|
|
126
|
+
const oldest = backups.shift();
|
|
127
|
+
if (oldest) {
|
|
128
|
+
try {
|
|
129
|
+
unlinkSync(join(backupDir, oldest));
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
/* best effort */
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return dest;
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=scheduler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Threat Cloud HTTP API Server
|
|
3
|
+
* 威脅雲 HTTP API 伺服器
|
|
4
|
+
*
|
|
5
|
+
* Endpoints:
|
|
6
|
+
* - POST /api/threats Upload anonymized threat data
|
|
7
|
+
* - POST /api/trap-intel Upload trap intelligence data
|
|
8
|
+
* - GET /api/rules Fetch rules (optional ?since= filter)
|
|
9
|
+
* - POST /api/rules Publish a new community rule
|
|
10
|
+
* - GET /api/stats Get threat statistics
|
|
11
|
+
* - GET /api/iocs Search/list IoCs
|
|
12
|
+
* - GET /api/iocs/:value Lookup single IoC
|
|
13
|
+
* - GET /health Health check
|
|
14
|
+
*
|
|
15
|
+
* @module @panguard-ai/threat-cloud/server
|
|
16
|
+
*/
|
|
17
|
+
import { ThreatCloudDB } from './database.js';
|
|
18
|
+
import { IoCStore } from './ioc-store.js';
|
|
19
|
+
import { Scheduler } from './scheduler.js';
|
|
20
|
+
import type { ServerConfig } from './types.js';
|
|
21
|
+
/**
|
|
22
|
+
* Threat Cloud API Server
|
|
23
|
+
* 威脅雲 API 伺服器
|
|
24
|
+
*/
|
|
25
|
+
export declare class ThreatCloudServer {
|
|
26
|
+
private server;
|
|
27
|
+
private readonly db;
|
|
28
|
+
private readonly iocStore;
|
|
29
|
+
private readonly correlation;
|
|
30
|
+
private readonly queryHandlers;
|
|
31
|
+
private readonly feedDistributor;
|
|
32
|
+
private readonly sightingStore;
|
|
33
|
+
private readonly auditLogger;
|
|
34
|
+
private readonly scheduler;
|
|
35
|
+
private readonly config;
|
|
36
|
+
private rateLimits;
|
|
37
|
+
/** Pre-hashed API keys for constant-time comparison */
|
|
38
|
+
private readonly hashedApiKeys;
|
|
39
|
+
constructor(config: ServerConfig);
|
|
40
|
+
/** Start the server / 啟動伺服器 */
|
|
41
|
+
start(): Promise<void>;
|
|
42
|
+
/** Stop the server gracefully / 優雅停止伺服器 */
|
|
43
|
+
stop(): Promise<void>;
|
|
44
|
+
/** Expose DB for testing / 暴露 DB 供測試使用 */
|
|
45
|
+
getDB(): ThreatCloudDB;
|
|
46
|
+
/** Expose IoC store for testing / 暴露 IoCStore 供測試使用 */
|
|
47
|
+
getIoCStore(): IoCStore;
|
|
48
|
+
/** Expose scheduler for backup management / 暴露排程器供備份管理 */
|
|
49
|
+
getScheduler(): Scheduler;
|
|
50
|
+
private handleRequest;
|
|
51
|
+
private handlePostThreat;
|
|
52
|
+
private handlePostTrapIntel;
|
|
53
|
+
private handleSearchIoCs;
|
|
54
|
+
private handleLookupIoC;
|
|
55
|
+
/** GET /api/rules?since=<ISO timestamp> */
|
|
56
|
+
private handleGetRules;
|
|
57
|
+
/** POST /api/rules */
|
|
58
|
+
private handlePostRule;
|
|
59
|
+
/** GET /api/stats (enhanced) */
|
|
60
|
+
private handleGetStats;
|
|
61
|
+
private handleListCampaigns;
|
|
62
|
+
private handleCampaignStats;
|
|
63
|
+
private handleGetCampaign;
|
|
64
|
+
private handleTimeSeries;
|
|
65
|
+
private handleGeoDistribution;
|
|
66
|
+
private handleTrends;
|
|
67
|
+
private handleMitreHeatmap;
|
|
68
|
+
private handleIPBlocklist;
|
|
69
|
+
private handleDomainBlocklist;
|
|
70
|
+
private handleIoCFeed;
|
|
71
|
+
private handleAgentUpdate;
|
|
72
|
+
private handlePostSighting;
|
|
73
|
+
private handleGetSightings;
|
|
74
|
+
private handleGetAuditLog;
|
|
75
|
+
/**
|
|
76
|
+
* Anonymize IP by zeroing last two octets (/16 for IPv4).
|
|
77
|
+
* GDPR-compliant: /16 masking prevents re-identification.
|
|
78
|
+
* 匿名化 IP(IPv4 遮蔽最後兩個八位元組,符合 GDPR)
|
|
79
|
+
*/
|
|
80
|
+
private anonymizeIP;
|
|
81
|
+
/**
|
|
82
|
+
* Verify API key using constant-time comparison to prevent timing attacks.
|
|
83
|
+
* 使用常數時間比較驗證 API key 以防止計時攻擊
|
|
84
|
+
*/
|
|
85
|
+
private verifyApiKey;
|
|
86
|
+
/** Rate limit check (supports per-IP and per-key) / 速率限制檢查 */
|
|
87
|
+
private checkRateLimit;
|
|
88
|
+
/** Validate IPv4 or IPv6 format / 驗證 IP 格式 */
|
|
89
|
+
private isValidIP;
|
|
90
|
+
/** Validate ISO timestamp with reasonable bounds / 驗證 ISO 時間戳格式 */
|
|
91
|
+
private isValidTimestamp;
|
|
92
|
+
/** Sanitize string input: truncate and strip control characters / 清理字串輸入 */
|
|
93
|
+
private sanitizeString;
|
|
94
|
+
/** Read request body with size limit / 讀取請求主體 */
|
|
95
|
+
private readBody;
|
|
96
|
+
/** Send JSON response / 發送 JSON 回應 */
|
|
97
|
+
private sendJson;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAM1C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EACV,YAAY,EAQb,MAAM,YAAY,CAAC;AAQpB;;;GAGG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAgD;IAC9D,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAgB;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAW;IACpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAoB;IAChD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAC9C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkB;IAClD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAC9C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,UAAU,CAA0C;IAC5D,uDAAuD;IACvD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAW;gBAE7B,MAAM,EAAE,YAAY;IAehC,+BAA+B;IACzB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAoB5B,2CAA2C;IACrC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAqB3B,0CAA0C;IAC1C,KAAK,IAAI,aAAa;IAItB,uDAAuD;IACvD,WAAW,IAAI,QAAQ;IAIvB,0DAA0D;IAC1D,YAAY,IAAI,SAAS;YAIX,aAAa;YAwOb,gBAAgB;YAyFhB,mBAAmB;IA2FjC,OAAO,CAAC,gBAAgB;IA0BxB,OAAO,CAAC,eAAe;IAgBvB,2CAA2C;IAC3C,OAAO,CAAC,cAAc;IAOtB,sBAAsB;YACR,cAAc;IAmD5B,gCAAgC;IAChC,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,mBAAmB;IAK3B,OAAO,CAAC,iBAAiB;IAczB,OAAO,CAAC,gBAAgB;IAiBxB,OAAO,CAAC,qBAAqB;IAM7B,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,iBAAiB;IASzB,OAAO,CAAC,qBAAqB;IAS7B,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,iBAAiB;YAcX,kBAAkB;IA4ChC,OAAO,CAAC,kBAAkB;IAmB1B,OAAO,CAAC,iBAAiB;IAmBzB;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAqBnB;;;OAGG;IACH,OAAO,CAAC,YAAY;IAUpB,8DAA8D;IAC9D,OAAO,CAAC,cAAc;IAkBtB,8CAA8C;IAC9C,OAAO,CAAC,SAAS;IAcjB,mEAAmE;IACnE,OAAO,CAAC,gBAAgB;IASxB,4EAA4E;IAC5E,OAAO,CAAC,cAAc;IAKtB,iDAAiD;IACjD,OAAO,CAAC,QAAQ;IAoBhB,sCAAsC;IACtC,OAAO,CAAC,QAAQ;CAIjB"}
|