Skip to content

Commit

Permalink
handle non resident keys (#498)
Browse files Browse the repository at this point in the history
* add byteaToBase64

* handle non-resident keys, enforce new keys are residents
  • Loading branch information
0xBigBoss authored Jun 28, 2024
1 parent a819220 commit 8ef8303
Show file tree
Hide file tree
Showing 18 changed files with 147 additions and 304 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ export function ConfirmButton({
const media = useMedia()
const { updateProfile } = useUser()
const { data: sendAccount } = useSendAccount()
const webauthnCreds =
sendAccount?.send_account_credentials
.filter((c) => !!c.webauthn_credentials)
.map((c) => c.webauthn_credentials as NonNullable<typeof c.webauthn_credentials>) ?? []
//Connect
const chainId = baseMainnetClient.chain.id
const pendingTags = usePendingTags()
Expand Down Expand Up @@ -193,7 +197,7 @@ export function ConfirmButton({
try {
throwIf(userOpError)
assert(!!userOp, 'User op is required')
await sendUserOp({ userOp })
await sendUserOp({ userOp, webauthnCreds })
} catch (e) {
setError(e.message.split('.').at(0))
}
Expand Down
6 changes: 5 additions & 1 deletion packages/app/features/account/settings/backup/confirm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ const AddSignerButton = ({ webauthnCred }: { webauthnCred: Tables<'webauthn_cred
const keySlot = sendAccount?.send_account_credentials?.find(
(c) => c.webauthn_credentials?.raw_credential_id === webauthnCred.raw_credential_id
)?.key_slot
const webauthnCreds =
sendAccount?.send_account_credentials
.filter((c) => !!c.webauthn_credentials && c.key_slot !== keySlot)
.map((c) => c.webauthn_credentials as NonNullable<typeof c.webauthn_credentials>) ?? []
const router = useRouter()
const form = useForm()
const {
Expand Down Expand Up @@ -194,7 +198,7 @@ const AddSignerButton = ({ webauthnCred }: { webauthnCred: Tables<'webauthn_cred
assert(!!userOp, 'User op is required')
const {
receipt: { transactionHash },
} = await sendUserOp({ userOp })
} = await sendUserOp({ userOp, webauthnCreds })
console.log('sent user op', transactionHash)
toast.show('Success!')
router.replace('/account/settings/backup')
Expand Down
6 changes: 5 additions & 1 deletion packages/app/features/account/settings/backup/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,10 @@ const RemovePasskeyConfirmation = ({
error: sendAccountError,
isLoading: isLoadingSendAccount,
} = useSendAccount()
const webauthnCreds =
sendAccount?.send_account_credentials
.filter((c) => !!c.webauthn_credentials)
.map((c) => c.webauthn_credentials as NonNullable<typeof c.webauthn_credentials>) ?? []
const {
data: usdcBal,
error: usdcBalError,
Expand Down Expand Up @@ -440,7 +444,7 @@ const RemovePasskeyConfirmation = ({
assert((usdcBal?.value ?? 0n) > 0n, 'No USDC balance to pay for gas fees')
assert(!!userOp, 'User op is required')

await sendUserOp({ userOp })
await sendUserOp({ userOp, webauthnCreds })
}

const { error } = await supabase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ interface Props {

export default function RecoverWithPasskey(props: Props) {
const onPress = async () => {
const rawIdsB64: { id: string; userHandle: string }[] = [] // this user is anon so only resident keys are allowed
const { encodedWebAuthnSig, accountName, keySlot } = await signChallenge(
props.challengeData.challenge as `0x${string}`
props.challengeData.challenge as `0x${string}`,
rawIdsB64
)

// SendVerifier.verifySignature expects the first byte to be the passkey keySlot, followed by the signature
Expand Down
277 changes: 0 additions & 277 deletions packages/app/features/send/confirm/index.tsx

This file was deleted.

5 changes: 5 additions & 0 deletions packages/app/features/send/confirm/screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ export function SendConfirmScreen() {

export function SendConfirm({ profile }: { profile: ProfileProp }) {
const { data: sendAccount } = useSendAccount()
const webauthnCreds =
sendAccount?.send_account_credentials
.filter((c) => !!c.webauthn_credentials)
.map((c) => c.webauthn_credentials as NonNullable<typeof c.webauthn_credentials>) ?? []
const [sentTxHash, setSentTxHash] = useState<Hex>()
const [queryParams] = useSendScreenParams()
const { sendToken, recipient, idType } = queryParams
Expand Down Expand Up @@ -134,6 +138,7 @@ export function SendConfirm({ profile }: { profile: ProfileProp }) {

const receipt = await sendUserOp({
userOp,
webauthnCreds,
})
assert(receipt.success, 'Failed to send user op')
setSentTxHash(receipt.receipt.transactionHash)
Expand Down
20 changes: 20 additions & 0 deletions packages/app/utils/byteaToBase64.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { describe, expect, it } from '@jest/globals'

import { byteaToBase64 } from './byteaToBase64'

describe('test byteaToBase64', () => {
it('test byteaToBase64', () => {
expect(byteaToBase64('\\x')).toBe('') // empty string
expect(byteaToBase64('\\x1234')).toBe('EjQ=') // single character
expect(byteaToBase64('\\x12345678')).toBe('EjRWeA==') // two characters
expect(byteaToBase64('\\x1234567890')).toBe('EjRWeJA=') // three characters
})
it('fails on invalid input', () => {
// @ts-expect-error Testing with null or empty string
expect(() => byteaToBase64('invalid-string')).toThrow('Hex string must start with \\x')
// @ts-expect-error Testing with null or empty string
expect(() => byteaToBase64('0x12345678901234567890123456789012345678901234')).toThrow(
'Hex string must start with \\x'
)
})
})
Loading

0 comments on commit 8ef8303

Please sign in to comment.