@zerodev/permissions 5.2.1-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/_cjs/constants.js +17 -0
  2. package/_cjs/constants.js.map +1 -0
  3. package/_cjs/deserializePermissionAccount.js +94 -0
  4. package/_cjs/deserializePermissionAccount.js.map +1 -0
  5. package/_cjs/index.js +12 -0
  6. package/_cjs/index.js.map +1 -0
  7. package/_cjs/package.json +1 -0
  8. package/_cjs/policies/callPolicyUtils.js +87 -0
  9. package/_cjs/policies/callPolicyUtils.js.map +1 -0
  10. package/_cjs/policies/index.js +16 -0
  11. package/_cjs/policies/index.js.map +1 -0
  12. package/_cjs/policies/toCallPolicy.js +42 -0
  13. package/_cjs/policies/toCallPolicy.js.map +1 -0
  14. package/_cjs/policies/toGasPolicy.js +30 -0
  15. package/_cjs/policies/toGasPolicy.js.map +1 -0
  16. package/_cjs/policies/toRateLimitPolicy.js +30 -0
  17. package/_cjs/policies/toRateLimitPolicy.js.map +1 -0
  18. package/_cjs/policies/toSignatureCallerPolicy.js +24 -0
  19. package/_cjs/policies/toSignatureCallerPolicy.js.map +1 -0
  20. package/_cjs/policies/toSudoPolicy.js +22 -0
  21. package/_cjs/policies/toSudoPolicy.js.map +1 -0
  22. package/_cjs/policies/types.js +19 -0
  23. package/_cjs/policies/types.js.map +1 -0
  24. package/_cjs/policies/utils/toPolicyId.js +11 -0
  25. package/_cjs/policies/utils/toPolicyId.js.map +1 -0
  26. package/_cjs/serializePermissionAccount.js +27 -0
  27. package/_cjs/serializePermissionAccount.js.map +1 -0
  28. package/_cjs/signers/index.js +12 -0
  29. package/_cjs/signers/index.js.map +1 -0
  30. package/_cjs/signers/toECDSASigner.js +39 -0
  31. package/_cjs/signers/toECDSASigner.js.map +1 -0
  32. package/_cjs/signers/toWebAuthnPubKey.js +97 -0
  33. package/_cjs/signers/toWebAuthnPubKey.js.map +1 -0
  34. package/_cjs/signers/toWebAuthnSigner.js +154 -0
  35. package/_cjs/signers/toWebAuthnSigner.js.map +1 -0
  36. package/_cjs/signers/utils/toSignerId.js +9 -0
  37. package/_cjs/signers/utils/toSignerId.js.map +1 -0
  38. package/_cjs/signers/webAuthnUtils.js +45 -0
  39. package/_cjs/signers/webAuthnUtils.js.map +1 -0
  40. package/_cjs/toPermissionValidator.js +102 -0
  41. package/_cjs/toPermissionValidator.js.map +1 -0
  42. package/_cjs/types.js +3 -0
  43. package/_cjs/types.js.map +1 -0
  44. package/_cjs/utils.js +37 -0
  45. package/_cjs/utils.js.map +1 -0
  46. package/_esm/constants.js +14 -0
  47. package/_esm/constants.js.map +1 -0
  48. package/_esm/deserializePermissionAccount.js +89 -0
  49. package/_esm/deserializePermissionAccount.js.map +1 -0
  50. package/_esm/index.js +5 -0
  51. package/_esm/index.js.map +1 -0
  52. package/_esm/package.json +1 -0
  53. package/_esm/policies/callPolicyUtils.js +82 -0
  54. package/_esm/policies/callPolicyUtils.js.map +1 -0
  55. package/_esm/policies/index.js +7 -0
  56. package/_esm/policies/index.js.map +1 -0
  57. package/_esm/policies/toCallPolicy.js +38 -0
  58. package/_esm/policies/toCallPolicy.js.map +1 -0
  59. package/_esm/policies/toGasPolicy.js +26 -0
  60. package/_esm/policies/toGasPolicy.js.map +1 -0
  61. package/_esm/policies/toRateLimitPolicy.js +26 -0
  62. package/_esm/policies/toRateLimitPolicy.js.map +1 -0
  63. package/_esm/policies/toSignatureCallerPolicy.js +20 -0
  64. package/_esm/policies/toSignatureCallerPolicy.js.map +1 -0
  65. package/_esm/policies/toSudoPolicy.js +18 -0
  66. package/_esm/policies/toSudoPolicy.js.map +1 -0
  67. package/_esm/policies/types.js +17 -0
  68. package/_esm/policies/types.js.map +1 -0
  69. package/_esm/policies/utils/toPolicyId.js +7 -0
  70. package/_esm/policies/utils/toPolicyId.js.map +1 -0
  71. package/_esm/serializePermissionAccount.js +23 -0
  72. package/_esm/serializePermissionAccount.js.map +1 -0
  73. package/_esm/signers/index.js +5 -0
  74. package/_esm/signers/index.js.map +1 -0
  75. package/_esm/signers/toECDSASigner.js +36 -0
  76. package/_esm/signers/toECDSASigner.js.map +1 -0
  77. package/_esm/signers/toWebAuthnPubKey.js +107 -0
  78. package/_esm/signers/toWebAuthnPubKey.js.map +1 -0
  79. package/_esm/signers/toWebAuthnSigner.js +164 -0
  80. package/_esm/signers/toWebAuthnSigner.js.map +1 -0
  81. package/_esm/signers/utils/toSignerId.js +5 -0
  82. package/_esm/signers/utils/toSignerId.js.map +1 -0
  83. package/_esm/signers/webAuthnUtils.js +41 -0
  84. package/_esm/signers/webAuthnUtils.js.map +1 -0
  85. package/_esm/toPermissionValidator.js +98 -0
  86. package/_esm/toPermissionValidator.js.map +1 -0
  87. package/_esm/types.js +3 -0
  88. package/_esm/types.js.map +1 -0
  89. package/_esm/utils.js +32 -0
  90. package/_esm/utils.js.map +1 -0
  91. package/_types/constants.d.ts +13 -0
  92. package/_types/constants.d.ts.map +1 -0
  93. package/_types/deserializePermissionAccount.d.ts +13 -0
  94. package/_types/deserializePermissionAccount.d.ts.map +1 -0
  95. package/_types/index.d.ts +6 -0
  96. package/_types/index.d.ts.map +1 -0
  97. package/_types/policies/callPolicyUtils.d.ts +5 -0
  98. package/_types/policies/callPolicyUtils.d.ts.map +1 -0
  99. package/_types/policies/index.d.ts +7 -0
  100. package/_types/policies/index.d.ts.map +1 -0
  101. package/_types/policies/toCallPolicy.d.ts +9 -0
  102. package/_types/policies/toCallPolicy.d.ts.map +1 -0
  103. package/_types/policies/toGasPolicy.d.ts +10 -0
  104. package/_types/policies/toGasPolicy.d.ts.map +1 -0
  105. package/_types/policies/toRateLimitPolicy.d.ts +9 -0
  106. package/_types/policies/toRateLimitPolicy.d.ts.map +1 -0
  107. package/_types/policies/toSignatureCallerPolicy.d.ts +8 -0
  108. package/_types/policies/toSignatureCallerPolicy.d.ts.map +1 -0
  109. package/_types/policies/toSudoPolicy.d.ts +6 -0
  110. package/_types/policies/toSudoPolicy.d.ts.map +1 -0
  111. package/_types/policies/types.d.ts +56 -0
  112. package/_types/policies/types.d.ts.map +1 -0
  113. package/_types/policies/utils/toPolicyId.d.ts +4 -0
  114. package/_types/policies/utils/toPolicyId.d.ts.map +1 -0
  115. package/_types/serializePermissionAccount.d.ts +5 -0
  116. package/_types/serializePermissionAccount.d.ts.map +1 -0
  117. package/_types/signers/index.d.ts +5 -0
  118. package/_types/signers/index.d.ts.map +1 -0
  119. package/_types/signers/toECDSASigner.d.ts +8 -0
  120. package/_types/signers/toECDSASigner.d.ts.map +1 -0
  121. package/_types/signers/toWebAuthnPubKey.d.ts +11 -0
  122. package/_types/signers/toWebAuthnPubKey.d.ts.map +1 -0
  123. package/_types/signers/toWebAuthnSigner.d.ts +16 -0
  124. package/_types/signers/toWebAuthnSigner.d.ts.map +1 -0
  125. package/_types/signers/utils/toSignerId.d.ts +4 -0
  126. package/_types/signers/utils/toSignerId.d.ts.map +1 -0
  127. package/_types/signers/webAuthnUtils.d.ts +13 -0
  128. package/_types/signers/webAuthnUtils.d.ts.map +1 -0
  129. package/_types/toPermissionValidator.d.ts +5 -0
  130. package/_types/toPermissionValidator.d.ts.map +1 -0
  131. package/_types/types.d.ts +49 -0
  132. package/_types/types.d.ts.map +1 -0
  133. package/_types/utils.d.ts +8 -0
  134. package/_types/utils.d.ts.map +1 -0
  135. package/constants.ts +17 -0
  136. package/deserializePermissionAccount.ts +119 -0
  137. package/index.ts +5 -0
  138. package/package.json +63 -0
  139. package/policies/callPolicyUtils.ts +122 -0
  140. package/policies/index.ts +12 -0
  141. package/policies/toCallPolicy.ts +65 -0
  142. package/policies/toGasPolicy.ts +44 -0
  143. package/policies/toRateLimitPolicy.ts +43 -0
  144. package/policies/toSignatureCallerPolicy.ts +34 -0
  145. package/policies/toSudoPolicy.ts +27 -0
  146. package/policies/types.ts +118 -0
  147. package/policies/utils/toPolicyId.ts +13 -0
  148. package/serializePermissionAccount.ts +38 -0
  149. package/signers/index.ts +10 -0
  150. package/signers/toECDSASigner.ts +61 -0
  151. package/signers/toWebAuthnPubKey.ts +152 -0
  152. package/signers/toWebAuthnSigner.ts +245 -0
  153. package/signers/utils/toSignerId.ts +9 -0
  154. package/signers/webAuthnUtils.ts +54 -0
  155. package/toPermissionValidator.ts +152 -0
  156. package/types.ts +71 -0
  157. package/utils.ts +42 -0
@@ -0,0 +1,43 @@
1
+ import { concatHex } from "viem"
2
+ import { PolicyFlags } from "../constants.js"
3
+ import { RATE_LIMIT_POLICY_CONTRACT } from "../constants.js"
4
+ import type { Policy, PolicyParams } from "../types.js"
5
+
6
+ export type RateLimitPolicyParams = PolicyParams & {
7
+ interval?: number
8
+ count: number
9
+ startAt?: number
10
+ type?: "rate-limit"
11
+ }
12
+
13
+ export async function toRateLimitPolicy({
14
+ policyAddress = RATE_LIMIT_POLICY_CONTRACT,
15
+ policyFlag = PolicyFlags.FOR_ALL_VALIDATION,
16
+ interval = 0,
17
+ count,
18
+ startAt = 0,
19
+ type = "rate-limit"
20
+ }: RateLimitPolicyParams): Promise<Policy> {
21
+ return {
22
+ getPolicyData: () => {
23
+ const intervalHex = interval.toString(16).padStart(12, "0")
24
+ const countHex = count.toString(16).padStart(12, "0")
25
+ const startAtHex = startAt.toString(16).padStart(12, "0")
26
+
27
+ const data = intervalHex + countHex + startAtHex
28
+
29
+ return `0x${data}`
30
+ },
31
+ getPolicyInfoInBytes: () => {
32
+ return concatHex([policyFlag, policyAddress])
33
+ },
34
+ policyParams: {
35
+ type,
36
+ policyAddress,
37
+ policyFlag,
38
+ interval,
39
+ count,
40
+ startAt
41
+ }
42
+ }
43
+ }
@@ -0,0 +1,34 @@
1
+ import { type Address, concatHex, encodeAbiParameters } from "viem"
2
+ import { PolicyFlags } from "../constants.js"
3
+ import { SIGNATURE_POLICY_CONTRACT } from "../constants.js"
4
+ import type { Policy, PolicyParams } from "../types.js"
5
+
6
+ export type SignatureCallerPolicyParams = PolicyParams & {
7
+ allowedCallers: Address[]
8
+ type?: "signature-caller"
9
+ }
10
+
11
+ export async function toSignatureCallerPolicy({
12
+ policyAddress = SIGNATURE_POLICY_CONTRACT,
13
+ policyFlag = PolicyFlags.FOR_ALL_VALIDATION,
14
+ allowedCallers,
15
+ type = "signature-caller"
16
+ }: SignatureCallerPolicyParams): Promise<Policy> {
17
+ return {
18
+ getPolicyData: () => {
19
+ return encodeAbiParameters(
20
+ [{ name: "allowedCallers", type: "address[]" }],
21
+ [allowedCallers]
22
+ )
23
+ },
24
+ getPolicyInfoInBytes: () => {
25
+ return concatHex([policyFlag, policyAddress])
26
+ },
27
+ policyParams: {
28
+ type,
29
+ policyAddress,
30
+ policyFlag,
31
+ allowedCallers
32
+ }
33
+ }
34
+ }
@@ -0,0 +1,27 @@
1
+ import { concatHex } from "viem"
2
+ import { PolicyFlags, SUDO_POLICY_CONTRACT } from "../constants.js"
3
+ import type { Policy, PolicyParams } from "../types.js"
4
+
5
+ export type SudoPolicyParams = PolicyParams & {
6
+ type?: "sudo"
7
+ }
8
+
9
+ export async function toSudoPolicy({
10
+ policyAddress = SUDO_POLICY_CONTRACT,
11
+ policyFlag = PolicyFlags.FOR_ALL_VALIDATION,
12
+ type = "sudo"
13
+ }: SudoPolicyParams): Promise<Policy> {
14
+ return {
15
+ getPolicyData: () => {
16
+ return "0x"
17
+ },
18
+ getPolicyInfoInBytes: () => {
19
+ return concatHex([policyFlag, policyAddress])
20
+ },
21
+ policyParams: {
22
+ type,
23
+ policyAddress,
24
+ policyFlag
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,118 @@
1
+ import { type ExtractAbiFunction, type ExtractAbiFunctionNames } from "abitype"
2
+ import type {
3
+ Abi,
4
+ AbiFunction,
5
+ AbiParameter,
6
+ AbiParameterKind,
7
+ AbiParameterToPrimitiveType,
8
+ AbiStateMutability,
9
+ Address,
10
+ Hex,
11
+ Narrow
12
+ } from "viem"
13
+
14
+ export enum CallType {
15
+ CALL = "0x00",
16
+ BATCH_CALL = "0x01",
17
+ DELEGATE_CALL = "0xff"
18
+ }
19
+
20
+ export enum ParamCondition {
21
+ EQUAL = 0,
22
+ GREATER_THAN = 1,
23
+ LESS_THAN = 2,
24
+ GREATER_THAN_OR_EQUAL = 3,
25
+ LESS_THAN_OR_EQUAL = 4,
26
+ NOT_EQUAL = 5
27
+ }
28
+
29
+ export interface ParamRule {
30
+ condition: ParamCondition
31
+ offset: number
32
+ param: Hex
33
+ }
34
+
35
+ export type PermissionCore = {
36
+ callType?: CallType
37
+ target: Address
38
+ selector?: Hex
39
+ valueLimit?: bigint
40
+ rules?: ParamRule[]
41
+ }
42
+
43
+ export type InferFunctionName<
44
+ TAbi extends Abi | readonly unknown[] = Abi,
45
+ TFunctionName extends string | undefined = string,
46
+ TAbiStateMutability extends AbiStateMutability = AbiStateMutability
47
+ > = TAbi extends Abi
48
+ ? ExtractAbiFunctionNames<
49
+ TAbi,
50
+ TAbiStateMutability
51
+ > extends infer AbiFunctionNames
52
+ ?
53
+ | AbiFunctionNames
54
+ | (TFunctionName extends AbiFunctionNames ? TFunctionName : never)
55
+ | (Abi extends TAbi ? string : never)
56
+ : never
57
+ : TFunctionName
58
+
59
+ export type GetFunctionArgs<
60
+ TAbi extends Abi | readonly unknown[],
61
+ TFunctionName extends string,
62
+ TAbiFunction extends AbiFunction = TAbi extends Abi
63
+ ? ExtractAbiFunction<TAbi, TFunctionName>
64
+ : AbiFunction,
65
+ TArgs = CombinedArgs<TAbiFunction["inputs"]>,
66
+ FailedToParseArgs =
67
+ | ([TArgs] extends [never] ? true : false)
68
+ | (readonly unknown[] extends TArgs ? true : false)
69
+ > = true extends FailedToParseArgs
70
+ ? {
71
+ args?: readonly unknown[]
72
+ }
73
+ : TArgs extends readonly []
74
+ ? { args?: never }
75
+ : {
76
+ args?: TArgs
77
+ }
78
+
79
+ export type Permission<
80
+ TAbi extends Abi | readonly unknown[],
81
+ TFunctionName extends string | undefined = string,
82
+ _FunctionName = TAbi extends Abi
83
+ ? InferFunctionName<TAbi, TFunctionName>
84
+ : never
85
+ > = PermissionCore & {
86
+ functionName?: _FunctionName
87
+ } & (TFunctionName extends string
88
+ ? { abi?: Narrow<TAbi> } & GetFunctionArgs<TAbi, TFunctionName>
89
+ : _FunctionName extends string
90
+ ? { abi?: [Narrow<TAbi[number]>] } & GetFunctionArgs<
91
+ TAbi,
92
+ _FunctionName
93
+ >
94
+ : never)
95
+
96
+ export type CombinedArgs<
97
+ TAbiParameters extends readonly AbiParameter[],
98
+ TAbiParameterKind extends AbiParameterKind = AbiParameterKind
99
+ > = {
100
+ [K in keyof TAbiParameters]: {
101
+ condition: ParamCondition
102
+ value: AbiParameterToPrimitiveType<TAbiParameters[K], TAbiParameterKind>
103
+ } | null
104
+ }
105
+
106
+ export type GeneratePermissionFromArgsParameters<
107
+ TAbi extends Abi | readonly unknown[],
108
+ TFunctionName extends string | undefined = string,
109
+ _FunctionName = TAbi extends Abi
110
+ ? InferFunctionName<TAbi, TFunctionName>
111
+ : never
112
+ > = {
113
+ functionName?: _FunctionName
114
+ } & (TFunctionName extends string
115
+ ? { abi: Narrow<TAbi> } & GetFunctionArgs<TAbi, TFunctionName>
116
+ : _FunctionName extends string
117
+ ? { abi: [Narrow<TAbi[number]>] } & GetFunctionArgs<TAbi, _FunctionName>
118
+ : never)
@@ -0,0 +1,13 @@
1
+ import { type Hex, concat, encodeAbiParameters } from "viem"
2
+ import type { Policy } from "../../types.js"
3
+
4
+ export const toPolicyId = (policies: Policy[]): Hex => {
5
+ return encodeAbiParameters(
6
+ [{ name: "policiesData", type: "bytes[]" }],
7
+ [
8
+ policies.map((policy) =>
9
+ concat([policy.getPolicyInfoInBytes(), policy.getPolicyData()])
10
+ )
11
+ ]
12
+ )
13
+ }
@@ -0,0 +1,38 @@
1
+ import type { KernelSmartAccount } from "@zerodev/sdk"
2
+ import type { EntryPoint } from "permissionless/types"
3
+ import type { Hex } from "viem"
4
+ import {
5
+ isPermissionValidatorPlugin,
6
+ serializePermissionAccountParams
7
+ } from "./utils.js"
8
+
9
+ export const serializePermissionAccount = async <entryPoint extends EntryPoint>(
10
+ account: KernelSmartAccount<entryPoint>,
11
+ privateKey?: Hex
12
+ ): Promise<string> => {
13
+ if (!isPermissionValidatorPlugin(account.kernelPluginManager))
14
+ throw new Error("Account plugin is not a permission validator")
15
+ const permissionParams =
16
+ account.kernelPluginManager.getPluginSerializationParams()
17
+ const action = account.kernelPluginManager.getAction()
18
+ const validityData = account.kernelPluginManager.getValidityData()
19
+ const enableSignature =
20
+ await account.kernelPluginManager.getPluginEnableSignature(
21
+ account.address
22
+ )
23
+ const accountParams = {
24
+ initCode: await account.generateInitCode(),
25
+ accountAddress: account.address
26
+ }
27
+
28
+ const paramsToBeSerialized = {
29
+ permissionParams,
30
+ action,
31
+ validityData,
32
+ accountParams,
33
+ enableSignature,
34
+ privateKey
35
+ }
36
+
37
+ return serializePermissionAccountParams(paramsToBeSerialized)
38
+ }
@@ -0,0 +1,10 @@
1
+ export {
2
+ toECDSASigner,
3
+ type ECDSAModularSignerParams
4
+ } from "./toECDSASigner.js"
5
+ export {
6
+ toWebAuthnSigner,
7
+ type WebAuthnModularSignerParams
8
+ } from "./toWebAuthnSigner.js"
9
+ export { WebAuthnMode } from "./toWebAuthnPubKey.js"
10
+ export { toSignerId } from "./utils/toSignerId.js"
@@ -0,0 +1,61 @@
1
+ import { constants, fixSignedData } from "@zerodev/sdk"
2
+ import type { TypedData } from "abitype"
3
+ import {
4
+ SignTransactionNotSupportedBySmartAccount,
5
+ type SmartAccountSigner
6
+ } from "permissionless/accounts"
7
+ import { type Address, type LocalAccount, type TypedDataDefinition } from "viem"
8
+ import { toAccount } from "viem/accounts"
9
+ import { ECDSA_SIGNER_CONTRACT } from "../constants.js"
10
+ import type { ModularSigner, ModularSignerParams } from "../types.js"
11
+
12
+ export type ECDSAModularSignerParams<
13
+ TSource extends string = "custom",
14
+ TAddress extends Address = Address
15
+ > = ModularSignerParams & {
16
+ signer: SmartAccountSigner<TSource, TAddress>
17
+ }
18
+
19
+ export function toECDSASigner<
20
+ TSource extends string = "custom",
21
+ TAddress extends Address = Address
22
+ >({
23
+ signer,
24
+ signerContractAddress = ECDSA_SIGNER_CONTRACT
25
+ }: ECDSAModularSignerParams<TSource, TAddress>): ModularSigner {
26
+ const viemSigner: LocalAccount = {
27
+ ...signer,
28
+ signTransaction: (_, __) => {
29
+ throw new SignTransactionNotSupportedBySmartAccount()
30
+ }
31
+ } as LocalAccount
32
+ const account = toAccount({
33
+ address: viemSigner.address,
34
+ async signMessage({ message }) {
35
+ return fixSignedData(await viemSigner.signMessage({ message }))
36
+ },
37
+ async signTransaction(_, __) {
38
+ throw new SignTransactionNotSupportedBySmartAccount()
39
+ },
40
+ async signTypedData<
41
+ const TTypedData extends TypedData | Record<string, unknown>,
42
+ TPrimaryType extends
43
+ | keyof TTypedData
44
+ | "EIP712Domain" = keyof TTypedData
45
+ >(typedData: TypedDataDefinition<TTypedData, TPrimaryType>) {
46
+ return fixSignedData(
47
+ await viemSigner.signTypedData<TTypedData, TPrimaryType>({
48
+ ...typedData
49
+ })
50
+ )
51
+ }
52
+ })
53
+ return {
54
+ account,
55
+ signerContractAddress,
56
+ getSignerData: () => {
57
+ return viemSigner.address
58
+ },
59
+ getDummySignature: () => constants.DUMMY_ECDSA_SIG
60
+ }
61
+ }
@@ -0,0 +1,152 @@
1
+ import { Buffer } from "buffer"
2
+ import { startAuthentication, startRegistration } from "@simplewebauthn/browser"
3
+ import { type Hex, keccak256 } from "viem"
4
+ import { type WebAuthnKey } from "./toWebAuthnSigner.js"
5
+ import { b64ToBytes, uint8ArrayToHexString } from "./webAuthnUtils.js"
6
+
7
+ export enum WebAuthnMode {
8
+ Register = "register",
9
+ Login = "login"
10
+ }
11
+
12
+ export const toWebAuthnPubKey = async ({
13
+ passkeyName,
14
+ passkeyServerUrl,
15
+ mode = WebAuthnMode.Login
16
+ }: {
17
+ passkeyName: string
18
+ passkeyServerUrl: string
19
+ mode: WebAuthnMode
20
+ }): Promise<WebAuthnKey> => {
21
+ let pubKey: string | undefined
22
+ let authenticatorIdHash: Hex
23
+ if (mode === WebAuthnMode.Login) {
24
+ // Get login options
25
+ const loginOptionsResponse = await fetch(
26
+ `${passkeyServerUrl}/login/options`,
27
+ {
28
+ method: "POST",
29
+ headers: { "Content-Type": "application/json" },
30
+ credentials: "include"
31
+ }
32
+ )
33
+ const loginOptions = await loginOptionsResponse.json()
34
+
35
+ // Start authentication (login)
36
+ const loginCred = await startAuthentication(loginOptions)
37
+
38
+ // get authenticatorIdHash
39
+ authenticatorIdHash = keccak256(
40
+ uint8ArrayToHexString(b64ToBytes(loginCred.id))
41
+ )
42
+
43
+ // Verify authentication
44
+ const loginVerifyResponse = await fetch(
45
+ `${passkeyServerUrl}/login/verify`,
46
+ {
47
+ method: "POST",
48
+ headers: { "Content-Type": "application/json" },
49
+ body: JSON.stringify({ cred: loginCred }),
50
+ credentials: "include"
51
+ }
52
+ )
53
+
54
+ const loginVerifyResult = await loginVerifyResponse.json()
55
+
56
+ if (window.sessionStorage === undefined) {
57
+ throw new Error("sessionStorage is not available")
58
+ }
59
+ sessionStorage.setItem("userId", loginVerifyResult.userId)
60
+
61
+ if (!loginVerifyResult.verification.verified) {
62
+ throw new Error("Login not verified")
63
+ }
64
+ // Import the key
65
+ pubKey = loginVerifyResult.pubkey // Uint8Array pubkey
66
+ } else {
67
+ if (!passkeyName) {
68
+ throw new Error("No passkey name provided")
69
+ }
70
+ // Get registration options
71
+ const registerOptionsResponse = await fetch(
72
+ `${passkeyServerUrl}/register/options`,
73
+ {
74
+ method: "POST",
75
+ headers: {
76
+ "Content-Type": "application/json"
77
+ },
78
+ body: JSON.stringify({ username: passkeyName }),
79
+ credentials: "include"
80
+ }
81
+ )
82
+ const registerOptions = await registerOptionsResponse.json()
83
+
84
+ // save userId to sessionStorage
85
+ if (window.sessionStorage === undefined) {
86
+ throw new Error("sessionStorage is not available")
87
+ }
88
+ sessionStorage.setItem("userId", registerOptions.userId)
89
+
90
+ // Start registration
91
+ const registerCred = await startRegistration(registerOptions.options)
92
+
93
+ // get authenticatorIdHash
94
+ authenticatorIdHash = keccak256(
95
+ uint8ArrayToHexString(b64ToBytes(registerCred.id))
96
+ )
97
+
98
+ // Verify registration
99
+ const registerVerifyResponse = await fetch(
100
+ `${passkeyServerUrl}/register/verify`,
101
+ {
102
+ method: "POST",
103
+ headers: {
104
+ "Content-Type": "application/json"
105
+ },
106
+ body: JSON.stringify({
107
+ userId: registerOptions.userId,
108
+ username: passkeyName,
109
+ cred: registerCred
110
+ }),
111
+ credentials: "include"
112
+ }
113
+ )
114
+
115
+ const registerVerifyResult = await registerVerifyResponse.json()
116
+ if (!registerVerifyResult.verified) {
117
+ throw new Error("Registration not verified")
118
+ }
119
+
120
+ // Import the key
121
+ pubKey = registerCred.response.publicKey
122
+ }
123
+ if (!pubKey) {
124
+ throw new Error("No public key returned from registration credential")
125
+ }
126
+
127
+ const spkiDer = Buffer.from(pubKey, "base64")
128
+ const key = await crypto.subtle.importKey(
129
+ "spki",
130
+ spkiDer,
131
+ {
132
+ name: "ECDSA",
133
+ namedCurve: "P-256"
134
+ },
135
+ true,
136
+ ["verify"]
137
+ )
138
+
139
+ // Export the key to the raw format
140
+ const rawKey = await crypto.subtle.exportKey("raw", key)
141
+ const rawKeyBuffer = Buffer.from(rawKey)
142
+
143
+ // The first byte is 0x04 (uncompressed), followed by x and y coordinates (32 bytes each for P-256)
144
+ const pubKeyX = rawKeyBuffer.subarray(1, 33).toString("hex")
145
+ const pubKeyY = rawKeyBuffer.subarray(33).toString("hex")
146
+
147
+ return {
148
+ pubX: BigInt(`0x${pubKeyX}`),
149
+ pubY: BigInt(`0x${pubKeyY}`),
150
+ authenticatorIdHash
151
+ }
152
+ }