@did-btcr2/cli 0.14.0 → 0.15.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 +61 -13
- package/dist/.tsbuildinfo +1 -1
- package/dist/cjs/index.js +637 -54
- package/dist/esm/src/cli.js +23 -2
- package/dist/esm/src/cli.js.map +1 -1
- package/dist/esm/src/commands/config.js +124 -8
- package/dist/esm/src/commands/config.js.map +1 -1
- package/dist/esm/src/commands/create.js +10 -1
- package/dist/esm/src/commands/create.js.map +1 -1
- package/dist/esm/src/commands/deactivate.js +14 -2
- package/dist/esm/src/commands/deactivate.js.map +1 -1
- package/dist/esm/src/commands/profile.js +5 -3
- package/dist/esm/src/commands/profile.js.map +1 -1
- package/dist/esm/src/commands/update.js +14 -2
- package/dist/esm/src/commands/update.js.map +1 -1
- package/dist/esm/src/config-schema.js +149 -0
- package/dist/esm/src/config-schema.js.map +1 -0
- package/dist/esm/src/config.js +506 -39
- package/dist/esm/src/config.js.map +1 -1
- package/dist/esm/src/keystore/paths.js +3 -2
- package/dist/esm/src/keystore/paths.js.map +1 -1
- package/dist/esm/src/output.js +49 -0
- package/dist/esm/src/output.js.map +1 -1
- package/dist/esm/src/types.js +11 -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/profile.d.ts.map +1 -1
- package/dist/types/src/commands/update.d.ts.map +1 -1
- package/dist/types/src/config-schema.d.ts +24 -0
- package/dist/types/src/config-schema.d.ts.map +1 -0
- package/dist/types/src/config.d.ts +219 -5
- package/dist/types/src/config.d.ts.map +1 -1
- package/dist/types/src/keystore/paths.d.ts.map +1 -1
- package/dist/types/src/output.d.ts +22 -0
- package/dist/types/src/output.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +32 -0
- package/dist/types/src/types.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/cli.ts +25 -2
- package/src/commands/config.ts +135 -8
- package/src/commands/create.ts +13 -1
- package/src/commands/deactivate.ts +22 -2
- package/src/commands/profile.ts +5 -3
- package/src/commands/update.ts +22 -2
- package/src/config-schema.ts +178 -0
- package/src/config.ts +676 -43
- package/src/keystore/paths.ts +3 -2
- package/src/output.ts +53 -0
- package/src/types.ts +22 -0
package/src/keystore/paths.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { homedir } from 'node:os';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
+
import { blankToUndef } from '../types.js';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Default keystore file path, following the XDG Base Directory Specification's
|
|
@@ -13,8 +14,8 @@ import { join } from 'node:path';
|
|
|
13
14
|
* 3. `~/.local/share/btcr2/keystore.json` (fallback)
|
|
14
15
|
*/
|
|
15
16
|
export function defaultKeystorePath(): string {
|
|
16
|
-
const base = process.env.XDG_DATA_HOME
|
|
17
|
-
?? process.env.LOCALAPPDATA
|
|
17
|
+
const base = blankToUndef(process.env.XDG_DATA_HOME)
|
|
18
|
+
?? blankToUndef(process.env.LOCALAPPDATA)
|
|
18
19
|
?? join(homedir(), '.local', 'share');
|
|
19
20
|
return join(base, 'btcr2', 'keystore.json');
|
|
20
21
|
}
|
package/src/output.ts
CHANGED
|
@@ -1,5 +1,58 @@
|
|
|
1
1
|
import type { CommandResult, GlobalOptions } from './types.js';
|
|
2
2
|
|
|
3
|
+
/** Placeholder printed in place of a redacted secret value. */
|
|
4
|
+
export const REDACTED = '********';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Key names whose (scalar) values are treated as secrets and redacted in printed
|
|
8
|
+
* output. Covers RPC passwords plus header credentials (`Authorization`, API
|
|
9
|
+
* keys, bearer tokens) that a profile can now carry in `btc.headers`/`rpcHeaders`.
|
|
10
|
+
*/
|
|
11
|
+
const SECRET_KEY = /(pass|secret|token|auth|api[-_]?key|credential|bearer)/i;
|
|
12
|
+
|
|
13
|
+
/** Whether a config key name looks like a secret (so its scalar value should be redacted). */
|
|
14
|
+
export function isSecretKey(key: string): boolean {
|
|
15
|
+
return SECRET_KEY.test(key);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Masks the password in a `scheme://user:pass@host` URL, leaving the rest of the
|
|
20
|
+
* value verbatim. A credential embedded in an endpoint URL (e.g. `rpcUrl`) is not
|
|
21
|
+
* caught by key-name matching, so it is scrubbed here regardless of the key.
|
|
22
|
+
*/
|
|
23
|
+
export function scrubUrlUserinfo(value: string | undefined): string | undefined {
|
|
24
|
+
if (value === undefined) return undefined;
|
|
25
|
+
return value.replace(/^([a-z][a-z0-9+.-]*:\/\/[^/@:]+):[^/@]*@/i, `$1:${REDACTED}@`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Returns a deep copy of `value` with secret scalar values replaced by
|
|
30
|
+
* {@link REDACTED}, so routine introspection (`config get`/`list`/`effective`)
|
|
31
|
+
* does not print RPC passwords or other secrets into terminal scrollback and CI
|
|
32
|
+
* logs. A secret-named key redacts only a scalar value (an object under such a
|
|
33
|
+
* key, e.g. a profile named `access-token`, is still traversed, not wholesale
|
|
34
|
+
* masked). Passwords embedded in URL values are scrubbed regardless of key name.
|
|
35
|
+
* When `keyName` is a secret name, a directly-passed scalar value is redacted
|
|
36
|
+
* (used when a single leaf value is printed). Display-only: the stored config and
|
|
37
|
+
* the value used to connect are untouched.
|
|
38
|
+
*/
|
|
39
|
+
export function redactSecrets(value: unknown, keyName?: string): unknown {
|
|
40
|
+
if (Array.isArray(value)) {
|
|
41
|
+
return value.map(item => redactSecrets(item));
|
|
42
|
+
}
|
|
43
|
+
if (value !== null && typeof value === 'object') {
|
|
44
|
+
const out: Record<string, unknown> = {};
|
|
45
|
+
for (const [ key, val ] of Object.entries(value as Record<string, unknown>)) {
|
|
46
|
+
out[key] = redactSecrets(val, key);
|
|
47
|
+
}
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
if (keyName !== undefined && isSecretKey(keyName)) {
|
|
51
|
+
return value === undefined ? undefined : REDACTED;
|
|
52
|
+
}
|
|
53
|
+
return typeof value === 'string' ? scrubUrlUserinfo(value) : value;
|
|
54
|
+
}
|
|
55
|
+
|
|
3
56
|
/**
|
|
4
57
|
* Formats a CommandResult for console output.
|
|
5
58
|
* In 'json' mode, the full result is serialized.
|
package/src/types.ts
CHANGED
|
@@ -2,6 +2,8 @@ import type { DidUpdateResult } from '@did-btcr2/api';
|
|
|
2
2
|
import type { PatchOperation } from '@did-btcr2/common';
|
|
3
3
|
import type { Btcr2DidDocument, ResolutionOptions } from '@did-btcr2/method';
|
|
4
4
|
import type { DidResolutionResult } from '@web5/dids';
|
|
5
|
+
import type { DoctorReport, EffectiveConfig } from './config.js';
|
|
6
|
+
import type { ConfigIssue } from './config-schema.js';
|
|
5
7
|
|
|
6
8
|
export type NetworkOption = 'bitcoin' | 'testnet3' | 'testnet4' | 'signet' | 'mutinynet' | 'regtest';
|
|
7
9
|
export type OutputFormat = 'json' | 'text';
|
|
@@ -10,6 +12,17 @@ export const SUPPORTED_NETWORKS: NetworkOption[] = [
|
|
|
10
12
|
'bitcoin', 'testnet3', 'testnet4', 'signet', 'mutinynet', 'regtest'
|
|
11
13
|
];
|
|
12
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Normalizes a blank value (empty or whitespace-only) to `undefined`, so a
|
|
17
|
+
* blank at any precedence layer defers to the next layer instead of masking it.
|
|
18
|
+
* A non-blank value is returned unchanged. This mirrors the `|| undefined`
|
|
19
|
+
* treatment the environment layer already applies in `readEnvOverrides`.
|
|
20
|
+
*/
|
|
21
|
+
export function blankToUndef(value: string | undefined): string | undefined {
|
|
22
|
+
if (value === undefined) return undefined;
|
|
23
|
+
return value.trim() === '' ? undefined : value;
|
|
24
|
+
}
|
|
25
|
+
|
|
13
26
|
export interface ResolveCommandOptions {
|
|
14
27
|
identifier : string;
|
|
15
28
|
options? : ResolutionOptions;
|
|
@@ -40,6 +53,10 @@ export type CommandResult =
|
|
|
40
53
|
| { action: 'config-set'; data: { path: string } }
|
|
41
54
|
| { action: 'config-unset'; data: { path: string } }
|
|
42
55
|
| { action: 'config-list'; data: unknown }
|
|
56
|
+
| { action: 'config-validate'; data: { ok: boolean; issues: ConfigIssue[] } }
|
|
57
|
+
| { action: 'config-effective'; data: EffectiveConfig }
|
|
58
|
+
| { action: 'config-path'; data: { config: string; keystore: string } }
|
|
59
|
+
| { action: 'config-doctor'; data: DoctorReport }
|
|
43
60
|
| { action: 'profile-add'; data: { profile: string } }
|
|
44
61
|
| { action: 'profile-use'; data: { profile: string } }
|
|
45
62
|
| { action: 'profile-show'; data: unknown }
|
|
@@ -57,6 +74,11 @@ export interface GlobalOptions {
|
|
|
57
74
|
btcRpcPass? : string;
|
|
58
75
|
casGateway? : string;
|
|
59
76
|
casRpcUrl? : string;
|
|
77
|
+
btcTimeout? : string;
|
|
78
|
+
casTimeout? : string;
|
|
79
|
+
btcRestHeader? : string[];
|
|
80
|
+
btcRpcWallet? : string;
|
|
81
|
+
btcRpcHeader? : string[];
|
|
60
82
|
keystore? : string;
|
|
61
83
|
passphraseFile?: string;
|
|
62
84
|
signingKey? : string;
|