Add getters factory for attachements (#4567)

* Add getter factory for attachements

* Override guard in test

* Add secret in env variables

* Return custom message on expiration

* Rename to signPayload

---------

Co-authored-by: Thomas Trompette <thomast@twenty.com>
This commit is contained in:
Thomas Trompette
2024-03-19 16:39:53 +01:00
committed by GitHub
parent 9f6c578a46
commit e579554d47
24 changed files with 306 additions and 55 deletions

View File

@ -1,11 +1,14 @@
import { Test, TestingModule } from '@nestjs/testing';
import { CanActivate } from '@nestjs/common';
import { FileService } from 'src/engine/modules/file/services/file.service';
import { FilePathGuard } from 'src/engine/modules/file/guards/file-path-guard';
import { FileController } from './file.controller';
describe('FileController', () => {
let controller: FileController;
const mock_FilePathGuard: CanActivate = { canActivate: jest.fn(() => true) };
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
@ -16,7 +19,10 @@ describe('FileController', () => {
useValue: {},
},
],
}).compile();
})
.overrideGuard(FilePathGuard)
.useValue(mock_FilePathGuard)
.compile();
controller = module.get<FileController>(FileController);
});

View File

@ -1,7 +1,8 @@
import { Controller, Get, Param, Res } from '@nestjs/common';
import { Controller, Get, Param, Res, UseGuards } from '@nestjs/common';
import { Response } from 'express';
import { FilePathGuard } from 'src/engine/modules/file/guards/file-path-guard';
import {
checkFilePath,
checkFilename,
@ -10,6 +11,7 @@ import { FileService } from 'src/engine/modules/file/services/file.service';
// TODO: Add cookie authentication
@Controller('files')
@UseGuards(FilePathGuard)
export class FileController {
constructor(private readonly fileService: FileService) {}

View File

@ -0,0 +1,11 @@
import { Module } from '@nestjs/common';
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
import { FileUploadResolver } from 'src/engine/modules/file/file-upload/resolvers/file-upload.resolver';
import { FileUploadService } from 'src/engine/modules/file/file-upload/services/file-upload.service';
@Module({
providers: [FileUploadService, FileUploadResolver, EnvironmentService],
exports: [FileUploadService, FileUploadResolver],
})
export class FileUploadModule {}

View File

@ -1,6 +1,6 @@
import { Test, TestingModule } from '@nestjs/testing';
import { FileUploadService } from 'src/engine/modules/file/services/file-upload.service';
import { FileUploadService } from 'src/engine/modules/file/file-upload/services/file-upload.service';
import { FileUploadResolver } from './file-upload.resolver';

View File

@ -5,7 +5,7 @@ import { GraphQLUpload, FileUpload } from 'graphql-upload';
import { FileFolder } from 'src/engine/modules/file/interfaces/file-folder.interface';
import { FileUploadService } from 'src/engine/modules/file/services/file-upload.service';
import { FileUploadService } from 'src/engine/modules/file/file-upload/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';

View File

@ -1,20 +1,17 @@
import { Module } from '@nestjs/common';
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
import { FilePathGuard } from 'src/engine/modules/file/guards/file-path-guard';
import { AuthModule } from 'src/engine/modules/auth/auth.module';
import { FileUploadModule } from 'src/engine/modules/file/file-upload/file-upload.module';
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,
EnvironmentService,
],
exports: [FileService, FileUploadService],
imports: [FileUploadModule, AuthModule],
providers: [FileService, EnvironmentService, FilePathGuard],
exports: [FileService],
controllers: [FileController],
})
export class FileModule {}

View File

@ -0,0 +1,52 @@
import {
Injectable,
CanActivate,
ExecutionContext,
HttpException,
HttpStatus,
} from '@nestjs/common';
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
import { TokenService } from 'src/engine/modules/auth/services/token.service';
@Injectable()
export class FilePathGuard implements CanActivate {
constructor(
private readonly tokenService: TokenService,
private readonly environmentService: EnvironmentService,
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const query = context.switchToHttp().getRequest().query;
if (query && query['token']) {
return !(await this.isExpired(query['token']));
}
return true;
}
private async isExpired(signedExpirationDate: string): Promise<boolean> {
const decodedPayload = await this.tokenService.decodePayload(
signedExpirationDate,
{
secret: this.environmentService.get('FILE_TOKEN_SECRET'),
},
);
const expirationDate = decodedPayload?.['expiration_date'];
if (!expirationDate) {
return true;
}
if (new Date(expirationDate) < new Date()) {
throw new HttpException(
'This url has expired. Please reload twenty page and open file again.',
HttpStatus.FORBIDDEN,
);
}
return false;
}
}