nigig-org/crates/apps/pdf/pdf-document/src
andodeki b720a166ec
Some checks failed
repo hygiene / hygiene (push) Has been cancelled
PDF engine / engine (push) Has been cancelled
PDF engine / makepad-integration (push) Has been cancelled
PDF engine / fuzz (push) Has been cancelled
feat(pdf): AcroForm actions and validation; JavaScript refused, not run
Phase 8 #8 of REVIEWS/DART_PDF_VS_MAKEPAD_PDF_GAP_ANALYSIS.md ("AcroForm
full support"). Design and merge criteria in
REVIEWS/adr/0012-pdf-acroform-full.md.

Form editing already worked. What was missing is everything that makes a
real form behave like one. Probing an invoice-shaped document:

  "qty"   required=true  /AA present? false
  "price" required=false /AA present? true
  "total" required=false /AA present? true
  -> is any /AA action exposed?  no accessor exists
  -> is /CO exposed?             no accessor exists

The /AA dictionaries sat in the raw field dictionary, reachable only by a
caller who knew to go digging. Nothing surfaced them, nothing ordered
calculations, and /Ff bit 2 (Required) was parsed and never enforced - a
form could be submitted with a mandatory field blank and nothing said so.

THE JAVASCRIPT DECISION

The review names JavaScript actions as a prerequisite. That is a product
and security call, and I flagged it for a human three times without a
specific answer; continuing to block the whole feature on it helps
nobody. This takes the reversible option and documents it loudly enough
to overrule:

  JavaScript is parsed, exposed, and NEVER EXECUTED.

Running it means embedding an interpreter and feeding it
attacker-controlled source from every PDF a user opens, with an API that
reaches the file system, network and host - and review rule 5 already
forbids the viewer launching anything. run_action returns
FormError::JavaScriptRefused carrying the source, so a host with its own
sandbox can decide for itself. A later ADR turns a refusal into an
execution; nothing has to be un-built.

Equally deliberate: this does NOT emulate JavaScript by recognising
AFNumber_Format and AFSimple_Calculate in the source and reimplementing
them natively. That works on boilerplate and produces a confidently
wrong number the moment a script differs by a character.

WHAT IS IMPLEMENTED

- /AA parsed into typed actions across all 14 triggers, on fields and
  widgets, with indirect action dictionaries resolved.
- /CO calculation order exposed in document order.
- Validation that needs no scripting: required, /MaxLen, comb fields,
  choice values against /Opt, checkbox and radio states.
- A field whose rules live in a script reports as UNVALIDATED, which is
  distinct from valid. Confusing the two is how a form silently accepts a
  value its own rules would reject.
- /SubmitForm parsed into URL, flags and fields and returned as data.
  This crate opens no sockets.

Also found: the /Ff comb bit (25) was absent from the flags module
entirely, and DO_NOT_SPELL_CHECK carried the wrong doc comment ("caps
input at /MaxLen", which is what /MaxLen does).

4 corpus fixtures, 13 acceptance tests, 20 unit tests. Both tripwires
mutation-checked: adding a helper that pattern-matches a script's source
fails one, removing the refusal branch fails the other.

TEST_TARGET=pdf 575 -> 607, TEST_TARGET=pdf-ui 619 -> 651.
rustfmt and clippy -D warnings clean.
2026-07-31 22:41:50 +00:00
..
annotation_edit.rs feat(pdf): implement annotation editing (Phase 8) 2026-07-28 17:12:40 +00:00
annotations.rs feat(pdf): implement annotation editing (Phase 8) 2026-07-28 17:12:40 +00:00
appearance.rs feat(pdf): complete Phase 3 document model with real form state 2026-07-27 15:49:46 +00:00
destinations.rs fix(pdf): restore a compiling, warning-free PDF baseline 2026-07-27 15:33:15 +00:00
document.rs feat(pdf): tagged structure tree, and the BMC bug that turned red green 2026-07-31 22:19:45 +00:00
form.rs feat(pdf): AcroForm actions and validation; JavaScript refused, not run 2026-07-31 22:41:50 +00:00
form_actions.rs feat(pdf): AcroForm actions and validation; JavaScript refused, not run 2026-07-31 22:41:50 +00:00
lib.rs feat(pdf): AcroForm actions and validation; JavaScript refused, not run 2026-07-31 22:41:50 +00:00
page.rs feat(pdf): transparency, and four operator-parsing bugs it exposed 2026-07-31 18:58:31 +00:00
save.rs fix(pdf): fuzz every target, and close two ADR 0004 gaps 2026-07-31 18:34:25 +00:00
signature.rs feat(pdf): read signatures, and fix a third ObjRef-destroying resolve 2026-07-31 20:02:29 +00:00
structure.rs feat(pdf): tagged structure tree, and the BMC bug that turned red green 2026-07-31 22:19:45 +00:00