@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.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
-
import { AuthFetch, BEEF_V1, BEEF_V2, Beef, BeefParty, BigNumber, BlockHeadersService, CachedKeyDeriver, Certificate, Curve, Hash, LocalKVStore, LockingScript, LookupResolver, MasterCertificate, MerklePath, P2PKH, PrivateKey, ProtoWallet, PublicKey, PushDrop, RPuzzle, Random, SHIPBroadcaster, Script, ScriptEvaluationError, Signature, Spend, SymmetricKey, Telemetry, Transaction, TransactionSignature, Utils, Validation, Validation as Validation$1, VerifiableCertificate, createNonce, defaultHttpClient, verifyNonce } from "@bsv/sdk";
|
|
2
|
+
import { AuthFetch, BEEF_V1, BEEF_V2, Beef, BeefParty, BeefTx, BigNumber, BlockHeadersService, CachedKeyDeriver, Certificate, Curve, Hash, LocalKVStore, LockingScript, LookupResolver, MasterCertificate, MerklePath, P2PKH, PrivateKey, ProtoWallet, PublicKey, PushDrop, RPuzzle, Random, SHIPBroadcaster, Script, ScriptEvaluationError, Signature, Spend, SymmetricKey, Telemetry, Transaction, TransactionSignature, Utils, Validation, Validation as Validation$1, VerifiableCertificate, createNonce, defaultHttpClient, verifyNonce } from "@bsv/sdk";
|
|
3
3
|
import { deleteDB, openDB } from "idb";
|
|
4
4
|
import { AESGCM, AESGCMDecrypt } from "@bsv/sdk/primitives/AESGCM";
|
|
5
5
|
import argon2Api from "hash-wasm/dist/argon2.umd.min.js";
|
|
@@ -4046,7 +4046,7 @@ var EntitySyncState = class EntitySyncState extends EntityBase {
|
|
|
4046
4046
|
log += formatSyncSection("OUTPUTS", c.outputs, (r) => `${r.outputId} ${r.txid}.${r.vout} ${r.transactionId} ${r.spendable ? "spendable" : ""} sats:${r.satoshis}`);
|
|
4047
4047
|
return log;
|
|
4048
4048
|
}
|
|
4049
|
-
async processSyncChunk(writer, args, chunk) {
|
|
4049
|
+
async processSyncChunk(writer, args, chunk, trx) {
|
|
4050
4050
|
const mes = [
|
|
4051
4051
|
new MergeEntity(chunk.provenTxs, EntityProvenTx.mergeFind, this.syncMap.provenTx),
|
|
4052
4052
|
new MergeEntity(chunk.outputBaskets, EntityOutputBasket.mergeFind, this.syncMap.outputBasket),
|
|
@@ -4067,16 +4067,16 @@ var EntitySyncState = class EntitySyncState extends EntityBase {
|
|
|
4067
4067
|
let done = true;
|
|
4068
4068
|
if (chunk.user != null) {
|
|
4069
4069
|
const ei = chunk.user;
|
|
4070
|
-
const { found, eo } = await EntityUser.mergeFind(writer, this.userId, ei);
|
|
4070
|
+
const { found, eo } = await EntityUser.mergeFind(writer, this.userId, ei, trx);
|
|
4071
4071
|
if (found) {
|
|
4072
|
-
if (await eo.mergeExisting(writer, args.since, ei)) {
|
|
4072
|
+
if (await eo.mergeExisting(writer, args.since, ei, void 0, trx)) {
|
|
4073
4073
|
maxUpdated_at = maxDate(maxUpdated_at, ei.updated_at);
|
|
4074
4074
|
updates++;
|
|
4075
4075
|
}
|
|
4076
4076
|
}
|
|
4077
4077
|
}
|
|
4078
4078
|
for (const me of mes) {
|
|
4079
|
-
const r = await me.merge(args.since, writer, this.userId, this.syncMap);
|
|
4079
|
+
const r = await me.merge(args.since, writer, this.userId, this.syncMap, trx);
|
|
4080
4080
|
me.esm.count += me.stateArray?.length || 0;
|
|
4081
4081
|
updates += r.updates;
|
|
4082
4082
|
inserts += r.inserts;
|
|
@@ -4087,7 +4087,7 @@ var EntitySyncState = class EntitySyncState extends EntityBase {
|
|
|
4087
4087
|
this.when = maxUpdated_at;
|
|
4088
4088
|
for (const me of mes) me.esm.count = 0;
|
|
4089
4089
|
}
|
|
4090
|
-
await this.updateStorage(writer, false);
|
|
4090
|
+
await this.updateStorage(writer, false, trx);
|
|
4091
4091
|
return {
|
|
4092
4092
|
done,
|
|
4093
4093
|
maxUpdated_at,
|
|
@@ -7810,6 +7810,23 @@ function mergePriorOptions(caVargs, saArgs) {
|
|
|
7810
7810
|
return Validation.validateSignActionArgs(saArgs);
|
|
7811
7811
|
}
|
|
7812
7812
|
//#endregion
|
|
7813
|
+
//#region ../src/utility/canonicalizeAtomicBeef.ts
|
|
7814
|
+
/**
|
|
7815
|
+
* Restricts an AtomicBEEF envelope to the transaction named by its BRC-95
|
|
7816
|
+
* prefix and that transaction's recursive dependency closure.
|
|
7817
|
+
*
|
|
7818
|
+
* Older senders could serialize unrelated, otherwise valid BEEF branches into
|
|
7819
|
+
* an AtomicBEEF envelope. Those branches are not part of the payment proof and
|
|
7820
|
+
* must not influence internalization. Proof and transaction validation still
|
|
7821
|
+
* run against the returned closure at each wallet trust boundary.
|
|
7822
|
+
*/
|
|
7823
|
+
function canonicalizeAtomicBeef(bytes) {
|
|
7824
|
+
const received = bytes instanceof Uint8Array ? Beef.fromBinaryView(bytes) : Beef.fromBinary(bytes);
|
|
7825
|
+
const txid = received.atomicTxid;
|
|
7826
|
+
if (txid == null || received.findTxid(txid) == null || received.isAtomic(txid)) return received;
|
|
7827
|
+
return Beef.fromBinary(received.toBinaryAtomic(txid));
|
|
7828
|
+
}
|
|
7829
|
+
//#endregion
|
|
7813
7830
|
//#region ../src/signer/methods/internalizeAction.ts
|
|
7814
7831
|
/**
|
|
7815
7832
|
* Internalize Action allows a wallet to take ownership of outputs in a pre-existing transaction.
|
|
@@ -7851,7 +7868,7 @@ function mergePriorOptions(caVargs, saArgs) {
|
|
|
7851
7868
|
*/
|
|
7852
7869
|
async function internalizeAction$1(wallet, auth, args) {
|
|
7853
7870
|
const vargs = Validation.validateInternalizeActionArgs(args);
|
|
7854
|
-
const { tx } = await validateAtomicBeef();
|
|
7871
|
+
const { ab, tx, txid } = await validateAtomicBeef();
|
|
7855
7872
|
const brc29ProtocolID = [2, "3241645161d8"];
|
|
7856
7873
|
for (const o of vargs.outputs) {
|
|
7857
7874
|
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}`);
|
|
@@ -7865,7 +7882,10 @@ async function internalizeAction$1(wallet, auth, args) {
|
|
|
7865
7882
|
default: throw new WERR_INTERNAL(`unexpected protocol ${o.protocol}`);
|
|
7866
7883
|
}
|
|
7867
7884
|
}
|
|
7868
|
-
return await wallet.storage.internalizeAction(
|
|
7885
|
+
return await wallet.storage.internalizeAction({
|
|
7886
|
+
...args,
|
|
7887
|
+
tx: ab.toBinaryAtomic(txid)
|
|
7888
|
+
});
|
|
7869
7889
|
function setupWalletPaymentForOutput(o, _dargs) {
|
|
7870
7890
|
const p = o.paymentRemittance;
|
|
7871
7891
|
const output = tx.outputs[o.outputIndex];
|
|
@@ -7888,7 +7908,7 @@ async function internalizeAction$1(wallet, auth, args) {
|
|
|
7888
7908
|
* 2. That the proofs are for the same block as recorded in the wallet's configured storage in the event of a reorg.
|
|
7889
7909
|
*/
|
|
7890
7910
|
async function validateAtomicBeef() {
|
|
7891
|
-
const ab =
|
|
7911
|
+
const ab = canonicalizeAtomicBeef(vargs.tx);
|
|
7892
7912
|
if (!await ab.verify(await wallet.getServices().getChainTracker(), false) || !ab.atomicTxid) {
|
|
7893
7913
|
console.log(`internalizeAction beef is invalid: ${ab.toLogString()}`);
|
|
7894
7914
|
throw new WERR_INVALID_PARAMETER("tx", "valid AtomicBEEF");
|
|
@@ -8219,28 +8239,70 @@ function verifyActionBatchManifestDigest(manifest) {
|
|
|
8219
8239
|
//#endregion
|
|
8220
8240
|
//#region ../src/utility/beefForTxids.ts
|
|
8221
8241
|
/**
|
|
8222
|
-
* Return
|
|
8242
|
+
* Return a minimal BEEF when the source contains data outside the requested
|
|
8243
|
+
* transaction dependency closure. Return undefined when no pruning is needed.
|
|
8244
|
+
*
|
|
8245
|
+
* This form lets forwarding clients retain the caller's original bytes in the
|
|
8246
|
+
* common no-op case instead of rebuilding and reserializing an equivalent BEEF.
|
|
8247
|
+
*/
|
|
8248
|
+
function pruneBeefForTxids(source, txids) {
|
|
8249
|
+
const selection = selectTransactions(source, txids);
|
|
8250
|
+
if (selection.transactions.size === source.txs.length && selection.bumpIndexes.size === source.bumps.length) return;
|
|
8251
|
+
return copySelection(source, selection);
|
|
8252
|
+
}
|
|
8253
|
+
/**
|
|
8254
|
+
* Return an independent minimal BEEF needed to prove the requested transactions.
|
|
8223
8255
|
*
|
|
8224
|
-
*
|
|
8225
|
-
*
|
|
8256
|
+
* Transactions remain in source order and are sorted by Beef when serialized.
|
|
8257
|
+
* The source is indexed and walked once, using an explicit stack so a hostile
|
|
8258
|
+
* dependency depth cannot exhaust the JavaScript call stack.
|
|
8226
8259
|
*/
|
|
8227
8260
|
function beefForTxids(source, txids) {
|
|
8228
|
-
|
|
8261
|
+
return copySelection(source, selectTransactions(source, txids));
|
|
8262
|
+
}
|
|
8263
|
+
function selectTransactions(source, txids) {
|
|
8264
|
+
const byTxid = /* @__PURE__ */ new Map();
|
|
8265
|
+
for (const tx of source.txs) byTxid.set(tx.txid, tx);
|
|
8266
|
+
const transactions = /* @__PURE__ */ new Set();
|
|
8267
|
+
const bumpIndexes = /* @__PURE__ */ new Set();
|
|
8229
8268
|
const visited = /* @__PURE__ */ new Set();
|
|
8230
|
-
const
|
|
8231
|
-
|
|
8269
|
+
const stack = [...txids];
|
|
8270
|
+
while (stack.length > 0) {
|
|
8271
|
+
const txid = stack.pop();
|
|
8272
|
+
if (txid == null || visited.has(txid)) continue;
|
|
8232
8273
|
visited.add(txid);
|
|
8233
|
-
const
|
|
8234
|
-
if (
|
|
8235
|
-
|
|
8236
|
-
|
|
8237
|
-
|
|
8238
|
-
|
|
8239
|
-
|
|
8274
|
+
const tx = byTxid.get(txid);
|
|
8275
|
+
if (tx == null) continue;
|
|
8276
|
+
transactions.add(tx);
|
|
8277
|
+
const bumpIndex = tx.bumpIndex;
|
|
8278
|
+
if (bumpIndex != null && Number.isSafeInteger(bumpIndex) && bumpIndex >= 0 && bumpIndex < source.bumps.length) bumpIndexes.add(bumpIndex);
|
|
8279
|
+
for (const inputTxid of tx.inputTxids) if (!visited.has(inputTxid)) stack.push(inputTxid);
|
|
8280
|
+
}
|
|
8281
|
+
return {
|
|
8282
|
+
transactions,
|
|
8283
|
+
bumpIndexes
|
|
8240
8284
|
};
|
|
8241
|
-
|
|
8285
|
+
}
|
|
8286
|
+
function copySelection(source, selection) {
|
|
8287
|
+
const beef = new Beef(source.version);
|
|
8288
|
+
const bumpIndexMap = /* @__PURE__ */ new Map();
|
|
8289
|
+
for (let index = 0; index < source.bumps.length; index++) {
|
|
8290
|
+
if (!selection.bumpIndexes.has(index)) continue;
|
|
8291
|
+
bumpIndexMap.set(index, beef.bumps.length);
|
|
8292
|
+
beef.bumps.push(cloneMerklePath(source.bumps[index]));
|
|
8293
|
+
}
|
|
8294
|
+
for (const sourceTx of source.txs) {
|
|
8295
|
+
if (!selection.transactions.has(sourceTx)) continue;
|
|
8296
|
+
const bumpIndex = sourceTx.bumpIndex == null ? void 0 : bumpIndexMap.get(sourceTx.bumpIndex);
|
|
8297
|
+
const rawTx = sourceTx.rawTxUint8Array;
|
|
8298
|
+
const copy = rawTx == null ? BeefTx.fromTxid(sourceTx.txid, bumpIndex) : new BeefTx(Uint8Array.from(rawTx), bumpIndex, Array.from(sourceTx.inputTxids));
|
|
8299
|
+
beef.txs.push(copy);
|
|
8300
|
+
}
|
|
8242
8301
|
return beef;
|
|
8243
8302
|
}
|
|
8303
|
+
function cloneMerklePath(source) {
|
|
8304
|
+
return new MerklePath(source.blockHeight, source.path.map((level) => level.map((leaf) => ({ ...leaf }))), false, false);
|
|
8305
|
+
}
|
|
8244
8306
|
//#endregion
|
|
8245
8307
|
//#region ../src/storage/methods/offsetKey.ts
|
|
8246
8308
|
function keyOffsetToHashedSecret(pub, keyOffset) {
|
|
@@ -10938,7 +11000,7 @@ function validateRequiredOutputs(storage, userId, vargs) {
|
|
|
10938
11000
|
* @returns {xinputs} extended validated required inputs.
|
|
10939
11001
|
*/
|
|
10940
11002
|
async function validateRequiredInputs(storage, userId, vargs) {
|
|
10941
|
-
|
|
11003
|
+
let beef = new Beef();
|
|
10942
11004
|
if (vargs.inputs.length === 0) return {
|
|
10943
11005
|
storageBeef: beef,
|
|
10944
11006
|
beef,
|
|
@@ -10964,6 +11026,7 @@ async function validateRequiredInputs(storage, userId, vargs) {
|
|
|
10964
11026
|
inputsByTxid[input.outpoint.txid] ||= [];
|
|
10965
11027
|
inputsByTxid[input.outpoint.txid].push(input);
|
|
10966
11028
|
}
|
|
11029
|
+
beef = beefForTxids(beef, Object.keys(inputsByTxid));
|
|
10967
11030
|
const localKnownInputTxids = {};
|
|
10968
11031
|
for (const [txid, txInputs] of Object.entries(inputsByTxid)) localKnownInputTxids[txid] = txInputs.every((input) => {
|
|
10969
11032
|
const output = preloadedOutputsByOutpoint[`${input.outpoint.txid}.${input.outpoint.vout}`];
|
|
@@ -12378,7 +12441,7 @@ var InternalizeActionContext = class {
|
|
|
12378
12441
|
* @returns
|
|
12379
12442
|
*/
|
|
12380
12443
|
async validateAtomicBeef(atomicBeef) {
|
|
12381
|
-
const ab =
|
|
12444
|
+
const ab = canonicalizeAtomicBeef(atomicBeef);
|
|
12382
12445
|
if (!await ab.verify(await this.storage.getServices().getChainTracker(), false) || !ab.atomicTxid) throw new WERR_INVALID_PARAMETER("tx", "valid AtomicBEEF");
|
|
12383
12446
|
const txid = ab.atomicTxid;
|
|
12384
12447
|
const btx = ab.findTxid(txid);
|
|
@@ -15225,11 +15288,19 @@ var StorageProvider = class StorageProvider extends StorageReaderWriter {
|
|
|
15225
15288
|
return await this.updateOutput(output.outputId, { basketId: void 0 });
|
|
15226
15289
|
}
|
|
15227
15290
|
async processSyncChunk(args, chunk) {
|
|
15228
|
-
|
|
15229
|
-
|
|
15230
|
-
|
|
15231
|
-
|
|
15232
|
-
|
|
15291
|
+
return await this.transaction(async (trx) => {
|
|
15292
|
+
const user = verifyTruthy(verifyOneOrNone(await this.findUsers({
|
|
15293
|
+
partial: { identityKey: args.identityKey },
|
|
15294
|
+
trx
|
|
15295
|
+
})));
|
|
15296
|
+
return await new EntitySyncState(verifyOne(await this.findSyncStates({
|
|
15297
|
+
partial: {
|
|
15298
|
+
storageIdentityKey: args.fromStorageIdentityKey,
|
|
15299
|
+
userId: user.userId
|
|
15300
|
+
},
|
|
15301
|
+
trx
|
|
15302
|
+
}))).processSyncChunk(this, args, chunk, trx);
|
|
15303
|
+
});
|
|
15233
15304
|
}
|
|
15234
15305
|
/**
|
|
15235
15306
|
* Handles storage changes when a valid MerklePath and mined block header are found for a ProvenTxReq txid.
|
|
@@ -17294,8 +17365,10 @@ var StorageIdb = class extends StorageProvider {
|
|
|
17294
17365
|
await tx.done;
|
|
17295
17366
|
return r;
|
|
17296
17367
|
} catch (err) {
|
|
17297
|
-
|
|
17298
|
-
|
|
17368
|
+
try {
|
|
17369
|
+
tx.abort();
|
|
17370
|
+
await tx.done;
|
|
17371
|
+
} catch {}
|
|
17299
17372
|
throw err;
|
|
17300
17373
|
}
|
|
17301
17374
|
}
|
|
@@ -18262,6 +18335,25 @@ var StorageClientBase = class {
|
|
|
18262
18335
|
* @returns `StorageCreateActionResults` supporting additional wallet processing to yield `createAction` results.
|
|
18263
18336
|
*/
|
|
18264
18337
|
async createAction(auth, args) {
|
|
18338
|
+
if (args.inputBEEF != null) if (args.inputs.length === 0) args = {
|
|
18339
|
+
...args,
|
|
18340
|
+
inputBEEF: void 0
|
|
18341
|
+
};
|
|
18342
|
+
else {
|
|
18343
|
+
let source;
|
|
18344
|
+
try {
|
|
18345
|
+
source = Beef.fromBinary(args.inputBEEF);
|
|
18346
|
+
} catch {
|
|
18347
|
+
source = void 0;
|
|
18348
|
+
}
|
|
18349
|
+
if (source != null) {
|
|
18350
|
+
const pruned = pruneBeefForTxids(source, args.inputs.map((input) => input.outpoint.txid));
|
|
18351
|
+
if (pruned != null) args = {
|
|
18352
|
+
...args,
|
|
18353
|
+
inputBEEF: pruned.toBinary()
|
|
18354
|
+
};
|
|
18355
|
+
}
|
|
18356
|
+
}
|
|
18265
18357
|
return await this.rpcCall("createAction", [auth, args]);
|
|
18266
18358
|
}
|
|
18267
18359
|
/**
|
|
@@ -30932,6 +31024,7 @@ var SetupClient = class SetupClient {
|
|
|
30932
31024
|
};
|
|
30933
31025
|
//#endregion
|
|
30934
31026
|
//#region ../src/CWIStyleWalletManager.ts
|
|
31027
|
+
const CWI_COMPONENT = "wallet-toolbox.cwi-manager";
|
|
30935
31028
|
/**
|
|
30936
31029
|
* Number of rounds used in PBKDF2 for deriving password keys.
|
|
30937
31030
|
*/
|
|
@@ -31164,11 +31257,11 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31164
31257
|
* @param hash The 32-byte SHA-256 hash of the presentation key.
|
|
31165
31258
|
* @returns A UMPToken object (including currentOutpoint) if found, otherwise undefined.
|
|
31166
31259
|
*/
|
|
31167
|
-
async findByPresentationKeyHash(hash) {
|
|
31168
|
-
return
|
|
31260
|
+
async findByPresentationKeyHash(hash, options) {
|
|
31261
|
+
return this.findToken({
|
|
31169
31262
|
service: "ls_users",
|
|
31170
31263
|
query: { presentationHash: Utils.toHex(hash) }
|
|
31171
|
-
}, "presentation");
|
|
31264
|
+
}, "presentation", options);
|
|
31172
31265
|
}
|
|
31173
31266
|
/**
|
|
31174
31267
|
* Finds a UMP token on-chain by the given recovery key hash, if it exists.
|
|
@@ -31177,13 +31270,13 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31177
31270
|
* @param hash The 32-byte SHA-256 hash of the recovery key.
|
|
31178
31271
|
* @returns A UMPToken object (including currentOutpoint) if found, otherwise undefined.
|
|
31179
31272
|
*/
|
|
31180
|
-
async findByRecoveryKeyHash(hash) {
|
|
31181
|
-
return
|
|
31273
|
+
async findByRecoveryKeyHash(hash, options) {
|
|
31274
|
+
return this.findToken({
|
|
31182
31275
|
service: "ls_users",
|
|
31183
31276
|
query: { recoveryHash: Utils.toHex(hash) }
|
|
31184
|
-
}, "recovery");
|
|
31277
|
+
}, "recovery", options);
|
|
31185
31278
|
}
|
|
31186
|
-
async findToken(question, lookupKind) {
|
|
31279
|
+
async findToken(question, lookupKind, options) {
|
|
31187
31280
|
const correlationId = this.telemetry.enabled === true ? this.telemetry.createCorrelationId() : void 0;
|
|
31188
31281
|
const startedAt = Date.now();
|
|
31189
31282
|
this.telemetry.capture({
|
|
@@ -31200,34 +31293,39 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31200
31293
|
correlationId
|
|
31201
31294
|
});
|
|
31202
31295
|
} catch (error) {
|
|
31203
|
-
const diagnostics = this.
|
|
31204
|
-
this.
|
|
31296
|
+
const diagnostics = this.emptyStats(correlationId);
|
|
31297
|
+
this.lookupFailed(lookupKind, "lookup-unavailable", diagnostics, startedAt, error);
|
|
31205
31298
|
throw new UMPTokenLookupError("lookup-unavailable", diagnostics, { cause: error });
|
|
31206
31299
|
}
|
|
31207
|
-
const diagnostics = this.
|
|
31300
|
+
const diagnostics = this.diagnosticsFor(resolution);
|
|
31208
31301
|
const tokens = this.parseLookupAnswers(resolution.answer);
|
|
31209
31302
|
const expectedHash = question.query[lookupKind === "presentation" ? "presentationHash" : "recoveryHash"].toLowerCase();
|
|
31210
31303
|
const matchingTokens = tokens.filter((token) => Utils.toHex(lookupKind === "presentation" ? token.presentationHash : token.recoveryHash).toLowerCase() === expectedHash);
|
|
31211
31304
|
if (matchingTokens.length > 1) {
|
|
31212
31305
|
const newest = this.resolveNewestToken(matchingTokens, resolution.answer.outputs);
|
|
31213
31306
|
if (newest != null) {
|
|
31214
|
-
this.
|
|
31307
|
+
this.lookupDone(lookupKind, "found", diagnostics, startedAt, { supersededTokens: matchingTokens.length - 1 });
|
|
31215
31308
|
return newest;
|
|
31216
31309
|
}
|
|
31310
|
+
const pinned = options?.pinnedOutpoint ? matchingTokens.find((token) => token.currentOutpoint === options.pinnedOutpoint) : void 0;
|
|
31311
|
+
if (pinned != null) {
|
|
31312
|
+
this.lookupDone(lookupKind, "found", diagnostics, startedAt);
|
|
31313
|
+
return pinned;
|
|
31314
|
+
}
|
|
31217
31315
|
const reason = "token-ambiguous";
|
|
31218
|
-
this.
|
|
31316
|
+
this.lookupFailed(lookupKind, reason, diagnostics, startedAt);
|
|
31219
31317
|
throw new UMPTokenLookupError(reason, diagnostics);
|
|
31220
31318
|
}
|
|
31221
31319
|
if (matchingTokens.length === 1) {
|
|
31222
|
-
this.
|
|
31320
|
+
this.lookupDone(lookupKind, "found", diagnostics, startedAt);
|
|
31223
31321
|
return matchingTokens[0];
|
|
31224
31322
|
}
|
|
31225
31323
|
if (resolution.progress.emptyHosts > 0) {
|
|
31226
|
-
this.
|
|
31324
|
+
this.lookupDone(lookupKind, "not-found", diagnostics, startedAt);
|
|
31227
31325
|
return;
|
|
31228
31326
|
}
|
|
31229
31327
|
const reason = resolution.answer.outputs.length > 0 ? "token-malformed" : "lookup-incomplete";
|
|
31230
|
-
this.
|
|
31328
|
+
this.lookupFailed(lookupKind, reason, diagnostics, startedAt);
|
|
31231
31329
|
throw new UMPTokenLookupError(reason, diagnostics);
|
|
31232
31330
|
}
|
|
31233
31331
|
/**
|
|
@@ -31258,7 +31356,7 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31258
31356
|
spent: /* @__PURE__ */ new Set()
|
|
31259
31357
|
};
|
|
31260
31358
|
evidence.txs.push(tx);
|
|
31261
|
-
this.
|
|
31359
|
+
this.collectSpends(tx, evidence.spent, /* @__PURE__ */ new Set());
|
|
31262
31360
|
evidenceByCandidate.set(outpoint, evidence);
|
|
31263
31361
|
} catch {}
|
|
31264
31362
|
if (evidenceByCandidate.size !== candidates.size) return void 0;
|
|
@@ -31267,7 +31365,7 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31267
31365
|
const provenContinuations = survivors.filter((outpoint) => {
|
|
31268
31366
|
const evidence = evidenceByCandidate.get(outpoint);
|
|
31269
31367
|
const token = candidates.get(outpoint);
|
|
31270
|
-
return evidence != null && token != null && evidence.txs.some((tx) => this.
|
|
31368
|
+
return evidence != null && token != null && evidence.txs.some((tx) => this.consumesIdentity(tx, token));
|
|
31271
31369
|
});
|
|
31272
31370
|
if (provenContinuations.length !== 1) return void 0;
|
|
31273
31371
|
return candidates.get(provenContinuations[0]);
|
|
@@ -31278,7 +31376,7 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31278
31376
|
* hash — on-chain proof that the candidate is an update of a same-identity
|
|
31279
31377
|
* predecessor rather than an independently minted token.
|
|
31280
31378
|
*/
|
|
31281
|
-
|
|
31379
|
+
consumesIdentity(tx, token) {
|
|
31282
31380
|
const presentationHash = Utils.toHex(token.presentationHash);
|
|
31283
31381
|
const recoveryHash = Utils.toHex(token.recoveryHash);
|
|
31284
31382
|
for (const input of tx.inputs) {
|
|
@@ -31304,7 +31402,7 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31304
31402
|
* renditions are absent from the lookup answer. Iterative so arbitrarily
|
|
31305
31403
|
* long update chains cannot exhaust the call stack.
|
|
31306
31404
|
*/
|
|
31307
|
-
|
|
31405
|
+
collectSpends(tx, spent, visited) {
|
|
31308
31406
|
const pending = [tx];
|
|
31309
31407
|
while (pending.length > 0) {
|
|
31310
31408
|
const current = pending.pop();
|
|
@@ -31319,7 +31417,7 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31319
31417
|
}
|
|
31320
31418
|
}
|
|
31321
31419
|
}
|
|
31322
|
-
|
|
31420
|
+
emptyStats(correlationId) {
|
|
31323
31421
|
return {
|
|
31324
31422
|
hostCount: 0,
|
|
31325
31423
|
completedHosts: 0,
|
|
@@ -31332,7 +31430,7 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31332
31430
|
...correlationId !== void 0 ? { correlationId } : {}
|
|
31333
31431
|
};
|
|
31334
31432
|
}
|
|
31335
|
-
|
|
31433
|
+
diagnosticsFor(resolution) {
|
|
31336
31434
|
const progress = resolution.progress;
|
|
31337
31435
|
return {
|
|
31338
31436
|
hostCount: progress.hostCount,
|
|
@@ -31346,7 +31444,7 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31346
31444
|
...progress.correlationId !== void 0 ? { correlationId: progress.correlationId } : {}
|
|
31347
31445
|
};
|
|
31348
31446
|
}
|
|
31349
|
-
|
|
31447
|
+
lookupAttrs(diagnostics) {
|
|
31350
31448
|
return {
|
|
31351
31449
|
hostCount: diagnostics.hostCount,
|
|
31352
31450
|
completedHosts: diagnostics.completedHosts,
|
|
@@ -31358,7 +31456,7 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31358
31456
|
outputCount: diagnostics.outputCount
|
|
31359
31457
|
};
|
|
31360
31458
|
}
|
|
31361
|
-
|
|
31459
|
+
lookupDone(lookupKind, result, diagnostics, startedAt, extraAttributes = {}) {
|
|
31362
31460
|
this.telemetry.capture({
|
|
31363
31461
|
name: "wallet-toolbox.ump.lookup.completed",
|
|
31364
31462
|
component: "wallet-toolbox.ump",
|
|
@@ -31368,12 +31466,12 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31368
31466
|
lookupKind,
|
|
31369
31467
|
result,
|
|
31370
31468
|
durationMs: Date.now() - startedAt,
|
|
31371
|
-
...this.
|
|
31469
|
+
...this.lookupAttrs(diagnostics),
|
|
31372
31470
|
...extraAttributes
|
|
31373
31471
|
}
|
|
31374
31472
|
});
|
|
31375
31473
|
}
|
|
31376
|
-
|
|
31474
|
+
lookupFailed(lookupKind, reason, diagnostics, startedAt, error) {
|
|
31377
31475
|
this.telemetry.capture({
|
|
31378
31476
|
name: "wallet-toolbox.ump.lookup.indeterminate",
|
|
31379
31477
|
component: "wallet-toolbox.ump",
|
|
@@ -31383,7 +31481,7 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31383
31481
|
lookupKind,
|
|
31384
31482
|
reason,
|
|
31385
31483
|
durationMs: Date.now() - startedAt,
|
|
31386
|
-
...this.
|
|
31484
|
+
...this.lookupAttrs(diagnostics)
|
|
31387
31485
|
},
|
|
31388
31486
|
error
|
|
31389
31487
|
});
|
|
@@ -31401,27 +31499,27 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31401
31499
|
* @returns The outpoint of the newly created UMP token (e.g. "abcd1234...ef.0").
|
|
31402
31500
|
*/
|
|
31403
31501
|
async buildAndSend(wallet, adminOriginator, token, oldTokenToConsume) {
|
|
31404
|
-
const fields = this.
|
|
31502
|
+
const fields = this.tokenFields(token);
|
|
31405
31503
|
const tokenOutput = [{
|
|
31406
31504
|
lockingScript: (await new PushDrop(wallet, adminOriginator).lock(fields, [2, "admin user management token"], "1", "self", true, true)).toHex(),
|
|
31407
31505
|
satoshis: 1,
|
|
31408
31506
|
outputDescription: "New UMP token output"
|
|
31409
31507
|
}];
|
|
31410
|
-
const { resolvedOldToken, inputToken } = await this.
|
|
31508
|
+
const { resolvedOldToken, inputToken } = await this.resolveOldInput(oldTokenToConsume);
|
|
31411
31509
|
const inputs = resolvedOldToken?.currentOutpoint ? [{
|
|
31412
31510
|
outpoint: resolvedOldToken.currentOutpoint,
|
|
31413
31511
|
unlockingScriptLength: 73,
|
|
31414
31512
|
inputDescription: "Consume old UMP token"
|
|
31415
31513
|
}] : [];
|
|
31416
|
-
const createResult = await this.
|
|
31417
|
-
if (!createResult.signableTransaction) return
|
|
31514
|
+
const createResult = await this.createAction(wallet, adminOriginator, inputs, tokenOutput, inputToken, resolvedOldToken);
|
|
31515
|
+
if (!createResult.signableTransaction) return this.broadcastFinal(createResult);
|
|
31418
31516
|
const reference = createResult.signableTransaction.reference;
|
|
31419
31517
|
const partialTx = Transaction.fromBEEF(createResult.signableTransaction.tx);
|
|
31420
|
-
if (resolvedOldToken?.currentOutpoint) return
|
|
31421
|
-
return
|
|
31518
|
+
if (resolvedOldToken?.currentOutpoint) return this.renewToken(wallet, adminOriginator, reference, partialTx);
|
|
31519
|
+
return this.broadcastNew(wallet, adminOriginator, reference);
|
|
31422
31520
|
}
|
|
31423
31521
|
/** Assembles the ordered number[][] fields array from a UMPToken. */
|
|
31424
|
-
|
|
31522
|
+
tokenFields(token) {
|
|
31425
31523
|
const fields = [];
|
|
31426
31524
|
fields[0] = token.passwordSalt;
|
|
31427
31525
|
fields[1] = token.passwordPresentationPrimary;
|
|
@@ -31448,20 +31546,20 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31448
31546
|
return fields;
|
|
31449
31547
|
}
|
|
31450
31548
|
/** Looks up the old token on the overlay; returns undefined resolved token if not found. */
|
|
31451
|
-
async
|
|
31549
|
+
async resolveOldInput(oldTokenToConsume) {
|
|
31452
31550
|
if (!oldTokenToConsume?.currentOutpoint) return {
|
|
31453
31551
|
resolvedOldToken: void 0,
|
|
31454
31552
|
inputToken: void 0
|
|
31455
31553
|
};
|
|
31456
31554
|
const inputToken = await this.findByOutpoint(oldTokenToConsume.currentOutpoint);
|
|
31457
|
-
if (inputToken == null) throw new Error("
|
|
31555
|
+
if (inputToken == null) throw new Error("Previous UMP token unavailable; update refused.");
|
|
31458
31556
|
return {
|
|
31459
31557
|
resolvedOldToken: oldTokenToConsume,
|
|
31460
31558
|
inputToken
|
|
31461
31559
|
};
|
|
31462
31560
|
}
|
|
31463
31561
|
/** Creates the UMP action without dropping a required old-token input on failure. */
|
|
31464
|
-
async
|
|
31562
|
+
async createAction(wallet, adminOriginator, inputs, outputs, inputToken, resolvedOldToken) {
|
|
31465
31563
|
try {
|
|
31466
31564
|
return await wallet.createAction({
|
|
31467
31565
|
description: resolvedOldToken == null ? "Create new UMP token" : "Renew UMP token (consume old, create new)",
|
|
@@ -31488,43 +31586,43 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31488
31586
|
}
|
|
31489
31587
|
}
|
|
31490
31588
|
/** Handles a fully-finalized (no signable tx) createAction result — broadcasts and returns outpoint. */
|
|
31491
|
-
async
|
|
31589
|
+
async broadcastFinal(createResult) {
|
|
31492
31590
|
const finalTxid = createResult.txid || (createResult.tx != null ? Transaction.fromAtomicBEEF(createResult.tx).id("hex") : void 0);
|
|
31493
|
-
if (!finalTxid) throw new Error("
|
|
31494
|
-
if (createResult.tx == null) throw new Error("
|
|
31591
|
+
if (!finalTxid) throw new Error("UMP transaction was not finalized.");
|
|
31592
|
+
if (createResult.tx == null) throw new Error("UMP transaction data missing.");
|
|
31495
31593
|
const broadcastTx = Transaction.fromAtomicBEEF(createResult.tx);
|
|
31496
31594
|
const result = await this.broadcaster.broadcast(broadcastTx);
|
|
31497
|
-
this.
|
|
31595
|
+
this.assertBroadcast(result, "create-finalized");
|
|
31498
31596
|
return `${finalTxid}.0`;
|
|
31499
31597
|
}
|
|
31500
31598
|
/** Signs the old-token input and broadcasts — used during UMP token renewal. */
|
|
31501
|
-
async
|
|
31599
|
+
async renewToken(wallet, adminOriginator, reference, partialTx) {
|
|
31502
31600
|
const unlockingScript = await new PushDrop(wallet, adminOriginator).unlock([2, "admin user management token"], "1", "self").sign(partialTx, 0);
|
|
31503
31601
|
const signResult = await wallet.signAction({
|
|
31504
31602
|
reference,
|
|
31505
31603
|
spends: { 0: { unlockingScript: unlockingScript.toHex() } }
|
|
31506
31604
|
}, adminOriginator);
|
|
31507
31605
|
const finalTxid = signResult.txid || (signResult.tx == null ? "" : Transaction.fromAtomicBEEF(signResult.tx).id("hex"));
|
|
31508
|
-
if (!finalTxid) throw new Error("Could not finalize
|
|
31509
|
-
if (signResult.tx == null) throw new Error("
|
|
31606
|
+
if (!finalTxid) throw new Error("Could not finalize renewed UMP token.");
|
|
31607
|
+
if (signResult.tx == null) throw new Error("Renewed UMP token transaction data missing.");
|
|
31510
31608
|
const result = await this.broadcaster.broadcast(Transaction.fromAtomicBEEF(signResult.tx));
|
|
31511
|
-
this.
|
|
31609
|
+
this.assertBroadcast(result, "renew");
|
|
31512
31610
|
return `${finalTxid}.0`;
|
|
31513
31611
|
}
|
|
31514
31612
|
/** Signs without input spending and broadcasts — used when creating a brand-new UMP token. */
|
|
31515
|
-
async
|
|
31613
|
+
async broadcastNew(wallet, adminOriginator, reference) {
|
|
31516
31614
|
const signResult = await wallet.signAction({
|
|
31517
31615
|
reference,
|
|
31518
31616
|
spends: {}
|
|
31519
31617
|
}, adminOriginator);
|
|
31520
31618
|
const finalTxid = signResult.txid || (signResult.tx == null ? "" : Transaction.fromAtomicBEEF(signResult.tx).id("hex"));
|
|
31521
|
-
if (!finalTxid) throw new Error("
|
|
31522
|
-
if (signResult.tx == null) throw new Error("
|
|
31619
|
+
if (!finalTxid) throw new Error("Could not finalize new UMP token.");
|
|
31620
|
+
if (signResult.tx == null) throw new Error("New UMP token transaction data missing.");
|
|
31523
31621
|
const result = await this.broadcaster.broadcast(Transaction.fromAtomicBEEF(signResult.tx));
|
|
31524
|
-
this.
|
|
31622
|
+
this.assertBroadcast(result, "create");
|
|
31525
31623
|
return `${finalTxid}.0`;
|
|
31526
31624
|
}
|
|
31527
|
-
|
|
31625
|
+
assertBroadcast(result, operation) {
|
|
31528
31626
|
const succeeded = result.status === "success";
|
|
31529
31627
|
this.telemetry.capture({
|
|
31530
31628
|
name: succeeded ? "wallet-toolbox.ump.broadcast.completed" : "wallet-toolbox.ump.broadcast.failed",
|
|
@@ -31553,12 +31651,12 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31553
31651
|
if (answer.type !== "output-list" || answer.outputs.length === 0) return [];
|
|
31554
31652
|
const tokens = [];
|
|
31555
31653
|
for (const output of answer.outputs) {
|
|
31556
|
-
const token = this.
|
|
31654
|
+
const token = this.parseOutput(output);
|
|
31557
31655
|
if (token != null) tokens.push(token);
|
|
31558
31656
|
}
|
|
31559
31657
|
return tokens;
|
|
31560
31658
|
}
|
|
31561
|
-
|
|
31659
|
+
parseOutput(output) {
|
|
31562
31660
|
try {
|
|
31563
31661
|
const tx = Transaction.fromBEEF(output.beef);
|
|
31564
31662
|
const txOutput = tx.outputs[output.outputIndex];
|
|
@@ -31608,14 +31706,14 @@ var OverlayUMPTokenInteractor = class {
|
|
|
31608
31706
|
correlationId
|
|
31609
31707
|
});
|
|
31610
31708
|
} catch (error) {
|
|
31611
|
-
const diagnostics = this.
|
|
31612
|
-
this.
|
|
31709
|
+
const diagnostics = this.emptyStats(correlationId);
|
|
31710
|
+
this.lookupFailed("outpoint", "lookup-unavailable", diagnostics, startedAt, error);
|
|
31613
31711
|
throw new UMPTokenLookupError("lookup-unavailable", diagnostics, { cause: error });
|
|
31614
31712
|
}
|
|
31615
31713
|
if (resolution.answer.outputs.length === 0) {
|
|
31616
31714
|
if (resolution.progress.emptyHosts === 0) {
|
|
31617
|
-
const diagnostics = this.
|
|
31618
|
-
this.
|
|
31715
|
+
const diagnostics = this.diagnosticsFor(resolution);
|
|
31716
|
+
this.lookupFailed("outpoint", "lookup-incomplete", diagnostics, startedAt);
|
|
31619
31717
|
throw new UMPTokenLookupError("lookup-incomplete", diagnostics);
|
|
31620
31718
|
}
|
|
31621
31719
|
return;
|
|
@@ -31757,20 +31855,20 @@ var CWIStyleWalletManager = class {
|
|
|
31757
31855
|
if (this._initSnapshot !== void 0) {
|
|
31758
31856
|
this.telemetry.capture({
|
|
31759
31857
|
name: "wallet-toolbox.snapshot.initialization.started",
|
|
31760
|
-
component:
|
|
31858
|
+
component: CWI_COMPONENT,
|
|
31761
31859
|
severity: "debug"
|
|
31762
31860
|
});
|
|
31763
31861
|
try {
|
|
31764
31862
|
await this.loadSnapshot(this._initSnapshot);
|
|
31765
31863
|
this.telemetry.capture({
|
|
31766
31864
|
name: "wallet-toolbox.snapshot.initialization.completed",
|
|
31767
|
-
component:
|
|
31865
|
+
component: CWI_COMPONENT,
|
|
31768
31866
|
severity: "info"
|
|
31769
31867
|
});
|
|
31770
31868
|
} catch (error) {
|
|
31771
31869
|
this.telemetry.capture({
|
|
31772
31870
|
name: "wallet-toolbox.snapshot.initialization.failed",
|
|
31773
|
-
component:
|
|
31871
|
+
component: CWI_COMPONENT,
|
|
31774
31872
|
severity: "error",
|
|
31775
31873
|
error
|
|
31776
31874
|
});
|
|
@@ -31779,9 +31877,11 @@ var CWIStyleWalletManager = class {
|
|
|
31779
31877
|
}
|
|
31780
31878
|
}
|
|
31781
31879
|
/**
|
|
31782
|
-
* Provides the presentation key.
|
|
31880
|
+
* Provides the presentation key. A WAB operator pin may be supplied by the
|
|
31881
|
+
* authentication manager; normal lookup and lineage resolution always run
|
|
31882
|
+
* before this ambiguity-only fallback.
|
|
31783
31883
|
*/
|
|
31784
|
-
async providePresentationKey(key) {
|
|
31884
|
+
async providePresentationKey(key, lookupOptions) {
|
|
31785
31885
|
if (this.authenticated) throw new Error("User is already authenticated");
|
|
31786
31886
|
if (this.authenticationMode === "recovery-key-and-password") throw new Error("Presentation key is not needed in this mode");
|
|
31787
31887
|
if (key.length !== 32 || key.some((byte) => !Number.isInteger(byte) || byte < 0 || byte > 255)) throw new TypeError("Presentation key must contain exactly 32 bytes.");
|
|
@@ -31790,17 +31890,17 @@ var CWIStyleWalletManager = class {
|
|
|
31790
31890
|
const startedAt = Date.now();
|
|
31791
31891
|
this.telemetry.capture({
|
|
31792
31892
|
name: "wallet-toolbox.authentication.account-lookup.started",
|
|
31793
|
-
component:
|
|
31893
|
+
component: CWI_COMPONENT,
|
|
31794
31894
|
severity: "debug",
|
|
31795
31895
|
attributes: { lookupKind: "presentation" }
|
|
31796
31896
|
});
|
|
31797
31897
|
let token;
|
|
31798
31898
|
try {
|
|
31799
|
-
token = await this.UMPTokenInteractor.findByPresentationKeyHash(hash);
|
|
31899
|
+
token = await this.UMPTokenInteractor.findByPresentationKeyHash(hash, lookupOptions);
|
|
31800
31900
|
} catch (error) {
|
|
31801
31901
|
this.telemetry.capture({
|
|
31802
31902
|
name: "wallet-toolbox.authentication.account-lookup.failed",
|
|
31803
|
-
component:
|
|
31903
|
+
component: CWI_COMPONENT,
|
|
31804
31904
|
severity: "warn",
|
|
31805
31905
|
attributes: {
|
|
31806
31906
|
lookupKind: "presentation",
|
|
@@ -31820,7 +31920,7 @@ var CWIStyleWalletManager = class {
|
|
|
31820
31920
|
}
|
|
31821
31921
|
this.telemetry.capture({
|
|
31822
31922
|
name: "wallet-toolbox.authentication.account-lookup.completed",
|
|
31823
|
-
component:
|
|
31923
|
+
component: CWI_COMPONENT,
|
|
31824
31924
|
severity: "info",
|
|
31825
31925
|
attributes: {
|
|
31826
31926
|
lookupKind: "presentation",
|
|
@@ -31836,11 +31936,11 @@ var CWIStyleWalletManager = class {
|
|
|
31836
31936
|
if (this.authenticated) throw new Error("User is already authenticated");
|
|
31837
31937
|
if (this.authenticationMode === "presentation-key-and-recovery-key") throw new Error("Password is not needed in this mode");
|
|
31838
31938
|
if (this.authenticationFlow === "unknown") throw new Error("Determine account status with a presentation or recovery key before providing a password.");
|
|
31839
|
-
if (this.authenticationFlow === "existing-user") await this.
|
|
31840
|
-
else await this.
|
|
31939
|
+
if (this.authenticationFlow === "existing-user") await this.unlockExisting(password);
|
|
31940
|
+
else await this.createNewUser(password);
|
|
31841
31941
|
}
|
|
31842
31942
|
/** Handles the password step for an existing user — derives keys, sets up infrastructure. */
|
|
31843
|
-
async
|
|
31943
|
+
async unlockExisting(password) {
|
|
31844
31944
|
if (this.currentUMPToken == null) throw new Error("Provide presentation or recovery key first.");
|
|
31845
31945
|
const derivedPasswordKey = await derivePasswordKey(this.currentUMPToken, Utils.toArray(password, "utf8"));
|
|
31846
31946
|
let rootPrimaryKey;
|
|
@@ -31853,11 +31953,11 @@ var CWIStyleWalletManager = class {
|
|
|
31853
31953
|
rootPrimaryKey = new SymmetricKey(this.XOR(this.recoveryKey, derivedPasswordKey)).decrypt(this.currentUMPToken.passwordRecoveryPrimary);
|
|
31854
31954
|
rootPrivilegedKey = new SymmetricKey(this.XOR(rootPrimaryKey, derivedPasswordKey)).decrypt(this.currentUMPToken.passwordPrimaryPrivileged);
|
|
31855
31955
|
}
|
|
31856
|
-
await this.
|
|
31956
|
+
await this.setupRoot(rootPrimaryKey, rootPrivilegedKey);
|
|
31857
31957
|
await this.switchProfile(this.activeProfileId);
|
|
31858
31958
|
}
|
|
31859
31959
|
/** Handles the password step for a new user — generates keys, builds UMP token, publishes on-chain. */
|
|
31860
|
-
async
|
|
31960
|
+
async createNewUser(password) {
|
|
31861
31961
|
if (this.authenticationMode !== "presentation-key-and-password") throw new Error("New-user flow requires presentation key and password mode.");
|
|
31862
31962
|
if (this.presentationKey == null) throw new Error("No presentation key provided for new-user flow.");
|
|
31863
31963
|
const recoveryKey = Random(32);
|
|
@@ -31896,14 +31996,14 @@ var CWIStyleWalletManager = class {
|
|
|
31896
31996
|
passwordKdf: this.kdfConfig
|
|
31897
31997
|
};
|
|
31898
31998
|
this.currentUMPToken = newToken;
|
|
31899
|
-
await this.
|
|
31999
|
+
await this.setupRoot(rootPrimaryKey);
|
|
31900
32000
|
await this.switchProfile(DEFAULT_PROFILE_ID);
|
|
31901
32001
|
if (this.newWalletFunder != null && this.underlying != null) try {
|
|
31902
32002
|
await this.newWalletFunder(this.presentationKey, this.underlying, this.adminOriginator);
|
|
31903
32003
|
} catch (error) {
|
|
31904
32004
|
this.telemetry.capture({
|
|
31905
32005
|
name: "wallet-toolbox.authentication.new-wallet-funding.failed",
|
|
31906
|
-
component:
|
|
32006
|
+
component: CWI_COMPONENT,
|
|
31907
32007
|
severity: "error",
|
|
31908
32008
|
error: /* @__PURE__ */ new Error("New wallet funding failed.")
|
|
31909
32009
|
});
|
|
@@ -31934,7 +32034,7 @@ var CWIStyleWalletManager = class {
|
|
|
31934
32034
|
const xorKey = this.XOR(this.presentationKey, recoveryKey);
|
|
31935
32035
|
const rootPrimaryKey = new SymmetricKey(xorKey).decrypt(this.currentUMPToken.presentationRecoveryPrimary);
|
|
31936
32036
|
const rootPrivilegedKey = new SymmetricKey(xorKey).decrypt(this.currentUMPToken.presentationRecoveryPrivileged);
|
|
31937
|
-
await this.
|
|
32037
|
+
await this.setupRoot(rootPrimaryKey, rootPrivilegedKey);
|
|
31938
32038
|
await this.switchProfile(this.activeProfileId);
|
|
31939
32039
|
}
|
|
31940
32040
|
}
|
|
@@ -31965,7 +32065,7 @@ var CWIStyleWalletManager = class {
|
|
|
31965
32065
|
if (snapshot.length > 16777216) throw new Error("Snapshot exceeds the maximum supported size.");
|
|
31966
32066
|
this.telemetry.capture({
|
|
31967
32067
|
name: "wallet-toolbox.snapshot.saved",
|
|
31968
|
-
component:
|
|
32068
|
+
component: CWI_COMPONENT,
|
|
31969
32069
|
severity: "info",
|
|
31970
32070
|
attributes: {
|
|
31971
32071
|
formatVersion: 2,
|
|
@@ -32003,12 +32103,12 @@ var CWIStyleWalletManager = class {
|
|
|
32003
32103
|
const tokenBytes = payloadReader.read(tokenLen);
|
|
32004
32104
|
const token = this.deserializeUMPToken(tokenBytes);
|
|
32005
32105
|
this.currentUMPToken = token;
|
|
32006
|
-
await this.
|
|
32106
|
+
await this.setupRoot(rootPrimaryKey);
|
|
32007
32107
|
await this.switchProfile(activeProfileId);
|
|
32008
32108
|
this.authenticationFlow = "existing-user";
|
|
32009
32109
|
this.telemetry.capture({
|
|
32010
32110
|
name: "wallet-toolbox.snapshot.loaded",
|
|
32011
|
-
component:
|
|
32111
|
+
component: CWI_COMPONENT,
|
|
32012
32112
|
severity: "info",
|
|
32013
32113
|
attributes: {
|
|
32014
32114
|
formatVersion: version,
|
|
@@ -32019,7 +32119,7 @@ var CWIStyleWalletManager = class {
|
|
|
32019
32119
|
this.destroy();
|
|
32020
32120
|
this.telemetry.capture({
|
|
32021
32121
|
name: "wallet-toolbox.snapshot.load-failed",
|
|
32022
|
-
component:
|
|
32122
|
+
component: CWI_COMPONENT,
|
|
32023
32123
|
severity: "error",
|
|
32024
32124
|
error
|
|
32025
32125
|
});
|
|
@@ -32036,7 +32136,7 @@ var CWIStyleWalletManager = class {
|
|
|
32036
32136
|
if (refreshed == null) return false;
|
|
32037
32137
|
if (refreshed.currentOutpoint && currentToken.currentOutpoint && refreshed.currentOutpoint === currentToken.currentOutpoint) return false;
|
|
32038
32138
|
this.currentUMPToken = refreshed;
|
|
32039
|
-
await this.
|
|
32139
|
+
await this.setupRoot(this.rootPrimaryKey);
|
|
32040
32140
|
this.saveSnapshot();
|
|
32041
32141
|
return true;
|
|
32042
32142
|
}
|
|
@@ -32095,7 +32195,7 @@ var CWIStyleWalletManager = class {
|
|
|
32095
32195
|
createdAt: Math.floor(Date.now() / 1e3)
|
|
32096
32196
|
};
|
|
32097
32197
|
this.profiles.push(newProfile);
|
|
32098
|
-
await this.
|
|
32198
|
+
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);
|
|
32099
32199
|
return newProfile.id;
|
|
32100
32200
|
}
|
|
32101
32201
|
/**
|
|
@@ -32112,7 +32212,7 @@ var CWIStyleWalletManager = class {
|
|
|
32112
32212
|
if (profileIndex === -1) throw new Error("Profile not found.");
|
|
32113
32213
|
this.profiles.splice(profileIndex, 1);
|
|
32114
32214
|
if (this.activeProfileId.every((x, i) => x === profileId[i])) await this.switchProfile(DEFAULT_PROFILE_ID);
|
|
32115
|
-
await this.
|
|
32215
|
+
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);
|
|
32116
32216
|
}
|
|
32117
32217
|
/**
|
|
32118
32218
|
* Switches the active profile. This re-derives keys and rebuilds the underlying wallet.
|
|
@@ -32153,14 +32253,14 @@ var CWIStyleWalletManager = class {
|
|
|
32153
32253
|
const recoveryKey = await this.getFactor("recoveryKey");
|
|
32154
32254
|
const presentationKey = await this.getFactor("presentationKey");
|
|
32155
32255
|
const rootPrivilegedKey = await this.getFactor("privilegedKey");
|
|
32156
|
-
await this.
|
|
32256
|
+
await this.updateFactors(passwordSalt, newPasswordKey, presentationKey, recoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
|
|
32157
32257
|
}
|
|
32158
32258
|
/**
|
|
32159
32259
|
* Retrieves the current recovery key. Requires privileged access.
|
|
32160
32260
|
*/
|
|
32161
32261
|
async getRecoveryKey() {
|
|
32162
32262
|
if (!this.authenticated || this.currentUMPToken == null || this.rootPrivilegedKeyManager == null) throw new Error("Not authenticated or missing required data.");
|
|
32163
|
-
return
|
|
32263
|
+
return this.getFactor("recoveryKey");
|
|
32164
32264
|
}
|
|
32165
32265
|
/**
|
|
32166
32266
|
* Changes the user's recovery key. Prompts user to save the new key.
|
|
@@ -32172,7 +32272,7 @@ var CWIStyleWalletManager = class {
|
|
|
32172
32272
|
const rootPrivilegedKey = await this.getFactor("privilegedKey");
|
|
32173
32273
|
const newRecoveryKey = Random(32);
|
|
32174
32274
|
await this.recoveryKeySaver(newRecoveryKey);
|
|
32175
|
-
await this.
|
|
32275
|
+
await this.updateFactors(this.currentUMPToken.passwordSalt, passwordKey, presentationKey, newRecoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
|
|
32176
32276
|
}
|
|
32177
32277
|
/**
|
|
32178
32278
|
* Changes the user's presentation key.
|
|
@@ -32183,7 +32283,7 @@ var CWIStyleWalletManager = class {
|
|
|
32183
32283
|
const recoveryKey = await this.getFactor("recoveryKey");
|
|
32184
32284
|
const passwordKey = await this.getFactor("passwordKey");
|
|
32185
32285
|
const rootPrivilegedKey = await this.getFactor("privilegedKey");
|
|
32186
|
-
await this.
|
|
32286
|
+
await this.updateFactors(this.currentUMPToken.passwordSalt, passwordKey, newPresentationKey, recoveryKey, this.rootPrimaryKey, rootPrivilegedKey, this.profiles);
|
|
32187
32287
|
if (this.presentationKey != null) this.presentationKey = newPresentationKey;
|
|
32188
32288
|
}
|
|
32189
32289
|
/**
|
|
@@ -32229,7 +32329,7 @@ var CWIStyleWalletManager = class {
|
|
|
32229
32329
|
} catch (error) {
|
|
32230
32330
|
this.telemetry.capture({
|
|
32231
32331
|
name: "wallet-toolbox.authentication.factor-decryption.failed",
|
|
32232
|
-
component:
|
|
32332
|
+
component: CWI_COMPONENT,
|
|
32233
32333
|
severity: "error",
|
|
32234
32334
|
attributes: { factor: factorName },
|
|
32235
32335
|
error
|
|
@@ -32242,7 +32342,7 @@ var CWIStyleWalletManager = class {
|
|
|
32242
32342
|
* Recomputes UMP token fields with updated factors and profiles, then publishes the update.
|
|
32243
32343
|
* This operation requires the *root* privileged key and the *default* profile wallet.
|
|
32244
32344
|
*/
|
|
32245
|
-
async
|
|
32345
|
+
async updateFactors(passwordSalt, passwordKey, presentationKey, recoveryKey, rootPrimaryKey, rootPrivilegedKey, profiles) {
|
|
32246
32346
|
if (!this.authenticated || this.rootPrimaryKey == null || this.currentUMPToken == null) throw new Error("Wallet is not properly authenticated or missing data for update.");
|
|
32247
32347
|
const oldTokenToConsume = { ...this.currentUMPToken };
|
|
32248
32348
|
if (!oldTokenToConsume.currentOutpoint) throw new Error("Cannot update UMP token: Old token has no outpoint.");
|
|
@@ -32293,7 +32393,7 @@ var CWIStyleWalletManager = class {
|
|
|
32293
32393
|
if (!currentActiveId.every((x) => x === 0)) {
|
|
32294
32394
|
this.telemetry.capture({
|
|
32295
32395
|
name: "wallet-toolbox.ump.profile-switch.started",
|
|
32296
|
-
component:
|
|
32396
|
+
component: CWI_COMPONENT,
|
|
32297
32397
|
severity: "debug",
|
|
32298
32398
|
attributes: { reason: "token-update" }
|
|
32299
32399
|
});
|
|
@@ -32309,7 +32409,7 @@ var CWIStyleWalletManager = class {
|
|
|
32309
32409
|
await this.switchProfile(currentActiveId);
|
|
32310
32410
|
this.telemetry.capture({
|
|
32311
32411
|
name: "wallet-toolbox.ump.profile-switch.completed",
|
|
32312
|
-
component:
|
|
32412
|
+
component: CWI_COMPONENT,
|
|
32313
32413
|
severity: "debug",
|
|
32314
32414
|
attributes: { reason: "token-update" }
|
|
32315
32415
|
});
|
|
@@ -32436,9 +32536,9 @@ var CWIStyleWalletManager = class {
|
|
|
32436
32536
|
* @param rootPrimaryKey The user's root primary key (32 bytes).
|
|
32437
32537
|
* @param ephemeralRootPrivilegedKey Optional root privileged key (e.g., during recovery flows).
|
|
32438
32538
|
*/
|
|
32439
|
-
async
|
|
32539
|
+
async setupRoot(rootKey, ephemeralRootPrivilegedKey) {
|
|
32440
32540
|
if (this.currentUMPToken == null) throw new Error("A UMP token must exist before setting up root infrastructure!");
|
|
32441
|
-
this.rootPrimaryKey =
|
|
32541
|
+
this.rootPrimaryKey = rootKey;
|
|
32442
32542
|
let oneTimePrivilegedKey = ephemeralRootPrivilegedKey == null ? void 0 : new PrivateKey(ephemeralRootPrivilegedKey);
|
|
32443
32543
|
this.rootPrivilegedKeyManager = new PrivilegedKeyManager(async (reason) => {
|
|
32444
32544
|
if (oneTimePrivilegedKey != null) {
|
|
@@ -32459,7 +32559,7 @@ var CWIStyleWalletManager = class {
|
|
|
32459
32559
|
});
|
|
32460
32560
|
this.profiles = [];
|
|
32461
32561
|
if (this.currentUMPToken.profilesEncrypted != null && this.currentUMPToken.profilesEncrypted.length > 0) try {
|
|
32462
|
-
const decryptedProfileBytes = new SymmetricKey(
|
|
32562
|
+
const decryptedProfileBytes = new SymmetricKey(rootKey).decrypt(this.currentUMPToken.profilesEncrypted);
|
|
32463
32563
|
const profilesJson = Utils.toUTF8(decryptedProfileBytes);
|
|
32464
32564
|
const profiles = JSON.parse(profilesJson);
|
|
32465
32565
|
if (!Array.isArray(profiles) || profiles.length > 1e3 || !profiles.every(isValidProfile)) throw new Error("Decrypted profile data is invalid or exceeds supported bounds.");
|
|
@@ -32468,7 +32568,7 @@ var CWIStyleWalletManager = class {
|
|
|
32468
32568
|
this.profiles = [];
|
|
32469
32569
|
this.telemetry.capture({
|
|
32470
32570
|
name: "wallet-toolbox.profile.load-failed",
|
|
32471
|
-
component:
|
|
32571
|
+
component: CWI_COMPONENT,
|
|
32472
32572
|
severity: "error",
|
|
32473
32573
|
error
|
|
32474
32574
|
});
|
|
@@ -32477,98 +32577,98 @@ var CWIStyleWalletManager = class {
|
|
|
32477
32577
|
}
|
|
32478
32578
|
this.authenticated = true;
|
|
32479
32579
|
}
|
|
32480
|
-
|
|
32580
|
+
assertReady(originator) {
|
|
32481
32581
|
if (!this.authenticated) throw new Error("User is not authenticated.");
|
|
32482
32582
|
if (this.underlying == null) throw new Error("Underlying wallet for the active profile is not initialized.");
|
|
32483
32583
|
if (originator === this.adminOriginator) throw new Error("External applications are not allowed to use the admin originator.");
|
|
32484
32584
|
}
|
|
32485
32585
|
async getPublicKey(args, originator) {
|
|
32486
|
-
this.
|
|
32487
|
-
return
|
|
32586
|
+
this.assertReady(originator);
|
|
32587
|
+
return this.underlying.getPublicKey(args, originator);
|
|
32488
32588
|
}
|
|
32489
32589
|
async revealCounterpartyKeyLinkage(args, originator) {
|
|
32490
|
-
this.
|
|
32491
|
-
return
|
|
32590
|
+
this.assertReady(originator);
|
|
32591
|
+
return this.underlying.revealCounterpartyKeyLinkage(args, originator);
|
|
32492
32592
|
}
|
|
32493
32593
|
async revealSpecificKeyLinkage(args, originator) {
|
|
32494
|
-
this.
|
|
32495
|
-
return
|
|
32594
|
+
this.assertReady(originator);
|
|
32595
|
+
return this.underlying.revealSpecificKeyLinkage(args, originator);
|
|
32496
32596
|
}
|
|
32497
32597
|
async encrypt(args, originator) {
|
|
32498
|
-
this.
|
|
32499
|
-
return
|
|
32598
|
+
this.assertReady(originator);
|
|
32599
|
+
return this.underlying.encrypt(args, originator);
|
|
32500
32600
|
}
|
|
32501
32601
|
async decrypt(args, originator) {
|
|
32502
|
-
this.
|
|
32503
|
-
return
|
|
32602
|
+
this.assertReady(originator);
|
|
32603
|
+
return this.underlying.decrypt(args, originator);
|
|
32504
32604
|
}
|
|
32505
32605
|
async createHmac(args, originator) {
|
|
32506
|
-
this.
|
|
32507
|
-
return
|
|
32606
|
+
this.assertReady(originator);
|
|
32607
|
+
return this.underlying.createHmac(args, originator);
|
|
32508
32608
|
}
|
|
32509
32609
|
async verifyHmac(args, originator) {
|
|
32510
|
-
this.
|
|
32511
|
-
return
|
|
32610
|
+
this.assertReady(originator);
|
|
32611
|
+
return this.underlying.verifyHmac(args, originator);
|
|
32512
32612
|
}
|
|
32513
32613
|
async createSignature(args, originator) {
|
|
32514
|
-
this.
|
|
32515
|
-
return
|
|
32614
|
+
this.assertReady(originator);
|
|
32615
|
+
return this.underlying.createSignature(args, originator);
|
|
32516
32616
|
}
|
|
32517
32617
|
async verifySignature(args, originator) {
|
|
32518
|
-
this.
|
|
32519
|
-
return
|
|
32618
|
+
this.assertReady(originator);
|
|
32619
|
+
return this.underlying.verifySignature(args, originator);
|
|
32520
32620
|
}
|
|
32521
32621
|
async createAction(args, originator) {
|
|
32522
|
-
this.
|
|
32523
|
-
return
|
|
32622
|
+
this.assertReady(originator);
|
|
32623
|
+
return this.underlying.createAction(args, originator);
|
|
32524
32624
|
}
|
|
32525
32625
|
async signAction(args, originator) {
|
|
32526
|
-
this.
|
|
32527
|
-
return
|
|
32626
|
+
this.assertReady(originator);
|
|
32627
|
+
return this.underlying.signAction(args, originator);
|
|
32528
32628
|
}
|
|
32529
32629
|
async abortAction(args, originator) {
|
|
32530
|
-
this.
|
|
32531
|
-
return
|
|
32630
|
+
this.assertReady(originator);
|
|
32631
|
+
return this.underlying.abortAction(args, originator);
|
|
32532
32632
|
}
|
|
32533
32633
|
async listActions(args, originator) {
|
|
32534
|
-
this.
|
|
32535
|
-
return
|
|
32634
|
+
this.assertReady(originator);
|
|
32635
|
+
return this.underlying.listActions(args, originator);
|
|
32536
32636
|
}
|
|
32537
32637
|
async internalizeAction(args, originator) {
|
|
32538
|
-
this.
|
|
32539
|
-
return
|
|
32638
|
+
this.assertReady(originator);
|
|
32639
|
+
return this.underlying.internalizeAction(args, originator);
|
|
32540
32640
|
}
|
|
32541
32641
|
async listOutputs(args, originator) {
|
|
32542
|
-
this.
|
|
32543
|
-
return
|
|
32642
|
+
this.assertReady(originator);
|
|
32643
|
+
return this.underlying.listOutputs(args, originator);
|
|
32544
32644
|
}
|
|
32545
32645
|
async relinquishOutput(args, originator) {
|
|
32546
|
-
this.
|
|
32547
|
-
return
|
|
32646
|
+
this.assertReady(originator);
|
|
32647
|
+
return this.underlying.relinquishOutput(args, originator);
|
|
32548
32648
|
}
|
|
32549
32649
|
async acquireCertificate(args, originator) {
|
|
32550
|
-
this.
|
|
32551
|
-
return
|
|
32650
|
+
this.assertReady(originator);
|
|
32651
|
+
return this.underlying.acquireCertificate(args, originator);
|
|
32552
32652
|
}
|
|
32553
32653
|
async listCertificates(args, originator) {
|
|
32554
|
-
this.
|
|
32555
|
-
return
|
|
32654
|
+
this.assertReady(originator);
|
|
32655
|
+
return this.underlying.listCertificates(args, originator);
|
|
32556
32656
|
}
|
|
32557
32657
|
async proveCertificate(args, originator) {
|
|
32558
|
-
this.
|
|
32559
|
-
return
|
|
32658
|
+
this.assertReady(originator);
|
|
32659
|
+
return this.underlying.proveCertificate(args, originator);
|
|
32560
32660
|
}
|
|
32561
32661
|
async relinquishCertificate(args, originator) {
|
|
32562
|
-
this.
|
|
32563
|
-
return
|
|
32662
|
+
this.assertReady(originator);
|
|
32663
|
+
return this.underlying.relinquishCertificate(args, originator);
|
|
32564
32664
|
}
|
|
32565
32665
|
async discoverByIdentityKey(args, originator) {
|
|
32566
|
-
this.
|
|
32567
|
-
return
|
|
32666
|
+
this.assertReady(originator);
|
|
32667
|
+
return this.underlying.discoverByIdentityKey(args, originator);
|
|
32568
32668
|
}
|
|
32569
32669
|
async discoverByAttributes(args, originator) {
|
|
32570
|
-
this.
|
|
32571
|
-
return
|
|
32670
|
+
this.assertReady(originator);
|
|
32671
|
+
return this.underlying.discoverByAttributes(args, originator);
|
|
32572
32672
|
}
|
|
32573
32673
|
async isAuthenticated(_, originator) {
|
|
32574
32674
|
if (!this.authenticated) throw new Error("User is not authenticated.");
|
|
@@ -32578,23 +32678,23 @@ var CWIStyleWalletManager = class {
|
|
|
32578
32678
|
async waitForAuthentication(_, originator) {
|
|
32579
32679
|
if (originator === this.adminOriginator) throw new Error("External applications are not allowed to use the admin originator.");
|
|
32580
32680
|
while (!this.authenticated || this.underlying == null) await new Promise((resolve) => setTimeout(resolve, 100));
|
|
32581
|
-
return
|
|
32681
|
+
return this.underlying.waitForAuthentication({}, originator);
|
|
32582
32682
|
}
|
|
32583
32683
|
async getHeight(_, originator) {
|
|
32584
|
-
this.
|
|
32585
|
-
return
|
|
32684
|
+
this.assertReady(originator);
|
|
32685
|
+
return this.underlying.getHeight({}, originator);
|
|
32586
32686
|
}
|
|
32587
32687
|
async getHeaderForHeight(args, originator) {
|
|
32588
|
-
this.
|
|
32589
|
-
return
|
|
32688
|
+
this.assertReady(originator);
|
|
32689
|
+
return this.underlying.getHeaderForHeight(args, originator);
|
|
32590
32690
|
}
|
|
32591
32691
|
async getNetwork(_, originator) {
|
|
32592
|
-
this.
|
|
32593
|
-
return
|
|
32692
|
+
this.assertReady(originator);
|
|
32693
|
+
return this.underlying.getNetwork({}, originator);
|
|
32594
32694
|
}
|
|
32595
32695
|
async getVersion(_, originator) {
|
|
32596
|
-
this.
|
|
32597
|
-
return
|
|
32696
|
+
this.assertReady(originator);
|
|
32697
|
+
return this.underlying.getVersion({}, originator);
|
|
32598
32698
|
}
|
|
32599
32699
|
};
|
|
32600
32700
|
//#endregion
|
|
@@ -32938,6 +33038,8 @@ const DEFAULT_MAX_RESPONSE_BYTES = 1024 * 1024;
|
|
|
32938
33038
|
const MAX_CONFIGURED_TIMEOUT_MS = 12e4;
|
|
32939
33039
|
const MAX_CONFIGURED_REQUEST_BYTES = 10 * 1024 * 1024;
|
|
32940
33040
|
const MAX_CONFIGURED_RESPONSE_BYTES = 10 * 1024 * 1024;
|
|
33041
|
+
const WAB_COMPONENT = "wallet-toolbox.wab-transport";
|
|
33042
|
+
const WAB_REQUEST_EVENT = "wallet-toolbox.wab.request.";
|
|
32941
33043
|
const defaultFetch = typeof globalThis !== "undefined" && typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : void 0;
|
|
32942
33044
|
/**
|
|
32943
33045
|
* A privacy-safe WAB transport failure. Response bodies and request payloads
|
|
@@ -32976,8 +33078,8 @@ function normalizeServerUrl(serverUrl) {
|
|
|
32976
33078
|
} catch {
|
|
32977
33079
|
throw new WABClientError("WAB_INVALID_CONFIGURATION", "WAB server URL must be an absolute URL.", false);
|
|
32978
33080
|
}
|
|
32979
|
-
if (parsed.username !== "" || parsed.password !== "" || parsed.search !== "" || parsed.hash !== "") throw new WABClientError("WAB_INVALID_CONFIGURATION", "WAB
|
|
32980
|
-
if (parsed.protocol !== "https:" && !(parsed.protocol === "http:" && isLocalHostname(parsed.hostname))) throw new WABClientError("WAB_INVALID_CONFIGURATION", "WAB
|
|
33081
|
+
if (parsed.username !== "" || parsed.password !== "" || parsed.search !== "" || parsed.hash !== "") throw new WABClientError("WAB_INVALID_CONFIGURATION", "WAB URL cannot include credentials, query, or fragment.", false);
|
|
33082
|
+
if (parsed.protocol !== "https:" && !(parsed.protocol === "http:" && isLocalHostname(parsed.hostname))) throw new WABClientError("WAB_INVALID_CONFIGURATION", "WAB URL requires HTTPS except on localhost.", false);
|
|
32981
33083
|
let pathname = parsed.pathname;
|
|
32982
33084
|
while (pathname.endsWith("/")) pathname = pathname.slice(0, -1);
|
|
32983
33085
|
return {
|
|
@@ -32987,7 +33089,7 @@ function normalizeServerUrl(serverUrl) {
|
|
|
32987
33089
|
}
|
|
32988
33090
|
function normalizePositiveInteger(value, fallback, maximum, name) {
|
|
32989
33091
|
const resolved = value ?? fallback;
|
|
32990
|
-
if (!Number.isInteger(resolved) || resolved <= 0 || resolved > maximum) throw new WABClientError("WAB_INVALID_CONFIGURATION", `${name} must be
|
|
33092
|
+
if (!Number.isInteger(resolved) || resolved <= 0 || resolved > maximum) throw new WABClientError("WAB_INVALID_CONFIGURATION", `${name} must be an integer from 1 to ${maximum}.`, false);
|
|
32991
33093
|
return resolved;
|
|
32992
33094
|
}
|
|
32993
33095
|
function assertSafePath(path) {
|
|
@@ -33012,20 +33114,20 @@ var WABTransport = class {
|
|
|
33012
33114
|
serverUrl;
|
|
33013
33115
|
serverOrigin;
|
|
33014
33116
|
telemetry;
|
|
33015
|
-
|
|
33016
|
-
|
|
33017
|
-
|
|
33018
|
-
|
|
33117
|
+
fetcher;
|
|
33118
|
+
timeout;
|
|
33119
|
+
requestLimit;
|
|
33120
|
+
responseLimit;
|
|
33019
33121
|
constructor(serverUrl, options = {}) {
|
|
33020
33122
|
const normalized = normalizeServerUrl(serverUrl);
|
|
33021
33123
|
this.serverUrl = normalized.baseUrl;
|
|
33022
33124
|
this.serverOrigin = normalized.origin;
|
|
33023
|
-
const
|
|
33024
|
-
if (typeof
|
|
33025
|
-
this.
|
|
33026
|
-
this.
|
|
33027
|
-
this.
|
|
33028
|
-
this.
|
|
33125
|
+
const fetcher = options.fetch ?? defaultFetch;
|
|
33126
|
+
if (typeof fetcher !== "function") throw new WABClientError("WAB_INVALID_CONFIGURATION", "WABClient requires a fetch implementation.", false);
|
|
33127
|
+
this.fetcher = fetcher;
|
|
33128
|
+
this.timeout = normalizePositiveInteger(options.timeoutMs, DEFAULT_TIMEOUT_MS, MAX_CONFIGURED_TIMEOUT_MS, "timeoutMs");
|
|
33129
|
+
this.requestLimit = normalizePositiveInteger(options.maxRequestBytes, DEFAULT_MAX_REQUEST_BYTES, MAX_CONFIGURED_REQUEST_BYTES, "maxRequestBytes");
|
|
33130
|
+
this.responseLimit = normalizePositiveInteger(options.maxResponseBytes, DEFAULT_MAX_RESPONSE_BYTES, MAX_CONFIGURED_RESPONSE_BYTES, "maxResponseBytes");
|
|
33029
33131
|
this.telemetry = new Telemetry(options.telemetry);
|
|
33030
33132
|
}
|
|
33031
33133
|
createCorrelationId() {
|
|
@@ -33033,38 +33135,9 @@ var WABTransport = class {
|
|
|
33033
33135
|
return isSafeCorrelationId(correlationId) ? correlationId : new Telemetry().createCorrelationId();
|
|
33034
33136
|
}
|
|
33035
33137
|
async request(path, options) {
|
|
33036
|
-
const metadata = this.createRequestMetadata(path, options);
|
|
33037
|
-
this.captureRequestStarted(metadata);
|
|
33038
|
-
const body = this.encodeRequestBody(options, metadata);
|
|
33039
|
-
const timeout = this.startRequestTimeout(metadata.errorContext);
|
|
33040
|
-
const response = await this.fetchResponse(metadata, body, timeout);
|
|
33041
|
-
const responseContext = this.createResponseContext(response, metadata);
|
|
33042
|
-
this.assertSuccessfulResponse(response, responseContext, metadata, timeout);
|
|
33043
|
-
const responseText = await this.readResponseText(response, responseContext, metadata, timeout);
|
|
33044
|
-
const parsed = this.parseResponseObject(responseText, response, responseContext, metadata);
|
|
33045
|
-
this.telemetry.capture({
|
|
33046
|
-
name: "wallet-toolbox.wab.request.completed",
|
|
33047
|
-
component: "wallet-toolbox.wab-transport",
|
|
33048
|
-
severity: "info",
|
|
33049
|
-
correlationId: metadata.correlationId,
|
|
33050
|
-
attributes: {
|
|
33051
|
-
operation: metadata.operation,
|
|
33052
|
-
method: metadata.method,
|
|
33053
|
-
route: metadata.path,
|
|
33054
|
-
serverOrigin: this.serverOrigin,
|
|
33055
|
-
status: response.status,
|
|
33056
|
-
endpointMarkerPresent: responseContext.endpointMarkerPresent,
|
|
33057
|
-
responseCorrelationMatched: responseContext.responseCorrelationMatched,
|
|
33058
|
-
responseBytes: new TextEncoder().encode(responseText).byteLength,
|
|
33059
|
-
durationMs: Date.now() - metadata.startedAt
|
|
33060
|
-
}
|
|
33061
|
-
});
|
|
33062
|
-
return parsed;
|
|
33063
|
-
}
|
|
33064
|
-
createRequestMetadata(path, options) {
|
|
33065
33138
|
assertSafePath(path);
|
|
33066
33139
|
const correlationId = options.correlationId != null && isSafeCorrelationId(options.correlationId) ? options.correlationId : this.createCorrelationId();
|
|
33067
|
-
|
|
33140
|
+
const metadata = {
|
|
33068
33141
|
method: options.method ?? "POST",
|
|
33069
33142
|
path,
|
|
33070
33143
|
operation: options.operation,
|
|
@@ -33076,46 +33149,73 @@ var WABTransport = class {
|
|
|
33076
33149
|
route: path
|
|
33077
33150
|
}
|
|
33078
33151
|
};
|
|
33079
|
-
}
|
|
33080
|
-
captureRequestStarted(metadata) {
|
|
33081
33152
|
this.telemetry.capture({
|
|
33082
|
-
name:
|
|
33083
|
-
component:
|
|
33153
|
+
name: `${WAB_REQUEST_EVENT}started`,
|
|
33154
|
+
component: WAB_COMPONENT,
|
|
33084
33155
|
severity: "debug",
|
|
33156
|
+
correlationId,
|
|
33157
|
+
attributes: {
|
|
33158
|
+
operation: metadata.operation,
|
|
33159
|
+
method: metadata.method,
|
|
33160
|
+
route: path,
|
|
33161
|
+
serverOrigin: this.serverOrigin
|
|
33162
|
+
}
|
|
33163
|
+
});
|
|
33164
|
+
const body = this.bodyFor(options, metadata);
|
|
33165
|
+
const timeout = this.startTimer(metadata.errorContext);
|
|
33166
|
+
const response = await this.fetch(metadata, body, timeout);
|
|
33167
|
+
const responseContext = {
|
|
33168
|
+
...metadata.errorContext,
|
|
33169
|
+
endpointMarkerPresent: isWabResponse(response),
|
|
33170
|
+
responseCorrelationMatched: response.headers.get("X-Correlation-ID") === correlationId
|
|
33171
|
+
};
|
|
33172
|
+
this.checkResponse(response, responseContext, metadata, timeout);
|
|
33173
|
+
const responseText = await this.readText(response, responseContext, metadata, timeout);
|
|
33174
|
+
const parsed = this.parse(responseText, response, responseContext, metadata);
|
|
33175
|
+
this.telemetry.capture({
|
|
33176
|
+
name: `${WAB_REQUEST_EVENT}completed`,
|
|
33177
|
+
component: WAB_COMPONENT,
|
|
33178
|
+
severity: "info",
|
|
33085
33179
|
correlationId: metadata.correlationId,
|
|
33086
33180
|
attributes: {
|
|
33087
33181
|
operation: metadata.operation,
|
|
33088
33182
|
method: metadata.method,
|
|
33089
33183
|
route: metadata.path,
|
|
33090
|
-
serverOrigin: this.serverOrigin
|
|
33184
|
+
serverOrigin: this.serverOrigin,
|
|
33185
|
+
status: response.status,
|
|
33186
|
+
endpointMarkerPresent: responseContext.endpointMarkerPresent,
|
|
33187
|
+
responseCorrelationMatched: responseContext.responseCorrelationMatched,
|
|
33188
|
+
responseBytes: new TextEncoder().encode(responseText).byteLength,
|
|
33189
|
+
durationMs: Date.now() - metadata.startedAt
|
|
33091
33190
|
}
|
|
33092
33191
|
});
|
|
33192
|
+
return parsed;
|
|
33093
33193
|
}
|
|
33094
|
-
|
|
33194
|
+
bodyFor(options, metadata) {
|
|
33095
33195
|
let body;
|
|
33096
33196
|
try {
|
|
33097
33197
|
body = options.body === void 0 ? void 0 : JSON.stringify(options.body);
|
|
33098
33198
|
} catch (cause) {
|
|
33099
|
-
const error = new WABClientError("WAB_INVALID_REQUEST", "WAB request
|
|
33199
|
+
const error = new WABClientError("WAB_INVALID_REQUEST", "WAB request encoding failed.", false, void 0, {
|
|
33100
33200
|
...metadata.errorContext,
|
|
33101
33201
|
cause
|
|
33102
33202
|
});
|
|
33103
|
-
this.
|
|
33203
|
+
this.report(metadata, error);
|
|
33104
33204
|
throw error;
|
|
33105
33205
|
}
|
|
33106
33206
|
if (options.body !== void 0 && body === void 0) {
|
|
33107
|
-
const error = new WABClientError("WAB_INVALID_REQUEST", "WAB request
|
|
33108
|
-
this.
|
|
33207
|
+
const error = new WABClientError("WAB_INVALID_REQUEST", "WAB request is not JSON-serializable.", false, void 0, metadata.errorContext);
|
|
33208
|
+
this.report(metadata, error);
|
|
33109
33209
|
throw error;
|
|
33110
33210
|
}
|
|
33111
|
-
if (body != null && new TextEncoder().encode(body).byteLength > this.
|
|
33112
|
-
const error = new WABClientError("WAB_REQUEST_TOO_LARGE", "WAB request
|
|
33113
|
-
this.
|
|
33211
|
+
if (body != null && new TextEncoder().encode(body).byteLength > this.requestLimit) {
|
|
33212
|
+
const error = new WABClientError("WAB_REQUEST_TOO_LARGE", "WAB request exceeds its size limit.", false, void 0, metadata.errorContext);
|
|
33213
|
+
this.report(metadata, error);
|
|
33114
33214
|
throw error;
|
|
33115
33215
|
}
|
|
33116
33216
|
return body;
|
|
33117
33217
|
}
|
|
33118
|
-
|
|
33218
|
+
startTimer(errorContext) {
|
|
33119
33219
|
const timeout = {
|
|
33120
33220
|
controller: new AbortController(),
|
|
33121
33221
|
timedOut: false
|
|
@@ -33125,12 +33225,12 @@ var WABTransport = class {
|
|
|
33125
33225
|
timeout.timedOut = true;
|
|
33126
33226
|
timeout.controller.abort();
|
|
33127
33227
|
reject(new WABClientError("WAB_TIMEOUT", "WAB request timed out.", true, void 0, errorContext));
|
|
33128
|
-
}, this.
|
|
33228
|
+
}, this.timeout);
|
|
33129
33229
|
});
|
|
33130
33230
|
return timeout;
|
|
33131
33231
|
}
|
|
33132
|
-
async
|
|
33133
|
-
const requestPromise = Promise.resolve().then(() => this.
|
|
33232
|
+
async fetch(metadata, body, timeout) {
|
|
33233
|
+
const requestPromise = Promise.resolve().then(() => this.fetcher(`${this.serverUrl}${metadata.path}`, {
|
|
33134
33234
|
method: metadata.method,
|
|
33135
33235
|
headers: {
|
|
33136
33236
|
Accept: "application/json",
|
|
@@ -33154,33 +33254,26 @@ var WABTransport = class {
|
|
|
33154
33254
|
...metadata.errorContext,
|
|
33155
33255
|
cause
|
|
33156
33256
|
});
|
|
33157
|
-
else error = new WABClientError("WAB_NETWORK_ERROR", "WAB request failed before
|
|
33257
|
+
else error = new WABClientError("WAB_NETWORK_ERROR", "WAB request failed before response.", true, void 0, {
|
|
33158
33258
|
...metadata.errorContext,
|
|
33159
33259
|
cause
|
|
33160
33260
|
});
|
|
33161
|
-
this.
|
|
33261
|
+
this.report(metadata, error);
|
|
33162
33262
|
throw error;
|
|
33163
33263
|
}
|
|
33164
33264
|
}
|
|
33165
|
-
|
|
33166
|
-
return {
|
|
33167
|
-
...metadata.errorContext,
|
|
33168
|
-
endpointMarkerPresent: isWabResponse(response),
|
|
33169
|
-
responseCorrelationMatched: response.headers.get("X-Correlation-ID") === metadata.correlationId
|
|
33170
|
-
};
|
|
33171
|
-
}
|
|
33172
|
-
assertSuccessfulResponse(response, responseContext, metadata, timeout) {
|
|
33265
|
+
checkResponse(response, responseContext, metadata, timeout) {
|
|
33173
33266
|
if (response.ok) return;
|
|
33174
33267
|
if (timeout.timer !== void 0) clearTimeout(timeout.timer);
|
|
33175
33268
|
const endpointMismatch = response.status === 404 && responseContext.endpointMarkerPresent !== true;
|
|
33176
|
-
const error = new WABClientError(endpointMismatch ? "WAB_ENDPOINT_MISMATCH" : "WAB_HTTP_ERROR", endpointMismatch ? "
|
|
33177
|
-
this.
|
|
33269
|
+
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);
|
|
33270
|
+
this.report(metadata, error);
|
|
33178
33271
|
response.body?.cancel().catch(() => {});
|
|
33179
33272
|
throw error;
|
|
33180
33273
|
}
|
|
33181
|
-
async
|
|
33274
|
+
async readText(response, responseContext, metadata, timeout) {
|
|
33182
33275
|
try {
|
|
33183
|
-
return await Promise.race([this.
|
|
33276
|
+
return await Promise.race([this.read(response, responseContext), timeout.promise]);
|
|
33184
33277
|
} catch (cause) {
|
|
33185
33278
|
let error;
|
|
33186
33279
|
if (cause instanceof WABClientError) error = cause;
|
|
@@ -33188,17 +33281,17 @@ var WABTransport = class {
|
|
|
33188
33281
|
...responseContext,
|
|
33189
33282
|
cause
|
|
33190
33283
|
});
|
|
33191
|
-
else error = new WABClientError("WAB_INVALID_RESPONSE", "WAB response
|
|
33284
|
+
else error = new WABClientError("WAB_INVALID_RESPONSE", "WAB response read failed.", true, response.status, {
|
|
33192
33285
|
...responseContext,
|
|
33193
33286
|
cause
|
|
33194
33287
|
});
|
|
33195
|
-
this.
|
|
33288
|
+
this.report(metadata, error);
|
|
33196
33289
|
throw error;
|
|
33197
33290
|
} finally {
|
|
33198
33291
|
if (timeout.timer !== void 0) clearTimeout(timeout.timer);
|
|
33199
33292
|
}
|
|
33200
33293
|
}
|
|
33201
|
-
|
|
33294
|
+
parse(responseText, response, responseContext, metadata) {
|
|
33202
33295
|
let parsed;
|
|
33203
33296
|
try {
|
|
33204
33297
|
parsed = JSON.parse(responseText);
|
|
@@ -33207,37 +33300,32 @@ var WABTransport = class {
|
|
|
33207
33300
|
...responseContext,
|
|
33208
33301
|
cause
|
|
33209
33302
|
});
|
|
33210
|
-
this.
|
|
33303
|
+
this.report(metadata, error);
|
|
33211
33304
|
throw error;
|
|
33212
33305
|
}
|
|
33213
33306
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
33214
33307
|
const error = new WABClientError("WAB_INVALID_RESPONSE", "WAB response must be a JSON object.", true, response.status, responseContext);
|
|
33215
|
-
this.
|
|
33308
|
+
this.report(metadata, error);
|
|
33216
33309
|
throw error;
|
|
33217
33310
|
}
|
|
33218
33311
|
return parsed;
|
|
33219
33312
|
}
|
|
33220
|
-
|
|
33221
|
-
this.captureFailure(metadata.operation, metadata.method, metadata.path, metadata.correlationId, metadata.startedAt, error);
|
|
33222
|
-
}
|
|
33223
|
-
async readBoundedResponse(response, responseContext) {
|
|
33224
|
-
await this.rejectOversizedDeclaredResponse(response, responseContext);
|
|
33225
|
-
const reader = response.body?.getReader();
|
|
33226
|
-
if (reader == null) return await this.readBoundedArrayBuffer(response, responseContext);
|
|
33227
|
-
return await this.readBoundedStream(reader, response, responseContext);
|
|
33228
|
-
}
|
|
33229
|
-
async rejectOversizedDeclaredResponse(response, responseContext) {
|
|
33313
|
+
async read(response, responseContext) {
|
|
33230
33314
|
const contentLength = Number(response.headers.get("content-length"));
|
|
33231
|
-
if (
|
|
33232
|
-
|
|
33233
|
-
|
|
33315
|
+
if (Number.isFinite(contentLength) && contentLength > this.responseLimit) {
|
|
33316
|
+
await this.stopBody(response);
|
|
33317
|
+
throw this.sizeError(response, responseContext);
|
|
33318
|
+
}
|
|
33319
|
+
const reader = response.body?.getReader();
|
|
33320
|
+
if (reader == null) return this.readBuffer(response, responseContext);
|
|
33321
|
+
return this.readStream(reader, response, responseContext);
|
|
33234
33322
|
}
|
|
33235
|
-
async
|
|
33323
|
+
async readBuffer(response, responseContext) {
|
|
33236
33324
|
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
33237
|
-
if (bytes.byteLength > this.
|
|
33325
|
+
if (bytes.byteLength > this.responseLimit) throw this.sizeError(response, responseContext);
|
|
33238
33326
|
return new TextDecoder().decode(bytes);
|
|
33239
33327
|
}
|
|
33240
|
-
async
|
|
33328
|
+
async readStream(reader, response, responseContext) {
|
|
33241
33329
|
const chunks = [];
|
|
33242
33330
|
let total = 0;
|
|
33243
33331
|
while (true) {
|
|
@@ -33245,15 +33333,12 @@ var WABTransport = class {
|
|
|
33245
33333
|
if (done) break;
|
|
33246
33334
|
if (value == null) continue;
|
|
33247
33335
|
total += value.byteLength;
|
|
33248
|
-
if (total > this.
|
|
33249
|
-
await this.
|
|
33250
|
-
throw this.
|
|
33336
|
+
if (total > this.responseLimit) {
|
|
33337
|
+
await this.stopReader(reader);
|
|
33338
|
+
throw this.sizeError(response, responseContext);
|
|
33251
33339
|
}
|
|
33252
33340
|
chunks.push(value);
|
|
33253
33341
|
}
|
|
33254
|
-
return this.decodeChunks(chunks, total);
|
|
33255
|
-
}
|
|
33256
|
-
decodeChunks(chunks, total) {
|
|
33257
33342
|
const bytes = new Uint8Array(total);
|
|
33258
33343
|
let offset = 0;
|
|
33259
33344
|
for (const chunk of chunks) {
|
|
@@ -33262,35 +33347,35 @@ var WABTransport = class {
|
|
|
33262
33347
|
}
|
|
33263
33348
|
return new TextDecoder().decode(bytes);
|
|
33264
33349
|
}
|
|
33265
|
-
|
|
33266
|
-
return new WABClientError("WAB_RESPONSE_TOO_LARGE", "WAB response
|
|
33350
|
+
sizeError(response, responseContext) {
|
|
33351
|
+
return new WABClientError("WAB_RESPONSE_TOO_LARGE", "WAB response exceeds its size limit.", false, response.status, responseContext);
|
|
33267
33352
|
}
|
|
33268
|
-
async
|
|
33353
|
+
async stopBody(response) {
|
|
33269
33354
|
try {
|
|
33270
33355
|
await response.body?.cancel();
|
|
33271
33356
|
} catch {}
|
|
33272
33357
|
}
|
|
33273
|
-
async
|
|
33358
|
+
async stopReader(reader) {
|
|
33274
33359
|
try {
|
|
33275
33360
|
await reader.cancel();
|
|
33276
33361
|
} catch {}
|
|
33277
33362
|
}
|
|
33278
|
-
|
|
33363
|
+
report(metadata, error) {
|
|
33279
33364
|
this.telemetry.capture({
|
|
33280
|
-
name:
|
|
33281
|
-
component:
|
|
33365
|
+
name: `${WAB_REQUEST_EVENT}failed`,
|
|
33366
|
+
component: WAB_COMPONENT,
|
|
33282
33367
|
severity: error.retryable ? "warn" : "error",
|
|
33283
|
-
correlationId,
|
|
33368
|
+
correlationId: metadata.correlationId,
|
|
33284
33369
|
attributes: {
|
|
33285
|
-
operation,
|
|
33286
|
-
method,
|
|
33287
|
-
route: path,
|
|
33370
|
+
operation: metadata.operation,
|
|
33371
|
+
method: metadata.method,
|
|
33372
|
+
route: metadata.path,
|
|
33288
33373
|
serverOrigin: this.serverOrigin,
|
|
33289
33374
|
retryable: error.retryable,
|
|
33290
33375
|
...error.status !== void 0 ? { status: error.status } : {},
|
|
33291
33376
|
...error.endpointMarkerPresent !== void 0 ? { endpointMarkerPresent: error.endpointMarkerPresent } : {},
|
|
33292
33377
|
...error.responseCorrelationMatched !== void 0 ? { responseCorrelationMatched: error.responseCorrelationMatched } : {},
|
|
33293
|
-
durationMs: Date.now() - startedAt
|
|
33378
|
+
durationMs: Date.now() - metadata.startedAt
|
|
33294
33379
|
},
|
|
33295
33380
|
error
|
|
33296
33381
|
});
|
|
@@ -33399,8 +33484,8 @@ var WABClient = class {
|
|
|
33399
33484
|
constructor(serverUrl, options = {}) {
|
|
33400
33485
|
this.transport = new WABTransport(serverUrl, options);
|
|
33401
33486
|
}
|
|
33402
|
-
|
|
33403
|
-
return
|
|
33487
|
+
getInfo() {
|
|
33488
|
+
return this.transport.request("/info", {
|
|
33404
33489
|
method: "GET",
|
|
33405
33490
|
operation: "get-info"
|
|
33406
33491
|
});
|
|
@@ -33410,15 +33495,15 @@ var WABClient = class {
|
|
|
33410
33495
|
}
|
|
33411
33496
|
async startAuthMethod(authMethod, presentationKey, payload, correlationId) {
|
|
33412
33497
|
assertHexIdentifier(presentationKey, "presentationKey");
|
|
33413
|
-
return
|
|
33498
|
+
return authMethod.startAuth(this.transport.serverUrl, presentationKey, payload, this.transport, correlationId);
|
|
33414
33499
|
}
|
|
33415
33500
|
async completeAuthMethod(authMethod, presentationKey, payload, correlationId) {
|
|
33416
33501
|
assertHexIdentifier(presentationKey, "presentationKey");
|
|
33417
|
-
return
|
|
33502
|
+
return authMethod.completeAuth(this.transport.serverUrl, presentationKey, payload, this.transport, correlationId);
|
|
33418
33503
|
}
|
|
33419
33504
|
async listLinkedMethods(presentationKey) {
|
|
33420
33505
|
assertHexIdentifier(presentationKey, "presentationKey");
|
|
33421
|
-
return
|
|
33506
|
+
return this.transport.request("/user/linkedMethods", {
|
|
33422
33507
|
operation: "list-linked-methods",
|
|
33423
33508
|
body: { presentationKey }
|
|
33424
33509
|
});
|
|
@@ -33426,7 +33511,7 @@ var WABClient = class {
|
|
|
33426
33511
|
async unlinkMethod(presentationKey, authMethodId) {
|
|
33427
33512
|
assertHexIdentifier(presentationKey, "presentationKey");
|
|
33428
33513
|
if (!Number.isSafeInteger(authMethodId) || authMethodId <= 0) throw new TypeError("authMethodId must be a positive safe integer.");
|
|
33429
|
-
return
|
|
33514
|
+
return this.transport.request("/user/unlinkMethod", {
|
|
33430
33515
|
operation: "unlink-method",
|
|
33431
33516
|
body: {
|
|
33432
33517
|
presentationKey,
|
|
@@ -33436,14 +33521,14 @@ var WABClient = class {
|
|
|
33436
33521
|
}
|
|
33437
33522
|
async requestFaucet(presentationKey) {
|
|
33438
33523
|
assertHexIdentifier(presentationKey, "presentationKey");
|
|
33439
|
-
return
|
|
33524
|
+
return this.transport.request("/faucet/request", {
|
|
33440
33525
|
operation: "request-faucet",
|
|
33441
33526
|
body: { presentationKey }
|
|
33442
33527
|
});
|
|
33443
33528
|
}
|
|
33444
33529
|
async deleteUser(presentationKey) {
|
|
33445
33530
|
assertHexIdentifier(presentationKey, "presentationKey");
|
|
33446
|
-
return
|
|
33531
|
+
return this.transport.request("/user/delete", {
|
|
33447
33532
|
operation: "delete-user",
|
|
33448
33533
|
body: { presentationKey }
|
|
33449
33534
|
});
|
|
@@ -33452,7 +33537,7 @@ var WABClient = class {
|
|
|
33452
33537
|
assertMethodType(methodType);
|
|
33453
33538
|
assertHexIdentifier(userIdHash, "userIdHash");
|
|
33454
33539
|
const normalizedPayload = normalizeAuthPayload(methodType, payload);
|
|
33455
|
-
return
|
|
33540
|
+
return this.transport.request("/auth/start", {
|
|
33456
33541
|
operation: "start-share-auth",
|
|
33457
33542
|
body: {
|
|
33458
33543
|
methodType,
|
|
@@ -33465,7 +33550,7 @@ var WABClient = class {
|
|
|
33465
33550
|
assertMethodType(methodType);
|
|
33466
33551
|
assertHexIdentifier(userIdHash, "userIdHash");
|
|
33467
33552
|
const normalizedPayload = normalizeAuthPayload(methodType, payload);
|
|
33468
|
-
return
|
|
33553
|
+
return this.transport.request("/share/store", {
|
|
33469
33554
|
operation: "store-share",
|
|
33470
33555
|
body: {
|
|
33471
33556
|
methodType,
|
|
@@ -33479,7 +33564,7 @@ var WABClient = class {
|
|
|
33479
33564
|
assertMethodType(methodType);
|
|
33480
33565
|
assertHexIdentifier(userIdHash, "userIdHash");
|
|
33481
33566
|
const normalizedPayload = normalizeAuthPayload(methodType, payload);
|
|
33482
|
-
return
|
|
33567
|
+
return this.transport.request("/share/retrieve", {
|
|
33483
33568
|
operation: "retrieve-share",
|
|
33484
33569
|
body: {
|
|
33485
33570
|
methodType,
|
|
@@ -33492,7 +33577,7 @@ var WABClient = class {
|
|
|
33492
33577
|
assertMethodType(methodType);
|
|
33493
33578
|
assertHexIdentifier(userIdHash, "userIdHash");
|
|
33494
33579
|
const normalizedPayload = normalizeAuthPayload(methodType, payload);
|
|
33495
|
-
return
|
|
33580
|
+
return this.transport.request("/share/update", {
|
|
33496
33581
|
operation: "update-share",
|
|
33497
33582
|
body: {
|
|
33498
33583
|
methodType,
|
|
@@ -33506,7 +33591,7 @@ var WABClient = class {
|
|
|
33506
33591
|
assertMethodType(methodType);
|
|
33507
33592
|
assertHexIdentifier(userIdHash, "userIdHash");
|
|
33508
33593
|
const normalizedPayload = normalizeAuthPayload(methodType, payload);
|
|
33509
|
-
return
|
|
33594
|
+
return this.transport.request("/share/delete", {
|
|
33510
33595
|
operation: "delete-share-user",
|
|
33511
33596
|
body: {
|
|
33512
33597
|
methodType,
|
|
@@ -33520,9 +33605,13 @@ var WABClient = class {
|
|
|
33520
33605
|
//#region ../src/WalletAuthenticationManager.ts
|
|
33521
33606
|
const DEFAULT_AUTH_SESSION_TTL_MS = 600 * 1e3;
|
|
33522
33607
|
const MAX_AUTH_SESSION_TTL_MS = 3600 * 1e3;
|
|
33608
|
+
const AUTH_COMPONENT = "wallet-toolbox.authentication-manager";
|
|
33609
|
+
const AUTH_EVENT = "wallet-toolbox.authentication.";
|
|
33610
|
+
const EXISTING_USER = "existing-user";
|
|
33611
|
+
const NEW_USER = "new-user";
|
|
33523
33612
|
var WABAccountContinuityError = class extends Error {
|
|
33524
33613
|
code = "WERR_WAB_ACCOUNT_CONTINUITY";
|
|
33525
|
-
constructor(message = "WAB and UMP
|
|
33614
|
+
constructor(message = "WAB and UMP accounts disagree; retry or recover.") {
|
|
33526
33615
|
super(message);
|
|
33527
33616
|
this.name = "WABAccountContinuityError";
|
|
33528
33617
|
}
|
|
@@ -33537,6 +33626,7 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
|
|
|
33537
33626
|
wabClient;
|
|
33538
33627
|
authMethod;
|
|
33539
33628
|
authSession;
|
|
33629
|
+
phoneChangeSession;
|
|
33540
33630
|
authSessionTtlMs;
|
|
33541
33631
|
constructor(...[adminOriginator, walletBuilder, interactor, recoveryKeySaver, passwordRetriever, wabClient, authMethod, stateSnapshot, options = {}]) {
|
|
33542
33632
|
super(adminOriginator, walletBuilder, interactor, recoveryKeySaver, passwordRetriever, async (presentationKey, wallet, adminOriginator) => {
|
|
@@ -33559,7 +33649,7 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
|
|
|
33559
33649
|
description: "Fund wallet",
|
|
33560
33650
|
options: { acceptDelayedBroadcast: false }
|
|
33561
33651
|
}, adminOriginator);
|
|
33562
|
-
if (faucetRedeemTXCreationResult.signableTransaction == null) throw new Error("Faucet redemption
|
|
33652
|
+
if (faucetRedeemTXCreationResult.signableTransaction == null) throw new Error("Faucet redemption was not signable.");
|
|
33563
33653
|
const faucetRedeemTX = Transaction.fromAtomicBEEF(faucetRedeemTXCreationResult.signableTransaction.tx);
|
|
33564
33654
|
const faucetRedemptionPuzzle = new RPuzzle();
|
|
33565
33655
|
const randomRedemptionPrivateKey = PrivateKey.fromRandom();
|
|
@@ -33592,7 +33682,7 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
|
|
|
33592
33682
|
* using the chosen AuthMethodInteractor.
|
|
33593
33683
|
*/
|
|
33594
33684
|
async startAuth(payload) {
|
|
33595
|
-
if (this.authMethod == null) throw new Error("No
|
|
33685
|
+
if (this.authMethod == null) throw new Error("No WAB authentication method selected.");
|
|
33596
33686
|
const authMethod = this.authMethod;
|
|
33597
33687
|
if (this.authenticated) throw new Error("User is already authenticated");
|
|
33598
33688
|
this.cancelAuth();
|
|
@@ -33605,8 +33695,8 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
|
|
|
33605
33695
|
...correlationId !== void 0 ? { correlationId } : {}
|
|
33606
33696
|
};
|
|
33607
33697
|
this.telemetry.capture({
|
|
33608
|
-
name:
|
|
33609
|
-
component:
|
|
33698
|
+
name: `${AUTH_EVENT}wab-start.started`,
|
|
33699
|
+
component: AUTH_COMPONENT,
|
|
33610
33700
|
severity: "debug",
|
|
33611
33701
|
correlationId,
|
|
33612
33702
|
attributes: { methodType: authMethod.methodType }
|
|
@@ -33618,8 +33708,8 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
|
|
|
33618
33708
|
throw new Error(message);
|
|
33619
33709
|
}
|
|
33620
33710
|
this.telemetry.capture({
|
|
33621
|
-
name:
|
|
33622
|
-
component:
|
|
33711
|
+
name: `${AUTH_EVENT}wab-start.completed`,
|
|
33712
|
+
component: AUTH_COMPONENT,
|
|
33623
33713
|
severity: "info",
|
|
33624
33714
|
correlationId,
|
|
33625
33715
|
attributes: { methodType: authMethod.methodType }
|
|
@@ -33627,8 +33717,8 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
|
|
|
33627
33717
|
} catch (error) {
|
|
33628
33718
|
this.cancelAuth();
|
|
33629
33719
|
this.telemetry.capture({
|
|
33630
|
-
name:
|
|
33631
|
-
component:
|
|
33720
|
+
name: `${AUTH_EVENT}wab-start.failed`,
|
|
33721
|
+
component: AUTH_COMPONENT,
|
|
33632
33722
|
severity: "warn",
|
|
33633
33723
|
correlationId,
|
|
33634
33724
|
attributes: { methodType: authMethod.methodType },
|
|
@@ -33641,22 +33731,22 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
|
|
|
33641
33731
|
* Completes the WAB-based flow, retrieving the final presentationKey from WAB if successful.
|
|
33642
33732
|
*/
|
|
33643
33733
|
async completeAuth(payload) {
|
|
33644
|
-
if (this.authMethod == null || this.authSession == null) throw new Error("
|
|
33734
|
+
if (this.authMethod == null || this.authSession == null) throw new Error("Start WAB authentication first.");
|
|
33645
33735
|
const authMethod = this.authMethod;
|
|
33646
33736
|
if (this.authSession.methodType !== authMethod.methodType) {
|
|
33647
33737
|
this.cancelAuth();
|
|
33648
|
-
throw new Error("
|
|
33738
|
+
throw new Error("WAB authentication method changed; restart.");
|
|
33649
33739
|
}
|
|
33650
33740
|
if (Date.now() >= this.authSession.expiresAt) {
|
|
33651
33741
|
this.cancelAuth();
|
|
33652
|
-
throw new Error("
|
|
33742
|
+
throw new Error("WAB authentication expired; restart.");
|
|
33653
33743
|
}
|
|
33654
33744
|
const session = this.authSession;
|
|
33655
33745
|
const result = await this.wabClient.completeAuthMethod(authMethod, session.presentationKey, payload, session.correlationId);
|
|
33656
33746
|
if (result.success !== true || result.presentationKey == null || result.presentationKey.length === 0) {
|
|
33657
33747
|
this.telemetry.capture({
|
|
33658
|
-
name:
|
|
33659
|
-
component:
|
|
33748
|
+
name: `${AUTH_EVENT}wab-complete.rejected`,
|
|
33749
|
+
component: AUTH_COMPONENT,
|
|
33660
33750
|
severity: "warn",
|
|
33661
33751
|
correlationId: session.correlationId,
|
|
33662
33752
|
attributes: { methodType: session.methodType }
|
|
@@ -33671,11 +33761,11 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
|
|
|
33671
33761
|
this.cancelAuth();
|
|
33672
33762
|
const wabAccountStatus = this.inferAccountStatus(result, session.presentationKey);
|
|
33673
33763
|
try {
|
|
33674
|
-
await this.
|
|
33764
|
+
await this.provideWABPresentationKey(result, wabAccountStatus);
|
|
33675
33765
|
} catch (error) {
|
|
33676
33766
|
this.telemetry.capture({
|
|
33677
|
-
name:
|
|
33678
|
-
component:
|
|
33767
|
+
name: `${AUTH_EVENT}ump-continuity.failed`,
|
|
33768
|
+
component: AUTH_COMPONENT,
|
|
33679
33769
|
severity: "warn",
|
|
33680
33770
|
correlationId: session.correlationId,
|
|
33681
33771
|
attributes: {
|
|
@@ -33686,18 +33776,18 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
|
|
|
33686
33776
|
});
|
|
33687
33777
|
throw error;
|
|
33688
33778
|
}
|
|
33689
|
-
if (wabAccountStatus ===
|
|
33779
|
+
if (wabAccountStatus === EXISTING_USER && this.authenticationFlow !== EXISTING_USER) {
|
|
33690
33780
|
super.destroy();
|
|
33691
33781
|
const error = new WABAccountContinuityError();
|
|
33692
33782
|
this.telemetry.capture({
|
|
33693
|
-
name:
|
|
33694
|
-
component:
|
|
33783
|
+
name: `${AUTH_EVENT}account-continuity.mismatch`,
|
|
33784
|
+
component: AUTH_COMPONENT,
|
|
33695
33785
|
severity: "error",
|
|
33696
33786
|
correlationId: session.correlationId,
|
|
33697
33787
|
attributes: {
|
|
33698
33788
|
methodType: session.methodType,
|
|
33699
33789
|
wabAccountStatus,
|
|
33700
|
-
umpAccountStatus:
|
|
33790
|
+
umpAccountStatus: NEW_USER
|
|
33701
33791
|
},
|
|
33702
33792
|
error
|
|
33703
33793
|
});
|
|
@@ -33705,8 +33795,8 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
|
|
|
33705
33795
|
}
|
|
33706
33796
|
const continuity = wabAccountStatus === this.authenticationFlow ? "matched" : "ump-existing";
|
|
33707
33797
|
this.telemetry.capture({
|
|
33708
|
-
name:
|
|
33709
|
-
component:
|
|
33798
|
+
name: `${AUTH_EVENT}completed`,
|
|
33799
|
+
component: AUTH_COMPONENT,
|
|
33710
33800
|
severity: continuity === "matched" ? "info" : "warn",
|
|
33711
33801
|
correlationId: session.correlationId,
|
|
33712
33802
|
attributes: {
|
|
@@ -33720,23 +33810,131 @@ var WalletAuthenticationManager = class extends CWIStyleWalletManager {
|
|
|
33720
33810
|
cancelAuth() {
|
|
33721
33811
|
this.authSession = void 0;
|
|
33722
33812
|
}
|
|
33813
|
+
readPendingPhoneChange(result) {
|
|
33814
|
+
const presentationKey = result.pendingPresentationKey;
|
|
33815
|
+
const changeId = result.pendingPhoneChangeId;
|
|
33816
|
+
if (presentationKey === void 0 && changeId === void 0) return void 0;
|
|
33817
|
+
if (!/^[0-9a-fA-F]{64}$/.test(presentationKey ?? "") || !Number.isSafeInteger(changeId) || changeId <= 0) throw new WABAccountContinuityError("WAB returned invalid pending phone-change data.");
|
|
33818
|
+
return {
|
|
33819
|
+
presentationKey,
|
|
33820
|
+
changeId
|
|
33821
|
+
};
|
|
33822
|
+
}
|
|
33823
|
+
async provideWABPresentationKey(result, wabAccountStatus) {
|
|
33824
|
+
const umpTokenOutpoint = typeof result.umpTokenOutpoint === "string" ? result.umpTokenOutpoint : void 0;
|
|
33825
|
+
const lookupOptions = umpTokenOutpoint == null ? void 0 : { pinnedOutpoint: umpTokenOutpoint };
|
|
33826
|
+
const pending = this.readPendingPhoneChange(result);
|
|
33827
|
+
let usePending = false;
|
|
33828
|
+
try {
|
|
33829
|
+
await this.providePresentationKey(Utils.toArray(result.presentationKey, "hex"), lookupOptions);
|
|
33830
|
+
} catch (error) {
|
|
33831
|
+
if (pending == null) throw error;
|
|
33832
|
+
usePending = true;
|
|
33833
|
+
}
|
|
33834
|
+
if (pending != null && (usePending || wabAccountStatus === EXISTING_USER && this.authenticationFlow !== EXISTING_USER)) {
|
|
33835
|
+
await this.providePresentationKey(Utils.toArray(pending.presentationKey, "hex"), lookupOptions);
|
|
33836
|
+
if (this.authenticationFlow === EXISTING_USER) await this.finalizePendingPhoneChange(result.presentationKey, pending);
|
|
33837
|
+
}
|
|
33838
|
+
}
|
|
33839
|
+
async finalizePendingPhoneChange(currentPresentationKey, pending) {
|
|
33840
|
+
const finalized = await this.phoneChange("finalize", {
|
|
33841
|
+
changeId: pending.changeId,
|
|
33842
|
+
presentationKey: currentPresentationKey,
|
|
33843
|
+
newPresentationKey: pending.presentationKey
|
|
33844
|
+
});
|
|
33845
|
+
if (finalized.success !== true || finalized.changeId !== pending.changeId) throw new WABAccountContinuityError(finalized.message || "WAB could not finalize the pending phone change.");
|
|
33846
|
+
}
|
|
33847
|
+
/**
|
|
33848
|
+
* Starts OTP verification for a replacement phone number. The same number
|
|
33849
|
+
* is valid and intentionally produces a fresh presentation key/hash.
|
|
33850
|
+
*/
|
|
33851
|
+
async startPhoneNumberChange(phoneNumber) {
|
|
33852
|
+
if (!this.authenticated) throw new Error("Not authenticated");
|
|
33853
|
+
const normalizedPhone = phoneNumber.trim();
|
|
33854
|
+
const currentPresentationKey = Utils.toHex(await this.getFactor("presentationKey"));
|
|
33855
|
+
const response = await this.phoneChange("start", {
|
|
33856
|
+
presentationKey: currentPresentationKey,
|
|
33857
|
+
phoneNumber: normalizedPhone
|
|
33858
|
+
});
|
|
33859
|
+
if (response.success !== true) throw new Error(response.message || "Phone change failed");
|
|
33860
|
+
this.phoneChangeSession = {
|
|
33861
|
+
phoneNumber: normalizedPhone,
|
|
33862
|
+
presentationKey: currentPresentationKey
|
|
33863
|
+
};
|
|
33864
|
+
}
|
|
33865
|
+
/**
|
|
33866
|
+
* Completes phone verification and stages the WAB association before
|
|
33867
|
+
* publishing the UMP key rotation. WAB retains both the current and pending
|
|
33868
|
+
* presentation keys until finalization, so either side of an interrupted
|
|
33869
|
+
* transition remains recoverable on the next verified login.
|
|
33870
|
+
*/
|
|
33871
|
+
async completePhoneNumberChange(otp) {
|
|
33872
|
+
const session = this.phoneChangeSession;
|
|
33873
|
+
if (session == null) throw new Error("No phone change");
|
|
33874
|
+
if (session.changeToken == null) {
|
|
33875
|
+
const authorization = await this.phoneChange("complete", {
|
|
33876
|
+
presentationKey: session.presentationKey,
|
|
33877
|
+
phoneNumber: session.phoneNumber,
|
|
33878
|
+
otp: otp.trim()
|
|
33879
|
+
});
|
|
33880
|
+
if (authorization.success !== true) throw new Error(authorization.message || "Phone change failed");
|
|
33881
|
+
if (/^[0-9a-fA-F]{64}$/.test(authorization.pendingPresentationKey ?? "") && Number.isSafeInteger(authorization.pendingPhoneChangeId) && authorization.pendingPhoneChangeId > 0) {
|
|
33882
|
+
session.newKey = Utils.toArray(authorization.pendingPresentationKey, "hex");
|
|
33883
|
+
session.changeId = authorization.pendingPhoneChangeId;
|
|
33884
|
+
} else if (typeof authorization.changeToken === "string" && authorization.changeToken.length > 0) session.changeToken = authorization.changeToken;
|
|
33885
|
+
else throw new Error(authorization.message || "Phone change failed");
|
|
33886
|
+
}
|
|
33887
|
+
session.newKey ??= Random(32);
|
|
33888
|
+
if (session.changeId == null) {
|
|
33889
|
+
const committed = await this.phoneChange("commit", {
|
|
33890
|
+
changeToken: session.changeToken,
|
|
33891
|
+
presentationKey: session.presentationKey,
|
|
33892
|
+
newPresentationKey: Utils.toHex(session.newKey)
|
|
33893
|
+
});
|
|
33894
|
+
if (committed.success !== true || !Number.isSafeInteger(committed.changeId) || committed.changeId <= 0) throw new Error(committed.message || "Phone change failed");
|
|
33895
|
+
session.changeId = committed.changeId;
|
|
33896
|
+
}
|
|
33897
|
+
const changeId = session.changeId;
|
|
33898
|
+
if (session.umpUpdated !== true) {
|
|
33899
|
+
await this.changePresentationKey(session.newKey);
|
|
33900
|
+
session.umpUpdated = true;
|
|
33901
|
+
}
|
|
33902
|
+
const finalized = await this.phoneChange("finalize", {
|
|
33903
|
+
changeId,
|
|
33904
|
+
presentationKey: session.presentationKey,
|
|
33905
|
+
newPresentationKey: Utils.toHex(session.newKey)
|
|
33906
|
+
});
|
|
33907
|
+
if (finalized.success !== true || finalized.changeId !== changeId) throw new Error(finalized.message || "Phone change failed");
|
|
33908
|
+
this.phoneChangeSession = void 0;
|
|
33909
|
+
return { changeId };
|
|
33910
|
+
}
|
|
33911
|
+
cancelPhoneNumberChange() {
|
|
33912
|
+
this.phoneChangeSession = void 0;
|
|
33913
|
+
}
|
|
33723
33914
|
destroy() {
|
|
33724
33915
|
this.cancelAuth();
|
|
33916
|
+
this.cancelPhoneNumberChange();
|
|
33725
33917
|
super.destroy();
|
|
33726
33918
|
}
|
|
33919
|
+
phoneChange(phase, body) {
|
|
33920
|
+
return this.wabClient.transport.request(`/auth/phone-change/${phase}`, {
|
|
33921
|
+
operation: "phone-change",
|
|
33922
|
+
body
|
|
33923
|
+
});
|
|
33924
|
+
}
|
|
33727
33925
|
inferAccountStatus(result, temporaryPresentationKey) {
|
|
33728
33926
|
if (result.presentationKey == null) throw new WABAccountContinuityError("WAB did not return a presentation key.");
|
|
33729
33927
|
const keyMatchesTemporary = this.constantTimeHexEqual(result.presentationKey, temporaryPresentationKey);
|
|
33730
33928
|
const rawAccountStatus = result.accountStatus;
|
|
33731
|
-
if (rawAccountStatus !== void 0 && rawAccountStatus !==
|
|
33929
|
+
if (rawAccountStatus !== void 0 && rawAccountStatus !== NEW_USER && rawAccountStatus !== EXISTING_USER) throw new WABAccountContinuityError("WAB returned an invalid account status.");
|
|
33732
33930
|
const rawExistingUser = result.existingUser;
|
|
33733
|
-
if (rawExistingUser !== void 0 && typeof rawExistingUser !== "boolean") throw new WABAccountContinuityError("WAB returned
|
|
33734
|
-
if (rawAccountStatus !== void 0 && rawExistingUser !== void 0 && rawAccountStatus ===
|
|
33931
|
+
if (rawExistingUser !== void 0 && typeof rawExistingUser !== "boolean") throw new WABAccountContinuityError("WAB returned invalid existing-user data.");
|
|
33932
|
+
if (rawAccountStatus !== void 0 && rawExistingUser !== void 0 && rawAccountStatus === EXISTING_USER !== rawExistingUser) throw new WABAccountContinuityError("WAB returned conflicting account status.");
|
|
33735
33933
|
let compatibilityStatus;
|
|
33736
|
-
if (typeof rawExistingUser === "boolean") compatibilityStatus = rawExistingUser ?
|
|
33934
|
+
if (typeof rawExistingUser === "boolean") compatibilityStatus = rawExistingUser ? EXISTING_USER : NEW_USER;
|
|
33737
33935
|
const explicitStatus = rawAccountStatus ?? compatibilityStatus;
|
|
33738
|
-
if (explicitStatus ===
|
|
33739
|
-
return explicitStatus ?? (keyMatchesTemporary ?
|
|
33936
|
+
if (explicitStatus === NEW_USER && !keyMatchesTemporary || explicitStatus === EXISTING_USER && keyMatchesTemporary) throw new WABAccountContinuityError("WAB returned conflicting account status.");
|
|
33937
|
+
return explicitStatus ?? (keyMatchesTemporary ? NEW_USER : EXISTING_USER);
|
|
33740
33938
|
}
|
|
33741
33939
|
constantTimeHexEqual(left, right) {
|
|
33742
33940
|
if (left.length !== right.length) return false;
|