Skip to content

Compare addresses case-insensitively: identity checks and SQL visibility - #44

Merged
markmnl merged 2 commits into
mainfrom
address-case-insensitive
Sep 5, 2026
Merged

Compare addresses case-insensitively: identity checks and SQL visibility#44
markmnl merged 2 commits into
mainfrom
address-case-insensitive

Conversation

@markmnl

@markmnl markmnl commented Sep 5, 2026

Copy link
Copy Markdown
Owner

Summary

fmsg addresses are case-insensitive (SPECIFICATION.md, case folding), but the webapi compared them byte-for-byte in two places. A first-party token's identity keeps the case the sub-account was created with (e.g. @markmnl_ChatGPT@fmsg.io), so a client that folded the address was refused with 403 from address must match authenticated user, and a mixed-case identity could miss messages whose stored recipient entries used another case. Seen live via fmsg-mcp on fmsg.io today.

  • Go identity checks: sameAddr (strings.EqualFold) at the six sites in internal/handlers/messages.go (from on create/update; ownership on update/delete/send/add-to), matching isRecipient which already compared that way. Unit test added.
  • SQL: every visibility, read-state, ownership and attachment query on msg / msg_to / msg_add_to now compares lower(col) against a lower-cased identity (visibleAddrs lower-cases) or lower($n). fmsgd's schema already provides msg_lower_idx, msg_to_lower_idx and msg_add_to_lower_idx expression indexes for exactly this, so the queries stay indexed. resolveLocalDelivery's UPDATE keeps an exact match because it targets rows this handler inserted with the same string. push_subscription (webapi's own table, IdP identities) is unchanged.

Test plan

  • go vet ./... && go test ./...
  • fmsg-docker integration suite with FMSG_WEBAPI_REF=address-case-insensitive: 14/14 passed locally (podman)
  • Mixed-case check on the test stacks: derived sub-account @alice_Mixed@hairpin.local (registered in fmsgid by hand: the CLI api-key create path does not register derived addresses, unlike POST /fmsg/sub-accounts) receives a message sent to the lower-case form, lists it, marks it read, sees the full thread, and sends with from in either casing; /fmsg/sent lists both
  • Deploy to fmsg.io and re-run the mixed-case send through mcp.fmsg.io

🤖 Generated with Claude Code

https://claude.ai/code/session_01AoApk9grYkP1EMd4F4GVMv

Mark Mennell and others added 2 commits September 5, 2026 16:17
fmsg addresses are case-insensitive (SPECIFICATION.md: case folding),
but the from/ownership checks compared bytes, so a first-party token whose
identity keeps the case a sub-account was created with (e.g.
@user_Agent@domain) was refused with 403 "from address must match
authenticated user" when a client sent the folded form. All six identity
checks in the message handlers now use sameAddr (EqualFold).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AoApk9grYkP1EMd4F4GVMv
The msg tables already carry lower(from_addr) / lower(addr) expression
indexes (fmsgd dd.sql), so every visibility, read-state, ownership and
attachment query now compares lower(col) against a lower-cased identity
or lower($n). A mixed-case identity now sees messages whose stored
recipient entries use any case.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AoApk9grYkP1EMd4F4GVMv
@markmnl markmnl changed the title Compare the authenticated identity to addresses case-insensitively Compare addresses case-insensitively: identity checks and SQL visibility Sep 5, 2026
@markmnl
markmnl merged commit 1e18bcd into main Sep 5, 2026
1 check passed
@markmnl
markmnl deleted the address-case-insensitive branch September 5, 2026 08:35
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