Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ulixee
GitHub Repository: ulixee/secret-agent
Path: blob/main/mitm-socket/lib/CertificateGenerator.ts
1030 views
1
import Log from '@secret-agent/commons/Logger';
2
import Resolvable from '@secret-agent/commons/Resolvable';
3
import { IBoundLog } from '@secret-agent/interfaces/ILog';
4
import { CanceledPromiseError } from '@secret-agent/commons/interfaces/IPendingWaitEvent';
5
import BaseIpcHandler from './BaseIpcHandler';
6
7
const { log } = Log(module);
8
9
let certRequestId = 0;
10
export default class CertificateGenerator extends BaseIpcHandler {
11
protected logger: IBoundLog = log.createChild(module);
12
13
private pendingCertsById = new Map<number, Resolvable<{ cert: string; expireDate: Date }>>();
14
15
private privateKey: string;
16
private waitForInit = new Resolvable<void>();
17
private hasWaitForInitListeners = false;
18
19
constructor(
20
options: Partial<{
21
debug?: boolean;
22
ipcSocketPath?: string;
23
storageDir?: string;
24
}> = {},
25
) {
26
super({ ...options, mode: 'certs' });
27
}
28
29
public async getPrivateKey(): Promise<string> {
30
await this.waitForInit;
31
return this.privateKey;
32
}
33
34
public async generateCerts(host: string): Promise<{ cert: string; expireDate: Date }> {
35
await this.waitForConnected;
36
certRequestId += 1;
37
const id = certRequestId;
38
39
const resolvable = new Resolvable<{ cert: string; expireDate: Date }>(10e3);
40
this.pendingCertsById.set(id, resolvable);
41
42
try {
43
await this.sendIpcMessage({ id, host });
44
} catch (error) {
45
if (this.isClosing) return;
46
throw error;
47
}
48
49
this.hasWaitForInitListeners = true;
50
await this.waitForInit;
51
return await resolvable.promise;
52
}
53
54
protected onMessage(rawMessage: string): void {
55
if (this.isClosing) return;
56
const message = JSON.parse(rawMessage);
57
if (this.options.debug) {
58
this.logger.info('CertificateGenerator.onMessage', {
59
...message,
60
});
61
}
62
63
if (message.status === 'init') {
64
this.privateKey = message.privateKey;
65
this.waitForInit.resolve();
66
return;
67
}
68
69
if (!message.id) {
70
this.logger.warn('CertificateGenerator.unprocessableMessage', {
71
message,
72
});
73
return;
74
}
75
76
const pending = this.pendingCertsById.get(message.id);
77
this.pendingCertsById.delete(message.id);
78
79
if (!pending) {
80
this.logger.warn('CertificateGenerator.unprocessableMessage:notFound', {
81
message,
82
});
83
return;
84
}
85
86
if (message.status === 'error') {
87
pending.reject(new Error(message.error));
88
} else if (message.status === 'certs') {
89
pending.resolve({ cert: message.cert, expireDate: new Date(message.expireDate * 1e3) });
90
}
91
}
92
93
protected beforeExit(): void {
94
for (const cert of this.pendingCertsById.values()) {
95
cert.reject(new CanceledPromiseError('Canceling certificate generation'));
96
}
97
if (this.hasWaitForInitListeners && this.waitForInit && !this.waitForInit.isResolved) {
98
this.waitForInit.reject(new CanceledPromiseError('Canceling ipc initialization'));
99
}
100
}
101
}
102
103