@did-btcr2/cli 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/cjs/index.js +310 -42
- package/dist/esm/src/commands/init.js +7 -1
- package/dist/esm/src/commands/init.js.map +1 -1
- package/dist/esm/src/commands/keystore.js +107 -8
- package/dist/esm/src/commands/keystore.js.map +1 -1
- package/dist/esm/src/config.js +27 -6
- package/dist/esm/src/config.js.map +1 -1
- package/dist/esm/src/keystore/file-key-store.js +48 -0
- package/dist/esm/src/keystore/file-key-store.js.map +1 -1
- package/dist/esm/src/keystore/passphrase.js +13 -0
- package/dist/esm/src/keystore/passphrase.js.map +1 -1
- package/dist/esm/src/keystore/session.js +250 -0
- package/dist/esm/src/keystore/session.js.map +1 -0
- package/dist/esm/src/paths.js +12 -0
- package/dist/esm/src/paths.js.map +1 -1
- package/dist/esm/src/types.js.map +1 -1
- package/dist/types/src/commands/init.d.ts.map +1 -1
- package/dist/types/src/commands/keystore.d.ts +5 -4
- package/dist/types/src/commands/keystore.d.ts.map +1 -1
- package/dist/types/src/config.d.ts.map +1 -1
- package/dist/types/src/keystore/file-key-store.d.ts +16 -0
- package/dist/types/src/keystore/file-key-store.d.ts.map +1 -1
- package/dist/types/src/keystore/passphrase.d.ts +10 -0
- package/dist/types/src/keystore/passphrase.d.ts.map +1 -1
- package/dist/types/src/keystore/session.d.ts +105 -0
- package/dist/types/src/keystore/session.d.ts.map +1 -0
- package/dist/types/src/paths.d.ts +10 -0
- package/dist/types/src/paths.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +15 -0
- package/dist/types/src/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/commands/init.ts +7 -1
- package/src/commands/keystore.ts +143 -9
- package/src/config.ts +28 -6
- package/src/keystore/file-key-store.ts +43 -0
- package/src/keystore/passphrase.ts +23 -0
- package/src/keystore/session.ts +303 -0
- package/src/paths.ts +13 -0
- package/src/types.ts +4 -1
package/dist/cjs/index.js
CHANGED
|
@@ -82,13 +82,13 @@ var import_common3 = require("@did-btcr2/common");
|
|
|
82
82
|
var import_commander = require("commander");
|
|
83
83
|
|
|
84
84
|
// src/commands/init.ts
|
|
85
|
-
var
|
|
85
|
+
var import_node_fs7 = require("fs");
|
|
86
86
|
|
|
87
87
|
// src/config.ts
|
|
88
88
|
var import_api = require("@did-btcr2/api");
|
|
89
89
|
var import_method = require("@did-btcr2/method");
|
|
90
|
-
var
|
|
91
|
-
var
|
|
90
|
+
var import_node_fs6 = require("fs");
|
|
91
|
+
var import_node_path5 = require("path");
|
|
92
92
|
|
|
93
93
|
// src/error.ts
|
|
94
94
|
var import_common = require("@did-btcr2/common");
|
|
@@ -167,6 +167,7 @@ var import_key_manager = require("@did-btcr2/key-manager");
|
|
|
167
167
|
// src/keystore/file-key-store.ts
|
|
168
168
|
var import_node_fs3 = require("fs");
|
|
169
169
|
var import_node_path3 = require("path");
|
|
170
|
+
var import_sha2 = require("@noble/hashes/sha2.js");
|
|
170
171
|
var import_utils2 = require("@noble/hashes/utils.js");
|
|
171
172
|
var import_base2 = require("@scure/base");
|
|
172
173
|
|
|
@@ -360,6 +361,7 @@ function blankToUndef(value) {
|
|
|
360
361
|
var ENV_HOME = "BTCR2_HOME";
|
|
361
362
|
var CONFIG_FILENAME = "config.json";
|
|
362
363
|
var KEYSTORE_FILENAME = "keystore.json";
|
|
364
|
+
var SESSION_FILENAME = "session.json";
|
|
363
365
|
function resolveHome(overrides) {
|
|
364
366
|
return blankToUndef(overrides?.home) ?? blankToUndef(process.env[ENV_HOME]) ?? platformDefaultHome();
|
|
365
367
|
}
|
|
@@ -376,6 +378,9 @@ function defaultConfigPath(overrides) {
|
|
|
376
378
|
function defaultKeystorePath(overrides) {
|
|
377
379
|
return (0, import_node_path2.join)(resolveHome(overrides), KEYSTORE_FILENAME);
|
|
378
380
|
}
|
|
381
|
+
function defaultSessionPath(overrides) {
|
|
382
|
+
return (0, import_node_path2.join)(resolveHome(overrides), SESSION_FILENAME);
|
|
383
|
+
}
|
|
379
384
|
|
|
380
385
|
// src/keystore/file-key-store.ts
|
|
381
386
|
var KEYSTORE_VERSION = 1;
|
|
@@ -830,6 +835,32 @@ function keystoreSummary(path) {
|
|
|
830
835
|
function keystoreProtection(path) {
|
|
831
836
|
return keystoreSummary(path).protection;
|
|
832
837
|
}
|
|
838
|
+
function keystoreVerifierId(path) {
|
|
839
|
+
if (!(0, import_node_fs3.existsSync)(path)) return void 0;
|
|
840
|
+
let parsed;
|
|
841
|
+
try {
|
|
842
|
+
parsed = JSON.parse((0, import_node_fs3.readFileSync)(path, "utf-8"));
|
|
843
|
+
} catch {
|
|
844
|
+
return void 0;
|
|
845
|
+
}
|
|
846
|
+
if (!parsed.verifier) return void 0;
|
|
847
|
+
return import_base2.base64urlnopad.encode((0, import_sha2.sha256)((0, import_utils2.utf8ToBytes)(JSON.stringify(parsed.verifier))));
|
|
848
|
+
}
|
|
849
|
+
function verifyKeystorePassphrase(path, passphrase) {
|
|
850
|
+
if (!(0, import_node_fs3.existsSync)(path)) return false;
|
|
851
|
+
let parsed;
|
|
852
|
+
try {
|
|
853
|
+
parsed = JSON.parse((0, import_node_fs3.readFileSync)(path, "utf-8"));
|
|
854
|
+
} catch {
|
|
855
|
+
return false;
|
|
856
|
+
}
|
|
857
|
+
if (parsed.protection !== "passphrase" || !parsed.verifier) return false;
|
|
858
|
+
try {
|
|
859
|
+
return bytesEqual(decryptSecret(parsed.verifier, passphrase), VERIFIER_PLAINTEXT);
|
|
860
|
+
} catch {
|
|
861
|
+
return false;
|
|
862
|
+
}
|
|
863
|
+
}
|
|
833
864
|
function initKeystore(path, options) {
|
|
834
865
|
ensureDir((0, import_node_path3.dirname)(path), 448);
|
|
835
866
|
let file;
|
|
@@ -923,6 +954,8 @@ function acquirePassphrase(options = {}) {
|
|
|
923
954
|
if (options.passphraseFile) {
|
|
924
955
|
return assertNonEmpty((0, import_node_fs4.readFileSync)(options.passphraseFile, "utf-8").replace(/\r?\n$/, ""));
|
|
925
956
|
}
|
|
957
|
+
const fromSession = options.beforePrompt?.();
|
|
958
|
+
if (fromSession) return assertNonEmpty(fromSession);
|
|
926
959
|
}
|
|
927
960
|
if (!process.stdin.isTTY) {
|
|
928
961
|
throw new KeyStoreError(
|
|
@@ -991,13 +1024,155 @@ function promptHidden(label) {
|
|
|
991
1024
|
return Buffer.from(bytes).toString("utf-8");
|
|
992
1025
|
}
|
|
993
1026
|
|
|
1027
|
+
// src/keystore/session.ts
|
|
1028
|
+
var import_node_fs5 = require("fs");
|
|
1029
|
+
var import_node_path4 = require("path");
|
|
1030
|
+
var import_utils3 = require("@noble/hashes/utils.js");
|
|
1031
|
+
var import_base3 = require("@scure/base");
|
|
1032
|
+
var SESSION_VERSION = 1;
|
|
1033
|
+
var DEFAULT_SESSION_TTL_MS = 60 * 60 * 1e3;
|
|
1034
|
+
var MAX_SESSION_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
1035
|
+
var ENV_KEYSTORE_TTL = "BTCR2_KEYSTORE_TTL";
|
|
1036
|
+
function writeSession(sessionPath, input) {
|
|
1037
|
+
const createdAt = Date.now();
|
|
1038
|
+
const session = {
|
|
1039
|
+
v: SESSION_VERSION,
|
|
1040
|
+
keystore: (0, import_node_path4.resolve)(input.keystorePath),
|
|
1041
|
+
verifierId: input.verifierId,
|
|
1042
|
+
passphrase: import_base3.base64urlnopad.encode((0, import_utils3.utf8ToBytes)(input.passphrase)),
|
|
1043
|
+
allowMainnet: input.allowMainnet ?? false,
|
|
1044
|
+
createdAt,
|
|
1045
|
+
expiresAt: createdAt + input.ttlMs,
|
|
1046
|
+
ttlSeconds: Math.round(input.ttlMs / 1e3)
|
|
1047
|
+
};
|
|
1048
|
+
ensureDir((0, import_node_path4.dirname)(sessionPath), 448);
|
|
1049
|
+
writeFileAtomic(sessionPath, `${JSON.stringify(session, null, 2)}
|
|
1050
|
+
`, 384);
|
|
1051
|
+
return session;
|
|
1052
|
+
}
|
|
1053
|
+
function clearSession(sessionPath) {
|
|
1054
|
+
let existed = false;
|
|
1055
|
+
try {
|
|
1056
|
+
existed = (0, import_node_fs5.existsSync)(sessionPath);
|
|
1057
|
+
if (existed) (0, import_node_fs5.rmSync)(sessionPath, { force: true });
|
|
1058
|
+
} catch {
|
|
1059
|
+
existed = false;
|
|
1060
|
+
}
|
|
1061
|
+
sweepSessionTemps(sessionPath);
|
|
1062
|
+
return existed;
|
|
1063
|
+
}
|
|
1064
|
+
function sweepSessionTemps(sessionPath) {
|
|
1065
|
+
const dir = (0, import_node_path4.dirname)(sessionPath);
|
|
1066
|
+
const prefix = `.${(0, import_node_path4.basename)(sessionPath)}.`;
|
|
1067
|
+
try {
|
|
1068
|
+
for (const name of (0, import_node_fs5.readdirSync)(dir)) {
|
|
1069
|
+
if (name.startsWith(prefix) && name.endsWith(".tmp")) {
|
|
1070
|
+
try {
|
|
1071
|
+
(0, import_node_fs5.rmSync)((0, import_node_path4.join)(dir, name), { force: true });
|
|
1072
|
+
} catch {
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
} catch {
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
function readLiveSessionPassphrase(sessionPath, keystorePath, currentVerifierId, isMainnetOperation = false) {
|
|
1080
|
+
const verdict = evaluateSession(sessionPath, keystorePath, currentVerifierId, Date.now());
|
|
1081
|
+
if (verdict.status === "live") {
|
|
1082
|
+
if (isMainnetOperation && !verdict.session.allowMainnet) return void 0;
|
|
1083
|
+
try {
|
|
1084
|
+
return Buffer.from(import_base3.base64urlnopad.decode(verdict.session.passphrase)).toString("utf-8");
|
|
1085
|
+
} catch {
|
|
1086
|
+
clearSession(sessionPath);
|
|
1087
|
+
return void 0;
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
if (verdict.status === "expired" || verdict.status === "stale" || verdict.status === "future" || verdict.status === "malformed") {
|
|
1091
|
+
clearSession(sessionPath);
|
|
1092
|
+
}
|
|
1093
|
+
return void 0;
|
|
1094
|
+
}
|
|
1095
|
+
function readSessionStatus(sessionPath, keystorePath, currentVerifierId) {
|
|
1096
|
+
const now = Date.now();
|
|
1097
|
+
const verdict = evaluateSession(sessionPath, keystorePath, currentVerifierId, now);
|
|
1098
|
+
if (verdict.status !== "live") return { active: false };
|
|
1099
|
+
return {
|
|
1100
|
+
active: true,
|
|
1101
|
+
expiresAt: verdict.session.expiresAt,
|
|
1102
|
+
secondsRemaining: Math.max(0, Math.round((verdict.session.expiresAt - now) / 1e3)),
|
|
1103
|
+
allowMainnet: verdict.session.allowMainnet
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1106
|
+
function parseTtlToMs(raw) {
|
|
1107
|
+
const match = /^(\d+)([smh]?)$/.exec(raw.trim());
|
|
1108
|
+
if (!match) return void 0;
|
|
1109
|
+
const n = Number(match[1]);
|
|
1110
|
+
if (!Number.isFinite(n)) return void 0;
|
|
1111
|
+
const unitMs = match[2] === "h" ? 36e5 : match[2] === "m" ? 6e4 : 1e3;
|
|
1112
|
+
return n * unitMs;
|
|
1113
|
+
}
|
|
1114
|
+
function evaluateSession(sessionPath, keystorePath, currentVerifierId, now) {
|
|
1115
|
+
const session = secureReadSession(sessionPath);
|
|
1116
|
+
if (!session) return { status: "none" };
|
|
1117
|
+
if (session.v !== SESSION_VERSION) return { status: "malformed" };
|
|
1118
|
+
if (typeof session.passphrase !== "string" || typeof session.keystore !== "string" || typeof session.verifierId !== "string" || typeof session.allowMainnet !== "boolean" || typeof session.createdAt !== "number" || typeof session.expiresAt !== "number") {
|
|
1119
|
+
return { status: "malformed" };
|
|
1120
|
+
}
|
|
1121
|
+
if (session.createdAt > now) return { status: "future" };
|
|
1122
|
+
if (now >= session.expiresAt) return { status: "expired" };
|
|
1123
|
+
if ((0, import_node_path4.resolve)(session.keystore) !== (0, import_node_path4.resolve)(keystorePath)) return { status: "foreign" };
|
|
1124
|
+
if (currentVerifierId === void 0 || session.verifierId !== currentVerifierId) return { status: "stale" };
|
|
1125
|
+
return { status: "live", session };
|
|
1126
|
+
}
|
|
1127
|
+
function secureReadSession(sessionPath) {
|
|
1128
|
+
let raw;
|
|
1129
|
+
if (process.platform === "win32") {
|
|
1130
|
+
try {
|
|
1131
|
+
raw = (0, import_node_fs5.readFileSync)(sessionPath, "utf-8");
|
|
1132
|
+
} catch {
|
|
1133
|
+
return void 0;
|
|
1134
|
+
}
|
|
1135
|
+
} else {
|
|
1136
|
+
let fd;
|
|
1137
|
+
try {
|
|
1138
|
+
fd = (0, import_node_fs5.openSync)(sessionPath, import_node_fs5.constants.O_RDONLY | import_node_fs5.constants.O_NOFOLLOW);
|
|
1139
|
+
} catch {
|
|
1140
|
+
return void 0;
|
|
1141
|
+
}
|
|
1142
|
+
try {
|
|
1143
|
+
const st = (0, import_node_fs5.fstatSync)(fd);
|
|
1144
|
+
const myUid = typeof process.getuid === "function" ? process.getuid() : void 0;
|
|
1145
|
+
if (!st.isFile() || myUid !== void 0 && st.uid !== myUid || (st.mode & 63) !== 0) {
|
|
1146
|
+
try {
|
|
1147
|
+
(0, import_node_fs5.rmSync)(sessionPath, { force: true });
|
|
1148
|
+
} catch {
|
|
1149
|
+
}
|
|
1150
|
+
return void 0;
|
|
1151
|
+
}
|
|
1152
|
+
raw = (0, import_node_fs5.readFileSync)(fd, "utf-8");
|
|
1153
|
+
} catch {
|
|
1154
|
+
return void 0;
|
|
1155
|
+
} finally {
|
|
1156
|
+
try {
|
|
1157
|
+
(0, import_node_fs5.closeSync)(fd);
|
|
1158
|
+
} catch {
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
try {
|
|
1163
|
+
return JSON.parse(raw);
|
|
1164
|
+
} catch {
|
|
1165
|
+
return void 0;
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
|
|
994
1169
|
// src/config.ts
|
|
995
1170
|
var CONFIG_SCHEMA_VERSION = 1;
|
|
996
1171
|
function writeConfigFile(path, mutate) {
|
|
997
1172
|
const raw = readConfigFile(path) ?? {};
|
|
998
1173
|
mutate(raw);
|
|
999
1174
|
raw.schemaVersion = CONFIG_SCHEMA_VERSION;
|
|
1000
|
-
ensureDir((0,
|
|
1175
|
+
ensureDir((0, import_node_path5.dirname)(path), 448);
|
|
1001
1176
|
writeFileAtomic(path, `${JSON.stringify(raw, null, 2)}
|
|
1002
1177
|
`, 384);
|
|
1003
1178
|
}
|
|
@@ -1007,7 +1182,7 @@ function writeDefaultConfigFile(path) {
|
|
|
1007
1182
|
defaults: { output: "text" },
|
|
1008
1183
|
profiles: Object.fromEntries(SUPPORTED_NETWORKS.map((n) => [n, {}]))
|
|
1009
1184
|
};
|
|
1010
|
-
ensureDir((0,
|
|
1185
|
+
ensureDir((0, import_node_path5.dirname)(path), 448);
|
|
1011
1186
|
writeFileAtomic(path, `${JSON.stringify(scaffold, null, 2)}
|
|
1012
1187
|
`, 384);
|
|
1013
1188
|
}
|
|
@@ -1072,7 +1247,7 @@ function readEnvOverrides() {
|
|
|
1072
1247
|
function parseConfigFileRaw(path) {
|
|
1073
1248
|
let content;
|
|
1074
1249
|
try {
|
|
1075
|
-
content = (0,
|
|
1250
|
+
content = (0, import_node_fs6.readFileSync)(path, "utf-8");
|
|
1076
1251
|
} catch (error) {
|
|
1077
1252
|
if (error.code === "ENOENT") return void 0;
|
|
1078
1253
|
throw new CLIError(
|
|
@@ -1264,7 +1439,7 @@ function trimTrailingNewline(value) {
|
|
|
1264
1439
|
}
|
|
1265
1440
|
function readSecretFile(path, source) {
|
|
1266
1441
|
try {
|
|
1267
|
-
return trimTrailingNewline((0,
|
|
1442
|
+
return trimTrailingNewline((0, import_node_fs6.readFileSync)(path, "utf-8"));
|
|
1268
1443
|
} catch (error) {
|
|
1269
1444
|
throw new CLIError(
|
|
1270
1445
|
`Could not read the RPC password ${source} at ${path}: ${error.message}`,
|
|
@@ -1398,13 +1573,28 @@ async function runDoctor(network, overrides) {
|
|
|
1398
1573
|
function defaultApiFactory(network, overrides) {
|
|
1399
1574
|
return (0, import_api.createApi)(resolveConnectionConfig(network, overrides));
|
|
1400
1575
|
}
|
|
1401
|
-
function buildKeystoreKms(overrides) {
|
|
1576
|
+
function buildKeystoreKms(overrides, network) {
|
|
1577
|
+
const keystorePath = resolveKeystorePath(overrides);
|
|
1578
|
+
const sessionPath = defaultSessionPath(overrides);
|
|
1579
|
+
const isMainnetOperation = network === "bitcoin";
|
|
1402
1580
|
return new FileBackedKeyManager({
|
|
1403
|
-
path:
|
|
1581
|
+
path: keystorePath,
|
|
1404
1582
|
// The store decides when to confirm: it passes `confirm: true` only while
|
|
1405
1583
|
// establishing a fresh keystore's passphrase, so a first-key typo is caught
|
|
1406
1584
|
// by a second entry (ADR 080). confirm is a no-op for env/file sources.
|
|
1407
|
-
|
|
1585
|
+
//
|
|
1586
|
+
// On the non-establishing path, a cached session (ADR 081) is consulted below
|
|
1587
|
+
// the env var / --passphrase-file and above the interactive prompt. It is
|
|
1588
|
+
// wired ONLY when not confirming, so establishment never consults the session
|
|
1589
|
+
// and a first passphrase is always entered fresh and twice. The session is
|
|
1590
|
+
// bound to this keystore's verifier, so a rotated passphrase invalidates it.
|
|
1591
|
+
getPassphrase: (opts) => acquirePassphrase({
|
|
1592
|
+
passphraseFile: overrides?.passphraseFile,
|
|
1593
|
+
confirm: opts?.confirm,
|
|
1594
|
+
...opts?.confirm ? {} : {
|
|
1595
|
+
beforePrompt: () => readLiveSessionPassphrase(sessionPath, keystorePath, keystoreVerifierId(keystorePath), isMainnetOperation)
|
|
1596
|
+
}
|
|
1597
|
+
})
|
|
1408
1598
|
});
|
|
1409
1599
|
}
|
|
1410
1600
|
function resolveKeystoreProtection(overrides) {
|
|
@@ -1442,7 +1632,7 @@ function resolveSigningKeyRef(overrides) {
|
|
|
1442
1632
|
function keystoreApiFactory(network, overrides) {
|
|
1443
1633
|
return (0, import_api.createApi)({
|
|
1444
1634
|
...resolveConnectionConfig(network, overrides),
|
|
1445
|
-
kms: buildKeystoreKms(overrides)
|
|
1635
|
+
kms: buildKeystoreKms(overrides, network)
|
|
1446
1636
|
});
|
|
1447
1637
|
}
|
|
1448
1638
|
function deriveNetwork(did) {
|
|
@@ -1501,11 +1691,11 @@ function registerInitCommand(program, globals) {
|
|
|
1501
1691
|
const keystorePath = resolveKeystorePath(g);
|
|
1502
1692
|
ensureDir(home, 448);
|
|
1503
1693
|
const created = [];
|
|
1504
|
-
if (!(0,
|
|
1694
|
+
if (!(0, import_node_fs7.existsSync)(configPath) || options.force) {
|
|
1505
1695
|
writeDefaultConfigFile(configPath);
|
|
1506
1696
|
created.push("config");
|
|
1507
1697
|
}
|
|
1508
|
-
const keystoreExists = (0,
|
|
1698
|
+
const keystoreExists = (0, import_node_fs7.existsSync)(keystorePath);
|
|
1509
1699
|
if (keystoreExists && options.force && !g.quiet) {
|
|
1510
1700
|
process.stderr.write(
|
|
1511
1701
|
`note: a keystore already exists at ${keystorePath} and was left intact. To re-establish it (discarding its keys), run "btcr2 keystore init --force".
|
|
@@ -1522,6 +1712,7 @@ function registerInitCommand(program, globals) {
|
|
|
1522
1712
|
protection: options.dev ? "none" : "passphrase",
|
|
1523
1713
|
getPassphrase: (opts) => acquirePassphrase({ passphraseFile: g.passphraseFile, confirm: opts?.confirm, prompt: "New keystore passphrase: " })
|
|
1524
1714
|
});
|
|
1715
|
+
clearSession(defaultSessionPath(g));
|
|
1525
1716
|
created.push("keystore");
|
|
1526
1717
|
}
|
|
1527
1718
|
const protection = keystoreSummary(keystorePath).protection;
|
|
@@ -1534,7 +1725,7 @@ function registerInitCommand(program, globals) {
|
|
|
1534
1725
|
}
|
|
1535
1726
|
|
|
1536
1727
|
// src/commands/create.ts
|
|
1537
|
-
var
|
|
1728
|
+
var import_utils4 = require("@noble/hashes/utils.js");
|
|
1538
1729
|
|
|
1539
1730
|
// src/keystore/resolve-key-ref.ts
|
|
1540
1731
|
function fingerprintOf(id) {
|
|
@@ -1642,7 +1833,7 @@ function registerCreateCommand(program, factory, keystoreFactory, globals) {
|
|
|
1642
1833
|
const publicKey2 = api2.kms.getPublicKey(keyId2);
|
|
1643
1834
|
const did2 = api2.createDid("deterministic", publicKey2, { network });
|
|
1644
1835
|
print(
|
|
1645
|
-
{ action: "create", data: did2, keyId: keyId2, publicKey: (0,
|
|
1836
|
+
{ action: "create", data: did2, keyId: keyId2, publicKey: (0, import_utils4.bytesToHex)(publicKey2) },
|
|
1646
1837
|
`Using stored key ${keyId2}.`
|
|
1647
1838
|
);
|
|
1648
1839
|
return;
|
|
@@ -1650,7 +1841,7 @@ function registerCreateCommand(program, factory, keystoreFactory, globals) {
|
|
|
1650
1841
|
assertKeystoreAllowedForNetwork(network, overrides);
|
|
1651
1842
|
const api = keystoreFactory(void 0, overrides);
|
|
1652
1843
|
const { did, keyId } = api.generateDid({ network, setActive: true });
|
|
1653
|
-
const publicKey = (0,
|
|
1844
|
+
const publicKey = (0, import_utils4.bytesToHex)(api.kms.getPublicKey(keyId));
|
|
1654
1845
|
print(
|
|
1655
1846
|
{ action: "create", data: did, keyId, publicKey },
|
|
1656
1847
|
`Generated and stored key ${keyId} (now the active key).`
|
|
@@ -1681,7 +1872,7 @@ function parseGenesisBytes(hex, type) {
|
|
|
1681
1872
|
const expected = EXPECTED_BYTES[type];
|
|
1682
1873
|
let bytes;
|
|
1683
1874
|
try {
|
|
1684
|
-
bytes = (0,
|
|
1875
|
+
bytes = (0, import_utils4.hexToBytes)(hex.trim());
|
|
1685
1876
|
} catch {
|
|
1686
1877
|
throw new CLIError(
|
|
1687
1878
|
`Invalid bytes: not valid hex. Expected ${expected.label}.`,
|
|
@@ -1941,8 +2132,8 @@ function parseJsonArg2(flagName) {
|
|
|
1941
2132
|
|
|
1942
2133
|
// src/commands/key.ts
|
|
1943
2134
|
var import_keypair = require("@did-btcr2/keypair");
|
|
1944
|
-
var
|
|
1945
|
-
var
|
|
2135
|
+
var import_utils5 = require("@noble/hashes/utils.js");
|
|
2136
|
+
var import_node_fs8 = require("fs");
|
|
1946
2137
|
function registerKeyCommand(program, factory, globals) {
|
|
1947
2138
|
const key = program.command("key").description("Manage keypairs in the encrypted keystore.");
|
|
1948
2139
|
const print = (result) => console.log(formatResult(result, globals()));
|
|
@@ -1951,7 +2142,7 @@ function registerKeyCommand(program, factory, globals) {
|
|
|
1951
2142
|
assertNameAvailable(api.kms.kms, options.name);
|
|
1952
2143
|
const setActive = options.setActive ?? false;
|
|
1953
2144
|
const id = api.kms.generateKey({ ...options.name && { tags: { name: options.name } }, setActive });
|
|
1954
|
-
print({ action: "key-generate", data: { keyId: id, publicKey: (0,
|
|
2145
|
+
print({ action: "key-generate", data: { keyId: id, publicKey: (0, import_utils5.bytesToHex)(api.kms.getPublicKey(id)), active: setActive } });
|
|
1955
2146
|
});
|
|
1956
2147
|
key.command("list").alias("ls").description("List stored keys.").action(() => {
|
|
1957
2148
|
const kms = factory(void 0, globals()).kms.kms;
|
|
@@ -1971,7 +2162,7 @@ function registerKeyCommand(program, factory, globals) {
|
|
|
1971
2162
|
const kms = factory(void 0, globals()).kms.kms;
|
|
1972
2163
|
const id = resolveKeyRef(kms, ref);
|
|
1973
2164
|
const entry = kms.getEntry(id);
|
|
1974
|
-
print({ action: "key-show", data: { keyId: id, publicKey: (0,
|
|
2165
|
+
print({ action: "key-show", data: { keyId: id, publicKey: (0, import_utils5.bytesToHex)(entry.publicKey), ...entry.tags && { tags: entry.tags } } });
|
|
1975
2166
|
});
|
|
1976
2167
|
key.command("import").description("Import a key: a secret from a hex file, or a public key as watch-only.").option("--secret-file <path>", "Path to a file containing a 32-byte secret key as hex.").option("--public <hex>", "A 33-byte compressed public key as hex (imported watch-only).").option("--name <name>", "A human-friendly name, stored as a tag.").option("--set-active", "Make this the active key.", false).action((options) => {
|
|
1977
2168
|
if (Boolean(options.secretFile) === Boolean(options.public)) {
|
|
@@ -1982,13 +2173,13 @@ function registerKeyCommand(program, factory, globals) {
|
|
|
1982
2173
|
const keyPair = options.secretFile ? new import_keypair.SchnorrKeyPair({ secretKey: readHexFile(options.secretFile, 32, "--secret-file") }) : new import_keypair.SchnorrKeyPair({ publicKey: parseHex(options.public ?? "", 33, "--public") });
|
|
1983
2174
|
const setActive = options.setActive ?? false;
|
|
1984
2175
|
const id = api.kms.import(keyPair, { ...options.name && { tags: { name: options.name } }, setActive });
|
|
1985
|
-
print({ action: "key-import", data: { keyId: id, publicKey: (0,
|
|
2176
|
+
print({ action: "key-import", data: { keyId: id, publicKey: (0, import_utils5.bytesToHex)(api.kms.getPublicKey(id)), watchOnly: !options.secretFile, active: setActive } });
|
|
1986
2177
|
});
|
|
1987
2178
|
key.command("export <ref>").description("Export a key. Public material by default; --secret writes the secret to a file.").option("--secret", "Export the secret key. Requires --out.", false).option("--out <path>", "Write the exported secret to this file (created 0600).").action((ref, options) => {
|
|
1988
2179
|
const api = factory(void 0, globals());
|
|
1989
2180
|
const id = resolveKeyRef(api.kms.kms, ref);
|
|
1990
2181
|
if (!options.secret) {
|
|
1991
|
-
print({ action: "key-export", data: { keyId: id, publicKey: (0,
|
|
2182
|
+
print({ action: "key-export", data: { keyId: id, publicKey: (0, import_utils5.bytesToHex)(api.kms.getPublicKey(id)) } });
|
|
1992
2183
|
return;
|
|
1993
2184
|
}
|
|
1994
2185
|
if (!options.out) {
|
|
@@ -1999,7 +2190,7 @@ function registerKeyCommand(program, factory, globals) {
|
|
|
1999
2190
|
throw new CLIError(`Key ${id} is watch-only and has no secret to export.`, "INVALID_ARGUMENT_ERROR", { keyId: id });
|
|
2000
2191
|
}
|
|
2001
2192
|
process.stderr.write("warning: writing an unencrypted secret key to disk. Protect this file and delete it when done.\n");
|
|
2002
|
-
writeSecretFile(options.out, (0,
|
|
2193
|
+
writeSecretFile(options.out, (0, import_utils5.bytesToHex)(keyPair.secretKey.bytes));
|
|
2003
2194
|
print({ action: "key-export", data: { keyId: id, secretWrittenTo: options.out } });
|
|
2004
2195
|
});
|
|
2005
2196
|
key.command("delete <ref>").alias("rm").description("Delete a key from the keystore.").option("--force", "Delete even if it is the active key.", false).action((ref, options) => {
|
|
@@ -2024,7 +2215,7 @@ function assertNameAvailable(kms, name) {
|
|
|
2024
2215
|
function parseHex(hex, expectedBytes, label) {
|
|
2025
2216
|
let bytes;
|
|
2026
2217
|
try {
|
|
2027
|
-
bytes = (0,
|
|
2218
|
+
bytes = (0, import_utils5.hexToBytes)(hex.trim());
|
|
2028
2219
|
} catch {
|
|
2029
2220
|
throw new CLIError(`Invalid hex for ${label}.`, "INVALID_ARGUMENT_ERROR", { label });
|
|
2030
2221
|
}
|
|
@@ -2040,7 +2231,7 @@ function parseHex(hex, expectedBytes, label) {
|
|
|
2040
2231
|
function readHexFile(path, expectedBytes, label) {
|
|
2041
2232
|
let content;
|
|
2042
2233
|
try {
|
|
2043
|
-
content = (0,
|
|
2234
|
+
content = (0, import_node_fs8.readFileSync)(path, "utf-8");
|
|
2044
2235
|
} catch {
|
|
2045
2236
|
throw new CLIError(`Cannot read ${label} at ${path}.`, "INVALID_ARGUMENT_ERROR", { label, path });
|
|
2046
2237
|
}
|
|
@@ -2049,7 +2240,7 @@ function readHexFile(path, expectedBytes, label) {
|
|
|
2049
2240
|
function writeSecretFile(path, contents) {
|
|
2050
2241
|
let fd;
|
|
2051
2242
|
try {
|
|
2052
|
-
fd = (0,
|
|
2243
|
+
fd = (0, import_node_fs8.openSync)(path, "wx", 384);
|
|
2053
2244
|
} catch (error) {
|
|
2054
2245
|
if (error.code === "EEXIST") {
|
|
2055
2246
|
throw new CLIError(`Refusing to overwrite existing file ${path}. Choose a new --out path.`, "INVALID_ARGUMENT_ERROR", { path });
|
|
@@ -2057,28 +2248,28 @@ function writeSecretFile(path, contents) {
|
|
|
2057
2248
|
throw error;
|
|
2058
2249
|
}
|
|
2059
2250
|
try {
|
|
2060
|
-
(0,
|
|
2251
|
+
(0, import_node_fs8.writeFileSync)(fd, contents);
|
|
2061
2252
|
} finally {
|
|
2062
|
-
(0,
|
|
2253
|
+
(0, import_node_fs8.closeSync)(fd);
|
|
2063
2254
|
}
|
|
2064
2255
|
}
|
|
2065
2256
|
|
|
2066
2257
|
// src/commands/keystore.ts
|
|
2067
|
-
var
|
|
2258
|
+
var import_node_fs9 = require("fs");
|
|
2068
2259
|
function registerKeystoreCommand(program, globals) {
|
|
2069
|
-
const keystore = program.command("keystore").description("Establish, inspect,
|
|
2260
|
+
const keystore = program.command("keystore").description("Establish, inspect, re-key, and unlock the keystore.");
|
|
2070
2261
|
const print = (result) => console.log(formatResult(result, globals()));
|
|
2071
2262
|
keystore.command("init").description("Establish the keystore (encrypted by default). Prompts for a passphrase and confirms it.").option("--dev", "Create an UNENCRYPTED dev keystore: plaintext keys, no passphrase. Testnet only; mainnet operations are refused.", false).option("--force", "Re-establish even if a keystore already exists (discards its keys).", false).action((options) => {
|
|
2072
2263
|
const g = globals();
|
|
2073
2264
|
const path = resolveKeystorePath(g);
|
|
2074
|
-
if ((0,
|
|
2265
|
+
if ((0, import_node_fs9.existsSync)(path) && !options.force) {
|
|
2075
2266
|
throw new CLIError(
|
|
2076
2267
|
`A keystore already exists at ${path}. Use --force to re-establish it (this discards its keys).`,
|
|
2077
2268
|
"INVALID_ARGUMENT_ERROR",
|
|
2078
2269
|
{ path }
|
|
2079
2270
|
);
|
|
2080
2271
|
}
|
|
2081
|
-
if ((0,
|
|
2272
|
+
if ((0, import_node_fs9.existsSync)(path) && options.force && !g.quiet) {
|
|
2082
2273
|
const { keyCount } = keystoreSummary(path);
|
|
2083
2274
|
if (keyCount > 0) {
|
|
2084
2275
|
process.stderr.write(
|
|
@@ -2096,16 +2287,18 @@ function registerKeystoreCommand(program, globals) {
|
|
|
2096
2287
|
protection: options.dev ? "none" : "passphrase",
|
|
2097
2288
|
getPassphrase: (opts) => acquirePassphrase({ passphraseFile: g.passphraseFile, confirm: opts?.confirm, prompt: "New keystore passphrase: " })
|
|
2098
2289
|
});
|
|
2290
|
+
clearSession(defaultSessionPath(g));
|
|
2099
2291
|
print({ action: "keystore-init", data: { path, protection: options.dev ? "dev" : "encrypted" } });
|
|
2100
2292
|
});
|
|
2101
|
-
keystore.command("status").description("Show the keystore path, protection mode, and
|
|
2293
|
+
keystore.command("status").description("Show the keystore path, protection mode, key count, and session state. Never decrypts or prompts.").action(() => {
|
|
2102
2294
|
const g = globals();
|
|
2103
2295
|
const path = resolveKeystorePath(g, { lenient: true });
|
|
2104
2296
|
const summary = keystoreSummary(path);
|
|
2297
|
+
const session = readSessionStatus(defaultSessionPath(g), path, keystoreVerifierId(path));
|
|
2105
2298
|
if (summary.protection === "dev" && !g.quiet && g.output !== "json") {
|
|
2106
2299
|
process.stderr.write("warning: this is an UNENCRYPTED dev keystore; keys are stored in plaintext.\n");
|
|
2107
2300
|
}
|
|
2108
|
-
print({ action: "keystore-status", data: { path, ...summary } });
|
|
2301
|
+
print({ action: "keystore-status", data: { path, ...summary, session } });
|
|
2109
2302
|
});
|
|
2110
2303
|
keystore.command("change-passphrase").alias("passwd").description("Change the keystore passphrase, re-sealing every key under the new one. Encrypted keystores only.").action(() => {
|
|
2111
2304
|
const g = globals();
|
|
@@ -2124,12 +2317,87 @@ function registerKeystoreCommand(program, globals) {
|
|
|
2124
2317
|
const oldPassphrase = acquirePassphrase({ passphraseFile: g.passphraseFile, prompt: "Current keystore passphrase: " });
|
|
2125
2318
|
const newPassphrase = acquirePassphrase({ forcePrompt: true, confirm: true, prompt: "New keystore passphrase: " });
|
|
2126
2319
|
const rekeyed = changeKeystorePassphrase(path, oldPassphrase, newPassphrase);
|
|
2320
|
+
clearSession(defaultSessionPath(g));
|
|
2127
2321
|
print({ action: "keystore-change-passphrase", data: { path, rekeyed } });
|
|
2128
2322
|
});
|
|
2323
|
+
keystore.command("unlock").description("Cache the keystore passphrase for a session so later commands do not re-prompt (ADR 081).").option("--ttl <duration>", `Session lifetime: bare seconds or an s/m/h suffix (default 1h, max 24h). Also $${ENV_KEYSTORE_TTL}.`).option("--allow-mainnet", "Permit unlocking when the active network is mainnet (bitcoin); this suspends per-use passphrase auth for the session.", false).action((options) => {
|
|
2324
|
+
const g = globals();
|
|
2325
|
+
const path = resolveKeystorePath(g);
|
|
2326
|
+
const summary = keystoreSummary(path);
|
|
2327
|
+
if (summary.protection === "absent") {
|
|
2328
|
+
throw new CLIError(`No keystore at ${path}. Run "btcr2 init" or "btcr2 keystore init" first.`, "INVALID_ARGUMENT_ERROR", { path });
|
|
2329
|
+
}
|
|
2330
|
+
if (summary.protection === "dev") {
|
|
2331
|
+
throw new CLIError(
|
|
2332
|
+
`The keystore at ${path} is an unencrypted dev keystore; it has no passphrase to cache, so no unlock is needed.`,
|
|
2333
|
+
"INVALID_ARGUMENT_ERROR",
|
|
2334
|
+
{ path }
|
|
2335
|
+
);
|
|
2336
|
+
}
|
|
2337
|
+
if (!summary.established) {
|
|
2338
|
+
throw new CLIError(
|
|
2339
|
+
`The keystore at ${path} has no passphrase established yet. Establish one with "btcr2 keystore init" or the first "btcr2 key generate".`,
|
|
2340
|
+
"INVALID_ARGUMENT_ERROR",
|
|
2341
|
+
{ path }
|
|
2342
|
+
);
|
|
2343
|
+
}
|
|
2344
|
+
if (!options.allowMainnet && resolveDefaultNetwork(g) === "bitcoin") {
|
|
2345
|
+
throw new CLIError(
|
|
2346
|
+
`Refusing to unlock for a mainnet (bitcoin) context: caching the passphrase suspends per-use authentication for the session. Pass --allow-mainnet to override, or keep signing mainnet updates with a per-use passphrase prompt.`,
|
|
2347
|
+
"MAINNET_UNLOCK_REFUSED_ERROR",
|
|
2348
|
+
{ path }
|
|
2349
|
+
);
|
|
2350
|
+
}
|
|
2351
|
+
const ttlMs = resolveSessionTtl(options.ttl);
|
|
2352
|
+
const passphrase = acquirePassphrase({ passphraseFile: g.passphraseFile, prompt: "Keystore passphrase: " });
|
|
2353
|
+
if (!verifyKeystorePassphrase(path, passphrase)) {
|
|
2354
|
+
throw new CLIError(`Incorrect passphrase for the keystore at ${path}; no session was created.`, "DECRYPT_ERROR", { path });
|
|
2355
|
+
}
|
|
2356
|
+
const verifierId = keystoreVerifierId(path);
|
|
2357
|
+
if (!verifierId) {
|
|
2358
|
+
throw new CLIError(`The keystore at ${path} has no verifier to bind a session to.`, "INVALID_ARGUMENT_ERROR", { path });
|
|
2359
|
+
}
|
|
2360
|
+
const session = writeSession(defaultSessionPath(g), {
|
|
2361
|
+
keystorePath: path,
|
|
2362
|
+
verifierId,
|
|
2363
|
+
passphrase,
|
|
2364
|
+
ttlMs,
|
|
2365
|
+
allowMainnet: !!options.allowMainnet
|
|
2366
|
+
});
|
|
2367
|
+
print({ action: "keystore-unlock", data: { keystore: path, expiresAt: session.expiresAt, ttlSeconds: session.ttlSeconds } });
|
|
2368
|
+
});
|
|
2369
|
+
keystore.command("lock").description("Revoke the cached session so later commands prompt for the passphrase again (ADR 081).").action(() => {
|
|
2370
|
+
const g = globals();
|
|
2371
|
+
const sessionPath = defaultSessionPath(g);
|
|
2372
|
+
const cleared = clearSession(sessionPath);
|
|
2373
|
+
print({ action: "keystore-lock", data: { path: sessionPath, cleared } });
|
|
2374
|
+
});
|
|
2375
|
+
}
|
|
2376
|
+
function resolveSessionTtl(flag) {
|
|
2377
|
+
const fromFlag = blankToUndef(flag);
|
|
2378
|
+
const raw = fromFlag ?? blankToUndef(process.env[ENV_KEYSTORE_TTL]);
|
|
2379
|
+
if (raw === void 0) return DEFAULT_SESSION_TTL_MS;
|
|
2380
|
+
const source = fromFlag !== void 0 ? "--ttl" : `$${ENV_KEYSTORE_TTL}`;
|
|
2381
|
+
const ms = parseTtlToMs(raw);
|
|
2382
|
+
if (ms === void 0 || ms <= 0) {
|
|
2383
|
+
throw new CLIError(
|
|
2384
|
+
`Invalid ${source} "${raw}": expected seconds or a value with an s/m/h suffix, e.g. 3600, 45m, or 2h.`,
|
|
2385
|
+
"INVALID_ARGUMENT_ERROR",
|
|
2386
|
+
{ value: raw, source }
|
|
2387
|
+
);
|
|
2388
|
+
}
|
|
2389
|
+
if (ms > MAX_SESSION_TTL_MS) {
|
|
2390
|
+
throw new CLIError(
|
|
2391
|
+
`${source} "${raw}" exceeds the 24h maximum for a cached passphrase.`,
|
|
2392
|
+
"INVALID_ARGUMENT_ERROR",
|
|
2393
|
+
{ value: raw, source }
|
|
2394
|
+
);
|
|
2395
|
+
}
|
|
2396
|
+
return ms;
|
|
2129
2397
|
}
|
|
2130
2398
|
|
|
2131
2399
|
// src/commands/config.ts
|
|
2132
|
-
var
|
|
2400
|
+
var import_node_fs10 = require("fs");
|
|
2133
2401
|
|
|
2134
2402
|
// src/config-schema.ts
|
|
2135
2403
|
var CONFIG_SCHEMA = {
|
|
@@ -2258,7 +2526,7 @@ function registerConfigCommand(program, globals) {
|
|
|
2258
2526
|
const print = (result) => console.log(formatResult(result, globals()));
|
|
2259
2527
|
config.command("init").description("Create a default config file with one profile per network.").option("--force", "Overwrite an existing config file.", false).action((options) => {
|
|
2260
2528
|
const p = path();
|
|
2261
|
-
if ((0,
|
|
2529
|
+
if ((0, import_node_fs10.existsSync)(p) && !options.force) {
|
|
2262
2530
|
throw new CLIError(`Config already exists at ${p}. Use --force to overwrite.`, "INVALID_ARGUMENT_ERROR", { path: p });
|
|
2263
2531
|
}
|
|
2264
2532
|
writeDefaultConfigFile(p);
|
|
@@ -2439,18 +2707,18 @@ function completionScript(shell) {
|
|
|
2439
2707
|
}
|
|
2440
2708
|
|
|
2441
2709
|
// src/version.ts
|
|
2442
|
-
var
|
|
2443
|
-
var
|
|
2710
|
+
var import_node_fs11 = require("fs");
|
|
2711
|
+
var import_node_path6 = require("path");
|
|
2444
2712
|
var import_node_url = require("url");
|
|
2445
2713
|
function readVersion() {
|
|
2446
|
-
let dir = (0,
|
|
2714
|
+
let dir = (0, import_node_path6.dirname)((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
2447
2715
|
for (let i = 0; i < 5; i++) {
|
|
2448
2716
|
try {
|
|
2449
|
-
const pkg = JSON.parse((0,
|
|
2717
|
+
const pkg = JSON.parse((0, import_node_fs11.readFileSync)((0, import_node_path6.join)(dir, "package.json"), "utf-8"));
|
|
2450
2718
|
if (pkg.name === "@did-btcr2/cli") return pkg.version;
|
|
2451
2719
|
} catch {
|
|
2452
2720
|
}
|
|
2453
|
-
dir = (0,
|
|
2721
|
+
dir = (0, import_node_path6.dirname)(dir);
|
|
2454
2722
|
}
|
|
2455
2723
|
return "0.0.0";
|
|
2456
2724
|
}
|
|
@@ -3,8 +3,9 @@ import { defaultConfigPath, resolveKeystorePath, writeDefaultConfigFile } from '
|
|
|
3
3
|
import { ensureDir } from '../keystore/atomic.js';
|
|
4
4
|
import { initKeystore, keystoreSummary } from '../keystore/file-key-store.js';
|
|
5
5
|
import { acquirePassphrase } from '../keystore/passphrase.js';
|
|
6
|
+
import { clearSession } from '../keystore/session.js';
|
|
6
7
|
import { formatResult } from '../output.js';
|
|
7
|
-
import { resolveHome } from '../paths.js';
|
|
8
|
+
import { defaultSessionPath, resolveHome } from '../paths.js';
|
|
8
9
|
/**
|
|
9
10
|
* Registers the top-level `btcr2 init`: the one-command entry point that creates
|
|
10
11
|
* the btcr2 home (ADR 079), writes a default config if none exists, and
|
|
@@ -51,6 +52,11 @@ export function registerInitCommand(program, globals) {
|
|
|
51
52
|
protection: options.dev ? 'none' : 'passphrase',
|
|
52
53
|
getPassphrase: (opts) => acquirePassphrase({ passphraseFile: g.passphraseFile, confirm: opts?.confirm, prompt: 'New keystore passphrase: ' }),
|
|
53
54
|
});
|
|
55
|
+
// A freshly established keystore mints a new verifier (or none, for --dev),
|
|
56
|
+
// so any cached session holds a passphrase for a keystore that no longer
|
|
57
|
+
// exists. Drop it, matching `keystore init` / `change-passphrase`, rather
|
|
58
|
+
// than leave a stale plaintext passphrase behind (ADR 081).
|
|
59
|
+
clearSession(defaultSessionPath(g));
|
|
54
60
|
created.push('keystore');
|
|
55
61
|
}
|
|
56
62
|
const protection = keystoreSummary(keystorePath).protection;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../../../src/commands/init.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAC9F,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../../../src/commands/init.ts"],"names":[],"mappings":"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"}
|