#!/usr/bin/env python3 """Silent attended decryption of the hash-verified primary archive download.""" import argparse from datetime import datetime, timezone import hashlib import json import os from pathlib import Path import subprocess from state_hub_preflight_lane import bao, data def digest(path): with path.open('rb') as source: return hashlib.file_digest(source,'sha256').hexdigest() def main(): p=argparse.ArgumentParser(description=__doc__) for name in ['source','output','transfer-receipt','receipt']: p.add_argument('--'+name,required=True,type=Path) a=p.parse_args();receipt={'schema':'platform.forgejo-primary-decryption.v1','status':'failed','started_at':datetime.now(timezone.utc).isoformat()} fd=os.open(a.receipt,os.O_WRONLY|os.O_CREAT|os.O_EXCL,0o600) try: raw=a.transfer_receipt.read_bytes() transfer=json.loads(raw) receipt['transfer_receipt_sha256']=hashlib.sha256(raw).hexdigest() if (transfer.get('schema')!='platform.forgejo-primary-archive.v1' or transfer.get('status')!='primary_fetched_pending_application_restore' or transfer.get('download_hash_matches') is not True or digest(a.source)!=transfer.get('ciphertext_sha256')): raise ValueError('verified_primary_download_required') value=data(bao(['read','-format=json','platform/data/workloads/railiance/backup/offsite-lane']))['data']['data']['AGE_PRIVATE_KEY'] with a.output.open('xb') as target: a.output.chmod(0o600) result=subprocess.run(['age','-d','-i','/dev/stdin',str(a.source)],input=(value.strip()+'\n').encode(),stdout=target,stderr=subprocess.PIPE,timeout=1200) if result.returncode: raise ValueError('primary_decryption_failed') # Preserve this operation's schema and times, not the transfer's. for key in ('destination','ciphertext_sha256','ciphertext_bytes','download_hash_matches','archive_profile'): if key in transfer: receipt[key]=transfer[key] receipt.update(status='primary_fetched_pending_application_restore', decrypted=True,plaintext_sha256=digest(a.output)) except Exception: receipt['error']='bounded_primary_decryption_failed' finally: receipt['finished_at']=datetime.now(timezone.utc).isoformat() with os.fdopen(fd,'w') as output: json.dump(receipt,output,indent=2) return int(receipt['status']=='failed') if __name__=='__main__': raise SystemExit(main())