import { Controller, Get, Put, Body, UseGuards, Req, } from '@nestjs/common'; import { JwtAuthGuard } from '../auth/jwt-auth.guard'; import { TenantDatabaseService } from './tenant-database.service'; import { getCentralPrisma } from '../prisma/central-prisma.service'; import { TenantId } from './tenant.decorator'; @Controller('tenant') @UseGuards(JwtAuthGuard) export class TenantController { constructor(private readonly tenantDbService: TenantDatabaseService) {} /** * Get integrations configuration for the current tenant */ @Get('integrations') async getIntegrationsConfig(@TenantId() domain: string) { const centralPrisma = getCentralPrisma(); // Look up tenant by domain const domainRecord = await centralPrisma.domain.findUnique({ where: { domain }, include: { tenant: { select: { id: true, integrationsConfig: true } } }, }); if (!domainRecord?.tenant || !domainRecord.tenant.integrationsConfig) { return { data: null }; } // Decrypt the config const config = this.tenantDbService.decryptIntegrationsConfig( domainRecord.tenant.integrationsConfig as any, ); // Return config with sensitive fields masked const maskedConfig = this.maskSensitiveFields(config); return { data: maskedConfig }; } /** * Update integrations configuration for the current tenant */ @Put('integrations') async updateIntegrationsConfig( @TenantId() domain: string, @Body() body: { integrationsConfig: any }, ) { const { integrationsConfig } = body; if (!domain) { throw new Error('Domain is missing from request'); } // Look up tenant by domain const centralPrisma = getCentralPrisma(); const domainRecord = await centralPrisma.domain.findUnique({ where: { domain }, include: { tenant: { select: { id: true, integrationsConfig: true } } }, }); if (!domainRecord?.tenant) { throw new Error(`Tenant with domain ${domain} not found`); } // Merge with existing config to preserve masked values let finalConfig = integrationsConfig; if (domainRecord.tenant.integrationsConfig) { const existingConfig = this.tenantDbService.decryptIntegrationsConfig( domainRecord.tenant.integrationsConfig as any, ); // Replace masked values with actual values from existing config finalConfig = this.unmaskConfig(integrationsConfig, existingConfig); } // Encrypt the config const encryptedConfig = this.tenantDbService.encryptIntegrationsConfig( finalConfig, ); // Update in database await centralPrisma.tenant.update({ where: { id: domainRecord.tenant.id }, data: { integrationsConfig: encryptedConfig as any, }, }); return { success: true, message: 'Integrations configuration updated successfully', }; } /** * Unmask config by replacing masked values with actual values from existing config */ private unmaskConfig(newConfig: any, existingConfig: any): any { const result = { ...newConfig }; // Unmask Twilio credentials if (result.twilio && existingConfig.twilio) { if (result.twilio.authToken === '••••••••' && existingConfig.twilio.authToken) { result.twilio.authToken = existingConfig.twilio.authToken; } if (result.twilio.apiSecret === '••••••••' && existingConfig.twilio.apiSecret) { result.twilio.apiSecret = existingConfig.twilio.apiSecret; } } // Unmask OpenAI credentials if (result.openai && existingConfig.openai) { if (result.openai.apiKey === '••••••••' && existingConfig.openai.apiKey) { result.openai.apiKey = existingConfig.openai.apiKey; } } return result; } /** * Mask sensitive fields for API responses */ private maskSensitiveFields(config: any): any { if (!config) return null; const masked = { ...config }; // Mask Twilio credentials if (masked.twilio) { masked.twilio = { ...masked.twilio, authToken: masked.twilio.authToken ? '••••••••' : '', apiSecret: masked.twilio.apiSecret ? '••••••••' : '', }; } // Mask OpenAI credentials if (masked.openai) { masked.openai = { ...masked.openai, apiKey: masked.openai.apiKey ? '••••••••' : '', }; } return masked; } }