58 lines
2.1 KiB
Python
58 lines
2.1 KiB
Python
"""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)
|