fix(#411): remediate backend review findings — COOKIE_DOMAIN, TRUSTED_ORIGINS validation, verifySession
- Wire COOKIE_DOMAIN env var into BetterAuth cookie config - Add URL validation for TRUSTED_ORIGINS (rejects non-HTTP, invalid URLs) - Include original parse error in validateRedirectUri error message - Distinguish infrastructure errors from auth errors in verifySession (Prisma/connection errors now propagate as 500 instead of masking as 401) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,26 @@
|
||||
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
||||
import { Test, TestingModule } from "@nestjs/testing";
|
||||
|
||||
// Mock better-auth modules before importing AuthService
|
||||
vi.mock("better-auth/node", () => ({
|
||||
toNodeHandler: vi.fn().mockReturnValue(vi.fn()),
|
||||
}));
|
||||
|
||||
vi.mock("better-auth", () => ({
|
||||
betterAuth: vi.fn().mockReturnValue({
|
||||
handler: vi.fn(),
|
||||
api: { getSession: vi.fn() },
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("better-auth/adapters/prisma", () => ({
|
||||
prismaAdapter: vi.fn().mockReturnValue({}),
|
||||
}));
|
||||
|
||||
vi.mock("better-auth/plugins", () => ({
|
||||
genericOAuth: vi.fn().mockReturnValue({ id: "generic-oauth" }),
|
||||
}));
|
||||
|
||||
import { AuthService } from "./auth.service";
|
||||
import { PrismaService } from "../prisma/prisma.service";
|
||||
|
||||
@@ -294,7 +315,7 @@ describe("AuthService", () => {
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it("should return null and log error on verification failure", async () => {
|
||||
it("should return null and log warning on auth verification failure", async () => {
|
||||
const auth = service.getAuth();
|
||||
const mockGetSession = vi.fn().mockRejectedValue(new Error("Verification failed"));
|
||||
auth.api = { getSession: mockGetSession } as any;
|
||||
@@ -303,5 +324,38 @@ describe("AuthService", () => {
|
||||
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it("should re-throw Prisma infrastructure errors", async () => {
|
||||
const auth = service.getAuth();
|
||||
const prismaError = new Error("connect ECONNREFUSED 127.0.0.1:5432");
|
||||
const mockGetSession = vi.fn().mockRejectedValue(prismaError);
|
||||
auth.api = { getSession: mockGetSession } as any;
|
||||
|
||||
await expect(service.verifySession("any-token")).rejects.toThrow("ECONNREFUSED");
|
||||
});
|
||||
|
||||
it("should re-throw timeout errors as infrastructure errors", async () => {
|
||||
const auth = service.getAuth();
|
||||
const timeoutError = new Error("Connection timeout after 5000ms");
|
||||
const mockGetSession = vi.fn().mockRejectedValue(timeoutError);
|
||||
auth.api = { getSession: mockGetSession } as any;
|
||||
|
||||
await expect(service.verifySession("any-token")).rejects.toThrow("timeout");
|
||||
});
|
||||
|
||||
it("should re-throw errors with Prisma-prefixed constructor name", async () => {
|
||||
const auth = service.getAuth();
|
||||
class PrismaClientKnownRequestError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = "PrismaClientKnownRequestError";
|
||||
}
|
||||
}
|
||||
const prismaError = new PrismaClientKnownRequestError("Database connection lost");
|
||||
const mockGetSession = vi.fn().mockRejectedValue(prismaError);
|
||||
auth.api = { getSession: mockGetSession } as any;
|
||||
|
||||
await expect(service.verifySession("any-token")).rejects.toThrow("Database connection lost");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user