Files
HiveGrid-Wireframes/hivegrid-cloud/apps/web/app/services/auth/sessionLifecycle.server.test.ts
T

64 lines
2.7 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from "vitest";
const storeMock = vi.hoisted(() => ({
createUserSession: vi.fn(),
revokeSessionByToken: vi.fn(),
}));
vi.mock("./sessionStore.server", () => ({
createUserSession: (...args: unknown[]) => storeMock.createUserSession(...args),
revokeSessionByToken: (...args: unknown[]) => storeMock.revokeSessionByToken(...args),
}));
const geoMock = vi.hoisted(() => ({ lookupCountry: vi.fn() }));
vi.mock("~/modules/ipAddress/services/geoip.server", () => ({
// Realistischer Mock: der Hash enthaelt die Roh-IP NICHT (wie der echte hashIp).
hashIp: () => "HASHED",
lookupCountry: (...args: unknown[]) => geoMock.lookupCountry(...args),
}));
import { buildSessionDeviceContext, endServerSession, startServerSession } from "./sessionLifecycle.server";
function requestWith(headers: Record<string, string>) {
return new Request("https://example.test/login", { headers });
}
beforeEach(() => {
vi.clearAllMocks();
geoMock.lookupCountry.mockResolvedValue({ countryCode: "DE", countryName: "Germany" });
});
describe("buildSessionDeviceContext (AD-22)", () => {
it("hashes the IP and resolves the country, never exposing the raw IP", async () => {
const ctx = await buildSessionDeviceContext(requestWith({ "user-agent": "Safari", "x-forwarded-for": "9.9.9.9" }));
expect(ctx.ipHash).toBe("HASHED");
expect(ctx.userAgent).toBe("Safari");
expect(ctx.approxLocation).toBe("Germany");
expect(JSON.stringify(ctx)).not.toContain("9.9.9.9");
});
it("yields nulls and skips the geo lookup when no IP is present", async () => {
const ctx = await buildSessionDeviceContext(requestWith({}));
expect(ctx.ipHash).toBeNull();
expect(ctx.userAgent).toBeNull();
expect(ctx.approxLocation).toBeNull();
expect(geoMock.lookupCountry).not.toHaveBeenCalled();
});
});
describe("startServerSession", () => {
it("creates a session row with the pseudonymized device context and returns the raw token", async () => {
storeMock.createUserSession.mockResolvedValue({ session: { id: "s1" }, rawToken: "tok-123" });
const token = await startServerSession({ request: requestWith({ "user-agent": "Safari", "x-forwarded-for": "1.2.3.4" }), userId: "u1" });
expect(token).toBe("tok-123");
expect(storeMock.createUserSession).toHaveBeenCalledWith({ userId: "u1", ipHash: "HASHED", userAgent: "Safari", approxLocation: "Germany" });
});
});
describe("endServerSession", () => {
it("delegates revocation to the store", async () => {
storeMock.revokeSessionByToken.mockResolvedValue(true);
await endServerSession("tok-123");
expect(storeMock.revokeSessionByToken).toHaveBeenCalledWith("tok-123");
});
});