import { beforeEach, describe, expect, test, vi } from "vitest"; import { isSafeRedirectUri } from "./client-utils"; describe("isSafeRedirectUri", () => { beforeEach(() => { vi.clearAllMocks(); }); test("should reject empty uri", async () => { expect(await isSafeRedirectUri("")).toBe(false); expect(await isSafeRedirectUri(undefined as unknown as string)).toBe(false); }); test("should allow relative paths", async () => { expect(await isSafeRedirectUri("/dashboard")).toBe(true); expect(await isSafeRedirectUri("/ui/console")).toBe(true); expect(await isSafeRedirectUri("/")).toBe(true); }); test("should reject protocol-relative paths", async () => { expect(await isSafeRedirectUri("//evil.com")).toBe(false); expect(await isSafeRedirectUri("\\\\evil.com")).toBe(false); }); test("should allow absolute URLs matching the current host", async () => { expect(await isSafeRedirectUri("https://my-zitadel.com/console")).toBe(true); }); test("should allow absolute URLs to external domains", async () => { expect(await isSafeRedirectUri("https://evil.com")).toBe(true); expect(await isSafeRedirectUri("https://settings.com/dashboard")).toBe(true); }); test("should reject non-http(s) protocols", async () => { expect(await isSafeRedirectUri("javascript:alert(1)")).toBe(false); expect(await isSafeRedirectUri("data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==")).toBe(false); expect(await isSafeRedirectUri("file:///etc/passwd")).toBe(false); }); test("should gracefully reject invalid, unparsable URLs that aren't relative", async () => { expect(await isSafeRedirectUri("not-a-valid-url")).toBe(false); expect(await isSafeRedirectUri("http://%")).toBe(false); }); });