@candledottv/cli 0.11.34 → 0.11.35
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/dist/index.js +40 -72
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -28392,6 +28392,7 @@ __export(exports_vault_support, {
|
|
|
28392
28392
|
vaultAlreadyExists: () => vaultAlreadyExists,
|
|
28393
28393
|
usage: () => usage,
|
|
28394
28394
|
unlockInteractively: () => unlockInteractively,
|
|
28395
|
+
typedConfirm: () => typedConfirm,
|
|
28395
28396
|
takeRepeatedFlag: () => takeRepeatedFlag,
|
|
28396
28397
|
runVaultCommand: () => runVaultCommand,
|
|
28397
28398
|
requireVaultRaw: () => requireVaultRaw,
|
|
@@ -28413,7 +28414,7 @@ __export(exports_vault_support, {
|
|
|
28413
28414
|
describeEntry: () => describeEntry,
|
|
28414
28415
|
derivationNotice: () => derivationNotice,
|
|
28415
28416
|
confirmSend: () => confirmSend,
|
|
28416
|
-
|
|
28417
|
+
confirmAddress: () => confirmAddress,
|
|
28417
28418
|
assertVaultHelperIdentities: () => assertVaultHelperIdentities,
|
|
28418
28419
|
assertNotOlderCopy: () => assertNotOlderCopy,
|
|
28419
28420
|
askForOwnPassphrase: () => askForOwnPassphrase,
|
|
@@ -28947,21 +28948,6 @@ async function assertNotOlderCopy(ctx, path, raw, accept) {
|
|
|
28947
28948
|
ctx.deps.stderr.write(`Opening an older copy: generation ${String(generation)} against the ${sidecar.lastGeneration} this machine last saw.${detail}
|
|
28948
28949
|
`);
|
|
28949
28950
|
}
|
|
28950
|
-
async function confirmLastSix(ctx, address, what) {
|
|
28951
|
-
const expected = address.slice(-6);
|
|
28952
|
-
const normalize3 = (value) => address.startsWith("0x") ? value.toLowerCase() : value;
|
|
28953
|
-
for (let attempt = 0;attempt < 3; attempt++) {
|
|
28954
|
-
const typed = (await ctx.deps.promptLine(`Type the last six characters of ${what} (${address}) to confirm: `)).trim();
|
|
28955
|
-
if (normalize3(typed) === normalize3(expected))
|
|
28956
|
-
return;
|
|
28957
|
-
const difference = Array.from({ length: Math.max(expected.length, typed.length) }, (_, i) => i).find((i) => normalize3(typed)[i] !== normalize3(expected)[i]) ?? 0;
|
|
28958
|
-
ctx.deps.stderr.write(`Expected ${expected}
|
|
28959
|
-
You typed ${typed}
|
|
28960
|
-
${" ".repeat(10 + difference)}^ character ${difference + 1} differs
|
|
28961
|
-
`);
|
|
28962
|
-
}
|
|
28963
|
-
throw new VaultError("DESTINATION_NOT_CONFIRMED", "That is not the last six characters of that address; nothing was done.", { suggestion: "Nothing was signed. Run it again and type the last six characters exactly as shown." });
|
|
28964
|
-
}
|
|
28965
28951
|
function groupAddress(address) {
|
|
28966
28952
|
const prefix = address.startsWith("0x") ? "0x" : "";
|
|
28967
28953
|
const body = address.slice(prefix.length);
|
|
@@ -28972,16 +28958,26 @@ function describeSend(amount, asset, to) {
|
|
|
28972
28958
|
return `send ${amount}${asset !== undefined ? ` ${asset}` : ""} to ${to}`;
|
|
28973
28959
|
}
|
|
28974
28960
|
async function confirmSend(ctx, send) {
|
|
28975
|
-
|
|
28976
|
-
display.write(`to ${groupAddress(send.address)}
|
|
28977
|
-
`);
|
|
28978
|
-
const typed = await ctx.deps.promptLine(`Type confirm to ${describeSend(send.amount, send.asset, send.address)}: `);
|
|
28979
|
-
if (typed.trim().toLowerCase() === "confirm")
|
|
28961
|
+
if (await typedConfirm(ctx, "to", send.address, describeSend(send.amount, send.asset, send.address)))
|
|
28980
28962
|
return;
|
|
28981
28963
|
throw new VaultError("DESTINATION_NOT_CONFIRMED", "The send was not confirmed; nothing was done.", {
|
|
28982
28964
|
suggestion: "Nothing was signed. Run it again and type confirm at the prompt."
|
|
28983
28965
|
});
|
|
28984
28966
|
}
|
|
28967
|
+
async function confirmAddress(ctx, label, address, action) {
|
|
28968
|
+
if (await typedConfirm(ctx, label, address, action))
|
|
28969
|
+
return;
|
|
28970
|
+
throw new VaultError("DESTINATION_NOT_CONFIRMED", "That was not confirmed; nothing was done.", {
|
|
28971
|
+
suggestion: "Nothing was signed or written. Run it again and type confirm at the prompt."
|
|
28972
|
+
});
|
|
28973
|
+
}
|
|
28974
|
+
async function typedConfirm(io, label, address, action) {
|
|
28975
|
+
const display = io.json ? io.deps.stderr : io.deps.stdout;
|
|
28976
|
+
display.write(`${label.padEnd(4)} ${groupAddress(address)}
|
|
28977
|
+
`);
|
|
28978
|
+
const typed = await io.deps.promptLine(`Type confirm to ${action}: `);
|
|
28979
|
+
return typed.trim().toLowerCase() === "confirm";
|
|
28980
|
+
}
|
|
28985
28981
|
function writeVaultFailure(ctx, error) {
|
|
28986
28982
|
if (isUsageError(error))
|
|
28987
28983
|
return usage(ctx, error.message);
|
|
@@ -29561,7 +29557,7 @@ async function maybeReconcileVaultTee(ctx, resolved, caller = "default") {
|
|
|
29561
29557
|
ctx.deps.stdout.write(`This profile acts as account ${cached}.
|
|
29562
29558
|
`);
|
|
29563
29559
|
try {
|
|
29564
|
-
await
|
|
29560
|
+
await confirmAddress(ctx, "account", cached, `act as account ${cached}`);
|
|
29565
29561
|
assertedAccount = cached;
|
|
29566
29562
|
} catch (error) {
|
|
29567
29563
|
if (isVaultError(error)) {
|
|
@@ -29622,7 +29618,7 @@ async function maybeReconcileVaultTee(ctx, resolved, caller = "default") {
|
|
|
29622
29618
|
const adoption = await adoptGrantedRow(ctx, resolved.entry, verdict.row, verdict.account, {
|
|
29623
29619
|
confirmDestination: async (destination) => {
|
|
29624
29620
|
try {
|
|
29625
|
-
await
|
|
29621
|
+
await confirmAddress(ctx, "vault", destination, `accept ${destination} as the sweep vault`);
|
|
29626
29622
|
return true;
|
|
29627
29623
|
} catch {
|
|
29628
29624
|
return false;
|
|
@@ -33841,7 +33837,7 @@ async function sweepEvmWallet(input) {
|
|
|
33841
33837
|
let stopped;
|
|
33842
33838
|
const somethingToMove = planned.length > 0 || ethBalance > 0n;
|
|
33843
33839
|
if (somethingToMove) {
|
|
33844
|
-
await
|
|
33840
|
+
await confirmAddress(ctx, "vault", destination, `sweep everything to ${destination}`);
|
|
33845
33841
|
const stopRequestedAt = entry.tee?.stopRequestedAt ?? new Date(deps.now()).toISOString();
|
|
33846
33842
|
vault = hold(await patchTee(ctx, vault, entry.id, (tee) => ({ ...tee, stopRequestedAt })));
|
|
33847
33843
|
if (!emergency)
|
|
@@ -34859,9 +34855,8 @@ function isSolanaAddress(value) {
|
|
|
34859
34855
|
return false;
|
|
34860
34856
|
}
|
|
34861
34857
|
}
|
|
34862
|
-
|
|
34863
|
-
|
|
34864
|
-
return typed === vault.slice(-6);
|
|
34858
|
+
function confirmVault(deps, json, vault, action) {
|
|
34859
|
+
return typedConfirm({ deps, json }, "vault", vault, action);
|
|
34865
34860
|
}
|
|
34866
34861
|
async function teeNew(args, ctx) {
|
|
34867
34862
|
const { deps, json } = ctx;
|
|
@@ -35058,8 +35053,8 @@ async function teeEnable(args, ctx) {
|
|
|
35058
35053
|
deps.stdout.write(`compromised agent within those limits. Once enabled a copy of this key stays in the TEE for good.
|
|
35059
35054
|
`);
|
|
35060
35055
|
}
|
|
35061
|
-
if (!await confirmVault(deps, vault)) {
|
|
35062
|
-
writeLocalFailure(deps, { code: "VAULT_NOT_CONFIRMED", message: "The vault
|
|
35056
|
+
if (!await confirmVault(deps, json, vault, `enable this TEE wallet with sweeps to ${vault}`)) {
|
|
35057
|
+
writeLocalFailure(deps, { code: "VAULT_NOT_CONFIRMED", message: "The vault was not confirmed. Nothing was enabled." }, json);
|
|
35063
35058
|
return 1;
|
|
35064
35059
|
}
|
|
35065
35060
|
const flow = await runImportFlow({
|
|
@@ -35719,8 +35714,8 @@ Stop the agent from your Candle session if you have not, and re-run candle tee d
|
|
|
35719
35714
|
deps.stdout.write(`Sweep ${address} -> vault ${vault} (solana-mainnet)
|
|
35720
35715
|
`);
|
|
35721
35716
|
}
|
|
35722
|
-
if (!await confirmVault(deps, vault)) {
|
|
35723
|
-
writeLocalFailure(deps, { code: "VAULT_NOT_CONFIRMED", message: "The vault
|
|
35717
|
+
if (!await confirmVault(deps, json, vault, `sweep everything to ${vault}`)) {
|
|
35718
|
+
writeLocalFailure(deps, { code: "VAULT_NOT_CONFIRMED", message: "The vault was not confirmed. Nothing was signed." }, json);
|
|
35724
35719
|
return 1;
|
|
35725
35720
|
}
|
|
35726
35721
|
const secret = base58.decode(entry.privateKey);
|
|
@@ -36436,6 +36431,7 @@ var init_tee = __esm(() => {
|
|
|
36436
36431
|
init_tee_evm();
|
|
36437
36432
|
init_tee_status_evm();
|
|
36438
36433
|
init_tee_status_wallet();
|
|
36434
|
+
init_vault_support();
|
|
36439
36435
|
init_wallets();
|
|
36440
36436
|
StoreChangedError = class StoreChangedError extends Error {
|
|
36441
36437
|
};
|
|
@@ -70287,7 +70283,7 @@ init_render();
|
|
|
70287
70283
|
init_secret_store();
|
|
70288
70284
|
|
|
70289
70285
|
// src/version.ts
|
|
70290
|
-
var CLI_VERSION = "0.11.
|
|
70286
|
+
var CLI_VERSION = "0.11.35";
|
|
70291
70287
|
|
|
70292
70288
|
// src/commands/auth.ts
|
|
70293
70289
|
init_keys_embedded_wallet();
|
|
@@ -71536,7 +71532,7 @@ var HELP = {
|
|
|
71536
71532
|
},
|
|
71537
71533
|
{
|
|
71538
71534
|
invocation: "export-key <label> --to <new-file>",
|
|
71539
|
-
description: "Export one key as plaintext (interactive ceremony)"
|
|
71535
|
+
description: "Export one key as plaintext (interactive ceremony: unlock, then type confirm under the address)"
|
|
71540
71536
|
}
|
|
71541
71537
|
],
|
|
71542
71538
|
flags: [
|
|
@@ -72872,14 +72868,6 @@ function groupAddress2(address) {
|
|
|
72872
72868
|
function confirmTyped(typed) {
|
|
72873
72869
|
return typeof typed === "string" && typed.trim().toLowerCase() === "confirm";
|
|
72874
72870
|
}
|
|
72875
|
-
function lastSixMismatch(address, typed) {
|
|
72876
|
-
const expected = address.slice(-6);
|
|
72877
|
-
const given = typeof typed === "string" ? typed.trim() : "";
|
|
72878
|
-
const fold = (value) => address.startsWith("0x") ? value.toLowerCase() : value;
|
|
72879
|
-
if (fold(given) === fold(expected))
|
|
72880
|
-
return;
|
|
72881
|
-
return Array.from({ length: Math.max(expected.length, given.length) }, (_, i) => i).find((i) => fold(given)[i] !== fold(expected)[i]) ?? 0;
|
|
72882
|
-
}
|
|
72883
72871
|
function rawToDecimal(raw, decimals) {
|
|
72884
72872
|
const text = raw.toString().padStart(decimals + 1, "0");
|
|
72885
72873
|
const whole = text.slice(0, text.length - decimals);
|
|
@@ -72963,7 +72951,6 @@ var TRANSFER_TOOLS = {
|
|
|
72963
72951
|
vault: "core_vault_transfer",
|
|
72964
72952
|
embedded: "candle_transfer"
|
|
72965
72953
|
};
|
|
72966
|
-
var LAST_SIX_TRIES = 3;
|
|
72967
72954
|
var OPEN_CARD_CAP = 5;
|
|
72968
72955
|
var MAX_REASON = 500;
|
|
72969
72956
|
var MAX_PARAMS_BYTES = 64 * 1024;
|
|
@@ -73399,25 +73386,6 @@ class CardBook {
|
|
|
73399
73386
|
step: "confirm"
|
|
73400
73387
|
});
|
|
73401
73388
|
}
|
|
73402
|
-
const differsAt = lastSixMismatch(params.to, confirm?.lastSix);
|
|
73403
|
-
if (differsAt !== undefined) {
|
|
73404
|
-
card2.lastSixFailures = (card2.lastSixFailures ?? 0) + 1;
|
|
73405
|
-
const left = LAST_SIX_TRIES - card2.lastSixFailures;
|
|
73406
|
-
if (left <= 0) {
|
|
73407
|
-
await this.deps.journal.append({
|
|
73408
|
-
type: "approval.refused",
|
|
73409
|
-
cardId: card2.cardId,
|
|
73410
|
-
viewClientId,
|
|
73411
|
-
code: "DESTINATION_NOT_CONFIRMED",
|
|
73412
|
-
step: "lastSix",
|
|
73413
|
-
withdrawn: true
|
|
73414
|
-
});
|
|
73415
|
-
this.approving.delete(card2.cardId);
|
|
73416
|
-
await this.close(card2.cardId, "withdrawn", { by: "last_six" });
|
|
73417
|
-
throw refused("DESTINATION_NOT_CONFIRMED", "That is not the last six characters of the address, three times. The card is withdrawn; nothing was sent.", { step: "lastSix", withdrawn: true });
|
|
73418
|
-
}
|
|
73419
|
-
throw await refuse3("DESTINATION_NOT_CONFIRMED", `That is not the last six characters of the address. Character ${differsAt + 1} differs. Nothing was sent.`, { step: "lastSix", differsAt, triesLeft: left });
|
|
73420
|
-
}
|
|
73421
73389
|
const engine = this.deps.transfers;
|
|
73422
73390
|
if (engine === undefined)
|
|
73423
73391
|
throw refused("NOT_IN_THIS_BUILD", "Transfers are not in this build of the core.");
|
|
@@ -73436,7 +73404,7 @@ class CardBook {
|
|
|
73436
73404
|
cardHash: card2.cardHash,
|
|
73437
73405
|
opId: card2.opId,
|
|
73438
73406
|
factorType: factorType2,
|
|
73439
|
-
confirm: { typed: true
|
|
73407
|
+
confirm: { typed: true },
|
|
73440
73408
|
viewClientId
|
|
73441
73409
|
});
|
|
73442
73410
|
this.publish(card2);
|
|
@@ -94512,7 +94480,7 @@ async function vaultExportKey(args, ctx) {
|
|
|
94512
94480
|
ctx.deps.stdout.write(`
|
|
94513
94481
|
${warning}
|
|
94514
94482
|
`);
|
|
94515
|
-
await
|
|
94483
|
+
await confirmAddress(ctx, "key", entry.address, `export the key for ${entry.address}`);
|
|
94516
94484
|
vault = hold(await markEverExported(vault, entry, ctx));
|
|
94517
94485
|
const secret = await decryptKey(vault, entry.id);
|
|
94518
94486
|
try {
|
|
@@ -97123,7 +97091,7 @@ async function promoteEvmFresh(input, fromLabel) {
|
|
|
97123
97091
|
addKeys: [blob]
|
|
97124
97092
|
}, ctx.deps));
|
|
97125
97093
|
scanStart = await appendScanStart(ctx, vault.path, address, height);
|
|
97126
|
-
await
|
|
97094
|
+
await confirmAddress(ctx, "vault", destination.address, `sweep this wallet home to ${destination.address}`);
|
|
97127
97095
|
if (toKey !== undefined) {
|
|
97128
97096
|
ctx.deps.stderr.write(`${[toKeyPlanLine(toKey), ...targetWarnings(toKey.target, "evm")].join(`
|
|
97129
97097
|
`)}
|
|
@@ -97219,7 +97187,7 @@ async function promoteEvmInPlace(input, subjectLabel, sweepTo) {
|
|
|
97219
97187
|
ctx.deps.stdout.write(`Authorities: the signer-role read (mint, freeze, upgrade and stake authorities) is Solana's; nothing is read on Hood, so any contract this key controls is not checked.
|
|
97220
97188
|
`);
|
|
97221
97189
|
printPromoteSentence(ctx, promoteSentence({ n: 1, form: "U", where: "above" }));
|
|
97222
|
-
await
|
|
97190
|
+
await confirmAddress(ctx, "address", first.subject.address, `promote ${first.subject.address}`);
|
|
97223
97191
|
ctx.deps.stderr.write(`${renderControlledBy(controlledBy, 1)}
|
|
97224
97192
|
`);
|
|
97225
97193
|
await confirmPromotion(ctx, 1);
|
|
@@ -97495,7 +97463,7 @@ async function promoteFresh(ctx, parsed, fromLabel, toKey) {
|
|
|
97495
97463
|
},
|
|
97496
97464
|
addKeys: [blob]
|
|
97497
97465
|
}, ctx.deps));
|
|
97498
|
-
await
|
|
97466
|
+
await confirmAddress(ctx, "vault", destination.address, `sweep this wallet home to ${destination.address}`);
|
|
97499
97467
|
if (toKey !== undefined) {
|
|
97500
97468
|
ctx.deps.stderr.write(`${[toKeyPlanLine(toKey), ...targetWarnings(toKey.target, "solana")].join(`
|
|
97501
97469
|
`)}
|
|
@@ -97604,10 +97572,10 @@ async function promoteInPlace(ctx, parsed, subjectLabel, toKey) {
|
|
|
97604
97572
|
if (toKey !== undefined)
|
|
97605
97573
|
await confirmResumeRebind(ctx, toKey, resumeChain);
|
|
97606
97574
|
const resumed = await resumePromote(ctx, vault, existing, opened.reopen, path, hold, {
|
|
97607
|
-
confirmAccount: (account) =>
|
|
97575
|
+
confirmAccount: (account) => confirmAddress(ctx, "account", account, `act as account ${account}`),
|
|
97608
97576
|
confirmDestination: async (destination2) => {
|
|
97609
97577
|
try {
|
|
97610
|
-
await
|
|
97578
|
+
await confirmAddress(ctx, "vault", destination2, `accept ${destination2} as the sweep vault`);
|
|
97611
97579
|
return true;
|
|
97612
97580
|
} catch {
|
|
97613
97581
|
return false;
|
|
@@ -97673,7 +97641,7 @@ async function promoteInPlace(ctx, parsed, subjectLabel, toKey) {
|
|
|
97673
97641
|
ctx.deps.stdout.write(`${authoritiesBlock(host, roles)}
|
|
97674
97642
|
`);
|
|
97675
97643
|
printPromoteSentence(ctx, promoteSentence({ n: 1, form: sentenceForm(roles), k: keysWithFindings(roles), where: "above" }));
|
|
97676
|
-
await
|
|
97644
|
+
await confirmAddress(ctx, "address", first.subject.address, `promote ${first.subject.address}`);
|
|
97677
97645
|
ctx.deps.stderr.write(`${renderControlledBy(controlledBy, 1)}
|
|
97678
97646
|
`);
|
|
97679
97647
|
await confirmPromotion(ctx, 1);
|
|
@@ -99495,14 +99463,14 @@ async function matchAgainstAccount(ctx, apiKey, derived) {
|
|
|
99495
99463
|
ctx.deps.stdout.write(`
|
|
99496
99464
|
This profile acts as account ${read2.account}.
|
|
99497
99465
|
`);
|
|
99498
|
-
const
|
|
99499
|
-
if (
|
|
99466
|
+
const confirmed = await typedConfirm(ctx, "account", read2.account, `record exposure against account ${read2.account}`);
|
|
99467
|
+
if (!confirmed) {
|
|
99500
99468
|
return {
|
|
99501
99469
|
matched: [],
|
|
99502
99470
|
unmatched: [],
|
|
99503
99471
|
account: undefined,
|
|
99504
99472
|
complete: false,
|
|
99505
|
-
reason: "
|
|
99473
|
+
reason: "the account this profile acts as was not confirmed",
|
|
99506
99474
|
refused: "EXPOSURE_ACCOUNT_MISMATCH"
|
|
99507
99475
|
};
|
|
99508
99476
|
}
|
package/package.json
CHANGED