@bcts/seedtool-cli 1.0.0-alpha.14 → 1.0.0-alpha.16

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/main.mjs CHANGED
@@ -2,17 +2,17 @@
2
2
  import { Command, Option } from "commander";
3
3
  import { SecureRandomNumberGenerator } from "@bcts/rand";
4
4
  import { SSKRGroupSpec, SSKRSecret, SSKRShare, SSKRSpec, Seed, sskrCombine, sskrGenerate } from "@bcts/components";
5
- import * as readline from "readline";
5
+ import * as readline from "node:readline";
6
6
  import { Envelope, SymmetricKey } from "@bcts/envelope";
7
7
  import { DATE, NAME, NOTE, SEED_TYPE } from "@bcts/known-values";
8
8
  import { CborDate, decodeCbor, expectBytes, toByteString, toTaggedValue } from "@bcts/dcbor";
9
9
  import { entropyToMnemonic, mnemonicToEntropy, validateMnemonic } from "@scure/bip39";
10
- import { wordlist } from "@scure/bip39/wordlists/english";
10
+ import { wordlist } from "@scure/bip39/wordlists/english.js";
11
11
  import { BytewordsStyle, MultipartDecoder, MultipartEncoder, UR, decodeBytewords, encodeBytewords } from "@bcts/uniform-resources";
12
12
  import { SSKR_SHARE, SSKR_SHARE_V1 } from "@bcts/tags";
13
- import { sha256 } from "@noble/hashes/sha256";
14
- import { hkdf } from "@noble/hashes/hkdf";
15
- import * as fs from "node:fs";
13
+ import { sha256 } from "@noble/hashes/sha2.js";
14
+ import { hkdf } from "@noble/hashes/hkdf.js";
15
+ import fs from "node:fs";
16
16
 
17
17
  //#region src/cli.ts
18
18
  /**
@@ -137,7 +137,7 @@ var Cli = class Cli {
137
137
  terminal: false
138
138
  });
139
139
  rl.on("line", (line) => {
140
- data += line + "\n";
140
+ data += `${line}\n`;
141
141
  });
142
142
  rl.on("close", () => {
143
143
  resolve(data.trim());
@@ -194,23 +194,23 @@ var Cli = class Cli {
194
194
  */
195
195
  clone() {
196
196
  const cli = new Cli();
197
- cli.input = this.input;
197
+ if (this.input !== void 0) cli.input = this.input;
198
198
  cli.count = this.count;
199
199
  cli.in = this.in;
200
200
  cli.out = this.out;
201
201
  cli.low = this.low;
202
202
  cli.high = this.high;
203
- cli.name = this.name;
204
- cli.note = this.note;
205
- cli.date = this.date;
203
+ if (this.name !== void 0) cli.name = this.name;
204
+ if (this.note !== void 0) cli.note = this.note;
205
+ if (this.date !== void 0) cli.date = this.date;
206
206
  cli.maxFragmentLen = this.maxFragmentLen;
207
207
  cli.additionalParts = this.additionalParts;
208
208
  cli.groups = [...this.groups];
209
209
  cli.groupThreshold = this.groupThreshold;
210
210
  cli.sskrFormat = this.sskrFormat;
211
- cli.deterministic = this.deterministic;
212
- cli.seed = this.seed?.clone();
213
- cli.rng = this.rng;
211
+ if (this.deterministic !== void 0) cli.deterministic = this.deterministic;
212
+ if (this.seed !== void 0) cli.seed = this.seed.clone();
213
+ if (this.rng !== void 0) cli.rng = this.rng;
214
214
  return cli;
215
215
  }
216
216
  };
@@ -332,7 +332,7 @@ var Seed$1 = class Seed$1 {
332
332
  * - Optional note assertion (if not empty)
333
333
  */
334
334
  toEnvelope() {
335
- let envelope = Envelope.new(toByteString(this._data));
335
+ let envelope = Envelope.new(this._data);
336
336
  envelope = envelope.addType(SEED_TYPE);
337
337
  if (this._creationDate !== void 0) {
338
338
  const cborDate = CborDate.fromDatetime(this._creationDate);
@@ -580,6 +580,10 @@ var Bip39Format = class {
580
580
  //#endregion
581
581
  //#region src/formats/sskr.ts
582
582
  /**
583
+ * SSKR format
584
+ * Ported from seedtool-cli-rust/src/formats/sskr.rs
585
+ */
586
+ /**
583
587
  * SSKR format handler.
584
588
  * Round-trippable: sskr shares → seed → sskr shares.
585
589
  * Supports multiple sub-formats: envelope, btw, btwm, btwu, ur.
@@ -604,16 +608,16 @@ var SSKRFormat = class {
604
608
  };
605
609
  function outputSskrSeed(seed, spec, format) {
606
610
  switch (format) {
607
- case "envelope": {
608
- const envelope = seed.toEnvelope();
611
+ case SSKRFormatKey.Envelope: {
612
+ const seedEnvelope = seed.toEnvelope();
609
613
  const contentKey = SymmetricKey.new();
610
- return envelope.wrap().encryptSubject(contentKey).sskrSplitFlattened(spec, contentKey).map((envelope$1) => envelope$1.urString()).join("\n");
614
+ return seedEnvelope.wrap().encryptSubject(contentKey).sskrSplitFlattened(spec, contentKey).map((env) => env.urString()).join("\n");
611
615
  }
612
- case "btw": return makeBytewordsShares(spec, seed, BytewordsStyle.Standard);
613
- case "btwm": return makeBytewordsShares(spec, seed, BytewordsStyle.Minimal);
614
- case "btwu": return makeBytewordsShares(spec, seed, BytewordsStyle.Uri);
615
- case "ur": return makeShares(spec, seed).map((share) => {
616
- return UR.fromCbor("sskr", toByteString(share.asBytes())).toString();
616
+ case SSKRFormatKey.Btw: return makeBytewordsShares(spec, seed, BytewordsStyle.Standard);
617
+ case SSKRFormatKey.Btwm: return makeBytewordsShares(spec, seed, BytewordsStyle.Minimal);
618
+ case SSKRFormatKey.Btwu: return makeBytewordsShares(spec, seed, BytewordsStyle.Uri);
619
+ case SSKRFormatKey.Ur: return makeShares(spec, seed).map((share) => {
620
+ return UR.new("sskr", toByteString(share.asBytes())).toString();
617
621
  }).join("\n");
618
622
  }
619
623
  }
@@ -635,7 +639,8 @@ function parseEnvelopes(input) {
635
639
  shareEnvelopes.push(envelope);
636
640
  } catch {}
637
641
  if (shareEnvelopes.length === 0) return null;
638
- const recoveredEnvelope = Envelope.sskrJoin(shareEnvelopes).unwrap();
642
+ const sskrJoin = Envelope.sskrJoin;
643
+ const recoveredEnvelope = sskrJoin(shareEnvelopes).unwrap();
639
644
  return Seed$1.fromEnvelope(recoveredEnvelope);
640
645
  } catch {
641
646
  return null;
@@ -656,7 +661,7 @@ function fromTaggedCborShares(taggedCborDataShares) {
656
661
  const cbor = decodeCbor(data);
657
662
  const tagged = cbor;
658
663
  if (tagged.tag !== SSKR_SHARE.value && tagged.tag !== SSKR_SHARE_V1.value) return null;
659
- const bytes = expectBytes(tagged.value || cbor);
664
+ const bytes = expectBytes(tagged.value !== void 0 ? tagged.value : cbor);
660
665
  untaggedShares.push(bytes);
661
666
  }
662
667
  return fromUntaggedCborShares(untaggedShares);
@@ -690,7 +695,7 @@ function parseUr(input, expectedTagValue, allowTaggedCbor) {
690
695
  urs.push(ur);
691
696
  } catch {}
692
697
  if (urs.length === 0) return null;
693
- for (const ur of urs) if (ur.type() !== expectedType) return null;
698
+ for (const ur of urs) if (ur.urTypeStr() !== expectedType) return null;
694
699
  const untaggedCborShares = [];
695
700
  for (const ur of urs) {
696
701
  let cbor = ur.cbor();
@@ -715,9 +720,9 @@ function parseSskrSeed(input) {
715
720
  if (btwmResult !== null) return btwmResult;
716
721
  const btwuResult = parseBytewords(input, BytewordsStyle.Uri);
717
722
  if (btwuResult !== null) return btwuResult;
718
- const urResult = parseUr(input, SSKR_SHARE.value, false);
723
+ const urResult = parseUr(input, Number(SSKR_SHARE.value), false);
719
724
  if (urResult !== null) return urResult;
720
- const urLegacyResult = parseUr(input, SSKR_SHARE_V1.value, true);
725
+ const urLegacyResult = parseUr(input, Number(SSKR_SHARE_V1.value), true);
721
726
  if (urLegacyResult !== null) return urLegacyResult;
722
727
  throw new Error("Insufficient or invalid SSKR shares.");
723
728
  }
@@ -794,7 +799,7 @@ var MultipartFormat = class {
794
799
  }
795
800
  if (!decoder.isComplete()) throw new Error("Insufficient multipart shares");
796
801
  const ur = decoder.message();
797
- if (ur === void 0) throw new Error("Failed to decode multipart message");
802
+ if (ur === void 0 || ur === null) throw new Error("Failed to decode multipart message");
798
803
  const envelope = Envelope.fromUR(ur);
799
804
  state.seed = Seed$1.fromEnvelope(envelope);
800
805
  return state;
@@ -1205,28 +1210,31 @@ var BytewordsUriFormat = class {
1205
1210
  //#endregion
1206
1211
  //#region src/formats/format.ts
1207
1212
  /**
1213
+ * Format traits and factory functions
1214
+ * Ported from seedtool-cli-rust/src/formats/format.rs
1215
+ */
1216
+ /**
1208
1217
  * Select input format by key.
1209
1218
  * Matches Rust select_input_format function.
1210
1219
  */
1211
1220
  function selectInputFormat(key) {
1212
1221
  switch (key) {
1213
- case "random": return new RandomFormat();
1214
- case "hex": return new HexFormat();
1215
- case "btw": return new BytewordsStandardFormat();
1216
- case "btwu": return new BytewordsUriFormat();
1217
- case "btwm": return new BytewordsMinimalFormat();
1218
- case "bits": return new BitsFormat();
1219
- case "cards": return new CardsFormat();
1220
- case "dice": return new DiceFormat();
1221
- case "base6": return new Base6Format();
1222
- case "base10": return new Base10Format();
1223
- case "ints": return new IntsFormat();
1224
- case "bip39": return new Bip39Format();
1225
- case "sskr": return new SSKRFormat();
1226
- case "envelope": return new EnvelopeFormat();
1227
- case "multipart": return new MultipartFormat();
1228
- case "seed": return new SeedFormat();
1229
- default: throw new Error(`Unknown input format: ${key}`);
1222
+ case InputFormatKey.Random: return new RandomFormat();
1223
+ case InputFormatKey.Hex: return new HexFormat();
1224
+ case InputFormatKey.Btw: return new BytewordsStandardFormat();
1225
+ case InputFormatKey.Btwu: return new BytewordsUriFormat();
1226
+ case InputFormatKey.Btwm: return new BytewordsMinimalFormat();
1227
+ case InputFormatKey.Bits: return new BitsFormat();
1228
+ case InputFormatKey.Cards: return new CardsFormat();
1229
+ case InputFormatKey.Dice: return new DiceFormat();
1230
+ case InputFormatKey.Base6: return new Base6Format();
1231
+ case InputFormatKey.Base10: return new Base10Format();
1232
+ case InputFormatKey.Ints: return new IntsFormat();
1233
+ case InputFormatKey.Bip39: return new Bip39Format();
1234
+ case InputFormatKey.Sskr: return new SSKRFormat();
1235
+ case InputFormatKey.Envelope: return new EnvelopeFormat();
1236
+ case InputFormatKey.Multipart: return new MultipartFormat();
1237
+ case InputFormatKey.Seed: return new SeedFormat();
1230
1238
  }
1231
1239
  }
1232
1240
  /**
@@ -1235,22 +1243,21 @@ function selectInputFormat(key) {
1235
1243
  */
1236
1244
  function selectOutputFormat(key) {
1237
1245
  switch (key) {
1238
- case "hex": return new HexFormat();
1239
- case "btw": return new BytewordsStandardFormat();
1240
- case "btwu": return new BytewordsUriFormat();
1241
- case "btwm": return new BytewordsMinimalFormat();
1242
- case "bits": return new BitsFormat();
1243
- case "cards": return new CardsFormat();
1244
- case "dice": return new DiceFormat();
1245
- case "base6": return new Base6Format();
1246
- case "base10": return new Base10Format();
1247
- case "ints": return new IntsFormat();
1248
- case "bip39": return new Bip39Format();
1249
- case "sskr": return new SSKRFormat();
1250
- case "envelope": return new EnvelopeFormat();
1251
- case "multipart": return new MultipartFormat();
1252
- case "seed": return new SeedFormat();
1253
- default: throw new Error(`Unknown output format: ${key}`);
1246
+ case OutputFormatKey.Hex: return new HexFormat();
1247
+ case OutputFormatKey.Btw: return new BytewordsStandardFormat();
1248
+ case OutputFormatKey.Btwu: return new BytewordsUriFormat();
1249
+ case OutputFormatKey.Btwm: return new BytewordsMinimalFormat();
1250
+ case OutputFormatKey.Bits: return new BitsFormat();
1251
+ case OutputFormatKey.Cards: return new CardsFormat();
1252
+ case OutputFormatKey.Dice: return new DiceFormat();
1253
+ case OutputFormatKey.Base6: return new Base6Format();
1254
+ case OutputFormatKey.Base10: return new Base10Format();
1255
+ case OutputFormatKey.Ints: return new IntsFormat();
1256
+ case OutputFormatKey.Bip39: return new Bip39Format();
1257
+ case OutputFormatKey.Sskr: return new SSKRFormat();
1258
+ case OutputFormatKey.Envelope: return new EnvelopeFormat();
1259
+ case OutputFormatKey.Multipart: return new MultipartFormat();
1260
+ case OutputFormatKey.Seed: return new SeedFormat();
1254
1261
  }
1255
1262
  }
1256
1263
 
@@ -1286,7 +1293,7 @@ function parseGroupSpec(value, previous) {
1286
1293
  const spec = SSKRGroupSpec.parse(value);
1287
1294
  return [...previous, spec];
1288
1295
  }
1289
- async function main() {
1296
+ function main() {
1290
1297
  const program = new Command();
1291
1298
  program.name("seedtool").description("A tool for generating and transforming cryptographic seeds.\n\nby Wolf McNally and Christopher Allen\n\nReport bugs to ChristopherA@BlockchainCommons.com.\n© 2024 Blockchain Commons.").version(VERSION).argument("[INPUT]", "The input to be transformed. If required and not present, it will be read from stdin.").option("-c, --count <COUNT>", "The number of output units (hex bytes, base-10 digits, etc.)", "16").addOption(new Option("-i, --in <INPUT_TYPE>", "The input format. If not specified, a new random seed is generated using a secure random number generator.").choices([
1292
1299
  "random",
@@ -1333,21 +1340,21 @@ async function main() {
1333
1340
  const args = program.args;
1334
1341
  const cli = new Cli();
1335
1342
  if (args.length > 0) cli.input = args[0];
1336
- else if (!process.stdin.isTTY) cli.input = fs.readFileSync(0, "utf-8").trim();
1343
+ else if (process.stdin.isTTY !== true) cli.input = fs.readFileSync(process.stdin.fd, "utf-8").trim();
1337
1344
  cli.count = parseInt(options.count, 10);
1338
1345
  cli.in = options.in;
1339
1346
  cli.out = options.out;
1340
1347
  cli.low = options.low;
1341
1348
  cli.high = options.high;
1342
- cli.name = options.name;
1343
- cli.note = options.note;
1344
- if (options.date) cli.date = parseCliDate(options.date);
1349
+ if (options.name !== void 0) cli.name = options.name;
1350
+ if (options.note !== void 0) cli.note = options.note;
1351
+ if (options.date !== void 0) cli.date = parseCliDate(options.date);
1345
1352
  cli.maxFragmentLen = parseInt(options.maxFragmentLen, 10);
1346
1353
  cli.additionalParts = parseInt(options.additionalParts, 10);
1347
1354
  cli.groups = options.groups;
1348
1355
  cli.groupThreshold = options.groupThreshold;
1349
1356
  cli.sskrFormat = options.sskrFormat;
1350
- if (options.deterministic) cli.rng = {
1357
+ if (options.deterministic !== void 0) cli.rng = {
1351
1358
  type: "deterministic",
1352
1359
  rng: DeterministicRandomNumberGenerator.newWithSeed(options.deterministic)
1353
1360
  };
@@ -1359,16 +1366,19 @@ async function main() {
1359
1366
  const outputFormat = selectOutputFormat(cli.out);
1360
1367
  if (!outputFormat.roundTrippable() && inputFormat.name() !== "random") {
1361
1368
  console.error(`Input for output form "${outputFormat.name()}" must be random.`);
1362
- process.exit(1);
1369
+ throw new Error("Invalid input format for non-round-trippable output format");
1363
1370
  }
1364
1371
  const processedCli = inputFormat.processInput(cli);
1365
1372
  const output = outputFormat.processOutput(processedCli);
1366
1373
  console.log(output);
1367
1374
  }
1368
- main().catch((error) => {
1369
- console.error(error.message);
1375
+ try {
1376
+ main();
1377
+ } catch (error) {
1378
+ const message = error instanceof Error ? error.message : String(error);
1379
+ console.error(message);
1370
1380
  process.exit(1);
1371
- });
1381
+ }
1372
1382
 
1373
1383
  //#endregion
1374
1384
  export { };