// src/integrations/digicert/DigiCertClient.js import axios from 'axios'; import { logger } from '../../utils/logger.js'; class DigiCertClient { static #instance = null; constructor() { if (DigiCertClient.#instance) return DigiCertClient.#instance; const apiKey = process.env.DIGICERT_API_KEY; const baseURL = process.env.DIGICERT_BASE_URL || 'https://one.digicert.com'; if (!apiKey) { logger('digicert:client', 'DIGICERT_API_KEY is missing from environment', 'error'); throw new Error('Missing DIGICERT_API_KEY'); } this.client = axios.create({ baseURL, headers: { 'x-api-key': apiKey, 'Content-Type': 'application/json', 'Accept': 'application/json' }, timeout: 60000 }); DigiCertClient.#instance = this; logger('digicert:client', 'DigiCertClient initialized'); } async enrollCertificate(csrBase64, commonName, deviceIp) { const seatEmail = process.env.DIGICERT_SEAT_EMAIL; if (!seatEmail) { // Previously this silently fell back to a hardcoded personal address, // which both pinned every cert to one person's email and leaked the // identity through the source. Fail loud so misconfig is obvious. throw new Error('DIGICERT_SEAT_EMAIL is not set in environment'); } const payload = { profile: { id: process.env.DIGICERT_PROFILE_ID }, csr: csrBase64, seat: { seat_id: `${commonName}-${Date.now()}`, seat_email: seatEmail, }, attributes: { subject: { common_name: commonName }, extensions: { san: { dns_names: [commonName], ip_addresses: [deviceIp] } } } }; const response = await this.client.post('/mpki/api/v1/certificate', payload); return response.data; } async pickupCertificate(requestId) { const payload = { profile: { id: process.env.DIGICERT_PROFILE_ID } }; const response = await this.client.post(`/mpki/api/v1/certificate-pickup/${requestId}`, payload); return response.data; } } export default new DigiCertClient();