summaryrefslogtreecommitdiff
path: root/server/providers
diff options
context:
space:
mode:
Diffstat (limited to 'server/providers')
-rw-r--r--server/providers/guards/auth.guard.ts17
-rw-r--r--server/providers/guards/roles.guard.ts37
-rw-r--r--server/providers/services/roles.service.ts25
-rw-r--r--server/providers/services/users.service.ts6
4 files changed, 83 insertions, 2 deletions
diff --git a/server/providers/guards/auth.guard.ts b/server/providers/guards/auth.guard.ts
index d7da81e..8c03ad8 100644
--- a/server/providers/guards/auth.guard.ts
+++ b/server/providers/guards/auth.guard.ts
@@ -1,13 +1,28 @@
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { JwtService } from '../services/jwt.service';
+import { SKIP_KEY } from 'server/decorators/skip.decorator';
+import { Reflector } from '@nestjs/core';
+import { Class } from 'server/dto/class.dto';
@Injectable()
export class AuthGuard implements CanActivate {
- constructor(private jwtService: JwtService) {}
+ constructor(private reflector: Reflector, private jwtService: JwtService) {}
canActivate(context: ExecutionContext) {
+ const skippedGuards = this.reflector.getAllAndOverride<Class<CanActivate>[]>(SKIP_KEY, [
+ context.getHandler(),
+ context.getClass(),
+ ]);
+ if (skippedGuards) {
+ const skippedGuard = skippedGuards.find((guard) => this instanceof guard);
+ if (skippedGuard) {
+ return true;
+ }
+ }
const req = context.switchToHttp().getRequest();
const authHeader = req.headers.authorization;
+ if (!authHeader) return false;
+
const jwt = authHeader.split(' ')[1];
try {
req.jwtBody = this.jwtService.parseToken(jwt);
diff --git a/server/providers/guards/roles.guard.ts b/server/providers/guards/roles.guard.ts
index e69de29..3ecc392 100644
--- a/server/providers/guards/roles.guard.ts
+++ b/server/providers/guards/roles.guard.ts
@@ -0,0 +1,37 @@
+import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
+import { Reflector } from '@nestjs/core';
+import { ROLES_CONTEXT_KEY } from 'server/decorators/roles.decorator';
+import { JwtBodyDto } from 'server/dto/jwt_body.dto';
+import { RoleKey } from 'server/entities/role.entity';
+import { RolesService } from '../services/roles.service';
+import { UsersService } from '../services/users.service';
+import { some } from 'lodash';
+
+@Injectable()
+export class RolesGuard implements CanActivate {
+ constructor(private reflector: Reflector, private usersService: UsersService, private rolesService: RolesService) {}
+
+ async canActivate(context: ExecutionContext): Promise<boolean> {
+ const requiredRoles = this.reflector.getAllAndOverride<RoleKey[]>(ROLES_CONTEXT_KEY, [
+ context.getHandler(),
+ context.getClass(),
+ ]);
+ console.log(requiredRoles);
+
+ if (!requiredRoles) {
+ return true;
+ }
+
+ const jwtBody: JwtBodyDto = context.switchToHttp().getRequest().jwtBody;
+
+ if (!jwtBody) return false; // unauthenticated users are not authorized
+
+ const user = await this.usersService.find(jwtBody.userId, ['userRoles']);
+ const roles = await this.rolesService.findByKey(...requiredRoles);
+ const roleMatches = user.userRoles.map((userRole) => {
+ return !!roles.find((role) => role.id === userRole.roleId);
+ });
+
+ return some(roleMatches);
+ }
+}
diff --git a/server/providers/services/roles.service.ts b/server/providers/services/roles.service.ts
new file mode 100644
index 0000000..7cd17ef
--- /dev/null
+++ b/server/providers/services/roles.service.ts
@@ -0,0 +1,25 @@
+import { Injectable } from '@nestjs/common';
+import { InjectRepository } from '@nestjs/typeorm';
+import { In, Repository } from 'typeorm';
+import * as bcrypt from 'bcrypt';
+import { Role, RoleKey } from 'server/entities/role.entity';
+
+@Injectable()
+export class RolesService {
+ constructor(
+ @InjectRepository(Role)
+ private rolesRepository: Repository<Role>,
+ ) {}
+
+ findByKey(...keys: RoleKey[]) {
+ return this.rolesRepository.find({ where: { key: In(keys) } });
+ }
+
+ findByIds(ids: number[]) {
+ return this.rolesRepository.findByIds(ids);
+ }
+
+ find(id: number, relations: string[] = []) {
+ return this.rolesRepository.findOne(id, { relations });
+ }
+}
diff --git a/server/providers/services/users.service.ts b/server/providers/services/users.service.ts
index 47a0360..c3ee086 100644
--- a/server/providers/services/users.service.ts
+++ b/server/providers/services/users.service.ts
@@ -11,6 +11,10 @@ export class UsersService {
private usersRespository: Repository<User>,
) {}
+ findAll(relations: string[] = []) {
+ return this.usersRespository.find({ relations });
+ }
+
findBy(options: Record<string, any>, relations: string[] = []) {
return this.usersRespository.findOne(options, { relations });
}
@@ -24,7 +28,7 @@ export class UsersService {
}
async verify(email: string, password: string) {
- const user = await this.usersRespository.findOne({ email }, { relations: ['refreshTokens'] });
+ const user = await this.usersRespository.findOne({ email }, { relations: ['refreshTokens', 'userRoles'] });
if (!user) return { verified: false, user: null };
const verified: boolean = await bcrypt.compare(password, user.passwordHash);
return { verified, user: verified ? user : null };