Skip to content

Parse MPMA CSV with the module written for it - #248

Closed
droplister wants to merge 1 commit into
refactor/naming-consistencyfrom
feat/use-validation-modules
Closed

Parse MPMA CSV with the module written for it#248
droplister wants to merge 1 commit into
refactor/naming-consistencyfrom
feat/use-validation-modules

Conversation

@droplister

Copy link
Copy Markdown
Member

Stacked on #247. Wires up the two validators #246 deliberately left undeleted — and finds that one of them must not go where I first said.

csv.ts → MPMA parsing

The form parsed CSV with line.match(/(".*?"|[^,]+)(?=\s*,|\s*$)/g) over text.split('\n'). parseCSV replaces that and adds what the loop never had:

  • formula-injection rejection — a row containing =cmd|calc was accepted before
  • a row cap (10,000)
  • real quoted-field parsing

Address checking is left off (validateAddresses: false) so the form's existing validateBitcoinAddress — which verifies the checksum — keeps running instead of the module's format-only test. The divisibility lookup and memo-length check are untouched.

One message changed. An unparseable quantity now reads "Quantity must be a number" rather than "Invalid quantity" — it says why rather than only that. The test asserting the old wording is updated.

file.ts → the CSV upload, not the inscription upload

The CSV upload had no size limit at all — only file.name.endsWith('.csv'), then the whole file was read into memory regardless of size. validateFile now bounds it at 2 MB and owns the extension check.

detectMaliciousPatterns is deliberately off: parseCSV already screens every field for injection, which covers the whole file rather than the first kilobyte, and a script-marker scan could trip on a legitimate memo.

Why file.ts is not wired into inscriptions

I said earlier that file-upload-input.tsx "validates nothing" and the inscription path was a gap. Checking the module changed that conclusion.

detectMaliciousContent rejects any text/* file containing <script, <iframe or javascript:. An HTML inscription carrying a script tag is exactly what that feature publishes — wiring this in would have broken inscriptions, which only started working in 0.7.0. Its type and extension checks are wrong there for the same reason: an inscription is arbitrary content by definition.

The size-only check those forms do is correct. file.ts was written for uploads that should be constrained; inscriptions aren't.

Tests

Two new cases covering exactly what the change buys:

  • a row carrying =cmd|calc is rejected
  • a quoted memo containing a comma survives as one field rather than splitting into a fourth column

Verification

  • tsc --noEmit clean; biome check src clean (672 files)
  • vitest run src — 3965 passed, 49 skipped
  • wxt build succeeds
  • playwright test e2e/pages/compose/send/mpma.spec.ts — 6 passed

validation/csv.ts and validation/file.ts were unreferenced, each the better
implementation of something a caller did inline and less carefully. This
wires csv.ts up, and file.ts where it actually fits.

The MPMA form parsed CSV with a regex over split lines. parseCSV replaces it
and adds what that loop never had: a row cap, proper quoted-field parsing,
and rejection of spreadsheet formula injection. Address checking is left off
so the checksum-validating validateBitcoinAddress the form already used
keeps running, rather than the module's format-only test - the surrounding
divisibility lookup and memo length check are unchanged.

One message changed: an unparseable quantity now reads "Quantity must be a
number" rather than "Invalid quantity", which says why rather than only
that. The test asserting the old wording is updated.

The CSV upload had no size limit at all, only a name check - the whole file
was read into memory whatever its size. validateFile now bounds it at 2MB
and owns the extension check. Malicious-pattern detection is deliberately
off: parseCSV already screens every field for injection, which covers the
whole file rather than the first kilobyte, and a scan for script markers
could trip on a legitimate memo.

file.ts is NOT wired into the inscription upload, and should not be. Its
detectMaliciousContent rejects any text file containing <script, <iframe or
javascript:, and an HTML inscription carrying a script tag is exactly what
that feature publishes. Its type and extension checks are wrong there for
the same reason. The size-only check those forms do is correct for content
meant to be arbitrary.

Adds tests for both new protections: a row carrying =cmd|calc is rejected,
and a quoted memo containing a comma survives as one field.

Claude-Session: https://claude.ai/code/session_01CcjnCrgosSeshymXLBxdGj
@droplister

Copy link
Copy Markdown
Member Author

Squashed into #249.

@droplister droplister closed this Aug 4, 2026
@droplister
droplister deleted the feat/use-validation-modules branch August 4, 2026 21:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant