Pre-release audit fixes

Security and correctness pass ahead of making the repo public.

- Address generation now uses crypto.getRandomValues with rejection
  sampling instead of Math.random. Users can mint addresses and observe
  the output, and V8's PRNG state is recoverable from observed values, so
  one user could predict another's addresses.

- Write the U+E000/U+E001 link-placeholder sentinels and the invisible
  character class as \u escapes. As literal characters they were invisible
  in review and rendered as empty strings; anything stripping them would
  have silently turned the final restore pass into inserting "<" between
  every character of every message.

- Assemble the DM body once and cap once. Notes were appended after the
  2000-char check, so a long email with oversized attachments produced a
  2038-char message that Discord rejected outright, losing the delivery.

- Budget the whole multipart payload rather than just the mail's own
  attachments, and take attachments individually. Generated message.txt/
  .html were not counted, and a single oversized file discarded every
  attachment alongside it.

- Bound HTML at 256KB before conversion. Parsing is quadratic in input
  size and email bodies are attacker-controlled; a crafted ~1MB body cost
  13s of CPU, now 0.9s worst case.

- Rate limit /list, /extend and /torch, not just /new.

- Log delivery failures (adapter type and error only, never content,
  addresses or owner ids) so a user with DMs closed is diagnosable
  instead of silently dropping mail.

- Track revoked_at so revoked addresses are cleaned up a grace period
  after revocation rather than surviving until their original expiry, and
  prune rate_limit rows whose window closed long ago. Includes a
  migration for existing deployments.

- Return 400 rather than throwing on a malformed interaction payload.

- package.json declared ISC while LICENSE is MIT; also replaces the
  scaffolding defaults with real metadata and scripts.
Psalm 25 17committed parent 9d5e1524e788305f4721f5ce8fa93b186d4282c18e35bb2Browse files
9 files changed+173−56

Rendering diff…