"""Stateless re-verification: given a CV (that someone else produced), re-check every 'verified' account by re-fetching its source and re-checking its proof. Nothing is trusted but the source platforms themselves. """ from __future__ import annotations from .model import CV, VERIFIED from .util import get_json, dig def verify_cv(cv: CV, *, getter=None, proof_fetcher=None): """Return a list of per-account results: {platform, handle, claimed_karma, status, notes} status: 'verified' | 'FAILED' | 'unverified-claim' """ results = [] for a in cv.accounts: r = {"platform": a.platform, "handle": a.handle, "claimed_karma": a.karma, "notes": []} if not a.is_verified(): r["status"] = "unverified-claim" results.append(r) continue ok = True # 1) re-fetch karma from the recorded source and compare if not a.source or not a.karma_path: ok = False r["notes"].append("marked verified but missing source/karma_path") else: try: data = get_json(a.source, getter=getter) if getter else get_json(a.source) live = dig(data, a.karma_path) if live != a.karma: ok = False r["notes"].append(f"karma mismatch: cv={a.karma} live={live}") except Exception as e: ok = False r["notes"].append(f"source unreachable: {e}") # 2) re-check the ownership proof, if any if a.proof: if proof_fetcher is None: r["notes"].append("proof present but no proof_fetcher supplied — not re-checked") else: from .proof import verify_link text, author = proof_fetcher(a.proof.get("url")) if not verify_link(a.proof.get("nonce"), a.handle, text, author): ok = False r["notes"].append("link-proof failed") r["status"] = "verified" if ok else "FAILED" results.append(r) return results def all_verified(results) -> bool: return all(r["status"] != "FAILED" for r in results)