Files
twenty/packages/twenty-server/src/engine/middlewares/graphql-hydrate-request-from-token.middleware.ts

106 lines
3.1 KiB
TypeScript

import { Injectable, NestMiddleware } from '@nestjs/common';
import { NextFunction, Request, Response } from 'express';
import { AuthGraphqlApiExceptionFilter } from 'src/engine/core-modules/auth/filters/auth-graphql-api-exception.filter';
import { TokenService } from 'src/engine/core-modules/auth/services/token.service';
import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
import { ExceptionHandlerService } from 'src/engine/core-modules/exception-handler/exception-handler.service';
import { WorkspaceMetadataVersionService } from 'src/engine/metadata-modules/workspace-metadata-version/workspace-metadata-version.service';
import { handleExceptionAndConvertToGraphQLError } from 'src/engine/utils/global-exception-handler.util';
class GraphqlTokenValidationProxy {
private tokenService: TokenService;
constructor(tokenService: TokenService) {
this.tokenService = tokenService;
}
async validateToken(req: Request) {
try {
return await this.tokenService.validateToken(req);
} catch (error) {
const authGraphqlApiExceptionFilter = new AuthGraphqlApiExceptionFilter();
throw authGraphqlApiExceptionFilter.catch(error);
}
}
}
@Injectable()
export class GraphQLHydrateRequestFromTokenMiddleware
implements NestMiddleware
{
constructor(
private readonly tokenService: TokenService,
private readonly workspaceMetadataVersionService: WorkspaceMetadataVersionService,
private readonly exceptionHandlerService: ExceptionHandlerService,
) {}
async use(req: Request, res: Response, next: NextFunction) {
const body = req.body;
const excludedOperations = [
'GetClientConfig',
'GetCurrentUser',
'GetWorkspaceFromInviteHash',
'Track',
'CheckUserExists',
'Challenge',
'Verify',
'SignUp',
'RenewToken',
'EmailPasswordResetLink',
'ValidatePasswordResetToken',
'UpdatePasswordViaResetToken',
'IntrospectionQuery',
'ExchangeAuthorizationCode',
];
if (
!this.tokenService.isTokenPresent(req) &&
(!body?.operationName || excludedOperations.includes(body.operationName))
) {
return next();
}
let data: AuthContext;
try {
const graphqlTokenValidationProxy = new GraphqlTokenValidationProxy(
this.tokenService,
);
data = await graphqlTokenValidationProxy.validateToken(req);
const metadataVersion =
await this.workspaceMetadataVersionService.getMetadataVersion(
data.workspace.id,
);
req.user = data.user;
req.apiKey = data.apiKey;
req.workspace = data.workspace;
req.workspaceId = data.workspace.id;
req.workspaceMetadataVersion = metadataVersion;
req.workspaceMemberId = data.workspaceMemberId;
} catch (error) {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.write(
JSON.stringify({
errors: [
handleExceptionAndConvertToGraphQLError(
error,
this.exceptionHandlerService,
),
],
}),
);
res.end();
return;
}
next();
}
}