@push.rocks/smartproxy 18.2.0 → 19.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/common/eventUtils.d.ts +1 -2
- package/dist_ts/common/eventUtils.js +2 -1
- package/dist_ts/core/models/common-types.d.ts +1 -1
- package/dist_ts/core/models/common-types.js +1 -1
- package/dist_ts/core/utils/event-utils.d.ts +9 -9
- package/dist_ts/core/utils/event-utils.js +6 -14
- package/dist_ts/http/models/http-types.d.ts +13 -1
- package/dist_ts/http/models/http-types.js +1 -1
- package/dist_ts/index.d.ts +4 -6
- package/dist_ts/index.js +4 -10
- package/dist_ts/proxies/index.d.ts +3 -2
- package/dist_ts/proxies/index.js +4 -5
- package/dist_ts/proxies/network-proxy/certificate-manager.d.ts +31 -49
- package/dist_ts/proxies/network-proxy/certificate-manager.js +77 -374
- package/dist_ts/proxies/network-proxy/models/types.d.ts +12 -1
- package/dist_ts/proxies/network-proxy/models/types.js +1 -1
- package/dist_ts/proxies/network-proxy/network-proxy.d.ts +2 -7
- package/dist_ts/proxies/network-proxy/network-proxy.js +10 -19
- package/dist_ts/proxies/smart-proxy/models/index.d.ts +1 -1
- package/dist_ts/proxies/smart-proxy/models/index.js +1 -5
- package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +13 -1
- package/dist_ts/proxies/smart-proxy/smart-proxy.js +2 -3
- package/package.json +1 -1
- package/readme.md +13 -5
- package/readme.plan.md +37 -20
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/common/eventUtils.ts +2 -2
- package/ts/core/models/common-types.ts +1 -1
- package/ts/core/utils/event-utils.ts +12 -21
- package/ts/http/models/http-types.ts +8 -4
- package/ts/index.ts +11 -14
- package/ts/proxies/index.ts +7 -4
- package/ts/proxies/network-proxy/certificate-manager.ts +92 -417
- package/ts/proxies/network-proxy/models/types.ts +14 -2
- package/ts/proxies/network-proxy/network-proxy.ts +10 -19
- package/ts/proxies/smart-proxy/models/index.ts +2 -1
- package/ts/proxies/smart-proxy/models/interfaces.ts +14 -1
- package/ts/proxies/smart-proxy/models/route-types.ts +1 -1
- package/ts/proxies/smart-proxy/smart-proxy.ts +1 -2
- package/ts/certificate/acme/acme-factory.ts +0 -48
- package/ts/certificate/acme/challenge-handler.ts +0 -110
- package/ts/certificate/acme/index.ts +0 -3
- package/ts/certificate/events/certificate-events.ts +0 -36
- package/ts/certificate/index.ts +0 -75
- package/ts/certificate/models/certificate-types.ts +0 -109
- package/ts/certificate/providers/cert-provisioner.ts +0 -519
- package/ts/certificate/providers/index.ts +0 -3
- package/ts/certificate/storage/file-storage.ts +0 -234
- package/ts/certificate/storage/index.ts +0 -3
- package/ts/certificate/utils/certificate-helpers.ts +0 -50
- package/ts/http/port80/acme-interfaces.ts +0 -169
- package/ts/http/port80/challenge-responder.ts +0 -246
- package/ts/http/port80/index.ts +0 -13
- package/ts/http/port80/port80-handler.ts +0 -728
|
@@ -1,519 +0,0 @@
|
|
|
1
|
-
import * as plugins from '../../plugins.js';
|
|
2
|
-
import type { IRouteConfig } from '../../proxies/smart-proxy/models/route-types.js';
|
|
3
|
-
import type { ICertificateData, IRouteForwardConfig, IDomainOptions } from '../models/certificate-types.js';
|
|
4
|
-
import { Port80HandlerEvents, CertProvisionerEvents } from '../events/certificate-events.js';
|
|
5
|
-
import { Port80Handler } from '../../http/port80/port80-handler.js';
|
|
6
|
-
|
|
7
|
-
// Interface for NetworkProxyBridge
|
|
8
|
-
interface INetworkProxyBridge {
|
|
9
|
-
applyExternalCertificate(certData: ICertificateData): void;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Type for static certificate provisioning
|
|
14
|
-
*/
|
|
15
|
-
export type TCertProvisionObject = plugins.tsclass.network.ICert | 'http01' | 'dns01';
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Interface for routes that need certificates
|
|
19
|
-
*/
|
|
20
|
-
interface ICertRoute {
|
|
21
|
-
domain: string;
|
|
22
|
-
route: IRouteConfig;
|
|
23
|
-
tlsMode: 'terminate' | 'terminate-and-reencrypt';
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* CertProvisioner manages certificate provisioning and renewal workflows,
|
|
28
|
-
* unifying static certificates and HTTP-01 challenges via Port80Handler.
|
|
29
|
-
*
|
|
30
|
-
* This class directly works with route configurations instead of converting to domain configs.
|
|
31
|
-
*/
|
|
32
|
-
export class CertProvisioner extends plugins.EventEmitter {
|
|
33
|
-
private routeConfigs: IRouteConfig[];
|
|
34
|
-
private certRoutes: ICertRoute[] = [];
|
|
35
|
-
private port80Handler: Port80Handler;
|
|
36
|
-
private networkProxyBridge: INetworkProxyBridge;
|
|
37
|
-
private certProvisionFunction?: (domain: string) => Promise<TCertProvisionObject>;
|
|
38
|
-
private routeForwards: IRouteForwardConfig[];
|
|
39
|
-
private renewThresholdDays: number;
|
|
40
|
-
private renewCheckIntervalHours: number;
|
|
41
|
-
private autoRenew: boolean;
|
|
42
|
-
private renewManager?: plugins.taskbuffer.TaskManager;
|
|
43
|
-
// Track provisioning type per domain
|
|
44
|
-
private provisionMap: Map<string, { type: 'http01' | 'dns01' | 'static', routeRef?: ICertRoute }>;
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Extract routes that need certificates
|
|
48
|
-
* @param routes Route configurations
|
|
49
|
-
*/
|
|
50
|
-
private extractCertificateRoutesFromRoutes(routes: IRouteConfig[]): ICertRoute[] {
|
|
51
|
-
const certRoutes: ICertRoute[] = [];
|
|
52
|
-
|
|
53
|
-
// Process all HTTPS routes that need certificates
|
|
54
|
-
for (const route of routes) {
|
|
55
|
-
// Only process routes with TLS termination that need certificates
|
|
56
|
-
if (route.action.type === 'forward' &&
|
|
57
|
-
route.action.tls &&
|
|
58
|
-
(route.action.tls.mode === 'terminate' || route.action.tls.mode === 'terminate-and-reencrypt') &&
|
|
59
|
-
route.match.domains) {
|
|
60
|
-
|
|
61
|
-
// Extract domains from the route
|
|
62
|
-
const domains = Array.isArray(route.match.domains)
|
|
63
|
-
? route.match.domains
|
|
64
|
-
: [route.match.domains];
|
|
65
|
-
|
|
66
|
-
// For each domain in the route, create a certRoute entry
|
|
67
|
-
for (const domain of domains) {
|
|
68
|
-
// Skip wildcard domains that can't use ACME unless we have a certProvider
|
|
69
|
-
if (domain.includes('*') && (!this.certProvisionFunction || this.certProvisionFunction.length === 0)) {
|
|
70
|
-
console.warn(`Skipping wildcard domain that requires a certProvisionFunction: ${domain}`);
|
|
71
|
-
continue;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
certRoutes.push({
|
|
75
|
-
domain,
|
|
76
|
-
route,
|
|
77
|
-
tlsMode: route.action.tls.mode
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return certRoutes;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Constructor for CertProvisioner
|
|
88
|
-
*
|
|
89
|
-
* @param routeConfigs Array of route configurations
|
|
90
|
-
* @param port80Handler HTTP-01 challenge handler instance
|
|
91
|
-
* @param networkProxyBridge Bridge for applying external certificates
|
|
92
|
-
* @param certProvider Optional callback returning a static cert or 'http01'
|
|
93
|
-
* @param renewThresholdDays Days before expiry to trigger renewals
|
|
94
|
-
* @param renewCheckIntervalHours Interval in hours to check for renewals
|
|
95
|
-
* @param autoRenew Whether to automatically schedule renewals
|
|
96
|
-
* @param routeForwards Route-specific forwarding configs for ACME challenges
|
|
97
|
-
*/
|
|
98
|
-
constructor(
|
|
99
|
-
routeConfigs: IRouteConfig[],
|
|
100
|
-
port80Handler: Port80Handler,
|
|
101
|
-
networkProxyBridge: INetworkProxyBridge,
|
|
102
|
-
certProvider?: (domain: string) => Promise<TCertProvisionObject>,
|
|
103
|
-
renewThresholdDays: number = 30,
|
|
104
|
-
renewCheckIntervalHours: number = 24,
|
|
105
|
-
autoRenew: boolean = true,
|
|
106
|
-
routeForwards: IRouteForwardConfig[] = []
|
|
107
|
-
) {
|
|
108
|
-
super();
|
|
109
|
-
this.routeConfigs = routeConfigs;
|
|
110
|
-
this.port80Handler = port80Handler;
|
|
111
|
-
this.networkProxyBridge = networkProxyBridge;
|
|
112
|
-
this.certProvisionFunction = certProvider;
|
|
113
|
-
this.renewThresholdDays = renewThresholdDays;
|
|
114
|
-
this.renewCheckIntervalHours = renewCheckIntervalHours;
|
|
115
|
-
this.autoRenew = autoRenew;
|
|
116
|
-
this.provisionMap = new Map();
|
|
117
|
-
this.routeForwards = routeForwards;
|
|
118
|
-
|
|
119
|
-
// Extract certificate routes during instantiation
|
|
120
|
-
this.certRoutes = this.extractCertificateRoutesFromRoutes(routeConfigs);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Start initial provisioning and schedule renewals.
|
|
125
|
-
*/
|
|
126
|
-
public async start(): Promise<void> {
|
|
127
|
-
// Subscribe to Port80Handler certificate events
|
|
128
|
-
this.setupEventSubscriptions();
|
|
129
|
-
|
|
130
|
-
// Apply route forwarding for ACME challenges
|
|
131
|
-
this.setupForwardingConfigs();
|
|
132
|
-
|
|
133
|
-
// Initial provisioning for all domains in routes
|
|
134
|
-
await this.provisionAllCertificates();
|
|
135
|
-
|
|
136
|
-
// Schedule renewals if enabled
|
|
137
|
-
if (this.autoRenew) {
|
|
138
|
-
this.scheduleRenewals();
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Set up event subscriptions for certificate events
|
|
144
|
-
*/
|
|
145
|
-
private setupEventSubscriptions(): void {
|
|
146
|
-
this.port80Handler.on(Port80HandlerEvents.CERTIFICATE_ISSUED, (data: ICertificateData) => {
|
|
147
|
-
// Add route reference if we have it
|
|
148
|
-
const routeRef = this.findRouteForDomain(data.domain);
|
|
149
|
-
const enhancedData: ICertificateData = {
|
|
150
|
-
...data,
|
|
151
|
-
source: 'http01',
|
|
152
|
-
isRenewal: false,
|
|
153
|
-
routeReference: routeRef ? {
|
|
154
|
-
routeId: routeRef.route.name,
|
|
155
|
-
routeName: routeRef.route.name
|
|
156
|
-
} : undefined
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
this.emit(CertProvisionerEvents.CERTIFICATE_ISSUED, enhancedData);
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
this.port80Handler.on(Port80HandlerEvents.CERTIFICATE_RENEWED, (data: ICertificateData) => {
|
|
163
|
-
// Add route reference if we have it
|
|
164
|
-
const routeRef = this.findRouteForDomain(data.domain);
|
|
165
|
-
const enhancedData: ICertificateData = {
|
|
166
|
-
...data,
|
|
167
|
-
source: 'http01',
|
|
168
|
-
isRenewal: true,
|
|
169
|
-
routeReference: routeRef ? {
|
|
170
|
-
routeId: routeRef.route.name,
|
|
171
|
-
routeName: routeRef.route.name
|
|
172
|
-
} : undefined
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
this.emit(CertProvisionerEvents.CERTIFICATE_RENEWED, enhancedData);
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
this.port80Handler.on(Port80HandlerEvents.CERTIFICATE_FAILED, (error) => {
|
|
179
|
-
this.emit(CertProvisionerEvents.CERTIFICATE_FAILED, error);
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Find a route for a given domain
|
|
185
|
-
*/
|
|
186
|
-
private findRouteForDomain(domain: string): ICertRoute | undefined {
|
|
187
|
-
return this.certRoutes.find(certRoute => certRoute.domain === domain);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Set up forwarding configurations for the Port80Handler
|
|
192
|
-
*/
|
|
193
|
-
private setupForwardingConfigs(): void {
|
|
194
|
-
for (const config of this.routeForwards) {
|
|
195
|
-
const domainOptions: IDomainOptions = {
|
|
196
|
-
domainName: config.domain,
|
|
197
|
-
sslRedirect: config.sslRedirect || false,
|
|
198
|
-
acmeMaintenance: false,
|
|
199
|
-
forward: config.target ? {
|
|
200
|
-
ip: config.target.host,
|
|
201
|
-
port: config.target.port
|
|
202
|
-
} : undefined
|
|
203
|
-
};
|
|
204
|
-
this.port80Handler.addDomain(domainOptions);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Provision certificates for all routes that need them
|
|
210
|
-
*/
|
|
211
|
-
private async provisionAllCertificates(): Promise<void> {
|
|
212
|
-
for (const certRoute of this.certRoutes) {
|
|
213
|
-
await this.provisionCertificateForRoute(certRoute);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Provision a certificate for a route
|
|
219
|
-
*/
|
|
220
|
-
private async provisionCertificateForRoute(certRoute: ICertRoute): Promise<void> {
|
|
221
|
-
const { domain, route } = certRoute;
|
|
222
|
-
const isWildcard = domain.includes('*');
|
|
223
|
-
let provision: TCertProvisionObject = 'http01';
|
|
224
|
-
|
|
225
|
-
// Try to get a certificate from the provision function
|
|
226
|
-
if (this.certProvisionFunction) {
|
|
227
|
-
try {
|
|
228
|
-
provision = await this.certProvisionFunction(domain);
|
|
229
|
-
} catch (err) {
|
|
230
|
-
console.error(`certProvider error for ${domain} on route ${route.name || 'unnamed'}:`, err);
|
|
231
|
-
}
|
|
232
|
-
} else if (isWildcard) {
|
|
233
|
-
// No certProvider: cannot handle wildcard without DNS-01 support
|
|
234
|
-
console.warn(`Skipping wildcard domain without certProvisionFunction: ${domain}`);
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// Store the route reference with the provision type
|
|
239
|
-
this.provisionMap.set(domain, {
|
|
240
|
-
type: provision === 'http01' || provision === 'dns01' ? provision : 'static',
|
|
241
|
-
routeRef: certRoute
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
// Handle different provisioning methods
|
|
245
|
-
if (provision === 'http01') {
|
|
246
|
-
if (isWildcard) {
|
|
247
|
-
console.warn(`Skipping HTTP-01 for wildcard domain: ${domain}`);
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
this.port80Handler.addDomain({
|
|
252
|
-
domainName: domain,
|
|
253
|
-
sslRedirect: true,
|
|
254
|
-
acmeMaintenance: true,
|
|
255
|
-
routeReference: {
|
|
256
|
-
routeId: route.name || domain,
|
|
257
|
-
routeName: route.name
|
|
258
|
-
}
|
|
259
|
-
});
|
|
260
|
-
} else if (provision === 'dns01') {
|
|
261
|
-
// DNS-01 challenges would be handled by the certProvisionFunction
|
|
262
|
-
// DNS-01 handling would go here if implemented
|
|
263
|
-
console.log(`DNS-01 challenge type set for ${domain}`);
|
|
264
|
-
} else {
|
|
265
|
-
// Static certificate (e.g., DNS-01 provisioned or user-provided)
|
|
266
|
-
const certObj = provision as plugins.tsclass.network.ICert;
|
|
267
|
-
const certData: ICertificateData = {
|
|
268
|
-
domain: certObj.domainName,
|
|
269
|
-
certificate: certObj.publicKey,
|
|
270
|
-
privateKey: certObj.privateKey,
|
|
271
|
-
expiryDate: new Date(certObj.validUntil),
|
|
272
|
-
source: 'static',
|
|
273
|
-
isRenewal: false,
|
|
274
|
-
routeReference: {
|
|
275
|
-
routeId: route.name || domain,
|
|
276
|
-
routeName: route.name
|
|
277
|
-
}
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
this.networkProxyBridge.applyExternalCertificate(certData);
|
|
281
|
-
this.emit(CertProvisionerEvents.CERTIFICATE_ISSUED, certData);
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Schedule certificate renewals using a task manager
|
|
287
|
-
*/
|
|
288
|
-
private scheduleRenewals(): void {
|
|
289
|
-
this.renewManager = new plugins.taskbuffer.TaskManager();
|
|
290
|
-
|
|
291
|
-
const renewTask = new plugins.taskbuffer.Task({
|
|
292
|
-
name: 'CertificateRenewals',
|
|
293
|
-
taskFunction: async () => await this.performRenewals()
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
const hours = this.renewCheckIntervalHours;
|
|
297
|
-
const cronExpr = `0 0 */${hours} * * *`;
|
|
298
|
-
|
|
299
|
-
this.renewManager.addAndScheduleTask(renewTask, cronExpr);
|
|
300
|
-
this.renewManager.start();
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
/**
|
|
304
|
-
* Perform renewals for all domains that need it
|
|
305
|
-
*/
|
|
306
|
-
private async performRenewals(): Promise<void> {
|
|
307
|
-
for (const [domain, info] of this.provisionMap.entries()) {
|
|
308
|
-
// Skip wildcard domains for HTTP-01 challenges
|
|
309
|
-
if (domain.includes('*') && info.type === 'http01') continue;
|
|
310
|
-
|
|
311
|
-
try {
|
|
312
|
-
await this.renewCertificateForDomain(domain, info.type, info.routeRef);
|
|
313
|
-
} catch (err) {
|
|
314
|
-
console.error(`Renewal error for ${domain}:`, err);
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
/**
|
|
320
|
-
* Renew a certificate for a specific domain
|
|
321
|
-
* @param domain Domain to renew
|
|
322
|
-
* @param provisionType Type of provisioning for this domain
|
|
323
|
-
* @param certRoute The route reference for this domain
|
|
324
|
-
*/
|
|
325
|
-
private async renewCertificateForDomain(
|
|
326
|
-
domain: string,
|
|
327
|
-
provisionType: 'http01' | 'dns01' | 'static',
|
|
328
|
-
certRoute?: ICertRoute
|
|
329
|
-
): Promise<void> {
|
|
330
|
-
if (provisionType === 'http01') {
|
|
331
|
-
await this.port80Handler.renewCertificate(domain);
|
|
332
|
-
} else if ((provisionType === 'static' || provisionType === 'dns01') && this.certProvisionFunction) {
|
|
333
|
-
const provision = await this.certProvisionFunction(domain);
|
|
334
|
-
|
|
335
|
-
if (provision !== 'http01' && provision !== 'dns01') {
|
|
336
|
-
const certObj = provision as plugins.tsclass.network.ICert;
|
|
337
|
-
const routeRef = certRoute?.route;
|
|
338
|
-
|
|
339
|
-
const certData: ICertificateData = {
|
|
340
|
-
domain: certObj.domainName,
|
|
341
|
-
certificate: certObj.publicKey,
|
|
342
|
-
privateKey: certObj.privateKey,
|
|
343
|
-
expiryDate: new Date(certObj.validUntil),
|
|
344
|
-
source: 'static',
|
|
345
|
-
isRenewal: true,
|
|
346
|
-
routeReference: routeRef ? {
|
|
347
|
-
routeId: routeRef.name || domain,
|
|
348
|
-
routeName: routeRef.name
|
|
349
|
-
} : undefined
|
|
350
|
-
};
|
|
351
|
-
|
|
352
|
-
this.networkProxyBridge.applyExternalCertificate(certData);
|
|
353
|
-
this.emit(CertProvisionerEvents.CERTIFICATE_RENEWED, certData);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
/**
|
|
359
|
-
* Stop all scheduled renewal tasks.
|
|
360
|
-
*/
|
|
361
|
-
public async stop(): Promise<void> {
|
|
362
|
-
if (this.renewManager) {
|
|
363
|
-
this.renewManager.stop();
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
/**
|
|
368
|
-
* Request a certificate on-demand for the given domain.
|
|
369
|
-
* This will look for a matching route configuration and provision accordingly.
|
|
370
|
-
*
|
|
371
|
-
* @param domain Domain name to provision
|
|
372
|
-
*/
|
|
373
|
-
public async requestCertificate(domain: string): Promise<void> {
|
|
374
|
-
const isWildcard = domain.includes('*');
|
|
375
|
-
// Find matching route
|
|
376
|
-
const certRoute = this.findRouteForDomain(domain);
|
|
377
|
-
|
|
378
|
-
// Determine provisioning method
|
|
379
|
-
let provision: TCertProvisionObject = 'http01';
|
|
380
|
-
|
|
381
|
-
if (this.certProvisionFunction) {
|
|
382
|
-
provision = await this.certProvisionFunction(domain);
|
|
383
|
-
} else if (isWildcard) {
|
|
384
|
-
// Cannot perform HTTP-01 on wildcard without certProvider
|
|
385
|
-
throw new Error(`Cannot request certificate for wildcard domain without certProvisionFunction: ${domain}`);
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
if (provision === 'http01') {
|
|
389
|
-
if (isWildcard) {
|
|
390
|
-
throw new Error(`Cannot request HTTP-01 certificate for wildcard domain: ${domain}`);
|
|
391
|
-
}
|
|
392
|
-
await this.port80Handler.renewCertificate(domain);
|
|
393
|
-
} else if (provision === 'dns01') {
|
|
394
|
-
// DNS-01 challenges would be handled by external mechanisms
|
|
395
|
-
console.log(`DNS-01 challenge requested for ${domain}`);
|
|
396
|
-
} else {
|
|
397
|
-
// Static certificate (e.g., DNS-01 provisioned) supports wildcards
|
|
398
|
-
const certObj = provision as plugins.tsclass.network.ICert;
|
|
399
|
-
const certData: ICertificateData = {
|
|
400
|
-
domain: certObj.domainName,
|
|
401
|
-
certificate: certObj.publicKey,
|
|
402
|
-
privateKey: certObj.privateKey,
|
|
403
|
-
expiryDate: new Date(certObj.validUntil),
|
|
404
|
-
source: 'static',
|
|
405
|
-
isRenewal: false,
|
|
406
|
-
routeReference: certRoute ? {
|
|
407
|
-
routeId: certRoute.route.name || domain,
|
|
408
|
-
routeName: certRoute.route.name
|
|
409
|
-
} : undefined
|
|
410
|
-
};
|
|
411
|
-
|
|
412
|
-
this.networkProxyBridge.applyExternalCertificate(certData);
|
|
413
|
-
this.emit(CertProvisionerEvents.CERTIFICATE_ISSUED, certData);
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
/**
|
|
418
|
-
* Add a new domain for certificate provisioning
|
|
419
|
-
*
|
|
420
|
-
* @param domain Domain to add
|
|
421
|
-
* @param options Domain configuration options
|
|
422
|
-
*/
|
|
423
|
-
public async addDomain(domain: string, options?: {
|
|
424
|
-
sslRedirect?: boolean;
|
|
425
|
-
acmeMaintenance?: boolean;
|
|
426
|
-
routeId?: string;
|
|
427
|
-
routeName?: string;
|
|
428
|
-
}): Promise<void> {
|
|
429
|
-
const domainOptions: IDomainOptions = {
|
|
430
|
-
domainName: domain,
|
|
431
|
-
sslRedirect: options?.sslRedirect ?? true,
|
|
432
|
-
acmeMaintenance: options?.acmeMaintenance ?? true,
|
|
433
|
-
routeReference: {
|
|
434
|
-
routeId: options?.routeId,
|
|
435
|
-
routeName: options?.routeName
|
|
436
|
-
}
|
|
437
|
-
};
|
|
438
|
-
|
|
439
|
-
this.port80Handler.addDomain(domainOptions);
|
|
440
|
-
|
|
441
|
-
// Find matching route or create a generic one
|
|
442
|
-
const existingRoute = this.findRouteForDomain(domain);
|
|
443
|
-
if (existingRoute) {
|
|
444
|
-
await this.provisionCertificateForRoute(existingRoute);
|
|
445
|
-
} else {
|
|
446
|
-
// We don't have a route, just provision the domain
|
|
447
|
-
const isWildcard = domain.includes('*');
|
|
448
|
-
let provision: TCertProvisionObject = 'http01';
|
|
449
|
-
|
|
450
|
-
if (this.certProvisionFunction) {
|
|
451
|
-
provision = await this.certProvisionFunction(domain);
|
|
452
|
-
} else if (isWildcard) {
|
|
453
|
-
throw new Error(`Cannot request certificate for wildcard domain without certProvisionFunction: ${domain}`);
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
this.provisionMap.set(domain, {
|
|
457
|
-
type: provision === 'http01' || provision === 'dns01' ? provision : 'static'
|
|
458
|
-
});
|
|
459
|
-
|
|
460
|
-
if (provision !== 'http01' && provision !== 'dns01') {
|
|
461
|
-
const certObj = provision as plugins.tsclass.network.ICert;
|
|
462
|
-
const certData: ICertificateData = {
|
|
463
|
-
domain: certObj.domainName,
|
|
464
|
-
certificate: certObj.publicKey,
|
|
465
|
-
privateKey: certObj.privateKey,
|
|
466
|
-
expiryDate: new Date(certObj.validUntil),
|
|
467
|
-
source: 'static',
|
|
468
|
-
isRenewal: false,
|
|
469
|
-
routeReference: {
|
|
470
|
-
routeId: options?.routeId,
|
|
471
|
-
routeName: options?.routeName
|
|
472
|
-
}
|
|
473
|
-
};
|
|
474
|
-
|
|
475
|
-
this.networkProxyBridge.applyExternalCertificate(certData);
|
|
476
|
-
this.emit(CertProvisionerEvents.CERTIFICATE_ISSUED, certData);
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
/**
|
|
482
|
-
* Update routes with new configurations
|
|
483
|
-
* This replaces all existing routes with new ones and re-provisions certificates as needed
|
|
484
|
-
*
|
|
485
|
-
* @param newRoutes New route configurations to use
|
|
486
|
-
*/
|
|
487
|
-
public async updateRoutes(newRoutes: IRouteConfig[]): Promise<void> {
|
|
488
|
-
// Store the new route configs
|
|
489
|
-
this.routeConfigs = newRoutes;
|
|
490
|
-
|
|
491
|
-
// Extract new certificate routes
|
|
492
|
-
const newCertRoutes = this.extractCertificateRoutesFromRoutes(newRoutes);
|
|
493
|
-
|
|
494
|
-
// Find domains that no longer need certificates
|
|
495
|
-
const oldDomains = new Set(this.certRoutes.map(r => r.domain));
|
|
496
|
-
const newDomains = new Set(newCertRoutes.map(r => r.domain));
|
|
497
|
-
|
|
498
|
-
// Domains to remove
|
|
499
|
-
const domainsToRemove = [...oldDomains].filter(d => !newDomains.has(d));
|
|
500
|
-
|
|
501
|
-
// Remove obsolete domains from provision map
|
|
502
|
-
for (const domain of domainsToRemove) {
|
|
503
|
-
this.provisionMap.delete(domain);
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
// Update the cert routes
|
|
507
|
-
this.certRoutes = newCertRoutes;
|
|
508
|
-
|
|
509
|
-
// Provision certificates for new routes
|
|
510
|
-
for (const certRoute of newCertRoutes) {
|
|
511
|
-
if (!oldDomains.has(certRoute.domain)) {
|
|
512
|
-
await this.provisionCertificateForRoute(certRoute);
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
// Type alias for backward compatibility
|
|
519
|
-
export type TSmartProxyCertProvisionObject = TCertProvisionObject;
|