Include full contents of all nested repositories
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
57
openclaw/extensions/tlon/src/urbit/base-url.ts
Normal file
57
openclaw/extensions/tlon/src/urbit/base-url.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { isBlockedHostnameOrIp } from "openclaw/plugin-sdk";
|
||||
|
||||
export type UrbitBaseUrlValidation =
|
||||
| { ok: true; baseUrl: string; hostname: string }
|
||||
| { ok: false; error: string };
|
||||
|
||||
function hasScheme(value: string): boolean {
|
||||
return /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(value);
|
||||
}
|
||||
|
||||
export function validateUrbitBaseUrl(raw: string): UrbitBaseUrlValidation {
|
||||
const trimmed = String(raw ?? "").trim();
|
||||
if (!trimmed) {
|
||||
return { ok: false, error: "Required" };
|
||||
}
|
||||
|
||||
const candidate = hasScheme(trimmed) ? trimmed : `https://${trimmed}`;
|
||||
|
||||
let parsed: URL;
|
||||
try {
|
||||
parsed = new URL(candidate);
|
||||
} catch {
|
||||
return { ok: false, error: "Invalid URL" };
|
||||
}
|
||||
|
||||
if (!["http:", "https:"].includes(parsed.protocol)) {
|
||||
return { ok: false, error: "URL must use http:// or https://" };
|
||||
}
|
||||
|
||||
if (parsed.username || parsed.password) {
|
||||
return { ok: false, error: "URL must not include credentials" };
|
||||
}
|
||||
|
||||
const hostname = parsed.hostname.trim().toLowerCase().replace(/\.$/, "");
|
||||
if (!hostname) {
|
||||
return { ok: false, error: "Invalid hostname" };
|
||||
}
|
||||
|
||||
// Normalize to origin so callers can't smuggle paths/query fragments into the base URL,
|
||||
// and strip a trailing dot from the hostname (DNS root label).
|
||||
const isIpv6 = hostname.includes(":");
|
||||
const host = parsed.port
|
||||
? `${isIpv6 ? `[${hostname}]` : hostname}:${parsed.port}`
|
||||
: isIpv6
|
||||
? `[${hostname}]`
|
||||
: hostname;
|
||||
|
||||
return { ok: true, baseUrl: `${parsed.protocol}//${host}`, hostname };
|
||||
}
|
||||
|
||||
export function isBlockedUrbitHostname(hostname: string): boolean {
|
||||
const normalized = hostname.trim().toLowerCase().replace(/\.$/, "");
|
||||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
return isBlockedHostnameOrIp(normalized);
|
||||
}
|
||||
Reference in New Issue
Block a user