mirror of
https://github.com/iamlukethedev/Claw3D.git
synced 2026-07-30 03:02:37 +00:00
fix(security): preserve stored token through empty-token UI state; handle non-JSON health responses
GatewayClient.ts — autosave effects no longer overwrite persisted gateway tokens with empty strings. When the in-memory token is empty (proxy handles auth server-side), the patch omits the token field (undefined) so mergeGatewaySettings/mergeGatewayProfiles treats it as "leave unchanged". adapterProfiles updater also preserves the existing stored token when the new token is empty, preventing floor-switch from erasing tokens. runtime/custom/http.ts — requestCustomRuntime() checks the response Content-Type before calling response.json(). Non-JSON responses (e.g. plain-text /health "OK") are returned as-is instead of throwing a JSON parse error, making the custom/local/claw3d health probe path reliable for runtimes that return plain text. Authored By: GSKNNFT
This commit is contained in:
@@ -1048,11 +1048,12 @@ export const useGatewayConnection = (
|
||||
useEffect(() => {
|
||||
if (!settingsLoaded) return;
|
||||
setAdapterProfiles((current) => {
|
||||
const nextProfile = {
|
||||
url: gatewayUrl.trim(),
|
||||
token,
|
||||
};
|
||||
const existing = current[selectedAdapterType];
|
||||
// Never overwrite a stored token with an empty string — the Studio proxy
|
||||
// injects the real token server-side; an empty token in UI state means
|
||||
// "let the proxy handle it", not "clear the saved token".
|
||||
const nextToken = token || existing?.token || "";
|
||||
const nextProfile = { url: gatewayUrl.trim(), token: nextToken };
|
||||
if (
|
||||
existing &&
|
||||
existing.url === nextProfile.url &&
|
||||
@@ -1072,11 +1073,15 @@ export const useGatewayConnection = (
|
||||
const baseline = loadedGatewaySettings.current;
|
||||
if (!baseline) return;
|
||||
const nextGatewayUrl = gatewayUrl.trim();
|
||||
// Use undefined for the token in the patch when the in-memory token is empty so
|
||||
// that mergeGatewaySettings / mergeGatewayProfiles treats it as "leave unchanged"
|
||||
// rather than overwriting the persisted token with an empty string.
|
||||
const persistToken = token || undefined;
|
||||
const nextProfiles = {
|
||||
...adapterProfiles,
|
||||
[selectedAdapterType]: {
|
||||
url: nextGatewayUrl,
|
||||
token,
|
||||
token: persistToken,
|
||||
},
|
||||
};
|
||||
if (
|
||||
@@ -1091,7 +1096,7 @@ export const useGatewayConnection = (
|
||||
{
|
||||
gateway: {
|
||||
url: nextGatewayUrl,
|
||||
token,
|
||||
token: persistToken,
|
||||
adapterType: selectedAdapterType,
|
||||
profiles: nextProfiles,
|
||||
},
|
||||
|
||||
@@ -54,6 +54,11 @@ export async function requestCustomRuntime<T = unknown>({
|
||||
text.trim() || `Custom runtime request failed (${response.status}) for ${pathname}.`
|
||||
);
|
||||
}
|
||||
const contentType = response.headers.get("content-type") ?? "";
|
||||
if (!contentType.includes("application/json")) {
|
||||
// Non-JSON success response (e.g. plain-text /health "OK") — return as-is.
|
||||
return (await response.text()) as unknown as T;
|
||||
}
|
||||
return (await response.json()) as T;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user