openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
66 lines (65 loc) • 2.3 kB
JavaScript
import { l as normalizeOptionalString } from "./string-coerce-CIXf7egm.js";
//#region src/infra/scp-host.ts
const SSH_TOKEN = /^[A-Za-z0-9._-]+$/;
const BRACKETED_IPV6 = /^\[[0-9A-Fa-f:.%]+\]$/;
const WHITESPACE = /\s/;
const SCP_REMOTE_PATH_UNSAFE_CHARS = /* @__PURE__ */ new Set([
"\\",
"'",
"\"",
"`",
"$",
";",
"|",
"&",
"<",
">"
]);
function hasControlOrWhitespace(value) {
for (const char of value) {
const code = char.charCodeAt(0);
if (code <= 31 || code === 127 || WHITESPACE.test(char)) return true;
}
return false;
}
/** Normalize an optional `[user@]host` SCP target or reject unsafe tokens. */
function normalizeScpRemoteHost(value) {
const trimmed = normalizeOptionalString(value);
if (!trimmed) return;
if (hasControlOrWhitespace(trimmed)) return;
if (trimmed.startsWith("-") || trimmed.includes("/") || trimmed.includes("\\")) return;
const firstAt = trimmed.indexOf("@");
const lastAt = trimmed.lastIndexOf("@");
let user;
let host = trimmed;
if (firstAt !== -1) {
if (firstAt !== lastAt || firstAt === 0 || firstAt === trimmed.length - 1) return;
user = trimmed.slice(0, firstAt);
host = trimmed.slice(firstAt + 1);
if (!SSH_TOKEN.test(user)) return;
}
if (!host || host.startsWith("-") || host.includes("@")) return;
if (host.includes(":") && !BRACKETED_IPV6.test(host)) return;
if (!SSH_TOKEN.test(host) && !BRACKETED_IPV6.test(host)) return;
return user ? `${user}@${host}` : host;
}
/** Return true when a value is safe for the SCP host position. */
function isSafeScpRemoteHost(value) {
return normalizeScpRemoteHost(value) !== void 0;
}
/** Normalize an absolute remote path that is safe for SCP command construction. */
function normalizeScpRemotePath(value) {
const trimmed = normalizeOptionalString(value);
if (!trimmed || !trimmed.startsWith("/")) return;
for (const char of trimmed) {
const code = char.charCodeAt(0);
if (code <= 31 || code === 127 || SCP_REMOTE_PATH_UNSAFE_CHARS.has(char)) return;
}
return trimmed;
}
/** Return true when a value is safe for the SCP remote path position. */
function isSafeScpRemotePath(value) {
return normalizeScpRemotePath(value) !== void 0;
}
//#endregion
export { normalizeScpRemotePath as i, isSafeScpRemotePath as n, normalizeScpRemoteHost as r, isSafeScpRemoteHost as t };