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:
@ -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);
|
||||
});
|
||||
|
||||
@ -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) {}
|
||||
|
||||
|
||||
@ -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 {}
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
@ -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 {}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user