Repository navigation
Conversation
…session wallet.getUserWallets skipped its address check when the caller had no session at all, so an anonymous request for any signer address (public on-chain) returned the full wallet rows that name it: names, descriptions, signer labels and import bodies. getWallet already refuses anonymous callers; the list now does too (401 without a session, 403 for an address the session does not hold). The client relied on the anonymous read to show the list before the user signed the session nonce. useUserWallets now waits for authorization and reports needsAuthorization, and /wallets shows an "Authorize wallet" prompt (reopening the auth modal) instead of claiming the user has no wallets. The two wallet-creation lists on that page are protectedProcedures and are gated the same way, with 401 no longer retried. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017rkSXEzcv4V5UecnbAuNvd
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This branch was successfully deployed
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.
What
wallet.getUserWallets(tRPC,publicProcedure) only checked the requested address when the caller had a session. With no session at all it ran the query anyway, soreturned, to anyone, every wallet row that names that address as a signer — name, description,
signersDescriptions(people's labels),rawImportBodies, script CBOR. Signer addresses are public on-chain, so the address proves nothing.getWalletalready refuses anonymous callers; the list exposed more than the single-wallet read.Change
src/server/api/routers/wallets.ts): no session →UNAUTHORIZED; session that doesn't hold the address →FORBIDDEN(unchanged). Same shape asgetWallet.src/hooks/useUserWallets.ts): the hook relied on the anonymous read to show the list before the user signed the session nonce. It now waits for authorization and returnsneedsAuthorization(also true when the list call comes back 401, e.g. expired cookie). A failed session check is not treated as "unauthorized" — the modal only opens on an answer./wallets(homepage/wallets/index.tsx): shows an "Authorize wallet" prompt (requestReauth→ reopens the auth modal) instead of the "Get started" empty state when the user is connected but not authorized.getUserNewWallets/getUserNewWalletsNotOwnerareprotectedProcedures that 401'd and retried without a session; they're now gated onisAuthorizedand 401 is not retried.Unaffected callers (checked):
/api/v1/walletIdsand the MCPwalletIdstool build their own caller with the JWT address as session; CI scripts and e2e use bot JWTs or an injectedmesh_wallet_sessioncookie.Tests
src/__tests__/trpc/userWalletsAuth.test.ts(6): anonymous → 401 with no DB read, wrong address (wallet session and NextAuth) → 403, own address / multi-wallet session / NextAuth user → list. Anonymous case fails onpreprod(resolves with the wallet row), passes here.npm run test:trpcagainst local Postgres: 15 suites, 117 tests passed.node scripts/run-tests.mjs: 1656 passed, 2 skipped (+ 97 in the second group), exit 0.npx tsc --noEmit: clean.next build --webpack+ bundle budget: within budget;/wallets1920.7 → 1920.9 KB gz.Not verified / out of scope
requestReauth→ layout clears its latch → refetch → modal opens.GET /api/v1/exportWallet/listMineis CORS-public and returnsid, name, description, type, numRequiredSigners, numSignersfor any address/stake key by design ("no proof of ownership is required") — same leak class, but the cross-instance import flow depends on it, so closing it needs a nonce-sign step.user.getUserByAddressis handled in fix(users): stop the public user lookup handing out linked Discord IDs #420.https://claude.ai/code/session_017rkSXEzcv4V5UecnbAuNvd
Generated by Claude Code