@agenticmail/enterprise 0.5.78 → 0.5.80
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/chunk-7MILGDAA.js +2191 -0
- package/dist/chunk-7RNT4O5T.js +15198 -0
- package/dist/chunk-AGFOJCSB.js +2191 -0
- package/dist/chunk-F4GSFCM3.js +898 -0
- package/dist/chunk-GWUIYH7I.js +15035 -0
- package/dist/chunk-PZA7YOJE.js +898 -0
- package/dist/chunk-Q3V7VZFQ.js +2191 -0
- package/dist/chunk-RRFB6G6M.js +15198 -0
- package/dist/chunk-VX3VFMVB.js +409 -0
- package/dist/chunk-WRPZCOWC.js +898 -0
- package/dist/cli.js +1 -1
- package/dist/dashboard/pages/agent-detail.js +313 -1
- package/dist/index.js +3 -3
- package/dist/pw-ai-KPETTB25.js +2212 -0
- package/dist/routes-PDHMCIXU.js +6676 -0
- package/dist/runtime-7HW4GX5L.js +48 -0
- package/dist/runtime-GYVO3NF3.js +47 -0
- package/dist/runtime-XXDCZZIK.js +48 -0
- package/dist/server-FMP4BFGW.js +12 -0
- package/dist/server-JRHDUNII.js +12 -0
- package/dist/server-VNW6G4GB.js +12 -0
- package/dist/setup-AANLREEL.js +20 -0
- package/dist/setup-O5FPRLK4.js +20 -0
- package/dist/setup-S4Z4PPIJ.js +20 -0
- package/package.json +15 -2
- package/src/agent-tools/common.ts +25 -0
- package/src/agent-tools/index.ts +4 -0
- package/src/agent-tools/schema/typebox.ts +25 -0
- package/src/agent-tools/tools/browser-tool.schema.ts +112 -0
- package/src/agent-tools/tools/browser-tool.ts +388 -0
- package/src/agent-tools/tools/gateway.ts +126 -0
- package/src/agent-tools/tools/nodes-utils.ts +80 -0
- package/src/browser/bridge-auth-registry.ts +34 -0
- package/src/browser/bridge-server.ts +93 -0
- package/src/browser/cdp.helpers.ts +180 -0
- package/src/browser/cdp.ts +466 -0
- package/src/browser/chrome.executables.ts +625 -0
- package/src/browser/chrome.profile-decoration.ts +198 -0
- package/src/browser/chrome.ts +349 -0
- package/src/browser/client-actions-core.ts +259 -0
- package/src/browser/client-actions-observe.ts +184 -0
- package/src/browser/client-actions-state.ts +284 -0
- package/src/browser/client-actions-types.ts +16 -0
- package/src/browser/client-actions-url.ts +11 -0
- package/src/browser/client-actions.ts +4 -0
- package/src/browser/client-fetch.ts +253 -0
- package/src/browser/client.ts +337 -0
- package/src/browser/config.ts +296 -0
- package/src/browser/constants.ts +8 -0
- package/src/browser/control-auth.ts +94 -0
- package/src/browser/control-service.ts +81 -0
- package/src/browser/csrf.ts +87 -0
- package/src/browser/enterprise-compat.ts +518 -0
- package/src/browser/extension-relay.ts +834 -0
- package/src/browser/http-auth.ts +63 -0
- package/src/browser/navigation-guard.ts +50 -0
- package/src/browser/paths.ts +49 -0
- package/src/browser/profiles-service.ts +187 -0
- package/src/browser/profiles.ts +113 -0
- package/src/browser/proxy-files.ts +41 -0
- package/src/browser/pw-ai-module.ts +52 -0
- package/src/browser/pw-ai-state.ts +9 -0
- package/src/browser/pw-ai.ts +65 -0
- package/src/browser/pw-role-snapshot.ts +434 -0
- package/src/browser/pw-session.ts +810 -0
- package/src/browser/pw-tools-core.activity.ts +68 -0
- package/src/browser/pw-tools-core.downloads.ts +281 -0
- package/src/browser/pw-tools-core.interactions.ts +646 -0
- package/src/browser/pw-tools-core.responses.ts +124 -0
- package/src/browser/pw-tools-core.shared.ts +70 -0
- package/src/browser/pw-tools-core.snapshot.ts +213 -0
- package/src/browser/pw-tools-core.state.ts +209 -0
- package/src/browser/pw-tools-core.storage.ts +128 -0
- package/src/browser/pw-tools-core.trace.ts +37 -0
- package/src/browser/pw-tools-core.ts +8 -0
- package/src/browser/resolved-config-refresh.ts +59 -0
- package/src/browser/routes/agent.act.shared.ts +52 -0
- package/src/browser/routes/agent.act.ts +575 -0
- package/src/browser/routes/agent.debug.ts +149 -0
- package/src/browser/routes/agent.shared.ts +143 -0
- package/src/browser/routes/agent.snapshot.ts +333 -0
- package/src/browser/routes/agent.storage.ts +451 -0
- package/src/browser/routes/agent.ts +13 -0
- package/src/browser/routes/basic.ts +202 -0
- package/src/browser/routes/dispatcher.ts +126 -0
- package/src/browser/routes/index.ts +11 -0
- package/src/browser/routes/path-output.ts +1 -0
- package/src/browser/routes/tabs.ts +217 -0
- package/src/browser/routes/types.ts +26 -0
- package/src/browser/routes/utils.ts +73 -0
- package/src/browser/screenshot.ts +54 -0
- package/src/browser/server-context.ts +688 -0
- package/src/browser/server-context.types.ts +65 -0
- package/src/browser/server-lifecycle.ts +48 -0
- package/src/browser/server-middleware.ts +37 -0
- package/src/browser/server.ts +110 -0
- package/src/browser/target-id.ts +30 -0
- package/src/browser/trash.ts +21 -0
- package/src/dashboard/pages/agent-detail.js +313 -1
- package/src/engine/agent-routes.ts +46 -0
- package/src/security/external-content.ts +299 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { ensureGatewayStartupAuth, loadConfig, resolveGatewayAuth } from "./enterprise-compat.js";
|
|
2
|
+
import type { OpenClawConfig } from "./enterprise-compat.js";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export type BrowserControlAuth = {
|
|
6
|
+
token?: string;
|
|
7
|
+
password?: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export function resolveBrowserControlAuth(
|
|
11
|
+
cfg: OpenClawConfig | undefined,
|
|
12
|
+
env: NodeJS.ProcessEnv = process.env,
|
|
13
|
+
): BrowserControlAuth {
|
|
14
|
+
const auth = resolveGatewayAuth({
|
|
15
|
+
authConfig: cfg?.gateway?.auth,
|
|
16
|
+
env,
|
|
17
|
+
tailscaleMode: cfg?.gateway?.tailscale?.mode,
|
|
18
|
+
});
|
|
19
|
+
const token = typeof auth.token === "string" ? auth.token.trim() : "";
|
|
20
|
+
const password = typeof auth.password === "string" ? auth.password.trim() : "";
|
|
21
|
+
return {
|
|
22
|
+
token: token || undefined,
|
|
23
|
+
password: password || undefined,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function shouldAutoGenerateBrowserAuth(env: NodeJS.ProcessEnv): boolean {
|
|
28
|
+
const nodeEnv = (env.NODE_ENV ?? "").trim().toLowerCase();
|
|
29
|
+
if (nodeEnv === "test") {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
const vitest = (env.VITEST ?? "").trim().toLowerCase();
|
|
33
|
+
if (vitest && vitest !== "0" && vitest !== "false" && vitest !== "off") {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function ensureBrowserControlAuth(params: {
|
|
40
|
+
cfg: OpenClawConfig;
|
|
41
|
+
env?: NodeJS.ProcessEnv;
|
|
42
|
+
}): Promise<{
|
|
43
|
+
auth: BrowserControlAuth;
|
|
44
|
+
generatedToken?: string;
|
|
45
|
+
}> {
|
|
46
|
+
const env = params.env ?? process.env;
|
|
47
|
+
const auth = resolveBrowserControlAuth(params.cfg, env);
|
|
48
|
+
if (auth.token || auth.password) {
|
|
49
|
+
return { auth };
|
|
50
|
+
}
|
|
51
|
+
if (!shouldAutoGenerateBrowserAuth(env)) {
|
|
52
|
+
return { auth };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Respect explicit password mode even if currently unset.
|
|
56
|
+
if (params.cfg.gateway?.auth?.mode === "password") {
|
|
57
|
+
return { auth };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (params.cfg.gateway?.auth?.mode === "none") {
|
|
61
|
+
return { auth };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (params.cfg.gateway?.auth?.mode === "trusted-proxy") {
|
|
65
|
+
return { auth };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Re-read latest config to avoid racing with concurrent config writers.
|
|
69
|
+
const latestCfg = loadConfig();
|
|
70
|
+
const latestAuth = resolveBrowserControlAuth(latestCfg, env);
|
|
71
|
+
if (latestAuth.token || latestAuth.password) {
|
|
72
|
+
return { auth: latestAuth };
|
|
73
|
+
}
|
|
74
|
+
if (latestCfg.gateway?.auth?.mode === "password") {
|
|
75
|
+
return { auth: latestAuth };
|
|
76
|
+
}
|
|
77
|
+
if (latestCfg.gateway?.auth?.mode === "none") {
|
|
78
|
+
return { auth: latestAuth };
|
|
79
|
+
}
|
|
80
|
+
if (latestCfg.gateway?.auth?.mode === "trusted-proxy") {
|
|
81
|
+
return { auth: latestAuth };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const ensured = await ensureGatewayStartupAuth({
|
|
85
|
+
cfg: latestCfg,
|
|
86
|
+
env,
|
|
87
|
+
persist: true,
|
|
88
|
+
});
|
|
89
|
+
const ensuredAuth = resolveBrowserControlAuth(ensured.cfg, env);
|
|
90
|
+
return {
|
|
91
|
+
auth: ensuredAuth,
|
|
92
|
+
generatedToken: ensured.generatedToken,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
import { resolveBrowserConfig } from "./config.js";
|
|
4
|
+
import { ensureBrowserControlAuth } from "./control-auth.js";
|
|
5
|
+
import { type BrowserServerState, createBrowserRouteContext } from "./server-context.js";
|
|
6
|
+
import { ensureExtensionRelayForProfiles, stopKnownBrowserProfiles } from "./server-lifecycle.js";
|
|
7
|
+
import { createSubsystemLogger, loadConfig } from "./enterprise-compat.js";
|
|
8
|
+
|
|
9
|
+
let state: BrowserServerState | null = null;
|
|
10
|
+
const log = createSubsystemLogger("browser");
|
|
11
|
+
const logService = log.child("service");
|
|
12
|
+
|
|
13
|
+
export function getBrowserControlState(): BrowserServerState | null {
|
|
14
|
+
return state;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function createBrowserControlContext() {
|
|
18
|
+
return createBrowserRouteContext({
|
|
19
|
+
getState: () => state,
|
|
20
|
+
refreshConfigFromDisk: true,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function startBrowserControlServiceFromConfig(): Promise<BrowserServerState | null> {
|
|
25
|
+
if (state) {
|
|
26
|
+
return state;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const cfg = loadConfig();
|
|
30
|
+
const resolved = resolveBrowserConfig(cfg.browser, cfg);
|
|
31
|
+
if (!resolved.enabled) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const ensured = await ensureBrowserControlAuth({ cfg });
|
|
36
|
+
if (ensured.generatedToken) {
|
|
37
|
+
logService.info("No browser auth configured; generated gateway.auth.token automatically.");
|
|
38
|
+
}
|
|
39
|
+
} catch (err) {
|
|
40
|
+
logService.warn(`failed to auto-configure browser auth: ${String(err)}`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
state = {
|
|
44
|
+
server: null,
|
|
45
|
+
port: resolved.controlPort,
|
|
46
|
+
resolved,
|
|
47
|
+
profiles: new Map(),
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
await ensureExtensionRelayForProfiles({
|
|
51
|
+
resolved,
|
|
52
|
+
onWarn: (message) => logService.warn(message),
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
logService.info(
|
|
56
|
+
`Browser control service ready (profiles=${Object.keys(resolved.profiles).length})`,
|
|
57
|
+
);
|
|
58
|
+
return state;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export async function stopBrowserControlService(): Promise<void> {
|
|
62
|
+
const current = state;
|
|
63
|
+
if (!current) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
await stopKnownBrowserProfiles({
|
|
68
|
+
getState: () => state,
|
|
69
|
+
onWarn: (message) => logService.warn(message),
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
state = null;
|
|
73
|
+
|
|
74
|
+
// Optional: Playwright is not always available (e.g. embedded gateway builds).
|
|
75
|
+
try {
|
|
76
|
+
const mod = await import("./pw-ai.js");
|
|
77
|
+
await mod.closePlaywrightBrowserConnection();
|
|
78
|
+
} catch {
|
|
79
|
+
// ignore
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { NextFunction, Request, Response } from "express";
|
|
2
|
+
import { isLoopbackHost } from "./enterprise-compat.js";
|
|
3
|
+
|
|
4
|
+
function firstHeader(value: string | string[] | undefined): string {
|
|
5
|
+
return Array.isArray(value) ? (value[0] ?? "") : (value ?? "");
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function isMutatingMethod(method: string): boolean {
|
|
9
|
+
const m = (method || "").trim().toUpperCase();
|
|
10
|
+
return m === "POST" || m === "PUT" || m === "PATCH" || m === "DELETE";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function isLoopbackUrl(value: string): boolean {
|
|
14
|
+
const v = value.trim();
|
|
15
|
+
if (!v || v === "null") {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
const parsed = new URL(v);
|
|
20
|
+
return isLoopbackHost(parsed.hostname);
|
|
21
|
+
} catch {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function shouldRejectBrowserMutation(params: {
|
|
27
|
+
method: string;
|
|
28
|
+
origin?: string;
|
|
29
|
+
referer?: string;
|
|
30
|
+
secFetchSite?: string;
|
|
31
|
+
}): boolean {
|
|
32
|
+
if (!isMutatingMethod(params.method)) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Strong signal when present: browser says this is cross-site.
|
|
37
|
+
// Avoid being overly clever with "same-site" since localhost vs 127.0.0.1 may differ.
|
|
38
|
+
const secFetchSite = (params.secFetchSite ?? "").trim().toLowerCase();
|
|
39
|
+
if (secFetchSite === "cross-site") {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const origin = (params.origin ?? "").trim();
|
|
44
|
+
if (origin) {
|
|
45
|
+
return !isLoopbackUrl(origin);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const referer = (params.referer ?? "").trim();
|
|
49
|
+
if (referer) {
|
|
50
|
+
return !isLoopbackUrl(referer);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Non-browser clients (curl/undici/Node) typically send no Origin/Referer.
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function browserMutationGuardMiddleware(): (
|
|
58
|
+
req: Request,
|
|
59
|
+
res: Response,
|
|
60
|
+
next: NextFunction,
|
|
61
|
+
) => void {
|
|
62
|
+
return (req: Request, res: Response, next: NextFunction) => {
|
|
63
|
+
// OPTIONS is used for CORS preflight. Even if cross-origin, the preflight isn't mutating.
|
|
64
|
+
const method = (req.method || "").trim().toUpperCase();
|
|
65
|
+
if (method === "OPTIONS") {
|
|
66
|
+
return next();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const origin = firstHeader(req.headers.origin);
|
|
70
|
+
const referer = firstHeader(req.headers.referer);
|
|
71
|
+
const secFetchSite = firstHeader(req.headers["sec-fetch-site"]);
|
|
72
|
+
|
|
73
|
+
if (
|
|
74
|
+
shouldRejectBrowserMutation({
|
|
75
|
+
method,
|
|
76
|
+
origin,
|
|
77
|
+
referer,
|
|
78
|
+
secFetchSite,
|
|
79
|
+
})
|
|
80
|
+
) {
|
|
81
|
+
res.status(403).send("Forbidden");
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
next();
|
|
86
|
+
};
|
|
87
|
+
}
|