diff --git a/extensions/bluebubbles/src/local-file-access.ts b/extensions/bluebubbles/src/local-file-access.ts deleted file mode 100644 index 9c79e0eb5cc..00000000000 --- a/extensions/bluebubbles/src/local-file-access.ts +++ /dev/null @@ -1,62 +0,0 @@ -import path from "node:path"; -import { fileURLToPath, URL } from "node:url"; -import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime"; - -function isLocalFileUrlHost(hostname: string): boolean { - const normalized = normalizeLowercaseStringOrEmpty(hostname); - return normalized === "" || normalized === "localhost"; -} - -function assertNoWindowsNetworkPath(filePath: string, label = "Path"): void { - if (process.platform !== "win32") { - return; - } - const normalized = filePath.replace(/\//g, "\\"); - if (normalized.startsWith("\\\\?\\UNC\\") || normalized.startsWith("\\\\")) { - throw new Error(`${label} cannot use Windows network paths: ${filePath}`); - } -} - -export function safeFileURLToPath(fileUrl: string): string { - let parsed: URL; - try { - parsed = new URL(fileUrl); - } catch { - throw new Error(`Invalid file:// URL: ${fileUrl}`); - } - if (parsed.protocol !== "file:") { - throw new Error(`Invalid file:// URL: ${fileUrl}`); - } - if (!isLocalFileUrlHost(parsed.hostname)) { - throw new Error(`file:// URLs with remote hosts are not allowed: ${fileUrl}`); - } - const filePath = fileURLToPath(parsed); - assertNoWindowsNetworkPath(filePath, "Local file URL"); - return filePath; -} - -function trySafeFileURLToPath(fileUrl: string): string | undefined { - try { - return safeFileURLToPath(fileUrl); - } catch { - return undefined; - } -} - -export function basenameFromMediaSource(source?: string): string | undefined { - if (!source) { - return undefined; - } - if (source.startsWith("file://")) { - const filePath = trySafeFileURLToPath(source); - return filePath ? path.basename(filePath) || undefined : undefined; - } - if (/^https?:\/\//i.test(source)) { - try { - return path.basename(new URL(source).pathname) || undefined; - } catch { - return undefined; - } - } - return path.basename(source) || undefined; -} diff --git a/extensions/bluebubbles/src/media-send.ts b/extensions/bluebubbles/src/media-send.ts index 75ac213b05a..003e022d9d1 100644 --- a/extensions/bluebubbles/src/media-send.ts +++ b/extensions/bluebubbles/src/media-send.ts @@ -2,11 +2,11 @@ import { constants as fsConstants } from "node:fs"; import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; +import { basenameFromMediaSource, safeFileURLToPath } from "openclaw/plugin-sdk/infra-runtime"; import { resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/media-runtime"; import { lowercasePreservingWhitespace } from "openclaw/plugin-sdk/text-runtime"; import { resolveBlueBubblesAccount } from "./accounts.js"; import { sendBlueBubblesAttachment } from "./attachments.js"; -import { basenameFromMediaSource, safeFileURLToPath } from "./local-file-access.js"; import { resolveBlueBubblesMessageId } from "./monitor-reply-cache.js"; import type { OpenClawConfig } from "./runtime-api.js"; import { getBlueBubblesRuntime } from "./runtime.js";