@cogcoin/client 0.5.14 → 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 +16 -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 -11
- package/dist/wallet/coin-control.js +100 -357
- 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 +179 -6
- package/dist/wallet/mining/runner.js +891 -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 -1240
- 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 +74 -10
- package/dist/wallet/tx/common.js +315 -138
- 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 +84 -914
- 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,16 +1,11 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
-
import { execFile
|
|
3
|
-
import {
|
|
4
|
-
import { dirname, join } from "node:path";
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { join } from "node:path";
|
|
5
4
|
import { promisify } from "node:util";
|
|
6
5
|
import { resolveWalletRuntimePathsForTesting } from "../runtime.js";
|
|
7
|
-
import {
|
|
6
|
+
import { createLegacyKeychainServiceName, deleteClientProtectedSecret, ensureClientPasswordConfigured as ensureClientPasswordConfiguredWithLocalFile, inspectClientPasswordReadiness, loadClientProtectedSecret, lockClientPasswordSession, readClientPasswordSessionStatus, storeClientProtectedSecret, changeClientPassword as changeClientPasswordWithLocalFile, unlockClientPasswordSession as unlockClientPasswordSessionWithLocalFile, } from "./client-password.js";
|
|
8
7
|
const execFileAsync = promisify(execFile);
|
|
9
|
-
const KEYCHAIN_SERVICE_NAME =
|
|
10
|
-
const LINUX_SECRET_TOOL_ATTRIBUTE_APPLICATION = "application";
|
|
11
|
-
const LINUX_SECRET_TOOL_ATTRIBUTE_KIND = "secret-kind";
|
|
12
|
-
const LINUX_SECRET_TOOL_ATTRIBUTE_KEY_ID = "key-id";
|
|
13
|
-
const LINUX_SECRET_TOOL_SECRET_KIND = "wallet-secret";
|
|
8
|
+
const KEYCHAIN_SERVICE_NAME = createLegacyKeychainServiceName();
|
|
14
9
|
export function createWalletSecretReference(walletRootId) {
|
|
15
10
|
return {
|
|
16
11
|
kind: "wallet-state-key",
|
|
@@ -29,86 +24,17 @@ function bytesToBase64(secret) {
|
|
|
29
24
|
function base64ToBytes(secret) {
|
|
30
25
|
return new Uint8Array(Buffer.from(secret, "base64"));
|
|
31
26
|
}
|
|
32
|
-
function createLinuxSecretToolAttributes(keyId) {
|
|
33
|
-
return [
|
|
34
|
-
LINUX_SECRET_TOOL_ATTRIBUTE_APPLICATION,
|
|
35
|
-
KEYCHAIN_SERVICE_NAME,
|
|
36
|
-
LINUX_SECRET_TOOL_ATTRIBUTE_KIND,
|
|
37
|
-
LINUX_SECRET_TOOL_SECRET_KIND,
|
|
38
|
-
LINUX_SECRET_TOOL_ATTRIBUTE_KEY_ID,
|
|
39
|
-
keyId,
|
|
40
|
-
];
|
|
41
|
-
}
|
|
42
|
-
function createLinuxSecretToolError(message, cause) {
|
|
43
|
-
return cause === undefined ? new Error(message) : new Error(message, { cause });
|
|
44
|
-
}
|
|
45
|
-
function isWalletSecretProviderMessage(error, message) {
|
|
46
|
-
return error instanceof Error && error.message === message;
|
|
47
|
-
}
|
|
48
|
-
function sanitizeSecretKeyId(keyId) {
|
|
49
|
-
return keyId.replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
50
|
-
}
|
|
51
27
|
function resolveSecretDirectoryPath(options) {
|
|
52
28
|
return join(options.stateRoot ?? resolveWalletRuntimePathsForTesting().stateRoot, "secrets");
|
|
53
29
|
}
|
|
54
|
-
function
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return false;
|
|
30
|
+
function resolveRuntimeRootPath(options) {
|
|
31
|
+
if (options.runtimeRoot != null) {
|
|
32
|
+
return options.runtimeRoot;
|
|
58
33
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|| normalized.includes("dbus")
|
|
62
|
-
|| normalized.includes("d-bus")
|
|
63
|
-
|| normalized.includes("cannot autolaunch")
|
|
64
|
-
|| normalized.includes("no such secret collection")
|
|
65
|
-
|| normalized.includes("collection is locked")
|
|
66
|
-
|| normalized.includes("prompt dismissed")
|
|
67
|
-
|| normalized.includes("not available");
|
|
68
|
-
}
|
|
69
|
-
function isLinuxSecretToolMissingSecretMessage(stderr) {
|
|
70
|
-
const normalized = stderr.trim().toLowerCase();
|
|
71
|
-
if (normalized.length === 0) {
|
|
72
|
-
return true;
|
|
34
|
+
if (options.stateRoot != null) {
|
|
35
|
+
return join(options.stateRoot, ".client-runtime");
|
|
73
36
|
}
|
|
74
|
-
return
|
|
75
|
-
|| normalized.includes("not found")
|
|
76
|
-
|| normalized.includes("does not exist")
|
|
77
|
-
|| normalized.includes("no such item")
|
|
78
|
-
|| normalized.includes("no secret");
|
|
79
|
-
}
|
|
80
|
-
async function runLinuxSecretTool(args, options = {}) {
|
|
81
|
-
return await new Promise((resolve, reject) => {
|
|
82
|
-
const child = spawn("secret-tool", [...args], {
|
|
83
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
84
|
-
});
|
|
85
|
-
let stdout = "";
|
|
86
|
-
let stderr = "";
|
|
87
|
-
child.once("error", reject);
|
|
88
|
-
child.stdout.setEncoding("utf8");
|
|
89
|
-
child.stderr.setEncoding("utf8");
|
|
90
|
-
child.stdout.on("data", (chunk) => {
|
|
91
|
-
stdout += chunk;
|
|
92
|
-
});
|
|
93
|
-
child.stderr.on("data", (chunk) => {
|
|
94
|
-
stderr += chunk;
|
|
95
|
-
});
|
|
96
|
-
child.once("close", (exitCode, signal) => {
|
|
97
|
-
resolve({
|
|
98
|
-
stdout,
|
|
99
|
-
stderr,
|
|
100
|
-
exitCode,
|
|
101
|
-
signal,
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
child.stdin.on("error", (error) => {
|
|
105
|
-
if ("code" in error && error.code === "EPIPE") {
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
reject(error);
|
|
109
|
-
});
|
|
110
|
-
child.stdin.end(options.stdin ?? undefined, "utf8");
|
|
111
|
-
});
|
|
37
|
+
return options.runtimeRoot ?? resolveWalletRuntimePathsForTesting().runtimeRoot;
|
|
112
38
|
}
|
|
113
39
|
export class MemoryWalletSecretProvider {
|
|
114
40
|
kind = "memory-test";
|
|
@@ -126,6 +52,39 @@ export class MemoryWalletSecretProvider {
|
|
|
126
52
|
async deleteSecret(keyId) {
|
|
127
53
|
this.#values.delete(keyId);
|
|
128
54
|
}
|
|
55
|
+
withPrompter(_prompter) {
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
async inspectClientPasswordReadiness() {
|
|
59
|
+
return "ready";
|
|
60
|
+
}
|
|
61
|
+
async ensureClientPasswordConfigured(_prompter) {
|
|
62
|
+
return "already-configured";
|
|
63
|
+
}
|
|
64
|
+
async unlockClientPasswordSession(_prompter) {
|
|
65
|
+
return {
|
|
66
|
+
unlocked: true,
|
|
67
|
+
unlockUntilUnixMs: null,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
async changeClientPassword(_prompter) {
|
|
71
|
+
return {
|
|
72
|
+
unlocked: true,
|
|
73
|
+
unlockUntilUnixMs: null,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
async lockClientPasswordSession() {
|
|
77
|
+
return {
|
|
78
|
+
unlocked: false,
|
|
79
|
+
unlockUntilUnixMs: null,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
async readClientPasswordSessionStatus() {
|
|
83
|
+
return {
|
|
84
|
+
unlocked: true,
|
|
85
|
+
unlockUntilUnixMs: null,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
129
88
|
}
|
|
130
89
|
class MacOsKeychainWalletSecretProvider {
|
|
131
90
|
kind = "macos-keychain";
|
|
@@ -167,234 +126,167 @@ class MacOsKeychainWalletSecretProvider {
|
|
|
167
126
|
]).catch(() => undefined);
|
|
168
127
|
}
|
|
169
128
|
}
|
|
170
|
-
class
|
|
171
|
-
kind
|
|
172
|
-
#
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
&& isLinuxSecretToolMissingSecretMessage(result.stderr)) {
|
|
189
|
-
throw createLinuxSecretToolError(`wallet_secret_missing_${options.keyId}`);
|
|
190
|
-
}
|
|
191
|
-
throw createLinuxSecretToolError("wallet_secret_provider_linux_runtime_error");
|
|
192
|
-
}
|
|
193
|
-
catch (error) {
|
|
194
|
-
if (error instanceof Error
|
|
195
|
-
&& (error.message === "wallet_secret_provider_linux_secret_tool_missing"
|
|
196
|
-
|| error.message === "wallet_secret_provider_linux_secret_service_unavailable"
|
|
197
|
-
|| error.message === "wallet_secret_provider_linux_runtime_error"
|
|
198
|
-
|| error.message === `wallet_secret_missing_${options.keyId}`)) {
|
|
199
|
-
throw error;
|
|
200
|
-
}
|
|
201
|
-
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
202
|
-
throw createLinuxSecretToolError("wallet_secret_provider_linux_secret_tool_missing", error);
|
|
203
|
-
}
|
|
204
|
-
throw createLinuxSecretToolError("wallet_secret_provider_linux_runtime_error", error);
|
|
205
|
-
}
|
|
129
|
+
class LocalFileWalletSecretProvider {
|
|
130
|
+
kind;
|
|
131
|
+
#stateRoot;
|
|
132
|
+
#directoryPath;
|
|
133
|
+
#platform;
|
|
134
|
+
#runtimeRoot;
|
|
135
|
+
#runtimeErrorCode;
|
|
136
|
+
#legacyMacKeychainReader;
|
|
137
|
+
#prompter;
|
|
138
|
+
constructor(options) {
|
|
139
|
+
this.kind = options.kind;
|
|
140
|
+
this.#stateRoot = options.stateRoot;
|
|
141
|
+
this.#directoryPath = options.directoryPath;
|
|
142
|
+
this.#platform = options.platform;
|
|
143
|
+
this.#runtimeRoot = options.runtimeRoot;
|
|
144
|
+
this.#runtimeErrorCode = options.runtimeErrorCode;
|
|
145
|
+
this.#legacyMacKeychainReader = options.legacyMacKeychainReader ?? null;
|
|
146
|
+
this.#prompter = options.prompter ?? null;
|
|
206
147
|
}
|
|
207
148
|
async loadSecret(keyId) {
|
|
208
|
-
|
|
209
|
-
|
|
149
|
+
return await loadClientProtectedSecret({
|
|
150
|
+
platform: this.#platform,
|
|
151
|
+
stateRoot: this.#stateRoot,
|
|
152
|
+
runtimeRoot: this.#runtimeRoot,
|
|
153
|
+
directoryPath: this.#directoryPath,
|
|
154
|
+
runtimeErrorCode: this.#runtimeErrorCode,
|
|
155
|
+
legacyMacKeychainReader: this.#legacyMacKeychainReader,
|
|
210
156
|
keyId,
|
|
211
|
-
|
|
157
|
+
prompt: this.#prompter ?? undefined,
|
|
212
158
|
});
|
|
213
|
-
return base64ToBytes(result.stdout.trim());
|
|
214
159
|
}
|
|
215
160
|
async storeSecret(keyId, secret) {
|
|
216
|
-
await
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
161
|
+
await storeClientProtectedSecret({
|
|
162
|
+
platform: this.#platform,
|
|
163
|
+
stateRoot: this.#stateRoot,
|
|
164
|
+
runtimeRoot: this.#runtimeRoot,
|
|
165
|
+
directoryPath: this.#directoryPath,
|
|
166
|
+
runtimeErrorCode: this.#runtimeErrorCode,
|
|
167
|
+
legacyMacKeychainReader: this.#legacyMacKeychainReader,
|
|
223
168
|
keyId,
|
|
224
|
-
|
|
225
|
-
|
|
169
|
+
secret,
|
|
170
|
+
prompt: this.#prompter ?? undefined,
|
|
226
171
|
});
|
|
227
172
|
}
|
|
228
173
|
async deleteSecret(keyId) {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
}
|
|
237
|
-
catch (error) {
|
|
238
|
-
if (error instanceof Error && error.message === `wallet_secret_missing_${keyId}`) {
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
throw error;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
class LinuxLocalFileWalletSecretProvider {
|
|
246
|
-
kind = "linux-local-file";
|
|
247
|
-
#directoryPath;
|
|
248
|
-
constructor(directoryPath) {
|
|
249
|
-
this.#directoryPath = directoryPath;
|
|
250
|
-
}
|
|
251
|
-
#resolveSecretPath(keyId) {
|
|
252
|
-
return join(this.#directoryPath, `${sanitizeSecretKeyId(keyId)}.secret`);
|
|
253
|
-
}
|
|
254
|
-
async hasSecret(keyId) {
|
|
255
|
-
try {
|
|
256
|
-
await access(this.#resolveSecretPath(keyId), constants.F_OK);
|
|
257
|
-
return true;
|
|
258
|
-
}
|
|
259
|
-
catch {
|
|
260
|
-
return false;
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
async loadSecret(keyId) {
|
|
264
|
-
try {
|
|
265
|
-
const encoded = await readFile(this.#resolveSecretPath(keyId), "utf8");
|
|
266
|
-
return base64ToBytes(encoded.trim());
|
|
267
|
-
}
|
|
268
|
-
catch (error) {
|
|
269
|
-
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
270
|
-
throw new Error(`wallet_secret_missing_${keyId}`);
|
|
271
|
-
}
|
|
272
|
-
throw createLinuxSecretToolError("wallet_secret_provider_linux_runtime_error", error);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
async storeSecret(keyId, secret) {
|
|
276
|
-
try {
|
|
277
|
-
await mkdir(this.#directoryPath, { recursive: true, mode: 0o700 });
|
|
278
|
-
await writeFileAtomic(this.#resolveSecretPath(keyId), `${bytesToBase64(secret)}\n`, { mode: 0o600 });
|
|
279
|
-
}
|
|
280
|
-
catch (error) {
|
|
281
|
-
throw createLinuxSecretToolError("wallet_secret_provider_linux_runtime_error", error);
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
async deleteSecret(keyId) {
|
|
285
|
-
await rm(this.#resolveSecretPath(keyId), { force: true }).catch(() => undefined);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
class LinuxFallbackWalletSecretProvider {
|
|
289
|
-
kind = "linux-secret-service-fallback";
|
|
290
|
-
#secretService;
|
|
291
|
-
#fileProvider;
|
|
292
|
-
constructor(options) {
|
|
293
|
-
this.#secretService = options.secretService;
|
|
294
|
-
this.#fileProvider = options.fileProvider;
|
|
295
|
-
}
|
|
296
|
-
async #loadFromFileOrRethrow(keyId, error) {
|
|
297
|
-
try {
|
|
298
|
-
return await this.#fileProvider.loadSecret(keyId);
|
|
299
|
-
}
|
|
300
|
-
catch (fileError) {
|
|
301
|
-
if (isWalletSecretProviderMessage(fileError, `wallet_secret_missing_${keyId}`)
|
|
302
|
-
&& (error.message === "wallet_secret_provider_linux_secret_tool_missing"
|
|
303
|
-
|| error.message === "wallet_secret_provider_linux_secret_service_unavailable")) {
|
|
304
|
-
throw error;
|
|
305
|
-
}
|
|
306
|
-
throw fileError;
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
async loadSecret(keyId) {
|
|
310
|
-
try {
|
|
311
|
-
return await this.#secretService.loadSecret(keyId);
|
|
312
|
-
}
|
|
313
|
-
catch (error) {
|
|
314
|
-
if (!(error instanceof Error)) {
|
|
315
|
-
throw error;
|
|
316
|
-
}
|
|
317
|
-
if (error.message === "wallet_secret_provider_linux_secret_tool_missing"
|
|
318
|
-
|| error.message === "wallet_secret_provider_linux_secret_service_unavailable"
|
|
319
|
-
|| error.message === `wallet_secret_missing_${keyId}`) {
|
|
320
|
-
return await this.#loadFromFileOrRethrow(keyId, error);
|
|
321
|
-
}
|
|
322
|
-
if (error.message === "wallet_secret_provider_linux_runtime_error"
|
|
323
|
-
&& await this.#fileProvider.hasSecret(keyId)) {
|
|
324
|
-
return await this.#fileProvider.loadSecret(keyId);
|
|
325
|
-
}
|
|
326
|
-
throw error;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
async storeSecret(keyId, secret) {
|
|
330
|
-
try {
|
|
331
|
-
await this.#secretService.storeSecret(keyId, secret);
|
|
332
|
-
}
|
|
333
|
-
catch (error) {
|
|
334
|
-
if (isWalletSecretProviderMessage(error, "wallet_secret_provider_linux_secret_tool_missing")
|
|
335
|
-
|| isWalletSecretProviderMessage(error, "wallet_secret_provider_linux_secret_service_unavailable")) {
|
|
336
|
-
await this.#fileProvider.storeSecret(keyId, secret);
|
|
337
|
-
return;
|
|
338
|
-
}
|
|
339
|
-
throw error;
|
|
340
|
-
}
|
|
174
|
+
await deleteClientProtectedSecret({
|
|
175
|
+
platform: this.#platform,
|
|
176
|
+
stateRoot: this.#stateRoot,
|
|
177
|
+
runtimeRoot: this.#runtimeRoot,
|
|
178
|
+
directoryPath: this.#directoryPath,
|
|
179
|
+
runtimeErrorCode: this.#runtimeErrorCode,
|
|
180
|
+
keyId,
|
|
181
|
+
});
|
|
341
182
|
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
this.#
|
|
345
|
-
this.#
|
|
346
|
-
|
|
183
|
+
withPrompter(prompter) {
|
|
184
|
+
return new LocalFileWalletSecretProvider({
|
|
185
|
+
stateRoot: this.#stateRoot,
|
|
186
|
+
directoryPath: this.#directoryPath,
|
|
187
|
+
kind: this.kind,
|
|
188
|
+
platform: this.#platform,
|
|
189
|
+
runtimeRoot: this.#runtimeRoot,
|
|
190
|
+
runtimeErrorCode: this.#runtimeErrorCode,
|
|
191
|
+
legacyMacKeychainReader: this.#legacyMacKeychainReader,
|
|
192
|
+
prompter,
|
|
193
|
+
});
|
|
347
194
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
195
|
+
async inspectClientPasswordReadiness() {
|
|
196
|
+
return await inspectClientPasswordReadiness({
|
|
197
|
+
platform: this.#platform,
|
|
198
|
+
stateRoot: this.#stateRoot,
|
|
199
|
+
runtimeRoot: this.#runtimeRoot,
|
|
200
|
+
directoryPath: this.#directoryPath,
|
|
201
|
+
runtimeErrorCode: this.#runtimeErrorCode,
|
|
202
|
+
legacyMacKeychainReader: this.#legacyMacKeychainReader,
|
|
203
|
+
});
|
|
354
204
|
}
|
|
355
|
-
|
|
356
|
-
const
|
|
357
|
-
|
|
205
|
+
async ensureClientPasswordConfigured(prompter) {
|
|
206
|
+
const result = await ensureClientPasswordConfiguredWithLocalFile({
|
|
207
|
+
platform: this.#platform,
|
|
208
|
+
stateRoot: this.#stateRoot,
|
|
209
|
+
runtimeRoot: this.#runtimeRoot,
|
|
210
|
+
directoryPath: this.#directoryPath,
|
|
211
|
+
runtimeErrorCode: this.#runtimeErrorCode,
|
|
212
|
+
legacyMacKeychainReader: this.#legacyMacKeychainReader,
|
|
213
|
+
prompt: prompter,
|
|
214
|
+
});
|
|
215
|
+
return result.action;
|
|
216
|
+
}
|
|
217
|
+
async unlockClientPasswordSession(prompter) {
|
|
218
|
+
return await unlockClientPasswordSessionWithLocalFile({
|
|
219
|
+
platform: this.#platform,
|
|
220
|
+
stateRoot: this.#stateRoot,
|
|
221
|
+
runtimeRoot: this.#runtimeRoot,
|
|
222
|
+
directoryPath: this.#directoryPath,
|
|
223
|
+
runtimeErrorCode: this.#runtimeErrorCode,
|
|
224
|
+
legacyMacKeychainReader: this.#legacyMacKeychainReader,
|
|
225
|
+
prompt: prompter,
|
|
226
|
+
});
|
|
358
227
|
}
|
|
359
|
-
async
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
return base64ToBytes(stdout.trim());
|
|
228
|
+
async changeClientPassword(prompter) {
|
|
229
|
+
return await changeClientPasswordWithLocalFile({
|
|
230
|
+
platform: this.#platform,
|
|
231
|
+
stateRoot: this.#stateRoot,
|
|
232
|
+
runtimeRoot: this.#runtimeRoot,
|
|
233
|
+
directoryPath: this.#directoryPath,
|
|
234
|
+
runtimeErrorCode: this.#runtimeErrorCode,
|
|
235
|
+
legacyMacKeychainReader: this.#legacyMacKeychainReader,
|
|
236
|
+
prompt: prompter,
|
|
237
|
+
});
|
|
370
238
|
}
|
|
371
|
-
async
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
]);
|
|
381
|
-
await writeFileAtomic(secretPath, `${stdout.trim()}\n`, { mode: 0o600 });
|
|
239
|
+
async lockClientPasswordSession() {
|
|
240
|
+
return await lockClientPasswordSession({
|
|
241
|
+
platform: this.#platform,
|
|
242
|
+
stateRoot: this.#stateRoot,
|
|
243
|
+
runtimeRoot: this.#runtimeRoot,
|
|
244
|
+
directoryPath: this.#directoryPath,
|
|
245
|
+
runtimeErrorCode: this.#runtimeErrorCode,
|
|
246
|
+
legacyMacKeychainReader: this.#legacyMacKeychainReader,
|
|
247
|
+
});
|
|
382
248
|
}
|
|
383
|
-
async
|
|
384
|
-
await
|
|
249
|
+
async readClientPasswordSessionStatus() {
|
|
250
|
+
return await readClientPasswordSessionStatus({
|
|
251
|
+
platform: this.#platform,
|
|
252
|
+
stateRoot: this.#stateRoot,
|
|
253
|
+
runtimeRoot: this.#runtimeRoot,
|
|
254
|
+
directoryPath: this.#directoryPath,
|
|
255
|
+
runtimeErrorCode: this.#runtimeErrorCode,
|
|
256
|
+
legacyMacKeychainReader: this.#legacyMacKeychainReader,
|
|
257
|
+
});
|
|
385
258
|
}
|
|
386
259
|
}
|
|
387
260
|
function createWalletSecretProviderForPlatform(platform, options = {}) {
|
|
388
|
-
if (platform === "darwin") {
|
|
389
|
-
return new MacOsKeychainWalletSecretProvider();
|
|
390
|
-
}
|
|
391
261
|
if (platform === "win32") {
|
|
392
|
-
return new
|
|
262
|
+
return new LocalFileWalletSecretProvider({
|
|
263
|
+
stateRoot: options.stateRoot ?? resolveWalletRuntimePathsForTesting().stateRoot,
|
|
264
|
+
directoryPath: resolveSecretDirectoryPath(options),
|
|
265
|
+
kind: "windows-local-file",
|
|
266
|
+
platform,
|
|
267
|
+
runtimeRoot: resolveRuntimeRootPath(options),
|
|
268
|
+
runtimeErrorCode: "wallet_secret_provider_windows_runtime_error",
|
|
269
|
+
});
|
|
393
270
|
}
|
|
394
271
|
if (platform === "linux") {
|
|
395
|
-
return new
|
|
396
|
-
|
|
397
|
-
|
|
272
|
+
return new LocalFileWalletSecretProvider({
|
|
273
|
+
stateRoot: options.stateRoot ?? resolveWalletRuntimePathsForTesting().stateRoot,
|
|
274
|
+
directoryPath: resolveSecretDirectoryPath(options),
|
|
275
|
+
kind: "linux-local-file",
|
|
276
|
+
platform,
|
|
277
|
+
runtimeRoot: resolveRuntimeRootPath(options),
|
|
278
|
+
runtimeErrorCode: "wallet_secret_provider_linux_runtime_error",
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
if (platform === "darwin") {
|
|
282
|
+
return new LocalFileWalletSecretProvider({
|
|
283
|
+
stateRoot: options.stateRoot ?? resolveWalletRuntimePathsForTesting().stateRoot,
|
|
284
|
+
directoryPath: resolveSecretDirectoryPath(options),
|
|
285
|
+
kind: "macos-local-file",
|
|
286
|
+
platform,
|
|
287
|
+
runtimeRoot: resolveRuntimeRootPath(options),
|
|
288
|
+
runtimeErrorCode: "wallet_secret_provider_macos_runtime_error",
|
|
289
|
+
legacyMacKeychainReader: new MacOsKeychainWalletSecretProvider(),
|
|
398
290
|
});
|
|
399
291
|
}
|
|
400
292
|
throw new Error(`wallet_secret_provider_unsupported_${platform}`);
|
|
@@ -424,11 +316,77 @@ export function createLazyDefaultWalletSecretProvider() {
|
|
|
424
316
|
async deleteSecret(keyId) {
|
|
425
317
|
await getResolved().deleteSecret(keyId);
|
|
426
318
|
},
|
|
319
|
+
withPrompter(prompter) {
|
|
320
|
+
return getResolved().withPrompter?.(prompter) ?? getResolved();
|
|
321
|
+
},
|
|
322
|
+
async inspectClientPasswordReadiness() {
|
|
323
|
+
return await getResolved().inspectClientPasswordReadiness?.() ?? "ready";
|
|
324
|
+
},
|
|
325
|
+
async ensureClientPasswordConfigured(prompter) {
|
|
326
|
+
return await getResolved().ensureClientPasswordConfigured?.(prompter) ?? "already-configured";
|
|
327
|
+
},
|
|
328
|
+
async unlockClientPasswordSession(prompter) {
|
|
329
|
+
return await getResolved().unlockClientPasswordSession?.(prompter) ?? {
|
|
330
|
+
unlocked: true,
|
|
331
|
+
unlockUntilUnixMs: null,
|
|
332
|
+
};
|
|
333
|
+
},
|
|
334
|
+
async changeClientPassword(prompter) {
|
|
335
|
+
return await getResolved().changeClientPassword?.(prompter) ?? {
|
|
336
|
+
unlocked: true,
|
|
337
|
+
unlockUntilUnixMs: null,
|
|
338
|
+
};
|
|
339
|
+
},
|
|
340
|
+
async lockClientPasswordSession() {
|
|
341
|
+
return await getResolved().lockClientPasswordSession?.() ?? {
|
|
342
|
+
unlocked: false,
|
|
343
|
+
unlockUntilUnixMs: null,
|
|
344
|
+
};
|
|
345
|
+
},
|
|
346
|
+
async readClientPasswordSessionStatus() {
|
|
347
|
+
return await getResolved().readClientPasswordSessionStatus?.() ?? {
|
|
348
|
+
unlocked: true,
|
|
349
|
+
unlockUntilUnixMs: null,
|
|
350
|
+
};
|
|
351
|
+
},
|
|
427
352
|
};
|
|
428
353
|
}
|
|
429
354
|
export function createMemoryWalletSecretProviderForTesting() {
|
|
430
355
|
return new MemoryWalletSecretProvider();
|
|
431
356
|
}
|
|
357
|
+
export function withInteractiveWalletSecretProvider(provider, prompter) {
|
|
358
|
+
return provider.withPrompter?.(prompter) ?? provider;
|
|
359
|
+
}
|
|
360
|
+
export async function ensureClientPasswordConfigured(provider, prompter) {
|
|
361
|
+
return await provider.ensureClientPasswordConfigured?.(prompter) ?? "already-configured";
|
|
362
|
+
}
|
|
363
|
+
export async function inspectClientPasswordSetupReadiness(provider) {
|
|
364
|
+
return await provider.inspectClientPasswordReadiness?.() ?? "ready";
|
|
365
|
+
}
|
|
366
|
+
export async function unlockClientPassword(provider, prompter) {
|
|
367
|
+
return await provider.unlockClientPasswordSession?.(prompter) ?? {
|
|
368
|
+
unlocked: true,
|
|
369
|
+
unlockUntilUnixMs: null,
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
export async function changeClientPassword(provider, prompter) {
|
|
373
|
+
return await provider.changeClientPassword?.(prompter) ?? {
|
|
374
|
+
unlocked: true,
|
|
375
|
+
unlockUntilUnixMs: null,
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
export async function lockClientPassword(provider) {
|
|
379
|
+
return await provider.lockClientPasswordSession?.() ?? {
|
|
380
|
+
unlocked: false,
|
|
381
|
+
unlockUntilUnixMs: null,
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
export async function readClientPasswordStatus(provider) {
|
|
385
|
+
return await provider.readClientPasswordSessionStatus?.() ?? {
|
|
386
|
+
unlocked: true,
|
|
387
|
+
unlockUntilUnixMs: null,
|
|
388
|
+
};
|
|
389
|
+
}
|
|
432
390
|
export function createWalletRootId() {
|
|
433
391
|
return `wallet-${randomUUID().replaceAll("-", "")}`;
|
|
434
392
|
}
|
|
@@ -12,11 +12,11 @@ export interface RawWalletStateEnvelope {
|
|
|
12
12
|
source: "primary" | "backup";
|
|
13
13
|
envelope: EncryptedEnvelopeV1;
|
|
14
14
|
}
|
|
15
|
-
export type WalletStateSaveAccess =
|
|
15
|
+
export type WalletStateSaveAccess = {
|
|
16
16
|
provider: WalletSecretProvider;
|
|
17
17
|
secretReference: WalletSecretReference;
|
|
18
18
|
};
|
|
19
|
-
export type WalletStateLoadAccess =
|
|
19
|
+
export type WalletStateLoadAccess = {
|
|
20
20
|
provider: WalletSecretProvider;
|
|
21
21
|
};
|
|
22
22
|
export declare function loadRawWalletStateEnvelope(paths: WalletStateStoragePaths): Promise<RawWalletStateEnvelope | null>;
|