84 lines
4.2 KiB
JavaScript
84 lines
4.2 KiB
JavaScript
import { afterEach, describe, expect, mock, spyOn, test } from "bun:test";
|
|
import { localDevelopmentAuth } from "./local-dev-auth.ts";
|
|
|
|
const originalProfile = process.env.EDGE_EVER_DEVELOPMENT_PROFILE;
|
|
const originalAutoLogin = process.env.EDGE_EVER_LOCAL_AUTO_LOGIN;
|
|
afterEach(() => {
|
|
if (originalProfile === undefined) delete process.env.EDGE_EVER_DEVELOPMENT_PROFILE;
|
|
else process.env.EDGE_EVER_DEVELOPMENT_PROFILE = originalProfile;
|
|
if (originalAutoLogin === undefined) delete process.env.EDGE_EVER_LOCAL_AUTO_LOGIN;
|
|
else process.env.EDGE_EVER_LOCAL_AUTO_LOGIN = originalAutoLogin;
|
|
mock.restore();
|
|
});
|
|
const setup = (profile = "local", autoLogin = "true") => {
|
|
process.env.EDGE_EVER_DEVELOPMENT_PROFILE = profile;
|
|
process.env.EDGE_EVER_LOCAL_AUTO_LOGIN = autoLogin;
|
|
const handlers = [];
|
|
const provision = mock(async () => ({ token: "test-token", maxAge: 100 }));
|
|
const plugin = localDevelopmentAuth(provision);
|
|
plugin.configureServer({ middlewares: { use: (handler) => handlers.push(handler) } });
|
|
return { handler: handlers[0], provision, plugin };
|
|
};
|
|
const request = (headers = {}) => ({
|
|
url: "/api/v1/auth/session", method: "GET", headers: { host: "127.0.0.1:5173", ...headers },
|
|
});
|
|
const response = () => ({ setHeader: mock(), end: mock() });
|
|
|
|
describe("local browser auto-login boundary", () => {
|
|
test("is serve-only and absent from remote, demo, plain web and opt-out development", () => {
|
|
for (const profile of ["remote", "demo", ""]) expect(setup(profile).handler).toBeUndefined();
|
|
expect(setup("local", "false").handler).toBeUndefined();
|
|
expect(setup().plugin.apply).toBe("serve");
|
|
});
|
|
|
|
test("returns a validated real session with an HttpOnly cookie for a new browser", async () => {
|
|
const { handler, provision } = setup();
|
|
const fetchMock = spyOn(globalThis, "fetch")
|
|
.mockResolvedValueOnce(Response.json({ authRequired: true, authenticated: false }))
|
|
.mockResolvedValueOnce(Response.json({ authRequired: true, authenticated: true, user: { id: "usr_real" } }));
|
|
const res = response();
|
|
const next = mock();
|
|
await handler(request(), res, next);
|
|
expect(provision).toHaveBeenCalledTimes(1);
|
|
expect(fetchMock.mock.calls[1][1].headers).toEqual({ Authorization: "Bearer test-token" });
|
|
expect(res.setHeader).toHaveBeenCalledWith("Set-Cookie", expect.stringContaining("HttpOnly; SameSite=Lax"));
|
|
expect(JSON.parse(res.end.mock.calls[0][0]).user.id).toBe("usr_real");
|
|
expect(next).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test("does not replace an existing authenticated account", async () => {
|
|
const { handler, provision } = setup();
|
|
spyOn(globalThis, "fetch").mockResolvedValue(Response.json({ authRequired: true, authenticated: true }));
|
|
await handler(request({ cookie: "edgeever_session=existing" }), response(), mock());
|
|
expect(provision).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test("does not create sessions for foreign hosts or cross-site requests", async () => {
|
|
const { handler, provision } = setup();
|
|
const fetchMock = spyOn(globalThis, "fetch");
|
|
for (const headers of [{ host: "example.com" }, { origin: "https://example.com" }, { "sec-fetch-site": "cross-site" }]) {
|
|
const next = mock();
|
|
await handler(request(headers), response(), next);
|
|
expect(next).toHaveBeenCalled();
|
|
}
|
|
expect(fetchMock).not.toHaveBeenCalled();
|
|
expect(provision).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test("preserves logout cookies and leaves the login screen accessible afterwards", async () => {
|
|
const { handler, provision } = setup();
|
|
spyOn(globalThis, "fetch")
|
|
.mockResolvedValueOnce(Response.json({ ok: true }, { headers: { "Set-Cookie": "edgeever_session=; Max-Age=0" } }))
|
|
.mockResolvedValueOnce(Response.json({ authRequired: true, authenticated: false }));
|
|
const res = response();
|
|
await handler({ ...request(), url: "/api/v1/auth/logout", method: "POST" }, res, mock());
|
|
expect(res.setHeader).toHaveBeenCalledWith("Set-Cookie", [
|
|
"edgeever_session=; Max-Age=0", "edgeever_local_logged_out=1; Path=/; HttpOnly; SameSite=Lax",
|
|
]);
|
|
const next = mock();
|
|
await handler(request({ cookie: "edgeever_local_logged_out=1" }), response(), next);
|
|
expect(next).toHaveBeenCalled();
|
|
expect(provision).not.toHaveBeenCalled();
|
|
});
|
|
});
|