@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,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query Handlers for advanced analytics
|
|
3
|
+
* 進階分析查詢處理器
|
|
4
|
+
*
|
|
5
|
+
* Provides timeseries, geo distribution, trends, and MITRE heatmap queries.
|
|
6
|
+
*
|
|
7
|
+
* @module @panguard-ai/threat-cloud/query-handlers
|
|
8
|
+
*/
|
|
9
|
+
export class QueryHandlers {
|
|
10
|
+
db;
|
|
11
|
+
constructor(db) {
|
|
12
|
+
this.db = db;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Time-series query: event counts grouped by time bucket.
|
|
16
|
+
* 時間序列查詢:依時間桶分組的事件計數
|
|
17
|
+
*/
|
|
18
|
+
getTimeSeries(granularity = 'day', since, attackType) {
|
|
19
|
+
const sinceDate = since ?? new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString();
|
|
20
|
+
// Whitelist granularity → strftime format to prevent SQL injection
|
|
21
|
+
const GRANULARITY_FORMATS = {
|
|
22
|
+
hour: '%Y-%m-%dT%H:00:00Z',
|
|
23
|
+
week: '%Y-W%W',
|
|
24
|
+
day: '%Y-%m-%d',
|
|
25
|
+
};
|
|
26
|
+
const format = GRANULARITY_FORMATS[granularity] ?? GRANULARITY_FORMATS['day'];
|
|
27
|
+
const conditions = ['timestamp > ?'];
|
|
28
|
+
const params = [sinceDate];
|
|
29
|
+
if (attackType) {
|
|
30
|
+
conditions.push('attack_type = ?');
|
|
31
|
+
params.push(attackType);
|
|
32
|
+
}
|
|
33
|
+
const where = conditions.join(' AND ');
|
|
34
|
+
const rows = this.db
|
|
35
|
+
.prepare(`SELECT strftime('${format}', timestamp) as ts, COUNT(*) as count
|
|
36
|
+
FROM enriched_threats
|
|
37
|
+
WHERE ${where}
|
|
38
|
+
GROUP BY ts
|
|
39
|
+
ORDER BY ts ASC`)
|
|
40
|
+
.all(...params);
|
|
41
|
+
return rows.map((r) => ({ timestamp: r.ts, count: r.count }));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Geographic distribution query.
|
|
45
|
+
* 地理分佈查詢
|
|
46
|
+
*/
|
|
47
|
+
getGeoDistribution(since) {
|
|
48
|
+
const sinceDate = since ?? new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString();
|
|
49
|
+
const regionRows = this.db
|
|
50
|
+
.prepare(`SELECT region, COUNT(*) as count, COUNT(DISTINCT attack_source_ip) as unique_ips
|
|
51
|
+
FROM enriched_threats
|
|
52
|
+
WHERE timestamp > ?
|
|
53
|
+
GROUP BY region
|
|
54
|
+
ORDER BY count DESC`)
|
|
55
|
+
.all(sinceDate);
|
|
56
|
+
return regionRows.map((r) => {
|
|
57
|
+
const topTypes = this.db
|
|
58
|
+
.prepare(`SELECT attack_type as type, COUNT(*) as count
|
|
59
|
+
FROM enriched_threats
|
|
60
|
+
WHERE region = ? AND timestamp > ?
|
|
61
|
+
GROUP BY attack_type
|
|
62
|
+
ORDER BY count DESC
|
|
63
|
+
LIMIT 5`)
|
|
64
|
+
.all(r.region, sinceDate);
|
|
65
|
+
return {
|
|
66
|
+
region: r.region,
|
|
67
|
+
count: r.count,
|
|
68
|
+
topAttackTypes: topTypes,
|
|
69
|
+
uniqueIPs: r.unique_ips,
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Trend analysis: compare current period with previous period.
|
|
75
|
+
* 趨勢分析:比較當前與前一期間
|
|
76
|
+
*/
|
|
77
|
+
getTrends(periodDays = 7) {
|
|
78
|
+
const now = Date.now();
|
|
79
|
+
const currentStart = new Date(now - periodDays * 24 * 60 * 60 * 1000).toISOString();
|
|
80
|
+
const previousStart = new Date(now - periodDays * 2 * 24 * 60 * 60 * 1000).toISOString();
|
|
81
|
+
const currentCounts = this.db
|
|
82
|
+
.prepare(`SELECT attack_type, COUNT(*) as count
|
|
83
|
+
FROM enriched_threats
|
|
84
|
+
WHERE timestamp > ?
|
|
85
|
+
GROUP BY attack_type`)
|
|
86
|
+
.all(currentStart);
|
|
87
|
+
const previousCounts = this.db
|
|
88
|
+
.prepare(`SELECT attack_type, COUNT(*) as count
|
|
89
|
+
FROM enriched_threats
|
|
90
|
+
WHERE timestamp > ? AND timestamp <= ?
|
|
91
|
+
GROUP BY attack_type`)
|
|
92
|
+
.all(previousStart, currentStart);
|
|
93
|
+
const prevMap = new Map(previousCounts.map((r) => [r.attack_type, r.count]));
|
|
94
|
+
const allTypes = new Set([
|
|
95
|
+
...currentCounts.map((r) => r.attack_type),
|
|
96
|
+
...previousCounts.map((r) => r.attack_type),
|
|
97
|
+
]);
|
|
98
|
+
const trends = [];
|
|
99
|
+
for (const attackType of allTypes) {
|
|
100
|
+
const currentCount = currentCounts.find((r) => r.attack_type === attackType)?.count ?? 0;
|
|
101
|
+
const previousCount = prevMap.get(attackType) ?? 0;
|
|
102
|
+
let changePercent = 0;
|
|
103
|
+
if (previousCount > 0) {
|
|
104
|
+
changePercent = Math.round(((currentCount - previousCount) / previousCount) * 100);
|
|
105
|
+
}
|
|
106
|
+
else if (currentCount > 0) {
|
|
107
|
+
changePercent = 100;
|
|
108
|
+
}
|
|
109
|
+
let direction = 'stable';
|
|
110
|
+
if (changePercent > 10)
|
|
111
|
+
direction = 'rising';
|
|
112
|
+
else if (changePercent < -10)
|
|
113
|
+
direction = 'falling';
|
|
114
|
+
trends.push({ attackType, currentCount, previousCount, changePercent, direction });
|
|
115
|
+
}
|
|
116
|
+
return trends.sort((a, b) => b.currentCount - a.currentCount);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* MITRE ATT&CK technique heatmap.
|
|
120
|
+
* MITRE ATT&CK 技術熱力圖
|
|
121
|
+
*/
|
|
122
|
+
getMitreHeatmap(since) {
|
|
123
|
+
const sinceDate = since ?? new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString();
|
|
124
|
+
const rows = this.db
|
|
125
|
+
.prepare(`SELECT mitre_techniques, severity
|
|
126
|
+
FROM enriched_threats
|
|
127
|
+
WHERE timestamp > ?`)
|
|
128
|
+
.all(sinceDate);
|
|
129
|
+
const techMap = new Map();
|
|
130
|
+
for (const row of rows) {
|
|
131
|
+
const techniques = JSON.parse(row.mitre_techniques);
|
|
132
|
+
for (const t of techniques) {
|
|
133
|
+
const entry = techMap.get(t) ?? { count: 0, severities: [] };
|
|
134
|
+
entry.count++;
|
|
135
|
+
entry.severities.push(row.severity);
|
|
136
|
+
techMap.set(t, entry);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const severityOrder = ['critical', 'high', 'medium', 'low'];
|
|
140
|
+
return [...techMap.entries()]
|
|
141
|
+
.map(([technique, data]) => {
|
|
142
|
+
const maxSeverity = severityOrder.find((s) => data.severities.includes(s)) ?? 'medium';
|
|
143
|
+
return { technique, count: data.count, severity: maxSeverity };
|
|
144
|
+
})
|
|
145
|
+
.sort((a, b) => b.count - a.count);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Enhanced stats combining all data sources.
|
|
149
|
+
* 增強統計:整合所有資料來源
|
|
150
|
+
*/
|
|
151
|
+
getEnhancedStats() {
|
|
152
|
+
const totalThreats = this.db.prepare('SELECT COUNT(*) as count FROM threats').get().count;
|
|
153
|
+
const totalRules = this.db.prepare('SELECT COUNT(*) as count FROM rules').get().count;
|
|
154
|
+
const topAttackTypes = this.db
|
|
155
|
+
.prepare(`SELECT attack_type as type, COUNT(*) as count
|
|
156
|
+
FROM threats
|
|
157
|
+
GROUP BY attack_type
|
|
158
|
+
ORDER BY count DESC
|
|
159
|
+
LIMIT 10`)
|
|
160
|
+
.all();
|
|
161
|
+
const totalIoCs = this.db.prepare("SELECT COUNT(*) as count FROM iocs WHERE status = 'active'").get().count;
|
|
162
|
+
const iocsByTypeRows = this.db
|
|
163
|
+
.prepare(`SELECT type, COUNT(*) as count FROM iocs WHERE status = 'active' GROUP BY type`)
|
|
164
|
+
.all();
|
|
165
|
+
const iocsByType = {};
|
|
166
|
+
for (const row of iocsByTypeRows) {
|
|
167
|
+
iocsByType[row.type] = row.count;
|
|
168
|
+
}
|
|
169
|
+
const activeCampaigns = this.db.prepare("SELECT COUNT(*) as count FROM campaigns WHERE status = 'active'").get().count;
|
|
170
|
+
const autoGeneratedRules = this.db.prepare('SELECT COUNT(*) as count FROM generated_patterns').get().count;
|
|
171
|
+
const trapEventsCount = this.db
|
|
172
|
+
.prepare("SELECT COUNT(*) as count FROM enriched_threats WHERE source_type = 'trap'")
|
|
173
|
+
.get().count;
|
|
174
|
+
const guardEventsCount = this.db
|
|
175
|
+
.prepare("SELECT COUNT(*) as count FROM enriched_threats WHERE source_type = 'guard'")
|
|
176
|
+
.get().count;
|
|
177
|
+
const topRegions = this.db
|
|
178
|
+
.prepare(`SELECT region, COUNT(*) as count
|
|
179
|
+
FROM enriched_threats
|
|
180
|
+
GROUP BY region
|
|
181
|
+
ORDER BY count DESC
|
|
182
|
+
LIMIT 10`)
|
|
183
|
+
.all();
|
|
184
|
+
const topMitreTechniques = this.db
|
|
185
|
+
.prepare(`SELECT mitre_technique as technique, COUNT(*) as count
|
|
186
|
+
FROM threats
|
|
187
|
+
GROUP BY mitre_technique
|
|
188
|
+
ORDER BY count DESC
|
|
189
|
+
LIMIT 10`)
|
|
190
|
+
.all();
|
|
191
|
+
const last24h = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();
|
|
192
|
+
const last24hThreats = this.db
|
|
193
|
+
.prepare('SELECT COUNT(*) as count FROM threats WHERE received_at > ?')
|
|
194
|
+
.get(last24h).count;
|
|
195
|
+
return {
|
|
196
|
+
totalThreats,
|
|
197
|
+
totalRules,
|
|
198
|
+
topAttackTypes,
|
|
199
|
+
topMitreTechniques,
|
|
200
|
+
last24hThreats,
|
|
201
|
+
totalIoCs,
|
|
202
|
+
iocsByType,
|
|
203
|
+
activeCampaigns,
|
|
204
|
+
autoGeneratedRules,
|
|
205
|
+
trapEventsCount,
|
|
206
|
+
guardEventsCount,
|
|
207
|
+
topRegions,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=query-handlers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-handlers.js","sourceRoot":"","sources":["../src/query-handlers.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAWH,MAAM,OAAO,aAAa;IACK;IAA7B,YAA6B,EAAqB;QAArB,OAAE,GAAF,EAAE,CAAmB;IAAG,CAAC;IAEtD;;;OAGG;IACH,aAAa,CACX,cAAuC,KAAK,EAC5C,KAAc,EACd,UAAmB;QAEnB,MAAM,SAAS,GAAG,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;QAEzF,mEAAmE;QACnE,MAAM,mBAAmB,GAA2B;YAClD,IAAI,EAAE,oBAAoB;YAC1B,IAAI,EAAE,QAAQ;YACd,GAAG,EAAE,UAAU;SAChB,CAAC;QACF,MAAM,MAAM,GAAG,mBAAmB,CAAC,WAAW,CAAC,IAAI,mBAAmB,CAAC,KAAK,CAAE,CAAC;QAE/E,MAAM,UAAU,GAAG,CAAC,eAAe,CAAC,CAAC;QACrC,MAAM,MAAM,GAAc,CAAC,SAAS,CAAC,CAAC;QAEtC,IAAI,UAAU,EAAE,CAAC;YACf,UAAU,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YACnC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC1B,CAAC;QAED,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAEvC,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;aACjB,OAAO,CACN,oBAAoB,MAAM;;iBAEjB,KAAK;;yBAEG,CAClB;aACA,GAAG,CAAC,GAAG,MAAM,CAAyC,CAAC;QAE1D,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAChE,CAAC;IAED;;;OAGG;IACH,kBAAkB,CAAC,KAAc;QAC/B,MAAM,SAAS,GAAG,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;QAEzF,MAAM,UAAU,GAAG,IAAI,CAAC,EAAE;aACvB,OAAO,CACN;;;;6BAIqB,CACtB;aACA,GAAG,CAAC,SAAS,CAAiE,CAAC;QAElF,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YAC1B,MAAM,QAAQ,GAAG,IAAI,CAAC,EAAE;iBACrB,OAAO,CACN;;;;;mBAKS,CACV;iBACA,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,SAAS,CAA2C,CAAC;YAEtE,OAAO;gBACL,MAAM,EAAE,CAAC,CAAC,MAAM;gBAChB,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,cAAc,EAAE,QAAQ;gBACxB,SAAS,EAAE,CAAC,CAAC,UAAU;aACxB,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACH,SAAS,CAAC,aAAqB,CAAC;QAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,YAAY,GAAG,IAAI,IAAI,CAAC,GAAG,GAAG,UAAU,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;QACpF,MAAM,aAAa,GAAG,IAAI,IAAI,CAAC,GAAG,GAAG,UAAU,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;QAEzF,MAAM,aAAa,GAAG,IAAI,CAAC,EAAE;aAC1B,OAAO,CACN;;;8BAGsB,CACvB;aACA,GAAG,CAAC,YAAY,CAAkD,CAAC;QAEtE,MAAM,cAAc,GAAG,IAAI,CAAC,EAAE;aAC3B,OAAO,CACN;;;8BAGsB,CACvB;aACA,GAAG,CAAC,aAAa,EAAE,YAAY,CAAkD,CAAC;QAErF,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC7E,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC;YACvB,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC;YAC1C,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC;SAC5C,CAAC,CAAC;QAEH,MAAM,MAAM,GAAiB,EAAE,CAAC;QAChC,KAAK,MAAM,UAAU,IAAI,QAAQ,EAAE,CAAC;YAClC,MAAM,YAAY,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,KAAK,UAAU,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC;YACzF,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;YAEnD,IAAI,aAAa,GAAG,CAAC,CAAC;YACtB,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;gBACtB,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,GAAG,aAAa,CAAC,GAAG,aAAa,CAAC,GAAG,GAAG,CAAC,CAAC;YACrF,CAAC;iBAAM,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;gBAC5B,aAAa,GAAG,GAAG,CAAC;YACtB,CAAC;YAED,IAAI,SAAS,GAA4B,QAAQ,CAAC;YAClD,IAAI,aAAa,GAAG,EAAE;gBAAE,SAAS,GAAG,QAAQ,CAAC;iBACxC,IAAI,aAAa,GAAG,CAAC,EAAE;gBAAE,SAAS,GAAG,SAAS,CAAC;YAEpD,MAAM,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,CAAC,CAAC;QACrF,CAAC;QAED,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC;IAChE,CAAC;IAED;;;OAGG;IACH,eAAe,CAAC,KAAc;QAC5B,MAAM,SAAS,GAAG,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;QAEzF,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;aACjB,OAAO,CACN;;6BAEqB,CACtB;aACA,GAAG,CAAC,SAAS,CAA0D,CAAC;QAE3E,MAAM,OAAO,GAAG,IAAI,GAAG,EAAmD,CAAC;QAE3E,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAa,CAAC;YAChE,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;gBAC3B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;gBAC7D,KAAK,CAAC,KAAK,EAAE,CAAC;gBACd,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBACpC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;QAED,MAAM,aAAa,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QAE5D,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;aAC1B,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,EAAE;YACzB,MAAM,WAAW,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC;YACvF,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;QACjE,CAAC,CAAC;aACD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IACvC,CAAC;IAED;;;OAGG;IACH,gBAAgB;QACd,MAAM,YAAY,GAChB,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,uCAAuC,CAAC,CAAC,GAAG,EAC7D,CAAC,KAAK,CAAC;QAER,MAAM,UAAU,GACd,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,qCAAqC,CAAC,CAAC,GAAG,EAC3D,CAAC,KAAK,CAAC;QAER,MAAM,cAAc,GAAG,IAAI,CAAC,EAAE;aAC3B,OAAO,CACN;;;;kBAIU,CACX;aACA,GAAG,EAA4C,CAAC;QAEnD,MAAM,SAAS,GACb,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,4DAA4D,CAAC,CAAC,GAAG,EAGlF,CAAC,KAAK,CAAC;QAER,MAAM,cAAc,GAAG,IAAI,CAAC,EAAE;aAC3B,OAAO,CAAC,gFAAgF,CAAC;aACzF,GAAG,EAA4C,CAAC;QAEnD,MAAM,UAAU,GAA2B,EAAE,CAAC;QAC9C,KAAK,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;YACjC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC;QACnC,CAAC;QAED,MAAM,eAAe,GACnB,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,iEAAiE,CAAC,CAAC,GAAG,EAGvF,CAAC,KAAK,CAAC;QAER,MAAM,kBAAkB,GACtB,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,kDAAkD,CAAC,CAAC,GAAG,EAGxE,CAAC,KAAK,CAAC;QAER,MAAM,eAAe,GACnB,IAAI,CAAC,EAAE;aACJ,OAAO,CAAC,2EAA2E,CAAC;aACpF,GAAG,EACP,CAAC,KAAK,CAAC;QAER,MAAM,gBAAgB,GACpB,IAAI,CAAC,EAAE;aACJ,OAAO,CAAC,4EAA4E,CAAC;aACrF,GAAG,EACP,CAAC,KAAK,CAAC;QAER,MAAM,UAAU,GAAG,IAAI,CAAC,EAAE;aACvB,OAAO,CACN;;;;kBAIU,CACX;aACA,GAAG,EAA8C,CAAC;QAErD,MAAM,kBAAkB,GAAG,IAAI,CAAC,EAAE;aAC/B,OAAO,CACN;;;;kBAIU,CACX;aACA,GAAG,EAAiD,CAAC;QAExD,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;QACzE,MAAM,cAAc,GAClB,IAAI,CAAC,EAAE;aACJ,OAAO,CAAC,6DAA6D,CAAC;aACtE,GAAG,CAAC,OAAO,CAGf,CAAC,KAAK,CAAC;QAER,OAAO;YACL,YAAY;YACZ,UAAU;YACV,cAAc;YACd,kBAAkB;YAClB,cAAc;YACd,SAAS;YACT,UAAU;YACV,eAAe;YACf,kBAAkB;YAClB,eAAe;YACf,gBAAgB;YAChB,UAAU;SACX,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IoC Reputation Scoring Engine
|
|
3
|
+
* IoC 信譽評分引擎
|
|
4
|
+
*
|
|
5
|
+
* Calculates reputation scores using a weighted formula:
|
|
6
|
+
* sighting frequency, severity, recency (time-decay), source diversity, confidence.
|
|
7
|
+
*
|
|
8
|
+
* @module @panguard-ai/threat-cloud/reputation-engine
|
|
9
|
+
*/
|
|
10
|
+
import type Database from 'better-sqlite3';
|
|
11
|
+
import type { ReputationConfig } from './types.js';
|
|
12
|
+
export declare class ReputationEngine {
|
|
13
|
+
private readonly db;
|
|
14
|
+
private readonly config;
|
|
15
|
+
constructor(db: Database.Database, config?: Partial<ReputationConfig>);
|
|
16
|
+
/**
|
|
17
|
+
* Recalculate reputation scores for all active IoCs.
|
|
18
|
+
* 重新計算所有活躍 IoC 的信譽分數
|
|
19
|
+
*/
|
|
20
|
+
recalculateAll(): {
|
|
21
|
+
updated: number;
|
|
22
|
+
duration: number;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Calculate reputation for a single IoC by ID.
|
|
26
|
+
* 計算單一 IoC 的信譽分數
|
|
27
|
+
*/
|
|
28
|
+
calculateForIoC(iocId: number): number;
|
|
29
|
+
/**
|
|
30
|
+
* Core scoring algorithm.
|
|
31
|
+
* 核心評分演算法
|
|
32
|
+
*/
|
|
33
|
+
private calculateScore;
|
|
34
|
+
/** Compute weighted severity score / 計算加權嚴重度分數 */
|
|
35
|
+
private computeSeverityScore;
|
|
36
|
+
/** Compute recency score with exponential decay / 計算時間衰減分數 */
|
|
37
|
+
private computeRecencyScore;
|
|
38
|
+
/**
|
|
39
|
+
* Get associated threat data for an IoC.
|
|
40
|
+
* 取得 IoC 的關聯威脅資料
|
|
41
|
+
*/
|
|
42
|
+
private getAssociatedThreats;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=reputation-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reputation-engine.d.ts","sourceRoot":"","sources":["../src/reputation-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA+BnD,qBAAa,gBAAgB;IAIzB,OAAO,CAAC,QAAQ,CAAC,EAAE;IAHrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmB;gBAGvB,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACtC,MAAM,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC;IAQpC;;;OAGG;IACH,cAAc,IAAI;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE;IA+BvD;;;OAGG;IACH,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAoBtC;;;OAGG;IACH,OAAO,CAAC,cAAc;IAkCtB,kDAAkD;IAClD,OAAO,CAAC,oBAAoB;IAa5B,8DAA8D;IAC9D,OAAO,CAAC,mBAAmB;IAQ3B;;;OAGG;IACH,OAAO,CAAC,oBAAoB;CA6D7B"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IoC Reputation Scoring Engine
|
|
3
|
+
* IoC 信譽評分引擎
|
|
4
|
+
*
|
|
5
|
+
* Calculates reputation scores using a weighted formula:
|
|
6
|
+
* sighting frequency, severity, recency (time-decay), source diversity, confidence.
|
|
7
|
+
*
|
|
8
|
+
* @module @panguard-ai/threat-cloud/reputation-engine
|
|
9
|
+
*/
|
|
10
|
+
/** Severity numeric mapping / 嚴重度數值對映 */
|
|
11
|
+
const SEVERITY_MAP = {
|
|
12
|
+
critical: 100,
|
|
13
|
+
high: 75,
|
|
14
|
+
medium: 50,
|
|
15
|
+
low: 25,
|
|
16
|
+
};
|
|
17
|
+
/** Default config / 預設配置 */
|
|
18
|
+
const DEFAULT_CONFIG = {
|
|
19
|
+
halfLifeDays: 30,
|
|
20
|
+
weights: {
|
|
21
|
+
sighting: 0.3,
|
|
22
|
+
severity: 0.25,
|
|
23
|
+
recency: 0.2,
|
|
24
|
+
diversity: 0.15,
|
|
25
|
+
confidence: 0.1,
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
export class ReputationEngine {
|
|
29
|
+
db;
|
|
30
|
+
config;
|
|
31
|
+
constructor(db, config) {
|
|
32
|
+
this.db = db;
|
|
33
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
34
|
+
if (config?.weights) {
|
|
35
|
+
this.config.weights = { ...DEFAULT_CONFIG.weights, ...config.weights };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Recalculate reputation scores for all active IoCs.
|
|
40
|
+
* 重新計算所有活躍 IoC 的信譽分數
|
|
41
|
+
*/
|
|
42
|
+
recalculateAll() {
|
|
43
|
+
const startTime = Date.now();
|
|
44
|
+
const iocs = this.db
|
|
45
|
+
.prepare("SELECT id, sightings, confidence, last_seen FROM iocs WHERE status = 'active'")
|
|
46
|
+
.all();
|
|
47
|
+
const updateStmt = this.db.prepare("UPDATE iocs SET reputation_score = ?, updated_at = datetime('now') WHERE id = ?");
|
|
48
|
+
const updateAll = this.db.transaction(() => {
|
|
49
|
+
for (const ioc of iocs) {
|
|
50
|
+
const score = this.calculateScore(ioc);
|
|
51
|
+
updateStmt.run(score, ioc.id);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
updateAll();
|
|
55
|
+
return {
|
|
56
|
+
updated: iocs.length,
|
|
57
|
+
duration: Date.now() - startTime,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Calculate reputation for a single IoC by ID.
|
|
62
|
+
* 計算單一 IoC 的信譽分數
|
|
63
|
+
*/
|
|
64
|
+
calculateForIoC(iocId) {
|
|
65
|
+
const ioc = this.db
|
|
66
|
+
.prepare('SELECT id, sightings, confidence, last_seen, type, normalized_value FROM iocs WHERE id = ?')
|
|
67
|
+
.get(iocId);
|
|
68
|
+
if (!ioc)
|
|
69
|
+
return 0;
|
|
70
|
+
return this.calculateScore(ioc);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Core scoring algorithm.
|
|
74
|
+
* 核心評分演算法
|
|
75
|
+
*/
|
|
76
|
+
calculateScore(ioc) {
|
|
77
|
+
const summary = this.getAssociatedThreats(ioc.id);
|
|
78
|
+
const w = this.config.weights;
|
|
79
|
+
// Sighting score: each sighting adds 5 pts, capped at 100
|
|
80
|
+
const sightingScore = Math.min(100, ioc.sightings * 5);
|
|
81
|
+
// Severity score: weighted average of associated threats
|
|
82
|
+
const severityScore = this.computeSeverityScore(summary.severityCounts, summary.totalThreats);
|
|
83
|
+
// Recency score: exponential decay with configurable half-life
|
|
84
|
+
const recencyScore = this.computeRecencyScore(ioc.last_seen);
|
|
85
|
+
// Diversity score: each unique source adds 25 pts, capped at 100
|
|
86
|
+
const diversityScore = Math.min(100, summary.uniqueSources * 25);
|
|
87
|
+
// Confidence score: max confidence across sightings
|
|
88
|
+
const confidenceScore = Math.max(ioc.confidence, summary.maxConfidence);
|
|
89
|
+
const rawScore = sightingScore * w.sighting +
|
|
90
|
+
severityScore * w.severity +
|
|
91
|
+
recencyScore * w.recency +
|
|
92
|
+
diversityScore * w.diversity +
|
|
93
|
+
confidenceScore * w.confidence;
|
|
94
|
+
return Math.max(0, Math.min(100, Math.round(rawScore)));
|
|
95
|
+
}
|
|
96
|
+
/** Compute weighted severity score / 計算加權嚴重度分數 */
|
|
97
|
+
computeSeverityScore(severityCounts, totalThreats) {
|
|
98
|
+
if (totalThreats === 0)
|
|
99
|
+
return 0;
|
|
100
|
+
let weightedSum = 0;
|
|
101
|
+
for (const [severity, count] of Object.entries(severityCounts)) {
|
|
102
|
+
weightedSum += (SEVERITY_MAP[severity] ?? 50) * count;
|
|
103
|
+
}
|
|
104
|
+
return weightedSum / totalThreats;
|
|
105
|
+
}
|
|
106
|
+
/** Compute recency score with exponential decay / 計算時間衰減分數 */
|
|
107
|
+
computeRecencyScore(lastSeen) {
|
|
108
|
+
const now = Date.now();
|
|
109
|
+
const lastSeenMs = new Date(lastSeen).getTime();
|
|
110
|
+
const daysSince = Math.max(0, (now - lastSeenMs) / (1000 * 60 * 60 * 24));
|
|
111
|
+
const lambda = Math.LN2 / this.config.halfLifeDays;
|
|
112
|
+
return 100 * Math.exp(-lambda * daysSince);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Get associated threat data for an IoC.
|
|
116
|
+
* 取得 IoC 的關聯威脅資料
|
|
117
|
+
*/
|
|
118
|
+
getAssociatedThreats(iocId) {
|
|
119
|
+
// Get the IoC's normalized value for matching
|
|
120
|
+
const ioc = this.db
|
|
121
|
+
.prepare('SELECT type, normalized_value FROM iocs WHERE id = ?')
|
|
122
|
+
.get(iocId);
|
|
123
|
+
if (!ioc) {
|
|
124
|
+
return {
|
|
125
|
+
totalThreats: 0,
|
|
126
|
+
severityCounts: {},
|
|
127
|
+
uniqueSources: 0,
|
|
128
|
+
maxConfidence: 0,
|
|
129
|
+
latestTimestamp: '',
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
// For IP-type IoCs, match against enriched_threats.attack_source_ip
|
|
133
|
+
if (ioc.type === 'ip') {
|
|
134
|
+
const rows = this.db
|
|
135
|
+
.prepare(`SELECT severity, source_type, confidence, timestamp
|
|
136
|
+
FROM enriched_threats
|
|
137
|
+
WHERE attack_source_ip = ?`)
|
|
138
|
+
.all(ioc.normalized_value);
|
|
139
|
+
const severityCounts = {};
|
|
140
|
+
const sources = new Set();
|
|
141
|
+
let maxConfidence = 0;
|
|
142
|
+
let latestTimestamp = '';
|
|
143
|
+
for (const row of rows) {
|
|
144
|
+
severityCounts[row.severity] = (severityCounts[row.severity] ?? 0) + 1;
|
|
145
|
+
sources.add(row.source_type);
|
|
146
|
+
if (row.confidence > maxConfidence)
|
|
147
|
+
maxConfidence = row.confidence;
|
|
148
|
+
if (row.timestamp > latestTimestamp)
|
|
149
|
+
latestTimestamp = row.timestamp;
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
totalThreats: rows.length,
|
|
153
|
+
severityCounts,
|
|
154
|
+
uniqueSources: sources.size,
|
|
155
|
+
maxConfidence,
|
|
156
|
+
latestTimestamp,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
// For non-IP types, no associated threats (future: match by metadata)
|
|
160
|
+
return {
|
|
161
|
+
totalThreats: 0,
|
|
162
|
+
severityCounts: {},
|
|
163
|
+
uniqueSources: 0,
|
|
164
|
+
maxConfidence: 0,
|
|
165
|
+
latestTimestamp: '',
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=reputation-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reputation-engine.js","sourceRoot":"","sources":["../src/reputation-engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
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 type Database from 'better-sqlite3';
|
|
11
|
+
import type { DetectedPattern, RuleGenerationResult, RuleGeneratorConfig } from './types.js';
|
|
12
|
+
export declare class RuleGenerator {
|
|
13
|
+
private readonly db;
|
|
14
|
+
private readonly config;
|
|
15
|
+
constructor(db: Database.Database, config?: Partial<RuleGeneratorConfig>);
|
|
16
|
+
/**
|
|
17
|
+
* Analyze recent events and generate rules for recurring patterns.
|
|
18
|
+
* 分析近期事件並為反覆出現的模式產生規則
|
|
19
|
+
*/
|
|
20
|
+
generateRules(): RuleGenerationResult;
|
|
21
|
+
/**
|
|
22
|
+
* Detect recurring patterns in enriched threat events.
|
|
23
|
+
* 偵測豐富化威脅事件中的反覆模式
|
|
24
|
+
*/
|
|
25
|
+
detectPatterns(): DetectedPattern[];
|
|
26
|
+
/**
|
|
27
|
+
* Get all generated patterns.
|
|
28
|
+
* 取得所有已產生的模式
|
|
29
|
+
*/
|
|
30
|
+
getGeneratedPatterns(): Array<{
|
|
31
|
+
patternHash: string;
|
|
32
|
+
attackType: string;
|
|
33
|
+
mitreTechniques: string[];
|
|
34
|
+
ruleId: string;
|
|
35
|
+
occurrences: number;
|
|
36
|
+
distinctIPs: number;
|
|
37
|
+
}>;
|
|
38
|
+
/** Create a new rule from a detected pattern */
|
|
39
|
+
private createRuleFromPattern;
|
|
40
|
+
/** Update an existing pattern's statistics */
|
|
41
|
+
private updatePattern;
|
|
42
|
+
/** Generate Sigma YAML rule content */
|
|
43
|
+
private generateSigmaYaml;
|
|
44
|
+
/** Pick highest severity from counts */
|
|
45
|
+
private pickMaxSeverity;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=rule-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-generator.d.ts","sourceRoot":"","sources":["../src/rule-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAqC7F,qBAAa,aAAa;IAItB,OAAO,CAAC,QAAQ,CAAC,EAAE;IAHrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;gBAG1B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACtC,MAAM,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC;IAKvC;;;OAGG;IACH,aAAa,IAAI,oBAAoB;IA+BrC;;;OAGG;IACH,cAAc,IAAI,eAAe,EAAE;IA2FnC;;;OAGG;IACH,oBAAoB,IAAI,KAAK,CAAC;QAC5B,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC;QACnB,eAAe,EAAE,MAAM,EAAE,CAAC;QAC1B,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IA8BF,gDAAgD;IAChD,OAAO,CAAC,qBAAqB;IAoC7B,8CAA8C;IAC9C,OAAO,CAAC,aAAa;IAyBrB,uCAAuC;IACvC,OAAO,CAAC,iBAAiB;IA0BzB,wCAAwC;IACxC,OAAO,CAAC,eAAe;CAMxB"}
|