mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 12:56:01 -06:00
fix(browser): decode CDP URL credentials
This commit is contained in:
@@ -199,6 +199,13 @@ describe("cdp.helpers", () => {
|
||||
expect(headers.Authorization).toBe(`Basic ${Buffer.from("user:pass").toString("base64")}`);
|
||||
});
|
||||
|
||||
it("decodes percent-encoded basic auth credentials from URLs", () => {
|
||||
const headers = getHeadersWithAuth("https://alice:p%40ss%20word@example.com");
|
||||
expect(headers.Authorization).toBe(
|
||||
`Basic ${Buffer.from("alice:p@ss word").toString("base64")}`,
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps preexisting authorization headers", () => {
|
||||
const headers = getHeadersWithAuth("https://user:pass@example.com", {
|
||||
Authorization: "Bearer token",
|
||||
|
||||
@@ -146,6 +146,28 @@ describe("cdp helpers", () => {
|
||||
expect(release).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("decodes URL credentials before sending guarded CDP auth headers", async () => {
|
||||
const release = vi.fn(async () => {});
|
||||
fetchWithSsrFGuardMock.mockResolvedValueOnce({
|
||||
response: {
|
||||
ok: true,
|
||||
status: 200,
|
||||
},
|
||||
release,
|
||||
});
|
||||
|
||||
await expect(
|
||||
fetchOk("http://alice:p%40ss%20word@127.0.0.1:9222/json/version", 250),
|
||||
).resolves.toBeUndefined();
|
||||
|
||||
const request = requireGuardedFetchRequest();
|
||||
expect(request?.url).toBe("http://127.0.0.1:9222/json/version");
|
||||
expect(request?.init?.headers).toEqual({
|
||||
Authorization: `Basic ${Buffer.from("alice:p@ss word").toString("base64")}`,
|
||||
});
|
||||
expect(release).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("preserves hostname allowlist while allowing exact loopback CDP fetches", async () => {
|
||||
const release = vi.fn(async () => {});
|
||||
fetchWithSsrFGuardMock.mockResolvedValueOnce({
|
||||
|
||||
@@ -113,6 +113,14 @@ export type CdpSendFn = (
|
||||
sessionId?: string,
|
||||
) => Promise<unknown>;
|
||||
|
||||
function decodeUrlUserInfo(value: string): string {
|
||||
try {
|
||||
return decodeURIComponent(value);
|
||||
} catch {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
function rawCdpMessageToString(data: WebSocket.RawData): string {
|
||||
if (typeof data === "string") {
|
||||
return data;
|
||||
@@ -141,7 +149,9 @@ export function getHeadersWithAuth(url: string, headers: Record<string, string>
|
||||
return mergedHeaders;
|
||||
}
|
||||
if (parsed.username || parsed.password) {
|
||||
const auth = Buffer.from(`${parsed.username}:${parsed.password}`).toString("base64");
|
||||
const username = decodeUrlUserInfo(parsed.username);
|
||||
const password = decodeUrlUserInfo(parsed.password);
|
||||
const auth = Buffer.from(`${username}:${password}`).toString("base64");
|
||||
return { ...mergedHeaders, Authorization: `Basic ${auth}` };
|
||||
}
|
||||
} catch {
|
||||
|
||||
Reference in New Issue
Block a user