feat: generate secret function and replaced few instances (#7810)
This PR fixes #4588 --------- Co-authored-by: Félix Malfait <felix@twenty.com> Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -2,14 +2,14 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { JwtModule as NestJwtModule } from '@nestjs/jwt';
|
||||
|
||||
import { JwtWrapperService } from 'src/engine/core-modules/jwt/services/jwt-wrapper.service';
|
||||
import { EnvironmentModule } from 'src/engine/core-modules/environment/environment.module';
|
||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||
import { JwtWrapperService } from 'src/engine/core-modules/jwt/services/jwt-wrapper.service';
|
||||
|
||||
const InternalJwtModule = NestJwtModule.registerAsync({
|
||||
useFactory: async (environmentService: EnvironmentService) => {
|
||||
return {
|
||||
secret: environmentService.get('ACCESS_TOKEN_SECRET'),
|
||||
secret: environmentService.get('APP_SECRET'),
|
||||
signOptions: {
|
||||
expiresIn: environmentService.get('ACCESS_TOKEN_EXPIRES_IN'),
|
||||
},
|
||||
|
||||
@ -1,11 +1,30 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
||||
import { JwtService, JwtSignOptions, JwtVerifyOptions } from '@nestjs/jwt';
|
||||
|
||||
import { createHash } from 'crypto';
|
||||
|
||||
import * as jwt from 'jsonwebtoken';
|
||||
|
||||
import {
|
||||
AuthException,
|
||||
AuthExceptionCode,
|
||||
} from 'src/engine/core-modules/auth/auth.exception';
|
||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||
|
||||
type WorkspaceTokenType =
|
||||
| 'ACCESS'
|
||||
| 'LOGIN'
|
||||
| 'REFRESH'
|
||||
| 'FILE'
|
||||
| 'POSTGRES_PROXY'
|
||||
| 'REMOTE_SERVER';
|
||||
|
||||
@Injectable()
|
||||
export class JwtWrapperService {
|
||||
constructor(private readonly jwtService: JwtService) {}
|
||||
constructor(
|
||||
private readonly jwtService: JwtService,
|
||||
private readonly environmentService: EnvironmentService,
|
||||
) {}
|
||||
|
||||
sign(payload: string | object, options?: JwtSignOptions): string {
|
||||
// Typescript does not handle well the overloads of the sign method, helping it a little bit
|
||||
@ -20,7 +39,58 @@ export class JwtWrapperService {
|
||||
return this.jwtService.verify(token, options);
|
||||
}
|
||||
|
||||
decode<T = any>(payload: string, options: jwt.DecodeOptions): T {
|
||||
decode<T = any>(payload: string, options?: jwt.DecodeOptions): T {
|
||||
return this.jwtService.decode(payload, options);
|
||||
}
|
||||
|
||||
verifyWorkspaceToken(
|
||||
token: string,
|
||||
type: WorkspaceTokenType,
|
||||
options?: JwtVerifyOptions,
|
||||
) {
|
||||
const payload = this.decode(token, {
|
||||
json: true,
|
||||
});
|
||||
|
||||
// TODO: check if this is really needed
|
||||
if (type !== 'FILE' && !payload.sub) {
|
||||
throw new UnauthorizedException('No payload sub');
|
||||
}
|
||||
|
||||
try {
|
||||
return this.jwtService.verify(token, {
|
||||
...options,
|
||||
secret: this.generateAppSecret(type, payload.workspaceId),
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof jwt.TokenExpiredError) {
|
||||
throw new AuthException(
|
||||
'Token has expired.',
|
||||
AuthExceptionCode.UNAUTHENTICATED,
|
||||
);
|
||||
} else if (error instanceof jwt.JsonWebTokenError) {
|
||||
throw new AuthException(
|
||||
'Token invalid.',
|
||||
AuthExceptionCode.UNAUTHENTICATED,
|
||||
);
|
||||
} else {
|
||||
throw new AuthException(
|
||||
'Unknown token error.',
|
||||
AuthExceptionCode.INVALID_INPUT,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
generateAppSecret(type: WorkspaceTokenType, workspaceId?: string): string {
|
||||
const appSecret = this.environmentService.get('APP_SECRET');
|
||||
|
||||
if (!appSecret) {
|
||||
throw new Error('APP_SECRET is not set');
|
||||
}
|
||||
|
||||
return createHash('sha256')
|
||||
.update(`${appSecret}${workspaceId}${type}`)
|
||||
.digest('hex');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user