Skip to content

Redesing Autofill setup and key storage#14

Merged
dbro merged 20 commits into
mainfrom
autofill-fixes
May 29, 2026
Merged

Redesing Autofill setup and key storage#14
dbro merged 20 commits into
mainfrom
autofill-fixes

Conversation

@dbro

@dbro dbro commented May 29, 2026

Copy link
Copy Markdown
Owner

Redesigns the vault sheet autofill setup so same-profile and cross-profile setup are presented as parallel option cards.

  • Replaces the old same-profile button plus collapsible cross-profile section with two matching autofill cards.
  • Adds tradeoff badges: SIMPLEST for same-profile and MOST ISOLATED for cross-profile.
  • Adds numbered cross-profile setup steps that match the everyday-profile pairing page language.
  • Renames the vault-side pairing modal/action to Pair everyday profile.
  • Removes the separate Check token step.
  • Auto-previews the confirmation code when a valid pairing token is pasted.

dbro and others added 20 commits May 27, 2026 10:58
window.open from a PWA standalone window was opening URLs in a new
standalone PWA context, causing scheme-less URLs like "paperlesspost.com"
to resolve relative to the PWA base path instead of opening in the
browser. Adding 'noopener,noreferrer' severs the opener relationship so
Chrome treats the new window as an independent browser tab.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Request readwrite permission explicitly in showOpenFilePicker and
requestPermission calls. On Android, createWritable() requires write
permission to be granted upfront — it cannot silently prompt the way
desktop Chrome does. Falls back to read permission if readwrite is
denied, preserving read-only vault support.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove legacy unauthenticated popup postMessage handler (hello/query
  via window.opener) that bypassed delegate verification entirely; the
  same-profile BC flow with ECDSA auth is the only supported path now
- Fix same-profile BC hello: import ECDH key from signed msg.ecdhSpki
  (SPKI) instead of unsigned msg.pubkey (JWK), closing the key-binding
  gap where an attacker could substitute their own ECDH key
- Fix cross-profile switchboard signatures: extend canonical signed
  payload from {url,nonce,ecdh,ts} to include msgType, uuid, vaultUuid,
  and query so a compromised relay cannot redirect operations or swap
  target records after signature verification

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…value

Track OriginalName in JS custom field state and use it in Go's lookup so
a name change doesn't break the match against the stored field value.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The short-header guard checked fieldStart > len(records) (needs 1 byte)
but the next two slices need 5 bytes. Match the fieldStart+5 guard
already used by UnmarshalHeader, and add a regression test.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
For both saveRecord and deleteRecord, conflict detection was running
after WASM memory and UI state were already mutated. Cancelling the
dialog left the edit/delete silently stranded in WASM — a later save
would apply it on top of the external change the user chose not to
overwrite. Also fixes web+portpass intent URLs being replayable
indefinitely by enforcing the same 60s freshness window used in the
switchboard WebSocket path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
saveSvAndBack() was updating WASM and the in-memory store but never
writing the vault file. Add onsvdbsave callback (parallel to ondbsave
for primary vault) that Dashboard implements via saveSecondaryDBFields,
which serialises and writes the secondary vault after a metadata save.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
saveFile() now returns true on an actual write or download, false on
conflict cancellation, AbortError, or write failure. saveDBFields()
guards clearing vaultDirty and showing "Vault info saved" on that
return value, so a conflict cancel or permission denial no longer
falsely marks the vault as clean.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Go's writeToClipboard and copyTOTP called navigator.clipboard.writeText
and ignored the returned Promise, so clipboard rejections were silently
swallowed and the UI reported success regardless. Move the async write
to JS: WASM now returns the plaintext value as JSON, and the wasm.js
wrappers (copyFieldToClipboard, copyCustomFieldToClipboard, copyTOTP)
are now async and own the await so rejections propagate to callers.
Dashboard await-s all three call sites; tests updated to match the
new raw-WASM API contract.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Five timestamp fields (headerLastSave, recordCreateTime, recordAccessTime,
recordPasswordExpiry, recordModTime) called binary.LittleEndian.Uint32
without first checking len(data) >= 4, allowing a valid-password
corrupted vault to panic rather than returning a clean error. Guards
now match the pattern already used for Version, UUID, DoubleClickAction,
ProtectedEntry, and PasswordExpiryInterval.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
randomFrom() and cryptoShuffle() used Uint32 % n which gives a slight
bias toward low indices when 2^32 is not divisible by n. Replace with
rejection sampling via unbiasedBelow(n): values in the biased tail
[floor(2^32/n)*n, 2^32) are discarded and redrawn. Expected extra
draws per call is less than one, and pools are small enough that
the limit computation is exact in 64-bit JS arithmetic.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Selection, keyboard navigation, copy-on-tap, context menu, and auto-expand
all used UUID alone to identify records. With UUID collisions across
simultaneously-open vaults the wrong vault could be targeted. Fixes all
functional paths; clipboard drain animation (cosmetic only) still matches
on UUID alone as that requires a separate change to clipboardContext.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
lockVault/lockAllVaults now clear selectedFile, dbItems, clipboard session/context,
and cancel the pending clipboard timer before calling onclosed(). Prevents stale
vault UUID from being used by App.svelte's handleIntent after lock.

Fix keyboard test: after openVault a recent handle is stored in IDB, so locking
returns to the re-unlock UI ("Vault is locked" + Master password field), not the
fresh "Open vault file" screen. Check for the password field instead.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
UnknownFields was map[byte][]byte in both header and Record, so a second
field with the same type ID silently overwrote the first. Changed to
[]unknownField to preserve all occurrences in the order they appear in
the file, matching the forward-compatibility intent. Marshal now emits
them in that same order rather than sorted-by-key.

Adds a header test for the duplicate case; updates the existing single
unknown-field test to use the new struct accessor.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@dbro dbro merged commit b00bbbf into main May 29, 2026
3 checks passed
@dbro dbro deleted the autofill-fixes branch May 29, 2026 23:29
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