Add endpoint to create postgres credentials (#5767)
First step for creating credentials for database proxy. In next PRs: - When calling endpoint, create database Postgres on proxy server - Setup user on database using postgresCredentials - Build remote server on DB to access workspace data
This commit is contained in:
@ -0,0 +1,20 @@
|
||||
import { ObjectType, Field } from '@nestjs/graphql';
|
||||
|
||||
import { IDField } from '@ptc-org/nestjs-query-graphql';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
|
||||
@ObjectType('PostgresCredentials')
|
||||
export class PostgresCredentialsDTO {
|
||||
@IDField(() => UUIDScalarType)
|
||||
id: string;
|
||||
|
||||
@Field()
|
||||
user: string;
|
||||
|
||||
@Field()
|
||||
password: string;
|
||||
|
||||
@Field()
|
||||
workspaceId: string;
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
import {
|
||||
Entity,
|
||||
Column,
|
||||
PrimaryGeneratedColumn,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
ManyToOne,
|
||||
Relation,
|
||||
} from 'typeorm';
|
||||
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
|
||||
@Entity({ name: 'postgresCredentials', schema: 'core' })
|
||||
export class PostgresCredentials {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ nullable: false })
|
||||
user: string;
|
||||
|
||||
@Column({ nullable: false })
|
||||
passwordHash: string;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt: Date;
|
||||
|
||||
@UpdateDateColumn({ type: 'timestamptz' })
|
||||
updatedAt: Date;
|
||||
|
||||
@Column({ nullable: true, type: 'timestamptz' })
|
||||
deletedAt: Date;
|
||||
|
||||
@ManyToOne(() => Workspace, (workspace) => workspace.allPostgresCredentials, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
workspace: Relation<Workspace>;
|
||||
|
||||
@Column({ nullable: false, type: 'uuid' })
|
||||
workspaceId: string;
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { PostgresCredentials } from 'src/engine/core-modules/postgres-credentials/postgres-credentials.entity';
|
||||
import { PostgresCredentialsResolver } from 'src/engine/core-modules/postgres-credentials/postgres-credentials.resolver';
|
||||
import { PostgresCredentialsService } from 'src/engine/core-modules/postgres-credentials/postgres-credentials.service';
|
||||
import { EnvironmentModule } from 'src/engine/integrations/environment/environment.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([PostgresCredentials], 'core'),
|
||||
EnvironmentModule,
|
||||
],
|
||||
providers: [
|
||||
PostgresCredentialsResolver,
|
||||
PostgresCredentialsService,
|
||||
PostgresCredentials,
|
||||
],
|
||||
})
|
||||
export class PostgresCredentialsModule {}
|
||||
@ -0,0 +1,35 @@
|
||||
import { UseGuards } from '@nestjs/common';
|
||||
import { Resolver, Mutation, Query } from '@nestjs/graphql';
|
||||
|
||||
import { PostgresCredentialsDTO } from 'src/engine/core-modules/postgres-credentials/dtos/postgres-credentials.dto';
|
||||
import { PostgresCredentialsService } from 'src/engine/core-modules/postgres-credentials/postgres-credentials.service';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
||||
import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard';
|
||||
|
||||
@Resolver(() => PostgresCredentialsDTO)
|
||||
export class PostgresCredentialsResolver {
|
||||
constructor(
|
||||
private readonly postgresCredentialsService: PostgresCredentialsService,
|
||||
) {}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Mutation(() => PostgresCredentialsDTO)
|
||||
async enablePostgresProxy(@AuthWorkspace() { id: workspaceId }: Workspace) {
|
||||
return this.postgresCredentialsService.enablePostgresProxy(workspaceId);
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Mutation(() => PostgresCredentialsDTO)
|
||||
async disablePostgresProxy(@AuthWorkspace() { id: workspaceId }: Workspace) {
|
||||
return this.postgresCredentialsService.disablePostgresProxy(workspaceId);
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Query(() => PostgresCredentialsDTO, { nullable: true })
|
||||
async getPostgresCredentials(
|
||||
@AuthWorkspace() { id: workspaceId }: Workspace,
|
||||
) {
|
||||
return this.postgresCredentialsService.getPostgresCredentials(workspaceId);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,117 @@
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { BadRequestException } from '@nestjs/common';
|
||||
|
||||
import { randomBytes } from 'crypto';
|
||||
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import {
|
||||
decryptText,
|
||||
encryptText,
|
||||
} from 'src/engine/core-modules/auth/auth.util';
|
||||
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
||||
import { PostgresCredentials } from 'src/engine/core-modules/postgres-credentials/postgres-credentials.entity';
|
||||
import { NotFoundError } from 'src/engine/utils/graphql-errors.util';
|
||||
import { PostgresCredentialsDTO } from 'src/engine/core-modules/postgres-credentials/dtos/postgres-credentials.dto';
|
||||
|
||||
export class PostgresCredentialsService {
|
||||
constructor(
|
||||
@InjectRepository(PostgresCredentials, 'core')
|
||||
private readonly postgresCredentialsRepository: Repository<PostgresCredentials>,
|
||||
private readonly environmentService: EnvironmentService,
|
||||
) {}
|
||||
|
||||
async enablePostgresProxy(
|
||||
workspaceId: string,
|
||||
): Promise<PostgresCredentialsDTO> {
|
||||
const user = `user_${randomBytes(4).toString('hex')}`;
|
||||
const password = randomBytes(16).toString('hex');
|
||||
|
||||
const key = this.environmentService.get('LOGIN_TOKEN_SECRET');
|
||||
const passwordHash = encryptText(password, key);
|
||||
|
||||
const existingCredentials =
|
||||
await this.postgresCredentialsRepository.findOne({
|
||||
where: {
|
||||
workspaceId,
|
||||
},
|
||||
});
|
||||
|
||||
if (existingCredentials) {
|
||||
throw new BadRequestException(
|
||||
'Postgres credentials already exist for this workspace',
|
||||
);
|
||||
}
|
||||
|
||||
const postgresCredentials = await this.postgresCredentialsRepository.create(
|
||||
{
|
||||
user,
|
||||
passwordHash,
|
||||
workspaceId,
|
||||
},
|
||||
);
|
||||
|
||||
await this.postgresCredentialsRepository.save(postgresCredentials);
|
||||
|
||||
return {
|
||||
id: postgresCredentials.id,
|
||||
user,
|
||||
password,
|
||||
workspaceId,
|
||||
};
|
||||
}
|
||||
|
||||
async disablePostgresProxy(
|
||||
workspaceId: string,
|
||||
): Promise<PostgresCredentialsDTO> {
|
||||
const postgresCredentials =
|
||||
await this.postgresCredentialsRepository.findOne({
|
||||
where: {
|
||||
workspaceId,
|
||||
},
|
||||
});
|
||||
|
||||
if (!postgresCredentials?.id) {
|
||||
throw new NotFoundError(
|
||||
'No valid Postgres credentials not found for this workspace',
|
||||
);
|
||||
}
|
||||
|
||||
await this.postgresCredentialsRepository.delete({
|
||||
id: postgresCredentials.id,
|
||||
});
|
||||
|
||||
const key = this.environmentService.get('LOGIN_TOKEN_SECRET');
|
||||
|
||||
return {
|
||||
id: postgresCredentials.id,
|
||||
user: postgresCredentials.user,
|
||||
password: decryptText(postgresCredentials.passwordHash, key),
|
||||
workspaceId: postgresCredentials.workspaceId,
|
||||
};
|
||||
}
|
||||
|
||||
async getPostgresCredentials(
|
||||
workspaceId: string,
|
||||
): Promise<PostgresCredentialsDTO | null> {
|
||||
const postgresCredentials =
|
||||
await this.postgresCredentialsRepository.findOne({
|
||||
where: {
|
||||
workspaceId,
|
||||
},
|
||||
});
|
||||
|
||||
if (!postgresCredentials) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const key = this.environmentService.get('LOGIN_TOKEN_SECRET');
|
||||
|
||||
return {
|
||||
id: postgresCredentials.id,
|
||||
user: postgresCredentials.user,
|
||||
password: decryptText(postgresCredentials.passwordHash, key),
|
||||
workspaceId: postgresCredentials.workspaceId,
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user