openmeld 0.3.91 → 0.3.95
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/dist/{add-me-membership-D-NWZyMz.js → add-me-membership-DGXnp5Cm.js} +2 -2
- package/dist/{add-me-membership-D-NWZyMz.js.map → add-me-membership-DGXnp5Cm.js.map} +1 -1
- package/dist/{api-client-foundation-CfNo8-pE.js → api-client-foundation-OXokafyL.js} +2 -2
- package/dist/{api-client-foundation-CfNo8-pE.js.map → api-client-foundation-OXokafyL.js.map} +1 -1
- package/dist/{auth-session-73FalW41.js → auth-session-yymO5FGR.js} +424 -37
- package/dist/auth-session-yymO5FGR.js.map +1 -0
- package/dist/{command-ByA1L4nv.js → command-D5gVrWiz.js} +11 -25
- package/dist/{command-ByA1L4nv.js.map → command-D5gVrWiz.js.map} +1 -1
- package/dist/native/openmeld-keychain.node +0 -0
- package/dist/openmeld.js +5 -4
- package/dist/openmeld.js.map +1 -1
- package/package.json +3 -2
- package/dist/auth-session-73FalW41.js.map +0 -1
|
@@ -2,9 +2,66 @@
|
|
|
2
2
|
|
|
3
3
|
import { Nt as openMeldRootDir, _n as __exportAll } from "./base-url-Cv9x5Es9.js";
|
|
4
4
|
import { t as CURRENT_DAEMON_EXECUTION_CONTRACT_EPOCH } from "./runtime-transport-J50KvRbm.js";
|
|
5
|
+
import { createRequire } from "node:module";
|
|
6
|
+
import { z } from "zod/v4";
|
|
5
7
|
import { join, resolve } from "node:path";
|
|
6
8
|
import { createHash, randomUUID } from "node:crypto";
|
|
7
|
-
import { mkdir, open, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
9
|
+
import { chmod, mkdir, open, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
10
|
+
import { spawn } from "node:child_process";
|
|
11
|
+
import { fileURLToPath } from "node:url";
|
|
12
|
+
//#region ../../packages/schemas/dist/schemas/local-machine/macos-keychain-helper.js
|
|
13
|
+
const macOsKeychainServiceSchema = z.string().trim().min(1).max(512);
|
|
14
|
+
const macOsKeychainAccountSchema = z.string().trim().min(1).max(512);
|
|
15
|
+
const macOsKeychainAccessTokenSchema = z.string().min(1).max(65536);
|
|
16
|
+
const macOsKeychainHelperOperationSchema = z.enum([
|
|
17
|
+
"store",
|
|
18
|
+
"read",
|
|
19
|
+
"delete"
|
|
20
|
+
]);
|
|
21
|
+
const macOsKeychainHelperRequestSchema = z.discriminatedUnion("operation", [
|
|
22
|
+
z.strictObject({
|
|
23
|
+
schemaVersion: z.literal(1),
|
|
24
|
+
operation: z.literal("store"),
|
|
25
|
+
service: macOsKeychainServiceSchema,
|
|
26
|
+
account: macOsKeychainAccountSchema,
|
|
27
|
+
accessToken: macOsKeychainAccessTokenSchema
|
|
28
|
+
}),
|
|
29
|
+
z.strictObject({
|
|
30
|
+
schemaVersion: z.literal(1),
|
|
31
|
+
operation: z.literal("read"),
|
|
32
|
+
service: macOsKeychainServiceSchema,
|
|
33
|
+
account: macOsKeychainAccountSchema
|
|
34
|
+
}),
|
|
35
|
+
z.strictObject({
|
|
36
|
+
schemaVersion: z.literal(1),
|
|
37
|
+
operation: z.literal("delete"),
|
|
38
|
+
service: macOsKeychainServiceSchema,
|
|
39
|
+
account: macOsKeychainAccountSchema
|
|
40
|
+
})
|
|
41
|
+
]);
|
|
42
|
+
const macOsKeychainHelperMutationSuccessSchema = z.strictObject({
|
|
43
|
+
schemaVersion: z.literal(1),
|
|
44
|
+
ok: z.literal(true),
|
|
45
|
+
operation: z.enum(["store", "delete"])
|
|
46
|
+
});
|
|
47
|
+
const macOsKeychainHelperReadSuccessSchema = z.strictObject({
|
|
48
|
+
schemaVersion: z.literal(1),
|
|
49
|
+
ok: z.literal(true),
|
|
50
|
+
operation: z.literal("read"),
|
|
51
|
+
accessToken: z.union([macOsKeychainAccessTokenSchema, z.null()])
|
|
52
|
+
});
|
|
53
|
+
const macOsKeychainHelperErrorSchema = z.strictObject({
|
|
54
|
+
schemaVersion: z.literal(1),
|
|
55
|
+
ok: z.literal(false),
|
|
56
|
+
operation: macOsKeychainHelperOperationSchema,
|
|
57
|
+
errorMessage: z.string().trim().min(1).max(2048)
|
|
58
|
+
});
|
|
59
|
+
const macOsKeychainHelperResponseSchema = z.union([
|
|
60
|
+
macOsKeychainHelperMutationSuccessSchema,
|
|
61
|
+
macOsKeychainHelperReadSuccessSchema,
|
|
62
|
+
macOsKeychainHelperErrorSchema
|
|
63
|
+
]);
|
|
64
|
+
//#endregion
|
|
8
65
|
//#region src/strategy-constants.ts
|
|
9
66
|
const DEFAULT_GATEWAY_CHAIN_TIMEOUT_MS = 3e4;
|
|
10
67
|
const DEFAULT_REMOTE_SESSION_TIMEOUT_MS = 8e3;
|
|
@@ -31,6 +88,234 @@ const HEARTBEAT_RESPONSE_TIMEOUT_MS = 15e3;
|
|
|
31
88
|
const DAEMON_RUNTIME_CONTRACT_EPOCH = CURRENT_DAEMON_EXECUTION_CONTRACT_EPOCH;
|
|
32
89
|
const OPENCLAW_CLI_TIMEOUT_MS = 3e4;
|
|
33
90
|
//#endregion
|
|
91
|
+
//#region src/runtime/distribution.ts
|
|
92
|
+
const BINARY_DISTRIBUTION = "binary";
|
|
93
|
+
const NPM_DISTRIBUTION = "npm";
|
|
94
|
+
/**
|
|
95
|
+
* The distribution form this CLI build was compiled for. Falls back to `npm`
|
|
96
|
+
* when the marker is absent (e.g. under Vitest, where no build-time define
|
|
97
|
+
* runs), which keeps the safe, path-independent default.
|
|
98
|
+
*/
|
|
99
|
+
function resolveOpenMeldDistribution() {
|
|
100
|
+
return NPM_DISTRIBUTION;
|
|
101
|
+
}
|
|
102
|
+
function isBinaryDistribution() {
|
|
103
|
+
return resolveOpenMeldDistribution() === BINARY_DISTRIBUTION;
|
|
104
|
+
}
|
|
105
|
+
//#endregion
|
|
106
|
+
//#region src/config/macos-native-keychain.ts
|
|
107
|
+
const MAC_OS_KEYCHAIN_HELPER_ARG = "__openmeld_macos_keychain_helper";
|
|
108
|
+
const HELPER_OUTPUT_MAX_BYTES = 128 * 1024;
|
|
109
|
+
let loadedAddon = null;
|
|
110
|
+
let unresponsiveKeychainError = null;
|
|
111
|
+
async function storeMacOsNativeKeychainToken(input) {
|
|
112
|
+
if (isBinaryDistribution()) {
|
|
113
|
+
await runBoundedMacOsNativeKeychainRequest({
|
|
114
|
+
operation: "store",
|
|
115
|
+
service: input.service,
|
|
116
|
+
account: input.account,
|
|
117
|
+
accessToken: input.accessToken
|
|
118
|
+
});
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
(await loadAddon()).store(input.service, input.account, input.accessToken);
|
|
122
|
+
}
|
|
123
|
+
async function readMacOsNativeKeychainToken(input) {
|
|
124
|
+
if (isBinaryDistribution()) return await runBoundedMacOsNativeKeychainRequest({
|
|
125
|
+
operation: "read",
|
|
126
|
+
service: input.service,
|
|
127
|
+
account: input.account
|
|
128
|
+
});
|
|
129
|
+
return (await loadAddon()).read(input.service, input.account);
|
|
130
|
+
}
|
|
131
|
+
async function deleteMacOsNativeKeychainToken(input) {
|
|
132
|
+
if (isBinaryDistribution()) {
|
|
133
|
+
await runBoundedMacOsNativeKeychainRequest({
|
|
134
|
+
operation: "delete",
|
|
135
|
+
service: input.service,
|
|
136
|
+
account: input.account
|
|
137
|
+
});
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
(await loadAddon()).remove(input.service, input.account);
|
|
141
|
+
}
|
|
142
|
+
async function runMacOsNativeKeychainRequestInChild(input, options = {}) {
|
|
143
|
+
const request = macOsKeychainHelperRequestSchema.parse({
|
|
144
|
+
schemaVersion: 1,
|
|
145
|
+
...input
|
|
146
|
+
});
|
|
147
|
+
const timeoutMs = options.timeoutMs ?? 5e3;
|
|
148
|
+
if (!(Number.isSafeInteger(timeoutMs) && timeoutMs > 0)) throw new Error("macOS Keychain helper timeout must be a positive integer");
|
|
149
|
+
return await new Promise((resolve, reject) => {
|
|
150
|
+
const child = spawn(process.execPath, [MAC_OS_KEYCHAIN_HELPER_ARG], {
|
|
151
|
+
env: process.env,
|
|
152
|
+
shell: false,
|
|
153
|
+
stdio: [
|
|
154
|
+
"pipe",
|
|
155
|
+
"pipe",
|
|
156
|
+
"pipe"
|
|
157
|
+
],
|
|
158
|
+
windowsHide: true
|
|
159
|
+
});
|
|
160
|
+
let settled = false;
|
|
161
|
+
let stdout = "";
|
|
162
|
+
let stderr = "";
|
|
163
|
+
const clearDeadline = () => {
|
|
164
|
+
clearTimeout(deadline);
|
|
165
|
+
};
|
|
166
|
+
const rejectOnce = (error) => {
|
|
167
|
+
if (settled) return;
|
|
168
|
+
settled = true;
|
|
169
|
+
clearDeadline();
|
|
170
|
+
reject(error);
|
|
171
|
+
};
|
|
172
|
+
const deadline = setTimeout(() => {
|
|
173
|
+
if (settled) return;
|
|
174
|
+
settled = true;
|
|
175
|
+
child.kill("SIGKILL");
|
|
176
|
+
reject(new MacOsNativeKeychainTimeoutError(`macOS Keychain did not respond within ${formatTimeout(timeoutMs)}`));
|
|
177
|
+
}, timeoutMs);
|
|
178
|
+
child.stdout.setEncoding("utf8");
|
|
179
|
+
child.stderr.setEncoding("utf8");
|
|
180
|
+
child.stdout.on("data", (chunk) => {
|
|
181
|
+
stdout += String(chunk);
|
|
182
|
+
if (Buffer.byteLength(stdout, "utf8") > HELPER_OUTPUT_MAX_BYTES) {
|
|
183
|
+
child.kill("SIGKILL");
|
|
184
|
+
rejectOnce(/* @__PURE__ */ new Error("macOS Keychain helper output was too large"));
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
child.stderr.on("data", (chunk) => {
|
|
188
|
+
stderr += String(chunk);
|
|
189
|
+
if (Buffer.byteLength(stderr, "utf8") > HELPER_OUTPUT_MAX_BYTES) stderr = stderr.slice(-131072);
|
|
190
|
+
});
|
|
191
|
+
child.once("error", (error) => {
|
|
192
|
+
rejectOnce(/* @__PURE__ */ new Error(`macOS Keychain helper could not start: ${toErrorMessage$1(error)}`));
|
|
193
|
+
});
|
|
194
|
+
child.stdin.once("error", (error) => {
|
|
195
|
+
rejectOnce(/* @__PURE__ */ new Error(`macOS Keychain helper input failed: ${toErrorMessage$1(error)}`));
|
|
196
|
+
});
|
|
197
|
+
child.once("close", (code) => {
|
|
198
|
+
if (settled) return;
|
|
199
|
+
clearDeadline();
|
|
200
|
+
settled = true;
|
|
201
|
+
try {
|
|
202
|
+
resolve(parseMacOsKeychainHelperResult({
|
|
203
|
+
code,
|
|
204
|
+
operation: request.operation,
|
|
205
|
+
stderr,
|
|
206
|
+
stdout
|
|
207
|
+
}));
|
|
208
|
+
} catch (error) {
|
|
209
|
+
reject(toError(error));
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
child.stdin.end(JSON.stringify(request), "utf8");
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
async function runMacOsNativeKeychainHelperIfRequested(argv = process.argv) {
|
|
216
|
+
if (!argv.includes(MAC_OS_KEYCHAIN_HELPER_ARG)) return false;
|
|
217
|
+
if (!(isBinaryDistribution() && process.platform === "darwin")) throw new Error("the internal macOS Keychain helper is only available in the macOS binary");
|
|
218
|
+
const rawRequest = await readHelperStdin();
|
|
219
|
+
let json;
|
|
220
|
+
try {
|
|
221
|
+
json = JSON.parse(rawRequest);
|
|
222
|
+
} catch {
|
|
223
|
+
throw new Error("invalid macOS Keychain helper request");
|
|
224
|
+
}
|
|
225
|
+
const request = macOsKeychainHelperRequestSchema.safeParse(json);
|
|
226
|
+
if (!request.success) throw new Error("invalid macOS Keychain helper request");
|
|
227
|
+
const response = await executeHelperRequest(request.data).catch((error) => ({
|
|
228
|
+
schemaVersion: 1,
|
|
229
|
+
ok: false,
|
|
230
|
+
operation: request.data.operation,
|
|
231
|
+
errorMessage: truncateErrorMessage(toErrorMessage$1(error))
|
|
232
|
+
}));
|
|
233
|
+
process.stdout.write(JSON.stringify(response));
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
async function runBoundedMacOsNativeKeychainRequest(input) {
|
|
237
|
+
if (unresponsiveKeychainError) throw unresponsiveKeychainError;
|
|
238
|
+
try {
|
|
239
|
+
if (input.operation === "read") return await runMacOsNativeKeychainRequestInChild(input);
|
|
240
|
+
await runMacOsNativeKeychainRequestInChild(input);
|
|
241
|
+
} catch (error) {
|
|
242
|
+
if (error instanceof MacOsNativeKeychainTimeoutError) unresponsiveKeychainError = error;
|
|
243
|
+
throw error;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
function parseMacOsKeychainHelperResult(input) {
|
|
247
|
+
if (input.code !== 0) throw new Error(`macOS Keychain helper exited with code ${input.code ?? "unknown"}${input.stderr.trim() ? `: ${input.stderr.trim()}` : ""}`);
|
|
248
|
+
let rawResponse;
|
|
249
|
+
try {
|
|
250
|
+
rawResponse = JSON.parse(input.stdout);
|
|
251
|
+
} catch {
|
|
252
|
+
throw new Error("macOS Keychain helper returned an invalid response");
|
|
253
|
+
}
|
|
254
|
+
const parsed = macOsKeychainHelperResponseSchema.safeParse(rawResponse);
|
|
255
|
+
if (!(parsed.success && parsed.data.operation === input.operation)) throw new Error("macOS Keychain helper returned an invalid response");
|
|
256
|
+
if (!parsed.data.ok) throw new Error(parsed.data.errorMessage);
|
|
257
|
+
return parsed.data.operation === "read" ? parsed.data.accessToken : void 0;
|
|
258
|
+
}
|
|
259
|
+
async function executeHelperRequest(input) {
|
|
260
|
+
const addon = await loadAddon();
|
|
261
|
+
if (input.operation === "store") {
|
|
262
|
+
addon.store(input.service, input.account, input.accessToken);
|
|
263
|
+
return {
|
|
264
|
+
schemaVersion: 1,
|
|
265
|
+
ok: true,
|
|
266
|
+
operation: "store"
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
if (input.operation === "delete") {
|
|
270
|
+
addon.remove(input.service, input.account);
|
|
271
|
+
return {
|
|
272
|
+
schemaVersion: 1,
|
|
273
|
+
ok: true,
|
|
274
|
+
operation: "delete"
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
return {
|
|
278
|
+
schemaVersion: 1,
|
|
279
|
+
ok: true,
|
|
280
|
+
operation: "read",
|
|
281
|
+
accessToken: addon.read(input.service, input.account)
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
async function readHelperStdin() {
|
|
285
|
+
let raw = "";
|
|
286
|
+
process.stdin.setEncoding("utf8");
|
|
287
|
+
for await (const chunk of process.stdin) {
|
|
288
|
+
raw += String(chunk);
|
|
289
|
+
if (Buffer.byteLength(raw, "utf8") > HELPER_OUTPUT_MAX_BYTES) throw new Error("macOS Keychain helper request was too large");
|
|
290
|
+
}
|
|
291
|
+
return raw;
|
|
292
|
+
}
|
|
293
|
+
function truncateErrorMessage(message) {
|
|
294
|
+
return (message.trim() || "macOS Keychain operation failed").slice(0, 2048);
|
|
295
|
+
}
|
|
296
|
+
function formatTimeout(timeoutMs) {
|
|
297
|
+
return timeoutMs % 1e3 === 0 ? `${timeoutMs / 1e3} seconds` : `${timeoutMs} ms`;
|
|
298
|
+
}
|
|
299
|
+
function toErrorMessage$1(error) {
|
|
300
|
+
return error instanceof Error ? error.message : String(error);
|
|
301
|
+
}
|
|
302
|
+
function toError(error) {
|
|
303
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
304
|
+
}
|
|
305
|
+
var MacOsNativeKeychainTimeoutError = class extends Error {
|
|
306
|
+
name = "MacOsNativeKeychainTimeoutError";
|
|
307
|
+
};
|
|
308
|
+
async function loadAddon() {
|
|
309
|
+
if (loadedAddon) return loadedAddon;
|
|
310
|
+
if (process.platform !== "darwin") throw new Error("macOS Keychain is only available on macOS");
|
|
311
|
+
if (isBinaryDistribution()) {
|
|
312
|
+
loadedAddon = (await import("./config/macos-native-keychain-embedded")).loadEmbeddedMacOsKeychainAddon();
|
|
313
|
+
return loadedAddon;
|
|
314
|
+
}
|
|
315
|
+
loadedAddon = createRequire(import.meta.url)(fileURLToPath(new URL("./native/openmeld-keychain.node", import.meta.url)));
|
|
316
|
+
return loadedAddon;
|
|
317
|
+
}
|
|
318
|
+
//#endregion
|
|
34
319
|
//#region src/config/token-store.ts
|
|
35
320
|
const TOKEN_STORE_KEYCHAIN_SERVICE = "sh.openmeld.auth.token";
|
|
36
321
|
const INSECURE_FALLBACK_ENV_KEY = "OPENMELD_AUTH_ALLOW_INSECURE_FILE_TOKEN";
|
|
@@ -44,6 +329,7 @@ const EXEC_FILE_BASE_OPTIONS = {
|
|
|
44
329
|
timeout: COMMAND_TIMEOUT_MS
|
|
45
330
|
};
|
|
46
331
|
let insecureFallbackWarningShown = false;
|
|
332
|
+
let macOsPrivateStorageWarningShown = false;
|
|
47
333
|
async function storeAccessToken(input) {
|
|
48
334
|
const key = buildTokenKey({
|
|
49
335
|
authBaseUrl: input.authBaseUrl,
|
|
@@ -60,8 +346,13 @@ async function storeAccessToken(input) {
|
|
|
60
346
|
};
|
|
61
347
|
}
|
|
62
348
|
if (process.platform === "darwin") try {
|
|
63
|
-
const account =
|
|
64
|
-
await
|
|
349
|
+
const account = buildUniqueMacOsAccount(key);
|
|
350
|
+
if (shouldUseNativeMacOsKeychain()) await storeMacOsNativeKeychainToken({
|
|
351
|
+
account,
|
|
352
|
+
service: TOKEN_STORE_KEYCHAIN_SERVICE,
|
|
353
|
+
accessToken: input.accessToken
|
|
354
|
+
});
|
|
355
|
+
else await setMacOsKeychainToken({
|
|
65
356
|
service: TOKEN_STORE_KEYCHAIN_SERVICE,
|
|
66
357
|
account,
|
|
67
358
|
accessToken: input.accessToken
|
|
@@ -82,7 +373,16 @@ async function storeAccessToken(input) {
|
|
|
82
373
|
key
|
|
83
374
|
};
|
|
84
375
|
}
|
|
85
|
-
|
|
376
|
+
const privateKey = buildUniqueTokenFileKey(key);
|
|
377
|
+
await setInsecureFileToken({
|
|
378
|
+
key: privateKey,
|
|
379
|
+
accessToken: input.accessToken
|
|
380
|
+
});
|
|
381
|
+
warnMacOsPrivateStorageFallback(error);
|
|
382
|
+
return {
|
|
383
|
+
provider: "insecure-file",
|
|
384
|
+
key: privateKey
|
|
385
|
+
};
|
|
86
386
|
}
|
|
87
387
|
if (process.platform === "win32") try {
|
|
88
388
|
await setWindowsDpapiToken({
|
|
@@ -120,7 +420,7 @@ async function storeAccessToken(input) {
|
|
|
120
420
|
}
|
|
121
421
|
async function readAccessToken(ref) {
|
|
122
422
|
try {
|
|
123
|
-
if (ref.provider === "macos-keychain") return toAccessTokenReadResult(await getMacOsKeychainToken(ref));
|
|
423
|
+
if (ref.provider === "macos-keychain") return toAccessTokenReadResult(shouldUseNativeMacOsKeychain() ? await readMacOsNativeKeychainToken(ref) : await getMacOsKeychainToken(ref));
|
|
124
424
|
if (ref.provider === "windows-dpapi") return toAccessTokenReadResult(await getWindowsDpapiToken(ref));
|
|
125
425
|
if (ref.provider === "insecure-file") return toAccessTokenReadResult(await getInsecureFileToken(ref));
|
|
126
426
|
return { status: "missing" };
|
|
@@ -133,7 +433,7 @@ async function readAccessToken(ref) {
|
|
|
133
433
|
}
|
|
134
434
|
async function deleteAccessToken(ref) {
|
|
135
435
|
if (ref.provider === "macos-keychain") {
|
|
136
|
-
await deleteMacOsKeychainToken(ref).catch(() => void 0);
|
|
436
|
+
await (shouldUseNativeMacOsKeychain() ? deleteMacOsNativeKeychainToken(ref) : deleteMacOsKeychainToken(ref)).catch(() => void 0);
|
|
137
437
|
return;
|
|
138
438
|
}
|
|
139
439
|
if (ref.provider === "windows-dpapi") {
|
|
@@ -146,7 +446,7 @@ function isStoredTokenRef(value) {
|
|
|
146
446
|
if (!(value && typeof value === "object")) return false;
|
|
147
447
|
const record = value;
|
|
148
448
|
const provider = normalizeString(record.provider);
|
|
149
|
-
if (provider === "macos-keychain") return Boolean(normalizeString(record.service) && normalizeString(record.account));
|
|
449
|
+
if (provider === "macos-keychain") return Boolean(normalizeString(record.service) && normalizeString(record.account) && record.accessGroup === void 0);
|
|
150
450
|
if (provider === "windows-dpapi" || provider === "insecure-file") return normalizeTokenFileKey(record.key) !== null;
|
|
151
451
|
return false;
|
|
152
452
|
}
|
|
@@ -154,8 +454,14 @@ function buildTokenKey(input) {
|
|
|
154
454
|
const rootDir = resolve(openMeldRootDir());
|
|
155
455
|
return createHash("sha256").update(`${input.clientId}\n${input.authBaseUrl}\n${rootDir}`).digest("hex");
|
|
156
456
|
}
|
|
157
|
-
function
|
|
158
|
-
return `openmeld-auth-${key}`;
|
|
457
|
+
function buildUniqueMacOsAccount(key) {
|
|
458
|
+
return `openmeld-auth-${key}-${randomUUID()}`;
|
|
459
|
+
}
|
|
460
|
+
function buildUniqueTokenFileKey(key) {
|
|
461
|
+
return createHash("sha256").update(`${key}\n${randomUUID()}`).digest("hex");
|
|
462
|
+
}
|
|
463
|
+
function shouldUseNativeMacOsKeychain() {
|
|
464
|
+
return isBinaryDistribution();
|
|
159
465
|
}
|
|
160
466
|
async function setMacOsKeychainToken(input) {
|
|
161
467
|
await runCommand("security", [
|
|
@@ -218,11 +524,13 @@ async function deleteWindowsDpapiToken(input) {
|
|
|
218
524
|
await rm(windowsDpapiTokenPath(input.key), { force: true });
|
|
219
525
|
}
|
|
220
526
|
async function setInsecureFileToken(input) {
|
|
221
|
-
await
|
|
222
|
-
|
|
527
|
+
await ensurePrivateTokenDirectory();
|
|
528
|
+
const path = insecureTokenPath(input.key);
|
|
529
|
+
await writeFile(path, `${input.accessToken}\n`, {
|
|
223
530
|
encoding: "utf8",
|
|
224
531
|
mode: 384
|
|
225
532
|
});
|
|
533
|
+
if (process.platform !== "win32") await chmod(path, 384);
|
|
226
534
|
}
|
|
227
535
|
async function getInsecureFileToken(input) {
|
|
228
536
|
const raw = await readFile(insecureTokenPath(input.key), "utf8").catch((error) => {
|
|
@@ -252,6 +560,11 @@ function allowInsecureFallback() {
|
|
|
252
560
|
if (fallbackEnabled) warnInsecureFallback("platform");
|
|
253
561
|
return fallbackEnabled;
|
|
254
562
|
}
|
|
563
|
+
function warnMacOsPrivateStorageFallback(error) {
|
|
564
|
+
if (macOsPrivateStorageWarningShown) return;
|
|
565
|
+
macOsPrivateStorageWarningShown = true;
|
|
566
|
+
console.warn(`[openmeld auth] macOS Keychain is unavailable. OpenMeld saved this session in a private file protected for your macOS user account, so setup can continue. A future successful setup or login will move the session back to Keychain. Details: ${toErrorMessage(error)}`);
|
|
567
|
+
}
|
|
255
568
|
function warnInsecureFallback(reason) {
|
|
256
569
|
if (insecureFallbackWarningShown) return;
|
|
257
570
|
insecureFallbackWarningShown = true;
|
|
@@ -264,6 +577,14 @@ function shouldForceInsecureStore() {
|
|
|
264
577
|
function isNativeSecureStorePlatform() {
|
|
265
578
|
return process.platform === "darwin" || process.platform === "win32";
|
|
266
579
|
}
|
|
580
|
+
async function ensurePrivateTokenDirectory() {
|
|
581
|
+
const directory = tokenDirectoryPath();
|
|
582
|
+
await mkdir(directory, {
|
|
583
|
+
recursive: true,
|
|
584
|
+
mode: 448
|
|
585
|
+
});
|
|
586
|
+
if (process.platform !== "win32") await chmod(directory, 448);
|
|
587
|
+
}
|
|
267
588
|
async function runPowerShellScript(script, token, entropy) {
|
|
268
589
|
const payload = JSON.stringify({
|
|
269
590
|
token,
|
|
@@ -415,6 +736,7 @@ var auth_session_exports = /* @__PURE__ */ __exportAll({
|
|
|
415
736
|
updateAuthSessionActiveOrganization: () => updateAuthSessionActiveOrganization
|
|
416
737
|
});
|
|
417
738
|
const TRAILING_SLASHES_RE = /\/+$/u;
|
|
739
|
+
let cachedAuthSession = null;
|
|
418
740
|
async function getAuthSessionState(options = {}) {
|
|
419
741
|
const localState = await getLocalAuthSessionState();
|
|
420
742
|
switch (localState.state) {
|
|
@@ -445,6 +767,7 @@ async function setAuthSession(input) {
|
|
|
445
767
|
if (!authBaseUrl) throw new Error("auth base URL is required");
|
|
446
768
|
const clientId = String(input.clientId ?? "").trim();
|
|
447
769
|
if (!clientId) throw new Error("client_id is required");
|
|
770
|
+
const previousTokenRef = normalizeTokenRef((await readSessionPayload())?.tokenRef);
|
|
448
771
|
const tokenRef = await storeAccessToken({
|
|
449
772
|
accessToken,
|
|
450
773
|
authBaseUrl,
|
|
@@ -465,11 +788,23 @@ async function setAuthSession(input) {
|
|
|
465
788
|
const path = authSessionPath();
|
|
466
789
|
await mkdir(join(openMeldRootDir(), "auth"), { recursive: true });
|
|
467
790
|
try {
|
|
791
|
+
await assertStoredAccessTokenReloads({
|
|
792
|
+
accessToken,
|
|
793
|
+
tokenRef
|
|
794
|
+
});
|
|
468
795
|
await writeSessionPayloadAtomically(path, payload);
|
|
469
796
|
} catch (error) {
|
|
470
797
|
await deleteAccessToken(tokenRef).catch(() => void 0);
|
|
471
798
|
throw error;
|
|
472
799
|
}
|
|
800
|
+
cacheAuthSession({
|
|
801
|
+
payload,
|
|
802
|
+
session: buildStoredAuthSession({
|
|
803
|
+
accessToken,
|
|
804
|
+
payload
|
|
805
|
+
})
|
|
806
|
+
});
|
|
807
|
+
if (previousTokenRef && !areStoredTokenRefsEqual(previousTokenRef, tokenRef)) await deleteAccessToken(previousTokenRef).catch(() => void 0);
|
|
473
808
|
}
|
|
474
809
|
async function getAuthSession() {
|
|
475
810
|
const localState = await getLocalAuthSessionState();
|
|
@@ -515,8 +850,17 @@ async function updateAuthSessionActiveOrganization(activeOrganization) {
|
|
|
515
850
|
...buildActiveOrganizationPayload(activeOrganization)
|
|
516
851
|
};
|
|
517
852
|
await writeSessionPayloadAtomically(authSessionPath(), nextPayload);
|
|
853
|
+
const currentCachedSession = readCachedAuthSession(payload);
|
|
854
|
+
if (currentCachedSession) cacheAuthSession({
|
|
855
|
+
payload: nextPayload,
|
|
856
|
+
session: buildStoredAuthSession({
|
|
857
|
+
accessToken: currentCachedSession.accessToken,
|
|
858
|
+
payload: nextPayload
|
|
859
|
+
})
|
|
860
|
+
});
|
|
518
861
|
}
|
|
519
862
|
async function clearAuthSession() {
|
|
863
|
+
cachedAuthSession = null;
|
|
520
864
|
const payload = await readSessionPayload();
|
|
521
865
|
if (payload?.v === 1 && isStoredTokenRef(payload.tokenRef)) await deleteAccessToken(payload.tokenRef).catch(() => void 0);
|
|
522
866
|
await removeSessionFileBestEffort();
|
|
@@ -543,30 +887,37 @@ async function getLocalAuthSessionState() {
|
|
|
543
887
|
state: "invalid",
|
|
544
888
|
session: null
|
|
545
889
|
};
|
|
546
|
-
|
|
547
|
-
if (
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
890
|
+
let session = readCachedAuthSession(payload);
|
|
891
|
+
if (!session) {
|
|
892
|
+
const accessToken = await readAccessToken(tokenRef);
|
|
893
|
+
if (accessToken.status === "missing") return {
|
|
894
|
+
reasonCode: "session_token_missing",
|
|
895
|
+
state: "invalid",
|
|
896
|
+
session: null
|
|
897
|
+
};
|
|
898
|
+
if (accessToken.status === "unavailable") return {
|
|
899
|
+
errorMessage: accessToken.errorMessage,
|
|
900
|
+
reasonCode: "session_token_unavailable",
|
|
901
|
+
state: "invalid",
|
|
902
|
+
session: null
|
|
903
|
+
};
|
|
904
|
+
session = buildStoredAuthSession({
|
|
905
|
+
accessToken: accessToken.accessToken,
|
|
906
|
+
payload: {
|
|
907
|
+
...payload,
|
|
908
|
+
v: 1,
|
|
909
|
+
tokenRef,
|
|
910
|
+
tokenType,
|
|
911
|
+
authBaseUrl,
|
|
912
|
+
clientId,
|
|
913
|
+
createdAt
|
|
914
|
+
}
|
|
915
|
+
});
|
|
916
|
+
cacheAuthSession({
|
|
917
|
+
payload,
|
|
918
|
+
session
|
|
919
|
+
});
|
|
920
|
+
}
|
|
570
921
|
if (isExpired(session.expiresAt)) return {
|
|
571
922
|
reasonCode: "session_expired",
|
|
572
923
|
state: "expired",
|
|
@@ -577,6 +928,42 @@ async function getLocalAuthSessionState() {
|
|
|
577
928
|
session
|
|
578
929
|
};
|
|
579
930
|
}
|
|
931
|
+
async function assertStoredAccessTokenReloads(input) {
|
|
932
|
+
const reloaded = await readAccessToken(input.tokenRef);
|
|
933
|
+
if (reloaded.status === "found" && reloaded.accessToken === input.accessToken) return;
|
|
934
|
+
if (reloaded.status === "unavailable") throw new Error(`stored access token could not be reloaded: ${reloaded.errorMessage}`);
|
|
935
|
+
throw new Error("stored access token could not be reloaded");
|
|
936
|
+
}
|
|
937
|
+
function buildStoredAuthSession(input) {
|
|
938
|
+
return {
|
|
939
|
+
v: 1,
|
|
940
|
+
accessToken: input.accessToken,
|
|
941
|
+
tokenType: input.payload.tokenType,
|
|
942
|
+
authBaseUrl: input.payload.authBaseUrl,
|
|
943
|
+
clientId: input.payload.clientId,
|
|
944
|
+
createdAt: input.payload.createdAt,
|
|
945
|
+
...typeof input.payload.expiresAt === "string" && input.payload.expiresAt.trim() ? { expiresAt: input.payload.expiresAt.trim() } : {},
|
|
946
|
+
...typeof input.payload.scope === "string" && input.payload.scope.trim() ? { scope: input.payload.scope.trim() } : {},
|
|
947
|
+
...buildAuthUserPayload(input.payload.user),
|
|
948
|
+
...buildActiveOrganizationPayload(input.payload.activeOrganization)
|
|
949
|
+
};
|
|
950
|
+
}
|
|
951
|
+
function cacheAuthSession(input) {
|
|
952
|
+
cachedAuthSession = {
|
|
953
|
+
payloadKey: buildAuthSessionPayloadKey(input.payload),
|
|
954
|
+
session: input.session
|
|
955
|
+
};
|
|
956
|
+
}
|
|
957
|
+
function readCachedAuthSession(payload) {
|
|
958
|
+
const payloadKey = buildAuthSessionPayloadKey(payload);
|
|
959
|
+
return cachedAuthSession?.payloadKey === payloadKey ? cachedAuthSession.session : null;
|
|
960
|
+
}
|
|
961
|
+
function buildAuthSessionPayloadKey(payload) {
|
|
962
|
+
return `${authSessionPath()}\n${JSON.stringify(payload)}`;
|
|
963
|
+
}
|
|
964
|
+
function areStoredTokenRefsEqual(left, right) {
|
|
965
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
966
|
+
}
|
|
580
967
|
function normalizeTokenRef(input) {
|
|
581
968
|
if (!isStoredTokenRef(input)) return null;
|
|
582
969
|
return input;
|
|
@@ -741,6 +1128,6 @@ async function removeSessionFileBestEffort() {
|
|
|
741
1128
|
await rm(authSessionPath(), { force: true }).catch(() => void 0);
|
|
742
1129
|
}
|
|
743
1130
|
//#endregion
|
|
744
|
-
export {
|
|
1131
|
+
export { REGISTER_RESPONSE_TIMEOUT_MS as A, MAX_HEARTBEAT_INTERVAL_MS as C, OPENCLAW_CLI_TIMEOUT_MS as D, MIN_SPACE_REQUEST_TIMEOUT_MS as E, RUNTIME_AGENT_CONTROLLER_REPORT_SYNC_INTERVAL_MS as M, RUNTIME_AGENT_CONTROLLER_REPORT_SYNC_RETRY_INTERVAL_MS as N, PROVIDER_CONVERSATION_PROOF_SYNC_INTERVAL_MS as O, RUNTIME_STATE_PERSIST_MIN_INTERVAL_MS as P, HEARTBEAT_RESPONSE_TIMEOUT_MS as S, MIN_HEARTBEAT_INTERVAL_MS as T, DAEMON_STREAM_KEEPALIVE_INTERVAL_MS as _, getAuthSessionState as a, DEFAULT_HEARTBEAT_INTERVAL_MS as b, setAuthSession as c, isBinaryDistribution as d, resolveOpenMeldDistribution as f, DAEMON_STREAM_CONNECT_TIMEOUT_MS as g, DAEMON_RUNTIME_CONTRACT_EPOCH as h, getAuthSessionMetadata as i, ROUTE_CATALOG_LOAD_TIMEOUT_MS as j, PROVIDER_CONVERSATION_PROOF_SYNC_RETRY_INTERVAL_MS as k, updateAuthSessionActiveOrganization as l, CATALOG_SYNC_SIGNAL_POLL_INTERVAL_MS as m, clearAuthSession as n, getCurrentAuthOwnerUserId as o, CATALOG_SYNC_RETRY_INTERVAL_MS as p, getAuthSession as r, normalizeStoredActiveOrganization as s, auth_session_exports as t, runMacOsNativeKeychainHelperIfRequested as u, DAEMON_STREAM_KEEPALIVE_PONG_TIMEOUT_MS as v, MAX_SPACE_REQUEST_TIMEOUT_MS as w, DEFAULT_SPACE_REQUEST_TIMEOUT_MS as x, DEFAULT_GATEWAY_CHAIN_TIMEOUT_MS as y };
|
|
745
1132
|
|
|
746
|
-
//# sourceMappingURL=auth-session-
|
|
1133
|
+
//# sourceMappingURL=auth-session-yymO5FGR.js.map
|