mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-17 12:11:20 +00:00
refactor: dedupe infra lowercase helpers
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { runCommandWithTimeout } from "../process/exec.js";
|
||||
import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js";
|
||||
import { isTailnetIPv4 } from "./tailnet.js";
|
||||
import { resolveWideAreaDiscoveryDomain } from "./widearea-dns.js";
|
||||
|
||||
@@ -279,7 +280,7 @@ function parseDnsSdResolve(stdout: string, instanceName: string): GatewayBonjour
|
||||
beacon.gatewayPort = parseIntOrNull(txt.gatewayPort);
|
||||
beacon.sshPort = parseIntOrNull(txt.sshPort);
|
||||
if (txt.gatewayTls) {
|
||||
const raw = txt.gatewayTls.trim().toLowerCase();
|
||||
const raw = normalizeOptionalLowercaseString(txt.gatewayTls);
|
||||
beacon.gatewayTls = raw === "1" || raw === "true" || raw === "yes";
|
||||
}
|
||||
if (txt.gatewayTlsSha256) {
|
||||
@@ -457,7 +458,7 @@ async function discoverWideAreaViaTailnetDns(
|
||||
cliPath: txtMap.cliPath || undefined,
|
||||
};
|
||||
if (txtMap.gatewayTls) {
|
||||
const raw = txtMap.gatewayTls.trim().toLowerCase();
|
||||
const raw = normalizeOptionalLowercaseString(txtMap.gatewayTls);
|
||||
beacon.gatewayTls = raw === "1" || raw === "true" || raw === "yes";
|
||||
}
|
||||
if (txtMap.gatewayTlsSha256) {
|
||||
@@ -541,7 +542,7 @@ function parseAvahiBrowse(stdout: string): GatewayBonjourBeacon[] {
|
||||
current.gatewayPort = parseIntOrNull(txt.gatewayPort);
|
||||
current.sshPort = parseIntOrNull(txt.sshPort);
|
||||
if (txt.gatewayTls) {
|
||||
const raw = txt.gatewayTls.trim().toLowerCase();
|
||||
const raw = normalizeOptionalLowercaseString(txt.gatewayTls);
|
||||
current.gatewayTls = raw === "1" || raw === "true" || raw === "yes";
|
||||
}
|
||||
if (txt.gatewayTlsSha256) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
import { matchesExecAllowlistPattern } from "./exec-allowlist-pattern.js";
|
||||
import type { ExecAllowlistEntry } from "./exec-approvals.js";
|
||||
import { resolveExecWrapperTrustPlan } from "./exec-wrapper-trust-plan.js";
|
||||
@@ -342,7 +343,9 @@ export function matchAllowlist(
|
||||
// Use the caller-supplied target platform rather than process.platform so that
|
||||
// a Linux gateway evaluating a Windows node command applies argPattern correctly.
|
||||
const effectivePlatform = platform ?? process.platform;
|
||||
const useArgPattern = String(effectivePlatform).trim().toLowerCase().startsWith("win");
|
||||
const useArgPattern = normalizeLowercaseStringOrEmpty(String(effectivePlatform)).startsWith(
|
||||
"win",
|
||||
);
|
||||
let pathOnlyMatch: ExecAllowlistEntry | null = null;
|
||||
for (const entry of entries) {
|
||||
const pattern = entry.pattern?.trim();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { HEARTBEAT_TOKEN } from "../auto-reply/tokens.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
|
||||
// Build a dynamic prompt for cron events by embedding the actual event content.
|
||||
// This ensures the model sees the reminder text directly instead of relying on
|
||||
@@ -72,7 +73,7 @@ function isHeartbeatAckEvent(evt: string): boolean {
|
||||
}
|
||||
|
||||
function isHeartbeatNoiseEvent(evt: string): boolean {
|
||||
const lower = evt.trim().toLowerCase();
|
||||
const lower = normalizeLowercaseStringOrEmpty(evt);
|
||||
if (!lower) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";
|
||||
|
||||
export function normalizeHostname(hostname: string): string {
|
||||
const normalized = hostname.trim().toLowerCase().replace(/\.$/, "");
|
||||
const normalized = normalizeLowercaseStringOrEmpty(hostname).replace(/\.$/, "");
|
||||
if (normalized.startsWith("[") && normalized.endsWith("]")) {
|
||||
return normalized.slice(1, -1);
|
||||
}
|
||||
|
||||
@@ -120,10 +120,7 @@ function looksLikeUnsupportedIpv4Literal(address: string): boolean {
|
||||
|
||||
// Returns true for private/internal and special-use non-global addresses.
|
||||
export function isPrivateIpAddress(address: string, policy?: SsrFPolicy): boolean {
|
||||
let normalized = address.trim().toLowerCase();
|
||||
if (normalized.startsWith("[") && normalized.endsWith("]")) {
|
||||
normalized = normalized.slice(1, -1);
|
||||
}
|
||||
const normalized = normalizeHostname(address);
|
||||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { formatCliCommand } from "../cli/command-format.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
import type { PortListener, PortListenerKind, PortUsage } from "./ports-types.js";
|
||||
|
||||
export function classifyPortListener(listener: PortListener, port: number): PortListenerKind {
|
||||
const raw = `${listener.commandLine ?? ""} ${listener.command ?? ""}`.trim().toLowerCase();
|
||||
const raw = normalizeLowercaseStringOrEmpty(
|
||||
`${listener.commandLine ?? ""} ${listener.command ?? ""}`,
|
||||
);
|
||||
if (raw.includes("openclaw")) {
|
||||
return "gateway";
|
||||
}
|
||||
@@ -34,7 +37,7 @@ function parseListenerAddress(address: string): { host: string; port: number } |
|
||||
if (lastColon <= 0 || lastColon >= normalized.length - 1) {
|
||||
return null;
|
||||
}
|
||||
const host = normalized.slice(0, lastColon).trim().toLowerCase();
|
||||
const host = normalizeLowercaseStringOrEmpty(normalized.slice(0, lastColon));
|
||||
const portToken = normalized.slice(lastColon + 1).trim();
|
||||
if (!/^\d+$/.test(portToken)) {
|
||||
return null;
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
type DeviceIdentity,
|
||||
} from "./device-identity.js";
|
||||
import { formatErrorMessage } from "./errors.js";
|
||||
import { normalizeHostname } from "./net/hostname.js";
|
||||
|
||||
export type ApnsRelayPushType = "alert" | "background";
|
||||
|
||||
@@ -74,7 +75,7 @@ function readAllowHttp(value: string | undefined): boolean {
|
||||
}
|
||||
|
||||
function isLoopbackRelayHostname(hostname: string): boolean {
|
||||
const normalized = hostname.trim().toLowerCase();
|
||||
const normalized = normalizeHostname(hostname);
|
||||
return (
|
||||
normalized === "localhost" ||
|
||||
normalized === "::1" ||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import process from "node:process";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
import { restoreTerminalState } from "../terminal/restore.js";
|
||||
import {
|
||||
collectErrorGraphCandidates,
|
||||
@@ -238,7 +239,7 @@ export function isTransientNetworkError(err: unknown): boolean {
|
||||
continue;
|
||||
}
|
||||
const rawMessage = (candidate as { message?: unknown }).message;
|
||||
const message = typeof rawMessage === "string" ? rawMessage.toLowerCase().trim() : "";
|
||||
const message = normalizeLowercaseStringOrEmpty(rawMessage);
|
||||
if (!message) {
|
||||
continue;
|
||||
}
|
||||
@@ -297,7 +298,7 @@ export function isTransientSqliteError(err: unknown): boolean {
|
||||
(candidate as { errstr?: unknown }).errstr,
|
||||
];
|
||||
for (const rawMessage of messageParts) {
|
||||
const message = typeof rawMessage === "string" ? rawMessage.toLowerCase().trim() : "";
|
||||
const message = normalizeLowercaseStringOrEmpty(rawMessage);
|
||||
if (!message) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { materializeGatewayAuthSecretRefs } from "../gateway/auth-config-utils.j
|
||||
import { assertExplicitGatewayAuthModeWhenBothConfigured } from "../gateway/auth-mode-policy.js";
|
||||
import { isLoopbackHost, isSecureWebSocketUrl } from "../gateway/net.js";
|
||||
import { issueDeviceBootstrapToken } from "../infra/device-bootstrap.js";
|
||||
import { normalizeHostname } from "../infra/net/hostname.js";
|
||||
import {
|
||||
pickMatchingExternalInterfaceAddress,
|
||||
safeNetworkInterfaces,
|
||||
@@ -78,7 +79,7 @@ function describeSecureMobilePairingFix(source?: string): string {
|
||||
}
|
||||
|
||||
function isPrivateLanHostname(host: string): boolean {
|
||||
const normalized = host.trim().toLowerCase().replace(/\.+$/, "");
|
||||
const normalized = normalizeHostname(host);
|
||||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js";
|
||||
|
||||
/** Read loose boolean params from tool input that may arrive as booleans or "true"/"false" strings. */
|
||||
export function readBooleanParam(
|
||||
params: Record<string, unknown>,
|
||||
@@ -7,14 +9,12 @@ export function readBooleanParam(
|
||||
if (typeof raw === "boolean") {
|
||||
return raw;
|
||||
}
|
||||
if (typeof raw === "string") {
|
||||
const trimmed = raw.trim().toLowerCase();
|
||||
if (trimmed === "true") {
|
||||
return true;
|
||||
}
|
||||
if (trimmed === "false") {
|
||||
return false;
|
||||
}
|
||||
const normalized = normalizeOptionalLowercaseString(raw);
|
||||
if (normalized === "true") {
|
||||
return true;
|
||||
}
|
||||
if (normalized === "false") {
|
||||
return false;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
requestBodyErrorToText,
|
||||
} from "../infra/http-body.js";
|
||||
import { pruneMapToMaxSize } from "../infra/map-size.js";
|
||||
import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js";
|
||||
import type { FixedWindowRateLimiter } from "./webhook-memory-guards.js";
|
||||
|
||||
export type WebhookBodyReadProfile = "pre-auth" | "post-auth";
|
||||
@@ -144,7 +145,7 @@ export function isJsonContentType(value: string | string[] | undefined): boolean
|
||||
if (!first) {
|
||||
return false;
|
||||
}
|
||||
const mediaType = first.split(";", 1)[0]?.trim().toLowerCase();
|
||||
const mediaType = normalizeOptionalLowercaseString(first.split(";", 1)[0]);
|
||||
return mediaType === "application/json" || Boolean(mediaType?.endsWith("+json"));
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,10 @@ import { writeJsonAtomic } from "../infra/json-files.js";
|
||||
import { type ConversationRef } from "../infra/outbound/session-binding-service.js";
|
||||
import { createSubsystemLogger } from "../logging/subsystem.js";
|
||||
import { resolveGlobalMap, resolveGlobalSingleton } from "../shared/global-singleton.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
import {
|
||||
normalizeOptionalLowercaseString,
|
||||
normalizeOptionalString,
|
||||
} from "../shared/string-coerce.js";
|
||||
import { getActivePluginRegistry } from "./runtime.js";
|
||||
import type {
|
||||
PluginConversationBinding,
|
||||
@@ -155,7 +158,7 @@ function resolveApprovalsPath(): string {
|
||||
}
|
||||
|
||||
function normalizeChannel(value: string): string {
|
||||
return value.trim().toLowerCase();
|
||||
return normalizeOptionalLowercaseString(value) ?? "";
|
||||
}
|
||||
|
||||
function normalizeConversation(params: PluginBindingConversation): PluginBindingConversation {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js";
|
||||
import {
|
||||
normalizePluginInteractiveNamespace,
|
||||
resolvePluginInteractiveMatch,
|
||||
@@ -49,7 +50,7 @@ export function registerPluginInteractiveHandler(
|
||||
interactiveHandlers.set(key, {
|
||||
...registration,
|
||||
namespace,
|
||||
channel: registration.channel.trim().toLowerCase(),
|
||||
channel: normalizeOptionalLowercaseString(registration.channel) ?? "",
|
||||
pluginId,
|
||||
pluginName: opts?.pluginName,
|
||||
pluginRoot: opts?.pluginRoot,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js";
|
||||
|
||||
export function toPluginInteractiveRegistryKey(channel: string, namespace: string): string {
|
||||
return `${channel.trim().toLowerCase()}:${namespace.trim()}`;
|
||||
return `${normalizeOptionalLowercaseString(channel) ?? ""}:${namespace.trim()}`;
|
||||
}
|
||||
|
||||
export function normalizePluginInteractiveNamespace(namespace: string): string {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import JSON5 from "json5";
|
||||
import { LEGACY_MANIFEST_KEYS, MANIFEST_KEY } from "../compat/legacy-names.js";
|
||||
import { parseBooleanValue } from "../utils/boolean.js";
|
||||
import { readStringValue } from "./string-coerce.js";
|
||||
import { normalizeOptionalLowercaseString, readStringValue } from "./string-coerce.js";
|
||||
import { normalizeCsvOrLooseStringList } from "./string-normalization.js";
|
||||
|
||||
export function normalizeStringList(input: unknown): string[] {
|
||||
@@ -105,7 +105,7 @@ export function parseOpenClawManifestInstallBase(
|
||||
const raw = input as Record<string, unknown>;
|
||||
const kindRaw =
|
||||
typeof raw.kind === "string" ? raw.kind : typeof raw.type === "string" ? raw.type : "";
|
||||
const kind = kindRaw.trim().toLowerCase();
|
||||
const kind = normalizeOptionalLowercaseString(kindRaw) ?? "";
|
||||
if (!allowedKinds.includes(kind)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user