#!/usr/bin/env python3
"""HTTPS server for the Protected Audience worklet UAF POC.

Serves poc.html / bid.js / decision.js with the headers Chrome's auction
worklet downloader requires (Ad-Auction-Allowed: true and a JS MIME type).

Generates a throwaway self-signed certificate on startup; pass
--ignore-certificate-errors to Chrome.
"""

import http.server
import os
import ssl
import subprocess
import sys
import tempfile

PORT = 8443
ROOT = os.path.dirname(os.path.abspath(__file__))


class Handler(http.server.BaseHTTPRequestHandler):
    protocol_version = "HTTP/1.1"

    def _serve(self, body: bytes, ctype: str, extra=None):
        self.send_response(200)
        self.send_header("Content-Type", ctype)
        self.send_header("Content-Length", str(len(body)))
        self.send_header("Cache-Control", "no-store")
        for k, v in (extra or {}).items():
            self.send_header(k, v)
        self.end_headers()
        if self.command != "HEAD":
            self.wfile.write(body)

    def do_GET(self):
        path = self.path.split("?", 1)[0]
        if path in ("/", "/poc.html"):
            with open(os.path.join(ROOT, "poc.html"), "rb") as f:
                self._serve(f.read(), "text/html; charset=utf-8",
                            {"Supports-Loading-Mode": "fenced-frame"})
        elif path == "/bid.js":
            with open(os.path.join(ROOT, "bid.js"), "rb") as f:
                self._serve(f.read(),
                            "application/javascript; charset=utf-8",
                            {"Ad-Auction-Allowed": "true",
                             "X-Allow-FLEDGE": "true"})
        elif path == "/decision.js":
            with open(os.path.join(ROOT, "decision.js"), "rb") as f:
                self._serve(f.read(),
                            "application/javascript; charset=utf-8",
                            {"Ad-Auction-Allowed": "true",
                             "X-Allow-FLEDGE": "true"})
        elif path == "/ad.html":
            self._serve(b"<!doctype html><title>ad</title>ad",
                        "text/html; charset=utf-8",
                        {"Supports-Loading-Mode": "fenced-frame"})
        else:
            self.send_response(404)
            self.send_header("Content-Length", "0")
            self.end_headers()

    do_HEAD = do_GET

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


def make_cert():
    d = tempfile.mkdtemp(prefix="poc-cert-")
    key = os.path.join(d, "key.pem")
    crt = os.path.join(d, "cert.pem")
    subprocess.check_call([
        "openssl", "req", "-x509", "-newkey", "rsa:2048", "-nodes",
        "-keyout", key, "-out", crt, "-days", "2",
        "-subj", "/CN=localhost",
        "-addext", "subjectAltName=DNS:localhost,IP:127.0.0.1",
    ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
    return key, crt


def main():
    key, crt = make_cert()
    ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
    ctx.load_cert_chain(certfile=crt, keyfile=key)
    httpd = http.server.ThreadingHTTPServer(("127.0.0.1", PORT), Handler)
    httpd.socket = ctx.wrap_socket(httpd.socket, server_side=True)
    sys.stderr.write(f"[server] listening on https://localhost:{PORT}/\n")
    sys.stderr.flush()
    httpd.serve_forever()


if __name__ == "__main__":
    main()
