@candledottv/cli 0.4.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/LICENSE +21 -0
- package/README.md +139 -0
- package/dist/index.js +4741 -0
- package/package.json +46 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,4741 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
4
|
+
|
|
5
|
+
// src/index.ts
|
|
6
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
7
|
+
import { realpathSync } from "node:fs";
|
|
8
|
+
import { readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
|
|
9
|
+
import { hostname } from "node:os";
|
|
10
|
+
import { pathToFileURL } from "node:url";
|
|
11
|
+
|
|
12
|
+
// src/client.ts
|
|
13
|
+
var DEFAULT_API_URL = "https://api.alpha.candle.tv";
|
|
14
|
+
function trimTrailingSlashes(url) {
|
|
15
|
+
return url.trim().replace(/\/+$/, "");
|
|
16
|
+
}
|
|
17
|
+
function resolveApiUrl(configuredApiUrl, env = process.env) {
|
|
18
|
+
const fromEnv = env.CANDLE_API_URL?.trim();
|
|
19
|
+
const resolved = fromEnv || configuredApiUrl?.trim() || DEFAULT_API_URL;
|
|
20
|
+
return trimTrailingSlashes(resolved);
|
|
21
|
+
}
|
|
22
|
+
function buildHeaders(opts) {
|
|
23
|
+
const headers = { "content-type": "application/json", accept: "application/json" };
|
|
24
|
+
if (opts.auth === "device" && opts.credentials.deviceToken) {
|
|
25
|
+
headers.authorization = `Bearer ${opts.credentials.deviceToken}`;
|
|
26
|
+
} else if (opts.auth === "key" && opts.credentials.apiKey) {
|
|
27
|
+
headers["x-api-key"] = opts.credentials.apiKey;
|
|
28
|
+
}
|
|
29
|
+
return headers;
|
|
30
|
+
}
|
|
31
|
+
function buildUrl(apiUrl, path) {
|
|
32
|
+
const base = trimTrailingSlashes(apiUrl);
|
|
33
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
34
|
+
return `${base}${normalizedPath}`;
|
|
35
|
+
}
|
|
36
|
+
function parseBody(text) {
|
|
37
|
+
if (text.length === 0)
|
|
38
|
+
return;
|
|
39
|
+
try {
|
|
40
|
+
return JSON.parse(text);
|
|
41
|
+
} catch {
|
|
42
|
+
return text;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function classifyError(status, raw) {
|
|
46
|
+
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
47
|
+
const obj = raw;
|
|
48
|
+
if (typeof obj.error === "string") {
|
|
49
|
+
const description = typeof obj.error_description === "string" ? obj.error_description : obj.error;
|
|
50
|
+
return { rfcError: obj.error, message: description };
|
|
51
|
+
}
|
|
52
|
+
if (obj.error && typeof obj.error === "object") {
|
|
53
|
+
const errorObj = obj.error;
|
|
54
|
+
const code = typeof errorObj.code === "string" ? errorObj.code : undefined;
|
|
55
|
+
const message = typeof errorObj.message === "string" ? errorObj.message : `Request failed with status ${status}`;
|
|
56
|
+
const uiHint = typeof errorObj.uiHint === "string" ? errorObj.uiHint : undefined;
|
|
57
|
+
const docsPath = typeof errorObj.docsPath === "string" ? errorObj.docsPath : undefined;
|
|
58
|
+
return { code, message, ...uiHint ? { uiHint } : {}, ...docsPath ? { docsPath } : {} };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return { message: `Request failed with status ${status}` };
|
|
62
|
+
}
|
|
63
|
+
async function apiRequest(path, opts) {
|
|
64
|
+
const url = buildUrl(opts.apiUrl, path);
|
|
65
|
+
const headers = buildHeaders(opts);
|
|
66
|
+
const body = opts.body === undefined ? undefined : JSON.stringify(opts.body);
|
|
67
|
+
const doFetch = opts.fetch ?? fetch;
|
|
68
|
+
let response;
|
|
69
|
+
try {
|
|
70
|
+
response = await doFetch(url, {
|
|
71
|
+
method: opts.method ?? "GET",
|
|
72
|
+
headers,
|
|
73
|
+
body
|
|
74
|
+
});
|
|
75
|
+
} catch (err) {
|
|
76
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
77
|
+
const env = opts.env ?? process.env;
|
|
78
|
+
const envOverride = env.CANDLE_API_URL?.trim();
|
|
79
|
+
return {
|
|
80
|
+
ok: false,
|
|
81
|
+
status: 0,
|
|
82
|
+
message: `Could not reach ${url}: ${reason} (set CANDLE_API_URL to override; ${envOverride ? `currently "${envOverride}"` : "currently unset"})`,
|
|
83
|
+
raw: undefined
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const text = await response.text();
|
|
87
|
+
const raw = parseBody(text);
|
|
88
|
+
if (response.ok) {
|
|
89
|
+
return { ok: true, status: response.status, body: raw };
|
|
90
|
+
}
|
|
91
|
+
const classified = classifyError(response.status, raw);
|
|
92
|
+
return { ok: false, status: response.status, raw, ...classified };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// src/commands/auth.ts
|
|
96
|
+
import { homedir as homedir2 } from "node:os";
|
|
97
|
+
import { join as join2 } from "node:path";
|
|
98
|
+
|
|
99
|
+
// src/args.ts
|
|
100
|
+
function parseArgs(args, spec) {
|
|
101
|
+
const valueFlags = new Set(spec.valueFlags ?? []);
|
|
102
|
+
const booleanFlags = new Set(spec.booleanFlags ?? []);
|
|
103
|
+
const values = {};
|
|
104
|
+
const booleans = new Set;
|
|
105
|
+
const positionals = [];
|
|
106
|
+
for (let i = 0;i < args.length; i++) {
|
|
107
|
+
const arg = args[i];
|
|
108
|
+
if (arg === undefined)
|
|
109
|
+
continue;
|
|
110
|
+
if (valueFlags.has(arg)) {
|
|
111
|
+
const value = args[++i];
|
|
112
|
+
if (!value || value.startsWith("-"))
|
|
113
|
+
return { error: `${arg} requires a value` };
|
|
114
|
+
values[arg] = value;
|
|
115
|
+
} else if (booleanFlags.has(arg)) {
|
|
116
|
+
booleans.add(arg);
|
|
117
|
+
} else if (arg.startsWith("-")) {
|
|
118
|
+
return { error: `Unknown flag: ${arg}` };
|
|
119
|
+
} else {
|
|
120
|
+
positionals.push(arg);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return { values, booleans, positionals };
|
|
124
|
+
}
|
|
125
|
+
function parseScopesList(raw) {
|
|
126
|
+
return raw.split(",").map((scope) => scope.trim()).filter(Boolean);
|
|
127
|
+
}
|
|
128
|
+
function parseUsdToMicros(raw) {
|
|
129
|
+
const cleaned = raw.trim().replace(/^\$/, "").replace(/,/g, "");
|
|
130
|
+
if (cleaned.length === 0)
|
|
131
|
+
return { ok: false, message: "--tx-limit requires a dollar amount, for example 100." };
|
|
132
|
+
const usd = Number(cleaned);
|
|
133
|
+
if (!Number.isFinite(usd))
|
|
134
|
+
return { ok: false, message: `--tx-limit is not a dollar amount: ${raw}` };
|
|
135
|
+
const usdMicros = Math.round(usd * 1e6);
|
|
136
|
+
if (usdMicros <= 0)
|
|
137
|
+
return { ok: false, message: "--tx-limit must be greater than $0." };
|
|
138
|
+
return { ok: true, usdMicros };
|
|
139
|
+
}
|
|
140
|
+
var TX_LIMIT_RESETS = ["daily", "weekly", "monthly", "never"];
|
|
141
|
+
function parseExpiresInDays(raw) {
|
|
142
|
+
const days = Number(raw.trim());
|
|
143
|
+
if (!Number.isInteger(days) || days <= 0) {
|
|
144
|
+
return { ok: false, message: `--expires-in must be a positive whole number of days, got: ${raw}` };
|
|
145
|
+
}
|
|
146
|
+
return { ok: true, days };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// src/render.ts
|
|
150
|
+
var ALL_AGENT_SCOPES = [
|
|
151
|
+
"launch:write",
|
|
152
|
+
"launch:read",
|
|
153
|
+
"activity:write",
|
|
154
|
+
"swap:write",
|
|
155
|
+
"transfer:write"
|
|
156
|
+
];
|
|
157
|
+
var DEFAULT_AGENT_SCOPES = ALL_AGENT_SCOPES.filter((scope) => scope !== "swap:write" && scope !== "transfer:write");
|
|
158
|
+
var SWAP_WRITE_NOTE = "moves funds -- this key can execute swaps on your behalf";
|
|
159
|
+
var TRANSFER_WRITE_NOTE = "moves funds -- this key can transfer assets between your wallets";
|
|
160
|
+
function formatScopesForSummary(scopes) {
|
|
161
|
+
return scopes.map((scope) => scope === "swap:write" ? `${scope} (${SWAP_WRITE_NOTE})` : scope === "transfer:write" ? `${scope} (${TRANSFER_WRITE_NOTE})` : scope).join(", ");
|
|
162
|
+
}
|
|
163
|
+
function renderTable(headers, rows) {
|
|
164
|
+
const widths = headers.map((header, col) => Math.max(header.length, ...rows.map((row) => (row[col] ?? "").length)));
|
|
165
|
+
const line = (cells) => cells.map((cell, col) => col === cells.length - 1 ? cell ?? "" : (cell ?? "").padEnd(widths[col] ?? 0)).join(" ");
|
|
166
|
+
const separator = widths.map((width) => "-".repeat(width)).join(" ");
|
|
167
|
+
return [line(headers), separator, ...rows.map(line)].join(`
|
|
168
|
+
`);
|
|
169
|
+
}
|
|
170
|
+
function formatTimestamp(ms, whenAbsent = "never") {
|
|
171
|
+
return ms === undefined ? whenAbsent : new Date(ms).toISOString();
|
|
172
|
+
}
|
|
173
|
+
function renderError(result, ctx) {
|
|
174
|
+
if (result.code === "DEVICE_TOKEN_INVALID") {
|
|
175
|
+
return "This device was revoked or its token is stale. Run: candle auth login";
|
|
176
|
+
}
|
|
177
|
+
if (result.status === 403 && result.code === "SCOPE_MISSING") {
|
|
178
|
+
return `${result.message}. Mint one that has it with: candle keys create --scopes <a,b,c>, or check an existing key's scopes with: candle keys list`;
|
|
179
|
+
}
|
|
180
|
+
if (result.status === 401 && ctx.authType === "key") {
|
|
181
|
+
return "API key invalid or revoked. Run: candle keys create";
|
|
182
|
+
}
|
|
183
|
+
if (result.status === 0) {
|
|
184
|
+
return `Could not reach ${ctx.apiUrl}. Set CANDLE_API_URL to override the API endpoint.`;
|
|
185
|
+
}
|
|
186
|
+
return result.message;
|
|
187
|
+
}
|
|
188
|
+
function suggestionFor(result, ctx) {
|
|
189
|
+
if (result.code === "DEVICE_TOKEN_INVALID")
|
|
190
|
+
return "Run: candle auth login";
|
|
191
|
+
if (result.status === 403 && result.code === "SCOPE_MISSING") {
|
|
192
|
+
return "Mint a key that has it: candle keys create --scopes <a,b,c>, or check an existing key's scopes: candle keys list";
|
|
193
|
+
}
|
|
194
|
+
if (result.status === 401 && ctx.authType === "key")
|
|
195
|
+
return "Run: candle keys create";
|
|
196
|
+
if (result.status === 0)
|
|
197
|
+
return "Set CANDLE_API_URL to override the API endpoint.";
|
|
198
|
+
return result.uiHint;
|
|
199
|
+
}
|
|
200
|
+
function errorEnvelope(result, ctx) {
|
|
201
|
+
const code = result.code ?? result.rfcError ?? (result.status === 0 ? "NETWORK_UNREACHABLE" : `HTTP_${result.status}`);
|
|
202
|
+
const message = result.status === 0 ? `Could not reach ${ctx.apiUrl}.` : result.message;
|
|
203
|
+
const suggestion = suggestionFor(result, ctx);
|
|
204
|
+
const docsUrl = result.docsPath ? `https://docs.candle.tv/${result.docsPath}` : undefined;
|
|
205
|
+
return {
|
|
206
|
+
ok: false,
|
|
207
|
+
code,
|
|
208
|
+
status: result.status,
|
|
209
|
+
message,
|
|
210
|
+
...suggestion ? { suggestion } : {},
|
|
211
|
+
...docsUrl ? { docsUrl } : {}
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
function writeFailure(deps, result, ctx, json) {
|
|
215
|
+
if (json)
|
|
216
|
+
deps.stdout.write(`${JSON.stringify(errorEnvelope(result, ctx))}
|
|
217
|
+
`);
|
|
218
|
+
else
|
|
219
|
+
deps.stderr.write(`${renderError(result, ctx)}
|
|
220
|
+
`);
|
|
221
|
+
}
|
|
222
|
+
function writeLocalFailure(deps, failure, json) {
|
|
223
|
+
if (json)
|
|
224
|
+
deps.stdout.write(`${JSON.stringify({ ok: false, ...failure })}
|
|
225
|
+
`);
|
|
226
|
+
else
|
|
227
|
+
deps.stderr.write(`${failure.suggestion ? `${failure.message} ${failure.suggestion}` : failure.message}
|
|
228
|
+
`);
|
|
229
|
+
}
|
|
230
|
+
function writeUsageFailure(deps, message, json) {
|
|
231
|
+
if (json)
|
|
232
|
+
deps.stdout.write(`${JSON.stringify({ ok: false, code: "USAGE", message })}
|
|
233
|
+
`);
|
|
234
|
+
else
|
|
235
|
+
deps.stderr.write(`${message}
|
|
236
|
+
`);
|
|
237
|
+
}
|
|
238
|
+
function portalDeviceUrl(apiUrl, portalOrigin) {
|
|
239
|
+
if (portalOrigin) {
|
|
240
|
+
try {
|
|
241
|
+
return `${new URL(portalOrigin).origin}/dev/agent`;
|
|
242
|
+
} catch {}
|
|
243
|
+
}
|
|
244
|
+
try {
|
|
245
|
+
const url = new URL(apiUrl);
|
|
246
|
+
const labels = url.hostname.split(".");
|
|
247
|
+
const apiLabel = labels.indexOf("api");
|
|
248
|
+
if (apiLabel !== -1 && labels.length > 1) {
|
|
249
|
+
labels.splice(apiLabel, 1);
|
|
250
|
+
url.hostname = labels.join(".");
|
|
251
|
+
}
|
|
252
|
+
return `${url.origin}/dev/agent`;
|
|
253
|
+
} catch {
|
|
254
|
+
return `${apiUrl}/dev/agent`;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// src/checks.ts
|
|
259
|
+
async function runLiveCheck(params) {
|
|
260
|
+
const { deps, apiUrl, path, auth, credential, check, passDetail } = params;
|
|
261
|
+
const result = await apiRequest(path, {
|
|
262
|
+
auth,
|
|
263
|
+
credentials: auth === "device" ? { deviceToken: credential } : { apiKey: credential },
|
|
264
|
+
apiUrl,
|
|
265
|
+
fetch: deps.fetch,
|
|
266
|
+
env: deps.env
|
|
267
|
+
});
|
|
268
|
+
return result.ok ? { check, state: "PASS", detail: passDetail } : { check, state: "FAIL", detail: renderError(result, { apiUrl, authType: auth }) };
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// src/secret-store.ts
|
|
272
|
+
import { chmod, mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
273
|
+
import { homedir } from "node:os";
|
|
274
|
+
import { dirname, join } from "node:path";
|
|
275
|
+
var SECRET_REFS = {
|
|
276
|
+
deviceToken: "device_token",
|
|
277
|
+
apiKey: "api_key"
|
|
278
|
+
};
|
|
279
|
+
function walletSignerRef(walletId) {
|
|
280
|
+
return `wallet_signer_${walletId}`;
|
|
281
|
+
}
|
|
282
|
+
function pemToStoredSigner(pem) {
|
|
283
|
+
return pem.replace(/-----BEGIN PRIVATE KEY-----/, "").replace(/-----END PRIVATE KEY-----/, "").replace(/\s+/g, "");
|
|
284
|
+
}
|
|
285
|
+
function configDir() {
|
|
286
|
+
return process.env.CANDLE_CONFIG_DIR?.trim() || join(homedir(), ".config", "candle");
|
|
287
|
+
}
|
|
288
|
+
function defaultCredentialsPath() {
|
|
289
|
+
return join(configDir(), "credentials.enc");
|
|
290
|
+
}
|
|
291
|
+
var PBKDF2_ITERATIONS = 210000;
|
|
292
|
+
var SALT_LENGTH_BYTES = 16;
|
|
293
|
+
var IV_LENGTH_BYTES = 12;
|
|
294
|
+
async function deriveKey(passphrase, salt, iterations) {
|
|
295
|
+
const keyMaterial = await crypto.subtle.importKey("raw", new TextEncoder().encode(passphrase), "PBKDF2", false, [
|
|
296
|
+
"deriveKey"
|
|
297
|
+
]);
|
|
298
|
+
return crypto.subtle.deriveKey({ name: "PBKDF2", salt, iterations, hash: "SHA-256" }, keyMaterial, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"]);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
class EncryptedFileSecretStore {
|
|
302
|
+
path;
|
|
303
|
+
iterations;
|
|
304
|
+
cachedPassphrase;
|
|
305
|
+
constructor(options = {}) {
|
|
306
|
+
this.path = options.path ?? defaultCredentialsPath();
|
|
307
|
+
this.iterations = options.iterations ?? PBKDF2_ITERATIONS;
|
|
308
|
+
}
|
|
309
|
+
async get(ref) {
|
|
310
|
+
const passphrase = await this.resolvePassphrase();
|
|
311
|
+
const contents = await this.readContents();
|
|
312
|
+
const entry = contents[ref];
|
|
313
|
+
if (!entry)
|
|
314
|
+
return null;
|
|
315
|
+
const salt = fromBase64(entry.salt);
|
|
316
|
+
const key = await deriveKey(passphrase, salt, entry.iterations);
|
|
317
|
+
const iv = fromBase64(entry.iv);
|
|
318
|
+
const ciphertext = fromBase64(entry.ciphertext);
|
|
319
|
+
let plaintext;
|
|
320
|
+
try {
|
|
321
|
+
plaintext = await crypto.subtle.decrypt({ name: "AES-GCM", iv }, key, ciphertext);
|
|
322
|
+
} catch {
|
|
323
|
+
throw new Error(`Could not decrypt the credential for "${ref}" in ${this.path}. CANDLE_KEYRING_PASSPHRASE is likely wrong for this file.`);
|
|
324
|
+
}
|
|
325
|
+
return new TextDecoder().decode(plaintext);
|
|
326
|
+
}
|
|
327
|
+
async set(ref, value) {
|
|
328
|
+
const passphrase = await this.resolvePassphrase();
|
|
329
|
+
const contents = await this.readContents();
|
|
330
|
+
const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH_BYTES));
|
|
331
|
+
const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH_BYTES));
|
|
332
|
+
const key = await deriveKey(passphrase, salt, this.iterations);
|
|
333
|
+
const ciphertext = await crypto.subtle.encrypt({ name: "AES-GCM", iv }, key, new TextEncoder().encode(value));
|
|
334
|
+
contents[ref] = {
|
|
335
|
+
salt: toBase64(salt),
|
|
336
|
+
iv: toBase64(iv),
|
|
337
|
+
ciphertext: toBase64(new Uint8Array(ciphertext)),
|
|
338
|
+
iterations: this.iterations
|
|
339
|
+
};
|
|
340
|
+
await this.writeContents(contents);
|
|
341
|
+
}
|
|
342
|
+
async delete(ref) {
|
|
343
|
+
await this.resolvePassphrase();
|
|
344
|
+
const contents = await this.readContents();
|
|
345
|
+
if (!(ref in contents))
|
|
346
|
+
return;
|
|
347
|
+
delete contents[ref];
|
|
348
|
+
await this.writeContents(contents);
|
|
349
|
+
}
|
|
350
|
+
async resolvePassphrase() {
|
|
351
|
+
if (this.cachedPassphrase !== undefined)
|
|
352
|
+
return this.cachedPassphrase;
|
|
353
|
+
const fromEnv = process.env.CANDLE_KEYRING_PASSPHRASE;
|
|
354
|
+
if (fromEnv) {
|
|
355
|
+
this.cachedPassphrase = fromEnv;
|
|
356
|
+
return fromEnv;
|
|
357
|
+
}
|
|
358
|
+
if (process.stdin.isTTY) {
|
|
359
|
+
const prompted = await promptHiddenPassphrase("Passphrase for Candle credential store: ");
|
|
360
|
+
this.cachedPassphrase = prompted;
|
|
361
|
+
return prompted;
|
|
362
|
+
}
|
|
363
|
+
throw new Error("No keychain available and no CANDLE_KEYRING_PASSPHRASE set; set it to use the encrypted file store on this machine");
|
|
364
|
+
}
|
|
365
|
+
async readContents() {
|
|
366
|
+
let raw;
|
|
367
|
+
try {
|
|
368
|
+
raw = await readFile(this.path, "utf8");
|
|
369
|
+
} catch (err) {
|
|
370
|
+
if (err.code === "ENOENT")
|
|
371
|
+
return {};
|
|
372
|
+
throw err;
|
|
373
|
+
}
|
|
374
|
+
try {
|
|
375
|
+
return JSON.parse(raw);
|
|
376
|
+
} catch {
|
|
377
|
+
throw new Error(`The credentials file at ${this.path} is not valid JSON and cannot be read. Delete it and re-run ` + "the command that stores your device token / API key to recreate it.");
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
async writeContents(contents) {
|
|
381
|
+
const dir = dirname(this.path);
|
|
382
|
+
await mkdir(dir, { recursive: true });
|
|
383
|
+
await chmod(dir, 448);
|
|
384
|
+
const tmpPath = `${this.path}.tmp`;
|
|
385
|
+
await writeFile(tmpPath, JSON.stringify(contents, null, 2), { encoding: "utf8", mode: 384 });
|
|
386
|
+
await chmod(tmpPath, 384);
|
|
387
|
+
await rename(tmpPath, this.path);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
async function promptHiddenSecret(promptText) {
|
|
391
|
+
if (!process.stdin.isTTY) {
|
|
392
|
+
throw new Error("No TTY available for interactive input; pass --key-file instead");
|
|
393
|
+
}
|
|
394
|
+
return promptHiddenPassphrase(promptText);
|
|
395
|
+
}
|
|
396
|
+
async function promptHiddenPassphrase(promptText) {
|
|
397
|
+
const readline = await import("node:readline");
|
|
398
|
+
return new Promise((resolve) => {
|
|
399
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: true });
|
|
400
|
+
const rlInternals = rl;
|
|
401
|
+
rlInternals._writeToOutput = (text) => {
|
|
402
|
+
if (text === promptText)
|
|
403
|
+
process.stdout.write(text);
|
|
404
|
+
};
|
|
405
|
+
rl.question(promptText, (answer) => {
|
|
406
|
+
rl.close();
|
|
407
|
+
process.stdout.write(`
|
|
408
|
+
`);
|
|
409
|
+
resolve(answer);
|
|
410
|
+
});
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
function toBase64(bytes) {
|
|
414
|
+
return Buffer.from(bytes).toString("base64");
|
|
415
|
+
}
|
|
416
|
+
function fromBase64(base64) {
|
|
417
|
+
return new Uint8Array(Buffer.from(base64, "base64"));
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// src/deps.ts
|
|
421
|
+
async function resolveDeviceToken(deps) {
|
|
422
|
+
const fromEnv = deps.env.CANDLE_DEVICE_TOKEN?.trim();
|
|
423
|
+
if (fromEnv)
|
|
424
|
+
return fromEnv;
|
|
425
|
+
const stored = await deps.store.get(SECRET_REFS.deviceToken);
|
|
426
|
+
return stored ?? undefined;
|
|
427
|
+
}
|
|
428
|
+
async function resolveApiKey(deps) {
|
|
429
|
+
const fromEnv = deps.env.CANDLE_API_KEY?.trim();
|
|
430
|
+
if (fromEnv)
|
|
431
|
+
return fromEnv;
|
|
432
|
+
const stored = await deps.store.get(SECRET_REFS.apiKey);
|
|
433
|
+
return stored ?? undefined;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// src/version.ts
|
|
437
|
+
var CLI_VERSION = "0.4.0";
|
|
438
|
+
|
|
439
|
+
// src/commands/auth.ts
|
|
440
|
+
var DEVICE_CODE_PATH = "/api/v1/agent/device/code";
|
|
441
|
+
var DEVICE_TOKEN_PATH = "/api/v1/agent/device/token";
|
|
442
|
+
var MAX_CLIENT_NAME_LENGTH = 64;
|
|
443
|
+
async function authLogin(args, ctx) {
|
|
444
|
+
const { deps, apiUrl, json } = ctx;
|
|
445
|
+
const parsed = parseArgs(args, { valueFlags: ["--scopes", "--label"], booleanFlags: ["--no-browser"] });
|
|
446
|
+
if ("error" in parsed) {
|
|
447
|
+
writeUsageFailure(deps, parsed.error, json);
|
|
448
|
+
return 2;
|
|
449
|
+
}
|
|
450
|
+
if (parsed.positionals.length > 0) {
|
|
451
|
+
writeUsageFailure(deps, `Unexpected argument: ${parsed.positionals[0]}`, json);
|
|
452
|
+
return 2;
|
|
453
|
+
}
|
|
454
|
+
const scopes = parsed.values["--scopes"] ? parseScopesList(parsed.values["--scopes"]) : undefined;
|
|
455
|
+
const label = parsed.values["--label"];
|
|
456
|
+
const noBrowser = parsed.booleans.has("--no-browser");
|
|
457
|
+
if (label !== undefined && label.length > MAX_CLIENT_NAME_LENGTH) {
|
|
458
|
+
deps.stderr.write(`--label must be at most ${MAX_CLIENT_NAME_LENGTH} characters (got ${label.length}). Shorten it and run: candle auth login --label <name>
|
|
459
|
+
`);
|
|
460
|
+
return 2;
|
|
461
|
+
}
|
|
462
|
+
const clientName = (label ?? `candle-cli/${CLI_VERSION}@${deps.hostname}`).slice(0, MAX_CLIENT_NAME_LENGTH);
|
|
463
|
+
const codeResult = await apiRequest(DEVICE_CODE_PATH, {
|
|
464
|
+
method: "POST",
|
|
465
|
+
auth: "none",
|
|
466
|
+
credentials: {},
|
|
467
|
+
apiUrl,
|
|
468
|
+
fetch: deps.fetch,
|
|
469
|
+
env: deps.env,
|
|
470
|
+
body: { clientName, ...scopes ? { scopes } : {} }
|
|
471
|
+
});
|
|
472
|
+
if (!codeResult.ok) {
|
|
473
|
+
writeFailure(deps, codeResult, { apiUrl, authType: "none" }, json);
|
|
474
|
+
return 1;
|
|
475
|
+
}
|
|
476
|
+
const code = codeResult.body;
|
|
477
|
+
const progress = json ? deps.stderr : deps.stdout;
|
|
478
|
+
progress.write(`Your device code: ${code.userCode}
|
|
479
|
+
`);
|
|
480
|
+
progress.write(`Open this URL to approve: ${code.verificationUriComplete}
|
|
481
|
+
`);
|
|
482
|
+
if (!noBrowser) {
|
|
483
|
+
try {
|
|
484
|
+
deps.openBrowser(code.verificationUriComplete);
|
|
485
|
+
} catch {}
|
|
486
|
+
}
|
|
487
|
+
const expiresAtMs = deps.now() + code.expiresIn * 1000;
|
|
488
|
+
let interval = code.interval;
|
|
489
|
+
while (deps.now() < expiresAtMs) {
|
|
490
|
+
await deps.sleep(interval * 1000);
|
|
491
|
+
const tokenResult = await apiRequest(DEVICE_TOKEN_PATH, {
|
|
492
|
+
method: "POST",
|
|
493
|
+
auth: "none",
|
|
494
|
+
credentials: {},
|
|
495
|
+
apiUrl,
|
|
496
|
+
fetch: deps.fetch,
|
|
497
|
+
env: deps.env,
|
|
498
|
+
body: { deviceCode: code.deviceCode }
|
|
499
|
+
});
|
|
500
|
+
if (tokenResult.ok) {
|
|
501
|
+
return finishLogin(tokenResult.body, ctx, { scopes, label, verificationUri: code.verificationUri });
|
|
502
|
+
}
|
|
503
|
+
if (tokenResult.rfcError === "authorization_pending")
|
|
504
|
+
continue;
|
|
505
|
+
if (tokenResult.rfcError === "slow_down") {
|
|
506
|
+
interval += 5;
|
|
507
|
+
continue;
|
|
508
|
+
}
|
|
509
|
+
if (tokenResult.rfcError === "access_denied" || tokenResult.rfcError === "expired_token" || tokenResult.rfcError === "invalid_grant") {
|
|
510
|
+
if (json)
|
|
511
|
+
deps.stderr.write(`${JSON.stringify(tokenResult)}
|
|
512
|
+
`);
|
|
513
|
+
else
|
|
514
|
+
deps.stderr.write(`${terminalRfcMessage(tokenResult.rfcError)}
|
|
515
|
+
`);
|
|
516
|
+
return 1;
|
|
517
|
+
}
|
|
518
|
+
writeFailure(deps, tokenResult, { apiUrl, authType: "none" }, json);
|
|
519
|
+
return 1;
|
|
520
|
+
}
|
|
521
|
+
if (json)
|
|
522
|
+
deps.stderr.write(`${JSON.stringify({ ok: false, reason: "expired_token" })}
|
|
523
|
+
`);
|
|
524
|
+
else
|
|
525
|
+
deps.stderr.write(`${terminalRfcMessage("expired_token")}
|
|
526
|
+
`);
|
|
527
|
+
return 1;
|
|
528
|
+
}
|
|
529
|
+
function terminalRfcMessage(rfcError) {
|
|
530
|
+
if (rfcError === "access_denied")
|
|
531
|
+
return "Authorization was denied.";
|
|
532
|
+
if (rfcError === "expired_token")
|
|
533
|
+
return "The device code expired before it was approved. Run: candle auth login";
|
|
534
|
+
return "This device code is unknown or was already used. Run: candle auth login";
|
|
535
|
+
}
|
|
536
|
+
function portalOriginFrom(verificationUri) {
|
|
537
|
+
if (!verificationUri)
|
|
538
|
+
return;
|
|
539
|
+
try {
|
|
540
|
+
return new URL(verificationUri).origin;
|
|
541
|
+
} catch {
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
async function finishLogin(rawBody, ctx, requested) {
|
|
546
|
+
const { deps, json, apiUrlFlag } = ctx;
|
|
547
|
+
const body = rawBody;
|
|
548
|
+
await deps.store.set(SECRET_REFS.deviceToken, body.deviceToken);
|
|
549
|
+
if (body.apiKey) {
|
|
550
|
+
await deps.store.set(SECRET_REFS.apiKey, body.apiKey.key);
|
|
551
|
+
}
|
|
552
|
+
const portalOrigin = portalOriginFrom(requested.verificationUri);
|
|
553
|
+
await deps.writeConfig({
|
|
554
|
+
deviceTokenPrefix: body.tokenPrefix,
|
|
555
|
+
...body.apiKey ? { keyPrefix: body.apiKey.keyPrefix, scopes: body.apiKey.scopes } : {},
|
|
556
|
+
...requested.label ? { label: requested.label } : {},
|
|
557
|
+
...apiUrlFlag ? { apiUrl: apiUrlFlag } : {},
|
|
558
|
+
...portalOrigin ? { portalOrigin } : {}
|
|
559
|
+
});
|
|
560
|
+
if (json) {
|
|
561
|
+
deps.stdout.write(`${JSON.stringify({
|
|
562
|
+
backend: deps.backend,
|
|
563
|
+
deviceTokenPrefix: body.tokenPrefix,
|
|
564
|
+
apiKeyPrefix: body.apiKey?.keyPrefix,
|
|
565
|
+
scopes: body.apiKey?.scopes,
|
|
566
|
+
apiKeyError: body.apiKeyError
|
|
567
|
+
})}
|
|
568
|
+
`);
|
|
569
|
+
return 0;
|
|
570
|
+
}
|
|
571
|
+
deps.stdout.write(`Device authorized. Credentials stored in the ${deps.backend} backend.
|
|
572
|
+
`);
|
|
573
|
+
deps.stdout.write(`Device token prefix: ${body.tokenPrefix}
|
|
574
|
+
`);
|
|
575
|
+
if (body.apiKey) {
|
|
576
|
+
deps.stdout.write(`API key prefix: ${body.apiKey.keyPrefix}
|
|
577
|
+
`);
|
|
578
|
+
deps.stdout.write(`Granted scopes: ${formatScopesForSummary(body.apiKey.scopes)}
|
|
579
|
+
`);
|
|
580
|
+
} else if (body.apiKeyError) {
|
|
581
|
+
const authorizedScopes = requested.scopes ?? [...ALL_AGENT_SCOPES];
|
|
582
|
+
deps.stdout.write(`Authorized scopes (no key issued yet): ${formatScopesForSummary(authorizedScopes)}
|
|
583
|
+
`);
|
|
584
|
+
deps.stdout.write(`${body.apiKeyError}
|
|
585
|
+
`);
|
|
586
|
+
deps.stdout.write(`Run: candle keys create
|
|
587
|
+
`);
|
|
588
|
+
}
|
|
589
|
+
return 0;
|
|
590
|
+
}
|
|
591
|
+
async function authLogout(args, ctx) {
|
|
592
|
+
const { deps, apiUrl, json } = ctx;
|
|
593
|
+
const parsed = parseArgs(args, { booleanFlags: ["--keep-key"] });
|
|
594
|
+
if ("error" in parsed) {
|
|
595
|
+
writeUsageFailure(deps, parsed.error, json);
|
|
596
|
+
return 2;
|
|
597
|
+
}
|
|
598
|
+
if (parsed.positionals.length > 0) {
|
|
599
|
+
writeUsageFailure(deps, `Unexpected argument: ${parsed.positionals[0]}`, json);
|
|
600
|
+
return 2;
|
|
601
|
+
}
|
|
602
|
+
const keepKey = parsed.booleans.has("--keep-key");
|
|
603
|
+
const config = await deps.readConfig();
|
|
604
|
+
const deviceToken = await resolveDeviceToken(deps);
|
|
605
|
+
let revokedKey;
|
|
606
|
+
if (!keepKey && deviceToken && config.keyPrefix) {
|
|
607
|
+
const result = await apiRequest(`/api/v1/agent/keys/${encodeURIComponent(config.keyPrefix)}`, {
|
|
608
|
+
method: "DELETE",
|
|
609
|
+
auth: "device",
|
|
610
|
+
credentials: { deviceToken },
|
|
611
|
+
apiUrl,
|
|
612
|
+
fetch: deps.fetch,
|
|
613
|
+
env: deps.env
|
|
614
|
+
});
|
|
615
|
+
if (result.ok) {
|
|
616
|
+
revokedKey = config.keyPrefix;
|
|
617
|
+
} else if (!json) {
|
|
618
|
+
deps.stdout.write(`Could not revoke the stored API key remotely (clearing it locally anyway).
|
|
619
|
+
`);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
await deps.store.delete(SECRET_REFS.deviceToken);
|
|
623
|
+
await deps.store.delete(SECRET_REFS.apiKey);
|
|
624
|
+
await deps.clearConfig();
|
|
625
|
+
const portalUrl = portalDeviceUrl(apiUrl, config.portalOrigin);
|
|
626
|
+
const liveEnvOverrides = ["CANDLE_DEVICE_TOKEN", "CANDLE_API_KEY"].filter((name) => deps.env[name]?.trim());
|
|
627
|
+
if (json) {
|
|
628
|
+
deps.stdout.write(`${JSON.stringify({ success: true, revokedKey: revokedKey ?? null, portalUrl, envOverrides: liveEnvOverrides })}
|
|
629
|
+
`);
|
|
630
|
+
return 0;
|
|
631
|
+
}
|
|
632
|
+
deps.stdout.write(`Local credentials cleared.
|
|
633
|
+
`);
|
|
634
|
+
if (liveEnvOverrides.length > 0) {
|
|
635
|
+
deps.stdout.write(`Still set in this shell: ${liveEnvOverrides.join(", ")}. Those beat the store, so they remain live until you unset them.
|
|
636
|
+
`);
|
|
637
|
+
}
|
|
638
|
+
deps.stdout.write(`The device token itself is session-only to revoke -- that is intentional (a stolen token cannot read device metadata or revoke a sibling device). Sign in to the portal to revoke it there.
|
|
639
|
+
`);
|
|
640
|
+
deps.stdout.write(`Portal: ${portalUrl}
|
|
641
|
+
`);
|
|
642
|
+
return 0;
|
|
643
|
+
}
|
|
644
|
+
function configFilePathForDisplay(env) {
|
|
645
|
+
const dir = env.CANDLE_CONFIG_DIR?.trim() || join2(homedir2(), ".config", "candle");
|
|
646
|
+
return join2(dir, "config.json");
|
|
647
|
+
}
|
|
648
|
+
async function authStatus(args, ctx) {
|
|
649
|
+
const { deps, apiUrl, json } = ctx;
|
|
650
|
+
const parsed = parseArgs(args, {});
|
|
651
|
+
if ("error" in parsed) {
|
|
652
|
+
writeUsageFailure(deps, parsed.error, json);
|
|
653
|
+
return 2;
|
|
654
|
+
}
|
|
655
|
+
if (parsed.positionals.length > 0) {
|
|
656
|
+
writeUsageFailure(deps, `Unexpected argument: ${parsed.positionals[0]}`, json);
|
|
657
|
+
return 2;
|
|
658
|
+
}
|
|
659
|
+
const config = await deps.readConfig();
|
|
660
|
+
const deviceToken = await resolveDeviceToken(deps);
|
|
661
|
+
const apiKey = await resolveApiKey(deps);
|
|
662
|
+
const rows = [];
|
|
663
|
+
if (!deviceToken) {
|
|
664
|
+
rows.push({ check: "Device token", state: "SKIP", detail: "not set. Run: candle auth login" });
|
|
665
|
+
} else {
|
|
666
|
+
rows.push(await runLiveCheck({
|
|
667
|
+
deps,
|
|
668
|
+
apiUrl,
|
|
669
|
+
path: "/api/v1/agent/keys",
|
|
670
|
+
auth: "device",
|
|
671
|
+
credential: deviceToken,
|
|
672
|
+
check: "Device token",
|
|
673
|
+
passDetail: "valid"
|
|
674
|
+
}));
|
|
675
|
+
}
|
|
676
|
+
if (!apiKey) {
|
|
677
|
+
rows.push({ check: "API key", state: "SKIP", detail: "not set. Run: candle keys create" });
|
|
678
|
+
} else {
|
|
679
|
+
rows.push(await runLiveCheck({
|
|
680
|
+
deps,
|
|
681
|
+
apiUrl,
|
|
682
|
+
path: "/api/v1/agent/tier",
|
|
683
|
+
auth: "key",
|
|
684
|
+
credential: apiKey,
|
|
685
|
+
check: "API key",
|
|
686
|
+
passDetail: "valid"
|
|
687
|
+
}));
|
|
688
|
+
}
|
|
689
|
+
let account;
|
|
690
|
+
if (apiKey) {
|
|
691
|
+
const identity = await apiRequest("/api/v1/agent/wallets/embedded", {
|
|
692
|
+
auth: "key",
|
|
693
|
+
credentials: { apiKey },
|
|
694
|
+
apiUrl,
|
|
695
|
+
fetch: deps.fetch,
|
|
696
|
+
env: deps.env
|
|
697
|
+
});
|
|
698
|
+
if (identity.ok)
|
|
699
|
+
account = identity.body.account;
|
|
700
|
+
}
|
|
701
|
+
const exitCode = rows.some((row) => row.state === "FAIL") ? 1 : 0;
|
|
702
|
+
const configPath = configFilePathForDisplay(deps.env);
|
|
703
|
+
if (json) {
|
|
704
|
+
deps.stdout.write(`${JSON.stringify({
|
|
705
|
+
backend: deps.backend,
|
|
706
|
+
deviceTokenPrefix: config.deviceTokenPrefix,
|
|
707
|
+
keyPrefix: config.keyPrefix,
|
|
708
|
+
account,
|
|
709
|
+
apiUrl,
|
|
710
|
+
configPath,
|
|
711
|
+
rows
|
|
712
|
+
})}
|
|
713
|
+
`);
|
|
714
|
+
return exitCode;
|
|
715
|
+
}
|
|
716
|
+
deps.stdout.write(`Account: ${account ?? "unknown"} at ${apiUrl}
|
|
717
|
+
`);
|
|
718
|
+
deps.stdout.write(`Backend: ${deps.backend}
|
|
719
|
+
`);
|
|
720
|
+
deps.stdout.write(`Device token prefix: ${config.deviceTokenPrefix ?? "not set"}
|
|
721
|
+
`);
|
|
722
|
+
deps.stdout.write(`API key prefix: ${config.keyPrefix ?? "not set"}
|
|
723
|
+
`);
|
|
724
|
+
deps.stdout.write(`Config file: ${configPath}
|
|
725
|
+
|
|
726
|
+
`);
|
|
727
|
+
deps.stdout.write(`${renderTable(["Check", "Status", "Detail"], rows.map((row) => [row.check, row.state, row.detail]))}
|
|
728
|
+
`);
|
|
729
|
+
return exitCode;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
// src/commands/doctor.ts
|
|
733
|
+
var MIN_NODE_MAJOR = 18;
|
|
734
|
+
var API_KEY_CHECK = "API key valid (launch:write)";
|
|
735
|
+
async function doctor(args, ctx) {
|
|
736
|
+
const { deps, apiUrl, json } = ctx;
|
|
737
|
+
const parsed = parseArgs(args, {});
|
|
738
|
+
if ("error" in parsed) {
|
|
739
|
+
writeUsageFailure(deps, parsed.error, json);
|
|
740
|
+
return 2;
|
|
741
|
+
}
|
|
742
|
+
if (parsed.positionals.length > 0) {
|
|
743
|
+
writeUsageFailure(deps, `Unexpected argument: ${parsed.positionals[0]}`, json);
|
|
744
|
+
return 2;
|
|
745
|
+
}
|
|
746
|
+
const rows = [];
|
|
747
|
+
const nodeMajor = Number(deps.nodeVersion.split(".")[0]);
|
|
748
|
+
rows.push(Number.isFinite(nodeMajor) && nodeMajor >= MIN_NODE_MAJOR ? { check: "Runtime version", state: "PASS", detail: `node ${deps.nodeVersion}` } : {
|
|
749
|
+
check: "Runtime version",
|
|
750
|
+
state: "FAIL",
|
|
751
|
+
detail: `node ${deps.nodeVersion} is below the minimum (${MIN_NODE_MAJOR}). Fix: upgrade Node.js to ${MIN_NODE_MAJOR} or later.`
|
|
752
|
+
});
|
|
753
|
+
rows.push({ check: "Keychain backend", state: "PASS", detail: deps.backend });
|
|
754
|
+
const deviceToken = await resolveDeviceToken(deps);
|
|
755
|
+
const apiKey = await resolveApiKey(deps);
|
|
756
|
+
rows.push(deviceToken ? {
|
|
757
|
+
check: "Credentials present",
|
|
758
|
+
state: "PASS",
|
|
759
|
+
detail: apiKey ? "device token and API key" : "device token only (no API key yet)"
|
|
760
|
+
} : { check: "Credentials present", state: "FAIL", detail: "No device token found. Fix: run candle auth login." });
|
|
761
|
+
const statusResult = await apiRequest("/api/v1/status", {
|
|
762
|
+
auth: "none",
|
|
763
|
+
credentials: {},
|
|
764
|
+
apiUrl,
|
|
765
|
+
fetch: deps.fetch,
|
|
766
|
+
env: deps.env
|
|
767
|
+
});
|
|
768
|
+
rows.push(statusResult.ok ? { check: "API reachable", state: "PASS", detail: apiUrl } : { check: "API reachable", state: "FAIL", detail: renderError(statusResult, { apiUrl, authType: "none" }) });
|
|
769
|
+
if (!deviceToken) {
|
|
770
|
+
rows.push({ check: "Device token valid", state: "SKIP", detail: "no device token to check" });
|
|
771
|
+
} else {
|
|
772
|
+
rows.push(await runLiveCheck({
|
|
773
|
+
deps,
|
|
774
|
+
apiUrl,
|
|
775
|
+
path: "/api/v1/agent/keys",
|
|
776
|
+
auth: "device",
|
|
777
|
+
credential: deviceToken,
|
|
778
|
+
check: "Device token valid",
|
|
779
|
+
passDetail: "valid"
|
|
780
|
+
}));
|
|
781
|
+
}
|
|
782
|
+
if (!apiKey) {
|
|
783
|
+
rows.push({ check: API_KEY_CHECK, state: "SKIP", detail: "no API key to check" });
|
|
784
|
+
} else {
|
|
785
|
+
const config = await deps.readConfig();
|
|
786
|
+
const passDetail = config.scopes ? `scopes: ${config.scopes.join(", ")}` : "valid";
|
|
787
|
+
rows.push(await runLiveCheck({
|
|
788
|
+
deps,
|
|
789
|
+
apiUrl,
|
|
790
|
+
path: "/api/v1/agent/tier",
|
|
791
|
+
auth: "key",
|
|
792
|
+
credential: apiKey,
|
|
793
|
+
check: API_KEY_CHECK,
|
|
794
|
+
passDetail
|
|
795
|
+
}));
|
|
796
|
+
}
|
|
797
|
+
let account;
|
|
798
|
+
if (!apiKey) {
|
|
799
|
+
rows.push({ check: "Launch wallet delegated", state: "SKIP", detail: "no API key to check" });
|
|
800
|
+
} else {
|
|
801
|
+
const result = await apiRequest("/api/v1/agent/wallets/embedded", {
|
|
802
|
+
auth: "key",
|
|
803
|
+
credentials: { apiKey },
|
|
804
|
+
apiUrl,
|
|
805
|
+
fetch: deps.fetch,
|
|
806
|
+
env: deps.env
|
|
807
|
+
});
|
|
808
|
+
if (!result.ok) {
|
|
809
|
+
rows.push({
|
|
810
|
+
check: "Launch wallet delegated",
|
|
811
|
+
state: "FAIL",
|
|
812
|
+
detail: renderError(result, { apiUrl, authType: "key" })
|
|
813
|
+
});
|
|
814
|
+
} else {
|
|
815
|
+
const body = result.body;
|
|
816
|
+
account = body.account;
|
|
817
|
+
const delegated = Boolean(body.wallets.solana?.delegated || body.wallets.evm?.delegated);
|
|
818
|
+
rows.push(delegated ? { check: "Launch wallet delegated", state: "PASS", detail: "delegated" } : {
|
|
819
|
+
check: "Launch wallet delegated",
|
|
820
|
+
state: "FAIL",
|
|
821
|
+
detail: "No launch wallet is delegated. Fix: delegate one in the portal."
|
|
822
|
+
});
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
rows.push(account !== undefined ? { check: "Account", state: "PASS", detail: account } : { check: "Account", state: "SKIP", detail: "could not resolve which account these credentials act as" });
|
|
826
|
+
const exitCode = rows.some((row) => row.state === "FAIL") ? 1 : 0;
|
|
827
|
+
if (json) {
|
|
828
|
+
deps.stdout.write(`${JSON.stringify({ rows, ...account !== undefined ? { account } : {} })}
|
|
829
|
+
`);
|
|
830
|
+
return exitCode;
|
|
831
|
+
}
|
|
832
|
+
deps.stdout.write(`${renderTable(["Check", "Status", "Detail"], rows.map((row) => [row.check, row.state, row.detail]))}
|
|
833
|
+
`);
|
|
834
|
+
return exitCode;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
// src/commands/keys.ts
|
|
838
|
+
var KEYS_PATH = "/api/v1/agent/keys";
|
|
839
|
+
var NO_DEVICE_TOKEN = {
|
|
840
|
+
code: "NO_DEVICE_TOKEN",
|
|
841
|
+
message: "No device token available.",
|
|
842
|
+
suggestion: "Run: candle auth login"
|
|
843
|
+
};
|
|
844
|
+
function mintedByLabel(mintedBy, ownDeviceTokenPrefix) {
|
|
845
|
+
if (!mintedBy)
|
|
846
|
+
return "browser session";
|
|
847
|
+
if (mintedBy === ownDeviceTokenPrefix)
|
|
848
|
+
return "this device";
|
|
849
|
+
return mintedBy;
|
|
850
|
+
}
|
|
851
|
+
async function keysList(args, ctx) {
|
|
852
|
+
const { deps, apiUrl, json } = ctx;
|
|
853
|
+
const parsed = parseArgs(args, {});
|
|
854
|
+
if ("error" in parsed) {
|
|
855
|
+
writeUsageFailure(deps, parsed.error, json);
|
|
856
|
+
return 2;
|
|
857
|
+
}
|
|
858
|
+
if (parsed.positionals.length > 0) {
|
|
859
|
+
writeUsageFailure(deps, `Unexpected argument: ${parsed.positionals[0]}`, json);
|
|
860
|
+
return 2;
|
|
861
|
+
}
|
|
862
|
+
const deviceToken = await resolveDeviceToken(deps);
|
|
863
|
+
if (!deviceToken) {
|
|
864
|
+
writeLocalFailure(deps, NO_DEVICE_TOKEN, json);
|
|
865
|
+
return 1;
|
|
866
|
+
}
|
|
867
|
+
const result = await apiRequest(KEYS_PATH, {
|
|
868
|
+
auth: "device",
|
|
869
|
+
credentials: { deviceToken },
|
|
870
|
+
apiUrl,
|
|
871
|
+
fetch: deps.fetch,
|
|
872
|
+
env: deps.env
|
|
873
|
+
});
|
|
874
|
+
if (!result.ok) {
|
|
875
|
+
writeFailure(deps, result, { apiUrl, authType: "device" }, json);
|
|
876
|
+
return 1;
|
|
877
|
+
}
|
|
878
|
+
if (json) {
|
|
879
|
+
deps.stdout.write(`${JSON.stringify(result.body)}
|
|
880
|
+
`);
|
|
881
|
+
return 0;
|
|
882
|
+
}
|
|
883
|
+
const body = result.body;
|
|
884
|
+
const config = await deps.readConfig();
|
|
885
|
+
const rows = body.keys.map((key) => [
|
|
886
|
+
key.keyPrefix,
|
|
887
|
+
key.scopes.join(","),
|
|
888
|
+
key.environment,
|
|
889
|
+
formatTimestamp(key.createdAt),
|
|
890
|
+
formatTimestamp(key.lastUsedAt),
|
|
891
|
+
key.revokedAt ? formatTimestamp(key.revokedAt) : "no",
|
|
892
|
+
mintedByLabel(key.mintedByDevicePrefix, config.deviceTokenPrefix)
|
|
893
|
+
]);
|
|
894
|
+
deps.stdout.write(`${renderTable(["Prefix", "Scopes", "Environment", "Created", "Last used", "Revoked", "Minted by"], rows)}
|
|
895
|
+
`);
|
|
896
|
+
return 0;
|
|
897
|
+
}
|
|
898
|
+
async function keysCreate(args, ctx) {
|
|
899
|
+
const { deps, apiUrl, json } = ctx;
|
|
900
|
+
const parsed = parseArgs(args, {
|
|
901
|
+
valueFlags: ["--scopes", "--environment", "--label", "--expires-in", "--tx-limit", "--reset"]
|
|
902
|
+
});
|
|
903
|
+
if ("error" in parsed) {
|
|
904
|
+
writeUsageFailure(deps, parsed.error, json);
|
|
905
|
+
return 2;
|
|
906
|
+
}
|
|
907
|
+
if (parsed.positionals.length > 0) {
|
|
908
|
+
writeUsageFailure(deps, `Unexpected argument: ${parsed.positionals[0]}`, json);
|
|
909
|
+
return 2;
|
|
910
|
+
}
|
|
911
|
+
const requestedScopes = parsed.values["--scopes"] ? parseScopesList(parsed.values["--scopes"]) : undefined;
|
|
912
|
+
const environment = parsed.values["--environment"];
|
|
913
|
+
const label = parsed.values["--label"]?.trim();
|
|
914
|
+
if (parsed.values["--label"] !== undefined && (label === undefined || label.length < 1 || label.length > 64)) {
|
|
915
|
+
writeUsageFailure(deps, "--label must be 1 to 64 characters.", json);
|
|
916
|
+
return 2;
|
|
917
|
+
}
|
|
918
|
+
let expiresInDays;
|
|
919
|
+
if (parsed.values["--expires-in"] !== undefined) {
|
|
920
|
+
const parsedDays = parseExpiresInDays(parsed.values["--expires-in"]);
|
|
921
|
+
if (!parsedDays.ok) {
|
|
922
|
+
writeUsageFailure(deps, parsedDays.message, json);
|
|
923
|
+
return 2;
|
|
924
|
+
}
|
|
925
|
+
expiresInDays = parsedDays.days;
|
|
926
|
+
}
|
|
927
|
+
if (parsed.values["--reset"] !== undefined && parsed.values["--tx-limit"] === undefined) {
|
|
928
|
+
writeUsageFailure(deps, "--reset requires --tx-limit.", json);
|
|
929
|
+
return 2;
|
|
930
|
+
}
|
|
931
|
+
let txLimit;
|
|
932
|
+
if (parsed.values["--tx-limit"] !== undefined) {
|
|
933
|
+
const parsedUsd = parseUsdToMicros(parsed.values["--tx-limit"]);
|
|
934
|
+
if (!parsedUsd.ok) {
|
|
935
|
+
writeUsageFailure(deps, parsedUsd.message, json);
|
|
936
|
+
return 2;
|
|
937
|
+
}
|
|
938
|
+
const reset = parsed.values["--reset"] ?? "daily";
|
|
939
|
+
if (!TX_LIMIT_RESETS.includes(reset)) {
|
|
940
|
+
writeUsageFailure(deps, `--reset must be one of: ${TX_LIMIT_RESETS.join(", ")}.`, json);
|
|
941
|
+
return 2;
|
|
942
|
+
}
|
|
943
|
+
txLimit = { usdMicros: parsedUsd.usdMicros, reset };
|
|
944
|
+
}
|
|
945
|
+
const deviceToken = await resolveDeviceToken(deps);
|
|
946
|
+
if (!deviceToken) {
|
|
947
|
+
writeLocalFailure(deps, NO_DEVICE_TOKEN, json);
|
|
948
|
+
return 1;
|
|
949
|
+
}
|
|
950
|
+
const result = await apiRequest(KEYS_PATH, {
|
|
951
|
+
method: "POST",
|
|
952
|
+
auth: "device",
|
|
953
|
+
credentials: { deviceToken },
|
|
954
|
+
apiUrl,
|
|
955
|
+
fetch: deps.fetch,
|
|
956
|
+
env: deps.env,
|
|
957
|
+
body: {
|
|
958
|
+
...requestedScopes ? { scopes: requestedScopes } : {},
|
|
959
|
+
...environment ? { environment } : {},
|
|
960
|
+
...label ? { label } : {},
|
|
961
|
+
...expiresInDays !== undefined ? { expiresInDays } : {},
|
|
962
|
+
...txLimit ? { txLimit } : {}
|
|
963
|
+
}
|
|
964
|
+
});
|
|
965
|
+
if (!result.ok) {
|
|
966
|
+
writeFailure(deps, result, { apiUrl, authType: "device" }, json);
|
|
967
|
+
return 1;
|
|
968
|
+
}
|
|
969
|
+
const body = result.body;
|
|
970
|
+
const existingKey = await deps.store.get(SECRET_REFS.apiKey);
|
|
971
|
+
let stored = false;
|
|
972
|
+
if (!existingKey) {
|
|
973
|
+
await deps.store.set(SECRET_REFS.apiKey, body.key);
|
|
974
|
+
await deps.writeConfig({ keyPrefix: body.keyPrefix, scopes: body.scopes });
|
|
975
|
+
stored = true;
|
|
976
|
+
}
|
|
977
|
+
if (json) {
|
|
978
|
+
deps.stdout.write(`${JSON.stringify({ ...body, stored })}
|
|
979
|
+
`);
|
|
980
|
+
return 0;
|
|
981
|
+
}
|
|
982
|
+
deps.stdout.write(`API key: ${body.key}
|
|
983
|
+
`);
|
|
984
|
+
deps.stdout.write(`This is the only time the plaintext key is shown; store it now.
|
|
985
|
+
`);
|
|
986
|
+
deps.stdout.write(`Prefix: ${body.keyPrefix}
|
|
987
|
+
`);
|
|
988
|
+
deps.stdout.write(`Scopes: ${formatScopesForSummary(body.scopes)}
|
|
989
|
+
`);
|
|
990
|
+
if (!requestedScopes) {
|
|
991
|
+
deps.stdout.write(`No --scopes given: the server granted the default scopes (swap:write excluded).
|
|
992
|
+
`);
|
|
993
|
+
}
|
|
994
|
+
deps.stdout.write(stored ? `Stored in the ${deps.backend} backend as the CLI's working key.
|
|
995
|
+
` : `Not stored: the CLI already manages a different working key. This key belongs to whichever agent it was minted for.
|
|
996
|
+
`);
|
|
997
|
+
return 0;
|
|
998
|
+
}
|
|
999
|
+
async function keysRevoke(args, ctx) {
|
|
1000
|
+
const { deps, apiUrl, json } = ctx;
|
|
1001
|
+
const parsed = parseArgs(args, {});
|
|
1002
|
+
if ("error" in parsed) {
|
|
1003
|
+
writeUsageFailure(deps, parsed.error, json);
|
|
1004
|
+
return 2;
|
|
1005
|
+
}
|
|
1006
|
+
if (parsed.positionals.length !== 1) {
|
|
1007
|
+
deps.stderr.write(`Usage: candle keys revoke <prefix>
|
|
1008
|
+
`);
|
|
1009
|
+
return 2;
|
|
1010
|
+
}
|
|
1011
|
+
const prefix = parsed.positionals[0];
|
|
1012
|
+
const deviceToken = await resolveDeviceToken(deps);
|
|
1013
|
+
if (!deviceToken) {
|
|
1014
|
+
writeLocalFailure(deps, NO_DEVICE_TOKEN, json);
|
|
1015
|
+
return 1;
|
|
1016
|
+
}
|
|
1017
|
+
const result = await apiRequest(`${KEYS_PATH}/${encodeURIComponent(prefix)}`, {
|
|
1018
|
+
method: "DELETE",
|
|
1019
|
+
auth: "device",
|
|
1020
|
+
credentials: { deviceToken },
|
|
1021
|
+
apiUrl,
|
|
1022
|
+
fetch: deps.fetch,
|
|
1023
|
+
env: deps.env
|
|
1024
|
+
});
|
|
1025
|
+
if (!result.ok) {
|
|
1026
|
+
writeFailure(deps, result, { apiUrl, authType: "device" }, json);
|
|
1027
|
+
return 1;
|
|
1028
|
+
}
|
|
1029
|
+
const config = await deps.readConfig();
|
|
1030
|
+
let clearedLocal = false;
|
|
1031
|
+
if (config.keyPrefix === prefix) {
|
|
1032
|
+
await deps.store.delete(SECRET_REFS.apiKey);
|
|
1033
|
+
await deps.writeConfig({ keyPrefix: undefined });
|
|
1034
|
+
clearedLocal = true;
|
|
1035
|
+
}
|
|
1036
|
+
if (json) {
|
|
1037
|
+
deps.stdout.write(`${JSON.stringify({ success: true, keyPrefix: prefix, clearedLocal })}
|
|
1038
|
+
`);
|
|
1039
|
+
return 0;
|
|
1040
|
+
}
|
|
1041
|
+
deps.stdout.write(`Revoked key ${prefix}.
|
|
1042
|
+
`);
|
|
1043
|
+
if (clearedLocal) {
|
|
1044
|
+
deps.stdout.write(`This was the CLI's stored working key; also cleared it locally.
|
|
1045
|
+
`);
|
|
1046
|
+
}
|
|
1047
|
+
return 0;
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
// src/commands/mcp.ts
|
|
1051
|
+
var MCP_TOOL_NAMES = [
|
|
1052
|
+
"candle_launch_token",
|
|
1053
|
+
"candle_launch_and_seed",
|
|
1054
|
+
"candle_get_market",
|
|
1055
|
+
"candle_get_feed",
|
|
1056
|
+
"candle_get_agent_profile",
|
|
1057
|
+
"candle_report_activity",
|
|
1058
|
+
"candle_trade",
|
|
1059
|
+
"candle_swap",
|
|
1060
|
+
"candle_transfer",
|
|
1061
|
+
"candle_sweep"
|
|
1062
|
+
];
|
|
1063
|
+
var READ_ONLY_TOOL_NAMES = ["candle_get_market", "candle_get_feed", "candle_get_agent_profile"];
|
|
1064
|
+
function mcpClientConfig(args) {
|
|
1065
|
+
return JSON.stringify({ mcpServers: { candle: { command: "candle", args: ["mcp", ...args] } } }, null, 2);
|
|
1066
|
+
}
|
|
1067
|
+
async function mcp(args, ctx) {
|
|
1068
|
+
const { deps, apiUrl, json } = ctx;
|
|
1069
|
+
const parsed = parseArgs(args, {
|
|
1070
|
+
valueFlags: ["--tools"],
|
|
1071
|
+
booleanFlags: ["--read-only", "--print-config"]
|
|
1072
|
+
});
|
|
1073
|
+
if ("error" in parsed) {
|
|
1074
|
+
writeUsageFailure(deps, parsed.error, json);
|
|
1075
|
+
return 2;
|
|
1076
|
+
}
|
|
1077
|
+
if (parsed.positionals.length > 0) {
|
|
1078
|
+
writeUsageFailure(deps, `Unexpected argument: ${parsed.positionals[0]}`, json);
|
|
1079
|
+
return 2;
|
|
1080
|
+
}
|
|
1081
|
+
const readOnly = parsed.booleans.has("--read-only");
|
|
1082
|
+
const toolsFlag = parsed.values["--tools"];
|
|
1083
|
+
if (readOnly && toolsFlag !== undefined) {
|
|
1084
|
+
writeUsageFailure(deps, "--read-only and --tools are mutually exclusive; --read-only IS a tool selection.", json);
|
|
1085
|
+
return 2;
|
|
1086
|
+
}
|
|
1087
|
+
let toolAllowlist;
|
|
1088
|
+
if (readOnly) {
|
|
1089
|
+
toolAllowlist = READ_ONLY_TOOL_NAMES.join(",");
|
|
1090
|
+
} else if (toolsFlag !== undefined) {
|
|
1091
|
+
const requested = toolsFlag.split(",").map((name) => name.trim()).filter((name) => name.length > 0);
|
|
1092
|
+
const unknown = requested.filter((name) => !MCP_TOOL_NAMES.includes(name));
|
|
1093
|
+
if (requested.length === 0 || unknown.length > 0) {
|
|
1094
|
+
writeUsageFailure(deps, `--tools must be a comma-separated list of: ${MCP_TOOL_NAMES.join(", ")}${unknown.length > 0 ? ` (unknown: ${unknown.join(", ")})` : ""}`, json);
|
|
1095
|
+
return 2;
|
|
1096
|
+
}
|
|
1097
|
+
toolAllowlist = requested.join(",");
|
|
1098
|
+
}
|
|
1099
|
+
if (parsed.booleans.has("--print-config")) {
|
|
1100
|
+
const launchArgs = [
|
|
1101
|
+
...readOnly ? ["--read-only"] : [],
|
|
1102
|
+
...toolsFlag !== undefined ? ["--tools", toolsFlag] : []
|
|
1103
|
+
];
|
|
1104
|
+
deps.stdout.write(`${mcpClientConfig(launchArgs)}
|
|
1105
|
+
`);
|
|
1106
|
+
return 0;
|
|
1107
|
+
}
|
|
1108
|
+
const apiKey = readOnly ? undefined : await resolveApiKey(deps);
|
|
1109
|
+
if (!readOnly && !apiKey) {
|
|
1110
|
+
writeLocalFailure(deps, { code: "NO_API_KEY", message: "No API key available.", suggestion: "Run: candle auth login" }, json);
|
|
1111
|
+
return 1;
|
|
1112
|
+
}
|
|
1113
|
+
const childEnv = {
|
|
1114
|
+
...deps.env,
|
|
1115
|
+
CANDLE_API_URL: apiUrl,
|
|
1116
|
+
...apiKey ? { CANDLE_AGENT_API_KEY: apiKey } : {},
|
|
1117
|
+
...toolAllowlist ? { CANDLE_MCP_TOOLS: toolAllowlist } : {}
|
|
1118
|
+
};
|
|
1119
|
+
deps.stderr.write(`Starting @candledottv/mcp against ${apiUrl}${toolAllowlist ? ` (tools: ${toolAllowlist})` : ""}
|
|
1120
|
+
`);
|
|
1121
|
+
return deps.runChild("npx", ["--yes", "@candledottv/mcp"], childEnv);
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
// src/commands/setup.ts
|
|
1125
|
+
var SKILLS_CLAUDE_COMMAND = "/plugin marketplace add candledottv/agentic";
|
|
1126
|
+
var CODING_AGENTS_DOCS = "https://docs.candle.tv/developers/coding-agents";
|
|
1127
|
+
function section(deps, title) {
|
|
1128
|
+
deps.stdout.write(`
|
|
1129
|
+
== ${title} ==
|
|
1130
|
+
`);
|
|
1131
|
+
}
|
|
1132
|
+
async function setup(args, ctx) {
|
|
1133
|
+
const { deps, apiUrl, json } = ctx;
|
|
1134
|
+
const parsed = parseArgs(args, { booleanFlags: ["--no-browser"] });
|
|
1135
|
+
if ("error" in parsed) {
|
|
1136
|
+
writeUsageFailure(deps, parsed.error, json);
|
|
1137
|
+
return 2;
|
|
1138
|
+
}
|
|
1139
|
+
if (parsed.positionals.length > 0) {
|
|
1140
|
+
writeUsageFailure(deps, `Unexpected argument: ${parsed.positionals[0]}`, json);
|
|
1141
|
+
return 2;
|
|
1142
|
+
}
|
|
1143
|
+
if (json) {
|
|
1144
|
+
writeUsageFailure(deps, "setup is an interactive wizard; for machine use, compose `auth login --json` and `doctor --json` directly", json);
|
|
1145
|
+
return 2;
|
|
1146
|
+
}
|
|
1147
|
+
deps.stdout.write(`candle setup: this wizard authorizes the device, shows funding, and verifies everything.
|
|
1148
|
+
`);
|
|
1149
|
+
section(deps, "1/4 Authorize this device");
|
|
1150
|
+
const deviceToken = await resolveDeviceToken(deps);
|
|
1151
|
+
const apiKey = await resolveApiKey(deps);
|
|
1152
|
+
if (deviceToken && apiKey) {
|
|
1153
|
+
deps.stdout.write(`Already authorized on this machine (device token + API key present). Skipping login.
|
|
1154
|
+
`);
|
|
1155
|
+
} else {
|
|
1156
|
+
const loginArgs = parsed.booleans.has("--no-browser") ? ["--no-browser"] : [];
|
|
1157
|
+
const loginExit = await authLogin(loginArgs, ctx);
|
|
1158
|
+
if (loginExit !== 0) {
|
|
1159
|
+
deps.stderr.write(`Setup stopped: device authorization did not complete.
|
|
1160
|
+
`);
|
|
1161
|
+
return loginExit;
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
section(deps, "2/4 Fund your agent's wallets");
|
|
1165
|
+
const key = await resolveApiKey(deps);
|
|
1166
|
+
const walletsResult = key ? await apiRequest("/api/v1/agent/wallets/embedded", {
|
|
1167
|
+
auth: "key",
|
|
1168
|
+
credentials: { apiKey: key },
|
|
1169
|
+
apiUrl,
|
|
1170
|
+
fetch: deps.fetch,
|
|
1171
|
+
env: deps.env
|
|
1172
|
+
}) : null;
|
|
1173
|
+
if (walletsResult?.ok) {
|
|
1174
|
+
const body = walletsResult.body;
|
|
1175
|
+
const solana = body.wallets?.solana ?? null;
|
|
1176
|
+
const evm = body.wallets?.evm ?? null;
|
|
1177
|
+
if (body.account)
|
|
1178
|
+
deps.stdout.write(`Account: ${body.account}
|
|
1179
|
+
`);
|
|
1180
|
+
if (solana)
|
|
1181
|
+
deps.stdout.write(`Solana (send SOL here): ${solana.address}
|
|
1182
|
+
`);
|
|
1183
|
+
if (evm)
|
|
1184
|
+
deps.stdout.write(`Hood (send ETH here): ${evm.address}
|
|
1185
|
+
`);
|
|
1186
|
+
deps.stdout.write(`Launches and trades are paid from these wallets. There is no minimum, and read-only requests work unfunded.
|
|
1187
|
+
`);
|
|
1188
|
+
deps.stdout.write(`
|
|
1189
|
+
Tell your agent (paste into its context):
|
|
1190
|
+
`);
|
|
1191
|
+
deps.stdout.write(` You operate a Candle agent account. API base URL: ${apiUrl} (send your API key in the x-api-key header).
|
|
1192
|
+
`);
|
|
1193
|
+
if (solana)
|
|
1194
|
+
deps.stdout.write(` Your Solana wallet: ${solana.address}
|
|
1195
|
+
`);
|
|
1196
|
+
if (evm)
|
|
1197
|
+
deps.stdout.write(` Your Hood Chain (EVM) wallet: ${evm.address}
|
|
1198
|
+
`);
|
|
1199
|
+
deps.stdout.write(` Check balances before trading, and ask me to fund whichever chain you need.
|
|
1200
|
+
`);
|
|
1201
|
+
} else {
|
|
1202
|
+
deps.stdout.write("Could not read the agent wallets right now; `candle wallets` shows them once the API is reachable.\n");
|
|
1203
|
+
}
|
|
1204
|
+
section(deps, "3/4 Connect your agent");
|
|
1205
|
+
deps.stdout.write(`Claude Code skills: ${SKILLS_CLAUDE_COMMAND}
|
|
1206
|
+
`);
|
|
1207
|
+
deps.stdout.write(`MCP (any client): candle mcp --print-config
|
|
1208
|
+
`);
|
|
1209
|
+
deps.stdout.write(`Other platforms: ${CODING_AGENTS_DOCS}
|
|
1210
|
+
`);
|
|
1211
|
+
section(deps, "4/4 Health check");
|
|
1212
|
+
const doctorExit = await doctor([], ctx);
|
|
1213
|
+
const config = await deps.readConfig();
|
|
1214
|
+
deps.stdout.write(`
|
|
1215
|
+
Console (keys, funding, withdrawal addresses, limits): ${portalDeviceUrl(apiUrl, config.portalOrigin)}
|
|
1216
|
+
`);
|
|
1217
|
+
deps.stdout.write(doctorExit === 0 ? `Setup complete. Your agent can launch, trade, and transfer the moment the wallets are funded.
|
|
1218
|
+
` : "Setup finished with failed checks above; fix them and re-run `candle doctor`.\n");
|
|
1219
|
+
return doctorExit;
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
// ../../node_modules/@scure/base/lib/esm/index.js
|
|
1223
|
+
/*! scure-base - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
1224
|
+
function isBytes(a) {
|
|
1225
|
+
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
|
|
1226
|
+
}
|
|
1227
|
+
function abytes(b, ...lengths) {
|
|
1228
|
+
if (!isBytes(b))
|
|
1229
|
+
throw new Error("Uint8Array expected");
|
|
1230
|
+
if (lengths.length > 0 && !lengths.includes(b.length))
|
|
1231
|
+
throw new Error("Uint8Array expected of length " + lengths + ", got length=" + b.length);
|
|
1232
|
+
}
|
|
1233
|
+
function isArrayOf(isString, arr) {
|
|
1234
|
+
if (!Array.isArray(arr))
|
|
1235
|
+
return false;
|
|
1236
|
+
if (arr.length === 0)
|
|
1237
|
+
return true;
|
|
1238
|
+
if (isString) {
|
|
1239
|
+
return arr.every((item) => typeof item === "string");
|
|
1240
|
+
} else {
|
|
1241
|
+
return arr.every((item) => Number.isSafeInteger(item));
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
function afn(input) {
|
|
1245
|
+
if (typeof input !== "function")
|
|
1246
|
+
throw new Error("function expected");
|
|
1247
|
+
return true;
|
|
1248
|
+
}
|
|
1249
|
+
function astr(label, input) {
|
|
1250
|
+
if (typeof input !== "string")
|
|
1251
|
+
throw new Error(`${label}: string expected`);
|
|
1252
|
+
return true;
|
|
1253
|
+
}
|
|
1254
|
+
function anumber(n) {
|
|
1255
|
+
if (!Number.isSafeInteger(n))
|
|
1256
|
+
throw new Error(`invalid integer: ${n}`);
|
|
1257
|
+
}
|
|
1258
|
+
function aArr(input) {
|
|
1259
|
+
if (!Array.isArray(input))
|
|
1260
|
+
throw new Error("array expected");
|
|
1261
|
+
}
|
|
1262
|
+
function astrArr(label, input) {
|
|
1263
|
+
if (!isArrayOf(true, input))
|
|
1264
|
+
throw new Error(`${label}: array of strings expected`);
|
|
1265
|
+
}
|
|
1266
|
+
function anumArr(label, input) {
|
|
1267
|
+
if (!isArrayOf(false, input))
|
|
1268
|
+
throw new Error(`${label}: array of numbers expected`);
|
|
1269
|
+
}
|
|
1270
|
+
function chain(...args) {
|
|
1271
|
+
const id = (a) => a;
|
|
1272
|
+
const wrap = (a, b) => (c) => a(b(c));
|
|
1273
|
+
const encode = args.map((x) => x.encode).reduceRight(wrap, id);
|
|
1274
|
+
const decode = args.map((x) => x.decode).reduce(wrap, id);
|
|
1275
|
+
return { encode, decode };
|
|
1276
|
+
}
|
|
1277
|
+
function alphabet(letters) {
|
|
1278
|
+
const lettersA = typeof letters === "string" ? letters.split("") : letters;
|
|
1279
|
+
const len = lettersA.length;
|
|
1280
|
+
astrArr("alphabet", lettersA);
|
|
1281
|
+
const indexes = new Map(lettersA.map((l, i) => [l, i]));
|
|
1282
|
+
return {
|
|
1283
|
+
encode: (digits) => {
|
|
1284
|
+
aArr(digits);
|
|
1285
|
+
return digits.map((i) => {
|
|
1286
|
+
if (!Number.isSafeInteger(i) || i < 0 || i >= len)
|
|
1287
|
+
throw new Error(`alphabet.encode: digit index outside alphabet "${i}". Allowed: ${letters}`);
|
|
1288
|
+
return lettersA[i];
|
|
1289
|
+
});
|
|
1290
|
+
},
|
|
1291
|
+
decode: (input) => {
|
|
1292
|
+
aArr(input);
|
|
1293
|
+
return input.map((letter) => {
|
|
1294
|
+
astr("alphabet.decode", letter);
|
|
1295
|
+
const i = indexes.get(letter);
|
|
1296
|
+
if (i === undefined)
|
|
1297
|
+
throw new Error(`Unknown letter: "${letter}". Allowed: ${letters}`);
|
|
1298
|
+
return i;
|
|
1299
|
+
});
|
|
1300
|
+
}
|
|
1301
|
+
};
|
|
1302
|
+
}
|
|
1303
|
+
function join3(separator = "") {
|
|
1304
|
+
astr("join", separator);
|
|
1305
|
+
return {
|
|
1306
|
+
encode: (from) => {
|
|
1307
|
+
astrArr("join.decode", from);
|
|
1308
|
+
return from.join(separator);
|
|
1309
|
+
},
|
|
1310
|
+
decode: (to) => {
|
|
1311
|
+
astr("join.decode", to);
|
|
1312
|
+
return to.split(separator);
|
|
1313
|
+
}
|
|
1314
|
+
};
|
|
1315
|
+
}
|
|
1316
|
+
function padding(bits, chr = "=") {
|
|
1317
|
+
anumber(bits);
|
|
1318
|
+
astr("padding", chr);
|
|
1319
|
+
return {
|
|
1320
|
+
encode(data) {
|
|
1321
|
+
astrArr("padding.encode", data);
|
|
1322
|
+
while (data.length * bits % 8)
|
|
1323
|
+
data.push(chr);
|
|
1324
|
+
return data;
|
|
1325
|
+
},
|
|
1326
|
+
decode(input) {
|
|
1327
|
+
astrArr("padding.decode", input);
|
|
1328
|
+
let end = input.length;
|
|
1329
|
+
if (end * bits % 8)
|
|
1330
|
+
throw new Error("padding: invalid, string should have whole number of bytes");
|
|
1331
|
+
for (;end > 0 && input[end - 1] === chr; end--) {
|
|
1332
|
+
const last = end - 1;
|
|
1333
|
+
const byte = last * bits;
|
|
1334
|
+
if (byte % 8 === 0)
|
|
1335
|
+
throw new Error("padding: invalid, string has too much padding");
|
|
1336
|
+
}
|
|
1337
|
+
return input.slice(0, end);
|
|
1338
|
+
}
|
|
1339
|
+
};
|
|
1340
|
+
}
|
|
1341
|
+
function normalize(fn) {
|
|
1342
|
+
afn(fn);
|
|
1343
|
+
return { encode: (from) => from, decode: (to) => fn(to) };
|
|
1344
|
+
}
|
|
1345
|
+
function convertRadix(data, from, to) {
|
|
1346
|
+
if (from < 2)
|
|
1347
|
+
throw new Error(`convertRadix: invalid from=${from}, base cannot be less than 2`);
|
|
1348
|
+
if (to < 2)
|
|
1349
|
+
throw new Error(`convertRadix: invalid to=${to}, base cannot be less than 2`);
|
|
1350
|
+
aArr(data);
|
|
1351
|
+
if (!data.length)
|
|
1352
|
+
return [];
|
|
1353
|
+
let pos = 0;
|
|
1354
|
+
const res = [];
|
|
1355
|
+
const digits = Array.from(data, (d) => {
|
|
1356
|
+
anumber(d);
|
|
1357
|
+
if (d < 0 || d >= from)
|
|
1358
|
+
throw new Error(`invalid integer: ${d}`);
|
|
1359
|
+
return d;
|
|
1360
|
+
});
|
|
1361
|
+
const dlen = digits.length;
|
|
1362
|
+
while (true) {
|
|
1363
|
+
let carry = 0;
|
|
1364
|
+
let done = true;
|
|
1365
|
+
for (let i = pos;i < dlen; i++) {
|
|
1366
|
+
const digit = digits[i];
|
|
1367
|
+
const fromCarry = from * carry;
|
|
1368
|
+
const digitBase = fromCarry + digit;
|
|
1369
|
+
if (!Number.isSafeInteger(digitBase) || fromCarry / from !== carry || digitBase - digit !== fromCarry) {
|
|
1370
|
+
throw new Error("convertRadix: carry overflow");
|
|
1371
|
+
}
|
|
1372
|
+
const div = digitBase / to;
|
|
1373
|
+
carry = digitBase % to;
|
|
1374
|
+
const rounded = Math.floor(div);
|
|
1375
|
+
digits[i] = rounded;
|
|
1376
|
+
if (!Number.isSafeInteger(rounded) || rounded * to + carry !== digitBase)
|
|
1377
|
+
throw new Error("convertRadix: carry overflow");
|
|
1378
|
+
if (!done)
|
|
1379
|
+
continue;
|
|
1380
|
+
else if (!rounded)
|
|
1381
|
+
pos = i;
|
|
1382
|
+
else
|
|
1383
|
+
done = false;
|
|
1384
|
+
}
|
|
1385
|
+
res.push(carry);
|
|
1386
|
+
if (done)
|
|
1387
|
+
break;
|
|
1388
|
+
}
|
|
1389
|
+
for (let i = 0;i < data.length - 1 && data[i] === 0; i++)
|
|
1390
|
+
res.push(0);
|
|
1391
|
+
return res.reverse();
|
|
1392
|
+
}
|
|
1393
|
+
var gcd = (a, b) => b === 0 ? a : gcd(b, a % b);
|
|
1394
|
+
var radix2carry = (from, to) => from + (to - gcd(from, to));
|
|
1395
|
+
var powers = /* @__PURE__ */ (() => {
|
|
1396
|
+
let res = [];
|
|
1397
|
+
for (let i = 0;i < 40; i++)
|
|
1398
|
+
res.push(2 ** i);
|
|
1399
|
+
return res;
|
|
1400
|
+
})();
|
|
1401
|
+
function convertRadix2(data, from, to, padding2) {
|
|
1402
|
+
aArr(data);
|
|
1403
|
+
if (from <= 0 || from > 32)
|
|
1404
|
+
throw new Error(`convertRadix2: wrong from=${from}`);
|
|
1405
|
+
if (to <= 0 || to > 32)
|
|
1406
|
+
throw new Error(`convertRadix2: wrong to=${to}`);
|
|
1407
|
+
if (radix2carry(from, to) > 32) {
|
|
1408
|
+
throw new Error(`convertRadix2: carry overflow from=${from} to=${to} carryBits=${radix2carry(from, to)}`);
|
|
1409
|
+
}
|
|
1410
|
+
let carry = 0;
|
|
1411
|
+
let pos = 0;
|
|
1412
|
+
const max = powers[from];
|
|
1413
|
+
const mask = powers[to] - 1;
|
|
1414
|
+
const res = [];
|
|
1415
|
+
for (const n of data) {
|
|
1416
|
+
anumber(n);
|
|
1417
|
+
if (n >= max)
|
|
1418
|
+
throw new Error(`convertRadix2: invalid data word=${n} from=${from}`);
|
|
1419
|
+
carry = carry << from | n;
|
|
1420
|
+
if (pos + from > 32)
|
|
1421
|
+
throw new Error(`convertRadix2: carry overflow pos=${pos} from=${from}`);
|
|
1422
|
+
pos += from;
|
|
1423
|
+
for (;pos >= to; pos -= to)
|
|
1424
|
+
res.push((carry >> pos - to & mask) >>> 0);
|
|
1425
|
+
const pow = powers[pos];
|
|
1426
|
+
if (pow === undefined)
|
|
1427
|
+
throw new Error("invalid carry");
|
|
1428
|
+
carry &= pow - 1;
|
|
1429
|
+
}
|
|
1430
|
+
carry = carry << to - pos & mask;
|
|
1431
|
+
if (!padding2 && pos >= from)
|
|
1432
|
+
throw new Error("Excess padding");
|
|
1433
|
+
if (!padding2 && carry > 0)
|
|
1434
|
+
throw new Error(`Non-zero padding: ${carry}`);
|
|
1435
|
+
if (padding2 && pos > 0)
|
|
1436
|
+
res.push(carry >>> 0);
|
|
1437
|
+
return res;
|
|
1438
|
+
}
|
|
1439
|
+
function radix(num) {
|
|
1440
|
+
anumber(num);
|
|
1441
|
+
const _256 = 2 ** 8;
|
|
1442
|
+
return {
|
|
1443
|
+
encode: (bytes) => {
|
|
1444
|
+
if (!isBytes(bytes))
|
|
1445
|
+
throw new Error("radix.encode input should be Uint8Array");
|
|
1446
|
+
return convertRadix(Array.from(bytes), _256, num);
|
|
1447
|
+
},
|
|
1448
|
+
decode: (digits) => {
|
|
1449
|
+
anumArr("radix.decode", digits);
|
|
1450
|
+
return Uint8Array.from(convertRadix(digits, num, _256));
|
|
1451
|
+
}
|
|
1452
|
+
};
|
|
1453
|
+
}
|
|
1454
|
+
function radix2(bits, revPadding = false) {
|
|
1455
|
+
anumber(bits);
|
|
1456
|
+
if (bits <= 0 || bits > 32)
|
|
1457
|
+
throw new Error("radix2: bits should be in (0..32]");
|
|
1458
|
+
if (radix2carry(8, bits) > 32 || radix2carry(bits, 8) > 32)
|
|
1459
|
+
throw new Error("radix2: carry overflow");
|
|
1460
|
+
return {
|
|
1461
|
+
encode: (bytes) => {
|
|
1462
|
+
if (!isBytes(bytes))
|
|
1463
|
+
throw new Error("radix2.encode input should be Uint8Array");
|
|
1464
|
+
return convertRadix2(Array.from(bytes), 8, bits, !revPadding);
|
|
1465
|
+
},
|
|
1466
|
+
decode: (digits) => {
|
|
1467
|
+
anumArr("radix2.decode", digits);
|
|
1468
|
+
return Uint8Array.from(convertRadix2(digits, bits, 8, revPadding));
|
|
1469
|
+
}
|
|
1470
|
+
};
|
|
1471
|
+
}
|
|
1472
|
+
function unsafeWrapper(fn) {
|
|
1473
|
+
afn(fn);
|
|
1474
|
+
return function(...args) {
|
|
1475
|
+
try {
|
|
1476
|
+
return fn.apply(null, args);
|
|
1477
|
+
} catch (e) {}
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
1480
|
+
var base16 = chain(radix2(4), alphabet("0123456789ABCDEF"), join3(""));
|
|
1481
|
+
var base32 = chain(radix2(5), alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"), padding(5), join3(""));
|
|
1482
|
+
var base32nopad = chain(radix2(5), alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"), join3(""));
|
|
1483
|
+
var base32hex = chain(radix2(5), alphabet("0123456789ABCDEFGHIJKLMNOPQRSTUV"), padding(5), join3(""));
|
|
1484
|
+
var base32hexnopad = chain(radix2(5), alphabet("0123456789ABCDEFGHIJKLMNOPQRSTUV"), join3(""));
|
|
1485
|
+
var base32crockford = chain(radix2(5), alphabet("0123456789ABCDEFGHJKMNPQRSTVWXYZ"), join3(""), normalize((s) => s.toUpperCase().replace(/O/g, "0").replace(/[IL]/g, "1")));
|
|
1486
|
+
var hasBase64Builtin = /* @__PURE__ */ (() => typeof Uint8Array.from([]).toBase64 === "function" && typeof Uint8Array.fromBase64 === "function")();
|
|
1487
|
+
var decodeBase64Builtin = (s, isUrl) => {
|
|
1488
|
+
astr("base64", s);
|
|
1489
|
+
const re = isUrl ? /^[A-Za-z0-9=_-]+$/ : /^[A-Za-z0-9=+/]+$/;
|
|
1490
|
+
const alphabet2 = isUrl ? "base64url" : "base64";
|
|
1491
|
+
if (s.length > 0 && !re.test(s))
|
|
1492
|
+
throw new Error("invalid base64");
|
|
1493
|
+
return Uint8Array.fromBase64(s, { alphabet: alphabet2, lastChunkHandling: "strict" });
|
|
1494
|
+
};
|
|
1495
|
+
var base64 = hasBase64Builtin ? {
|
|
1496
|
+
encode(b) {
|
|
1497
|
+
abytes(b);
|
|
1498
|
+
return b.toBase64();
|
|
1499
|
+
},
|
|
1500
|
+
decode(s) {
|
|
1501
|
+
return decodeBase64Builtin(s, false);
|
|
1502
|
+
}
|
|
1503
|
+
} : chain(radix2(6), alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), padding(6), join3(""));
|
|
1504
|
+
var base64nopad = chain(radix2(6), alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), join3(""));
|
|
1505
|
+
var base64url = hasBase64Builtin ? {
|
|
1506
|
+
encode(b) {
|
|
1507
|
+
abytes(b);
|
|
1508
|
+
return b.toBase64({ alphabet: "base64url" });
|
|
1509
|
+
},
|
|
1510
|
+
decode(s) {
|
|
1511
|
+
return decodeBase64Builtin(s, true);
|
|
1512
|
+
}
|
|
1513
|
+
} : chain(radix2(6), alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"), padding(6), join3(""));
|
|
1514
|
+
var base64urlnopad = chain(radix2(6), alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"), join3(""));
|
|
1515
|
+
var genBase58 = (abc) => chain(radix(58), alphabet(abc), join3(""));
|
|
1516
|
+
var base58 = genBase58("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz");
|
|
1517
|
+
var base58flickr = genBase58("123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ");
|
|
1518
|
+
var base58xrp = genBase58("rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz");
|
|
1519
|
+
var BECH_ALPHABET = chain(alphabet("qpzry9x8gf2tvdw0s3jn54khce6mua7l"), join3(""));
|
|
1520
|
+
var POLYMOD_GENERATORS = [996825010, 642813549, 513874426, 1027748829, 705979059];
|
|
1521
|
+
function bech32Polymod(pre) {
|
|
1522
|
+
const b = pre >> 25;
|
|
1523
|
+
let chk = (pre & 33554431) << 5;
|
|
1524
|
+
for (let i = 0;i < POLYMOD_GENERATORS.length; i++) {
|
|
1525
|
+
if ((b >> i & 1) === 1)
|
|
1526
|
+
chk ^= POLYMOD_GENERATORS[i];
|
|
1527
|
+
}
|
|
1528
|
+
return chk;
|
|
1529
|
+
}
|
|
1530
|
+
function bechChecksum(prefix, words, encodingConst = 1) {
|
|
1531
|
+
const len = prefix.length;
|
|
1532
|
+
let chk = 1;
|
|
1533
|
+
for (let i = 0;i < len; i++) {
|
|
1534
|
+
const c = prefix.charCodeAt(i);
|
|
1535
|
+
if (c < 33 || c > 126)
|
|
1536
|
+
throw new Error(`Invalid prefix (${prefix})`);
|
|
1537
|
+
chk = bech32Polymod(chk) ^ c >> 5;
|
|
1538
|
+
}
|
|
1539
|
+
chk = bech32Polymod(chk);
|
|
1540
|
+
for (let i = 0;i < len; i++)
|
|
1541
|
+
chk = bech32Polymod(chk) ^ prefix.charCodeAt(i) & 31;
|
|
1542
|
+
for (let v of words)
|
|
1543
|
+
chk = bech32Polymod(chk) ^ v;
|
|
1544
|
+
for (let i = 0;i < 6; i++)
|
|
1545
|
+
chk = bech32Polymod(chk);
|
|
1546
|
+
chk ^= encodingConst;
|
|
1547
|
+
return BECH_ALPHABET.encode(convertRadix2([chk % powers[30]], 30, 5, false));
|
|
1548
|
+
}
|
|
1549
|
+
function genBech32(encoding) {
|
|
1550
|
+
const ENCODING_CONST = encoding === "bech32" ? 1 : 734539939;
|
|
1551
|
+
const _words = radix2(5);
|
|
1552
|
+
const fromWords = _words.decode;
|
|
1553
|
+
const toWords = _words.encode;
|
|
1554
|
+
const fromWordsUnsafe = unsafeWrapper(fromWords);
|
|
1555
|
+
function encode(prefix, words, limit = 90) {
|
|
1556
|
+
astr("bech32.encode prefix", prefix);
|
|
1557
|
+
if (isBytes(words))
|
|
1558
|
+
words = Array.from(words);
|
|
1559
|
+
anumArr("bech32.encode", words);
|
|
1560
|
+
const plen = prefix.length;
|
|
1561
|
+
if (plen === 0)
|
|
1562
|
+
throw new TypeError(`Invalid prefix length ${plen}`);
|
|
1563
|
+
const actualLength = plen + 7 + words.length;
|
|
1564
|
+
if (limit !== false && actualLength > limit)
|
|
1565
|
+
throw new TypeError(`Length ${actualLength} exceeds limit ${limit}`);
|
|
1566
|
+
const lowered = prefix.toLowerCase();
|
|
1567
|
+
const sum = bechChecksum(lowered, words, ENCODING_CONST);
|
|
1568
|
+
return `${lowered}1${BECH_ALPHABET.encode(words)}${sum}`;
|
|
1569
|
+
}
|
|
1570
|
+
function decode(str, limit = 90) {
|
|
1571
|
+
astr("bech32.decode input", str);
|
|
1572
|
+
const slen = str.length;
|
|
1573
|
+
if (slen < 8 || limit !== false && slen > limit)
|
|
1574
|
+
throw new TypeError(`invalid string length: ${slen} (${str}). Expected (8..${limit})`);
|
|
1575
|
+
const lowered = str.toLowerCase();
|
|
1576
|
+
if (str !== lowered && str !== str.toUpperCase())
|
|
1577
|
+
throw new Error(`String must be lowercase or uppercase`);
|
|
1578
|
+
const sepIndex = lowered.lastIndexOf("1");
|
|
1579
|
+
if (sepIndex === 0 || sepIndex === -1)
|
|
1580
|
+
throw new Error(`Letter "1" must be present between prefix and data only`);
|
|
1581
|
+
const prefix = lowered.slice(0, sepIndex);
|
|
1582
|
+
const data = lowered.slice(sepIndex + 1);
|
|
1583
|
+
if (data.length < 6)
|
|
1584
|
+
throw new Error("Data must be at least 6 characters long");
|
|
1585
|
+
const words = BECH_ALPHABET.decode(data).slice(0, -6);
|
|
1586
|
+
const sum = bechChecksum(prefix, words, ENCODING_CONST);
|
|
1587
|
+
if (!data.endsWith(sum))
|
|
1588
|
+
throw new Error(`Invalid checksum in ${str}: expected "${sum}"`);
|
|
1589
|
+
return { prefix, words };
|
|
1590
|
+
}
|
|
1591
|
+
const decodeUnsafe = unsafeWrapper(decode);
|
|
1592
|
+
function decodeToBytes(str) {
|
|
1593
|
+
const { prefix, words } = decode(str, false);
|
|
1594
|
+
return { prefix, words, bytes: fromWords(words) };
|
|
1595
|
+
}
|
|
1596
|
+
function encodeFromBytes(prefix, bytes) {
|
|
1597
|
+
return encode(prefix, toWords(bytes));
|
|
1598
|
+
}
|
|
1599
|
+
return {
|
|
1600
|
+
encode,
|
|
1601
|
+
decode,
|
|
1602
|
+
encodeFromBytes,
|
|
1603
|
+
decodeToBytes,
|
|
1604
|
+
decodeUnsafe,
|
|
1605
|
+
fromWords,
|
|
1606
|
+
fromWordsUnsafe,
|
|
1607
|
+
toWords
|
|
1608
|
+
};
|
|
1609
|
+
}
|
|
1610
|
+
var bech32 = genBech32("bech32");
|
|
1611
|
+
var bech32m = genBech32("bech32m");
|
|
1612
|
+
var hasHexBuiltin = /* @__PURE__ */ (() => typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function")();
|
|
1613
|
+
var hexBuiltin = {
|
|
1614
|
+
encode(data) {
|
|
1615
|
+
abytes(data);
|
|
1616
|
+
return data.toHex();
|
|
1617
|
+
},
|
|
1618
|
+
decode(s) {
|
|
1619
|
+
astr("hex", s);
|
|
1620
|
+
return Uint8Array.fromHex(s);
|
|
1621
|
+
}
|
|
1622
|
+
};
|
|
1623
|
+
var hex = hasHexBuiltin ? hexBuiltin : chain(radix2(4), alphabet("0123456789abcdef"), join3(""), normalize((s) => {
|
|
1624
|
+
if (typeof s !== "string" || s.length % 2 !== 0)
|
|
1625
|
+
throw new TypeError(`hex.decode: expected string, got ${typeof s} with length ${s.length}`);
|
|
1626
|
+
return s.toLowerCase();
|
|
1627
|
+
}));
|
|
1628
|
+
|
|
1629
|
+
// ../../node_modules/@hpke/chacha20poly1305/esm/src/chacha/utils.js
|
|
1630
|
+
function isBytes2(a) {
|
|
1631
|
+
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
|
|
1632
|
+
}
|
|
1633
|
+
function abool(b) {
|
|
1634
|
+
if (typeof b !== "boolean")
|
|
1635
|
+
throw new Error(`boolean expected, not ${b}`);
|
|
1636
|
+
}
|
|
1637
|
+
function anumber2(n) {
|
|
1638
|
+
if (!Number.isSafeInteger(n) || n < 0) {
|
|
1639
|
+
throw new Error("positive integer expected, got " + n);
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
function abytes2(value, length, title = "") {
|
|
1643
|
+
const bytes = isBytes2(value);
|
|
1644
|
+
const len = value?.length;
|
|
1645
|
+
const needsLen = length !== undefined;
|
|
1646
|
+
if (!bytes || needsLen && len !== length) {
|
|
1647
|
+
const prefix = title && `"${title}" `;
|
|
1648
|
+
const ofLen = needsLen ? ` of length ${length}` : "";
|
|
1649
|
+
const got = bytes ? `length=${len}` : `type=${typeof value}`;
|
|
1650
|
+
throw new Error(prefix + "expected Uint8Array" + ofLen + ", got " + got);
|
|
1651
|
+
}
|
|
1652
|
+
return value;
|
|
1653
|
+
}
|
|
1654
|
+
function aexists(instance, checkFinished = true) {
|
|
1655
|
+
if (instance.destroyed)
|
|
1656
|
+
throw new Error("Hash instance has been destroyed");
|
|
1657
|
+
if (checkFinished && instance.finished) {
|
|
1658
|
+
throw new Error("Hash#digest() has already been called");
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
function aoutput(out, instance) {
|
|
1662
|
+
abytes2(out, undefined, "output");
|
|
1663
|
+
const min = instance.outputLen;
|
|
1664
|
+
if (out.length < min) {
|
|
1665
|
+
throw new Error("digestInto() expects output buffer of length at least " + min);
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
function u32(arr) {
|
|
1669
|
+
return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));
|
|
1670
|
+
}
|
|
1671
|
+
function clean(...arrays) {
|
|
1672
|
+
for (let i = 0;i < arrays.length; i++) {
|
|
1673
|
+
arrays[i].fill(0);
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
function createView(arr) {
|
|
1677
|
+
return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
1678
|
+
}
|
|
1679
|
+
var isLE = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68)();
|
|
1680
|
+
function checkOpts(defaults, opts) {
|
|
1681
|
+
if (opts == null || typeof opts !== "object") {
|
|
1682
|
+
throw new Error("options must be defined");
|
|
1683
|
+
}
|
|
1684
|
+
const merged = Object.assign(defaults, opts);
|
|
1685
|
+
return merged;
|
|
1686
|
+
}
|
|
1687
|
+
function equalBytes(a, b) {
|
|
1688
|
+
if (a.length !== b.length)
|
|
1689
|
+
return false;
|
|
1690
|
+
let diff = 0;
|
|
1691
|
+
for (let i = 0;i < a.length; i++)
|
|
1692
|
+
diff |= a[i] ^ b[i];
|
|
1693
|
+
return diff === 0;
|
|
1694
|
+
}
|
|
1695
|
+
var wrapCipher = (params, constructor) => {
|
|
1696
|
+
function wrappedCipher(key, ...args) {
|
|
1697
|
+
abytes2(key, undefined, "key");
|
|
1698
|
+
if (!isLE) {
|
|
1699
|
+
throw new Error("Non little-endian hardware is not yet supported");
|
|
1700
|
+
}
|
|
1701
|
+
if (params.nonceLength !== undefined) {
|
|
1702
|
+
const nonce = args[0];
|
|
1703
|
+
abytes2(nonce, params.varSizeNonce ? undefined : params.nonceLength, "nonce");
|
|
1704
|
+
}
|
|
1705
|
+
const tagl = params.tagLength;
|
|
1706
|
+
if (tagl && args[1] !== undefined)
|
|
1707
|
+
abytes2(args[1], undefined, "AAD");
|
|
1708
|
+
const cipher = constructor(key, ...args);
|
|
1709
|
+
const checkOutput = (fnLength, output) => {
|
|
1710
|
+
if (output !== undefined) {
|
|
1711
|
+
if (fnLength !== 2)
|
|
1712
|
+
throw new Error("cipher output not supported");
|
|
1713
|
+
abytes2(output, undefined, "output");
|
|
1714
|
+
}
|
|
1715
|
+
};
|
|
1716
|
+
let called = false;
|
|
1717
|
+
const wrCipher = {
|
|
1718
|
+
encrypt(data, output) {
|
|
1719
|
+
if (called) {
|
|
1720
|
+
throw new Error("cannot encrypt() twice with same key + nonce");
|
|
1721
|
+
}
|
|
1722
|
+
called = true;
|
|
1723
|
+
abytes2(data);
|
|
1724
|
+
checkOutput(cipher.encrypt.length, output);
|
|
1725
|
+
return cipher.encrypt(data, output);
|
|
1726
|
+
},
|
|
1727
|
+
decrypt(data, output) {
|
|
1728
|
+
abytes2(data);
|
|
1729
|
+
if (tagl && data.length < tagl) {
|
|
1730
|
+
throw new Error('"ciphertext" expected length bigger than tagLength=' + tagl);
|
|
1731
|
+
}
|
|
1732
|
+
checkOutput(cipher.decrypt.length, output);
|
|
1733
|
+
return cipher.decrypt(data, output);
|
|
1734
|
+
}
|
|
1735
|
+
};
|
|
1736
|
+
return wrCipher;
|
|
1737
|
+
}
|
|
1738
|
+
Object.assign(wrappedCipher, params);
|
|
1739
|
+
return wrappedCipher;
|
|
1740
|
+
};
|
|
1741
|
+
function getOutput(expectedLength, out, onlyAligned = true) {
|
|
1742
|
+
if (out === undefined)
|
|
1743
|
+
return new Uint8Array(expectedLength);
|
|
1744
|
+
if (out.length !== expectedLength) {
|
|
1745
|
+
throw new Error('"output" expected Uint8Array of length ' + expectedLength + ", got: " + out.length);
|
|
1746
|
+
}
|
|
1747
|
+
if (onlyAligned && !isAligned32(out)) {
|
|
1748
|
+
throw new Error("invalid output, must be aligned");
|
|
1749
|
+
}
|
|
1750
|
+
return out;
|
|
1751
|
+
}
|
|
1752
|
+
function u64Lengths(dataLength, aadLength, isLE2) {
|
|
1753
|
+
abool(isLE2);
|
|
1754
|
+
const num = new Uint8Array(16);
|
|
1755
|
+
const view = createView(num);
|
|
1756
|
+
view.setBigUint64(0, BigInt(aadLength), isLE2);
|
|
1757
|
+
view.setBigUint64(8, BigInt(dataLength), isLE2);
|
|
1758
|
+
return num;
|
|
1759
|
+
}
|
|
1760
|
+
function isAligned32(bytes) {
|
|
1761
|
+
return bytes.byteOffset % 4 === 0;
|
|
1762
|
+
}
|
|
1763
|
+
function copyBytes(bytes) {
|
|
1764
|
+
return Uint8Array.from(bytes);
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
// ../../node_modules/@hpke/chacha20poly1305/esm/src/chacha/_arx.js
|
|
1768
|
+
var _utf8ToBytes = (str) => Uint8Array.from(str.split("").map((c) => c.charCodeAt(0)));
|
|
1769
|
+
var sigma16 = _utf8ToBytes("expand 16-byte k");
|
|
1770
|
+
var sigma32 = _utf8ToBytes("expand 32-byte k");
|
|
1771
|
+
var sigma16_32 = u32(sigma16);
|
|
1772
|
+
var sigma32_32 = u32(sigma32);
|
|
1773
|
+
function rotl(a, b) {
|
|
1774
|
+
return a << b | a >>> 32 - b;
|
|
1775
|
+
}
|
|
1776
|
+
function isAligned322(b) {
|
|
1777
|
+
return b.byteOffset % 4 === 0;
|
|
1778
|
+
}
|
|
1779
|
+
var BLOCK_LEN = 64;
|
|
1780
|
+
var BLOCK_LEN32 = 16;
|
|
1781
|
+
var MAX_COUNTER = 2 ** 32 - 1;
|
|
1782
|
+
var U32_EMPTY = Uint32Array.of();
|
|
1783
|
+
function runCipher(core, sigma, key, nonce, data, output, counter, rounds) {
|
|
1784
|
+
const len = data.length;
|
|
1785
|
+
const block = new Uint8Array(BLOCK_LEN);
|
|
1786
|
+
const b32 = u32(block);
|
|
1787
|
+
const isAligned = isAligned322(data) && isAligned322(output);
|
|
1788
|
+
const d32 = isAligned ? u32(data) : U32_EMPTY;
|
|
1789
|
+
const o32 = isAligned ? u32(output) : U32_EMPTY;
|
|
1790
|
+
for (let pos = 0;pos < len; counter++) {
|
|
1791
|
+
core(sigma, key, nonce, b32, counter, rounds);
|
|
1792
|
+
if (counter >= MAX_COUNTER)
|
|
1793
|
+
throw new Error("arx: counter overflow");
|
|
1794
|
+
const take = Math.min(BLOCK_LEN, len - pos);
|
|
1795
|
+
if (isAligned && take === BLOCK_LEN) {
|
|
1796
|
+
const pos32 = pos / 4;
|
|
1797
|
+
if (pos % 4 !== 0)
|
|
1798
|
+
throw new Error("arx: invalid block position");
|
|
1799
|
+
for (let j = 0, posj;j < BLOCK_LEN32; j++) {
|
|
1800
|
+
posj = pos32 + j;
|
|
1801
|
+
o32[posj] = d32[posj] ^ b32[j];
|
|
1802
|
+
}
|
|
1803
|
+
pos += BLOCK_LEN;
|
|
1804
|
+
continue;
|
|
1805
|
+
}
|
|
1806
|
+
for (let j = 0, posj;j < take; j++) {
|
|
1807
|
+
posj = pos + j;
|
|
1808
|
+
output[posj] = data[posj] ^ block[j];
|
|
1809
|
+
}
|
|
1810
|
+
pos += take;
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
function createCipher(core, opts) {
|
|
1814
|
+
const { allowShortKeys, extendNonceFn, counterLength, counterRight, rounds } = checkOpts({
|
|
1815
|
+
allowShortKeys: false,
|
|
1816
|
+
counterLength: 8,
|
|
1817
|
+
counterRight: false,
|
|
1818
|
+
rounds: 20
|
|
1819
|
+
}, opts);
|
|
1820
|
+
if (typeof core !== "function")
|
|
1821
|
+
throw new Error("core must be a function");
|
|
1822
|
+
anumber2(counterLength);
|
|
1823
|
+
anumber2(rounds);
|
|
1824
|
+
abool(counterRight);
|
|
1825
|
+
abool(allowShortKeys);
|
|
1826
|
+
return (key, nonce, data, output, counter = 0) => {
|
|
1827
|
+
abytes2(key, undefined, "key");
|
|
1828
|
+
abytes2(nonce, undefined, "nonce");
|
|
1829
|
+
abytes2(data, undefined, "data");
|
|
1830
|
+
const len = data.length;
|
|
1831
|
+
if (output === undefined)
|
|
1832
|
+
output = new Uint8Array(len);
|
|
1833
|
+
abytes2(output, undefined, "output");
|
|
1834
|
+
anumber2(counter);
|
|
1835
|
+
if (counter < 0 || counter >= MAX_COUNTER) {
|
|
1836
|
+
throw new Error("arx: counter overflow");
|
|
1837
|
+
}
|
|
1838
|
+
if (output.length < len) {
|
|
1839
|
+
throw new Error(`arx: output (${output.length}) is shorter than data (${len})`);
|
|
1840
|
+
}
|
|
1841
|
+
const toClean = [];
|
|
1842
|
+
const l = key.length;
|
|
1843
|
+
let k;
|
|
1844
|
+
let sigma;
|
|
1845
|
+
if (l === 32) {
|
|
1846
|
+
toClean.push(k = copyBytes(key));
|
|
1847
|
+
sigma = sigma32_32;
|
|
1848
|
+
} else if (l === 16 && allowShortKeys) {
|
|
1849
|
+
k = new Uint8Array(32);
|
|
1850
|
+
k.set(key);
|
|
1851
|
+
k.set(key, 16);
|
|
1852
|
+
sigma = sigma16_32;
|
|
1853
|
+
toClean.push(k);
|
|
1854
|
+
} else {
|
|
1855
|
+
abytes2(key, 32, "arx key");
|
|
1856
|
+
throw new Error("invalid key size");
|
|
1857
|
+
}
|
|
1858
|
+
if (!isAligned322(nonce))
|
|
1859
|
+
toClean.push(nonce = copyBytes(nonce));
|
|
1860
|
+
const k32 = u32(k);
|
|
1861
|
+
if (extendNonceFn) {
|
|
1862
|
+
if (nonce.length !== 24) {
|
|
1863
|
+
throw new Error(`arx: extended nonce must be 24 bytes`);
|
|
1864
|
+
}
|
|
1865
|
+
extendNonceFn(sigma, k32, u32(nonce.subarray(0, 16)), k32);
|
|
1866
|
+
nonce = nonce.subarray(16);
|
|
1867
|
+
}
|
|
1868
|
+
const nonceNcLen = 16 - counterLength;
|
|
1869
|
+
if (nonceNcLen !== nonce.length) {
|
|
1870
|
+
throw new Error(`arx: nonce must be ${nonceNcLen} or 16 bytes`);
|
|
1871
|
+
}
|
|
1872
|
+
if (nonceNcLen !== 12) {
|
|
1873
|
+
const nc = new Uint8Array(12);
|
|
1874
|
+
nc.set(nonce, counterRight ? 0 : 12 - nonce.length);
|
|
1875
|
+
nonce = nc;
|
|
1876
|
+
toClean.push(nonce);
|
|
1877
|
+
}
|
|
1878
|
+
const n32 = u32(nonce);
|
|
1879
|
+
runCipher(core, sigma, k32, n32, data, output, counter, rounds);
|
|
1880
|
+
clean(...toClean);
|
|
1881
|
+
return output;
|
|
1882
|
+
};
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
// ../../node_modules/@hpke/chacha20poly1305/esm/src/chacha/_poly1305.js
|
|
1886
|
+
function u8to16(a, i) {
|
|
1887
|
+
return a[i++] & 255 | (a[i++] & 255) << 8;
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
class Poly1305 {
|
|
1891
|
+
constructor(key) {
|
|
1892
|
+
Object.defineProperty(this, "blockLen", {
|
|
1893
|
+
enumerable: true,
|
|
1894
|
+
configurable: true,
|
|
1895
|
+
writable: true,
|
|
1896
|
+
value: 16
|
|
1897
|
+
});
|
|
1898
|
+
Object.defineProperty(this, "outputLen", {
|
|
1899
|
+
enumerable: true,
|
|
1900
|
+
configurable: true,
|
|
1901
|
+
writable: true,
|
|
1902
|
+
value: 16
|
|
1903
|
+
});
|
|
1904
|
+
Object.defineProperty(this, "buffer", {
|
|
1905
|
+
enumerable: true,
|
|
1906
|
+
configurable: true,
|
|
1907
|
+
writable: true,
|
|
1908
|
+
value: new Uint8Array(16)
|
|
1909
|
+
});
|
|
1910
|
+
Object.defineProperty(this, "r", {
|
|
1911
|
+
enumerable: true,
|
|
1912
|
+
configurable: true,
|
|
1913
|
+
writable: true,
|
|
1914
|
+
value: new Uint16Array(10)
|
|
1915
|
+
});
|
|
1916
|
+
Object.defineProperty(this, "h", {
|
|
1917
|
+
enumerable: true,
|
|
1918
|
+
configurable: true,
|
|
1919
|
+
writable: true,
|
|
1920
|
+
value: new Uint16Array(10)
|
|
1921
|
+
});
|
|
1922
|
+
Object.defineProperty(this, "pad", {
|
|
1923
|
+
enumerable: true,
|
|
1924
|
+
configurable: true,
|
|
1925
|
+
writable: true,
|
|
1926
|
+
value: new Uint16Array(8)
|
|
1927
|
+
});
|
|
1928
|
+
Object.defineProperty(this, "pos", {
|
|
1929
|
+
enumerable: true,
|
|
1930
|
+
configurable: true,
|
|
1931
|
+
writable: true,
|
|
1932
|
+
value: 0
|
|
1933
|
+
});
|
|
1934
|
+
Object.defineProperty(this, "finished", {
|
|
1935
|
+
enumerable: true,
|
|
1936
|
+
configurable: true,
|
|
1937
|
+
writable: true,
|
|
1938
|
+
value: false
|
|
1939
|
+
});
|
|
1940
|
+
key = copyBytes(abytes2(key, 32, "key"));
|
|
1941
|
+
const t0 = u8to16(key, 0);
|
|
1942
|
+
const t1 = u8to16(key, 2);
|
|
1943
|
+
const t2 = u8to16(key, 4);
|
|
1944
|
+
const t3 = u8to16(key, 6);
|
|
1945
|
+
const t4 = u8to16(key, 8);
|
|
1946
|
+
const t5 = u8to16(key, 10);
|
|
1947
|
+
const t6 = u8to16(key, 12);
|
|
1948
|
+
const t7 = u8to16(key, 14);
|
|
1949
|
+
this.r[0] = t0 & 8191;
|
|
1950
|
+
this.r[1] = (t0 >>> 13 | t1 << 3) & 8191;
|
|
1951
|
+
this.r[2] = (t1 >>> 10 | t2 << 6) & 7939;
|
|
1952
|
+
this.r[3] = (t2 >>> 7 | t3 << 9) & 8191;
|
|
1953
|
+
this.r[4] = (t3 >>> 4 | t4 << 12) & 255;
|
|
1954
|
+
this.r[5] = t4 >>> 1 & 8190;
|
|
1955
|
+
this.r[6] = (t4 >>> 14 | t5 << 2) & 8191;
|
|
1956
|
+
this.r[7] = (t5 >>> 11 | t6 << 5) & 8065;
|
|
1957
|
+
this.r[8] = (t6 >>> 8 | t7 << 8) & 8191;
|
|
1958
|
+
this.r[9] = t7 >>> 5 & 127;
|
|
1959
|
+
for (let i = 0;i < 8; i++)
|
|
1960
|
+
this.pad[i] = u8to16(key, 16 + 2 * i);
|
|
1961
|
+
}
|
|
1962
|
+
process(data, offset, isLast = false) {
|
|
1963
|
+
const hibit = isLast ? 0 : 1 << 11;
|
|
1964
|
+
const { h, r } = this;
|
|
1965
|
+
const r0 = r[0];
|
|
1966
|
+
const r1 = r[1];
|
|
1967
|
+
const r2 = r[2];
|
|
1968
|
+
const r3 = r[3];
|
|
1969
|
+
const r4 = r[4];
|
|
1970
|
+
const r5 = r[5];
|
|
1971
|
+
const r6 = r[6];
|
|
1972
|
+
const r7 = r[7];
|
|
1973
|
+
const r8 = r[8];
|
|
1974
|
+
const r9 = r[9];
|
|
1975
|
+
const t0 = u8to16(data, offset + 0);
|
|
1976
|
+
const t1 = u8to16(data, offset + 2);
|
|
1977
|
+
const t2 = u8to16(data, offset + 4);
|
|
1978
|
+
const t3 = u8to16(data, offset + 6);
|
|
1979
|
+
const t4 = u8to16(data, offset + 8);
|
|
1980
|
+
const t5 = u8to16(data, offset + 10);
|
|
1981
|
+
const t6 = u8to16(data, offset + 12);
|
|
1982
|
+
const t7 = u8to16(data, offset + 14);
|
|
1983
|
+
const h0 = h[0] + (t0 & 8191);
|
|
1984
|
+
const h1 = h[1] + ((t0 >>> 13 | t1 << 3) & 8191);
|
|
1985
|
+
const h2 = h[2] + ((t1 >>> 10 | t2 << 6) & 8191);
|
|
1986
|
+
const h3 = h[3] + ((t2 >>> 7 | t3 << 9) & 8191);
|
|
1987
|
+
const h4 = h[4] + ((t3 >>> 4 | t4 << 12) & 8191);
|
|
1988
|
+
const h5 = h[5] + (t4 >>> 1 & 8191);
|
|
1989
|
+
const h6 = h[6] + ((t4 >>> 14 | t5 << 2) & 8191);
|
|
1990
|
+
const h7 = h[7] + ((t5 >>> 11 | t6 << 5) & 8191);
|
|
1991
|
+
const h8 = h[8] + ((t6 >>> 8 | t7 << 8) & 8191);
|
|
1992
|
+
const h9 = h[9] + (t7 >>> 5 | hibit);
|
|
1993
|
+
let c = 0;
|
|
1994
|
+
let d0 = c + h0 * r0 + h1 * (5 * r9) + h2 * (5 * r8) + h3 * (5 * r7) + h4 * (5 * r6);
|
|
1995
|
+
c = d0 >>> 13;
|
|
1996
|
+
d0 &= 8191;
|
|
1997
|
+
d0 += h5 * (5 * r5) + h6 * (5 * r4) + h7 * (5 * r3) + h8 * (5 * r2) + h9 * (5 * r1);
|
|
1998
|
+
c += d0 >>> 13;
|
|
1999
|
+
d0 &= 8191;
|
|
2000
|
+
let d1 = c + h0 * r1 + h1 * r0 + h2 * (5 * r9) + h3 * (5 * r8) + h4 * (5 * r7);
|
|
2001
|
+
c = d1 >>> 13;
|
|
2002
|
+
d1 &= 8191;
|
|
2003
|
+
d1 += h5 * (5 * r6) + h6 * (5 * r5) + h7 * (5 * r4) + h8 * (5 * r3) + h9 * (5 * r2);
|
|
2004
|
+
c += d1 >>> 13;
|
|
2005
|
+
d1 &= 8191;
|
|
2006
|
+
let d2 = c + h0 * r2 + h1 * r1 + h2 * r0 + h3 * (5 * r9) + h4 * (5 * r8);
|
|
2007
|
+
c = d2 >>> 13;
|
|
2008
|
+
d2 &= 8191;
|
|
2009
|
+
d2 += h5 * (5 * r7) + h6 * (5 * r6) + h7 * (5 * r5) + h8 * (5 * r4) + h9 * (5 * r3);
|
|
2010
|
+
c += d2 >>> 13;
|
|
2011
|
+
d2 &= 8191;
|
|
2012
|
+
let d3 = c + h0 * r3 + h1 * r2 + h2 * r1 + h3 * r0 + h4 * (5 * r9);
|
|
2013
|
+
c = d3 >>> 13;
|
|
2014
|
+
d3 &= 8191;
|
|
2015
|
+
d3 += h5 * (5 * r8) + h6 * (5 * r7) + h7 * (5 * r6) + h8 * (5 * r5) + h9 * (5 * r4);
|
|
2016
|
+
c += d3 >>> 13;
|
|
2017
|
+
d3 &= 8191;
|
|
2018
|
+
let d4 = c + h0 * r4 + h1 * r3 + h2 * r2 + h3 * r1 + h4 * r0;
|
|
2019
|
+
c = d4 >>> 13;
|
|
2020
|
+
d4 &= 8191;
|
|
2021
|
+
d4 += h5 * (5 * r9) + h6 * (5 * r8) + h7 * (5 * r7) + h8 * (5 * r6) + h9 * (5 * r5);
|
|
2022
|
+
c += d4 >>> 13;
|
|
2023
|
+
d4 &= 8191;
|
|
2024
|
+
let d5 = c + h0 * r5 + h1 * r4 + h2 * r3 + h3 * r2 + h4 * r1;
|
|
2025
|
+
c = d5 >>> 13;
|
|
2026
|
+
d5 &= 8191;
|
|
2027
|
+
d5 += h5 * r0 + h6 * (5 * r9) + h7 * (5 * r8) + h8 * (5 * r7) + h9 * (5 * r6);
|
|
2028
|
+
c += d5 >>> 13;
|
|
2029
|
+
d5 &= 8191;
|
|
2030
|
+
let d6 = c + h0 * r6 + h1 * r5 + h2 * r4 + h3 * r3 + h4 * r2;
|
|
2031
|
+
c = d6 >>> 13;
|
|
2032
|
+
d6 &= 8191;
|
|
2033
|
+
d6 += h5 * r1 + h6 * r0 + h7 * (5 * r9) + h8 * (5 * r8) + h9 * (5 * r7);
|
|
2034
|
+
c += d6 >>> 13;
|
|
2035
|
+
d6 &= 8191;
|
|
2036
|
+
let d7 = c + h0 * r7 + h1 * r6 + h2 * r5 + h3 * r4 + h4 * r3;
|
|
2037
|
+
c = d7 >>> 13;
|
|
2038
|
+
d7 &= 8191;
|
|
2039
|
+
d7 += h5 * r2 + h6 * r1 + h7 * r0 + h8 * (5 * r9) + h9 * (5 * r8);
|
|
2040
|
+
c += d7 >>> 13;
|
|
2041
|
+
d7 &= 8191;
|
|
2042
|
+
let d8 = c + h0 * r8 + h1 * r7 + h2 * r6 + h3 * r5 + h4 * r4;
|
|
2043
|
+
c = d8 >>> 13;
|
|
2044
|
+
d8 &= 8191;
|
|
2045
|
+
d8 += h5 * r3 + h6 * r2 + h7 * r1 + h8 * r0 + h9 * (5 * r9);
|
|
2046
|
+
c += d8 >>> 13;
|
|
2047
|
+
d8 &= 8191;
|
|
2048
|
+
let d9 = c + h0 * r9 + h1 * r8 + h2 * r7 + h3 * r6 + h4 * r5;
|
|
2049
|
+
c = d9 >>> 13;
|
|
2050
|
+
d9 &= 8191;
|
|
2051
|
+
d9 += h5 * r4 + h6 * r3 + h7 * r2 + h8 * r1 + h9 * r0;
|
|
2052
|
+
c += d9 >>> 13;
|
|
2053
|
+
d9 &= 8191;
|
|
2054
|
+
c = (c << 2) + c | 0;
|
|
2055
|
+
c = c + d0 | 0;
|
|
2056
|
+
d0 = c & 8191;
|
|
2057
|
+
c = c >>> 13;
|
|
2058
|
+
d1 += c;
|
|
2059
|
+
h[0] = d0;
|
|
2060
|
+
h[1] = d1;
|
|
2061
|
+
h[2] = d2;
|
|
2062
|
+
h[3] = d3;
|
|
2063
|
+
h[4] = d4;
|
|
2064
|
+
h[5] = d5;
|
|
2065
|
+
h[6] = d6;
|
|
2066
|
+
h[7] = d7;
|
|
2067
|
+
h[8] = d8;
|
|
2068
|
+
h[9] = d9;
|
|
2069
|
+
}
|
|
2070
|
+
finalize() {
|
|
2071
|
+
const { h, pad } = this;
|
|
2072
|
+
const g = new Uint16Array(10);
|
|
2073
|
+
let c = h[1] >>> 13;
|
|
2074
|
+
h[1] &= 8191;
|
|
2075
|
+
for (let i = 2;i < 10; i++) {
|
|
2076
|
+
h[i] += c;
|
|
2077
|
+
c = h[i] >>> 13;
|
|
2078
|
+
h[i] &= 8191;
|
|
2079
|
+
}
|
|
2080
|
+
h[0] += c * 5;
|
|
2081
|
+
c = h[0] >>> 13;
|
|
2082
|
+
h[0] &= 8191;
|
|
2083
|
+
h[1] += c;
|
|
2084
|
+
c = h[1] >>> 13;
|
|
2085
|
+
h[1] &= 8191;
|
|
2086
|
+
h[2] += c;
|
|
2087
|
+
g[0] = h[0] + 5;
|
|
2088
|
+
c = g[0] >>> 13;
|
|
2089
|
+
g[0] &= 8191;
|
|
2090
|
+
for (let i = 1;i < 10; i++) {
|
|
2091
|
+
g[i] = h[i] + c;
|
|
2092
|
+
c = g[i] >>> 13;
|
|
2093
|
+
g[i] &= 8191;
|
|
2094
|
+
}
|
|
2095
|
+
g[9] -= 1 << 13;
|
|
2096
|
+
let mask = (c ^ 1) - 1;
|
|
2097
|
+
for (let i = 0;i < 10; i++)
|
|
2098
|
+
g[i] &= mask;
|
|
2099
|
+
mask = ~mask;
|
|
2100
|
+
for (let i = 0;i < 10; i++)
|
|
2101
|
+
h[i] = h[i] & mask | g[i];
|
|
2102
|
+
h[0] = (h[0] | h[1] << 13) & 65535;
|
|
2103
|
+
h[1] = (h[1] >>> 3 | h[2] << 10) & 65535;
|
|
2104
|
+
h[2] = (h[2] >>> 6 | h[3] << 7) & 65535;
|
|
2105
|
+
h[3] = (h[3] >>> 9 | h[4] << 4) & 65535;
|
|
2106
|
+
h[4] = (h[4] >>> 12 | h[5] << 1 | h[6] << 14) & 65535;
|
|
2107
|
+
h[5] = (h[6] >>> 2 | h[7] << 11) & 65535;
|
|
2108
|
+
h[6] = (h[7] >>> 5 | h[8] << 8) & 65535;
|
|
2109
|
+
h[7] = (h[8] >>> 8 | h[9] << 5) & 65535;
|
|
2110
|
+
let f = h[0] + pad[0];
|
|
2111
|
+
h[0] = f & 65535;
|
|
2112
|
+
for (let i = 1;i < 8; i++) {
|
|
2113
|
+
f = (h[i] + pad[i] | 0) + (f >>> 16) | 0;
|
|
2114
|
+
h[i] = f & 65535;
|
|
2115
|
+
}
|
|
2116
|
+
clean(g);
|
|
2117
|
+
}
|
|
2118
|
+
update(data) {
|
|
2119
|
+
aexists(this);
|
|
2120
|
+
abytes2(data);
|
|
2121
|
+
data = copyBytes(data);
|
|
2122
|
+
const { buffer, blockLen } = this;
|
|
2123
|
+
const len = data.length;
|
|
2124
|
+
for (let pos = 0;pos < len; ) {
|
|
2125
|
+
const take = Math.min(blockLen - this.pos, len - pos);
|
|
2126
|
+
if (take === blockLen) {
|
|
2127
|
+
for (;blockLen <= len - pos; pos += blockLen)
|
|
2128
|
+
this.process(data, pos);
|
|
2129
|
+
continue;
|
|
2130
|
+
}
|
|
2131
|
+
buffer.set(data.subarray(pos, pos + take), this.pos);
|
|
2132
|
+
this.pos += take;
|
|
2133
|
+
pos += take;
|
|
2134
|
+
if (this.pos === blockLen) {
|
|
2135
|
+
this.process(buffer, 0, false);
|
|
2136
|
+
this.pos = 0;
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2139
|
+
return this;
|
|
2140
|
+
}
|
|
2141
|
+
destroy() {
|
|
2142
|
+
clean(this.h, this.r, this.buffer, this.pad);
|
|
2143
|
+
}
|
|
2144
|
+
digestInto(out) {
|
|
2145
|
+
aexists(this);
|
|
2146
|
+
aoutput(out, this);
|
|
2147
|
+
this.finished = true;
|
|
2148
|
+
const { buffer, h } = this;
|
|
2149
|
+
let { pos } = this;
|
|
2150
|
+
if (pos) {
|
|
2151
|
+
buffer[pos++] = 1;
|
|
2152
|
+
for (;pos < 16; pos++)
|
|
2153
|
+
buffer[pos] = 0;
|
|
2154
|
+
this.process(buffer, 0, true);
|
|
2155
|
+
}
|
|
2156
|
+
this.finalize();
|
|
2157
|
+
let opos = 0;
|
|
2158
|
+
for (let i = 0;i < 8; i++) {
|
|
2159
|
+
out[opos++] = h[i] >>> 0;
|
|
2160
|
+
out[opos++] = h[i] >>> 8;
|
|
2161
|
+
}
|
|
2162
|
+
return out;
|
|
2163
|
+
}
|
|
2164
|
+
digest() {
|
|
2165
|
+
const { buffer, outputLen } = this;
|
|
2166
|
+
this.digestInto(buffer);
|
|
2167
|
+
const res = buffer.slice(0, outputLen);
|
|
2168
|
+
this.destroy();
|
|
2169
|
+
return res;
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
function wrapConstructorWithKey(hashCons) {
|
|
2173
|
+
const hashC = (msg, key) => hashCons(key).update(msg).digest();
|
|
2174
|
+
const tmp = hashCons(new Uint8Array(32));
|
|
2175
|
+
hashC.outputLen = tmp.outputLen;
|
|
2176
|
+
hashC.blockLen = tmp.blockLen;
|
|
2177
|
+
hashC.create = (key) => hashCons(key);
|
|
2178
|
+
return hashC;
|
|
2179
|
+
}
|
|
2180
|
+
var poly1305 = /* @__PURE__ */ (() => wrapConstructorWithKey((key) => new Poly1305(key)))();
|
|
2181
|
+
|
|
2182
|
+
// ../../node_modules/@hpke/chacha20poly1305/esm/src/chacha/chacha.js
|
|
2183
|
+
function chachaCore(s, k, n, out, cnt, rounds = 20) {
|
|
2184
|
+
const y00 = s[0], y01 = s[1], y02 = s[2], y03 = s[3], y04 = k[0], y05 = k[1], y06 = k[2], y07 = k[3], y08 = k[4], y09 = k[5], y10 = k[6], y11 = k[7], y12 = cnt, y13 = n[0], y14 = n[1], y15 = n[2];
|
|
2185
|
+
let x00 = y00, x01 = y01, x02 = y02, x03 = y03, x04 = y04, x05 = y05, x06 = y06, x07 = y07, x08 = y08, x09 = y09, x10 = y10, x11 = y11, x12 = y12, x13 = y13, x14 = y14, x15 = y15;
|
|
2186
|
+
for (let r = 0;r < rounds; r += 2) {
|
|
2187
|
+
x00 = x00 + x04 | 0;
|
|
2188
|
+
x12 = rotl(x12 ^ x00, 16);
|
|
2189
|
+
x08 = x08 + x12 | 0;
|
|
2190
|
+
x04 = rotl(x04 ^ x08, 12);
|
|
2191
|
+
x00 = x00 + x04 | 0;
|
|
2192
|
+
x12 = rotl(x12 ^ x00, 8);
|
|
2193
|
+
x08 = x08 + x12 | 0;
|
|
2194
|
+
x04 = rotl(x04 ^ x08, 7);
|
|
2195
|
+
x01 = x01 + x05 | 0;
|
|
2196
|
+
x13 = rotl(x13 ^ x01, 16);
|
|
2197
|
+
x09 = x09 + x13 | 0;
|
|
2198
|
+
x05 = rotl(x05 ^ x09, 12);
|
|
2199
|
+
x01 = x01 + x05 | 0;
|
|
2200
|
+
x13 = rotl(x13 ^ x01, 8);
|
|
2201
|
+
x09 = x09 + x13 | 0;
|
|
2202
|
+
x05 = rotl(x05 ^ x09, 7);
|
|
2203
|
+
x02 = x02 + x06 | 0;
|
|
2204
|
+
x14 = rotl(x14 ^ x02, 16);
|
|
2205
|
+
x10 = x10 + x14 | 0;
|
|
2206
|
+
x06 = rotl(x06 ^ x10, 12);
|
|
2207
|
+
x02 = x02 + x06 | 0;
|
|
2208
|
+
x14 = rotl(x14 ^ x02, 8);
|
|
2209
|
+
x10 = x10 + x14 | 0;
|
|
2210
|
+
x06 = rotl(x06 ^ x10, 7);
|
|
2211
|
+
x03 = x03 + x07 | 0;
|
|
2212
|
+
x15 = rotl(x15 ^ x03, 16);
|
|
2213
|
+
x11 = x11 + x15 | 0;
|
|
2214
|
+
x07 = rotl(x07 ^ x11, 12);
|
|
2215
|
+
x03 = x03 + x07 | 0;
|
|
2216
|
+
x15 = rotl(x15 ^ x03, 8);
|
|
2217
|
+
x11 = x11 + x15 | 0;
|
|
2218
|
+
x07 = rotl(x07 ^ x11, 7);
|
|
2219
|
+
x00 = x00 + x05 | 0;
|
|
2220
|
+
x15 = rotl(x15 ^ x00, 16);
|
|
2221
|
+
x10 = x10 + x15 | 0;
|
|
2222
|
+
x05 = rotl(x05 ^ x10, 12);
|
|
2223
|
+
x00 = x00 + x05 | 0;
|
|
2224
|
+
x15 = rotl(x15 ^ x00, 8);
|
|
2225
|
+
x10 = x10 + x15 | 0;
|
|
2226
|
+
x05 = rotl(x05 ^ x10, 7);
|
|
2227
|
+
x01 = x01 + x06 | 0;
|
|
2228
|
+
x12 = rotl(x12 ^ x01, 16);
|
|
2229
|
+
x11 = x11 + x12 | 0;
|
|
2230
|
+
x06 = rotl(x06 ^ x11, 12);
|
|
2231
|
+
x01 = x01 + x06 | 0;
|
|
2232
|
+
x12 = rotl(x12 ^ x01, 8);
|
|
2233
|
+
x11 = x11 + x12 | 0;
|
|
2234
|
+
x06 = rotl(x06 ^ x11, 7);
|
|
2235
|
+
x02 = x02 + x07 | 0;
|
|
2236
|
+
x13 = rotl(x13 ^ x02, 16);
|
|
2237
|
+
x08 = x08 + x13 | 0;
|
|
2238
|
+
x07 = rotl(x07 ^ x08, 12);
|
|
2239
|
+
x02 = x02 + x07 | 0;
|
|
2240
|
+
x13 = rotl(x13 ^ x02, 8);
|
|
2241
|
+
x08 = x08 + x13 | 0;
|
|
2242
|
+
x07 = rotl(x07 ^ x08, 7);
|
|
2243
|
+
x03 = x03 + x04 | 0;
|
|
2244
|
+
x14 = rotl(x14 ^ x03, 16);
|
|
2245
|
+
x09 = x09 + x14 | 0;
|
|
2246
|
+
x04 = rotl(x04 ^ x09, 12);
|
|
2247
|
+
x03 = x03 + x04 | 0;
|
|
2248
|
+
x14 = rotl(x14 ^ x03, 8);
|
|
2249
|
+
x09 = x09 + x14 | 0;
|
|
2250
|
+
x04 = rotl(x04 ^ x09, 7);
|
|
2251
|
+
}
|
|
2252
|
+
let oi = 0;
|
|
2253
|
+
out[oi++] = y00 + x00 | 0;
|
|
2254
|
+
out[oi++] = y01 + x01 | 0;
|
|
2255
|
+
out[oi++] = y02 + x02 | 0;
|
|
2256
|
+
out[oi++] = y03 + x03 | 0;
|
|
2257
|
+
out[oi++] = y04 + x04 | 0;
|
|
2258
|
+
out[oi++] = y05 + x05 | 0;
|
|
2259
|
+
out[oi++] = y06 + x06 | 0;
|
|
2260
|
+
out[oi++] = y07 + x07 | 0;
|
|
2261
|
+
out[oi++] = y08 + x08 | 0;
|
|
2262
|
+
out[oi++] = y09 + x09 | 0;
|
|
2263
|
+
out[oi++] = y10 + x10 | 0;
|
|
2264
|
+
out[oi++] = y11 + x11 | 0;
|
|
2265
|
+
out[oi++] = y12 + x12 | 0;
|
|
2266
|
+
out[oi++] = y13 + x13 | 0;
|
|
2267
|
+
out[oi++] = y14 + x14 | 0;
|
|
2268
|
+
out[oi++] = y15 + x15 | 0;
|
|
2269
|
+
}
|
|
2270
|
+
var chacha20 = /* @__PURE__ */ createCipher(chachaCore, {
|
|
2271
|
+
counterRight: false,
|
|
2272
|
+
counterLength: 4,
|
|
2273
|
+
allowShortKeys: false
|
|
2274
|
+
});
|
|
2275
|
+
var ZEROS16 = /* @__PURE__ */ new Uint8Array(16);
|
|
2276
|
+
var updatePadded = (h, msg) => {
|
|
2277
|
+
h.update(msg);
|
|
2278
|
+
const leftover = msg.length % 16;
|
|
2279
|
+
if (leftover)
|
|
2280
|
+
h.update(ZEROS16.subarray(leftover));
|
|
2281
|
+
};
|
|
2282
|
+
var ZEROS32 = /* @__PURE__ */ new Uint8Array(32);
|
|
2283
|
+
function computeTag(fn, key, nonce, ciphertext, AAD) {
|
|
2284
|
+
if (AAD !== undefined)
|
|
2285
|
+
abytes2(AAD, undefined, "AAD");
|
|
2286
|
+
const authKey = fn(key, nonce, ZEROS32);
|
|
2287
|
+
const lengths = u64Lengths(ciphertext.length, AAD ? AAD.length : 0, true);
|
|
2288
|
+
const h = poly1305.create(authKey);
|
|
2289
|
+
if (AAD)
|
|
2290
|
+
updatePadded(h, AAD);
|
|
2291
|
+
updatePadded(h, ciphertext);
|
|
2292
|
+
h.update(lengths);
|
|
2293
|
+
const res = h.digest();
|
|
2294
|
+
clean(authKey, lengths);
|
|
2295
|
+
return res;
|
|
2296
|
+
}
|
|
2297
|
+
var _poly1305_aead = (xorStream) => (key, nonce, AAD) => {
|
|
2298
|
+
const tagLength = 16;
|
|
2299
|
+
return {
|
|
2300
|
+
encrypt(plaintext, output) {
|
|
2301
|
+
const plength = plaintext.length;
|
|
2302
|
+
output = getOutput(plength + tagLength, output, false);
|
|
2303
|
+
output.set(plaintext);
|
|
2304
|
+
const oPlain = output.subarray(0, -tagLength);
|
|
2305
|
+
xorStream(key, nonce, oPlain, oPlain, 1);
|
|
2306
|
+
const tag = computeTag(xorStream, key, nonce, oPlain, AAD);
|
|
2307
|
+
output.set(tag, plength);
|
|
2308
|
+
clean(tag);
|
|
2309
|
+
return output;
|
|
2310
|
+
},
|
|
2311
|
+
decrypt(ciphertext, output) {
|
|
2312
|
+
output = getOutput(ciphertext.length - tagLength, output, false);
|
|
2313
|
+
const data = ciphertext.subarray(0, -tagLength);
|
|
2314
|
+
const passedTag = ciphertext.subarray(-tagLength);
|
|
2315
|
+
const tag = computeTag(xorStream, key, nonce, data, AAD);
|
|
2316
|
+
if (!equalBytes(passedTag, tag))
|
|
2317
|
+
throw new Error("invalid tag");
|
|
2318
|
+
output.set(ciphertext.subarray(0, -tagLength));
|
|
2319
|
+
xorStream(key, nonce, output, output, 1);
|
|
2320
|
+
clean(tag);
|
|
2321
|
+
return output;
|
|
2322
|
+
}
|
|
2323
|
+
};
|
|
2324
|
+
};
|
|
2325
|
+
var chacha20poly1305 = /* @__PURE__ */ wrapCipher({ blockSize: 64, nonceLength: 12, tagLength: 16 }, _poly1305_aead(chacha20));
|
|
2326
|
+
|
|
2327
|
+
// ../../node_modules/@hpke/common/esm/src/errors.js
|
|
2328
|
+
class HpkeError extends Error {
|
|
2329
|
+
constructor(e) {
|
|
2330
|
+
let message;
|
|
2331
|
+
if (e instanceof Error) {
|
|
2332
|
+
message = e.message;
|
|
2333
|
+
} else if (typeof e === "string") {
|
|
2334
|
+
message = e;
|
|
2335
|
+
} else {
|
|
2336
|
+
message = "";
|
|
2337
|
+
}
|
|
2338
|
+
super(message);
|
|
2339
|
+
this.name = this.constructor.name;
|
|
2340
|
+
}
|
|
2341
|
+
}
|
|
2342
|
+
|
|
2343
|
+
class InvalidParamError extends HpkeError {
|
|
2344
|
+
}
|
|
2345
|
+
class SerializeError extends HpkeError {
|
|
2346
|
+
}
|
|
2347
|
+
|
|
2348
|
+
class DeserializeError extends HpkeError {
|
|
2349
|
+
}
|
|
2350
|
+
|
|
2351
|
+
class EncapError extends HpkeError {
|
|
2352
|
+
}
|
|
2353
|
+
|
|
2354
|
+
class DecapError extends HpkeError {
|
|
2355
|
+
}
|
|
2356
|
+
|
|
2357
|
+
class ExportError extends HpkeError {
|
|
2358
|
+
}
|
|
2359
|
+
|
|
2360
|
+
class SealError extends HpkeError {
|
|
2361
|
+
}
|
|
2362
|
+
|
|
2363
|
+
class OpenError extends HpkeError {
|
|
2364
|
+
}
|
|
2365
|
+
|
|
2366
|
+
class MessageLimitReachedError extends HpkeError {
|
|
2367
|
+
}
|
|
2368
|
+
|
|
2369
|
+
class DeriveKeyPairError extends HpkeError {
|
|
2370
|
+
}
|
|
2371
|
+
|
|
2372
|
+
class NotSupportedError extends HpkeError {
|
|
2373
|
+
}
|
|
2374
|
+
// ../../node_modules/@hpke/common/esm/_dnt.shims.js
|
|
2375
|
+
var dntGlobals = {};
|
|
2376
|
+
var dntGlobalThis = createMergeProxy(globalThis, dntGlobals);
|
|
2377
|
+
function createMergeProxy(baseObj, extObj) {
|
|
2378
|
+
return new Proxy(baseObj, {
|
|
2379
|
+
get(_target, prop, _receiver) {
|
|
2380
|
+
if (prop in extObj) {
|
|
2381
|
+
return extObj[prop];
|
|
2382
|
+
} else {
|
|
2383
|
+
return baseObj[prop];
|
|
2384
|
+
}
|
|
2385
|
+
},
|
|
2386
|
+
set(_target, prop, value) {
|
|
2387
|
+
if (prop in extObj) {
|
|
2388
|
+
delete extObj[prop];
|
|
2389
|
+
}
|
|
2390
|
+
baseObj[prop] = value;
|
|
2391
|
+
return true;
|
|
2392
|
+
},
|
|
2393
|
+
deleteProperty(_target, prop) {
|
|
2394
|
+
let success = false;
|
|
2395
|
+
if (prop in extObj) {
|
|
2396
|
+
delete extObj[prop];
|
|
2397
|
+
success = true;
|
|
2398
|
+
}
|
|
2399
|
+
if (prop in baseObj) {
|
|
2400
|
+
delete baseObj[prop];
|
|
2401
|
+
success = true;
|
|
2402
|
+
}
|
|
2403
|
+
return success;
|
|
2404
|
+
},
|
|
2405
|
+
ownKeys(_target) {
|
|
2406
|
+
const baseKeys = Reflect.ownKeys(baseObj);
|
|
2407
|
+
const extKeys = Reflect.ownKeys(extObj);
|
|
2408
|
+
const extKeysSet = new Set(extKeys);
|
|
2409
|
+
return [...baseKeys.filter((k) => !extKeysSet.has(k)), ...extKeys];
|
|
2410
|
+
},
|
|
2411
|
+
defineProperty(_target, prop, desc) {
|
|
2412
|
+
if (prop in extObj) {
|
|
2413
|
+
delete extObj[prop];
|
|
2414
|
+
}
|
|
2415
|
+
Reflect.defineProperty(baseObj, prop, desc);
|
|
2416
|
+
return true;
|
|
2417
|
+
},
|
|
2418
|
+
getOwnPropertyDescriptor(_target, prop) {
|
|
2419
|
+
if (prop in extObj) {
|
|
2420
|
+
return Reflect.getOwnPropertyDescriptor(extObj, prop);
|
|
2421
|
+
} else {
|
|
2422
|
+
return Reflect.getOwnPropertyDescriptor(baseObj, prop);
|
|
2423
|
+
}
|
|
2424
|
+
},
|
|
2425
|
+
has(_target, prop) {
|
|
2426
|
+
return prop in extObj || prop in baseObj;
|
|
2427
|
+
}
|
|
2428
|
+
});
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2431
|
+
// ../../node_modules/@hpke/common/esm/src/algorithm.js
|
|
2432
|
+
async function loadSubtleCrypto() {
|
|
2433
|
+
if (dntGlobalThis !== undefined && globalThis.crypto !== undefined) {
|
|
2434
|
+
return globalThis.crypto.subtle;
|
|
2435
|
+
}
|
|
2436
|
+
try {
|
|
2437
|
+
const { webcrypto } = await import("crypto");
|
|
2438
|
+
return webcrypto.subtle;
|
|
2439
|
+
} catch (e) {
|
|
2440
|
+
throw new NotSupportedError(e);
|
|
2441
|
+
}
|
|
2442
|
+
}
|
|
2443
|
+
|
|
2444
|
+
class NativeAlgorithm {
|
|
2445
|
+
constructor() {
|
|
2446
|
+
Object.defineProperty(this, "_api", {
|
|
2447
|
+
enumerable: true,
|
|
2448
|
+
configurable: true,
|
|
2449
|
+
writable: true,
|
|
2450
|
+
value: undefined
|
|
2451
|
+
});
|
|
2452
|
+
}
|
|
2453
|
+
async _setup() {
|
|
2454
|
+
if (this._api !== undefined) {
|
|
2455
|
+
return;
|
|
2456
|
+
}
|
|
2457
|
+
this._api = await loadSubtleCrypto();
|
|
2458
|
+
}
|
|
2459
|
+
}
|
|
2460
|
+
// ../../node_modules/@hpke/common/esm/src/identifiers.js
|
|
2461
|
+
var Mode = {
|
|
2462
|
+
Base: 0,
|
|
2463
|
+
Psk: 1,
|
|
2464
|
+
Auth: 2,
|
|
2465
|
+
AuthPsk: 3
|
|
2466
|
+
};
|
|
2467
|
+
var KemId = {
|
|
2468
|
+
NotAssigned: 0,
|
|
2469
|
+
DhkemP256HkdfSha256: 16,
|
|
2470
|
+
DhkemP384HkdfSha384: 17,
|
|
2471
|
+
DhkemP521HkdfSha512: 18,
|
|
2472
|
+
DhkemSecp256k1HkdfSha256: 19,
|
|
2473
|
+
DhkemX25519HkdfSha256: 32,
|
|
2474
|
+
DhkemX448HkdfSha512: 33,
|
|
2475
|
+
HybridkemX25519Kyber768: 48,
|
|
2476
|
+
MlKem512: 64,
|
|
2477
|
+
MlKem768: 65,
|
|
2478
|
+
MlKem1024: 66,
|
|
2479
|
+
XWing: 25722
|
|
2480
|
+
};
|
|
2481
|
+
var KdfId = {
|
|
2482
|
+
HkdfSha256: 1,
|
|
2483
|
+
HkdfSha384: 2,
|
|
2484
|
+
HkdfSha512: 3
|
|
2485
|
+
};
|
|
2486
|
+
var AeadId = {
|
|
2487
|
+
Aes128Gcm: 1,
|
|
2488
|
+
Aes256Gcm: 2,
|
|
2489
|
+
Chacha20Poly1305: 3,
|
|
2490
|
+
ExportOnly: 65535
|
|
2491
|
+
};
|
|
2492
|
+
// ../../node_modules/@hpke/common/esm/src/consts.js
|
|
2493
|
+
var INPUT_LENGTH_LIMIT = 8192;
|
|
2494
|
+
var INFO_LENGTH_LIMIT = 65536;
|
|
2495
|
+
var MINIMUM_PSK_LENGTH = 32;
|
|
2496
|
+
var EMPTY = new Uint8Array(0);
|
|
2497
|
+
|
|
2498
|
+
// ../../node_modules/@hpke/common/esm/src/interfaces/kemInterface.js
|
|
2499
|
+
var SUITE_ID_HEADER_KEM = new Uint8Array([
|
|
2500
|
+
75,
|
|
2501
|
+
69,
|
|
2502
|
+
77,
|
|
2503
|
+
0,
|
|
2504
|
+
0
|
|
2505
|
+
]);
|
|
2506
|
+
|
|
2507
|
+
// ../../node_modules/@hpke/common/esm/src/utils/misc.js
|
|
2508
|
+
var isCryptoKeyPair = (x) => typeof x === "object" && x !== null && typeof x.privateKey === "object" && typeof x.publicKey === "object";
|
|
2509
|
+
function i2Osp(n, w) {
|
|
2510
|
+
if (w <= 0) {
|
|
2511
|
+
throw new Error("i2Osp: too small size");
|
|
2512
|
+
}
|
|
2513
|
+
if (n >= 256 ** w) {
|
|
2514
|
+
throw new Error("i2Osp: too large integer");
|
|
2515
|
+
}
|
|
2516
|
+
const ret = new Uint8Array(w);
|
|
2517
|
+
for (let i = 0;i < w && n; i++) {
|
|
2518
|
+
ret[w - (i + 1)] = n % 256;
|
|
2519
|
+
n = n >> 8;
|
|
2520
|
+
}
|
|
2521
|
+
return ret;
|
|
2522
|
+
}
|
|
2523
|
+
function concat(a, b) {
|
|
2524
|
+
const ret = new Uint8Array(a.length + b.length);
|
|
2525
|
+
ret.set(a, 0);
|
|
2526
|
+
ret.set(b, a.length);
|
|
2527
|
+
return ret;
|
|
2528
|
+
}
|
|
2529
|
+
function base64UrlToBytes(v) {
|
|
2530
|
+
const base642 = v.replace(/-/g, "+").replace(/_/g, "/");
|
|
2531
|
+
const byteString = atob(base642);
|
|
2532
|
+
const ret = new Uint8Array(byteString.length);
|
|
2533
|
+
for (let i = 0;i < byteString.length; i++) {
|
|
2534
|
+
ret[i] = byteString.charCodeAt(i);
|
|
2535
|
+
}
|
|
2536
|
+
return ret;
|
|
2537
|
+
}
|
|
2538
|
+
function xor(a, b) {
|
|
2539
|
+
if (a.byteLength !== b.byteLength) {
|
|
2540
|
+
throw new Error("xor: different length inputs");
|
|
2541
|
+
}
|
|
2542
|
+
const buf = new Uint8Array(a.byteLength);
|
|
2543
|
+
for (let i = 0;i < a.byteLength; i++) {
|
|
2544
|
+
buf[i] = a[i] ^ b[i];
|
|
2545
|
+
}
|
|
2546
|
+
return buf;
|
|
2547
|
+
}
|
|
2548
|
+
|
|
2549
|
+
// ../../node_modules/@hpke/common/esm/src/kems/dhkem.js
|
|
2550
|
+
var LABEL_EAE_PRK = new Uint8Array([101, 97, 101, 95, 112, 114, 107]);
|
|
2551
|
+
var LABEL_SHARED_SECRET = new Uint8Array([
|
|
2552
|
+
115,
|
|
2553
|
+
104,
|
|
2554
|
+
97,
|
|
2555
|
+
114,
|
|
2556
|
+
101,
|
|
2557
|
+
100,
|
|
2558
|
+
95,
|
|
2559
|
+
115,
|
|
2560
|
+
101,
|
|
2561
|
+
99,
|
|
2562
|
+
114,
|
|
2563
|
+
101,
|
|
2564
|
+
116
|
|
2565
|
+
]);
|
|
2566
|
+
function concat3(a, b, c) {
|
|
2567
|
+
const ret = new Uint8Array(a.length + b.length + c.length);
|
|
2568
|
+
ret.set(a, 0);
|
|
2569
|
+
ret.set(b, a.length);
|
|
2570
|
+
ret.set(c, a.length + b.length);
|
|
2571
|
+
return ret;
|
|
2572
|
+
}
|
|
2573
|
+
|
|
2574
|
+
class Dhkem {
|
|
2575
|
+
constructor(id, prim, kdf) {
|
|
2576
|
+
Object.defineProperty(this, "id", {
|
|
2577
|
+
enumerable: true,
|
|
2578
|
+
configurable: true,
|
|
2579
|
+
writable: true,
|
|
2580
|
+
value: undefined
|
|
2581
|
+
});
|
|
2582
|
+
Object.defineProperty(this, "secretSize", {
|
|
2583
|
+
enumerable: true,
|
|
2584
|
+
configurable: true,
|
|
2585
|
+
writable: true,
|
|
2586
|
+
value: 0
|
|
2587
|
+
});
|
|
2588
|
+
Object.defineProperty(this, "encSize", {
|
|
2589
|
+
enumerable: true,
|
|
2590
|
+
configurable: true,
|
|
2591
|
+
writable: true,
|
|
2592
|
+
value: 0
|
|
2593
|
+
});
|
|
2594
|
+
Object.defineProperty(this, "publicKeySize", {
|
|
2595
|
+
enumerable: true,
|
|
2596
|
+
configurable: true,
|
|
2597
|
+
writable: true,
|
|
2598
|
+
value: 0
|
|
2599
|
+
});
|
|
2600
|
+
Object.defineProperty(this, "privateKeySize", {
|
|
2601
|
+
enumerable: true,
|
|
2602
|
+
configurable: true,
|
|
2603
|
+
writable: true,
|
|
2604
|
+
value: 0
|
|
2605
|
+
});
|
|
2606
|
+
Object.defineProperty(this, "_prim", {
|
|
2607
|
+
enumerable: true,
|
|
2608
|
+
configurable: true,
|
|
2609
|
+
writable: true,
|
|
2610
|
+
value: undefined
|
|
2611
|
+
});
|
|
2612
|
+
Object.defineProperty(this, "_kdf", {
|
|
2613
|
+
enumerable: true,
|
|
2614
|
+
configurable: true,
|
|
2615
|
+
writable: true,
|
|
2616
|
+
value: undefined
|
|
2617
|
+
});
|
|
2618
|
+
this.id = id;
|
|
2619
|
+
this._prim = prim;
|
|
2620
|
+
this._kdf = kdf;
|
|
2621
|
+
const suiteId = new Uint8Array(SUITE_ID_HEADER_KEM);
|
|
2622
|
+
suiteId.set(i2Osp(this.id, 2), 3);
|
|
2623
|
+
this._kdf.init(suiteId);
|
|
2624
|
+
}
|
|
2625
|
+
async serializePublicKey(key) {
|
|
2626
|
+
return await this._prim.serializePublicKey(key);
|
|
2627
|
+
}
|
|
2628
|
+
async deserializePublicKey(key) {
|
|
2629
|
+
return await this._prim.deserializePublicKey(key);
|
|
2630
|
+
}
|
|
2631
|
+
async serializePrivateKey(key) {
|
|
2632
|
+
return await this._prim.serializePrivateKey(key);
|
|
2633
|
+
}
|
|
2634
|
+
async deserializePrivateKey(key) {
|
|
2635
|
+
return await this._prim.deserializePrivateKey(key);
|
|
2636
|
+
}
|
|
2637
|
+
async importKey(format, key, isPublic = true) {
|
|
2638
|
+
return await this._prim.importKey(format, key, isPublic);
|
|
2639
|
+
}
|
|
2640
|
+
async generateKeyPair() {
|
|
2641
|
+
return await this._prim.generateKeyPair();
|
|
2642
|
+
}
|
|
2643
|
+
async deriveKeyPair(ikm) {
|
|
2644
|
+
if (ikm.byteLength > INPUT_LENGTH_LIMIT) {
|
|
2645
|
+
throw new InvalidParamError("Too long ikm");
|
|
2646
|
+
}
|
|
2647
|
+
return await this._prim.deriveKeyPair(ikm);
|
|
2648
|
+
}
|
|
2649
|
+
async encap(params) {
|
|
2650
|
+
let ke;
|
|
2651
|
+
if (params.ekm === undefined) {
|
|
2652
|
+
ke = await this.generateKeyPair();
|
|
2653
|
+
} else if (isCryptoKeyPair(params.ekm)) {
|
|
2654
|
+
ke = params.ekm;
|
|
2655
|
+
} else {
|
|
2656
|
+
ke = await this.deriveKeyPair(params.ekm);
|
|
2657
|
+
}
|
|
2658
|
+
const enc = await this._prim.serializePublicKey(ke.publicKey);
|
|
2659
|
+
const pkrm = await this._prim.serializePublicKey(params.recipientPublicKey);
|
|
2660
|
+
try {
|
|
2661
|
+
let dh;
|
|
2662
|
+
if (params.senderKey === undefined) {
|
|
2663
|
+
dh = new Uint8Array(await this._prim.dh(ke.privateKey, params.recipientPublicKey));
|
|
2664
|
+
} else {
|
|
2665
|
+
const sks = isCryptoKeyPair(params.senderKey) ? params.senderKey.privateKey : params.senderKey;
|
|
2666
|
+
const dh1 = new Uint8Array(await this._prim.dh(ke.privateKey, params.recipientPublicKey));
|
|
2667
|
+
const dh2 = new Uint8Array(await this._prim.dh(sks, params.recipientPublicKey));
|
|
2668
|
+
dh = concat(dh1, dh2);
|
|
2669
|
+
}
|
|
2670
|
+
let kemContext;
|
|
2671
|
+
if (params.senderKey === undefined) {
|
|
2672
|
+
kemContext = concat(new Uint8Array(enc), new Uint8Array(pkrm));
|
|
2673
|
+
} else {
|
|
2674
|
+
const pks = isCryptoKeyPair(params.senderKey) ? params.senderKey.publicKey : await this._prim.derivePublicKey(params.senderKey);
|
|
2675
|
+
const pksm = await this._prim.serializePublicKey(pks);
|
|
2676
|
+
kemContext = concat3(new Uint8Array(enc), new Uint8Array(pkrm), new Uint8Array(pksm));
|
|
2677
|
+
}
|
|
2678
|
+
const sharedSecret = await this._generateSharedSecret(dh, kemContext);
|
|
2679
|
+
return {
|
|
2680
|
+
enc,
|
|
2681
|
+
sharedSecret
|
|
2682
|
+
};
|
|
2683
|
+
} catch (e) {
|
|
2684
|
+
throw new EncapError(e);
|
|
2685
|
+
}
|
|
2686
|
+
}
|
|
2687
|
+
async decap(params) {
|
|
2688
|
+
const pke = await this._prim.deserializePublicKey(params.enc);
|
|
2689
|
+
const skr = isCryptoKeyPair(params.recipientKey) ? params.recipientKey.privateKey : params.recipientKey;
|
|
2690
|
+
const pkr = isCryptoKeyPair(params.recipientKey) ? params.recipientKey.publicKey : await this._prim.derivePublicKey(params.recipientKey);
|
|
2691
|
+
const pkrm = await this._prim.serializePublicKey(pkr);
|
|
2692
|
+
try {
|
|
2693
|
+
let dh;
|
|
2694
|
+
if (params.senderPublicKey === undefined) {
|
|
2695
|
+
dh = new Uint8Array(await this._prim.dh(skr, pke));
|
|
2696
|
+
} else {
|
|
2697
|
+
const dh1 = new Uint8Array(await this._prim.dh(skr, pke));
|
|
2698
|
+
const dh2 = new Uint8Array(await this._prim.dh(skr, params.senderPublicKey));
|
|
2699
|
+
dh = concat(dh1, dh2);
|
|
2700
|
+
}
|
|
2701
|
+
let kemContext;
|
|
2702
|
+
if (params.senderPublicKey === undefined) {
|
|
2703
|
+
kemContext = concat(new Uint8Array(params.enc), new Uint8Array(pkrm));
|
|
2704
|
+
} else {
|
|
2705
|
+
const pksm = await this._prim.serializePublicKey(params.senderPublicKey);
|
|
2706
|
+
kemContext = new Uint8Array(params.enc.byteLength + pkrm.byteLength + pksm.byteLength);
|
|
2707
|
+
kemContext.set(new Uint8Array(params.enc), 0);
|
|
2708
|
+
kemContext.set(new Uint8Array(pkrm), params.enc.byteLength);
|
|
2709
|
+
kemContext.set(new Uint8Array(pksm), params.enc.byteLength + pkrm.byteLength);
|
|
2710
|
+
}
|
|
2711
|
+
return await this._generateSharedSecret(dh, kemContext);
|
|
2712
|
+
} catch (e) {
|
|
2713
|
+
throw new DecapError(e);
|
|
2714
|
+
}
|
|
2715
|
+
}
|
|
2716
|
+
async _generateSharedSecret(dh, kemContext) {
|
|
2717
|
+
const labeledIkm = this._kdf.buildLabeledIkm(LABEL_EAE_PRK, dh);
|
|
2718
|
+
const labeledInfo = this._kdf.buildLabeledInfo(LABEL_SHARED_SECRET, kemContext, this.secretSize);
|
|
2719
|
+
return await this._kdf.extractAndExpand(EMPTY.buffer, labeledIkm.buffer, labeledInfo.buffer, this.secretSize);
|
|
2720
|
+
}
|
|
2721
|
+
}
|
|
2722
|
+
// ../../node_modules/@hpke/common/esm/src/interfaces/dhkemPrimitives.js
|
|
2723
|
+
var KEM_USAGES = ["deriveBits"];
|
|
2724
|
+
var LABEL_DKP_PRK = new Uint8Array([
|
|
2725
|
+
100,
|
|
2726
|
+
107,
|
|
2727
|
+
112,
|
|
2728
|
+
95,
|
|
2729
|
+
112,
|
|
2730
|
+
114,
|
|
2731
|
+
107
|
|
2732
|
+
]);
|
|
2733
|
+
var LABEL_SK = new Uint8Array([115, 107]);
|
|
2734
|
+
|
|
2735
|
+
// ../../node_modules/@hpke/common/esm/src/utils/bignum.js
|
|
2736
|
+
class Bignum {
|
|
2737
|
+
constructor(size) {
|
|
2738
|
+
Object.defineProperty(this, "_num", {
|
|
2739
|
+
enumerable: true,
|
|
2740
|
+
configurable: true,
|
|
2741
|
+
writable: true,
|
|
2742
|
+
value: undefined
|
|
2743
|
+
});
|
|
2744
|
+
this._num = new Uint8Array(size);
|
|
2745
|
+
}
|
|
2746
|
+
val() {
|
|
2747
|
+
return this._num;
|
|
2748
|
+
}
|
|
2749
|
+
reset() {
|
|
2750
|
+
this._num.fill(0);
|
|
2751
|
+
}
|
|
2752
|
+
set(src) {
|
|
2753
|
+
if (src.length !== this._num.length) {
|
|
2754
|
+
throw new Error("Bignum.set: invalid argument");
|
|
2755
|
+
}
|
|
2756
|
+
this._num.set(src);
|
|
2757
|
+
}
|
|
2758
|
+
isZero() {
|
|
2759
|
+
for (let i = 0;i < this._num.length; i++) {
|
|
2760
|
+
if (this._num[i] !== 0) {
|
|
2761
|
+
return false;
|
|
2762
|
+
}
|
|
2763
|
+
}
|
|
2764
|
+
return true;
|
|
2765
|
+
}
|
|
2766
|
+
lessThan(v) {
|
|
2767
|
+
if (v.length !== this._num.length) {
|
|
2768
|
+
throw new Error("Bignum.lessThan: invalid argument");
|
|
2769
|
+
}
|
|
2770
|
+
for (let i = 0;i < this._num.length; i++) {
|
|
2771
|
+
if (this._num[i] < v[i]) {
|
|
2772
|
+
return true;
|
|
2773
|
+
}
|
|
2774
|
+
if (this._num[i] > v[i]) {
|
|
2775
|
+
return false;
|
|
2776
|
+
}
|
|
2777
|
+
}
|
|
2778
|
+
return false;
|
|
2779
|
+
}
|
|
2780
|
+
}
|
|
2781
|
+
|
|
2782
|
+
// ../../node_modules/@hpke/common/esm/src/kems/dhkemPrimitives/ec.js
|
|
2783
|
+
var LABEL_CANDIDATE = new Uint8Array([
|
|
2784
|
+
99,
|
|
2785
|
+
97,
|
|
2786
|
+
110,
|
|
2787
|
+
100,
|
|
2788
|
+
105,
|
|
2789
|
+
100,
|
|
2790
|
+
97,
|
|
2791
|
+
116,
|
|
2792
|
+
101
|
|
2793
|
+
]);
|
|
2794
|
+
var ORDER_P_256 = new Uint8Array([
|
|
2795
|
+
255,
|
|
2796
|
+
255,
|
|
2797
|
+
255,
|
|
2798
|
+
255,
|
|
2799
|
+
0,
|
|
2800
|
+
0,
|
|
2801
|
+
0,
|
|
2802
|
+
0,
|
|
2803
|
+
255,
|
|
2804
|
+
255,
|
|
2805
|
+
255,
|
|
2806
|
+
255,
|
|
2807
|
+
255,
|
|
2808
|
+
255,
|
|
2809
|
+
255,
|
|
2810
|
+
255,
|
|
2811
|
+
188,
|
|
2812
|
+
230,
|
|
2813
|
+
250,
|
|
2814
|
+
173,
|
|
2815
|
+
167,
|
|
2816
|
+
23,
|
|
2817
|
+
158,
|
|
2818
|
+
132,
|
|
2819
|
+
243,
|
|
2820
|
+
185,
|
|
2821
|
+
202,
|
|
2822
|
+
194,
|
|
2823
|
+
252,
|
|
2824
|
+
99,
|
|
2825
|
+
37,
|
|
2826
|
+
81
|
|
2827
|
+
]);
|
|
2828
|
+
var ORDER_P_384 = new Uint8Array([
|
|
2829
|
+
255,
|
|
2830
|
+
255,
|
|
2831
|
+
255,
|
|
2832
|
+
255,
|
|
2833
|
+
255,
|
|
2834
|
+
255,
|
|
2835
|
+
255,
|
|
2836
|
+
255,
|
|
2837
|
+
255,
|
|
2838
|
+
255,
|
|
2839
|
+
255,
|
|
2840
|
+
255,
|
|
2841
|
+
255,
|
|
2842
|
+
255,
|
|
2843
|
+
255,
|
|
2844
|
+
255,
|
|
2845
|
+
255,
|
|
2846
|
+
255,
|
|
2847
|
+
255,
|
|
2848
|
+
255,
|
|
2849
|
+
255,
|
|
2850
|
+
255,
|
|
2851
|
+
255,
|
|
2852
|
+
255,
|
|
2853
|
+
199,
|
|
2854
|
+
99,
|
|
2855
|
+
77,
|
|
2856
|
+
129,
|
|
2857
|
+
244,
|
|
2858
|
+
55,
|
|
2859
|
+
45,
|
|
2860
|
+
223,
|
|
2861
|
+
88,
|
|
2862
|
+
26,
|
|
2863
|
+
13,
|
|
2864
|
+
178,
|
|
2865
|
+
72,
|
|
2866
|
+
176,
|
|
2867
|
+
167,
|
|
2868
|
+
122,
|
|
2869
|
+
236,
|
|
2870
|
+
236,
|
|
2871
|
+
25,
|
|
2872
|
+
106,
|
|
2873
|
+
204,
|
|
2874
|
+
197,
|
|
2875
|
+
41,
|
|
2876
|
+
115
|
|
2877
|
+
]);
|
|
2878
|
+
var ORDER_P_521 = new Uint8Array([
|
|
2879
|
+
1,
|
|
2880
|
+
255,
|
|
2881
|
+
255,
|
|
2882
|
+
255,
|
|
2883
|
+
255,
|
|
2884
|
+
255,
|
|
2885
|
+
255,
|
|
2886
|
+
255,
|
|
2887
|
+
255,
|
|
2888
|
+
255,
|
|
2889
|
+
255,
|
|
2890
|
+
255,
|
|
2891
|
+
255,
|
|
2892
|
+
255,
|
|
2893
|
+
255,
|
|
2894
|
+
255,
|
|
2895
|
+
255,
|
|
2896
|
+
255,
|
|
2897
|
+
255,
|
|
2898
|
+
255,
|
|
2899
|
+
255,
|
|
2900
|
+
255,
|
|
2901
|
+
255,
|
|
2902
|
+
255,
|
|
2903
|
+
255,
|
|
2904
|
+
255,
|
|
2905
|
+
255,
|
|
2906
|
+
255,
|
|
2907
|
+
255,
|
|
2908
|
+
255,
|
|
2909
|
+
255,
|
|
2910
|
+
255,
|
|
2911
|
+
255,
|
|
2912
|
+
250,
|
|
2913
|
+
81,
|
|
2914
|
+
134,
|
|
2915
|
+
135,
|
|
2916
|
+
131,
|
|
2917
|
+
191,
|
|
2918
|
+
47,
|
|
2919
|
+
150,
|
|
2920
|
+
107,
|
|
2921
|
+
127,
|
|
2922
|
+
204,
|
|
2923
|
+
1,
|
|
2924
|
+
72,
|
|
2925
|
+
247,
|
|
2926
|
+
9,
|
|
2927
|
+
165,
|
|
2928
|
+
208,
|
|
2929
|
+
59,
|
|
2930
|
+
181,
|
|
2931
|
+
201,
|
|
2932
|
+
184,
|
|
2933
|
+
137,
|
|
2934
|
+
156,
|
|
2935
|
+
71,
|
|
2936
|
+
174,
|
|
2937
|
+
187,
|
|
2938
|
+
111,
|
|
2939
|
+
183,
|
|
2940
|
+
30,
|
|
2941
|
+
145,
|
|
2942
|
+
56,
|
|
2943
|
+
100,
|
|
2944
|
+
9
|
|
2945
|
+
]);
|
|
2946
|
+
var PKCS8_ALG_ID_P_256 = new Uint8Array([
|
|
2947
|
+
48,
|
|
2948
|
+
65,
|
|
2949
|
+
2,
|
|
2950
|
+
1,
|
|
2951
|
+
0,
|
|
2952
|
+
48,
|
|
2953
|
+
19,
|
|
2954
|
+
6,
|
|
2955
|
+
7,
|
|
2956
|
+
42,
|
|
2957
|
+
134,
|
|
2958
|
+
72,
|
|
2959
|
+
206,
|
|
2960
|
+
61,
|
|
2961
|
+
2,
|
|
2962
|
+
1,
|
|
2963
|
+
6,
|
|
2964
|
+
8,
|
|
2965
|
+
42,
|
|
2966
|
+
134,
|
|
2967
|
+
72,
|
|
2968
|
+
206,
|
|
2969
|
+
61,
|
|
2970
|
+
3,
|
|
2971
|
+
1,
|
|
2972
|
+
7,
|
|
2973
|
+
4,
|
|
2974
|
+
39,
|
|
2975
|
+
48,
|
|
2976
|
+
37,
|
|
2977
|
+
2,
|
|
2978
|
+
1,
|
|
2979
|
+
1,
|
|
2980
|
+
4,
|
|
2981
|
+
32
|
|
2982
|
+
]);
|
|
2983
|
+
var PKCS8_ALG_ID_P_384 = new Uint8Array([
|
|
2984
|
+
48,
|
|
2985
|
+
78,
|
|
2986
|
+
2,
|
|
2987
|
+
1,
|
|
2988
|
+
0,
|
|
2989
|
+
48,
|
|
2990
|
+
16,
|
|
2991
|
+
6,
|
|
2992
|
+
7,
|
|
2993
|
+
42,
|
|
2994
|
+
134,
|
|
2995
|
+
72,
|
|
2996
|
+
206,
|
|
2997
|
+
61,
|
|
2998
|
+
2,
|
|
2999
|
+
1,
|
|
3000
|
+
6,
|
|
3001
|
+
5,
|
|
3002
|
+
43,
|
|
3003
|
+
129,
|
|
3004
|
+
4,
|
|
3005
|
+
0,
|
|
3006
|
+
34,
|
|
3007
|
+
4,
|
|
3008
|
+
55,
|
|
3009
|
+
48,
|
|
3010
|
+
53,
|
|
3011
|
+
2,
|
|
3012
|
+
1,
|
|
3013
|
+
1,
|
|
3014
|
+
4,
|
|
3015
|
+
48
|
|
3016
|
+
]);
|
|
3017
|
+
var PKCS8_ALG_ID_P_521 = new Uint8Array([
|
|
3018
|
+
48,
|
|
3019
|
+
96,
|
|
3020
|
+
2,
|
|
3021
|
+
1,
|
|
3022
|
+
0,
|
|
3023
|
+
48,
|
|
3024
|
+
16,
|
|
3025
|
+
6,
|
|
3026
|
+
7,
|
|
3027
|
+
42,
|
|
3028
|
+
134,
|
|
3029
|
+
72,
|
|
3030
|
+
206,
|
|
3031
|
+
61,
|
|
3032
|
+
2,
|
|
3033
|
+
1,
|
|
3034
|
+
6,
|
|
3035
|
+
5,
|
|
3036
|
+
43,
|
|
3037
|
+
129,
|
|
3038
|
+
4,
|
|
3039
|
+
0,
|
|
3040
|
+
35,
|
|
3041
|
+
4,
|
|
3042
|
+
73,
|
|
3043
|
+
48,
|
|
3044
|
+
71,
|
|
3045
|
+
2,
|
|
3046
|
+
1,
|
|
3047
|
+
1,
|
|
3048
|
+
4,
|
|
3049
|
+
66
|
|
3050
|
+
]);
|
|
3051
|
+
|
|
3052
|
+
class Ec extends NativeAlgorithm {
|
|
3053
|
+
constructor(kem, hkdf) {
|
|
3054
|
+
super();
|
|
3055
|
+
Object.defineProperty(this, "_hkdf", {
|
|
3056
|
+
enumerable: true,
|
|
3057
|
+
configurable: true,
|
|
3058
|
+
writable: true,
|
|
3059
|
+
value: undefined
|
|
3060
|
+
});
|
|
3061
|
+
Object.defineProperty(this, "_alg", {
|
|
3062
|
+
enumerable: true,
|
|
3063
|
+
configurable: true,
|
|
3064
|
+
writable: true,
|
|
3065
|
+
value: undefined
|
|
3066
|
+
});
|
|
3067
|
+
Object.defineProperty(this, "_nPk", {
|
|
3068
|
+
enumerable: true,
|
|
3069
|
+
configurable: true,
|
|
3070
|
+
writable: true,
|
|
3071
|
+
value: undefined
|
|
3072
|
+
});
|
|
3073
|
+
Object.defineProperty(this, "_nSk", {
|
|
3074
|
+
enumerable: true,
|
|
3075
|
+
configurable: true,
|
|
3076
|
+
writable: true,
|
|
3077
|
+
value: undefined
|
|
3078
|
+
});
|
|
3079
|
+
Object.defineProperty(this, "_nDh", {
|
|
3080
|
+
enumerable: true,
|
|
3081
|
+
configurable: true,
|
|
3082
|
+
writable: true,
|
|
3083
|
+
value: undefined
|
|
3084
|
+
});
|
|
3085
|
+
Object.defineProperty(this, "_order", {
|
|
3086
|
+
enumerable: true,
|
|
3087
|
+
configurable: true,
|
|
3088
|
+
writable: true,
|
|
3089
|
+
value: undefined
|
|
3090
|
+
});
|
|
3091
|
+
Object.defineProperty(this, "_bitmask", {
|
|
3092
|
+
enumerable: true,
|
|
3093
|
+
configurable: true,
|
|
3094
|
+
writable: true,
|
|
3095
|
+
value: undefined
|
|
3096
|
+
});
|
|
3097
|
+
Object.defineProperty(this, "_pkcs8AlgId", {
|
|
3098
|
+
enumerable: true,
|
|
3099
|
+
configurable: true,
|
|
3100
|
+
writable: true,
|
|
3101
|
+
value: undefined
|
|
3102
|
+
});
|
|
3103
|
+
this._hkdf = hkdf;
|
|
3104
|
+
switch (kem) {
|
|
3105
|
+
case KemId.DhkemP256HkdfSha256:
|
|
3106
|
+
this._alg = { name: "ECDH", namedCurve: "P-256" };
|
|
3107
|
+
this._nPk = 65;
|
|
3108
|
+
this._nSk = 32;
|
|
3109
|
+
this._nDh = 32;
|
|
3110
|
+
this._order = ORDER_P_256;
|
|
3111
|
+
this._bitmask = 255;
|
|
3112
|
+
this._pkcs8AlgId = PKCS8_ALG_ID_P_256;
|
|
3113
|
+
break;
|
|
3114
|
+
case KemId.DhkemP384HkdfSha384:
|
|
3115
|
+
this._alg = { name: "ECDH", namedCurve: "P-384" };
|
|
3116
|
+
this._nPk = 97;
|
|
3117
|
+
this._nSk = 48;
|
|
3118
|
+
this._nDh = 48;
|
|
3119
|
+
this._order = ORDER_P_384;
|
|
3120
|
+
this._bitmask = 255;
|
|
3121
|
+
this._pkcs8AlgId = PKCS8_ALG_ID_P_384;
|
|
3122
|
+
break;
|
|
3123
|
+
default:
|
|
3124
|
+
this._alg = { name: "ECDH", namedCurve: "P-521" };
|
|
3125
|
+
this._nPk = 133;
|
|
3126
|
+
this._nSk = 66;
|
|
3127
|
+
this._nDh = 66;
|
|
3128
|
+
this._order = ORDER_P_521;
|
|
3129
|
+
this._bitmask = 1;
|
|
3130
|
+
this._pkcs8AlgId = PKCS8_ALG_ID_P_521;
|
|
3131
|
+
break;
|
|
3132
|
+
}
|
|
3133
|
+
}
|
|
3134
|
+
async serializePublicKey(key) {
|
|
3135
|
+
await this._setup();
|
|
3136
|
+
try {
|
|
3137
|
+
return await this._api.exportKey("raw", key);
|
|
3138
|
+
} catch (e) {
|
|
3139
|
+
throw new SerializeError(e);
|
|
3140
|
+
}
|
|
3141
|
+
}
|
|
3142
|
+
async deserializePublicKey(key) {
|
|
3143
|
+
await this._setup();
|
|
3144
|
+
try {
|
|
3145
|
+
return await this._importRawKey(key, true);
|
|
3146
|
+
} catch (e) {
|
|
3147
|
+
throw new DeserializeError(e);
|
|
3148
|
+
}
|
|
3149
|
+
}
|
|
3150
|
+
async serializePrivateKey(key) {
|
|
3151
|
+
await this._setup();
|
|
3152
|
+
try {
|
|
3153
|
+
const jwk = await this._api.exportKey("jwk", key);
|
|
3154
|
+
if (!("d" in jwk)) {
|
|
3155
|
+
throw new Error("Not private key");
|
|
3156
|
+
}
|
|
3157
|
+
return base64UrlToBytes(jwk["d"]).buffer;
|
|
3158
|
+
} catch (e) {
|
|
3159
|
+
throw new SerializeError(e);
|
|
3160
|
+
}
|
|
3161
|
+
}
|
|
3162
|
+
async deserializePrivateKey(key) {
|
|
3163
|
+
await this._setup();
|
|
3164
|
+
try {
|
|
3165
|
+
return await this._importRawKey(key, false);
|
|
3166
|
+
} catch (e) {
|
|
3167
|
+
throw new DeserializeError(e);
|
|
3168
|
+
}
|
|
3169
|
+
}
|
|
3170
|
+
async importKey(format, key, isPublic) {
|
|
3171
|
+
await this._setup();
|
|
3172
|
+
try {
|
|
3173
|
+
if (format === "raw") {
|
|
3174
|
+
return await this._importRawKey(key, isPublic);
|
|
3175
|
+
}
|
|
3176
|
+
if (key instanceof ArrayBuffer) {
|
|
3177
|
+
throw new Error("Invalid jwk key format");
|
|
3178
|
+
}
|
|
3179
|
+
return await this._importJWK(key, isPublic);
|
|
3180
|
+
} catch (e) {
|
|
3181
|
+
throw new DeserializeError(e);
|
|
3182
|
+
}
|
|
3183
|
+
}
|
|
3184
|
+
async generateKeyPair() {
|
|
3185
|
+
await this._setup();
|
|
3186
|
+
try {
|
|
3187
|
+
return await this._api.generateKey(this._alg, true, KEM_USAGES);
|
|
3188
|
+
} catch (e) {
|
|
3189
|
+
throw new NotSupportedError(e);
|
|
3190
|
+
}
|
|
3191
|
+
}
|
|
3192
|
+
async deriveKeyPair(ikm) {
|
|
3193
|
+
await this._setup();
|
|
3194
|
+
try {
|
|
3195
|
+
const dkpPrk = await this._hkdf.labeledExtract(EMPTY.buffer, LABEL_DKP_PRK, new Uint8Array(ikm));
|
|
3196
|
+
const bn = new Bignum(this._nSk);
|
|
3197
|
+
for (let counter = 0;bn.isZero() || !bn.lessThan(this._order); counter++) {
|
|
3198
|
+
if (counter > 255) {
|
|
3199
|
+
throw new Error("Faild to derive a key pair");
|
|
3200
|
+
}
|
|
3201
|
+
const bytes = new Uint8Array(await this._hkdf.labeledExpand(dkpPrk, LABEL_CANDIDATE, i2Osp(counter, 1), this._nSk));
|
|
3202
|
+
bytes[0] = bytes[0] & this._bitmask;
|
|
3203
|
+
bn.set(bytes);
|
|
3204
|
+
}
|
|
3205
|
+
const sk = await this._deserializePkcs8Key(bn.val());
|
|
3206
|
+
bn.reset();
|
|
3207
|
+
return {
|
|
3208
|
+
privateKey: sk,
|
|
3209
|
+
publicKey: await this.derivePublicKey(sk)
|
|
3210
|
+
};
|
|
3211
|
+
} catch (e) {
|
|
3212
|
+
throw new DeriveKeyPairError(e);
|
|
3213
|
+
}
|
|
3214
|
+
}
|
|
3215
|
+
async derivePublicKey(key) {
|
|
3216
|
+
await this._setup();
|
|
3217
|
+
try {
|
|
3218
|
+
const jwk = await this._api.exportKey("jwk", key);
|
|
3219
|
+
delete jwk["d"];
|
|
3220
|
+
delete jwk["key_ops"];
|
|
3221
|
+
return await this._api.importKey("jwk", jwk, this._alg, true, []);
|
|
3222
|
+
} catch (e) {
|
|
3223
|
+
throw new DeserializeError(e);
|
|
3224
|
+
}
|
|
3225
|
+
}
|
|
3226
|
+
async dh(sk, pk) {
|
|
3227
|
+
try {
|
|
3228
|
+
await this._setup();
|
|
3229
|
+
const bits = await this._api.deriveBits({
|
|
3230
|
+
name: "ECDH",
|
|
3231
|
+
public: pk
|
|
3232
|
+
}, sk, this._nDh * 8);
|
|
3233
|
+
return bits;
|
|
3234
|
+
} catch (e) {
|
|
3235
|
+
throw new SerializeError(e);
|
|
3236
|
+
}
|
|
3237
|
+
}
|
|
3238
|
+
async _importRawKey(key, isPublic) {
|
|
3239
|
+
if (isPublic && key.byteLength !== this._nPk) {
|
|
3240
|
+
throw new Error("Invalid public key for the ciphersuite");
|
|
3241
|
+
}
|
|
3242
|
+
if (!isPublic && key.byteLength !== this._nSk) {
|
|
3243
|
+
throw new Error("Invalid private key for the ciphersuite");
|
|
3244
|
+
}
|
|
3245
|
+
if (isPublic) {
|
|
3246
|
+
return await this._api.importKey("raw", key, this._alg, true, []);
|
|
3247
|
+
}
|
|
3248
|
+
return await this._deserializePkcs8Key(new Uint8Array(key));
|
|
3249
|
+
}
|
|
3250
|
+
async _importJWK(key, isPublic) {
|
|
3251
|
+
if (typeof key.crv === "undefined" || key.crv !== this._alg.namedCurve) {
|
|
3252
|
+
throw new Error(`Invalid crv: ${key.crv}`);
|
|
3253
|
+
}
|
|
3254
|
+
if (isPublic) {
|
|
3255
|
+
if (typeof key.d !== "undefined") {
|
|
3256
|
+
throw new Error("Invalid key: `d` should not be set");
|
|
3257
|
+
}
|
|
3258
|
+
return await this._api.importKey("jwk", key, this._alg, true, []);
|
|
3259
|
+
}
|
|
3260
|
+
if (typeof key.d === "undefined") {
|
|
3261
|
+
throw new Error("Invalid key: `d` not found");
|
|
3262
|
+
}
|
|
3263
|
+
return await this._api.importKey("jwk", key, this._alg, true, KEM_USAGES);
|
|
3264
|
+
}
|
|
3265
|
+
async _deserializePkcs8Key(k) {
|
|
3266
|
+
const pkcs8Key = new Uint8Array(this._pkcs8AlgId.length + k.length);
|
|
3267
|
+
pkcs8Key.set(this._pkcs8AlgId, 0);
|
|
3268
|
+
pkcs8Key.set(k, this._pkcs8AlgId.length);
|
|
3269
|
+
return await this._api.importKey("pkcs8", pkcs8Key, this._alg, true, KEM_USAGES);
|
|
3270
|
+
}
|
|
3271
|
+
}
|
|
3272
|
+
// ../../node_modules/@hpke/common/esm/src/kdfs/hkdf.js
|
|
3273
|
+
var HPKE_VERSION = new Uint8Array([72, 80, 75, 69, 45, 118, 49]);
|
|
3274
|
+
|
|
3275
|
+
class HkdfNative extends NativeAlgorithm {
|
|
3276
|
+
constructor() {
|
|
3277
|
+
super();
|
|
3278
|
+
Object.defineProperty(this, "id", {
|
|
3279
|
+
enumerable: true,
|
|
3280
|
+
configurable: true,
|
|
3281
|
+
writable: true,
|
|
3282
|
+
value: KdfId.HkdfSha256
|
|
3283
|
+
});
|
|
3284
|
+
Object.defineProperty(this, "hashSize", {
|
|
3285
|
+
enumerable: true,
|
|
3286
|
+
configurable: true,
|
|
3287
|
+
writable: true,
|
|
3288
|
+
value: 0
|
|
3289
|
+
});
|
|
3290
|
+
Object.defineProperty(this, "_suiteId", {
|
|
3291
|
+
enumerable: true,
|
|
3292
|
+
configurable: true,
|
|
3293
|
+
writable: true,
|
|
3294
|
+
value: EMPTY
|
|
3295
|
+
});
|
|
3296
|
+
Object.defineProperty(this, "algHash", {
|
|
3297
|
+
enumerable: true,
|
|
3298
|
+
configurable: true,
|
|
3299
|
+
writable: true,
|
|
3300
|
+
value: {
|
|
3301
|
+
name: "HMAC",
|
|
3302
|
+
hash: "SHA-256",
|
|
3303
|
+
length: 256
|
|
3304
|
+
}
|
|
3305
|
+
});
|
|
3306
|
+
}
|
|
3307
|
+
init(suiteId) {
|
|
3308
|
+
this._suiteId = suiteId;
|
|
3309
|
+
}
|
|
3310
|
+
buildLabeledIkm(label, ikm) {
|
|
3311
|
+
this._checkInit();
|
|
3312
|
+
const ret = new Uint8Array(7 + this._suiteId.byteLength + label.byteLength + ikm.byteLength);
|
|
3313
|
+
ret.set(HPKE_VERSION, 0);
|
|
3314
|
+
ret.set(this._suiteId, 7);
|
|
3315
|
+
ret.set(label, 7 + this._suiteId.byteLength);
|
|
3316
|
+
ret.set(ikm, 7 + this._suiteId.byteLength + label.byteLength);
|
|
3317
|
+
return ret;
|
|
3318
|
+
}
|
|
3319
|
+
buildLabeledInfo(label, info, len) {
|
|
3320
|
+
this._checkInit();
|
|
3321
|
+
const ret = new Uint8Array(9 + this._suiteId.byteLength + label.byteLength + info.byteLength);
|
|
3322
|
+
ret.set(new Uint8Array([0, len]), 0);
|
|
3323
|
+
ret.set(HPKE_VERSION, 2);
|
|
3324
|
+
ret.set(this._suiteId, 9);
|
|
3325
|
+
ret.set(label, 9 + this._suiteId.byteLength);
|
|
3326
|
+
ret.set(info, 9 + this._suiteId.byteLength + label.byteLength);
|
|
3327
|
+
return ret;
|
|
3328
|
+
}
|
|
3329
|
+
async extract(salt, ikm) {
|
|
3330
|
+
await this._setup();
|
|
3331
|
+
if (salt.byteLength === 0) {
|
|
3332
|
+
salt = new ArrayBuffer(this.hashSize);
|
|
3333
|
+
}
|
|
3334
|
+
if (salt.byteLength !== this.hashSize) {
|
|
3335
|
+
throw new InvalidParamError("The salt length must be the same as the hashSize");
|
|
3336
|
+
}
|
|
3337
|
+
const key = await this._api.importKey("raw", salt, this.algHash, false, [
|
|
3338
|
+
"sign"
|
|
3339
|
+
]);
|
|
3340
|
+
return await this._api.sign("HMAC", key, ikm);
|
|
3341
|
+
}
|
|
3342
|
+
async expand(prk, info, len) {
|
|
3343
|
+
await this._setup();
|
|
3344
|
+
const key = await this._api.importKey("raw", prk, this.algHash, false, [
|
|
3345
|
+
"sign"
|
|
3346
|
+
]);
|
|
3347
|
+
const okm = new ArrayBuffer(len);
|
|
3348
|
+
const p = new Uint8Array(okm);
|
|
3349
|
+
let prev = EMPTY;
|
|
3350
|
+
const mid = new Uint8Array(info);
|
|
3351
|
+
const tail = new Uint8Array(1);
|
|
3352
|
+
if (len > 255 * this.hashSize) {
|
|
3353
|
+
throw new Error("Entropy limit reached");
|
|
3354
|
+
}
|
|
3355
|
+
const tmp = new Uint8Array(this.hashSize + mid.length + 1);
|
|
3356
|
+
for (let i = 1, cur = 0;cur < p.length; i++) {
|
|
3357
|
+
tail[0] = i;
|
|
3358
|
+
tmp.set(prev, 0);
|
|
3359
|
+
tmp.set(mid, prev.length);
|
|
3360
|
+
tmp.set(tail, prev.length + mid.length);
|
|
3361
|
+
prev = new Uint8Array(await this._api.sign("HMAC", key, tmp.slice(0, prev.length + mid.length + 1)));
|
|
3362
|
+
if (p.length - cur >= prev.length) {
|
|
3363
|
+
p.set(prev, cur);
|
|
3364
|
+
cur += prev.length;
|
|
3365
|
+
} else {
|
|
3366
|
+
p.set(prev.slice(0, p.length - cur), cur);
|
|
3367
|
+
cur += p.length - cur;
|
|
3368
|
+
}
|
|
3369
|
+
}
|
|
3370
|
+
return okm;
|
|
3371
|
+
}
|
|
3372
|
+
async extractAndExpand(salt, ikm, info, len) {
|
|
3373
|
+
await this._setup();
|
|
3374
|
+
const baseKey = await this._api.importKey("raw", ikm, "HKDF", false, ["deriveBits"]);
|
|
3375
|
+
return await this._api.deriveBits({
|
|
3376
|
+
name: "HKDF",
|
|
3377
|
+
hash: this.algHash.hash,
|
|
3378
|
+
salt,
|
|
3379
|
+
info
|
|
3380
|
+
}, baseKey, len * 8);
|
|
3381
|
+
}
|
|
3382
|
+
async labeledExtract(salt, label, ikm) {
|
|
3383
|
+
return await this.extract(salt, this.buildLabeledIkm(label, ikm).buffer);
|
|
3384
|
+
}
|
|
3385
|
+
async labeledExpand(prk, label, info, len) {
|
|
3386
|
+
return await this.expand(prk, this.buildLabeledInfo(label, info, len).buffer, len);
|
|
3387
|
+
}
|
|
3388
|
+
_checkInit() {
|
|
3389
|
+
if (this._suiteId === EMPTY) {
|
|
3390
|
+
throw new Error("Not initialized. Call init()");
|
|
3391
|
+
}
|
|
3392
|
+
}
|
|
3393
|
+
}
|
|
3394
|
+
|
|
3395
|
+
class HkdfSha256Native extends HkdfNative {
|
|
3396
|
+
constructor() {
|
|
3397
|
+
super(...arguments);
|
|
3398
|
+
Object.defineProperty(this, "id", {
|
|
3399
|
+
enumerable: true,
|
|
3400
|
+
configurable: true,
|
|
3401
|
+
writable: true,
|
|
3402
|
+
value: KdfId.HkdfSha256
|
|
3403
|
+
});
|
|
3404
|
+
Object.defineProperty(this, "hashSize", {
|
|
3405
|
+
enumerable: true,
|
|
3406
|
+
configurable: true,
|
|
3407
|
+
writable: true,
|
|
3408
|
+
value: 32
|
|
3409
|
+
});
|
|
3410
|
+
Object.defineProperty(this, "algHash", {
|
|
3411
|
+
enumerable: true,
|
|
3412
|
+
configurable: true,
|
|
3413
|
+
writable: true,
|
|
3414
|
+
value: {
|
|
3415
|
+
name: "HMAC",
|
|
3416
|
+
hash: "SHA-256",
|
|
3417
|
+
length: 256
|
|
3418
|
+
}
|
|
3419
|
+
});
|
|
3420
|
+
}
|
|
3421
|
+
}
|
|
3422
|
+
// ../../node_modules/@hpke/chacha20poly1305/esm/src/chacha20Poly1305.js
|
|
3423
|
+
class Chacha20Poly1305Context {
|
|
3424
|
+
constructor(key) {
|
|
3425
|
+
Object.defineProperty(this, "_key", {
|
|
3426
|
+
enumerable: true,
|
|
3427
|
+
configurable: true,
|
|
3428
|
+
writable: true,
|
|
3429
|
+
value: undefined
|
|
3430
|
+
});
|
|
3431
|
+
this._key = new Uint8Array(key);
|
|
3432
|
+
}
|
|
3433
|
+
async seal(iv, data, aad) {
|
|
3434
|
+
return await this._seal(iv, data, aad);
|
|
3435
|
+
}
|
|
3436
|
+
async open(iv, data, aad) {
|
|
3437
|
+
return await this._open(iv, data, aad);
|
|
3438
|
+
}
|
|
3439
|
+
_seal(iv, data, aad) {
|
|
3440
|
+
return new Promise((resolve) => {
|
|
3441
|
+
const ret = chacha20poly1305(this._key, new Uint8Array(iv), new Uint8Array(aad)).encrypt(new Uint8Array(data));
|
|
3442
|
+
resolve(ret.buffer);
|
|
3443
|
+
});
|
|
3444
|
+
}
|
|
3445
|
+
_open(iv, data, aad) {
|
|
3446
|
+
return new Promise((resolve) => {
|
|
3447
|
+
const ret = chacha20poly1305(this._key, new Uint8Array(iv), new Uint8Array(aad)).decrypt(new Uint8Array(data));
|
|
3448
|
+
resolve(ret.buffer);
|
|
3449
|
+
});
|
|
3450
|
+
}
|
|
3451
|
+
}
|
|
3452
|
+
|
|
3453
|
+
class Chacha20Poly1305 {
|
|
3454
|
+
constructor() {
|
|
3455
|
+
Object.defineProperty(this, "id", {
|
|
3456
|
+
enumerable: true,
|
|
3457
|
+
configurable: true,
|
|
3458
|
+
writable: true,
|
|
3459
|
+
value: AeadId.Chacha20Poly1305
|
|
3460
|
+
});
|
|
3461
|
+
Object.defineProperty(this, "keySize", {
|
|
3462
|
+
enumerable: true,
|
|
3463
|
+
configurable: true,
|
|
3464
|
+
writable: true,
|
|
3465
|
+
value: 32
|
|
3466
|
+
});
|
|
3467
|
+
Object.defineProperty(this, "nonceSize", {
|
|
3468
|
+
enumerable: true,
|
|
3469
|
+
configurable: true,
|
|
3470
|
+
writable: true,
|
|
3471
|
+
value: 12
|
|
3472
|
+
});
|
|
3473
|
+
Object.defineProperty(this, "tagSize", {
|
|
3474
|
+
enumerable: true,
|
|
3475
|
+
configurable: true,
|
|
3476
|
+
writable: true,
|
|
3477
|
+
value: 16
|
|
3478
|
+
});
|
|
3479
|
+
}
|
|
3480
|
+
createEncryptionContext(key) {
|
|
3481
|
+
return new Chacha20Poly1305Context(key);
|
|
3482
|
+
}
|
|
3483
|
+
}
|
|
3484
|
+
// ../../node_modules/@hpke/core/esm/src/utils/emitNotSupported.js
|
|
3485
|
+
function emitNotSupported() {
|
|
3486
|
+
return new Promise((_resolve, reject) => {
|
|
3487
|
+
reject(new NotSupportedError("Not supported"));
|
|
3488
|
+
});
|
|
3489
|
+
}
|
|
3490
|
+
|
|
3491
|
+
// ../../node_modules/@hpke/core/esm/src/exporterContext.js
|
|
3492
|
+
var LABEL_SEC = new Uint8Array([115, 101, 99]);
|
|
3493
|
+
|
|
3494
|
+
class ExporterContextImpl {
|
|
3495
|
+
constructor(api, kdf, exporterSecret) {
|
|
3496
|
+
Object.defineProperty(this, "_api", {
|
|
3497
|
+
enumerable: true,
|
|
3498
|
+
configurable: true,
|
|
3499
|
+
writable: true,
|
|
3500
|
+
value: undefined
|
|
3501
|
+
});
|
|
3502
|
+
Object.defineProperty(this, "exporterSecret", {
|
|
3503
|
+
enumerable: true,
|
|
3504
|
+
configurable: true,
|
|
3505
|
+
writable: true,
|
|
3506
|
+
value: undefined
|
|
3507
|
+
});
|
|
3508
|
+
Object.defineProperty(this, "_kdf", {
|
|
3509
|
+
enumerable: true,
|
|
3510
|
+
configurable: true,
|
|
3511
|
+
writable: true,
|
|
3512
|
+
value: undefined
|
|
3513
|
+
});
|
|
3514
|
+
this._api = api;
|
|
3515
|
+
this._kdf = kdf;
|
|
3516
|
+
this.exporterSecret = exporterSecret;
|
|
3517
|
+
}
|
|
3518
|
+
async seal(_data, _aad) {
|
|
3519
|
+
return await emitNotSupported();
|
|
3520
|
+
}
|
|
3521
|
+
async open(_data, _aad) {
|
|
3522
|
+
return await emitNotSupported();
|
|
3523
|
+
}
|
|
3524
|
+
async export(exporterContext, len) {
|
|
3525
|
+
if (exporterContext.byteLength > INPUT_LENGTH_LIMIT) {
|
|
3526
|
+
throw new InvalidParamError("Too long exporter context");
|
|
3527
|
+
}
|
|
3528
|
+
try {
|
|
3529
|
+
return await this._kdf.labeledExpand(this.exporterSecret, LABEL_SEC, new Uint8Array(exporterContext), len);
|
|
3530
|
+
} catch (e) {
|
|
3531
|
+
throw new ExportError(e);
|
|
3532
|
+
}
|
|
3533
|
+
}
|
|
3534
|
+
}
|
|
3535
|
+
|
|
3536
|
+
class RecipientExporterContextImpl extends ExporterContextImpl {
|
|
3537
|
+
}
|
|
3538
|
+
|
|
3539
|
+
class SenderExporterContextImpl extends ExporterContextImpl {
|
|
3540
|
+
constructor(api, kdf, exporterSecret, enc) {
|
|
3541
|
+
super(api, kdf, exporterSecret);
|
|
3542
|
+
Object.defineProperty(this, "enc", {
|
|
3543
|
+
enumerable: true,
|
|
3544
|
+
configurable: true,
|
|
3545
|
+
writable: true,
|
|
3546
|
+
value: undefined
|
|
3547
|
+
});
|
|
3548
|
+
this.enc = enc;
|
|
3549
|
+
return;
|
|
3550
|
+
}
|
|
3551
|
+
}
|
|
3552
|
+
|
|
3553
|
+
// ../../node_modules/@hpke/core/esm/src/encryptionContext.js
|
|
3554
|
+
class EncryptionContextImpl extends ExporterContextImpl {
|
|
3555
|
+
constructor(api, kdf, params) {
|
|
3556
|
+
super(api, kdf, params.exporterSecret);
|
|
3557
|
+
Object.defineProperty(this, "_aead", {
|
|
3558
|
+
enumerable: true,
|
|
3559
|
+
configurable: true,
|
|
3560
|
+
writable: true,
|
|
3561
|
+
value: undefined
|
|
3562
|
+
});
|
|
3563
|
+
Object.defineProperty(this, "_nK", {
|
|
3564
|
+
enumerable: true,
|
|
3565
|
+
configurable: true,
|
|
3566
|
+
writable: true,
|
|
3567
|
+
value: undefined
|
|
3568
|
+
});
|
|
3569
|
+
Object.defineProperty(this, "_nN", {
|
|
3570
|
+
enumerable: true,
|
|
3571
|
+
configurable: true,
|
|
3572
|
+
writable: true,
|
|
3573
|
+
value: undefined
|
|
3574
|
+
});
|
|
3575
|
+
Object.defineProperty(this, "_nT", {
|
|
3576
|
+
enumerable: true,
|
|
3577
|
+
configurable: true,
|
|
3578
|
+
writable: true,
|
|
3579
|
+
value: undefined
|
|
3580
|
+
});
|
|
3581
|
+
Object.defineProperty(this, "_ctx", {
|
|
3582
|
+
enumerable: true,
|
|
3583
|
+
configurable: true,
|
|
3584
|
+
writable: true,
|
|
3585
|
+
value: undefined
|
|
3586
|
+
});
|
|
3587
|
+
if (params.key === undefined || params.baseNonce === undefined || params.seq === undefined) {
|
|
3588
|
+
throw new Error("Required parameters are missing");
|
|
3589
|
+
}
|
|
3590
|
+
this._aead = params.aead;
|
|
3591
|
+
this._nK = this._aead.keySize;
|
|
3592
|
+
this._nN = this._aead.nonceSize;
|
|
3593
|
+
this._nT = this._aead.tagSize;
|
|
3594
|
+
const key = this._aead.createEncryptionContext(params.key);
|
|
3595
|
+
this._ctx = {
|
|
3596
|
+
key,
|
|
3597
|
+
baseNonce: params.baseNonce,
|
|
3598
|
+
seq: params.seq
|
|
3599
|
+
};
|
|
3600
|
+
}
|
|
3601
|
+
computeNonce(k) {
|
|
3602
|
+
const seqBytes = i2Osp(k.seq, k.baseNonce.byteLength);
|
|
3603
|
+
return xor(k.baseNonce, seqBytes).buffer;
|
|
3604
|
+
}
|
|
3605
|
+
incrementSeq(k) {
|
|
3606
|
+
if (k.seq > Number.MAX_SAFE_INTEGER) {
|
|
3607
|
+
throw new MessageLimitReachedError("Message limit reached");
|
|
3608
|
+
}
|
|
3609
|
+
k.seq += 1;
|
|
3610
|
+
return;
|
|
3611
|
+
}
|
|
3612
|
+
}
|
|
3613
|
+
|
|
3614
|
+
// ../../node_modules/@hpke/core/esm/src/mutex.js
|
|
3615
|
+
var __classPrivateFieldGet = function(receiver, state, kind, f) {
|
|
3616
|
+
if (kind === "a" && !f)
|
|
3617
|
+
throw new TypeError("Private accessor was defined without a getter");
|
|
3618
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver))
|
|
3619
|
+
throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
3620
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
3621
|
+
};
|
|
3622
|
+
var __classPrivateFieldSet = function(receiver, state, value, kind, f) {
|
|
3623
|
+
if (kind === "m")
|
|
3624
|
+
throw new TypeError("Private method is not writable");
|
|
3625
|
+
if (kind === "a" && !f)
|
|
3626
|
+
throw new TypeError("Private accessor was defined without a setter");
|
|
3627
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver))
|
|
3628
|
+
throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
3629
|
+
return kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;
|
|
3630
|
+
};
|
|
3631
|
+
var _Mutex_locked;
|
|
3632
|
+
|
|
3633
|
+
class Mutex {
|
|
3634
|
+
constructor() {
|
|
3635
|
+
_Mutex_locked.set(this, Promise.resolve());
|
|
3636
|
+
}
|
|
3637
|
+
async lock() {
|
|
3638
|
+
let releaseLock;
|
|
3639
|
+
const nextLock = new Promise((resolve) => {
|
|
3640
|
+
releaseLock = resolve;
|
|
3641
|
+
});
|
|
3642
|
+
const previousLock = __classPrivateFieldGet(this, _Mutex_locked, "f");
|
|
3643
|
+
__classPrivateFieldSet(this, _Mutex_locked, nextLock, "f");
|
|
3644
|
+
await previousLock;
|
|
3645
|
+
return releaseLock;
|
|
3646
|
+
}
|
|
3647
|
+
}
|
|
3648
|
+
_Mutex_locked = new WeakMap;
|
|
3649
|
+
|
|
3650
|
+
// ../../node_modules/@hpke/core/esm/src/recipientContext.js
|
|
3651
|
+
var __classPrivateFieldGet2 = function(receiver, state, kind, f) {
|
|
3652
|
+
if (kind === "a" && !f)
|
|
3653
|
+
throw new TypeError("Private accessor was defined without a getter");
|
|
3654
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver))
|
|
3655
|
+
throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
3656
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
3657
|
+
};
|
|
3658
|
+
var __classPrivateFieldSet2 = function(receiver, state, value, kind, f) {
|
|
3659
|
+
if (kind === "m")
|
|
3660
|
+
throw new TypeError("Private method is not writable");
|
|
3661
|
+
if (kind === "a" && !f)
|
|
3662
|
+
throw new TypeError("Private accessor was defined without a setter");
|
|
3663
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver))
|
|
3664
|
+
throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
3665
|
+
return kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;
|
|
3666
|
+
};
|
|
3667
|
+
var _RecipientContextImpl_mutex;
|
|
3668
|
+
|
|
3669
|
+
class RecipientContextImpl extends EncryptionContextImpl {
|
|
3670
|
+
constructor() {
|
|
3671
|
+
super(...arguments);
|
|
3672
|
+
_RecipientContextImpl_mutex.set(this, undefined);
|
|
3673
|
+
}
|
|
3674
|
+
async open(data, aad = EMPTY.buffer) {
|
|
3675
|
+
__classPrivateFieldSet2(this, _RecipientContextImpl_mutex, __classPrivateFieldGet2(this, _RecipientContextImpl_mutex, "f") ?? new Mutex, "f");
|
|
3676
|
+
const release = await __classPrivateFieldGet2(this, _RecipientContextImpl_mutex, "f").lock();
|
|
3677
|
+
let pt;
|
|
3678
|
+
try {
|
|
3679
|
+
pt = await this._ctx.key.open(this.computeNonce(this._ctx), data, aad);
|
|
3680
|
+
} catch (e) {
|
|
3681
|
+
throw new OpenError(e);
|
|
3682
|
+
} finally {
|
|
3683
|
+
release();
|
|
3684
|
+
}
|
|
3685
|
+
this.incrementSeq(this._ctx);
|
|
3686
|
+
return pt;
|
|
3687
|
+
}
|
|
3688
|
+
}
|
|
3689
|
+
_RecipientContextImpl_mutex = new WeakMap;
|
|
3690
|
+
|
|
3691
|
+
// ../../node_modules/@hpke/core/esm/src/senderContext.js
|
|
3692
|
+
var __classPrivateFieldGet3 = function(receiver, state, kind, f) {
|
|
3693
|
+
if (kind === "a" && !f)
|
|
3694
|
+
throw new TypeError("Private accessor was defined without a getter");
|
|
3695
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver))
|
|
3696
|
+
throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
3697
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
3698
|
+
};
|
|
3699
|
+
var __classPrivateFieldSet3 = function(receiver, state, value, kind, f) {
|
|
3700
|
+
if (kind === "m")
|
|
3701
|
+
throw new TypeError("Private method is not writable");
|
|
3702
|
+
if (kind === "a" && !f)
|
|
3703
|
+
throw new TypeError("Private accessor was defined without a setter");
|
|
3704
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver))
|
|
3705
|
+
throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
3706
|
+
return kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;
|
|
3707
|
+
};
|
|
3708
|
+
var _SenderContextImpl_mutex;
|
|
3709
|
+
|
|
3710
|
+
class SenderContextImpl extends EncryptionContextImpl {
|
|
3711
|
+
constructor(api, kdf, params, enc) {
|
|
3712
|
+
super(api, kdf, params);
|
|
3713
|
+
Object.defineProperty(this, "enc", {
|
|
3714
|
+
enumerable: true,
|
|
3715
|
+
configurable: true,
|
|
3716
|
+
writable: true,
|
|
3717
|
+
value: undefined
|
|
3718
|
+
});
|
|
3719
|
+
_SenderContextImpl_mutex.set(this, undefined);
|
|
3720
|
+
this.enc = enc;
|
|
3721
|
+
}
|
|
3722
|
+
async seal(data, aad = EMPTY.buffer) {
|
|
3723
|
+
__classPrivateFieldSet3(this, _SenderContextImpl_mutex, __classPrivateFieldGet3(this, _SenderContextImpl_mutex, "f") ?? new Mutex, "f");
|
|
3724
|
+
const release = await __classPrivateFieldGet3(this, _SenderContextImpl_mutex, "f").lock();
|
|
3725
|
+
let ct;
|
|
3726
|
+
try {
|
|
3727
|
+
ct = await this._ctx.key.seal(this.computeNonce(this._ctx), data, aad);
|
|
3728
|
+
} catch (e) {
|
|
3729
|
+
throw new SealError(e);
|
|
3730
|
+
} finally {
|
|
3731
|
+
release();
|
|
3732
|
+
}
|
|
3733
|
+
this.incrementSeq(this._ctx);
|
|
3734
|
+
return ct;
|
|
3735
|
+
}
|
|
3736
|
+
}
|
|
3737
|
+
_SenderContextImpl_mutex = new WeakMap;
|
|
3738
|
+
|
|
3739
|
+
// ../../node_modules/@hpke/core/esm/src/cipherSuiteNative.js
|
|
3740
|
+
var LABEL_BASE_NONCE = new Uint8Array([
|
|
3741
|
+
98,
|
|
3742
|
+
97,
|
|
3743
|
+
115,
|
|
3744
|
+
101,
|
|
3745
|
+
95,
|
|
3746
|
+
110,
|
|
3747
|
+
111,
|
|
3748
|
+
110,
|
|
3749
|
+
99,
|
|
3750
|
+
101
|
|
3751
|
+
]);
|
|
3752
|
+
var LABEL_EXP = new Uint8Array([101, 120, 112]);
|
|
3753
|
+
var LABEL_INFO_HASH = new Uint8Array([
|
|
3754
|
+
105,
|
|
3755
|
+
110,
|
|
3756
|
+
102,
|
|
3757
|
+
111,
|
|
3758
|
+
95,
|
|
3759
|
+
104,
|
|
3760
|
+
97,
|
|
3761
|
+
115,
|
|
3762
|
+
104
|
|
3763
|
+
]);
|
|
3764
|
+
var LABEL_KEY = new Uint8Array([107, 101, 121]);
|
|
3765
|
+
var LABEL_PSK_ID_HASH = new Uint8Array([
|
|
3766
|
+
112,
|
|
3767
|
+
115,
|
|
3768
|
+
107,
|
|
3769
|
+
95,
|
|
3770
|
+
105,
|
|
3771
|
+
100,
|
|
3772
|
+
95,
|
|
3773
|
+
104,
|
|
3774
|
+
97,
|
|
3775
|
+
115,
|
|
3776
|
+
104
|
|
3777
|
+
]);
|
|
3778
|
+
var LABEL_SECRET = new Uint8Array([115, 101, 99, 114, 101, 116]);
|
|
3779
|
+
var SUITE_ID_HEADER_HPKE = new Uint8Array([
|
|
3780
|
+
72,
|
|
3781
|
+
80,
|
|
3782
|
+
75,
|
|
3783
|
+
69,
|
|
3784
|
+
0,
|
|
3785
|
+
0,
|
|
3786
|
+
0,
|
|
3787
|
+
0,
|
|
3788
|
+
0,
|
|
3789
|
+
0
|
|
3790
|
+
]);
|
|
3791
|
+
|
|
3792
|
+
class CipherSuiteNative extends NativeAlgorithm {
|
|
3793
|
+
constructor(params) {
|
|
3794
|
+
super();
|
|
3795
|
+
Object.defineProperty(this, "_kem", {
|
|
3796
|
+
enumerable: true,
|
|
3797
|
+
configurable: true,
|
|
3798
|
+
writable: true,
|
|
3799
|
+
value: undefined
|
|
3800
|
+
});
|
|
3801
|
+
Object.defineProperty(this, "_kdf", {
|
|
3802
|
+
enumerable: true,
|
|
3803
|
+
configurable: true,
|
|
3804
|
+
writable: true,
|
|
3805
|
+
value: undefined
|
|
3806
|
+
});
|
|
3807
|
+
Object.defineProperty(this, "_aead", {
|
|
3808
|
+
enumerable: true,
|
|
3809
|
+
configurable: true,
|
|
3810
|
+
writable: true,
|
|
3811
|
+
value: undefined
|
|
3812
|
+
});
|
|
3813
|
+
Object.defineProperty(this, "_suiteId", {
|
|
3814
|
+
enumerable: true,
|
|
3815
|
+
configurable: true,
|
|
3816
|
+
writable: true,
|
|
3817
|
+
value: undefined
|
|
3818
|
+
});
|
|
3819
|
+
if (typeof params.kem === "number") {
|
|
3820
|
+
throw new InvalidParamError("KemId cannot be used");
|
|
3821
|
+
}
|
|
3822
|
+
this._kem = params.kem;
|
|
3823
|
+
if (typeof params.kdf === "number") {
|
|
3824
|
+
throw new InvalidParamError("KdfId cannot be used");
|
|
3825
|
+
}
|
|
3826
|
+
this._kdf = params.kdf;
|
|
3827
|
+
if (typeof params.aead === "number") {
|
|
3828
|
+
throw new InvalidParamError("AeadId cannot be used");
|
|
3829
|
+
}
|
|
3830
|
+
this._aead = params.aead;
|
|
3831
|
+
this._suiteId = new Uint8Array(SUITE_ID_HEADER_HPKE);
|
|
3832
|
+
this._suiteId.set(i2Osp(this._kem.id, 2), 4);
|
|
3833
|
+
this._suiteId.set(i2Osp(this._kdf.id, 2), 6);
|
|
3834
|
+
this._suiteId.set(i2Osp(this._aead.id, 2), 8);
|
|
3835
|
+
this._kdf.init(this._suiteId);
|
|
3836
|
+
}
|
|
3837
|
+
get kem() {
|
|
3838
|
+
return this._kem;
|
|
3839
|
+
}
|
|
3840
|
+
get kdf() {
|
|
3841
|
+
return this._kdf;
|
|
3842
|
+
}
|
|
3843
|
+
get aead() {
|
|
3844
|
+
return this._aead;
|
|
3845
|
+
}
|
|
3846
|
+
async createSenderContext(params) {
|
|
3847
|
+
this._validateInputLength(params);
|
|
3848
|
+
await this._setup();
|
|
3849
|
+
const dh = await this._kem.encap(params);
|
|
3850
|
+
let mode;
|
|
3851
|
+
if (params.psk !== undefined) {
|
|
3852
|
+
mode = params.senderKey !== undefined ? Mode.AuthPsk : Mode.Psk;
|
|
3853
|
+
} else {
|
|
3854
|
+
mode = params.senderKey !== undefined ? Mode.Auth : Mode.Base;
|
|
3855
|
+
}
|
|
3856
|
+
return await this._keyScheduleS(mode, dh.sharedSecret, dh.enc, params);
|
|
3857
|
+
}
|
|
3858
|
+
async createRecipientContext(params) {
|
|
3859
|
+
this._validateInputLength(params);
|
|
3860
|
+
await this._setup();
|
|
3861
|
+
const sharedSecret = await this._kem.decap(params);
|
|
3862
|
+
let mode;
|
|
3863
|
+
if (params.psk !== undefined) {
|
|
3864
|
+
mode = params.senderPublicKey !== undefined ? Mode.AuthPsk : Mode.Psk;
|
|
3865
|
+
} else {
|
|
3866
|
+
mode = params.senderPublicKey !== undefined ? Mode.Auth : Mode.Base;
|
|
3867
|
+
}
|
|
3868
|
+
return await this._keyScheduleR(mode, sharedSecret, params);
|
|
3869
|
+
}
|
|
3870
|
+
async seal(params, pt, aad = EMPTY.buffer) {
|
|
3871
|
+
const ctx = await this.createSenderContext(params);
|
|
3872
|
+
return {
|
|
3873
|
+
ct: await ctx.seal(pt, aad),
|
|
3874
|
+
enc: ctx.enc
|
|
3875
|
+
};
|
|
3876
|
+
}
|
|
3877
|
+
async open(params, ct, aad = EMPTY.buffer) {
|
|
3878
|
+
const ctx = await this.createRecipientContext(params);
|
|
3879
|
+
return await ctx.open(ct, aad);
|
|
3880
|
+
}
|
|
3881
|
+
async _keySchedule(mode, sharedSecret, params) {
|
|
3882
|
+
const pskId = params.psk === undefined ? EMPTY : new Uint8Array(params.psk.id);
|
|
3883
|
+
const pskIdHash = await this._kdf.labeledExtract(EMPTY.buffer, LABEL_PSK_ID_HASH, pskId);
|
|
3884
|
+
const info = params.info === undefined ? EMPTY : new Uint8Array(params.info);
|
|
3885
|
+
const infoHash = await this._kdf.labeledExtract(EMPTY.buffer, LABEL_INFO_HASH, info);
|
|
3886
|
+
const keyScheduleContext = new Uint8Array(1 + pskIdHash.byteLength + infoHash.byteLength);
|
|
3887
|
+
keyScheduleContext.set(new Uint8Array([mode]), 0);
|
|
3888
|
+
keyScheduleContext.set(new Uint8Array(pskIdHash), 1);
|
|
3889
|
+
keyScheduleContext.set(new Uint8Array(infoHash), 1 + pskIdHash.byteLength);
|
|
3890
|
+
const psk = params.psk === undefined ? EMPTY : new Uint8Array(params.psk.key);
|
|
3891
|
+
const ikm = this._kdf.buildLabeledIkm(LABEL_SECRET, psk).buffer;
|
|
3892
|
+
const exporterSecretInfo = this._kdf.buildLabeledInfo(LABEL_EXP, keyScheduleContext, this._kdf.hashSize).buffer;
|
|
3893
|
+
const exporterSecret = await this._kdf.extractAndExpand(sharedSecret, ikm, exporterSecretInfo, this._kdf.hashSize);
|
|
3894
|
+
if (this._aead.id === AeadId.ExportOnly) {
|
|
3895
|
+
return { aead: this._aead, exporterSecret };
|
|
3896
|
+
}
|
|
3897
|
+
const keyInfo = this._kdf.buildLabeledInfo(LABEL_KEY, keyScheduleContext, this._aead.keySize).buffer;
|
|
3898
|
+
const key = await this._kdf.extractAndExpand(sharedSecret, ikm, keyInfo, this._aead.keySize);
|
|
3899
|
+
const baseNonceInfo = this._kdf.buildLabeledInfo(LABEL_BASE_NONCE, keyScheduleContext, this._aead.nonceSize).buffer;
|
|
3900
|
+
const baseNonce = await this._kdf.extractAndExpand(sharedSecret, ikm, baseNonceInfo, this._aead.nonceSize);
|
|
3901
|
+
return {
|
|
3902
|
+
aead: this._aead,
|
|
3903
|
+
exporterSecret,
|
|
3904
|
+
key,
|
|
3905
|
+
baseNonce: new Uint8Array(baseNonce),
|
|
3906
|
+
seq: 0
|
|
3907
|
+
};
|
|
3908
|
+
}
|
|
3909
|
+
async _keyScheduleS(mode, sharedSecret, enc, params) {
|
|
3910
|
+
const res = await this._keySchedule(mode, sharedSecret, params);
|
|
3911
|
+
if (res.key === undefined) {
|
|
3912
|
+
return new SenderExporterContextImpl(this._api, this._kdf, res.exporterSecret, enc);
|
|
3913
|
+
}
|
|
3914
|
+
return new SenderContextImpl(this._api, this._kdf, res, enc);
|
|
3915
|
+
}
|
|
3916
|
+
async _keyScheduleR(mode, sharedSecret, params) {
|
|
3917
|
+
const res = await this._keySchedule(mode, sharedSecret, params);
|
|
3918
|
+
if (res.key === undefined) {
|
|
3919
|
+
return new RecipientExporterContextImpl(this._api, this._kdf, res.exporterSecret);
|
|
3920
|
+
}
|
|
3921
|
+
return new RecipientContextImpl(this._api, this._kdf, res);
|
|
3922
|
+
}
|
|
3923
|
+
_validateInputLength(params) {
|
|
3924
|
+
if (params.info !== undefined && params.info.byteLength > INFO_LENGTH_LIMIT) {
|
|
3925
|
+
throw new InvalidParamError("Too long info");
|
|
3926
|
+
}
|
|
3927
|
+
if (params.psk !== undefined) {
|
|
3928
|
+
if (params.psk.key.byteLength < MINIMUM_PSK_LENGTH) {
|
|
3929
|
+
throw new InvalidParamError(`PSK must have at least ${MINIMUM_PSK_LENGTH} bytes`);
|
|
3930
|
+
}
|
|
3931
|
+
if (params.psk.key.byteLength > INPUT_LENGTH_LIMIT) {
|
|
3932
|
+
throw new InvalidParamError("Too long psk.key");
|
|
3933
|
+
}
|
|
3934
|
+
if (params.psk.id.byteLength > INPUT_LENGTH_LIMIT) {
|
|
3935
|
+
throw new InvalidParamError("Too long psk.id");
|
|
3936
|
+
}
|
|
3937
|
+
}
|
|
3938
|
+
return;
|
|
3939
|
+
}
|
|
3940
|
+
}
|
|
3941
|
+
|
|
3942
|
+
// ../../node_modules/@hpke/core/esm/src/kems/dhkemNative.js
|
|
3943
|
+
class DhkemP256HkdfSha256Native extends Dhkem {
|
|
3944
|
+
constructor() {
|
|
3945
|
+
const kdf = new HkdfSha256Native;
|
|
3946
|
+
const prim = new Ec(KemId.DhkemP256HkdfSha256, kdf);
|
|
3947
|
+
super(KemId.DhkemP256HkdfSha256, prim, kdf);
|
|
3948
|
+
Object.defineProperty(this, "id", {
|
|
3949
|
+
enumerable: true,
|
|
3950
|
+
configurable: true,
|
|
3951
|
+
writable: true,
|
|
3952
|
+
value: KemId.DhkemP256HkdfSha256
|
|
3953
|
+
});
|
|
3954
|
+
Object.defineProperty(this, "secretSize", {
|
|
3955
|
+
enumerable: true,
|
|
3956
|
+
configurable: true,
|
|
3957
|
+
writable: true,
|
|
3958
|
+
value: 32
|
|
3959
|
+
});
|
|
3960
|
+
Object.defineProperty(this, "encSize", {
|
|
3961
|
+
enumerable: true,
|
|
3962
|
+
configurable: true,
|
|
3963
|
+
writable: true,
|
|
3964
|
+
value: 65
|
|
3965
|
+
});
|
|
3966
|
+
Object.defineProperty(this, "publicKeySize", {
|
|
3967
|
+
enumerable: true,
|
|
3968
|
+
configurable: true,
|
|
3969
|
+
writable: true,
|
|
3970
|
+
value: 65
|
|
3971
|
+
});
|
|
3972
|
+
Object.defineProperty(this, "privateKeySize", {
|
|
3973
|
+
enumerable: true,
|
|
3974
|
+
configurable: true,
|
|
3975
|
+
writable: true,
|
|
3976
|
+
value: 32
|
|
3977
|
+
});
|
|
3978
|
+
}
|
|
3979
|
+
}
|
|
3980
|
+
|
|
3981
|
+
// ../../node_modules/@hpke/core/esm/src/native.js
|
|
3982
|
+
class CipherSuite extends CipherSuiteNative {
|
|
3983
|
+
}
|
|
3984
|
+
|
|
3985
|
+
class DhkemP256HkdfSha256 extends DhkemP256HkdfSha256Native {
|
|
3986
|
+
}
|
|
3987
|
+
class HkdfSha256 extends HkdfSha256Native {
|
|
3988
|
+
}
|
|
3989
|
+
// src/internal/encoding.ts
|
|
3990
|
+
function toArrayBuffer(view) {
|
|
3991
|
+
return view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength);
|
|
3992
|
+
}
|
|
3993
|
+
function arrayBufferToBase64(data) {
|
|
3994
|
+
return Buffer.from(data).toString("base64");
|
|
3995
|
+
}
|
|
3996
|
+
function base64ToArrayBuffer(base642) {
|
|
3997
|
+
const buf = Buffer.from(base642, "base64");
|
|
3998
|
+
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
|
|
3999
|
+
}
|
|
4000
|
+
|
|
4001
|
+
// src/wallet-import.ts
|
|
4002
|
+
function buildCipherSuite() {
|
|
4003
|
+
return new CipherSuite({
|
|
4004
|
+
kem: new DhkemP256HkdfSha256,
|
|
4005
|
+
kdf: new HkdfSha256,
|
|
4006
|
+
aead: new Chacha20Poly1305
|
|
4007
|
+
});
|
|
4008
|
+
}
|
|
4009
|
+
function parseSolanaSecret(input) {
|
|
4010
|
+
const trimmed = input.trim();
|
|
4011
|
+
if (!trimmed.startsWith("[")) {
|
|
4012
|
+
try {
|
|
4013
|
+
return base58.decode(trimmed);
|
|
4014
|
+
} catch {
|
|
4015
|
+
throw new Error("Invalid Solana private key: expected a base58 string or an id.json byte array.");
|
|
4016
|
+
}
|
|
4017
|
+
}
|
|
4018
|
+
const parsed = (() => {
|
|
4019
|
+
try {
|
|
4020
|
+
return JSON.parse(trimmed);
|
|
4021
|
+
} catch {
|
|
4022
|
+
return;
|
|
4023
|
+
}
|
|
4024
|
+
})();
|
|
4025
|
+
const isByteArray = Array.isArray(parsed) && parsed.length === 64 && parsed.every((value) => Number.isInteger(value) && value >= 0 && value <= 255);
|
|
4026
|
+
if (!isByteArray) {
|
|
4027
|
+
throw new Error("This looks like a Solana keyfile (id.json) but is not a 64-byte array. Pass the file's contents, e.g. [12,34,...].");
|
|
4028
|
+
}
|
|
4029
|
+
return Uint8Array.from(parsed);
|
|
4030
|
+
}
|
|
4031
|
+
function decodeWalletPrivateKey(chain2, privateKey) {
|
|
4032
|
+
if (chain2 === "evm") {
|
|
4033
|
+
const hex2 = privateKey.startsWith("0x") ? privateKey.slice(2) : privateKey;
|
|
4034
|
+
if (hex2.length === 0 || hex2.length % 2 !== 0 || !/^[0-9a-fA-F]+$/.test(hex2)) {
|
|
4035
|
+
throw new Error('Invalid EVM private key: expected a hex string (optionally "0x"-prefixed)');
|
|
4036
|
+
}
|
|
4037
|
+
return Uint8Array.from(Buffer.from(hex2, "hex"));
|
|
4038
|
+
}
|
|
4039
|
+
return parseSolanaSecret(privateKey);
|
|
4040
|
+
}
|
|
4041
|
+
async function encryptWalletKeyForImport(params) {
|
|
4042
|
+
const plaintext = decodeWalletPrivateKey(params.chain, params.privateKey);
|
|
4043
|
+
const suite = buildCipherSuite();
|
|
4044
|
+
const recipientPublicKey = await suite.kem.deserializePublicKey(base64ToArrayBuffer(params.encryptionPublicKey));
|
|
4045
|
+
const sender = await suite.createSenderContext({ recipientPublicKey });
|
|
4046
|
+
const ciphertext = await sender.seal(toArrayBuffer(plaintext));
|
|
4047
|
+
return {
|
|
4048
|
+
ciphertext: arrayBufferToBase64(ciphertext),
|
|
4049
|
+
encapsulatedKey: arrayBufferToBase64(sender.enc)
|
|
4050
|
+
};
|
|
4051
|
+
}
|
|
4052
|
+
async function generateSignerKeypair() {
|
|
4053
|
+
const keyPair = await crypto.subtle.generateKey({ name: "ECDSA", namedCurve: "P-256" }, true, ["sign", "verify"]);
|
|
4054
|
+
const [publicKeyDer, privateKeyDer] = await Promise.all([
|
|
4055
|
+
crypto.subtle.exportKey("spki", keyPair.publicKey),
|
|
4056
|
+
crypto.subtle.exportKey("pkcs8", keyPair.privateKey)
|
|
4057
|
+
]);
|
|
4058
|
+
return {
|
|
4059
|
+
privateKeyPem: derToPem(privateKeyDer, "PRIVATE KEY"),
|
|
4060
|
+
publicKeyDerBase64: arrayBufferToBase64(publicKeyDer)
|
|
4061
|
+
};
|
|
4062
|
+
}
|
|
4063
|
+
function derToPem(der, label) {
|
|
4064
|
+
const base642 = arrayBufferToBase64(der);
|
|
4065
|
+
const lines = base642.match(/.{1,64}/g) ?? [base642];
|
|
4066
|
+
return `-----BEGIN ${label}-----
|
|
4067
|
+
${lines.join(`
|
|
4068
|
+
`)}
|
|
4069
|
+
-----END ${label}-----
|
|
4070
|
+
`;
|
|
4071
|
+
}
|
|
4072
|
+
|
|
4073
|
+
// src/commands/wallets.ts
|
|
4074
|
+
async function wallets(args, ctx) {
|
|
4075
|
+
const { deps, apiUrl, json } = ctx;
|
|
4076
|
+
const parsed = parseArgs(args, {});
|
|
4077
|
+
if ("error" in parsed) {
|
|
4078
|
+
writeUsageFailure(deps, parsed.error, json);
|
|
4079
|
+
return 2;
|
|
4080
|
+
}
|
|
4081
|
+
if (parsed.positionals.length > 0) {
|
|
4082
|
+
writeUsageFailure(deps, `Unexpected argument: ${parsed.positionals[0]}`, json);
|
|
4083
|
+
return 2;
|
|
4084
|
+
}
|
|
4085
|
+
const apiKey = await resolveApiKey(deps);
|
|
4086
|
+
if (!apiKey) {
|
|
4087
|
+
writeLocalFailure(deps, { code: "NO_API_KEY", message: "No API key available.", suggestion: "Run: candle keys create" }, json);
|
|
4088
|
+
return 1;
|
|
4089
|
+
}
|
|
4090
|
+
const embedded = await apiRequest("/api/v1/agent/wallets/embedded", {
|
|
4091
|
+
auth: "key",
|
|
4092
|
+
credentials: { apiKey },
|
|
4093
|
+
apiUrl,
|
|
4094
|
+
fetch: deps.fetch,
|
|
4095
|
+
env: deps.env
|
|
4096
|
+
});
|
|
4097
|
+
if (!embedded.ok) {
|
|
4098
|
+
writeFailure(deps, embedded, { apiUrl, authType: "key" }, json);
|
|
4099
|
+
return 1;
|
|
4100
|
+
}
|
|
4101
|
+
const linked = await apiRequest("/api/v1/agent/wallets", {
|
|
4102
|
+
auth: "key",
|
|
4103
|
+
credentials: { apiKey },
|
|
4104
|
+
apiUrl,
|
|
4105
|
+
fetch: deps.fetch,
|
|
4106
|
+
env: deps.env
|
|
4107
|
+
});
|
|
4108
|
+
if (!linked.ok) {
|
|
4109
|
+
writeFailure(deps, linked, { apiUrl, authType: "key" }, json);
|
|
4110
|
+
return 1;
|
|
4111
|
+
}
|
|
4112
|
+
if (json) {
|
|
4113
|
+
deps.stdout.write(`${JSON.stringify({ embedded: embedded.body, linked: linked.body })}
|
|
4114
|
+
`);
|
|
4115
|
+
return 0;
|
|
4116
|
+
}
|
|
4117
|
+
const embeddedBody = embedded.body;
|
|
4118
|
+
const linkedBody = linked.body;
|
|
4119
|
+
deps.stdout.write(`Embedded (launch) wallets:
|
|
4120
|
+
`);
|
|
4121
|
+
deps.stdout.write(`${renderTable(["Wallet", "Address", "Delegated", "Launches on"], [
|
|
4122
|
+
[
|
|
4123
|
+
"solana",
|
|
4124
|
+
embeddedBody.wallets.solana?.address ?? "none",
|
|
4125
|
+
embeddedBody.wallets.solana?.delegated ? "yes" : "no",
|
|
4126
|
+
"solana"
|
|
4127
|
+
],
|
|
4128
|
+
[
|
|
4129
|
+
"evm",
|
|
4130
|
+
embeddedBody.wallets.evm?.address ?? "none",
|
|
4131
|
+
embeddedBody.wallets.evm?.delegated ? "yes" : "no",
|
|
4132
|
+
"hood"
|
|
4133
|
+
]
|
|
4134
|
+
])}
|
|
4135
|
+
`);
|
|
4136
|
+
deps.stdout.write(`
|
|
4137
|
+
Linked wallets:
|
|
4138
|
+
`);
|
|
4139
|
+
if (linkedBody.page.length === 0) {
|
|
4140
|
+
deps.stdout.write(`(none)
|
|
4141
|
+
`);
|
|
4142
|
+
} else {
|
|
4143
|
+
deps.stdout.write(`${renderTable(["Id", "Wallet", "Address", "Label", "Revoked"], linkedBody.page.map((wallet) => [
|
|
4144
|
+
wallet._id,
|
|
4145
|
+
wallet.chain,
|
|
4146
|
+
wallet.address,
|
|
4147
|
+
wallet.label ?? "-",
|
|
4148
|
+
wallet.revokedAt ? "yes" : "no"
|
|
4149
|
+
]))}
|
|
4150
|
+
`);
|
|
4151
|
+
}
|
|
4152
|
+
return 0;
|
|
4153
|
+
}
|
|
4154
|
+
async function resolveKeyMaterial(keyFile, chain2, ctx) {
|
|
4155
|
+
if (keyFile !== undefined) {
|
|
4156
|
+
try {
|
|
4157
|
+
return { ok: true, privateKey: (await ctx.deps.readFile(keyFile)).trim() };
|
|
4158
|
+
} catch (error) {
|
|
4159
|
+
return { ok: false, message: `Could not read --key-file: ${error instanceof Error ? error.message : error}` };
|
|
4160
|
+
}
|
|
4161
|
+
}
|
|
4162
|
+
try {
|
|
4163
|
+
const promptText = chain2 === "solana" ? "Solana private key (base58 or id.json contents; input hidden): " : "EVM private key (hex; input hidden): ";
|
|
4164
|
+
const entered = (await ctx.deps.promptSecret(promptText)).trim();
|
|
4165
|
+
if (entered.length === 0)
|
|
4166
|
+
return { ok: false, message: "No private key entered" };
|
|
4167
|
+
return { ok: true, privateKey: entered };
|
|
4168
|
+
} catch (error) {
|
|
4169
|
+
return { ok: false, message: error instanceof Error ? error.message : String(error) };
|
|
4170
|
+
}
|
|
4171
|
+
}
|
|
4172
|
+
function resolveImportAddress(chain2, privateKey, addressFlag) {
|
|
4173
|
+
if (chain2 === "evm") {
|
|
4174
|
+
if (!addressFlag)
|
|
4175
|
+
return { ok: false, message: "--address is required for --chain evm" };
|
|
4176
|
+
return { ok: true, address: addressFlag };
|
|
4177
|
+
}
|
|
4178
|
+
let secret;
|
|
4179
|
+
try {
|
|
4180
|
+
secret = parseSolanaSecret(privateKey);
|
|
4181
|
+
} catch (error) {
|
|
4182
|
+
return { ok: false, message: error instanceof Error ? error.message : String(error) };
|
|
4183
|
+
}
|
|
4184
|
+
if (secret.length !== 64) {
|
|
4185
|
+
return { ok: false, message: `Invalid Solana private key: expected 64 bytes, got ${secret.length}` };
|
|
4186
|
+
}
|
|
4187
|
+
const derived = base58.encode(secret.slice(32));
|
|
4188
|
+
if (addressFlag !== undefined && addressFlag !== derived) {
|
|
4189
|
+
return {
|
|
4190
|
+
ok: false,
|
|
4191
|
+
message: `--address does not match this private key (the key derives ${derived}). Refusing to import a mismatched pair.`
|
|
4192
|
+
};
|
|
4193
|
+
}
|
|
4194
|
+
return { ok: true, address: derived };
|
|
4195
|
+
}
|
|
4196
|
+
async function walletsImport(args, ctx) {
|
|
4197
|
+
const { deps, apiUrl, json } = ctx;
|
|
4198
|
+
const parsed = parseArgs(args, {
|
|
4199
|
+
valueFlags: ["--chain", "--address", "--label", "--key-file", "--signer-out"]
|
|
4200
|
+
});
|
|
4201
|
+
if ("error" in parsed) {
|
|
4202
|
+
writeUsageFailure(deps, parsed.error, json);
|
|
4203
|
+
return 2;
|
|
4204
|
+
}
|
|
4205
|
+
if (parsed.positionals.length > 0) {
|
|
4206
|
+
writeUsageFailure(deps, `Unexpected argument: ${parsed.positionals[0]}`, json);
|
|
4207
|
+
return 2;
|
|
4208
|
+
}
|
|
4209
|
+
const chainFlag = parsed.values["--chain"];
|
|
4210
|
+
const chainValid = chainFlag === "solana" || chainFlag === "evm";
|
|
4211
|
+
const missing = [];
|
|
4212
|
+
if (!chainValid)
|
|
4213
|
+
missing.push("--chain <solana|evm>");
|
|
4214
|
+
if (chainFlag === "evm" && parsed.values["--address"] === undefined)
|
|
4215
|
+
missing.push("--address <0x...>");
|
|
4216
|
+
if (missing.length > 0) {
|
|
4217
|
+
deps.stderr.write(`Missing required: ${missing.join(", ")}
|
|
4218
|
+
`);
|
|
4219
|
+
deps.stderr.write(`Example: candle wallets import --chain evm --address 0xYourWallet --api-url ${apiUrl}
|
|
4220
|
+
`);
|
|
4221
|
+
return 2;
|
|
4222
|
+
}
|
|
4223
|
+
const chain2 = chainFlag;
|
|
4224
|
+
const material = await resolveKeyMaterial(parsed.values["--key-file"], chain2, ctx);
|
|
4225
|
+
if (!material.ok) {
|
|
4226
|
+
writeLocalFailure(deps, { code: "KEY_INPUT_FAILED", message: material.message }, json);
|
|
4227
|
+
return 1;
|
|
4228
|
+
}
|
|
4229
|
+
const resolvedAddress = resolveImportAddress(chain2, material.privateKey, parsed.values["--address"]);
|
|
4230
|
+
if (!resolvedAddress.ok) {
|
|
4231
|
+
writeLocalFailure(deps, { code: "KEY_INPUT_FAILED", message: resolvedAddress.message }, json);
|
|
4232
|
+
return 1;
|
|
4233
|
+
}
|
|
4234
|
+
const address = resolvedAddress.address;
|
|
4235
|
+
const apiKey = await resolveApiKey(deps);
|
|
4236
|
+
if (!apiKey) {
|
|
4237
|
+
writeLocalFailure(deps, { code: "NO_API_KEY", message: "No API key available.", suggestion: "Run: candle keys create" }, json);
|
|
4238
|
+
return 1;
|
|
4239
|
+
}
|
|
4240
|
+
const init = await apiRequest("/api/v1/agent/wallets/import/init", {
|
|
4241
|
+
method: "POST",
|
|
4242
|
+
body: { chain: chain2, address },
|
|
4243
|
+
auth: "key",
|
|
4244
|
+
credentials: { apiKey },
|
|
4245
|
+
apiUrl,
|
|
4246
|
+
fetch: deps.fetch,
|
|
4247
|
+
env: deps.env
|
|
4248
|
+
});
|
|
4249
|
+
if (!init.ok) {
|
|
4250
|
+
writeFailure(deps, init, { apiUrl, authType: "key" }, json);
|
|
4251
|
+
return 1;
|
|
4252
|
+
}
|
|
4253
|
+
const { encryptionPublicKey } = init.body;
|
|
4254
|
+
const { ciphertext, encapsulatedKey } = await encryptWalletKeyForImport({
|
|
4255
|
+
chain: chain2,
|
|
4256
|
+
privateKey: material.privateKey,
|
|
4257
|
+
encryptionPublicKey
|
|
4258
|
+
});
|
|
4259
|
+
const signer = await generateSignerKeypair();
|
|
4260
|
+
const submit = await apiRequest("/api/v1/agent/wallets/import/submit", {
|
|
4261
|
+
method: "POST",
|
|
4262
|
+
body: {
|
|
4263
|
+
chain: chain2,
|
|
4264
|
+
address,
|
|
4265
|
+
ciphertext,
|
|
4266
|
+
encapsulatedKey,
|
|
4267
|
+
signerPublicKey: signer.publicKeyDerBase64,
|
|
4268
|
+
...parsed.values["--label"] !== undefined ? { label: parsed.values["--label"] } : {}
|
|
4269
|
+
},
|
|
4270
|
+
auth: "key",
|
|
4271
|
+
credentials: { apiKey },
|
|
4272
|
+
apiUrl,
|
|
4273
|
+
fetch: deps.fetch,
|
|
4274
|
+
env: deps.env
|
|
4275
|
+
});
|
|
4276
|
+
if (!submit.ok) {
|
|
4277
|
+
writeFailure(deps, submit, { apiUrl, authType: "key" }, json);
|
|
4278
|
+
return 1;
|
|
4279
|
+
}
|
|
4280
|
+
const result = submit.body;
|
|
4281
|
+
await deps.store.set(walletSignerRef(result.id), pemToStoredSigner(signer.privateKeyPem));
|
|
4282
|
+
const signerOut = parsed.values["--signer-out"];
|
|
4283
|
+
if (signerOut !== undefined) {
|
|
4284
|
+
try {
|
|
4285
|
+
await deps.writeFile(signerOut, signer.privateKeyPem);
|
|
4286
|
+
} catch (error) {
|
|
4287
|
+
deps.stderr.write(`Warning: could not write --signer-out (${error instanceof Error ? error.message : error}); the signer is stored in the ${deps.backend} store
|
|
4288
|
+
`);
|
|
4289
|
+
}
|
|
4290
|
+
}
|
|
4291
|
+
const verification = await verifyImportLanded({ id: result.id, apiKey, apiUrl, ctx });
|
|
4292
|
+
if (verification.status === "missing") {
|
|
4293
|
+
writeLocalFailure(deps, {
|
|
4294
|
+
code: "IMPORT_NOT_VISIBLE",
|
|
4295
|
+
message: `The server accepted the import (wallet id ${result.id}) but it is not on the account these ` + `credentials belong to${verification.account !== undefined ? ` (${verification.account})` : ""}. ` + `That usually means the CLI is logged in as a different Candle account than you expect. ` + `Run: candle doctor --api-url ${apiUrl}`
|
|
4296
|
+
}, json);
|
|
4297
|
+
return 1;
|
|
4298
|
+
}
|
|
4299
|
+
if (json) {
|
|
4300
|
+
deps.stdout.write(`${JSON.stringify({
|
|
4301
|
+
id: result.id,
|
|
4302
|
+
address: result.address,
|
|
4303
|
+
chain: result.chain,
|
|
4304
|
+
privyWalletId: result.privyWalletId,
|
|
4305
|
+
account: verification.account,
|
|
4306
|
+
apiUrl,
|
|
4307
|
+
signerStore: deps.backend,
|
|
4308
|
+
verified: verification.status === "verified",
|
|
4309
|
+
...signerOut !== undefined ? { signerOut } : {}
|
|
4310
|
+
})}
|
|
4311
|
+
`);
|
|
4312
|
+
return 0;
|
|
4313
|
+
}
|
|
4314
|
+
deps.stdout.write(`Imported ${result.chain} wallet ${result.address}
|
|
4315
|
+
`);
|
|
4316
|
+
deps.stdout.write(` Account: ${verification.account ?? "unknown"} at ${apiUrl}
|
|
4317
|
+
`);
|
|
4318
|
+
deps.stdout.write(` Wallet id: ${result.id}
|
|
4319
|
+
`);
|
|
4320
|
+
deps.stdout.write(` Privy wallet id: ${result.privyWalletId}
|
|
4321
|
+
`);
|
|
4322
|
+
if (signerOut !== undefined) {
|
|
4323
|
+
deps.stdout.write(` Signer key: exported to ${signerOut} (and in the ${deps.backend} store)
|
|
4324
|
+
`);
|
|
4325
|
+
deps.stdout.write(`Back up ${signerOut}: trades from this wallet sign with it, and it cannot be re-downloaded.
|
|
4326
|
+
`);
|
|
4327
|
+
} else {
|
|
4328
|
+
deps.stdout.write(` Signer key: stored in your ${deps.backend} store; nothing to save by hand
|
|
4329
|
+
`);
|
|
4330
|
+
}
|
|
4331
|
+
if (verification.status === "unchecked") {
|
|
4332
|
+
deps.stdout.write(`Note: could not read the wallet back to confirm which account it landed on. Run: candle wallets --api-url ${apiUrl}
|
|
4333
|
+
`);
|
|
4334
|
+
}
|
|
4335
|
+
return 0;
|
|
4336
|
+
}
|
|
4337
|
+
async function verifyImportLanded(args) {
|
|
4338
|
+
const { deps } = args.ctx;
|
|
4339
|
+
const listed = await apiRequest("/api/v1/agent/wallets", {
|
|
4340
|
+
method: "GET",
|
|
4341
|
+
auth: "key",
|
|
4342
|
+
credentials: { apiKey: args.apiKey },
|
|
4343
|
+
apiUrl: args.apiUrl,
|
|
4344
|
+
fetch: deps.fetch,
|
|
4345
|
+
env: deps.env
|
|
4346
|
+
});
|
|
4347
|
+
if (!listed.ok)
|
|
4348
|
+
return { status: "unchecked" };
|
|
4349
|
+
const page = listed.body.page;
|
|
4350
|
+
if (!Array.isArray(page))
|
|
4351
|
+
return { status: "unchecked" };
|
|
4352
|
+
const account = page.find((row) => typeof row.userAddress === "string")?.userAddress;
|
|
4353
|
+
const found = page.some((row) => row._id === args.id);
|
|
4354
|
+
return { status: found ? "verified" : "missing", ...account !== undefined ? { account } : {} };
|
|
4355
|
+
}
|
|
4356
|
+
async function walletsRevoke(args, ctx) {
|
|
4357
|
+
const { deps, apiUrl, json } = ctx;
|
|
4358
|
+
const parsed = parseArgs(args, {});
|
|
4359
|
+
if ("error" in parsed) {
|
|
4360
|
+
writeUsageFailure(deps, parsed.error, json);
|
|
4361
|
+
return 2;
|
|
4362
|
+
}
|
|
4363
|
+
const [walletId, extra] = parsed.positionals;
|
|
4364
|
+
if (!walletId || extra !== undefined) {
|
|
4365
|
+
deps.stderr.write(`Usage: candle wallets revoke <wallet-id>
|
|
4366
|
+
`);
|
|
4367
|
+
return 2;
|
|
4368
|
+
}
|
|
4369
|
+
const apiKey = await resolveApiKey(deps);
|
|
4370
|
+
if (!apiKey) {
|
|
4371
|
+
writeLocalFailure(deps, { code: "NO_API_KEY", message: "No API key available.", suggestion: "Run: candle keys create" }, json);
|
|
4372
|
+
return 1;
|
|
4373
|
+
}
|
|
4374
|
+
const result = await apiRequest(`/api/v1/agent/wallets/${encodeURIComponent(walletId)}`, {
|
|
4375
|
+
method: "DELETE",
|
|
4376
|
+
auth: "key",
|
|
4377
|
+
credentials: { apiKey },
|
|
4378
|
+
apiUrl,
|
|
4379
|
+
fetch: deps.fetch,
|
|
4380
|
+
env: deps.env
|
|
4381
|
+
});
|
|
4382
|
+
if (!result.ok) {
|
|
4383
|
+
writeFailure(deps, result, { apiUrl, authType: "key" }, json);
|
|
4384
|
+
return 1;
|
|
4385
|
+
}
|
|
4386
|
+
try {
|
|
4387
|
+
await deps.store.delete(walletSignerRef(walletId));
|
|
4388
|
+
} catch {}
|
|
4389
|
+
if (json) {
|
|
4390
|
+
deps.stdout.write(`${JSON.stringify({ revoked: walletId, ...result.body })}
|
|
4391
|
+
`);
|
|
4392
|
+
return 0;
|
|
4393
|
+
}
|
|
4394
|
+
deps.stdout.write(`Revoked linked wallet ${walletId}
|
|
4395
|
+
`);
|
|
4396
|
+
return 0;
|
|
4397
|
+
}
|
|
4398
|
+
|
|
4399
|
+
// src/config.ts
|
|
4400
|
+
import { chmod as chmod2, mkdir as mkdir2, readFile as readFile2, rm, writeFile as writeFile2 } from "node:fs/promises";
|
|
4401
|
+
import { homedir as homedir3 } from "node:os";
|
|
4402
|
+
import { join as join4 } from "node:path";
|
|
4403
|
+
function configDir2() {
|
|
4404
|
+
return process.env.CANDLE_CONFIG_DIR?.trim() || join4(homedir3(), ".config", "candle");
|
|
4405
|
+
}
|
|
4406
|
+
function configFilePath() {
|
|
4407
|
+
return join4(configDir2(), "config.json");
|
|
4408
|
+
}
|
|
4409
|
+
async function readConfig() {
|
|
4410
|
+
try {
|
|
4411
|
+
const raw = await readFile2(configFilePath(), "utf8");
|
|
4412
|
+
return JSON.parse(raw);
|
|
4413
|
+
} catch (err) {
|
|
4414
|
+
if (err.code === "ENOENT")
|
|
4415
|
+
return {};
|
|
4416
|
+
throw err;
|
|
4417
|
+
}
|
|
4418
|
+
}
|
|
4419
|
+
async function writeConfig(patch) {
|
|
4420
|
+
const current = await readConfig();
|
|
4421
|
+
const next = { ...current, ...patch };
|
|
4422
|
+
const dir = configDir2();
|
|
4423
|
+
await mkdir2(dir, { recursive: true });
|
|
4424
|
+
await chmod2(dir, 448);
|
|
4425
|
+
await writeFile2(configFilePath(), JSON.stringify(next, null, 2), "utf8");
|
|
4426
|
+
}
|
|
4427
|
+
async function clearConfig() {
|
|
4428
|
+
try {
|
|
4429
|
+
await rm(configFilePath());
|
|
4430
|
+
} catch (err) {
|
|
4431
|
+
if (err.code !== "ENOENT")
|
|
4432
|
+
throw err;
|
|
4433
|
+
}
|
|
4434
|
+
}
|
|
4435
|
+
|
|
4436
|
+
// src/keychain.ts
|
|
4437
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
4438
|
+
var SERVICE = "tv.candle.cli";
|
|
4439
|
+
var PROBE_ACCOUNT = "tv.candle.cli.probe";
|
|
4440
|
+
var UNSAFE_FOR_SECURITY_COMMAND_LINE = /["\\\n\r]/;
|
|
4441
|
+
var RUN_TIMEOUT_MS = 1e4;
|
|
4442
|
+
function run(bin, args, stdin) {
|
|
4443
|
+
return new Promise((resolve, reject) => {
|
|
4444
|
+
const child = spawn(bin, args, { stdio: ["pipe", "pipe", "pipe"], env: process.env });
|
|
4445
|
+
let stdout = "";
|
|
4446
|
+
let stderr = "";
|
|
4447
|
+
let settled = false;
|
|
4448
|
+
const timeout = setTimeout(() => {
|
|
4449
|
+
if (settled)
|
|
4450
|
+
return;
|
|
4451
|
+
child.kill("SIGKILL");
|
|
4452
|
+
}, RUN_TIMEOUT_MS);
|
|
4453
|
+
child.stdin.on("error", () => {});
|
|
4454
|
+
child.stdout.on("data", (chunk) => {
|
|
4455
|
+
stdout += chunk.toString("utf8");
|
|
4456
|
+
});
|
|
4457
|
+
child.stderr.on("data", (chunk) => {
|
|
4458
|
+
stderr += chunk.toString("utf8");
|
|
4459
|
+
});
|
|
4460
|
+
child.on("error", (err) => {
|
|
4461
|
+
if (settled)
|
|
4462
|
+
return;
|
|
4463
|
+
settled = true;
|
|
4464
|
+
clearTimeout(timeout);
|
|
4465
|
+
reject(err);
|
|
4466
|
+
});
|
|
4467
|
+
child.on("close", (code) => {
|
|
4468
|
+
if (settled)
|
|
4469
|
+
return;
|
|
4470
|
+
settled = true;
|
|
4471
|
+
clearTimeout(timeout);
|
|
4472
|
+
resolve({ status: code ?? -1, stdout, stderr });
|
|
4473
|
+
});
|
|
4474
|
+
if (stdin !== undefined)
|
|
4475
|
+
child.stdin.write(stdin);
|
|
4476
|
+
child.stdin.end();
|
|
4477
|
+
});
|
|
4478
|
+
}
|
|
4479
|
+
function binaryResolvable(bin) {
|
|
4480
|
+
return spawnSync("which", [bin], { env: process.env }).status === 0;
|
|
4481
|
+
}
|
|
4482
|
+
|
|
4483
|
+
class KeychainSecretStore {
|
|
4484
|
+
binary;
|
|
4485
|
+
constructor(binary = "security") {
|
|
4486
|
+
this.binary = binary;
|
|
4487
|
+
}
|
|
4488
|
+
async get(ref) {
|
|
4489
|
+
const result = await run(this.binary, ["find-generic-password", "-s", SERVICE, "-a", ref, "-w"]);
|
|
4490
|
+
if (result.status !== 0)
|
|
4491
|
+
return null;
|
|
4492
|
+
return result.stdout.replace(/\n$/, "");
|
|
4493
|
+
}
|
|
4494
|
+
async set(ref, value) {
|
|
4495
|
+
if (UNSAFE_FOR_SECURITY_COMMAND_LINE.test(value)) {
|
|
4496
|
+
throw new Error("Refusing to store this secret in the macOS Keychain: it contains a quote, backslash, or " + "newline, which could break out of the quoted argument on security's command-on-stdin line");
|
|
4497
|
+
}
|
|
4498
|
+
const command = `add-generic-password -U -s "${SERVICE}" -a "${ref}" -w "${value}"
|
|
4499
|
+
`;
|
|
4500
|
+
const result = await run(this.binary, ["-i"], command);
|
|
4501
|
+
if (result.status !== 0) {
|
|
4502
|
+
throw new Error(`Failed to store credential in the macOS Keychain (security exited ${result.status})`);
|
|
4503
|
+
}
|
|
4504
|
+
}
|
|
4505
|
+
async delete(ref) {
|
|
4506
|
+
const command = `delete-generic-password -s "${SERVICE}" -a "${ref}"
|
|
4507
|
+
`;
|
|
4508
|
+
await run(this.binary, ["-i"], command);
|
|
4509
|
+
}
|
|
4510
|
+
}
|
|
4511
|
+
|
|
4512
|
+
class SecretToolSecretStore {
|
|
4513
|
+
binary;
|
|
4514
|
+
constructor(binary = "secret-tool") {
|
|
4515
|
+
this.binary = binary;
|
|
4516
|
+
}
|
|
4517
|
+
async get(ref) {
|
|
4518
|
+
const result = await run(this.binary, ["lookup", "service", SERVICE, "account", ref]);
|
|
4519
|
+
if (result.status !== 0)
|
|
4520
|
+
return null;
|
|
4521
|
+
const value = result.stdout.replace(/\n$/, "");
|
|
4522
|
+
return value.length > 0 ? value : null;
|
|
4523
|
+
}
|
|
4524
|
+
async set(ref, value) {
|
|
4525
|
+
const result = await run(this.binary, ["store", "--label=Candle CLI", "service", SERVICE, "account", ref], value);
|
|
4526
|
+
if (result.status !== 0) {
|
|
4527
|
+
throw new Error(`Failed to store credential via secret-tool (exited ${result.status})`);
|
|
4528
|
+
}
|
|
4529
|
+
}
|
|
4530
|
+
async delete(ref) {
|
|
4531
|
+
await run(this.binary, ["clear", "service", SERVICE, "account", ref]);
|
|
4532
|
+
}
|
|
4533
|
+
}
|
|
4534
|
+
async function probeSecretTool(store) {
|
|
4535
|
+
const probeValue = crypto.randomUUID();
|
|
4536
|
+
try {
|
|
4537
|
+
await store.set(PROBE_ACCOUNT, probeValue);
|
|
4538
|
+
const got = await store.get(PROBE_ACCOUNT);
|
|
4539
|
+
return got === probeValue;
|
|
4540
|
+
} catch {
|
|
4541
|
+
return false;
|
|
4542
|
+
} finally {
|
|
4543
|
+
try {
|
|
4544
|
+
await store.delete(PROBE_ACCOUNT);
|
|
4545
|
+
} catch {}
|
|
4546
|
+
}
|
|
4547
|
+
}
|
|
4548
|
+
async function resolveSecretStore(platform = process.platform) {
|
|
4549
|
+
if (platform === "darwin" && binaryResolvable("security")) {
|
|
4550
|
+
return { store: new KeychainSecretStore, backend: "keychain" };
|
|
4551
|
+
}
|
|
4552
|
+
if (platform === "linux" && binaryResolvable("secret-tool")) {
|
|
4553
|
+
const candidate = new SecretToolSecretStore;
|
|
4554
|
+
if (await probeSecretTool(candidate)) {
|
|
4555
|
+
return { store: candidate, backend: "secret-tool" };
|
|
4556
|
+
}
|
|
4557
|
+
}
|
|
4558
|
+
return { store: new EncryptedFileSecretStore, backend: "encrypted-file" };
|
|
4559
|
+
}
|
|
4560
|
+
|
|
4561
|
+
// src/index.ts
|
|
4562
|
+
function extractGlobalFlags(argv) {
|
|
4563
|
+
const rest = [];
|
|
4564
|
+
const flags = { json: false, help: false, version: false };
|
|
4565
|
+
for (let i = 0;i < argv.length; i++) {
|
|
4566
|
+
const arg = argv[i];
|
|
4567
|
+
if (arg === "--json")
|
|
4568
|
+
flags.json = true;
|
|
4569
|
+
else if (arg === "--help" || arg === "-h")
|
|
4570
|
+
flags.help = true;
|
|
4571
|
+
else if (arg === "--version" || arg === "-v")
|
|
4572
|
+
flags.version = true;
|
|
4573
|
+
else if (arg === "--api-url") {
|
|
4574
|
+
const value = argv[++i];
|
|
4575
|
+
if (value === undefined)
|
|
4576
|
+
return { error: "--api-url requires a value" };
|
|
4577
|
+
flags.apiUrl = value;
|
|
4578
|
+
} else if (arg?.startsWith("--api-url="))
|
|
4579
|
+
flags.apiUrl = arg.slice("--api-url=".length);
|
|
4580
|
+
else if (arg !== undefined)
|
|
4581
|
+
rest.push(arg);
|
|
4582
|
+
}
|
|
4583
|
+
return { rest, flags };
|
|
4584
|
+
}
|
|
4585
|
+
var HELP_TEXT = `candle: manage Candle agent credentials from the terminal
|
|
4586
|
+
|
|
4587
|
+
Usage: candle <command> [subcommand] [options]
|
|
4588
|
+
|
|
4589
|
+
Commands:
|
|
4590
|
+
auth login [--scopes <a,b,c>] [--label <name>] [--no-browser] Authorize this device
|
|
4591
|
+
auth status Show credential status
|
|
4592
|
+
auth logout [--keep-key] Clear local credentials
|
|
4593
|
+
keys list List API keys
|
|
4594
|
+
keys create [--scopes <a,b,c>] [--label <name>] Create an API key
|
|
4595
|
+
[--expires-in <days>] [--tx-limit <usd> [--reset daily|weekly|monthly|never]]
|
|
4596
|
+
keys revoke <prefix> Revoke an API key
|
|
4597
|
+
wallets Show launch and linked wallets
|
|
4598
|
+
wallets import --chain <solana|evm> [options] Import a wallet you own (key via --key-file or hidden prompt)
|
|
4599
|
+
wallets revoke <wallet-id> Revoke a linked wallet
|
|
4600
|
+
setup [--no-browser] One wizard: authorize, fund, connect, verify
|
|
4601
|
+
mcp [--tools <a,b,c>] [--read-only] [--print-config] Run the Candle MCP server with stored credentials
|
|
4602
|
+
doctor Diagnose CLI setup
|
|
4603
|
+
|
|
4604
|
+
Global options:
|
|
4605
|
+
--api-url <url> Override the API base URL
|
|
4606
|
+
--json Machine-readable output
|
|
4607
|
+
--help, -h Show this help
|
|
4608
|
+
--version, -v Show the CLI version
|
|
4609
|
+
`;
|
|
4610
|
+
async function run2(argv, deps) {
|
|
4611
|
+
const extracted = extractGlobalFlags(argv);
|
|
4612
|
+
if ("error" in extracted) {
|
|
4613
|
+
deps.stderr.write(`${extracted.error}
|
|
4614
|
+
`);
|
|
4615
|
+
return 2;
|
|
4616
|
+
}
|
|
4617
|
+
const { rest, flags } = extracted;
|
|
4618
|
+
if (flags.version) {
|
|
4619
|
+
deps.stdout.write(`${CLI_VERSION}
|
|
4620
|
+
`);
|
|
4621
|
+
return 0;
|
|
4622
|
+
}
|
|
4623
|
+
if (flags.help) {
|
|
4624
|
+
deps.stdout.write(HELP_TEXT);
|
|
4625
|
+
return 0;
|
|
4626
|
+
}
|
|
4627
|
+
const tokens = rest[0] === "candle" ? rest.slice(1) : rest;
|
|
4628
|
+
const [cmd, sub, ...cmdArgs] = tokens;
|
|
4629
|
+
const config = await deps.readConfig();
|
|
4630
|
+
const apiUrl = flags.apiUrl ?? resolveApiUrl(config.apiUrl, deps.env);
|
|
4631
|
+
const ctx = { deps, json: flags.json, apiUrl, apiUrlFlag: flags.apiUrl };
|
|
4632
|
+
if (cmd === "auth") {
|
|
4633
|
+
if (sub === "login")
|
|
4634
|
+
return authLogin(cmdArgs, ctx);
|
|
4635
|
+
if (sub === "status")
|
|
4636
|
+
return authStatus(cmdArgs, ctx);
|
|
4637
|
+
if (sub === "logout")
|
|
4638
|
+
return authLogout(cmdArgs, ctx);
|
|
4639
|
+
return unknownCommand(deps, sub === undefined ? undefined : `auth ${sub}`);
|
|
4640
|
+
}
|
|
4641
|
+
if (cmd === "keys") {
|
|
4642
|
+
if (sub === "list")
|
|
4643
|
+
return keysList(cmdArgs, ctx);
|
|
4644
|
+
if (sub === "create")
|
|
4645
|
+
return keysCreate(cmdArgs, ctx);
|
|
4646
|
+
if (sub === "revoke")
|
|
4647
|
+
return keysRevoke(cmdArgs, ctx);
|
|
4648
|
+
return unknownCommand(deps, sub === undefined ? undefined : `keys ${sub}`);
|
|
4649
|
+
}
|
|
4650
|
+
if (cmd === "wallets") {
|
|
4651
|
+
if (sub === "import")
|
|
4652
|
+
return walletsImport(cmdArgs, ctx);
|
|
4653
|
+
if (sub === "revoke")
|
|
4654
|
+
return walletsRevoke(cmdArgs, ctx);
|
|
4655
|
+
return wallets(tokens.slice(1), ctx);
|
|
4656
|
+
}
|
|
4657
|
+
if (cmd === "doctor")
|
|
4658
|
+
return doctor(tokens.slice(1), ctx);
|
|
4659
|
+
if (cmd === "mcp")
|
|
4660
|
+
return mcp(tokens.slice(1), ctx);
|
|
4661
|
+
if (cmd === "setup")
|
|
4662
|
+
return setup(tokens.slice(1), ctx);
|
|
4663
|
+
return unknownCommand(deps, cmd);
|
|
4664
|
+
}
|
|
4665
|
+
function unknownCommand(deps, token) {
|
|
4666
|
+
if (token !== undefined)
|
|
4667
|
+
deps.stderr.write(`Unknown command: ${token}
|
|
4668
|
+
`);
|
|
4669
|
+
deps.stderr.write(HELP_TEXT);
|
|
4670
|
+
return 1;
|
|
4671
|
+
}
|
|
4672
|
+
function realOpenBrowser(url) {
|
|
4673
|
+
try {
|
|
4674
|
+
const platform = process.platform;
|
|
4675
|
+
const child = platform === "darwin" ? spawn2("open", [url], { stdio: "ignore", detached: true }) : platform === "win32" ? spawn2("cmd", ["/c", "start", "", url], { stdio: "ignore", detached: true }) : spawn2("xdg-open", [url], { stdio: "ignore", detached: true });
|
|
4676
|
+
child.on("error", () => {});
|
|
4677
|
+
child.unref();
|
|
4678
|
+
} catch {}
|
|
4679
|
+
}
|
|
4680
|
+
async function buildRealDeps() {
|
|
4681
|
+
const { store, backend } = await resolveSecretStore();
|
|
4682
|
+
return {
|
|
4683
|
+
fetch: globalThis.fetch,
|
|
4684
|
+
store,
|
|
4685
|
+
backend,
|
|
4686
|
+
readConfig,
|
|
4687
|
+
writeConfig,
|
|
4688
|
+
clearConfig,
|
|
4689
|
+
stdout: {
|
|
4690
|
+
write: (chunk) => {
|
|
4691
|
+
process.stdout.write(chunk);
|
|
4692
|
+
}
|
|
4693
|
+
},
|
|
4694
|
+
stderr: {
|
|
4695
|
+
write: (chunk) => {
|
|
4696
|
+
process.stderr.write(chunk);
|
|
4697
|
+
}
|
|
4698
|
+
},
|
|
4699
|
+
now: () => Date.now(),
|
|
4700
|
+
sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
|
|
4701
|
+
openBrowser: realOpenBrowser,
|
|
4702
|
+
env: process.env,
|
|
4703
|
+
nodeVersion: process.versions.node,
|
|
4704
|
+
hostname: hostname(),
|
|
4705
|
+
runChild: (command, args, env) => new Promise((resolve) => {
|
|
4706
|
+
const child = spawn2(command, args, {
|
|
4707
|
+
stdio: "inherit",
|
|
4708
|
+
env,
|
|
4709
|
+
shell: process.platform === "win32"
|
|
4710
|
+
});
|
|
4711
|
+
child.on("error", () => resolve(1));
|
|
4712
|
+
child.on("close", (code) => resolve(code ?? 1));
|
|
4713
|
+
}),
|
|
4714
|
+
readFile: (path) => readFile3(path, "utf8"),
|
|
4715
|
+
writeFile: (path, content) => writeFile3(path, content, { mode: 384 }),
|
|
4716
|
+
promptSecret: promptHiddenSecret
|
|
4717
|
+
};
|
|
4718
|
+
}
|
|
4719
|
+
async function main() {
|
|
4720
|
+
const deps = await buildRealDeps();
|
|
4721
|
+
const code = await run2(process.argv.slice(2), deps);
|
|
4722
|
+
process.exit(code);
|
|
4723
|
+
}
|
|
4724
|
+
function entryHref(argv1) {
|
|
4725
|
+
try {
|
|
4726
|
+
return pathToFileURL(realpathSync(argv1)).href;
|
|
4727
|
+
} catch {
|
|
4728
|
+
return pathToFileURL(argv1).href;
|
|
4729
|
+
}
|
|
4730
|
+
}
|
|
4731
|
+
var isMainModule = process.argv[1] !== undefined && import.meta.url === entryHref(process.argv[1]);
|
|
4732
|
+
if (isMainModule) {
|
|
4733
|
+
main().catch((err) => {
|
|
4734
|
+
process.stderr.write(`Unexpected error: ${err instanceof Error ? err.message : String(err)}
|
|
4735
|
+
`);
|
|
4736
|
+
process.exit(1);
|
|
4737
|
+
});
|
|
4738
|
+
}
|
|
4739
|
+
export {
|
|
4740
|
+
run2 as run
|
|
4741
|
+
};
|