#!/usr/bin/env python3 """Download one reviewed ciphertext using privately entered provider access. No OpenBao, SSO, Kubernetes, credential discovery, provider writes or age key. Run by the operator in their own terminal, never through a recorded agent PTY. """ import argparse import base64 from datetime import datetime, timezone import getpass import hashlib import importlib.util import json import os from pathlib import Path import re import shutil import signal import sys import tempfile import urllib.request import urllib.error import warnings HERE = Path(__file__).resolve().parent spec = importlib.util.spec_from_file_location('offsite', HERE / 'identity-offsite.py') offsite = importlib.util.module_from_spec(spec) spec.loader.exec_module(offsite) ACCOUNT_BASE = offsite.HOST + '/remote.php/dav/files/Backup/railiance-backups/net-kingdom-identity/' def private_prompt(label): # getpass opens the terminal with os.open, which does not require seeking. # Reject redirected input and turn its echoing fallback warning into an # exception before it can read a credential without echo suppression. if not sys.stdin.isatty() or not sys.stderr.isatty(): raise offsite.Refused() with warnings.catch_warnings(): warnings.simplefilter('error', getpass.GetPassWarning) return getpass.getpass(label) def failure_metadata(error): # No exception messages, response bodies, URLs or headers enter receipts. if isinstance(error, urllib.error.HTTPError): return {'failure_kind': 'provider_http_error', 'http_status': int(error.code)} if isinstance(error, urllib.error.URLError): return {'failure_kind': 'provider_transport_error'} if isinstance(error, getpass.GetPassWarning): return {'failure_kind': 'terminal_echo_suppression_unavailable'} if isinstance(error, offsite.Refused): return {'failure_kind': 'scope_or_integrity_refusal'} return {'failure_kind': 'local_operation_failed'} def validate(record): if (record.get('schema') != 'netkingdom.identity-offsite.v1' or record.get('status') != 'readback_verified' or record.get('provider') != 'Storage Share' or record.get('folder') != 'Backup/railiance-backups/net-kingdom-identity' or not offsite.NAME.fullmatch(record.get('artifact', '')) or not re.fullmatch('[a-f0-9]{64}', record.get('ciphertext_sha256', '')) or type(record.get('ciphertext_bytes')) is not int or not 0 < record['ciphertext_bytes'] <= offsite.LIMIT or not re.fullmatch(r'"[^"\x00-\x20]{1,180}"', record.get('etag', ''))): raise offsite.Refused() def retrieve(record, secret, mode, client=None): validate(record) if mode not in {'account', 'folder-share'} or not secret or any(c in secret for c in '\r\n\x00'): raise offsite.Refused() auth = offsite.headers(secret) if mode == 'folder-share' else { 'Authorization': 'Basic ' + base64.b64encode(('Backup:' + secret).encode()).decode(), 'Accept-Encoding': 'identity'} url = (offsite.BASE if mode == 'folder-share' else ACCOUNT_BASE) + record['artifact'] client = client or offsite.opener() directory = None complete = False try: with client.open(urllib.request.Request(url, method='HEAD', headers=auth), timeout=30) as response: if offsite.etag(response, url, record['ciphertext_bytes']) != record['etag']: raise offsite.Refused() directory = Path(tempfile.mkdtemp(prefix='nk49-identity-fetched-', dir='/tmp')) target = directory / record['artifact'] auth['If-Match'] = record['etag'] count = 0 digest = hashlib.sha256() with client.open(urllib.request.Request(url, headers=auth), timeout=180) as response: if offsite.etag(response, url, record['ciphertext_bytes']) != record['etag']: raise offsite.Refused() fd = os.open(target, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, 0o600) with os.fdopen(fd, 'wb') as output: while block := response.read(1024 * 1024): count += len(block) if count > record['ciphertext_bytes']: raise offsite.Refused() digest.update(block) output.write(block) output.flush() os.fsync(output.fileno()) if count != record['ciphertext_bytes'] or digest.hexdigest() != record['ciphertext_sha256']: raise offsite.Refused() with client.open(urllib.request.Request(url, method='HEAD', headers=auth), timeout=30) as response: if offsite.etag(response, url, record['ciphertext_bytes']) != record['etag']: raise offsite.Refused() complete = True # Closed allowlist: never copy arbitrary source-receipt fields to output. result = {k: record[k] for k in ('schema', 'provider', 'folder', 'artifact', 'ciphertext_bytes', 'ciphertext_sha256', 'etag')} result.update(status='readback_verified', fetched_path=str(target), independent_owner_retrieval_verified=True, credential_source='independently_held_provider_access', provider_auth_mode=mode, openbao_contacted=False, sso_contacted=False, provider_writes_performed=False, age_private_key_used=False, secret_values_exported=False, object_unchanged_during_transfer=True, downloaded_at=datetime.now(timezone.utc).isoformat()) return result finally: if directory is not None and not complete: shutil.rmtree(directory) def interrupted(signum, frame): raise InterruptedError() def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--source-receipt', required=True) parser.add_argument('--receipt', required=True) parser.add_argument('--auth', choices=('account', 'folder-share'), default='account') args = parser.parse_args() os.umask(0o077) fd = os.open(args.receipt, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, 0o600) result = {'status': 'failed', 'error': 'offline_retrieval_failed_private_diagnostics_suppressed'} stage = 'source_receipt_validation' try: record = json.loads(Path(args.source_receipt).read_text()) validate(record) # getpass must never fall back to echoed stdin (e.g. a captured agent tool). stage = 'private_provider_prompt' secret = private_prompt('Storage Share Backup app password or exact folder-share token: ') try: stage = 'provider_download' result = retrieve(record, secret, args.auth) finally: secret = None except (Exception, KeyboardInterrupt) as error: result.update(failed_stage=stage, **failure_metadata(error)) finally: with os.fdopen(fd, 'w') as output: json.dump(result, output, indent=2) output.write('\n') ok = result['status'] == 'readback_verified' print('OK: ciphertext retrieved without OpenBao or SSO; ETag, size and SHA256 verified.' if ok else 'ERROR: retrieval refused; private diagnostics suppressed. Use a new receipt path to retry.') return 0 if ok else 1 if __name__ == '__main__': for sig in (signal.SIGINT, signal.SIGTERM, signal.SIGHUP): signal.signal(sig, interrupted) sys.exit(main())