Replace stub wallet keypair with real Phantom sign-in
Auth now goes through an actual connected Solana wallet instead of a locally-generated ed25519 keypair. Phantom's window.solana provider is only reachable from a page's own JS world, not an isolated-world content script, so this adds a second world:'MAIN' content script (wallet-bridge.content.ts + wallet-bridge/inject.ts) that talks to window.solana directly and relays to the isolated world via window CustomEvents (wallet-bridge/relay.ts), matched by request id. wallet-connect.ts orchestrates: try a silent onlyIfTrusted connect on load; if that fails, show an on-page banner (wallet-bridge/banner.ts) whose click handler is what actually calls connect() -- Phantom requires a real user gesture for the approval popup on a first-ever connect, which a click relayed from the extension popup wouldn't count as by the time it reaches the wallet. background/wallet-auth.ts runs the REST auth flow (nonce -> ask the tab's content script to sign it -> verify -> store session token) once a wallet reports connected. ws-client.ts no longer force-retries with a known-bad token on auth failure; it calls onAuthExpired instead (which clears the token and prompts a silent wallet reconnect) and exposes reconnectNow() so background.ts can short-circuit the backoff wait once a fresh token exists. identity.ts and its tweetnacl dependency are gone -- no more stub signer. Untested against real Phantom (no browser automation available this session) -- flagged in CLAUDE.md as needing manual verification, along with a note that world:'MAIN' needs Firefox 128+. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01YXiHuScXrjxBh7yFGAPq3B
This commit is contained in:
@@ -1,17 +1,21 @@
|
||||
import { getSessionToken } from '@/background/backend-client';
|
||||
import { clearSessionToken, getSessionToken } from '@/background/backend-client';
|
||||
import { getConnectionStatus, setConnectionStatus } from '@/background/connection-status';
|
||||
import { applyLockState, getLockState } from '@/background/lock-state';
|
||||
import { handleWalletConnected, requestWalletReconnect } from '@/background/wallet-auth';
|
||||
import { connectWsClient } from '@/background/ws-client';
|
||||
import type { NexaMessage } from '@/shared/messaging';
|
||||
|
||||
export default defineBackground(() => {
|
||||
connectWsClient({
|
||||
const ws = connectWsClient({
|
||||
getToken: getSessionToken,
|
||||
onLockState: (state) => void applyLockState(state),
|
||||
onStatusChange: (status) => void setConnectionStatus(status),
|
||||
onAuthExpired: () => {
|
||||
void clearSessionToken().then(() => requestWalletReconnect());
|
||||
},
|
||||
});
|
||||
|
||||
browser.runtime.onMessage.addListener((message: NexaMessage, _sender, sendResponse) => {
|
||||
browser.runtime.onMessage.addListener((message: NexaMessage, sender, sendResponse) => {
|
||||
switch (message?.type) {
|
||||
case 'nexa:get-lock-state':
|
||||
getLockState().then(sendResponse);
|
||||
@@ -27,6 +31,12 @@ export default defineBackground(() => {
|
||||
browser.action.openPopup().catch(() => undefined);
|
||||
return false;
|
||||
|
||||
case 'nexa:wallet-connected':
|
||||
handleWalletConnected(sender.tab?.id, message.walletAddress)
|
||||
.then(() => ws.reconnectNow())
|
||||
.catch(() => undefined); // signing/verify failed — ws-client's own retry loop keeps trying
|
||||
return false;
|
||||
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user