@bsv/wallet-toolbox 1.1.25 → 1.1.27

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 (209) hide show
  1. package/docs/client.md +78 -2313
  2. package/docs/setup.md +15 -19
  3. package/docs/wallet.md +78 -2313
  4. package/out/src/Setup.d.ts +4 -0
  5. package/out/src/Setup.d.ts.map +1 -1
  6. package/out/src/Setup.js +19 -9
  7. package/out/src/Setup.js.map +1 -1
  8. package/out/src/Wallet.d.ts +1 -6
  9. package/out/src/Wallet.d.ts.map +1 -1
  10. package/out/src/Wallet.js +2 -29
  11. package/out/src/Wallet.js.map +1 -1
  12. package/out/src/index.all.d.ts +0 -9
  13. package/out/src/index.all.d.ts.map +1 -1
  14. package/out/src/index.all.js +0 -9
  15. package/out/src/index.all.js.map +1 -1
  16. package/out/src/index.client.d.ts +0 -9
  17. package/out/src/index.client.d.ts.map +1 -1
  18. package/out/src/index.client.js +0 -9
  19. package/out/src/index.client.js.map +1 -1
  20. package/out/src/storage/WalletStorageManager.d.ts.map +1 -1
  21. package/out/src/storage/WalletStorageManager.js +2 -0
  22. package/out/src/storage/WalletStorageManager.js.map +1 -1
  23. package/out/test/examples/backup.test.d.ts +14 -0
  24. package/out/test/examples/backup.test.d.ts.map +1 -0
  25. package/out/test/examples/backup.test.js +59 -0
  26. package/out/test/examples/backup.test.js.map +1 -0
  27. package/out/test/wallet/action/abortAction.test.d.ts.map +1 -0
  28. package/out/test/{Wallet → wallet}/action/abortAction.test.js.map +1 -1
  29. package/out/test/wallet/action/createAction.test.d.ts.map +1 -0
  30. package/out/test/{Wallet → wallet}/action/createAction.test.js.map +1 -1
  31. package/out/test/{Wallet → wallet}/action/createAction2.test.d.ts.map +1 -1
  32. package/out/test/{Wallet → wallet}/action/createAction2.test.js.map +1 -1
  33. package/out/test/wallet/action/createActionToGenerateBeefs.man.test.d.ts.map +1 -0
  34. package/out/test/{Wallet → wallet}/action/createActionToGenerateBeefs.man.test.js.map +1 -1
  35. package/out/test/wallet/action/internalizeAction.test.d.ts.map +1 -0
  36. package/out/test/{Wallet → wallet}/action/internalizeAction.test.js.map +1 -1
  37. package/out/test/wallet/action/relinquishOutput.test.d.ts.map +1 -0
  38. package/out/test/{Wallet → wallet}/action/relinquishOutput.test.js.map +1 -1
  39. package/out/test/wallet/construct/Wallet.constructor.test.d.ts.map +1 -0
  40. package/out/test/{Wallet → wallet}/construct/Wallet.constructor.test.js.map +1 -1
  41. package/out/test/wallet/list/listActions.test.d.ts.map +1 -0
  42. package/out/test/{Wallet → wallet}/list/listActions.test.js.map +1 -1
  43. package/out/test/wallet/list/listActions2.test.d.ts.map +1 -0
  44. package/out/test/{Wallet → wallet}/list/listActions2.test.js.map +1 -1
  45. package/out/test/wallet/list/listCertificates.test.d.ts.map +1 -0
  46. package/out/test/{Wallet → wallet}/list/listCertificates.test.js.map +1 -1
  47. package/out/test/wallet/list/listOutputs.test.d.ts.map +1 -0
  48. package/out/test/{Wallet → wallet}/list/listOutputs.test.js.map +1 -1
  49. package/out/test/wallet/sync/Wallet.sync.test.d.ts.map +1 -0
  50. package/out/test/{Wallet → wallet}/sync/Wallet.sync.test.js.map +1 -1
  51. package/out/tsconfig.all.tsbuildinfo +1 -1
  52. package/package.json +3 -3
  53. package/src/Setup.ts +22 -9
  54. package/src/Wallet.ts +3 -47
  55. package/src/index.all.ts +0 -9
  56. package/src/index.client.ts +0 -9
  57. package/src/storage/WalletStorageManager.ts +1 -0
  58. package/test/examples/backup.test.ts +66 -0
  59. package/out/src/CWIStyleWalletManager.d.ts +0 -411
  60. package/out/src/CWIStyleWalletManager.d.ts.map +0 -1
  61. package/out/src/CWIStyleWalletManager.js +0 -1131
  62. package/out/src/CWIStyleWalletManager.js.map +0 -1
  63. package/out/src/SetupClient.d.ts +0 -249
  64. package/out/src/SetupClient.d.ts.map +0 -1
  65. package/out/src/SetupClient.js +0 -252
  66. package/out/src/SetupClient.js.map +0 -1
  67. package/out/src/SimpleWalletManager.d.ts +0 -169
  68. package/out/src/SimpleWalletManager.d.ts.map +0 -1
  69. package/out/src/SimpleWalletManager.js +0 -315
  70. package/out/src/SimpleWalletManager.js.map +0 -1
  71. package/out/src/WalletAuthenticationManager.d.ts +0 -33
  72. package/out/src/WalletAuthenticationManager.d.ts.map +0 -1
  73. package/out/src/WalletAuthenticationManager.js +0 -107
  74. package/out/src/WalletAuthenticationManager.js.map +0 -1
  75. package/out/src/WalletPermissionsManager.d.ts +0 -575
  76. package/out/src/WalletPermissionsManager.d.ts.map +0 -1
  77. package/out/src/WalletPermissionsManager.js +0 -1807
  78. package/out/src/WalletPermissionsManager.js.map +0 -1
  79. package/out/src/WalletSettingsManager.d.ts +0 -59
  80. package/out/src/WalletSettingsManager.d.ts.map +0 -1
  81. package/out/src/WalletSettingsManager.js +0 -168
  82. package/out/src/WalletSettingsManager.js.map +0 -1
  83. package/out/src/__tests/CWIStyleWalletManager.test.d.ts +0 -2
  84. package/out/src/__tests/CWIStyleWalletManager.test.d.ts.map +0 -1
  85. package/out/src/__tests/CWIStyleWalletManager.test.js +0 -472
  86. package/out/src/__tests/CWIStyleWalletManager.test.js.map +0 -1
  87. package/out/src/__tests/WalletPermissionsManager.callbacks.test.d.ts +0 -2
  88. package/out/src/__tests/WalletPermissionsManager.callbacks.test.d.ts.map +0 -1
  89. package/out/src/__tests/WalletPermissionsManager.callbacks.test.js +0 -239
  90. package/out/src/__tests/WalletPermissionsManager.callbacks.test.js.map +0 -1
  91. package/out/src/__tests/WalletPermissionsManager.checks.test.d.ts +0 -2
  92. package/out/src/__tests/WalletPermissionsManager.checks.test.d.ts.map +0 -1
  93. package/out/src/__tests/WalletPermissionsManager.checks.test.js +0 -644
  94. package/out/src/__tests/WalletPermissionsManager.checks.test.js.map +0 -1
  95. package/out/src/__tests/WalletPermissionsManager.encryption.test.d.ts +0 -2
  96. package/out/src/__tests/WalletPermissionsManager.encryption.test.d.ts.map +0 -1
  97. package/out/src/__tests/WalletPermissionsManager.encryption.test.js +0 -295
  98. package/out/src/__tests/WalletPermissionsManager.encryption.test.js.map +0 -1
  99. package/out/src/__tests/WalletPermissionsManager.fixtures.d.ts +0 -82
  100. package/out/src/__tests/WalletPermissionsManager.fixtures.d.ts.map +0 -1
  101. package/out/src/__tests/WalletPermissionsManager.fixtures.js +0 -260
  102. package/out/src/__tests/WalletPermissionsManager.fixtures.js.map +0 -1
  103. package/out/src/__tests/WalletPermissionsManager.flows.test.d.ts +0 -2
  104. package/out/src/__tests/WalletPermissionsManager.flows.test.d.ts.map +0 -1
  105. package/out/src/__tests/WalletPermissionsManager.flows.test.js +0 -389
  106. package/out/src/__tests/WalletPermissionsManager.flows.test.js.map +0 -1
  107. package/out/src/__tests/WalletPermissionsManager.initialization.test.d.ts +0 -2
  108. package/out/src/__tests/WalletPermissionsManager.initialization.test.d.ts.map +0 -1
  109. package/out/src/__tests/WalletPermissionsManager.initialization.test.js +0 -227
  110. package/out/src/__tests/WalletPermissionsManager.initialization.test.js.map +0 -1
  111. package/out/src/__tests/WalletPermissionsManager.proxying.test.d.ts +0 -2
  112. package/out/src/__tests/WalletPermissionsManager.proxying.test.d.ts.map +0 -1
  113. package/out/src/__tests/WalletPermissionsManager.proxying.test.js +0 -566
  114. package/out/src/__tests/WalletPermissionsManager.proxying.test.js.map +0 -1
  115. package/out/src/__tests/WalletPermissionsManager.tokens.test.d.ts +0 -2
  116. package/out/src/__tests/WalletPermissionsManager.tokens.test.d.ts.map +0 -1
  117. package/out/src/__tests/WalletPermissionsManager.tokens.test.js +0 -460
  118. package/out/src/__tests/WalletPermissionsManager.tokens.test.js.map +0 -1
  119. package/out/src/utility/identityUtils.d.ts +0 -31
  120. package/out/src/utility/identityUtils.d.ts.map +0 -1
  121. package/out/src/utility/identityUtils.js +0 -114
  122. package/out/src/utility/identityUtils.js.map +0 -1
  123. package/out/src/wab-client/WABClient.d.ts +0 -38
  124. package/out/src/wab-client/WABClient.d.ts.map +0 -1
  125. package/out/src/wab-client/WABClient.js +0 -95
  126. package/out/src/wab-client/WABClient.js.map +0 -1
  127. package/out/src/wab-client/__tests/WABClient.test.d.ts +0 -2
  128. package/out/src/wab-client/__tests/WABClient.test.d.ts.map +0 -1
  129. package/out/src/wab-client/__tests/WABClient.test.js +0 -47
  130. package/out/src/wab-client/__tests/WABClient.test.js.map +0 -1
  131. package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.d.ts +0 -34
  132. package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.d.ts.map +0 -1
  133. package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.js +0 -16
  134. package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.js.map +0 -1
  135. package/out/src/wab-client/auth-method-interactors/PersonaIDInteractor.d.ts +0 -7
  136. package/out/src/wab-client/auth-method-interactors/PersonaIDInteractor.d.ts.map +0 -1
  137. package/out/src/wab-client/auth-method-interactors/PersonaIDInteractor.js +0 -40
  138. package/out/src/wab-client/auth-method-interactors/PersonaIDInteractor.js.map +0 -1
  139. package/out/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.d.ts +0 -28
  140. package/out/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.d.ts.map +0 -1
  141. package/out/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.js +0 -73
  142. package/out/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.js.map +0 -1
  143. package/out/test/Wallet/action/abortAction.test.d.ts.map +0 -1
  144. package/out/test/Wallet/action/createAction.test.d.ts.map +0 -1
  145. package/out/test/Wallet/action/createActionToGenerateBeefs.man.test.d.ts.map +0 -1
  146. package/out/test/Wallet/action/internalizeAction.test.d.ts.map +0 -1
  147. package/out/test/Wallet/action/relinquishOutput.test.d.ts.map +0 -1
  148. package/out/test/Wallet/construct/Wallet.constructor.test.d.ts.map +0 -1
  149. package/out/test/Wallet/list/listActions.test.d.ts.map +0 -1
  150. package/out/test/Wallet/list/listActions2.test.d.ts.map +0 -1
  151. package/out/test/Wallet/list/listCertificates.test.d.ts.map +0 -1
  152. package/out/test/Wallet/list/listOutputs.test.d.ts.map +0 -1
  153. package/out/test/Wallet/sync/Wallet.sync.test.d.ts.map +0 -1
  154. package/src/CWIStyleWalletManager.ts +0 -1891
  155. package/src/SimpleWalletManager.ts +0 -553
  156. package/src/WalletAuthenticationManager.ts +0 -183
  157. package/src/WalletPermissionsManager.ts +0 -2639
  158. package/src/WalletSettingsManager.ts +0 -241
  159. package/src/__tests/CWIStyleWalletManager.test.ts +0 -709
  160. package/src/__tests/WalletPermissionsManager.callbacks.test.ts +0 -328
  161. package/src/__tests/WalletPermissionsManager.checks.test.ts +0 -857
  162. package/src/__tests/WalletPermissionsManager.encryption.test.ts +0 -407
  163. package/src/__tests/WalletPermissionsManager.fixtures.ts +0 -283
  164. package/src/__tests/WalletPermissionsManager.flows.test.ts +0 -490
  165. package/src/__tests/WalletPermissionsManager.initialization.test.ts +0 -333
  166. package/src/__tests/WalletPermissionsManager.proxying.test.ts +0 -753
  167. package/src/__tests/WalletPermissionsManager.tokens.test.ts +0 -584
  168. package/src/utility/identityUtils.ts +0 -170
  169. package/src/wab-client/WABClient.ts +0 -103
  170. package/src/wab-client/__tests/WABClient.test.ts +0 -58
  171. package/src/wab-client/auth-method-interactors/AuthMethodInteractor.ts +0 -47
  172. package/src/wab-client/auth-method-interactors/PersonaIDInteractor.ts +0 -45
  173. package/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.ts +0 -82
  174. /package/out/test/{Wallet → wallet}/action/abortAction.test.d.ts +0 -0
  175. /package/out/test/{Wallet → wallet}/action/abortAction.test.js +0 -0
  176. /package/out/test/{Wallet → wallet}/action/createAction.test.d.ts +0 -0
  177. /package/out/test/{Wallet → wallet}/action/createAction.test.js +0 -0
  178. /package/out/test/{Wallet → wallet}/action/createAction2.test.d.ts +0 -0
  179. /package/out/test/{Wallet → wallet}/action/createAction2.test.js +0 -0
  180. /package/out/test/{Wallet → wallet}/action/createActionToGenerateBeefs.man.test.d.ts +0 -0
  181. /package/out/test/{Wallet → wallet}/action/createActionToGenerateBeefs.man.test.js +0 -0
  182. /package/out/test/{Wallet → wallet}/action/internalizeAction.test.d.ts +0 -0
  183. /package/out/test/{Wallet → wallet}/action/internalizeAction.test.js +0 -0
  184. /package/out/test/{Wallet → wallet}/action/relinquishOutput.test.d.ts +0 -0
  185. /package/out/test/{Wallet → wallet}/action/relinquishOutput.test.js +0 -0
  186. /package/out/test/{Wallet → wallet}/construct/Wallet.constructor.test.d.ts +0 -0
  187. /package/out/test/{Wallet → wallet}/construct/Wallet.constructor.test.js +0 -0
  188. /package/out/test/{Wallet → wallet}/list/listActions.test.d.ts +0 -0
  189. /package/out/test/{Wallet → wallet}/list/listActions.test.js +0 -0
  190. /package/out/test/{Wallet → wallet}/list/listActions2.test.d.ts +0 -0
  191. /package/out/test/{Wallet → wallet}/list/listActions2.test.js +0 -0
  192. /package/out/test/{Wallet → wallet}/list/listCertificates.test.d.ts +0 -0
  193. /package/out/test/{Wallet → wallet}/list/listCertificates.test.js +0 -0
  194. /package/out/test/{Wallet → wallet}/list/listOutputs.test.d.ts +0 -0
  195. /package/out/test/{Wallet → wallet}/list/listOutputs.test.js +0 -0
  196. /package/out/test/{Wallet → wallet}/sync/Wallet.sync.test.d.ts +0 -0
  197. /package/out/test/{Wallet → wallet}/sync/Wallet.sync.test.js +0 -0
  198. /package/test/{Wallet → wallet}/action/abortAction.test.ts +0 -0
  199. /package/test/{Wallet → wallet}/action/createAction.test.ts +0 -0
  200. /package/test/{Wallet → wallet}/action/createAction2.test.ts +0 -0
  201. /package/test/{Wallet → wallet}/action/createActionToGenerateBeefs.man.test.ts +0 -0
  202. /package/test/{Wallet → wallet}/action/internalizeAction.test.ts +0 -0
  203. /package/test/{Wallet → wallet}/action/relinquishOutput.test.ts +0 -0
  204. /package/test/{Wallet → wallet}/construct/Wallet.constructor.test.ts +0 -0
  205. /package/test/{Wallet → wallet}/list/listActions.test.ts +0 -0
  206. /package/test/{Wallet → wallet}/list/listActions2.test.ts +0 -0
  207. /package/test/{Wallet → wallet}/list/listCertificates.test.ts +0 -0
  208. /package/test/{Wallet → wallet}/list/listOutputs.test.ts +0 -0
  209. /package/test/{Wallet → wallet}/sync/Wallet.sync.test.ts +0 -0
@@ -1,644 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const WalletPermissionsManager_fixtures_1 = require("./WalletPermissionsManager.fixtures");
4
- const WalletPermissionsManager_1 = require("../WalletPermissionsManager");
5
- jest.mock('@bsv/sdk', () => WalletPermissionsManager_fixtures_1.MockedBSV_SDK);
6
- describe('WalletPermissionsManager - Permission Checks', () => {
7
- let underlying;
8
- let manager;
9
- beforeEach(() => {
10
- // Fresh mock wallet before each test
11
- underlying = (0, WalletPermissionsManager_fixtures_1.mockUnderlyingWallet)();
12
- });
13
- afterEach(() => {
14
- jest.clearAllMocks();
15
- });
16
- /* ------------------------------------------------------
17
- * 5) PROTOCOL USAGE (DPACP) TESTS
18
- * ------------------------------------------------------ */
19
- describe('Protocol Usage (DPACP)', () => {
20
- it('should skip permission prompt if secLevel=0 (open usage)', async () => {
21
- manager = new WalletPermissionsManager_1.WalletPermissionsManager(underlying, 'admin.com', {
22
- seekProtocolPermissionsForSigning: true // Typically enforced
23
- });
24
- // Attempt createSignature with protocolID=[0, "someProtocol"]
25
- // Because securityLevel=0, the manager should skip checks
26
- await expect(manager.createSignature({
27
- protocolID: [0, 'open-protocol'],
28
- data: [0x01, 0x02],
29
- keyID: '1'
30
- }, 'some-user.com')).resolves.not.toThrow();
31
- // No permission request
32
- const activeRequests = manager.activeRequests;
33
- expect(activeRequests.size).toBe(0);
34
- // Underlying createSignature called once
35
- expect(underlying.createSignature).toHaveBeenCalledTimes(1);
36
- });
37
- it('should prompt for protocol usage if securityLevel=1 and no existing token', async () => {
38
- manager = new WalletPermissionsManager_1.WalletPermissionsManager(underlying, 'admin.com', {
39
- seekProtocolPermissionsForSigning: true
40
- });
41
- // We'll bind a callback that grants ephemeral permission automatically
42
- manager.bindCallback('onProtocolPermissionRequested', async (request) => {
43
- // For tests, automatically grant ephemeral permission
44
- await manager.grantPermission({
45
- requestID: request.requestID,
46
- ephemeral: true
47
- });
48
- });
49
- // Because secLevel=1, we need a valid DPACP token
50
- // We have no token => manager triggers a request => callback grants ephemeral => passes
51
- await expect(manager.createSignature({
52
- protocolID: [1, 'test-protocol'],
53
- data: [0x99, 0xaa],
54
- keyID: '1'
55
- }, 'some-nonadmin.com')).resolves.not.toThrow();
56
- // The underlying signature should succeed
57
- expect(underlying.createSignature).toHaveBeenCalledTimes(1);
58
- });
59
- it('should deny protocol usage if user denies permission', async () => {
60
- manager = new WalletPermissionsManager_1.WalletPermissionsManager(underlying, 'admin.com', {});
61
- // The callback denies the request
62
- manager.bindCallback('onProtocolPermissionRequested', request => {
63
- manager.denyPermission(request.requestID);
64
- });
65
- // Attempt an operation that requires protocol permission
66
- await expect(manager.encrypt({
67
- protocolID: [1, 'needs-perm'],
68
- plaintext: [1, 2, 3],
69
- keyID: 'xyz'
70
- }, 'external-app.com')).rejects.toThrow(/Permission denied/);
71
- // Underlying encrypt was never called
72
- expect(underlying.encrypt).toHaveBeenCalledTimes(0);
73
- });
74
- it('should enforce privileged token if differentiatePrivilegedOperations=true', async () => {
75
- // By default, differentiatePrivilegedOperations is true.
76
- manager = new WalletPermissionsManager_1.WalletPermissionsManager(underlying, 'admin.com', {
77
- seekProtocolPermissionsForSigning: true
78
- });
79
- manager.bindCallback('onProtocolPermissionRequested', async (req) => {
80
- // The request has `privileged=true`, so the resulting token must also be privileged.
81
- // We'll grant ephemeral to simulate success quickly.
82
- await manager.grantPermission({
83
- requestID: req.requestID,
84
- ephemeral: true
85
- });
86
- });
87
- // Attempt a privileged signature
88
- await expect(manager.createSignature({
89
- protocolID: [1, 'high-level-crypto'],
90
- privileged: true,
91
- data: [0xc0, 0xff, 0xee],
92
- keyID: '1'
93
- }, 'nonadmin.app')).resolves.not.toThrow();
94
- // Confirm underlying was ultimately called
95
- expect(underlying.createSignature).toHaveBeenCalledTimes(1);
96
- });
97
- it('should ignore `privileged=true` if differentiatePrivilegedOperations=false', async () => {
98
- manager = new WalletPermissionsManager_1.WalletPermissionsManager(underlying, 'admin.com', {
99
- differentiatePrivilegedOperations: false, // Forces privileged usage to be treated as non-privileged
100
- seekProtocolPermissionsForSigning: true
101
- });
102
- // Because we treat privileged as false, the permission request does not need privileged credentials.
103
- manager.bindCallback('onProtocolPermissionRequested', async (req) => {
104
- await manager.grantPermission({
105
- requestID: req.requestID,
106
- ephemeral: true
107
- });
108
- });
109
- await expect(manager.createSignature({
110
- protocolID: [1, 'some-protocol'],
111
- privileged: true, // This flag will be ignored
112
- data: [0x99],
113
- keyID: 'keyXYZ'
114
- }, 'nonadmin.com')).resolves.not.toThrow();
115
- });
116
- it('should fail if protocol name is admin-reserved and caller is not admin', async () => {
117
- // admin-reserved means protocol name starts with "admin" or "p ".
118
- manager = new WalletPermissionsManager_1.WalletPermissionsManager(underlying, 'secure.admin.com');
119
- // Non-admin tries to do e.g. `createHmac` with protocol name "admin super-secret"
120
- await expect(manager.createHmac({
121
- protocolID: [1, 'admin super-secret'],
122
- data: [0x01, 0x02],
123
- keyID: '1'
124
- }, 'not-an-admin.com')).rejects.toThrow(/admin-only/i);
125
- // Underlying call never invoked
126
- expect(underlying.createHmac).toHaveBeenCalledTimes(0);
127
- });
128
- it('should prompt for renewal if token is found but expired', async () => {
129
- manager = new WalletPermissionsManager_1.WalletPermissionsManager(underlying, 'admin.com', {});
130
- // Suppose the user already had a token but it’s expired. We mock `findProtocolToken` so that
131
- // it returns an expired token, forcing a renewal request.
132
- const expiredToken = {
133
- txid: 'oldtxid123',
134
- outputIndex: 0,
135
- outputScript: 'deadbeef',
136
- satoshis: 1,
137
- originator: 'some-nonadmin.com',
138
- expiry: 1, // definitely in the past
139
- privileged: false,
140
- securityLevel: 1,
141
- protocol: 'test-protocol',
142
- counterparty: 'self'
143
- };
144
- jest
145
- .spyOn(manager, 'findProtocolToken')
146
- .mockResolvedValue(expiredToken);
147
- // We'll bind a callback that grants a renewal ephemeral
148
- manager.bindCallback('onProtocolPermissionRequested', async (req) => {
149
- expect(req.renewal).toBe(true);
150
- expect(req.previousToken).toEqual(expiredToken);
151
- await manager.grantPermission({
152
- requestID: req.requestID,
153
- ephemeral: true
154
- });
155
- });
156
- // Now call an operation that requires protocol usage
157
- await manager.createSignature({
158
- protocolID: [1, 'test-protocol'],
159
- data: [0xfe],
160
- keyID: '1'
161
- }, 'some-nonadmin.com');
162
- // Should succeed after renewal
163
- expect(underlying.createSignature).toHaveBeenCalledTimes(1);
164
- });
165
- });
166
- /* ------------------------------------------------------
167
- * 6) BASKET USAGE (DBAP) TESTS
168
- * ------------------------------------------------------ */
169
- describe('Basket Usage (DBAP)', () => {
170
- it('should fail immediately if using an admin-only basket as non-admin', async () => {
171
- manager = new WalletPermissionsManager_1.WalletPermissionsManager(underlying, 'admin.com');
172
- // Attempt to createAction to insert into "admin secret-basket" from a non-admin origin
173
- await expect(manager.createAction({
174
- description: 'Insert into admin basket',
175
- outputs: [
176
- {
177
- lockingScript: 'abcd',
178
- satoshis: 100,
179
- basket: 'admin secret-basket',
180
- outputDescription: 'Nothing to see here'
181
- }
182
- ]
183
- }, 'non-admin.com')).rejects.toThrow(/admin-only/i);
184
- // Underlying createAction never called
185
- expect(underlying.createAction).toHaveBeenCalledTimes(0);
186
- });
187
- it('should fail immediately if using the reserved basket "default" as non-admin', async () => {
188
- manager = new WalletPermissionsManager_1.WalletPermissionsManager(underlying, 'admin.com');
189
- await expect(manager.createAction({
190
- description: 'Insert to default basket',
191
- outputs: [
192
- {
193
- lockingScript: '0x1234',
194
- satoshis: 1,
195
- basket: 'default',
196
- outputDescription: 'Nothing to see here'
197
- }
198
- ]
199
- }, 'some-nonadmin.com')).rejects.toThrow(/admin-only/i);
200
- });
201
- it('should prompt for insertion permission if seekBasketInsertionPermissions=true', async () => {
202
- manager = new WalletPermissionsManager_1.WalletPermissionsManager(underlying, 'admin.com', {
203
- seekBasketInsertionPermissions: true
204
- });
205
- // auto-grant ephemeral
206
- manager.bindCallback('onBasketAccessRequested', async (req) => {
207
- await manager.grantPermission({
208
- requestID: req.requestID,
209
- ephemeral: true
210
- });
211
- });
212
- // Also auto-grant unrelated spending authorization (since this is createAction)
213
- manager.bindCallback('onSpendingAuthorizationRequested', async (req) => {
214
- await manager.grantPermission({
215
- requestID: req.requestID,
216
- ephemeral: true
217
- });
218
- });
219
- await expect(manager.createAction({
220
- description: 'Insert to user-basket',
221
- outputs: [
222
- {
223
- lockingScript: 'op_return',
224
- satoshis: 1,
225
- basket: 'user-basket',
226
- outputDescription: 'Nothing to see here'
227
- }
228
- ]
229
- }, 'some-nonadmin.com')).resolves.not.toThrow();
230
- // Confirm underlying createAction was eventually invoked
231
- expect(underlying.createAction).toHaveBeenCalledTimes(1);
232
- });
233
- it('should skip insertion permission if seekBasketInsertionPermissions=false', async () => {
234
- manager = new WalletPermissionsManager_1.WalletPermissionsManager(underlying, 'admin.com', {
235
- seekBasketInsertionPermissions: false
236
- });
237
- // Auto-grant unrelated spending authorization (since this is createAction)
238
- manager.bindCallback('onSpendingAuthorizationRequested', async (req) => {
239
- await manager.grantPermission({
240
- requestID: req.requestID,
241
- ephemeral: true
242
- });
243
- });
244
- await manager.createAction({
245
- description: 'Insert to user-basket',
246
- outputs: [
247
- {
248
- lockingScript: 'op_return',
249
- satoshis: 1,
250
- basket: 'some-basket',
251
- outputDescription: 'Nothing to see here'
252
- }
253
- ]
254
- }, 'nonadmin.com');
255
- // No requests queued, underlying is called
256
- const activeRequests = manager.activeRequests;
257
- expect(activeRequests.size).toBe(0);
258
- expect(underlying.createAction).toHaveBeenCalledTimes(1);
259
- });
260
- it('should require listing permission if seekBasketListingPermissions=true and no token', async () => {
261
- manager = new WalletPermissionsManager_1.WalletPermissionsManager(underlying, 'admin.com', {
262
- seekBasketListingPermissions: true
263
- });
264
- manager.bindCallback('onBasketAccessRequested', async (req) => {
265
- // Deny for test
266
- manager.denyPermission(req.requestID);
267
- });
268
- // Attempt to list a user basket
269
- await expect(manager.listOutputs({ basket: 'user-basket' }, 'some-user.com')).rejects.toThrow(/Permission denied/);
270
- // There is one underlying call: internally, we called listOutputs to check if we had permission
271
- // (we did not, we sought it, and the user denied). So we see this call here, but we DO NOT see
272
- // the actual proxied call (for listing outputs in user-basket), since it was denied.
273
- expect(underlying.listOutputs).toHaveBeenCalledTimes(1);
274
- expect(underlying.listOutputs).toHaveBeenLastCalledWith({
275
- basket: 'admin basket-access',
276
- include: 'locking scripts',
277
- tagQueryMode: 'all',
278
- tags: ['originator some-user.com', 'basket user-basket']
279
- }, 'admin.com');
280
- });
281
- it('should prompt for removal permission if seekBasketRemovalPermissions=true', async () => {
282
- manager = new WalletPermissionsManager_1.WalletPermissionsManager(underlying, 'admin.com', {
283
- seekBasketRemovalPermissions: true
284
- });
285
- manager.bindCallback('onBasketAccessRequested', async (req) => {
286
- // auto-grant ephemeral
287
- await manager.grantPermission({
288
- requestID: req.requestID,
289
- ephemeral: true
290
- });
291
- });
292
- await expect(manager.relinquishOutput({
293
- output: 'someTxid.1',
294
- basket: 'user-basket'
295
- }, 'some-user.com')).resolves.not.toThrow();
296
- expect(underlying.relinquishOutput).toHaveBeenCalledTimes(1);
297
- });
298
- });
299
- /* ------------------------------------------------------
300
- * 7) CERTIFICATE USAGE (DCAP) TESTS
301
- * ------------------------------------------------------ */
302
- describe('Certificate Usage (DCAP)', () => {
303
- it('should skip certificate disclosure permission if config.seekCertificateDisclosurePermissions=false', async () => {
304
- manager = new WalletPermissionsManager_1.WalletPermissionsManager(underlying, 'admin.com', {
305
- seekCertificateDisclosurePermissions: false
306
- });
307
- // Directly call proveCertificate with no token => no prompt => immediate success
308
- await expect(manager.proveCertificate({
309
- certificate: {
310
- type: 'KYC',
311
- subject: '02abcdef...',
312
- serialNumber: '123',
313
- certifier: '02ccc...',
314
- fields: { name: 'Alice', dob: '2000-01-01' }
315
- },
316
- fieldsToReveal: ['name'],
317
- verifier: '02xyz...',
318
- privileged: false
319
- }, 'nonadmin.com')).resolves.not.toThrow();
320
- expect(underlying.proveCertificate).toHaveBeenCalledTimes(1);
321
- });
322
- it('should require permission if seekCertificateDisclosurePermissions=true, no valid token', async () => {
323
- manager = new WalletPermissionsManager_1.WalletPermissionsManager(underlying, 'admin.com', {
324
- seekCertificateDisclosurePermissions: true
325
- });
326
- // Auto-grant ephemeral for test
327
- manager.bindCallback('onCertificateAccessRequested', async (req) => {
328
- await manager.grantPermission({
329
- requestID: req.requestID,
330
- ephemeral: true
331
- });
332
- });
333
- // Because we don't have a stored token, it triggers request -> ephemeral granted -> success
334
- await manager.proveCertificate({
335
- certificate: {
336
- type: 'KYC',
337
- subject: '02abc..',
338
- serialNumber: 'xyz',
339
- certifier: '02dddd...',
340
- fields: { name: 'Bob', nationality: 'Mars' }
341
- },
342
- fieldsToReveal: ['name'],
343
- verifier: '02xxxx..',
344
- privileged: false
345
- }, 'some-user.com');
346
- expect(underlying.proveCertificate).toHaveBeenCalledTimes(1);
347
- });
348
- it('should check that requested fields are a subset of the token’s fields', async () => {
349
- manager = new WalletPermissionsManager_1.WalletPermissionsManager(underlying, 'admin.com', {
350
- seekCertificateDisclosurePermissions: true
351
- });
352
- // Suppose we find an existing token that covers fields: ['name', 'dob', 'nationality']
353
- const existingToken = {
354
- txid: 'aabbcc',
355
- outputIndex: 0,
356
- outputScript: 'scriptHex',
357
- satoshis: 1,
358
- originator: 'some-user.com',
359
- expiry: 9999999999, // not expired
360
- privileged: false,
361
- certType: 'KYC',
362
- certFields: ['name', 'dob', 'nationality'],
363
- verifier: '02eeee...'
364
- };
365
- jest
366
- .spyOn(manager, 'findCertificateToken')
367
- .mockImplementation(async (orig, priv, verif, ct, requestedFields) => {
368
- // if requestedFields includes "someMissingField", return undefined
369
- // else return the existingToken
370
- if (requestedFields.includes('someMissingField')) {
371
- return undefined; // forces a request
372
- }
373
- return existingToken; // forces immediate success
374
- });
375
- // Attempt to prove certificate revealing only 'name' -> Should pass without prompt
376
- await manager.proveCertificate({
377
- certificate: {
378
- type: 'KYC',
379
- certifier: '02eeee...',
380
- subject: '02some...',
381
- serialNumber: '',
382
- fields: { name: 'Charlie', dob: '1999-01-01', nationality: 'EU' }
383
- },
384
- fieldsToReveal: ['name'],
385
- verifier: '02eeee...',
386
- privileged: false
387
- }, 'some-user.com');
388
- expect(underlying.proveCertificate).toHaveBeenCalledTimes(1);
389
- // Attempt to reveal a field the token does NOT cover -> triggers request
390
- // Since the existing token does not cover 'someMissingField', we expect a prompt. Let’s deny it:
391
- manager.bindCallback('onCertificateAccessRequested', async (req) => {
392
- manager.denyPermission(req.requestID);
393
- });
394
- const secondAttempt = manager.proveCertificate({
395
- certificate: {
396
- type: 'KYC',
397
- certifier: '02eeee...',
398
- fields: { name: 'Charlie', dob: '1999-01-01', nationality: 'EU' }
399
- },
400
- fieldsToReveal: ['dob', 'someMissingField'],
401
- verifier: '02eeee...',
402
- privileged: false
403
- }, 'some-user.com');
404
- await expect(secondAttempt).rejects.toThrow(/Permission denied/);
405
- // Underlying proveCertificate not called for second attempt
406
- expect(underlying.proveCertificate).toHaveBeenCalledTimes(1);
407
- });
408
- it('should prompt for renewal if token is expired', async () => {
409
- manager = new WalletPermissionsManager_1.WalletPermissionsManager(underlying, 'admin.com', {
410
- seekCertificateDisclosurePermissions: true
411
- });
412
- // Mock an expired token
413
- const expiredCertToken = {
414
- txid: 'old-expired',
415
- outputIndex: 0,
416
- outputScript: 'deadbeef',
417
- satoshis: 1,
418
- originator: 'app.com',
419
- expiry: 1,
420
- privileged: false,
421
- certType: 'KYC',
422
- certFields: ['name', 'dob'],
423
- verifier: '02verifier'
424
- };
425
- jest
426
- .spyOn(manager, 'findCertificateToken')
427
- .mockResolvedValue(expiredCertToken);
428
- // Callback that grants renewal ephemeral
429
- manager.bindCallback('onCertificateAccessRequested', async (req) => {
430
- expect(req.renewal).toBe(true);
431
- await manager.grantPermission({
432
- requestID: req.requestID,
433
- ephemeral: true
434
- });
435
- });
436
- await manager.proveCertificate({
437
- certificate: {
438
- type: 'KYC',
439
- fields: { name: 'Bob', dob: '1970' },
440
- certifier: '02verifier'
441
- },
442
- fieldsToReveal: ['name'],
443
- verifier: '02verifier',
444
- privileged: false
445
- }, 'app.com');
446
- // Succeeds after ephemeral renewal
447
- expect(underlying.proveCertificate).toHaveBeenCalledTimes(1);
448
- });
449
- });
450
- /* ------------------------------------------------------
451
- * 8) SPENDING AUTHORIZATION (DSAP) TESTS
452
- * ------------------------------------------------------ */
453
- describe('Spending Authorization (DSAP)', () => {
454
- it('should skip if seekSpendingPermissions=false', async () => {
455
- manager = new WalletPermissionsManager_1.WalletPermissionsManager(underlying, 'admin.com', {
456
- seekSpendingPermissions: false
457
- });
458
- // createAction that tries to net spend 200 sats
459
- const result = await manager.createAction({
460
- description: 'Some spend transaction',
461
- outputs: [
462
- {
463
- lockingScript: 'script1',
464
- satoshis: 200,
465
- outputDescription: 'Nothing to see here'
466
- }
467
- ]
468
- }, 'user.com');
469
- // No prompt triggered
470
- const activeRequests = manager.activeRequests;
471
- expect(activeRequests.size).toBe(0);
472
- // Underlying createAction definitely called
473
- expect(underlying.createAction).toHaveBeenCalledTimes(1);
474
- expect(result.signableTransaction).toBeDefined();
475
- });
476
- it('should require spending token if netSpent > 0 and seekSpendingPermissions=true', async () => {
477
- manager = new WalletPermissionsManager_1.WalletPermissionsManager(underlying, 'admin.com', {
478
- seekSpendingPermissions: true
479
- });
480
- // We’ll also mock the signableTransaction return to help manager compute netSpent
481
- underlying.createAction.mockResolvedValueOnce({
482
- signableTransaction: {
483
- tx: [0x00], // minimal
484
- reference: 'ref1'
485
- }
486
- });
487
- // The manager tries to parse the transaction to find netSpent.
488
- // By default, netSpent = totalOutput + fee - totalExplicitInputs
489
- // We haven't provided any explicit inputs in the createAction call, so netSpent = 200 + fee
490
- // Auto-grant ephemeral for test
491
- manager.bindCallback('onSpendingAuthorizationRequested', async (req) => {
492
- await manager.grantPermission({
493
- requestID: req.requestID,
494
- ephemeral: true,
495
- amount: 1000
496
- });
497
- });
498
- await expect(manager.createAction({
499
- description: 'Spend 200 sats with no input from user',
500
- outputs: [
501
- {
502
- outputDescription: 'Nothing to see here',
503
- lockingScript: '0xabc',
504
- satoshis: 200
505
- }
506
- ]
507
- }, 'some-user.com')).resolves.not.toThrow();
508
- // underlying createAction called
509
- expect(underlying.createAction).toHaveBeenCalledTimes(1);
510
- });
511
- it('should check monthly limit usage and prompt renewal if insufficient', async () => {
512
- manager = new WalletPermissionsManager_1.WalletPermissionsManager(underlying, 'admin.com');
513
- // Suppose we find an existing DSAP token with authorizedAmount=500
514
- // manager.findSpendingToken() is used internally, so let's mock it
515
- const existingSpendingToken = {
516
- txid: 'dsap-old',
517
- outputIndex: 0,
518
- outputScript: 'scriptHex',
519
- satoshis: 1,
520
- originator: 'shopper.com',
521
- authorizedAmount: 500,
522
- expiry: 0 // indefinite
523
- };
524
- jest
525
- .spyOn(manager, 'findSpendingToken')
526
- .mockResolvedValue(existingSpendingToken);
527
- // Next, manager.querySpentSince(token) sums the user’s monthly spending from labeled actions
528
- // Let’s stub that to say they've already spent 400.
529
- jest.spyOn(manager, 'querySpentSince').mockResolvedValue(400);
530
- // Attempt spending 200 => total usage would be 600 which exceeds 500 => prompt renewal
531
- // We'll auto-deny for test
532
- manager.bindCallback('onSpendingAuthorizationRequested', req => {
533
- manager.denyPermission(req.requestID);
534
- });
535
- await expect(manager.createAction({
536
- description: 'Buy something for 200 sats',
537
- outputs: [
538
- {
539
- outputDescription: 'Nothing to see here',
540
- lockingScript: 'op_return',
541
- satoshis: 200
542
- }
543
- ]
544
- }, 'shopper.com')).rejects.toThrow(/Permission denied/);
545
- // The underlying createAction call was started but the manager calls abortAction upon denial
546
- expect(underlying.abortAction).toHaveBeenCalledTimes(1);
547
- });
548
- it('should pass if usage plus new spend is within the monthly limit', async () => {
549
- manager = new WalletPermissionsManager_1.WalletPermissionsManager(underlying, 'admin.com', {});
550
- // existing DSAP token with authorizedAmount=1000
551
- const dsapToken = {
552
- txid: 'dsap123',
553
- outputIndex: 0,
554
- outputScript: 'scriptHex',
555
- satoshis: 1,
556
- originator: 'shopper.com',
557
- authorizedAmount: 1000,
558
- expiry: 0
559
- };
560
- jest
561
- .spyOn(manager, 'findSpendingToken')
562
- .mockResolvedValue(dsapToken);
563
- // Suppose they've spent 200 so far
564
- jest.spyOn(manager, 'querySpentSince').mockResolvedValue(200);
565
- // Attempt new spending of 500 => total=700 which is <= 1000 => no prompt
566
- await manager.createAction({
567
- description: 'Spend 500 sats',
568
- outputs: [
569
- {
570
- outputDescription: 'Nothing to see here',
571
- lockingScript: '0xabc',
572
- satoshis: 500
573
- }
574
- ]
575
- }, 'shopper.com');
576
- // Success, no new permission requested
577
- const activeRequests = manager.activeRequests;
578
- expect(activeRequests.size).toBe(0);
579
- expect(underlying.createAction).toHaveBeenCalledTimes(1);
580
- });
581
- });
582
- /* ------------------------------------------------------
583
- * 9) LABEL USAGE PERMISSION TESTS
584
- * ------------------------------------------------------ */
585
- describe('Label Usage Permission', () => {
586
- it('should fail if label starts with "admin" and caller is not admin', async () => {
587
- manager = new WalletPermissionsManager_1.WalletPermissionsManager(underlying, 'admin.com');
588
- // Attempt to createAction with a label "admin secret-stuff"
589
- await expect(manager.createAction({
590
- description: 'Applying admin label?',
591
- labels: ['admin secret-stuff']
592
- }, 'nonadmin.com')).rejects.toThrow(/admin-only/);
593
- // Underlying createAction never called
594
- expect(underlying.createAction).toHaveBeenCalledTimes(0);
595
- });
596
- it('should skip label permission if seekPermissionWhenApplyingActionLabels=false', async () => {
597
- manager = new WalletPermissionsManager_1.WalletPermissionsManager(underlying, 'admin.com', {
598
- seekPermissionWhenApplyingActionLabels: false
599
- });
600
- // Non-admin applies label "my-app-label"
601
- await expect(manager.createAction({ description: 'Add label', labels: ['my-app-label'] }, 'some-app.com')).resolves.not.toThrow();
602
- // No prompt
603
- const activeRequests = manager.activeRequests;
604
- expect(activeRequests.size).toBe(0);
605
- // Called underlying
606
- expect(underlying.createAction).toHaveBeenCalledTimes(1);
607
- });
608
- it('should prompt for label usage if seekPermissionWhenApplyingActionLabels=true', async () => {
609
- manager = new WalletPermissionsManager_1.WalletPermissionsManager(underlying, 'admin.com', {
610
- seekPermissionWhenApplyingActionLabels: true
611
- });
612
- manager.bindCallback('onProtocolPermissionRequested', async (req) => {
613
- // This request will have protocolID=[1, "action label <label>"], etc.
614
- await manager.grantPermission({
615
- requestID: req.requestID,
616
- ephemeral: true
617
- });
618
- });
619
- await manager.createAction({
620
- description: 'Add label "user-label-123"',
621
- labels: ['user-label-123']
622
- }, 'nonadmin.com');
623
- // Underlying is called
624
- expect(underlying.createAction).toHaveBeenCalledTimes(1);
625
- });
626
- it('should also prompt for listing actions by label if seekPermissionWhenListingActionsByLabel=true', async () => {
627
- manager = new WalletPermissionsManager_1.WalletPermissionsManager(underlying, 'admin.com', {
628
- seekPermissionWhenListingActionsByLabel: true
629
- });
630
- manager.bindCallback('onProtocolPermissionRequested', async (req) => {
631
- // auto-grant ephemeral
632
- await manager.grantPermission({
633
- requestID: req.requestID,
634
- ephemeral: true
635
- });
636
- });
637
- await expect(manager.listActions({
638
- labels: ['search-this-label']
639
- }, 'external-app.com')).resolves.not.toThrow();
640
- expect(underlying.listActions).toHaveBeenCalledTimes(1);
641
- });
642
- });
643
- });
644
- //# sourceMappingURL=WalletPermissionsManager.checks.test.js.map