Teep002 commited on
Commit
363e325
·
verified ·
1 Parent(s): 9e04f3f

undefined - Initial Deployment

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +823 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Security Scanner
3
- emoji: 😻
4
- colorFrom: indigo
5
- colorTo: indigo
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: security-scanner
3
+ emoji: 🐳
4
+ colorFrom: gray
5
+ colorTo: blue
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,823 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Security Scanner | Comprehensive Threat Analysis</title>
7
+ <style>
8
+ :root {
9
+ --bg-color: #1a1a1a;
10
+ --text-color: #e0e0e0;
11
+ --card-bg: #2d2d2d;
12
+ --border-color: #444;
13
+ --primary-color: #3498db;
14
+ --primary-hover: #2980b9;
15
+ --secondary-text: #b0b0b0;
16
+ }
17
+
18
+ .light-mode {
19
+ --bg-color: #f5f7fa;
20
+ --text-color: #333;
21
+ --card-bg: white;
22
+ --border-color: #e1e4e8;
23
+ --secondary-text: #7f8c8d;
24
+ }
25
+
26
+ body {
27
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
28
+ line-height: 1.6;
29
+ margin: 0;
30
+ padding: 0;
31
+ background-color: var(--bg-color);
32
+ color: var(--text-color);
33
+ transition: background-color 0.3s, color 0.3s;
34
+ }
35
+
36
+ .container {
37
+ max-width: 800px;
38
+ margin: 0 auto;
39
+ padding: 20px;
40
+ position: relative;
41
+ }
42
+
43
+ header {
44
+ text-align: center;
45
+ margin-bottom: 30px;
46
+ padding: 20px 0;
47
+ border-bottom: 1px solid var(--border-color);
48
+ position: relative;
49
+ }
50
+
51
+ h1 {
52
+ color: var(--primary-color);
53
+ margin-bottom: 10px;
54
+ }
55
+
56
+ .description {
57
+ color: var(--secondary-text);
58
+ margin-bottom: 20px;
59
+ }
60
+
61
+ .scanner-form {
62
+ background: var(--card-bg);
63
+ padding: 25px;
64
+ border-radius: 8px;
65
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
66
+ margin-bottom: 30px;
67
+ }
68
+
69
+ .form-group {
70
+ margin-bottom: 20px;
71
+ }
72
+
73
+ label {
74
+ display: block;
75
+ margin-bottom: 8px;
76
+ font-weight: 600;
77
+ }
78
+
79
+ input[type="text"] {
80
+ width: 100%;
81
+ padding: 10px;
82
+ border: 1px solid #ddd;
83
+ border-radius: 4px;
84
+ font-size: 16px;
85
+ }
86
+
87
+ .radio-group {
88
+ display: flex;
89
+ gap: 20px;
90
+ margin-bottom: 15px;
91
+ justify-content: center;
92
+ flex-wrap: wrap;
93
+ }
94
+
95
+ .radio-option {
96
+ display: flex;
97
+ align-items: center;
98
+ }
99
+
100
+ .radio-option input {
101
+ margin-right: 8px;
102
+ }
103
+
104
+ button {
105
+ background-color: #3498db;
106
+ color: white;
107
+ border: none;
108
+ padding: 12px 20px;
109
+ border-radius: 4px;
110
+ cursor: pointer;
111
+ font-size: 16px;
112
+ font-weight: 600;
113
+ transition: background-color 0.3s;
114
+ width: 100%;
115
+ }
116
+
117
+ button:hover {
118
+ background-color: #2980b9;
119
+ }
120
+
121
+ button:disabled {
122
+ background-color: #95a5a6;
123
+ cursor: not-allowed;
124
+ }
125
+
126
+ .results {
127
+ background: white;
128
+ padding: 25px;
129
+ border-radius: 8px;
130
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
131
+ display: none;
132
+ }
133
+
134
+ .result-item {
135
+ margin-bottom: 15px;
136
+ padding-bottom: 15px;
137
+ border-bottom: 1px solid #eee;
138
+ }
139
+
140
+ .result-item:last-child {
141
+ border-bottom: none;
142
+ }
143
+
144
+ .result-title {
145
+ font-weight: 600;
146
+ color: #2c3e50;
147
+ margin-bottom: 5px;
148
+ }
149
+
150
+ .loading {
151
+ text-align: center;
152
+ display: none;
153
+ margin: 20px 0;
154
+ }
155
+
156
+ .spinner {
157
+ border: 4px solid rgba(0, 0, 0, 0.1);
158
+ border-radius: 50%;
159
+ border-top: 4px solid #3498db;
160
+ width: 30px;
161
+ height: 30px;
162
+ animation: spin 1s linear infinite;
163
+ margin: 0 auto 10px;
164
+ }
165
+
166
+ @keyframes spin {
167
+ 0% { transform: rotate(0deg); }
168
+ 100% { transform: rotate(360deg); }
169
+ }
170
+
171
+ .error-message {
172
+ color: #e74c3c;
173
+ margin-top: 5px;
174
+ font-size: 14px;
175
+ display: none;
176
+ }
177
+
178
+ footer {
179
+ text-align: center;
180
+ margin-top: 40px;
181
+ padding: 20px 0;
182
+ color: #7f8c8d;
183
+ font-size: 14px;
184
+ }
185
+
186
+ .hash-info {
187
+ font-size: 13px;
188
+ color: #7f8c8d;
189
+ margin-top: 5px;
190
+ }
191
+
192
+ /* Modal Styles */
193
+ .modal {
194
+ display: none;
195
+ position: fixed;
196
+ z-index: 1;
197
+ left: 0;
198
+ top: 0;
199
+ width: 100%;
200
+ height: 100%;
201
+ overflow: auto;
202
+ background-color: rgba(0,0,0,0.4);
203
+ }
204
+
205
+ .modal-content {
206
+ background-color: #fefefe;
207
+ margin: 15% auto;
208
+ padding: 20px;
209
+ border-radius: 8px;
210
+ width: 80%;
211
+ max-width: 500px;
212
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
213
+ }
214
+
215
+ .modal-header {
216
+ display: flex;
217
+ justify-content: space-between;
218
+ align-items: center;
219
+ margin-bottom: 15px;
220
+ }
221
+
222
+ .modal-title {
223
+ color: #e74c3c;
224
+ font-weight: bold;
225
+ font-size: 20px;
226
+ margin: 0;
227
+ }
228
+
229
+ .close-modal {
230
+ color: #aaa;
231
+ font-size: 28px;
232
+ font-weight: bold;
233
+ cursor: pointer;
234
+ }
235
+
236
+ .close-modal:hover {
237
+ color: #333;
238
+ }
239
+
240
+ .modal-body {
241
+ margin-bottom: 20px;
242
+ }
243
+
244
+ .modal-footer {
245
+ text-align: right;
246
+ }
247
+
248
+ .modal-button {
249
+ background-color: #3498db;
250
+ color: white;
251
+ border: none;
252
+ padding: 8px 16px;
253
+ border-radius: 4px;
254
+ cursor: pointer;
255
+ }
256
+
257
+ .progress-text {
258
+ margin-top: 10px;
259
+ font-style: italic;
260
+ color: #7f8c8d;
261
+ }
262
+
263
+ .result-text {
264
+ white-space: pre-wrap;
265
+ word-wrap: break-word;
266
+ background-color: #f8f9fa;
267
+ padding: 10px;
268
+ border-radius: 4px;
269
+ font-family: monospace;
270
+ }
271
+
272
+ /* Circular Progress Indicators */
273
+ .score-container {
274
+ display: flex;
275
+ flex-wrap: wrap;
276
+ gap: 20px;
277
+ margin-top: 15px;
278
+ }
279
+
280
+ .score-item {
281
+ display: flex;
282
+ flex-direction: column;
283
+ align-items: center;
284
+ }
285
+
286
+ .circular-progress {
287
+ position: relative;
288
+ width: 80px;
289
+ height: 80px;
290
+ border-radius: 50%;
291
+ display: flex;
292
+ align-items: center;
293
+ justify-content: center;
294
+ margin-bottom: 8px;
295
+ }
296
+
297
+ .circular-progress::before {
298
+ content: "";
299
+ position: absolute;
300
+ width: 70px;
301
+ height: 70px;
302
+ border-radius: 50%;
303
+ background-color: white;
304
+ }
305
+
306
+ .progress-value {
307
+ position: relative;
308
+ font-weight: bold;
309
+ font-size: 18px;
310
+ }
311
+
312
+ .score-label {
313
+ font-size: 14px;
314
+ font-weight: 600;
315
+ }
316
+
317
+ .malicious {
318
+ background: conic-gradient(#e74c3c var(--progress), #f5b7b1 0deg);
319
+ }
320
+
321
+ .suspicious {
322
+ background: conic-gradient(#f39c12 var(--progress), #fad7a0 0deg);
323
+ }
324
+
325
+ .harmless {
326
+ background: conic-gradient(#2ecc71 var(--progress), #abebc6 0deg);
327
+ }
328
+
329
+ .undetected {
330
+ background: conic-gradient(#95a5a6 var(--progress), #d5dbdb 0deg);
331
+ }
332
+ </style>
333
+ </head>
334
+ <body>
335
+ <div class="container">
336
+ <header>
337
+ <h1>Security Scanner</h1>
338
+ <p class="description">Comprehensive threat analysis for domains, IPs, and file hashes</p>
339
+ <button id="theme-toggle" style="position: absolute; top: 20px; right: 20px; padding: 5px 10px; background: var(--primary-color); color: white; border: none; border-radius: 4px; cursor: pointer;">Light Mode</button>
340
+ </header>
341
+
342
+ <div class="scanner-form">
343
+ <div class="radio-group">
344
+ <div class="radio-option">
345
+ <input type="radio" id="url-check" name="check-type" value="url" checked>
346
+ <label for="url-check">URL Check</label>
347
+ </div>
348
+ <div class="radio-option">
349
+ <input type="radio" id="domain-check" name="check-type" value="domain">
350
+ <label for="domain-check">Domain Analysis</label>
351
+ </div>
352
+ <div class="radio-option">
353
+ <input type="radio" id="ip-check" name="check-type" value="ip">
354
+ <label for="ip-check">IP Reputation</label>
355
+ </div>
356
+ <div class="radio-option">
357
+ <input type="radio" id="hash-check" name="check-type" value="hash">
358
+ <label for="hash-check">File Hash Check</label>
359
+ </div>
360
+ </div>
361
+
362
+ <div class="form-group" id="url-ip-domain-group">
363
+ <label for="target" id="target-label">Enter domain to scan (example.com)</label>
364
+ <input type="text" id="target" placeholder="example.com">
365
+ <div class="error-message" id="target-error"></div>
366
+ </div>
367
+
368
+ <div class="form-group" id="hash-group" style="display: none;">
369
+ <label for="hash-input">Enter file hash (MD5, SHA-1, SHA-256, etc.)</label>
370
+ <input type="text" id="hash-input" placeholder="e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855">
371
+ <div class="error-message" id="hash-error"></div>
372
+ <p class="hash-info">Enter the cryptographic hash of a file to check its reputation</p>
373
+ </div>
374
+
375
+ <button id="scan-button" disabled>Scan Now</button>
376
+ </div>
377
+
378
+ <div class="loading" id="loading">
379
+ <div class="spinner"></div>
380
+ <p>Analyzing, please wait...</p>
381
+ <p class="progress-text" id="progress-text">Waiting for the analysis report</p>
382
+ </div>
383
+
384
+ <div class="results" id="results">
385
+ <h2>Scan Results</h2>
386
+ <div class="result-item">
387
+ <div class="result-title">Threat Scores:</div>
388
+ <div class="score-container" id="score-container" style="justify-content: center;">
389
+ <!-- Scores will be inserted here dynamically -->
390
+ </div>
391
+ </div>
392
+ <div class="result-item">
393
+ <div class="result-title">Target:</div>
394
+ <div id="result-target"></div>
395
+ </div>
396
+ <div class="result-item">
397
+ <div class="result-title">Type:</div>
398
+ <div id="result-type"></div>
399
+ </div>
400
+ <div class="result-item">
401
+ <div class="result-title">Details:</div>
402
+ <div class="result-text" id="result-details"></div>
403
+ </div>
404
+ <div class="result-item">
405
+ <div class="result-title">Last Updated:</div>
406
+ <div id="result-date"></div>
407
+ </div>
408
+ </div>
409
+ </div>
410
+
411
+ <!-- Error Modal -->
412
+ <div id="error-modal" class="modal">
413
+ <div class="modal-content">
414
+ <div class="modal-header">
415
+ <h3 class="modal-title">Error</h3>
416
+ <span class="close-modal">&times;</span>
417
+ </div>
418
+ <div class="modal-body" id="modal-error-message">
419
+ An error occurred while processing your request.
420
+ </div>
421
+ <div class="modal-footer">
422
+ <button class="modal-button" id="close-modal-btn">OK</button>
423
+ </div>
424
+ </div>
425
+ </div>
426
+
427
+ <footer>
428
+ <p>Security Scanner System | Powered by n8n automation</p>
429
+ <div class="scan-stats" style="margin-top: 10px; font-size: 14px; color: var(--secondary-text);">
430
+ <span>Total Scans: <span id="total-scans">0</span></span> |
431
+ <span>URL Checks: <span id="url-scans">0</span></span> |
432
+ <span>Domain Analysis: <span id="domain-scans">0</span></span> |
433
+ <span>IP Reputation: <span id="ip-scans">0</span></span> |
434
+ <span>File Hash: <span id="hash-scans">0</span></span>
435
+ </div>
436
+ </footer>
437
+
438
+ <script>
439
+ document.addEventListener('DOMContentLoaded', function() {
440
+ // Theme toggle functionality
441
+ const themeToggle = document.getElementById('theme-toggle');
442
+ themeToggle.addEventListener('click', function() {
443
+ document.body.classList.toggle('light-mode');
444
+ themeToggle.textContent = document.body.classList.contains('light-mode') ? 'Dark Mode' : 'Light Mode';
445
+ localStorage.setItem('theme', document.body.classList.contains('light-mode') ? 'light' : 'dark');
446
+ });
447
+
448
+ // Set initial theme from localStorage
449
+ if (localStorage.getItem('theme') === 'light') {
450
+ document.body.classList.add('light-mode');
451
+ themeToggle.textContent = 'Dark Mode';
452
+ }
453
+
454
+ // Scan counters
455
+ let scanCounters = {
456
+ total: 0,
457
+ url: 0,
458
+ domain: 0,
459
+ ip: 0,
460
+ hash: 0
461
+ };
462
+
463
+ // Load counters from localStorage if available
464
+ const savedCounters = localStorage.getItem('scanCounters');
465
+ if (savedCounters) {
466
+ scanCounters = JSON.parse(savedCounters);
467
+ updateCounterDisplay();
468
+ }
469
+ // DOM Elements
470
+ const urlRadio = document.getElementById('url-check');
471
+ const domainRadio = document.getElementById('domain-check');
472
+ const ipRadio = document.getElementById('ip-check');
473
+ const hashRadio = document.getElementById('hash-check');
474
+ const targetLabel = document.getElementById('target-label');
475
+ const targetInput = document.getElementById('target');
476
+ const urlIpDomainGroup = document.getElementById('url-ip-domain-group');
477
+ const hashGroup = document.getElementById('hash-group');
478
+ const hashInput = document.getElementById('hash-input');
479
+ const scanButton = document.getElementById('scan-button');
480
+ const loadingDiv = document.getElementById('loading');
481
+ const progressText = document.getElementById('progress-text');
482
+ const resultsDiv = document.getElementById('results');
483
+ const scoreContainer = document.getElementById('score-container');
484
+ const targetError = document.getElementById('target-error');
485
+ const hashError = document.getElementById('hash-error');
486
+
487
+ // Modal elements
488
+ const errorModal = document.getElementById('error-modal');
489
+ const modalErrorMessage = document.getElementById('modal-error-message');
490
+ const closeModalBtn = document.getElementById('close-modal-btn');
491
+ const closeModalSpan = document.querySelector('.close-modal');
492
+
493
+ // Validation patterns
494
+ const DOMAIN_REGEX = /^(?!:\/\/)(?:[a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.[a-zA-Z]{2,}$/;
495
+ const URL_REGEX = /^(https?:\/\/)?(www\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}(\/[^\s]*)?$/;
496
+ const PUBLIC_IP_REGEX = /^(?!0)(?!10\.|127\.|172\.(1[6-9]|2[0-9]|3[0-1])\.|192\.168\.)(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
497
+ const HASH_REGEX = /^[a-fA-F0-9]{32,128}$/;
498
+
499
+ // Event listeners for radio buttons
500
+ urlRadio.addEventListener('change', updateFormFields);
501
+ domainRadio.addEventListener('change', updateFormFields);
502
+ ipRadio.addEventListener('change', updateFormFields);
503
+ hashRadio.addEventListener('change', updateFormFields);
504
+
505
+ function updateFormFields() {
506
+ if(urlRadio.checked) {
507
+ urlIpDomainGroup.style.display = 'block';
508
+ hashGroup.style.display = 'none';
509
+ targetLabel.textContent = 'Enter URL to scan (example.com/path)';
510
+ targetInput.placeholder = 'example.com/path';
511
+ targetInput.value = '';
512
+ hashInput.value = '';
513
+ }
514
+ else if(domainRadio.checked) {
515
+ urlIpDomainGroup.style.display = 'block';
516
+ hashGroup.style.display = 'none';
517
+ targetLabel.textContent = 'Enter domain to analyze (example.com)';
518
+ targetInput.placeholder = 'example.com';
519
+ targetInput.value = '';
520
+ hashInput.value = '';
521
+ }
522
+ else if(ipRadio.checked) {
523
+ urlIpDomainGroup.style.display = 'block';
524
+ hashGroup.style.display = 'none';
525
+ targetLabel.textContent = 'Enter public IP address to check';
526
+ targetInput.placeholder = '8.8.8.8';
527
+ targetInput.value = '';
528
+ hashInput.value = '';
529
+ }
530
+ else if(hashRadio.checked) {
531
+ urlIpDomainGroup.style.display = 'none';
532
+ hashGroup.style.display = 'block';
533
+ targetInput.value = '';
534
+ hashInput.value = '';
535
+ }
536
+
537
+ scanButton.disabled = true;
538
+ clearErrors();
539
+ }
540
+
541
+ // Input validation
542
+ targetInput.addEventListener('input', validateInput);
543
+ hashInput.addEventListener('input', validateInput);
544
+
545
+ // Modal event listeners
546
+ closeModalBtn.addEventListener('click', function() {
547
+ errorModal.style.display = 'none';
548
+ });
549
+
550
+ closeModalSpan.addEventListener('click', function() {
551
+ errorModal.style.display = 'none';
552
+ });
553
+
554
+ window.addEventListener('click', function(event) {
555
+ if (event.target === errorModal) {
556
+ errorModal.style.display = 'none';
557
+ }
558
+ });
559
+
560
+ function validateInput() {
561
+ clearErrors();
562
+ let isValid = false;
563
+
564
+ if(urlRadio.checked) {
565
+ // URL validation
566
+ if(targetInput.value.trim() === '') {
567
+ showError(targetError, 'Please enter a URL');
568
+ } else if(!URL_REGEX.test(targetInput.value.trim())) {
569
+ showError(targetError, 'Please enter a valid URL (example.com/path) without http/https/www');
570
+ } else {
571
+ isValid = true;
572
+ }
573
+ }
574
+ else if(domainRadio.checked) {
575
+ // Domain validation (strict)
576
+ if(targetInput.value.trim() === '') {
577
+ showError(targetError, 'Please enter a domain');
578
+ } else if(!DOMAIN_REGEX.test(targetInput.value.trim())) {
579
+ showError(targetError, 'Please enter a valid domain (example.com) without http/https/www or paths');
580
+ } else {
581
+ isValid = true;
582
+ }
583
+ }
584
+ else if(ipRadio.checked) {
585
+ // Public IP validation
586
+ const ip = targetInput.value.trim();
587
+ if(ip === '') {
588
+ showError(targetError, 'Please enter an IP address');
589
+ } else if(!PUBLIC_IP_REGEX.test(ip)) {
590
+ showError(targetError, 'Please enter a valid public IPv4 address (e.g. 8.8.8.8)');
591
+ } else if(isPrivateIP(ip)) {
592
+ showError(targetError, 'This is a private IP address. Please enter a public IP.');
593
+ } else {
594
+ isValid = true;
595
+ }
596
+ }
597
+ else if(hashRadio.checked) {
598
+ // Hash validation
599
+ if(hashInput.value.trim() === '') {
600
+ showError(hashError, 'Please enter a file hash');
601
+ } else if(!HASH_REGEX.test(hashInput.value.trim())) {
602
+ showError(hashError, 'Please enter a valid hash (MD5, SHA-1, SHA-256, etc.)');
603
+ } else {
604
+ isValid = true;
605
+ }
606
+ }
607
+
608
+ scanButton.disabled = !isValid;
609
+ return isValid;
610
+ }
611
+
612
+ function isPrivateIP(ip) {
613
+ // Check against standard private IP ranges
614
+ const ipParts = ip.split('.').map(Number);
615
+
616
+ // 10.0.0.0/8
617
+ if(ipParts[0] === 10) return true;
618
+
619
+ // 172.16.0.0/12
620
+ if(ipParts[0] === 172 && ipParts[1] >= 16 && ipParts[1] <= 31) return true;
621
+
622
+ // 192.168.0.0/16
623
+ if(ipParts[0] === 192 && ipParts[1] === 168) return true;
624
+
625
+ // 127.0.0.0/8
626
+ if(ipParts[0] === 127) return true;
627
+
628
+ // 169.254.0.0/16 (link-local)
629
+ if(ipParts[0] === 169 && ipParts[1] === 254) return true;
630
+
631
+ return false;
632
+ }
633
+
634
+ function showError(element, message) {
635
+ element.textContent = message;
636
+ element.style.display = 'block';
637
+ }
638
+
639
+ function clearErrors() {
640
+ targetError.style.display = 'none';
641
+ hashError.style.display = 'none';
642
+ }
643
+
644
+ function showModalError(message) {
645
+ modalErrorMessage.textContent = message;
646
+ errorModal.style.display = 'block';
647
+
648
+ // Ensure modal is visible in dark/light mode
649
+ const modalContent = document.querySelector('.modal-content');
650
+ if (document.body.classList.contains('light-mode')) {
651
+ modalContent.style.backgroundColor = 'white';
652
+ modalContent.style.color = '#333';
653
+ } else {
654
+ modalContent.style.backgroundColor = '#2d2d2d';
655
+ modalContent.style.color = '#e0e0e0';
656
+ }
657
+ }
658
+
659
+ function createScoreIndicator(type, score) {
660
+ const percentage = Math.min(100, Math.max(0, score));
661
+ const progress = (percentage / 100) * 360;
662
+
663
+ const scoreItem = document.createElement('div');
664
+ scoreItem.className = 'score-item';
665
+
666
+ const progressDiv = document.createElement('div');
667
+ progressDiv.className = `circular-progress ${type}`;
668
+ progressDiv.style.setProperty('--progress', `${progress}deg`);
669
+
670
+ const progressValue = document.createElement('div');
671
+ progressValue.className = 'progress-value';
672
+ progressValue.textContent = `${percentage}%`;
673
+
674
+ const scoreLabel = document.createElement('div');
675
+ scoreLabel.className = 'score-label';
676
+ scoreLabel.textContent = type.charAt(0).toUpperCase() + type.slice(1);
677
+
678
+ progressDiv.appendChild(progressValue);
679
+ scoreItem.appendChild(progressDiv);
680
+ scoreItem.appendChild(scoreLabel);
681
+
682
+ return scoreItem;
683
+ }
684
+
685
+ function parseScoresFromResponse(text) {
686
+ // Extract scores from the text response
687
+ const scores = {
688
+ malicious: 0,
689
+ suspicious: 0,
690
+ harmless: 0,
691
+ undetected: 0
692
+ };
693
+
694
+ // More robust score parsing that looks for various formats
695
+ const scorePatterns = [
696
+ // Matches "Malicious: 75%" or "Malicious Score: 75"
697
+ /(malicious)[\s:]*(\d+)/i,
698
+ /(suspicious)[\s:]*(\d+)/i,
699
+ /(harmless)[\s:]*(\d+)/i,
700
+ /(undetected)[\s:]*(\d+)/i,
701
+ // Matches "75% malicious" or "75 malicious"
702
+ /(\d+)[%\s]*(malicious)/i,
703
+ /(\d+)[%\s]*(suspicious)/i,
704
+ /(\d+)[%\s]*(harmless)/i,
705
+ /(\d+)[%\s]*(undetected)/i
706
+ ];
707
+
708
+ for (const pattern of scorePatterns) {
709
+ const matches = text.matchAll(pattern);
710
+ for (const match of matches) {
711
+ let type, value;
712
+ if (match[2] && isNaN(match[2])) {
713
+ // Pattern like "75 malicious"
714
+ value = parseInt(match[1]);
715
+ type = match[2].toLowerCase();
716
+ } else {
717
+ // Pattern like "malicious: 75"
718
+ type = match[1].toLowerCase();
719
+ value = parseInt(match[2]);
720
+ }
721
+
722
+ if (type in scores) {
723
+ scores[type] = Math.min(100, Math.max(0, value));
724
+ }
725
+ }
726
+ }
727
+
728
+ return scores;
729
+ }
730
+
731
+ // Handle form submission
732
+ scanButton.addEventListener('click', function() {
733
+ if(!validateInput()) return;
734
+
735
+ // Update counters
736
+ const checkType = document.querySelector('input[name="check-type"]:checked').value;
737
+ scanCounters.total++;
738
+ scanCounters[checkType]++;
739
+ localStorage.setItem('scanCounters', JSON.stringify(scanCounters));
740
+ updateCounterDisplay();
741
+
742
+ // Show loading with persistent message, hide results
743
+ loadingDiv.style.display = 'block';
744
+ progressText.textContent = 'Waiting for the analysis report...';
745
+ resultsDiv.style.display = 'none';
746
+ scoreContainer.innerHTML = ''; // Clear previous scores
747
+ let data = { type: checkType };
748
+
749
+ if(checkType === 'hash') {
750
+ data.target = hashInput.value.trim();
751
+ } else {
752
+ data.target = targetInput.value.trim();
753
+ }
754
+
755
+ sendToWebhook(data);
756
+ });
757
+
758
+ function sendToWebhook(data) {
759
+ // Start timeout timer to show we're still waiting
760
+ const timeoutTimer = setTimeout(() => {
761
+ progressText.textContent = 'Still processing... this may take a moment';
762
+ }, 5000);
763
+
764
+ fetch('https://workflow.porifyx.com/webhook/150f8de3-d60c-4110-9ac8-22031a8cf6bb', {
765
+ method: 'POST',
766
+ headers: {
767
+ 'Content-Type': 'application/json'
768
+ },
769
+ body: JSON.stringify(data)
770
+ })
771
+ .then(response => {
772
+ clearTimeout(timeoutTimer);
773
+
774
+ if (!response.ok) {
775
+ return response.text().then(text => {
776
+ throw new Error(text || `HTTP error! status: ${response.status}`);
777
+ });
778
+ }
779
+ return response.text(); // Get response as text
780
+ })
781
+ .then(textResponse => {
782
+ // Hide loading, show results
783
+ loadingDiv.style.display = 'none';
784
+ resultsDiv.style.display = 'block';
785
+
786
+ // Display results
787
+ document.getElementById('result-target').textContent = data.target || 'N/A';
788
+ document.getElementById('result-type').textContent = data.type ? data.type.toUpperCase() : 'N/A';
789
+ document.getElementById('result-details').textContent = textResponse;
790
+ document.getElementById('result-date').textContent = new Date().toLocaleString();
791
+
792
+ // Parse and display scores - always show all indicators even if 0
793
+ const scores = parseScoresFromResponse(textResponse);
794
+ scoreContainer.innerHTML = '';
795
+
796
+ // Always show all score indicators
797
+ scoreContainer.appendChild(createScoreIndicator('malicious', scores.malicious));
798
+ scoreContainer.appendChild(createScoreIndicator('suspicious', scores.suspicious));
799
+ scoreContainer.appendChild(createScoreIndicator('harmless', scores.harmless));
800
+ scoreContainer.appendChild(createScoreIndicator('undetected', scores.undetected));
801
+
802
+ // Display the raw response for debugging
803
+ console.log('Webhook response:', textResponse);
804
+ })
805
+ .catch(error => {
806
+ clearTimeout(timeoutTimer);
807
+ console.error('Error:', error);
808
+ loadingDiv.style.display = 'none';
809
+ showModalError(error.message || 'An error occurred while scanning. Please try again.');
810
+ });
811
+ }
812
+
813
+ function updateCounterDisplay() {
814
+ document.getElementById('total-scans').textContent = scanCounters.total;
815
+ document.getElementById('url-scans').textContent = scanCounters.url;
816
+ document.getElementById('domain-scans').textContent = scanCounters.domain;
817
+ document.getElementById('ip-scans').textContent = scanCounters.ip;
818
+ document.getElementById('hash-scans').textContent = scanCounters.hash;
819
+ }
820
+ });
821
+ </script>
822
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Teep002/security-scanner" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
823
+ </html>