UNPKG

@sourceloop/ctrl-plane-tenant-management-service

Version:

Tenant Management microservice for SaaS control plane

89 lines (81 loc) 3.23 kB
import {repository} from '@loopback/repository'; import {SubscriptionDTO, TenantWithRelations} from '../models'; import {CryptoHelperService} from './crypto-helper.service'; import {service, inject} from '@loopback/core'; import {TenantRepository, WebhookSecretRepository} from '../repositories'; import {HttpErrors} from '@loopback/rest'; import {IProvisioningService} from '../types'; import {ILogger, LOGGER} from '@sourceloop/core'; import {TenantStatus} from '../enums'; import {EventConnectorBinding} from '../keys'; import {EventConnector, EventTypes} from './event-connector'; import {randomUUID} from 'crypto'; /** * Service for provisioning tenants. */ export class ProvisioningService<T extends SubscriptionDTO> implements IProvisioningService<T> { /** * Constructs a new instance of the ProvisioningService. * @param cryptoHelperService - Service for cryptographic operations. * @param eventConnector - Event Connector provided by consumer to invoke publish on. * @param webhookSecretRepo - Repository for webhook secrets. * @param logger - Logger service for logging messages. */ constructor( @service(CryptoHelperService) private cryptoHelperService: CryptoHelperService, @inject(EventConnectorBinding) private eventConnector: EventConnector, @repository(WebhookSecretRepository) private webhookSecretRepo: WebhookSecretRepository, @repository(TenantRepository) private tenantRepository: TenantRepository, @inject(LOGGER.LOGGER_INJECT) private logger: ILogger, ) {} /** * The `provisionTenant` function provisions a new tenant by generating a temporary token, retrieving * the subscription details, generating a random HMAC secret, starting a build process, and storing the * webhook secret and build context to later verify the webhook callback. * @param {Tenant} tenant - The `tenant` parameter is an object that represents a tenant. It likely * contains information such as the tenant's ID, name, and other relevant details. * @param {string} subscription - The `subscription` parameter is an object that contains * the details of the subscription opted by the tenant. */ async provisionTenant( tenant: TenantWithRelations, subscription: T, ): Promise<void> { await this.tenantRepository.updateById(tenant.id, { status: TenantStatus.PROVISIONING, }); if (!subscription.id) { throw HttpErrors.BadRequest('Subscription ID is required'); } const hmacSecret = this.cryptoHelperService.generateRandomString(32); if (subscription.plan?.tier === undefined) { this.logger.error( `Tier not found in plan for subscription: ${subscription.id}`, ); throw new HttpErrors.InternalServerError(); } const context = randomUUID(); await this.eventConnector.publish({ type: EventTypes.TENANT_PROVISIONING, tenant: tenant, subscription: subscription, secret: hmacSecret, context: context, }); await this.webhookSecretRepo.set(tenant.id, { secret: hmacSecret, context: context, }); await this.webhookSecretRepo.expire( tenant.id, +process.env.WEBHOOK_SECRET_EXPIRY!, ); } }