[TASK-8116] feat: persist webauthn data#623
Conversation
After register o login, persist the webauthn data in local storage so it can be used to create the passkey validator and kernel client without needing to ask for passkey again (except for operations of course).
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
WalkthroughThe pull request introduces significant changes to the passkey and wallet management system. The modifications focus on improving the handling of WebAuthn keys, local storage operations, and the setup process for passkeys. The changes involve refactoring the context management, enhancing local storage utility functions, and streamlining the component logic for passkey registration and account setup. Changes
Sequence DiagramsequenceDiagram
participant User
participant SetupPasskey
participant ZeroDevContext
participant LocalStorage
User->>SetupPasskey: Initiate Registration
SetupPasskey->>ZeroDevContext: handleRegister()
ZeroDevContext->>LocalStorage: Save WebAuthnKey
ZeroDevContext-->>SetupPasskey: Registration Complete
SetupPasskey->>ZeroDevContext: Add Account
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (4)
src/utils/general.utils.ts (2)
87-98: Enhance bigint serialization with type safety.The implementation correctly handles
bigintserialization, but it could benefit from type safety improvements.Consider this type-safe implementation:
if (typeof localStorage === 'undefined') return try { // Convert the data to a string before storing it in localStorage - const serializedData = JSON.stringify(data, (_key, value) => { - if ('bigint' === typeof value) { - return { - '@type': 'BigInt', - value: value.toString(), - } - } - return value - }) + const serializedData = JSON.stringify(data, (_key, value) => { + if (typeof value === 'bigint') { + return { + '@type': 'BigInt' as const, + value: value.toString(), + } + } + return value + }) localStorage.setItem(key, serializedData) console.log(`Saved ${key} to localStorage:`, data)
107-119: Improve bigint deserialization with type guards.The implementation correctly handles
bigintdeserialization, but it could benefit from type safety improvements.Consider this type-safe implementation:
if (typeof localStorage === 'undefined') return try { const data = localStorage.getItem(key) if (data === null) { console.log(`No data found in localStorage for ${key}`) return null } - const parsedData = JSON.parse(data, (_key, value) => { - if (value && typeof value === 'object' && value['@type'] === 'BigInt') { - return BigInt(value.value) - } - return value - }) + const parsedData = JSON.parse(data, (_key, value) => { + if (value && + typeof value === 'object' && + '@type' in value && + value['@type'] === 'BigInt' && + 'value' in value && + typeof value.value === 'string') { + return BigInt(value.value) + } + return value + }) console.log(`Retrieved ${key} from localStorage:`, parsedData) return parsedDatasrc/components/Setup/Views/SetupPasskey.tsx (2)
31-43: Enhance error handling specificityWhile error handling is implemented, the error message is generic and doesn't provide specific feedback to users about what went wrong during passkey registration.
Consider this enhancement:
onClick={async () => { try { await handleRegister(handle) } catch (e) { console.error('Error registering passkey', e) - setError('Error registering passkey') + setError( + e instanceof Error + ? e.message + : 'Failed to register passkey. Please try again.' + ) } }}
46-46: Enhance error message accessibilityThe error message should be more accessible to screen readers.
Consider this enhancement:
- {error && <p className="text-sm font-bold text-error">{error}</p>} + {error && ( + <p + role="alert" + aria-live="polite" + className="text-sm font-bold text-error" + > + {error} + </p> + )}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/components/Setup/Setup.helpers.ts(0 hunks)src/components/Setup/Views/SetupPasskey.tsx(1 hunks)src/context/walletContext/zeroDevContext.context.tsx(7 hunks)src/utils/general.utils.ts(2 hunks)
💤 Files with no reviewable changes (1)
- src/components/Setup/Setup.helpers.ts
🔇 Additional comments (2)
src/utils/general.utils.ts (1)
Line range hint
87-119: Verify WebAuthn data serialization.The enhanced local storage utilities correctly handle
bigintvalues, which is crucial for storing WebAuthn credentials. Let's verify that all WebAuthn-related data is properly serialized.✅ Verification successful
WebAuthn data serialization implementation verified successfully
The enhanced localStorage utilities are properly integrated with the WebAuthn implementation in
zeroDevContext.context.tsx, correctly handling WebAuthn credentials during both registration and login flows. The bigint serialization enhancement is actively used and necessary for storing WebAuthn keys.🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check for WebAuthn-related data structures and their usage of bigint values # Test: Search for WebAuthn credential structures rg -A 5 "interface.*Credential|type.*Credential" # Test: Search for WebAuthn-related local storage operations rg -A 5 "saveToLocalStorage.*[Cc]redential|getFromLocalStorage.*[Cc]redential"Length of output: 131
Script:
#!/bin/bash # Search for WebAuthn-related files and code rg -i "webauthn" --type ts # Search for actual usage of the enhanced localStorage utilities rg -A 5 "saveToLocalStorage\(|getFromLocalStorage\(" --type tsLength of output: 3490
src/components/Setup/Views/SetupPasskey.tsx (1)
7-7: Verify WebAuthn data persistence implementationWhile the component now handles address and user state, I don't see explicit persistence of WebAuthn data to local storage as mentioned in the PR objectives. This might affect the requirement of not asking users to input their passkey again.
Let's verify if the persistence is handled elsewhere:
Also applies to: 12-13
✅ Verification successful
WebAuthn persistence implementation verified
The WebAuthn data persistence is properly implemented through the zeroDevContext, which handles storage via
LOCAL_STORAGE_WEB_AUTHN_KEY. The SetupPasskey component correctly integrates with this context through theuseZeroDevhook, ensuring proper persistence of passkey data.🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Search for WebAuthn/passkey related storage operations rg -i "localStorage.*(webauthn|passkey)" # Search for potential storage utility functions rg -i "storage.*webauthn|passkey.*storage" # Look for any WebAuthn related classes/interfaces ast-grep --pattern 'interface $INTERFACE { $$$ webauthn $$$ }'Length of output: 662
Script:
#!/bin/bash # Check for zeroDevContext usage in SetupPasskey rg -l "useZeroDev|zeroDevContext" src/components/Setup/Views/SetupPasskey.tsx # Find saveToLocalStorage implementation ast-grep --pattern 'function saveToLocalStorage($_,$_) { $$$ }' # Look for LOCAL_STORAGE_WEB_AUTHN_KEY definition rg "LOCAL_STORAGE_WEB_AUTHN_KEY.*=" -A 1 # Get more context around the storage operations rg -B 2 -A 2 "saveToLocalStorage.*WEB_AUTHN_KEY"Length of output: 1358
Script:
#!/bin/bash # Get context usage in SetupPasskey rg -A 5 -B 5 "useZeroDev|zeroDevContext" src/components/Setup/Views/SetupPasskey.tsx # Look for any webauthn/passkey related state or effects rg -A 3 "useState|useEffect" src/components/Setup/Views/SetupPasskey.tsx # Check for any registration or setup handlers ast-grep --pattern 'const $HANDLER = async () => { $$$ }' src/components/Setup/Views/SetupPasskey.tsxLength of output: 1265
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/components/Setup/Views/SetupPasskey.tsx (2)
16-31: Consider simplifying the effect implementation.The current implementation could be improved for better maintainability and type safety:
useEffect(() => { if (address && user) { - addAccount({ - accountIdentifier: address, - accountType: WalletProviderType.PEANUT, - userId: user?.user.userId as string, - }) - .then(() => { - handleNext() - }) - .catch((e) => { - console.error('Error adding account', e) - setError('Error adding account') - }) + const setupAccount = async () => { + try { + if (!user.user.userId) throw new Error('User ID is required') + await addAccount({ + accountIdentifier: address, + accountType: WalletProviderType.PEANUT, + userId: user.user.userId, + }) + handleNext() + } catch (e) { + console.error('Error adding account', e) + setError('Error adding account') + } + } + setupAccount() } }, [address, addAccount, user, handleNext])
35-47: Consider using more semantic class names.The button implementation looks good with proper error handling and loading state. However, consider using a more semantic class name instead of
text-nowrap.- className="text-nowrap" + className="whitespace-nowrap"
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/components/Setup/Views/SetupPasskey.tsx(1 hunks)
🔇 Additional comments (3)
src/components/Setup/Views/SetupPasskey.tsx (3)
7-7: LGTM! Clean hook implementation.The added imports and hook usage follow React best practices, with clear destructuring of required dependencies.
Also applies to: 12-13
16-31: Error handling implementation looks good!The error handling follows the previously suggested pattern, properly catching and displaying errors to users.
37-43: Verify webauthn data persistence.The registration handler is implemented, but let's verify that the webauthn data is properly persisted in local storage after registration.
✅ Verification successful
WebAuthn data persistence is properly implemented.
The implementation correctly persists WebAuthn data in localStorage after successful passkey registration, using ZeroDev's passkey validator. The data is stored with a dedicated key and is properly reused during subsequent authentications.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Search for local storage persistence of webauthn data rg -A 5 'localStorage.setItem.*webauthn|localStorage.getItem.*webauthn'Length of output: 73
Script:
#!/bin/bash # Search for handleRegister implementation and storage patterns ast-grep --pattern 'const handleRegister = async $_' # Search for alternative storage patterns rg -A 5 "setItem|getItem" # Search for credential storage patterns rg -A 5 "credential.*store|store.*credential"Length of output: 14381
Script:
#!/bin/bash # Search for auth-related files fd "auth|webauthn|passkey" --type f # Search for authentication-related patterns rg -A 5 "webauthn|passkey|authenticator|credential" # Look for specific setup component implementation ast-grep --pattern 'function SetupPasskey'Length of output: 15135
kushagrasarathe
left a comment
There was a problem hiding this comment.
@jjramirezn added one nit, rest lgtm 🫡
| ////// Lifecycle hooks | ||
| // | ||
| useEffect(() => { | ||
| const storedWebAuthnKey = getFromLocalStorage(LOCAL_STORAGE_WEB_AUTHN_KEY) |
There was a problem hiding this comment.
@jjramirezn we have UserPreferences in utils, which maintains other keys in local-storage and is being commonly used, lets use that here 🫡
There was a problem hiding this comment.
webauthn key is not an user preference and very particular for the web authentication flow so I'm ok having it as another key
|
|
||
| return client | ||
| setWebAuthnKey(webAuthnKey) | ||
| saveToLocalStorage(LOCAL_STORAGE_WEB_AUTHN_KEY, webAuthnKey) |
There was a problem hiding this comment.
same updateUserPreferences in utils
After register o login, persist the webauthn data in local storage so it can be used to create the passkey validator and kernel client without needing to ask for passkey again (except for operations of course).
Summary by CodeRabbit
Refactor
Bug Fixes
Chores