@bsv/btms-permission-module 1.0.0
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/INTEGRATION.md +399 -0
- package/README.md +174 -0
- package/dist/BasicTokenModule.d.ts +307 -0
- package/dist/BasicTokenModule.d.ts.map +1 -0
- package/dist/BasicTokenModule.js +1018 -0
- package/dist/TokenUsagePrompt.d.ts +32 -0
- package/dist/TokenUsagePrompt.d.ts.map +1 -0
- package/dist/TokenUsagePrompt.js +181 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/types.d.ts +67 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +19 -0
- package/package.json +37 -0
- package/src/BasicTokenModule.ts +1145 -0
- package/src/index.ts +28 -0
- package/src/types.ts +81 -0
- package/tsconfig.json +27 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import { PermissionsModule } from '@bsv/wallet-toolbox-client';
|
|
2
|
+
import { BTMS } from '@bsv/btms';
|
|
3
|
+
/**
|
|
4
|
+
* BasicTokenModule - BTMS Permission Module
|
|
5
|
+
*
|
|
6
|
+
* SECURITY MODEL:
|
|
7
|
+
* This module enforces permissions when spending BTMS tokens stored in
|
|
8
|
+
* permissioned baskets (format: "p btms <assetId>"). It prevents unauthorized
|
|
9
|
+
* token transfers by requiring explicit user approval for each transaction.
|
|
10
|
+
*
|
|
11
|
+
* THREAT MODEL:
|
|
12
|
+
* - Malicious dApp attempts to spend tokens without user knowledge
|
|
13
|
+
* - Malicious dApp gets approval for one transaction, attempts to sign different transaction
|
|
14
|
+
* - Malicious dApp attempts to bypass authorization checks
|
|
15
|
+
* - Malicious dApp attempts to steal tokens via preimage manipulation
|
|
16
|
+
*
|
|
17
|
+
* SECURITY BOUNDARIES:
|
|
18
|
+
* 1. createAction: Extracts token details and prompts user for approval
|
|
19
|
+
* 2. createSignature: Verifies session authorization + preimage integrity
|
|
20
|
+
* 3. Session authorization: Time-limited (60s) to prevent replay attacks
|
|
21
|
+
* 4. Preimage verification: Ensures signed transaction matches approved transaction
|
|
22
|
+
*
|
|
23
|
+
* AUTHORIZATION FLOW:
|
|
24
|
+
* 1. createAction → extract token info → prompt user → grant session auth
|
|
25
|
+
* 2. createSignature → verify session auth → verify preimage → allow signature
|
|
26
|
+
*
|
|
27
|
+
* ISSUANCE HANDLING:
|
|
28
|
+
* Token issuance is auto-approved (no user prompt) because:
|
|
29
|
+
* - Issuance creates new tokens (doesn't spend existing ones)
|
|
30
|
+
* - Detected by ISSUE_MARKER in locking script or btms_issue tag
|
|
31
|
+
* - Short signatures (<157 bytes) are assumed to be issuance
|
|
32
|
+
*/
|
|
33
|
+
export declare class BasicTokenModule implements PermissionsModule {
|
|
34
|
+
private readonly requestTokenAccess;
|
|
35
|
+
private readonly btms;
|
|
36
|
+
/**
|
|
37
|
+
* Session-based authorization tracking.
|
|
38
|
+
*
|
|
39
|
+
* SECURITY: Time-limited to prevent replay attacks. Each approval expires after 60s.
|
|
40
|
+
* Key: originator (dApp identifier)
|
|
41
|
+
* Value: timestamp of approval (milliseconds since epoch)
|
|
42
|
+
*/
|
|
43
|
+
private sessionAuthorizations;
|
|
44
|
+
private readonly SESSION_TIMEOUT_MS;
|
|
45
|
+
/**
|
|
46
|
+
* Authorized transaction data from createAction responses.
|
|
47
|
+
*
|
|
48
|
+
* SECURITY: Stores cryptographic commitments (hashOutputs, outpoints) to verify
|
|
49
|
+
* that createSignature is signing the exact transaction the user approved.
|
|
50
|
+
* This prevents a malicious dApp from getting approval for one transaction
|
|
51
|
+
* and then signing a different transaction.
|
|
52
|
+
*
|
|
53
|
+
* Key: originator (dApp identifier)
|
|
54
|
+
* Value: authorized transaction details (reference, hashOutputs, outpoints, timestamp)
|
|
55
|
+
*/
|
|
56
|
+
private authorizedTransactions;
|
|
57
|
+
/**
|
|
58
|
+
* Creates a new BasicTokenModule instance.
|
|
59
|
+
*
|
|
60
|
+
* @param requestTokenAccess - Callback to prompt user for token spending approval.
|
|
61
|
+
* Should return true if user approves, false if denied.
|
|
62
|
+
* SECURITY: This callback MUST be implemented securely to prevent UI spoofing.
|
|
63
|
+
* @param btms - BTMS instance for fetching token metadata via getAssetInfo
|
|
64
|
+
*/
|
|
65
|
+
constructor(requestTokenAccess: (app: string, message: string) => Promise<boolean>, btms: BTMS);
|
|
66
|
+
/**
|
|
67
|
+
* Periodic cleanup of expired session authorizations.
|
|
68
|
+
* Runs every 30 seconds to prevent memory leaks.
|
|
69
|
+
*/
|
|
70
|
+
private startSessionCleanup;
|
|
71
|
+
/**
|
|
72
|
+
* Intercepts wallet method requests for P-basket/protocol operations.
|
|
73
|
+
*
|
|
74
|
+
* SECURITY: This is the main entry point for all permission checks.
|
|
75
|
+
* All token spending operations MUST go through this method.
|
|
76
|
+
*
|
|
77
|
+
* @param req - Request object containing method, args, and originator
|
|
78
|
+
* @returns Modified args (unchanged in this implementation)
|
|
79
|
+
* @throws Error if authorization is denied
|
|
80
|
+
*/
|
|
81
|
+
onRequest(req: {
|
|
82
|
+
method: string;
|
|
83
|
+
args: object;
|
|
84
|
+
originator: string;
|
|
85
|
+
}): Promise<{
|
|
86
|
+
args: object;
|
|
87
|
+
}>;
|
|
88
|
+
/**
|
|
89
|
+
* Transforms responses from the underlying wallet.
|
|
90
|
+
* For createAction: Captures signable transaction data for security verification.
|
|
91
|
+
*/
|
|
92
|
+
onResponse(res: unknown, context: {
|
|
93
|
+
method: string;
|
|
94
|
+
originator: string;
|
|
95
|
+
}): Promise<unknown>;
|
|
96
|
+
/**
|
|
97
|
+
* Captures authorized transaction data from createAction response.
|
|
98
|
+
*
|
|
99
|
+
* SECURITY: This data is used to verify that createSignature calls are signing
|
|
100
|
+
* the exact transaction the user approved. Prevents transaction substitution attacks.
|
|
101
|
+
*
|
|
102
|
+
* Captured data:
|
|
103
|
+
* 1. reference - Transaction reference for matching
|
|
104
|
+
* 2. hashOutputs - BIP-143 hash of all outputs (prevents output modification)
|
|
105
|
+
* 3. authorizedOutpoints - Whitelist of inputs that can be signed (prevents input substitution)
|
|
106
|
+
* 4. timestamp - For expiry checking
|
|
107
|
+
*
|
|
108
|
+
* @param result - createAction response
|
|
109
|
+
* @param originator - dApp identifier
|
|
110
|
+
*/
|
|
111
|
+
private captureAuthorizedTransaction;
|
|
112
|
+
/**
|
|
113
|
+
* Computes BIP-143 hashOutputs from a transaction.
|
|
114
|
+
*
|
|
115
|
+
* SECURITY: This hash commits to all transaction outputs. Any modification
|
|
116
|
+
* to outputs (amounts, recipients, scripts) will change this hash.
|
|
117
|
+
*
|
|
118
|
+
* @param tx - Transaction to compute hashOutputs for
|
|
119
|
+
* @returns Hex-encoded double-SHA256 hash of all outputs
|
|
120
|
+
*/
|
|
121
|
+
private computeHashOutputs;
|
|
122
|
+
/**
|
|
123
|
+
* Handles createAction requests that involve BTMS P-baskets.
|
|
124
|
+
*
|
|
125
|
+
* SECURITY: This is the primary authorization checkpoint. User approval here
|
|
126
|
+
* grants session authorization for subsequent createSignature calls.
|
|
127
|
+
*
|
|
128
|
+
* ISSUANCE DETECTION: Token issuance is auto-approved because it creates new
|
|
129
|
+
* tokens rather than spending existing ones. Detected by:
|
|
130
|
+
* - ISSUE_MARKER in locking script
|
|
131
|
+
* - btms_issue tag in outputs
|
|
132
|
+
* - No inputs (issuance doesn't spend existing UTXOs)
|
|
133
|
+
*
|
|
134
|
+
* @param args - createAction arguments
|
|
135
|
+
* @param originator - dApp identifier
|
|
136
|
+
* @throws Error if user denies authorization
|
|
137
|
+
*/
|
|
138
|
+
private handleCreateAction;
|
|
139
|
+
private enrichSpendInfoWithMetadata;
|
|
140
|
+
private classifyTokenAction;
|
|
141
|
+
/**
|
|
142
|
+
* Extracts comprehensive token spend information from createAction args.
|
|
143
|
+
*
|
|
144
|
+
* Parses ALL output locking scripts to get token data, and extracts
|
|
145
|
+
* recipient info from the action description.
|
|
146
|
+
*/
|
|
147
|
+
private extractTokenSpendInfo;
|
|
148
|
+
/**
|
|
149
|
+
* Prompts user for token spend authorization with detailed information.
|
|
150
|
+
*
|
|
151
|
+
* SECURITY: The prompt data is JSON-encoded to prevent injection attacks.
|
|
152
|
+
* The UI component (TokenAccessPrompt) is responsible for safely rendering this data.
|
|
153
|
+
*
|
|
154
|
+
* @param originator - dApp identifier
|
|
155
|
+
* @param spendInfo - Parsed token spend information
|
|
156
|
+
* @throws Error if user denies authorization
|
|
157
|
+
*/
|
|
158
|
+
private promptForTokenSpend;
|
|
159
|
+
/**
|
|
160
|
+
* Prompts user for token burn authorization (burns all inputs with no token outputs).
|
|
161
|
+
*/
|
|
162
|
+
private promptForTokenBurn;
|
|
163
|
+
/**
|
|
164
|
+
* Prompts user for generic authorization when token details cannot be parsed.
|
|
165
|
+
*
|
|
166
|
+
* SECURITY: Fallback prompt when we can't extract detailed token information.
|
|
167
|
+
* Still requires explicit user approval.
|
|
168
|
+
*
|
|
169
|
+
* @param originator - dApp identifier
|
|
170
|
+
* @throws Error if user denies authorization
|
|
171
|
+
*/
|
|
172
|
+
private promptForGenericAuthorization;
|
|
173
|
+
/**
|
|
174
|
+
* Handles createSignature requests for BTMS token spending.
|
|
175
|
+
*
|
|
176
|
+
* SECURITY: This is the second checkpoint. It verifies that:
|
|
177
|
+
* 1. Session authorization exists (granted by createAction approval)
|
|
178
|
+
* 2. The preimage matches the authorized transaction (prevents transaction substitution)
|
|
179
|
+
*
|
|
180
|
+
* ISSUANCE HANDLING:
|
|
181
|
+
* Token issuance is auto-approved via multiple detection methods:
|
|
182
|
+
* - Session auth from createAction (if ISSUE_MARKER or btms_issue tag detected)
|
|
183
|
+
* - Preimage parsing (checks for ISSUE_MARKER in scriptCode)
|
|
184
|
+
* - Short signatures (<157 bytes, not full BIP-143 preimages)
|
|
185
|
+
*
|
|
186
|
+
* @param args - createSignature arguments
|
|
187
|
+
* @param originator - dApp identifier
|
|
188
|
+
* @throws Error if authorization is denied or verification fails
|
|
189
|
+
*/
|
|
190
|
+
private handleCreateSignature;
|
|
191
|
+
/**
|
|
192
|
+
* Verifies that a BIP-143 preimage matches the authorized transaction.
|
|
193
|
+
*
|
|
194
|
+
* SECURITY: This prevents a malicious dApp from:
|
|
195
|
+
* 1. Getting approval for one transaction
|
|
196
|
+
* 2. Signing a different transaction with different outputs or inputs
|
|
197
|
+
*
|
|
198
|
+
* BIP-143 preimage structure:
|
|
199
|
+
* - Version: 4 bytes
|
|
200
|
+
* - hashPrevouts: 32 bytes
|
|
201
|
+
* - hashSequence: 32 bytes
|
|
202
|
+
* - Outpoint (txid + vout): 36 bytes
|
|
203
|
+
* - scriptCode: variable (varint length + script)
|
|
204
|
+
* - Value: 8 bytes
|
|
205
|
+
* - Sequence: 4 bytes
|
|
206
|
+
* - hashOutputs: 32 bytes
|
|
207
|
+
* - Locktime: 4 bytes
|
|
208
|
+
* - Sighash type: 4 bytes
|
|
209
|
+
*
|
|
210
|
+
* Verification checks:
|
|
211
|
+
* 1. Outpoint being signed is in our authorized list
|
|
212
|
+
* 2. hashOutputs matches what we computed from createAction
|
|
213
|
+
*
|
|
214
|
+
* @param data - BIP-143 preimage bytes
|
|
215
|
+
* @param authorizedTx - Authorized transaction data from createAction
|
|
216
|
+
* @param _originator - dApp identifier (unused, for future logging)
|
|
217
|
+
* @throws Error if verification fails
|
|
218
|
+
*/
|
|
219
|
+
private verifyPreimage;
|
|
220
|
+
/**
|
|
221
|
+
* Grants session authorization for an originator.
|
|
222
|
+
*
|
|
223
|
+
* SECURITY: Session authorization is time-limited (60s) to prevent replay attacks.
|
|
224
|
+
* After expiry, user must re-approve the transaction.
|
|
225
|
+
*
|
|
226
|
+
* @param originator - dApp identifier
|
|
227
|
+
*/
|
|
228
|
+
private grantSessionAuthorization;
|
|
229
|
+
/**
|
|
230
|
+
* Checks if an originator has valid session authorization.
|
|
231
|
+
*
|
|
232
|
+
* SECURITY: Automatically expires and removes stale authorizations.
|
|
233
|
+
*
|
|
234
|
+
* @param originator - dApp identifier
|
|
235
|
+
* @returns true if valid session authorization exists
|
|
236
|
+
*/
|
|
237
|
+
private hasSessionAuthorization;
|
|
238
|
+
/**
|
|
239
|
+
* Checks if a signature request is for token issuance by examining the BIP-143 preimage.
|
|
240
|
+
*
|
|
241
|
+
* ISSUANCE DETECTION: Parses the scriptCode from the preimage and checks for ISSUE_MARKER.
|
|
242
|
+
* This is needed because during issuance, createAction doesn't have P-basket outputs
|
|
243
|
+
* (basket is added later via internalizeAction), so handleCreateAction isn't triggered.
|
|
244
|
+
*
|
|
245
|
+
* @param preimage - BIP-143 preimage data
|
|
246
|
+
* @returns true if this is a token issuance signature
|
|
247
|
+
*/
|
|
248
|
+
private isIssuanceFromPreimage;
|
|
249
|
+
/**
|
|
250
|
+
* Handles listActions requests that query BTMS token labels.
|
|
251
|
+
*
|
|
252
|
+
* Prompts the user when an app tries to list token transactions.
|
|
253
|
+
* This provides transparency about which apps are accessing token history.
|
|
254
|
+
*
|
|
255
|
+
* @param args - listActions arguments
|
|
256
|
+
* @param originator - dApp identifier
|
|
257
|
+
* @throws Error if user denies authorization
|
|
258
|
+
*/
|
|
259
|
+
private handleListActions;
|
|
260
|
+
/**
|
|
261
|
+
* Handles listOutputs requests that query BTMS token baskets.
|
|
262
|
+
*
|
|
263
|
+
* Prompts the user when an app tries to list token balances/UTXOs.
|
|
264
|
+
* This provides transparency about which apps are accessing token data.
|
|
265
|
+
*
|
|
266
|
+
* @param args - listOutputs arguments
|
|
267
|
+
* @param originator - dApp identifier
|
|
268
|
+
* @throws Error if user denies authorization
|
|
269
|
+
*/
|
|
270
|
+
private handleListOutputs;
|
|
271
|
+
/**
|
|
272
|
+
* Prompts user once per session for BTMS token access (listActions/listOutputs).
|
|
273
|
+
*/
|
|
274
|
+
private promptForBTMSAccess;
|
|
275
|
+
/**
|
|
276
|
+
* Fetches metadata for a specific asset using btms.getAssetInfo.
|
|
277
|
+
*
|
|
278
|
+
* @param assetId - The asset ID to look up
|
|
279
|
+
* @returns Token metadata or null if not found
|
|
280
|
+
*/
|
|
281
|
+
private getAssetMetadata;
|
|
282
|
+
/**
|
|
283
|
+
* Checks if the createAction is for token issuance.
|
|
284
|
+
*
|
|
285
|
+
* ISSUANCE DETECTION: Token issuance is detected by:
|
|
286
|
+
* 1. Output tags containing 'btms_type_issue'
|
|
287
|
+
* 2. Locking script contains ISSUE_MARKER in assetId field
|
|
288
|
+
*
|
|
289
|
+
* @param args - createAction arguments
|
|
290
|
+
* @returns true if this is a token issuance operation
|
|
291
|
+
*/
|
|
292
|
+
private isTokenIssuance;
|
|
293
|
+
/**
|
|
294
|
+
* Parses a BTMS token locking script to extract token information.
|
|
295
|
+
*
|
|
296
|
+
* BTMS TOKEN STRUCTURE:
|
|
297
|
+
* - Field 0: assetId (or "ISSUE" for issuance)
|
|
298
|
+
* - Field 1: amount (as string)
|
|
299
|
+
* - Field 2: metadata (optional JSON string)
|
|
300
|
+
* - Field 3: signature (present in signed PushDrop scripts)
|
|
301
|
+
*
|
|
302
|
+
* @param lockingScriptHex - Hex-encoded locking script
|
|
303
|
+
* @returns Parsed token info or null if parsing fails
|
|
304
|
+
*/
|
|
305
|
+
private parseTokenLockingScript;
|
|
306
|
+
}
|
|
307
|
+
//# sourceMappingURL=BasicTokenModule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BasicTokenModule.d.ts","sourceRoot":"","sources":["../src/BasicTokenModule.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAC9D,OAAO,EAAE,IAAI,EAAgB,MAAM,WAAW,CAAA;AAG9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,qBAAa,gBAAiB,YAAW,iBAAiB;IACxD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAoD;IACvF,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAM;IAE3B;;;;;;OAMG;IACH,OAAO,CAAC,qBAAqB,CAAiC;IAC9D,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAQ;IAE3C;;;;;;;;;;OAUG;IACH,OAAO,CAAC,sBAAsB,CAAgD;IAE9E;;;;;;;OAOG;gBAED,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,EACtE,IAAI,EAAE,IAAI;IAYZ;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAgB3B;;;;;;;;;OASG;IACG,SAAS,CAAC,GAAG,EAAE;QACnB,MAAM,EAAE,MAAM,CAAA;QACd,IAAI,EAAE,MAAM,CAAA;QACZ,UAAU,EAAE,MAAM,CAAA;KACnB,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IA4B7B;;;OAGG;IACG,UAAU,CACd,GAAG,EAAE,OAAO,EACZ,OAAO,EAAE;QACP,MAAM,EAAE,MAAM,CAAA;QACd,UAAU,EAAE,MAAM,CAAA;KACnB,GACA,OAAO,CAAC,OAAO,CAAC;IAUnB;;;;;;;;;;;;;;OAcG;YACW,4BAA4B;IAiD1C;;;;;;;;OAQG;IACH,OAAO,CAAC,kBAAkB;IAsC1B;;;;;;;;;;;;;;;OAeG;YACW,kBAAkB;YA8ClB,2BAA2B;IAezC,OAAO,CAAC,mBAAmB;IAsB3B;;;;;OAKG;IACH,OAAO,CAAC,qBAAqB;IAwJ7B;;;;;;;;;OASG;YACW,mBAAmB;IA+BjC;;OAEG;YACW,kBAAkB;IA4BhC;;;;;;;;OAQG;YACW,6BAA6B;IAe3C;;;;;;;;;;;;;;;;OAgBG;YACW,qBAAqB;IAuDnC;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,OAAO,CAAC,cAAc;IA6FtB;;;;;;;OAOG;IACH,OAAO,CAAC,yBAAyB;IAOjC;;;;;;;OAOG;IACH,OAAO,CAAC,uBAAuB;IAsB/B;;;;;;;;;OASG;IACH,OAAO,CAAC,sBAAsB;IAwD9B;;;;;;;;;OASG;YACW,iBAAiB;IAoB/B;;;;;;;;;OASG;YACW,iBAAiB;IAe/B;;OAEG;YACW,mBAAmB;IAmBjC;;;;;OAKG;YACW,gBAAgB;IAe9B;;;;;;;;;OASG;IACH,OAAO,CAAC,eAAe;IAoCvB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,uBAAuB;CAsDhC"}
|