@did-btcr2/cli 0.11.0 → 0.12.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/dist/.tsbuildinfo +1 -1
- package/dist/cjs/index.js +205 -137
- package/dist/esm/src/cli.js +1 -1
- package/dist/esm/src/cli.js.map +1 -1
- package/dist/esm/src/commands/create.js +109 -30
- package/dist/esm/src/commands/create.js.map +1 -1
- package/dist/esm/src/config.js +20 -0
- package/dist/esm/src/config.js.map +1 -1
- package/dist/esm/src/keystore/resolve-key-ref.js +13 -8
- package/dist/esm/src/keystore/resolve-key-ref.js.map +1 -1
- package/dist/types/src/commands/create.d.ts +19 -1
- package/dist/types/src/commands/create.d.ts.map +1 -1
- package/dist/types/src/config.d.ts +9 -0
- package/dist/types/src/config.d.ts.map +1 -1
- package/dist/types/src/keystore/resolve-key-ref.d.ts +3 -2
- package/dist/types/src/keystore/resolve-key-ref.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +2 -5
- package/dist/types/src/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/cli.ts +1 -1
- package/src/commands/create.ts +140 -52
- package/src/config.ts +23 -0
- package/src/keystore/resolve-key-ref.ts +16 -11
- package/src/types.ts +1 -7
package/dist/cjs/index.js
CHANGED
|
@@ -43,6 +43,7 @@ __export(index_exports, {
|
|
|
43
43
|
registerProfileCommand: () => registerProfileCommand,
|
|
44
44
|
registerResolveCommand: () => registerResolveCommand,
|
|
45
45
|
registerUpdateCommand: () => registerUpdateCommand,
|
|
46
|
+
resolveDefaultNetwork: () => resolveDefaultNetwork,
|
|
46
47
|
setConfigPath: () => setConfigPath,
|
|
47
48
|
unsetConfigPath: () => unsetConfigPath,
|
|
48
49
|
writeConfigFile: () => writeConfigFile
|
|
@@ -57,96 +58,8 @@ var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
|
57
58
|
var import_common3 = require("@did-btcr2/common");
|
|
58
59
|
var import_commander = require("commander");
|
|
59
60
|
|
|
60
|
-
// src/error.ts
|
|
61
|
-
var import_common = require("@did-btcr2/common");
|
|
62
|
-
var CLIError = class extends import_common.DidMethodError {
|
|
63
|
-
constructor(message, type = "CLIError", data) {
|
|
64
|
-
super(message, { type, name: "CLIError", data });
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
// src/output.ts
|
|
69
|
-
function formatResult(result, options) {
|
|
70
|
-
if (options.output === "json") {
|
|
71
|
-
return JSON.stringify(result, null, 2);
|
|
72
|
-
}
|
|
73
|
-
const { data } = result;
|
|
74
|
-
return typeof data === "string" ? data : JSON.stringify(data, null, 2);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// src/types.ts
|
|
78
|
-
var SUPPORTED_NETWORKS = [
|
|
79
|
-
"bitcoin",
|
|
80
|
-
"testnet3",
|
|
81
|
-
"testnet4",
|
|
82
|
-
"signet",
|
|
83
|
-
"mutinynet",
|
|
84
|
-
"regtest"
|
|
85
|
-
];
|
|
86
|
-
|
|
87
61
|
// src/commands/create.ts
|
|
88
|
-
var
|
|
89
|
-
k: { length: 33, label: "secp256k1 compressed public key (33 bytes)" },
|
|
90
|
-
x: { length: 32, label: "SHA-256 hash (32 bytes)" }
|
|
91
|
-
};
|
|
92
|
-
function registerCreateCommand(program, factory, globals) {
|
|
93
|
-
program.command("create").description("Create an identifier and initial DID document").requiredOption("-t, --type <type>", "Identifier type <k|x>", "k").requiredOption(
|
|
94
|
-
"-n, --network <network>",
|
|
95
|
-
"Identifier bitcoin network <bitcoin|testnet3|testnet4|signet|mutinynet|regtest>"
|
|
96
|
-
).requiredOption(
|
|
97
|
-
"-b, --bytes <bytes>",
|
|
98
|
-
"Genesis bytes as a hex string. If type=k, MUST be secp256k1 public key. If type=x, MUST be SHA-256 hash of a genesis document"
|
|
99
|
-
).action(async (options) => {
|
|
100
|
-
const parsed = validateCreateOptions(options);
|
|
101
|
-
const api = factory();
|
|
102
|
-
const type = parsed.type === "k" ? "deterministic" : "external";
|
|
103
|
-
const genesisBytes = Buffer.from(parsed.bytes, "hex");
|
|
104
|
-
const data = api.createDid(type, genesisBytes, { network: parsed.network });
|
|
105
|
-
const result = { action: "create", data };
|
|
106
|
-
console.log(formatResult(result, globals()));
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
function validateCreateOptions(options) {
|
|
110
|
-
if (!["k", "x"].includes(options.type)) {
|
|
111
|
-
throw new CLIError(
|
|
112
|
-
'Invalid type. Must be "k" or "x".',
|
|
113
|
-
"INVALID_ARGUMENT_ERROR",
|
|
114
|
-
options
|
|
115
|
-
);
|
|
116
|
-
}
|
|
117
|
-
if (!SUPPORTED_NETWORKS.includes(options.network)) {
|
|
118
|
-
throw new CLIError(
|
|
119
|
-
'Invalid network. Must be one of "bitcoin", "testnet3", "testnet4", "signet", "mutinynet", or "regtest".',
|
|
120
|
-
"INVALID_ARGUMENT_ERROR",
|
|
121
|
-
options
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
const buf = Buffer.from(options.bytes, "hex");
|
|
125
|
-
if (buf.length === 0) {
|
|
126
|
-
throw new CLIError(
|
|
127
|
-
"Invalid bytes. Must be a non-empty hex string.",
|
|
128
|
-
"INVALID_ARGUMENT_ERROR",
|
|
129
|
-
options
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
const expected = EXPECTED_BYTES[options.type];
|
|
133
|
-
if (buf.length !== expected.length) {
|
|
134
|
-
throw new CLIError(
|
|
135
|
-
`Invalid bytes length for type="${options.type}": expected ${expected.label}, got ${buf.length} bytes.`,
|
|
136
|
-
"INVALID_ARGUMENT_ERROR",
|
|
137
|
-
options
|
|
138
|
-
);
|
|
139
|
-
}
|
|
140
|
-
return {
|
|
141
|
-
type: options.type,
|
|
142
|
-
network: options.network,
|
|
143
|
-
bytes: options.bytes
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// src/commands/resolve.ts
|
|
148
|
-
var import_api2 = require("@did-btcr2/api");
|
|
149
|
-
var import_promises = require("fs/promises");
|
|
62
|
+
var import_utils2 = require("@noble/hashes/utils.js");
|
|
150
63
|
|
|
151
64
|
// src/config.ts
|
|
152
65
|
var import_api = require("@did-btcr2/api");
|
|
@@ -154,6 +67,14 @@ var import_node_fs4 = require("fs");
|
|
|
154
67
|
var import_node_os2 = require("os");
|
|
155
68
|
var import_node_path4 = require("path");
|
|
156
69
|
|
|
70
|
+
// src/error.ts
|
|
71
|
+
var import_common = require("@did-btcr2/common");
|
|
72
|
+
var CLIError = class extends import_common.DidMethodError {
|
|
73
|
+
constructor(message, type = "CLIError", data) {
|
|
74
|
+
super(message, { type, name: "CLIError", data });
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
157
78
|
// src/keystore/atomic.ts
|
|
158
79
|
var import_node_fs = require("fs");
|
|
159
80
|
var import_node_path = require("path");
|
|
@@ -609,6 +530,16 @@ function promptHidden(label) {
|
|
|
609
530
|
return Buffer.from(bytes).toString("utf-8");
|
|
610
531
|
}
|
|
611
532
|
|
|
533
|
+
// src/types.ts
|
|
534
|
+
var SUPPORTED_NETWORKS = [
|
|
535
|
+
"bitcoin",
|
|
536
|
+
"testnet3",
|
|
537
|
+
"testnet4",
|
|
538
|
+
"signet",
|
|
539
|
+
"mutinynet",
|
|
540
|
+
"regtest"
|
|
541
|
+
];
|
|
542
|
+
|
|
612
543
|
// src/config.ts
|
|
613
544
|
var CONFIG_SCHEMA_VERSION = 1;
|
|
614
545
|
function writeConfigFile(path, mutate) {
|
|
@@ -687,6 +618,17 @@ function profileToOverrides(config, profileName) {
|
|
|
687
618
|
casGateway: profile.cas?.gateway
|
|
688
619
|
};
|
|
689
620
|
}
|
|
621
|
+
function resolveDefaultNetwork(overrides) {
|
|
622
|
+
const configPath = overrides?.config ?? defaultConfigPath();
|
|
623
|
+
const file = readConfigFile(configPath);
|
|
624
|
+
const explicit = file?.defaults?.network;
|
|
625
|
+
if (explicit && SUPPORTED_NETWORKS.includes(explicit)) return explicit;
|
|
626
|
+
const profile = overrides?.profile ?? file?.defaults?.profile;
|
|
627
|
+
if (profile && SUPPORTED_NETWORKS.includes(profile)) {
|
|
628
|
+
return profile;
|
|
629
|
+
}
|
|
630
|
+
return "regtest";
|
|
631
|
+
}
|
|
690
632
|
function resolveConnectionConfig(network, overrides) {
|
|
691
633
|
if (!network) return {};
|
|
692
634
|
const configPath = overrides?.config ?? defaultConfigPath();
|
|
@@ -742,7 +684,172 @@ function deriveNetwork(did) {
|
|
|
742
684
|
return network;
|
|
743
685
|
}
|
|
744
686
|
|
|
687
|
+
// src/keystore/resolve-key-ref.ts
|
|
688
|
+
function fingerprintOf(id) {
|
|
689
|
+
return /^urn:kms:secp256k1:([0-9a-f]{32})$/.exec(id)?.[1];
|
|
690
|
+
}
|
|
691
|
+
function resolveKeyRef(kms, ref) {
|
|
692
|
+
if (!ref) {
|
|
693
|
+
if (!kms.activeKeyId) {
|
|
694
|
+
throw new CLIError(
|
|
695
|
+
"No key specified and no active key is set. Use --key <ref> or set one with `btcr2 key use <ref>`.",
|
|
696
|
+
"INVALID_ARGUMENT_ERROR"
|
|
697
|
+
);
|
|
698
|
+
}
|
|
699
|
+
return kms.activeKeyId;
|
|
700
|
+
}
|
|
701
|
+
const ids = kms.listKeys();
|
|
702
|
+
if (ids.includes(ref)) return ref;
|
|
703
|
+
const byName = ids.filter((id) => kms.getEntry(id).tags?.name === ref);
|
|
704
|
+
if (byName.length === 1) return byName[0];
|
|
705
|
+
if (byName.length > 1) {
|
|
706
|
+
throw new CLIError(
|
|
707
|
+
`Ambiguous key name "${ref}" matches ${byName.length} keys.`,
|
|
708
|
+
"KEY_REF_AMBIGUOUS_ERROR",
|
|
709
|
+
{ ref }
|
|
710
|
+
);
|
|
711
|
+
}
|
|
712
|
+
const prefix = ref.toLowerCase();
|
|
713
|
+
const byPrefix = ids.filter((id) => fingerprintOf(id)?.startsWith(prefix));
|
|
714
|
+
if (byPrefix.length === 1) return byPrefix[0];
|
|
715
|
+
if (byPrefix.length > 1) {
|
|
716
|
+
throw new CLIError(
|
|
717
|
+
`Ambiguous key reference "${ref}" matches ${byPrefix.length} keys by fingerprint.`,
|
|
718
|
+
"KEY_REF_AMBIGUOUS_ERROR",
|
|
719
|
+
{ ref }
|
|
720
|
+
);
|
|
721
|
+
}
|
|
722
|
+
throw new CLIError(`No key matches reference "${ref}".`, "KEY_NOT_FOUND_ERROR", { ref });
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
// src/output.ts
|
|
726
|
+
function formatResult(result, options) {
|
|
727
|
+
if (options.output === "json") {
|
|
728
|
+
return JSON.stringify(result, null, 2);
|
|
729
|
+
}
|
|
730
|
+
const { data } = result;
|
|
731
|
+
return typeof data === "string" ? data : JSON.stringify(data, null, 2);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
// src/commands/create.ts
|
|
735
|
+
var EXPECTED_BYTES = {
|
|
736
|
+
k: { length: 33, label: "secp256k1 compressed public key (33 bytes)" },
|
|
737
|
+
x: { length: 32, label: "SHA-256 hash (32 bytes)" }
|
|
738
|
+
};
|
|
739
|
+
function registerCreateCommand(program, factory, keystoreFactory, globals) {
|
|
740
|
+
program.command("create").description("Create an identifier and initial DID document").option("-t, --type <type>", "Identifier type <k|x>", "k").option(
|
|
741
|
+
"-n, --network <network>",
|
|
742
|
+
"Identifier bitcoin network <bitcoin|testnet3|testnet4|signet|mutinynet|regtest> (default: config defaults.network, else regtest)"
|
|
743
|
+
).option(
|
|
744
|
+
"-b, --bytes <bytes>",
|
|
745
|
+
"Genesis bytes as a hex string. For type=k, a 33-byte secp256k1 public key (omit to generate a key). For type=x, the 32-byte SHA-256 hash of a genesis document."
|
|
746
|
+
).action(async (options) => {
|
|
747
|
+
const g = globals();
|
|
748
|
+
if (options.type !== "k" && options.type !== "x") {
|
|
749
|
+
throw new CLIError('Invalid type. Must be "k" or "x".', "INVALID_ARGUMENT_ERROR", options);
|
|
750
|
+
}
|
|
751
|
+
const overrides = overridesFromGlobals(g);
|
|
752
|
+
const network = resolveNetwork(options.network, overrides);
|
|
753
|
+
const signingKey = g.signingKey;
|
|
754
|
+
const print = (result, note) => {
|
|
755
|
+
console.log(formatResult(result, g));
|
|
756
|
+
if (note && g.output !== "json") process.stderr.write(`${note}
|
|
757
|
+
`);
|
|
758
|
+
};
|
|
759
|
+
if (options.type === "x") {
|
|
760
|
+
if (signingKey) {
|
|
761
|
+
throw new CLIError(
|
|
762
|
+
"--signing-key applies only to deterministic identifiers (-t k).",
|
|
763
|
+
"INVALID_ARGUMENT_ERROR"
|
|
764
|
+
);
|
|
765
|
+
}
|
|
766
|
+
if (options.bytes === void 0) {
|
|
767
|
+
throw new CLIError(
|
|
768
|
+
"External identifiers (-t x) require --bytes <hex>, the 32-byte genesis document hash. Key generation is only available for -t k.",
|
|
769
|
+
"INVALID_ARGUMENT_ERROR"
|
|
770
|
+
);
|
|
771
|
+
}
|
|
772
|
+
const genesisBytes = parseGenesisBytes(options.bytes, "x");
|
|
773
|
+
const did2 = factory().createDid("external", genesisBytes, { network });
|
|
774
|
+
print({ action: "create", data: did2 });
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
if (options.bytes !== void 0 && signingKey) {
|
|
778
|
+
throw new CLIError(
|
|
779
|
+
"Provide at most one of --bytes or --signing-key.",
|
|
780
|
+
"INVALID_ARGUMENT_ERROR"
|
|
781
|
+
);
|
|
782
|
+
}
|
|
783
|
+
if (options.bytes !== void 0) {
|
|
784
|
+
const genesisBytes = parseGenesisBytes(options.bytes, "k");
|
|
785
|
+
const did2 = factory().createDid("deterministic", genesisBytes, { network });
|
|
786
|
+
print({ action: "create", data: did2 });
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
if (signingKey) {
|
|
790
|
+
const api2 = keystoreFactory(void 0, overrides);
|
|
791
|
+
const keyId2 = resolveKeyRef(api2.kms.kms, signingKey);
|
|
792
|
+
const publicKey2 = api2.kms.getPublicKey(keyId2);
|
|
793
|
+
const did2 = api2.createDid("deterministic", publicKey2, { network });
|
|
794
|
+
print(
|
|
795
|
+
{ action: "create", data: did2, keyId: keyId2, publicKey: (0, import_utils2.bytesToHex)(publicKey2) },
|
|
796
|
+
`Using stored key ${keyId2}.`
|
|
797
|
+
);
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
const api = keystoreFactory(void 0, overrides);
|
|
801
|
+
const { did, keyId } = api.generateDid({ network, setActive: true });
|
|
802
|
+
const publicKey = (0, import_utils2.bytesToHex)(api.kms.getPublicKey(keyId));
|
|
803
|
+
print(
|
|
804
|
+
{ action: "create", data: did, keyId, publicKey },
|
|
805
|
+
`Generated and stored key ${keyId} (now the active key).`
|
|
806
|
+
);
|
|
807
|
+
});
|
|
808
|
+
}
|
|
809
|
+
function overridesFromGlobals(g) {
|
|
810
|
+
return {
|
|
811
|
+
config: g.config,
|
|
812
|
+
profile: g.profile,
|
|
813
|
+
keystore: g.keystore,
|
|
814
|
+
passphraseFile: g.passphraseFile
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
function resolveNetwork(explicit, overrides) {
|
|
818
|
+
if (!explicit) return resolveDefaultNetwork(overrides);
|
|
819
|
+
if (!SUPPORTED_NETWORKS.includes(explicit)) {
|
|
820
|
+
throw new CLIError(
|
|
821
|
+
'Invalid network. Must be one of "bitcoin", "testnet3", "testnet4", "signet", "mutinynet", or "regtest".',
|
|
822
|
+
"INVALID_ARGUMENT_ERROR",
|
|
823
|
+
{ network: explicit }
|
|
824
|
+
);
|
|
825
|
+
}
|
|
826
|
+
return explicit;
|
|
827
|
+
}
|
|
828
|
+
function parseGenesisBytes(hex, type) {
|
|
829
|
+
const expected = EXPECTED_BYTES[type];
|
|
830
|
+
let bytes;
|
|
831
|
+
try {
|
|
832
|
+
bytes = (0, import_utils2.hexToBytes)(hex.trim());
|
|
833
|
+
} catch {
|
|
834
|
+
throw new CLIError(
|
|
835
|
+
`Invalid bytes: not valid hex. Expected ${expected.label}.`,
|
|
836
|
+
"INVALID_ARGUMENT_ERROR",
|
|
837
|
+
{ bytes: hex }
|
|
838
|
+
);
|
|
839
|
+
}
|
|
840
|
+
if (bytes.length !== expected.length) {
|
|
841
|
+
throw new CLIError(
|
|
842
|
+
`Invalid bytes length for type="${type}": expected ${expected.label}, got ${bytes.length} bytes.`,
|
|
843
|
+
"INVALID_ARGUMENT_ERROR",
|
|
844
|
+
{ bytes: hex }
|
|
845
|
+
);
|
|
846
|
+
}
|
|
847
|
+
return bytes;
|
|
848
|
+
}
|
|
849
|
+
|
|
745
850
|
// src/commands/resolve.ts
|
|
851
|
+
var import_api2 = require("@did-btcr2/api");
|
|
852
|
+
var import_promises = require("fs/promises");
|
|
746
853
|
function registerResolveCommand(program, factory, globals) {
|
|
747
854
|
program.command("resolve").alias("read").description("Resolve the DID document of the identifier.").requiredOption("-i, --identifier <identifier>", "did:btcr2 identifier").option("-r, --resolution-options <json>", "JSON string containing resolution options").option("-p, --resolution-options-path <path>", "Path to a JSON file containing resolution options").action(async (options) => {
|
|
748
855
|
const parsed = await validateResolveOptions(options);
|
|
@@ -783,46 +890,6 @@ async function validateResolveOptions(options) {
|
|
|
783
890
|
|
|
784
891
|
// src/commands/update.ts
|
|
785
892
|
var import_key_manager2 = require("@did-btcr2/key-manager");
|
|
786
|
-
|
|
787
|
-
// src/keystore/resolve-key-ref.ts
|
|
788
|
-
function fingerprintOf(id) {
|
|
789
|
-
return /^urn:kms:secp256k1:([0-9a-f]{32})$/.exec(id)?.[1];
|
|
790
|
-
}
|
|
791
|
-
function resolveKeyRef(kms, ref) {
|
|
792
|
-
if (!ref) {
|
|
793
|
-
if (!kms.activeKeyId) {
|
|
794
|
-
throw new CLIError(
|
|
795
|
-
"No key specified and no active key is set. Use --key <ref> or set one with `btcr2 key use <ref>`.",
|
|
796
|
-
"INVALID_ARGUMENT_ERROR"
|
|
797
|
-
);
|
|
798
|
-
}
|
|
799
|
-
return kms.activeKeyId;
|
|
800
|
-
}
|
|
801
|
-
const ids = kms.listKeys();
|
|
802
|
-
if (ids.includes(ref)) return ref;
|
|
803
|
-
const prefix = ref.toLowerCase();
|
|
804
|
-
const byPrefix = ids.filter((id) => fingerprintOf(id)?.startsWith(prefix));
|
|
805
|
-
if (byPrefix.length === 1) return byPrefix[0];
|
|
806
|
-
if (byPrefix.length > 1) {
|
|
807
|
-
throw new CLIError(
|
|
808
|
-
`Ambiguous key reference "${ref}" matches ${byPrefix.length} keys by fingerprint.`,
|
|
809
|
-
"KEY_REF_AMBIGUOUS_ERROR",
|
|
810
|
-
{ ref }
|
|
811
|
-
);
|
|
812
|
-
}
|
|
813
|
-
const byName = ids.filter((id) => kms.getEntry(id).tags?.name === ref);
|
|
814
|
-
if (byName.length === 1) return byName[0];
|
|
815
|
-
if (byName.length > 1) {
|
|
816
|
-
throw new CLIError(
|
|
817
|
-
`Ambiguous key name "${ref}" matches ${byName.length} keys.`,
|
|
818
|
-
"KEY_REF_AMBIGUOUS_ERROR",
|
|
819
|
-
{ ref }
|
|
820
|
-
);
|
|
821
|
-
}
|
|
822
|
-
throw new CLIError(`No key matches reference "${ref}".`, "KEY_NOT_FOUND_ERROR", { ref });
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
// src/commands/update.ts
|
|
826
893
|
function registerUpdateCommand(program, factory, globals) {
|
|
827
894
|
program.command("update").description("Update a did:btcr2 document.").requiredOption(
|
|
828
895
|
"-s, --source-document <json>",
|
|
@@ -966,7 +1033,7 @@ function parseJsonArg2(flagName) {
|
|
|
966
1033
|
|
|
967
1034
|
// src/commands/key.ts
|
|
968
1035
|
var import_keypair = require("@did-btcr2/keypair");
|
|
969
|
-
var
|
|
1036
|
+
var import_utils3 = require("@noble/hashes/utils.js");
|
|
970
1037
|
var import_node_fs5 = require("fs");
|
|
971
1038
|
function registerKeyCommand(program, factory, globals) {
|
|
972
1039
|
const key = program.command("key").description("Manage keypairs in the encrypted keystore.");
|
|
@@ -976,7 +1043,7 @@ function registerKeyCommand(program, factory, globals) {
|
|
|
976
1043
|
assertNameAvailable(api.kms.kms, options.name);
|
|
977
1044
|
const setActive = options.setActive ?? false;
|
|
978
1045
|
const id = api.kms.generateKey({ ...options.name && { tags: { name: options.name } }, setActive });
|
|
979
|
-
print({ action: "key-generate", data: { keyId: id, publicKey: (0,
|
|
1046
|
+
print({ action: "key-generate", data: { keyId: id, publicKey: (0, import_utils3.bytesToHex)(api.kms.getPublicKey(id)), active: setActive } });
|
|
980
1047
|
});
|
|
981
1048
|
key.command("list").alias("ls").description("List stored keys.").action(() => {
|
|
982
1049
|
const kms = factory(void 0, globals()).kms.kms;
|
|
@@ -996,7 +1063,7 @@ function registerKeyCommand(program, factory, globals) {
|
|
|
996
1063
|
const kms = factory(void 0, globals()).kms.kms;
|
|
997
1064
|
const id = resolveKeyRef(kms, ref);
|
|
998
1065
|
const entry = kms.getEntry(id);
|
|
999
|
-
print({ action: "key-show", data: { keyId: id, publicKey: (0,
|
|
1066
|
+
print({ action: "key-show", data: { keyId: id, publicKey: (0, import_utils3.bytesToHex)(entry.publicKey), ...entry.tags && { tags: entry.tags } } });
|
|
1000
1067
|
});
|
|
1001
1068
|
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) => {
|
|
1002
1069
|
if (Boolean(options.secretFile) === Boolean(options.public)) {
|
|
@@ -1007,13 +1074,13 @@ function registerKeyCommand(program, factory, globals) {
|
|
|
1007
1074
|
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") });
|
|
1008
1075
|
const setActive = options.setActive ?? false;
|
|
1009
1076
|
const id = api.kms.import(keyPair, { ...options.name && { tags: { name: options.name } }, setActive });
|
|
1010
|
-
print({ action: "key-import", data: { keyId: id, publicKey: (0,
|
|
1077
|
+
print({ action: "key-import", data: { keyId: id, publicKey: (0, import_utils3.bytesToHex)(api.kms.getPublicKey(id)), watchOnly: !options.secretFile, active: setActive } });
|
|
1011
1078
|
});
|
|
1012
1079
|
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) => {
|
|
1013
1080
|
const api = factory(void 0, globals());
|
|
1014
1081
|
const id = resolveKeyRef(api.kms.kms, ref);
|
|
1015
1082
|
if (!options.secret) {
|
|
1016
|
-
print({ action: "key-export", data: { keyId: id, publicKey: (0,
|
|
1083
|
+
print({ action: "key-export", data: { keyId: id, publicKey: (0, import_utils3.bytesToHex)(api.kms.getPublicKey(id)) } });
|
|
1017
1084
|
return;
|
|
1018
1085
|
}
|
|
1019
1086
|
if (!options.out) {
|
|
@@ -1024,7 +1091,7 @@ function registerKeyCommand(program, factory, globals) {
|
|
|
1024
1091
|
throw new CLIError(`Key ${id} is watch-only and has no secret to export.`, "INVALID_ARGUMENT_ERROR", { keyId: id });
|
|
1025
1092
|
}
|
|
1026
1093
|
process.stderr.write("warning: writing an unencrypted secret key to disk. Protect this file and delete it when done.\n");
|
|
1027
|
-
writeSecretFile(options.out, (0,
|
|
1094
|
+
writeSecretFile(options.out, (0, import_utils3.bytesToHex)(keyPair.secretKey.bytes));
|
|
1028
1095
|
print({ action: "key-export", data: { keyId: id, secretWrittenTo: options.out } });
|
|
1029
1096
|
});
|
|
1030
1097
|
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) => {
|
|
@@ -1049,7 +1116,7 @@ function assertNameAvailable(kms, name) {
|
|
|
1049
1116
|
function parseHex(hex, expectedBytes, label) {
|
|
1050
1117
|
let bytes;
|
|
1051
1118
|
try {
|
|
1052
|
-
bytes = (0,
|
|
1119
|
+
bytes = (0, import_utils3.hexToBytes)(hex.trim());
|
|
1053
1120
|
} catch {
|
|
1054
1121
|
throw new CLIError(`Invalid hex for ${label}.`, "INVALID_ARGUMENT_ERROR", { label });
|
|
1055
1122
|
}
|
|
@@ -1246,7 +1313,7 @@ var DidBtcr2Cli = class {
|
|
|
1246
1313
|
constructor(factory = defaultApiFactory, keystoreFactory = keystoreApiFactory) {
|
|
1247
1314
|
this.program = new import_commander.Command("btcr2").version(`btcr2 ${VERSION}`, "-v, --version", "Output the current version").description("CLI tool for the did:btcr2 method").option("-o, --output <format>", "Output format <json|text>", "text").option("--verbose", "Verbose output", false).option("--quiet", "Suppress non-essential output", false).option("-c, --config <path>", "Path to config file (default: $XDG_CONFIG_HOME/btcr2/config.json)").option("--profile <name>", "Config profile name (default: auto-detected from network)").option("--btc-rest <url>", "Override Bitcoin REST endpoint (Esplora API)").option("--btc-rpc-url <url>", "Override Bitcoin Core RPC endpoint").option("--btc-rpc-user <user>", "Bitcoin Core RPC username").option("--btc-rpc-pass <pass>", "Bitcoin Core RPC password").option("--cas-gateway <url>", "IPFS HTTP gateway for CAS reads").option("--keystore <path>", "Path to the keystore file (default: $XDG_DATA_HOME/btcr2/keystore.json)").option("--passphrase-file <path>", "Read the keystore passphrase from a file (unattended use)").option("--signing-key <ref>", "Key for update/deactivate signing: a URN, fingerprint prefix, or name");
|
|
1248
1315
|
const globals = () => this.program.opts();
|
|
1249
|
-
registerCreateCommand(this.program, factory, globals);
|
|
1316
|
+
registerCreateCommand(this.program, factory, keystoreFactory, globals);
|
|
1250
1317
|
registerResolveCommand(this.program, factory, globals);
|
|
1251
1318
|
registerUpdateCommand(this.program, keystoreFactory, globals);
|
|
1252
1319
|
registerDeactivateCommand(this.program, keystoreFactory, globals);
|
|
@@ -1312,6 +1379,7 @@ function handleError(error, verbose) {
|
|
|
1312
1379
|
registerProfileCommand,
|
|
1313
1380
|
registerResolveCommand,
|
|
1314
1381
|
registerUpdateCommand,
|
|
1382
|
+
resolveDefaultNetwork,
|
|
1315
1383
|
setConfigPath,
|
|
1316
1384
|
unsetConfigPath,
|
|
1317
1385
|
writeConfigFile
|
package/dist/esm/src/cli.js
CHANGED
|
@@ -40,7 +40,7 @@ export class DidBtcr2Cli {
|
|
|
40
40
|
.option('--passphrase-file <path>', 'Read the keystore passphrase from a file (unattended use)')
|
|
41
41
|
.option('--signing-key <ref>', 'Key for update/deactivate signing: a URN, fingerprint prefix, or name');
|
|
42
42
|
const globals = () => this.program.opts();
|
|
43
|
-
registerCreateCommand(this.program, factory, globals);
|
|
43
|
+
registerCreateCommand(this.program, factory, keystoreFactory, globals);
|
|
44
44
|
registerResolveCommand(this.program, factory, globals);
|
|
45
45
|
registerUpdateCommand(this.program, keystoreFactory, globals);
|
|
46
46
|
registerDeactivateCommand(this.program, keystoreFactory, globals);
|
package/dist/esm/src/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EACL,yBAAyB,EACzB,qBAAqB,EACrB,qBAAqB,EACrB,yBAAyB,EACzB,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAmB,MAAM,aAAa,CAAC;AAErF,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC;;GAEG;AACH,MAAM,OAAO,WAAW;IACN,OAAO,CAAU;IAEjC;;;;;;;;;;;;;OAaG;IACH,YACE,UAAsB,iBAAiB,EACvC,kBAA8B,kBAAkB;QAEhD,IAAI,CAAC,OAAO,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;aAChC,OAAO,CAAC,SAAS,OAAO,EAAE,EAAE,eAAe,EAAE,4BAA4B,CAAC;aAC1E,WAAW,CAAC,mCAAmC,CAAC;aAChD,MAAM,CAAC,uBAAuB,EAAE,2BAA2B,EAAE,MAAM,CAAC;aACpE,MAAM,CAAC,WAAW,EAAE,gBAAgB,EAAE,KAAK,CAAC;aAC5C,MAAM,CAAC,SAAS,EAAE,+BAA+B,EAAE,KAAK,CAAC;aACzD,MAAM,CAAC,qBAAqB,EAAE,mEAAmE,CAAC;aAClG,MAAM,CAAC,kBAAkB,EAAE,2DAA2D,CAAC;aACvF,MAAM,CAAC,kBAAkB,EAAE,8CAA8C,CAAC;aAC1E,MAAM,CAAC,qBAAqB,EAAE,oCAAoC,CAAC;aACnE,MAAM,CAAC,uBAAuB,EAAE,2BAA2B,CAAC;aAC5D,MAAM,CAAC,uBAAuB,EAAE,2BAA2B,CAAC;aAC5D,MAAM,CAAC,qBAAqB,EAAE,iCAAiC,CAAC;aAChE,MAAM,CAAC,mBAAmB,EAAE,yEAAyE,CAAC;aACtG,MAAM,CAAC,0BAA0B,EAAE,2DAA2D,CAAC;aAC/F,MAAM,CAAC,qBAAqB,EAAE,uEAAuE,CAAC,CAAC;QAE1G,MAAM,OAAO,GAAG,GAAkB,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAmB,CAAC;QAE1E,qBAAqB,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,49 +1,128 @@
|
|
|
1
|
+
import { bytesToHex, hexToBytes } from '@noble/hashes/utils.js';
|
|
2
|
+
import { resolveDefaultNetwork } from '../config.js';
|
|
1
3
|
import { CLIError } from '../error.js';
|
|
4
|
+
import { resolveKeyRef } from '../keystore/resolve-key-ref.js';
|
|
2
5
|
import { formatResult } from '../output.js';
|
|
3
|
-
import { SUPPORTED_NETWORKS
|
|
6
|
+
import { SUPPORTED_NETWORKS } from '../types.js';
|
|
4
7
|
/** Expected byte length per identifier type: compressed secp256k1 = 33, SHA-256 hash = 32. */
|
|
5
8
|
const EXPECTED_BYTES = {
|
|
6
9
|
k: { length: 33, label: 'secp256k1 compressed public key (33 bytes)' },
|
|
7
10
|
x: { length: 32, label: 'SHA-256 hash (32 bytes)' },
|
|
8
11
|
};
|
|
9
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Registers the `create` command.
|
|
14
|
+
*
|
|
15
|
+
* A deterministic (`-t k`) identifier has three mutually-exclusive input modes,
|
|
16
|
+
* selected by which is present:
|
|
17
|
+
* - generate (neither `--bytes` nor `--signing-key`): mint a fresh key, persist
|
|
18
|
+
* it to the keystore, set it active, and print the identifier. Sealing the
|
|
19
|
+
* secret prompts for the keystore passphrase.
|
|
20
|
+
* - existing (`--signing-key <ref>`): use a stored key's public key as the
|
|
21
|
+
* genesis bytes. Reading a public key never decrypts, so this never prompts.
|
|
22
|
+
* - raw (`--bytes <hex>`): a 33-byte public key as hex. Offline, keystore-free.
|
|
23
|
+
*
|
|
24
|
+
* An external (`-t x`) identifier is raw-bytes-only: a 32-byte genesis-document
|
|
25
|
+
* hash via `--bytes`. Generation and `--signing-key` apply only to `-t k`.
|
|
26
|
+
*
|
|
27
|
+
* The keystore-free `factory` serves the raw-bytes path; the keystore-aware
|
|
28
|
+
* `keystoreFactory` serves the generate and existing-key paths.
|
|
29
|
+
*/
|
|
30
|
+
export function registerCreateCommand(program, factory, keystoreFactory, globals) {
|
|
10
31
|
program
|
|
11
32
|
.command('create')
|
|
12
33
|
.description('Create an identifier and initial DID document')
|
|
13
|
-
.
|
|
14
|
-
.
|
|
15
|
-
|
|
16
|
-
'
|
|
17
|
-
'
|
|
34
|
+
.option('-t, --type <type>', 'Identifier type <k|x>', 'k')
|
|
35
|
+
.option('-n, --network <network>', 'Identifier bitcoin network <bitcoin|testnet3|testnet4|signet|mutinynet|regtest> '
|
|
36
|
+
+ '(default: config defaults.network, else regtest)')
|
|
37
|
+
.option('-b, --bytes <bytes>', 'Genesis bytes as a hex string. '
|
|
38
|
+
+ 'For type=k, a 33-byte secp256k1 public key (omit to generate a key). '
|
|
39
|
+
+ 'For type=x, the 32-byte SHA-256 hash of a genesis document.')
|
|
18
40
|
.action(async (options) => {
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
|
|
41
|
+
const g = globals();
|
|
42
|
+
if (options.type !== 'k' && options.type !== 'x') {
|
|
43
|
+
throw new CLIError('Invalid type. Must be "k" or "x".', 'INVALID_ARGUMENT_ERROR', options);
|
|
44
|
+
}
|
|
45
|
+
const overrides = overridesFromGlobals(g);
|
|
46
|
+
const network = resolveNetwork(options.network, overrides);
|
|
47
|
+
const signingKey = g.signingKey;
|
|
48
|
+
/** Prints the result, plus a stderr provenance line in text mode. */
|
|
49
|
+
const print = (result, note) => {
|
|
50
|
+
console.log(formatResult(result, g));
|
|
51
|
+
if (note && g.output !== 'json')
|
|
52
|
+
process.stderr.write(`${note}\n`);
|
|
53
|
+
};
|
|
54
|
+
// External: raw-bytes only.
|
|
55
|
+
if (options.type === 'x') {
|
|
56
|
+
if (signingKey) {
|
|
57
|
+
throw new CLIError('--signing-key applies only to deterministic identifiers (-t k).', 'INVALID_ARGUMENT_ERROR');
|
|
58
|
+
}
|
|
59
|
+
if (options.bytes === undefined) {
|
|
60
|
+
throw new CLIError('External identifiers (-t x) require --bytes <hex>, the 32-byte genesis document hash. '
|
|
61
|
+
+ 'Key generation is only available for -t k.', 'INVALID_ARGUMENT_ERROR');
|
|
62
|
+
}
|
|
63
|
+
const genesisBytes = parseGenesisBytes(options.bytes, 'x');
|
|
64
|
+
const did = factory().createDid('external', genesisBytes, { network });
|
|
65
|
+
print({ action: 'create', data: did });
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// Deterministic (KEY): three mutually-exclusive modes.
|
|
69
|
+
if (options.bytes !== undefined && signingKey) {
|
|
70
|
+
throw new CLIError('Provide at most one of --bytes or --signing-key.', 'INVALID_ARGUMENT_ERROR');
|
|
71
|
+
}
|
|
72
|
+
// Raw bytes: keystore-free, offline.
|
|
73
|
+
if (options.bytes !== undefined) {
|
|
74
|
+
const genesisBytes = parseGenesisBytes(options.bytes, 'k');
|
|
75
|
+
const did = factory().createDid('deterministic', genesisBytes, { network });
|
|
76
|
+
print({ action: 'create', data: did });
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
// Existing key: read its public key from the keystore (no passphrase prompt).
|
|
80
|
+
if (signingKey) {
|
|
81
|
+
const api = keystoreFactory(undefined, overrides);
|
|
82
|
+
const keyId = resolveKeyRef(api.kms.kms, signingKey);
|
|
83
|
+
const publicKey = api.kms.getPublicKey(keyId);
|
|
84
|
+
const did = api.createDid('deterministic', publicKey, { network });
|
|
85
|
+
print({ action: 'create', data: did, keyId, publicKey: bytesToHex(publicKey) }, `Using stored key ${keyId}.`);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
// Generate: mint a fresh key, persist it, and set it active (passphrase prompt).
|
|
89
|
+
const api = keystoreFactory(undefined, overrides);
|
|
90
|
+
const { did, keyId } = api.generateDid({ network, setActive: true });
|
|
91
|
+
const publicKey = bytesToHex(api.kms.getPublicKey(keyId));
|
|
92
|
+
print({ action: 'create', data: did, keyId, publicKey }, `Generated and stored key ${keyId} (now the active key).`);
|
|
26
93
|
});
|
|
27
94
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
95
|
+
/** Builds the keystore- and config-resolution overrides from the global flags. */
|
|
96
|
+
function overridesFromGlobals(g) {
|
|
97
|
+
return {
|
|
98
|
+
config: g.config,
|
|
99
|
+
profile: g.profile,
|
|
100
|
+
keystore: g.keystore,
|
|
101
|
+
passphraseFile: g.passphraseFile,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/** Validates an explicit `--network`, or resolves the default from configuration. */
|
|
105
|
+
function resolveNetwork(explicit, overrides) {
|
|
106
|
+
if (!explicit)
|
|
107
|
+
return resolveDefaultNetwork(overrides);
|
|
108
|
+
if (!SUPPORTED_NETWORKS.includes(explicit)) {
|
|
109
|
+
throw new CLIError('Invalid network. Must be one of "bitcoin", "testnet3", "testnet4", "signet", "mutinynet", or "regtest".', 'INVALID_ARGUMENT_ERROR', { network: explicit });
|
|
31
110
|
}
|
|
32
|
-
|
|
33
|
-
|
|
111
|
+
return explicit;
|
|
112
|
+
}
|
|
113
|
+
/** Parses and length-checks hex genesis bytes for the given identifier type. */
|
|
114
|
+
function parseGenesisBytes(hex, type) {
|
|
115
|
+
const expected = EXPECTED_BYTES[type];
|
|
116
|
+
let bytes;
|
|
117
|
+
try {
|
|
118
|
+
bytes = hexToBytes(hex.trim());
|
|
34
119
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
throw new CLIError('Invalid bytes. Must be a non-empty hex string.', 'INVALID_ARGUMENT_ERROR', options);
|
|
120
|
+
catch {
|
|
121
|
+
throw new CLIError(`Invalid bytes: not valid hex. Expected ${expected.label}.`, 'INVALID_ARGUMENT_ERROR', { bytes: hex });
|
|
38
122
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
throw new CLIError(`Invalid bytes length for type="${options.type}": expected ${expected.label}, got ${buf.length} bytes.`, 'INVALID_ARGUMENT_ERROR', options);
|
|
123
|
+
if (bytes.length !== expected.length) {
|
|
124
|
+
throw new CLIError(`Invalid bytes length for type="${type}": expected ${expected.label}, got ${bytes.length} bytes.`, 'INVALID_ARGUMENT_ERROR', { bytes: hex });
|
|
42
125
|
}
|
|
43
|
-
return
|
|
44
|
-
type: options.type,
|
|
45
|
-
network: options.network,
|
|
46
|
-
bytes: options.bytes,
|
|
47
|
-
};
|
|
126
|
+
return bytes;
|
|
48
127
|
}
|
|
49
128
|
//# sourceMappingURL=create.js.map
|