mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 05:16:23 -06:00
refactor(media): share local source path resolution
This commit is contained in:
@@ -4,21 +4,19 @@ import { randomUUID } from "node:crypto";
|
||||
import fs from "node:fs/promises";
|
||||
import type { IncomingMessage, ServerResponse } from "node:http";
|
||||
import path from "node:path";
|
||||
import { isPassThroughRemoteMediaSource } from "@openclaw/media-core/media-source-url";
|
||||
import { resolveDefaultAgentId } from "../agents/agent-scope-config.js";
|
||||
import { getRuntimeConfig } from "../config/config.js";
|
||||
import { resolveStateDir } from "../config/paths.js";
|
||||
import { readLocalFileSafely } from "../infra/fs-safe.js";
|
||||
import { tryReadJson, writeJson } from "../infra/json-files.js";
|
||||
import { safeFileURLToPath } from "../infra/local-file-access.js";
|
||||
import { assertLocalMediaAllowed } from "../media/local-media-access.js";
|
||||
import { resolveLocalMediaPath } from "../media/local-media-path.js";
|
||||
import {
|
||||
createImageProcessor,
|
||||
getImageMetadata,
|
||||
readImageProbeFromHeader,
|
||||
} from "../media/media-services.js";
|
||||
import { MEDIA_MAX_BYTES, saveMediaBuffer, saveMediaSource } from "../media/store.js";
|
||||
import { resolveUserPath } from "../utils.js";
|
||||
import type { AuthRateLimiter } from "./auth-rate-limit.js";
|
||||
import type { ResolvedGatewayAuth } from "./auth.js";
|
||||
import { sendJson, sendMethodNotAllowed, sendMissingScopeForbidden } from "./http-common.js";
|
||||
@@ -35,8 +33,6 @@ const OUTGOING_IMAGE_ROUTE_PREFIX = "/api/chat/media/outgoing";
|
||||
const DEFAULT_TRANSIENT_OUTGOING_IMAGE_TTL_MS = 15 * 60 * 1000;
|
||||
const MANAGED_OUTGOING_ATTACHMENT_ID_RE =
|
||||
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
||||
const DATA_URL_RE = /^data:/i;
|
||||
const WINDOWS_DRIVE_RE = /^[A-Za-z]:[\\/]/;
|
||||
|
||||
export const DEFAULT_MANAGED_IMAGE_ATTACHMENT_LIMITS = {
|
||||
maxBytes: 12 * 1024 * 1024,
|
||||
@@ -274,27 +270,6 @@ function deriveAltText(source: string, index: number) {
|
||||
return localName || fallback;
|
||||
}
|
||||
|
||||
function resolveLocalMediaPath(source: string): string | undefined {
|
||||
const trimmed = source.trim();
|
||||
if (!trimmed || isPassThroughRemoteMediaSource(trimmed) || DATA_URL_RE.test(trimmed)) {
|
||||
return undefined;
|
||||
}
|
||||
if (trimmed.startsWith("file://")) {
|
||||
try {
|
||||
return safeFileURLToPath(trimmed);
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
if (trimmed.startsWith("~")) {
|
||||
return resolveUserPath(trimmed);
|
||||
}
|
||||
if (path.isAbsolute(trimmed) || WINDOWS_DRIVE_RE.test(trimmed)) {
|
||||
return path.resolve(trimmed);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function parseImageDataUrl(
|
||||
source: string,
|
||||
alt: string,
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import path from "node:path";
|
||||
import { isPassThroughRemoteMediaSource } from "@openclaw/media-core/media-source-url";
|
||||
import { safeFileURLToPath } from "../infra/local-file-access.js";
|
||||
import { resolveUserPath } from "../utils.js";
|
||||
|
||||
const DATA_URL_RE = /^data:/i;
|
||||
const WINDOWS_DRIVE_RE = /^[A-Za-z]:[\\/]/;
|
||||
|
||||
/** Resolves a media source to a local path when it is not a remote or data URL. */
|
||||
export function resolveLocalMediaPath(source: string): string | undefined {
|
||||
const trimmed = source.trim();
|
||||
if (!trimmed || isPassThroughRemoteMediaSource(trimmed) || DATA_URL_RE.test(trimmed)) {
|
||||
return undefined;
|
||||
}
|
||||
if (trimmed.startsWith("file://")) {
|
||||
try {
|
||||
return safeFileURLToPath(trimmed);
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
if (trimmed.startsWith("~")) {
|
||||
return resolveUserPath(trimmed);
|
||||
}
|
||||
if (path.isAbsolute(trimmed) || WINDOWS_DRIVE_RE.test(trimmed)) {
|
||||
return path.resolve(trimmed);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
// Local media root helpers normalize and match allowed local media roots.
|
||||
import path from "node:path";
|
||||
import { isPassThroughRemoteMediaSource } from "@openclaw/media-core/media-source-url";
|
||||
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
|
||||
import { uniqueStrings } from "@openclaw/normalization-core/string-normalization";
|
||||
import { resolveAgentWorkspaceDir } from "../agents/agent-scope.js";
|
||||
@@ -10,17 +9,15 @@ import {
|
||||
} from "../agents/tool-fs-policy.js";
|
||||
import { resolveStateDir } from "../config/paths.js";
|
||||
import type { OpenClawConfig } from "../config/types.js";
|
||||
import { safeFileURLToPath } from "../infra/local-file-access.js";
|
||||
import { resolvePreferredOpenClawTmpDir } from "../infra/tmp-openclaw-dir.js";
|
||||
import { resolveConfigDir, resolveUserPath } from "../utils.js";
|
||||
import { resolveConfigDir } from "../utils.js";
|
||||
import { resolveLocalMediaPath } from "./local-media-path.js";
|
||||
|
||||
type BuildMediaLocalRootsOptions = {
|
||||
preferredTmpDir?: string;
|
||||
};
|
||||
|
||||
let cachedPreferredTmpDir: string | undefined;
|
||||
const DATA_URL_RE = /^data:/i;
|
||||
const WINDOWS_DRIVE_RE = /^[A-Za-z]:[\\/]/;
|
||||
|
||||
function resolveCachedPreferredTmpDir(): string {
|
||||
if (!cachedPreferredTmpDir) {
|
||||
@@ -78,27 +75,6 @@ export function getAgentScopedMediaLocalRoots(
|
||||
return roots;
|
||||
}
|
||||
|
||||
function resolveLocalMediaPath(source: string): string | undefined {
|
||||
const trimmed = source.trim();
|
||||
if (!trimmed || isPassThroughRemoteMediaSource(trimmed) || DATA_URL_RE.test(trimmed)) {
|
||||
return undefined;
|
||||
}
|
||||
if (trimmed.startsWith("file://")) {
|
||||
try {
|
||||
return safeFileURLToPath(trimmed);
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
if (trimmed.startsWith("~")) {
|
||||
return resolveUserPath(trimmed);
|
||||
}
|
||||
if (path.isAbsolute(trimmed) || WINDOWS_DRIVE_RE.test(trimmed)) {
|
||||
return path.resolve(trimmed);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/** Adds only concrete local source parent directories to an existing root allowlist. */
|
||||
export function appendLocalMediaParentRoots(
|
||||
roots: readonly string[],
|
||||
|
||||
Reference in New Issue
Block a user