fix: clarify control ui auth hints (fixes #1690)
This commit is contained in:
@@ -34,6 +34,7 @@ Docs: https://docs.clawd.bot
|
|||||||
- Models: default missing custom provider fields so minimal configs are accepted.
|
- Models: default missing custom provider fields so minimal configs are accepted.
|
||||||
- Gateway: skip Tailscale DNS probing when tailscale.mode is off. (#1671)
|
- Gateway: skip Tailscale DNS probing when tailscale.mode is off. (#1671)
|
||||||
- Gateway: reduce log noise for late invokes + remote node probes; debounce skills refresh. (#1607) Thanks @petter-b.
|
- Gateway: reduce log noise for late invokes + remote node probes; debounce skills refresh. (#1607) Thanks @petter-b.
|
||||||
|
- Gateway: clarify Control UI/WebChat auth error hints for missing tokens. (#1690)
|
||||||
- macOS: default direct-transport `ws://` URLs to port 18789; document `gateway.remote.transport`. (#1603) Thanks @ngutman.
|
- macOS: default direct-transport `ws://` URLs to port 18789; document `gateway.remote.transport`. (#1603) Thanks @ngutman.
|
||||||
- Voice Call: return stream TwiML for outbound conversation calls on initial Twilio webhook. (#1634)
|
- Voice Call: return stream TwiML for outbound conversation calls on initial Twilio webhook. (#1634)
|
||||||
- Google Chat: tighten email allowlist matching, typing cleanup, media caps, and onboarding/docs/tests. (#1635) Thanks @iHildy.
|
- Google Chat: tighten email allowlist matching, typing cleanup, media caps, and onboarding/docs/tests. (#1635) Thanks @iHildy.
|
||||||
|
|||||||
@@ -230,6 +230,21 @@ describe("gateway server auth/connect", () => {
|
|||||||
ws.close();
|
ws.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("returns control ui hint when token is missing", async () => {
|
||||||
|
const ws = await openWs(port);
|
||||||
|
const res = await connectReq(ws, {
|
||||||
|
client: {
|
||||||
|
id: GATEWAY_CLIENT_NAMES.CONTROL_UI,
|
||||||
|
version: "1.0.0",
|
||||||
|
platform: "web",
|
||||||
|
mode: GATEWAY_CLIENT_MODES.WEBCHAT,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.ok).toBe(false);
|
||||||
|
expect(res.error?.message ?? "").toContain("Control UI settings");
|
||||||
|
ws.close();
|
||||||
|
});
|
||||||
|
|
||||||
test("rejects control ui without device identity by default", async () => {
|
test("rejects control ui without device identity by default", async () => {
|
||||||
const ws = await openWs(port);
|
const ws = await openWs(port);
|
||||||
const res = await connectReq(ws, {
|
const res = await connectReq(ws, {
|
||||||
|
|||||||
@@ -66,19 +66,34 @@ function formatGatewayAuthFailureMessage(params: {
|
|||||||
authMode: ResolvedGatewayAuth["mode"];
|
authMode: ResolvedGatewayAuth["mode"];
|
||||||
authProvided: AuthProvidedKind;
|
authProvided: AuthProvidedKind;
|
||||||
reason?: string;
|
reason?: string;
|
||||||
|
client?: { id?: string | null; mode?: string | null };
|
||||||
}): string {
|
}): string {
|
||||||
const { authMode, authProvided, reason } = params;
|
const { authMode, authProvided, reason, client } = params;
|
||||||
|
const isCli = isGatewayCliClient(client);
|
||||||
|
const isControlUi = client?.id === GATEWAY_CLIENT_IDS.CONTROL_UI;
|
||||||
|
const isWebchat = isWebchatClient(client);
|
||||||
|
const uiHint = "open a tokenized dashboard URL or paste token in Control UI settings";
|
||||||
|
const tokenHint = isCli
|
||||||
|
? "set gateway.remote.token to match gateway.auth.token"
|
||||||
|
: isControlUi || isWebchat
|
||||||
|
? uiHint
|
||||||
|
: "provide gateway auth token";
|
||||||
|
const passwordHint = isCli
|
||||||
|
? "set gateway.remote.password to match gateway.auth.password"
|
||||||
|
: isControlUi || isWebchat
|
||||||
|
? "enter the password in Control UI settings"
|
||||||
|
: "provide gateway auth password";
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
case "token_missing":
|
case "token_missing":
|
||||||
return "unauthorized: gateway token missing (set gateway.remote.token to match gateway.auth.token)";
|
return `unauthorized: gateway token missing (${tokenHint})`;
|
||||||
case "token_mismatch":
|
case "token_mismatch":
|
||||||
return "unauthorized: gateway token mismatch (set gateway.remote.token to match gateway.auth.token)";
|
return `unauthorized: gateway token mismatch (${tokenHint})`;
|
||||||
case "token_missing_config":
|
case "token_missing_config":
|
||||||
return "unauthorized: gateway token not configured on gateway (set gateway.auth.token)";
|
return "unauthorized: gateway token not configured on gateway (set gateway.auth.token)";
|
||||||
case "password_missing":
|
case "password_missing":
|
||||||
return "unauthorized: gateway password missing (set gateway.remote.password to match gateway.auth.password)";
|
return `unauthorized: gateway password missing (${passwordHint})`;
|
||||||
case "password_mismatch":
|
case "password_mismatch":
|
||||||
return "unauthorized: gateway password mismatch (set gateway.remote.password to match gateway.auth.password)";
|
return `unauthorized: gateway password mismatch (${passwordHint})`;
|
||||||
case "password_missing_config":
|
case "password_missing_config":
|
||||||
return "unauthorized: gateway password not configured on gateway (set gateway.auth.password)";
|
return "unauthorized: gateway password not configured on gateway (set gateway.auth.password)";
|
||||||
case "tailscale_user_missing":
|
case "tailscale_user_missing":
|
||||||
@@ -90,10 +105,10 @@ function formatGatewayAuthFailureMessage(params: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (authMode === "token" && authProvided === "none") {
|
if (authMode === "token" && authProvided === "none") {
|
||||||
return "unauthorized: gateway token missing (set gateway.remote.token to match gateway.auth.token)";
|
return `unauthorized: gateway token missing (${tokenHint})`;
|
||||||
}
|
}
|
||||||
if (authMode === "password" && authProvided === "none") {
|
if (authMode === "password" && authProvided === "none") {
|
||||||
return "unauthorized: gateway password missing (set gateway.remote.password to match gateway.auth.password)";
|
return `unauthorized: gateway password missing (${passwordHint})`;
|
||||||
}
|
}
|
||||||
return "unauthorized";
|
return "unauthorized";
|
||||||
}
|
}
|
||||||
@@ -532,6 +547,7 @@ export function attachGatewayWsMessageHandler(params: {
|
|||||||
authMode: resolvedAuth.mode,
|
authMode: resolvedAuth.mode,
|
||||||
authProvided,
|
authProvided,
|
||||||
reason: authResult.reason,
|
reason: authResult.reason,
|
||||||
|
client: connectParams.client,
|
||||||
});
|
});
|
||||||
setCloseCause("unauthorized", {
|
setCloseCause("unauthorized", {
|
||||||
authMode: resolvedAuth.mode,
|
authMode: resolvedAuth.mode,
|
||||||
|
|||||||
Reference in New Issue
Block a user