Skip to content

fix(account): Day 6 review gate, web lane fixes - #193

Merged
WillCybertron merged 6 commits into
mainfrom
fix/account-web-gate
Nov 12, 2026
Merged

WillCybertron merged 6 commits into
mainfrom
fix/account-web-gate

Conversation

@WillCybertron

@WillCybertron WillCybertron commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

The Account-web lane's items from the Day 6 review gate (docs/mobile/review/GATE-REPORT.md in the meta repo). Each fix has a test that fails without it.

Fixes

  • M7 (store.ts fromPlay): a Play purchase grants only the product Google names. A subscription's lineItems[0].productId (a one-time product's productId) must equal the claimed SKU, else 422 transaction_invalid, on POST /v1/purchases and on Pub/Sub notifications. Test: payments.test.ts "M7: a Play subscription token grants only the product Google names".
  • M2, sign-in part (signin.ts): registering the root passkey while the account has no key log needs a sign-in at most 300 s old (auth_time), at /v1/auth/passkey/options and at /verify: 401 reauth_required. Core's freshSignIn does the check; the genesis part is Account-core's (fix(account): gate M1, M2 and M3 with hardening: product pin on the verified DID, a viewer address on every request, fresh device-bound genesis with a notice, no tokens for deleted accounts #191). Test: signin-web.test.ts "M2: a session older than 5 minutes cannot register the root passkey".
  • Lead, deleted accounts (signin.ts, deletion.ts): redeemLoginCode refuses a deleted account and deletion deletes its login codes. Sessions and refresh tokens already go with the account (fix(account): SMA's Ed25519 key test; retention for sign-in rows, rate counters, sessions and push tokens #183); rotate and accessToken check deleted_at since Account-core's fix(account): gate M1, M2 and M3 with hardening: product pin on the verified DID, a viewer address on every request, fresh device-bound genesis with a notice, no tokens for deleted accounts #191. Test: "lead: a login code of a deleted account is refused".
  • Lead, email decoy (signin.ts): a web start without Turnstile stores a code row for every address and mails only an existing email sign-in, so verify answers alike with and without an account (403 turnstile_required, then 401 code_invalid). The per-address limit now counts both alike too, and such a start answers after at least 1 s either way, so the mail's latency does not tell either. Test: "lead: a web email start without Turnstile answers alike".
  • Lead, grant before delivery (store.ts, jobs.ts, schema.sql): the entitlement row carries its pending plan.changed (event id, delivered_at) in the same statement, and the new grants job resends a lost or refused one under the same event id (1 minute doubling, at most an hour) until the product takes it. An owner without a key log waits for it; a deleted owner, or a product the stage never calls, is dropped. outbound.ts is unchanged. Test: payments.test.ts "lead: a refused or lost plan.changed is resent".
  • Hardening, method.add (stepup.ts, methods.ts, openapi.yaml): the step-up params are {type, subject}, the new sign-in's Apple or Google sub, email or passkey credential id, and the added method must be exactly that one. No client calls method.add yet. Test: methods.test.ts "gate hardening: the method.add approval names the new sign-in".
  • Hardening, Apple notices (signin.ts, apple.ts): applied in event_time order (seconds, as in Apple's documented example, or milliseconds); a consent-revoked ends only the Apple sessions and tokens that existed when Apple sent it. Test: signin-web.test.ts "hardening: Apple server notices apply in order".

Decisions

Checks

@chatgpt-codex-connector

Copy link
Copy Markdown
Codex Review Summary: ❌ Failed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ❌ Failed 2026-11-12T09:19:59.717294Z
We couldn’t complete this review. Comment @codex review to try again.
b8b51c8 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

…or the root passkey, grant resend, ordered Apple notices

- M7: a Play subscription grants only the product Google names (lineItems[0].productId), on purchases and
  on Pub/Sub notifications (422 transaction_invalid otherwise)
- M2 (sign-in part): registering the root passkey before the key log needs a sign-in at most 300 s old
  (401 reauth_required), at options and at verify
- leads: login codes of a deleted account are refused and deleted with it; a web email start without
  Turnstile stores a code row either way, so verify answers alike with and without an account; a store
  grant is pending in the same write as the entitlement and a job resends a lost or refused plan.changed
  under the same event id
- hardening: the method.add step-up names the new sign-in (params.subject), so an approval cannot add a
  different identity; Apple server notices apply in order, so a late consent-revoked cannot end a newer
  session or token
… events kept; grants for a product the stage never calls are dropped, not retried
…l start without Turnstile takes the same least time whether it mails or not
@WillCybertron
WillCybertron merged commit 9ba1e6b into main Nov 12, 2026
1 check passed
@WillCybertron
WillCybertron deleted the fix/account-web-gate branch November 12, 2026 09:43
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