mirror of
https://github.com/CyberMind-FR/secubox-deb.git
synced 2026-07-01 11:47:31 +00:00
Compare commits
No commits in common. "febf58fd278eb1687ad23f6234f08e6815a878a2" and "66b608d760b30bafd245a5d08ffe3780dff2010e" have entirely different histories.
febf58fd27
...
66b608d760
|
|
@ -33,7 +33,5 @@
|
|||
"card_evidence_active": "Compliance analysis: trackers before consent (GDPR art. 6.1.a + 7) and extra-EU transfers (art. 44). See the PDF report for details.",
|
||||
"node_detail_cdn": "CDN / cache",
|
||||
"node_detail_antibot": "Anti-bot",
|
||||
"antibot_alert": "⚠ {n} site(s) challenged that you are human",
|
||||
"node_detail_opgrade": "Operator / state",
|
||||
"opgrade_alert": "⛔ {n} operator-grade / state-adjacent surface(s)"
|
||||
"antibot_alert": "⚠ {n} site(s) challenged that you are human"
|
||||
}
|
||||
|
|
@ -33,7 +33,5 @@
|
|||
"card_evidence_active": "Analyse de conformité : traqueurs avant consentement (RGPD art. 6.1.a + 7) et transferts hors UE (art. 44). Voir le rapport PDF pour le détail.",
|
||||
"node_detail_cdn": "CDN / cache",
|
||||
"node_detail_antibot": "Anti-bot",
|
||||
"antibot_alert": "⚠ {n} site(s) ont vérifié que vous êtes humain",
|
||||
"node_detail_opgrade": "Opérateur / état",
|
||||
"opgrade_alert": "⛔ {n} surface(s) opérateur-grade / proche-État"
|
||||
"antibot_alert": "⚠ {n} site(s) ont vérifié que vous êtes humain"
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
|
||||
<title>{{ t.page_title }} — VILLAGE3B</title>
|
||||
<link rel="stylesheet" href="/toolbox/social.css?v=26c">
|
||||
<link rel="stylesheet" href="/toolbox/social.css?v=264b">
|
||||
<script>
|
||||
// Inline JSON safer than a data-* attribute : FR text has
|
||||
// apostrophes (l'effacement) that would break single-quoted
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
window.__SOCIAL_I18N__ = {{ t_json | safe }};
|
||||
</script>
|
||||
<script defer src="/toolbox/d3.v7.min.js"></script>
|
||||
<script defer src="/toolbox/social.js?v=26c"></script>
|
||||
<script defer src="/toolbox/social.js?v=264b"></script>
|
||||
</head>
|
||||
<body data-token="{{ token }}" data-lang="{{ lang }}">
|
||||
|
||||
|
|
@ -34,7 +34,6 @@
|
|||
<div class="stat-tile"><span class="stat-n" data-bind="total_sites">0</span><span class="stat-l">{{ t.stats_total_sites }}</span></div>
|
||||
</section>
|
||||
<p class="graph-hint">{{ t.graph_swipe_hint }}</p>
|
||||
<div id="opgrade-alert" class="opgrade-alert" hidden></div>
|
||||
<div id="antibot-alert" class="antibot-alert" hidden></div>
|
||||
<svg id="social-graph" role="img" preserveAspectRatio="xMidYMid meet"></svg>
|
||||
</section>
|
||||
|
|
@ -53,8 +52,6 @@
|
|||
<dd data-bind="nd_cdn">—</dd>
|
||||
<dt>{{ t.node_detail_antibot }}</dt>
|
||||
<dd data-bind="nd_antibot">—</dd>
|
||||
<dt>{{ t.node_detail_opgrade }}</dt>
|
||||
<dd data-bind="nd_opgrade">—</dd>
|
||||
<dt>{{ t.node_detail_sites }}</dt>
|
||||
<dd data-bind="nd_sites">—</dd>
|
||||
<dt>{{ t.node_detail_first_seen }}</dt>
|
||||
|
|
|
|||
|
|
@ -1,29 +1,3 @@
|
|||
secubox-toolbox (2.6.7-1~bookworm1) bookworm; urgency=medium
|
||||
|
||||
* Phase 12.C (#518, parent #514) — operator-grade / state-adjacent
|
||||
identity detection (extends Utiq #500). Passive, top-severity tier.
|
||||
- social_graph.py detect_operator_grade(): telco header-enrichment
|
||||
(MSISDN / x-acr / WAP bearer), operator-consortium IDs (Utiq /
|
||||
TrustPid), and data-broker / state-adjacent analytics hosts
|
||||
(LiveRamp / Oracle-BlueKai / Acxiom / Neustar / Tapad / Experian
|
||||
/ Palantir-class). Returns (vendor, category) for severity tier.
|
||||
- social.py: social_host_meta.opgrade_vendor + opgrade_category;
|
||||
new social_opgrade per-client table; record_host_opgrade +
|
||||
record_opgrade_event + opgrade_for_client; fetch_graph carries
|
||||
it + stats; aggregate by_opgrade + opgrade_clients; wipe_mac
|
||||
clears social_opgrade.
|
||||
- social.js: top-tier void-purple lens (above anti-bot cinnabar)
|
||||
+ pulsing double ring + ⛔ "operator-grade / state-adjacent"
|
||||
banner; node-detail shows vendor + category.
|
||||
- index.html operator tab: opérateur-grade breakdown card.
|
||||
- social_report.py: operator-grade evidence section in the PDF.
|
||||
- i18n: node_detail_opgrade + opgrade_alert (FR/EN). Assets
|
||||
cache-busted ?v=26c.
|
||||
Detection only — no bypass. Factual network-surface flagging, no
|
||||
claim about any specific entity.
|
||||
|
||||
-- Gerald KERMA <devel@cybermind.fr> Wed, 10 Jun 2026 12:00:00 +0200
|
||||
|
||||
secubox-toolbox (2.6.6-1~bookworm1) bookworm; urgency=medium
|
||||
|
||||
* Phase 12.B follow-up (#516) — fix the Clients-tab 🕸️ Carto link
|
||||
|
|
|
|||
|
|
@ -382,59 +382,6 @@ def detect_antibot(flow) -> Optional[str]:
|
|||
return None
|
||||
|
||||
|
||||
# ─── operator-grade / state-adjacent identity detection (Phase 12.C #518) ──
|
||||
# The heaviest identity surfaces : carrier header-enrichment (the network
|
||||
# itself injects your phone number / subscriber id), operator-consortium
|
||||
# IDs (Utiq / TrustPid), and known data-broker / state-adjacent analytics
|
||||
# aggregation endpoints. We flag the network SURFACE factually — never a
|
||||
# claim about a specific entity. Returns (vendor, category) or (None, None).
|
||||
# category ∈ {telco-enrichment, consortium, data-broker} for severity tiering.
|
||||
_OPGRADE_HEADERS = ( # carrier-injected request headers
|
||||
("telco-enrichment", "MSISDN-header", (
|
||||
"x-msisdn", "x-up-calling-line-id", "x-nokia-msisdn", "x-wap-msisdn",
|
||||
"x-up-subno", "msisdn", "x-forwarded-for-msisdn", "x-network-info")),
|
||||
("telco-enrichment", "Verizon/AT&T-ACR", ("x-acr",)),
|
||||
("telco-enrichment", "WAP-bearer", ("x-up-bearer-type",)),
|
||||
("consortium", "TrustPid", ("x-trustpid",)),
|
||||
)
|
||||
_OPGRADE_HOSTS = ( # host eTLD+1 fragments
|
||||
("consortium", "Utiq", ("utiq.com", "consenthub.utiq")),
|
||||
("consortium", "TrustPid", ("trustpid.com", "trustpid")),
|
||||
("data-broker", "LiveRamp", ("rlcdn.com", "liveramp.com", "liveramp")),
|
||||
("data-broker", "Oracle-BlueKai", ("bluekai.com", "bkrtx.com")),
|
||||
("data-broker", "Acxiom", ("acxiom.com", "acxiom-online")),
|
||||
("data-broker", "Neustar", ("neustar.biz", "agkn.com")),
|
||||
("data-broker", "Tapad", ("tapad.com",)),
|
||||
("data-broker", "Experian", ("experian.com", "tapestry.experian")),
|
||||
("data-broker", "Palantir-class", ("palantir.com", "palantircloud", "foundry.palantir")),
|
||||
)
|
||||
|
||||
|
||||
def detect_operator_grade(flow) -> tuple:
|
||||
"""Return (vendor, category) for an operator-grade / state-adjacent
|
||||
identity surface, or (None, None). Passive ; factual.
|
||||
"""
|
||||
try:
|
||||
# 1) Carrier-injected request headers (the strongest signal —
|
||||
# the NETWORK enriched the request with subscriber identity).
|
||||
try:
|
||||
keys = " ".join(k.lower() for k in flow.request.headers.keys())
|
||||
except Exception:
|
||||
keys = ""
|
||||
for category, vendor, hdrs in _OPGRADE_HEADERS:
|
||||
if any(h in keys for h in hdrs):
|
||||
return vendor, category
|
||||
|
||||
# 2) Host-based : consortium IDs + data-broker / state-adjacent.
|
||||
host = (flow.request.host or "").lower()
|
||||
for category, vendor, frags in _OPGRADE_HOSTS:
|
||||
if any(f in host for f in frags):
|
||||
return vendor, category
|
||||
except Exception:
|
||||
pass
|
||||
return None, None
|
||||
|
||||
|
||||
# ─── JA4 lookup ───
|
||||
def _ja4_hash(flow) -> Optional[str]:
|
||||
"""Pull the JA4 fingerprint set by the ja4 addon, if present."""
|
||||
|
|
@ -502,18 +449,6 @@ class SocialGraph:
|
|||
client_mac_hash=mac_hash, src_site=src_site,
|
||||
antibot_vendor=antibot,
|
||||
)
|
||||
# Phase 12.C (#518) — operator-grade / state-adjacent identity.
|
||||
op_vendor, op_category = detect_operator_grade(flow)
|
||||
if op_vendor:
|
||||
if resp_host:
|
||||
_social.record_host_opgrade(
|
||||
domain=resp_host, opgrade_vendor=op_vendor,
|
||||
opgrade_category=op_category,
|
||||
)
|
||||
_social.record_opgrade_event(
|
||||
client_mac_hash=mac_hash, src_site=src_site,
|
||||
opgrade_vendor=op_vendor, category=op_category,
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
|
|
|||
|
|
@ -112,16 +112,13 @@ CREATE TABLE IF NOT EXISTS social_links (
|
|||
);
|
||||
|
||||
-- Phase 12.A (#515) — host-stable CDN/edge metadata, mac-independent.
|
||||
-- Phase 12.B (#516) adds antibot_vendor. Phase 12.C (#518) adds
|
||||
-- opgrade_vendor + opgrade_category (operator-grade / state-adjacent).
|
||||
-- Phase 12.B (#516) adds antibot_vendor (anti-bot / CAPTCHA vendor).
|
||||
CREATE TABLE IF NOT EXISTS social_host_meta (
|
||||
tracker_domain TEXT PRIMARY KEY,
|
||||
cdn_vendor TEXT,
|
||||
cache_status TEXT,
|
||||
antibot_vendor TEXT,
|
||||
opgrade_vendor TEXT,
|
||||
opgrade_category TEXT,
|
||||
last_seen INTEGER NOT NULL
|
||||
tracker_domain TEXT PRIMARY KEY,
|
||||
cdn_vendor TEXT,
|
||||
cache_status TEXT,
|
||||
antibot_vendor TEXT,
|
||||
last_seen INTEGER NOT NULL
|
||||
);
|
||||
|
||||
-- Phase 12.B (#516) — per-client "challenged your humanity" log.
|
||||
|
|
@ -133,17 +130,6 @@ CREATE TABLE IF NOT EXISTS social_antibot (
|
|||
last_seen INTEGER NOT NULL,
|
||||
PRIMARY KEY (client_mac_hash, src_site, antibot_vendor)
|
||||
);
|
||||
|
||||
-- Phase 12.C (#518) — per-client operator-grade / state-adjacent log.
|
||||
CREATE TABLE IF NOT EXISTS social_opgrade (
|
||||
client_mac_hash TEXT NOT NULL,
|
||||
src_site TEXT NOT NULL,
|
||||
opgrade_vendor TEXT NOT NULL,
|
||||
category TEXT NOT NULL,
|
||||
hits INTEGER NOT NULL DEFAULT 0,
|
||||
last_seen INTEGER NOT NULL,
|
||||
PRIMARY KEY (client_mac_hash, src_site, opgrade_vendor)
|
||||
);
|
||||
"""
|
||||
|
||||
|
||||
|
|
@ -170,9 +156,6 @@ _PHASE11C_MIGRATIONS = (
|
|||
# Phase 12.B (#516) — anti-bot vendor column on the host-meta table
|
||||
# (created by 12.A ; additive on a 2.6.3/2.6.4 → upgrade).
|
||||
("social_host_meta", "antibot_vendor", "TEXT"),
|
||||
# Phase 12.C (#518) — operator-grade / state-adjacent columns.
|
||||
("social_host_meta", "opgrade_vendor", "TEXT"),
|
||||
("social_host_meta", "opgrade_category", "TEXT"),
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -429,83 +412,6 @@ def antibot_for_client(mac_hash: str, since_seconds: int = 86400) -> List[Dict]:
|
|||
return out
|
||||
|
||||
|
||||
# ── Phase 12.C (#518) — operator-grade / state-adjacent recording ──
|
||||
|
||||
def _record_host_opgrade_sync(domain, vendor, category) -> None:
|
||||
try:
|
||||
with _conn() as c:
|
||||
c.execute(
|
||||
"INSERT INTO social_host_meta(tracker_domain, opgrade_vendor, "
|
||||
"opgrade_category, last_seen) VALUES (?, ?, ?, ?) "
|
||||
"ON CONFLICT(tracker_domain) DO UPDATE SET "
|
||||
"opgrade_vendor=excluded.opgrade_vendor, "
|
||||
"opgrade_category=excluded.opgrade_category, "
|
||||
"last_seen=excluded.last_seen",
|
||||
(domain, vendor, category, int(time.time())),
|
||||
)
|
||||
except Exception as e: # pragma: no cover
|
||||
log.warning("record_host_opgrade failed: %s", e)
|
||||
|
||||
|
||||
def record_host_opgrade(*, domain: str, opgrade_vendor: str,
|
||||
opgrade_category: Optional[str] = None) -> None:
|
||||
if not (domain and opgrade_vendor):
|
||||
return
|
||||
try:
|
||||
_executor.submit(_record_host_opgrade_sync, domain, opgrade_vendor,
|
||||
opgrade_category)
|
||||
except RuntimeError:
|
||||
pass
|
||||
|
||||
|
||||
def _record_opgrade_event_sync(mac_hash, src_site, vendor, category) -> None:
|
||||
try:
|
||||
with _conn() as c:
|
||||
c.execute(
|
||||
"INSERT INTO social_opgrade(client_mac_hash, src_site, "
|
||||
"opgrade_vendor, category, hits, last_seen) "
|
||||
"VALUES (?, ?, ?, ?, 1, ?) "
|
||||
"ON CONFLICT(client_mac_hash, src_site, opgrade_vendor) DO UPDATE "
|
||||
"SET hits = hits + 1, category = excluded.category, "
|
||||
"last_seen = excluded.last_seen",
|
||||
(mac_hash, src_site, vendor, category, int(time.time())),
|
||||
)
|
||||
except Exception as e: # pragma: no cover
|
||||
log.warning("record_opgrade_event failed: %s", e)
|
||||
|
||||
|
||||
def record_opgrade_event(*, client_mac_hash: str, src_site: str,
|
||||
opgrade_vendor: str, category: str) -> None:
|
||||
if not (client_mac_hash and src_site and opgrade_vendor):
|
||||
return
|
||||
try:
|
||||
_executor.submit(_record_opgrade_event_sync, client_mac_hash,
|
||||
src_site, opgrade_vendor, category or "")
|
||||
except RuntimeError:
|
||||
pass
|
||||
|
||||
|
||||
def opgrade_for_client(mac_hash: str, since_seconds: int = 86400) -> List[Dict]:
|
||||
"""Per-client operator-grade / state-adjacent list for the alert tile
|
||||
+ the PDF evidence section."""
|
||||
since = int(time.time()) - max(since_seconds, 3600)
|
||||
out: List[Dict] = []
|
||||
if not mac_hash:
|
||||
return out
|
||||
try:
|
||||
with _conn() as c:
|
||||
for r in c.execute(
|
||||
"SELECT src_site, opgrade_vendor, category, hits, last_seen "
|
||||
"FROM social_opgrade WHERE client_mac_hash = ? AND last_seen >= ? "
|
||||
"ORDER BY last_seen DESC LIMIT 100",
|
||||
(mac_hash, since),
|
||||
).fetchall():
|
||||
out.append(dict(r))
|
||||
except Exception as e: # pragma: no cover
|
||||
log.warning("opgrade_for_client failed: %s", e)
|
||||
return out
|
||||
|
||||
|
||||
def fold_recent(window_seconds: int = 300) -> Tuple[int, int]:
|
||||
"""Fold raw edges from the last `window_seconds` into the node + link
|
||||
aggregate tables. Returns (nodes_touched, links_touched).
|
||||
|
|
@ -700,8 +606,7 @@ def fetch_graph(mac_hash: str, since_seconds: int = 86400) -> Dict:
|
|||
# can colour/label by edge-network vendor.
|
||||
for r in c.execute(
|
||||
"SELECT n.tracker_domain, n.hits, n.first_seen, n.last_seen, "
|
||||
"n.sites_jsonl, m.cdn_vendor, m.cache_status, m.antibot_vendor, "
|
||||
"m.opgrade_vendor, m.opgrade_category "
|
||||
"n.sites_jsonl, m.cdn_vendor, m.cache_status, m.antibot_vendor "
|
||||
"FROM social_nodes n "
|
||||
"LEFT JOIN social_host_meta m ON m.tracker_domain = n.tracker_domain "
|
||||
"WHERE n.client_mac_hash = ? AND n.last_seen >= ? "
|
||||
|
|
@ -724,8 +629,6 @@ def fetch_graph(mac_hash: str, since_seconds: int = 86400) -> Dict:
|
|||
"cdn_vendor": r["cdn_vendor"],
|
||||
"cache_status": r["cache_status"],
|
||||
"antibot_vendor": r["antibot_vendor"],
|
||||
"opgrade_vendor": r["opgrade_vendor"],
|
||||
"opgrade_category": r["opgrade_category"],
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -767,9 +670,6 @@ def fetch_graph(mac_hash: str, since_seconds: int = 86400) -> Dict:
|
|||
# Phase 12.B — per-client anti-bot challenges for the alert tile.
|
||||
antibot = antibot_for_client(mac_hash, since_seconds=since_seconds)
|
||||
out["antibot"] = antibot
|
||||
# Phase 12.C — operator-grade / state-adjacent surfaces.
|
||||
opgrade = opgrade_for_client(mac_hash, since_seconds=since_seconds)
|
||||
out["opgrade"] = opgrade
|
||||
out["stats"] = {
|
||||
"total_trackers": (stats_row["total_trackers"] or 0) if stats_row else 0,
|
||||
"total_sites": sites_count,
|
||||
|
|
@ -777,8 +677,6 @@ def fetch_graph(mac_hash: str, since_seconds: int = 86400) -> Dict:
|
|||
"last_seen": stats_row["last_seen"] if stats_row else None,
|
||||
"antibot_sites": len({a["src_site"] for a in antibot}),
|
||||
"antibot_vendors": sorted({a["antibot_vendor"] for a in antibot}),
|
||||
"opgrade_sites": len({o["src_site"] for o in opgrade}),
|
||||
"opgrade_vendors": sorted({o["opgrade_vendor"] for o in opgrade}),
|
||||
}
|
||||
except Exception as e: # pragma: no cover
|
||||
log.warning("fetch_graph failed: %s", e)
|
||||
|
|
@ -796,7 +694,7 @@ def wipe_mac(mac_hash: str) -> int:
|
|||
try:
|
||||
with _conn() as c:
|
||||
for table in ("social_edges", "social_nodes", "social_links",
|
||||
"social_antibot", "social_opgrade"):
|
||||
"social_antibot"):
|
||||
cur = c.execute(
|
||||
f"DELETE FROM {table} WHERE client_mac_hash = ?", (mac_hash,)
|
||||
)
|
||||
|
|
@ -823,8 +721,6 @@ def aggregate(hours: int = 24) -> Dict:
|
|||
"by_cdn": [], # Phase 12.A
|
||||
"by_antibot": [], # Phase 12.B
|
||||
"antibot_clients": 0, # Phase 12.B
|
||||
"by_opgrade": [], # Phase 12.C
|
||||
"opgrade_clients": 0, # Phase 12.C
|
||||
}
|
||||
try:
|
||||
with _conn() as c:
|
||||
|
|
@ -891,24 +787,6 @@ def aggregate(hours: int = 24) -> Dict:
|
|||
"WHERE last_seen >= ?",
|
||||
(since,),
|
||||
).fetchone()[0]
|
||||
# Phase 12.C — operator-grade / state-adjacent breakdown.
|
||||
out["by_opgrade"] = [
|
||||
dict(r)
|
||||
for r in c.execute(
|
||||
"SELECT opgrade_vendor, category, "
|
||||
"COUNT(DISTINCT src_site) AS sites, "
|
||||
"COUNT(DISTINCT client_mac_hash) AS clients, "
|
||||
"SUM(hits) AS events "
|
||||
"FROM social_opgrade WHERE last_seen >= ? "
|
||||
"GROUP BY opgrade_vendor ORDER BY events DESC LIMIT 25",
|
||||
(since,),
|
||||
).fetchall()
|
||||
]
|
||||
out["opgrade_clients"] = c.execute(
|
||||
"SELECT COUNT(DISTINCT client_mac_hash) FROM social_opgrade "
|
||||
"WHERE last_seen >= ?",
|
||||
(since,),
|
||||
).fetchone()[0]
|
||||
except Exception as e: # pragma: no cover
|
||||
log.warning("aggregate failed: %s", e)
|
||||
return out
|
||||
|
|
|
|||
|
|
@ -49,28 +49,15 @@ _L = {
|
|||
"Nous rapportons le fait observé, pas l'absence de garanties (SCC).",
|
||||
"Legal basis: GDPR art. 44+ (international transfers). We report the "
|
||||
"observed fact, not the absence of safeguards (SCC)."),
|
||||
"ev_opgrade": ("Évidence : surfaces opérateur-grade / proche-État",
|
||||
"Evidence: operator-grade / state-adjacent surfaces"),
|
||||
"ev_opgrade_basis": ("Enrichissement réseau (MSISDN/ACR), identifiants de "
|
||||
"consortium opérateur, et courtiers de données / analytics "
|
||||
"proches-État. Fait réseau observé, sans qualification d'entité.",
|
||||
"Network enrichment (MSISDN/ACR), operator-consortium IDs, and "
|
||||
"data-broker / state-adjacent analytics. Observed network fact, "
|
||||
"no entity qualification."),
|
||||
"col_tracker": ("Traqueur", "Tracker"),
|
||||
"col_sites": ("Sites", "Sites"),
|
||||
"col_hits": ("Occurrences", "Hits"),
|
||||
"col_country": ("Pays", "Country"),
|
||||
"col_asn": ("Hébergeur (ASN)", "Host (ASN)"),
|
||||
"col_opvendor": ("Surface", "Surface"),
|
||||
"col_opcat": ("Catégorie", "Category"),
|
||||
"col_site": ("Site", "Site"),
|
||||
"none_pre": ("Aucun traqueur déclenché avant consentement détecté.",
|
||||
"No tracker fired before consent detected."),
|
||||
"none_eu": ("Aucun transfert hors UE/EEE détecté.",
|
||||
"No extra-EU/EEA transfer detected."),
|
||||
"none_op": ("Aucune surface opérateur-grade / proche-État détectée.",
|
||||
"No operator-grade / state-adjacent surface detected."),
|
||||
"footer": ("Rapport factuel — données calculées localement, aucune donnée externe. "
|
||||
"Anonyme : aucune valeur de cookie brute conservée. Droit à l'effacement : RGPD art. 17.",
|
||||
"Factual report — computed locally, no external data. Anonymous: no raw cookie "
|
||||
|
|
@ -100,8 +87,6 @@ def build_social_report(mac_hash: str, since_seconds: int = 7 * 86400) -> Dict:
|
|||
"total_sites": stats.get("total_sites", 0),
|
||||
"pre_consent": evidence.get("pre_consent", []),
|
||||
"extra_eu": evidence.get("extra_eu", []),
|
||||
# Phase 12.C — operator-grade / state-adjacent surfaces.
|
||||
"opgrade": _social.opgrade_for_client(mac_hash, since_seconds=since_seconds),
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -196,21 +181,6 @@ def render_social_pdf(report: Dict) -> bytes:
|
|||
])
|
||||
else:
|
||||
_note(pdf, family, _bi("none_eu"))
|
||||
pdf.ln(3)
|
||||
|
||||
# ── Evidence : operator-grade / state-adjacent (Phase 12.C) ──
|
||||
bi("ev_opgrade", 12, "B", 110, 64, 201, gap=0.3)
|
||||
bi("ev_opgrade_basis", 8, "", 120, 120, 120, gap=1)
|
||||
op = report.get("opgrade", [])
|
||||
if op:
|
||||
_table(pdf, family, op, [
|
||||
(_bi("col_opvendor"), "opgrade_vendor", 45),
|
||||
(_bi("col_opcat"), "category", 40),
|
||||
(_bi("col_site"), "src_site", 55),
|
||||
(_bi("col_hits"), "hits", 25),
|
||||
])
|
||||
else:
|
||||
_note(pdf, family, _bi("none_op"))
|
||||
pdf.ln(4)
|
||||
|
||||
# ── Footer ──
|
||||
|
|
|
|||
|
|
@ -144,10 +144,6 @@
|
|||
<h2>🤖 Anti-bot / "prouvez que vous êtes humain"</h2>
|
||||
<div id="social-antibot"><div class="empty">loading…</div></div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>📡 Opérateur-grade / proche-État</h2>
|
||||
<div id="social-opgrade"><div class="empty">loading…</div></div>
|
||||
</div>
|
||||
<div class="card" style="grid-column:1/-1">
|
||||
<h2>🎯 Top tracker domains</h2>
|
||||
<div id="social-trackers"><div class="empty">loading…</div></div>
|
||||
|
|
@ -409,16 +405,6 @@ async function loadSocial() {
|
|||
'</tbody></table>'
|
||||
: '<div class="empty">aucun anti-bot détecté</div>';
|
||||
}
|
||||
const og = document.getElementById('social-opgrade');
|
||||
if (og) {
|
||||
const bo = agg.by_opgrade || [];
|
||||
og.innerHTML = bo.length
|
||||
? `<p style="font-size:0.8rem;color:var(--p31-dim);margin-bottom:0.5rem">${agg.opgrade_clients||0} client(s) exposé(s)</p>` +
|
||||
'<table><thead><tr><th>Vendor</th><th>catégorie</th><th>sites</th><th>clients</th><th>events</th></tr></thead><tbody>' +
|
||||
bo.map(r => `<tr><td>📡 ${r.opgrade_vendor}</td><td>${r.category}</td><td>${r.sites}</td><td>${r.clients}</td><td>${r.events}</td></tr>`).join('') +
|
||||
'</tbody></table>'
|
||||
: '<div class="empty">aucune surface opérateur-grade détectée</div>';
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshAll() {
|
||||
|
|
|
|||
|
|
@ -327,27 +327,3 @@ 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; }
|
||||
|
|
|
|||
|
|
@ -58,16 +58,6 @@
|
|||
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;
|
||||
|
||||
|
|
@ -93,7 +83,6 @@
|
|||
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.
|
||||
|
|
@ -133,8 +122,6 @@
|
|||
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,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -227,10 +214,7 @@
|
|||
function nodeColor(d) {
|
||||
if (d.kind === 'eye') return 'var(--cinnabar)';
|
||||
if (d.kind === 'site') return 'var(--gold-hermetic)';
|
||||
// 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.
|
||||
// Phase 12.B — anti-bot hosts get the highest-severity lens.
|
||||
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)';
|
||||
|
|
@ -247,10 +231,6 @@
|
|||
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)
|
||||
|
|
@ -347,7 +327,6 @@
|
|||
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', ' ') : '—');
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user