import type { Dispatcher } from "undici"; import { describe, expect, test, vi } from "vitest"; import { logger } from "@homarr/log"; import { LoggingAgent } from "../fetch-agent"; vi.mock("undici", () => { return { Agent: class Agent { dispatch(_options: Dispatcher.DispatchOptions, _handler: Dispatcher.DispatchHandler): boolean { return true; } }, setGlobalDispatcher: () => undefined, }; }); const REDACTED = "REDACTED"; describe("LoggingAgent should log all requests", () => { test("should log all requests", () => { // Arrange const infoLogSpy = vi.spyOn(logger, "debug"); const agent = new LoggingAgent(); // Act agent.dispatch({ origin: "https://homarr.dev", path: "/", method: "GET" }, {}); // Assert expect(infoLogSpy).toHaveBeenCalledWith("Dispatching request https://homarr.dev/ (0 headers)"); }); test("should show amount of headers", () => { // Arrange const infoLogSpy = vi.spyOn(logger, "debug"); const agent = new LoggingAgent(); // Act agent.dispatch( { origin: "https://homarr.dev", path: "/", method: "GET", headers: { "Content-Type": "text/html", "User-Agent": "Mozilla/5.0", }, }, {}, ); // Assert expect(infoLogSpy).toHaveBeenCalledWith(expect.stringContaining("(2 headers)")); }); test.each([ ["/?hex=a3815e8ada2ef9a31", `/?hex=${REDACTED}`], ["/?uuid=f7c3f65e-c511-4f90-ba9a-3fd31418bd49", `/?uuid=${REDACTED}`], ["/?password=complexPassword123", `/?password=${REDACTED}`], [ // JWT for John Doe "/?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c", `/?jwt=${REDACTED}`, ], ["/?one=a1&two=b2&three=c3", `/?one=${REDACTED}&two=${REDACTED}&three=${REDACTED}`], ["/?numberWith13Chars=1234567890123", `/?numberWith13Chars=${REDACTED}`], [`/?stringWith13Chars=${"a".repeat(13)}`, `/?stringWith13Chars=${REDACTED}`], ])("should redact sensitive data in url https://homarr.dev%s", (path, expected) => { // Arrange const infoLogSpy = vi.spyOn(logger, "debug"); const agent = new LoggingAgent(); // Act agent.dispatch({ origin: "https://homarr.dev", path, method: "GET" }, {}); // Assert expect(infoLogSpy).toHaveBeenCalledWith(expect.stringContaining(` https://homarr.dev${expected} `)); }); test.each([ ["empty", "/?empty"], ["numbers with max 12 chars", "/?number=123456789012"], ["true", "/?true=true"], ["false", "/?false=false"], ["strings with max 12 chars", `/?short=${"a".repeat(12)}`], ["dates", "/?date=2022-01-01"], ["date times", "/?datetime=2022-01-01T00:00:00.000Z"], ])("should not redact values that are %s", (_reason, path) => { // Arrange const infoLogSpy = vi.spyOn(logger, "debug"); const agent = new LoggingAgent(); // Act agent.dispatch({ origin: "https://homarr.dev", path, method: "GET" }, {}); // Assert expect(infoLogSpy).toHaveBeenCalledWith(expect.stringContaining(` https://homarr.dev${path} `)); }); });