@organigram/passkey-wallet 0.1.6

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 (79) hide show
  1. package/.organigram-docs-cache/passkey-wallet/api-extractor.json +35 -0
  2. package/.organigram-docs-cache/passkey-wallet/api-model/passkey-wallet.api.json +3166 -0
  3. package/.organigram-docs-cache/passkey-wallet/entry/index.d.ts +9 -0
  4. package/.organigram-docs-cache/passkey-wallet/tmp/node-compile-cache/v24.12.0-arm64-cf738c9d-501/05732508 +0 -0
  5. package/.organigram-docs-cache/passkey-wallet/tmp/node-compile-cache/v24.12.0-arm64-cf738c9d-501/166b6dbf +0 -0
  6. package/.organigram-docs-cache/passkey-wallet/tmp/node-compile-cache/v24.12.0-arm64-cf738c9d-501/41c20e23 +0 -0
  7. package/.organigram-docs-cache/passkey-wallet/tmp/node-compile-cache/v24.12.0-arm64-cf738c9d-501/7111ea58 +0 -0
  8. package/.organigram-docs-cache/passkey-wallet/tmp/tsx-501/17844-1822dfbab9819e9f6a93485fe3da5dbf3745311c +1 -0
  9. package/.organigram-docs-cache/passkey-wallet/tmp/tsx-501/17844-45a65cfdc7a50c53817c1dad3954ae3d2d2c35fb +1 -0
  10. package/.organigram-docs-cache/passkey-wallet/tmp/tsx-501/17844-fee5290b05398fe9e3b878deefd22383744f1526 +1 -0
  11. package/.organigram-docs-cache/passkey-wallet/yaml/passkey-wallet/createorganigrampasskeywalletinput.yml +17 -0
  12. package/.organigram-docs-cache/passkey-wallet/yaml/passkey-wallet/identitypasskeycapabilities.yml +16 -0
  13. package/.organigram-docs-cache/passkey-wallet/yaml/passkey-wallet/organigrampasskeycapabilities.yml +18 -0
  14. package/.organigram-docs-cache/passkey-wallet/yaml/passkey-wallet/organigrampasskeyprovider.yml +16 -0
  15. package/.organigram-docs-cache/passkey-wallet/yaml/passkey-wallet/organigrampasskeyprovideractions.yml +20 -0
  16. package/.organigram-docs-cache/passkey-wallet/yaml/passkey-wallet/passkeyprfunavailableerror.yml +28 -0
  17. package/.organigram-docs-cache/passkey-wallet/yaml/passkey-wallet/passkeyproviderevent.yml +11 -0
  18. package/.organigram-docs-cache/passkey-wallet/yaml/passkey-wallet/passkeyproviderlistener.yml +11 -0
  19. package/.organigram-docs-cache/passkey-wallet/yaml/passkey-wallet/passkeyregistrationresult.yml +15 -0
  20. package/.organigram-docs-cache/passkey-wallet/yaml/passkey-wallet/passkeyvaultdecrypterror.yml +28 -0
  21. package/.organigram-docs-cache/passkey-wallet/yaml/passkey-wallet/passkeyvaultenvelopedata.yml +18 -0
  22. package/.organigram-docs-cache/passkey-wallet/yaml/passkey-wallet/passkeyvaultenvelopeinput.yml +19 -0
  23. package/.organigram-docs-cache/passkey-wallet/yaml/passkey-wallet/passkeywalletapiclient.yml +33 -0
  24. package/.organigram-docs-cache/passkey-wallet/yaml/passkey-wallet/passkeywalletcapabilities.yml +11 -0
  25. package/.organigram-docs-cache/passkey-wallet/yaml/passkey-wallet/passkeywalletlogincapabilities.yml +14 -0
  26. package/.organigram-docs-cache/passkey-wallet/yaml/passkey-wallet/passkeywalletregistrationcapabilities.yml +18 -0
  27. package/.organigram-docs-cache/passkey-wallet/yaml/passkey-wallet/passkeywalletvaultpayload.yml +18 -0
  28. package/.organigram-docs-cache/passkey-wallet/yaml/passkey-wallet/unlockedpasskeywallet.yml +21 -0
  29. package/.organigram-docs-cache/passkey-wallet/yaml/passkey-wallet.yml +870 -0
  30. package/.organigram-docs-cache/passkey-wallet/yaml/toc.yml +43 -0
  31. package/.turbo/turbo-build.log +6 -0
  32. package/.turbo/turbo-docs$colon$generate.log +118 -0
  33. package/.turbo/turbo-lint.log +13 -0
  34. package/.turbo/turbo-test.log +152 -0
  35. package/.turbo/turbo-typecheck.log +5 -0
  36. package/CHANGELOG.md +8 -0
  37. package/LICENSE.md +21 -0
  38. package/README.md +427 -0
  39. package/__mocks__/organigram-js.ts +19 -0
  40. package/__mocks__/wagmi.ts +1 -0
  41. package/dist/crypto.d.ts +39 -0
  42. package/dist/crypto.js +95 -0
  43. package/dist/eip1193.d.ts +24 -0
  44. package/dist/eip1193.js +103 -0
  45. package/dist/errors.d.ts +7 -0
  46. package/dist/errors.js +13 -0
  47. package/dist/index.d.ts +4 -0
  48. package/dist/index.js +4 -0
  49. package/dist/rainbowkit.d.ts +14 -0
  50. package/dist/rainbowkit.js +128 -0
  51. package/dist/types.d.ts +45 -0
  52. package/dist/types.js +17 -0
  53. package/dist/vault.d.ts +10 -0
  54. package/dist/vault.js +41 -0
  55. package/dist/wallet.d.ts +15 -0
  56. package/dist/wallet.js +30 -0
  57. package/dist/webauthn-client.d.ts +73 -0
  58. package/dist/webauthn-client.js +234 -0
  59. package/dist/webauthn-server.d.ts +62 -0
  60. package/dist/webauthn-server.js +133 -0
  61. package/jest.config.ts +32 -0
  62. package/package.json +61 -0
  63. package/src/crypto.test.ts +69 -0
  64. package/src/crypto.ts +193 -0
  65. package/src/eip1193.ts +169 -0
  66. package/src/errors.ts +16 -0
  67. package/src/index.ts +4 -0
  68. package/src/rainbowkit.test.ts +42 -0
  69. package/src/rainbowkit.ts +171 -0
  70. package/src/types.ts +82 -0
  71. package/src/vault.test.ts +23 -0
  72. package/src/vault.ts +77 -0
  73. package/src/wallet.ts +61 -0
  74. package/src/webauthn-client.test.ts +103 -0
  75. package/src/webauthn-client.ts +430 -0
  76. package/src/webauthn-server.test.ts +43 -0
  77. package/src/webauthn-server.ts +258 -0
  78. package/tsconfig.build.json +15 -0
  79. package/tsconfig.json +27 -0
@@ -0,0 +1,258 @@
1
+ import {
2
+ generateAuthenticationOptions,
3
+ generateRegistrationOptions,
4
+ verifyAuthenticationResponse,
5
+ verifyRegistrationResponse
6
+ } from '@simplewebauthn/server'
7
+ import { getAddress, isAddress } from 'viem'
8
+
9
+ import {
10
+ base64UrlToBytes,
11
+ passkeyVaultAlgorithm,
12
+ type PasskeyVaultEnvelopeData,
13
+ passkeyVaultKeyVersion
14
+ } from './crypto'
15
+
16
+ export const passkeyChallengeTtlMs = 5 * 60 * 1000
17
+
18
+ export type PasskeyVaultEnvelopeInput = {
19
+ address: string
20
+ encryptedMnemonic: string
21
+ salt: string
22
+ nonce: string
23
+ algorithm: string
24
+ keyVersion: number
25
+ }
26
+
27
+ export const validatePasskeyVaultEnvelopeInput = (
28
+ input: PasskeyVaultEnvelopeInput
29
+ ): PasskeyVaultEnvelopeInput & { address: `0x${string}` } => {
30
+ if (!isAddress(input.address)) {
31
+ throw new Error('Passkey vault envelope requires a valid wallet address.')
32
+ }
33
+ if (input.encryptedMnemonic.trim() === '') {
34
+ throw new Error(
35
+ 'Passkey vault envelope requires encrypted recovery phrase data.'
36
+ )
37
+ }
38
+ if (input.salt.trim() === '') {
39
+ throw new Error('Passkey vault envelope requires a salt.')
40
+ }
41
+ if (input.nonce.trim() === '') {
42
+ throw new Error('Passkey vault envelope requires a nonce.')
43
+ }
44
+ if (input.algorithm !== passkeyVaultAlgorithm) {
45
+ throw new Error('Passkey vault envelope algorithm is not supported.')
46
+ }
47
+ if (input.keyVersion !== passkeyVaultKeyVersion) {
48
+ throw new Error('Passkey vault envelope key version is not supported.')
49
+ }
50
+
51
+ return {
52
+ ...input,
53
+ address: getAddress(input.address as `0x${string}`)
54
+ }
55
+ }
56
+
57
+ export const createPasskeyChallengeExpiry = (): Date =>
58
+ new Date(Date.now() + passkeyChallengeTtlMs)
59
+
60
+ export const getWebAuthnClientDataChallenge = (response: unknown): string => {
61
+ const clientDataJSON = (response as {
62
+ response?: {
63
+ clientDataJSON?: string
64
+ }
65
+ })?.response?.clientDataJSON
66
+ if (typeof clientDataJSON !== 'string' || clientDataJSON === '') {
67
+ throw new Error('WebAuthn response is missing client data.')
68
+ }
69
+
70
+ const clientData = JSON.parse(
71
+ new TextDecoder().decode(base64UrlToBytes(clientDataJSON))
72
+ ) as {
73
+ challenge?: unknown
74
+ }
75
+ if (typeof clientData.challenge !== 'string' || clientData.challenge === '') {
76
+ throw new Error('WebAuthn response is missing its challenge.')
77
+ }
78
+
79
+ return clientData.challenge
80
+ }
81
+
82
+ export const createPasskeyRegistrationOptions = async ({
83
+ rpId,
84
+ userAddress,
85
+ email
86
+ }: {
87
+ rpId: string
88
+ userAddress?: string | null
89
+ email?: string | null
90
+ }) =>
91
+ await generateRegistrationOptions({
92
+ rpName: 'Organigram',
93
+ rpID: rpId,
94
+ userName: email ?? userAddress ?? 'Organigram passkey wallet',
95
+ userDisplayName: email ?? userAddress ?? 'Organigram passkey wallet',
96
+ attestationType: 'none',
97
+ authenticatorSelection: {
98
+ residentKey: 'required',
99
+ userVerification: 'required'
100
+ },
101
+ extensions: {
102
+ prf: {
103
+ eval: {
104
+ first: new Uint8Array(32)
105
+ }
106
+ }
107
+ }
108
+ } as Parameters<typeof generateRegistrationOptions>[0])
109
+
110
+ type VerifiedPasskeyRegistrationResponse = Awaited<
111
+ ReturnType<typeof verifyRegistrationResponse>
112
+ > & {
113
+ registrationInfo: NonNullable<
114
+ Awaited<ReturnType<typeof verifyRegistrationResponse>>['registrationInfo']
115
+ >
116
+ }
117
+
118
+ export const verifyPasskeyRegistration = async ({
119
+ response,
120
+ expectedChallenge,
121
+ expectedOrigin,
122
+ expectedRpId,
123
+ envelope
124
+ }: {
125
+ response: unknown
126
+ expectedChallenge: string
127
+ expectedOrigin: string
128
+ expectedRpId: string
129
+ envelope: PasskeyVaultEnvelopeInput
130
+ }): Promise<{
131
+ verification: VerifiedPasskeyRegistrationResponse
132
+ vaultEnvelope: PasskeyVaultEnvelopeInput & { address: `0x${string}` }
133
+ }> => {
134
+ const vaultEnvelope = validatePasskeyVaultEnvelopeInput(envelope)
135
+ const verification = await verifyRegistrationResponse({
136
+ response: response as Parameters<
137
+ typeof verifyRegistrationResponse
138
+ >[0]['response'],
139
+ expectedChallenge,
140
+ expectedOrigin,
141
+ expectedRPID: expectedRpId,
142
+ requireUserVerification: true
143
+ })
144
+
145
+ if (!verification.verified || verification.registrationInfo == null) {
146
+ throw new Error('Passkey registration was not verified.')
147
+ }
148
+
149
+ return {
150
+ verification: verification as VerifiedPasskeyRegistrationResponse,
151
+ vaultEnvelope
152
+ }
153
+ }
154
+
155
+ export const createPasskeyAuthenticationOptions = async ({
156
+ rpId,
157
+ credentials = []
158
+ }: {
159
+ rpId: string
160
+ credentials?: Array<{
161
+ credentialId: string
162
+ transports: string[]
163
+ }>
164
+ }) => {
165
+ const isDiscoverableAuthentication = credentials.length === 0
166
+
167
+ return await generateAuthenticationOptions({
168
+ rpID: rpId,
169
+ userVerification: 'required',
170
+ ...(!isDiscoverableAuthentication
171
+ ? {
172
+ allowCredentials: credentials.map(credential => ({
173
+ id: credential.credentialId,
174
+ transports: credential.transports as AuthenticatorTransport[]
175
+ }))
176
+ }
177
+ : {}),
178
+ extensions: {
179
+ prf: isDiscoverableAuthentication
180
+ ? {
181
+ eval: {
182
+ first: new Uint8Array(32)
183
+ }
184
+ }
185
+ : {
186
+ evalByCredential: Object.fromEntries(
187
+ credentials.map(credential => [
188
+ credential.credentialId,
189
+ {
190
+ first: new Uint8Array(32)
191
+ }
192
+ ])
193
+ )
194
+ }
195
+ }
196
+ } as Parameters<typeof generateAuthenticationOptions>[0])
197
+ }
198
+
199
+ export const verifyPasskeyAuthentication = async ({
200
+ response,
201
+ expectedChallenge,
202
+ expectedOrigin,
203
+ expectedRpId,
204
+ credential
205
+ }: {
206
+ response: unknown
207
+ expectedChallenge: string
208
+ expectedOrigin: string
209
+ expectedRpId: string
210
+ credential: {
211
+ credentialId: string
212
+ publicKey: string
213
+ signCount: number
214
+ }
215
+ }): Promise<Awaited<ReturnType<typeof verifyAuthenticationResponse>>> =>
216
+ await verifyAuthenticationResponse({
217
+ response: response as Parameters<
218
+ typeof verifyAuthenticationResponse
219
+ >[0]['response'],
220
+ expectedChallenge,
221
+ expectedOrigin,
222
+ expectedRPID: expectedRpId,
223
+ credential: {
224
+ id: credential.credentialId,
225
+ publicKey: Buffer.from(credential.publicKey, 'base64url'),
226
+ counter: credential.signCount
227
+ },
228
+ requireUserVerification: true
229
+ })
230
+
231
+ export const toPasskeyVaultEnvelopeData = ({
232
+ encryptedMnemonic,
233
+ salt,
234
+ nonce,
235
+ algorithm,
236
+ keyVersion
237
+ }: {
238
+ encryptedMnemonic: string
239
+ salt: string
240
+ nonce: string
241
+ algorithm: string
242
+ keyVersion: number
243
+ }): PasskeyVaultEnvelopeData => {
244
+ if (algorithm !== passkeyVaultAlgorithm) {
245
+ throw new Error('Passkey vault envelope algorithm is not supported.')
246
+ }
247
+ if (keyVersion !== passkeyVaultKeyVersion) {
248
+ throw new Error('Passkey vault envelope key version is not supported.')
249
+ }
250
+
251
+ return {
252
+ algorithm,
253
+ keyVersion,
254
+ ciphertext: encryptedMnemonic,
255
+ salt,
256
+ nonce
257
+ }
258
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "rootDir": "src",
5
+ "outDir": "dist",
6
+ "noEmit": false,
7
+ "types": ["node"]
8
+ },
9
+ "include": ["src/**/*.ts"],
10
+ "exclude": [
11
+ "node_modules",
12
+ "dist",
13
+ "src/**/*.test.ts"
14
+ ]
15
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "extends": "@tsconfig/recommended/tsconfig.json",
3
+ "compilerOptions": {
4
+ "lib": ["ESNext", "DOM"],
5
+ "target": "ESNext",
6
+ "strict": true,
7
+ "removeComments": false,
8
+ "resolveJsonModule": true,
9
+ "preserveConstEnums": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "rootDir": ".",
13
+ "sourceMap": false,
14
+ "declaration": true,
15
+ "noEmit": true,
16
+ "types": ["node", "jest"]
17
+ },
18
+ "include": [
19
+ "src/**/*.ts",
20
+ "__mocks__/**/*.ts",
21
+ "jest.config.ts"
22
+ ],
23
+ "exclude": [
24
+ "node_modules",
25
+ "dist"
26
+ ]
27
+ }