muaddib-scanner 1.0.21 → 1.0.22
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.fr.md +6 -0
- package/README.md +6 -0
- package/bin/muaddib.js +125 -34
- package/data/iocs.json +1 -1
- package/package.json +2 -1
package/README.fr.md
CHANGED
package/README.md
CHANGED
package/bin/muaddib.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
3
2
|
const { run } = require('../src/index.js');
|
|
4
3
|
const { updateIOCs } = require('../src/ioc/updater.js');
|
|
5
4
|
const { watch } = require('../src/watch.js');
|
|
@@ -10,6 +9,7 @@ const args = process.argv.slice(2);
|
|
|
10
9
|
const command = args[0];
|
|
11
10
|
const options = args.slice(1);
|
|
12
11
|
|
|
12
|
+
// Parse options
|
|
13
13
|
let target = '.';
|
|
14
14
|
let jsonOutput = false;
|
|
15
15
|
let htmlOutput = null;
|
|
@@ -43,35 +43,109 @@ for (let i = 0; i < options.length; i++) {
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
Usage:
|
|
51
|
-
muaddib scan [path] [options] Scan a project
|
|
52
|
-
muaddib watch [path] Watch a project in real-time
|
|
53
|
-
muaddib daemon [options] Start background daemon
|
|
54
|
-
muaddib update Update IOCs
|
|
55
|
-
muaddib scrape Scrape new IOCs from advisories
|
|
56
|
-
muaddib help Show help
|
|
46
|
+
// Menu interactif si pas de commande
|
|
47
|
+
async function interactiveMenu() {
|
|
48
|
+
const { select, input, confirm } = await import('@inquirer/prompts');
|
|
57
49
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
--fail-on [level] Severity level for exit code (critical|high|medium|low)
|
|
64
|
-
Default: high (fail on HIGH and CRITICAL)
|
|
65
|
-
--webhook [url] Send Discord/Slack alert
|
|
66
|
-
--paranoid Enable ultra-strict rules (more false positives)
|
|
50
|
+
console.log(`
|
|
51
|
+
╔══════════════════════════════════════════╗
|
|
52
|
+
║ MUAD'DIB - npm Supply Chain Hunter ║
|
|
53
|
+
║ "The worms must die." ║
|
|
54
|
+
╚══════════════════════════════════════════╝
|
|
67
55
|
`);
|
|
68
|
-
|
|
56
|
+
|
|
57
|
+
const action = await select({
|
|
58
|
+
message: 'Que veux-tu faire ?',
|
|
59
|
+
choices: [
|
|
60
|
+
{ name: 'Scanner un projet', value: 'scan' },
|
|
61
|
+
{ name: 'Scanner avec mode paranoid', value: 'scan-paranoid' },
|
|
62
|
+
{ name: 'Surveiller un projet (watch)', value: 'watch' },
|
|
63
|
+
{ name: 'Lancer le daemon', value: 'daemon' },
|
|
64
|
+
{ name: 'Mettre a jour les IOCs', value: 'update' },
|
|
65
|
+
{ name: 'Scraper nouveaux IOCs', value: 'scrape' },
|
|
66
|
+
{ name: 'Quitter', value: 'quit' }
|
|
67
|
+
]
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
if (action === 'quit') {
|
|
71
|
+
console.log('Bye!');
|
|
72
|
+
process.exit(0);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (action === 'scan' || action === 'scan-paranoid') {
|
|
76
|
+
const path = await input({
|
|
77
|
+
message: 'Chemin du projet :',
|
|
78
|
+
default: '.'
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const outputFormat = await select({
|
|
82
|
+
message: 'Format de sortie :',
|
|
83
|
+
choices: [
|
|
84
|
+
{ name: 'Console (defaut)', value: 'console' },
|
|
85
|
+
{ name: 'JSON', value: 'json' },
|
|
86
|
+
{ name: 'HTML', value: 'html' },
|
|
87
|
+
{ name: 'SARIF (GitHub Security)', value: 'sarif' }
|
|
88
|
+
]
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const opts = {
|
|
92
|
+
json: outputFormat === 'json',
|
|
93
|
+
html: outputFormat === 'html' ? 'muaddib-report.html' : null,
|
|
94
|
+
sarif: outputFormat === 'sarif' ? 'muaddib-results.sarif' : null,
|
|
95
|
+
explain: true,
|
|
96
|
+
failLevel: 'high',
|
|
97
|
+
paranoid: action === 'scan-paranoid'
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const exitCode = await run(path, opts);
|
|
101
|
+
process.exit(exitCode);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (action === 'watch') {
|
|
105
|
+
const path = await input({
|
|
106
|
+
message: 'Chemin du projet :',
|
|
107
|
+
default: '.'
|
|
108
|
+
});
|
|
109
|
+
watch(path);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (action === 'daemon') {
|
|
113
|
+
const useWebhook = await confirm({
|
|
114
|
+
message: 'Configurer un webhook Discord/Slack ?',
|
|
115
|
+
default: false
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
let webhook = null;
|
|
119
|
+
if (useWebhook) {
|
|
120
|
+
webhook = await input({
|
|
121
|
+
message: 'URL du webhook :'
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
startDaemon({ webhook });
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (action === 'update') {
|
|
128
|
+
await updateIOCs();
|
|
129
|
+
process.exit(0);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (action === 'scrape') {
|
|
133
|
+
const result = await runScraper();
|
|
134
|
+
console.log(`[OK] ${result.added} nouveaux IOCs (total: ${result.total})`);
|
|
135
|
+
process.exit(0);
|
|
136
|
+
}
|
|
69
137
|
}
|
|
70
138
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
139
|
+
// Main
|
|
140
|
+
if (!command) {
|
|
141
|
+
interactiveMenu().catch(err => {
|
|
142
|
+
console.error('[ERROR]', err.message);
|
|
143
|
+
process.exit(1);
|
|
144
|
+
});
|
|
145
|
+
} else if (command === 'scan') {
|
|
146
|
+
run(target, {
|
|
147
|
+
json: jsonOutput,
|
|
148
|
+
html: htmlOutput,
|
|
75
149
|
sarif: sarifOutput,
|
|
76
150
|
explain: explainMode,
|
|
77
151
|
failLevel: failLevel,
|
|
@@ -91,7 +165,7 @@ if (command === 'scan') {
|
|
|
91
165
|
});
|
|
92
166
|
} else if (command === 'scrape') {
|
|
93
167
|
runScraper().then(result => {
|
|
94
|
-
console.log(`[OK] ${result.added}
|
|
168
|
+
console.log(`[OK] ${result.added} nouveaux IOCs (total: ${result.total})`);
|
|
95
169
|
process.exit(0);
|
|
96
170
|
}).catch(err => {
|
|
97
171
|
console.error('[ERROR]', err.message);
|
|
@@ -100,12 +174,29 @@ if (command === 'scan') {
|
|
|
100
174
|
} else if (command === 'daemon') {
|
|
101
175
|
startDaemon({ webhook: webhookUrl });
|
|
102
176
|
} else if (command === 'help') {
|
|
103
|
-
console.log(
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
177
|
+
console.log(`
|
|
178
|
+
MUAD'DIB - npm Supply Chain Threat Hunter
|
|
179
|
+
|
|
180
|
+
Usage:
|
|
181
|
+
muaddib Mode interactif
|
|
182
|
+
muaddib scan [path] [options] Scanner un projet
|
|
183
|
+
muaddib watch [path] Surveiller en temps reel
|
|
184
|
+
muaddib daemon [options] Lancer le daemon
|
|
185
|
+
muaddib update Mettre a jour les IOCs
|
|
186
|
+
muaddib scrape Scraper nouveaux IOCs
|
|
187
|
+
|
|
188
|
+
Options:
|
|
189
|
+
--json Sortie JSON
|
|
190
|
+
--html [file] Rapport HTML
|
|
191
|
+
--sarif [file] Rapport SARIF (GitHub Security)
|
|
192
|
+
--explain Explications detaillees
|
|
193
|
+
--fail-on [level] Niveau d'echec (critical|high|medium|low)
|
|
194
|
+
--webhook [url] Webhook Discord/Slack
|
|
195
|
+
--paranoid Mode ultra-strict
|
|
196
|
+
`);
|
|
197
|
+
process.exit(0);
|
|
108
198
|
} else {
|
|
109
|
-
console.log(`
|
|
199
|
+
console.log(`Commande inconnue: ${command}`);
|
|
200
|
+
console.log('Tape "muaddib help" pour voir les commandes.');
|
|
110
201
|
process.exit(1);
|
|
111
202
|
}
|
package/data/iocs.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "muaddib-scanner",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.22",
|
|
4
4
|
"description": "Supply-chain threat detection & response for npm",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"node": ">=18.0.0"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
+
"@inquirer/prompts": "^8.1.0",
|
|
39
40
|
"acorn": "^8.14.0",
|
|
40
41
|
"acorn-walk": "^8.3.4",
|
|
41
42
|
"js-yaml": "^4.1.0",
|