diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 5b450fc..8f361dd 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -35,15 +35,31 @@ const Header = () => { const address = isConnected ? (isBitcoinConnected ? bitcoinAccount.address : ethereumAccount.address) : undefined; const [walletWizardOpen, setWalletWizardOpen] = useState(false); - const [hasShownWizard, setHasShownWizard] = useState(false); + + // Use sessionStorage to persist wizard state across navigation + const getHasShownWizard = () => { + try { + return sessionStorage.getItem('hasShownWalletWizard') === 'true'; + } catch { + return false; + } + }; + + const setHasShownWizard = (value: boolean) => { + try { + sessionStorage.setItem('hasShownWalletWizard', value.toString()); + } catch { + // Fallback if sessionStorage is not available + } + }; // Auto-open wizard when wallet connects for the first time React.useEffect(() => { - if (isConnected && !hasShownWizard) { + if (isConnected && !getHasShownWizard()) { setWalletWizardOpen(true); setHasShownWizard(true); } - }, [isConnected, hasShownWizard]); + }, [isConnected]); const handleConnect = async () => { setWalletWizardOpen(true); diff --git a/src/components/ui/wallet-wizard.tsx b/src/components/ui/wallet-wizard.tsx index a10c418..68e8e92 100644 --- a/src/components/ui/wallet-wizard.tsx +++ b/src/components/ui/wallet-wizard.tsx @@ -28,7 +28,7 @@ export function WalletWizard({ }: WalletWizardProps) { const [currentStep, setCurrentStep] = React.useState(1); const [isLoading, setIsLoading] = React.useState(false); - const { currentUser, isAuthenticated, verificationStatus } = useAuth(); + const { currentUser, isAuthenticated, verificationStatus, isDelegationValid } = useAuth(); // Reset wizard when opened and determine starting step React.useEffect(() => { @@ -44,7 +44,7 @@ export function WalletWizard({ } setIsLoading(false); } - }, [open, isAuthenticated, verificationStatus]); + }, [open, isAuthenticated, verificationStatus, isDelegationValid]); // Auto-advance from step 1 to 2 only when wallet connects during the session React.useEffect(() => { @@ -68,8 +68,27 @@ export function WalletWizard({ }; const getStepStatus = (step: WizardStep) => { - if (currentStep > step) return "completed"; - if (currentStep === step) return "current"; + // Step 1: Wallet connection - completed when authenticated + if (step === 1) { + if (isAuthenticated) return "completed"; + if (currentStep === step) return "current"; + return "pending"; + } + + // Step 2: Verification - completed when verified (either owner or none) + if (step === 2) { + if (verificationStatus === 'verified-owner' || verificationStatus === 'verified-none') return "completed"; + if (currentStep === step) return "current"; + return "pending"; + } + + // Step 3: Key delegation - completed when delegation is valid + if (step === 3) { + if (isDelegationValid()) return "completed"; + if (currentStep === step) return "current"; + return "pending"; + } + return "pending"; }; diff --git a/src/lib/identity/signatures/message-signing.ts b/src/lib/identity/signatures/message-signing.ts index 4a612a4..8c59ff9 100644 --- a/src/lib/identity/signatures/message-signing.ts +++ b/src/lib/identity/signatures/message-signing.ts @@ -1,8 +1,7 @@ import { OpchanMessage } from '@/types'; import { KeyDelegation } from './key-delegation'; -// Maximum age of a message in milliseconds (24 hours) -const MAX_MESSAGE_AGE = 24 * 60 * 60 * 1000; + export class MessageSigning { private keyDelegation: KeyDelegation; @@ -39,15 +38,12 @@ export class MessageSigning { verifyMessage(message: OpchanMessage): boolean { // Check for required signature fields if (!message.signature || !message.browserPubKey) { - console.warn('Message is missing signature information', message.id); + const messageId = 'id' in message ? message.id : `${message.type}-${message.timestamp}`; + console.warn('Message is missing signature information', messageId); return false; } - // Check if message is too old (anti-replay protection) - if (this.isMessageTooOld(message)) { - console.warn(`Message ${message.id} is too old (timestamp: ${message.timestamp})`); - return false; - } + // Reconstruct the original signed content const signedContent = JSON.stringify({ @@ -64,21 +60,12 @@ export class MessageSigning { ); if (!isValid) { - console.warn(`Invalid signature for message ${message.id}`); + const messageId = 'id' in message ? message.id : `${message.type}-${message.timestamp}`; + console.warn(`Invalid signature for message ${messageId}`); } return isValid; } - /** - * Checks if a message's timestamp is older than the maximum allowed age - */ - private isMessageTooOld(message: OpchanMessage): boolean { - if (!message.timestamp) return true; - - const currentTime = Date.now(); - const messageAge = currentTime - message.timestamp; - - return messageAge > MAX_MESSAGE_AGE; - } + } \ No newline at end of file