-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmalware.html
More file actions
107 lines (97 loc) · 3.65 KB
/
Copy pathmalware.html
File metadata and controls
107 lines (97 loc) · 3.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
---
layout: default
title: Malware Database
---
<div class="malware-index">
<section class="hero">
<h1>🦠 Malware Database</h1>
<p class="hero-subtitle">A cross-reference database of malware and tools used by threat actors. Track which actors use which malware and discover related threats.</p>
<div class="quick-stats">
<div class="stat">
<span class="stat-number" id="malware-count">-</span>
<span class="stat-label">Malware Families</span>
</div>
</div>
</section>
<!-- Filters -->
<section class="quick-filters">
<h2>Quick Filters</h2>
<div class="filter-chips">
<div class="filter-group">
<label>Search:</label>
<input type="text" id="malware-search" placeholder="Search malware...">
</div>
<button id="apply-filters-btn">Search</button>
<button id="clear-filters-btn" class="secondary">Clear</button>
</div>
</section>
<!-- Malware List -->
<section class="malware-section">
<p id="malware-api-error" class="api-load-error" hidden role="alert"></p>
<div class="malware-grid" id="malware-grid">
<!-- Populated via JS -->
</div>
</section>
</div>
<script>
// Load malware index from generated data (canonical URL: /api/malware-index.json)
var API_MALWARE_INDEX = '{{ "/api/malware-index.json" | relative_url }}';
var API_FACETS = '{{ "/api/facets.json" | relative_url }}';
Promise.all([
fetch(API_MALWARE_INDEX).then(function (r) {
if (!r.ok) throw new Error('Malware index HTTP ' + r.status);
return r.json();
}),
fetch(API_FACETS).then(function (r) {
if (!r.ok) throw new Error('Facets HTTP ' + r.status);
return r.json();
})
]).then(function (results) {
var data = results[0];
var malware = data.malware || [];
document.getElementById('malware-count').textContent = malware.length;
renderMalware(malware);
setupFilters(malware);
}).catch(function (err) {
var el = document.getElementById('malware-api-error');
if (el) {
el.hidden = false;
el.textContent = 'Could not load malware data from the API. Try refreshing the page or run ruby scripts/generate-indexes.rb if you are developing locally. (' + (err && err.message ? err.message : 'error') + ')';
}
document.getElementById('malware-count').textContent = '?';
});
function renderMalware(list) {
const grid = document.getElementById('malware-grid');
grid.innerHTML = list.map(m => `
<div class="malware-card">
<h3><a href="${m.url}">${esc(m.name)}</a></h3>
<div class="card-meta">
${m.category ? `<span class="category">${esc(m.category)}</span>` : ''}
</div>
<p class="card-desc">Used by <strong>${m.actor_count}</strong> threat actor${m.actor_count !== 1 ? 's' : ''}</p>
<a href="${m.url}" class="card-link">View details →</a>
</div>
`).join('');
}
function setupFilters(list) {
document.getElementById('apply-filters-btn').onclick = () => {
const term = document.getElementById('malware-search').value.toLowerCase();
const filtered = list.filter(m =>
!term || m.name.toLowerCase().includes(term)
);
renderMalware(filtered);
};
document.getElementById('clear-filters-btn').onclick = () => {
document.getElementById('malware-search').value = '';
renderMalware(list);
};
document.getElementById('malware-search').addEventListener('keypress', e => {
if (e.key === 'Enter') {
document.getElementById('apply-filters-btn').click();
}
});
}
function esc(s) {
return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
}
</script>