@cogcoin/client 0.5.15 → 1.0.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 +80 -25
- package/dist/app-paths.d.ts +5 -6
- package/dist/app-paths.js +8 -16
- package/dist/art/balance.txt +10 -0
- package/dist/art/welcome.txt +16 -0
- package/dist/bitcoind/bootstrap/controller.d.ts +1 -0
- package/dist/bitcoind/bootstrap/controller.js +53 -1
- package/dist/bitcoind/client/follow-block-times.d.ts +1 -0
- package/dist/bitcoind/client/follow-block-times.js +1 -1
- package/dist/bitcoind/client/internal-types.d.ts +7 -3
- package/dist/bitcoind/client/managed-client.d.ts +4 -2
- package/dist/bitcoind/client/managed-client.js +14 -0
- package/dist/bitcoind/client/sync-engine.js +72 -11
- package/dist/bitcoind/hash-order.d.ts +4 -0
- package/dist/bitcoind/hash-order.js +13 -0
- package/dist/bitcoind/indexer-daemon-main.js +11 -3
- package/dist/bitcoind/normalize.js +3 -2
- package/dist/bitcoind/processing-start-height.d.ts +5 -0
- package/dist/bitcoind/processing-start-height.js +7 -0
- package/dist/bitcoind/progress/constants.d.ts +4 -0
- package/dist/bitcoind/progress/constants.js +4 -0
- package/dist/bitcoind/progress/controller.d.ts +2 -1
- package/dist/bitcoind/progress/controller.js +3 -3
- package/dist/bitcoind/progress/follow-scene.d.ts +6 -2
- package/dist/bitcoind/progress/follow-scene.js +29 -6
- package/dist/bitcoind/progress/formatting.d.ts +1 -0
- package/dist/bitcoind/progress/formatting.js +6 -0
- package/dist/bitcoind/progress/train-scene.js +37 -18
- package/dist/bitcoind/progress/tty-renderer.d.ts +6 -1
- package/dist/bitcoind/progress/tty-renderer.js +8 -4
- package/dist/bitcoind/rpc.d.ts +2 -1
- package/dist/bitcoind/rpc.js +3 -0
- package/dist/bitcoind/types.d.ts +6 -0
- package/dist/bytes.d.ts +1 -0
- package/dist/bytes.js +3 -0
- package/dist/cli/art.d.ts +2 -0
- package/dist/cli/art.js +37 -0
- package/dist/cli/commands/client-admin.d.ts +2 -0
- package/dist/cli/commands/client-admin.js +91 -0
- package/dist/cli/commands/follow.js +0 -2
- package/dist/cli/commands/mining-admin.js +6 -47
- package/dist/cli/commands/mining-read.js +11 -50
- package/dist/cli/commands/mining-runtime.js +38 -3
- package/dist/cli/commands/service-runtime.js +0 -2
- package/dist/cli/commands/status.js +8 -2
- package/dist/cli/commands/sync.js +51 -4
- package/dist/cli/commands/wallet-admin.js +142 -136
- package/dist/cli/commands/wallet-mutation.js +91 -79
- package/dist/cli/commands/wallet-read.js +15 -18
- package/dist/cli/context.js +4 -14
- package/dist/cli/mining-format.d.ts +0 -1
- package/dist/cli/mining-format.js +5 -37
- package/dist/cli/mining-json.d.ts +0 -18
- package/dist/cli/mining-json.js +0 -35
- package/dist/cli/mutation-command-groups.d.ts +1 -2
- package/dist/cli/mutation-command-groups.js +0 -5
- package/dist/cli/mutation-json.d.ts +24 -145
- package/dist/cli/mutation-json.js +30 -136
- package/dist/cli/mutation-resolved-json.d.ts +0 -7
- package/dist/cli/mutation-resolved-json.js +4 -10
- package/dist/cli/mutation-success.d.ts +2 -0
- package/dist/cli/mutation-success.js +11 -1
- package/dist/cli/mutation-text-format.js +1 -3
- package/dist/cli/output.d.ts +1 -1
- package/dist/cli/output.js +254 -231
- package/dist/cli/parse.d.ts +1 -1
- package/dist/cli/parse.js +93 -122
- package/dist/cli/preview-json.d.ts +17 -120
- package/dist/cli/preview-json.js +14 -97
- package/dist/cli/prompt.js +8 -13
- package/dist/cli/read-json.d.ts +15 -37
- package/dist/cli/read-json.js +44 -140
- package/dist/cli/runner.js +10 -13
- package/dist/cli/types.d.ts +8 -17
- package/dist/cli/types.js +0 -2
- package/dist/cli/wallet-format.d.ts +1 -0
- package/dist/cli/wallet-format.js +205 -144
- package/dist/cli/workflow-hints.d.ts +3 -3
- package/dist/cli/workflow-hints.js +11 -8
- package/dist/client/default-client.d.ts +3 -1
- package/dist/client/default-client.js +45 -2
- package/dist/client/factory.js +1 -1
- package/dist/client/initialization.js +23 -0
- package/dist/client/persistence.js +5 -5
- package/dist/client/store-adapter.js +1 -0
- package/dist/sqlite/checkpoints.d.ts +1 -0
- package/dist/sqlite/checkpoints.js +7 -0
- package/dist/sqlite/store.js +14 -1
- package/dist/types.d.ts +1 -0
- package/dist/wallet/coin-control.d.ts +41 -12
- package/dist/wallet/coin-control.js +100 -428
- package/dist/wallet/descriptor-normalization.d.ts +1 -3
- package/dist/wallet/descriptor-normalization.js +0 -16
- package/dist/wallet/lifecycle.d.ts +7 -99
- package/dist/wallet/lifecycle.js +513 -968
- package/dist/wallet/managed-core-wallet.d.ts +13 -0
- package/dist/wallet/managed-core-wallet.js +20 -0
- package/dist/wallet/mining/constants.d.ts +5 -12
- package/dist/wallet/mining/constants.js +5 -12
- package/dist/wallet/mining/control.d.ts +1 -13
- package/dist/wallet/mining/control.js +45 -349
- package/dist/wallet/mining/index.d.ts +3 -4
- package/dist/wallet/mining/index.js +1 -2
- package/dist/wallet/mining/runner.d.ts +116 -13
- package/dist/wallet/mining/runner.js +885 -501
- package/dist/wallet/mining/runtime-artifacts.js +23 -3
- package/dist/wallet/mining/sentence-protocol.d.ts +44 -0
- package/dist/wallet/mining/sentence-protocol.js +123 -0
- package/dist/wallet/mining/sentences.d.ts +4 -8
- package/dist/wallet/mining/sentences.js +3 -52
- package/dist/wallet/mining/state.d.ts +11 -6
- package/dist/wallet/mining/state.js +7 -6
- package/dist/wallet/mining/types.d.ts +2 -30
- package/dist/wallet/mining/visualizer.d.ts +31 -3
- package/dist/wallet/mining/visualizer.js +135 -13
- package/dist/wallet/read/context.d.ts +0 -2
- package/dist/wallet/read/context.js +119 -140
- package/dist/wallet/read/filter.js +2 -11
- package/dist/wallet/read/index.d.ts +1 -1
- package/dist/wallet/read/project.js +24 -77
- package/dist/wallet/read/types.d.ts +10 -25
- package/dist/wallet/reset.d.ts +0 -1
- package/dist/wallet/reset.js +60 -138
- package/dist/wallet/root-resolution.d.ts +1 -5
- package/dist/wallet/root-resolution.js +0 -18
- package/dist/wallet/runtime.d.ts +0 -6
- package/dist/wallet/runtime.js +0 -8
- package/dist/wallet/state/client-password-agent.js +208 -0
- package/dist/wallet/state/client-password.d.ts +65 -0
- package/dist/wallet/state/client-password.js +952 -0
- package/dist/wallet/state/crypto.d.ts +1 -20
- package/dist/wallet/state/crypto.js +0 -63
- package/dist/wallet/state/provider.d.ts +23 -11
- package/dist/wallet/state/provider.js +248 -290
- package/dist/wallet/state/storage.d.ts +2 -2
- package/dist/wallet/state/storage.js +48 -16
- package/dist/wallet/tx/anchor.d.ts +3 -28
- package/dist/wallet/tx/anchor.js +349 -1250
- package/dist/wallet/tx/bitcoin-transfer.d.ts +35 -0
- package/dist/wallet/tx/bitcoin-transfer.js +200 -0
- package/dist/wallet/tx/cog.d.ts +5 -1
- package/dist/wallet/tx/cog.js +149 -185
- package/dist/wallet/tx/common.d.ts +61 -8
- package/dist/wallet/tx/common.js +266 -146
- package/dist/wallet/tx/domain-admin.d.ts +3 -1
- package/dist/wallet/tx/domain-admin.js +61 -99
- package/dist/wallet/tx/domain-market.d.ts +5 -1
- package/dist/wallet/tx/domain-market.js +221 -228
- package/dist/wallet/tx/field.d.ts +4 -10
- package/dist/wallet/tx/field.js +83 -924
- package/dist/wallet/tx/identity-selector.d.ts +9 -3
- package/dist/wallet/tx/identity-selector.js +17 -35
- package/dist/wallet/tx/index.d.ts +3 -1
- package/dist/wallet/tx/index.js +2 -1
- package/dist/wallet/tx/register.d.ts +3 -1
- package/dist/wallet/tx/register.js +62 -220
- package/dist/wallet/tx/reputation.d.ts +3 -1
- package/dist/wallet/tx/reputation.js +58 -95
- package/dist/wallet/types.d.ts +8 -122
- package/package.json +5 -5
- package/dist/wallet/archive.d.ts +0 -4
- package/dist/wallet/archive.js +0 -41
- package/dist/wallet/mining/hook-protocol.d.ts +0 -47
- package/dist/wallet/mining/hook-protocol.js +0 -161
- package/dist/wallet/mining/hook-runner.js +0 -52
- package/dist/wallet/mining/hooks.d.ts +0 -38
- package/dist/wallet/mining/hooks.js +0 -520
- package/dist/wallet/state/explicit-lock.d.ts +0 -4
- package/dist/wallet/state/explicit-lock.js +0 -19
- package/dist/wallet/state/session.d.ts +0 -12
- package/dist/wallet/state/session.js +0 -23
- /package/dist/wallet/{mining/hook-runner.d.ts → state/client-password-agent.d.ts} +0 -0
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import type { WalletRuntimePaths } from "./runtime.js";
|
|
2
|
-
import { loadWalletExplicitLock } from "./state/explicit-lock.js";
|
|
3
2
|
import type { WalletSecretProvider } from "./state/provider.js";
|
|
4
|
-
import { loadUnlockSession } from "./state/session.js";
|
|
5
3
|
import { type RawWalletStateEnvelope } from "./state/storage.js";
|
|
6
|
-
export type WalletRootResolutionSource = "wallet-state" | "
|
|
4
|
+
export type WalletRootResolutionSource = "wallet-state" | "default-uninitialized";
|
|
7
5
|
export interface WalletRootResolution {
|
|
8
6
|
walletRootId: string;
|
|
9
7
|
source: WalletRootResolutionSource;
|
|
@@ -15,6 +13,4 @@ export declare function resolveWalletRootIdFromLocalArtifacts(options: {
|
|
|
15
13
|
primaryPath: string;
|
|
16
14
|
backupPath: string;
|
|
17
15
|
}) => Promise<RawWalletStateEnvelope | null>;
|
|
18
|
-
loadUnlockSession?: typeof loadUnlockSession;
|
|
19
|
-
loadWalletExplicitLock?: typeof loadWalletExplicitLock;
|
|
20
16
|
}): Promise<WalletRootResolution>;
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { UNINITIALIZED_WALLET_ROOT_ID } from "../bitcoind/service-paths.js";
|
|
2
|
-
import { loadWalletExplicitLock } from "./state/explicit-lock.js";
|
|
3
|
-
import { loadUnlockSession } from "./state/session.js";
|
|
4
2
|
import { extractWalletRootIdHintFromWalletStateEnvelope, loadRawWalletStateEnvelope, } from "./state/storage.js";
|
|
5
3
|
export async function resolveWalletRootIdFromLocalArtifacts(options) {
|
|
6
4
|
const rawEnvelope = await (options.loadRawWalletStateEnvelope ?? loadRawWalletStateEnvelope)({
|
|
@@ -14,22 +12,6 @@ export async function resolveWalletRootIdFromLocalArtifacts(options) {
|
|
|
14
12
|
source: "wallet-state",
|
|
15
13
|
};
|
|
16
14
|
}
|
|
17
|
-
const session = await (options.loadUnlockSession ?? loadUnlockSession)(options.paths.walletUnlockSessionPath, {
|
|
18
|
-
provider: options.provider,
|
|
19
|
-
}).catch(() => null);
|
|
20
|
-
if (session !== null) {
|
|
21
|
-
return {
|
|
22
|
-
walletRootId: session.walletRootId,
|
|
23
|
-
source: "unlock-session",
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
const explicitLock = await (options.loadWalletExplicitLock ?? loadWalletExplicitLock)(options.paths.walletExplicitLockPath).catch(() => null);
|
|
27
|
-
if (explicitLock?.walletRootId) {
|
|
28
|
-
return {
|
|
29
|
-
walletRootId: explicitLock.walletRootId,
|
|
30
|
-
source: "explicit-lock",
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
15
|
return {
|
|
34
16
|
walletRootId: UNINITIALIZED_WALLET_ROOT_ID,
|
|
35
17
|
source: "default-uninitialized",
|
package/dist/wallet/runtime.d.ts
CHANGED
|
@@ -9,7 +9,6 @@ export interface WalletRuntimePaths {
|
|
|
9
9
|
clientConfigPath: string;
|
|
10
10
|
runtimeRoot: string;
|
|
11
11
|
walletRuntimeRoot: string;
|
|
12
|
-
hooksRoot: string;
|
|
13
12
|
stateRoot: string;
|
|
14
13
|
walletStateRoot: string;
|
|
15
14
|
seedRegistryPath: string;
|
|
@@ -22,16 +21,11 @@ export interface WalletRuntimePaths {
|
|
|
22
21
|
walletStateBackupPath: string;
|
|
23
22
|
walletInitPendingPath: string;
|
|
24
23
|
walletInitPendingBackupPath: string;
|
|
25
|
-
walletUnlockSessionPath: string;
|
|
26
|
-
walletExplicitLockPath: string;
|
|
27
24
|
walletControlLockPath: string;
|
|
28
25
|
bitcoindLockPath: string;
|
|
29
26
|
bitcoindStatusPath: string;
|
|
30
27
|
indexerDaemonLockPath: string;
|
|
31
28
|
indexerStatusPath: string;
|
|
32
|
-
hooksMiningDir: string;
|
|
33
|
-
hooksMiningEntrypointPath: string;
|
|
34
|
-
hooksMiningPackageJsonPath: string;
|
|
35
29
|
miningRoot: string;
|
|
36
30
|
miningStatusPath: string;
|
|
37
31
|
miningEventsPath: string;
|
package/dist/wallet/runtime.js
CHANGED
|
@@ -28,8 +28,6 @@ export function deriveWalletRuntimePathsForSeed(basePaths, seedName) {
|
|
|
28
28
|
walletStateBackupPath: join(seedLayout.walletStateRoot, "wallet-state.enc.bak"),
|
|
29
29
|
walletInitPendingPath: join(seedLayout.walletStateRoot, "wallet-init-pending.enc"),
|
|
30
30
|
walletInitPendingBackupPath: join(seedLayout.walletStateRoot, "wallet-init-pending.enc.bak"),
|
|
31
|
-
walletUnlockSessionPath: join(seedLayout.walletRuntimeRoot, "wallet-unlock-session.enc"),
|
|
32
|
-
walletExplicitLockPath: join(seedLayout.walletRuntimeRoot, "wallet-explicit-lock.json"),
|
|
33
31
|
miningRoot: join(seedLayout.walletRuntimeRoot, "mining"),
|
|
34
32
|
miningStatusPath: join(seedLayout.walletRuntimeRoot, "mining", "status.json"),
|
|
35
33
|
miningEventsPath: join(seedLayout.walletRuntimeRoot, "mining", "events.jsonl"),
|
|
@@ -43,7 +41,6 @@ export function resolveWalletRuntimePathsForTesting(resolution = {}) {
|
|
|
43
41
|
clientConfigPath: paths.clientConfigPath,
|
|
44
42
|
runtimeRoot: paths.runtimeRoot,
|
|
45
43
|
walletRuntimeRoot: paths.runtimeRoot,
|
|
46
|
-
hooksRoot: paths.hooksRoot,
|
|
47
44
|
stateRoot: paths.stateRoot,
|
|
48
45
|
walletStateRoot: paths.stateRoot,
|
|
49
46
|
seedRegistryPath: join(paths.stateRoot, "seed-index.json"),
|
|
@@ -56,16 +53,11 @@ export function resolveWalletRuntimePathsForTesting(resolution = {}) {
|
|
|
56
53
|
walletStateBackupPath: join(paths.stateRoot, "wallet-state.enc.bak"),
|
|
57
54
|
walletInitPendingPath: join(paths.stateRoot, "wallet-init-pending.enc"),
|
|
58
55
|
walletInitPendingBackupPath: join(paths.stateRoot, "wallet-init-pending.enc.bak"),
|
|
59
|
-
walletUnlockSessionPath: join(paths.runtimeRoot, "wallet-unlock-session.enc"),
|
|
60
|
-
walletExplicitLockPath: join(paths.runtimeRoot, "wallet-explicit-lock.json"),
|
|
61
56
|
walletControlLockPath: paths.walletControlLockPath,
|
|
62
57
|
bitcoindLockPath: paths.bitcoindLockPath,
|
|
63
58
|
bitcoindStatusPath: paths.bitcoindStatusPath,
|
|
64
59
|
indexerDaemonLockPath: paths.indexerDaemonLockPath,
|
|
65
60
|
indexerStatusPath: paths.indexerStatusPath,
|
|
66
|
-
hooksMiningDir: paths.hooksMiningDir,
|
|
67
|
-
hooksMiningEntrypointPath: paths.hooksMiningEntrypointPath,
|
|
68
|
-
hooksMiningPackageJsonPath: paths.hooksMiningPackageJsonPath,
|
|
69
61
|
miningRoot: join(paths.runtimeRoot, "mining"),
|
|
70
62
|
miningStatusPath: join(paths.runtimeRoot, "mining", "status.json"),
|
|
71
63
|
miningEventsPath: join(paths.runtimeRoot, "mining", "events.jsonl"),
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
|
|
2
|
+
import net from "node:net";
|
|
3
|
+
import { rm } from "node:fs/promises";
|
|
4
|
+
function zeroizeBuffer(buffer) {
|
|
5
|
+
if (buffer != null) {
|
|
6
|
+
buffer.fill(0);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
function createAgentError(message) {
|
|
10
|
+
return JSON.stringify({
|
|
11
|
+
ok: false,
|
|
12
|
+
error: message,
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
async function readBootstrapConfig() {
|
|
16
|
+
const endpoint = process.argv[2] ?? "";
|
|
17
|
+
const unlockUntilUnixMs = Number(process.argv[3] ?? "");
|
|
18
|
+
if (endpoint.length === 0 || !Number.isFinite(unlockUntilUnixMs)) {
|
|
19
|
+
throw new Error("wallet_client_password_agent_bootstrap_invalid");
|
|
20
|
+
}
|
|
21
|
+
const raw = await new Promise((resolve, reject) => {
|
|
22
|
+
let received = "";
|
|
23
|
+
const onData = (chunk) => {
|
|
24
|
+
received += chunk.toString("utf8");
|
|
25
|
+
const newlineIndex = received.indexOf("\n");
|
|
26
|
+
if (newlineIndex !== -1) {
|
|
27
|
+
cleanup();
|
|
28
|
+
resolve(received.slice(0, newlineIndex));
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const onEnd = () => {
|
|
32
|
+
cleanup();
|
|
33
|
+
reject(new Error("wallet_client_password_agent_bootstrap_missing"));
|
|
34
|
+
};
|
|
35
|
+
const onError = (error) => {
|
|
36
|
+
cleanup();
|
|
37
|
+
reject(error);
|
|
38
|
+
};
|
|
39
|
+
const cleanup = () => {
|
|
40
|
+
process.stdin.off("data", onData);
|
|
41
|
+
process.stdin.off("end", onEnd);
|
|
42
|
+
process.stdin.off("error", onError);
|
|
43
|
+
};
|
|
44
|
+
process.stdin.on("data", onData);
|
|
45
|
+
process.stdin.on("end", onEnd);
|
|
46
|
+
process.stdin.on("error", onError);
|
|
47
|
+
});
|
|
48
|
+
const parsed = JSON.parse(raw);
|
|
49
|
+
if (typeof parsed.derivedKeyBase64 !== "string") {
|
|
50
|
+
throw new Error("wallet_client_password_agent_bootstrap_invalid");
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
endpoint,
|
|
54
|
+
unlockUntilUnixMs,
|
|
55
|
+
derivedKey: Buffer.from(parsed.derivedKeyBase64, "base64"),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
async function main() {
|
|
59
|
+
const bootstrap = await readBootstrapConfig();
|
|
60
|
+
let key = bootstrap.derivedKey;
|
|
61
|
+
let unlockUntilUnixMs = bootstrap.unlockUntilUnixMs;
|
|
62
|
+
let expiryTimer = null;
|
|
63
|
+
const cleanupAndExit = async () => {
|
|
64
|
+
if (expiryTimer !== null) {
|
|
65
|
+
clearTimeout(expiryTimer);
|
|
66
|
+
expiryTimer = null;
|
|
67
|
+
}
|
|
68
|
+
zeroizeBuffer(key);
|
|
69
|
+
key = Buffer.alloc(0);
|
|
70
|
+
if (!bootstrap.endpoint.startsWith("\\\\.\\")) {
|
|
71
|
+
await rm(bootstrap.endpoint, { force: true }).catch(() => undefined);
|
|
72
|
+
}
|
|
73
|
+
process.exit(0);
|
|
74
|
+
};
|
|
75
|
+
const refreshExpiry = () => {
|
|
76
|
+
if (expiryTimer !== null) {
|
|
77
|
+
clearTimeout(expiryTimer);
|
|
78
|
+
}
|
|
79
|
+
const remainingMs = Math.max(0, unlockUntilUnixMs - Date.now());
|
|
80
|
+
expiryTimer = setTimeout(() => {
|
|
81
|
+
void cleanupAndExit();
|
|
82
|
+
}, remainingMs);
|
|
83
|
+
expiryTimer.unref();
|
|
84
|
+
};
|
|
85
|
+
const encryptSecret = (secretBase64) => {
|
|
86
|
+
const nonce = randomBytes(12);
|
|
87
|
+
const cipher = createCipheriv("aes-256-gcm", key, nonce);
|
|
88
|
+
const ciphertext = Buffer.concat([
|
|
89
|
+
cipher.update(Buffer.from(secretBase64, "base64")),
|
|
90
|
+
cipher.final(),
|
|
91
|
+
]);
|
|
92
|
+
const tag = cipher.getAuthTag();
|
|
93
|
+
return {
|
|
94
|
+
nonce: nonce.toString("base64"),
|
|
95
|
+
tag: tag.toString("base64"),
|
|
96
|
+
ciphertext: ciphertext.toString("base64"),
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
const decryptSecret = (options) => {
|
|
100
|
+
const decipher = createDecipheriv("aes-256-gcm", key, Buffer.from(options.nonce, "base64"));
|
|
101
|
+
decipher.setAuthTag(Buffer.from(options.tag, "base64"));
|
|
102
|
+
return Buffer.concat([
|
|
103
|
+
decipher.update(Buffer.from(options.ciphertext, "base64")),
|
|
104
|
+
decipher.final(),
|
|
105
|
+
]).toString("base64");
|
|
106
|
+
};
|
|
107
|
+
const server = net.createServer((socket) => {
|
|
108
|
+
let received = "";
|
|
109
|
+
const send = (payload) => {
|
|
110
|
+
socket.end(`${JSON.stringify(payload)}\n`);
|
|
111
|
+
};
|
|
112
|
+
socket.on("data", (chunk) => {
|
|
113
|
+
received += chunk.toString("utf8");
|
|
114
|
+
const newlineIndex = received.indexOf("\n");
|
|
115
|
+
if (newlineIndex === -1) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
let parsed;
|
|
119
|
+
try {
|
|
120
|
+
parsed = JSON.parse(received.slice(0, newlineIndex));
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
send({ ok: false, error: "wallet_client_password_agent_protocol_error" });
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
switch (parsed.command) {
|
|
128
|
+
case "status":
|
|
129
|
+
send({ ok: true, unlockUntilUnixMs });
|
|
130
|
+
return;
|
|
131
|
+
case "lock":
|
|
132
|
+
send({ ok: true, unlockUntilUnixMs: null });
|
|
133
|
+
setImmediate(() => {
|
|
134
|
+
void cleanupAndExit();
|
|
135
|
+
});
|
|
136
|
+
return;
|
|
137
|
+
case "refresh":
|
|
138
|
+
if (!Number.isFinite(parsed.unlockUntilUnixMs)) {
|
|
139
|
+
send({ ok: false, error: "wallet_client_password_agent_protocol_error" });
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
unlockUntilUnixMs = Number(parsed.unlockUntilUnixMs);
|
|
143
|
+
refreshExpiry();
|
|
144
|
+
send({ ok: true, unlockUntilUnixMs });
|
|
145
|
+
return;
|
|
146
|
+
case "encrypt":
|
|
147
|
+
if (typeof parsed.secretBase64 !== "string") {
|
|
148
|
+
send({ ok: false, error: "wallet_client_password_agent_protocol_error" });
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
send({
|
|
152
|
+
ok: true,
|
|
153
|
+
unlockUntilUnixMs,
|
|
154
|
+
envelope: encryptSecret(parsed.secretBase64),
|
|
155
|
+
});
|
|
156
|
+
return;
|
|
157
|
+
case "decrypt":
|
|
158
|
+
if (typeof parsed.envelope?.nonce !== "string"
|
|
159
|
+
|| typeof parsed.envelope?.tag !== "string"
|
|
160
|
+
|| typeof parsed.envelope?.ciphertext !== "string") {
|
|
161
|
+
send({ ok: false, error: "wallet_client_password_agent_protocol_error" });
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
send({
|
|
165
|
+
ok: true,
|
|
166
|
+
unlockUntilUnixMs,
|
|
167
|
+
secretBase64: decryptSecret({
|
|
168
|
+
nonce: parsed.envelope.nonce,
|
|
169
|
+
tag: parsed.envelope.tag,
|
|
170
|
+
ciphertext: parsed.envelope.ciphertext,
|
|
171
|
+
}),
|
|
172
|
+
});
|
|
173
|
+
return;
|
|
174
|
+
default:
|
|
175
|
+
send({ ok: false, error: "wallet_client_password_agent_protocol_error" });
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
send({
|
|
180
|
+
ok: false,
|
|
181
|
+
error: error instanceof Error ? error.message : String(error),
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
process.on("SIGTERM", () => {
|
|
187
|
+
void cleanupAndExit();
|
|
188
|
+
});
|
|
189
|
+
process.on("SIGINT", () => {
|
|
190
|
+
void cleanupAndExit();
|
|
191
|
+
});
|
|
192
|
+
process.on("exit", () => {
|
|
193
|
+
zeroizeBuffer(key);
|
|
194
|
+
});
|
|
195
|
+
refreshExpiry();
|
|
196
|
+
await new Promise((resolve, reject) => {
|
|
197
|
+
server.once("error", reject);
|
|
198
|
+
server.listen(bootstrap.endpoint, () => {
|
|
199
|
+
server.off("error", reject);
|
|
200
|
+
resolve();
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
process.stdout.write("ready\n");
|
|
204
|
+
}
|
|
205
|
+
void main().catch((error) => {
|
|
206
|
+
process.stderr.write(`${createAgentError(error instanceof Error ? error.message : String(error))}\n`);
|
|
207
|
+
process.exit(1);
|
|
208
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export declare const CLIENT_PASSWORD_SETUP_AUTO_UNLOCK_SECONDS = 86400;
|
|
2
|
+
export type ClientPasswordReadiness = "ready" | "setup-required" | "migration-required";
|
|
3
|
+
export type ClientPasswordSetupAction = "created" | "migrated" | "already-configured";
|
|
4
|
+
export interface ClientPasswordPrompt {
|
|
5
|
+
readonly isInteractive: boolean;
|
|
6
|
+
writeLine(message: string): void;
|
|
7
|
+
prompt(message: string): Promise<string>;
|
|
8
|
+
promptHidden?(message: string): Promise<string>;
|
|
9
|
+
}
|
|
10
|
+
export interface ClientPasswordSessionStatus {
|
|
11
|
+
unlocked: boolean;
|
|
12
|
+
unlockUntilUnixMs: number | null;
|
|
13
|
+
}
|
|
14
|
+
export interface ClientPasswordStorageOptions {
|
|
15
|
+
platform: NodeJS.Platform;
|
|
16
|
+
stateRoot: string;
|
|
17
|
+
runtimeRoot: string;
|
|
18
|
+
directoryPath: string;
|
|
19
|
+
runtimeErrorCode: string;
|
|
20
|
+
legacyMacKeychainReader?: {
|
|
21
|
+
loadSecret(keyId: string): Promise<Uint8Array>;
|
|
22
|
+
} | null;
|
|
23
|
+
}
|
|
24
|
+
export declare function resolveLocalSecretFilePath(directoryPath: string, keyId: string): string;
|
|
25
|
+
export declare function inspectClientPasswordReadiness(options: ClientPasswordStorageOptions): Promise<ClientPasswordReadiness>;
|
|
26
|
+
export declare function readClientPasswordSessionStatus(options: ClientPasswordStorageOptions): Promise<ClientPasswordSessionStatus>;
|
|
27
|
+
export declare function lockClientPasswordSession(options: ClientPasswordStorageOptions): Promise<ClientPasswordSessionStatus>;
|
|
28
|
+
export declare function ensureClientPasswordConfigured(options: ClientPasswordStorageOptions & {
|
|
29
|
+
prompt: ClientPasswordPrompt;
|
|
30
|
+
}): Promise<{
|
|
31
|
+
action: ClientPasswordSetupAction;
|
|
32
|
+
session: ClientPasswordSessionStatus;
|
|
33
|
+
}>;
|
|
34
|
+
export declare function loadClientProtectedSecret(options: ClientPasswordStorageOptions & {
|
|
35
|
+
keyId: string;
|
|
36
|
+
prompt?: ClientPasswordPrompt;
|
|
37
|
+
}): Promise<Uint8Array>;
|
|
38
|
+
export declare function storeClientProtectedSecret(options: ClientPasswordStorageOptions & {
|
|
39
|
+
keyId: string;
|
|
40
|
+
secret: Uint8Array;
|
|
41
|
+
prompt?: ClientPasswordPrompt;
|
|
42
|
+
}): Promise<void>;
|
|
43
|
+
export declare function deleteClientProtectedSecret(options: ClientPasswordStorageOptions & {
|
|
44
|
+
keyId: string;
|
|
45
|
+
}): Promise<void>;
|
|
46
|
+
export declare function unlockClientPasswordSession(options: ClientPasswordStorageOptions & {
|
|
47
|
+
prompt: ClientPasswordPrompt;
|
|
48
|
+
}): Promise<ClientPasswordSessionStatus>;
|
|
49
|
+
export declare function changeClientPassword(options: ClientPasswordStorageOptions & {
|
|
50
|
+
prompt: ClientPasswordPrompt;
|
|
51
|
+
}): Promise<ClientPasswordSessionStatus>;
|
|
52
|
+
export declare function createLegacyKeychainServiceName(): string;
|
|
53
|
+
export declare function createAgentBootstrapState(options: {
|
|
54
|
+
unlockUntilUnixMs: number;
|
|
55
|
+
derivedKeyBase64: string;
|
|
56
|
+
}): {
|
|
57
|
+
unlockUntilUnixMs: number;
|
|
58
|
+
derivedKeyBase64: string;
|
|
59
|
+
};
|
|
60
|
+
export declare function describeClientPasswordLockedMessage(): string;
|
|
61
|
+
export declare function describeClientPasswordSetupMessage(): string;
|
|
62
|
+
export declare function describeClientPasswordMigrationMessage(): string;
|
|
63
|
+
export declare function listLocalSecretFilesForTesting(options: {
|
|
64
|
+
directoryPath: string;
|
|
65
|
+
}): Promise<string[]>;
|