[Fix] Address review feedback on storage utility and Dockerfiles

- Dockerfile.health_check: HEALTHCHECK now verifies the script is intact
  instead of unconditionally exiting 0
- secureStorage.ts: replace deprecated escape/unescape with
  encodeURIComponent/decodeURIComponent; don't delete legacy values on
  decode failure so in-flight flows can time out naturally
- OAuth callback: add same-origin check before redirecting to stored
  return URL
This commit is contained in:
Yuneng Jiang 2026-04-08 17:51:34 -07:00
parent 4272d80c83
commit 464c98878e
No known key found for this signature in database
3 changed files with 26 additions and 10 deletions

View file

@ -18,7 +18,7 @@ USER appuser
# Health check
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
CMD ["python", "-c", "import sys; sys.exit(0)"]
CMD ["python", "/app/health_check_client.py", "--help"]
# Set entrypoint
ENTRYPOINT ["python", "/app/health_check_client.py"]

View file

@ -60,7 +60,17 @@ const McpOAuthCallbackContent = () => {
}
const returnUrl = getSecureItem(RETURN_URL_STORAGE_KEY);
const destination = returnUrl || resolveDefaultRedirect();
let destination = resolveDefaultRedirect();
if (returnUrl) {
try {
const parsed = new URL(returnUrl, window.location.origin);
if (parsed.origin === window.location.origin) {
destination = parsed.href;
}
} catch {
// invalid URL — fall through to default
}
}
window.location.replace(destination);
}, [payload]);

View file

@ -1,10 +1,20 @@
function encode(value: string): string {
// btoa cannot handle characters outside Latin-1, so we percent-encode first.
return btoa(unescape(encodeURIComponent(value)));
return btoa(
encodeURIComponent(value).replace(
/%([0-9A-F]{2})/g,
(_, p1) => String.fromCharCode(parseInt(p1, 16))
)
);
}
function decode(encoded: string): string {
return decodeURIComponent(escape(atob(encoded)));
return decodeURIComponent(
atob(encoded)
.split("")
.map((c) => "%" + c.charCodeAt(0).toString(16).padStart(2, "0"))
.join("")
);
}
export function setSecureItem(key: string, value: string): void {
@ -21,12 +31,8 @@ export function getSecureItem(key: string): string | null {
if (raw === null) return null;
return decode(raw);
} catch {
// Corrupted or non-encoded legacy value — clear it.
try {
window.sessionStorage.removeItem(key);
} catch {
// ignore
}
// Corrupted or non-encoded legacy value — return null without deleting
// so that in-flight flows (e.g. OAuth) can time out naturally.
return null;
}
}