test(security): add and refactor api security/idor coverage
Test Suite / test (24.15.0) (push) Has been cancelled
Test Suite / test (24.15.0) (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
import { NotFoundException } from '@nestjs/common';
|
||||
import { RecipesService } from './recipes.service';
|
||||
|
||||
describe('RecipesService IDOR security', () => {
|
||||
const prismaMock = {
|
||||
recipe: {
|
||||
findUnique: jest.fn(),
|
||||
findFirst: jest.fn(),
|
||||
findMany: jest.fn(),
|
||||
create: jest.fn(),
|
||||
update: jest.fn(),
|
||||
delete: jest.fn(),
|
||||
},
|
||||
recipeIngredient: {
|
||||
findMany: jest.fn(),
|
||||
create: jest.fn(),
|
||||
deleteMany: jest.fn(),
|
||||
},
|
||||
product: {
|
||||
findMany: jest.fn(),
|
||||
findFirst: jest.fn(),
|
||||
},
|
||||
user: {
|
||||
findUnique: jest.fn(),
|
||||
},
|
||||
recipeShare: {
|
||||
findUnique: jest.fn(),
|
||||
create: jest.fn(),
|
||||
delete: jest.fn(),
|
||||
},
|
||||
$transaction: jest.fn(),
|
||||
};
|
||||
|
||||
const aiServiceMock = {};
|
||||
const recipeMatchingServiceMock = {};
|
||||
|
||||
const service = new RecipesService(prismaMock as any, aiServiceMock as any, recipeMatchingServiceMock as any);
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
const setRecipeAsOwnedByAnotherUser = () => {
|
||||
prismaMock.recipe.findUnique.mockResolvedValue({
|
||||
id: 1,
|
||||
ownerId: 100,
|
||||
});
|
||||
};
|
||||
|
||||
it('findAll scopar resultaten till userId (owner eller shared)', async () => {
|
||||
prismaMock.recipe.findMany.mockResolvedValue([]);
|
||||
|
||||
await service.findAll(42);
|
||||
|
||||
expect(prismaMock.recipe.findMany).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
where: expect.objectContaining({
|
||||
OR: expect.arrayContaining([
|
||||
{ ownerId: 42 },
|
||||
{ isPublic: true },
|
||||
{ shares: { some: { userId: 42 } } },
|
||||
]),
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('findOne nekar access om recipe inte är owner/shared/public', async () => {
|
||||
prismaMock.recipe.findFirst.mockResolvedValue(null);
|
||||
|
||||
await expect(service.findOne(1, 42)).rejects.toThrow(NotFoundException);
|
||||
});
|
||||
|
||||
it('findOne tillåter owner att läsa eget recipe', async () => {
|
||||
prismaMock.recipe.findFirst.mockResolvedValue({
|
||||
id: 1,
|
||||
ownerId: 42,
|
||||
isPublic: false,
|
||||
name: 'Test Recipe',
|
||||
description: '',
|
||||
instructions: '',
|
||||
mealPlanDayOfWeek: null,
|
||||
imageUrl: null,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
|
||||
const result = await service.findOne(1, 42);
|
||||
expect(result).toBeDefined();
|
||||
});
|
||||
|
||||
it('findOne tillåter shared user att läsa shared recipe', async () => {
|
||||
prismaMock.recipe.findFirst.mockResolvedValue({
|
||||
id: 1,
|
||||
ownerId: 100,
|
||||
isPublic: false,
|
||||
shares: [{ userId: 42 }],
|
||||
});
|
||||
|
||||
const result = await service.findOne(1, 42);
|
||||
expect(result).toBeDefined();
|
||||
});
|
||||
|
||||
it('findOne tillåter alla att läsa public recipe', async () => {
|
||||
prismaMock.recipe.findFirst.mockResolvedValue({
|
||||
id: 1,
|
||||
ownerId: 100,
|
||||
isPublic: true,
|
||||
});
|
||||
|
||||
const result = await service.findOne(1, 42);
|
||||
expect(result).toBeDefined();
|
||||
});
|
||||
|
||||
it.each([
|
||||
{
|
||||
name: 'update',
|
||||
action: () => service.update(1, {} as any, 42),
|
||||
},
|
||||
{
|
||||
name: 'remove',
|
||||
action: () => service.remove(1, 42),
|
||||
},
|
||||
{
|
||||
name: 'shareWithUser',
|
||||
action: () => service.shareWithUser(1, 42, 'someuser'),
|
||||
},
|
||||
{
|
||||
name: 'unshareWithUser',
|
||||
action: () => service.unshareWithUser(1, 42, 'someuser'),
|
||||
},
|
||||
{
|
||||
name: 'setVisibility',
|
||||
action: () => service.setVisibility(1, 42, true),
|
||||
},
|
||||
{
|
||||
name: 'addIngredient',
|
||||
action: () => service.addIngredient(1, { productId: 1, quantity: 100 } as any, 42),
|
||||
},
|
||||
{
|
||||
name: 'updateImage',
|
||||
action: () => service.updateImage(1, 'http://example.com/image.jpg', 42),
|
||||
},
|
||||
])('%s nekar icke-owner', async ({ action }) => {
|
||||
setRecipeAsOwnedByAnotherUser();
|
||||
|
||||
await expect(action()).rejects.toThrow(NotFoundException);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user