@zerodev/wallet-core 0.0.1-alpha.18 → 0.0.1-alpha.19
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.
- package/dist/_cjs/actions/auth/getOAuthLoginUrl.js +18 -0
- package/dist/_cjs/actions/auth/getOAuthLoginUrl.js.map +1 -0
- package/dist/_cjs/actions/auth/getWhoami.js +2 -2
- package/dist/_cjs/actions/auth/getWhoami.js.map +1 -1
- package/dist/_cjs/actions/auth/index.js +3 -1
- package/dist/_cjs/actions/auth/index.js.map +1 -1
- package/dist/_cjs/actions/auth/loginWithStamp.js +5 -5
- package/dist/_cjs/actions/auth/loginWithStamp.js.map +1 -1
- package/dist/_cjs/actions/index.js +2 -1
- package/dist/_cjs/actions/index.js.map +1 -1
- package/dist/_cjs/actions/wallet/signingUtils.js +2 -2
- package/dist/_cjs/actions/wallet/signingUtils.js.map +1 -1
- package/dist/_cjs/client/createClient.js +5 -5
- package/dist/_cjs/client/createClient.js.map +1 -1
- package/dist/_cjs/client/decorators/client.js +1 -0
- package/dist/_cjs/client/decorators/client.js.map +1 -1
- package/dist/_cjs/client/transports/createTransport.js +5 -5
- package/dist/_cjs/client/transports/createTransport.js.map +1 -1
- package/dist/_cjs/client/transports/rest.js +5 -5
- package/dist/_cjs/client/transports/rest.js.map +1 -1
- package/dist/_cjs/core/createZeroDevWallet.js +29 -61
- package/dist/_cjs/core/createZeroDevWallet.js.map +1 -1
- package/dist/_cjs/index.js.map +1 -1
- package/dist/_cjs/stampers/indexedDbStamper.js +17 -2
- package/dist/_cjs/stampers/indexedDbStamper.js.map +1 -1
- package/dist/_cjs/stampers/webauthnStamper.js +23 -3
- package/dist/_cjs/stampers/webauthnStamper.js.map +1 -1
- package/dist/_cjs/utils/exportPrivateKey.js +1 -1
- package/dist/_cjs/utils/exportPrivateKey.js.map +1 -1
- package/dist/_cjs/utils/exportWallet.js +2 -6
- package/dist/_cjs/utils/exportWallet.js.map +1 -1
- package/dist/_cjs/utils/hpke.js +4 -15
- package/dist/_cjs/utils/hpke.js.map +1 -1
- package/dist/_cjs/utils/utils.js +5 -6
- package/dist/_cjs/utils/utils.js.map +1 -1
- package/dist/_esm/actions/auth/getOAuthLoginUrl.js +23 -0
- package/dist/_esm/actions/auth/getOAuthLoginUrl.js.map +1 -0
- package/dist/_esm/actions/auth/getWhoami.js +2 -2
- package/dist/_esm/actions/auth/getWhoami.js.map +1 -1
- package/dist/_esm/actions/auth/index.js +1 -0
- package/dist/_esm/actions/auth/index.js.map +1 -1
- package/dist/_esm/actions/auth/loginWithStamp.js +5 -5
- package/dist/_esm/actions/auth/loginWithStamp.js.map +1 -1
- package/dist/_esm/actions/index.js +1 -1
- package/dist/_esm/actions/index.js.map +1 -1
- package/dist/_esm/actions/wallet/signingUtils.js +2 -2
- package/dist/_esm/actions/wallet/signingUtils.js.map +1 -1
- package/dist/_esm/client/createClient.js +5 -5
- package/dist/_esm/client/createClient.js.map +1 -1
- package/dist/_esm/client/decorators/client.js +2 -1
- package/dist/_esm/client/decorators/client.js.map +1 -1
- package/dist/_esm/client/transports/createTransport.js +5 -5
- package/dist/_esm/client/transports/createTransport.js.map +1 -1
- package/dist/_esm/client/transports/rest.js +5 -5
- package/dist/_esm/client/transports/rest.js.map +1 -1
- package/dist/_esm/core/createZeroDevWallet.js +30 -62
- package/dist/_esm/core/createZeroDevWallet.js.map +1 -1
- package/dist/_esm/index.js.map +1 -1
- package/dist/_esm/stampers/indexedDbStamper.js +17 -2
- package/dist/_esm/stampers/indexedDbStamper.js.map +1 -1
- package/dist/_esm/stampers/webauthnStamper.js +23 -4
- package/dist/_esm/stampers/webauthnStamper.js.map +1 -1
- package/dist/_esm/utils/exportPrivateKey.js +1 -1
- package/dist/_esm/utils/exportPrivateKey.js.map +1 -1
- package/dist/_esm/utils/exportWallet.js +2 -6
- package/dist/_esm/utils/exportWallet.js.map +1 -1
- package/dist/_esm/utils/hpke.js +6 -22
- package/dist/_esm/utils/hpke.js.map +1 -1
- package/dist/_esm/utils/utils.js +5 -6
- package/dist/_esm/utils/utils.js.map +1 -1
- package/dist/_types/actions/auth/getOAuthLoginUrl.d.ts +30 -0
- package/dist/_types/actions/auth/getOAuthLoginUrl.d.ts.map +1 -0
- package/dist/_types/actions/auth/index.d.ts +1 -0
- package/dist/_types/actions/auth/index.d.ts.map +1 -1
- package/dist/_types/actions/auth/loginWithStamp.d.ts +2 -1
- package/dist/_types/actions/auth/loginWithStamp.d.ts.map +1 -1
- package/dist/_types/actions/index.d.ts +1 -1
- package/dist/_types/actions/index.d.ts.map +1 -1
- package/dist/_types/client/decorators/client.d.ts +7 -1
- package/dist/_types/client/decorators/client.d.ts.map +1 -1
- package/dist/_types/client/transports/rest.d.ts +5 -4
- package/dist/_types/client/transports/rest.d.ts.map +1 -1
- package/dist/_types/client/types.d.ts +9 -9
- package/dist/_types/client/types.d.ts.map +1 -1
- package/dist/_types/core/createZeroDevWallet.d.ts +3 -0
- package/dist/_types/core/createZeroDevWallet.d.ts.map +1 -1
- package/dist/_types/index.d.ts +1 -1
- package/dist/_types/index.d.ts.map +1 -1
- package/dist/_types/stampers/index.d.ts +1 -1
- package/dist/_types/stampers/index.d.ts.map +1 -1
- package/dist/_types/stampers/indexedDbStamper.d.ts +2 -2
- package/dist/_types/stampers/indexedDbStamper.d.ts.map +1 -1
- package/dist/_types/stampers/types.d.ts +31 -5
- package/dist/_types/stampers/types.d.ts.map +1 -1
- package/dist/_types/stampers/webauthnStamper.d.ts +2 -2
- package/dist/_types/stampers/webauthnStamper.d.ts.map +1 -1
- package/dist/_types/types/session.d.ts +2 -3
- package/dist/_types/types/session.d.ts.map +1 -1
- package/dist/_types/utils/buildClientSignature.d.ts +3 -3
- package/dist/_types/utils/buildClientSignature.d.ts.map +1 -1
- package/dist/_types/utils/exportWallet.d.ts.map +1 -1
- package/dist/_types/utils/hpke.d.ts.map +1 -1
- package/dist/_types/utils/utils.d.ts.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +2 -1
- package/src/actions/auth/getOAuthLoginUrl.ts +48 -0
- package/src/actions/auth/getWhoami.ts +2 -2
- package/src/actions/auth/index.ts +5 -0
- package/src/actions/auth/loginWithStamp.ts +7 -6
- package/src/actions/index.ts +3 -0
- package/src/actions/wallet/signingUtils.ts +2 -2
- package/src/client/createClient.ts +6 -6
- package/src/client/decorators/client.ts +13 -0
- package/src/client/transports/createTransport.ts +5 -5
- package/src/client/transports/rest.ts +11 -10
- package/src/client/types.ts +9 -9
- package/src/core/createZeroDevWallet.ts +35 -77
- package/src/index.ts +5 -2
- package/src/stampers/index.ts +2 -2
- package/src/stampers/indexedDbStamper.ts +24 -4
- package/src/stampers/types.ts +33 -5
- package/src/stampers/webauthnStamper.ts +27 -6
- package/src/types/session.ts +2 -3
- package/src/utils/buildClientSignature.ts +3 -3
- package/src/utils/exportPrivateKey.ts +1 -1
- package/src/utils/exportWallet.ts +2 -6
- package/src/utils/hpke.ts +7 -33
- package/src/utils/utils.ts +5 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zerodev/wallet-core",
|
|
3
|
-
"version": "0.0.1-alpha.
|
|
3
|
+
"version": "0.0.1-alpha.19",
|
|
4
4
|
"description": "ZeroDev Wallet SDK built on Turnkey",
|
|
5
5
|
"main": "./dist/_cjs/index.js",
|
|
6
6
|
"module": "./dist/_esm/index.js",
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
],
|
|
50
50
|
"license": "MIT",
|
|
51
51
|
"dependencies": {
|
|
52
|
+
"@noble/ciphers": "^2.2.0",
|
|
52
53
|
"@noble/curves": "^2.2.0",
|
|
53
54
|
"@noble/hashes": "^2.2.0",
|
|
54
55
|
"@turnkey/http": "^3.12.1",
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { Client } from '../../client/types.js'
|
|
2
|
+
|
|
3
|
+
export type GetOAuthLoginUrlParameters = {
|
|
4
|
+
/** OAuth provider — currently only `'google'` is supported. */
|
|
5
|
+
provider: 'google'
|
|
6
|
+
/** The project ID for the request. */
|
|
7
|
+
projectId: string
|
|
8
|
+
/**
|
|
9
|
+
* The session public key (compressed P-256 hex, lowercase, with or
|
|
10
|
+
* without `0x` prefix). The backend embeds `sha256(utf8(hex))` as the
|
|
11
|
+
* OIDC `nonce` so the SDK can verify the URL was minted for this key.
|
|
12
|
+
*/
|
|
13
|
+
publicKey: string
|
|
14
|
+
/**
|
|
15
|
+
* Where the popup should land after the OAuth round-trip
|
|
16
|
+
* (e.g. `https://app.example.com/dashboard?oauth_success=true`).
|
|
17
|
+
* Must be on the project's whitelist.
|
|
18
|
+
*/
|
|
19
|
+
returnTo: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type GetOAuthLoginUrlReturnType = string
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Fetches the Google OAuth authorization URL from the backend.
|
|
26
|
+
*
|
|
27
|
+
* The SDK must verify the returned URL's `nonce` against
|
|
28
|
+
* `sha256(utf8(publicKey))` (and the host is `accounts.google.com`)
|
|
29
|
+
* before opening it in a popup — the backend is not a trusted party.
|
|
30
|
+
* See audit finding TOB-KMS-1.
|
|
31
|
+
*/
|
|
32
|
+
export async function getOAuthLoginUrl(
|
|
33
|
+
client: Client,
|
|
34
|
+
params: GetOAuthLoginUrlParameters,
|
|
35
|
+
): Promise<GetOAuthLoginUrlReturnType> {
|
|
36
|
+
if (params.provider !== 'google') {
|
|
37
|
+
throw new Error(`Unsupported OAuth provider: ${params.provider}`)
|
|
38
|
+
}
|
|
39
|
+
const query = new URLSearchParams({
|
|
40
|
+
project_id: params.projectId,
|
|
41
|
+
pub_key: params.publicKey.replace(/^0x/, '').toLowerCase(),
|
|
42
|
+
return_to: params.returnTo,
|
|
43
|
+
})
|
|
44
|
+
return await client.request<string>({
|
|
45
|
+
path: `oauth/google/login-url?${query.toString()}`,
|
|
46
|
+
method: 'GET',
|
|
47
|
+
})
|
|
48
|
+
}
|
|
@@ -51,7 +51,7 @@ export async function getWhoami(
|
|
|
51
51
|
// Step 1: Inner stamp over the payload (for Turnkey verification)
|
|
52
52
|
const innerBody = { organizationId }
|
|
53
53
|
const innerBodyString = canonicalizeEx(innerBody)
|
|
54
|
-
const innerStamp = await client.
|
|
54
|
+
const innerStamp = await client.apiKeyStamper.stamp(innerBodyString)
|
|
55
55
|
|
|
56
56
|
// Step 2: Build full body with inner stamp embedded
|
|
57
57
|
const fullBody = {
|
|
@@ -64,7 +64,7 @@ export async function getWhoami(
|
|
|
64
64
|
|
|
65
65
|
// Step 3: Outer stamp over full body (for KMS middleware)
|
|
66
66
|
const fullBodyString = canonicalizeEx(fullBody)
|
|
67
|
-
const outerStamp = await client.
|
|
67
|
+
const outerStamp = await client.apiKeyStamper.stamp(fullBodyString)
|
|
68
68
|
|
|
69
69
|
return await client.request({
|
|
70
70
|
path: `${projectId}/whoami`,
|
|
@@ -23,6 +23,11 @@ export {
|
|
|
23
23
|
type GetAuthProxyConfigIdReturnType,
|
|
24
24
|
getAuthProxyConfigId,
|
|
25
25
|
} from './getAuthProxyConfigId.js'
|
|
26
|
+
export {
|
|
27
|
+
type GetOAuthLoginUrlParameters,
|
|
28
|
+
type GetOAuthLoginUrlReturnType,
|
|
29
|
+
getOAuthLoginUrl,
|
|
30
|
+
} from './getOAuthLoginUrl.js'
|
|
26
31
|
export {
|
|
27
32
|
type GetWhoamiParameters,
|
|
28
33
|
type GetWhoamiReturnType,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { canonicalizeEx } from 'json-canonicalize'
|
|
2
2
|
import type { Client } from '../../client/types.js'
|
|
3
3
|
import type { Stamp } from '../../stampers/types.js'
|
|
4
|
+
import type { StamperType } from '../../types/session.js'
|
|
4
5
|
|
|
5
6
|
export type EmailCustomization = {
|
|
6
7
|
/** A template for the URL to be used in a magic link button, e.g. `https://dapp.xyz/%s`. The auth bundle will be interpolated into the `%s`. */
|
|
@@ -15,7 +16,7 @@ export type LoginWithStampParameters = {
|
|
|
15
16
|
/** The encoded public key for the request */
|
|
16
17
|
targetPublicKey: string
|
|
17
18
|
/** The stamper type for the request */
|
|
18
|
-
stampWith?:
|
|
19
|
+
stampWith?: StamperType
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
export type LoginWithStampReturnType = {
|
|
@@ -58,12 +59,12 @@ export async function loginWithStamp(
|
|
|
58
59
|
type: 'ACTIVITY_TYPE_STAMP_LOGIN',
|
|
59
60
|
})
|
|
60
61
|
let stamp: Stamp
|
|
61
|
-
if (stampWith === '
|
|
62
|
-
stamp = await client.
|
|
63
|
-
} else if (stampWith === '
|
|
64
|
-
stamp = await client.
|
|
62
|
+
if (stampWith === 'apiKey') {
|
|
63
|
+
stamp = await client.apiKeyStamper.stamp(stampPayload)
|
|
64
|
+
} else if (stampWith === 'passkey') {
|
|
65
|
+
stamp = await client.passkeyStamper.stamp(stampPayload)
|
|
65
66
|
} else {
|
|
66
|
-
stamp = await client.
|
|
67
|
+
stamp = await client.apiKeyStamper.stamp(stampPayload)
|
|
67
68
|
}
|
|
68
69
|
|
|
69
70
|
return client.request({
|
package/src/actions/index.ts
CHANGED
|
@@ -12,10 +12,13 @@ export {
|
|
|
12
12
|
type GetAuthenticatorsParameters,
|
|
13
13
|
type GetAuthenticatorsReturnType,
|
|
14
14
|
type GetAuthProxyConfigIdReturnType,
|
|
15
|
+
type GetOAuthLoginUrlParameters,
|
|
16
|
+
type GetOAuthLoginUrlReturnType,
|
|
15
17
|
type GetWhoamiParameters,
|
|
16
18
|
type GetWhoamiReturnType,
|
|
17
19
|
getAuthenticators,
|
|
18
20
|
getAuthProxyConfigId,
|
|
21
|
+
getOAuthLoginUrl,
|
|
19
22
|
getWhoami,
|
|
20
23
|
type LoginWithOTPParameters,
|
|
21
24
|
type LoginWithOTPReturnType,
|
|
@@ -47,7 +47,7 @@ export async function sendSigningRequest(
|
|
|
47
47
|
|
|
48
48
|
// Inner stamp over the Turnkey payload (for Turnkey verification)
|
|
49
49
|
const innerBodyString = canonicalizeEx(turnkeyPayload)
|
|
50
|
-
const innerStamp = await client.
|
|
50
|
+
const innerStamp = await client.apiKeyStamper.stamp(innerBodyString)
|
|
51
51
|
|
|
52
52
|
// Build full body with inner stamp embedded
|
|
53
53
|
const fullBody = {
|
|
@@ -61,7 +61,7 @@ export async function sendSigningRequest(
|
|
|
61
61
|
|
|
62
62
|
// Outer stamp over full body (for KMS middleware)
|
|
63
63
|
const fullBodyString = canonicalizeEx(fullBody)
|
|
64
|
-
const outerStamp = await client.
|
|
64
|
+
const outerStamp = await client.apiKeyStamper.stamp(fullBodyString)
|
|
65
65
|
|
|
66
66
|
const { signature } = await client.request({
|
|
67
67
|
path: `${projectId}/${path}`,
|
|
@@ -16,8 +16,8 @@ export function createBaseClient<
|
|
|
16
16
|
>(config: ClientConfig): Client<extended> {
|
|
17
17
|
const {
|
|
18
18
|
transport,
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
apiKeyStamper,
|
|
20
|
+
passkeyStamper,
|
|
21
21
|
organizationId,
|
|
22
22
|
key = 'zeroDevWallet',
|
|
23
23
|
name = 'ZeroDev Wallet Client',
|
|
@@ -29,8 +29,8 @@ export function createBaseClient<
|
|
|
29
29
|
request,
|
|
30
30
|
value,
|
|
31
31
|
} = transport({
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
apiKeyStamper,
|
|
33
|
+
passkeyStamper,
|
|
34
34
|
})
|
|
35
35
|
const transportInstance = { ...transportConfig, ...value }
|
|
36
36
|
|
|
@@ -39,8 +39,8 @@ export function createBaseClient<
|
|
|
39
39
|
const client = {
|
|
40
40
|
transport: transportInstance,
|
|
41
41
|
request,
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
apiKeyStamper,
|
|
43
|
+
passkeyStamper,
|
|
44
44
|
organizationId,
|
|
45
45
|
key,
|
|
46
46
|
name,
|
|
@@ -13,12 +13,15 @@ import {
|
|
|
13
13
|
type GetAuthenticatorsParameters,
|
|
14
14
|
type GetAuthenticatorsReturnType,
|
|
15
15
|
type GetAuthProxyConfigIdReturnType,
|
|
16
|
+
type GetOAuthLoginUrlParameters,
|
|
17
|
+
type GetOAuthLoginUrlReturnType,
|
|
16
18
|
type GetUserWalletParameters,
|
|
17
19
|
type GetUserWalletReturnType,
|
|
18
20
|
type GetWhoamiParameters,
|
|
19
21
|
type GetWhoamiReturnType,
|
|
20
22
|
getAuthenticators,
|
|
21
23
|
getAuthProxyConfigId,
|
|
24
|
+
getOAuthLoginUrl,
|
|
22
25
|
getUserWallet,
|
|
23
26
|
getWhoami,
|
|
24
27
|
type LoginWithOTPParameters,
|
|
@@ -153,6 +156,15 @@ export type ZeroDevWalletActions = {
|
|
|
153
156
|
* Gets the auth proxy config ID from the backend
|
|
154
157
|
*/
|
|
155
158
|
getAuthProxyConfigId: () => Promise<GetAuthProxyConfigIdReturnType>
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Fetches the Google OAuth authorization URL from the backend.
|
|
162
|
+
* The caller must verify the URL's `nonce` against `sha256(utf8(publicKey))`
|
|
163
|
+
* before opening it (audit finding TOB-KMS-1).
|
|
164
|
+
*/
|
|
165
|
+
getOAuthLoginUrl: (
|
|
166
|
+
params: GetOAuthLoginUrlParameters,
|
|
167
|
+
) => Promise<GetOAuthLoginUrlReturnType>
|
|
156
168
|
}
|
|
157
169
|
|
|
158
170
|
/**
|
|
@@ -197,5 +209,6 @@ export function zeroDevWalletActions(client: Client): ZeroDevWalletActions {
|
|
|
197
209
|
registerWithOTP: (params) => registerWithOTP(client, params),
|
|
198
210
|
loginWithOTP: (params) => loginWithOTP(client, params),
|
|
199
211
|
getAuthProxyConfigId: () => getAuthProxyConfigId(client),
|
|
212
|
+
getOAuthLoginUrl: (params) => getOAuthLoginUrl(client, params),
|
|
200
213
|
}
|
|
201
214
|
}
|
|
@@ -26,14 +26,14 @@ export function zeroDevWalletTransport(
|
|
|
26
26
|
name = 'ZeroDev Wallet Transport',
|
|
27
27
|
} = options
|
|
28
28
|
|
|
29
|
-
return ({
|
|
29
|
+
return ({ apiKeyStamper, passkeyStamper }) => {
|
|
30
30
|
// Create REST transport with stamper
|
|
31
31
|
const transport = rest(baseUrl, {
|
|
32
32
|
timeoutMs,
|
|
33
33
|
key,
|
|
34
34
|
name,
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
apiKeyStamper,
|
|
36
|
+
passkeyStamper,
|
|
37
37
|
})
|
|
38
38
|
|
|
39
39
|
return {
|
|
@@ -46,8 +46,8 @@ export function zeroDevWalletTransport(
|
|
|
46
46
|
},
|
|
47
47
|
request: transport.request,
|
|
48
48
|
value: {
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
apiKeyStamper,
|
|
50
|
+
passkeyStamper,
|
|
51
51
|
},
|
|
52
52
|
}
|
|
53
53
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { canonicalizeEx } from 'json-canonicalize'
|
|
2
2
|
import { RestRequestError, RestTimeoutError } from '../../errors/request.js'
|
|
3
|
-
import type {
|
|
3
|
+
import type { ApiKeyStamper, PasskeyStamper } from '../../stampers/types.js'
|
|
4
|
+
import type { StamperType } from '../../types/session.js'
|
|
4
5
|
|
|
5
6
|
export type RestRequestArgs = {
|
|
6
7
|
path: string
|
|
@@ -8,7 +9,7 @@ export type RestRequestArgs = {
|
|
|
8
9
|
body?: any
|
|
9
10
|
headers?: Record<string, string>
|
|
10
11
|
stamp?: boolean
|
|
11
|
-
stampWith?:
|
|
12
|
+
stampWith?: StamperType
|
|
12
13
|
stampPostion?: 'body' | 'headers'
|
|
13
14
|
/** Include credentials (cookies) in the request */
|
|
14
15
|
credentials?: RequestCredentials
|
|
@@ -32,8 +33,8 @@ export type RestTransportConfig = {
|
|
|
32
33
|
timeoutMs?: number
|
|
33
34
|
key?: string
|
|
34
35
|
name?: string
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
apiKeyStamper: ApiKeyStamper
|
|
37
|
+
passkeyStamper: PasskeyStamper
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
export function rest(url: string, cfg: RestTransportConfig): RestTransport {
|
|
@@ -56,13 +57,13 @@ export function rest(url: string, cfg: RestTransportConfig): RestTransport {
|
|
|
56
57
|
|
|
57
58
|
// Handle stamping if requested
|
|
58
59
|
if (args.stamp) {
|
|
59
|
-
let stamper:
|
|
60
|
-
if (args.stampWith === '
|
|
61
|
-
stamper = cfg.
|
|
62
|
-
} else if (args.stampWith === '
|
|
63
|
-
stamper = cfg.
|
|
60
|
+
let stamper: ApiKeyStamper | PasskeyStamper
|
|
61
|
+
if (args.stampWith === 'apiKey') {
|
|
62
|
+
stamper = cfg.apiKeyStamper
|
|
63
|
+
} else if (args.stampWith === 'passkey') {
|
|
64
|
+
stamper = cfg.passkeyStamper
|
|
64
65
|
} else {
|
|
65
|
-
stamper = cfg.
|
|
66
|
+
stamper = cfg.apiKeyStamper
|
|
66
67
|
}
|
|
67
68
|
const { body, apiUrl } = args.body
|
|
68
69
|
const bodyString = canonicalizeEx(body ?? args.body)
|
package/src/client/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ApiKeyStamper, PasskeyStamper } from '../stampers/types.js'
|
|
2
2
|
import type { RestRequestFn } from './transports/rest.js'
|
|
3
3
|
|
|
4
4
|
export type TransportConfig = {
|
|
@@ -17,8 +17,8 @@ export type TransportConfig = {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export type Transport = (options: {
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
apiKeyStamper: ApiKeyStamper
|
|
21
|
+
passkeyStamper: PasskeyStamper
|
|
22
22
|
}) => {
|
|
23
23
|
config: TransportConfig
|
|
24
24
|
request: RestRequestFn
|
|
@@ -27,8 +27,8 @@ export type Transport = (options: {
|
|
|
27
27
|
|
|
28
28
|
export type ClientConfig = {
|
|
29
29
|
transport: Transport
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
apiKeyStamper: ApiKeyStamper
|
|
31
|
+
passkeyStamper: PasskeyStamper
|
|
32
32
|
organizationId?: string
|
|
33
33
|
key?: string
|
|
34
34
|
name?: string
|
|
@@ -39,10 +39,10 @@ export type Client<extended extends Extended | undefined = undefined> = {
|
|
|
39
39
|
transport: TransportConfig & Record<string, unknown>
|
|
40
40
|
/** Request function from transport */
|
|
41
41
|
request: RestRequestFn
|
|
42
|
-
/**
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
|
|
42
|
+
/** API Key Stamper for authenticated requests */
|
|
43
|
+
apiKeyStamper: ApiKeyStamper
|
|
44
|
+
/** Passkey Stamper for authenticated requests */
|
|
45
|
+
passkeyStamper: PasskeyStamper
|
|
46
46
|
/** Organization ID */
|
|
47
47
|
organizationId?: string
|
|
48
48
|
/** A key for the client */
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { getWebAuthnAttestation } from '@turnkey/http'
|
|
2
1
|
import type { LocalAccount } from 'viem/accounts'
|
|
3
2
|
import type {
|
|
4
3
|
EmailCustomization,
|
|
@@ -17,6 +16,7 @@ import {
|
|
|
17
16
|
KMS_SERVER_URL,
|
|
18
17
|
} from '../constants.js'
|
|
19
18
|
import { createIndexedDbStamper } from '../stampers/indexedDbStamper.js'
|
|
19
|
+
import type { ApiKeyStamper, PasskeyStamper } from '../stampers/types.js'
|
|
20
20
|
import { createWebauthnStamper } from '../stampers/webauthnStamper.js'
|
|
21
21
|
import { createWebStorageAdapter } from '../storage/adapters.js'
|
|
22
22
|
import {
|
|
@@ -26,19 +26,15 @@ import {
|
|
|
26
26
|
import { SessionType, type ZeroDevWalletSession } from '../types/session.js'
|
|
27
27
|
import { buildClientSignature } from '../utils/buildClientSignature.js'
|
|
28
28
|
import { encryptOtpAttempt } from '../utils/encryptOtpAttempt.js'
|
|
29
|
-
import {
|
|
30
|
-
base64UrlEncode,
|
|
31
|
-
generateCompressedPublicKeyFromKeyPair,
|
|
32
|
-
generateRandomBuffer,
|
|
33
|
-
humanReadableDateTime,
|
|
34
|
-
parseSession,
|
|
35
|
-
} from '../utils/utils.js'
|
|
29
|
+
import { humanReadableDateTime, parseSession } from '../utils/utils.js'
|
|
36
30
|
export interface ZeroDevWalletConfig {
|
|
37
31
|
organizationId?: string
|
|
38
32
|
proxyBaseUrl?: string
|
|
39
33
|
projectId: string
|
|
40
34
|
sessionStorage?: StorageAdapter
|
|
41
35
|
rpId?: string
|
|
36
|
+
apiKeyStamper?: ApiKeyStamper
|
|
37
|
+
passkeyStamper?: PasskeyStamper
|
|
42
38
|
}
|
|
43
39
|
|
|
44
40
|
// Re-export EmailCustomization for convenience
|
|
@@ -134,13 +130,14 @@ export async function createZeroDevWallet(
|
|
|
134
130
|
sessionStorage || createWebStorageAdapter(),
|
|
135
131
|
)
|
|
136
132
|
|
|
137
|
-
const
|
|
133
|
+
const apiKeyStamper = config.apiKeyStamper ?? (await createIndexedDbStamper())
|
|
138
134
|
|
|
139
|
-
const
|
|
135
|
+
const passkeyStamper =
|
|
136
|
+
config.passkeyStamper ?? (await createWebauthnStamper({ rpId }))
|
|
140
137
|
|
|
141
138
|
const client = createClient({
|
|
142
|
-
|
|
143
|
-
|
|
139
|
+
apiKeyStamper,
|
|
140
|
+
passkeyStamper,
|
|
144
141
|
transport: zeroDevWalletTransport({
|
|
145
142
|
baseUrl: config.proxyBaseUrl || `${KMS_SERVER_URL}/api/v1`,
|
|
146
143
|
}),
|
|
@@ -151,8 +148,8 @@ export async function createZeroDevWallet(
|
|
|
151
148
|
return {
|
|
152
149
|
client,
|
|
153
150
|
async getPublicKey() {
|
|
154
|
-
await client.
|
|
155
|
-
const compressedPublicKey = await client.
|
|
151
|
+
await client.apiKeyStamper.resetKeyPair()
|
|
152
|
+
const compressedPublicKey = await client.apiKeyStamper.getPublicKey()
|
|
156
153
|
return compressedPublicKey
|
|
157
154
|
},
|
|
158
155
|
|
|
@@ -191,30 +188,22 @@ export async function createZeroDevWallet(
|
|
|
191
188
|
if (!activeSession) {
|
|
192
189
|
throw new Error('No active session')
|
|
193
190
|
}
|
|
194
|
-
if (activeSession.stamperType === '
|
|
195
|
-
const newKeyPair = await crypto.subtle.generateKey(
|
|
196
|
-
{
|
|
197
|
-
name: 'ECDSA',
|
|
198
|
-
namedCurve: 'P-256',
|
|
199
|
-
},
|
|
200
|
-
false,
|
|
201
|
-
['sign', 'verify'],
|
|
202
|
-
)
|
|
191
|
+
if (activeSession.stamperType === 'apiKey') {
|
|
203
192
|
const compressedPublicKeyHex =
|
|
204
|
-
await
|
|
193
|
+
await client.apiKeyStamper.prepareKeyRotation()
|
|
205
194
|
const data = await client.loginWithStamp({
|
|
206
195
|
targetPublicKey: compressedPublicKeyHex,
|
|
207
196
|
projectId,
|
|
208
197
|
organizationId: activeSession.organizationId,
|
|
209
|
-
stampWith: '
|
|
198
|
+
stampWith: 'apiKey',
|
|
210
199
|
})
|
|
211
|
-
await client.
|
|
200
|
+
await client.apiKeyStamper.commitKeyRotation()
|
|
212
201
|
const parsedSession = parseSession(data.session)
|
|
213
202
|
const session: ZeroDevWalletSession = {
|
|
214
203
|
id: `session_indexedDb_${Date.now()}`,
|
|
215
204
|
userId: parsedSession.userId,
|
|
216
205
|
organizationId: parsedSession.organizationId,
|
|
217
|
-
stamperType: '
|
|
206
|
+
stamperType: 'apiKey',
|
|
218
207
|
sessionType: SessionType.READ_WRITE,
|
|
219
208
|
token: data.session,
|
|
220
209
|
expiry: parsedSession.expiry,
|
|
@@ -240,17 +229,15 @@ export async function createZeroDevWallet(
|
|
|
240
229
|
if (data.session) {
|
|
241
230
|
// Parse the JWT to get session data
|
|
242
231
|
const parsedSession = parseSession(data.session)
|
|
243
|
-
const publicKey = await client.indexedDbStamper.getPublicKey()
|
|
244
232
|
const session: ZeroDevWalletSession = {
|
|
245
233
|
id: `session_oauth_${Date.now()}`,
|
|
246
234
|
userId: parsedSession.userId,
|
|
247
235
|
organizationId: parsedSession.organizationId,
|
|
248
|
-
stamperType: '
|
|
236
|
+
stamperType: 'apiKey',
|
|
249
237
|
sessionType: parsedSession.sessionType || SessionType.READ_WRITE,
|
|
250
238
|
token: data.session,
|
|
251
239
|
expiry: parsedSession.expiry,
|
|
252
240
|
createdAt: Date.now(),
|
|
253
|
-
publicKey: publicKey || '',
|
|
254
241
|
}
|
|
255
242
|
await sessionStorageManager.storeSession(session, session.id)
|
|
256
243
|
}
|
|
@@ -263,62 +250,35 @@ export async function createZeroDevWallet(
|
|
|
263
250
|
'mode' in params &&
|
|
264
251
|
params.mode === 'register'
|
|
265
252
|
) {
|
|
266
|
-
await client.
|
|
267
|
-
const tempPublicKey = await client.
|
|
253
|
+
await client.apiKeyStamper.resetKeyPair()
|
|
254
|
+
const tempPublicKey = await client.apiKeyStamper.getPublicKey()
|
|
268
255
|
if (!tempPublicKey) {
|
|
269
256
|
throw new Error('Failed to get public key')
|
|
270
257
|
}
|
|
271
|
-
const challenge = generateRandomBuffer()
|
|
272
|
-
const encodedChallenge = base64UrlEncode(challenge)
|
|
273
|
-
const authenticatorUserId = generateRandomBuffer()
|
|
274
258
|
const name = `ZeroDevWallet-${humanReadableDateTime()}`
|
|
275
|
-
const attestation
|
|
276
|
-
|
|
259
|
+
const { attestation, encodedChallenge } =
|
|
260
|
+
await passkeyStamper.register({
|
|
277
261
|
rp: { id: rpId, name: '' },
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
{
|
|
281
|
-
type: 'public-key',
|
|
282
|
-
alg: -7,
|
|
283
|
-
},
|
|
284
|
-
{
|
|
285
|
-
type: 'public-key',
|
|
286
|
-
alg: -257,
|
|
287
|
-
},
|
|
288
|
-
],
|
|
289
|
-
user: {
|
|
290
|
-
id: authenticatorUserId,
|
|
291
|
-
name,
|
|
292
|
-
displayName: name,
|
|
293
|
-
},
|
|
294
|
-
},
|
|
295
|
-
})
|
|
262
|
+
userName: name,
|
|
263
|
+
})
|
|
296
264
|
const data = await client.registerWithPasskey({
|
|
297
265
|
attestation,
|
|
298
266
|
challenge: encodedChallenge,
|
|
299
267
|
projectId,
|
|
300
268
|
encodedPublicKey: tempPublicKey,
|
|
301
269
|
})
|
|
302
|
-
const newKeyPair = await crypto.subtle.generateKey(
|
|
303
|
-
{
|
|
304
|
-
name: 'ECDSA',
|
|
305
|
-
namedCurve: 'P-256',
|
|
306
|
-
},
|
|
307
|
-
false,
|
|
308
|
-
['sign', 'verify'],
|
|
309
|
-
)
|
|
310
270
|
const compressedPublicKeyHex =
|
|
311
|
-
await
|
|
271
|
+
await client.apiKeyStamper.prepareKeyRotation()
|
|
312
272
|
const loginData = await client.loginWithStamp({
|
|
313
273
|
projectId,
|
|
314
274
|
targetPublicKey: compressedPublicKeyHex,
|
|
315
275
|
organizationId: data.subOrganizationId,
|
|
316
276
|
})
|
|
317
|
-
await client.
|
|
277
|
+
await client.apiKeyStamper.commitKeyRotation()
|
|
318
278
|
const parsedSession = parseSession(loginData.session)
|
|
319
279
|
const session: ZeroDevWalletSession = {
|
|
320
280
|
id: `session_indexedDb_${Date.now()}`,
|
|
321
|
-
stamperType: '
|
|
281
|
+
stamperType: 'apiKey',
|
|
322
282
|
createdAt: Date.now(),
|
|
323
283
|
sessionType: SessionType.READ_WRITE,
|
|
324
284
|
userId: parsedSession.userId,
|
|
@@ -336,9 +296,8 @@ export async function createZeroDevWallet(
|
|
|
336
296
|
'mode' in params &&
|
|
337
297
|
params.mode === 'login'
|
|
338
298
|
) {
|
|
339
|
-
await client.
|
|
340
|
-
const generatedPublicKey =
|
|
341
|
-
await client.indexedDbStamper.getPublicKey()
|
|
299
|
+
await client.apiKeyStamper.resetKeyPair()
|
|
300
|
+
const generatedPublicKey = await client.apiKeyStamper.getPublicKey()
|
|
342
301
|
if (!generatedPublicKey) {
|
|
343
302
|
throw new Error('Failed to get public key')
|
|
344
303
|
}
|
|
@@ -346,12 +305,12 @@ export async function createZeroDevWallet(
|
|
|
346
305
|
targetPublicKey: generatedPublicKey,
|
|
347
306
|
projectId,
|
|
348
307
|
organizationId,
|
|
349
|
-
stampWith: '
|
|
308
|
+
stampWith: 'passkey',
|
|
350
309
|
})
|
|
351
310
|
const parsedSession = parseSession(loginData.session)
|
|
352
311
|
const session: ZeroDevWalletSession = {
|
|
353
312
|
id: `session_indexedDb_${Date.now()}`,
|
|
354
|
-
stamperType: '
|
|
313
|
+
stamperType: 'apiKey',
|
|
355
314
|
createdAt: Date.now(),
|
|
356
315
|
sessionType: SessionType.READ_WRITE,
|
|
357
316
|
userId: parsedSession.userId,
|
|
@@ -416,8 +375,8 @@ export async function createZeroDevWallet(
|
|
|
416
375
|
const { otpId, otpCode, otpEncryptionTargetBundle } = otpParams
|
|
417
376
|
|
|
418
377
|
// Step 1: Generate new key pair
|
|
419
|
-
await client.
|
|
420
|
-
const targetPublicKey = await client.
|
|
378
|
+
await client.apiKeyStamper.resetKeyPair()
|
|
379
|
+
const targetPublicKey = await client.apiKeyStamper.getPublicKey()
|
|
421
380
|
|
|
422
381
|
if (!targetPublicKey) {
|
|
423
382
|
throw new Error('Failed to get public key')
|
|
@@ -449,7 +408,7 @@ export async function createZeroDevWallet(
|
|
|
449
408
|
const clientSignature = await buildClientSignature({
|
|
450
409
|
verificationToken,
|
|
451
410
|
publicKey: targetPublicKey,
|
|
452
|
-
stamper: client.
|
|
411
|
+
stamper: client.apiKeyStamper,
|
|
453
412
|
})
|
|
454
413
|
|
|
455
414
|
// Step 4: Login via backend (not Auth Proxy!)
|
|
@@ -466,13 +425,12 @@ export async function createZeroDevWallet(
|
|
|
466
425
|
id: `session_otp_${Date.now()}`,
|
|
467
426
|
userId: parsedSession.userId,
|
|
468
427
|
organizationId: parsedSession.organizationId,
|
|
469
|
-
stamperType: '
|
|
428
|
+
stamperType: 'apiKey',
|
|
470
429
|
sessionType:
|
|
471
430
|
parsedSession.sessionType || SessionType.READ_WRITE,
|
|
472
431
|
token: data.session,
|
|
473
432
|
expiry: parsedSession.expiry,
|
|
474
433
|
createdAt: Date.now(),
|
|
475
|
-
publicKey: targetPublicKey,
|
|
476
434
|
}
|
|
477
435
|
await sessionStorageManager.storeSession(session, session.id)
|
|
478
436
|
}
|
|
@@ -488,7 +446,7 @@ export async function createZeroDevWallet(
|
|
|
488
446
|
|
|
489
447
|
async logout() {
|
|
490
448
|
await sessionStorageManager.clearAllSessions()
|
|
491
|
-
await client.
|
|
449
|
+
await client.apiKeyStamper.resetKeyPair()
|
|
492
450
|
return true
|
|
493
451
|
},
|
|
494
452
|
|
package/src/index.ts
CHANGED
|
@@ -80,9 +80,12 @@ export {
|
|
|
80
80
|
createWebauthnStamper,
|
|
81
81
|
} from './stampers/index.js'
|
|
82
82
|
export type {
|
|
83
|
+
ApiKeyStamper,
|
|
84
|
+
Attestation,
|
|
83
85
|
IframeStamper,
|
|
84
|
-
|
|
85
|
-
|
|
86
|
+
PasskeyRegistrationOptions,
|
|
87
|
+
PasskeyRegistrationResult,
|
|
88
|
+
PasskeyStamper,
|
|
86
89
|
} from './stampers/types.js'
|
|
87
90
|
// Storage
|
|
88
91
|
export type { StorageAdapter, StorageManager } from './storage/manager.js'
|
package/src/stampers/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export { createIframeStamper } from './iframeStamper.js'
|
|
2
2
|
export { createIndexedDbStamper } from './indexedDbStamper.js'
|
|
3
3
|
export type {
|
|
4
|
+
ApiKeyStamper,
|
|
4
5
|
IframeStamper,
|
|
5
|
-
|
|
6
|
-
WebauthnStamper,
|
|
6
|
+
PasskeyStamper,
|
|
7
7
|
} from './types.js'
|
|
8
8
|
export { createWebauthnStamper } from './webauthnStamper.js'
|