119 lines
3.0 KiB
JavaScript
119 lines
3.0 KiB
JavaScript
jest.mock("jsonwebtoken", () => ({
|
|
verify: jest.fn(),
|
|
}));
|
|
|
|
jest.mock("../models/session.model", () => ({
|
|
getActiveSessionWithUser: jest.fn(),
|
|
}));
|
|
|
|
jest.mock("../utils/logger", () => ({
|
|
logError: jest.fn(),
|
|
}));
|
|
|
|
const jwt = require("jsonwebtoken");
|
|
const Session = require("../models/session.model");
|
|
const auth = require("../middleware/auth");
|
|
|
|
function createResponse() {
|
|
const res = {};
|
|
res.status = jest.fn().mockReturnValue(res);
|
|
res.json = jest.fn().mockReturnValue(res);
|
|
return res;
|
|
}
|
|
|
|
describe("auth middleware", () => {
|
|
const originalJwtSecret = process.env.JWT_SECRET;
|
|
|
|
beforeEach(() => {
|
|
process.env.JWT_SECRET = "test-secret";
|
|
jest.clearAllMocks();
|
|
});
|
|
|
|
afterAll(() => {
|
|
if (originalJwtSecret === undefined) {
|
|
delete process.env.JWT_SECRET;
|
|
} else {
|
|
process.env.JWT_SECRET = originalJwtSecret;
|
|
}
|
|
});
|
|
|
|
test("uses a valid bearer token without reading the session cookie", async () => {
|
|
jwt.verify.mockReturnValue({ id: 5, role: "admin" });
|
|
|
|
const req = {
|
|
headers: {
|
|
authorization: "Bearer valid-token",
|
|
cookie: "sid=session-id",
|
|
},
|
|
};
|
|
const res = createResponse();
|
|
const next = jest.fn();
|
|
|
|
await auth(req, res, next);
|
|
|
|
expect(jwt.verify).toHaveBeenCalledWith("valid-token", "test-secret");
|
|
expect(Session.getActiveSessionWithUser).not.toHaveBeenCalled();
|
|
expect(req.user).toEqual({ id: 5, role: "admin" });
|
|
expect(next).toHaveBeenCalled();
|
|
});
|
|
|
|
test("falls back to a valid session cookie when the bearer token is stale", async () => {
|
|
jwt.verify.mockImplementation(() => {
|
|
throw new Error("stale token");
|
|
});
|
|
Session.getActiveSessionWithUser.mockResolvedValue({
|
|
id: "session-id",
|
|
user_id: 7,
|
|
role: "user",
|
|
username: "shopper",
|
|
});
|
|
|
|
const req = {
|
|
headers: {
|
|
authorization: "Bearer stale-token",
|
|
cookie: "sid=session-id",
|
|
},
|
|
};
|
|
const res = createResponse();
|
|
const next = jest.fn();
|
|
|
|
await auth(req, res, next);
|
|
|
|
expect(Session.getActiveSessionWithUser).toHaveBeenCalledWith("session-id");
|
|
expect(req.user).toEqual({
|
|
id: 7,
|
|
role: "user",
|
|
username: "shopper",
|
|
});
|
|
expect(req.session_id).toBe("session-id");
|
|
expect(next).toHaveBeenCalled();
|
|
expect(res.status).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test("rejects a stale bearer token when no session cookie is present", async () => {
|
|
jwt.verify.mockImplementation(() => {
|
|
throw new Error("stale token");
|
|
});
|
|
|
|
const req = {
|
|
headers: {
|
|
authorization: "Bearer stale-token",
|
|
},
|
|
};
|
|
const res = createResponse();
|
|
const next = jest.fn();
|
|
|
|
await auth(req, res, next);
|
|
|
|
expect(Session.getActiveSessionWithUser).not.toHaveBeenCalled();
|
|
expect(next).not.toHaveBeenCalled();
|
|
expect(res.status).toHaveBeenCalledWith(401);
|
|
expect(res.json).toHaveBeenCalledWith({
|
|
error: {
|
|
code: "unauthorized",
|
|
message: "Invalid or expired token",
|
|
},
|
|
});
|
|
});
|
|
});
|