fix: complete and harden the persistence/security cleanup#317
Merged
Conversation
…direct Re-registering an existing-but-unverified email had begun overwriting its password_hash, so an attacker who knows a victim's email could set the password on the account the victim then activates by clicking the verification mail. Restore the always-409 response for any existing email; the dedicated /api/auth/resend route refreshes only the token, so re-verification still works without a credential-rewrite path. safeRedirect returned the resolved pathname without rechecking it, so "/..//evil.com" normalized to the protocol-relative "//evil.com" and slipped through as a same-origin path. Reject any result that isn't single-slash-rooted. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ine page replayPending left a permanently-rejected op (404/400/409/413) at the head of the queue and broke out, wedging every later change behind it forever. It now drops such ops and keeps draining, while still retrying transient failures and holding on 401 until re-auth. The legacy "keep-offline" IndexedDB was deleted outright, discarding un-replayed offline edits — migrate its pending ops into the per-owner DB before removing it. Pending-op stamps are now strictly monotonic so a create can't replay after an update queued in the same millisecond; a 401 refresh keeps the cached notes on screen instead of blanking to an empty guest list; and create() upserts so a concurrent refresh can't drop the note the user just made. The rewritten service worker cached no HTML and left offline navigations on the browser's error page. Add a neutral, precached /offline fallback served on navigation failure — the personalized app shell is still never cached. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Removes the shelved client-side encryption feature — the PBKDF2 passphrase crypto, the useEncryption hook, the setup/unlock UI, the enc salt route — and its handling across the web and iOS clients. Notes previously stored as "enc:" ciphertext are no longer decrypted; that data loss is accepted, as the feature never carried real data. Replaces middleware.ts with proxy.ts for route protection and per-request CSP nonces, adds verified email/password sign-in with a resend flow, and reworks the notes API, sharing, and share-token generation. This is the in-flight cleanup an earlier agent left uncommitted. The security and offline-reliability fixes layered on top of it are in the two preceding commits. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Completes and hardens the in-flight persistence/security cleanup an earlier agent left uncommitted. Three commits:
Security —
fix(security)password_hash, letting an attacker set the password on an account the victim then activates via the verification email. Restores the always-409 response;/api/auth/resendrefreshes only the token.Offline reliability —
fix(offline)keep-offlineIndexedDB into the per-owner DB before deleting it, instead of discarding queued offline edits.create()upserts so a concurrent refresh can't drop the new note./offlinefallback served on navigation failure (the personalized app shell is still never cached).Cleanup —
refactorenc:ciphertext are no longer decrypted — accepted data loss (the feature carried no real data).middleware.tswithproxy.ts(route protection + per-request CSP nonce), adds verified email/password sign-in with a resend flow, and reworks the notes API, sharing, and share tokens.Test plan
npm run build— clean (local)npm test— 125 passing locally (incl. new regression tests for the poison-op drop and monotonic ordering)/offlinerenders the neutral fallback (screenshot inscreenshots/)main(fix: open the note a Spotlight result points at on the Mac #312) and may need a rebase for the iOS files🤖 Generated with Claude Code