@bopen-io/wallet-toolbox 2.15.0-bopen.2 → 2.15.1
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/CHANGELOG.md +183 -0
- package/README.md +127 -25
- package/docs/client.md +312 -154
- package/docs/monitor.md +2 -2
- package/docs/no-send-expiry.md +7 -2
- package/docs/services.md +143 -60
- package/docs/wallet.md +208 -117
- package/out/src/CWIStyleWalletManager.d.ts +36 -5
- package/out/src/CWIStyleWalletManager.d.ts.map +1 -1
- package/out/src/CWIStyleWalletManager.js +356 -60
- package/out/src/CWIStyleWalletManager.js.map +1 -1
- package/out/src/Wallet.d.ts.map +1 -1
- package/out/src/Wallet.js +8 -3
- package/out/src/Wallet.js.map +1 -1
- package/out/src/WalletAuthenticationManager.d.ts +3 -0
- package/out/src/WalletAuthenticationManager.d.ts.map +1 -1
- package/out/src/WalletAuthenticationManager.js +86 -3
- package/out/src/WalletAuthenticationManager.js.map +1 -1
- package/out/src/WalletPermissionsManager.d.ts +63 -9
- package/out/src/WalletPermissionsManager.d.ts.map +1 -1
- package/out/src/WalletPermissionsManager.js +213 -49
- package/out/src/WalletPermissionsManager.js.map +1 -1
- package/out/src/monitor/Monitor.js +1 -1
- package/out/src/monitor/Monitor.js.map +1 -1
- package/out/src/monitor/monitorValidation.d.ts +2 -1
- package/out/src/monitor/monitorValidation.d.ts.map +1 -1
- package/out/src/monitor/monitorValidation.js +2 -2
- package/out/src/monitor/monitorValidation.js.map +1 -1
- package/out/src/monitor/tasks/TaskNewHeader.d.ts.map +1 -1
- package/out/src/monitor/tasks/TaskNewHeader.js +1 -1
- package/out/src/monitor/tasks/TaskNewHeader.js.map +1 -1
- package/out/src/monitor/tasks/TaskReviewUtxos.d.ts.map +1 -1
- package/out/src/monitor/tasks/TaskReviewUtxos.js +2 -1
- package/out/src/monitor/tasks/TaskReviewUtxos.js.map +1 -1
- package/out/src/sdk/WERR_errors.d.ts +4 -0
- package/out/src/sdk/WERR_errors.d.ts.map +1 -1
- package/out/src/sdk/WERR_errors.js +4 -0
- package/out/src/sdk/WERR_errors.js.map +1 -1
- package/out/src/sdk/WalletErrorFromJson.d.ts.map +1 -1
- package/out/src/sdk/WalletErrorFromJson.js +23 -2
- package/out/src/sdk/WalletErrorFromJson.js.map +1 -1
- package/out/src/sdk/WalletStorage.interfaces.d.ts +11 -0
- package/out/src/sdk/WalletStorage.interfaces.d.ts.map +1 -1
- package/out/src/sdk/types.d.ts +12 -1
- package/out/src/sdk/types.d.ts.map +1 -1
- package/out/src/sdk/types.js +19 -2
- package/out/src/sdk/types.js.map +1 -1
- package/out/src/services/Services.d.ts.map +1 -1
- package/out/src/services/Services.js +5 -3
- package/out/src/services/Services.js.map +1 -1
- package/out/src/services/chaintracker/BHServiceClient.js +2 -2
- package/out/src/services/chaintracker/BHServiceClient.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Chaintracks.js +2 -2
- package/out/src/services/chaintracker/chaintracks/Chaintracks.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/ChaintracksServiceClient.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/ChaintracksServiceClient.js +3 -1
- package/out/src/services/chaintracker/chaintracks/ChaintracksServiceClient.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/GoChaintracksServiceClient.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/GoChaintracksServiceClient.js +3 -1
- package/out/src/services/chaintracker/chaintracks/GoChaintracksServiceClient.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorBase.js +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorBase.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorBase.js +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorBase.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorChaintracksSSE.js +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorChaintracksSSE.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainIngestorWs.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainIngestorWs.js +2 -0
- package/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainIngestorWs.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Storage/BulkStorageBase.js +2 -2
- package/out/src/services/chaintracker/chaintracks/Storage/BulkStorageBase.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageBase.js +6 -6
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageBase.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageIdb.js +2 -2
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageIdb.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageKnex.js +2 -2
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageKnex.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageNoDb.d.ts +1 -0
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageNoDb.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageNoDb.js +11 -3
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageNoDb.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.js +13 -9
- package/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/BulkFilesReader.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/BulkFilesReader.js +2 -2
- package/out/src/services/chaintracker/chaintracks/util/BulkFilesReader.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/InlineBulkFileDataValidator.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/InlineBulkFileDataValidator.js +2 -2
- package/out/src/services/chaintracker/chaintracks/util/InlineBulkFileDataValidator.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/blockHeaderUtilities.d.ts +23 -5
- package/out/src/services/chaintracker/chaintracks/util/blockHeaderUtilities.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/blockHeaderUtilities.js +58 -16
- package/out/src/services/chaintracker/chaintracks/util/blockHeaderUtilities.js.map +1 -1
- package/out/src/services/createDefaultWalletServicesOptions.d.ts +6 -3
- package/out/src/services/createDefaultWalletServicesOptions.d.ts.map +1 -1
- package/out/src/services/createDefaultWalletServicesOptions.js +18 -6
- package/out/src/services/createDefaultWalletServicesOptions.js.map +1 -1
- package/out/src/services/networkConfig.d.ts +7 -0
- package/out/src/services/networkConfig.d.ts.map +1 -1
- package/out/src/services/networkConfig.js +25 -2
- package/out/src/services/networkConfig.js.map +1 -1
- package/out/src/services/providers/SdkWhatsOnChain.d.ts +8 -2
- package/out/src/services/providers/SdkWhatsOnChain.d.ts.map +1 -1
- package/out/src/services/providers/SdkWhatsOnChain.js +17 -6
- package/out/src/services/providers/SdkWhatsOnChain.js.map +1 -1
- package/out/src/services/validateMerklePathResult.d.ts +4 -3
- package/out/src/services/validateMerklePathResult.d.ts.map +1 -1
- package/out/src/services/validateMerklePathResult.js +6 -6
- package/out/src/services/validateMerklePathResult.js.map +1 -1
- package/out/src/signer/actionBatch/ActionBatchWorkspace.d.ts.map +1 -1
- package/out/src/signer/actionBatch/ActionBatchWorkspace.js +3 -2
- package/out/src/signer/actionBatch/ActionBatchWorkspace.js.map +1 -1
- package/out/src/signer/methods/buildSignableTransaction.d.ts.map +1 -1
- package/out/src/signer/methods/buildSignableTransaction.js +7 -3
- package/out/src/signer/methods/buildSignableTransaction.js.map +1 -1
- package/out/src/signer/methods/createAction.d.ts +32 -1
- package/out/src/signer/methods/createAction.d.ts.map +1 -1
- package/out/src/signer/methods/createAction.js +56 -1
- package/out/src/signer/methods/createAction.js.map +1 -1
- package/out/src/signer/methods/internalizeAction.js +1 -1
- package/out/src/signer/methods/internalizeAction.js.map +1 -1
- package/out/src/signer/methods/signAction.js +8 -1
- package/out/src/signer/methods/signAction.js.map +1 -1
- package/out/src/storage/StorageIdb.js +4 -4
- package/out/src/storage/StorageIdb.js.map +1 -1
- package/out/src/storage/StorageKnex.d.ts +6 -2
- package/out/src/storage/StorageKnex.d.ts.map +1 -1
- package/out/src/storage/StorageKnex.js +114 -0
- package/out/src/storage/StorageKnex.js.map +1 -1
- package/out/src/storage/WalletStorageManager.d.ts.map +1 -1
- package/out/src/storage/WalletStorageManager.js +5 -0
- package/out/src/storage/WalletStorageManager.js.map +1 -1
- package/out/src/storage/methods/ListOutputsSpecOp.d.ts.map +1 -1
- package/out/src/storage/methods/ListOutputsSpecOp.js +84 -0
- package/out/src/storage/methods/ListOutputsSpecOp.js.map +1 -1
- package/out/src/storage/methods/attemptToPostReqsToNetwork.d.ts.map +1 -1
- package/out/src/storage/methods/attemptToPostReqsToNetwork.js +7 -3
- package/out/src/storage/methods/attemptToPostReqsToNetwork.js.map +1 -1
- package/out/src/storage/methods/createAction.d.ts +5 -0
- package/out/src/storage/methods/createAction.d.ts.map +1 -1
- package/out/src/storage/methods/createAction.js +13 -6
- package/out/src/storage/methods/createAction.js.map +1 -1
- package/out/src/storage/methods/generateChange.d.ts +6 -0
- package/out/src/storage/methods/generateChange.d.ts.map +1 -1
- package/out/src/storage/methods/generateChange.js +10 -3
- package/out/src/storage/methods/generateChange.js.map +1 -1
- package/out/src/storage/methods/internalizeAction.d.ts +8 -1
- package/out/src/storage/methods/internalizeAction.d.ts.map +1 -1
- package/out/src/storage/methods/internalizeAction.js +106 -42
- package/out/src/storage/methods/internalizeAction.js.map +1 -1
- package/out/src/storage/methods/listOutputsKnex.js +1 -1
- package/out/src/storage/methods/listOutputsKnex.js.map +1 -1
- package/out/src/storage/methods/noSendExpiry.d.ts.map +1 -1
- package/out/src/storage/methods/noSendExpiry.js +14 -4
- package/out/src/storage/methods/noSendExpiry.js.map +1 -1
- package/out/src/storage/remoting/StorageClientBase.d.ts.map +1 -1
- package/out/src/storage/remoting/StorageClientBase.js +15 -5
- package/out/src/storage/remoting/StorageClientBase.js.map +1 -1
- package/out/src/storage/remoting/StorageServer.d.ts.map +1 -1
- package/out/src/storage/remoting/StorageServer.js +12 -1
- package/out/src/storage/remoting/StorageServer.js.map +1 -1
- package/out/src/storage/remoting/syncChunkBinary.d.ts +10 -0
- package/out/src/storage/remoting/syncChunkBinary.d.ts.map +1 -1
- package/out/src/storage/remoting/syncChunkBinary.js +15 -11
- package/out/src/storage/remoting/syncChunkBinary.js.map +1 -1
- package/out/src/storage/schema/KnexMigrations.d.ts +1 -0
- package/out/src/storage/schema/KnexMigrations.d.ts.map +1 -1
- package/out/src/storage/schema/KnexMigrations.js +26 -4
- package/out/src/storage/schema/KnexMigrations.js.map +1 -1
- package/out/src/storage/sync/liveSyncGuards.d.ts +11 -0
- package/out/src/storage/sync/liveSyncGuards.d.ts.map +1 -0
- package/out/src/storage/sync/liveSyncGuards.js +22 -0
- package/out/src/storage/sync/liveSyncGuards.js.map +1 -0
- package/out/src/utility/actionOutputAuthorizations.d.ts +10 -0
- package/out/src/utility/actionOutputAuthorizations.d.ts.map +1 -0
- package/out/src/utility/actionOutputAuthorizations.js +25 -0
- package/out/src/utility/actionOutputAuthorizations.js.map +1 -0
- package/out/src/utility/index.all.d.ts +1 -0
- package/out/src/utility/index.all.d.ts.map +1 -1
- package/out/src/utility/index.all.js +1 -0
- package/out/src/utility/index.all.js.map +1 -1
- package/out/src/utility/index.client.d.ts +1 -0
- package/out/src/utility/index.client.d.ts.map +1 -1
- package/out/src/utility/index.client.js +1 -0
- package/out/src/utility/index.client.js.map +1 -1
- package/out/src/utility/numericTotalOutputs.d.ts +7 -0
- package/out/src/utility/numericTotalOutputs.d.ts.map +1 -0
- package/out/src/utility/numericTotalOutputs.js +15 -0
- package/out/src/utility/numericTotalOutputs.js.map +1 -0
- package/out/src/utility/utilityHelpers.d.ts.map +1 -1
- package/out/src/utility/utilityHelpers.js +2 -0
- package/out/src/utility/utilityHelpers.js.map +1 -1
- package/package.json +43 -46
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.WalletPermissionsManager = void 0;
|
|
4
|
+
exports.withBrc205Capabilities = withBrc205Capabilities;
|
|
5
|
+
exports.encryptMetadata = encryptMetadata;
|
|
6
|
+
exports.maybeDecryptMetadata = maybeDecryptMetadata;
|
|
4
7
|
const validationHelpers_1 = require("@bsv/sdk/wallet/validationHelpers");
|
|
5
8
|
const sdk_1 = require("@bsv/sdk");
|
|
6
9
|
const utils_1 = require("@bsv/sdk/primitives/utils");
|
|
7
10
|
const brc114ActionTimeLabels_1 = require("./utility/brc114ActionTimeLabels");
|
|
8
11
|
const brc177NoSendExpiry_1 = require("./utility/brc177NoSendExpiry");
|
|
9
12
|
const exactActionSpend_1 = require("./utility/exactActionSpend");
|
|
13
|
+
const actionOutputAuthorizations_1 = require("./utility/actionOutputAuthorizations");
|
|
10
14
|
const WERR_errors_1 = require("./sdk/WERR_errors");
|
|
15
|
+
const types_1 = require("./sdk/types");
|
|
11
16
|
// Imported from the leaf module directly (not generateChange.ts, which
|
|
12
17
|
// transitively imports StorageProvider.ts and the full signer/create-action
|
|
13
18
|
// module graph) to avoid an unrelated circular-import edge from this file.
|
|
@@ -115,6 +120,70 @@ function deepEqual(object1, object2) {
|
|
|
115
120
|
function isObject(object) {
|
|
116
121
|
return object != null && typeof object === 'object';
|
|
117
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* A permissions module handles request/response transformation for a specific P-protocol or P-basket scheme under BRC-98/99.
|
|
125
|
+
* Modules are registered in the config mapped by their scheme ID.
|
|
126
|
+
*
|
|
127
|
+
* Modules that handled a `createAction` returning a signable transaction also receive that action's
|
|
128
|
+
* `signAction` through `onRequest` and `onResponse`, with method `signAction` and the `action` being
|
|
129
|
+
* signed. A module may add `spends`
|
|
130
|
+
* for inputs it supplied.
|
|
131
|
+
*/
|
|
132
|
+
// BRC-205 attribute grammar: key = lower *( lower / DIGIT / "-" ); value = 1*( unreserved / pct-encoded ).
|
|
133
|
+
const BRC205_KEY = /^[a-z][a-z0-9-]*$/;
|
|
134
|
+
const BRC205_VALUE = /^(?:[A-Za-z0-9._~-]|%[0-9A-F]{2})+$/;
|
|
135
|
+
const BRC205_MAX_KEY_BYTES = 64;
|
|
136
|
+
const BRC205_MAX_VALUE_BYTES = 256;
|
|
137
|
+
const BRC205_MAX_ATTRIBUTES = 24;
|
|
138
|
+
const BRC205_MAX_BYTES = 2048;
|
|
139
|
+
/** UTF-16 code-unit order: locale-independent, so the advertised attribute order is stable everywhere. */
|
|
140
|
+
const compareCodeUnits = (a, b) => Number(a > b) - Number(a < b);
|
|
141
|
+
/**
|
|
142
|
+
* Appends the BRC-205 capability attributes of `modules` to a wallet version string:
|
|
143
|
+
* `base; key=value; key2=value2;`, one space after every nonterminal semicolon, no spaces around
|
|
144
|
+
* `=`, a trailing semicolon when attributes are present. Modules are visited by scheme id and
|
|
145
|
+
* their keys in order, so the result is deterministic. Attributes the underlying string already
|
|
146
|
+
* carries are kept and their keys are not repeated; an invalid key or value, or one that would
|
|
147
|
+
* exceed BRC-205's limits, is left out. With nothing to add the string is returned unchanged.
|
|
148
|
+
*/
|
|
149
|
+
function withBrc205Capabilities(version, modules) {
|
|
150
|
+
const separator = version.indexOf(';');
|
|
151
|
+
const base = separator === -1 ? version : version.slice(0, separator);
|
|
152
|
+
const attributes = separator === -1
|
|
153
|
+
? []
|
|
154
|
+
: version
|
|
155
|
+
.slice(separator + 1)
|
|
156
|
+
.split(';')
|
|
157
|
+
.map(attribute => attribute.trim())
|
|
158
|
+
.filter(attribute => attribute !== '');
|
|
159
|
+
const keys = new Set(attributes.map(attribute => attribute.split('=')[0]));
|
|
160
|
+
let added = 0;
|
|
161
|
+
for (const scheme of Object.keys(modules).sort(compareCodeUnits)) {
|
|
162
|
+
const capabilities = modules[scheme]?.capabilities ?? {};
|
|
163
|
+
for (const key of Object.keys(capabilities).sort(compareCodeUnits)) {
|
|
164
|
+
const value = capabilities[key];
|
|
165
|
+
if (!BRC205_KEY.test(key) ||
|
|
166
|
+
key.length > BRC205_MAX_KEY_BYTES ||
|
|
167
|
+
typeof value !== 'string' ||
|
|
168
|
+
!BRC205_VALUE.test(value) ||
|
|
169
|
+
value.length > BRC205_MAX_VALUE_BYTES ||
|
|
170
|
+
keys.has(key) ||
|
|
171
|
+
attributes.length >= BRC205_MAX_ATTRIBUTES) {
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
const attribute = `${key}=${value}`;
|
|
175
|
+
const candidate = `${base}; ${[...attributes, attribute].join('; ')};`;
|
|
176
|
+
if (candidate.length > BRC205_MAX_BYTES)
|
|
177
|
+
continue;
|
|
178
|
+
keys.add(key);
|
|
179
|
+
attributes.push(attribute);
|
|
180
|
+
added++;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (added === 0)
|
|
184
|
+
return version;
|
|
185
|
+
return `${base}; ${attributes.join('; ')};`;
|
|
186
|
+
}
|
|
118
187
|
/**
|
|
119
188
|
* A map from each permission type to a special "admin basket" name used for storing
|
|
120
189
|
* the tokens. The tokens themselves are unspent transaction outputs (UTXOs) with a
|
|
@@ -126,6 +195,42 @@ const BASKET_MAP = {
|
|
|
126
195
|
certificate: 'admin certificate-access',
|
|
127
196
|
spending: 'admin spending-authorization'
|
|
128
197
|
};
|
|
198
|
+
/**
|
|
199
|
+
* Preserves the confidentiality of transaction descriptions, input/output descriptions and
|
|
200
|
+
* custom instructions from lower storage layers. Always used with `keyID="1"` and `counterparty="self"`.
|
|
201
|
+
*/
|
|
202
|
+
const METADATA_ENCRYPTION_PROTOCOL = [2, 'admin metadata encryption'];
|
|
203
|
+
/**
|
|
204
|
+
* Encrypts metadata through `wallet` as a permissions manager with `encryptWalletMetadata` does.
|
|
205
|
+
* Permission modules use this for metadata they store through the underlying wallet directly.
|
|
206
|
+
*/
|
|
207
|
+
async function encryptMetadata(wallet, plaintext, originator) {
|
|
208
|
+
const { ciphertext } = await wallet.encrypt({
|
|
209
|
+
plaintext: (0, utils_1.toArray)(plaintext, 'utf8'),
|
|
210
|
+
protocolID: METADATA_ENCRYPTION_PROTOCOL,
|
|
211
|
+
keyID: '1'
|
|
212
|
+
}, originator);
|
|
213
|
+
return (0, utils_1.toBase64)(ciphertext);
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Decrypts metadata that a permissions manager with `encryptWalletMetadata` stored through `wallet`.
|
|
217
|
+
* A value that does not decrypt, such as metadata stored without encryption, is returned unchanged.
|
|
218
|
+
* Permission modules use this to read metadata from their own baskets through the underlying wallet.
|
|
219
|
+
*/
|
|
220
|
+
async function maybeDecryptMetadata(wallet, ciphertext, originator) {
|
|
221
|
+
try {
|
|
222
|
+
const { plaintext } = await wallet.decrypt({
|
|
223
|
+
ciphertext: (0, utils_1.toArray)(ciphertext, 'base64'),
|
|
224
|
+
protocolID: METADATA_ENCRYPTION_PROTOCOL,
|
|
225
|
+
keyID: '1'
|
|
226
|
+
}, originator);
|
|
227
|
+
return (0, utils_1.toUTF8)(plaintext);
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
// Decryption failed (e.g. wrong key, unencrypted legacy value) — return original string unchanged
|
|
231
|
+
return ciphertext;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
129
234
|
/**
|
|
130
235
|
* @class WalletPermissionsManager
|
|
131
236
|
*
|
|
@@ -196,6 +301,10 @@ class WalletPermissionsManager {
|
|
|
196
301
|
blockedActionReferences = new Set();
|
|
197
302
|
/** Pending references whose action was created with `noSend`. */
|
|
198
303
|
pendingNoSendReferences = new Set();
|
|
304
|
+
/** P-modules that handled each pending action's createAction, in request order. */
|
|
305
|
+
pendingActionModules = new Map();
|
|
306
|
+
/** The createAction arguments those P-modules returned, for their signAction hooks. */
|
|
307
|
+
pendingActionCreateArgs = new Map();
|
|
199
308
|
/**
|
|
200
309
|
* Originator binding for signed no-send actions, keyed by lowercase txid.
|
|
201
310
|
* Signing drops the pending reference, so without this a non-admin caller
|
|
@@ -284,7 +393,12 @@ class WalletPermissionsManager {
|
|
|
284
393
|
...config.permissionModules,
|
|
285
394
|
// BRC-177 is a built-in reserved BRC-111 module in every Toolbox wallet.
|
|
286
395
|
nosend: {
|
|
396
|
+
// BRC-177 L365: this revision, including batches and `never`.
|
|
397
|
+
capabilities: { 'brc177-nosend': '2' },
|
|
287
398
|
onRequest: async (req) => {
|
|
399
|
+
// Signing an action this module already authorized at createAction needs nothing further.
|
|
400
|
+
if (req.method === 'signAction')
|
|
401
|
+
return { args: req.args };
|
|
288
402
|
const labels = req.args.labels;
|
|
289
403
|
(0, brc177NoSendExpiry_1.parseBrc177NoSendExpiryLabels)(labels);
|
|
290
404
|
if (req.method !== 'createAction' && req.method !== 'listActions') {
|
|
@@ -1867,14 +1981,6 @@ class WalletPermissionsManager {
|
|
|
1867
1981
|
2,
|
|
1868
1982
|
'admin permission token encryption'
|
|
1869
1983
|
];
|
|
1870
|
-
/**
|
|
1871
|
-
* Similarly, we will use a "metadata encryption" protocol to preserve the confidentiality
|
|
1872
|
-
* of transaction descriptions and input/output descriptions from lower storage layers.
|
|
1873
|
-
*/
|
|
1874
|
-
static METADATA_ENCRYPTION_PROTOCOL = [
|
|
1875
|
-
2,
|
|
1876
|
-
'admin metadata encryption'
|
|
1877
|
-
];
|
|
1878
1984
|
/** We always use `keyID="1"` and `counterparty="self"` for these encryption ops. */
|
|
1879
1985
|
async encryptPermissionTokenField(plaintext) {
|
|
1880
1986
|
const data = typeof plaintext === 'string' ? (0, utils_1.toArray)(plaintext, 'utf8') : plaintext;
|
|
@@ -2003,12 +2109,7 @@ class WalletPermissionsManager {
|
|
|
2003
2109
|
if (!this.config.encryptWalletMetadata) {
|
|
2004
2110
|
return plaintext;
|
|
2005
2111
|
}
|
|
2006
|
-
|
|
2007
|
-
plaintext: (0, utils_1.toArray)(plaintext, 'utf8'),
|
|
2008
|
-
protocolID: WalletPermissionsManager.METADATA_ENCRYPTION_PROTOCOL,
|
|
2009
|
-
keyID: '1'
|
|
2010
|
-
}, this.adminOriginator);
|
|
2011
|
-
return (0, utils_1.toBase64)(ciphertext);
|
|
2112
|
+
return await encryptMetadata(this.underlying, plaintext, this.adminOriginator);
|
|
2012
2113
|
}
|
|
2013
2114
|
/**
|
|
2014
2115
|
* Attempts to decrypt metadata. if decryption fails, assumes the value is already plaintext and returns it.
|
|
@@ -2016,18 +2117,7 @@ class WalletPermissionsManager {
|
|
|
2016
2117
|
* @returns The decrypted metadata. If decryption fails, returns the original value instead.
|
|
2017
2118
|
*/
|
|
2018
2119
|
async maybeDecryptMetadata(ciphertext) {
|
|
2019
|
-
|
|
2020
|
-
const { plaintext } = await this.underlying.decrypt({
|
|
2021
|
-
ciphertext: (0, utils_1.toArray)(ciphertext, 'base64'),
|
|
2022
|
-
protocolID: WalletPermissionsManager.METADATA_ENCRYPTION_PROTOCOL,
|
|
2023
|
-
keyID: '1'
|
|
2024
|
-
}, this.adminOriginator);
|
|
2025
|
-
return (0, utils_1.toUTF8)(plaintext);
|
|
2026
|
-
}
|
|
2027
|
-
catch {
|
|
2028
|
-
// Decryption failed (e.g. wrong key, unencrypted legacy value) — return original string unchanged
|
|
2029
|
-
return ciphertext;
|
|
2030
|
-
}
|
|
2120
|
+
return await maybeDecryptMetadata(this.underlying, ciphertext, this.adminOriginator);
|
|
2031
2121
|
}
|
|
2032
2122
|
/** Helper to see if a token's expiry is in the past. */
|
|
2033
2123
|
isTokenExpired(expiry) {
|
|
@@ -3106,8 +3196,10 @@ class WalletPermissionsManager {
|
|
|
3106
3196
|
labels: [...(args.labels || []), `admin originator ${originator}`, `admin month ${this.getCurrentMonthYearUTC()}`]
|
|
3107
3197
|
};
|
|
3108
3198
|
let createResult;
|
|
3199
|
+
let moduleArgs;
|
|
3109
3200
|
try {
|
|
3110
|
-
|
|
3201
|
+
;
|
|
3202
|
+
({ createResult, moduleArgs } = await this.callCreateActionWithPModules(finalArgs, pModulesByScheme, originator));
|
|
3111
3203
|
}
|
|
3112
3204
|
catch (error) {
|
|
3113
3205
|
this.forgetSentNoSendActionsInError(error);
|
|
@@ -3120,7 +3212,8 @@ class WalletPermissionsManager {
|
|
|
3120
3212
|
// data. This ensures malformed BEEF is still aborted and cannot leave an
|
|
3121
3213
|
// untracked action that may later be signed under another originator.
|
|
3122
3214
|
const reference = createResult.signableTransaction.reference;
|
|
3123
|
-
|
|
3215
|
+
const pModules = Array.from(pModulesByScheme.values());
|
|
3216
|
+
this.bindPendingAction(reference, originator, vargs.isNoSend, pModules, moduleArgs);
|
|
3124
3217
|
// 7a) Parse the signable tx to determine net spend, then gate on spending
|
|
3125
3218
|
// authorization. SECURITY (GHSA-36f9-7rg5-cpf8) defense-in-depth: confirm every
|
|
3126
3219
|
// caller-requested output actually appears in the transaction we are about to
|
|
@@ -3167,30 +3260,34 @@ class WalletPermissionsManager {
|
|
|
3167
3260
|
// 9) Finalize or return the signable transaction based on whether more signatures are needed.
|
|
3168
3261
|
if (vargs.isSignAction)
|
|
3169
3262
|
return createResult;
|
|
3263
|
+
let signResult;
|
|
3264
|
+
const action = this.signingAction(reference, vargs.isNoSend);
|
|
3170
3265
|
try {
|
|
3171
|
-
const
|
|
3266
|
+
const signArgs = await this.signActionArgsThroughPModules(pModules, {
|
|
3172
3267
|
reference,
|
|
3173
3268
|
spends: {},
|
|
3174
3269
|
options: { ...args.options, returnTXIDOnly: false }
|
|
3175
|
-
}, originator);
|
|
3176
|
-
this.
|
|
3270
|
+
}, action, originator);
|
|
3271
|
+
signResult = await this.underlying.signAction(signArgs, originator);
|
|
3272
|
+
this.assertAuthorizedSignResult(reference, signArgs.spends, signResult);
|
|
3177
3273
|
this.clearPendingAction(reference);
|
|
3178
3274
|
if (vargs.isNoSend && signResult.txid != null) {
|
|
3179
3275
|
this.recordNoSendAction(signResult.txid, originator);
|
|
3180
3276
|
}
|
|
3181
3277
|
this.forgetSentNoSendActions(signResult.sendWithResults);
|
|
3182
|
-
return {
|
|
3183
|
-
...createResult,
|
|
3184
|
-
...signResult,
|
|
3185
|
-
noSendChange: noSendChangeOnSignedTransaction(createResult.noSendChange, signResult.txid),
|
|
3186
|
-
signableTransaction: undefined
|
|
3187
|
-
};
|
|
3188
3278
|
}
|
|
3189
3279
|
catch (error) {
|
|
3190
3280
|
this.forgetSentNoSendActionsInError(error);
|
|
3191
3281
|
await this.blockAndAbortAction(reference);
|
|
3192
3282
|
throw error;
|
|
3193
3283
|
}
|
|
3284
|
+
signResult = await this.signActionResultThroughPModules(pModules, signResult, action, originator);
|
|
3285
|
+
return {
|
|
3286
|
+
...createResult,
|
|
3287
|
+
...signResult,
|
|
3288
|
+
noSendChange: noSendChangeOnSignedTransaction(createResult.noSendChange, signResult.txid),
|
|
3289
|
+
signableTransaction: undefined
|
|
3290
|
+
};
|
|
3194
3291
|
}
|
|
3195
3292
|
/** Scans outputs to split P-scheme baskets from regular baskets; registers P-modules as a side effect. */
|
|
3196
3293
|
collectNonPBaskets(outputs, pModulesByScheme) {
|
|
@@ -3235,7 +3332,8 @@ class WalletPermissionsManager {
|
|
|
3235
3332
|
originalOutputDescriptions[i] = output.outputDescription;
|
|
3236
3333
|
output.outputDescription = await this.maybeEncryptMetadata(output.outputDescription);
|
|
3237
3334
|
}
|
|
3238
|
-
|
|
3335
|
+
// P-basket custom instructions are encrypted after the permission modules run.
|
|
3336
|
+
if (output.customInstructions && output.basket?.startsWith('p ') !== true) {
|
|
3239
3337
|
output.customInstructions = await this.maybeEncryptMetadata(output.customInstructions);
|
|
3240
3338
|
}
|
|
3241
3339
|
});
|
|
@@ -3248,6 +3346,15 @@ class WalletPermissionsManager {
|
|
|
3248
3346
|
]);
|
|
3249
3347
|
return { originalInputDescriptions, originalOutputDescriptions };
|
|
3250
3348
|
}
|
|
3349
|
+
/** Encrypts P-basket output custom instructions as the permission modules left them. */
|
|
3350
|
+
async encryptCreateActionModuleMetadata(args) {
|
|
3351
|
+
if (args.outputs === undefined)
|
|
3352
|
+
return args;
|
|
3353
|
+
const outputs = await Promise.all(args.outputs.map(async (output) => !output.customInstructions || output.basket?.startsWith('p ') !== true
|
|
3354
|
+
? output
|
|
3355
|
+
: { ...output, customInstructions: await this.maybeEncryptMetadata(output.customInstructions) }));
|
|
3356
|
+
return { ...args, outputs };
|
|
3357
|
+
}
|
|
3251
3358
|
/** Calls underlying createAction, chaining P-module request/response transforms when needed. */
|
|
3252
3359
|
async callCreateActionWithPModules(finalArgs, pModulesByScheme, originator) {
|
|
3253
3360
|
const pModules = Array.from(pModulesByScheme.values());
|
|
@@ -3260,7 +3367,9 @@ class WalletPermissionsManager {
|
|
|
3260
3367
|
});
|
|
3261
3368
|
transformedArgs = transformed.args;
|
|
3262
3369
|
}
|
|
3263
|
-
|
|
3370
|
+
const moduleArgs = transformedArgs;
|
|
3371
|
+
let createResult = await this.underlying.createAction(await this.encryptCreateActionModuleMetadata(moduleArgs), originator);
|
|
3372
|
+
const locallyAuthorizedResult = createResult;
|
|
3264
3373
|
const exactWalletSpend = (0, exactActionSpend_1.getExactActionSpend)(createResult);
|
|
3265
3374
|
for (let i = pModules.length - 1; i >= 0; i--) {
|
|
3266
3375
|
createResult = await pModules[i].onResponse(createResult, { method: 'createAction', originator: originator });
|
|
@@ -3271,7 +3380,8 @@ class WalletPermissionsManager {
|
|
|
3271
3380
|
if (exactWalletSpend !== undefined) {
|
|
3272
3381
|
(0, exactActionSpend_1.setExactActionSpend)(publicResult, exactWalletSpend);
|
|
3273
3382
|
}
|
|
3274
|
-
|
|
3383
|
+
(0, actionOutputAuthorizations_1.copyActionOutputAuthorizations)(locallyAuthorizedResult, publicResult);
|
|
3384
|
+
return { createResult: publicResult, moduleArgs };
|
|
3275
3385
|
}
|
|
3276
3386
|
/**
|
|
3277
3387
|
* Computes the net satoshis the originator is spending in a createAction call,
|
|
@@ -3505,19 +3615,25 @@ class WalletPermissionsManager {
|
|
|
3505
3615
|
throw new WERR_errors_1.WERR_UNAUTHORIZED('The action reference belongs to a different originator.');
|
|
3506
3616
|
}
|
|
3507
3617
|
}
|
|
3508
|
-
bindPendingAction(reference, originator, noSend) {
|
|
3618
|
+
bindPendingAction(reference, originator, noSend, pModules, createArgs) {
|
|
3509
3619
|
if (this.pendingActionOriginators.has(reference)) {
|
|
3510
3620
|
throw new WERR_errors_1.WERR_UNAUTHORIZED('The action reference is already pending.');
|
|
3511
3621
|
}
|
|
3512
3622
|
this.pendingActionOriginators.set(reference, originator ?? '');
|
|
3513
3623
|
if (noSend)
|
|
3514
3624
|
this.pendingNoSendReferences.add(reference);
|
|
3625
|
+
if (pModules.length > 0) {
|
|
3626
|
+
this.pendingActionModules.set(reference, pModules);
|
|
3627
|
+
this.pendingActionCreateArgs.set(reference, createArgs);
|
|
3628
|
+
}
|
|
3515
3629
|
}
|
|
3516
3630
|
clearPendingAction(reference) {
|
|
3517
3631
|
this.pendingActionOriginators.delete(reference);
|
|
3518
3632
|
this.pendingActionTemplates.delete(reference);
|
|
3519
3633
|
this.blockedActionReferences.delete(reference);
|
|
3520
3634
|
this.pendingNoSendReferences.delete(reference);
|
|
3635
|
+
this.pendingActionModules.delete(reference);
|
|
3636
|
+
this.pendingActionCreateArgs.delete(reference);
|
|
3521
3637
|
}
|
|
3522
3638
|
/** Lets the originator that created a signed no-send action, and only it, abort it. */
|
|
3523
3639
|
recordNoSendAction(txid, originator, reference) {
|
|
@@ -3554,29 +3670,51 @@ class WalletPermissionsManager {
|
|
|
3554
3670
|
this.forgetSentNoSendActions(error.sendWithResults);
|
|
3555
3671
|
}
|
|
3556
3672
|
}
|
|
3673
|
+
/** The action a signAction hook call signs, from the template bound at createAction. */
|
|
3674
|
+
signingAction(reference, noSend) {
|
|
3675
|
+
const transaction = this.pendingActionTemplates.get(reference);
|
|
3676
|
+
if (transaction === undefined)
|
|
3677
|
+
return undefined;
|
|
3678
|
+
const createArgs = this.pendingActionCreateArgs.get(reference);
|
|
3679
|
+
return createArgs === undefined
|
|
3680
|
+
? { reference, transaction, noSend }
|
|
3681
|
+
: { reference, transaction, noSend, createArgs };
|
|
3682
|
+
}
|
|
3683
|
+
/** Passes signAction args through the P-modules that handled the action's createAction, in request order. */
|
|
3684
|
+
async signActionArgsThroughPModules(pModules, args, action, originator) {
|
|
3685
|
+
return (await pModules.reduce(async (previous, module) => (await module.onRequest({ method: 'signAction', args: await previous, originator: originator, action })).args, Promise.resolve(args)));
|
|
3686
|
+
}
|
|
3687
|
+
/** Passes a signAction result back through the same P-modules in reverse order. */
|
|
3688
|
+
async signActionResultThroughPModules(pModules, result, action, originator) {
|
|
3689
|
+
return await pModules.reduceRight(async (previous, module) => await module.onResponse(await previous, { method: 'signAction', originator: originator, action }), Promise.resolve(result));
|
|
3690
|
+
}
|
|
3557
3691
|
async signAction(...args) {
|
|
3558
3692
|
const [requestArgs, originator] = args;
|
|
3559
3693
|
this.assertPendingActionOriginator(requestArgs.reference, originator, false);
|
|
3560
3694
|
// The wallet takes noSend from signAction's options, else from createAction's.
|
|
3561
3695
|
const noSend = (requestArgs.options?.noSend ?? this.pendingNoSendReferences.has(requestArgs.reference)) === true;
|
|
3696
|
+
const pModules = this.pendingActionModules.get(requestArgs.reference) ?? [];
|
|
3697
|
+
const action = this.signingAction(requestArgs.reference, noSend);
|
|
3698
|
+
let result;
|
|
3562
3699
|
try {
|
|
3563
|
-
const
|
|
3700
|
+
const signArgs = await this.signActionArgsThroughPModules(pModules, {
|
|
3564
3701
|
...requestArgs,
|
|
3565
3702
|
options: { ...requestArgs.options, returnTXIDOnly: false }
|
|
3566
|
-
}, originator);
|
|
3567
|
-
this.
|
|
3703
|
+
}, action, originator);
|
|
3704
|
+
result = await this.underlying.signAction(signArgs, originator);
|
|
3705
|
+
this.assertAuthorizedSignResult(requestArgs.reference, signArgs.spends, result);
|
|
3568
3706
|
this.clearPendingAction(requestArgs.reference);
|
|
3569
3707
|
if (noSend && result.txid != null) {
|
|
3570
3708
|
this.recordNoSendAction(result.txid, originator, requestArgs.reference);
|
|
3571
3709
|
}
|
|
3572
3710
|
this.forgetSentNoSendActions(result.sendWithResults);
|
|
3573
|
-
return result;
|
|
3574
3711
|
}
|
|
3575
3712
|
catch (error) {
|
|
3576
3713
|
this.forgetSentNoSendActionsInError(error);
|
|
3577
3714
|
await this.blockAndAbortAction(requestArgs.reference);
|
|
3578
3715
|
throw error;
|
|
3579
3716
|
}
|
|
3717
|
+
return await this.signActionResultThroughPModules(pModules, result, action, originator);
|
|
3580
3718
|
}
|
|
3581
3719
|
async abortAction(...args) {
|
|
3582
3720
|
const [requestArgs, originator] = args;
|
|
@@ -3689,14 +3827,29 @@ class WalletPermissionsManager {
|
|
|
3689
3827
|
});
|
|
3690
3828
|
}
|
|
3691
3829
|
}
|
|
3830
|
+
/**
|
|
3831
|
+
* Encrypts custom instructions that permission modules can still introduce.
|
|
3832
|
+
* Normal-basket instructions are already encrypted once by
|
|
3833
|
+
* authorizeInternalizeActionBaskets, before modules run. Encrypting them
|
|
3834
|
+
* again here wrapped ciphertext inside ciphertext whenever a registered
|
|
3835
|
+
* p-label or p-basket caused modules to run, and listOutputs decrypts only
|
|
3836
|
+
* one layer. Permission-module baskets are not covered by that earlier pass.
|
|
3837
|
+
*/
|
|
3692
3838
|
async encryptInternalizeActionModuleMetadata(requestArgs) {
|
|
3839
|
+
const encryptionTasks = [];
|
|
3693
3840
|
for (const outIndex in requestArgs.outputs) {
|
|
3694
3841
|
const output = requestArgs.outputs[outIndex];
|
|
3695
|
-
const
|
|
3696
|
-
|
|
3842
|
+
const remittance = output.insertionRemittance;
|
|
3843
|
+
const customInstructions = remittance?.customInstructions;
|
|
3844
|
+
if (output.protocol !== 'basket insertion' || remittance == null || !customInstructions)
|
|
3697
3845
|
continue;
|
|
3698
|
-
|
|
3846
|
+
if (!remittance.basket.startsWith('p '))
|
|
3847
|
+
continue;
|
|
3848
|
+
encryptionTasks.push(this.maybeEncryptMetadata(customInstructions).then(encrypted => {
|
|
3849
|
+
remittance.customInstructions = encrypted;
|
|
3850
|
+
}));
|
|
3699
3851
|
}
|
|
3852
|
+
await Promise.all(encryptionTasks);
|
|
3700
3853
|
}
|
|
3701
3854
|
async runInternalizeActionModules(requestArgs, originator, modules) {
|
|
3702
3855
|
let transformedArgs = requestArgs;
|
|
@@ -4090,8 +4243,16 @@ class WalletPermissionsManager {
|
|
|
4090
4243
|
async getNetwork(...args) {
|
|
4091
4244
|
return await this.underlying.getNetwork(...args);
|
|
4092
4245
|
}
|
|
4246
|
+
/**
|
|
4247
|
+
* The underlying wallet's version string with the BRC-205 capability attributes of every
|
|
4248
|
+
* configured permission module appended (see `withBrc205Capabilities`).
|
|
4249
|
+
*/
|
|
4093
4250
|
async getVersion(...args) {
|
|
4094
|
-
|
|
4251
|
+
const result = await this.underlying.getVersion(...args);
|
|
4252
|
+
return {
|
|
4253
|
+
...result,
|
|
4254
|
+
version: withBrc205Capabilities(result.version, this.config.permissionModules ?? {})
|
|
4255
|
+
};
|
|
4095
4256
|
}
|
|
4096
4257
|
/* ---------------------------------------------------------------------
|
|
4097
4258
|
* 8) INTERNAL HELPER UTILITIES
|
|
@@ -4144,6 +4305,9 @@ class WalletPermissionsManager {
|
|
|
4144
4305
|
return true;
|
|
4145
4306
|
if (basket.startsWith('admin'))
|
|
4146
4307
|
return true;
|
|
4308
|
+
// Lists P-basket outputs past their permission modules.
|
|
4309
|
+
if (basket === types_1.specOpBasketPrefixOutputs)
|
|
4310
|
+
return true;
|
|
4147
4311
|
return false;
|
|
4148
4312
|
}
|
|
4149
4313
|
/**
|