Path: blob/main/mitm-socket/lib/CertificateGenerator.ts
1030 views
import Log from '@secret-agent/commons/Logger';1import Resolvable from '@secret-agent/commons/Resolvable';2import { IBoundLog } from '@secret-agent/interfaces/ILog';3import { CanceledPromiseError } from '@secret-agent/commons/interfaces/IPendingWaitEvent';4import BaseIpcHandler from './BaseIpcHandler';56const { log } = Log(module);78let certRequestId = 0;9export default class CertificateGenerator extends BaseIpcHandler {10protected logger: IBoundLog = log.createChild(module);1112private pendingCertsById = new Map<number, Resolvable<{ cert: string; expireDate: Date }>>();1314private privateKey: string;15private waitForInit = new Resolvable<void>();16private hasWaitForInitListeners = false;1718constructor(19options: Partial<{20debug?: boolean;21ipcSocketPath?: string;22storageDir?: string;23}> = {},24) {25super({ ...options, mode: 'certs' });26}2728public async getPrivateKey(): Promise<string> {29await this.waitForInit;30return this.privateKey;31}3233public async generateCerts(host: string): Promise<{ cert: string; expireDate: Date }> {34await this.waitForConnected;35certRequestId += 1;36const id = certRequestId;3738const resolvable = new Resolvable<{ cert: string; expireDate: Date }>(10e3);39this.pendingCertsById.set(id, resolvable);4041try {42await this.sendIpcMessage({ id, host });43} catch (error) {44if (this.isClosing) return;45throw error;46}4748this.hasWaitForInitListeners = true;49await this.waitForInit;50return await resolvable.promise;51}5253protected onMessage(rawMessage: string): void {54if (this.isClosing) return;55const message = JSON.parse(rawMessage);56if (this.options.debug) {57this.logger.info('CertificateGenerator.onMessage', {58...message,59});60}6162if (message.status === 'init') {63this.privateKey = message.privateKey;64this.waitForInit.resolve();65return;66}6768if (!message.id) {69this.logger.warn('CertificateGenerator.unprocessableMessage', {70message,71});72return;73}7475const pending = this.pendingCertsById.get(message.id);76this.pendingCertsById.delete(message.id);7778if (!pending) {79this.logger.warn('CertificateGenerator.unprocessableMessage:notFound', {80message,81});82return;83}8485if (message.status === 'error') {86pending.reject(new Error(message.error));87} else if (message.status === 'certs') {88pending.resolve({ cert: message.cert, expireDate: new Date(message.expireDate * 1e3) });89}90}9192protected beforeExit(): void {93for (const cert of this.pendingCertsById.values()) {94cert.reject(new CanceledPromiseError('Canceling certificate generation'));95}96if (this.hasWaitForInitListeners && this.waitForInit && !this.waitForInit.isResolved) {97this.waitForInit.reject(new CanceledPromiseError('Canceling ipc initialization'));98}99}100}101102103