mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-15 15:13:48 -06:00
fix(signal): validate managed connection ownership
This commit is contained in:
@@ -315,26 +315,58 @@ describe("probeManagedSignalSetup", () => {
|
||||
expect(mocks.spawnDaemon).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("probes a separate connection URL with selected-account verification", async () => {
|
||||
it("requires a separate connection URL to become healthy with the managed daemon", async () => {
|
||||
const candidate = { ...transport, url: "https://signal.example:9443" };
|
||||
await probeManagedSignalSetup(
|
||||
createParams(
|
||||
{
|
||||
channels: {
|
||||
signal: {
|
||||
accounts: {
|
||||
work: { account, transport: candidate },
|
||||
},
|
||||
},
|
||||
const cfg = {
|
||||
channels: {
|
||||
signal: {
|
||||
accounts: {
|
||||
work: { account, transport: candidate },
|
||||
},
|
||||
},
|
||||
candidate,
|
||||
),
|
||||
);
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
mocks.probeTransport
|
||||
.mockResolvedValueOnce({ ok: false, error: "connection refused" })
|
||||
.mockResolvedValueOnce({ ok: true, status: 200 })
|
||||
.mockResolvedValueOnce({ ok: true, status: 200 });
|
||||
|
||||
await expect(probeManagedSignalSetup(createParams(cfg, candidate))).resolves.toMatchObject({
|
||||
ok: true,
|
||||
});
|
||||
|
||||
expect(mocks.probeTransport).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
expect.not.objectContaining({ nativeAccountBinding: "owner-known-bound-account" }),
|
||||
);
|
||||
expect(mocks.probeTransport).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
expect.objectContaining({ nativeAccountBinding: "owner-known-bound-account" }),
|
||||
);
|
||||
expect(mocks.probeTransport).toHaveBeenNthCalledWith(
|
||||
3,
|
||||
expect.not.objectContaining({ nativeAccountBinding: "owner-known-bound-account" }),
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects a separate connection URL already served by an independent daemon", async () => {
|
||||
const candidate = { ...transport, url: "https://signal.example:9443" };
|
||||
const cfg = {
|
||||
channels: {
|
||||
signal: {
|
||||
accounts: {
|
||||
work: { account, transport: candidate },
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
await expect(probeManagedSignalSetup(createParams(cfg, candidate))).resolves.toMatchObject({
|
||||
ok: false,
|
||||
error: expect.stringContaining("external-native"),
|
||||
});
|
||||
|
||||
expect(mocks.probeTransport).toHaveBeenCalledOnce();
|
||||
expect(mocks.spawnDaemon).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -79,6 +79,18 @@ async function probeManagedBind(params: {
|
||||
return result;
|
||||
}
|
||||
|
||||
function hasSeparateConnectionUrl(params: {
|
||||
transport: SignalManagedNativeTransport;
|
||||
resolved: ResolvedManagedSignalTransport;
|
||||
}): boolean {
|
||||
return !isSignalManagedNativeConnectionUrlForBind({
|
||||
...params.transport,
|
||||
url: params.resolved.baseUrl,
|
||||
httpHost: params.resolved.httpHost,
|
||||
httpPort: params.resolved.httpPort,
|
||||
});
|
||||
}
|
||||
|
||||
async function probeSeparateConnectionUrl(params: {
|
||||
cfg: OpenClawConfig;
|
||||
accountId: string;
|
||||
@@ -88,14 +100,7 @@ async function probeSeparateConnectionUrl(params: {
|
||||
abortSignal?: AbortSignal;
|
||||
}): Promise<SignalTransportProbeResult> {
|
||||
params.abortSignal?.throwIfAborted();
|
||||
if (
|
||||
isSignalManagedNativeConnectionUrlForBind({
|
||||
...params.transport,
|
||||
url: params.resolved.baseUrl,
|
||||
httpHost: params.resolved.httpHost,
|
||||
httpPort: params.resolved.httpPort,
|
||||
})
|
||||
) {
|
||||
if (!hasSeparateConnectionUrl(params)) {
|
||||
return { ok: true, status: 200, error: null };
|
||||
}
|
||||
const result = await probeSignalTransport({
|
||||
@@ -169,6 +174,16 @@ export async function probeManagedSignalSetup(params: {
|
||||
httpHost: resolved.httpHost,
|
||||
httpPort: resolved.httpPort,
|
||||
});
|
||||
if (hasSeparateConnectionUrl({ ...params, resolved })) {
|
||||
const preexistingConnection = await probeSeparateConnectionUrl({ ...params, resolved });
|
||||
if (preexistingConnection.ok) {
|
||||
return {
|
||||
ok: false,
|
||||
error:
|
||||
"Signal managed connection URL was already serving the selected account before OpenClaw started its daemon. Use external-native for an independently operated Signal server.",
|
||||
};
|
||||
}
|
||||
}
|
||||
params.abortSignal?.throwIfAborted();
|
||||
const spawnedDaemon = spawnSignalDaemon({
|
||||
cliPath: resolved.cliPath,
|
||||
|
||||
Reference in New Issue
Block a user