@did-btcr2/cli 0.15.0 → 0.16.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/README.md +47 -6
- package/dist/.tsbuildinfo +1 -1
- package/dist/cjs/index.js +563 -117
- package/dist/esm/src/cli.js +7 -4
- package/dist/esm/src/cli.js.map +1 -1
- package/dist/esm/src/commands/config.js +11 -15
- package/dist/esm/src/commands/config.js.map +1 -1
- package/dist/esm/src/commands/create.js +4 -1
- package/dist/esm/src/commands/create.js.map +1 -1
- package/dist/esm/src/commands/deactivate.js +3 -1
- package/dist/esm/src/commands/deactivate.js.map +1 -1
- package/dist/esm/src/commands/index.js +2 -0
- package/dist/esm/src/commands/index.js.map +1 -1
- package/dist/esm/src/commands/init.js +63 -0
- package/dist/esm/src/commands/init.js.map +1 -0
- package/dist/esm/src/commands/keystore.js +81 -0
- package/dist/esm/src/commands/keystore.js.map +1 -0
- package/dist/esm/src/commands/profile.js +1 -1
- package/dist/esm/src/commands/profile.js.map +1 -1
- package/dist/esm/src/commands/update.js +3 -1
- package/dist/esm/src/commands/update.js.map +1 -1
- package/dist/esm/src/config.js +85 -28
- package/dist/esm/src/config.js.map +1 -1
- package/dist/esm/src/keystore/file-key-store.js +340 -32
- package/dist/esm/src/keystore/file-key-store.js.map +1 -1
- package/dist/esm/src/keystore/passphrase.js +40 -10
- package/dist/esm/src/keystore/passphrase.js.map +1 -1
- package/dist/esm/src/keystore/paths.js +6 -18
- package/dist/esm/src/keystore/paths.js.map +1 -1
- package/dist/esm/src/paths.js +59 -0
- package/dist/esm/src/paths.js.map +1 -0
- package/dist/esm/src/types.js.map +1 -1
- package/dist/types/src/cli.d.ts.map +1 -1
- package/dist/types/src/commands/config.d.ts.map +1 -1
- package/dist/types/src/commands/create.d.ts.map +1 -1
- package/dist/types/src/commands/deactivate.d.ts.map +1 -1
- package/dist/types/src/commands/index.d.ts +2 -0
- package/dist/types/src/commands/index.d.ts.map +1 -1
- package/dist/types/src/commands/init.d.ts +13 -0
- package/dist/types/src/commands/init.d.ts.map +1 -0
- package/dist/types/src/commands/keystore.d.ts +10 -0
- package/dist/types/src/commands/keystore.d.ts.map +1 -0
- package/dist/types/src/commands/update.d.ts.map +1 -1
- package/dist/types/src/config.d.ts +38 -14
- package/dist/types/src/config.d.ts.map +1 -1
- package/dist/types/src/keystore/file-key-store.d.ts +86 -10
- package/dist/types/src/keystore/file-key-store.d.ts.map +1 -1
- package/dist/types/src/keystore/passphrase.d.ts +16 -1
- package/dist/types/src/keystore/passphrase.d.ts.map +1 -1
- package/dist/types/src/keystore/paths.d.ts +6 -10
- package/dist/types/src/keystore/paths.d.ts.map +1 -1
- package/dist/types/src/paths.d.ts +54 -0
- package/dist/types/src/paths.d.ts.map +1 -0
- package/dist/types/src/types.d.ts +38 -0
- package/dist/types/src/types.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/cli.ts +8 -3
- package/src/commands/config.ts +12 -14
- package/src/commands/create.ts +4 -1
- package/src/commands/deactivate.ts +3 -1
- package/src/commands/index.ts +2 -0
- package/src/commands/init.ts +74 -0
- package/src/commands/keystore.ts +98 -0
- package/src/commands/profile.ts +1 -1
- package/src/commands/update.ts +3 -1
- package/src/config.ts +93 -32
- package/src/keystore/file-key-store.ts +455 -43
- package/src/keystore/passphrase.ts +48 -8
- package/src/keystore/paths.ts +6 -19
- package/src/paths.ts +79 -0
- package/src/types.ts +13 -1
|
@@ -6,6 +6,12 @@ import type { DoctorReport, EffectiveConfig } from './config.js';
|
|
|
6
6
|
import type { ConfigIssue } from './config-schema.js';
|
|
7
7
|
export type NetworkOption = 'bitcoin' | 'testnet3' | 'testnet4' | 'signet' | 'mutinynet' | 'regtest';
|
|
8
8
|
export type OutputFormat = 'json' | 'text';
|
|
9
|
+
/**
|
|
10
|
+
* How a keystore protects its secrets, as reported by `keystore status` and
|
|
11
|
+
* `btcr2 init`: `encrypted` (passphrase-sealed), `dev` (plaintext, testnet-only),
|
|
12
|
+
* or `absent` (no keystore file yet).
|
|
13
|
+
*/
|
|
14
|
+
export type KeystoreProtectionLabel = 'encrypted' | 'dev' | 'absent';
|
|
9
15
|
export declare const SUPPORTED_NETWORKS: NetworkOption[];
|
|
10
16
|
/**
|
|
11
17
|
* Normalizes a blank value (empty or whitespace-only) to `undefined`, so a
|
|
@@ -88,6 +94,15 @@ export type CommandResult = {
|
|
|
88
94
|
keyId: string;
|
|
89
95
|
active: true;
|
|
90
96
|
};
|
|
97
|
+
} | {
|
|
98
|
+
action: 'init';
|
|
99
|
+
data: {
|
|
100
|
+
home: string;
|
|
101
|
+
config: string;
|
|
102
|
+
keystore: string;
|
|
103
|
+
created: string[];
|
|
104
|
+
protection: KeystoreProtectionLabel;
|
|
105
|
+
};
|
|
91
106
|
} | {
|
|
92
107
|
action: 'config-init';
|
|
93
108
|
data: {
|
|
@@ -121,12 +136,34 @@ export type CommandResult = {
|
|
|
121
136
|
} | {
|
|
122
137
|
action: 'config-path';
|
|
123
138
|
data: {
|
|
139
|
+
home: string;
|
|
124
140
|
config: string;
|
|
125
141
|
keystore: string;
|
|
126
142
|
};
|
|
127
143
|
} | {
|
|
128
144
|
action: 'config-doctor';
|
|
129
145
|
data: DoctorReport;
|
|
146
|
+
} | {
|
|
147
|
+
action: 'keystore-init';
|
|
148
|
+
data: {
|
|
149
|
+
path: string;
|
|
150
|
+
protection: 'encrypted' | 'dev';
|
|
151
|
+
};
|
|
152
|
+
} | {
|
|
153
|
+
action: 'keystore-status';
|
|
154
|
+
data: {
|
|
155
|
+
path: string;
|
|
156
|
+
protection: KeystoreProtectionLabel;
|
|
157
|
+
established: boolean;
|
|
158
|
+
keyCount: number;
|
|
159
|
+
active: string | undefined;
|
|
160
|
+
};
|
|
161
|
+
} | {
|
|
162
|
+
action: 'keystore-change-passphrase';
|
|
163
|
+
data: {
|
|
164
|
+
path: string;
|
|
165
|
+
rekeyed: number;
|
|
166
|
+
};
|
|
130
167
|
} | {
|
|
131
168
|
action: 'profile-add';
|
|
132
169
|
data: {
|
|
@@ -150,6 +187,7 @@ export interface GlobalOptions {
|
|
|
150
187
|
output: OutputFormat;
|
|
151
188
|
verbose: boolean;
|
|
152
189
|
quiet: boolean;
|
|
190
|
+
home?: string;
|
|
153
191
|
config?: string;
|
|
154
192
|
profile?: string;
|
|
155
193
|
btcRest?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,GAAG,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;AACrG,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,CAAC;AAE3C,eAAO,MAAM,kBAAkB,EAAE,aAAa,EAE7C,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAG1E;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAG,MAAM,CAAC;IACpB,OAAO,CAAC,EAAK,iBAAiB,CAAC;CAChC;AAED,MAAM,WAAW,oBAAoB;IACnC,cAAc,EAAS,gBAAgB,CAAC;IACxC,OAAO,EAAgB,cAAc,EAAE,CAAC;IACxC,eAAe,EAAQ,MAAM,CAAC;IAC9B,oBAAoB,EAAG,MAAM,CAAC;IAC9B,QAAQ,EAAe,MAAM,CAAC;CAC/B;AAED,MAAM,MAAM,aAAa,GACrB;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACtE;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,mBAAmB,CAAA;CAAE,GAChD;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,eAAe,CAAA;CAAE,GAC3C;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,eAAe,CAAA;CAAE,GAC/C;IAAE,MAAM,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,GACvF;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;CAAE,GAC3G;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAA;CAAE,GACjG;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,GACzG;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAC/F;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,IAAI,CAAA;KAAE,CAAA;CAAE,GAChE;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,IAAI,CAAA;KAAE,CAAA;CAAE,GAC5D;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACjD;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GACvC;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAChD;IAAE,MAAM,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAClD;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GACxC;IAAE,MAAM,EAAE,iBAAiB,CAAC;IAAC,IAAI,EAAE;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,WAAW,EAAE,CAAA;KAAE,CAAA;CAAE,GAC3E;IAAE,MAAM,EAAE,kBAAkB,CAAC;IAAC,IAAI,EAAE,eAAe,CAAA;CAAE,GACrD;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@did-btcr2/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CLI for interacting with did-btcr2-js, the JavaScript/TypeScript reference implementation of the did:btcr2 method. Exposes various parts of multiple packages in the did-btcr2-js monorepo.",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|
|
@@ -61,10 +61,10 @@
|
|
|
61
61
|
"@scure/base": "^1.2.6",
|
|
62
62
|
"@web5/dids": "^1.2.0",
|
|
63
63
|
"commander": "^13.1.0",
|
|
64
|
-
"@did-btcr2/keypair": "^0.13.1",
|
|
65
64
|
"@did-btcr2/api": "^0.16.1",
|
|
66
|
-
"@did-btcr2/
|
|
65
|
+
"@did-btcr2/keypair": "^0.13.1",
|
|
67
66
|
"@did-btcr2/common": "^9.1.0",
|
|
67
|
+
"@did-btcr2/key-manager": "^0.7.0",
|
|
68
68
|
"@did-btcr2/method": "^0.54.1"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
package/src/cli.ts
CHANGED
|
@@ -5,7 +5,9 @@ import {
|
|
|
5
5
|
registerConfigCommand,
|
|
6
6
|
registerCreateCommand,
|
|
7
7
|
registerDeactivateCommand,
|
|
8
|
+
registerInitCommand,
|
|
8
9
|
registerKeyCommand,
|
|
10
|
+
registerKeystoreCommand,
|
|
9
11
|
registerProfileCommand,
|
|
10
12
|
registerResolveCommand,
|
|
11
13
|
registerUpdateCommand,
|
|
@@ -44,7 +46,8 @@ export class DidBtcr2Cli {
|
|
|
44
46
|
.option('-o, --output <format>', 'Output format <json|text> (default: config defaults.output, else text)')
|
|
45
47
|
.option('--verbose', 'Verbose output', false)
|
|
46
48
|
.option('--quiet', 'Suppress non-essential output', false)
|
|
47
|
-
.option('
|
|
49
|
+
.option('--home <dir>', 'btcr2 home directory holding config.json + keystore.json (default: ~/.btcr2, %LOCALAPPDATA%\\btcr2 on Windows; overrides $BTCR2_HOME)')
|
|
50
|
+
.option('-c, --config <path>', 'Path to config file (default: <home>/config.json)')
|
|
48
51
|
.option('--profile <name>', 'Config profile name (default: auto-detected from network)')
|
|
49
52
|
.option('--btc-rest <url>', 'Override Bitcoin REST endpoint (Esplora API)')
|
|
50
53
|
.option('--btc-rpc-url <url>', 'Override Bitcoin Core RPC endpoint')
|
|
@@ -57,7 +60,7 @@ export class DidBtcr2Cli {
|
|
|
57
60
|
.option('--btc-rest-header <header>', 'Extra Bitcoin REST header "Key: Value" (repeatable)', collectHeader, [])
|
|
58
61
|
.option('--btc-rpc-wallet <name>', 'Bitcoin Core wallet name for wallet-scoped RPCs')
|
|
59
62
|
.option('--btc-rpc-header <header>', 'Extra Bitcoin Core RPC header "Key: Value" (repeatable)', collectHeader, [])
|
|
60
|
-
.option('--keystore <path>', 'Path to the keystore file (default:
|
|
63
|
+
.option('--keystore <path>', 'Path to the keystore file (default: <home>/keystore.json)')
|
|
61
64
|
.option('--passphrase-file <path>', 'Read the keystore passphrase from a file (unattended use)')
|
|
62
65
|
.option('--signing-key <ref>', 'Key for create/update/deactivate signing: a URN, fingerprint prefix, or name');
|
|
63
66
|
|
|
@@ -70,14 +73,16 @@ export class DidBtcr2Cli {
|
|
|
70
73
|
// value is written back so every command reads it through globals().output.
|
|
71
74
|
this.program.hook('preAction', () => {
|
|
72
75
|
const opts = this.program.opts() as GlobalOptions;
|
|
73
|
-
opts.output = resolveOutputFormat({ output: opts.output, config: opts.config });
|
|
76
|
+
opts.output = resolveOutputFormat({ output: opts.output, config: opts.config, home: opts.home });
|
|
74
77
|
});
|
|
75
78
|
|
|
79
|
+
registerInitCommand(this.program, globals);
|
|
76
80
|
registerCreateCommand(this.program, factory, keystoreFactory, globals);
|
|
77
81
|
registerResolveCommand(this.program, factory, globals);
|
|
78
82
|
registerUpdateCommand(this.program, keystoreFactory, globals);
|
|
79
83
|
registerDeactivateCommand(this.program, keystoreFactory, globals);
|
|
80
84
|
registerKeyCommand(this.program, keystoreFactory, globals);
|
|
85
|
+
registerKeystoreCommand(this.program, globals);
|
|
81
86
|
registerConfigCommand(this.program, globals);
|
|
82
87
|
registerProfileCommand(this.program, globals);
|
|
83
88
|
registerCompletionCommand(this.program, globals);
|
package/src/commands/config.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { Command } from 'commander';
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
|
-
import { dirname } from 'node:path';
|
|
4
3
|
import {
|
|
5
4
|
CONFIG_SCHEMA_VERSION,
|
|
6
5
|
defaultConfigPath,
|
|
@@ -9,23 +8,24 @@ import {
|
|
|
9
8
|
readConfigFile,
|
|
10
9
|
resolveDefaultNetwork,
|
|
11
10
|
resolveEffectiveConfig,
|
|
11
|
+
resolveKeystorePath,
|
|
12
12
|
runDoctor,
|
|
13
13
|
setConfigPath,
|
|
14
14
|
unsetConfigPath,
|
|
15
15
|
writeConfigFile,
|
|
16
|
+
writeDefaultConfigFile,
|
|
16
17
|
} from '../config.js';
|
|
17
18
|
import { findConfigIssues, validateConfigSet } from '../config-schema.js';
|
|
18
19
|
import { CLIError } from '../error.js';
|
|
19
|
-
import { ensureDir, writeFileAtomic } from '../keystore/atomic.js';
|
|
20
|
-
import { defaultKeystorePath } from '../keystore/paths.js';
|
|
21
20
|
import { formatResult, REDACTED, redactSecrets, scrubUrlUserinfo } from '../output.js';
|
|
21
|
+
import { resolveHome } from '../paths.js';
|
|
22
22
|
import type { CommandResult, GlobalOptions, NetworkOption } from '../types.js';
|
|
23
23
|
import { SUPPORTED_NETWORKS } from '../types.js';
|
|
24
24
|
|
|
25
25
|
/** Registers the `config` command group for reading and writing CLI configuration. */
|
|
26
26
|
export function registerConfigCommand(program: Command, globals: () => GlobalOptions): void {
|
|
27
27
|
const config = program.command('config').description('Read and write CLI configuration.');
|
|
28
|
-
const path = (): string => globals().config ?? defaultConfigPath();
|
|
28
|
+
const path = (): string => globals().config ?? defaultConfigPath(globals());
|
|
29
29
|
const print = (result: CommandResult): void => console.log(formatResult(result, globals()));
|
|
30
30
|
|
|
31
31
|
config
|
|
@@ -37,13 +37,7 @@ export function registerConfigCommand(program: Command, globals: () => GlobalOpt
|
|
|
37
37
|
if (existsSync(p) && !options.force) {
|
|
38
38
|
throw new CLIError(`Config already exists at ${p}. Use --force to overwrite.`, 'INVALID_ARGUMENT_ERROR', { path: p });
|
|
39
39
|
}
|
|
40
|
-
|
|
41
|
-
schemaVersion : CONFIG_SCHEMA_VERSION,
|
|
42
|
-
defaults : { output: 'text' },
|
|
43
|
-
profiles : Object.fromEntries(SUPPORTED_NETWORKS.map(n => [ n, {} ])),
|
|
44
|
-
};
|
|
45
|
-
ensureDir(dirname(p), 0o700);
|
|
46
|
-
writeFileAtomic(p, `${JSON.stringify(scaffold, null, 2)}\n`, 0o600);
|
|
40
|
+
writeDefaultConfigFile(p);
|
|
47
41
|
print({ action: 'config-init', data: { path: p } });
|
|
48
42
|
});
|
|
49
43
|
|
|
@@ -128,11 +122,15 @@ export function registerConfigCommand(program: Command, globals: () => GlobalOpt
|
|
|
128
122
|
|
|
129
123
|
config
|
|
130
124
|
.command('path')
|
|
131
|
-
.description('Print the resolved config-file and keystore paths.')
|
|
125
|
+
.description('Print the resolved home directory, config-file, and keystore paths.')
|
|
132
126
|
.action(() => {
|
|
127
|
+
const g = globals();
|
|
133
128
|
const data = {
|
|
134
|
-
|
|
135
|
-
|
|
129
|
+
home : resolveHome(g),
|
|
130
|
+
config : g.config ?? defaultConfigPath(g),
|
|
131
|
+
// Diagnostic command: report the path even when the config is malformed
|
|
132
|
+
// (this is a command you run to find and fix a broken config).
|
|
133
|
+
keystore : resolveKeystorePath(g, { lenient: true }),
|
|
136
134
|
};
|
|
137
135
|
print({ action: 'config-path', data });
|
|
138
136
|
});
|
package/src/commands/create.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { bytesToHex, hexToBytes } from '@noble/hashes/utils.js';
|
|
2
2
|
import type { Command } from 'commander';
|
|
3
3
|
import type { ApiFactory, ConnectionOverrides } from '../config.js';
|
|
4
|
-
import { profileNetworkMismatch, resolveDefaultNetwork } from '../config.js';
|
|
4
|
+
import { assertKeystoreAllowedForNetwork, profileNetworkMismatch, resolveDefaultNetwork } from '../config.js';
|
|
5
5
|
import { CLIError } from '../error.js';
|
|
6
6
|
import { resolveKeyRef } from '../keystore/resolve-key-ref.js';
|
|
7
7
|
import { formatResult } from '../output.js';
|
|
@@ -132,6 +132,8 @@ export function registerCreateCommand(
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
// Generate: mint a fresh key, persist it, and set it active (passphrase prompt).
|
|
135
|
+
// Refuse to seal a fresh mainnet key into an unencrypted dev keystore (ADR 080).
|
|
136
|
+
assertKeystoreAllowedForNetwork(network, overrides);
|
|
135
137
|
const api = keystoreFactory(undefined, overrides);
|
|
136
138
|
const { did, keyId } = api.generateDid({ network, setActive: true });
|
|
137
139
|
const publicKey = bytesToHex(api.kms.getPublicKey(keyId));
|
|
@@ -145,6 +147,7 @@ export function registerCreateCommand(
|
|
|
145
147
|
/** Builds the keystore- and config-resolution overrides from the global flags. */
|
|
146
148
|
function overridesFromGlobals(g: GlobalOptions): ConnectionOverrides {
|
|
147
149
|
return {
|
|
150
|
+
home : g.home,
|
|
148
151
|
config : g.config,
|
|
149
152
|
profile : g.profile,
|
|
150
153
|
keystore : g.keystore,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { PublishToCasMode } from '@did-btcr2/api';
|
|
2
2
|
import { KeyManagerSigner } from '@did-btcr2/key-manager';
|
|
3
3
|
import type { Command } from 'commander';
|
|
4
|
-
import { deriveNetwork, resolveBroadcastOptions, resolveSigningKeyRef, type ApiFactory } from '../config.js';
|
|
4
|
+
import { assertKeystoreAllowedForNetwork, deriveNetwork, resolveBroadcastOptions, resolveSigningKeyRef, type ApiFactory } from '../config.js';
|
|
5
5
|
import { CLIError } from '../error.js';
|
|
6
6
|
import { resolveKeyRef } from '../keystore/resolve-key-ref.js';
|
|
7
7
|
import { formatResult } from '../output.js';
|
|
@@ -88,6 +88,8 @@ export function registerDeactivateCommand(
|
|
|
88
88
|
// Deactivation is an update that applies the deactivation patch. The core
|
|
89
89
|
// method has no separate deactivate path, so this routes through update.
|
|
90
90
|
const network = deriveNetwork(did);
|
|
91
|
+
// Refuse to sign a mainnet deactivation with an unencrypted dev keystore (ADR 080).
|
|
92
|
+
assertKeystoreAllowedForNetwork(network, globals());
|
|
91
93
|
const api = factory(network, globals());
|
|
92
94
|
const keyId = resolveKeyRef(api.kms.kms, resolveSigningKeyRef(globals()));
|
|
93
95
|
const signer = new KeyManagerSigner(api.kms.kms, keyId);
|
package/src/commands/index.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
export { registerInitCommand } from './init.js';
|
|
1
2
|
export { registerCreateCommand } from './create.js';
|
|
2
3
|
export { registerResolveCommand } from './resolve.js';
|
|
3
4
|
export { registerUpdateCommand } from './update.js';
|
|
4
5
|
export { registerDeactivateCommand } from './deactivate.js';
|
|
5
6
|
export { registerKeyCommand } from './key.js';
|
|
7
|
+
export { registerKeystoreCommand } from './keystore.js';
|
|
6
8
|
export { registerConfigCommand } from './config.js';
|
|
7
9
|
export { registerProfileCommand } from './profile.js';
|
|
8
10
|
export { registerCompletionCommand } from './completion.js';
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { defaultConfigPath, resolveKeystorePath, writeDefaultConfigFile } from '../config.js';
|
|
4
|
+
import { ensureDir } from '../keystore/atomic.js';
|
|
5
|
+
import { initKeystore, keystoreSummary } from '../keystore/file-key-store.js';
|
|
6
|
+
import { acquirePassphrase } from '../keystore/passphrase.js';
|
|
7
|
+
import { formatResult } from '../output.js';
|
|
8
|
+
import { resolveHome } from '../paths.js';
|
|
9
|
+
import type { CommandResult, GlobalOptions } from '../types.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Registers the top-level `btcr2 init`: the one-command entry point that creates
|
|
13
|
+
* the btcr2 home (ADR 079), writes a default config if none exists, and
|
|
14
|
+
* establishes the keystore if none exists (encrypted with a confirmed passphrase
|
|
15
|
+
* by default, or `--dev` for an unencrypted testnet keystore). Idempotent:
|
|
16
|
+
* existing files are left untouched unless `--force` is given. Establishing the
|
|
17
|
+
* passphrase here, up front and confirmed, is what keeps the first `key generate`
|
|
18
|
+
* off the accidental-first-seal path (ADR 080).
|
|
19
|
+
*/
|
|
20
|
+
export function registerInitCommand(program: Command, globals: () => GlobalOptions): void {
|
|
21
|
+
const print = (result: CommandResult): void => console.log(formatResult(result, globals()));
|
|
22
|
+
|
|
23
|
+
program
|
|
24
|
+
.command('init')
|
|
25
|
+
.description('Set up the btcr2 home: create the directory, a default config, and establish the keystore.')
|
|
26
|
+
.option('--dev', 'Establish an UNENCRYPTED dev keystore: plaintext keys, no passphrase. Testnet only.', false)
|
|
27
|
+
.option('--force', 'Re-create the config and keystore even if they already exist.', false)
|
|
28
|
+
.action((options: { dev?: boolean; force?: boolean }) => {
|
|
29
|
+
const g = globals();
|
|
30
|
+
const home = resolveHome(g);
|
|
31
|
+
const configPath = g.config ?? defaultConfigPath(g);
|
|
32
|
+
const keystorePath = resolveKeystorePath(g);
|
|
33
|
+
ensureDir(home, 0o700);
|
|
34
|
+
|
|
35
|
+
const created: string[] = [];
|
|
36
|
+
|
|
37
|
+
// The config is regenerable, so --force may re-scaffold it.
|
|
38
|
+
if (!existsSync(configPath) || options.force) {
|
|
39
|
+
writeDefaultConfigFile(configPath);
|
|
40
|
+
created.push('config');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// The keystore holds unrecoverable secret keys, so `init` never overwrites
|
|
44
|
+
// an existing one, even with --force: re-establishing a keystore is the
|
|
45
|
+
// explicit, deliberate `keystore init --force`. `init` only establishes a
|
|
46
|
+
// keystore when none exists.
|
|
47
|
+
const keystoreExists = existsSync(keystorePath);
|
|
48
|
+
if (keystoreExists && options.force && !g.quiet) {
|
|
49
|
+
process.stderr.write(
|
|
50
|
+
`note: a keystore already exists at ${keystorePath} and was left intact. `
|
|
51
|
+
+ 'To re-establish it (discarding its keys), run "btcr2 keystore init --force".\n',
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
if (!keystoreExists) {
|
|
55
|
+
if (options.dev && !g.quiet) {
|
|
56
|
+
process.stderr.write(
|
|
57
|
+
'warning: establishing an UNENCRYPTED dev keystore. Keys are stored in plaintext. '
|
|
58
|
+
+ 'Use it only for disposable testnet material; mainnet operations will be refused.\n',
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
initKeystore(keystorePath, {
|
|
62
|
+
protection : options.dev ? 'none' : 'passphrase',
|
|
63
|
+
getPassphrase : (opts) => acquirePassphrase({ passphraseFile: g.passphraseFile, confirm: opts?.confirm, prompt: 'New keystore passphrase: ' }),
|
|
64
|
+
});
|
|
65
|
+
created.push('keystore');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const protection = keystoreSummary(keystorePath).protection;
|
|
69
|
+
print({ action: 'init', data: { home, config: configPath, keystore: keystorePath, created, protection } });
|
|
70
|
+
if (!g.quiet && g.output !== 'json') {
|
|
71
|
+
process.stderr.write(`btcr2 home ready at ${home}. Next: btcr2 key generate --set-active\n`);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { resolveKeystorePath } from '../config.js';
|
|
4
|
+
import { CLIError } from '../error.js';
|
|
5
|
+
import { changeKeystorePassphrase, initKeystore, keystoreSummary } from '../keystore/file-key-store.js';
|
|
6
|
+
import { acquirePassphrase } from '../keystore/passphrase.js';
|
|
7
|
+
import { formatResult } from '../output.js';
|
|
8
|
+
import type { CommandResult, GlobalOptions } from '../types.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Registers the `keystore` command group: establish, inspect, and re-key the
|
|
12
|
+
* encrypted keystore (ADR 080). These operate on the keystore file directly (no
|
|
13
|
+
* Bitcoin connection or KeyManager) and never decrypt a key except when
|
|
14
|
+
* re-sealing during `change-passphrase`.
|
|
15
|
+
*/
|
|
16
|
+
export function registerKeystoreCommand(program: Command, globals: () => GlobalOptions): void {
|
|
17
|
+
const keystore = program.command('keystore').description('Establish, inspect, and re-key the keystore.');
|
|
18
|
+
const print = (result: CommandResult): void => console.log(formatResult(result, globals()));
|
|
19
|
+
|
|
20
|
+
keystore
|
|
21
|
+
.command('init')
|
|
22
|
+
.description('Establish the keystore (encrypted by default). Prompts for a passphrase and confirms it.')
|
|
23
|
+
.option('--dev', 'Create an UNENCRYPTED dev keystore: plaintext keys, no passphrase. Testnet only; mainnet operations are refused.', false)
|
|
24
|
+
.option('--force', 'Re-establish even if a keystore already exists (discards its keys).', false)
|
|
25
|
+
.action((options: { dev?: boolean; force?: boolean }) => {
|
|
26
|
+
const g = globals();
|
|
27
|
+
const path = resolveKeystorePath(g);
|
|
28
|
+
if (existsSync(path) && !options.force) {
|
|
29
|
+
throw new CLIError(
|
|
30
|
+
`A keystore already exists at ${path}. Use --force to re-establish it (this discards its keys).`,
|
|
31
|
+
'INVALID_ARGUMENT_ERROR',
|
|
32
|
+
{ path },
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
// --force re-establishes over an existing keystore; make the key loss loud.
|
|
36
|
+
if (existsSync(path) && options.force && !g.quiet) {
|
|
37
|
+
const { keyCount } = keystoreSummary(path);
|
|
38
|
+
if (keyCount > 0) {
|
|
39
|
+
process.stderr.write(
|
|
40
|
+
`warning: re-establishing the keystore at ${path} permanently discards its ${keyCount} existing key(s).\n`,
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (options.dev && !g.quiet) {
|
|
45
|
+
process.stderr.write(
|
|
46
|
+
'warning: creating an UNENCRYPTED dev keystore. Keys are stored in plaintext. '
|
|
47
|
+
+ 'Use it only for disposable testnet material; mainnet operations will be refused.\n',
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
initKeystore(path, {
|
|
51
|
+
protection : options.dev ? 'none' : 'passphrase',
|
|
52
|
+
getPassphrase : (opts) => acquirePassphrase({ passphraseFile: g.passphraseFile, confirm: opts?.confirm, prompt: 'New keystore passphrase: ' }),
|
|
53
|
+
});
|
|
54
|
+
print({ action: 'keystore-init', data: { path, protection: options.dev ? 'dev' : 'encrypted' } });
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
keystore
|
|
58
|
+
.command('status')
|
|
59
|
+
.description('Show the keystore path, protection mode, and key count. Never decrypts or prompts.')
|
|
60
|
+
.action(() => {
|
|
61
|
+
const g = globals();
|
|
62
|
+
// Diagnostic command: report status even when the config is malformed,
|
|
63
|
+
// rather than crashing on the config you ran this to inspect.
|
|
64
|
+
const path = resolveKeystorePath(g, { lenient: true });
|
|
65
|
+
const summary = keystoreSummary(path);
|
|
66
|
+
if (summary.protection === 'dev' && !g.quiet && g.output !== 'json') {
|
|
67
|
+
process.stderr.write('warning: this is an UNENCRYPTED dev keystore; keys are stored in plaintext.\n');
|
|
68
|
+
}
|
|
69
|
+
print({ action: 'keystore-status', data: { path, ...summary } });
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
keystore
|
|
73
|
+
.command('change-passphrase')
|
|
74
|
+
.alias('passwd')
|
|
75
|
+
.description('Change the keystore passphrase, re-sealing every key under the new one. Encrypted keystores only.')
|
|
76
|
+
.action(() => {
|
|
77
|
+
const g = globals();
|
|
78
|
+
const path = resolveKeystorePath(g);
|
|
79
|
+
const summary = keystoreSummary(path);
|
|
80
|
+
if (summary.protection === 'absent') {
|
|
81
|
+
throw new CLIError(`No keystore at ${path}. Run "btcr2 keystore init" first.`, 'INVALID_ARGUMENT_ERROR', { path });
|
|
82
|
+
}
|
|
83
|
+
if (summary.protection === 'dev') {
|
|
84
|
+
throw new CLIError(
|
|
85
|
+
`The keystore at ${path} is an unencrypted dev keystore; there is no passphrase to change.`,
|
|
86
|
+
'INVALID_ARGUMENT_ERROR',
|
|
87
|
+
{ path },
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
// Current passphrase may come from the env var / file (unattended); the new
|
|
91
|
+
// one must be entered fresh (forcePrompt) so it cannot be silently satisfied
|
|
92
|
+
// by the same source and make the change a no-op.
|
|
93
|
+
const oldPassphrase = acquirePassphrase({ passphraseFile: g.passphraseFile, prompt: 'Current keystore passphrase: ' });
|
|
94
|
+
const newPassphrase = acquirePassphrase({ forcePrompt: true, confirm: true, prompt: 'New keystore passphrase: ' });
|
|
95
|
+
const rekeyed = changeKeystorePassphrase(path, oldPassphrase, newPassphrase);
|
|
96
|
+
print({ action: 'keystore-change-passphrase', data: { path, rekeyed } });
|
|
97
|
+
});
|
|
98
|
+
}
|
package/src/commands/profile.ts
CHANGED
|
@@ -7,7 +7,7 @@ import type { CommandResult, GlobalOptions } from '../types.js';
|
|
|
7
7
|
/** Registers the `profile` command group for managing configuration profiles. */
|
|
8
8
|
export function registerProfileCommand(program: Command, globals: () => GlobalOptions): void {
|
|
9
9
|
const profile = program.command('profile').description('Manage configuration profiles.');
|
|
10
|
-
const path = (): string => globals().config ?? defaultConfigPath();
|
|
10
|
+
const path = (): string => globals().config ?? defaultConfigPath(globals());
|
|
11
11
|
const print = (result: CommandResult): void => console.log(formatResult(result, globals()));
|
|
12
12
|
|
|
13
13
|
profile
|
package/src/commands/update.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { PublishToCasMode } from '@did-btcr2/api';
|
|
2
2
|
import { KeyManagerSigner } from '@did-btcr2/key-manager';
|
|
3
3
|
import type { Command } from 'commander';
|
|
4
|
-
import { deriveNetwork, resolveBroadcastOptions, resolveSigningKeyRef, type ApiFactory } from '../config.js';
|
|
4
|
+
import { assertKeystoreAllowedForNetwork, deriveNetwork, resolveBroadcastOptions, resolveSigningKeyRef, type ApiFactory } from '../config.js';
|
|
5
5
|
import { CLIError } from '../error.js';
|
|
6
6
|
import { resolveKeyRef } from '../keystore/resolve-key-ref.js';
|
|
7
7
|
import { formatResult } from '../output.js';
|
|
@@ -88,6 +88,8 @@ export function registerUpdateCommand(
|
|
|
88
88
|
);
|
|
89
89
|
}
|
|
90
90
|
const network = deriveNetwork(did);
|
|
91
|
+
// Refuse to sign a mainnet update with an unencrypted dev keystore (ADR 080).
|
|
92
|
+
assertKeystoreAllowedForNetwork(network, globals());
|
|
91
93
|
const api = factory(network, globals());
|
|
92
94
|
const keyId = resolveKeyRef(api.kms.kms, resolveSigningKeyRef(globals()));
|
|
93
95
|
const signer = new KeyManagerSigner(api.kms.kms, keyId);
|