Files
hoppscotch/packages/hoppscotch-backend/src/team-environments/gql-team-env-team.guard.ts

58 lines
2.0 KiB
TypeScript

import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { TeamEnvironmentsService } from './team-environments.service';
import {
BUG_AUTH_NO_USER_CTX,
BUG_TEAM_ENV_GUARD_NO_ENV_ID,
BUG_TEAM_ENV_GUARD_NO_REQUIRE_ROLES,
TEAM_ENVIRONMENT_NOT_TEAM_MEMBER,
TEAM_ENVIRONMENT_NOT_FOUND,
} from 'src/errors';
import { TeamService } from 'src/team/team.service';
import { GqlExecutionContext } from '@nestjs/graphql';
import * as E from 'fp-ts/Either';
import { TeamMemberRole } from '@prisma/client';
import { throwErr } from 'src/utils';
/**
* A guard which checks whether the caller of a GQL Operation
* is in the team which owns the environment.
* This guard also requires the RequireRole decorator for access control
*/
@Injectable()
export class GqlTeamEnvTeamGuard implements CanActivate {
constructor(
private readonly reflector: Reflector,
private readonly teamEnvironmentService: TeamEnvironmentsService,
private readonly teamService: TeamService,
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const requireRoles = this.reflector.get<TeamMemberRole[]>(
'requiresTeamRole',
context.getHandler(),
);
if (!requireRoles) throw new Error(BUG_TEAM_ENV_GUARD_NO_REQUIRE_ROLES);
const gqlExecCtx = GqlExecutionContext.create(context);
const { user } = gqlExecCtx.getContext().req;
if (user == undefined) throw new Error(BUG_AUTH_NO_USER_CTX);
const { id } = gqlExecCtx.getArgs<{ id: string }>();
if (!id) throwErr(BUG_TEAM_ENV_GUARD_NO_ENV_ID);
const teamEnvironment =
await this.teamEnvironmentService.getTeamEnvironment(id);
if (E.isLeft(teamEnvironment)) throwErr(TEAM_ENVIRONMENT_NOT_FOUND);
const member = await this.teamService.getTeamMember(
teamEnvironment.right.teamID,
user.uid,
);
if (!member) throwErr(TEAM_ENVIRONMENT_NOT_TEAM_MEMBER);
return requireRoles.includes(member.role);
}
}