Prevent file upload in demo workspaces (#4503)

* Build demo env guard

* Put guard for auth

* Add todo

---------

Co-authored-by: Thomas Trompette <thomast@twenty.com>
This commit is contained in:
Thomas Trompette
2024-03-15 19:15:22 +01:00
committed by GitHub
parent 1cc8edd016
commit 8980cc576c
7 changed files with 65 additions and 49 deletions

View File

@ -0,0 +1,36 @@
import {
Injectable,
ExecutionContext,
UnauthorizedException,
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
import { getRequest } from 'src/utils/extract-request';
@Injectable()
export class DemoEnvGuard extends AuthGuard(['jwt']) {
constructor(private readonly environmentService: EnvironmentService) {
super();
}
getRequest(context: ExecutionContext) {
return getRequest(context);
}
// TODO: input should be typed
handleRequest(err: any, user: any) {
const demoWorkspaceIds = this.environmentService.get('DEMO_WORKSPACE_IDS');
const currentUserWorkspaceId = user?.workspace?.id;
if (!currentUserWorkspaceId) {
throw new UnauthorizedException('Unauthorized for not logged in user');
}
if (demoWorkspaceIds.includes(currentUserWorkspaceId)) {
throw new UnauthorizedException('Unauthorized for demo workspace');
}
return user;
}
}

View File

@ -8,6 +8,7 @@ import { GoogleAPIsRequest } from 'src/engine/modules/auth/strategies/google-api
import { GoogleAPIsService } from 'src/engine/modules/auth/services/google-apis.service';
import { TokenService } from 'src/engine/modules/auth/services/token.service';
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
import { DemoEnvGuard } from 'src/engine/guards/demo.env.guard';
@Controller('auth/google-apis')
export class GoogleAPIsAuthController {
@ -25,7 +26,7 @@ export class GoogleAPIsAuthController {
}
@Get('get-access-token')
@UseGuards(GoogleAPIsProviderEnabledGuard, GoogleAPIsOauthGuard)
@UseGuards(GoogleAPIsProviderEnabledGuard, GoogleAPIsOauthGuard, DemoEnvGuard)
async googleAuthGetAccessToken(
@Req() req: GoogleAPIsRequest,
@Res() res: Response,
@ -37,12 +38,6 @@ export class GoogleAPIsAuthController {
const { workspaceMemberId, workspaceId } =
await this.tokenService.verifyTransientToken(transientToken);
const demoWorkspaceIds = this.environmentService.get('DEMO_WORKSPACE_IDS');
if (demoWorkspaceIds.includes(workspaceId)) {
throw new Error('Cannot connect Google account to demo workspace');
}
if (!workspaceId) {
throw new Error('Workspace not found');
}

View File

@ -2,6 +2,7 @@ import { Controller, Get, Req, Res, UseGuards } from '@nestjs/common';
import { Response } from 'express';
import { DemoEnvGuard } from 'src/engine/guards/demo.env.guard';
import { GoogleAPIsOauthGuard } from 'src/engine/modules/auth/guards/google-apis-oauth.guard';
import { GoogleAPIsProviderEnabledGuard } from 'src/engine/modules/auth/guards/google-apis-provider-enabled.guard';
import { GoogleAPIsService } from 'src/engine/modules/auth/services/google-apis.service';
@ -25,7 +26,7 @@ export class GoogleGmailAuthController {
}
@Get('get-access-token')
@UseGuards(GoogleAPIsProviderEnabledGuard, GoogleAPIsOauthGuard)
@UseGuards(GoogleAPIsProviderEnabledGuard, GoogleAPIsOauthGuard, DemoEnvGuard)
async googleAuthGetAccessToken(
@Req() req: GoogleAPIsRequest,
@Res() res: Response,
@ -37,25 +38,18 @@ export class GoogleGmailAuthController {
const { workspaceMemberId, workspaceId } =
await this.tokenService.verifyTransientToken(transientToken);
const demoWorkspaceIds = this.environmentService.get('DEMO_WORKSPACE_IDS');
if (demoWorkspaceIds.includes(workspaceId)) {
throw new Error('Cannot connect Gmail account to demo workspace');
}
if (!workspaceId) {
throw new Error('Workspace not found');
}
if (workspaceId)
await this.googleGmailService.saveConnectedAccount({
handle: email,
workspaceMemberId: workspaceMemberId,
workspaceId: workspaceId,
provider: 'gmail',
accessToken,
refreshToken,
});
await this.googleGmailService.saveConnectedAccount({
handle: email,
workspaceMemberId: workspaceMemberId,
workspaceId: workspaceId,
provider: 'gmail',
accessToken,
refreshToken,
});
return res.redirect(
`${this.environmentService.get('FRONT_BASE_URL')}/settings/accounts`,

View File

@ -1,12 +1,19 @@
import { Module } from '@nestjs/common';
import { EnvironmentService } from 'src/integrations/environment/environment.service';
import { FileService } from './services/file.service';
import { FileUploadService } from './services/file-upload.service';
import { FileUploadResolver } from './resolvers/file-upload.resolver';
import { FileController } from './controllers/file.controller';
@Module({
providers: [FileService, FileUploadService, FileUploadResolver],
providers: [
FileService,
FileUploadService,
FileUploadResolver,
EnvironmentService,
],
exports: [FileService, FileUploadService],
controllers: [FileController],
})

View File

@ -8,8 +8,9 @@ import { FileFolder } from 'src/engine/modules/file/interfaces/file-folder.inter
import { FileUploadService } from 'src/engine/modules/file/services/file-upload.service';
import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard';
import { streamToBuffer } from 'src/utils/stream-to-buffer';
import { DemoEnvGuard } from 'src/engine/guards/demo.env.guard';
@UseGuards(JwtAuthGuard)
@UseGuards(JwtAuthGuard, DemoEnvGuard)
@Resolver()
export class FileUploadResolver {
constructor(private readonly fileUploadService: FileUploadService) {}

View File

@ -6,7 +6,7 @@ import {
ResolveField,
Mutation,
} from '@nestjs/graphql';
import { ForbiddenException, UseGuards } from '@nestjs/common';
import { UseGuards } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import crypto from 'crypto';
@ -22,6 +22,7 @@ import { EnvironmentService } from 'src/engine/integrations/environment/environm
import { streamToBuffer } from 'src/utils/stream-to-buffer';
import { FileUploadService } from 'src/engine/modules/file/services/file-upload.service';
import { assert } from 'src/utils/assert';
import { DemoEnvGuard } from 'src/engine/guards/demo.env.guard';
import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard';
import { User } from 'src/engine/modules/user/user.entity';
import { WorkspaceMember } from 'src/engine/modules/user/dtos/workspace-member.dto';
@ -108,20 +109,9 @@ export class UserResolver {
return paths[0];
}
@UseGuards(DemoEnvGuard)
@Mutation(() => User)
async deleteUser(@AuthUser() { id: userId, defaultWorkspace }: User) {
// Get the list of demo workspace IDs
const demoWorkspaceIds = this.environmentService.get('DEMO_WORKSPACE_IDS');
const currentUserWorkspaceId = defaultWorkspace.id;
// Check if the user's default workspace ID is in the list of demo workspace IDs
if (demoWorkspaceIds.includes(currentUserWorkspaceId)) {
throw new ForbiddenException(
'Deletion of users with a default demo workspace is not allowed.',
);
}
async deleteUser(@AuthUser() { id: userId }: User) {
// Proceed with user deletion
return this.userService.deleteUser(userId);
}

View File

@ -6,7 +6,7 @@ import {
ResolveField,
Parent,
} from '@nestjs/graphql';
import { ForbiddenException, UseGuards } from '@nestjs/common';
import { UseGuards } from '@nestjs/common';
import { FileUpload, GraphQLUpload } from 'graphql-upload';
@ -18,12 +18,12 @@ import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorat
import { assert } from 'src/utils/assert';
import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard';
import { UpdateWorkspaceInput } from 'src/engine/modules/workspace/dtos/update-workspace-input';
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
import { User } from 'src/engine/modules/user/user.entity';
import { AuthUser } from 'src/engine/decorators/auth/auth-user.decorator';
import { ActivateWorkspaceInput } from 'src/engine/modules/workspace/dtos/activate-workspace-input';
import { BillingSubscription } from 'src/engine/modules/billing/entities/billing-subscription.entity';
import { BillingService } from 'src/engine/modules/billing/billing.service';
import { DemoEnvGuard } from 'src/engine/guards/demo.env.guard';
import { Workspace } from './workspace.entity';
@ -35,7 +35,6 @@ export class WorkspaceResolver {
constructor(
private readonly workspaceService: WorkspaceService,
private readonly fileUploadService: FileUploadService,
private readonly environmentService: EnvironmentService,
private readonly billingService: BillingService,
) {}
@ -89,15 +88,9 @@ export class WorkspaceResolver {
return paths[0];
}
@UseGuards(DemoEnvGuard)
@Mutation(() => Workspace)
async deleteCurrentWorkspace(@AuthWorkspace() { id }: Workspace) {
const demoWorkspaceIds = this.environmentService.get('DEMO_WORKSPACE_IDS');
// Check if the id is in the list of demo workspaceIds
if (demoWorkspaceIds.includes(id)) {
throw new ForbiddenException('Demo workspaces cannot be deleted.');
}
return this.workspaceService.deleteWorkspace(id);
}