@did-btcr2/cli 0.15.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.
Files changed (76) hide show
  1. package/README.md +47 -6
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/cjs/index.js +836 -122
  4. package/dist/esm/src/cli.js +7 -4
  5. package/dist/esm/src/cli.js.map +1 -1
  6. package/dist/esm/src/commands/config.js +11 -15
  7. package/dist/esm/src/commands/config.js.map +1 -1
  8. package/dist/esm/src/commands/create.js +4 -1
  9. package/dist/esm/src/commands/create.js.map +1 -1
  10. package/dist/esm/src/commands/deactivate.js +3 -1
  11. package/dist/esm/src/commands/deactivate.js.map +1 -1
  12. package/dist/esm/src/commands/index.js +2 -0
  13. package/dist/esm/src/commands/index.js.map +1 -1
  14. package/dist/esm/src/commands/init.js +69 -0
  15. package/dist/esm/src/commands/init.js.map +1 -0
  16. package/dist/esm/src/commands/keystore.js +180 -0
  17. package/dist/esm/src/commands/keystore.js.map +1 -0
  18. package/dist/esm/src/commands/profile.js +1 -1
  19. package/dist/esm/src/commands/profile.js.map +1 -1
  20. package/dist/esm/src/commands/update.js +3 -1
  21. package/dist/esm/src/commands/update.js.map +1 -1
  22. package/dist/esm/src/config.js +109 -31
  23. package/dist/esm/src/config.js.map +1 -1
  24. package/dist/esm/src/keystore/file-key-store.js +388 -32
  25. package/dist/esm/src/keystore/file-key-store.js.map +1 -1
  26. package/dist/esm/src/keystore/passphrase.js +53 -10
  27. package/dist/esm/src/keystore/passphrase.js.map +1 -1
  28. package/dist/esm/src/keystore/paths.js +6 -18
  29. package/dist/esm/src/keystore/paths.js.map +1 -1
  30. package/dist/esm/src/keystore/session.js +250 -0
  31. package/dist/esm/src/keystore/session.js.map +1 -0
  32. package/dist/esm/src/paths.js +71 -0
  33. package/dist/esm/src/paths.js.map +1 -0
  34. package/dist/esm/src/types.js.map +1 -1
  35. package/dist/types/src/cli.d.ts.map +1 -1
  36. package/dist/types/src/commands/config.d.ts.map +1 -1
  37. package/dist/types/src/commands/create.d.ts.map +1 -1
  38. package/dist/types/src/commands/deactivate.d.ts.map +1 -1
  39. package/dist/types/src/commands/index.d.ts +2 -0
  40. package/dist/types/src/commands/index.d.ts.map +1 -1
  41. package/dist/types/src/commands/init.d.ts +13 -0
  42. package/dist/types/src/commands/init.d.ts.map +1 -0
  43. package/dist/types/src/commands/keystore.d.ts +11 -0
  44. package/dist/types/src/commands/keystore.d.ts.map +1 -0
  45. package/dist/types/src/commands/update.d.ts.map +1 -1
  46. package/dist/types/src/config.d.ts +38 -14
  47. package/dist/types/src/config.d.ts.map +1 -1
  48. package/dist/types/src/keystore/file-key-store.d.ts +102 -10
  49. package/dist/types/src/keystore/file-key-store.d.ts.map +1 -1
  50. package/dist/types/src/keystore/passphrase.d.ts +26 -1
  51. package/dist/types/src/keystore/passphrase.d.ts.map +1 -1
  52. package/dist/types/src/keystore/paths.d.ts +6 -10
  53. package/dist/types/src/keystore/paths.d.ts.map +1 -1
  54. package/dist/types/src/keystore/session.d.ts +105 -0
  55. package/dist/types/src/keystore/session.d.ts.map +1 -0
  56. package/dist/types/src/paths.d.ts +64 -0
  57. package/dist/types/src/paths.d.ts.map +1 -0
  58. package/dist/types/src/types.d.ts +53 -0
  59. package/dist/types/src/types.d.ts.map +1 -1
  60. package/package.json +3 -3
  61. package/src/cli.ts +8 -3
  62. package/src/commands/config.ts +12 -14
  63. package/src/commands/create.ts +4 -1
  64. package/src/commands/deactivate.ts +3 -1
  65. package/src/commands/index.ts +2 -0
  66. package/src/commands/init.ts +80 -0
  67. package/src/commands/keystore.ts +232 -0
  68. package/src/commands/profile.ts +1 -1
  69. package/src/commands/update.ts +3 -1
  70. package/src/config.ts +118 -35
  71. package/src/keystore/file-key-store.ts +498 -43
  72. package/src/keystore/passphrase.ts +71 -8
  73. package/src/keystore/paths.ts +6 -19
  74. package/src/keystore/session.ts +303 -0
  75. package/src/paths.ts +92 -0
  76. package/src/types.ts +16 -1
@@ -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,GACrE;IAAE,MAAM,EAAE,eAAe,CAAC;IAAC,IAAI,EAAE,YAAY,CAAA;CAAE,GAC/C;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACpD;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACpD;IAAE,MAAM,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GACzC;IAAE,MAAM,EAAE,gBAAgB,CAAC;IAAC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAE5D,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAW,YAAY,CAAC;IAC9B,OAAO,EAAU,OAAO,CAAC;IACzB,KAAK,EAAY,OAAO,CAAC;IACzB,MAAM,CAAC,EAAU,MAAM,CAAC;IACxB,OAAO,CAAC,EAAS,MAAM,CAAC;IACxB,OAAO,CAAC,EAAS,MAAM,CAAC;IACxB,SAAS,CAAC,EAAO,MAAM,CAAC;IACxB,UAAU,CAAC,EAAM,MAAM,CAAC;IACxB,UAAU,CAAC,EAAM,MAAM,CAAC;IACxB,UAAU,CAAC,EAAM,MAAM,CAAC;IACxB,SAAS,CAAC,EAAO,MAAM,CAAC;IACxB,UAAU,CAAC,EAAM,MAAM,CAAC;IACxB,UAAU,CAAC,EAAM,MAAM,CAAC;IACxB,aAAa,CAAC,EAAG,MAAM,EAAE,CAAC;IAC1B,YAAY,CAAC,EAAI,MAAM,CAAC;IACxB,YAAY,CAAC,EAAI,MAAM,EAAE,CAAC;IAC1B,QAAQ,CAAC,EAAQ,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAM,MAAM,CAAC;CACzB"}
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.15.0",
3
+ "version": "0.17.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,11 +61,11 @@
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
65
  "@did-btcr2/key-manager": "^0.7.0",
67
66
  "@did-btcr2/common": "^9.1.0",
68
- "@did-btcr2/method": "^0.54.1"
67
+ "@did-btcr2/method": "^0.54.1",
68
+ "@did-btcr2/keypair": "^0.13.1"
69
69
  },
70
70
  "devDependencies": {
71
71
  "@eslint/js": "^9.21.0",
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('-c, --config <path>', 'Path to config file (default: $XDG_CONFIG_HOME/btcr2/config.json)')
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: $XDG_DATA_HOME/btcr2/keystore.json)')
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);
@@ -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
- const scaffold = {
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
- config : globals().config ?? defaultConfigPath(),
135
- keystore : globals().keystore ?? defaultKeystorePath(),
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
  });
@@ -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);
@@ -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,80 @@
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 { clearSession } from '../keystore/session.js';
8
+ import { formatResult } from '../output.js';
9
+ import { defaultSessionPath, resolveHome } from '../paths.js';
10
+ import type { CommandResult, GlobalOptions } from '../types.js';
11
+
12
+ /**
13
+ * Registers the top-level `btcr2 init`: the one-command entry point that creates
14
+ * the btcr2 home (ADR 079), writes a default config if none exists, and
15
+ * establishes the keystore if none exists (encrypted with a confirmed passphrase
16
+ * by default, or `--dev` for an unencrypted testnet keystore). Idempotent:
17
+ * existing files are left untouched unless `--force` is given. Establishing the
18
+ * passphrase here, up front and confirmed, is what keeps the first `key generate`
19
+ * off the accidental-first-seal path (ADR 080).
20
+ */
21
+ export function registerInitCommand(program: Command, globals: () => GlobalOptions): void {
22
+ const print = (result: CommandResult): void => console.log(formatResult(result, globals()));
23
+
24
+ program
25
+ .command('init')
26
+ .description('Set up the btcr2 home: create the directory, a default config, and establish the keystore.')
27
+ .option('--dev', 'Establish an UNENCRYPTED dev keystore: plaintext keys, no passphrase. Testnet only.', false)
28
+ .option('--force', 'Re-create the config and keystore even if they already exist.', false)
29
+ .action((options: { dev?: boolean; force?: boolean }) => {
30
+ const g = globals();
31
+ const home = resolveHome(g);
32
+ const configPath = g.config ?? defaultConfigPath(g);
33
+ const keystorePath = resolveKeystorePath(g);
34
+ ensureDir(home, 0o700);
35
+
36
+ const created: string[] = [];
37
+
38
+ // The config is regenerable, so --force may re-scaffold it.
39
+ if (!existsSync(configPath) || options.force) {
40
+ writeDefaultConfigFile(configPath);
41
+ created.push('config');
42
+ }
43
+
44
+ // The keystore holds unrecoverable secret keys, so `init` never overwrites
45
+ // an existing one, even with --force: re-establishing a keystore is the
46
+ // explicit, deliberate `keystore init --force`. `init` only establishes a
47
+ // keystore when none exists.
48
+ const keystoreExists = existsSync(keystorePath);
49
+ if (keystoreExists && options.force && !g.quiet) {
50
+ process.stderr.write(
51
+ `note: a keystore already exists at ${keystorePath} and was left intact. `
52
+ + 'To re-establish it (discarding its keys), run "btcr2 keystore init --force".\n',
53
+ );
54
+ }
55
+ if (!keystoreExists) {
56
+ if (options.dev && !g.quiet) {
57
+ process.stderr.write(
58
+ 'warning: establishing an UNENCRYPTED dev keystore. Keys are stored in plaintext. '
59
+ + 'Use it only for disposable testnet material; mainnet operations will be refused.\n',
60
+ );
61
+ }
62
+ initKeystore(keystorePath, {
63
+ protection : options.dev ? 'none' : 'passphrase',
64
+ getPassphrase : (opts) => acquirePassphrase({ passphraseFile: g.passphraseFile, confirm: opts?.confirm, prompt: 'New keystore passphrase: ' }),
65
+ });
66
+ // A freshly established keystore mints a new verifier (or none, for --dev),
67
+ // so any cached session holds a passphrase for a keystore that no longer
68
+ // exists. Drop it, matching `keystore init` / `change-passphrase`, rather
69
+ // than leave a stale plaintext passphrase behind (ADR 081).
70
+ clearSession(defaultSessionPath(g));
71
+ created.push('keystore');
72
+ }
73
+
74
+ const protection = keystoreSummary(keystorePath).protection;
75
+ print({ action: 'init', data: { home, config: configPath, keystore: keystorePath, created, protection } });
76
+ if (!g.quiet && g.output !== 'json') {
77
+ process.stderr.write(`btcr2 home ready at ${home}. Next: btcr2 key generate --set-active\n`);
78
+ }
79
+ });
80
+ }
@@ -0,0 +1,232 @@
1
+ import type { Command } from 'commander';
2
+ import { existsSync } from 'node:fs';
3
+ import { resolveDefaultNetwork, resolveKeystorePath } from '../config.js';
4
+ import { CLIError } from '../error.js';
5
+ import {
6
+ changeKeystorePassphrase,
7
+ initKeystore,
8
+ keystoreSummary,
9
+ keystoreVerifierId,
10
+ verifyKeystorePassphrase,
11
+ } from '../keystore/file-key-store.js';
12
+ import { acquirePassphrase } from '../keystore/passphrase.js';
13
+ import {
14
+ clearSession,
15
+ DEFAULT_SESSION_TTL_MS,
16
+ ENV_KEYSTORE_TTL,
17
+ MAX_SESSION_TTL_MS,
18
+ parseTtlToMs,
19
+ readSessionStatus,
20
+ writeSession,
21
+ } from '../keystore/session.js';
22
+ import { formatResult } from '../output.js';
23
+ import { defaultSessionPath } from '../paths.js';
24
+ import { blankToUndef, type CommandResult, type GlobalOptions } from '../types.js';
25
+
26
+ /**
27
+ * Registers the `keystore` command group: establish, inspect, and re-key the
28
+ * encrypted keystore (ADR 080), plus the session unlock agent (ADR 081). These
29
+ * operate on the keystore and session files directly (no Bitcoin connection or
30
+ * KeyManager) and never decrypt a key except when re-sealing during
31
+ * `change-passphrase`.
32
+ */
33
+ export function registerKeystoreCommand(program: Command, globals: () => GlobalOptions): void {
34
+ const keystore = program.command('keystore').description('Establish, inspect, re-key, and unlock the keystore.');
35
+ const print = (result: CommandResult): void => console.log(formatResult(result, globals()));
36
+
37
+ keystore
38
+ .command('init')
39
+ .description('Establish the keystore (encrypted by default). Prompts for a passphrase and confirms it.')
40
+ .option('--dev', 'Create an UNENCRYPTED dev keystore: plaintext keys, no passphrase. Testnet only; mainnet operations are refused.', false)
41
+ .option('--force', 'Re-establish even if a keystore already exists (discards its keys).', false)
42
+ .action((options: { dev?: boolean; force?: boolean }) => {
43
+ const g = globals();
44
+ const path = resolveKeystorePath(g);
45
+ if (existsSync(path) && !options.force) {
46
+ throw new CLIError(
47
+ `A keystore already exists at ${path}. Use --force to re-establish it (this discards its keys).`,
48
+ 'INVALID_ARGUMENT_ERROR',
49
+ { path },
50
+ );
51
+ }
52
+ // --force re-establishes over an existing keystore; make the key loss loud.
53
+ if (existsSync(path) && options.force && !g.quiet) {
54
+ const { keyCount } = keystoreSummary(path);
55
+ if (keyCount > 0) {
56
+ process.stderr.write(
57
+ `warning: re-establishing the keystore at ${path} permanently discards its ${keyCount} existing key(s).\n`,
58
+ );
59
+ }
60
+ }
61
+ if (options.dev && !g.quiet) {
62
+ process.stderr.write(
63
+ 'warning: creating an UNENCRYPTED dev keystore. Keys are stored in plaintext. '
64
+ + 'Use it only for disposable testnet material; mainnet operations will be refused.\n',
65
+ );
66
+ }
67
+ initKeystore(path, {
68
+ protection : options.dev ? 'none' : 'passphrase',
69
+ getPassphrase : (opts) => acquirePassphrase({ passphraseFile: g.passphraseFile, confirm: opts?.confirm, prompt: 'New keystore passphrase: ' }),
70
+ });
71
+ // A re-established keystore mints a new verifier (or none, for --dev), so any
72
+ // cached session now holds a passphrase for a keystore that no longer exists.
73
+ // Drop it rather than leave a stale plaintext passphrase behind (ADR 081).
74
+ clearSession(defaultSessionPath(g));
75
+ print({ action: 'keystore-init', data: { path, protection: options.dev ? 'dev' : 'encrypted' } });
76
+ });
77
+
78
+ keystore
79
+ .command('status')
80
+ .description('Show the keystore path, protection mode, key count, and session state. Never decrypts or prompts.')
81
+ .action(() => {
82
+ const g = globals();
83
+ // Diagnostic command: report status even when the config is malformed,
84
+ // rather than crashing on the config you ran this to inspect.
85
+ const path = resolveKeystorePath(g, { lenient: true });
86
+ const summary = keystoreSummary(path);
87
+ const session = readSessionStatus(defaultSessionPath(g), path, keystoreVerifierId(path));
88
+ if (summary.protection === 'dev' && !g.quiet && g.output !== 'json') {
89
+ process.stderr.write('warning: this is an UNENCRYPTED dev keystore; keys are stored in plaintext.\n');
90
+ }
91
+ print({ action: 'keystore-status', data: { path, ...summary, session } });
92
+ });
93
+
94
+ keystore
95
+ .command('change-passphrase')
96
+ .alias('passwd')
97
+ .description('Change the keystore passphrase, re-sealing every key under the new one. Encrypted keystores only.')
98
+ .action(() => {
99
+ const g = globals();
100
+ const path = resolveKeystorePath(g);
101
+ const summary = keystoreSummary(path);
102
+ if (summary.protection === 'absent') {
103
+ throw new CLIError(`No keystore at ${path}. Run "btcr2 keystore init" first.`, 'INVALID_ARGUMENT_ERROR', { path });
104
+ }
105
+ if (summary.protection === 'dev') {
106
+ throw new CLIError(
107
+ `The keystore at ${path} is an unencrypted dev keystore; there is no passphrase to change.`,
108
+ 'INVALID_ARGUMENT_ERROR',
109
+ { path },
110
+ );
111
+ }
112
+ // Current passphrase may come from the env var / file (unattended); the new
113
+ // one must be entered fresh (forcePrompt) so it cannot be silently satisfied
114
+ // by the same source and make the change a no-op.
115
+ const oldPassphrase = acquirePassphrase({ passphraseFile: g.passphraseFile, prompt: 'Current keystore passphrase: ' });
116
+ const newPassphrase = acquirePassphrase({ forcePrompt: true, confirm: true, prompt: 'New keystore passphrase: ' });
117
+ const rekeyed = changeKeystorePassphrase(path, oldPassphrase, newPassphrase);
118
+ // The rotated verifier already invalidates a cached session by fingerprint,
119
+ // but the session file still holds the OLD passphrase in plaintext; delete it.
120
+ clearSession(defaultSessionPath(g));
121
+ print({ action: 'keystore-change-passphrase', data: { path, rekeyed } });
122
+ });
123
+
124
+ keystore
125
+ .command('unlock')
126
+ .description('Cache the keystore passphrase for a session so later commands do not re-prompt (ADR 081).')
127
+ .option('--ttl <duration>', `Session lifetime: bare seconds or an s/m/h suffix (default 1h, max 24h). Also $${ENV_KEYSTORE_TTL}.`)
128
+ .option('--allow-mainnet', 'Permit unlocking when the active network is mainnet (bitcoin); this suspends per-use passphrase auth for the session.', false)
129
+ .action((options: { ttl?: string; allowMainnet?: boolean }) => {
130
+ const g = globals();
131
+ const path = resolveKeystorePath(g);
132
+ const summary = keystoreSummary(path);
133
+ if (summary.protection === 'absent') {
134
+ throw new CLIError(`No keystore at ${path}. Run "btcr2 init" or "btcr2 keystore init" first.`, 'INVALID_ARGUMENT_ERROR', { path });
135
+ }
136
+ if (summary.protection === 'dev') {
137
+ throw new CLIError(
138
+ `The keystore at ${path} is an unencrypted dev keystore; it has no passphrase to cache, so no unlock is needed.`,
139
+ 'INVALID_ARGUMENT_ERROR',
140
+ { path },
141
+ );
142
+ }
143
+ if (!summary.established) {
144
+ throw new CLIError(
145
+ `The keystore at ${path} has no passphrase established yet. `
146
+ + 'Establish one with "btcr2 keystore init" or the first "btcr2 key generate".',
147
+ 'INVALID_ARGUMENT_ERROR',
148
+ { path },
149
+ );
150
+ }
151
+ // An unlocked encrypted keystore signs prompt-free for the whole TTL,
152
+ // silently removing per-use passphrase auth. Two guards, both keyed to
153
+ // --allow-mainnet (ADR 081): this early refusal when the *configured* default
154
+ // network is mainnet (a clear signal before caching anything), plus the
155
+ // authoritative one at consumption, where the session records `allowMainnet`
156
+ // (below) and a `bitcoin` operation, whose network is derived from the DID
157
+ // rather than the config, is withheld from a session that lacks it. The
158
+ // active network defaults to a testnet, so this early refusal never fires
159
+ // for the demo.
160
+ if (!options.allowMainnet && resolveDefaultNetwork(g) === 'bitcoin') {
161
+ throw new CLIError(
162
+ `Refusing to unlock for a mainnet (bitcoin) context: caching the passphrase suspends per-use `
163
+ + 'authentication for the session. Pass --allow-mainnet to override, or keep signing mainnet '
164
+ + 'updates with a per-use passphrase prompt.',
165
+ 'MAINNET_UNLOCK_REFUSED_ERROR',
166
+ { path },
167
+ );
168
+ }
169
+ const ttlMs = resolveSessionTtl(options.ttl);
170
+ // Acquire the passphrase directly (env / file / prompt) with NO session
171
+ // consultation and NO confirm, verify it against the keystore verifier, and
172
+ // only then cache it. A wrong passphrase writes no session file.
173
+ const passphrase = acquirePassphrase({ passphraseFile: g.passphraseFile, prompt: 'Keystore passphrase: ' });
174
+ if (!verifyKeystorePassphrase(path, passphrase)) {
175
+ throw new CLIError(`Incorrect passphrase for the keystore at ${path}; no session was created.`, 'DECRYPT_ERROR', { path });
176
+ }
177
+ const verifierId = keystoreVerifierId(path);
178
+ if (!verifierId) {
179
+ // An established keystore always carries a verifier; defensive guard.
180
+ throw new CLIError(`The keystore at ${path} has no verifier to bind a session to.`, 'INVALID_ARGUMENT_ERROR', { path });
181
+ }
182
+ const session = writeSession(defaultSessionPath(g), {
183
+ keystorePath : path,
184
+ verifierId,
185
+ passphrase,
186
+ ttlMs,
187
+ allowMainnet : !!options.allowMainnet,
188
+ });
189
+ print({ action: 'keystore-unlock', data: { keystore: path, expiresAt: session.expiresAt, ttlSeconds: session.ttlSeconds } });
190
+ });
191
+
192
+ keystore
193
+ .command('lock')
194
+ .description('Revoke the cached session so later commands prompt for the passphrase again (ADR 081).')
195
+ .action(() => {
196
+ const g = globals();
197
+ // Resolve the session from the home only (defaultSessionPath never reads the
198
+ // config), so lock revokes even under a malformed config.
199
+ const sessionPath = defaultSessionPath(g);
200
+ const cleared = clearSession(sessionPath);
201
+ print({ action: 'keystore-lock', data: { path: sessionPath, cleared } });
202
+ });
203
+ }
204
+
205
+ /**
206
+ * Resolves the session TTL in milliseconds from the `--ttl` flag, then
207
+ * `$BTCR2_KEYSTORE_TTL`, then the one-hour default. Rejects a non-positive,
208
+ * malformed, or over-24h value with a {@link CLIError} that names the actual
209
+ * source (the flag or the env var) so the operator fixes the right input.
210
+ */
211
+ function resolveSessionTtl(flag?: string): number {
212
+ const fromFlag = blankToUndef(flag);
213
+ const raw = fromFlag ?? blankToUndef(process.env[ENV_KEYSTORE_TTL]);
214
+ if (raw === undefined) return DEFAULT_SESSION_TTL_MS;
215
+ const source = fromFlag !== undefined ? '--ttl' : `$${ENV_KEYSTORE_TTL}`;
216
+ const ms = parseTtlToMs(raw);
217
+ if (ms === undefined || ms <= 0) {
218
+ throw new CLIError(
219
+ `Invalid ${source} "${raw}": expected seconds or a value with an s/m/h suffix, e.g. 3600, 45m, or 2h.`,
220
+ 'INVALID_ARGUMENT_ERROR',
221
+ { value: raw, source },
222
+ );
223
+ }
224
+ if (ms > MAX_SESSION_TTL_MS) {
225
+ throw new CLIError(
226
+ `${source} "${raw}" exceeds the 24h maximum for a cached passphrase.`,
227
+ 'INVALID_ARGUMENT_ERROR',
228
+ { value: raw, source },
229
+ );
230
+ }
231
+ return ms;
232
+ }
@@ -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
@@ -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);