mirror of
https://github.com/gethomepage/homepage.git
synced 2026-08-31 01:15:53 -07:00
Chore: simplify sanitizeErrorURL
This commit is contained in:
@@ -69,11 +69,5 @@ export function jsonArrayFilter(data, filter) {
|
||||
}
|
||||
|
||||
export function sanitizeErrorURL(errorURL) {
|
||||
// Dont display sensitive params on frontend
|
||||
const url = new URL(errorURL);
|
||||
["apikey", "api_key", "token", "t", "access_token", "auth"].forEach((key) => {
|
||||
if (url.searchParams.has(key)) url.searchParams.set(key, "***");
|
||||
if (url.hash.includes(key)) url.hash = url.hash.replace(new RegExp(`${key}=[^&]+`), `${key}=***`);
|
||||
});
|
||||
return url.toString();
|
||||
return `${new URL(errorURL).hostname} (see logs for details)`;
|
||||
}
|
||||
|
||||
@@ -83,25 +83,14 @@ describe("utils/proxy/api-helpers", () => {
|
||||
expect(jsonArrayFilter(data, (item) => item.a > 1)).toEqual([{ a: 2 }]);
|
||||
});
|
||||
|
||||
it("sanitizeErrorURL redacts sensitive query params and hash fragments", () => {
|
||||
const input = "https://example.com/path?apikey=123&token=abc#access_token=xyz&other=1";
|
||||
const output = sanitizeErrorURL(input);
|
||||
|
||||
const url = new URL(output);
|
||||
expect(url.searchParams.get("apikey")).toBe("***");
|
||||
expect(url.searchParams.get("token")).toBe("***");
|
||||
expect(url.hash).toContain("access_token=***");
|
||||
expect(url.hash).toContain("other=1");
|
||||
it("sanitizeErrorURL returns only the hostname regardless of where credentials appear", () => {
|
||||
const input = "https://user:pass@example.com/secret-path-key/status?custom_secret=abc#token=xyz";
|
||||
expect(sanitizeErrorURL(input)).toBe("example.com (see logs for details)");
|
||||
});
|
||||
|
||||
it("sanitizeErrorURL only redacts known keys", () => {
|
||||
const input = "https://example.com/path?api_key=123&safe=ok#auth=abc&safe_hash=1";
|
||||
const output = sanitizeErrorURL(input);
|
||||
|
||||
const url = new URL(output);
|
||||
expect(url.searchParams.get("api_key")).toBe("***");
|
||||
expect(url.searchParams.get("safe")).toBe("ok");
|
||||
expect(url.hash).toContain("auth=***");
|
||||
expect(url.hash).toContain("safe_hash=1");
|
||||
it("sanitizeErrorURL accepts URL objects and omits the port", () => {
|
||||
expect(sanitizeErrorURL(new URL("http://192.168.1.10:8080/api?apikey=123"))).toBe(
|
||||
"192.168.1.10 (see logs for details)",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -263,7 +263,7 @@ describe("utils/proxy/handlers/credentialed", () => {
|
||||
expect(res.body).toEqual({
|
||||
error: {
|
||||
message: "HTTP Error",
|
||||
url: "http://x/api/statistics",
|
||||
url: "x (see logs for details)",
|
||||
data: { detail: "Invalid token." },
|
||||
},
|
||||
});
|
||||
@@ -414,7 +414,7 @@ describe("utils/proxy/handlers/credentialed", () => {
|
||||
expect(params.headers["X-Finnhub-Token"]).toBe("finnhub-token");
|
||||
});
|
||||
|
||||
it("sanitizes embedded query params when a downstream error contains a url", async () => {
|
||||
it("replaces embedded error urls with the hostname when a downstream error contains a url", async () => {
|
||||
getServiceWidget.mockResolvedValue({ type: "linkwarden", url: "http://example", key: "token" });
|
||||
httpProxy.mockResolvedValue([500, "application/json", { error: { message: "oops", url: "http://bad" } }]);
|
||||
|
||||
@@ -424,7 +424,7 @@ describe("utils/proxy/handlers/credentialed", () => {
|
||||
await credentialedProxyHandler(req, res);
|
||||
|
||||
expect(res.statusCode).toBe(500);
|
||||
expect(res.body.error.url).toContain("apikey=***");
|
||||
expect(res.body.error.url).toBe("example (see logs for details)");
|
||||
});
|
||||
|
||||
it("ends the response for 204/304 statuses", async () => {
|
||||
@@ -451,7 +451,7 @@ describe("utils/proxy/handlers/credentialed", () => {
|
||||
|
||||
expect(res.statusCode).toBe(500);
|
||||
expect(res.body.error.message).toBe("Invalid data");
|
||||
expect(res.body.error.url).toContain("http://example/api/v1/collections");
|
||||
expect(res.body.error.url).toBe("example (see logs for details)");
|
||||
});
|
||||
|
||||
it("applies the response mapping function when provided", async () => {
|
||||
|
||||
@@ -151,7 +151,7 @@ describe("utils/proxy/handlers/generic", () => {
|
||||
await genericProxyHandler(req, res);
|
||||
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.body.error.url).toContain("apikey=***");
|
||||
expect(res.body.error.url).toBe("example (see logs for details)");
|
||||
});
|
||||
|
||||
it("returns an Invalid data error when validation fails", async () => {
|
||||
@@ -223,7 +223,7 @@ describe("utils/proxy/handlers/generic", () => {
|
||||
|
||||
expect(res.statusCode).toBe(500);
|
||||
expect(res.body.error.message).toBe("HTTP Error");
|
||||
expect(res.body.error.url).toContain("apikey=***");
|
||||
expect(res.body.error.url).toBe("example (see logs for details)");
|
||||
expect(res.body.error.data).toBe("fail");
|
||||
});
|
||||
|
||||
|
||||
@@ -436,6 +436,6 @@ describe("utils/proxy/http httpProxy", () => {
|
||||
expect(status).toBe(500);
|
||||
expect(contentType).toBe("application/json");
|
||||
expect(data.error.message).toBe("boom");
|
||||
expect(data.error.url).toContain("apikey=***");
|
||||
expect(data.error.url).toBe("example.com (see logs for details)");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -77,7 +77,7 @@ describe("widgets/dockhand/proxy", () => {
|
||||
|
||||
expect(res.statusCode).toBe(500);
|
||||
expect(res.body.error.message).toBe("HTTP Error");
|
||||
expect(res.body.error.url).toContain("token=***");
|
||||
expect(res.body.error.url).toBe("dockhand (see logs for details)");
|
||||
});
|
||||
|
||||
it("supports token auth", async () => {
|
||||
|
||||
@@ -47,7 +47,14 @@ export default async function frigateProxyHandler(req, res, map) {
|
||||
});
|
||||
|
||||
if (loginStatus !== 200) {
|
||||
logger.error("HTTP Error %d calling %s", loginStatus, sanitizeErrorURL(loginUrl));
|
||||
const errorURL = new URL(loginUrl);
|
||||
logger.error(
|
||||
"HTTP Error %d calling %s//%s%s...",
|
||||
loginStatus,
|
||||
errorURL.protocol,
|
||||
errorURL.host,
|
||||
errorURL.pathname,
|
||||
);
|
||||
return res.status(status).json({
|
||||
error: {
|
||||
message: `HTTP Error ${status} while trying to login to Frigate`,
|
||||
@@ -63,7 +70,8 @@ export default async function frigateProxyHandler(req, res, map) {
|
||||
}
|
||||
|
||||
if (status >= 400) {
|
||||
logger.error("HTTP Error %d calling %s", status, sanitizeErrorURL(url));
|
||||
const errorURL = new URL(url);
|
||||
logger.error("HTTP Error %d calling %s//%s%s...", status, errorURL.protocol, errorURL.host, errorURL.pathname);
|
||||
return res.status(status).json({
|
||||
error: {
|
||||
message: `HTTP Error ${status} from Frigate`,
|
||||
|
||||
@@ -99,7 +99,7 @@ describe("widgets/frigate/proxy", () => {
|
||||
expect.objectContaining({
|
||||
error: expect.objectContaining({
|
||||
message: "HTTP Error 401 from Frigate",
|
||||
url: "http://frigate/api/stats",
|
||||
url: "frigate (see logs for details)",
|
||||
}),
|
||||
}),
|
||||
);
|
||||
@@ -162,7 +162,7 @@ describe("widgets/frigate/proxy", () => {
|
||||
expect.objectContaining({
|
||||
error: expect.objectContaining({
|
||||
message: "HTTP Error 401 while trying to login to Frigate",
|
||||
url: "http://frigate/api/stats",
|
||||
url: "frigate (see logs for details)",
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -34,7 +34,8 @@ export default async function komodoProxyHandler(req, res) {
|
||||
let resultData = data;
|
||||
|
||||
if (status >= 400) {
|
||||
logger.error("HTTP Error %d calling %s", status, sanitizeErrorURL(url));
|
||||
const errorURL = new URL(url);
|
||||
logger.error("HTTP Error %d calling %s//%s%s...", status, errorURL.protocol, errorURL.host, errorURL.pathname);
|
||||
}
|
||||
|
||||
if (status === 200) {
|
||||
|
||||
Reference in New Issue
Block a user