muaddib-scanner 1.0.9 → 1.0.10
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/.muaddib-cache/iocs.json +355 -0
- package/package.json +3 -3
- package/rapport.html +159 -0
- package/src/scanner/typosquat.js +52 -118
- package/.github/workflows/scan.yml +0 -33
- package/CONTRIBUTING.md +0 -98
- package/docs/threat-model.md +0 -116
- package/test/samples/malicious.js +0 -20
- package/tests/run-tests.js +0 -389
- package/tests/samples/ast/malicious.js +0 -20
- package/tests/samples/clean/safe.js +0 -14
- package/tests/samples/dataflow/exfiltration.js +0 -20
- package/tests/samples/edge/empty/empty.js +0 -0
- package/tests/samples/edge/invalid-syntax/broken.js +0 -5
- package/tests/samples/edge/large-file/large.js +0 -6
- package/tests/samples/edge/non-js/readme.txt +0 -3
- package/tests/samples/markers/shai-hulud.js +0 -10
- package/tests/samples/obfuscation/obfuscated.js +0 -1
- package/tests/samples/package/package.json +0 -9
- package/tests/samples/shell/malicious.sh +0 -13
- package/tests/samples/typosquat/package.json +0 -11
- package/vscode-extension/.vscode/launch.json +0 -13
- package/vscode-extension/.vscodeignore +0 -0
- package/vscode-extension/LICENSE +0 -21
- package/vscode-extension/README.md +0 -0
- package/vscode-extension/extension.js +0 -271
- package/vscode-extension/icon.png +0 -0
- package/vscode-extension/muaddib-vscode-1.0.0.vsix +0 -0
- package/vscode-extension/package.json +0 -69
- package/vscode-extension/vscode-extension/README.md +0 -44
- package/vscode-extension/vscode-extension/package.json +0 -64
|
@@ -1,271 +0,0 @@
|
|
|
1
|
-
const vscode = require('vscode');
|
|
2
|
-
const { exec } = require('child_process');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
|
|
5
|
-
let diagnosticCollection;
|
|
6
|
-
|
|
7
|
-
function activate(context) {
|
|
8
|
-
console.log('MUAD\'DIB Security Scanner active');
|
|
9
|
-
|
|
10
|
-
// Collection de diagnostics pour afficher les erreurs
|
|
11
|
-
diagnosticCollection = vscode.languages.createDiagnosticCollection('muaddib');
|
|
12
|
-
context.subscriptions.push(diagnosticCollection);
|
|
13
|
-
|
|
14
|
-
// Commande: Scanner le projet
|
|
15
|
-
const scanCommand = vscode.commands.registerCommand('muaddib.scan', async () => {
|
|
16
|
-
await scanProject();
|
|
17
|
-
});
|
|
18
|
-
context.subscriptions.push(scanCommand);
|
|
19
|
-
|
|
20
|
-
// Commande: Scanner le fichier actuel
|
|
21
|
-
const scanFileCommand = vscode.commands.registerCommand('muaddib.scanFile', async () => {
|
|
22
|
-
await scanCurrentFile();
|
|
23
|
-
});
|
|
24
|
-
context.subscriptions.push(scanFileCommand);
|
|
25
|
-
|
|
26
|
-
// Auto-scan a l'ouverture si active
|
|
27
|
-
const config = vscode.workspace.getConfiguration('muaddib');
|
|
28
|
-
if (config.get('autoScan')) {
|
|
29
|
-
scanProject();
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Re-scan quand package.json change
|
|
33
|
-
const watcher = vscode.workspace.createFileSystemWatcher('**/package.json');
|
|
34
|
-
watcher.onDidChange(() => {
|
|
35
|
-
const config = vscode.workspace.getConfiguration('muaddib');
|
|
36
|
-
if (config.get('autoScan')) {
|
|
37
|
-
scanProject();
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
context.subscriptions.push(watcher);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async function scanProject() {
|
|
44
|
-
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
|
|
45
|
-
if (!workspaceFolder) {
|
|
46
|
-
vscode.window.showWarningMessage('MUAD\'DIB: Aucun projet ouvert');
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const projectPath = workspaceFolder.uri.fsPath;
|
|
51
|
-
|
|
52
|
-
vscode.window.withProgress({
|
|
53
|
-
location: vscode.ProgressLocation.Notification,
|
|
54
|
-
title: 'MUAD\'DIB: Scan en cours...',
|
|
55
|
-
cancellable: false
|
|
56
|
-
}, async () => {
|
|
57
|
-
return new Promise((resolve) => {
|
|
58
|
-
const config = vscode.workspace.getConfiguration('muaddib');
|
|
59
|
-
const webhookUrl = config.get('webhookUrl');
|
|
60
|
-
const failLevel = config.get('failLevel');
|
|
61
|
-
|
|
62
|
-
let cmd = `npx muaddib-scanner scan "${projectPath}" --json`;
|
|
63
|
-
if (webhookUrl) {
|
|
64
|
-
cmd += ` --webhook "${webhookUrl}"`;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
exec(cmd, { maxBuffer: 10 * 1024 * 1024 }, (error, stdout, stderr) => {
|
|
68
|
-
try {
|
|
69
|
-
// Si pas de JSON valide, c'est que le scan est propre
|
|
70
|
-
if (!stdout || !stdout.trim().startsWith('{')) {
|
|
71
|
-
vscode.window.showInformationMessage('MUAD\'DIB: Aucune menace detectee');
|
|
72
|
-
diagnosticCollection.clear();
|
|
73
|
-
resolve();
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
const result = JSON.parse(stdout);
|
|
77
|
-
displayResults(result, projectPath);
|
|
78
|
-
} catch (e) {
|
|
79
|
-
if (stdout.includes('Aucune menace')) {
|
|
80
|
-
vscode.window.showInformationMessage('MUAD\'DIB: Aucune menace detectee');
|
|
81
|
-
diagnosticCollection.clear();
|
|
82
|
-
} else {
|
|
83
|
-
vscode.window.showErrorMessage(`MUAD\'DIB: Erreur de scan - ${e.message}`);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
resolve();
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
async function scanCurrentFile() {
|
|
93
|
-
const editor = vscode.window.activeTextEditor;
|
|
94
|
-
if (!editor) {
|
|
95
|
-
vscode.window.showWarningMessage('MUAD\'DIB: Aucun fichier ouvert');
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const filePath = editor.document.uri.fsPath;
|
|
100
|
-
if (!filePath.endsWith('.js') && !filePath.endsWith('.json')) {
|
|
101
|
-
vscode.window.showWarningMessage('MUAD\'DIB: Seuls les fichiers JS et JSON sont scannes');
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const dirPath = path.dirname(filePath);
|
|
106
|
-
|
|
107
|
-
vscode.window.withProgress({
|
|
108
|
-
location: vscode.ProgressLocation.Notification,
|
|
109
|
-
title: 'MUAD\'DIB: Scan du fichier...',
|
|
110
|
-
cancellable: false
|
|
111
|
-
}, async () => {
|
|
112
|
-
return new Promise((resolve) => {
|
|
113
|
-
exec(`npx muaddib-scanner scan "${dirPath}" --json`, { maxBuffer: 10 * 1024 * 1024 }, (error, stdout, stderr) => {
|
|
114
|
-
try {
|
|
115
|
-
const result = JSON.parse(stdout);
|
|
116
|
-
// Filtrer les menaces pour ce fichier seulement
|
|
117
|
-
const fileThreats = result.threats.filter(t =>
|
|
118
|
-
t.file === path.basename(filePath) || t.file.includes(path.basename(filePath))
|
|
119
|
-
);
|
|
120
|
-
if (fileThreats.length > 0) {
|
|
121
|
-
result.threats = fileThreats;
|
|
122
|
-
result.summary.total = fileThreats.length;
|
|
123
|
-
displayResults(result, dirPath);
|
|
124
|
-
} else {
|
|
125
|
-
vscode.window.showInformationMessage('MUAD\'DIB: Aucune menace dans ce fichier');
|
|
126
|
-
}
|
|
127
|
-
} catch (e) {
|
|
128
|
-
vscode.window.showInformationMessage('MUAD\'DIB: Aucune menace detectee');
|
|
129
|
-
}
|
|
130
|
-
resolve();
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function displayResults(result, projectPath) {
|
|
137
|
-
const { threats, summary } = result;
|
|
138
|
-
|
|
139
|
-
// Clear previous diagnostics
|
|
140
|
-
diagnosticCollection.clear();
|
|
141
|
-
|
|
142
|
-
if (threats.length === 0) {
|
|
143
|
-
vscode.window.showInformationMessage('MUAD\'DIB: Aucune menace detectee');
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Afficher le score
|
|
148
|
-
const scoreMessage = `MUAD'DIB: Score ${summary.riskScore}/100 (${summary.riskLevel}) - ${summary.total} menace(s)`;
|
|
149
|
-
|
|
150
|
-
if (summary.riskLevel === 'CRITICAL' || summary.riskLevel === 'HIGH') {
|
|
151
|
-
vscode.window.showErrorMessage(scoreMessage, 'Voir details').then(selection => {
|
|
152
|
-
if (selection === 'Voir details') {
|
|
153
|
-
showDetailPanel(result);
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
} else {
|
|
157
|
-
vscode.window.showWarningMessage(scoreMessage, 'Voir details').then(selection => {
|
|
158
|
-
if (selection === 'Voir details') {
|
|
159
|
-
showDetailPanel(result);
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// Creer les diagnostics pour chaque menace
|
|
165
|
-
const diagnosticsMap = new Map();
|
|
166
|
-
|
|
167
|
-
for (const threat of threats) {
|
|
168
|
-
const filePath = path.join(projectPath, threat.file);
|
|
169
|
-
const uri = vscode.Uri.file(filePath);
|
|
170
|
-
|
|
171
|
-
const severity = threat.severity === 'CRITICAL' ? vscode.DiagnosticSeverity.Error
|
|
172
|
-
: threat.severity === 'HIGH' ? vscode.DiagnosticSeverity.Error
|
|
173
|
-
: threat.severity === 'MEDIUM' ? vscode.DiagnosticSeverity.Warning
|
|
174
|
-
: vscode.DiagnosticSeverity.Information;
|
|
175
|
-
|
|
176
|
-
const line = (threat.line || 1) - 1;
|
|
177
|
-
const range = new vscode.Range(line, 0, line, 100);
|
|
178
|
-
|
|
179
|
-
const diagnostic = new vscode.Diagnostic(
|
|
180
|
-
range,
|
|
181
|
-
`[${threat.severity}] ${threat.message}`,
|
|
182
|
-
severity
|
|
183
|
-
);
|
|
184
|
-
diagnostic.source = 'MUAD\'DIB';
|
|
185
|
-
diagnostic.code = threat.rule_id || threat.type;
|
|
186
|
-
|
|
187
|
-
if (!diagnosticsMap.has(uri.toString())) {
|
|
188
|
-
diagnosticsMap.set(uri.toString(), []);
|
|
189
|
-
}
|
|
190
|
-
diagnosticsMap.get(uri.toString()).push(diagnostic);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Appliquer les diagnostics
|
|
194
|
-
for (const [uriString, diagnostics] of diagnosticsMap) {
|
|
195
|
-
diagnosticCollection.set(vscode.Uri.parse(uriString), diagnostics);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
function showDetailPanel(result) {
|
|
200
|
-
const panel = vscode.window.createWebviewPanel(
|
|
201
|
-
'muaddibResults',
|
|
202
|
-
'MUAD\'DIB - Resultats',
|
|
203
|
-
vscode.ViewColumn.Two,
|
|
204
|
-
{ enableScripts: true }
|
|
205
|
-
);
|
|
206
|
-
|
|
207
|
-
const { threats, summary } = result;
|
|
208
|
-
|
|
209
|
-
const threatRows = threats.map(t => `
|
|
210
|
-
<tr class="${t.severity.toLowerCase()}">
|
|
211
|
-
<td>${t.severity}</td>
|
|
212
|
-
<td>${t.type}</td>
|
|
213
|
-
<td>${t.message}</td>
|
|
214
|
-
<td>${t.file}</td>
|
|
215
|
-
<td>${t.playbook || '-'}</td>
|
|
216
|
-
</tr>
|
|
217
|
-
`).join('');
|
|
218
|
-
|
|
219
|
-
panel.webview.html = `
|
|
220
|
-
<!DOCTYPE html>
|
|
221
|
-
<html>
|
|
222
|
-
<head>
|
|
223
|
-
<style>
|
|
224
|
-
body { font-family: -apple-system, BlinkMacSystemFont, sans-serif; padding: 20px; background: #1e1e1e; color: #fff; }
|
|
225
|
-
h1 { color: #e94560; }
|
|
226
|
-
.score { font-size: 24px; margin: 20px 0; }
|
|
227
|
-
.critical { color: #e74c3c; }
|
|
228
|
-
.high { color: #e67e22; }
|
|
229
|
-
.medium { color: #f1c40f; }
|
|
230
|
-
.low { color: #3498db; }
|
|
231
|
-
table { width: 100%; border-collapse: collapse; margin-top: 20px; }
|
|
232
|
-
th, td { padding: 10px; text-align: left; border-bottom: 1px solid #333; }
|
|
233
|
-
th { background: #2d2d2d; color: #e94560; }
|
|
234
|
-
tr.critical { background: rgba(231, 76, 60, 0.2); }
|
|
235
|
-
tr.high { background: rgba(230, 126, 34, 0.2); }
|
|
236
|
-
tr.medium { background: rgba(241, 196, 15, 0.1); }
|
|
237
|
-
</style>
|
|
238
|
-
</head>
|
|
239
|
-
<body>
|
|
240
|
-
<h1>MUAD'DIB Security Scan</h1>
|
|
241
|
-
<div class="score">
|
|
242
|
-
Score: <strong>${summary.riskScore}/100</strong>
|
|
243
|
-
(<span class="${summary.riskLevel.toLowerCase()}">${summary.riskLevel}</span>)
|
|
244
|
-
</div>
|
|
245
|
-
<p>CRITICAL: ${summary.critical} | HIGH: ${summary.high} | MEDIUM: ${summary.medium}</p>
|
|
246
|
-
<table>
|
|
247
|
-
<thead>
|
|
248
|
-
<tr>
|
|
249
|
-
<th>Severite</th>
|
|
250
|
-
<th>Type</th>
|
|
251
|
-
<th>Message</th>
|
|
252
|
-
<th>Fichier</th>
|
|
253
|
-
<th>Recommandation</th>
|
|
254
|
-
</tr>
|
|
255
|
-
</thead>
|
|
256
|
-
<tbody>
|
|
257
|
-
${threatRows}
|
|
258
|
-
</tbody>
|
|
259
|
-
</table>
|
|
260
|
-
</body>
|
|
261
|
-
</html>
|
|
262
|
-
`;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
function deactivate() {
|
|
266
|
-
if (diagnosticCollection) {
|
|
267
|
-
diagnosticCollection.dispose();
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
module.exports = { activate, deactivate };
|
|
Binary file
|
|
Binary file
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "muaddib-vscode",
|
|
3
|
-
"displayName": "MUAD'DIB Security Scanner",
|
|
4
|
-
"description": "Detecte les attaques supply chain npm directement dans VS Code",
|
|
5
|
-
"version": "1.0.3",
|
|
6
|
-
"publisher": "dnszlsk",
|
|
7
|
-
"engines": {
|
|
8
|
-
"vscode": "^1.85.0"
|
|
9
|
-
},
|
|
10
|
-
"categories": [
|
|
11
|
-
"Linters",
|
|
12
|
-
"Other"
|
|
13
|
-
],
|
|
14
|
-
"keywords": [
|
|
15
|
-
"security",
|
|
16
|
-
"npm",
|
|
17
|
-
"supply-chain",
|
|
18
|
-
"malware",
|
|
19
|
-
"scanner"
|
|
20
|
-
],
|
|
21
|
-
"icon": "icon.png",
|
|
22
|
-
"activationEvents": [
|
|
23
|
-
"workspaceContains:package.json"
|
|
24
|
-
],
|
|
25
|
-
"main": "./extension.js",
|
|
26
|
-
"contributes": {
|
|
27
|
-
"commands": [
|
|
28
|
-
{
|
|
29
|
-
"command": "muaddib.scan",
|
|
30
|
-
"title": "MUAD'DIB: Scan Project"
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
"command": "muaddib.scanFile",
|
|
34
|
-
"title": "MUAD'DIB: Scan Current File"
|
|
35
|
-
}
|
|
36
|
-
],
|
|
37
|
-
"configuration": {
|
|
38
|
-
"title": "MUAD'DIB",
|
|
39
|
-
"properties": {
|
|
40
|
-
"muaddib.autoScan": {
|
|
41
|
-
"type": "boolean",
|
|
42
|
-
"default": true,
|
|
43
|
-
"description": "Scanner automatiquement a l'ouverture du projet"
|
|
44
|
-
},
|
|
45
|
-
"muaddib.webhookUrl": {
|
|
46
|
-
"type": "string",
|
|
47
|
-
"default": "",
|
|
48
|
-
"description": "URL du webhook Discord/Slack pour les alertes"
|
|
49
|
-
},
|
|
50
|
-
"muaddib.failLevel": {
|
|
51
|
-
"type": "string",
|
|
52
|
-
"enum": [
|
|
53
|
-
"critical",
|
|
54
|
-
"high",
|
|
55
|
-
"medium",
|
|
56
|
-
"low"
|
|
57
|
-
],
|
|
58
|
-
"default": "high",
|
|
59
|
-
"description": "Niveau de severite pour afficher les alertes"
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
},
|
|
64
|
-
"repository": {
|
|
65
|
-
"type": "git",
|
|
66
|
-
"url": "https://github.com/DNSZLSK/muad-dib"
|
|
67
|
-
},
|
|
68
|
-
"license": "MIT"
|
|
69
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
# MUAD'DIB Security Scanner for VS Code
|
|
2
|
-
|
|
3
|
-
Detecte les attaques supply chain npm directement dans VS Code.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- Scan automatique a l'ouverture d'un projet npm
|
|
8
|
-
- Detection des packages malveillants (Shai-Hulud, event-stream, etc.)
|
|
9
|
-
- Detection du typosquatting
|
|
10
|
-
- Analyse AST et dataflow
|
|
11
|
-
- Score de risque 0-100
|
|
12
|
-
- Alertes Discord/Slack
|
|
13
|
-
- Diagnostics inline dans l'editeur
|
|
14
|
-
|
|
15
|
-
## Installation
|
|
16
|
-
|
|
17
|
-
1. Installer l'extension depuis VS Code Marketplace
|
|
18
|
-
2. Ouvrir un projet npm
|
|
19
|
-
3. Le scan se lance automatiquement
|
|
20
|
-
|
|
21
|
-
## Commandes
|
|
22
|
-
|
|
23
|
-
- `MUAD'DIB: Scan Project` — Scanner tout le projet
|
|
24
|
-
- `MUAD'DIB: Scan Current File` — Scanner le fichier actuel
|
|
25
|
-
|
|
26
|
-
## Configuration
|
|
27
|
-
|
|
28
|
-
- `muaddib.autoScan` — Scanner automatiquement (defaut: true)
|
|
29
|
-
- `muaddib.webhookUrl` — URL webhook Discord/Slack
|
|
30
|
-
- `muaddib.failLevel` — Niveau d'alerte (critical/high/medium/low)
|
|
31
|
-
|
|
32
|
-
## Prerequis
|
|
33
|
-
|
|
34
|
-
- Node.js >= 18
|
|
35
|
-
- muaddib-scanner installe globalement : `npm install -g muaddib-scanner`
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
Sauvegarde.
|
|
39
|
-
|
|
40
|
-
Ouvre `vscode-extension/.vscodeignore` et mets :
|
|
41
|
-
```
|
|
42
|
-
.git
|
|
43
|
-
node_modules
|
|
44
|
-
*.md
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "muaddib-vscode",
|
|
3
|
-
"displayName": "MUAD'DIB Security Scanner",
|
|
4
|
-
"description": "Detecte les attaques supply chain npm directement dans VS Code",
|
|
5
|
-
"version": "1.0.0",
|
|
6
|
-
"publisher": "dnszlsk",
|
|
7
|
-
"engines": {
|
|
8
|
-
"vscode": "^1.85.0"
|
|
9
|
-
},
|
|
10
|
-
"categories": [
|
|
11
|
-
"Linters",
|
|
12
|
-
"Other"
|
|
13
|
-
],
|
|
14
|
-
"keywords": [
|
|
15
|
-
"security",
|
|
16
|
-
"npm",
|
|
17
|
-
"supply-chain",
|
|
18
|
-
"malware",
|
|
19
|
-
"scanner"
|
|
20
|
-
],
|
|
21
|
-
"activationEvents": [
|
|
22
|
-
"workspaceContains:package.json"
|
|
23
|
-
],
|
|
24
|
-
"main": "./extension.js",
|
|
25
|
-
"icon": "icon.png",
|
|
26
|
-
"contributes": {
|
|
27
|
-
"commands": [
|
|
28
|
-
{
|
|
29
|
-
"command": "muaddib.scan",
|
|
30
|
-
"title": "MUAD'DIB: Scan Project"
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
"command": "muaddib.scanFile",
|
|
34
|
-
"title": "MUAD'DIB: Scan Current File"
|
|
35
|
-
}
|
|
36
|
-
],
|
|
37
|
-
"configuration": {
|
|
38
|
-
"title": "MUAD'DIB",
|
|
39
|
-
"properties": {
|
|
40
|
-
"muaddib.autoScan": {
|
|
41
|
-
"type": "boolean",
|
|
42
|
-
"default": true,
|
|
43
|
-
"description": "Scanner automatiquement a l'ouverture du projet"
|
|
44
|
-
},
|
|
45
|
-
"muaddib.webhookUrl": {
|
|
46
|
-
"type": "string",
|
|
47
|
-
"default": "",
|
|
48
|
-
"description": "URL du webhook Discord/Slack pour les alertes"
|
|
49
|
-
},
|
|
50
|
-
"muaddib.failLevel": {
|
|
51
|
-
"type": "string",
|
|
52
|
-
"enum": ["critical", "high", "medium", "low"],
|
|
53
|
-
"default": "high",
|
|
54
|
-
"description": "Niveau de severite pour afficher les alertes"
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
},
|
|
59
|
-
"repository": {
|
|
60
|
-
"type": "git",
|
|
61
|
-
"url": "https://github.com/DNSZLSK/muad-dib"
|
|
62
|
-
},
|
|
63
|
-
"license": "MIT"
|
|
64
|
-
}
|