🎯 Top tracker domains
@@ -405,6 +409,16 @@ async function loadSocial() {
''
: '
aucun anti-bot détecté
';
}
+ const og = document.getElementById('social-opgrade');
+ if (og) {
+ const bo = agg.by_opgrade || [];
+ og.innerHTML = bo.length
+ ? `
${agg.opgrade_clients||0} client(s) exposé(s)
` +
+ '
| Vendor | catégorie | sites | clients | events |
' +
+ bo.map(r => `| 📡 ${r.opgrade_vendor} | ${r.category} | ${r.sites} | ${r.clients} | ${r.events} |
`).join('') +
+ '
'
+ : '
aucune surface opérateur-grade détectée
';
+ }
}
async function refreshAll() {
diff --git a/packages/secubox-toolbox/www/toolbox/social.css b/packages/secubox-toolbox/www/toolbox/social.css
index 05d94add..f42c4c25 100644
--- a/packages/secubox-toolbox/www/toolbox/social.css
+++ b/packages/secubox-toolbox/www/toolbox/social.css
@@ -327,3 +327,27 @@ dialog h2 {
.ring-guides circle { fill: none; stroke-width: 1; pointer-events: none; }
.ring-inner { stroke: var(--gold-hermetic); stroke-opacity: .18; stroke-dasharray: 2 4; }
.ring-outer { stroke: var(--cyber-cyan); stroke-opacity: .14; stroke-dasharray: 2 6; }
+
+/* ── Operator-grade / state-adjacent (Phase 12.C) — top severity ── */
+.opgrade-ring {
+ fill: none;
+ stroke: var(--void-purple);
+ stroke-width: 2;
+ opacity: .9;
+ animation: opgrade-pulse 1.8s ease-in-out infinite;
+ transform-origin: center;
+ transform-box: fill-box;
+}
+@keyframes opgrade-pulse { 0%,100% { r: 13px; opacity: .5; } 50% { r: 17px; opacity: 1; } }
+.opgrade-alert {
+ position: absolute; top: 8px; left: 50%; transform: translateX(-50%);
+ z-index: 7;
+ background: var(--void-purple);
+ color: #fff;
+ font-family: 'JetBrains Mono', monospace;
+ font-size: 11px; font-weight: bold;
+ padding: 5px 12px; border-radius: 3px;
+ max-width: 90%; text-align: center;
+ box-shadow: 0 2px 12px rgba(110,64,201,.5);
+}
+.opgrade-alert + .antibot-alert { top: 38px; }
diff --git a/packages/secubox-toolbox/www/toolbox/social.js b/packages/secubox-toolbox/www/toolbox/social.js
index 42846602..95932273 100644
--- a/packages/secubox-toolbox/www/toolbox/social.js
+++ b/packages/secubox-toolbox/www/toolbox/social.js
@@ -58,6 +58,16 @@
el.hidden = false;
}
+ // Phase 12.C — top-severity operator-grade / state-adjacent banner.
+ function updateOpgradeTile(sites, vendors) {
+ const el = document.getElementById('opgrade-alert');
+ if (!el) return;
+ if (!sites) { el.hidden = true; return; }
+ const v = (vendors || []).join(', ');
+ el.textContent = t('opgrade_alert', { n: sites }) + (v ? ' — ' + v : '');
+ el.hidden = false;
+ }
+
// ─── graph state ───
let simulation = null;
@@ -83,6 +93,7 @@
bind('total_sites', graph.stats.total_sites || 0);
// Phase 12.B — "challenged your humanity" alert tile.
updateAntibotTile(graph.stats.antibot_sites || 0, graph.stats.antibot_vendors || []);
+ updateOpgradeTile(graph.stats.opgrade_sites || 0, graph.stats.opgrade_vendors || []);
// Empty graph → just return ; the stats tiles already show 0/0 and
// the user knows. No persistent overlay message.
@@ -122,6 +133,8 @@
cdn_vendor: n.cdn_vendor || null,
cache_status: n.cache_status || null,
antibot_vendor: n.antibot_vendor || null,
+ opgrade_vendor: n.opgrade_vendor || null,
+ opgrade_category: n.opgrade_category || null,
});
}
@@ -214,7 +227,10 @@
function nodeColor(d) {
if (d.kind === 'eye') return 'var(--cinnabar)';
if (d.kind === 'site') return 'var(--gold-hermetic)';
- // Phase 12.B — anti-bot hosts get the highest-severity lens.
+ // Severity tiers (highest first):
+ // 12.C operator-grade / state-adjacent = void-purple (top).
+ if (d.opgrade_vendor) return 'var(--void-purple)';
+ // 12.B anti-bot = cinnabar.
if (d.antibot_vendor) return 'var(--cinnabar)';
if (d.cdn_vendor && CDN_COLORS[d.cdn_vendor]) return CDN_COLORS[d.cdn_vendor];
return 'var(--cyber-cyan)';
@@ -231,6 +247,10 @@
nodeG.filter(d => d.kind === 'tracker' && d.antibot_vendor)
.append('circle').attr('class', 'antibot-ring').attr('r', 12);
+ // Phase 12.C — operator-grade hosts get the top-tier double ring.
+ nodeG.filter(d => d.kind === 'tracker' && d.opgrade_vendor)
+ .append('circle').attr('class', 'opgrade-ring').attr('r', 14);
+
// Site + tracker nodes.
nodeG.filter(d => d.kind !== 'eye').append('circle')
.attr('r', d => d.kind === 'tracker' ? 7 : 10)
@@ -327,6 +347,7 @@
bind('nd_asn', '—');
bind('nd_cdn', node.cdn_vendor ? (node.cdn_vendor + (node.cache_status ? ' · ' + node.cache_status : '')) : '—');
bind('nd_antibot', node.antibot_vendor ? ('🤖 ' + node.antibot_vendor) : '—');
+ bind('nd_opgrade', node.opgrade_vendor ? ('📡 ' + node.opgrade_vendor + (node.opgrade_category ? ' (' + node.opgrade_category + ')' : '')) : '—');
bind('nd_sites', (node.sites || []).join(', ') || '—');
bind('nd_first_seen', node.first_seen ? new Date(node.first_seen * 1000).toISOString().slice(0, 16).replace('T', ' ') : '—');
bind('nd_last_seen', node.last_seen ? new Date(node.last_seen * 1000).toISOString().slice(0, 16).replace('T', ' ') : '—');