#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = ["curl-cffi>=0.13"]
# ///
# Execute one read-only research command through a deliberately configured
# Scriptable Step on an owned Airlock IAM trial and return its value through a
# legacy ESP ticket response header.
#
# Invocation:
#   uv run --script airlock-owned-trial-command-oracle.py \
#     --base https://<owned-tenant>/login --application <id> \
#     --email EMAIL --password PASSWORD --command 'id'
#
# No engagement-identifying header is sent: this helper targets only a researcher-owned vendor tenant.
# Prerequisite: the owned trial's active config maps the retained Referer header
# into Scriptable Step input `forged-user`, URL-decodes the command, executes it,
# and maps output key `leak` into X-ESP-Ticket. Never aim this helper at target
# infrastructure; it is for product-code research in a tenant you own.
import argparse, base64
from urllib.parse import quote, unquote
from curl_cffi import requests

def main():
 ap=argparse.ArgumentParser(); ap.add_argument('--base',required=True); ap.add_argument('--application',default='portal-application-id'); ap.add_argument('--email',required=True); ap.add_argument('--password',required=True); ap.add_argument('--command',required=True); ap.add_argument('--ticket-output'); a=ap.parse_args()
 base=a.base.rstrip('/'); ref='https://cmd.invalid/'+quote(a.command,safe=''); ident={}; extra={'Referer':ref}; s=requests.Session(impersonate='chrome')
 s.get(base+'/ui/app/auth/application/access',headers={**ident,**extra},timeout=30,toadex_capture=False)
 common={**ident,**extra,'X-Same-Domain':'1','Accept':'application/json, text/plain, */*','X-CSRFT759':s.cookies.get('CSRFT759-S') or ''}
 s.delete(base+'/rest/public/authentication/flow',headers=common,timeout=30,toadex_capture=False)
 r=s.post(base+f'/rest/public/authentication/applications/{a.application}/access',headers={**common,'Content-Type':'application/json'},data=b'',timeout=30,toadex_capture=False)
 ticket=r.headers.get('X-ESP-Ticket')
 if not ticket and r.status_code==401:
  r=s.post(base+'/rest/public/authentication/password/check',headers={**common,'X-Continue-Flow':'true','Content-Type':'application/json'},json={'username':a.email,'password':a.password},timeout=30,toadex_capture=False); ticket=r.headers.get('X-ESP-Ticket')
 if not ticket: raise SystemExit(f'no ticket: status={r.status_code} body={r.text[:300]!r}')
 if a.ticket_output: open(a.ticket_output,'w').write(ticket)
 raw=base64.b64decode(ticket); clear=raw[65:-8].decode('utf-8','replace')
 vals={}
 for part in clear.split(';'):
  if '=' in part:
   k,v=part.split('=',1); vals[k]=unquote(v)
 print(vals.get('leak',''))
if __name__=='__main__': main()
