From e1df486b02e62a9a9890752d42141671c0f37e25 Mon Sep 17 00:00:00 2001 From: jxom <7336481+jxom@users.noreply.github.com> Date: Thu, 16 Jan 2025 11:31:28 +1100 Subject: [PATCH] feat: remove webauthn-p256 in favor of Ox (#3232) * feat: remove webauthn-p256 in favor of Ox Co-Authored-By: Micah Zoltu * chore: up size --------- Co-authored-by: Micah Zoltu --- .changeset/forty-walls-invite.md | 5 ++ package.json | 2 +- pnpm-lock.yaml | 65 +++++++++++++++---- .../accounts/createWebAuthnCredential.ts | 34 ++++++++-- .../implementations/toCoinbaseSmartAccount.ts | 10 ++- .../accounts/toWebAuthnAccount.test.ts | 32 ++++----- .../accounts/toWebAuthnAccount.ts | 20 ++++-- src/account-abstraction/accounts/types.ts | 9 ++- src/package.json | 3 +- 9 files changed, 132 insertions(+), 48 deletions(-) create mode 100644 .changeset/forty-walls-invite.md diff --git a/.changeset/forty-walls-invite.md b/.changeset/forty-walls-invite.md new file mode 100644 index 0000000000..0b176a8b1f --- /dev/null +++ b/.changeset/forty-walls-invite.md @@ -0,0 +1,5 @@ +--- +"viem": patch +--- + +Upgraded WebAuthn Accounts to use `ox` instead of `webauthn-p256`. diff --git a/package.json b/package.json index 234436ba8a..0bd4beeaad 100644 --- a/package.json +++ b/package.json @@ -127,7 +127,7 @@ { "name": "import * from 'viem/account-abstraction'", "path": "./src/_esm/account-abstraction/index.js", - "limit": "47 kB", + "limit": "49 kB", "import": "*" }, { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 659bde53eb..2cfa9ef677 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -56,7 +56,7 @@ importers: version: 20.16.12 '@vitest/coverage-v8': specifier: ^1.0.4 - version: 1.0.4(vitest@1.0.4(@types/node@20.16.12)(@vitest/ui@1.0.4)(terser@5.36.0)) + version: 1.0.4(vitest@1.0.4) '@vitest/ui': specifier: ^1.0.4 version: 1.0.4(vitest@1.0.4) @@ -559,11 +559,8 @@ importers: specifier: 1.0.6 version: 1.0.6(ws@8.18.0) ox: - specifier: 0.6.0 - version: 0.6.0(typescript@5.7.3)(zod@3.23.8) - webauthn-p256: - specifier: 0.0.10 - version: 0.0.10 + specifier: 0.6.5 + version: 0.6.5(typescript@5.7.3)(zod@3.23.8) ws: specifier: 8.18.0 version: 8.18.0 @@ -2642,7 +2639,6 @@ packages: bun@1.1.30: resolution: {integrity: sha512-ysRL1pq10Xba0jqVLPrKU3YIv0ohfp3cTajCPtpjCyppbn3lfiAVNpGoHfyaxS17OlPmWmR67UZRPw/EueQuug==} - cpu: [arm64, x64] os: [darwin, linux, win32] hasBin: true @@ -4284,6 +4280,14 @@ packages: typescript: optional: true + ox@0.6.5: + resolution: {integrity: sha512-vmnH8KvMDwFZDbNY1mq2CBRBWIgSliZB/dFV0xKp+DfF/dJkTENt6nmA+DzHSSAgL/GO2ydjkXWvlndJgSY4KQ==} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + p-filter@2.1.0: resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} engines: {node: '>=8'} @@ -5434,6 +5438,14 @@ packages: typescript: optional: true + viem@2.22.8: + resolution: {integrity: sha512-iB3PW/a/qzpYbpjo3R662u6a/zo6piZHez/N/bOC25C79FYXBCs8mQDqwiHk3FYErUhS4KVZLabKV9zGMd+EgQ==} + peerDependencies: + typescript: '>=5.0.4' + peerDependenciesMeta: + typescript: + optional: true + viem@file:src: resolution: {directory: src, type: directory} peerDependencies: @@ -6690,7 +6702,7 @@ snapshots: pino-http: 8.6.1 pino-pretty: 10.3.1 prom-client: 14.2.0 - viem: 2.22.7(typescript@5.6.2)(zod@3.23.8) + viem: 2.22.8(typescript@5.6.2)(zod@3.23.8) yargs: 17.7.2 zod: 3.23.8 zod-validation-error: 1.5.0(zod@3.23.8) @@ -7573,7 +7585,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitest/coverage-v8@1.0.4(vitest@1.0.4(@types/node@20.16.12)(@vitest/ui@1.0.4)(terser@5.36.0))': + '@vitest/coverage-v8@1.0.4(vitest@1.0.4)': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 0.2.3 @@ -9977,7 +9989,21 @@ snapshots: transitivePeerDependencies: - zod - ox@0.6.0(typescript@5.7.3)(zod@3.23.8): + ox@0.6.5(typescript@5.6.2)(zod@3.23.8): + dependencies: + '@adraffy/ens-normalize': 1.11.0 + '@noble/curves': 1.7.0 + '@noble/hashes': 1.6.1 + '@scure/bip32': 1.6.0 + '@scure/bip39': 1.5.0 + abitype: 1.0.7(typescript@5.6.2)(zod@3.23.8) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 5.6.2 + transitivePeerDependencies: + - zod + + ox@0.6.5(typescript@5.7.3)(zod@3.23.8): dependencies: '@adraffy/ens-normalize': 1.11.0 '@noble/curves': 1.7.0 @@ -11295,7 +11321,7 @@ snapshots: - utf-8-validate - zod - viem@file:src(typescript@5.6.2)(zod@3.23.8): + viem@2.22.8(typescript@5.6.2)(zod@3.23.8): dependencies: '@noble/curves': 1.7.0 '@noble/hashes': 1.6.1 @@ -11313,6 +11339,23 @@ snapshots: - utf-8-validate - zod + viem@file:src(typescript@5.6.2)(zod@3.23.8): + dependencies: + '@noble/curves': 1.7.0 + '@noble/hashes': 1.6.1 + '@scure/bip32': 1.6.0 + '@scure/bip39': 1.5.0 + abitype: 1.0.7(typescript@5.6.2)(zod@3.23.8) + isows: 1.0.6(ws@8.18.0) + ox: 0.6.5(typescript@5.6.2)(zod@3.23.8) + ws: 8.18.0 + optionalDependencies: + typescript: 5.6.2 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + - zod + vite-node@1.0.4(@types/node@20.16.12)(terser@5.36.0): dependencies: cac: 6.7.14 diff --git a/src/account-abstraction/accounts/createWebAuthnCredential.ts b/src/account-abstraction/accounts/createWebAuthnCredential.ts index 30415e9e80..6af6a0239d 100644 --- a/src/account-abstraction/accounts/createWebAuthnCredential.ts +++ b/src/account-abstraction/accounts/createWebAuthnCredential.ts @@ -1,7 +1,27 @@ -// biome-ignore lint/performance/noBarrelFile: -export { - type CreateCredentialParameters as CreateWebAuthnCredentialParameters, - type CreateCredentialReturnType as CreateWebAuthnCredentialReturnType, - type P256Credential, - createCredential as createWebAuthnCredential, -} from 'webauthn-p256' +// TODO(v3): Remove this in favor of `ox/WebAuthnP256` entirely. +import * as PublicKey from 'ox/PublicKey' +import * as WebAuthnP256 from 'ox/WebAuthnP256' + +import type { Hex } from '../../types/misc.js' + +export type P256Credential = { + id: WebAuthnP256.P256Credential['id'] + publicKey: Hex + raw: WebAuthnP256.P256Credential['raw'] +} + +export type CreateWebAuthnCredentialParameters = + WebAuthnP256.createCredential.Options + +export type CreateWebAuthnCredentialReturnType = P256Credential + +export async function createWebAuthnCredential( + parameters: CreateWebAuthnCredentialParameters, +): Promise { + const credential = await WebAuthnP256.createCredential(parameters) + return { + id: credential.id, + publicKey: PublicKey.toHex(credential.publicKey, { includePrefix: false }), + raw: credential.raw, + } +} diff --git a/src/account-abstraction/accounts/implementations/toCoinbaseSmartAccount.ts b/src/account-abstraction/accounts/implementations/toCoinbaseSmartAccount.ts index 8c5fb6472f..1927ad70e4 100644 --- a/src/account-abstraction/accounts/implementations/toCoinbaseSmartAccount.ts +++ b/src/account-abstraction/accounts/implementations/toCoinbaseSmartAccount.ts @@ -1,8 +1,6 @@ import type { Address, TypedData } from 'abitype' -import { - type WebAuthnData, - parseSignature as parseP256Signature, -} from 'webauthn-p256' +import * as Signature from 'ox/Signature' +import type * as WebAuthnP256 from 'ox/WebAuthnP256' import type { LocalAccount } from '../../../accounts/types.js' import { readContract } from '../../../actions/public/readContract.js' @@ -319,10 +317,10 @@ export function toWebAuthnSignature({ webauthn, signature, }: { - webauthn: WebAuthnData + webauthn: WebAuthnP256.SignMetadata signature: Hex }) { - const { r, s } = parseP256Signature(signature) + const { r, s } = Signature.fromHex(signature) return encodeAbiParameters( [ { diff --git a/src/account-abstraction/accounts/toWebAuthnAccount.test.ts b/src/account-abstraction/accounts/toWebAuthnAccount.test.ts index 2c421054b6..6fb6a1fbd0 100644 --- a/src/account-abstraction/accounts/toWebAuthnAccount.test.ts +++ b/src/account-abstraction/accounts/toWebAuthnAccount.test.ts @@ -1,6 +1,6 @@ +import { PublicKey, Signature, WebAuthnP256 } from 'ox' import { expect, test } from 'vitest' -import { verify } from 'webauthn-p256' import { typedData } from '../../../test/src/constants.js' import { hashMessage, hashTypedData, keccak256 } from '../../utils/index.js' import { toWebAuthnAccount } from './toWebAuthnAccount.js' @@ -109,11 +109,11 @@ test('sign', async () => { } `) - const valid = await verify({ - publicKey: account.publicKey, - signature, - webauthn, - hash: keccak256('0xdeadbeef'), + const valid = WebAuthnP256.verify({ + challenge: keccak256('0xdeadbeef'), + metadata: webauthn, + signature: Signature.fromHex(signature), + publicKey: PublicKey.fromHex(account.publicKey), }) expect(valid).toBeTruthy() }) @@ -169,11 +169,11 @@ test('signMessage', async () => { } `) - const valid = await verify({ - publicKey: account.publicKey, - signature, - webauthn, - hash: hashMessage('hello world'), + const valid = WebAuthnP256.verify({ + challenge: hashMessage('hello world'), + metadata: webauthn, + signature: Signature.fromHex(signature), + publicKey: PublicKey.fromHex(account.publicKey), }) expect(valid).toBeTruthy() }) @@ -230,14 +230,14 @@ test('signTypedData', async () => { } `) - const valid = await verify({ - publicKey: account.publicKey, - signature, - webauthn, - hash: hashTypedData({ + const valid = WebAuthnP256.verify({ + challenge: hashTypedData({ ...typedData.basic, primaryType: 'Mail', }), + metadata: webauthn, + signature: Signature.fromHex(signature), + publicKey: PublicKey.fromHex(account.publicKey), }) expect(valid).toBeTruthy() }) diff --git a/src/account-abstraction/accounts/toWebAuthnAccount.ts b/src/account-abstraction/accounts/toWebAuthnAccount.ts index 1983ecf548..24fb02bae5 100644 --- a/src/account-abstraction/accounts/toWebAuthnAccount.ts +++ b/src/account-abstraction/accounts/toWebAuthnAccount.ts @@ -1,8 +1,10 @@ -import { type P256Credential, type SignParameters, sign } from 'webauthn-p256' +import * as Signature from 'ox/Signature' +import * as WebAuthnP256 from 'ox/WebAuthnP256' import type { ErrorType } from '../../errors/utils.js' import { hashMessage } from '../../utils/signature/hashMessage.js' import { hashTypedData } from '../../utils/signature/hashTypedData.js' +import type { P256Credential } from './createWebAuthnCredential.js' import type { WebAuthnAccount } from './types.js' export type ToWebAuthnAccountParameters = { @@ -19,11 +21,11 @@ export type ToWebAuthnAccountParameters = { * * @default window.navigator.credentials.get */ - getFn?: SignParameters['getFn'] | undefined + getFn?: WebAuthnP256.sign.Options['getFn'] | undefined /** * The relying party identifier to use. */ - rpId?: SignParameters['rpId'] | undefined + rpId?: WebAuthnP256.sign.Options['rpId'] | undefined } export type ToWebAuthnAccountReturnType = WebAuthnAccount @@ -44,7 +46,17 @@ export function toWebAuthnAccount( id, publicKey, async sign({ hash }) { - return sign({ credentialId: id, getFn, hash, rpId }) + const { metadata, raw, signature } = await WebAuthnP256.sign({ + credentialId: id, + getFn, + challenge: hash, + rpId, + }) + return { + signature: Signature.toHex(signature), + raw, + webauthn: metadata, + } }, async signMessage({ message }) { return this.sign({ hash: hashMessage(message) }) diff --git a/src/account-abstraction/accounts/types.ts b/src/account-abstraction/accounts/types.ts index 4eeacdf457..7005de9fdc 100644 --- a/src/account-abstraction/accounts/types.ts +++ b/src/account-abstraction/accounts/types.ts @@ -1,5 +1,5 @@ import type { Abi, Address, TypedData } from 'abitype' -import type { SignReturnType as WebAuthnSignReturnType } from 'webauthn-p256' +import type * as WebAuthnP256 from 'ox/WebAuthnP256' import type { Client } from '../../clients/createClient.js' import type { Hash, Hex, SignableMessage } from '../../types/misc.js' @@ -219,6 +219,13 @@ export type SmartAccount< > > +// TODO(v3): Remove this in favor of `WebAuthnP256.sign.ReturnType` from Ox. +export type WebAuthnSignReturnType = { + signature: Hex + webauthn: WebAuthnP256.SignMetadata + raw: WebAuthnP256.sign.ReturnType['raw'] +} + export type WebAuthnAccount = { id: string publicKey: Hex diff --git a/src/package.json b/src/package.json index de2b50934c..050722b3bf 100644 --- a/src/package.json +++ b/src/package.json @@ -151,8 +151,7 @@ "@scure/bip39": "1.5.0", "abitype": "1.0.7", "isows": "1.0.6", - "ox": "0.6.0", - "webauthn-p256": "0.0.10", + "ox": "0.6.5", "ws": "8.18.0" }, "license": "MIT",