#!/usr/bin/env python3 """Validate reviewed public recovery metadata before requesting custody input. Never opens TLS material, archive plaintext or any key. This validates bindings, not owner assent, archive contents or recovery authority. """ import argparse import hashlib import importlib.util import json import os from pathlib import Path import re import stat from urllib.parse import urlsplit ROOT=Path(__file__).resolve().parents[2] # The executable closure extends the synthetic fixture closure with the attended # custody entry point and this validator. Tests and historical receipts do not run. SOURCE_PATHS=tuple(sorted([ 'sso-mfa/bootstrap/sops-custody-unlock.sh','sso-mfa/bootstrap/sops-private.py','sso-mfa/bootstrap/sops-custody-fd.py', 'sso-mfa/k8s/privacyidea/key-custody-remote.py', *('tools/bootstrap-recovery/'+name for name in ( 'isolated-keycape.py','isolated-keycape-session.py','run-isolated-keycape.sh', 'prepare-isolated-keycape.py','isolated-lldap.py','identity-bundle.py', 'identity-backup-profile.json','retrieve-identity-offline.py','identity-offsite.py', 'verify-identity.py','identity-custody.json','identity-files.py', 'check-privacyidea-database.py'))])) class Refused(Exception):pass def require(value): if not value:raise Refused() def metadata_path(path): path=Path(os.path.abspath(path)) require(not any(p.is_symlink() for p in (path,*path.parents))) st=path.stat() require(stat.S_ISREG(st.st_mode) and st.st_uid==os.getuid() and st.st_nlink==1 and not st.st_mode&0o077) return path def read_metadata(path,limit=128*1024): path=metadata_path(path) require(0