import type { Context } from "@yaakapp/api"; import { beforeEach, describe, expect, test, vi } from "vite-plus/test"; const ntlmMock = vi.hoisted(() => ({ createType1Message: vi.fn(), parseType2Message: vi.fn(), createType3Message: vi.fn(), })); vi.mock("httpntlm", () => ({ ntlm: ntlmMock })); import { plugin } from "../src"; describe("auth-ntlm", () => { beforeEach(() => { ntlmMock.createType1Message.mockReset(); ntlmMock.parseType2Message.mockReset(); ntlmMock.createType3Message.mockReset(); ntlmMock.createType1Message.mockReturnValue("NTLM TYPE1"); // oxlint-disable-next-line no-explicit-any ntlmMock.parseType2Message.mockReturnValue({} as any); ntlmMock.createType3Message.mockReturnValue("NTLM TYPE3"); }); test("uses NTLM challenge when Negotiate and NTLM headers are separate", async () => { const send = vi.fn().mockResolvedValue({ headers: [ { name: "WWW-Authenticate", value: "Negotiate" }, { name: "WWW-Authenticate", value: "NTLM TlRMTVNTUAACAAAAAA==" }, ], }); const ctx = { httpRequest: { send } } as unknown as Context; const result = await plugin.authentication?.onApply(ctx, { values: {}, headers: [], url: "https://example.local/resource", method: "GET", contextId: "ctx", }); expect(ntlmMock.parseType2Message).toHaveBeenCalledWith( "NTLM TlRMTVNTUAACAAAAAA==", expect.any(Function), ); expect(result).toEqual({ setHeaders: [{ name: "Authorization", value: "NTLM TYPE3" }] }); }); test("uses NTLM challenge when auth schemes are comma-separated in one header", async () => { const send = vi.fn().mockResolvedValue({ headers: [{ name: "www-authenticate", value: "Negotiate, NTLM TlRMTVNTUAACAAAAAA==" }], }); const ctx = { httpRequest: { send } } as unknown as Context; await plugin.authentication?.onApply(ctx, { values: {}, headers: [], url: "https://example.local/resource", method: "GET", contextId: "ctx", }); expect(ntlmMock.parseType2Message).toHaveBeenCalledWith( "NTLM TlRMTVNTUAACAAAAAA==", expect.any(Function), ); }); test("throws a clear error when NTLM challenge is missing", async () => { const send = vi.fn().mockResolvedValue({ headers: [{ name: "WWW-Authenticate", value: "Negotiate" }], }); const ctx = { httpRequest: { send } } as unknown as Context; await expect( plugin.authentication?.onApply(ctx, { values: {}, headers: [], url: "https://example.local/resource", method: "GET", contextId: "ctx", }), ).rejects.toThrow("Unable to find NTLM challenge in WWW-Authenticate response headers"); }); });