mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 14:00:47 +00:00
fix(device-pair): reject invalid remote setup URLs
Fail setup-code generation when gateway.remote.url is configured but malformed, instead of falling back to a bind-derived URL and issuing a bootstrap token.
This commit is contained in:
@@ -70,6 +70,7 @@ type ApprovedPairingDevice = ApprovedPairingResult["device"];
|
||||
const INTERNAL_PAIRING_SCOPES = ["operator.write", "operator.pairing"];
|
||||
|
||||
function createApi(params?: {
|
||||
config?: OpenClawPluginApi["config"];
|
||||
runtime?: OpenClawPluginApi["runtime"];
|
||||
pluginConfig?: Record<string, unknown>;
|
||||
registerCommand?: (command: OpenClawPluginCommandDefinition) => void;
|
||||
@@ -78,7 +79,7 @@ function createApi(params?: {
|
||||
id: "device-pair",
|
||||
name: "device-pair",
|
||||
source: "test",
|
||||
config: {
|
||||
config: params?.config ?? {
|
||||
gateway: {
|
||||
auth: {
|
||||
mode: "token",
|
||||
@@ -96,6 +97,7 @@ function createApi(params?: {
|
||||
}
|
||||
|
||||
function registerPairCommand(params?: {
|
||||
config?: OpenClawPluginApi["config"];
|
||||
runtime?: OpenClawPluginApi["runtime"];
|
||||
pluginConfig?: Record<string, unknown>;
|
||||
}): OpenClawPluginCommandDefinition {
|
||||
@@ -649,6 +651,36 @@ describe("device-pair /pair default setup code", () => {
|
||||
expect(result).toEqual({ text: "Error: Configured publicUrl is invalid." });
|
||||
});
|
||||
|
||||
it("rejects invalid gateway.remote.url before falling back to bind-derived setup urls", async () => {
|
||||
const command = registerPairCommand({
|
||||
config: {
|
||||
gateway: {
|
||||
bind: "custom",
|
||||
customBindHost: "127.0.0.1",
|
||||
remote: { url: "http://localhost:notaport" },
|
||||
auth: {
|
||||
mode: "token",
|
||||
token: "gateway-token",
|
||||
},
|
||||
},
|
||||
},
|
||||
pluginConfig: {
|
||||
publicUrl: undefined,
|
||||
},
|
||||
});
|
||||
const result = await command.handler(
|
||||
createCommandContext({
|
||||
channel: "webchat",
|
||||
args: "",
|
||||
commandBody: "/pair",
|
||||
gatewayClientScopes: ["operator.write", "operator.pairing"],
|
||||
}),
|
||||
);
|
||||
|
||||
expect(pluginApiMocks.issueDeviceBootstrapToken).not.toHaveBeenCalled();
|
||||
expect(result).toEqual({ text: "Error: Configured gateway.remote.url is invalid." });
|
||||
});
|
||||
|
||||
it.each([
|
||||
"http://localhost:notaport",
|
||||
"http:gateway.example.test",
|
||||
|
||||
@@ -321,6 +321,12 @@ async function resolveGatewayUrl(api: OpenClawPluginApi): Promise<ResolveUrlResu
|
||||
return { error: "Configured publicUrl is invalid." };
|
||||
}
|
||||
|
||||
const configuredRemoteUrl = normalizeOptionalString(cfg.gateway?.remote?.url);
|
||||
const remoteUrl = configuredRemoteUrl ? normalizeUrl(configuredRemoteUrl, scheme) : null;
|
||||
if (configuredRemoteUrl && !remoteUrl) {
|
||||
return { error: "Configured gateway.remote.url is invalid." };
|
||||
}
|
||||
|
||||
const tailscaleMode = cfg.gateway?.tailscale?.mode ?? "off";
|
||||
if (tailscaleMode === "serve" || tailscaleMode === "funnel") {
|
||||
const host = await resolveTailnetHost();
|
||||
@@ -330,12 +336,8 @@ async function resolveGatewayUrl(api: OpenClawPluginApi): Promise<ResolveUrlResu
|
||||
return { url: `wss://${host}`, source: `gateway.tailscale.mode=${tailscaleMode}` };
|
||||
}
|
||||
|
||||
const remoteUrl = normalizeOptionalString(cfg.gateway?.remote?.url);
|
||||
if (remoteUrl) {
|
||||
const url = normalizeUrl(remoteUrl, scheme);
|
||||
if (url) {
|
||||
return { url, source: "gateway.remote.url" };
|
||||
}
|
||||
return { url: remoteUrl, source: "gateway.remote.url" };
|
||||
}
|
||||
|
||||
const bindResult = resolveGatewayBindUrl({
|
||||
|
||||
Reference in New Issue
Block a user