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