@bsv/wallet-toolbox-client 2.9.0 → 2.10.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/out/index.client.cjs +529 -331
- package/out/index.client.cjs.map +1 -1
- package/out/index.client.d.cts +82 -52
- package/out/index.client.d.cts.map +1 -1
- package/out/index.client.d.mts +82 -52
- package/out/index.client.d.mts.map +1 -1
- package/out/index.client.mjs +530 -332
- package/out/index.client.mjs.map +1 -1
- package/package.json +1 -1
package/out/index.client.cjs
CHANGED
|
@@ -4081,7 +4081,7 @@ var EntitySyncState = class EntitySyncState extends EntityBase {
|
|
|
4081
4081
|
log += formatSyncSection("OUTPUTS", c.outputs, (r) => `${r.outputId} ${r.txid}.${r.vout} ${r.transactionId} ${r.spendable ? "spendable" : ""} sats:${r.satoshis}`);
|
|
4082
4082
|
return log;
|
|
4083
4083
|
}
|
|
4084
|
-
async processSyncChunk(writer, args, chunk) {
|
|
4084
|
+
async processSyncChunk(writer, args, chunk, trx) {
|
|
4085
4085
|
const mes = [
|
|
4086
4086
|
new MergeEntity(chunk.provenTxs, EntityProvenTx.mergeFind, this.syncMap.provenTx),
|
|
4087
4087
|
new MergeEntity(chunk.outputBaskets, EntityOutputBasket.mergeFind, this.syncMap.outputBasket),
|
|
@@ -4102,16 +4102,16 @@ var EntitySyncState = class EntitySyncState extends EntityBase {
|
|
|
4102
4102
|
let done = true;
|
|
4103
4103
|
if (chunk.user != null) {
|
|
4104
4104
|
const ei = chunk.user;
|
|
4105
|
-
const { found, eo } = await EntityUser.mergeFind(writer, this.userId, ei);
|
|
4105
|
+
const { found, eo } = await EntityUser.mergeFind(writer, this.userId, ei, trx);
|
|
4106
4106
|
if (found) {
|
|
4107
|
-
if (await eo.mergeExisting(writer, args.since, ei)) {
|
|
4107
|
+
if (await eo.mergeExisting(writer, args.since, ei, void 0, trx)) {
|
|
4108
4108
|
maxUpdated_at = maxDate(maxUpdated_at, ei.updated_at);
|
|
4109
4109
|
updates++;
|
|
4110
4110
|
}
|
|
4111
4111
|
}
|
|
4112
4112
|
}
|
|
4113
4113
|
for (const me of mes) {
|
|
4114
|
-
const r = await me.merge(args.since, writer, this.userId, this.syncMap);
|
|
4114
|
+
const r = await me.merge(args.since, writer, this.userId, this.syncMap, trx);
|
|
4115
4115
|
me.esm.count += me.stateArray?.length || 0;
|
|
4116
4116
|
updates += r.updates;
|
|
4117
4117
|
inserts += r.inserts;
|
|
@@ -4122,7 +4122,7 @@ var EntitySyncState = class EntitySyncState extends EntityBase {
|
|
|
4122
4122
|
this.when = maxUpdated_at;
|
|
4123
4123
|
for (const me of mes) me.esm.count = 0;
|
|
4124
4124
|
}
|
|
4125
|
-
await this.updateStorage(writer, false);
|
|
4125
|
+
await this.updateStorage(writer, false, trx);
|
|
4126
4126
|
return {
|
|
4127
4127
|
done,
|
|
4128
4128
|
maxUpdated_at,
|
|
@@ -7845,6 +7845,23 @@ function mergePriorOptions(caVargs, saArgs) {
|
|
|
7845
7845
|
return _bsv_sdk.Validation.validateSignActionArgs(saArgs);
|
|
7846
7846
|
}
|
|
7847
7847
|
//#endregion
|
|
7848
|
+
//#region ../src/utility/canonicalizeAtomicBeef.ts
|
|
7849
|
+
/**
|
|
7850
|
+
* Restricts an AtomicBEEF envelope to the transaction named by its BRC-95
|
|
7851
|
+
* prefix and that transaction's recursive dependency closure.
|
|
7852
|
+
*
|
|
7853
|
+
* Older senders could serialize unrelated, otherwise valid BEEF branches into
|
|
7854
|
+
* an AtomicBEEF envelope. Those branches are not part of the payment proof and
|
|
7855
|
+
* must not influence internalization. Proof and transaction validation still
|
|
7856
|
+
* run against the returned closure at each wallet trust boundary.
|
|
7857
|
+
*/
|
|
7858
|
+
function canonicalizeAtomicBeef(bytes) {
|
|
7859
|
+
const received = bytes instanceof Uint8Array ? _bsv_sdk.Beef.fromBinaryView(bytes) : _bsv_sdk.Beef.fromBinary(bytes);
|
|
7860
|
+
const txid = received.atomicTxid;
|
|
7861
|
+
if (txid == null || received.findTxid(txid) == null || received.isAtomic(txid)) return received;
|
|
7862
|
+
return _bsv_sdk.Beef.fromBinary(received.toBinaryAtomic(txid));
|
|
7863
|
+
}
|
|
7864
|
+
//#endregion
|
|
7848
7865
|
//#region ../src/signer/methods/internalizeAction.ts
|
|
7849
7866
|
/**
|
|
7850
7867
|
* Internalize Action allows a wallet to take ownership of outputs in a pre-existing transaction.
|
|
@@ -7886,7 +7903,7 @@ function mergePriorOptions(caVargs, saArgs) {
|
|
|
7886
7903
|
*/
|
|
7887
7904
|
async function internalizeAction$1(wallet, auth, args) {
|
|
7888
7905
|
const vargs = _bsv_sdk.Validation.validateInternalizeActionArgs(args);
|
|
7889
|
-
const { tx } = await validateAtomicBeef();
|
|
7906
|
+
const { ab, tx, txid } = await validateAtomicBeef();
|
|
7890
7907
|
const brc29ProtocolID = [2, "3241645161d8"];
|
|
7891
7908
|
for (const o of vargs.outputs) {
|
|
7892
7909
|
if (o.outputIndex < 0 || o.outputIndex >= tx.outputs.length) throw new WERR_INVALID_PARAMETER("outputIndex", `a valid output index in range 0 to ${tx.outputs.length - 1}`);
|
|
@@ -7900,7 +7917,10 @@ async function internalizeAction$1(wallet, auth, args) {
|
|
|
7900
7917
|
default: throw new WERR_INTERNAL(`unexpected protocol ${o.protocol}`);
|
|
7901
7918
|
}
|
|
7902
7919
|
}
|
|
7903
|
-
return await wallet.storage.internalizeAction(
|
|
7920
|
+
return await wallet.storage.internalizeAction({
|
|
7921
|
+
...args,
|
|
7922
|
+
tx: ab.toBinaryAtomic(txid)
|
|
7923
|
+
});
|
|
7904
7924
|
function setupWalletPaymentForOutput(o, _dargs) {
|
|
7905
7925
|
const p = o.paymentRemittance;
|
|
7906
7926
|
const output = tx.outputs[o.outputIndex];
|
|
@@ -7923,7 +7943,7 @@ async function internalizeAction$1(wallet, auth, args) {
|
|
|
7923
7943
|
* 2. That the proofs are for the same block as recorded in the wallet's configured storage in the event of a reorg.
|
|
7924
7944
|
*/
|
|
7925
7945
|
async function validateAtomicBeef() {
|
|
7926
|
-
const ab =
|
|
7946
|
+
const ab = canonicalizeAtomicBeef(vargs.tx);
|
|
7927
7947
|
if (!await ab.verify(await wallet.getServices().getChainTracker(), false) || !ab.atomicTxid) {
|
|
7928
7948
|
console.log(`internalizeAction beef is invalid: ${ab.toLogString()}`);
|
|
7929
7949
|
throw new WERR_INVALID_PARAMETER("tx", "valid AtomicBEEF");
|
|
@@ -8254,28 +8274,70 @@ function verifyActionBatchManifestDigest(manifest) {
|
|
|
8254
8274
|
//#endregion
|
|
8255
8275
|
//#region ../src/utility/beefForTxids.ts
|
|
8256
8276
|
/**
|
|
8257
|
-
* Return
|
|
8277
|
+
* Return a minimal BEEF when the source contains data outside the requested
|
|
8278
|
+
* transaction dependency closure. Return undefined when no pruning is needed.
|
|
8279
|
+
*
|
|
8280
|
+
* This form lets forwarding clients retain the caller's original bytes in the
|
|
8281
|
+
* common no-op case instead of rebuilding and reserializing an equivalent BEEF.
|
|
8282
|
+
*/
|
|
8283
|
+
function pruneBeefForTxids(source, txids) {
|
|
8284
|
+
const selection = selectTransactions(source, txids);
|
|
8285
|
+
if (selection.transactions.size === source.txs.length && selection.bumpIndexes.size === source.bumps.length) return;
|
|
8286
|
+
return copySelection(source, selection);
|
|
8287
|
+
}
|
|
8288
|
+
/**
|
|
8289
|
+
* Return an independent minimal BEEF needed to prove the requested transactions.
|
|
8258
8290
|
*
|
|
8259
|
-
*
|
|
8260
|
-
*
|
|
8291
|
+
* Transactions remain in source order and are sorted by Beef when serialized.
|
|
8292
|
+
* The source is indexed and walked once, using an explicit stack so a hostile
|
|
8293
|
+
* dependency depth cannot exhaust the JavaScript call stack.
|
|
8261
8294
|
*/
|
|
8262
8295
|
function beefForTxids(source, txids) {
|
|
8263
|
-
|
|
8296
|
+
return copySelection(source, selectTransactions(source, txids));
|
|
8297
|
+
}
|
|
8298
|
+
function selectTransactions(source, txids) {
|
|
8299
|
+
const byTxid = /* @__PURE__ */ new Map();
|
|
8300
|
+
for (const tx of source.txs) byTxid.set(tx.txid, tx);
|
|
8301
|
+
const transactions = /* @__PURE__ */ new Set();
|
|
8302
|
+
const bumpIndexes = /* @__PURE__ */ new Set();
|
|
8264
8303
|
const visited = /* @__PURE__ */ new Set();
|
|
8265
|
-
const
|
|
8266
|
-
|
|
8304
|
+
const stack = [...txids];
|
|
8305
|
+
while (stack.length > 0) {
|
|
8306
|
+
const txid = stack.pop();
|
|
8307
|
+
if (txid == null || visited.has(txid)) continue;
|
|
8267
8308
|
visited.add(txid);
|
|
8268
|
-
const
|
|
8269
|
-
if (
|
|
8270
|
-
|
|
8271
|
-
|
|
8272
|
-
|
|
8273
|
-
|
|
8274
|
-
|
|
8309
|
+
const tx = byTxid.get(txid);
|
|
8310
|
+
if (tx == null) continue;
|
|
8311
|
+
transactions.add(tx);
|
|
8312
|
+
const bumpIndex = tx.bumpIndex;
|
|
8313
|
+
if (bumpIndex != null && Number.isSafeInteger(bumpIndex) && bumpIndex >= 0 && bumpIndex < source.bumps.length) bumpIndexes.add(bumpIndex);
|
|
8314
|
+
for (const inputTxid of tx.inputTxids) if (!visited.has(inputTxid)) stack.push(inputTxid);
|
|
8315
|
+
}
|
|
8316
|
+
return {
|
|
8317
|
+
transactions,
|
|
8318
|
+
bumpIndexes
|
|
8275
8319
|
};
|
|
8276
|
-
|
|
8320
|
+
}
|
|
8321
|
+
function copySelection(source, selection) {
|
|
8322
|
+
const beef = new _bsv_sdk.Beef(source.version);
|
|
8323
|
+
const bumpIndexMap = /* @__PURE__ */ new Map();
|
|
8324
|
+
for (let index = 0; index < source.bumps.length; index++) {
|
|
8325
|
+
if (!selection.bumpIndexes.has(index)) continue;
|
|
8326
|
+
bumpIndexMap.set(index, beef.bumps.length);
|
|
8327
|
+
beef.bumps.push(cloneMerklePath(source.bumps[index]));
|
|
8328
|
+
}
|
|
8329
|
+
for (const sourceTx of source.txs) {
|
|
8330
|
+
if (!selection.transactions.has(sourceTx)) continue;
|
|
8331
|
+
const bumpIndex = sourceTx.bumpIndex == null ? void 0 : bumpIndexMap.get(sourceTx.bumpIndex);
|
|
8332
|
+
const rawTx = sourceTx.rawTxUint8Array;
|
|
8333
|
+
const copy = rawTx == null ? _bsv_sdk.BeefTx.fromTxid(sourceTx.txid, bumpIndex) : new _bsv_sdk.BeefTx(Uint8Array.from(rawTx), bumpIndex, Array.from(sourceTx.inputTxids));
|
|
8334
|
+
beef.txs.push(copy);
|
|
8335
|
+
}
|
|
8277
8336
|
return beef;
|
|
8278
8337
|
}
|
|
8338
|
+
function cloneMerklePath(source) {
|
|
8339
|
+
return new _bsv_sdk.MerklePath(source.blockHeight, source.path.map((level) => level.map((leaf) => ({ ...leaf }))), false, false);
|
|
8340
|
+
}
|
|
8279
8341
|
//#endregion
|
|
8280
8342
|
//#region ../src/storage/methods/offsetKey.ts
|
|
8281
8343
|
function keyOffsetToHashedSecret(pub, keyOffset) {
|
|
@@ -10973,7 +11035,7 @@ function validateRequiredOutputs(storage, userId, vargs) {
|
|
|
10973
11035
|
* @returns {xinputs} extended validated required inputs.
|
|
10974
11036
|
*/
|
|
10975
11037
|
async function validateRequiredInputs(storage, userId, vargs) {
|
|
10976
|
-
|
|
11038
|
+
let beef = new _bsv_sdk.Beef();
|
|
10977
11039
|
if (vargs.inputs.length === 0) return {
|
|
10978
11040
|
storageBeef: beef,
|
|
10979
11041
|
beef,
|
|
@@ -10999,6 +11061,7 @@ async function validateRequiredInputs(storage, userId, vargs) {
|
|
|
10999
11061
|
inputsByTxid[input.outpoint.txid] ||= [];
|
|
11000
11062
|
inputsByTxid[input.outpoint.txid].push(input);
|
|
11001
11063
|
}
|
|
11064
|
+
beef = beefForTxids(beef, Object.keys(inputsByTxid));
|
|
11002
11065
|
const localKnownInputTxids = {};
|
|
11003
11066
|
for (const [txid, txInputs] of Object.entries(inputsByTxid)) localKnownInputTxids[txid] = txInputs.every((input) => {
|
|
11004
11067
|
const output = preloadedOutputsByOutpoint[`${input.outpoint.txid}.${input.outpoint.vout}`];
|
|
@@ -12413,7 +12476,7 @@ var InternalizeActionContext = class {
|
|
|
12413
12476
|
* @returns
|
|
12414
12477
|
*/
|
|
12415
12478
|
async validateAtomicBeef(atomicBeef) {
|
|
12416
|
-
const ab =
|
|
12479
|
+
const ab = canonicalizeAtomicBeef(atomicBeef);
|
|
12417
12480
|
if (!await ab.verify(await this.storage.getServices().getChainTracker(), false) || !ab.atomicTxid) throw new WERR_INVALID_PARAMETER("tx", "valid AtomicBEEF");
|
|
12418
12481
|
const txid = ab.atomicTxid;
|
|
12419
12482
|
const btx = ab.findTxid(txid);
|
|
@@ -15260,11 +15323,19 @@ var StorageProvider = class StorageProvider extends StorageReaderWriter {
|
|
|
15260
15323
|
return await this.updateOutput(output.outputId, { basketId: void 0 });
|
|
15261
15324
|
}
|
|
15262
15325
|
async processSyncChunk(args, chunk) {
|
|
15263
|
-
|
|
15264
|
-
|
|
15265
|
-
|
|
15266
|
-
|
|
15267
|
-
|
|
15326
|
+
return await this.transaction(async (trx) => {
|
|
15327
|
+
const user = verifyTruthy(verifyOneOrNone(await this.findUsers({
|
|
15328
|
+
partial: { identityKey: args.identityKey },
|
|
15329
|
+
trx
|
|
15330
|
+
})));
|
|
15331
|
+
return await new EntitySyncState(verifyOne(await this.findSyncStates({
|
|
15332
|
+
partial: {
|
|
15333
|
+
storageIdentityKey: args.fromStorageIdentityKey,
|
|
15334
|
+
userId: user.userId
|
|
15335
|
+
},
|
|
15336
|
+
trx
|
|
15337
|
+
}))).processSyncChunk(this, args, chunk, trx);
|
|
15338
|
+
});
|
|
15268
15339
|
}
|
|
15269
15340
|
/**
|
|
15270
15341
|
* Handles storage changes when a valid MerklePath and mined block header are found for a ProvenTxReq txid.
|
|
@@ -17329,8 +17400,10 @@ var StorageIdb = class extends StorageProvider {
|
|
|
17329
17400
|
await tx.done;
|
|
17330
17401
|
return r;
|
|
17331
17402
|
} catch (err) {
|
|
17332
|
-
|
|
17333
|
-
|
|
17403
|
+
try {
|
|
17404
|
+
tx.abort();
|
|
17405
|
+
await tx.done;
|
|
17406
|
+
} catch {}
|
|
17334
17407
|
throw err;
|
|
17335
17408
|
}
|
|
17336
17409
|
}
|
|
@@ -18297,6 +18370,25 @@ var StorageClientBase = class {
|
|
|
18297
18370
|
* @returns `StorageCreateActionResults` supporting additional wallet processing to yield `createAction` results.
|
|
18298
18371
|
*/
|
|
18299
18372
|
async createAction(auth, args) {
|
|
18373
|
+
if (args.inputBEEF != null) if (args.inputs.length === 0) args = {
|
|
18374
|
+
...args,
|
|
18375
|
+
inputBEEF: void 0
|
|
18376
|
+
};
|
|
18377
|
+
else {
|
|
18378
|
+
let source;
|
|
18379
|
+
try {
|
|
18380
|
+
source = _bsv_sdk.Beef.fromBinary(args.inputBEEF);
|
|
18381
|
+
} catch {
|
|
18382
|
+
source = void 0;
|
|
18383
|
+
}
|
|
18384
|
+
if (source != null) {
|
|
18385
|
+
const pruned = pruneBeefForTxids(source, args.inputs.map((input) => input.outpoint.txid));
|
|
18386
|
+
if (pruned != null) args = {
|
|
18387
|
+
...args,
|
|
18388
|
+
inputBEEF: pruned.toBinary()
|
|
18389
|
+
};
|
|
18390
|
+
}
|
|
18391
|
+
}
|
|
18300
18392
|
return await this.rpcCall("createAction", [auth, args]);
|
|
18301
18393
|
}
|
|
18302
18394
|
/**
|
|
@@ -30967,6 +31059,7 @@ var SetupClient = class SetupClient {
|
|
|
30967
31059
|
};
|
|
30968
31060
|
//#endregion
|
|
30969
31061
|
//#region ../src/CWIStyleWalletManager.ts
|
|
31062
|
+
const CWI_COMPONENT = "wallet-toolbox.cwi-manager";
|
|
30970
31063
|
/**
|
|
30971
31064
|
* Number of rounds used in PBKDF2 for deriving password keys.
|
|
30972
31065
|
*/
|
|
@@ -31199,11 +31292,11 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31199
31292
|
* @param hash The 32-byte SHA-256 hash of the presentation key.
|
|
31200
31293
|
* @returns A UMPToken object (including currentOutpoint) if found, otherwise undefined.
|
|
31201
31294
|
*/
|
|
31202
|
-
async findByPresentationKeyHash(hash) {
|
|
31203
|
-
return
|
|
31295
|
+
async findByPresentationKeyHash(hash, options) {
|
|
31296
|
+
return this.findToken({
|
|
31204
31297
|
service: "ls_users",
|
|
31205
31298
|
query: { presentationHash: _bsv_sdk.Utils.toHex(hash) }
|
|
31206
|
-
}, "presentation");
|
|
31299
|
+
}, "presentation", options);
|
|
31207
31300
|
}
|
|
31208
31301
|
/**
|
|
31209
31302
|
* Finds a UMP token on-chain by the given recovery key hash, if it exists.
|
|
@@ -31212,13 +31305,13 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31212
31305
|
* @param hash The 32-byte SHA-256 hash of the recovery key.
|
|
31213
31306
|
* @returns A UMPToken object (including currentOutpoint) if found, otherwise undefined.
|
|
31214
31307
|
*/
|
|
31215
|
-
async findByRecoveryKeyHash(hash) {
|
|
31216
|
-
return
|
|
31308
|
+
async findByRecoveryKeyHash(hash, options) {
|
|
31309
|
+
return this.findToken({
|
|
31217
31310
|
service: "ls_users",
|
|
31218
31311
|
query: { recoveryHash: _bsv_sdk.Utils.toHex(hash) }
|
|
31219
|
-
}, "recovery");
|
|
31312
|
+
}, "recovery", options);
|
|
31220
31313
|
}
|
|
31221
|
-
async findToken(question, lookupKind) {
|
|
31314
|
+
async findToken(question, lookupKind, options) {
|
|
31222
31315
|
const correlationId = this.telemetry.enabled === true ? this.telemetry.createCorrelationId() : void 0;
|
|
31223
31316
|
const startedAt = Date.now();
|
|
31224
31317
|
this.telemetry.capture({
|
|
@@ -31235,34 +31328,39 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31235
31328
|
correlationId
|
|
31236
31329
|
});
|
|
31237
31330
|
} catch (error) {
|
|
31238
|
-
const diagnostics = this.
|
|
31239
|
-
this.
|
|
31331
|
+
const diagnostics = this.emptyStats(correlationId);
|
|
31332
|
+
this.lookupFailed(lookupKind, "lookup-unavailable", diagnostics, startedAt, error);
|
|
31240
31333
|
throw new UMPTokenLookupError("lookup-unavailable", diagnostics, { cause: error });
|
|
31241
31334
|
}
|
|
31242
|
-
const diagnostics = this.
|
|
31335
|
+
const diagnostics = this.diagnosticsFor(resolution);
|
|
31243
31336
|
const tokens = this.parseLookupAnswers(resolution.answer);
|
|
31244
31337
|
const expectedHash = question.query[lookupKind === "presentation" ? "presentationHash" : "recoveryHash"].toLowerCase();
|
|
31245
31338
|
const matchingTokens = tokens.filter((token) => _bsv_sdk.Utils.toHex(lookupKind === "presentation" ? token.presentationHash : token.recoveryHash).toLowerCase() === expectedHash);
|
|
31246
31339
|
if (matchingTokens.length > 1) {
|
|
31247
31340
|
const newest = this.resolveNewestToken(matchingTokens, resolution.answer.outputs);
|
|
31248
31341
|
if (newest != null) {
|
|
31249
|
-
this.
|
|
31342
|
+
this.lookupDone(lookupKind, "found", diagnostics, startedAt, { supersededTokens: matchingTokens.length - 1 });
|
|
31250
31343
|
return newest;
|
|
31251
31344
|
}
|
|
31345
|
+
const pinned = options?.pinnedOutpoint ? matchingTokens.find((token) => token.currentOutpoint === options.pinnedOutpoint) : void 0;
|
|
31346
|
+
if (pinned != null) {
|
|
31347
|
+
this.lookupDone(lookupKind, "found", diagnostics, startedAt);
|
|
31348
|
+
return pinned;
|
|
31349
|
+
}
|
|
31252
31350
|
const reason = "token-ambiguous";
|
|
31253
|
-
this.
|
|
31351
|
+
this.lookupFailed(lookupKind, reason, diagnostics, startedAt);
|
|
31254
31352
|
throw new UMPTokenLookupError(reason, diagnostics);
|
|
31255
31353
|
}
|
|
31256
31354
|
if (matchingTokens.length === 1) {
|
|
31257
|
-
this.
|
|
31355
|
+
this.lookupDone(lookupKind, "found", diagnostics, startedAt);
|
|
31258
31356
|
return matchingTokens[0];
|
|
31259
31357
|
}
|
|
31260
31358
|
if (resolution.progress.emptyHosts > 0) {
|
|
31261
|
-
this.
|
|
31359
|
+
this.lookupDone(lookupKind, "not-found", diagnostics, startedAt);
|
|
31262
31360
|
return;
|
|
31263
31361
|
}
|
|
31264
31362
|
const reason = resolution.answer.outputs.length > 0 ? "token-malformed" : "lookup-incomplete";
|
|
31265
|
-
this.
|
|
31363
|
+
this.lookupFailed(lookupKind, reason, diagnostics, startedAt);
|
|
31266
31364
|
throw new UMPTokenLookupError(reason, diagnostics);
|
|
31267
31365
|
}
|
|
31268
31366
|
/**
|
|
@@ -31293,7 +31391,7 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31293
31391
|
spent: /* @__PURE__ */ new Set()
|
|
31294
31392
|
};
|
|
31295
31393
|
evidence.txs.push(tx);
|
|
31296
|
-
this.
|
|
31394
|
+
this.collectSpends(tx, evidence.spent, /* @__PURE__ */ new Set());
|
|
31297
31395
|
evidenceByCandidate.set(outpoint, evidence);
|
|
31298
31396
|
} catch {}
|
|
31299
31397
|
if (evidenceByCandidate.size !== candidates.size) return void 0;
|
|
@@ -31302,7 +31400,7 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31302
31400
|
const provenContinuations = survivors.filter((outpoint) => {
|
|
31303
31401
|
const evidence = evidenceByCandidate.get(outpoint);
|
|
31304
31402
|
const token = candidates.get(outpoint);
|
|
31305
|
-
return evidence != null && token != null && evidence.txs.some((tx) => this.
|
|
31403
|
+
return evidence != null && token != null && evidence.txs.some((tx) => this.consumesIdentity(tx, token));
|
|
31306
31404
|
});
|
|
31307
31405
|
if (provenContinuations.length !== 1) return void 0;
|
|
31308
31406
|
return candidates.get(provenContinuations[0]);
|
|
@@ -31313,7 +31411,7 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31313
31411
|
* hash — on-chain proof that the candidate is an update of a same-identity
|
|
31314
31412
|
* predecessor rather than an independently minted token.
|
|
31315
31413
|
*/
|
|
31316
|
-
|
|
31414
|
+
consumesIdentity(tx, token) {
|
|
31317
31415
|
const presentationHash = _bsv_sdk.Utils.toHex(token.presentationHash);
|
|
31318
31416
|
const recoveryHash = _bsv_sdk.Utils.toHex(token.recoveryHash);
|
|
31319
31417
|
for (const input of tx.inputs) {
|
|
@@ -31339,7 +31437,7 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31339
31437
|
* renditions are absent from the lookup answer. Iterative so arbitrarily
|
|
31340
31438
|
* long update chains cannot exhaust the call stack.
|
|
31341
31439
|
*/
|
|
31342
|
-
|
|
31440
|
+
collectSpends(tx, spent, visited) {
|
|
31343
31441
|
const pending = [tx];
|
|
31344
31442
|
while (pending.length > 0) {
|
|
31345
31443
|
const current = pending.pop();
|
|
@@ -31354,7 +31452,7 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31354
31452
|
}
|
|
31355
31453
|
}
|
|
31356
31454
|
}
|
|
31357
|
-
|
|
31455
|
+
emptyStats(correlationId) {
|
|
31358
31456
|
return {
|
|
31359
31457
|
hostCount: 0,
|
|
31360
31458
|
completedHosts: 0,
|
|
@@ -31367,7 +31465,7 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31367
31465
|
...correlationId !== void 0 ? { correlationId } : {}
|
|
31368
31466
|
};
|
|
31369
31467
|
}
|
|
31370
|
-
|
|
31468
|
+
diagnosticsFor(resolution) {
|
|
31371
31469
|
const progress = resolution.progress;
|
|
31372
31470
|
return {
|
|
31373
31471
|
hostCount: progress.hostCount,
|
|
@@ -31381,7 +31479,7 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31381
31479
|
...progress.correlationId !== void 0 ? { correlationId: progress.correlationId } : {}
|
|
31382
31480
|
};
|
|
31383
31481
|
}
|
|
31384
|
-
|
|
31482
|
+
lookupAttrs(diagnostics) {
|
|
31385
31483
|
return {
|
|
31386
31484
|
hostCount: diagnostics.hostCount,
|
|
31387
31485
|
completedHosts: diagnostics.completedHosts,
|
|
@@ -31393,7 +31491,7 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31393
31491
|
outputCount: diagnostics.outputCount
|
|
31394
31492
|
};
|
|
31395
31493
|
}
|
|
31396
|
-
|
|
31494
|
+
lookupDone(lookupKind, result, diagnostics, startedAt, extraAttributes = {}) {
|
|
31397
31495
|
this.telemetry.capture({
|
|
31398
31496
|
name: "wallet-toolbox.ump.lookup.completed",
|
|
31399
31497
|
component: "wallet-toolbox.ump",
|
|
@@ -31403,12 +31501,12 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31403
31501
|
lookupKind,
|
|
31404
31502
|
result,
|
|
31405
31503
|
durationMs: Date.now() - startedAt,
|
|
31406
|
-
...this.
|
|
31504
|
+
...this.lookupAttrs(diagnostics),
|
|
31407
31505
|
...extraAttributes
|
|
31408
31506
|
}
|
|
31409
31507
|
});
|
|
31410
31508
|
}
|
|
31411
|
-
|
|
31509
|
+
lookupFailed(lookupKind, reason, diagnostics, startedAt, error) {
|
|
31412
31510
|
this.telemetry.capture({
|
|
31413
31511
|
name: "wallet-toolbox.ump.lookup.indeterminate",
|
|
31414
31512
|
component: "wallet-toolbox.ump",
|
|
@@ -31418,7 +31516,7 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31418
31516
|
lookupKind,
|
|
31419
31517
|
reason,
|
|
31420
31518
|
durationMs: Date.now() - startedAt,
|
|
31421
|
-
...this.
|
|
31519
|
+
...this.lookupAttrs(diagnostics)
|
|
31422
31520
|
},
|
|
31423
31521
|
error
|
|
31424
31522
|
});
|
|
@@ -31436,27 +31534,27 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31436
31534
|
* @returns The outpoint of the newly created UMP token (e.g. "abcd1234...ef.0").
|
|
31437
31535
|
*/
|
|
31438
31536
|
async buildAndSend(wallet, adminOriginator, token, oldTokenToConsume) {
|
|
31439
|
-
const fields = this.
|
|
31537
|
+
const fields = this.tokenFields(token);
|
|
31440
31538
|
const tokenOutput = [{
|
|
31441
31539
|
lockingScript: (await new _bsv_sdk.PushDrop(wallet, adminOriginator).lock(fields, [2, "admin user management token"], "1", "self", true, true)).toHex(),
|
|
31442
31540
|
satoshis: 1,
|
|
31443
31541
|
outputDescription: "New UMP token output"
|
|
31444
31542
|
}];
|
|
31445
|
-
const { resolvedOldToken, inputToken } = await this.
|
|
31543
|
+
const { resolvedOldToken, inputToken } = await this.resolveOldInput(oldTokenToConsume);
|
|
31446
31544
|
const inputs = resolvedOldToken?.currentOutpoint ? [{
|
|
31447
31545
|
outpoint: resolvedOldToken.currentOutpoint,
|
|
31448
31546
|
unlockingScriptLength: 73,
|
|
31449
31547
|
inputDescription: "Consume old UMP token"
|
|
31450
31548
|
}] : [];
|
|
31451
|
-
const createResult = await this.
|
|
31452
|
-
if (!createResult.signableTransaction) return
|
|
31549
|
+
const createResult = await this.createAction(wallet, adminOriginator, inputs, tokenOutput, inputToken, resolvedOldToken);
|
|
31550
|
+
if (!createResult.signableTransaction) return this.broadcastFinal(createResult);
|
|
31453
31551
|
const reference = createResult.signableTransaction.reference;
|
|
31454
31552
|
const partialTx = _bsv_sdk.Transaction.fromBEEF(createResult.signableTransaction.tx);
|
|
31455
|
-
if (resolvedOldToken?.currentOutpoint) return
|
|
31456
|
-
return
|
|
31553
|
+
if (resolvedOldToken?.currentOutpoint) return this.renewToken(wallet, adminOriginator, reference, partialTx);
|
|
31554
|
+
return this.broadcastNew(wallet, adminOriginator, reference);
|
|
31457
31555
|
}
|
|
31458
31556
|
/** Assembles the ordered number[][] fields array from a UMPToken. */
|
|
31459
|
-
|
|
31557
|
+
tokenFields(token) {
|
|
31460
31558
|
const fields = [];
|
|
31461
31559
|
fields[0] = token.passwordSalt;
|
|
31462
31560
|
fields[1] = token.passwordPresentationPrimary;
|
|
@@ -31483,20 +31581,20 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31483
31581
|
return fields;
|
|
31484
31582
|
}
|
|
31485
31583
|
/** Looks up the old token on the overlay; returns undefined resolved token if not found. */
|
|
31486
|
-
async
|
|
31584
|
+
async resolveOldInput(oldTokenToConsume) {
|
|
31487
31585
|
if (!oldTokenToConsume?.currentOutpoint) return {
|
|
31488
31586
|
resolvedOldToken: void 0,
|
|
31489
31587
|
inputToken: void 0
|
|
31490
31588
|
};
|
|
31491
31589
|
const inputToken = await this.findByOutpoint(oldTokenToConsume.currentOutpoint);
|
|
31492
|
-
if (inputToken == null) throw new Error("
|
|
31590
|
+
if (inputToken == null) throw new Error("Previous UMP token unavailable; update refused.");
|
|
31493
31591
|
return {
|
|
31494
31592
|
resolvedOldToken: oldTokenToConsume,
|
|
31495
31593
|
inputToken
|
|
31496
31594
|
};
|
|
31497
31595
|
}
|
|
31498
31596
|
/** Creates the UMP action without dropping a required old-token input on failure. */
|
|
31499
|
-
async
|
|
31597
|
+
async createAction(wallet, adminOriginator, inputs, outputs, inputToken, resolvedOldToken) {
|
|
31500
31598
|
try {
|
|
31501
31599
|
return await wallet.createAction({
|
|
31502
31600
|
description: resolvedOldToken == null ? "Create new UMP token" : "Renew UMP token (consume old, create new)",
|
|
@@ -31523,43 +31621,43 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31523
31621
|
}
|
|
31524
31622
|
}
|
|
31525
31623
|
/** Handles a fully-finalized (no signable tx) createAction result — broadcasts and returns outpoint. */
|
|
31526
|
-
async
|
|
31624
|
+
async broadcastFinal(createResult) {
|
|
31527
31625
|
const finalTxid = createResult.txid || (createResult.tx != null ? _bsv_sdk.Transaction.fromAtomicBEEF(createResult.tx).id("hex") : void 0);
|
|
31528
|
-
if (!finalTxid) throw new Error("
|
|
31529
|
-
if (createResult.tx == null) throw new Error("
|
|
31626
|
+
if (!finalTxid) throw new Error("UMP transaction was not finalized.");
|
|
31627
|
+
if (createResult.tx == null) throw new Error("UMP transaction data missing.");
|
|
31530
31628
|
const broadcastTx = _bsv_sdk.Transaction.fromAtomicBEEF(createResult.tx);
|
|
31531
31629
|
const result = await this.broadcaster.broadcast(broadcastTx);
|
|
31532
|
-
this.
|
|
31630
|
+
this.assertBroadcast(result, "create-finalized");
|
|
31533
31631
|
return `${finalTxid}.0`;
|
|
31534
31632
|
}
|
|
31535
31633
|
/** Signs the old-token input and broadcasts — used during UMP token renewal. */
|
|
31536
|
-
async
|
|
31634
|
+
async renewToken(wallet, adminOriginator, reference, partialTx) {
|
|
31537
31635
|
const unlockingScript = await new _bsv_sdk.PushDrop(wallet, adminOriginator).unlock([2, "admin user management token"], "1", "self").sign(partialTx, 0);
|
|
31538
31636
|
const signResult = await wallet.signAction({
|
|
31539
31637
|
reference,
|
|
31540
31638
|
spends: { 0: { unlockingScript: unlockingScript.toHex() } }
|
|
31541
31639
|
}, adminOriginator);
|
|
31542
31640
|
const finalTxid = signResult.txid || (signResult.tx == null ? "" : _bsv_sdk.Transaction.fromAtomicBEEF(signResult.tx).id("hex"));
|
|
31543
|
-
if (!finalTxid) throw new Error("Could not finalize
|
|
31544
|
-
if (signResult.tx == null) throw new Error("
|
|
31641
|
+
if (!finalTxid) throw new Error("Could not finalize renewed UMP token.");
|
|
31642
|
+
if (signResult.tx == null) throw new Error("Renewed UMP token transaction data missing.");
|
|
31545
31643
|
const result = await this.broadcaster.broadcast(_bsv_sdk.Transaction.fromAtomicBEEF(signResult.tx));
|
|
31546
|
-
this.
|
|
31644
|
+
this.assertBroadcast(result, "renew");
|
|
31547
31645
|
return `${finalTxid}.0`;
|
|
31548
31646
|
}
|
|
31549
31647
|
/** Signs without input spending and broadcasts — used when creating a brand-new UMP token. */
|
|
31550
|
-
async
|
|
31648
|
+
async broadcastNew(wallet, adminOriginator, reference) {
|
|
31551
31649
|
const signResult = await wallet.signAction({
|
|
31552
31650
|
reference,
|
|
31553
31651
|
spends: {}
|
|
31554
31652
|
}, adminOriginator);
|
|
31555
31653
|
const finalTxid = signResult.txid || (signResult.tx == null ? "" : _bsv_sdk.Transaction.fromAtomicBEEF(signResult.tx).id("hex"));
|
|
31556
|
-
if (!finalTxid) throw new Error("
|
|
31557
|
-
if (signResult.tx == null) throw new Error("
|
|
31654
|
+
if (!finalTxid) throw new Error("Could not finalize new UMP token.");
|
|
31655
|
+
if (signResult.tx == null) throw new Error("New UMP token transaction data missing.");
|
|
31558
31656
|
const result = await this.broadcaster.broadcast(_bsv_sdk.Transaction.fromAtomicBEEF(signResult.tx));
|
|
31559
|
-
this.
|
|
31657
|
+
this.assertBroadcast(result, "create");
|
|
31560
31658
|
return `${finalTxid}.0`;
|
|
31561
31659
|
}
|
|
31562
|
-
|
|
31660
|
+
assertBroadcast(result, operation) {
|
|
31563
31661
|
const succeeded = result.status === "success";
|
|
31564
31662
|
this.telemetry.capture({
|
|
31565
31663
|
name: succeeded ? "wallet-toolbox.ump.broadcast.completed" : "wallet-toolbox.ump.broadcast.failed",
|
|
@@ -31588,12 +31686,12 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31588
31686
|
if (answer.type !== "output-list" || answer.outputs.length === 0) return [];
|
|
31589
31687
|
const tokens = [];
|
|
31590
31688
|
for (const output of answer.outputs) {
|
|
31591
|
-
const token = this.
|
|
31689
|
+
const token = this.parseOutput(output);
|
|
31592
31690
|
if (token != null) tokens.push(token);
|
|
31593
31691
|
}
|
|
31594
31692
|
return tokens;
|
|
31595
31693
|
}
|
|
31596
|
-
|
|
31694
|
+
parseOutput(output) {
|
|
31597
31695
|
try {
|
|
31598
31696
|
const tx = _bsv_sdk.Transaction.fromBEEF(output.beef);
|
|
31599
31697
|
const txOutput = tx.outputs[output.outputIndex];
|
|
@@ -31643,14 +31741,14 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31643
31741
|
correlationId
|
|
31644
31742
|
});
|
|
31645
31743
|
} catch (error) {
|
|
31646
|
-
const diagnostics = this.
|
|
31647
|
-
this.
|
|
31744
|
+
const diagnostics = this.emptyStats(correlationId);
|
|
31745
|
+
this.lookupFailed("outpoint", "lookup-unavailable", diagnostics, startedAt, error);
|
|
31648
31746
|
throw new UMPTokenLookupError("lookup-unavailable", diagnostics, { cause: error });
|
|
31649
31747
|
}
|
|
31650
31748
|
if (resolution.answer.outputs.length === 0) {
|
|
31651
31749
|
if (resolution.progress.emptyHosts === 0) {
|
|
31652
|
-
const diagnostics = this.
|
|
31653
|
-
this.
|
|
31750
|
+
const diagnostics = this.diagnosticsFor(resolution);
|
|
31751
|
+
this.lookupFailed("outpoint", "lookup-incomplete", diagnostics, startedAt);
|
|
31654
31752
|
throw new UMPTokenLookupError("lookup-incomplete", diagnostics);
|
|
31655
31753
|
}
|
|
31656
31754
|
return;
|
|
@@ -31792,20 +31890,20 @@ var CWIStyleWalletManager = class {
|
|
|
31792
31890
|
if (this._initSnapshot !== void 0) {
|
|
31793
31891
|
this.telemetry.capture({
|
|
31794
31892
|
name: "wallet-toolbox.snapshot.initialization.started",
|
|
31795
|
-
component:
|
|
31893
|
+
component: CWI_COMPONENT,
|
|
31796
31894
|
severity: "debug"
|
|
31797
31895
|
});
|
|
31798
31896
|
try {
|
|
31799
31897
|
await this.loadSnapshot(this._initSnapshot);
|
|
31800
31898
|
this.telemetry.capture({
|
|
31801
31899
|
name: "wallet-toolbox.snapshot.initialization.completed",
|
|
31802
|
-
component:
|
|
31900
|
+
component: CWI_COMPONENT,
|
|
31803
31901
|
severity: "info"
|
|
31804
31902
|
});
|
|
31805
31903
|
} catch (error) {
|
|
31806
31904
|
this.telemetry.capture({
|
|
31807
31905
|
name: "wallet-toolbox.snapshot.initialization.failed",
|
|
31808
|
-
component:
|
|
31906
|
+
component: CWI_COMPONENT,
|
|
31809
31907
|
severity: "error",
|
|
31810
31908
|
error
|
|
31811
31909
|
});
|
|
@@ -31814,9 +31912,11 @@ var CWIStyleWalletManager = class {
|
|
|
31814
31912
|
}
|
|
31815
31913
|
}
|
|
31816
31914
|
/**
|
|
31817
|
-
* Provides the presentation key.
|
|
31915
|
+
* Provides the presentation key. A WAB operator pin may be supplied by the
|
|
31916
|
+
* authentication manager; normal lookup and lineage resolution always run
|
|
31917
|
+
* before this ambiguity-only fallback.
|
|
31818
31918
|
*/
|
|
31819
|
-
async providePresentationKey(key) {
|
|
31919
|
+
async providePresentationKey(key, lookupOptions) {
|
|
31820
31920
|
if (this.authenticated) throw new Error("User is already authenticated");
|
|
31821
31921
|
if (this.authenticationMode === "recovery-key-and-password") throw new Error("Presentation key is not needed in this mode");
|
|
31822
31922
|
if (key.length !== 32 || key.some((byte) => !Number.isInteger(byte) || byte < 0 || byte > 255)) throw new TypeError("Presentation key must contain exactly 32 bytes.");
|
|
@@ -31825,17 +31925,17 @@ var CWIStyleWalletManager = class {
|
|
|
31825
31925
|
const startedAt = Date.now();
|
|
31826
31926
|
this.telemetry.capture({
|
|
31827
31927
|
name: "wallet-toolbox.authentication.account-lookup.started",
|
|
31828
|
-
component:
|
|
31928
|
+
component: CWI_COMPONENT,
|
|
31829
31929
|
severity: "debug",
|
|
31830
31930
|
attributes: { lookupKind: "presentation" }
|
|
31831
31931
|
});
|
|
31832
31932
|
let token;
|
|
31833
31933
|
try {
|
|
31834
|
-
token = await this.UMPTokenInteractor.findByPresentationKeyHash(hash);
|
|
31934
|
+
token = await this.UMPTokenInteractor.findByPresentationKeyHash(hash, lookupOptions);
|
|
31835
31935
|
} catch (error) {
|
|
31836
31936
|
this.telemetry.capture({
|
|
31837
31937
|
name: "wallet-toolbox.authentication.account-lookup.failed",
|
|
31838
|
-
component:
|
|
31938
|
+
component: CWI_COMPONENT,
|
|
31839
31939
|
severity: "warn",
|
|
31840
31940
|
attributes: {
|
|
31841
31941
|
lookupKind: "presentation",
|
|
@@ -31855,7 +31955,7 @@ var CWIStyleWalletManager = class {
|
|
|
31855
31955
|
}
|
|
31856
31956
|
this.telemetry.capture({
|
|
31857
31957
|
name: "wallet-toolbox.authentication.account-lookup.completed",
|
|
31858
|
-
component:
|
|
31958
|
+
component: CWI_COMPONENT,
|
|
31859
31959
|
severity: "info",
|
|
31860
31960
|
attributes: {
|
|
31861
31961
|
lookupKind: "presentation",
|
|
@@ -31871,11 +31971,11 @@ var CWIStyleWalletManager = class {
|
|
|
31871
31971
|
if (this.authenticated) throw new Error("User is already authenticated");
|
|
31872
31972
|
if (this.authenticationMode === "presentation-key-and-recovery-key") throw new Error("Password is not needed in this mode");
|
|
31873
31973
|
if (this.authenticationFlow === "unknown") throw new Error("Determine account status with a presentation or recovery key before providing a password.");
|
|
31874
|
-
if (this.authenticationFlow === "existing-user") await this.
|
|
31875
|
-
else await this.
|
|
31974
|
+
if (this.authenticationFlow === "existing-user") await this.unlockExisting(password);
|
|
31975
|
+
else await this.createNewUser(password);
|
|
31876
31976
|
}
|
|
31877
31977
|
/** Handles the password step for an existing user — derives keys, sets up infrastructure. */
|
|
31878
|
-
async
|
|
31978
|
+
async unlockExisting(password) {
|
|
31879
31979
|
if (this.currentUMPToken == null) throw new Error("Provide presentation or recovery key first.");
|
|
31880
31980
|
const derivedPasswordKey = await derivePasswordKey(this.currentUMPToken, _bsv_sdk.Utils.toArray(password, "utf8"));
|
|
31881
31981
|
let rootPrimaryKey;
|
|
@@ -31888,11 +31988,11 @@ var CWIStyleWalletManager = class {
|
|
|
31888
31988
|
rootPrimaryKey = new _bsv_sdk.SymmetricKey(this.XOR(this.recoveryKey, derivedPasswordKey)).decrypt(this.currentUMPToken.passwordRecoveryPrimary);
|
|
31889
31989
|
rootPrivilegedKey = new _bsv_sdk.SymmetricKey(this.XOR(rootPrimaryKey, derivedPasswordKey)).decrypt(this.currentUMPToken.passwordPrimaryPrivileged);
|
|
31890
31990
|
}
|
|
31891
|
-
await this.
|
|
31991
|
+
await this.setupRoot(rootPrimaryKey, rootPrivilegedKey);
|
|
31892
31992
|
await this.switchProfile(this.activeProfileId);
|
|
31893
31993
|
}
|
|
31894
31994
|
/** Handles the password step for a new user — generates keys, builds UMP token, publishes on-chain. */
|
|
31895
|
-
async
|
|
31995
|
+
async createNewUser(password) {
|
|
31896
31996
|
if (this.authenticationMode !== "presentation-key-and-password") throw new Error("New-user flow requires presentation key and password mode.");
|
|
31897
31997
|
if (this.presentationKey == null) throw new Error("No presentation key provided for new-user flow.");
|
|
31898
31998
|
const recoveryKey = (0, _bsv_sdk.Random)(32);
|
|
@@ -31931,14 +32031,14 @@ var CWIStyleWalletManager = class {
|
|
|
31931
32031
|
passwordKdf: this.kdfConfig
|
|
31932
32032
|
};
|
|
31933
32033
|
this.currentUMPToken = newToken;
|
|
31934
|
-
await this.
|
|
32034
|
+
await this.setupRoot(rootPrimaryKey);
|
|
31935
32035
|
await this.switchProfile(DEFAULT_PROFILE_ID);
|
|
31936
32036
|
if (this.newWalletFunder != null && this.underlying != null) try {
|
|
31937
32037
|
await this.newWalletFunder(this.presentationKey, this.underlying, this.adminOriginator);
|
|
31938
32038
|
} catch (error) {
|
|
31939
32039
|
this.telemetry.capture({
|
|
31940
32040
|
name: "wallet-toolbox.authentication.new-wallet-funding.failed",
|
|
31941
|
-
component:
|
|
32041
|
+
component: CWI_COMPONENT,
|
|
31942
32042
|
severity: "error",
|
|
31943
32043
|
error: /* @__PURE__ */ new Error("New wallet funding failed.")
|
|
31944
32044
|
});
|
|
@@ -31969,7 +32069,7 @@ var CWIStyleWalletManager = class {
|
|
|
31969
32069
|
const xorKey = this.XOR(this.presentationKey, recoveryKey);
|
|
31970
32070
|
const rootPrimaryKey = new _bsv_sdk.SymmetricKey(xorKey).decrypt(this.currentUMPToken.presentationRecoveryPrimary);
|
|
31971
32071
|
const rootPrivilegedKey = new _bsv_sdk.SymmetricKey(xorKey).decrypt(this.currentUMPToken.presentationRecoveryPrivileged);
|
|
31972
|
-
await this.
|
|
32072
|
+
await this.setupRoot(rootPrimaryKey, rootPrivilegedKey);
|
|
31973
32073
|
await this.switchProfile(this.activeProfileId);
|
|
31974
32074
|
}
|
|
31975
32075
|
}
|
|
@@ -32000,7 +32100,7 @@ var CWIStyleWalletManager = class {
|
|
|
32000
32100
|
if (snapshot.length > 16777216) throw new Error("Snapshot exceeds the maximum supported size.");
|
|
32001
32101
|
this.telemetry.capture({
|
|
32002
32102
|
name: "wallet-toolbox.snapshot.saved",
|
|
32003
|
-
component:
|
|
32103
|
+
component: CWI_COMPONENT,
|
|
32004
32104
|
severity: "info",
|
|
32005
32105
|
attributes: {
|
|
32006
32106
|
formatVersion: 2,
|
|
@@ -32038,12 +32138,12 @@ var CWIStyleWalletManager = class {
|
|
|
32038
32138
|
const tokenBytes = payloadReader.read(tokenLen);
|
|
32039
32139
|
const token = this.deserializeUMPToken(tokenBytes);
|
|
32040
32140
|
this.currentUMPToken = token;
|
|
32041
|
-
await this.
|
|
32141
|
+
await this.setupRoot(rootPrimaryKey);
|
|
32042
32142
|
await this.switchProfile(activeProfileId);
|
|
32043
32143
|
this.authenticationFlow = "existing-user";
|
|
32044
32144
|
this.telemetry.capture({
|
|
32045
32145
|
name: "wallet-toolbox.snapshot.loaded",
|
|
32046
|
-
component:
|
|
32146
|
+
component: CWI_COMPONENT,
|
|
32047
32147
|
severity: "info",
|
|
32048
32148
|
attributes: {
|
|
32049
32149
|
formatVersion: version,
|
|
@@ -32054,7 +32154,7 @@ var CWIStyleWalletManager = class {
|
|
|
32054
32154
|
this.destroy();
|
|
32055
32155
|
this.telemetry.capture({
|
|
32056
32156
|
name: "wallet-toolbox.snapshot.load-failed",
|
|
32057
|
-
component:
|
|
32157
|
+
component: CWI_COMPONENT,
|
|
32058
32158
|
severity: "error",
|
|
32059
32159
|
error
|
|
32060
32160
|
});
|
|
@@ -32071,7 +32171,7 @@ var CWIStyleWalletManager = class {
|
|
|
32071
32171
|
if (refreshed == null) return false;
|
|
32072
32172
|
if (refreshed.currentOutpoint && currentToken.currentOutpoint && refreshed.currentOutpoint === currentToken.currentOutpoint) return false;
|
|
32073
32173
|
this.currentUMPToken = refreshed;
|
|
32074
|
-
await this.
|
|
32174
|
+
await this.setupRoot(this.rootPrimaryKey);
|
|
32075
32175
|
this.saveSnapshot();
|
|
32076
32176
|
return true;
|
|
32077
32177
|
}
|
|
@@ -32130,7 +32230,7 @@ var CWIStyleWalletManager = class {
|
|
|
32130
32230
|
createdAt: Math.floor(Date.now() / 1e3)
|
|
32131
32231
|
};
|
|
32132
32232
|
this.profiles.push(newProfile);
|
|
32133
|
-
await this.
|
|
32233
|
+
await this.updateFactors(this.currentUMPToken.passwordSalt, await this.getFactor("passwordKey"), await this.getFactor("presentationKey"), await this.getFactor("recoveryKey"), this.rootPrimaryKey, await this.getFactor("privilegedKey"), this.profiles);
|
|
32134
32234
|
return newProfile.id;
|
|
32135
32235
|
}
|
|
32136
32236
|
/**
|
|
@@ -32147,7 +32247,7 @@ var CWIStyleWalletManager = class {
|
|
|
32147
32247
|
if (profileIndex === -1) throw new Error("Profile not found.");
|
|
32148
32248
|
this.profiles.splice(profileIndex, 1);
|
|
32149
32249
|
if (this.activeProfileId.every((x, i) => x === profileId[i])) await this.switchProfile(DEFAULT_PROFILE_ID);
|
|
32150
|
-
await this.
|
|
32250
|
+
await this.updateFactors(this.currentUMPToken.passwordSalt, await this.getFactor("passwordKey"), await this.getFactor("presentationKey"), await this.getFactor("recoveryKey"), this.rootPrimaryKey, await this.getFactor("privilegedKey"), this.profiles);
|
|
32151
32251
|
}
|
|
32152
32252
|
/**
|
|
32153
32253
|
* Switches the active profile. This re-derives keys and rebuilds the underlying wallet.
|
|
@@ -32188,14 +32288,14 @@ var CWIStyleWalletManager = class {
|
|
|
32188
32288
|
const recoveryKey = await this.getFactor("recoveryKey");
|
|
32189
32289
|
const presentationKey = await this.getFactor("presentationKey");
|
|
32190
32290
|
const rootPrivilegedKey = await this.getFactor("privilegedKey");
|
|
32191
|
-
await this.
|
|
32291
|
+
await this.updateFactors(passwordSalt, newPasswordKey, presentationKey, recoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
|
|
32192
32292
|
}
|
|
32193
32293
|
/**
|
|
32194
32294
|
* Retrieves the current recovery key. Requires privileged access.
|
|
32195
32295
|
*/
|
|
32196
32296
|
async getRecoveryKey() {
|
|
32197
32297
|
if (!this.authenticated || this.currentUMPToken == null || this.rootPrivilegedKeyManager == null) throw new Error("Not authenticated or missing required data.");
|
|
32198
|
-
return
|
|
32298
|
+
return this.getFactor("recoveryKey");
|
|
32199
32299
|
}
|
|
32200
32300
|
/**
|
|
32201
32301
|
* Changes the user's recovery key. Prompts user to save the new key.
|
|
@@ -32207,7 +32307,7 @@ var CWIStyleWalletManager = class {
|
|
|
32207
32307
|
const rootPrivilegedKey = await this.getFactor("privilegedKey");
|
|
32208
32308
|
const newRecoveryKey = (0, _bsv_sdk.Random)(32);
|
|
32209
32309
|
await this.recoveryKeySaver(newRecoveryKey);
|
|
32210
|
-
await this.
|
|
32310
|
+
await this.updateFactors(this.currentUMPToken.passwordSalt, passwordKey, presentationKey, newRecoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
|
|
32211
32311
|
}
|
|
32212
32312
|
/**
|
|
32213
32313
|
* Changes the user's presentation key.
|
|
@@ -32218,7 +32318,7 @@ var CWIStyleWalletManager = class {
|
|
|
32218
32318
|
const recoveryKey = await this.getFactor("recoveryKey");
|
|
32219
32319
|
const passwordKey = await this.getFactor("passwordKey");
|
|
32220
32320
|
const rootPrivilegedKey = await this.getFactor("privilegedKey");
|
|
32221
|
-
await this.
|
|
32321
|
+
await this.updateFactors(this.currentUMPToken.passwordSalt, passwordKey, newPresentationKey, recoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
|
|
32222
32322
|
if (this.presentationKey != null) this.presentationKey = newPresentationKey;
|
|
32223
32323
|
}
|
|
32224
32324
|
/**
|
|
@@ -32264,7 +32364,7 @@ var CWIStyleWalletManager = class {
|
|
|
32264
32364
|
} catch (error) {
|
|
32265
32365
|
this.telemetry.capture({
|
|
32266
32366
|
name: "wallet-toolbox.authentication.factor-decryption.failed",
|
|
32267
|
-
component:
|
|
32367
|
+
component: CWI_COMPONENT,
|
|
32268
32368
|
severity: "error",
|
|
32269
32369
|
attributes: { factor: factorName },
|
|
32270
32370
|
error
|
|
@@ -32277,7 +32377,7 @@ var CWIStyleWalletManager = class {
|
|
|
32277
32377
|
* Recomputes UMP token fields with updated factors and profiles, then publishes the update.
|
|
32278
32378
|
* This operation requires the *root* privileged key and the *default* profile wallet.
|
|
32279
32379
|
*/
|
|
32280
|
-
async
|
|
32380
|
+
async updateFactors(passwordSalt, passwordKey, presentationKey, recoveryKey, rootPrimaryKey, rootPrivilegedKey, profiles) {
|
|
32281
32381
|
if (!this.authenticated || this.rootPrimaryKey == null || this.currentUMPToken == null) throw new Error("Wallet is not properly authenticated or missing data for update.");
|
|
32282
32382
|
const oldTokenToConsume = { ...this.currentUMPToken };
|
|
32283
32383
|
if (!oldTokenToConsume.currentOutpoint) throw new Error("Cannot update UMP token: Old token has no outpoint.");
|
|
@@ -32328,7 +32428,7 @@ var CWIStyleWalletManager = class {
|
|
|
32328
32428
|
if (!currentActiveId.every((x) => x === 0)) {
|
|
32329
32429
|
this.telemetry.capture({
|
|
32330
32430
|
name: "wallet-toolbox.ump.profile-switch.started",
|
|
32331
|
-
component:
|
|
32431
|
+
component: CWI_COMPONENT,
|
|
32332
32432
|
severity: "debug",
|
|
32333
32433
|
attributes: { reason: "token-update" }
|
|
32334
32434
|
});
|
|
@@ -32344,7 +32444,7 @@ var CWIStyleWalletManager = class {
|
|
|
32344
32444
|
await this.switchProfile(currentActiveId);
|
|
32345
32445
|
this.telemetry.capture({
|
|
32346
32446
|
name: "wallet-toolbox.ump.profile-switch.completed",
|
|
32347
|
-
component:
|
|
32447
|
+
component: CWI_COMPONENT,
|
|
32348
32448
|
severity: "debug",
|
|
32349
32449
|
attributes: { reason: "token-update" }
|
|
32350
32450
|
});
|
|
@@ -32471,9 +32571,9 @@ var CWIStyleWalletManager = class {
|
|
|
32471
32571
|
* @param rootPrimaryKey The user's root primary key (32 bytes).
|
|
32472
32572
|
* @param ephemeralRootPrivilegedKey Optional root privileged key (e.g., during recovery flows).
|
|
32473
32573
|
*/
|
|
32474
|
-
async
|
|
32574
|
+
async setupRoot(rootKey, ephemeralRootPrivilegedKey) {
|
|
32475
32575
|
if (this.currentUMPToken == null) throw new Error("A UMP token must exist before setting up root infrastructure!");
|
|
32476
|
-
this.rootPrimaryKey =
|
|
32576
|
+
this.rootPrimaryKey = rootKey;
|
|
32477
32577
|
let oneTimePrivilegedKey = ephemeralRootPrivilegedKey == null ? void 0 : new _bsv_sdk.PrivateKey(ephemeralRootPrivilegedKey);
|
|
32478
32578
|
this.rootPrivilegedKeyManager = new PrivilegedKeyManager(async (reason) => {
|
|
32479
32579
|
if (oneTimePrivilegedKey != null) {
|
|
@@ -32494,7 +32594,7 @@ var CWIStyleWalletManager = class {
|
|
|
32494
32594
|
});
|
|
32495
32595
|
this.profiles = [];
|
|
32496
32596
|
if (this.currentUMPToken.profilesEncrypted != null && this.currentUMPToken.profilesEncrypted.length > 0) try {
|
|
32497
|
-
const decryptedProfileBytes = new _bsv_sdk.SymmetricKey(
|
|
32597
|
+
const decryptedProfileBytes = new _bsv_sdk.SymmetricKey(rootKey).decrypt(this.currentUMPToken.profilesEncrypted);
|
|
32498
32598
|
const profilesJson = _bsv_sdk.Utils.toUTF8(decryptedProfileBytes);
|
|
32499
32599
|
const profiles = JSON.parse(profilesJson);
|
|
32500
32600
|
if (!Array.isArray(profiles) || profiles.length > 1e3 || !profiles.every(isValidProfile)) throw new Error("Decrypted profile data is invalid or exceeds supported bounds.");
|
|
@@ -32503,7 +32603,7 @@ var CWIStyleWalletManager = class {
|
|
|
32503
32603
|
this.profiles = [];
|
|
32504
32604
|
this.telemetry.capture({
|
|
32505
32605
|
name: "wallet-toolbox.profile.load-failed",
|
|
32506
|
-
component:
|
|
32606
|
+
component: CWI_COMPONENT,
|
|
32507
32607
|
severity: "error",
|
|
32508
32608
|
error
|
|
32509
32609
|
});
|
|
@@ -32512,98 +32612,98 @@ var CWIStyleWalletManager = class {
|
|
|
32512
32612
|
}
|
|
32513
32613
|
this.authenticated = true;
|
|
32514
32614
|
}
|
|
32515
|
-
|
|
32615
|
+
assertReady(originator) {
|
|
32516
32616
|
if (!this.authenticated) throw new Error("User is not authenticated.");
|
|
32517
32617
|
if (this.underlying == null) throw new Error("Underlying wallet for the active profile is not initialized.");
|
|
32518
32618
|
if (originator === this.adminOriginator) throw new Error("External applications are not allowed to use the admin originator.");
|
|
32519
32619
|
}
|
|
32520
32620
|
async getPublicKey(args, originator) {
|
|
32521
|
-
this.
|
|
32522
|
-
return
|
|
32621
|
+
this.assertReady(originator);
|
|
32622
|
+
return this.underlying.getPublicKey(args, originator);
|
|
32523
32623
|
}
|
|
32524
32624
|
async revealCounterpartyKeyLinkage(args, originator) {
|
|
32525
|
-
this.
|
|
32526
|
-
return
|
|
32625
|
+
this.assertReady(originator);
|
|
32626
|
+
return this.underlying.revealCounterpartyKeyLinkage(args, originator);
|
|
32527
32627
|
}
|
|
32528
32628
|
async revealSpecificKeyLinkage(args, originator) {
|
|
32529
|
-
this.
|
|
32530
|
-
return
|
|
32629
|
+
this.assertReady(originator);
|
|
32630
|
+
return this.underlying.revealSpecificKeyLinkage(args, originator);
|
|
32531
32631
|
}
|
|
32532
32632
|
async encrypt(args, originator) {
|
|
32533
|
-
this.
|
|
32534
|
-
return
|
|
32633
|
+
this.assertReady(originator);
|
|
32634
|
+
return this.underlying.encrypt(args, originator);
|
|
32535
32635
|
}
|
|
32536
32636
|
async decrypt(args, originator) {
|
|
32537
|
-
this.
|
|
32538
|
-
return
|
|
32637
|
+
this.assertReady(originator);
|
|
32638
|
+
return this.underlying.decrypt(args, originator);
|
|
32539
32639
|
}
|
|
32540
32640
|
async createHmac(args, originator) {
|
|
32541
|
-
this.
|
|
32542
|
-
return
|
|
32641
|
+
this.assertReady(originator);
|
|
32642
|
+
return this.underlying.createHmac(args, originator);
|
|
32543
32643
|
}
|
|
32544
32644
|
async verifyHmac(args, originator) {
|
|
32545
|
-
this.
|
|
32546
|
-
return
|
|
32645
|
+
this.assertReady(originator);
|
|
32646
|
+
return this.underlying.verifyHmac(args, originator);
|
|
32547
32647
|
}
|
|
32548
32648
|
async createSignature(args, originator) {
|
|
32549
|
-
this.
|
|
32550
|
-
return
|
|
32649
|
+
this.assertReady(originator);
|
|
32650
|
+
return this.underlying.createSignature(args, originator);
|
|
32551
32651
|
}
|
|
32552
32652
|
async verifySignature(args, originator) {
|
|
32553
|
-
this.
|
|
32554
|
-
return
|
|
32653
|
+
this.assertReady(originator);
|
|
32654
|
+
return this.underlying.verifySignature(args, originator);
|
|
32555
32655
|
}
|
|
32556
32656
|
async createAction(args, originator) {
|
|
32557
|
-
this.
|
|
32558
|
-
return
|
|
32657
|
+
this.assertReady(originator);
|
|
32658
|
+
return this.underlying.createAction(args, originator);
|
|
32559
32659
|
}
|
|
32560
32660
|
async signAction(args, originator) {
|
|
32561
|
-
this.
|
|
32562
|
-
return
|
|
32661
|
+
this.assertReady(originator);
|
|
32662
|
+
return this.underlying.signAction(args, originator);
|
|
32563
32663
|
}
|
|
32564
32664
|
async abortAction(args, originator) {
|
|
32565
|
-
this.
|
|
32566
|
-
return
|
|
32665
|
+
this.assertReady(originator);
|
|
32666
|
+
return this.underlying.abortAction(args, originator);
|
|
32567
32667
|
}
|
|
32568
32668
|
async listActions(args, originator) {
|
|
32569
|
-
this.
|
|
32570
|
-
return
|
|
32669
|
+
this.assertReady(originator);
|
|
32670
|
+
return this.underlying.listActions(args, originator);
|
|
32571
32671
|
}
|
|
32572
32672
|
async internalizeAction(args, originator) {
|
|
32573
|
-
this.
|
|
32574
|
-
return
|
|
32673
|
+
this.assertReady(originator);
|
|
32674
|
+
return this.underlying.internalizeAction(args, originator);
|
|
32575
32675
|
}
|
|
32576
32676
|
async listOutputs(args, originator) {
|
|
32577
|
-
this.
|
|
32578
|
-
return
|
|
32677
|
+
this.assertReady(originator);
|
|
32678
|
+
return this.underlying.listOutputs(args, originator);
|
|
32579
32679
|
}
|
|
32580
32680
|
async relinquishOutput(args, originator) {
|
|
32581
|
-
this.
|
|
32582
|
-
return
|
|
32681
|
+
this.assertReady(originator);
|
|
32682
|
+
return this.underlying.relinquishOutput(args, originator);
|
|
32583
32683
|
}
|
|
32584
32684
|
async acquireCertificate(args, originator) {
|
|
32585
|
-
this.
|
|
32586
|
-
return
|
|
32685
|
+
this.assertReady(originator);
|
|
32686
|
+
return this.underlying.acquireCertificate(args, originator);
|
|
32587
32687
|
}
|
|
32588
32688
|
async listCertificates(args, originator) {
|
|
32589
|
-
this.
|
|
32590
|
-
return
|
|
32689
|
+
this.assertReady(originator);
|
|
32690
|
+
return this.underlying.listCertificates(args, originator);
|
|
32591
32691
|
}
|
|
32592
32692
|
async proveCertificate(args, originator) {
|
|
32593
|
-
this.
|
|
32594
|
-
return
|
|
32693
|
+
this.assertReady(originator);
|
|
32694
|
+
return this.underlying.proveCertificate(args, originator);
|
|
32595
32695
|
}
|
|
32596
32696
|
async relinquishCertificate(args, originator) {
|
|
32597
|
-
this.
|
|
32598
|
-
return
|
|
32697
|
+
this.assertReady(originator);
|
|
32698
|
+
return this.underlying.relinquishCertificate(args, originator);
|
|
32599
32699
|
}
|
|
32600
32700
|
async discoverByIdentityKey(args, originator) {
|
|
32601
|
-
this.
|
|
32602
|
-
return
|
|
32701
|
+
this.assertReady(originator);
|
|
32702
|
+
return this.underlying.discoverByIdentityKey(args, originator);
|
|
32603
32703
|
}
|
|
32604
32704
|
async discoverByAttributes(args, originator) {
|
|
32605
|
-
this.
|
|
32606
|
-
return
|
|
32705
|
+
this.assertReady(originator);
|
|
32706
|
+
return this.underlying.discoverByAttributes(args, originator);
|
|
32607
32707
|
}
|
|
32608
32708
|
async isAuthenticated(_, originator) {
|
|
32609
32709
|
if (!this.authenticated) throw new Error("User is not authenticated.");
|
|
@@ -32613,23 +32713,23 @@ var CWIStyleWalletManager = class {
|
|
|
32613
32713
|
async waitForAuthentication(_, originator) {
|
|
32614
32714
|
if (originator === this.adminOriginator) throw new Error("External applications are not allowed to use the admin originator.");
|
|
32615
32715
|
while (!this.authenticated || this.underlying == null) await new Promise((resolve) => setTimeout(resolve, 100));
|
|
32616
|
-
return
|
|
32716
|
+
return this.underlying.waitForAuthentication({}, originator);
|
|
32617
32717
|
}
|
|
32618
32718
|
async getHeight(_, originator) {
|
|
32619
|
-
this.
|
|
32620
|
-
return
|
|
32719
|
+
this.assertReady(originator);
|
|
32720
|
+
return this.underlying.getHeight({}, originator);
|
|
32621
32721
|
}
|
|
32622
32722
|
async getHeaderForHeight(args, originator) {
|
|
32623
|
-
this.
|
|
32624
|
-
return
|
|
32723
|
+
this.assertReady(originator);
|
|
32724
|
+
return this.underlying.getHeaderForHeight(args, originator);
|
|
32625
32725
|
}
|
|
32626
32726
|
async getNetwork(_, originator) {
|
|
32627
|
-
this.
|
|
32628
|
-
return
|
|
32727
|
+
this.assertReady(originator);
|
|
32728
|
+
return this.underlying.getNetwork({}, originator);
|
|
32629
32729
|
}
|
|
32630
32730
|
async getVersion(_, originator) {
|
|
32631
|
-
this.
|
|
32632
|
-
return
|
|
32731
|
+
this.assertReady(originator);
|
|
32732
|
+
return this.underlying.getVersion({}, originator);
|
|
32633
32733
|
}
|
|
32634
32734
|
};
|
|
32635
32735
|
//#endregion
|
|
@@ -32973,6 +33073,8 @@ const DEFAULT_MAX_RESPONSE_BYTES = 1024 * 1024;
|
|
|
32973
33073
|
const MAX_CONFIGURED_TIMEOUT_MS = 12e4;
|
|
32974
33074
|
const MAX_CONFIGURED_REQUEST_BYTES = 10 * 1024 * 1024;
|
|
32975
33075
|
const MAX_CONFIGURED_RESPONSE_BYTES = 10 * 1024 * 1024;
|
|
33076
|
+
const WAB_COMPONENT = "wallet-toolbox.wab-transport";
|
|
33077
|
+
const WAB_REQUEST_EVENT = "wallet-toolbox.wab.request.";
|
|
32976
33078
|
const defaultFetch = typeof globalThis !== "undefined" && typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : void 0;
|
|
32977
33079
|
/**
|
|
32978
33080
|
* A privacy-safe WAB transport failure. Response bodies and request payloads
|
|
@@ -33011,8 +33113,8 @@ function normalizeServerUrl(serverUrl) {
|
|
|
33011
33113
|
} catch {
|
|
33012
33114
|
throw new WABClientError("WAB_INVALID_CONFIGURATION", "WAB server URL must be an absolute URL.", false);
|
|
33013
33115
|
}
|
|
33014
|
-
if (parsed.username !== "" || parsed.password !== "" || parsed.search !== "" || parsed.hash !== "") throw new WABClientError("WAB_INVALID_CONFIGURATION", "WAB
|
|
33015
|
-
if (parsed.protocol !== "https:" && !(parsed.protocol === "http:" && isLocalHostname(parsed.hostname))) throw new WABClientError("WAB_INVALID_CONFIGURATION", "WAB
|
|
33116
|
+
if (parsed.username !== "" || parsed.password !== "" || parsed.search !== "" || parsed.hash !== "") throw new WABClientError("WAB_INVALID_CONFIGURATION", "WAB URL cannot include credentials, query, or fragment.", false);
|
|
33117
|
+
if (parsed.protocol !== "https:" && !(parsed.protocol === "http:" && isLocalHostname(parsed.hostname))) throw new WABClientError("WAB_INVALID_CONFIGURATION", "WAB URL requires HTTPS except on localhost.", false);
|
|
33016
33118
|
let pathname = parsed.pathname;
|
|
33017
33119
|
while (pathname.endsWith("/")) pathname = pathname.slice(0, -1);
|
|
33018
33120
|
return {
|
|
@@ -33022,7 +33124,7 @@ function normalizeServerUrl(serverUrl) {
|
|
|
33022
33124
|
}
|
|
33023
33125
|
function normalizePositiveInteger(value, fallback, maximum, name) {
|
|
33024
33126
|
const resolved = value ?? fallback;
|
|
33025
|
-
if (!Number.isInteger(resolved) || resolved <= 0 || resolved > maximum) throw new WABClientError("WAB_INVALID_CONFIGURATION", `${name} must be
|
|
33127
|
+
if (!Number.isInteger(resolved) || resolved <= 0 || resolved > maximum) throw new WABClientError("WAB_INVALID_CONFIGURATION", `${name} must be an integer from 1 to ${maximum}.`, false);
|
|
33026
33128
|
return resolved;
|
|
33027
33129
|
}
|
|
33028
33130
|
function assertSafePath(path) {
|
|
@@ -33047,20 +33149,20 @@ var WABTransport = class {
|
|
|
33047
33149
|
serverUrl;
|
|
33048
33150
|
serverOrigin;
|
|
33049
33151
|
telemetry;
|
|
33050
|
-
|
|
33051
|
-
|
|
33052
|
-
|
|
33053
|
-
|
|
33152
|
+
fetcher;
|
|
33153
|
+
timeout;
|
|
33154
|
+
requestLimit;
|
|
33155
|
+
responseLimit;
|
|
33054
33156
|
constructor(serverUrl, options = {}) {
|
|
33055
33157
|
const normalized = normalizeServerUrl(serverUrl);
|
|
33056
33158
|
this.serverUrl = normalized.baseUrl;
|
|
33057
33159
|
this.serverOrigin = normalized.origin;
|
|
33058
|
-
const
|
|
33059
|
-
if (typeof
|
|
33060
|
-
this.
|
|
33061
|
-
this.
|
|
33062
|
-
this.
|
|
33063
|
-
this.
|
|
33160
|
+
const fetcher = options.fetch ?? defaultFetch;
|
|
33161
|
+
if (typeof fetcher !== "function") throw new WABClientError("WAB_INVALID_CONFIGURATION", "WABClient requires a fetch implementation.", false);
|
|
33162
|
+
this.fetcher = fetcher;
|
|
33163
|
+
this.timeout = normalizePositiveInteger(options.timeoutMs, DEFAULT_TIMEOUT_MS, MAX_CONFIGURED_TIMEOUT_MS, "timeoutMs");
|
|
33164
|
+
this.requestLimit = normalizePositiveInteger(options.maxRequestBytes, DEFAULT_MAX_REQUEST_BYTES, MAX_CONFIGURED_REQUEST_BYTES, "maxRequestBytes");
|
|
33165
|
+
this.responseLimit = normalizePositiveInteger(options.maxResponseBytes, DEFAULT_MAX_RESPONSE_BYTES, MAX_CONFIGURED_RESPONSE_BYTES, "maxResponseBytes");
|
|
33064
33166
|
this.telemetry = new _bsv_sdk.Telemetry(options.telemetry);
|
|
33065
33167
|
}
|
|
33066
33168
|
createCorrelationId() {
|
|
@@ -33068,38 +33170,9 @@ var WABTransport = class {
|
|
|
33068
33170
|
return isSafeCorrelationId(correlationId) ? correlationId : new _bsv_sdk.Telemetry().createCorrelationId();
|
|
33069
33171
|
}
|
|
33070
33172
|
async request(path, options) {
|
|
33071
|
-
const metadata = this.createRequestMetadata(path, options);
|
|
33072
|
-
this.captureRequestStarted(metadata);
|
|
33073
|
-
const body = this.encodeRequestBody(options, metadata);
|
|
33074
|
-
const timeout = this.startRequestTimeout(metadata.errorContext);
|
|
33075
|
-
const response = await this.fetchResponse(metadata, body, timeout);
|
|
33076
|
-
const responseContext = this.createResponseContext(response, metadata);
|
|
33077
|
-
this.assertSuccessfulResponse(response, responseContext, metadata, timeout);
|
|
33078
|
-
const responseText = await this.readResponseText(response, responseContext, metadata, timeout);
|
|
33079
|
-
const parsed = this.parseResponseObject(responseText, response, responseContext, metadata);
|
|
33080
|
-
this.telemetry.capture({
|
|
33081
|
-
name: "wallet-toolbox.wab.request.completed",
|
|
33082
|
-
component: "wallet-toolbox.wab-transport",
|
|
33083
|
-
severity: "info",
|
|
33084
|
-
correlationId: metadata.correlationId,
|
|
33085
|
-
attributes: {
|
|
33086
|
-
operation: metadata.operation,
|
|
33087
|
-
method: metadata.method,
|
|
33088
|
-
route: metadata.path,
|
|
33089
|
-
serverOrigin: this.serverOrigin,
|
|
33090
|
-
status: response.status,
|
|
33091
|
-
endpointMarkerPresent: responseContext.endpointMarkerPresent,
|
|
33092
|
-
responseCorrelationMatched: responseContext.responseCorrelationMatched,
|
|
33093
|
-
responseBytes: new TextEncoder().encode(responseText).byteLength,
|
|
33094
|
-
durationMs: Date.now() - metadata.startedAt
|
|
33095
|
-
}
|
|
33096
|
-
});
|
|
33097
|
-
return parsed;
|
|
33098
|
-
}
|
|
33099
|
-
createRequestMetadata(path, options) {
|
|
33100
33173
|
assertSafePath(path);
|
|
33101
33174
|
const correlationId = options.correlationId != null && isSafeCorrelationId(options.correlationId) ? options.correlationId : this.createCorrelationId();
|
|
33102
|
-
|
|
33175
|
+
const metadata = {
|
|
33103
33176
|
method: options.method ?? "POST",
|
|
33104
33177
|
path,
|
|
33105
33178
|
operation: options.operation,
|
|
@@ -33111,46 +33184,73 @@ var WABTransport = class {
|
|
|
33111
33184
|
route: path
|
|
33112
33185
|
}
|
|
33113
33186
|
};
|
|
33114
|
-
}
|
|
33115
|
-
captureRequestStarted(metadata) {
|
|
33116
33187
|
this.telemetry.capture({
|
|
33117
|
-
name:
|
|
33118
|
-
component:
|
|
33188
|
+
name: `${WAB_REQUEST_EVENT}started`,
|
|
33189
|
+
component: WAB_COMPONENT,
|
|
33119
33190
|
severity: "debug",
|
|
33191
|
+
correlationId,
|
|
33192
|
+
attributes: {
|
|
33193
|
+
operation: metadata.operation,
|
|
33194
|
+
method: metadata.method,
|
|
33195
|
+
route: path,
|
|
33196
|
+
serverOrigin: this.serverOrigin
|
|
33197
|
+
}
|
|
33198
|
+
});
|
|
33199
|
+
const body = this.bodyFor(options, metadata);
|
|
33200
|
+
const timeout = this.startTimer(metadata.errorContext);
|
|
33201
|
+
const response = await this.fetch(metadata, body, timeout);
|
|
33202
|
+
const responseContext = {
|
|
33203
|
+
...metadata.errorContext,
|
|
33204
|
+
endpointMarkerPresent: isWabResponse(response),
|
|
33205
|
+
responseCorrelationMatched: response.headers.get("X-Correlation-ID") === correlationId
|
|
33206
|
+
};
|
|
33207
|
+
this.checkResponse(response, responseContext, metadata, timeout);
|
|
33208
|
+
const responseText = await this.readText(response, responseContext, metadata, timeout);
|
|
33209
|
+
const parsed = this.parse(responseText, response, responseContext, metadata);
|
|
33210
|
+
this.telemetry.capture({
|
|
33211
|
+
name: `${WAB_REQUEST_EVENT}completed`,
|
|
33212
|
+
component: WAB_COMPONENT,
|
|
33213
|
+
severity: "info",
|
|
33120
33214
|
correlationId: metadata.correlationId,
|
|
33121
33215
|
attributes: {
|
|
33122
33216
|
operation: metadata.operation,
|
|
33123
33217
|
method: metadata.method,
|
|
33124
33218
|
route: metadata.path,
|
|
33125
|
-
serverOrigin: this.serverOrigin
|
|
33219
|
+
serverOrigin: this.serverOrigin,
|
|
33220
|
+
status: response.status,
|
|
33221
|
+
endpointMarkerPresent: responseContext.endpointMarkerPresent,
|
|
33222
|
+
responseCorrelationMatched: responseContext.responseCorrelationMatched,
|
|
33223
|
+
responseBytes: new TextEncoder().encode(responseText).byteLength,
|
|
33224
|
+
durationMs: Date.now() - metadata.startedAt
|
|
33126
33225
|
}
|
|
33127
33226
|
});
|
|
33227
|
+
return parsed;
|
|
33128
33228
|
}
|
|
33129
|
-
|
|
33229
|
+
bodyFor(options, metadata) {
|
|
33130
33230
|
let body;
|
|
33131
33231
|
try {
|
|
33132
33232
|
body = options.body === void 0 ? void 0 : JSON.stringify(options.body);
|
|
33133
33233
|
} catch (cause) {
|
|
33134
|
-
const error = new WABClientError("WAB_INVALID_REQUEST", "WAB request
|
|
33234
|
+
const error = new WABClientError("WAB_INVALID_REQUEST", "WAB request encoding failed.", false, void 0, {
|
|
33135
33235
|
...metadata.errorContext,
|
|
33136
33236
|
cause
|
|
33137
33237
|
});
|
|
33138
|
-
this.
|
|
33238
|
+
this.report(metadata, error);
|
|
33139
33239
|
throw error;
|
|
33140
33240
|
}
|
|
33141
33241
|
if (options.body !== void 0 && body === void 0) {
|
|
33142
|
-
const error = new WABClientError("WAB_INVALID_REQUEST", "WAB request
|
|
33143
|
-
this.
|
|
33242
|
+
const error = new WABClientError("WAB_INVALID_REQUEST", "WAB request is not JSON-serializable.", false, void 0, metadata.errorContext);
|
|
33243
|
+
this.report(metadata, error);
|
|
33144
33244
|
throw error;
|
|
33145
33245
|
}
|
|
33146
|
-
if (body != null && new TextEncoder().encode(body).byteLength > this.
|
|
33147
|
-
const error = new WABClientError("WAB_REQUEST_TOO_LARGE", "WAB request
|
|
33148
|
-
this.
|
|
33246
|
+
if (body != null && new TextEncoder().encode(body).byteLength > this.requestLimit) {
|
|
33247
|
+
const error = new WABClientError("WAB_REQUEST_TOO_LARGE", "WAB request exceeds its size limit.", false, void 0, metadata.errorContext);
|
|
33248
|
+
this.report(metadata, error);
|
|
33149
33249
|
throw error;
|
|
33150
33250
|
}
|
|
33151
33251
|
return body;
|
|
33152
33252
|
}
|
|
33153
|
-
|
|
33253
|
+
startTimer(errorContext) {
|
|
33154
33254
|
const timeout = {
|
|
33155
33255
|
controller: new AbortController(),
|
|
33156
33256
|
timedOut: false
|
|
@@ -33160,12 +33260,12 @@ var WABTransport = class {
|
|
|
33160
33260
|
timeout.timedOut = true;
|
|
33161
33261
|
timeout.controller.abort();
|
|
33162
33262
|
reject(new WABClientError("WAB_TIMEOUT", "WAB request timed out.", true, void 0, errorContext));
|
|
33163
|
-
}, this.
|
|
33263
|
+
}, this.timeout);
|
|
33164
33264
|
});
|
|
33165
33265
|
return timeout;
|
|
33166
33266
|
}
|
|
33167
|
-
async
|
|
33168
|
-
const requestPromise = Promise.resolve().then(() => this.
|
|
33267
|
+
async fetch(metadata, body, timeout) {
|
|
33268
|
+
const requestPromise = Promise.resolve().then(() => this.fetcher(`${this.serverUrl}${metadata.path}`, {
|
|
33169
33269
|
method: metadata.method,
|
|
33170
33270
|
headers: {
|
|
33171
33271
|
Accept: "application/json",
|
|
@@ -33189,33 +33289,26 @@ var WABTransport = class {
|
|
|
33189
33289
|
...metadata.errorContext,
|
|
33190
33290
|
cause
|
|
33191
33291
|
});
|
|
33192
|
-
else error = new WABClientError("WAB_NETWORK_ERROR", "WAB request failed before
|
|
33292
|
+
else error = new WABClientError("WAB_NETWORK_ERROR", "WAB request failed before response.", true, void 0, {
|
|
33193
33293
|
...metadata.errorContext,
|
|
33194
33294
|
cause
|
|
33195
33295
|
});
|
|
33196
|
-
this.
|
|
33296
|
+
this.report(metadata, error);
|
|
33197
33297
|
throw error;
|
|
33198
33298
|
}
|
|
33199
33299
|
}
|
|
33200
|
-
|
|
33201
|
-
return {
|
|
33202
|
-
...metadata.errorContext,
|
|
33203
|
-
endpointMarkerPresent: isWabResponse(response),
|
|
33204
|
-
responseCorrelationMatched: response.headers.get("X-Correlation-ID") === metadata.correlationId
|
|
33205
|
-
};
|
|
33206
|
-
}
|
|
33207
|
-
assertSuccessfulResponse(response, responseContext, metadata, timeout) {
|
|
33300
|
+
checkResponse(response, responseContext, metadata, timeout) {
|
|
33208
33301
|
if (response.ok) return;
|
|
33209
33302
|
if (timeout.timer !== void 0) clearTimeout(timeout.timer);
|
|
33210
33303
|
const endpointMismatch = response.status === 404 && responseContext.endpointMarkerPresent !== true;
|
|
33211
|
-
const error = new WABClientError(endpointMismatch ? "WAB_ENDPOINT_MISMATCH" : "WAB_HTTP_ERROR", endpointMismatch ? "
|
|
33212
|
-
this.
|
|
33304
|
+
const error = new WABClientError(endpointMismatch ? "WAB_ENDPOINT_MISMATCH" : "WAB_HTTP_ERROR", endpointMismatch ? "WAB endpoint is incompatible." : `WAB request failed with HTTP status ${response.status}.`, isRetryableStatus(response.status), response.status, responseContext);
|
|
33305
|
+
this.report(metadata, error);
|
|
33213
33306
|
response.body?.cancel().catch(() => {});
|
|
33214
33307
|
throw error;
|
|
33215
33308
|
}
|
|
33216
|
-
async
|
|
33309
|
+
async readText(response, responseContext, metadata, timeout) {
|
|
33217
33310
|
try {
|
|
33218
|
-
return await Promise.race([this.
|
|
33311
|
+
return await Promise.race([this.read(response, responseContext), timeout.promise]);
|
|
33219
33312
|
} catch (cause) {
|
|
33220
33313
|
let error;
|
|
33221
33314
|
if (cause instanceof WABClientError) error = cause;
|
|
@@ -33223,17 +33316,17 @@ var WABTransport = class {
|
|
|
33223
33316
|
...responseContext,
|
|
33224
33317
|
cause
|
|
33225
33318
|
});
|
|
33226
|
-
else error = new WABClientError("WAB_INVALID_RESPONSE", "WAB response
|
|
33319
|
+
else error = new WABClientError("WAB_INVALID_RESPONSE", "WAB response read failed.", true, response.status, {
|
|
33227
33320
|
...responseContext,
|
|
33228
33321
|
cause
|
|
33229
33322
|
});
|
|
33230
|
-
this.
|
|
33323
|
+
this.report(metadata, error);
|
|
33231
33324
|
throw error;
|
|
33232
33325
|
} finally {
|
|
33233
33326
|
if (timeout.timer !== void 0) clearTimeout(timeout.timer);
|
|
33234
33327
|
}
|
|
33235
33328
|
}
|
|
33236
|
-
|
|
33329
|
+
parse(responseText, response, responseContext, metadata) {
|
|
33237
33330
|
let parsed;
|
|
33238
33331
|
try {
|
|
33239
33332
|
parsed = JSON.parse(responseText);
|
|
@@ -33242,37 +33335,32 @@ var WABTransport = class {
|
|
|
33242
33335
|
...responseContext,
|
|
33243
33336
|
cause
|
|
33244
33337
|
});
|
|
33245
|
-
this.
|
|
33338
|
+
this.report(metadata, error);
|
|
33246
33339
|
throw error;
|
|
33247
33340
|
}
|
|
33248
33341
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
33249
33342
|
const error = new WABClientError("WAB_INVALID_RESPONSE", "WAB response must be a JSON object.", true, response.status, responseContext);
|
|
33250
|
-
this.
|
|
33343
|
+
this.report(metadata, error);
|
|
33251
33344
|
throw error;
|
|
33252
33345
|
}
|
|
33253
33346
|
return parsed;
|
|
33254
33347
|
}
|
|
33255
|
-
|
|
33256
|
-
this.captureFailure(metadata.operation, metadata.method, metadata.path, metadata.correlationId, metadata.startedAt, error);
|
|
33257
|
-
}
|
|
33258
|
-
async readBoundedResponse(response, responseContext) {
|
|
33259
|
-
await this.rejectOversizedDeclaredResponse(response, responseContext);
|
|
33260
|
-
const reader = response.body?.getReader();
|
|
33261
|
-
if (reader == null) return await this.readBoundedArrayBuffer(response, responseContext);
|
|
33262
|
-
return await this.readBoundedStream(reader, response, responseContext);
|
|
33263
|
-
}
|
|
33264
|
-
async rejectOversizedDeclaredResponse(response, responseContext) {
|
|
33348
|
+
async read(response, responseContext) {
|
|
33265
33349
|
const contentLength = Number(response.headers.get("content-length"));
|
|
33266
|
-
if (
|
|
33267
|
-
|
|
33268
|
-
|
|
33350
|
+
if (Number.isFinite(contentLength) && contentLength > this.responseLimit) {
|
|
33351
|
+
await this.stopBody(response);
|
|
33352
|
+
throw this.sizeError(response, responseContext);
|
|
33353
|
+
}
|
|
33354
|
+
const reader = response.body?.getReader();
|
|
33355
|
+
if (reader == null) return this.readBuffer(response, responseContext);
|
|
33356
|
+
return this.readStream(reader, response, responseContext);
|
|
33269
33357
|
}
|
|
33270
|
-
async
|
|
33358
|
+
async readBuffer(response, responseContext) {
|
|
33271
33359
|
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
33272
|
-
if (bytes.byteLength > this.
|
|
33360
|
+
if (bytes.byteLength > this.responseLimit) throw this.sizeError(response, responseContext);
|
|
33273
33361
|
return new TextDecoder().decode(bytes);
|
|
33274
33362
|
}
|
|
33275
|
-
async
|
|
33363
|
+
async readStream(reader, response, responseContext) {
|
|
33276
33364
|
const chunks = [];
|
|
33277
33365
|
let total = 0;
|
|
33278
33366
|
while (true) {
|
|
@@ -33280,15 +33368,12 @@ var WABTransport = class {
|
|
|
33280
33368
|
if (done) break;
|
|
33281
33369
|
if (value == null) continue;
|
|
33282
33370
|
total += value.byteLength;
|
|
33283
|
-
if (total > this.
|
|
33284
|
-
await this.
|
|
33285
|
-
throw this.
|
|
33371
|
+
if (total > this.responseLimit) {
|
|
33372
|
+
await this.stopReader(reader);
|
|
33373
|
+
throw this.sizeError(response, responseContext);
|
|
33286
33374
|
}
|
|
33287
33375
|
chunks.push(value);
|
|
33288
33376
|
}
|
|
33289
|
-
return this.decodeChunks(chunks, total);
|
|
33290
|
-
}
|
|
33291
|
-
decodeChunks(chunks, total) {
|
|
33292
33377
|
const bytes = new Uint8Array(total);
|
|
33293
33378
|
let offset = 0;
|
|
33294
33379
|
for (const chunk of chunks) {
|
|
@@ -33297,35 +33382,35 @@ var WABTransport = class {
|
|
|
33297
33382
|
}
|
|
33298
33383
|
return new TextDecoder().decode(bytes);
|
|
33299
33384
|
}
|
|
33300
|
-
|
|
33301
|
-
return new WABClientError("WAB_RESPONSE_TOO_LARGE", "WAB response
|
|
33385
|
+
sizeError(response, responseContext) {
|
|
33386
|
+
return new WABClientError("WAB_RESPONSE_TOO_LARGE", "WAB response exceeds its size limit.", false, response.status, responseContext);
|
|
33302
33387
|
}
|
|
33303
|
-
async
|
|
33388
|
+
async stopBody(response) {
|
|
33304
33389
|
try {
|
|
33305
33390
|
await response.body?.cancel();
|
|
33306
33391
|
} catch {}
|
|
33307
33392
|
}
|
|
33308
|
-
async
|
|
33393
|
+
async stopReader(reader) {
|
|
33309
33394
|
try {
|
|
33310
33395
|
await reader.cancel();
|
|
33311
33396
|
} catch {}
|
|
33312
33397
|
}
|
|
33313
|
-
|
|
33398
|
+
report(metadata, error) {
|
|
33314
33399
|
this.telemetry.capture({
|
|
33315
|
-
name:
|
|
33316
|
-
component:
|
|
33400
|
+
name: `${WAB_REQUEST_EVENT}failed`,
|
|
33401
|
+
component: WAB_COMPONENT,
|
|
33317
33402
|
severity: error.retryable ? "warn" : "error",
|
|
33318
|
-
correlationId,
|
|
33403
|
+
correlationId: metadata.correlationId,
|
|
33319
33404
|
attributes: {
|
|
33320
|
-
operation,
|
|
33321
|
-
method,
|
|
33322
|
-
route: path,
|
|
33405
|
+
operation: metadata.operation,
|
|
33406
|
+
method: metadata.method,
|
|
33407
|
+
route: metadata.path,
|
|
33323
33408
|
serverOrigin: this.serverOrigin,
|
|
33324
33409
|
retryable: error.retryable,
|
|
33325
33410
|
...error.status !== void 0 ? { status: error.status } : {},
|
|
33326
33411
|
...error.endpointMarkerPresent !== void 0 ? { endpointMarkerPresent: error.endpointMarkerPresent } : {},
|
|
33327
33412
|
...error.responseCorrelationMatched !== void 0 ? { responseCorrelationMatched: error.responseCorrelationMatched } : {},
|
|
33328
|
-
durationMs: Date.now() - startedAt
|
|
33413
|
+
durationMs: Date.now() - metadata.startedAt
|
|
33329
33414
|
},
|
|
33330
33415
|
error
|
|
33331
33416
|
});
|
|
@@ -33434,8 +33519,8 @@ var WABClient = class {
|
|
|
33434
33519
|
constructor(serverUrl, options = {}) {
|
|
33435
33520
|
this.transport = new WABTransport(serverUrl, options);
|
|
33436
33521
|
}
|
|
33437
|
-
|
|
33438
|
-
return
|
|
33522
|
+
getInfo() {
|
|
33523
|
+
return this.transport.request("/info", {
|
|
33439
33524
|
method: "GET",
|
|
33440
33525
|
operation: "get-info"
|
|
33441
33526
|
});
|
|
@@ -33445,15 +33530,15 @@ var WABClient = class {
|
|
|
33445
33530
|
}
|
|
33446
33531
|
async startAuthMethod(authMethod, presentationKey, payload, correlationId) {
|
|
33447
33532
|
assertHexIdentifier(presentationKey, "presentationKey");
|
|
33448
|
-
return
|
|
33533
|
+
return authMethod.startAuth(this.transport.serverUrl, presentationKey, payload, this.transport, correlationId);
|
|
33449
33534
|
}
|
|
33450
33535
|
async completeAuthMethod(authMethod, presentationKey, payload, correlationId) {
|
|
33451
33536
|
assertHexIdentifier(presentationKey, "presentationKey");
|
|
33452
|
-
return
|
|
33537
|
+
return authMethod.completeAuth(this.transport.serverUrl, presentationKey, payload, this.transport, correlationId);
|
|
33453
33538
|
}
|
|
33454
33539
|
async listLinkedMethods(presentationKey) {
|
|
33455
33540
|
assertHexIdentifier(presentationKey, "presentationKey");
|
|
33456
|
-
return
|
|
33541
|
+
return this.transport.request("/user/linkedMethods", {
|
|
33457
33542
|
operation: "list-linked-methods",
|
|
33458
33543
|
body: { presentationKey }
|
|
33459
33544
|
});
|
|
@@ -33461,7 +33546,7 @@ var WABClient = class {
|
|
|
33461
33546
|
async unlinkMethod(presentationKey, authMethodId) {
|
|
33462
33547
|
assertHexIdentifier(presentationKey, "presentationKey");
|
|
33463
33548
|
if (!Number.isSafeInteger(authMethodId) || authMethodId <= 0) throw new TypeError("authMethodId must be a positive safe integer.");
|
|
33464
|
-
return
|
|
33549
|
+
return this.transport.request("/user/unlinkMethod", {
|
|
33465
33550
|
operation: "unlink-method",
|
|
33466
33551
|
body: {
|
|
33467
33552
|
presentationKey,
|
|
@@ -33471,14 +33556,14 @@ var WABClient = class {
|
|
|
33471
33556
|
}
|
|
33472
33557
|
async requestFaucet(presentationKey) {
|
|
33473
33558
|
assertHexIdentifier(presentationKey, "presentationKey");
|
|
33474
|
-
return
|
|
33559
|
+
return this.transport.request("/faucet/request", {
|
|
33475
33560
|
operation: "request-faucet",
|
|
33476
33561
|
body: { presentationKey }
|
|
33477
33562
|
});
|
|
33478
33563
|
}
|
|
33479
33564
|
async deleteUser(presentationKey) {
|
|
33480
33565
|
assertHexIdentifier(presentationKey, "presentationKey");
|
|
33481
|
-
return
|
|
33566
|
+
return this.transport.request("/user/delete", {
|
|
33482
33567
|
operation: "delete-user",
|
|
33483
33568
|
body: { presentationKey }
|
|
33484
33569
|
});
|
|
@@ -33487,7 +33572,7 @@ var WABClient = class {
|
|
|
33487
33572
|
assertMethodType(methodType);
|
|
33488
33573
|
assertHexIdentifier(userIdHash, "userIdHash");
|
|
33489
33574
|
const normalizedPayload = normalizeAuthPayload(methodType, payload);
|
|
33490
|
-
return
|
|
33575
|
+
return this.transport.request("/auth/start", {
|
|
33491
33576
|
operation: "start-share-auth",
|
|
33492
33577
|
body: {
|
|
33493
33578
|
methodType,
|
|
@@ -33500,7 +33585,7 @@ var WABClient = class {
|
|
|
33500
33585
|
assertMethodType(methodType);
|
|
33501
33586
|
assertHexIdentifier(userIdHash, "userIdHash");
|
|
33502
33587
|
const normalizedPayload = normalizeAuthPayload(methodType, payload);
|
|
33503
|
-
return
|
|
33588
|
+
return this.transport.request("/share/store", {
|
|
33504
33589
|
operation: "store-share",
|
|
33505
33590
|
body: {
|
|
33506
33591
|
methodType,
|
|
@@ -33514,7 +33599,7 @@ var WABClient = class {
|
|
|
33514
33599
|
assertMethodType(methodType);
|
|
33515
33600
|
assertHexIdentifier(userIdHash, "userIdHash");
|
|
33516
33601
|
const normalizedPayload = normalizeAuthPayload(methodType, payload);
|
|
33517
|
-
return
|
|
33602
|
+
return this.transport.request("/share/retrieve", {
|
|
33518
33603
|
operation: "retrieve-share",
|
|
33519
33604
|
body: {
|
|
33520
33605
|
methodType,
|
|
@@ -33527,7 +33612,7 @@ var WABClient = class {
|
|
|
33527
33612
|
assertMethodType(methodType);
|
|
33528
33613
|
assertHexIdentifier(userIdHash, "userIdHash");
|
|
33529
33614
|
const normalizedPayload = normalizeAuthPayload(methodType, payload);
|
|
33530
|
-
return
|
|
33615
|
+
return this.transport.request("/share/update", {
|
|
33531
33616
|
operation: "update-share",
|
|
33532
33617
|
body: {
|
|
33533
33618
|
methodType,
|
|
@@ -33541,7 +33626,7 @@ var WABClient = class {
|
|
|
33541
33626
|
assertMethodType(methodType);
|
|
33542
33627
|
assertHexIdentifier(userIdHash, "userIdHash");
|
|
33543
33628
|
const normalizedPayload = normalizeAuthPayload(methodType, payload);
|
|
33544
|
-
return
|
|
33629
|
+
return this.transport.request("/share/delete", {
|
|
33545
33630
|
operation: "delete-share-user",
|
|
33546
33631
|
body: {
|
|
33547
33632
|
methodType,
|
|
@@ -33555,9 +33640,13 @@ var WABClient = class {
|
|
|
33555
33640
|
//#region ../src/WalletAuthenticationManager.ts
|
|
33556
33641
|
const DEFAULT_AUTH_SESSION_TTL_MS = 600 * 1e3;
|
|
33557
33642
|
const MAX_AUTH_SESSION_TTL_MS = 3600 * 1e3;
|
|
33643
|
+
const AUTH_COMPONENT = "wallet-toolbox.authentication-manager";
|
|
33644
|
+
const AUTH_EVENT = "wallet-toolbox.authentication.";
|
|
33645
|
+
const EXISTING_USER = "existing-user";
|
|
33646
|
+
const NEW_USER = "new-user";
|
|
33558
33647
|
var WABAccountContinuityError = class extends Error {
|
|
33559
33648
|
code = "WERR_WAB_ACCOUNT_CONTINUITY";
|
|
33560
|
-
constructor(message = "WAB and UMP
|
|
33649
|
+
constructor(message = "WAB and UMP accounts disagree; retry or recover.") {
|
|
33561
33650
|
super(message);
|
|
33562
33651
|
this.name = "WABAccountContinuityError";
|
|
33563
33652
|
}
|
|
@@ -33572,6 +33661,7 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
|
|
|
33572
33661
|
wabClient;
|
|
33573
33662
|
authMethod;
|
|
33574
33663
|
authSession;
|
|
33664
|
+
phoneChangeSession;
|
|
33575
33665
|
authSessionTtlMs;
|
|
33576
33666
|
constructor(...[adminOriginator, walletBuilder, interactor, recoveryKeySaver, passwordRetriever, wabClient, authMethod, stateSnapshot, options = {}]) {
|
|
33577
33667
|
super(adminOriginator, walletBuilder, interactor, recoveryKeySaver, passwordRetriever, async (presentationKey, wallet, adminOriginator) => {
|
|
@@ -33594,7 +33684,7 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
|
|
|
33594
33684
|
description: "Fund wallet",
|
|
33595
33685
|
options: { acceptDelayedBroadcast: false }
|
|
33596
33686
|
}, adminOriginator);
|
|
33597
|
-
if (faucetRedeemTXCreationResult.signableTransaction == null) throw new Error("Faucet redemption
|
|
33687
|
+
if (faucetRedeemTXCreationResult.signableTransaction == null) throw new Error("Faucet redemption was not signable.");
|
|
33598
33688
|
const faucetRedeemTX = _bsv_sdk.Transaction.fromAtomicBEEF(faucetRedeemTXCreationResult.signableTransaction.tx);
|
|
33599
33689
|
const faucetRedemptionPuzzle = new _bsv_sdk.RPuzzle();
|
|
33600
33690
|
const randomRedemptionPrivateKey = _bsv_sdk.PrivateKey.fromRandom();
|
|
@@ -33627,7 +33717,7 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
|
|
|
33627
33717
|
* using the chosen AuthMethodInteractor.
|
|
33628
33718
|
*/
|
|
33629
33719
|
async startAuth(payload) {
|
|
33630
|
-
if (this.authMethod == null) throw new Error("No
|
|
33720
|
+
if (this.authMethod == null) throw new Error("No WAB authentication method selected.");
|
|
33631
33721
|
const authMethod = this.authMethod;
|
|
33632
33722
|
if (this.authenticated) throw new Error("User is already authenticated");
|
|
33633
33723
|
this.cancelAuth();
|
|
@@ -33640,8 +33730,8 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
|
|
|
33640
33730
|
...correlationId !== void 0 ? { correlationId } : {}
|
|
33641
33731
|
};
|
|
33642
33732
|
this.telemetry.capture({
|
|
33643
|
-
name:
|
|
33644
|
-
component:
|
|
33733
|
+
name: `${AUTH_EVENT}wab-start.started`,
|
|
33734
|
+
component: AUTH_COMPONENT,
|
|
33645
33735
|
severity: "debug",
|
|
33646
33736
|
correlationId,
|
|
33647
33737
|
attributes: { methodType: authMethod.methodType }
|
|
@@ -33653,8 +33743,8 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
|
|
|
33653
33743
|
throw new Error(message);
|
|
33654
33744
|
}
|
|
33655
33745
|
this.telemetry.capture({
|
|
33656
|
-
name:
|
|
33657
|
-
component:
|
|
33746
|
+
name: `${AUTH_EVENT}wab-start.completed`,
|
|
33747
|
+
component: AUTH_COMPONENT,
|
|
33658
33748
|
severity: "info",
|
|
33659
33749
|
correlationId,
|
|
33660
33750
|
attributes: { methodType: authMethod.methodType }
|
|
@@ -33662,8 +33752,8 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
|
|
|
33662
33752
|
} catch (error) {
|
|
33663
33753
|
this.cancelAuth();
|
|
33664
33754
|
this.telemetry.capture({
|
|
33665
|
-
name:
|
|
33666
|
-
component:
|
|
33755
|
+
name: `${AUTH_EVENT}wab-start.failed`,
|
|
33756
|
+
component: AUTH_COMPONENT,
|
|
33667
33757
|
severity: "warn",
|
|
33668
33758
|
correlationId,
|
|
33669
33759
|
attributes: { methodType: authMethod.methodType },
|
|
@@ -33676,22 +33766,22 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
|
|
|
33676
33766
|
* Completes the WAB-based flow, retrieving the final presentationKey from WAB if successful.
|
|
33677
33767
|
*/
|
|
33678
33768
|
async completeAuth(payload) {
|
|
33679
|
-
if (this.authMethod == null || this.authSession == null) throw new Error("
|
|
33769
|
+
if (this.authMethod == null || this.authSession == null) throw new Error("Start WAB authentication first.");
|
|
33680
33770
|
const authMethod = this.authMethod;
|
|
33681
33771
|
if (this.authSession.methodType !== authMethod.methodType) {
|
|
33682
33772
|
this.cancelAuth();
|
|
33683
|
-
throw new Error("
|
|
33773
|
+
throw new Error("WAB authentication method changed; restart.");
|
|
33684
33774
|
}
|
|
33685
33775
|
if (Date.now() >= this.authSession.expiresAt) {
|
|
33686
33776
|
this.cancelAuth();
|
|
33687
|
-
throw new Error("
|
|
33777
|
+
throw new Error("WAB authentication expired; restart.");
|
|
33688
33778
|
}
|
|
33689
33779
|
const session = this.authSession;
|
|
33690
33780
|
const result = await this.wabClient.completeAuthMethod(authMethod, session.presentationKey, payload, session.correlationId);
|
|
33691
33781
|
if (result.success !== true || result.presentationKey == null || result.presentationKey.length === 0) {
|
|
33692
33782
|
this.telemetry.capture({
|
|
33693
|
-
name:
|
|
33694
|
-
component:
|
|
33783
|
+
name: `${AUTH_EVENT}wab-complete.rejected`,
|
|
33784
|
+
component: AUTH_COMPONENT,
|
|
33695
33785
|
severity: "warn",
|
|
33696
33786
|
correlationId: session.correlationId,
|
|
33697
33787
|
attributes: { methodType: session.methodType }
|
|
@@ -33706,11 +33796,11 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
|
|
|
33706
33796
|
this.cancelAuth();
|
|
33707
33797
|
const wabAccountStatus = this.inferAccountStatus(result, session.presentationKey);
|
|
33708
33798
|
try {
|
|
33709
|
-
await this.
|
|
33799
|
+
await this.provideWABPresentationKey(result, wabAccountStatus);
|
|
33710
33800
|
} catch (error) {
|
|
33711
33801
|
this.telemetry.capture({
|
|
33712
|
-
name:
|
|
33713
|
-
component:
|
|
33802
|
+
name: `${AUTH_EVENT}ump-continuity.failed`,
|
|
33803
|
+
component: AUTH_COMPONENT,
|
|
33714
33804
|
severity: "warn",
|
|
33715
33805
|
correlationId: session.correlationId,
|
|
33716
33806
|
attributes: {
|
|
@@ -33721,18 +33811,18 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
|
|
|
33721
33811
|
});
|
|
33722
33812
|
throw error;
|
|
33723
33813
|
}
|
|
33724
|
-
if (wabAccountStatus ===
|
|
33814
|
+
if (wabAccountStatus === EXISTING_USER && this.authenticationFlow !== EXISTING_USER) {
|
|
33725
33815
|
super.destroy();
|
|
33726
33816
|
const error = new WABAccountContinuityError();
|
|
33727
33817
|
this.telemetry.capture({
|
|
33728
|
-
name:
|
|
33729
|
-
component:
|
|
33818
|
+
name: `${AUTH_EVENT}account-continuity.mismatch`,
|
|
33819
|
+
component: AUTH_COMPONENT,
|
|
33730
33820
|
severity: "error",
|
|
33731
33821
|
correlationId: session.correlationId,
|
|
33732
33822
|
attributes: {
|
|
33733
33823
|
methodType: session.methodType,
|
|
33734
33824
|
wabAccountStatus,
|
|
33735
|
-
umpAccountStatus:
|
|
33825
|
+
umpAccountStatus: NEW_USER
|
|
33736
33826
|
},
|
|
33737
33827
|
error
|
|
33738
33828
|
});
|
|
@@ -33740,8 +33830,8 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
|
|
|
33740
33830
|
}
|
|
33741
33831
|
const continuity = wabAccountStatus === this.authenticationFlow ? "matched" : "ump-existing";
|
|
33742
33832
|
this.telemetry.capture({
|
|
33743
|
-
name:
|
|
33744
|
-
component:
|
|
33833
|
+
name: `${AUTH_EVENT}completed`,
|
|
33834
|
+
component: AUTH_COMPONENT,
|
|
33745
33835
|
severity: continuity === "matched" ? "info" : "warn",
|
|
33746
33836
|
correlationId: session.correlationId,
|
|
33747
33837
|
attributes: {
|
|
@@ -33755,23 +33845,131 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
|
|
|
33755
33845
|
cancelAuth() {
|
|
33756
33846
|
this.authSession = void 0;
|
|
33757
33847
|
}
|
|
33848
|
+
readPendingPhoneChange(result) {
|
|
33849
|
+
const presentationKey = result.pendingPresentationKey;
|
|
33850
|
+
const changeId = result.pendingPhoneChangeId;
|
|
33851
|
+
if (presentationKey === void 0 && changeId === void 0) return void 0;
|
|
33852
|
+
if (!/^[0-9a-fA-F]{64}$/.test(presentationKey ?? "") || !Number.isSafeInteger(changeId) || changeId <= 0) throw new WABAccountContinuityError("WAB returned invalid pending phone-change data.");
|
|
33853
|
+
return {
|
|
33854
|
+
presentationKey,
|
|
33855
|
+
changeId
|
|
33856
|
+
};
|
|
33857
|
+
}
|
|
33858
|
+
async provideWABPresentationKey(result, wabAccountStatus) {
|
|
33859
|
+
const umpTokenOutpoint = typeof result.umpTokenOutpoint === "string" ? result.umpTokenOutpoint : void 0;
|
|
33860
|
+
const lookupOptions = umpTokenOutpoint == null ? void 0 : { pinnedOutpoint: umpTokenOutpoint };
|
|
33861
|
+
const pending = this.readPendingPhoneChange(result);
|
|
33862
|
+
let usePending = false;
|
|
33863
|
+
try {
|
|
33864
|
+
await this.providePresentationKey(_bsv_sdk.Utils.toArray(result.presentationKey, "hex"), lookupOptions);
|
|
33865
|
+
} catch (error) {
|
|
33866
|
+
if (pending == null) throw error;
|
|
33867
|
+
usePending = true;
|
|
33868
|
+
}
|
|
33869
|
+
if (pending != null && (usePending || wabAccountStatus === EXISTING_USER && this.authenticationFlow !== EXISTING_USER)) {
|
|
33870
|
+
await this.providePresentationKey(_bsv_sdk.Utils.toArray(pending.presentationKey, "hex"), lookupOptions);
|
|
33871
|
+
if (this.authenticationFlow === EXISTING_USER) await this.finalizePendingPhoneChange(result.presentationKey, pending);
|
|
33872
|
+
}
|
|
33873
|
+
}
|
|
33874
|
+
async finalizePendingPhoneChange(currentPresentationKey, pending) {
|
|
33875
|
+
const finalized = await this.phoneChange("finalize", {
|
|
33876
|
+
changeId: pending.changeId,
|
|
33877
|
+
presentationKey: currentPresentationKey,
|
|
33878
|
+
newPresentationKey: pending.presentationKey
|
|
33879
|
+
});
|
|
33880
|
+
if (finalized.success !== true || finalized.changeId !== pending.changeId) throw new WABAccountContinuityError(finalized.message || "WAB could not finalize the pending phone change.");
|
|
33881
|
+
}
|
|
33882
|
+
/**
|
|
33883
|
+
* Starts OTP verification for a replacement phone number. The same number
|
|
33884
|
+
* is valid and intentionally produces a fresh presentation key/hash.
|
|
33885
|
+
*/
|
|
33886
|
+
async startPhoneNumberChange(phoneNumber) {
|
|
33887
|
+
if (!this.authenticated) throw new Error("Not authenticated");
|
|
33888
|
+
const normalizedPhone = phoneNumber.trim();
|
|
33889
|
+
const currentPresentationKey = _bsv_sdk.Utils.toHex(await this.getFactor("presentationKey"));
|
|
33890
|
+
const response = await this.phoneChange("start", {
|
|
33891
|
+
presentationKey: currentPresentationKey,
|
|
33892
|
+
phoneNumber: normalizedPhone
|
|
33893
|
+
});
|
|
33894
|
+
if (response.success !== true) throw new Error(response.message || "Phone change failed");
|
|
33895
|
+
this.phoneChangeSession = {
|
|
33896
|
+
phoneNumber: normalizedPhone,
|
|
33897
|
+
presentationKey: currentPresentationKey
|
|
33898
|
+
};
|
|
33899
|
+
}
|
|
33900
|
+
/**
|
|
33901
|
+
* Completes phone verification and stages the WAB association before
|
|
33902
|
+
* publishing the UMP key rotation. WAB retains both the current and pending
|
|
33903
|
+
* presentation keys until finalization, so either side of an interrupted
|
|
33904
|
+
* transition remains recoverable on the next verified login.
|
|
33905
|
+
*/
|
|
33906
|
+
async completePhoneNumberChange(otp) {
|
|
33907
|
+
const session = this.phoneChangeSession;
|
|
33908
|
+
if (session == null) throw new Error("No phone change");
|
|
33909
|
+
if (session.changeToken == null) {
|
|
33910
|
+
const authorization = await this.phoneChange("complete", {
|
|
33911
|
+
presentationKey: session.presentationKey,
|
|
33912
|
+
phoneNumber: session.phoneNumber,
|
|
33913
|
+
otp: otp.trim()
|
|
33914
|
+
});
|
|
33915
|
+
if (authorization.success !== true) throw new Error(authorization.message || "Phone change failed");
|
|
33916
|
+
if (/^[0-9a-fA-F]{64}$/.test(authorization.pendingPresentationKey ?? "") && Number.isSafeInteger(authorization.pendingPhoneChangeId) && authorization.pendingPhoneChangeId > 0) {
|
|
33917
|
+
session.newKey = _bsv_sdk.Utils.toArray(authorization.pendingPresentationKey, "hex");
|
|
33918
|
+
session.changeId = authorization.pendingPhoneChangeId;
|
|
33919
|
+
} else if (typeof authorization.changeToken === "string" && authorization.changeToken.length > 0) session.changeToken = authorization.changeToken;
|
|
33920
|
+
else throw new Error(authorization.message || "Phone change failed");
|
|
33921
|
+
}
|
|
33922
|
+
session.newKey ??= (0, _bsv_sdk.Random)(32);
|
|
33923
|
+
if (session.changeId == null) {
|
|
33924
|
+
const committed = await this.phoneChange("commit", {
|
|
33925
|
+
changeToken: session.changeToken,
|
|
33926
|
+
presentationKey: session.presentationKey,
|
|
33927
|
+
newPresentationKey: _bsv_sdk.Utils.toHex(session.newKey)
|
|
33928
|
+
});
|
|
33929
|
+
if (committed.success !== true || !Number.isSafeInteger(committed.changeId) || committed.changeId <= 0) throw new Error(committed.message || "Phone change failed");
|
|
33930
|
+
session.changeId = committed.changeId;
|
|
33931
|
+
}
|
|
33932
|
+
const changeId = session.changeId;
|
|
33933
|
+
if (session.umpUpdated !== true) {
|
|
33934
|
+
await this.changePresentationKey(session.newKey);
|
|
33935
|
+
session.umpUpdated = true;
|
|
33936
|
+
}
|
|
33937
|
+
const finalized = await this.phoneChange("finalize", {
|
|
33938
|
+
changeId,
|
|
33939
|
+
presentationKey: session.presentationKey,
|
|
33940
|
+
newPresentationKey: _bsv_sdk.Utils.toHex(session.newKey)
|
|
33941
|
+
});
|
|
33942
|
+
if (finalized.success !== true || finalized.changeId !== changeId) throw new Error(finalized.message || "Phone change failed");
|
|
33943
|
+
this.phoneChangeSession = void 0;
|
|
33944
|
+
return { changeId };
|
|
33945
|
+
}
|
|
33946
|
+
cancelPhoneNumberChange() {
|
|
33947
|
+
this.phoneChangeSession = void 0;
|
|
33948
|
+
}
|
|
33758
33949
|
destroy() {
|
|
33759
33950
|
this.cancelAuth();
|
|
33951
|
+
this.cancelPhoneNumberChange();
|
|
33760
33952
|
super.destroy();
|
|
33761
33953
|
}
|
|
33954
|
+
phoneChange(phase, body) {
|
|
33955
|
+
return this.wabClient.transport.request(`/auth/phone-change/${phase}`, {
|
|
33956
|
+
operation: "phone-change",
|
|
33957
|
+
body
|
|
33958
|
+
});
|
|
33959
|
+
}
|
|
33762
33960
|
inferAccountStatus(result, temporaryPresentationKey) {
|
|
33763
33961
|
if (result.presentationKey == null) throw new WABAccountContinuityError("WAB did not return a presentation key.");
|
|
33764
33962
|
const keyMatchesTemporary = this.constantTimeHexEqual(result.presentationKey, temporaryPresentationKey);
|
|
33765
33963
|
const rawAccountStatus = result.accountStatus;
|
|
33766
|
-
if (rawAccountStatus !== void 0 && rawAccountStatus !==
|
|
33964
|
+
if (rawAccountStatus !== void 0 && rawAccountStatus !== NEW_USER && rawAccountStatus !== EXISTING_USER) throw new WABAccountContinuityError("WAB returned an invalid account status.");
|
|
33767
33965
|
const rawExistingUser = result.existingUser;
|
|
33768
|
-
if (rawExistingUser !== void 0 && typeof rawExistingUser !== "boolean") throw new WABAccountContinuityError("WAB returned
|
|
33769
|
-
if (rawAccountStatus !== void 0 && rawExistingUser !== void 0 && rawAccountStatus ===
|
|
33966
|
+
if (rawExistingUser !== void 0 && typeof rawExistingUser !== "boolean") throw new WABAccountContinuityError("WAB returned invalid existing-user data.");
|
|
33967
|
+
if (rawAccountStatus !== void 0 && rawExistingUser !== void 0 && rawAccountStatus === EXISTING_USER !== rawExistingUser) throw new WABAccountContinuityError("WAB returned conflicting account status.");
|
|
33770
33968
|
let compatibilityStatus;
|
|
33771
|
-
if (typeof rawExistingUser === "boolean") compatibilityStatus = rawExistingUser ?
|
|
33969
|
+
if (typeof rawExistingUser === "boolean") compatibilityStatus = rawExistingUser ? EXISTING_USER : NEW_USER;
|
|
33772
33970
|
const explicitStatus = rawAccountStatus ?? compatibilityStatus;
|
|
33773
|
-
if (explicitStatus ===
|
|
33774
|
-
return explicitStatus ?? (keyMatchesTemporary ?
|
|
33971
|
+
if (explicitStatus === NEW_USER && !keyMatchesTemporary || explicitStatus === EXISTING_USER && keyMatchesTemporary) throw new WABAccountContinuityError("WAB returned conflicting account status.");
|
|
33972
|
+
return explicitStatus ?? (keyMatchesTemporary ? NEW_USER : EXISTING_USER);
|
|
33775
33973
|
}
|
|
33776
33974
|
constantTimeHexEqual(left, right) {
|
|
33777
33975
|
if (left.length !== right.length) return false;
|