#!/usr/bin/env python3 """§4.3, último punto del plan: contrastar páginas capturadas contra Internet Archive. No compara el texto (una instantánea de hace años difiere por fuerza: fechas, barras laterales, bloques rotativos). Compara lo que de verdad delata una inyección: **el conjunto de hosts externos a los que la página carga scripts o iframes**. Si nuestra captura referencia hosts que la versión histórica no tenía, hay que mirarlo. """ import os, re, json, sys, urllib.request, random from collections import Counter from urllib.parse import urlsplit, unquote BASE = "/home/rafa/joomla-migration/mirror-antiguo" RUN = open(os.path.join(BASE, "CURRENT_RUN")).read().strip() DIR = os.path.join(BASE, "runs", RUN) SITE = os.path.join(DIR, "site", "antiguo.feadulta.com") N = int(sys.argv[1]) if len(sys.argv) > 1 else 10 SRC = re.compile(r'<(?:script|iframe)[^>]+src=["\']((?:https?:)?//[^"\'/]+)', re.I) UA = {"User-Agent": "feadulta-archiver/1.0 (verificacion de integridad; incident-183)"} def hosts(html): out = set() for m in SRC.findall(html): h = m.split("//", 1)[-1].lower() # web.archive.org reescribe los recursos: nos quedamos con el host original if h.startswith("web.archive.org"): continue out.add(h) return out # candidatas: URLs /es/ que Wayback conoce Y que tenemos capturadas cand = [] for fn in ("wayback-antiguo.txt", "wayback-feadulta.txt"): for line in open(os.path.join(BASE, "inventory", fn), errors="replace"): u = line.strip() s = urlsplit(u) if s.query or not s.path.startswith("/es/") or not s.path.endswith(".html"): continue p = unquote(s.path).lstrip("/") if os.path.isfile(os.path.join(SITE, p)): cand.append((u, p)) random.seed(20260730) sample = random.sample(cand, min(N, len(cand))) print("candidatas:", len(cand), "- muestra:", len(sample), "\n") res, extra_total = [], Counter() for url, rel in sample: local = open(os.path.join(SITE, rel), encoding="utf-8", errors="replace").read() hl = hosts(local) try: req = urllib.request.Request("https://web.archive.org/web/2id_/" + url, headers=UA) arch = urllib.request.urlopen(req, timeout=90).read().decode("utf-8", "replace") ha = hosts(arch) estado = "ok" except Exception as e: ha, estado = set(), "sin snapshot (%s)" % type(e).__name__ extra = hl - ha if estado == "ok": for h in extra: extra_total[h] += 1 print("%-70s %s" % (rel[-68:], estado)) if estado == "ok" and extra: print(" hosts solo en nuestra captura:", ", ".join(sorted(extra))) res.append({"url": url, "estado": estado, "hosts_mirror": sorted(hl), "hosts_wayback": sorted(ha), "solo_en_mirror": sorted(extra)}) print("\n--- hosts presentes solo en nuestra captura (agregado) ---") if extra_total: for h, c in extra_total.most_common(): print("%4d %s" % (c, h)) else: print("ninguno") json.dump(res, open(os.path.join(DIR, "wayback-contraste.json"), "w"), indent=2, ensure_ascii=False) print("\ninforme:", os.path.join(DIR, "wayback-contraste.json"))