Rename refreshToken to appToken and add fields (#4691)
This commit is contained in:
@ -0,0 +1,39 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||||
|
|
||||||
|
export class UpdateRefreshTokenTable1711624086253
|
||||||
|
implements MigrationInterface
|
||||||
|
{
|
||||||
|
name = 'UpdateRefreshTokenTable1711624086253';
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "core"."refreshToken" RENAME TO "appToken"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "core"."appToken" ADD "workspaceId" uuid`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "core"."appToken" ADD "type" text NOT NULL DEFAULT 'REFRESH_TOKEN'`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(`ALTER TABLE "core"."appToken" ADD "value" text`);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "core"."appToken" ADD CONSTRAINT "FK_d6ae19a7aa2bbd4919053257772" FOREIGN KEY ("workspaceId") REFERENCES "core"."workspace"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "core"."appToken" DROP CONSTRAINT "FK_d6ae19a7aa2bbd4919053257772"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "core"."appToken" DROP COLUMN "value"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(`ALTER TABLE "core"."appToken" DROP COLUMN "type"`);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "core"."appToken" DROP COLUMN "workspaceId"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "core"."appToken" RENAME TO "refreshToken"`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,7 +6,7 @@ import { EnvironmentService } from 'src/engine/integrations/environment/environm
|
|||||||
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
|
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
|
||||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||||
import { RefreshToken } from 'src/engine/core-modules/refresh-token/refresh-token.entity';
|
import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
|
||||||
import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
||||||
import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
|
import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
|
||||||
import { BillingSubscriptionItem } from 'src/engine/core-modules/billing/entities/billing-subscription-item.entity';
|
import { BillingSubscriptionItem } from 'src/engine/core-modules/billing/entities/billing-subscription-item.entity';
|
||||||
@ -28,7 +28,7 @@ export class TypeORMService implements OnModuleInit, OnModuleDestroy {
|
|||||||
User,
|
User,
|
||||||
Workspace,
|
Workspace,
|
||||||
UserWorkspace,
|
UserWorkspace,
|
||||||
RefreshToken,
|
AppToken,
|
||||||
FeatureFlagEntity,
|
FeatureFlagEntity,
|
||||||
BillingSubscription,
|
BillingSubscription,
|
||||||
BillingSubscriptionItem,
|
BillingSubscriptionItem,
|
||||||
|
|||||||
@ -4,13 +4,11 @@ import {
|
|||||||
ReadResolverOpts,
|
ReadResolverOpts,
|
||||||
} from '@ptc-org/nestjs-query-graphql';
|
} from '@ptc-org/nestjs-query-graphql';
|
||||||
|
|
||||||
|
import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
|
||||||
|
import { CreateAppTokenInput } from 'src/engine/core-modules/app-token/dtos/create-app-token.input';
|
||||||
import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard';
|
import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard';
|
||||||
|
|
||||||
import { RefreshToken } from './refresh-token.entity';
|
export const appTokenAutoResolverOpts: AutoResolverOpts<
|
||||||
|
|
||||||
import { CreateRefreshTokenInput } from './dtos/create-refresh-token.input';
|
|
||||||
|
|
||||||
export const refreshTokenAutoResolverOpts: AutoResolverOpts<
|
|
||||||
any,
|
any,
|
||||||
any,
|
any,
|
||||||
unknown,
|
unknown,
|
||||||
@ -19,9 +17,9 @@ export const refreshTokenAutoResolverOpts: AutoResolverOpts<
|
|||||||
PagingStrategies
|
PagingStrategies
|
||||||
>[] = [
|
>[] = [
|
||||||
{
|
{
|
||||||
EntityClass: RefreshToken,
|
EntityClass: AppToken,
|
||||||
DTOClass: RefreshToken,
|
DTOClass: AppToken,
|
||||||
CreateDTOClass: CreateRefreshTokenInput,
|
CreateDTOClass: CreateAppTokenInput,
|
||||||
enableTotalCount: true,
|
enableTotalCount: true,
|
||||||
pagingStrategy: PagingStrategies.CURSOR,
|
pagingStrategy: PagingStrategies.CURSOR,
|
||||||
read: {
|
read: {
|
||||||
@ -11,19 +11,22 @@ import {
|
|||||||
} from 'typeorm';
|
} from 'typeorm';
|
||||||
import { BeforeCreateOne, IDField } from '@ptc-org/nestjs-query-graphql';
|
import { BeforeCreateOne, IDField } from '@ptc-org/nestjs-query-graphql';
|
||||||
|
|
||||||
|
import { BeforeCreateOneAppToken } from 'src/engine/core-modules/app-token/hooks/before-create-one-app-token.hook';
|
||||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||||
|
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||||
|
export enum AppTokenType {
|
||||||
|
RefreshToken = 'REFRESH_TOKEN',
|
||||||
|
}
|
||||||
|
|
||||||
import { BeforeCreateOneRefreshToken } from './hooks/before-create-one-refresh-token.hook';
|
@Entity({ name: 'appToken', schema: 'core' })
|
||||||
|
@ObjectType('AppToken')
|
||||||
@Entity({ name: 'refreshToken', schema: 'core' })
|
@BeforeCreateOne(BeforeCreateOneAppToken)
|
||||||
@ObjectType('RefreshToken')
|
export class AppToken {
|
||||||
@BeforeCreateOne(BeforeCreateOneRefreshToken)
|
|
||||||
export class RefreshToken {
|
|
||||||
@IDField(() => ID)
|
@IDField(() => ID)
|
||||||
@PrimaryGeneratedColumn('uuid')
|
@PrimaryGeneratedColumn('uuid')
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
@ManyToOne(() => User, (user) => user.refreshTokens, {
|
@ManyToOne(() => User, (user) => user.appTokens, {
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
})
|
})
|
||||||
@JoinColumn({ name: 'userId' })
|
@JoinColumn({ name: 'userId' })
|
||||||
@ -32,6 +35,22 @@ export class RefreshToken {
|
|||||||
@Column()
|
@Column()
|
||||||
userId: string;
|
userId: string;
|
||||||
|
|
||||||
|
@ManyToOne(() => Workspace, (workspace) => workspace.appTokens, {
|
||||||
|
onDelete: 'CASCADE',
|
||||||
|
})
|
||||||
|
@JoinColumn({ name: 'workspaceId' })
|
||||||
|
workspace: Workspace;
|
||||||
|
|
||||||
|
@Column({ nullable: true })
|
||||||
|
workspaceId: string;
|
||||||
|
|
||||||
|
@Field()
|
||||||
|
@Column({ nullable: false, type: 'text', default: AppTokenType.RefreshToken })
|
||||||
|
type: AppTokenType;
|
||||||
|
|
||||||
|
@Column({ nullable: true, type: 'text' })
|
||||||
|
value: string;
|
||||||
|
|
||||||
@Field()
|
@Field()
|
||||||
@Column('timestamp with time zone')
|
@Column('timestamp with time zone')
|
||||||
expiresAt: Date;
|
expiresAt: Date;
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { NestjsQueryGraphQLModule } from '@ptc-org/nestjs-query-graphql';
|
||||||
|
import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
|
||||||
|
|
||||||
|
import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
|
||||||
|
import { appTokenAutoResolverOpts } from 'src/engine/core-modules/app-token/app-token.auto-resolver-opts';
|
||||||
|
import { AppTokenService } from 'src/engine/core-modules/app-token/services/app-token.service';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [
|
||||||
|
NestjsQueryGraphQLModule.forFeature({
|
||||||
|
imports: [NestjsQueryTypeOrmModule.forFeature([AppToken], 'core')],
|
||||||
|
services: [AppTokenService],
|
||||||
|
resolvers: appTokenAutoResolverOpts,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class AppTokenModule {}
|
||||||
@ -3,7 +3,7 @@ import { Field, InputType } from '@nestjs/graphql';
|
|||||||
import { IsDate, IsNotEmpty } from 'class-validator';
|
import { IsDate, IsNotEmpty } from 'class-validator';
|
||||||
|
|
||||||
@InputType()
|
@InputType()
|
||||||
export class CreateRefreshTokenInput {
|
export class CreateAppTokenInput {
|
||||||
@IsDate()
|
@IsDate()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
@Field()
|
@Field()
|
||||||
@ -4,9 +4,9 @@ import {
|
|||||||
} from '@ptc-org/nestjs-query-graphql';
|
} from '@ptc-org/nestjs-query-graphql';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
import { RefreshToken } from 'src/engine/core-modules/refresh-token/refresh-token.entity';
|
import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
|
||||||
|
|
||||||
export class BeforeCreateOneRefreshToken<T extends RefreshToken>
|
export class BeforeCreateOneAppToken<T extends AppToken>
|
||||||
implements BeforeCreateOneHook<T, any>
|
implements BeforeCreateOneHook<T, any>
|
||||||
{
|
{
|
||||||
async run(
|
async run(
|
||||||
@ -1,25 +1,24 @@
|
|||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||||
|
|
||||||
import { RefreshToken } from 'src/engine/core-modules/refresh-token/refresh-token.entity';
|
import { AppTokenService } from 'src/engine/core-modules/app-token/services/app-token.service';
|
||||||
|
import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
|
||||||
|
|
||||||
import { RefreshTokenService } from './refresh-token.service';
|
describe('AppTokenService', () => {
|
||||||
|
let service: AppTokenService;
|
||||||
describe('RefreshTokenService', () => {
|
|
||||||
let service: RefreshTokenService;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
providers: [
|
providers: [
|
||||||
RefreshTokenService,
|
AppTokenService,
|
||||||
{
|
{
|
||||||
provide: getRepositoryToken(RefreshToken),
|
provide: getRepositoryToken(AppToken),
|
||||||
useValue: {},
|
useValue: {},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}).compile();
|
}).compile();
|
||||||
|
|
||||||
service = module.get<RefreshTokenService>(RefreshTokenService);
|
service = module.get<AppTokenService>(AppTokenService);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be defined', () => {
|
it('should be defined', () => {
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
|
||||||
|
|
||||||
|
import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
|
||||||
|
|
||||||
|
export class AppTokenService extends TypeOrmQueryService<AppToken> {}
|
||||||
@ -7,7 +7,7 @@ import { HttpModule } from '@nestjs/axios';
|
|||||||
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
||||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||||
import { RefreshToken } from 'src/engine/core-modules/refresh-token/refresh-token.entity';
|
import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
|
||||||
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
|
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
|
||||||
import { UserModule } from 'src/engine/core-modules/user/user.module';
|
import { UserModule } from 'src/engine/core-modules/user/user.module';
|
||||||
import { WorkspaceManagerModule } from 'src/engine/workspace-manager/workspace-manager.module';
|
import { WorkspaceManagerModule } from 'src/engine/workspace-manager/workspace-manager.module';
|
||||||
@ -48,7 +48,7 @@ const jwtModule = JwtModule.registerAsync({
|
|||||||
WorkspaceManagerModule,
|
WorkspaceManagerModule,
|
||||||
TypeORMModule,
|
TypeORMModule,
|
||||||
TypeOrmModule.forFeature(
|
TypeOrmModule.forFeature(
|
||||||
[Workspace, User, RefreshToken, FeatureFlagEntity],
|
[Workspace, User, AppToken, FeatureFlagEntity],
|
||||||
'core',
|
'core',
|
||||||
),
|
),
|
||||||
HttpModule,
|
HttpModule,
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import { InjectRepository } from '@nestjs/typeorm';
|
|||||||
|
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
|
|
||||||
|
import { AppTokenInput } from 'src/engine/core-modules/auth/dto/app-token.input';
|
||||||
import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard';
|
import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard';
|
||||||
import { AuthUser } from 'src/engine/decorators/auth/auth-user.decorator';
|
import { AuthUser } from 'src/engine/decorators/auth/auth-user.decorator';
|
||||||
import { assert } from 'src/utils/assert';
|
import { assert } from 'src/utils/assert';
|
||||||
@ -34,7 +35,6 @@ import { ExchangeAuthCode } from 'src/engine/core-modules/auth/dto/exchange-auth
|
|||||||
|
|
||||||
import { ApiKeyToken, AuthTokens } from './dto/token.entity';
|
import { ApiKeyToken, AuthTokens } from './dto/token.entity';
|
||||||
import { TokenService } from './services/token.service';
|
import { TokenService } from './services/token.service';
|
||||||
import { RefreshTokenInput } from './dto/refresh-token.input';
|
|
||||||
import { Verify } from './dto/verify.entity';
|
import { Verify } from './dto/verify.entity';
|
||||||
import { VerifyInput } from './dto/verify.input';
|
import { VerifyInput } from './dto/verify.input';
|
||||||
import { AuthService } from './services/auth.service';
|
import { AuthService } from './services/auth.service';
|
||||||
@ -170,13 +170,13 @@ export class AuthResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Mutation(() => AuthTokens)
|
@Mutation(() => AuthTokens)
|
||||||
async renewToken(@Args() args: RefreshTokenInput): Promise<AuthTokens> {
|
async renewToken(@Args() args: AppTokenInput): Promise<AuthTokens> {
|
||||||
if (!args.refreshToken) {
|
if (!args.appToken) {
|
||||||
throw new BadRequestException('Refresh token is mendatory');
|
throw new BadRequestException('Refresh token is mendatory');
|
||||||
}
|
}
|
||||||
|
|
||||||
const tokens = await this.tokenService.generateTokensFromRefreshToken(
|
const tokens = await this.tokenService.generateTokensFromRefreshToken(
|
||||||
args.refreshToken,
|
args.appToken,
|
||||||
);
|
);
|
||||||
|
|
||||||
return { tokens: tokens };
|
return { tokens: tokens };
|
||||||
|
|||||||
@ -3,9 +3,9 @@ import { ArgsType, Field } from '@nestjs/graphql';
|
|||||||
import { IsNotEmpty, IsString } from 'class-validator';
|
import { IsNotEmpty, IsString } from 'class-validator';
|
||||||
|
|
||||||
@ArgsType()
|
@ArgsType()
|
||||||
export class RefreshTokenInput {
|
export class AppTokenInput {
|
||||||
@Field(() => String)
|
@Field(() => String)
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
@IsString()
|
@IsString()
|
||||||
refreshToken: string;
|
appToken: string;
|
||||||
}
|
}
|
||||||
@ -3,7 +3,7 @@ import { JwtService } from '@nestjs/jwt';
|
|||||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||||
|
|
||||||
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
||||||
import { RefreshToken } from 'src/engine/core-modules/refresh-token/refresh-token.entity';
|
import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
|
||||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||||
import { JwtAuthStrategy } from 'src/engine/core-modules/auth/strategies/jwt.auth.strategy';
|
import { JwtAuthStrategy } from 'src/engine/core-modules/auth/strategies/jwt.auth.strategy';
|
||||||
import { EmailService } from 'src/engine/integrations/email/email.service';
|
import { EmailService } from 'src/engine/integrations/email/email.service';
|
||||||
@ -39,7 +39,7 @@ describe('TokenService', () => {
|
|||||||
useValue: {},
|
useValue: {},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: getRepositoryToken(RefreshToken, 'core'),
|
provide: getRepositoryToken(AppToken, 'core'),
|
||||||
useValue: {},
|
useValue: {},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -34,7 +34,10 @@ import {
|
|||||||
} from 'src/engine/core-modules/auth/dto/token.entity';
|
} from 'src/engine/core-modules/auth/dto/token.entity';
|
||||||
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
||||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||||
import { RefreshToken } from 'src/engine/core-modules/refresh-token/refresh-token.entity';
|
import {
|
||||||
|
AppToken,
|
||||||
|
AppTokenType,
|
||||||
|
} from 'src/engine/core-modules/app-token/app-token.entity';
|
||||||
import { ValidatePasswordResetToken } from 'src/engine/core-modules/auth/dto/validate-password-reset-token.entity';
|
import { ValidatePasswordResetToken } from 'src/engine/core-modules/auth/dto/validate-password-reset-token.entity';
|
||||||
import { EmailService } from 'src/engine/integrations/email/email.service';
|
import { EmailService } from 'src/engine/integrations/email/email.service';
|
||||||
import { InvalidatePassword } from 'src/engine/core-modules/auth/dto/invalidate-password.entity';
|
import { InvalidatePassword } from 'src/engine/core-modules/auth/dto/invalidate-password.entity';
|
||||||
@ -53,8 +56,8 @@ export class TokenService {
|
|||||||
private readonly environmentService: EnvironmentService,
|
private readonly environmentService: EnvironmentService,
|
||||||
@InjectRepository(User, 'core')
|
@InjectRepository(User, 'core')
|
||||||
private readonly userRepository: Repository<User>,
|
private readonly userRepository: Repository<User>,
|
||||||
@InjectRepository(RefreshToken, 'core')
|
@InjectRepository(AppToken, 'core')
|
||||||
private readonly refreshTokenRepository: Repository<RefreshToken>,
|
private readonly appTokenRepository: Repository<AppToken>,
|
||||||
@InjectRepository(Workspace, 'core')
|
@InjectRepository(Workspace, 'core')
|
||||||
private readonly workspaceRepository: Repository<Workspace>,
|
private readonly workspaceRepository: Repository<Workspace>,
|
||||||
private readonly emailService: EmailService,
|
private readonly emailService: EmailService,
|
||||||
@ -103,15 +106,15 @@ export class TokenService {
|
|||||||
const refreshTokenPayload = {
|
const refreshTokenPayload = {
|
||||||
userId,
|
userId,
|
||||||
expiresAt,
|
expiresAt,
|
||||||
|
type: AppTokenType.RefreshToken,
|
||||||
};
|
};
|
||||||
const jwtPayload = {
|
const jwtPayload = {
|
||||||
sub: userId,
|
sub: userId,
|
||||||
};
|
};
|
||||||
|
|
||||||
const refreshToken =
|
const refreshToken = this.appTokenRepository.create(refreshTokenPayload);
|
||||||
this.refreshTokenRepository.create(refreshTokenPayload);
|
|
||||||
|
|
||||||
await this.refreshTokenRepository.save(refreshToken);
|
await this.appTokenRepository.save(refreshToken);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
token: this.jwtService.sign(jwtPayload, {
|
token: this.jwtService.sign(jwtPayload, {
|
||||||
@ -360,7 +363,7 @@ export class TokenService {
|
|||||||
UnprocessableEntityException,
|
UnprocessableEntityException,
|
||||||
);
|
);
|
||||||
|
|
||||||
const token = await this.refreshTokenRepository.findOneBy({
|
const token = await this.appTokenRepository.findOneBy({
|
||||||
id: jwtPayload.jti,
|
id: jwtPayload.jti,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -379,15 +382,16 @@ export class TokenService {
|
|||||||
) {
|
) {
|
||||||
// Revoke all user refresh tokens
|
// Revoke all user refresh tokens
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
user.refreshTokens.map(
|
user.appTokens.map(async ({ id, type }) => {
|
||||||
async ({ id }) =>
|
if (type === AppTokenType.RefreshToken) {
|
||||||
await this.refreshTokenRepository.update(
|
await this.appTokenRepository.update(
|
||||||
{ id },
|
{ id },
|
||||||
{
|
{
|
||||||
revokedAt: new Date(),
|
revokedAt: new Date(),
|
||||||
},
|
},
|
||||||
),
|
);
|
||||||
),
|
}
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
throw new ForbiddenException(
|
throw new ForbiddenException(
|
||||||
@ -408,7 +412,7 @@ export class TokenService {
|
|||||||
} = await this.verifyRefreshToken(token);
|
} = await this.verifyRefreshToken(token);
|
||||||
|
|
||||||
// Revoke old refresh token
|
// Revoke old refresh token
|
||||||
await this.refreshTokenRepository.update(
|
await this.appTokenRepository.update(
|
||||||
{
|
{
|
||||||
id,
|
id,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { Module } from '@nestjs/common';
|
|||||||
|
|
||||||
import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.module';
|
import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.module';
|
||||||
import { UserModule } from 'src/engine/core-modules/user/user.module';
|
import { UserModule } from 'src/engine/core-modules/user/user.module';
|
||||||
import { RefreshTokenModule } from 'src/engine/core-modules/refresh-token/refresh-token.module';
|
import { AppTokenModule } from 'src/engine/core-modules/app-token/app-token.module';
|
||||||
import { AuthModule } from 'src/engine/core-modules/auth/auth.module';
|
import { AuthModule } from 'src/engine/core-modules/auth/auth.module';
|
||||||
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
|
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
|
||||||
import { OpenApiModule } from 'src/engine/core-modules/open-api/open-api.module';
|
import { OpenApiModule } from 'src/engine/core-modules/open-api/open-api.module';
|
||||||
@ -25,7 +25,7 @@ import { ClientConfigModule } from './client-config/client-config.module';
|
|||||||
FeatureFlagModule,
|
FeatureFlagModule,
|
||||||
FileModule,
|
FileModule,
|
||||||
OpenApiModule,
|
OpenApiModule,
|
||||||
RefreshTokenModule,
|
AppTokenModule,
|
||||||
TimelineMessagingModule,
|
TimelineMessagingModule,
|
||||||
TimelineCalendarEventModule,
|
TimelineCalendarEventModule,
|
||||||
UserModule,
|
UserModule,
|
||||||
|
|||||||
@ -1,20 +0,0 @@
|
|||||||
import { Module } from '@nestjs/common';
|
|
||||||
|
|
||||||
import { NestjsQueryGraphQLModule } from '@ptc-org/nestjs-query-graphql';
|
|
||||||
import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
|
|
||||||
|
|
||||||
import { RefreshToken } from './refresh-token.entity';
|
|
||||||
import { refreshTokenAutoResolverOpts } from './refresh-token.auto-resolver-opts';
|
|
||||||
|
|
||||||
import { RefreshTokenService } from './services/refresh-token.service';
|
|
||||||
|
|
||||||
@Module({
|
|
||||||
imports: [
|
|
||||||
NestjsQueryGraphQLModule.forFeature({
|
|
||||||
imports: [NestjsQueryTypeOrmModule.forFeature([RefreshToken], 'core')],
|
|
||||||
services: [RefreshTokenService],
|
|
||||||
resolvers: refreshTokenAutoResolverOpts,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
})
|
|
||||||
export class RefreshTokenModule {}
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
|
|
||||||
|
|
||||||
import { RefreshToken } from 'src/engine/core-modules/refresh-token/refresh-token.entity';
|
|
||||||
|
|
||||||
export class RefreshTokenService extends TypeOrmQueryService<RefreshToken> {}
|
|
||||||
@ -11,7 +11,7 @@ import {
|
|||||||
} from 'typeorm';
|
} from 'typeorm';
|
||||||
import { IDField } from '@ptc-org/nestjs-query-graphql';
|
import { IDField } from '@ptc-org/nestjs-query-graphql';
|
||||||
|
|
||||||
import { RefreshToken } from 'src/engine/core-modules/refresh-token/refresh-token.entity';
|
import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
|
||||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||||
import { WorkspaceMember } from 'src/engine/core-modules/user/dtos/workspace-member.dto';
|
import { WorkspaceMember } from 'src/engine/core-modules/user/dtos/workspace-member.dto';
|
||||||
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
||||||
@ -85,10 +85,10 @@ export class User {
|
|||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
passwordResetTokenExpiresAt: Date;
|
passwordResetTokenExpiresAt: Date;
|
||||||
|
|
||||||
@OneToMany(() => RefreshToken, (refreshToken) => refreshToken.user, {
|
@OneToMany(() => AppToken, (appToken) => appToken.user, {
|
||||||
cascade: true,
|
cascade: true,
|
||||||
})
|
})
|
||||||
refreshTokens: RefreshToken[];
|
appTokens: AppToken[];
|
||||||
|
|
||||||
@Field(() => WorkspaceMember, { nullable: true })
|
@Field(() => WorkspaceMember, { nullable: true })
|
||||||
workspaceMember: WorkspaceMember;
|
workspaceMember: WorkspaceMember;
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import { User } from 'src/engine/core-modules/user/user.entity';
|
|||||||
import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
||||||
import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
|
import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
|
||||||
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
||||||
|
import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
|
||||||
|
|
||||||
@Entity({ name: 'workspace', schema: 'core' })
|
@Entity({ name: 'workspace', schema: 'core' })
|
||||||
@ObjectType('Workspace')
|
@ObjectType('Workspace')
|
||||||
@ -55,6 +56,11 @@ export class Workspace {
|
|||||||
@UpdateDateColumn({ type: 'timestamp with time zone' })
|
@UpdateDateColumn({ type: 'timestamp with time zone' })
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
|
|
||||||
|
@OneToMany(() => AppToken, (appToken) => appToken.workspace, {
|
||||||
|
cascade: true,
|
||||||
|
})
|
||||||
|
appTokens: AppToken[];
|
||||||
|
|
||||||
@OneToMany(() => User, (user) => user.defaultWorkspace)
|
@OneToMany(() => User, (user) => user.defaultWorkspace)
|
||||||
users: User[];
|
users: User[];
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import { CreateObjectInput } from 'src/engine/metadata-modules/object-metadata/d
|
|||||||
|
|
||||||
const coreObjectNames = [
|
const coreObjectNames = [
|
||||||
'featureFlag',
|
'featureFlag',
|
||||||
'refreshToken',
|
'appToken',
|
||||||
'workspace',
|
'workspace',
|
||||||
'user',
|
'user',
|
||||||
'event',
|
'event',
|
||||||
|
|||||||
Reference in New Issue
Block a user