@0xsequence/wallet-wdk 3.0.2 → 3.0.3

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 (47) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-lint.log +1 -1
  3. package/.turbo/turbo-typecheck.log +1 -1
  4. package/CHANGELOG.md +12 -0
  5. package/dist/sequence/handlers/authcode.d.ts.map +1 -1
  6. package/dist/sequence/handlers/authcode.js +6 -0
  7. package/dist/sequence/handlers/identity.d.ts +1 -0
  8. package/dist/sequence/handlers/identity.d.ts.map +1 -1
  9. package/dist/sequence/handlers/identity.js +3 -0
  10. package/dist/sequence/handlers/idtoken.d.ts +33 -0
  11. package/dist/sequence/handlers/idtoken.d.ts.map +1 -0
  12. package/dist/sequence/handlers/idtoken.js +110 -0
  13. package/dist/sequence/handlers/index.d.ts +1 -0
  14. package/dist/sequence/handlers/index.d.ts.map +1 -1
  15. package/dist/sequence/handlers/index.js +1 -0
  16. package/dist/sequence/manager.d.ts +20 -14
  17. package/dist/sequence/manager.d.ts.map +1 -1
  18. package/dist/sequence/manager.js +21 -3
  19. package/dist/sequence/sessions.d.ts.map +1 -1
  20. package/dist/sequence/sessions.js +5 -1
  21. package/dist/sequence/signers.d.ts.map +1 -1
  22. package/dist/sequence/signers.js +4 -0
  23. package/dist/sequence/types/signer.d.ts +1 -1
  24. package/dist/sequence/types/signer.js +1 -1
  25. package/dist/sequence/types/wallet.d.ts +1 -1
  26. package/dist/sequence/wallets.d.ts +7 -1
  27. package/dist/sequence/wallets.d.ts.map +1 -1
  28. package/dist/sequence/wallets.js +69 -7
  29. package/package.json +6 -6
  30. package/src/sequence/handlers/authcode.ts +6 -0
  31. package/src/sequence/handlers/identity.ts +4 -0
  32. package/src/sequence/handlers/idtoken.ts +140 -0
  33. package/src/sequence/handlers/index.ts +1 -0
  34. package/src/sequence/manager.ts +78 -29
  35. package/src/sequence/sessions.ts +7 -1
  36. package/src/sequence/signers.ts +5 -0
  37. package/src/sequence/types/signer.ts +1 -1
  38. package/src/sequence/types/wallet.ts +1 -1
  39. package/src/sequence/wallets.ts +88 -9
  40. package/test/authcode-pkce.test.ts +1 -1
  41. package/test/authcode.test.ts +2 -2
  42. package/test/identity-auth-dbs.test.ts +86 -2
  43. package/test/identity-signer.test.ts +1 -1
  44. package/test/idtoken.test.ts +327 -0
  45. package/test/sessions-idtoken.test.ts +97 -0
  46. package/test/signers-kindof.test.ts +22 -0
  47. package/test/wallets.test.ts +141 -1
@@ -0,0 +1,97 @@
1
+ import { afterEach, describe, expect, it, vi } from 'vitest'
2
+ import { Hash, Hex, Mnemonic, Secp256k1, Address as OxAddress } from 'ox'
3
+ import { Payload } from '@0xsequence/wallet-primitives'
4
+ import { newManager } from './constants.js'
5
+ import { Manager } from '../src/sequence/index.js'
6
+ import { Kinds } from '../src/sequence/types/signer.js'
7
+
8
+ describe('Sessions ID token attestation', () => {
9
+ let manager: Manager | undefined
10
+
11
+ afterEach(async () => {
12
+ await manager?.stop()
13
+ })
14
+
15
+ it('Should include issuer and audience hashes for google-id-token implicit session authorization', async () => {
16
+ manager = newManager({
17
+ identity: {
18
+ google: {
19
+ enabled: true,
20
+ clientId: 'test-google-client-id',
21
+ authMethod: 'id-token',
22
+ },
23
+ },
24
+ })
25
+
26
+ const wallet = await manager.wallets.signUp({
27
+ mnemonic: Mnemonic.random(Mnemonic.english),
28
+ kind: 'mnemonic',
29
+ noGuard: true,
30
+ })
31
+ expect(wallet).toBeDefined()
32
+
33
+ const signersModule = (manager as any).shared.modules.signers
34
+ vi.spyOn(signersModule, 'kindOf').mockResolvedValue(Kinds.LoginGoogle)
35
+
36
+ const sessionAddress = OxAddress.fromPublicKey(Secp256k1.getPublicKey({ privateKey: Secp256k1.randomPrivateKey() }))
37
+ const requestId = await manager.sessions.prepareAuthorizeImplicitSession(wallet!, sessionAddress, {
38
+ target: 'https://example.com',
39
+ applicationData: '0x1234',
40
+ })
41
+
42
+ const request = await manager.signatures.get(requestId)
43
+ expect(request.action).toBe('session-implicit-authorize')
44
+ expect(Payload.isSessionImplicitAuthorize(request.envelope.payload)).toBe(true)
45
+
46
+ if (!Payload.isSessionImplicitAuthorize(request.envelope.payload)) {
47
+ throw new Error('Expected session implicit authorize payload')
48
+ }
49
+
50
+ const attestation = request.envelope.payload.attestation
51
+ expect(Hex.fromBytes(attestation.issuerHash)).toBe(Hash.keccak256(Hex.fromString('https://accounts.google.com')))
52
+ expect(Hex.fromBytes(attestation.audienceHash)).toBe(Hash.keccak256(Hex.fromString('test-google-client-id')))
53
+ expect(Hex.fromBytes(attestation.applicationData)).toBe('0x1234')
54
+ expect(Hex.fromBytes(attestation.identityType)).toBe('0x00000002')
55
+ })
56
+
57
+ it('Should include issuer and audience hashes for apple implicit session authorization', async () => {
58
+ manager = newManager({
59
+ identity: {
60
+ apple: {
61
+ enabled: true,
62
+ clientId: 'test-apple-client-id',
63
+ },
64
+ },
65
+ })
66
+
67
+ const wallet = await manager.wallets.signUp({
68
+ mnemonic: Mnemonic.random(Mnemonic.english),
69
+ kind: 'mnemonic',
70
+ noGuard: true,
71
+ })
72
+ expect(wallet).toBeDefined()
73
+
74
+ const signersModule = (manager as any).shared.modules.signers
75
+ vi.spyOn(signersModule, 'kindOf').mockResolvedValue(Kinds.LoginApple)
76
+
77
+ const sessionAddress = OxAddress.fromPublicKey(Secp256k1.getPublicKey({ privateKey: Secp256k1.randomPrivateKey() }))
78
+ const requestId = await manager.sessions.prepareAuthorizeImplicitSession(wallet!, sessionAddress, {
79
+ target: 'https://example.com',
80
+ applicationData: '0x1234',
81
+ })
82
+
83
+ const request = await manager.signatures.get(requestId)
84
+ expect(request.action).toBe('session-implicit-authorize')
85
+ expect(Payload.isSessionImplicitAuthorize(request.envelope.payload)).toBe(true)
86
+
87
+ if (!Payload.isSessionImplicitAuthorize(request.envelope.payload)) {
88
+ throw new Error('Expected session implicit authorize payload')
89
+ }
90
+
91
+ const attestation = request.envelope.payload.attestation
92
+ expect(Hex.fromBytes(attestation.issuerHash)).toBe(Hash.keccak256(Hex.fromString('https://appleid.apple.com')))
93
+ expect(Hex.fromBytes(attestation.audienceHash)).toBe(Hash.keccak256(Hex.fromString('test-apple-client-id')))
94
+ expect(Hex.fromBytes(attestation.applicationData)).toBe('0x1234')
95
+ expect(Hex.fromBytes(attestation.identityType)).toBe('0x00000002')
96
+ })
97
+ })
@@ -37,4 +37,26 @@ describe('Signers.kindOf', () => {
37
37
  await signers.kindOf(wallet, '0x2222222222222222222222222222222222222222')
38
38
  expect(getWitnessFor).toHaveBeenCalledTimes(1)
39
39
  })
40
+
41
+ it('normalizes legacy Google PKCE signer kind to the canonical Google signer kind', async () => {
42
+ const getWitnessFor = vi.fn().mockResolvedValue({
43
+ payload: {
44
+ type: 'message',
45
+ message: '0x' + Buffer.from(JSON.stringify({ signerKind: 'login-google-pkce' }), 'utf8').toString('hex'),
46
+ },
47
+ })
48
+
49
+ const manager = newManager({
50
+ stateProvider: {
51
+ getWitnessFor,
52
+ getWitnessForSapient: vi.fn(),
53
+ } as any,
54
+ })
55
+
56
+ const signers = (manager as any).shared.modules.signers
57
+ const wallet = '0x1111111111111111111111111111111111111111'
58
+ const signer = '0x2222222222222222222222222222222222222222'
59
+
60
+ await expect(signers.kindOf(wallet, signer)).resolves.toBe(Kinds.LoginGoogle)
61
+ })
40
62
  })
@@ -1,8 +1,13 @@
1
- import { afterEach, describe, expect, it } from 'vitest'
1
+ import { afterEach, describe, expect, it, vi } from 'vitest'
2
2
  import { Manager, SignerActionable, SignerReady } from '../src/sequence/index.js'
3
3
  import { Mnemonic, Address } from 'ox'
4
4
  import { newManager } from './constants.js'
5
5
  import { Config, Constants, Network } from '@0xsequence/wallet-primitives'
6
+ import { AuthCodePkceHandler } from '../src/sequence/handlers/authcode-pkce.js'
7
+ import { IdTokenHandler } from '../src/sequence/handlers/idtoken.js'
8
+ import { IdentitySigner } from '../src/identity/signer.js'
9
+ import { MnemonicHandler } from '../src/sequence/handlers/mnemonic.js'
10
+ import { Kinds } from '../src/sequence/types/signer.js'
6
11
 
7
12
  describe('Wallets', () => {
8
13
  let manager: Manager | undefined
@@ -24,6 +29,141 @@ describe('Wallets', () => {
24
29
  await expect(manager.wallets.has(wallet!)).resolves.toBeTruthy()
25
30
  })
26
31
 
32
+ it('Should create a new wallet using google-id-token when Google ID token auth is enabled', async () => {
33
+ manager = newManager({
34
+ identity: {
35
+ google: {
36
+ enabled: true,
37
+ clientId: 'test-google-client-id',
38
+ authMethod: 'id-token',
39
+ },
40
+ },
41
+ })
42
+
43
+ const handler = (manager as any).shared.handlers.get(Kinds.LoginGoogle) as IdTokenHandler
44
+ const loginMnemonic = Mnemonic.random(Mnemonic.english)
45
+ const loginSigner = MnemonicHandler.toSigner(loginMnemonic)
46
+ if (!loginSigner) {
47
+ throw new Error('Failed to create login signer for test')
48
+ }
49
+
50
+ const completeAuthSpy = vi
51
+ .spyOn(handler, 'completeAuth')
52
+ .mockResolvedValue([loginSigner as unknown as IdentitySigner, { email: 'google-user@example.com' }])
53
+
54
+ const wallet = await manager.wallets.signUp({
55
+ kind: 'google-id-token',
56
+ idToken: 'eyJhbGciOiJub25lIn0.eyJleHAiOjQxMDI0NDQ4MDB9.',
57
+ noGuard: true,
58
+ })
59
+
60
+ expect(wallet).toBeDefined()
61
+ expect(completeAuthSpy).toHaveBeenCalledWith('eyJhbGciOiJub25lIn0.eyJleHAiOjQxMDI0NDQ4MDB9.')
62
+ await expect(manager.wallets.has(wallet!)).resolves.toBeTruthy()
63
+
64
+ const walletEntry = await manager.wallets.get(wallet!)
65
+ expect(walletEntry).toBeDefined()
66
+ expect(walletEntry!.loginType).toBe(Kinds.LoginGoogle)
67
+ expect(walletEntry!.loginEmail).toBe('google-user@example.com')
68
+
69
+ const configuration = await manager.wallets.getConfiguration(wallet!)
70
+ expect(configuration.login).toHaveLength(1)
71
+ expect(configuration.login[0]!.kind).toBe(Kinds.LoginGoogle)
72
+ })
73
+
74
+ it('Should register and unregister Google ID token UI callbacks through the manager', async () => {
75
+ manager = newManager({
76
+ identity: {
77
+ google: {
78
+ enabled: true,
79
+ clientId: 'test-google-client-id',
80
+ authMethod: 'id-token',
81
+ },
82
+ },
83
+ })
84
+
85
+ const handler = (manager as any).shared.handlers.get(Kinds.LoginGoogle) as IdTokenHandler
86
+ const promptIdToken = vi.fn()
87
+
88
+ const unregister = manager.registerIdTokenUI(promptIdToken)
89
+
90
+ expect(handler['onPromptIdToken']).toBe(promptIdToken)
91
+
92
+ unregister()
93
+
94
+ expect(handler['onPromptIdToken']).toBeUndefined()
95
+ })
96
+
97
+ it('Should keep Google PKCE redirect flow as the default when authMethod is not specified', async () => {
98
+ manager = newManager({
99
+ identity: {
100
+ google: {
101
+ enabled: true,
102
+ clientId: 'test-google-client-id',
103
+ },
104
+ },
105
+ })
106
+
107
+ const handler = (manager as any).shared.handlers.get(Kinds.LoginGoogle) as AuthCodePkceHandler
108
+ expect(handler).toBeInstanceOf(AuthCodePkceHandler)
109
+
110
+ const commitAuthSpy = vi
111
+ .spyOn(handler, 'commitAuth')
112
+ .mockResolvedValue('https://accounts.google.com/o/oauth2/v2/auth?state=test-state')
113
+
114
+ const url = await manager.wallets.startSignUpWithRedirect({
115
+ kind: 'google-pkce',
116
+ target: '/auth/return',
117
+ metadata: {},
118
+ })
119
+
120
+ expect(url).toBe('https://accounts.google.com/o/oauth2/v2/auth?state=test-state')
121
+ expect(commitAuthSpy).toHaveBeenCalledWith('/auth/return', true)
122
+ })
123
+
124
+ it('Should reject google-id-token signup when Google is configured for redirect auth', async () => {
125
+ manager = newManager({
126
+ identity: {
127
+ google: {
128
+ enabled: true,
129
+ clientId: 'test-google-client-id',
130
+ },
131
+ },
132
+ })
133
+
134
+ await expect(
135
+ manager.wallets.signUp({
136
+ kind: 'google-id-token',
137
+ idToken: 'eyJhbGciOiJub25lIn0.eyJleHAiOjQxMDI0NDQ4MDB9.',
138
+ noGuard: true,
139
+ }),
140
+ ).rejects.toThrow('handler-does-not-support-id-token')
141
+ })
142
+
143
+ it('Should reject custom ID token signup when the provider uses redirect auth', async () => {
144
+ manager = newManager({
145
+ identity: {
146
+ customProviders: [
147
+ {
148
+ kind: 'custom-oidc',
149
+ authMethod: 'authcode',
150
+ issuer: 'https://issuer.example.com',
151
+ oauthUrl: 'https://issuer.example.com/oauth/authorize',
152
+ clientId: 'test-custom-client-id',
153
+ },
154
+ ],
155
+ },
156
+ })
157
+
158
+ await expect(
159
+ manager.wallets.signUp({
160
+ kind: 'custom-oidc',
161
+ idToken: 'eyJhbGciOiJub25lIn0.eyJleHAiOjQxMDI0NDQ4MDB9.',
162
+ noGuard: true,
163
+ }),
164
+ ).rejects.toThrow('handler-does-not-support-id-token')
165
+ })
166
+
27
167
  it('Should get a specific wallet by address', async () => {
28
168
  manager = newManager()
29
169
  const mnemonic = Mnemonic.random(Mnemonic.english)