-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from isdi-coders-2023/feature/middleware
Add guards and validation
- Loading branch information
Showing
17 changed files
with
325 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { LoggedGuard } from './logged.guard'; | ||
import { ExecutionContext } from '@nestjs/common'; | ||
import { CryptoService } from '../crypto/crypto.service'; | ||
|
||
const cryptoServiceMock: CryptoService = { | ||
verifyToken: jest.fn().mockResolvedValue({}), | ||
} as unknown as CryptoService; | ||
|
||
describe('AuthGuard', () => { | ||
const loggedGuard = new LoggedGuard(cryptoServiceMock); | ||
it('should be defined', () => { | ||
expect(loggedGuard).toBeDefined(); | ||
}); | ||
|
||
describe('When we call canActivate method', () => { | ||
it('should return true', async () => { | ||
const context = { | ||
switchToHttp: () => ({ | ||
getRequest: () => ({ | ||
headers: { | ||
authorization: 'Bearer token', | ||
}, | ||
}), | ||
}), | ||
} as unknown as ExecutionContext; | ||
const result = await loggedGuard.canActivate(context); | ||
expect(result).toBe(true); | ||
}); | ||
|
||
describe('And there are NOT Authorization header', () => { | ||
it('should throw BadRequestException', async () => { | ||
const context = { | ||
switchToHttp: () => ({ | ||
getRequest: () => ({ | ||
headers: {}, | ||
}), | ||
}), | ||
} as ExecutionContext; | ||
try { | ||
await loggedGuard.canActivate(context); | ||
} catch (error) { | ||
expect(error.message).toBe('Authorization header is required'); | ||
} | ||
}); | ||
}); | ||
|
||
describe('And token is invalid', () => { | ||
it('should throw ForbiddenException', async () => { | ||
const context = { | ||
switchToHttp: () => ({ | ||
getRequest: () => ({ | ||
headers: { | ||
authorization: 'Bearer token', | ||
}, | ||
}), | ||
}), | ||
} as ExecutionContext; | ||
cryptoServiceMock.verifyToken = jest | ||
.fn() | ||
.mockRejectedValue(new Error()); | ||
try { | ||
await loggedGuard.canActivate(context); | ||
} catch (error) { | ||
expect(error.message).toBe('Invalid token'); | ||
} | ||
}); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { | ||
BadRequestException, | ||
CanActivate, | ||
ExecutionContext, | ||
ForbiddenException, | ||
Injectable, | ||
} from '@nestjs/common'; | ||
import { CryptoService } from '../crypto/crypto.service'; | ||
|
||
@Injectable() | ||
export class LoggedGuard implements CanActivate { | ||
constructor(private readonly cryptoService: CryptoService) {} | ||
|
||
async canActivate(context: ExecutionContext): Promise<boolean> { | ||
const request = context.switchToHttp().getRequest(); | ||
const auth = request.headers.authorization; | ||
if (!auth) { | ||
throw new BadRequestException('Authorization header is required'); | ||
} | ||
const token = auth.split(' ')[1]; | ||
try { | ||
request.payload = await this.cryptoService.verifyToken(token); | ||
return true; | ||
} catch (error) { | ||
throw new ForbiddenException('Invalid token'); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import { Test, TestingModule } from '@nestjs/testing'; | ||
import { ExecutionContext, NotFoundException } from '@nestjs/common'; | ||
import { PolicyOwnerGuard } from './owner.guard'; | ||
import { PoliciesService } from '../../policies/policies.service'; | ||
|
||
describe('PolicyOwnerGuard', () => { | ||
let guard: PolicyOwnerGuard; | ||
let policiesService: PoliciesService; | ||
|
||
beforeEach(async () => { | ||
const module: TestingModule = await Test.createTestingModule({ | ||
providers: [ | ||
PolicyOwnerGuard, | ||
{ provide: PoliciesService, useValue: { findOne: jest.fn() } }, | ||
], | ||
}).compile(); | ||
|
||
guard = module.get<PolicyOwnerGuard>(PolicyOwnerGuard); | ||
policiesService = module.get<PoliciesService>(PoliciesService); | ||
}); | ||
|
||
it('should allow access if the user is the owner of the policy', async () => { | ||
const request = { | ||
user: { id: 'user5' }, | ||
params: { id: 'policy1' }, | ||
}; | ||
const policy = { | ||
id: 'policy1', | ||
userId: 'user5', | ||
carMake: 'Cruzcampo', | ||
carModel: 'Especial', | ||
carAge: 5, | ||
plateNumber: 'XYZ1234', | ||
policyNumber: 101, | ||
claims: [], | ||
}; | ||
|
||
jest.spyOn(policiesService, 'findOne').mockResolvedValue(policy); | ||
const context = { | ||
switchToHttp: () => ({ getRequest: () => request }), | ||
} as unknown as ExecutionContext; | ||
|
||
await expect(guard.canActivate(context)).resolves.toBeTruthy(); | ||
}); | ||
|
||
// it('should throw a ForbiddenException if the user is not the owner of the policy', async () => { | ||
// const request = { | ||
// user: { id: 'user2' }, | ||
// params: { id: 'policy1' }, | ||
// }; | ||
// const policy = { | ||
// id: 'policy1', | ||
// userId: 'user1', | ||
// carMake: 'Fanta', | ||
// carModel: 'Limón', | ||
// carAge: 5, | ||
// plateNumber: 'XYZ1234', | ||
// policyNumber: 101, | ||
// claims: [], | ||
// }; | ||
|
||
// jest.spyOn(policiesService, 'findOne').mockResolvedValue(policy); | ||
// const context = { | ||
// switchToHttp: () => ({ getRequest: () => request }), | ||
// } as unknown as ExecutionContext; | ||
|
||
// await expect(guard.canActivate(context)).rejects.toThrow( | ||
// ForbiddenException, | ||
// ); | ||
// }); | ||
|
||
it('should throw a NotFoundException if the policy does not exist', async () => { | ||
const request = { | ||
user: { id: 'user1' }, | ||
params: { id: 'policy1' }, | ||
}; | ||
|
||
jest.spyOn(policiesService, 'findOne').mockResolvedValue(null as any); | ||
const context = { | ||
switchToHttp: () => ({ getRequest: () => request }), | ||
} as unknown as ExecutionContext; | ||
|
||
await expect(guard.canActivate(context)).rejects.toThrow(NotFoundException); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { | ||
Injectable, | ||
CanActivate, | ||
ExecutionContext, | ||
NotFoundException, | ||
ForbiddenException, | ||
} from '@nestjs/common'; | ||
import { PoliciesService } from '../../policies/policies.service'; | ||
|
||
@Injectable() | ||
export class PolicyOwnerGuard implements CanActivate { | ||
constructor(private readonly policiesService: PoliciesService) {} | ||
|
||
async canActivate(context: ExecutionContext): Promise<boolean> { | ||
const request = context.switchToHttp().getRequest(); | ||
const user = request.user; | ||
const policyId = request.params.id; | ||
|
||
const policy = await this.policiesService.findOne(policyId); | ||
if (!policy) { | ||
throw new NotFoundException(`Policy not found`); | ||
} | ||
|
||
if (policy.userId !== user.id) { | ||
throw new ForbiddenException('Access Denied'); | ||
} | ||
|
||
return true; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,16 @@ | ||
import { IsInt, IsString } from 'class-validator'; | ||
|
||
export class CreatePolicyDto { | ||
@IsString() | ||
carMake: string; | ||
@IsString() | ||
carModel: string; | ||
@IsInt() | ||
carAge: number; | ||
@IsString() | ||
plateNumber: string; | ||
@IsString() | ||
policyType: string; | ||
@IsString() | ||
userId: string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,13 @@ | ||
import { Module } from '@nestjs/common'; | ||
import { PoliciesService } from './policies.service'; | ||
import { PoliciesController } from './policies.controller'; | ||
import { PrismaService } from 'src/prisma/prisma.service'; | ||
import { PrismaModule } from 'src/prisma/prisma.module'; | ||
import { PrismaService } from '../prisma/prisma.service'; | ||
import { PrismaModule } from '../prisma/prisma.module'; | ||
import { CoreModule } from '../core/core.module'; | ||
|
||
@Module({ | ||
controllers: [PoliciesController], | ||
providers: [PoliciesService, PrismaService], | ||
imports: [PrismaModule], | ||
imports: [PrismaModule, CoreModule], | ||
}) | ||
export class PoliciesModule {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.