refactor(tlon): align internal network naming

This commit is contained in:
Vincent Koc 2026-04-05 09:55:54 +01:00
parent 4a85810091
commit 2489913ede
8 changed files with 34 additions and 32 deletions

View File

@ -2,7 +2,7 @@ export type TlonAccountFieldsInput = {
ship?: string;
url?: string;
code?: string;
allowPrivateNetwork?: boolean;
dangerouslyAllowPrivateNetwork?: boolean;
groupChannels?: string[];
dmAllowlist?: string[];
autoDiscoverChannels?: boolean;
@ -14,10 +14,10 @@ export function buildTlonAccountFields(input: TlonAccountFieldsInput) {
...(input.ship ? { ship: input.ship } : {}),
...(input.url ? { url: input.url } : {}),
...(input.code ? { code: input.code } : {}),
...(typeof input.allowPrivateNetwork === "boolean"
...(typeof input.dangerouslyAllowPrivateNetwork === "boolean"
? {
network: {
dangerouslyAllowPrivateNetwork: input.allowPrivateNetwork,
dangerouslyAllowPrivateNetwork: input.dangerouslyAllowPrivateNetwork,
},
}
: {}),

View File

@ -37,9 +37,9 @@ async function createHttpPokeApi(params: {
url: string;
code: string;
ship: string;
allowPrivateNetwork?: boolean;
dangerouslyAllowPrivateNetwork?: boolean;
}) {
const ssrfPolicy = ssrfPolicyFromAllowPrivateNetwork(params.allowPrivateNetwork);
const ssrfPolicy = ssrfPolicyFromAllowPrivateNetwork(params.dangerouslyAllowPrivateNetwork);
const cookie = await authenticate(params.url, params.code, { ssrfPolicy });
const channelId = `${Math.floor(Date.now() / 1000)}-${crypto.randomUUID()}`;
const channelPath = `/~/channel/${channelId}`;
@ -119,7 +119,7 @@ async function withHttpPokeAccountApi<T>(
url: account.url,
ship: account.ship,
code: account.code,
allowPrivateNetwork: account.allowPrivateNetwork ?? undefined,
dangerouslyAllowPrivateNetwork: account.dangerouslyAllowPrivateNetwork ?? undefined,
});
try {
@ -167,7 +167,7 @@ export const tlonRuntimeOutbound: ChannelOutboundAdapter = {
shipName: account.ship.replace(/^~/, ""),
verbose: false,
getCode: async () => account.code,
allowPrivateNetwork: account.allowPrivateNetwork ?? undefined,
dangerouslyAllowPrivateNetwork: account.dangerouslyAllowPrivateNetwork ?? undefined,
});
const uploadedUrl = mediaUrl ? await uploadImageFromUrl(mediaUrl) : undefined;
@ -197,7 +197,7 @@ export const tlonRuntimeOutbound: ChannelOutboundAdapter = {
export async function probeTlonAccount(account: ConfiguredTlonAccount) {
try {
const ssrfPolicy = ssrfPolicyFromAllowPrivateNetwork(account.allowPrivateNetwork);
const ssrfPolicy = ssrfPolicyFromAllowPrivateNetwork(account.dangerouslyAllowPrivateNetwork);
const cookie = await authenticate(account.url, account.code, { ssrfPolicy });
const { response, release } = await urbitFetch({
baseUrl: account.url,

View File

@ -73,7 +73,7 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
const botShipName = normalizeShip(account.ship);
runtime.log?.(`[tlon] Starting monitor for ${botShipName}`);
const ssrfPolicy = ssrfPolicyFromAllowPrivateNetwork(account.allowPrivateNetwork);
const ssrfPolicy = ssrfPolicyFromAllowPrivateNetwork(account.dangerouslyAllowPrivateNetwork);
// Store validated values for use in closures (TypeScript narrowing doesn't propagate)
const accountUrl = account.url;

View File

@ -14,7 +14,7 @@ const baseAccount: TlonResolvedAccount = {
ship: "~sampel-palnet",
url: "https://example.com",
code: "lidlut-tabwed-pillex-ridrup",
allowPrivateNetwork: false,
dangerouslyAllowPrivateNetwork: false,
groupChannels: ["chat/~host/general"],
dmAllowlist: ["~zod"],
groupInviteAllowlist: ["~bus"],

View File

@ -23,7 +23,7 @@ export type TlonSetupInput = ChannelSetupInput & {
ship?: string;
url?: string;
code?: string;
allowPrivateNetwork?: boolean;
dangerouslyAllowPrivateNetwork?: boolean;
groupChannels?: string[];
dmAllowlist?: string[];
autoDiscoverChannels?: boolean;

View File

@ -38,21 +38,21 @@ export const tlonSetupWizard = createTlonSetupWizardBase({
throw new Error(`Invalid URL: ${validatedUrl.error}`);
}
let allowPrivateNetwork = resolved.allowPrivateNetwork ?? false;
let dangerouslyAllowPrivateNetwork = resolved.dangerouslyAllowPrivateNetwork ?? false;
if (isBlockedUrbitHostname(validatedUrl.hostname)) {
allowPrivateNetwork = await prompter.confirm({
dangerouslyAllowPrivateNetwork = await prompter.confirm({
message:
"Ship URL looks like a private/internal host. Allow private network access? (SSRF risk)",
initialValue: allowPrivateNetwork,
initialValue: dangerouslyAllowPrivateNetwork,
});
if (!allowPrivateNetwork) {
if (!dangerouslyAllowPrivateNetwork) {
throw new Error("Refusing private/internal ship URL without explicit network opt-in");
}
}
next = applyTlonSetupConfig({
cfg: next,
accountId,
input: { allowPrivateNetwork },
input: { dangerouslyAllowPrivateNetwork },
});
const currentGroups = resolved.groupChannels;

View File

@ -10,7 +10,7 @@ type ClientConfig = {
shipName: string;
verbose: boolean;
getCode: () => Promise<string>;
allowPrivateNetwork?: boolean;
dangerouslyAllowPrivateNetwork?: boolean;
};
type StorageService = "presigned-url" | "credentials";
@ -112,7 +112,7 @@ function sanitizeFileName(fileName: string): string {
async function getAuthCookie(config: ClientConfig): Promise<string> {
return await authenticate(config.shipUrl, await config.getCode(), {
ssrfPolicy: ssrfPolicyFromAllowPrivateNetwork(config.allowPrivateNetwork),
ssrfPolicy: ssrfPolicyFromAllowPrivateNetwork(config.dangerouslyAllowPrivateNetwork),
});
}
@ -121,7 +121,7 @@ async function scryJson<T>(config: ClientConfig, cookie: string, path: string):
{
baseUrl: config.shipUrl,
cookie,
ssrfPolicy: ssrfPolicyFromAllowPrivateNetwork(config.allowPrivateNetwork),
ssrfPolicy: ssrfPolicyFromAllowPrivateNetwork(config.dangerouslyAllowPrivateNetwork),
},
{ path, auditContext: "tlon-storage-scry" },
)) as T;

View File

@ -5,7 +5,10 @@ import {
resolveMergedAccountConfig,
} from "openclaw/plugin-sdk/account-resolution";
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
import { hasLegacyFlatAllowPrivateNetworkAlias, isPrivateNetworkOptInEnabled } from "openclaw/plugin-sdk/ssrf-runtime";
import {
hasLegacyFlatAllowPrivateNetworkAlias,
isPrivateNetworkOptInEnabled,
} from "openclaw/plugin-sdk/ssrf-runtime";
type TlonAccountConfig = {
name?: string;
@ -36,7 +39,7 @@ export type TlonResolvedAccount = {
ship: string | null;
url: string | null;
code: string | null;
allowPrivateNetwork: boolean | null;
dangerouslyAllowPrivateNetwork: boolean | null;
groupChannels: string[];
dmAllowlist: string[];
/** Ships allowed to invite us to groups (security: prevent malicious group invites) */
@ -88,7 +91,7 @@ export function resolveTlonAccount(
ship: null,
url: null,
code: null,
allowPrivateNetwork: null,
dangerouslyAllowPrivateNetwork: null,
groupChannels: [],
dmAllowlist: [],
groupInviteAllowlist: [],
@ -105,15 +108,14 @@ export function resolveTlonAccount(
const ship = (merged.ship ?? null) as string | null;
const url = (merged.url ?? null) as string | null;
const code = (merged.code ?? null) as string | null;
const allowPrivateNetwork =
isPrivateNetworkOptInEnabled(merged)
? true
: typeof merged.network?.dangerouslyAllowPrivateNetwork === "boolean"
? merged.network.dangerouslyAllowPrivateNetwork
: hasLegacyFlatAllowPrivateNetworkAlias(merged) &&
typeof merged.allowPrivateNetwork === "boolean"
? merged.allowPrivateNetwork
: null;
const dangerouslyAllowPrivateNetwork = isPrivateNetworkOptInEnabled(merged)
? true
: typeof merged.network?.dangerouslyAllowPrivateNetwork === "boolean"
? merged.network.dangerouslyAllowPrivateNetwork
: hasLegacyFlatAllowPrivateNetworkAlias(merged) &&
typeof merged.allowPrivateNetwork === "boolean"
? merged.allowPrivateNetwork
: null;
const groupChannels = (merged.groupChannels ?? []) as string[];
const dmAllowlist = (merged.dmAllowlist ?? []) as string[];
const groupInviteAllowlist = (merged.groupInviteAllowlist ?? []) as string[];
@ -133,7 +135,7 @@ export function resolveTlonAccount(
ship,
url,
code,
allowPrivateNetwork,
dangerouslyAllowPrivateNetwork,
groupChannels,
dmAllowlist,
groupInviteAllowlist,