@panguard-ai/core 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/adapters/adapter-registry.d.ts +150 -0
- package/dist/adapters/adapter-registry.d.ts.map +1 -0
- package/dist/adapters/adapter-registry.js +271 -0
- package/dist/adapters/adapter-registry.js.map +1 -0
- package/dist/adapters/base-adapter.d.ts +101 -0
- package/dist/adapters/base-adapter.d.ts.map +1 -0
- package/dist/adapters/base-adapter.js +160 -0
- package/dist/adapters/base-adapter.js.map +1 -0
- package/dist/adapters/defender-adapter.d.ts +90 -0
- package/dist/adapters/defender-adapter.d.ts.map +1 -0
- package/dist/adapters/defender-adapter.js +227 -0
- package/dist/adapters/defender-adapter.js.map +1 -0
- package/dist/adapters/index.d.ts +22 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +23 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/syslog-adapter.d.ts +207 -0
- package/dist/adapters/syslog-adapter.d.ts.map +1 -0
- package/dist/adapters/syslog-adapter.js +432 -0
- package/dist/adapters/syslog-adapter.js.map +1 -0
- package/dist/adapters/types.d.ts +135 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +13 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/adapters/wazuh-adapter.d.ts +120 -0
- package/dist/adapters/wazuh-adapter.d.ts.map +1 -0
- package/dist/adapters/wazuh-adapter.js +266 -0
- package/dist/adapters/wazuh-adapter.js.map +1 -0
- package/dist/ai/claude-provider.d.ts +66 -0
- package/dist/ai/claude-provider.d.ts.map +1 -0
- package/dist/ai/claude-provider.js +166 -0
- package/dist/ai/claude-provider.js.map +1 -0
- package/dist/ai/funnel-router.d.ts +75 -0
- package/dist/ai/funnel-router.d.ts.map +1 -0
- package/dist/ai/funnel-router.js +173 -0
- package/dist/ai/funnel-router.js.map +1 -0
- package/dist/ai/index.d.ts +77 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +95 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/ollama-provider.d.ts +73 -0
- package/dist/ai/ollama-provider.d.ts.map +1 -0
- package/dist/ai/ollama-provider.js +200 -0
- package/dist/ai/ollama-provider.js.map +1 -0
- package/dist/ai/openai-provider.d.ts +70 -0
- package/dist/ai/openai-provider.d.ts.map +1 -0
- package/dist/ai/openai-provider.js +175 -0
- package/dist/ai/openai-provider.js.map +1 -0
- package/dist/ai/prompts/event-classifier.d.ts +25 -0
- package/dist/ai/prompts/event-classifier.d.ts.map +1 -0
- package/dist/ai/prompts/event-classifier.js +94 -0
- package/dist/ai/prompts/event-classifier.js.map +1 -0
- package/dist/ai/prompts/index.d.ts +13 -0
- package/dist/ai/prompts/index.d.ts.map +1 -0
- package/dist/ai/prompts/index.js +13 -0
- package/dist/ai/prompts/index.js.map +1 -0
- package/dist/ai/prompts/report-generator.d.ts +25 -0
- package/dist/ai/prompts/report-generator.d.ts.map +1 -0
- package/dist/ai/prompts/report-generator.js +131 -0
- package/dist/ai/prompts/report-generator.js.map +1 -0
- package/dist/ai/prompts/threat-analyzer.d.ts +26 -0
- package/dist/ai/prompts/threat-analyzer.d.ts.map +1 -0
- package/dist/ai/prompts/threat-analyzer.js +75 -0
- package/dist/ai/prompts/threat-analyzer.js.map +1 -0
- package/dist/ai/provider-base.d.ts +100 -0
- package/dist/ai/provider-base.d.ts.map +1 -0
- package/dist/ai/provider-base.js +166 -0
- package/dist/ai/provider-base.js.map +1 -0
- package/dist/ai/response-parser.d.ts +36 -0
- package/dist/ai/response-parser.d.ts.map +1 -0
- package/dist/ai/response-parser.js +195 -0
- package/dist/ai/response-parser.js.map +1 -0
- package/dist/ai/token-tracker.d.ts +72 -0
- package/dist/ai/token-tracker.d.ts.map +1 -0
- package/dist/ai/token-tracker.js +145 -0
- package/dist/ai/token-tracker.js.map +1 -0
- package/dist/ai/types.d.ts +138 -0
- package/dist/ai/types.d.ts.map +1 -0
- package/dist/ai/types.js +12 -0
- package/dist/ai/types.js.map +1 -0
- package/dist/cli/index.d.ts +146 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +515 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/prompts.d.ts +58 -0
- package/dist/cli/prompts.d.ts.map +1 -0
- package/dist/cli/prompts.js +327 -0
- package/dist/cli/prompts.js.map +1 -0
- package/dist/cli/wizard.d.ts +58 -0
- package/dist/cli/wizard.d.ts.map +1 -0
- package/dist/cli/wizard.js +200 -0
- package/dist/cli/wizard.js.map +1 -0
- package/dist/discovery/firewall-checker.d.ts +28 -0
- package/dist/discovery/firewall-checker.d.ts.map +1 -0
- package/dist/discovery/firewall-checker.js +379 -0
- package/dist/discovery/firewall-checker.js.map +1 -0
- package/dist/discovery/index.d.ts +23 -0
- package/dist/discovery/index.d.ts.map +1 -0
- package/dist/discovery/index.js +29 -0
- package/dist/discovery/index.js.map +1 -0
- package/dist/discovery/network-scanner.d.ts +60 -0
- package/dist/discovery/network-scanner.d.ts.map +1 -0
- package/dist/discovery/network-scanner.js +640 -0
- package/dist/discovery/network-scanner.js.map +1 -0
- package/dist/discovery/os-detector.d.ts +24 -0
- package/dist/discovery/os-detector.d.ts.map +1 -0
- package/dist/discovery/os-detector.js +253 -0
- package/dist/discovery/os-detector.js.map +1 -0
- package/dist/discovery/osquery-provider.d.ts +127 -0
- package/dist/discovery/osquery-provider.d.ts.map +1 -0
- package/dist/discovery/osquery-provider.js +214 -0
- package/dist/discovery/osquery-provider.js.map +1 -0
- package/dist/discovery/risk-scorer.d.ts +66 -0
- package/dist/discovery/risk-scorer.d.ts.map +1 -0
- package/dist/discovery/risk-scorer.js +294 -0
- package/dist/discovery/risk-scorer.js.map +1 -0
- package/dist/discovery/security-tools.d.ts +31 -0
- package/dist/discovery/security-tools.d.ts.map +1 -0
- package/dist/discovery/security-tools.js +346 -0
- package/dist/discovery/security-tools.js.map +1 -0
- package/dist/discovery/service-detector.d.ts +28 -0
- package/dist/discovery/service-detector.d.ts.map +1 -0
- package/dist/discovery/service-detector.js +300 -0
- package/dist/discovery/service-detector.js.map +1 -0
- package/dist/discovery/types.d.ts +502 -0
- package/dist/discovery/types.d.ts.map +1 -0
- package/dist/discovery/types.js +12 -0
- package/dist/discovery/types.js.map +1 -0
- package/dist/discovery/user-auditor.d.ts +28 -0
- package/dist/discovery/user-auditor.d.ts.map +1 -0
- package/dist/discovery/user-auditor.js +385 -0
- package/dist/discovery/user-auditor.js.map +1 -0
- package/dist/i18n/config.d.ts +45 -0
- package/dist/i18n/config.d.ts.map +1 -0
- package/dist/i18n/config.js +135 -0
- package/dist/i18n/config.js.map +1 -0
- package/dist/i18n/index.d.ts +8 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +8 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/monitor/event-normalizer.d.ts +102 -0
- package/dist/monitor/event-normalizer.d.ts.map +1 -0
- package/dist/monitor/event-normalizer.js +195 -0
- package/dist/monitor/event-normalizer.js.map +1 -0
- package/dist/monitor/file-monitor.d.ts +90 -0
- package/dist/monitor/file-monitor.d.ts.map +1 -0
- package/dist/monitor/file-monitor.js +222 -0
- package/dist/monitor/file-monitor.js.map +1 -0
- package/dist/monitor/index.d.ts +147 -0
- package/dist/monitor/index.d.ts.map +1 -0
- package/dist/monitor/index.js +293 -0
- package/dist/monitor/index.js.map +1 -0
- package/dist/monitor/log-monitor.d.ts +102 -0
- package/dist/monitor/log-monitor.d.ts.map +1 -0
- package/dist/monitor/log-monitor.js +245 -0
- package/dist/monitor/log-monitor.js.map +1 -0
- package/dist/monitor/network-monitor.d.ts +103 -0
- package/dist/monitor/network-monitor.d.ts.map +1 -0
- package/dist/monitor/network-monitor.js +336 -0
- package/dist/monitor/network-monitor.js.map +1 -0
- package/dist/monitor/process-monitor.d.ts +108 -0
- package/dist/monitor/process-monitor.d.ts.map +1 -0
- package/dist/monitor/process-monitor.js +245 -0
- package/dist/monitor/process-monitor.js.map +1 -0
- package/dist/monitor/threat-intel-feeds.d.ts +141 -0
- package/dist/monitor/threat-intel-feeds.d.ts.map +1 -0
- package/dist/monitor/threat-intel-feeds.js +430 -0
- package/dist/monitor/threat-intel-feeds.js.map +1 -0
- package/dist/monitor/threat-intel.d.ts +83 -0
- package/dist/monitor/threat-intel.d.ts.map +1 -0
- package/dist/monitor/threat-intel.js +215 -0
- package/dist/monitor/threat-intel.js.map +1 -0
- package/dist/monitor/types.d.ts +65 -0
- package/dist/monitor/types.d.ts.map +1 -0
- package/dist/monitor/types.js +20 -0
- package/dist/monitor/types.js.map +1 -0
- package/dist/rules/index.d.ts +115 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +244 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/rule-loader.d.ts +54 -0
- package/dist/rules/rule-loader.d.ts.map +1 -0
- package/dist/rules/rule-loader.js +167 -0
- package/dist/rules/rule-loader.js.map +1 -0
- package/dist/rules/sigma-matcher.d.ts +40 -0
- package/dist/rules/sigma-matcher.d.ts.map +1 -0
- package/dist/rules/sigma-matcher.js +447 -0
- package/dist/rules/sigma-matcher.js.map +1 -0
- package/dist/rules/sigma-parser.d.ts +36 -0
- package/dist/rules/sigma-parser.d.ts.map +1 -0
- package/dist/rules/sigma-parser.js +180 -0
- package/dist/rules/sigma-parser.js.map +1 -0
- package/dist/rules/types.d.ts +112 -0
- package/dist/rules/types.d.ts.map +1 -0
- package/dist/rules/types.js +11 -0
- package/dist/rules/types.js.map +1 -0
- package/dist/rules/yara-scanner.d.ts +103 -0
- package/dist/rules/yara-scanner.d.ts.map +1 -0
- package/dist/rules/yara-scanner.js +421 -0
- package/dist/rules/yara-scanner.js.map +1 -0
- package/dist/scoring/achievements.d.ts +76 -0
- package/dist/scoring/achievements.d.ts.map +1 -0
- package/dist/scoring/achievements.js +211 -0
- package/dist/scoring/achievements.js.map +1 -0
- package/dist/scoring/index.d.ts +3 -0
- package/dist/scoring/index.d.ts.map +1 -0
- package/dist/scoring/index.js +3 -0
- package/dist/scoring/index.js.map +1 -0
- package/dist/scoring/security-score.d.ts +60 -0
- package/dist/scoring/security-score.d.ts.map +1 -0
- package/dist/scoring/security-score.js +211 -0
- package/dist/scoring/security-score.js.map +1 -0
- package/dist/types.d.ts +71 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/index.d.ts +10 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +38 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +71 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/validation.d.ts +35 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +56 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* YARA Scanner - File scanning using YARA rules
|
|
3
|
+
* YARA 掃描器 - 使用 YARA 規則掃描檔案
|
|
4
|
+
*
|
|
5
|
+
* Provides an abstraction over YARA scanning that:
|
|
6
|
+
* - Loads .yar rule files from a directory
|
|
7
|
+
* - Scans individual files or entire directories
|
|
8
|
+
* - Converts results to SecurityEvent format for unified pipeline
|
|
9
|
+
* - Gracefully degrades when YARA native bindings are not available
|
|
10
|
+
*
|
|
11
|
+
* @module @panguard-ai/core/rules/yara-scanner
|
|
12
|
+
*/
|
|
13
|
+
import { readdir, stat, readFile } from 'node:fs/promises';
|
|
14
|
+
import { join, extname, resolve } from 'node:path';
|
|
15
|
+
import { createHash } from 'node:crypto';
|
|
16
|
+
import { createLogger } from '../utils/logger.js';
|
|
17
|
+
const logger = createLogger('yara-scanner');
|
|
18
|
+
/**
|
|
19
|
+
* YARA-based file scanner
|
|
20
|
+
* 基於 YARA 的檔案掃描器
|
|
21
|
+
*
|
|
22
|
+
* Supports two modes:
|
|
23
|
+
* 1. Native YARA via @automattic/yara (requires native bindings)
|
|
24
|
+
* 2. Pattern-based fallback using regex matching on file content
|
|
25
|
+
*/
|
|
26
|
+
export class YaraScanner {
|
|
27
|
+
ruleFiles = [];
|
|
28
|
+
compiledPatterns = [];
|
|
29
|
+
yaraAvailable = false;
|
|
30
|
+
/** Load YARA rules from a directory (non-recursive) / 從目錄載入 YARA 規則(非遞迴) */
|
|
31
|
+
async loadRules(rulesDir) {
|
|
32
|
+
const resolvedDir = resolve(rulesDir);
|
|
33
|
+
this.ruleFiles = [];
|
|
34
|
+
this.compiledPatterns = [];
|
|
35
|
+
try {
|
|
36
|
+
const files = await readdir(resolvedDir);
|
|
37
|
+
const yarFiles = files.filter((f) => extname(f) === '.yar' || extname(f) === '.yara');
|
|
38
|
+
for (const file of yarFiles) {
|
|
39
|
+
const filePath = join(resolvedDir, file);
|
|
40
|
+
const content = await readFile(filePath, 'utf-8');
|
|
41
|
+
this.ruleFiles.push({ path: filePath, name: file, content });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
logger.warn(`Failed to load YARA rules from ${rulesDir}: ${err instanceof Error ? err.message : String(err)}`);
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
|
48
|
+
// Try to use native YARA bindings
|
|
49
|
+
this.yaraAvailable = await this.checkNativeYara();
|
|
50
|
+
// Always compile fallback patterns
|
|
51
|
+
this.compiledPatterns = this.compilePatterns();
|
|
52
|
+
logger.info(`Loaded ${this.ruleFiles.length} YARA rule files (native YARA: ${this.yaraAvailable ? 'available' : 'fallback mode'})`);
|
|
53
|
+
return this.ruleFiles.length;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Recursively load YARA rules from a directory tree
|
|
57
|
+
* 從目錄樹遞迴載入 YARA 規則
|
|
58
|
+
*
|
|
59
|
+
* @param rulesDir - Root directory to scan / 要掃描的根目錄
|
|
60
|
+
* @param source - Source tag for loaded rules / 載入規則的來源標記
|
|
61
|
+
* @returns Number of rule files loaded / 載入的規則檔數量
|
|
62
|
+
*/
|
|
63
|
+
async loadRulesRecursive(rulesDir, source) {
|
|
64
|
+
const resolvedDir = resolve(rulesDir);
|
|
65
|
+
const files = [];
|
|
66
|
+
const walk = async (dir) => {
|
|
67
|
+
let entries;
|
|
68
|
+
try {
|
|
69
|
+
entries = await readdir(dir, { withFileTypes: true, encoding: 'utf-8' });
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
for (const entry of entries) {
|
|
75
|
+
const fullPath = join(dir, entry.name);
|
|
76
|
+
if (entry.isDirectory()) {
|
|
77
|
+
await walk(fullPath);
|
|
78
|
+
}
|
|
79
|
+
else if (entry.isFile()) {
|
|
80
|
+
const ext = extname(entry.name).toLowerCase();
|
|
81
|
+
if (ext !== '.yar' && ext !== '.yara')
|
|
82
|
+
continue;
|
|
83
|
+
try {
|
|
84
|
+
const content = await readFile(fullPath, 'utf-8');
|
|
85
|
+
files.push({ path: fullPath, name: entry.name, content, source });
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
// Skip unreadable files
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
try {
|
|
94
|
+
await walk(resolvedDir);
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
logger.warn(`Failed to recursively load YARA rules from ${rulesDir}: ${err instanceof Error ? err.message : String(err)}`);
|
|
98
|
+
}
|
|
99
|
+
logger.info(`Recursively loaded ${files.length} YARA rule files from ${rulesDir} (source: ${source ?? 'unset'})`);
|
|
100
|
+
return files.length;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Load rules from both custom and community directories
|
|
104
|
+
* 從自訂和社群目錄載入規則
|
|
105
|
+
*
|
|
106
|
+
* @param customDir - Custom rules directory / 自訂規則目錄
|
|
107
|
+
* @param communityDir - Optional community rules directory / 可選的社群規則目錄
|
|
108
|
+
* @returns Total number of rule files loaded / 載入的規則檔總數
|
|
109
|
+
*/
|
|
110
|
+
async loadAllRules(customDir, communityDir) {
|
|
111
|
+
this.ruleFiles = [];
|
|
112
|
+
this.compiledPatterns = [];
|
|
113
|
+
// Load custom rules recursively / 遞迴載入自訂規則
|
|
114
|
+
await this.loadFromDirRecursive(customDir, 'custom');
|
|
115
|
+
// Load community rules if directory exists / 如果目錄存在則載入社群規則
|
|
116
|
+
if (communityDir !== undefined) {
|
|
117
|
+
await this.loadFromDirRecursive(communityDir, 'community');
|
|
118
|
+
}
|
|
119
|
+
// Initialize scanning engine / 初始化掃描引擎
|
|
120
|
+
this.yaraAvailable = await this.checkNativeYara();
|
|
121
|
+
this.compiledPatterns = this.compilePatterns();
|
|
122
|
+
logger.info(`Loaded ${this.ruleFiles.length} total YARA rule files (native YARA: ${this.yaraAvailable ? 'available' : 'fallback mode'})`);
|
|
123
|
+
return this.ruleFiles.length;
|
|
124
|
+
}
|
|
125
|
+
/** Recursively collect .yar/.yara files and append to this.ruleFiles */
|
|
126
|
+
async loadFromDirRecursive(dir, source) {
|
|
127
|
+
const resolvedDir = resolve(dir);
|
|
128
|
+
const walk = async (currentDir) => {
|
|
129
|
+
let entries;
|
|
130
|
+
try {
|
|
131
|
+
entries = await readdir(currentDir, { withFileTypes: true, encoding: 'utf-8' });
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
for (const entry of entries) {
|
|
137
|
+
const fullPath = join(currentDir, entry.name);
|
|
138
|
+
if (entry.isDirectory()) {
|
|
139
|
+
await walk(fullPath);
|
|
140
|
+
}
|
|
141
|
+
else if (entry.isFile()) {
|
|
142
|
+
const ext = extname(entry.name).toLowerCase();
|
|
143
|
+
if (ext !== '.yar' && ext !== '.yara')
|
|
144
|
+
continue;
|
|
145
|
+
try {
|
|
146
|
+
const content = await readFile(fullPath, 'utf-8');
|
|
147
|
+
this.ruleFiles.push({ path: fullPath, name: entry.name, content, source });
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// Skip unreadable files
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
try {
|
|
156
|
+
await walk(resolvedDir);
|
|
157
|
+
}
|
|
158
|
+
catch (err) {
|
|
159
|
+
logger.warn(`Failed to load YARA rules from ${dir}: ${err instanceof Error ? err.message : String(err)}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/** Get number of loaded rule files / 取得已載入的規則檔數量 */
|
|
163
|
+
getRuleCount() {
|
|
164
|
+
return this.ruleFiles.length;
|
|
165
|
+
}
|
|
166
|
+
/** Check if native YARA is available / 檢查原生 YARA 是否可用 */
|
|
167
|
+
isNativeAvailable() {
|
|
168
|
+
return this.yaraAvailable;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Scan a single file / 掃描單一檔案
|
|
172
|
+
*/
|
|
173
|
+
async scanFile(filePath) {
|
|
174
|
+
const start = Date.now();
|
|
175
|
+
const resolvedPath = resolve(filePath);
|
|
176
|
+
const fileBuffer = await readFile(resolvedPath);
|
|
177
|
+
const fileStats = await stat(resolvedPath);
|
|
178
|
+
const sha256 = createHash('sha256').update(fileBuffer).digest('hex');
|
|
179
|
+
let matches;
|
|
180
|
+
if (this.yaraAvailable) {
|
|
181
|
+
matches = await this.scanWithNativeYara(resolvedPath);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
matches = this.scanWithPatterns(fileBuffer.toString('utf-8'), resolvedPath);
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
filePath: resolvedPath,
|
|
188
|
+
fileSize: fileStats.size,
|
|
189
|
+
sha256,
|
|
190
|
+
matches,
|
|
191
|
+
scannedAt: new Date().toISOString(),
|
|
192
|
+
durationMs: Date.now() - start,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Scan a directory recursively / 遞迴掃描目錄
|
|
197
|
+
*/
|
|
198
|
+
async scanDirectory(dirPath, options = {}) {
|
|
199
|
+
const { maxDepth = 5, extensions } = options;
|
|
200
|
+
const results = [];
|
|
201
|
+
const resolvedDir = resolve(dirPath);
|
|
202
|
+
await this.walkDir(resolvedDir, 0, maxDepth, extensions, results);
|
|
203
|
+
return results;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Convert YARA scan result to SecurityEvent / 轉換 YARA 掃描結果為 SecurityEvent
|
|
207
|
+
*/
|
|
208
|
+
toSecurityEvent(result) {
|
|
209
|
+
if (result.matches.length === 0)
|
|
210
|
+
return null;
|
|
211
|
+
const topMatch = result.matches[0];
|
|
212
|
+
const severity = this.inferSeverity(topMatch);
|
|
213
|
+
const mitreTechnique = topMatch.meta['mitre'] ?? topMatch.meta['mitre_attack'] ?? undefined;
|
|
214
|
+
// Determine source from the rule file that produced the top match / 從產生最高比對的規則檔判斷來源
|
|
215
|
+
const matchedRuleFile = this.ruleFiles.find((rf) => rf.name === topMatch.namespace);
|
|
216
|
+
const ruleSource = matchedRuleFile?.source;
|
|
217
|
+
return {
|
|
218
|
+
id: `yara-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
219
|
+
timestamp: new Date(result.scannedAt),
|
|
220
|
+
source: 'file',
|
|
221
|
+
severity,
|
|
222
|
+
category: 'malware_detection',
|
|
223
|
+
description: `YARA match: ${result.matches.map((m) => m.rule).join(', ')} in ${result.filePath}`,
|
|
224
|
+
host: '',
|
|
225
|
+
raw: {
|
|
226
|
+
filePath: result.filePath,
|
|
227
|
+
sha256: result.sha256,
|
|
228
|
+
fileSize: result.fileSize,
|
|
229
|
+
yaraRules: result.matches.map((m) => m.rule),
|
|
230
|
+
tags: result.matches.flatMap((m) => m.tags),
|
|
231
|
+
mitreTechnique,
|
|
232
|
+
ruleSource,
|
|
233
|
+
},
|
|
234
|
+
metadata: {},
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
// -- Private methods --
|
|
238
|
+
async checkNativeYara() {
|
|
239
|
+
try {
|
|
240
|
+
await import('@automattic/yara');
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
async scanWithNativeYara(filePath) {
|
|
248
|
+
try {
|
|
249
|
+
const yara = await import('@automattic/yara');
|
|
250
|
+
const results = [];
|
|
251
|
+
for (const ruleFile of this.ruleFiles) {
|
|
252
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
253
|
+
const yaraModule = yara;
|
|
254
|
+
const scanner = new yaraModule.default.Scanner();
|
|
255
|
+
scanner.addRules(ruleFile.content);
|
|
256
|
+
const scanResult = scanner.scanFile(filePath);
|
|
257
|
+
for (const match of scanResult.rules ?? []) {
|
|
258
|
+
results.push({
|
|
259
|
+
rule: match.id ?? match.rule ?? 'unknown',
|
|
260
|
+
namespace: ruleFile.name,
|
|
261
|
+
tags: match.tags ?? [],
|
|
262
|
+
meta: match.meta ?? {},
|
|
263
|
+
strings: (match.strings ?? []).map((s) => ({
|
|
264
|
+
identifier: s.identifier,
|
|
265
|
+
offset: s.offset,
|
|
266
|
+
data: s.data.toString('utf-8').slice(0, 100),
|
|
267
|
+
})),
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return results;
|
|
272
|
+
}
|
|
273
|
+
catch (err) {
|
|
274
|
+
logger.warn(`Native YARA scan failed, falling back to patterns: ${err instanceof Error ? err.message : String(err)}`);
|
|
275
|
+
const content = await readFile(filePath, 'utf-8').catch(() => '');
|
|
276
|
+
return this.scanWithPatterns(content, filePath);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Fallback pattern-based scanning / 退路:基於模式的掃描
|
|
281
|
+
* Extracts string patterns from YARA rules and matches against file content
|
|
282
|
+
*/
|
|
283
|
+
scanWithPatterns(content, _filePath) {
|
|
284
|
+
const matches = [];
|
|
285
|
+
const lowerContent = content.toLowerCase();
|
|
286
|
+
for (const pattern of this.compiledPatterns) {
|
|
287
|
+
const matchedStrings = [];
|
|
288
|
+
for (const str of pattern.strings) {
|
|
289
|
+
const idx = lowerContent.indexOf(str.value.toLowerCase());
|
|
290
|
+
if (idx !== -1) {
|
|
291
|
+
matchedStrings.push({
|
|
292
|
+
identifier: str.identifier,
|
|
293
|
+
offset: idx,
|
|
294
|
+
data: content.slice(idx, idx + Math.min(str.value.length, 50)),
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
// Check if enough strings matched based on condition
|
|
299
|
+
const requiredMatches = pattern.conditionAny ? 1 : pattern.strings.length;
|
|
300
|
+
if (matchedStrings.length >= requiredMatches && matchedStrings.length > 0) {
|
|
301
|
+
matches.push({
|
|
302
|
+
rule: pattern.ruleName,
|
|
303
|
+
namespace: pattern.sourceFile,
|
|
304
|
+
tags: pattern.tags,
|
|
305
|
+
meta: pattern.meta,
|
|
306
|
+
strings: matchedStrings,
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return matches;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Parse YARA rule files into compiled patterns for fallback matching
|
|
314
|
+
* 解析 YARA 規則檔為編譯的模式(退路比對用)
|
|
315
|
+
*/
|
|
316
|
+
compilePatterns() {
|
|
317
|
+
const patterns = [];
|
|
318
|
+
for (const ruleFile of this.ruleFiles) {
|
|
319
|
+
const ruleBlocks = ruleFile.content.split(/\brule\s+/);
|
|
320
|
+
for (const block of ruleBlocks) {
|
|
321
|
+
if (!block.trim())
|
|
322
|
+
continue;
|
|
323
|
+
const nameMatch = block.match(/^(\w+)\s*(?::\s*([\w\s]+))?\s*\{/);
|
|
324
|
+
if (!nameMatch)
|
|
325
|
+
continue;
|
|
326
|
+
const ruleName = nameMatch[1] ?? 'unknown';
|
|
327
|
+
const tags = (nameMatch[2] ?? '').trim().split(/\s+/).filter(Boolean);
|
|
328
|
+
// Extract meta
|
|
329
|
+
const meta = {};
|
|
330
|
+
const metaBlock = block.match(/meta\s*:\s*([\s\S]*?)(?=strings\s*:|condition\s*:|$)/);
|
|
331
|
+
if (metaBlock?.[1]) {
|
|
332
|
+
const metaLines = metaBlock[1].matchAll(/(\w+)\s*=\s*"([^"]*)"/g);
|
|
333
|
+
for (const m of metaLines) {
|
|
334
|
+
if (m[1] && m[2] !== undefined) {
|
|
335
|
+
meta[m[1]] = m[2];
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
// Extract strings
|
|
340
|
+
const strings = [];
|
|
341
|
+
const stringsBlock = block.match(/strings\s*:\s*([\s\S]*?)(?=condition\s*:|$)/);
|
|
342
|
+
if (stringsBlock?.[1]) {
|
|
343
|
+
const stringDefs = stringsBlock[1].matchAll(/(\$\w+)\s*=\s*"([^"]*)"/g);
|
|
344
|
+
for (const s of stringDefs) {
|
|
345
|
+
if (s[1] && s[2] !== undefined) {
|
|
346
|
+
strings.push({ identifier: s[1], value: s[2] });
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
// Check condition for "any of them" vs "all of them"
|
|
351
|
+
const conditionBlock = block.match(/condition\s*:\s*([\s\S]*?)(?=\}|$)/);
|
|
352
|
+
const condition = conditionBlock?.[1]?.trim() ?? '';
|
|
353
|
+
const conditionAny = condition.includes('any of') || condition.includes('1 of') || condition.includes(' or ');
|
|
354
|
+
if (strings.length > 0) {
|
|
355
|
+
patterns.push({
|
|
356
|
+
ruleName,
|
|
357
|
+
sourceFile: ruleFile.name,
|
|
358
|
+
tags,
|
|
359
|
+
meta,
|
|
360
|
+
strings,
|
|
361
|
+
conditionAny,
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return patterns;
|
|
367
|
+
}
|
|
368
|
+
inferSeverity(match) {
|
|
369
|
+
const severity = match.meta['severity']?.toLowerCase();
|
|
370
|
+
if (severity === 'critical')
|
|
371
|
+
return 'critical';
|
|
372
|
+
if (severity === 'high')
|
|
373
|
+
return 'high';
|
|
374
|
+
if (severity === 'medium')
|
|
375
|
+
return 'medium';
|
|
376
|
+
if (severity === 'low')
|
|
377
|
+
return 'low';
|
|
378
|
+
// Infer from tags
|
|
379
|
+
const tagStr = match.tags.join(' ').toLowerCase();
|
|
380
|
+
if (tagStr.includes('apt') || tagStr.includes('ransomware'))
|
|
381
|
+
return 'critical';
|
|
382
|
+
if (tagStr.includes('webshell') || tagStr.includes('malware'))
|
|
383
|
+
return 'high';
|
|
384
|
+
if (tagStr.includes('suspicious'))
|
|
385
|
+
return 'medium';
|
|
386
|
+
return 'medium';
|
|
387
|
+
}
|
|
388
|
+
async walkDir(dir, depth, maxDepth, extensions, results) {
|
|
389
|
+
if (depth > maxDepth)
|
|
390
|
+
return;
|
|
391
|
+
try {
|
|
392
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
393
|
+
for (const entry of entries) {
|
|
394
|
+
const fullPath = join(dir, entry.name);
|
|
395
|
+
if (entry.isDirectory()) {
|
|
396
|
+
// Skip common non-target directories
|
|
397
|
+
if (['node_modules', '.git', '.cache', 'dist', '__pycache__'].includes(entry.name))
|
|
398
|
+
continue;
|
|
399
|
+
await this.walkDir(fullPath, depth + 1, maxDepth, extensions, results);
|
|
400
|
+
}
|
|
401
|
+
else if (entry.isFile()) {
|
|
402
|
+
if (extensions && !extensions.includes(extname(entry.name)))
|
|
403
|
+
continue;
|
|
404
|
+
try {
|
|
405
|
+
const result = await this.scanFile(fullPath);
|
|
406
|
+
if (result.matches.length > 0) {
|
|
407
|
+
results.push(result);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
catch {
|
|
411
|
+
// Skip unreadable files
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
catch {
|
|
417
|
+
// Skip unreadable directories
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
//# sourceMappingURL=yara-scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yara-scanner.js","sourceRoot":"","sources":["../../src/rules/yara-scanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Achievement System - Security gamification with badges and milestones
|
|
3
|
+
* 成就系統 - 安全遊戲化(徽章與里程碑)
|
|
4
|
+
*
|
|
5
|
+
* Tracks user progress and awards achievements for security best practices.
|
|
6
|
+
* Designed to encourage continuous security improvement.
|
|
7
|
+
*
|
|
8
|
+
* @module @panguard-ai/core/scoring/achievements
|
|
9
|
+
*/
|
|
10
|
+
/** Achievement definition / 成就定義 */
|
|
11
|
+
export interface Achievement {
|
|
12
|
+
id: string;
|
|
13
|
+
name: string;
|
|
14
|
+
nameZhTW: string;
|
|
15
|
+
description: string;
|
|
16
|
+
descriptionZhTW: string;
|
|
17
|
+
category: 'scan' | 'guard' | 'response' | 'compliance' | 'streak';
|
|
18
|
+
icon: string;
|
|
19
|
+
condition: (stats: AchievementStats) => boolean;
|
|
20
|
+
}
|
|
21
|
+
/** User stats for achievement checking / 成就檢查的用戶統計 */
|
|
22
|
+
export interface AchievementStats {
|
|
23
|
+
totalScans: number;
|
|
24
|
+
consecutiveSafeDays: number;
|
|
25
|
+
threatsBlocked: number;
|
|
26
|
+
vulnsFixedWithin24h: number;
|
|
27
|
+
totalVulnsFixed: number;
|
|
28
|
+
complianceScore: number;
|
|
29
|
+
securityScore: number;
|
|
30
|
+
allRecommendationsEnabled: boolean;
|
|
31
|
+
firstScanCompleted: boolean;
|
|
32
|
+
guardRunningDays: number;
|
|
33
|
+
rulesActive: number;
|
|
34
|
+
chatChannelsConfigured: number;
|
|
35
|
+
}
|
|
36
|
+
/** Earned achievement / 已獲得的成就 */
|
|
37
|
+
export interface EarnedAchievement {
|
|
38
|
+
achievement: Achievement;
|
|
39
|
+
earnedAt: string;
|
|
40
|
+
notified: boolean;
|
|
41
|
+
}
|
|
42
|
+
/** All defined achievements / 所有已定義的成就 */
|
|
43
|
+
export declare const ACHIEVEMENTS: Achievement[];
|
|
44
|
+
/**
|
|
45
|
+
* Achievement Tracker - manages earned achievements
|
|
46
|
+
* 成就追蹤器 - 管理已獲得的成就
|
|
47
|
+
*/
|
|
48
|
+
export declare class AchievementTracker {
|
|
49
|
+
private earned;
|
|
50
|
+
/**
|
|
51
|
+
* Check stats against all achievements, return newly earned ones
|
|
52
|
+
* 檢查統計數據,回傳新獲得的成就
|
|
53
|
+
*/
|
|
54
|
+
check(stats: AchievementStats): EarnedAchievement[];
|
|
55
|
+
/** Get all earned achievements / 取得所有已獲得的成就 */
|
|
56
|
+
getEarned(): EarnedAchievement[];
|
|
57
|
+
/** Get count of earned achievements / 取得已獲得成就數量 */
|
|
58
|
+
getEarnedCount(): number;
|
|
59
|
+
/** Get total available achievements / 取得所有可用成就數量 */
|
|
60
|
+
getTotalCount(): number;
|
|
61
|
+
/** Mark an achievement as notified / 標記成就已通知 */
|
|
62
|
+
markNotified(id: string): void;
|
|
63
|
+
/** Get un-notified achievements / 取得未通知的成就 */
|
|
64
|
+
getUnnotified(): EarnedAchievement[];
|
|
65
|
+
/** Load earned achievements from serialized data / 從序列化資料載入 */
|
|
66
|
+
load(data: Array<{
|
|
67
|
+
id: string;
|
|
68
|
+
earnedAt: string;
|
|
69
|
+
}>): void;
|
|
70
|
+
/** Serialize earned achievements / 序列化已獲得的成就 */
|
|
71
|
+
serialize(): Array<{
|
|
72
|
+
id: string;
|
|
73
|
+
earnedAt: string;
|
|
74
|
+
}>;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=achievements.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"achievements.d.ts","sourceRoot":"","sources":["../../src/scoring/achievements.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,oCAAoC;AACpC,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,UAAU,GAAG,YAAY,GAAG,QAAQ,CAAC;IAClE,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,OAAO,CAAC;CACjD;AAED,sDAAsD;AACtD,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,yBAAyB,EAAE,OAAO,CAAC;IACnC,kBAAkB,EAAE,OAAO,CAAC;IAC5B,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,sBAAsB,EAAE,MAAM,CAAC;CAChC;AAED,kCAAkC;AAClC,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,WAAW,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,0CAA0C;AAC1C,eAAO,MAAM,YAAY,EAAE,WAAW,EAkIrC,CAAC;AAEF;;;GAGG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAA6C;IAE3D;;;OAGG;IACH,KAAK,CAAC,KAAK,EAAE,gBAAgB,GAAG,iBAAiB,EAAE;IAqBnD,+CAA+C;IAC/C,SAAS,IAAI,iBAAiB,EAAE;IAIhC,mDAAmD;IACnD,cAAc,IAAI,MAAM;IAIxB,oDAAoD;IACpD,aAAa,IAAI,MAAM;IAIvB,gDAAgD;IAChD,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAK9B,8CAA8C;IAC9C,aAAa,IAAI,iBAAiB,EAAE;IAIpC,+DAA+D;IAC/D,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,IAAI;IAazD,gDAAgD;IAChD,SAAS,IAAI,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CAMrD"}
|