#!/usr/bin/env python3
# Generates a VALID PDF that carries ACTIVE CONTENT (an OpenAction JavaScript that auto-runs on open,
# plus a /Launch action) — the exact class of thing VIYUH BDR's Threat-Extraction (CDR) layer disarms.
# Byte offsets in the xref are computed correctly so strict parsers (and the CDR engine) accept it.
#
#   python3 _gen-cdr-sample.py            -> writes disguised-invoice.pdf next to this script
#
# Use: host it and download it in Chrome. The download guard intercepts it (PDF = disarmable):
#   * CDR engine UP    -> "Disarming …" then "Disarmed — removed javascript" and a CLEAN pdf lands.
#   * CDR engine DOWN  -> ONE "CDR unavailable — delivered original" (auto-clears); after 2, the
#                         circuit-breaker pauses CDR for the session. NO notification storm (the bug we fixed).
import os, zlib  # zlib unused but handy if you later want compressed streams

HERE = os.path.dirname(os.path.abspath(__file__))
OUT = os.path.join(HERE, "disguised-invoice.pdf")

# A tiny page that shows some text, so the file looks like a real invoice in a viewer.
content = b"BT /F1 18 Tf 40 96 Td (INVOICE #INV-2026-0417  --  Amount due: $4,820.00) Tj ET\n" \
          b"BT /F1 11 Tf 40 60 Td (This PDF carries auto-run JavaScript + a Launch action for CDR testing.) Tj ET"

# The active content CDR should strip: an OpenAction that runs JS on open, and a Launch action.
js = b"app.alert('CDR test: if you can read this alert, the active content was NOT removed.'); " \
     b"this.exportDataObject({cName:'x'});"

objs = []
objs.append(b"<< /Type /Catalog /Pages 2 0 R /OpenAction 5 0 R /Names << /JavaScript 6 0 R >> >>")
objs.append(b"<< /Type /Pages /Kids [3 0 R] /Count 1 >>")
objs.append(b"<< /Type /Page /Parent 2 0 R /MediaBox [0 0 420 144] "
            b"/Resources << /Font << /F1 4 0 R >> >> /Contents 7 0 R >>")
objs.append(b"<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>")
objs.append(b"<< /Type /Action /S /JavaScript /JS (" + js + b") >>")
objs.append(b"<< /Names [(EvilJS) 5 0 R] >>")
objs.append(b"<< /Length " + str(len(content)).encode() + b" >>\nstream\n" + content + b"\nendstream")
# A /Launch action object (dangling ref-free, but present as active content the engine flags).
objs.append(b"<< /Type /Action /S /Launch /F (calc.exe) >>")

def build():
    out = bytearray(b"%PDF-1.7\n%\xe2\xe3\xcf\xd3\n")
    offsets = []
    for i, body in enumerate(objs, start=1):
        offsets.append(len(out))
        out += str(i).encode() + b" 0 obj\n" + body + b"\nendobj\n"
    xref_pos = len(out)
    n = len(objs) + 1
    out += b"xref\n0 " + str(n).encode() + b"\n"
    out += b"0000000000 65535 f \n"
    for off in offsets:
        out += ("%010d 00000 n \n" % off).encode()
    out += b"trailer\n<< /Size " + str(n).encode() + b" /Root 1 0 R >>\n"
    out += b"startxref\n" + str(xref_pos).encode() + b"\n%%EOF\n"
    return bytes(out)

data = build()
with open(OUT, "wb") as f:
    f.write(data)
print("wrote", OUT, "(%d bytes)" % len(data))
