Fix white screen on token expire (#5271)
While using middleware (executed pre-graphql) for graphql endpoint, we need to swallow exception and return errors with a 200. Otherwise it's not a valid graphql response
This commit is contained in:
@ -21,8 +21,8 @@ import { MetadataGraphQLApiModule } from 'src/engine/api/graphql/metadata-graphq
|
|||||||
import { GraphQLConfigModule } from 'src/engine/api/graphql/graphql-config/graphql-config.module';
|
import { GraphQLConfigModule } from 'src/engine/api/graphql/graphql-config/graphql-config.module';
|
||||||
import { GraphQLConfigService } from 'src/engine/api/graphql/graphql-config/graphql-config.service';
|
import { GraphQLConfigService } from 'src/engine/api/graphql/graphql-config/graphql-config.service';
|
||||||
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
||||||
import { UserWorkspaceMiddleware } from 'src/engine/middlewares/user-workspace.middleware';
|
|
||||||
import { WorkspaceCacheVersionModule } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.module';
|
import { WorkspaceCacheVersionModule } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.module';
|
||||||
|
import { GraphQLHydrateRequestFromTokenMiddleware } from 'src/engine/middlewares/graphql-hydrate-request-from-token.middleware';
|
||||||
|
|
||||||
import { CoreEngineModule } from './engine/core-modules/core-engine.module';
|
import { CoreEngineModule } from './engine/core-modules/core-engine.module';
|
||||||
import { IntegrationsModule } from './engine/integrations/integrations.module';
|
import { IntegrationsModule } from './engine/integrations/integrations.module';
|
||||||
@ -79,11 +79,11 @@ export class AppModule {
|
|||||||
|
|
||||||
configure(consumer: MiddlewareConsumer) {
|
configure(consumer: MiddlewareConsumer) {
|
||||||
consumer
|
consumer
|
||||||
.apply(UserWorkspaceMiddleware)
|
.apply(GraphQLHydrateRequestFromTokenMiddleware)
|
||||||
.forRoutes({ path: 'graphql', method: RequestMethod.ALL });
|
.forRoutes({ path: 'graphql', method: RequestMethod.ALL });
|
||||||
|
|
||||||
consumer
|
consumer
|
||||||
.apply(UserWorkspaceMiddleware)
|
.apply(GraphQLHydrateRequestFromTokenMiddleware)
|
||||||
.forRoutes({ path: 'metadata', method: RequestMethod.ALL });
|
.forRoutes({ path: 'metadata', method: RequestMethod.ALL });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,74 @@
|
|||||||
|
import { Injectable, NestMiddleware } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { Request, Response, NextFunction } from 'express';
|
||||||
|
|
||||||
|
import { TokenService } from 'src/engine/core-modules/auth/services/token.service';
|
||||||
|
import { JwtData } from 'src/engine/core-modules/auth/types/jwt-data.type';
|
||||||
|
import { ExceptionHandlerService } from 'src/engine/integrations/exception-handler/exception-handler.service';
|
||||||
|
import { WorkspaceCacheVersionService } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.service';
|
||||||
|
import { handleExceptionAndConvertToGraphQLError } from 'src/engine/utils/global-exception-handler.util';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class GraphQLHydrateRequestFromTokenMiddleware
|
||||||
|
implements NestMiddleware
|
||||||
|
{
|
||||||
|
constructor(
|
||||||
|
private readonly tokenService: TokenService,
|
||||||
|
private readonly workspaceCacheVersionService: WorkspaceCacheVersionService,
|
||||||
|
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',
|
||||||
|
'IntrospectionQuery',
|
||||||
|
];
|
||||||
|
|
||||||
|
if (
|
||||||
|
!this.tokenService.isTokenPresent(req) &&
|
||||||
|
(!body?.operationName || excludedOperations.includes(body.operationName))
|
||||||
|
) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
let data: JwtData;
|
||||||
|
|
||||||
|
try {
|
||||||
|
data = await this.tokenService.validateToken(req);
|
||||||
|
const cacheVersion = await this.workspaceCacheVersionService.getVersion(
|
||||||
|
data.workspace.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
req.user = data.user;
|
||||||
|
req.workspace = data.workspace;
|
||||||
|
req.cacheVersion = cacheVersion;
|
||||||
|
} catch (error) {
|
||||||
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||||
|
res.write(
|
||||||
|
JSON.stringify({
|
||||||
|
errors: [
|
||||||
|
handleExceptionAndConvertToGraphQLError(
|
||||||
|
error,
|
||||||
|
this.exceptionHandlerService,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
res.end();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,49 +0,0 @@
|
|||||||
import { Injectable, NestMiddleware } from '@nestjs/common';
|
|
||||||
|
|
||||||
import { Request, Response, NextFunction } from 'express';
|
|
||||||
|
|
||||||
import { TokenService } from 'src/engine/core-modules/auth/services/token.service';
|
|
||||||
import { WorkspaceCacheVersionService } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.service';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class UserWorkspaceMiddleware implements NestMiddleware {
|
|
||||||
constructor(
|
|
||||||
private readonly tokenService: TokenService,
|
|
||||||
private readonly workspaceCacheVersionService: WorkspaceCacheVersionService,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
async use(req: Request, res: Response, next: NextFunction) {
|
|
||||||
const body = req.body;
|
|
||||||
|
|
||||||
const excludedOperations = [
|
|
||||||
'GetClientConfig',
|
|
||||||
'GetCurrentUser',
|
|
||||||
'GetWorkspaceFromInviteHash',
|
|
||||||
'Track',
|
|
||||||
'CheckUserExists',
|
|
||||||
'Challenge',
|
|
||||||
'Verify',
|
|
||||||
'SignUp',
|
|
||||||
'RenewToken',
|
|
||||||
'IntrospectionQuery',
|
|
||||||
];
|
|
||||||
|
|
||||||
if (
|
|
||||||
!this.tokenService.isTokenPresent(req) &&
|
|
||||||
(!body?.operationName || excludedOperations.includes(body.operationName))
|
|
||||||
) {
|
|
||||||
return next();
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await this.tokenService.validateToken(req);
|
|
||||||
const cacheVersion = await this.workspaceCacheVersionService.getVersion(
|
|
||||||
data.workspace.id,
|
|
||||||
);
|
|
||||||
|
|
||||||
req.user = data.user;
|
|
||||||
req.workspace = data.workspace;
|
|
||||||
req.cacheVersion = cacheVersion;
|
|
||||||
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user