Skip to content

Commit

Permalink
Merge pull request sinamics#535 from sinamics/api-auth-wrapper
Browse files Browse the repository at this point in the history
New auth wrapper for api endpoints
  • Loading branch information
sinamics authored Aug 30, 2024
2 parents e96cc6a + 3536299 commit cbd14f7
Show file tree
Hide file tree
Showing 16 changed files with 1,113 additions and 1,374 deletions.
296 changes: 169 additions & 127 deletions src/pages/api/__tests__/v1/network/networkById.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,141 +32,183 @@ jest.mock("~/utils/rateLimit", () => ({
})),
}));

it("should respond 200 when network is found", async () => {
// Mock the decryption to return a valid user ID
(encryptionModule.decryptAndVerifyToken as jest.Mock).mockResolvedValue({
userId: "userId",
describe("/api/getNetworkById", () => {
// Reset the mocks
beforeEach(() => {
jest.clearAllMocks();
});

// Mock the database to return a network
prisma.network.findUnique = jest.fn().mockResolvedValue({
nwid: "test_nw_id",
nwname: "credent_second",
authorId: 1,
it("should respond 200 when network is found", async () => {
// Mock the decryption to return a valid user ID
(encryptionModule.decryptAndVerifyToken as jest.Mock).mockResolvedValue({
userId: "userId",
});

// Mock the database to return a network
prisma.network.findUnique = jest.fn().mockResolvedValue({
nwid: "test_nw_id",
nwname: "credent_second",
authorId: "userId",
});

// Mock the ztController to return a network detail
(ztController.local_network_detail as jest.Mock).mockResolvedValue({
network: { id: "networkId", name: "networkName" },
});

const req = {
method: "GET",
headers: { "x-ztnet-auth": "validApiKey" },
query: { id: "networkId" },
} as unknown as NextApiRequest;

const res = {
status: jest.fn().mockReturnThis(),
json: jest.fn(),
end: jest.fn(),
setHeader: jest.fn(), // Mock `setHeader` rate limiter uses it
} as unknown as NextApiResponse;

await apiNetworkByIdHandler(req, res);

expect(res.status).toHaveBeenCalledWith(200);
expect(res.json).toHaveBeenCalledWith({
id: "networkId",
name: "networkName",
authorId: "userId",
nwid: "test_nw_id",
nwname: "credent_second",
});
});

// Mock the ztController to return a network detail
(ztController.local_network_detail as jest.Mock).mockResolvedValue({
network: { id: "networkId", name: "networkName" },
it("should respond 401 when network is not found", async () => {
// Mock the decryption to return a valid user ID
(encryptionModule.decryptAndVerifyToken as jest.Mock).mockResolvedValue({
userId: "userId",
});

// Mock the database to return a network
prisma.network.findUnique = jest.fn().mockResolvedValue(null);

const req = {
method: "GET",
headers: { "x-ztnet-auth": "validApiKey" },
query: { id: "networkId" },
} as unknown as NextApiRequest;

const res = {
status: jest.fn().mockReturnThis(),
json: jest.fn(),
end: jest.fn(),
setHeader: jest.fn(), // Mock `setHeader` rate limiter uses it
} as unknown as NextApiResponse;

await apiNetworkByIdHandler(req, res);

expect(res.status).toHaveBeenCalledWith(401);
expect(res.json).toHaveBeenCalledWith({
error: "Network not found or access denied.",
});
});

const req = {
method: "GET",
headers: { "x-ztnet-auth": "validApiKey" },
query: { id: "networkId" },
} as unknown as NextApiRequest;

const res = {
status: jest.fn().mockReturnThis(),
json: jest.fn(),
end: jest.fn(),
setHeader: jest.fn(), // Mock `setHeader` rate limiter uses it
} as unknown as NextApiResponse;

await apiNetworkByIdHandler(req, res);

expect(res.status).toHaveBeenCalledWith(200);
expect(res.json).toHaveBeenCalledWith({
id: "networkId",
name: "networkName",
authorId: 1,
nwid: "test_nw_id",
nwname: "credent_second",
it("should respond with an error when ztController throws an error", async () => {
// Mock the decryption to return a valid user ID
(encryptionModule.decryptAndVerifyToken as jest.Mock).mockResolvedValue({
userId: "ztnetUserId",
});

// Mock the database to return a network
prisma.network.findUnique = jest.fn().mockResolvedValue({
nwid: "networkId",
name: "networkName",
authorId: "ztnetUserId",
});

// Mock the ztController to throw an error
const error = new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Internal server error",
});

(ztController.local_network_detail as jest.Mock).mockRejectedValue(error);

const req = {
method: "GET",
headers: { "x-ztnet-auth": "validApiKey" },
query: { id: "networkId" },
} as unknown as NextApiRequest;

const res = {
status: jest.fn().mockReturnThis(),
json: jest.fn(),
end: jest.fn(),
setHeader: jest.fn(), // Mock `setHeader` rate limiter uses it
} as unknown as NextApiResponse;

await apiNetworkByIdHandler(req, res);

const httpCode = getHTTPStatusCodeFromError(error);
expect(res.status).toHaveBeenCalledWith(httpCode);
expect(res.json).toHaveBeenCalledWith({ error: error.message });
});
});

it("should respond 401 when network is not found", async () => {
// Mock the decryption to return a valid user ID
(encryptionModule.decryptAndVerifyToken as jest.Mock).mockResolvedValue({
userId: "userId",
});

// Mock the database to return a network
prisma.network.findUnique = jest.fn().mockResolvedValue(null);

const req = {
method: "GET",
headers: { "x-ztnet-auth": "validApiKey" },
query: { id: "networkId" },
} as unknown as NextApiRequest;

const res = {
status: jest.fn().mockReturnThis(),
json: jest.fn(),
end: jest.fn(),
setHeader: jest.fn(), // Mock `setHeader` rate limiter uses it
} as unknown as NextApiResponse;

await apiNetworkByIdHandler(req, res);

expect(res.status).toHaveBeenCalledWith(401);
expect(res.json).toHaveBeenCalledWith({ error: "Network not found or access denied." });
});

it("should respond with an error when ztController throws an error", async () => {
// Mock the decryption to return a valid user ID
(encryptionModule.decryptAndVerifyToken as jest.Mock).mockResolvedValue({
userId: "ztnetUserId",
it("should respond 401 when decryptAndVerifyToken fails", async () => {
// Mock the decryption to fail
(encryptionModule.decryptAndVerifyToken as jest.Mock).mockRejectedValue(
new Error("Invalid token"),
);

const req = {
method: "GET",
headers: { "x-ztnet-auth": "invalidApiKey" },
query: { id: "networkId" },
} as unknown as NextApiRequest;

const res = {
status: jest.fn().mockReturnThis(),
json: jest.fn(),
end: jest.fn(),
setHeader: jest.fn(), // Mock `setHeader` if rate limiter uses it
} as unknown as NextApiResponse;

await apiNetworkByIdHandler(req, res);

expect(res.status).toHaveBeenCalledWith(401);
expect(res.json).toHaveBeenCalledWith(
expect.objectContaining({ error: expect.any(String) }),
);
});

// Mock the database to return a network
prisma.network.findUnique = jest.fn().mockResolvedValue({
nwid: "networkId",
name: "networkName",
authorId: 1,
it("should respond 401 when user is not the author of the network", async () => {
// Mock the decryption to return a valid user ID
(encryptionModule.decryptAndVerifyToken as jest.Mock).mockResolvedValue({
userId: "userId",
});

const req = {
method: "GET",
headers: { "x-ztnet-auth": "validApiKey" },
query: { id: "networkIdThatUserDoesNotOwn" },
} as unknown as NextApiRequest;

const res = {
status: jest.fn().mockReturnThis(),
end: jest.fn(),
json: jest.fn().mockReturnThis(),
setHeader: jest.fn(), // Mock `setHeader` rate limiter uses it
} as unknown as NextApiResponse;

// Mock the database to return a network
prisma.network.findUnique = jest.fn().mockResolvedValue({
nwid: "networkIdThatUserDoesNotOwn",
nwname: "Some Network",
authorId: "anotherUserId",
});

await apiNetworkByIdHandler(req, res);

expect(res.status).toHaveBeenCalledWith(401);
expect(res.json).toHaveBeenCalledWith({
error: "Network not found or access denied.",
});
});

// Mock the ztController to throw an error
const error = new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Internal server error",
});

(ztController.local_network_detail as jest.Mock).mockRejectedValue(error);

const req = {
method: "GET",
headers: { "x-ztnet-auth": "validApiKey" },
query: { id: "networkId" },
} as unknown as NextApiRequest;

const res = {
status: jest.fn().mockReturnThis(),
json: jest.fn(),
end: jest.fn(),
setHeader: jest.fn(), // Mock `setHeader` rate limiter uses it
} as unknown as NextApiResponse;

await apiNetworkByIdHandler(req, res);

const httpCode = getHTTPStatusCodeFromError(error);
expect(res.status).toHaveBeenCalledWith(httpCode);
expect(res.json).toHaveBeenCalledWith({ error: error.message });
});

it("should respond 401 when decryptAndVerifyToken fails", async () => {
// Mock the decryption to fail
(encryptionModule.decryptAndVerifyToken as jest.Mock).mockRejectedValue(
new Error("Invalid token"),
);

const req = {
method: "GET",
headers: { "x-ztnet-auth": "invalidApiKey" },
query: { id: "networkId" },
} as unknown as NextApiRequest;

const res = {
status: jest.fn().mockReturnThis(),
json: jest.fn(),
end: jest.fn(),
setHeader: jest.fn(), // Mock `setHeader` if rate limiter uses it
} as unknown as NextApiResponse;

await apiNetworkByIdHandler(req, res);

expect(res.status).toHaveBeenCalledWith(401);
expect(res.json).toHaveBeenCalledWith(
expect.objectContaining({ error: expect.any(String) }),
);
});
37 changes: 25 additions & 12 deletions src/pages/api/__tests__/v1/networkMembers/updateMember.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,6 @@ describe("Update Network Members", () => {
authorId: 1,
});

// Mock the database to return a network
prisma.network.findUnique = jest.fn().mockResolvedValue({
nwid: "test_nw_id",
nwname: "credent_second",
authorId: 1,
networkMembers: [{ id: "memberId" }],
});

const mockRegister = jest.fn().mockResolvedValue({ id: "memberId" });
appRouter.createCaller = jest
.fn()
Expand Down Expand Up @@ -103,7 +95,21 @@ describe("Update Network Members", () => {
// Assertions
expect(res.status).toHaveBeenCalledWith(401);
});

it("should respond 200 when member is successfully updated", async () => {
// Mock the database to return a network
prisma.network.findUnique = jest.fn().mockResolvedValue({
nwid: "test_nw_id",
nwname: "credent_second",
authorId: "userId",
networkMembers: [{ id: "memberId" }],
});

// mock the token
prisma.aPIToken.findUnique = jest.fn().mockResolvedValue({
expiresAt: new Date(),
});

const req = {
method: "POST",
headers: { "x-ztnet-auth": "validApiKey" },
Expand All @@ -119,8 +125,15 @@ describe("Update Network Members", () => {
// Assertions
expect(res.status).toHaveBeenCalledWith(200);
});
// Example for a 400 response
it("should respond 400 for invalid input", async () => {

it("should respond 401 for invalid input", async () => {
// Mock the database to return a network
prisma.network.findUnique = jest.fn().mockResolvedValue({
nwid: "test_nw_id",
nwname: "credent_second",
authorId: 1,
networkMembers: [{ id: "memberId" }],
});
const req = {
method: "POST",
headers: { "x-ztnet-auth": "validApiKey" },
Expand All @@ -134,7 +147,7 @@ describe("Update Network Members", () => {
await apiNetworkUpdateMembersHandler(req, res);

// Assertions
expect(res.status).toHaveBeenCalledWith(400);
expect(res.status).toHaveBeenCalledWith(401);
});

it("should respond 401 when decryptAndVerifyToken fails", async () => {
Expand All @@ -146,7 +159,7 @@ describe("Update Network Members", () => {
const req = {
method: "POST",
headers: { "x-ztnet-auth": "invalidApiKey" },
query: { id: "networkId" },
query: { id: "networkId", memberId: "memberId" },
body: { name: "New Name", authorized: "true" },
} as unknown as NextApiRequest;

Expand Down
Loading

0 comments on commit cbd14f7

Please sign in to comment.