import { Injectable } from '@nestjs/common'; import type { WhmcsRegisterMtlsRequest } from '@hexahost/contracts'; import { normalizeCertificateFingerprint } from '@hexahost/integration-auth'; import { PrismaService } from '../../prisma/prisma.service'; type InstallationRef = { id: string; }; @Injectable() export class WhmcsMtlsService { constructor(private readonly prisma: PrismaService) {} async registerFingerprint( installation: InstallationRef, input: WhmcsRegisterMtlsRequest, idempotencyKey: string, ): Promise<{ integrationId: string; fingerprint: string | null; subject: string | null; registered: boolean; }> { const existingOp = await this.prisma.integrationOperation.findUnique({ where: { idempotencyKey }, }); if (existingOp?.result) { return existingOp.result as { integrationId: string; fingerprint: string | null; subject: string | null; registered: boolean; }; } const fingerprint = normalizeCertificateFingerprint(input.fingerprint); const updated = await this.prisma.whmcsInstallation.update({ where: { id: installation.id }, data: { mtlsClientFingerprint: fingerprint, mtlsClientSubject: input.subject ?? null, }, select: { integrationId: true, mtlsClientFingerprint: true, mtlsClientSubject: true, }, }); const result = { integrationId: updated.integrationId, fingerprint: updated.mtlsClientFingerprint, subject: updated.mtlsClientSubject, registered: true, }; await this.prisma.integrationOperation.create({ data: { installationId: installation.id, idempotencyKey, operation: 'mtls:register', status: 'COMPLETED', result: result as object, }, }); return result; } async getMtlsStatus(installation: InstallationRef) { const row = await this.prisma.whmcsInstallation.findUniqueOrThrow({ where: { id: installation.id }, select: { integrationId: true, mtlsClientFingerprint: true, mtlsClientSubject: true, }, }); return { integrationId: row.integrationId, mtlsEnabled: process.env['INTEGRATION_MTLS_ENABLED'] === 'true', fingerprintRegistered: Boolean(row.mtlsClientFingerprint), fingerprintPreview: row.mtlsClientFingerprint ? `${row.mtlsClientFingerprint.slice(0, 8)}…${row.mtlsClientFingerprint.slice(-8)}` : null, subject: row.mtlsClientSubject, }; } }