@push.rocks/smartproxy 15.0.2 → 16.0.2
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/certificate/index.d.ts +10 -4
- package/dist_ts/certificate/index.js +5 -7
- package/dist_ts/certificate/models/certificate-types.d.ts +35 -15
- package/dist_ts/certificate/providers/cert-provisioner.d.ts +41 -15
- package/dist_ts/certificate/providers/cert-provisioner.js +201 -41
- package/dist_ts/forwarding/config/forwarding-types.d.ts +40 -76
- package/dist_ts/forwarding/config/forwarding-types.js +19 -18
- package/dist_ts/forwarding/config/index.d.ts +4 -2
- package/dist_ts/forwarding/config/index.js +5 -3
- package/dist_ts/forwarding/handlers/base-handler.js +3 -1
- package/dist_ts/forwarding/index.d.ts +5 -6
- package/dist_ts/forwarding/index.js +3 -3
- package/dist_ts/http/models/http-types.js +1 -1
- package/dist_ts/http/port80/acme-interfaces.d.ts +30 -0
- package/dist_ts/http/port80/acme-interfaces.js +46 -1
- package/dist_ts/http/port80/port80-handler.d.ts +17 -2
- package/dist_ts/http/port80/port80-handler.js +49 -11
- package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +2 -61
- package/dist_ts/proxies/smart-proxy/models/interfaces.js +5 -4
- package/dist_ts/proxies/smart-proxy/models/route-types.d.ts +118 -4
- package/dist_ts/proxies/smart-proxy/network-proxy-bridge.d.ts +70 -4
- package/dist_ts/proxies/smart-proxy/network-proxy-bridge.js +193 -43
- package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +2 -5
- package/dist_ts/proxies/smart-proxy/route-connection-handler.js +25 -146
- package/dist_ts/proxies/smart-proxy/route-helpers/index.d.ts +7 -0
- package/dist_ts/proxies/smart-proxy/route-helpers/index.js +9 -0
- package/dist_ts/proxies/smart-proxy/route-helpers.d.ts +54 -1
- package/dist_ts/proxies/smart-proxy/route-helpers.js +102 -1
- package/dist_ts/proxies/smart-proxy/route-manager.d.ts +3 -9
- package/dist_ts/proxies/smart-proxy/route-manager.js +3 -115
- package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +72 -10
- package/dist_ts/proxies/smart-proxy/smart-proxy.js +135 -268
- package/dist_ts/proxies/smart-proxy/timeout-manager.js +3 -3
- package/dist_ts/proxies/smart-proxy/utils/index.d.ts +12 -0
- package/dist_ts/proxies/smart-proxy/utils/index.js +19 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers.d.ts +174 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers.js +332 -0
- package/dist_ts/proxies/smart-proxy/utils/route-migration-utils.d.ts +51 -0
- package/dist_ts/proxies/smart-proxy/utils/route-migration-utils.js +124 -0
- package/dist_ts/proxies/smart-proxy/utils/route-patterns.d.ts +131 -0
- package/dist_ts/proxies/smart-proxy/utils/route-patterns.js +217 -0
- package/dist_ts/proxies/smart-proxy/utils/route-utils.d.ts +79 -0
- package/dist_ts/proxies/smart-proxy/utils/route-utils.js +266 -0
- package/dist_ts/proxies/smart-proxy/utils/route-validators.d.ts +73 -0
- package/dist_ts/proxies/smart-proxy/utils/route-validators.js +242 -0
- package/package.json +1 -1
- package/readme.md +139 -111
- package/readme.plan.md +164 -312
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/certificate/index.ts +17 -9
- package/ts/certificate/models/certificate-types.ts +37 -16
- package/ts/certificate/providers/cert-provisioner.ts +247 -54
- package/ts/forwarding/config/forwarding-types.ts +79 -107
- package/ts/forwarding/config/index.ts +4 -2
- package/ts/forwarding/handlers/base-handler.ts +4 -2
- package/ts/forwarding/index.ts +3 -2
- package/ts/http/models/http-types.ts +0 -1
- package/ts/http/port80/acme-interfaces.ts +84 -0
- package/ts/http/port80/port80-handler.ts +61 -15
- package/ts/proxies/smart-proxy/models/interfaces.ts +7 -64
- package/ts/proxies/smart-proxy/models/route-types.ts +152 -22
- package/ts/proxies/smart-proxy/network-proxy-bridge.ts +226 -55
- package/ts/proxies/smart-proxy/route-connection-handler.ts +36 -205
- package/ts/proxies/smart-proxy/route-helpers/index.ts +9 -0
- package/ts/proxies/smart-proxy/route-helpers.ts +165 -11
- package/ts/proxies/smart-proxy/route-manager.ts +3 -130
- package/ts/proxies/smart-proxy/smart-proxy.ts +157 -329
- package/ts/proxies/smart-proxy/timeout-manager.ts +2 -2
- package/ts/proxies/smart-proxy/utils/index.ts +40 -0
- package/ts/proxies/smart-proxy/utils/route-helpers.ts +455 -0
- package/ts/proxies/smart-proxy/utils/route-migration-utils.ts +165 -0
- package/ts/proxies/smart-proxy/utils/route-patterns.ts +309 -0
- package/ts/proxies/smart-proxy/utils/route-utils.ts +330 -0
- package/ts/proxies/smart-proxy/utils/route-validators.ts +269 -0
- package/ts/forwarding/config/domain-config.ts +0 -28
- package/ts/forwarding/config/domain-manager.ts +0 -283
- package/ts/proxies/smart-proxy/connection-handler.ts +0 -1240
- package/ts/proxies/smart-proxy/port-range-manager.ts +0 -211
- /package/ts/proxies/smart-proxy/{domain-config-manager.ts → domain-config-manager.ts.bak} +0 -0
|
@@ -1,63 +1,112 @@
|
|
|
1
1
|
import * as plugins from '../../plugins.js';
|
|
2
|
-
import type {
|
|
3
|
-
import type { ICertificateData,
|
|
2
|
+
import type { IRouteConfig } from '../../proxies/smart-proxy/models/route-types.js';
|
|
3
|
+
import type { ICertificateData, IRouteForwardConfig, IDomainOptions } from '../models/certificate-types.js';
|
|
4
4
|
import { Port80HandlerEvents, CertProvisionerEvents } from '../events/certificate-events.js';
|
|
5
5
|
import { Port80Handler } from '../../http/port80/port80-handler.js';
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
// Interface for NetworkProxyBridge
|
|
7
8
|
interface INetworkProxyBridge {
|
|
8
9
|
applyExternalCertificate(certData: ICertificateData): void;
|
|
9
10
|
}
|
|
10
11
|
|
|
11
|
-
// This will be imported after NetworkProxyBridge is migrated
|
|
12
|
-
// import type { NetworkProxyBridge } from '../../proxies/smart-proxy/network-proxy-bridge.js';
|
|
13
|
-
|
|
14
|
-
// For backward compatibility
|
|
15
|
-
export type TSmartProxyCertProvisionObject = plugins.tsclass.network.ICert | 'http01';
|
|
16
|
-
|
|
17
12
|
/**
|
|
18
13
|
* Type for static certificate provisioning
|
|
19
14
|
*/
|
|
20
15
|
export type TCertProvisionObject = plugins.tsclass.network.ICert | 'http01' | 'dns01';
|
|
21
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
|
+
|
|
22
26
|
/**
|
|
23
27
|
* CertProvisioner manages certificate provisioning and renewal workflows,
|
|
24
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.
|
|
25
31
|
*/
|
|
26
32
|
export class CertProvisioner extends plugins.EventEmitter {
|
|
27
|
-
private
|
|
33
|
+
private routeConfigs: IRouteConfig[];
|
|
34
|
+
private certRoutes: ICertRoute[] = [];
|
|
28
35
|
private port80Handler: Port80Handler;
|
|
29
36
|
private networkProxyBridge: INetworkProxyBridge;
|
|
30
37
|
private certProvisionFunction?: (domain: string) => Promise<TCertProvisionObject>;
|
|
31
|
-
private
|
|
38
|
+
private routeForwards: IRouteForwardConfig[];
|
|
32
39
|
private renewThresholdDays: number;
|
|
33
40
|
private renewCheckIntervalHours: number;
|
|
34
41
|
private autoRenew: boolean;
|
|
35
42
|
private renewManager?: plugins.taskbuffer.TaskManager;
|
|
36
43
|
// Track provisioning type per domain
|
|
37
|
-
private provisionMap: Map<string, 'http01' | 'dns01' | 'static'>;
|
|
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
|
+
}
|
|
38
85
|
|
|
39
86
|
/**
|
|
40
|
-
*
|
|
87
|
+
* Constructor for CertProvisioner
|
|
88
|
+
*
|
|
89
|
+
* @param routeConfigs Array of route configurations
|
|
41
90
|
* @param port80Handler HTTP-01 challenge handler instance
|
|
42
91
|
* @param networkProxyBridge Bridge for applying external certificates
|
|
43
92
|
* @param certProvider Optional callback returning a static cert or 'http01'
|
|
44
93
|
* @param renewThresholdDays Days before expiry to trigger renewals
|
|
45
94
|
* @param renewCheckIntervalHours Interval in hours to check for renewals
|
|
46
95
|
* @param autoRenew Whether to automatically schedule renewals
|
|
47
|
-
* @param
|
|
96
|
+
* @param routeForwards Route-specific forwarding configs for ACME challenges
|
|
48
97
|
*/
|
|
49
98
|
constructor(
|
|
50
|
-
|
|
99
|
+
routeConfigs: IRouteConfig[],
|
|
51
100
|
port80Handler: Port80Handler,
|
|
52
101
|
networkProxyBridge: INetworkProxyBridge,
|
|
53
102
|
certProvider?: (domain: string) => Promise<TCertProvisionObject>,
|
|
54
103
|
renewThresholdDays: number = 30,
|
|
55
104
|
renewCheckIntervalHours: number = 24,
|
|
56
105
|
autoRenew: boolean = true,
|
|
57
|
-
|
|
106
|
+
routeForwards: IRouteForwardConfig[] = []
|
|
58
107
|
) {
|
|
59
108
|
super();
|
|
60
|
-
this.
|
|
109
|
+
this.routeConfigs = routeConfigs;
|
|
61
110
|
this.port80Handler = port80Handler;
|
|
62
111
|
this.networkProxyBridge = networkProxyBridge;
|
|
63
112
|
this.certProvisionFunction = certProvider;
|
|
@@ -65,7 +114,10 @@ export class CertProvisioner extends plugins.EventEmitter {
|
|
|
65
114
|
this.renewCheckIntervalHours = renewCheckIntervalHours;
|
|
66
115
|
this.autoRenew = autoRenew;
|
|
67
116
|
this.provisionMap = new Map();
|
|
68
|
-
this.
|
|
117
|
+
this.routeForwards = routeForwards;
|
|
118
|
+
|
|
119
|
+
// Extract certificate routes during instantiation
|
|
120
|
+
this.certRoutes = this.extractCertificateRoutesFromRoutes(routeConfigs);
|
|
69
121
|
}
|
|
70
122
|
|
|
71
123
|
/**
|
|
@@ -75,11 +127,11 @@ export class CertProvisioner extends plugins.EventEmitter {
|
|
|
75
127
|
// Subscribe to Port80Handler certificate events
|
|
76
128
|
this.setupEventSubscriptions();
|
|
77
129
|
|
|
78
|
-
// Apply
|
|
130
|
+
// Apply route forwarding for ACME challenges
|
|
79
131
|
this.setupForwardingConfigs();
|
|
80
132
|
|
|
81
|
-
// Initial provisioning for all domains
|
|
82
|
-
await this.
|
|
133
|
+
// Initial provisioning for all domains in routes
|
|
134
|
+
await this.provisionAllCertificates();
|
|
83
135
|
|
|
84
136
|
// Schedule renewals if enabled
|
|
85
137
|
if (this.autoRenew) {
|
|
@@ -91,13 +143,36 @@ export class CertProvisioner extends plugins.EventEmitter {
|
|
|
91
143
|
* Set up event subscriptions for certificate events
|
|
92
144
|
*/
|
|
93
145
|
private setupEventSubscriptions(): void {
|
|
94
|
-
// We need to reimplement subscribeToPort80Handler here
|
|
95
146
|
this.port80Handler.on(Port80HandlerEvents.CERTIFICATE_ISSUED, (data: ICertificateData) => {
|
|
96
|
-
|
|
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);
|
|
97
160
|
});
|
|
98
161
|
|
|
99
162
|
this.port80Handler.on(Port80HandlerEvents.CERTIFICATE_RENEWED, (data: ICertificateData) => {
|
|
100
|
-
|
|
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);
|
|
101
176
|
});
|
|
102
177
|
|
|
103
178
|
this.port80Handler.on(Port80HandlerEvents.CERTIFICATE_FAILED, (error) => {
|
|
@@ -105,38 +180,45 @@ export class CertProvisioner extends plugins.EventEmitter {
|
|
|
105
180
|
});
|
|
106
181
|
}
|
|
107
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
|
+
|
|
108
190
|
/**
|
|
109
191
|
* Set up forwarding configurations for the Port80Handler
|
|
110
192
|
*/
|
|
111
193
|
private setupForwardingConfigs(): void {
|
|
112
|
-
for (const config of this.
|
|
194
|
+
for (const config of this.routeForwards) {
|
|
113
195
|
const domainOptions: IDomainOptions = {
|
|
114
196
|
domainName: config.domain,
|
|
115
197
|
sslRedirect: config.sslRedirect || false,
|
|
116
198
|
acmeMaintenance: false,
|
|
117
|
-
forward: config.
|
|
118
|
-
|
|
199
|
+
forward: config.target ? {
|
|
200
|
+
ip: config.target.host,
|
|
201
|
+
port: config.target.port
|
|
202
|
+
} : undefined
|
|
119
203
|
};
|
|
120
204
|
this.port80Handler.addDomain(domainOptions);
|
|
121
205
|
}
|
|
122
206
|
}
|
|
123
207
|
|
|
124
208
|
/**
|
|
125
|
-
* Provision certificates for all
|
|
209
|
+
* Provision certificates for all routes that need them
|
|
126
210
|
*/
|
|
127
|
-
private async
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
for (const domain of domains) {
|
|
131
|
-
await this.provisionDomain(domain);
|
|
211
|
+
private async provisionAllCertificates(): Promise<void> {
|
|
212
|
+
for (const certRoute of this.certRoutes) {
|
|
213
|
+
await this.provisionCertificateForRoute(certRoute);
|
|
132
214
|
}
|
|
133
215
|
}
|
|
134
216
|
|
|
135
217
|
/**
|
|
136
|
-
* Provision a certificate for a
|
|
137
|
-
* @param domain Domain to provision
|
|
218
|
+
* Provision a certificate for a route
|
|
138
219
|
*/
|
|
139
|
-
private async
|
|
220
|
+
private async provisionCertificateForRoute(certRoute: ICertRoute): Promise<void> {
|
|
221
|
+
const { domain, route } = certRoute;
|
|
140
222
|
const isWildcard = domain.includes('*');
|
|
141
223
|
let provision: TCertProvisionObject = 'http01';
|
|
142
224
|
|
|
@@ -145,7 +227,7 @@ export class CertProvisioner extends plugins.EventEmitter {
|
|
|
145
227
|
try {
|
|
146
228
|
provision = await this.certProvisionFunction(domain);
|
|
147
229
|
} catch (err) {
|
|
148
|
-
console.error(`certProvider error for ${domain}:`, err);
|
|
230
|
+
console.error(`certProvider error for ${domain} on route ${route.name || 'unnamed'}:`, err);
|
|
149
231
|
}
|
|
150
232
|
} else if (isWildcard) {
|
|
151
233
|
// No certProvider: cannot handle wildcard without DNS-01 support
|
|
@@ -153,6 +235,12 @@ export class CertProvisioner extends plugins.EventEmitter {
|
|
|
153
235
|
return;
|
|
154
236
|
}
|
|
155
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
|
+
|
|
156
244
|
// Handle different provisioning methods
|
|
157
245
|
if (provision === 'http01') {
|
|
158
246
|
if (isWildcard) {
|
|
@@ -160,19 +248,21 @@ export class CertProvisioner extends plugins.EventEmitter {
|
|
|
160
248
|
return;
|
|
161
249
|
}
|
|
162
250
|
|
|
163
|
-
this.provisionMap.set(domain, 'http01');
|
|
164
251
|
this.port80Handler.addDomain({
|
|
165
252
|
domainName: domain,
|
|
166
253
|
sslRedirect: true,
|
|
167
|
-
acmeMaintenance: true
|
|
254
|
+
acmeMaintenance: true,
|
|
255
|
+
routeReference: {
|
|
256
|
+
routeId: route.name || domain,
|
|
257
|
+
routeName: route.name
|
|
258
|
+
}
|
|
168
259
|
});
|
|
169
260
|
} else if (provision === 'dns01') {
|
|
170
261
|
// DNS-01 challenges would be handled by the certProvisionFunction
|
|
171
|
-
this.provisionMap.set(domain, 'dns01');
|
|
172
262
|
// DNS-01 handling would go here if implemented
|
|
263
|
+
console.log(`DNS-01 challenge type set for ${domain}`);
|
|
173
264
|
} else {
|
|
174
265
|
// Static certificate (e.g., DNS-01 provisioned or user-provided)
|
|
175
|
-
this.provisionMap.set(domain, 'static');
|
|
176
266
|
const certObj = provision as plugins.tsclass.network.ICert;
|
|
177
267
|
const certData: ICertificateData = {
|
|
178
268
|
domain: certObj.domainName,
|
|
@@ -180,7 +270,11 @@ export class CertProvisioner extends plugins.EventEmitter {
|
|
|
180
270
|
privateKey: certObj.privateKey,
|
|
181
271
|
expiryDate: new Date(certObj.validUntil),
|
|
182
272
|
source: 'static',
|
|
183
|
-
isRenewal: false
|
|
273
|
+
isRenewal: false,
|
|
274
|
+
routeReference: {
|
|
275
|
+
routeId: route.name || domain,
|
|
276
|
+
routeName: route.name
|
|
277
|
+
}
|
|
184
278
|
};
|
|
185
279
|
|
|
186
280
|
this.networkProxyBridge.applyExternalCertificate(certData);
|
|
@@ -210,12 +304,12 @@ export class CertProvisioner extends plugins.EventEmitter {
|
|
|
210
304
|
* Perform renewals for all domains that need it
|
|
211
305
|
*/
|
|
212
306
|
private async performRenewals(): Promise<void> {
|
|
213
|
-
for (const [domain,
|
|
307
|
+
for (const [domain, info] of this.provisionMap.entries()) {
|
|
214
308
|
// Skip wildcard domains for HTTP-01 challenges
|
|
215
|
-
if (domain.includes('*') && type === 'http01') continue;
|
|
309
|
+
if (domain.includes('*') && info.type === 'http01') continue;
|
|
216
310
|
|
|
217
311
|
try {
|
|
218
|
-
await this.
|
|
312
|
+
await this.renewCertificateForDomain(domain, info.type, info.routeRef);
|
|
219
313
|
} catch (err) {
|
|
220
314
|
console.error(`Renewal error for ${domain}:`, err);
|
|
221
315
|
}
|
|
@@ -226,8 +320,13 @@ export class CertProvisioner extends plugins.EventEmitter {
|
|
|
226
320
|
* Renew a certificate for a specific domain
|
|
227
321
|
* @param domain Domain to renew
|
|
228
322
|
* @param provisionType Type of provisioning for this domain
|
|
323
|
+
* @param certRoute The route reference for this domain
|
|
229
324
|
*/
|
|
230
|
-
private async
|
|
325
|
+
private async renewCertificateForDomain(
|
|
326
|
+
domain: string,
|
|
327
|
+
provisionType: 'http01' | 'dns01' | 'static',
|
|
328
|
+
certRoute?: ICertRoute
|
|
329
|
+
): Promise<void> {
|
|
231
330
|
if (provisionType === 'http01') {
|
|
232
331
|
await this.port80Handler.renewCertificate(domain);
|
|
233
332
|
} else if ((provisionType === 'static' || provisionType === 'dns01') && this.certProvisionFunction) {
|
|
@@ -235,13 +334,19 @@ export class CertProvisioner extends plugins.EventEmitter {
|
|
|
235
334
|
|
|
236
335
|
if (provision !== 'http01' && provision !== 'dns01') {
|
|
237
336
|
const certObj = provision as plugins.tsclass.network.ICert;
|
|
337
|
+
const routeRef = certRoute?.route;
|
|
338
|
+
|
|
238
339
|
const certData: ICertificateData = {
|
|
239
340
|
domain: certObj.domainName,
|
|
240
341
|
certificate: certObj.publicKey,
|
|
241
342
|
privateKey: certObj.privateKey,
|
|
242
343
|
expiryDate: new Date(certObj.validUntil),
|
|
243
344
|
source: 'static',
|
|
244
|
-
isRenewal: true
|
|
345
|
+
isRenewal: true,
|
|
346
|
+
routeReference: routeRef ? {
|
|
347
|
+
routeId: routeRef.name || domain,
|
|
348
|
+
routeName: routeRef.name
|
|
349
|
+
} : undefined
|
|
245
350
|
};
|
|
246
351
|
|
|
247
352
|
this.networkProxyBridge.applyExternalCertificate(certData);
|
|
@@ -261,10 +366,14 @@ export class CertProvisioner extends plugins.EventEmitter {
|
|
|
261
366
|
|
|
262
367
|
/**
|
|
263
368
|
* Request a certificate on-demand for the given domain.
|
|
369
|
+
* This will look for a matching route configuration and provision accordingly.
|
|
370
|
+
*
|
|
264
371
|
* @param domain Domain name to provision
|
|
265
372
|
*/
|
|
266
373
|
public async requestCertificate(domain: string): Promise<void> {
|
|
267
374
|
const isWildcard = domain.includes('*');
|
|
375
|
+
// Find matching route
|
|
376
|
+
const certRoute = this.findRouteForDomain(domain);
|
|
268
377
|
|
|
269
378
|
// Determine provisioning method
|
|
270
379
|
let provision: TCertProvisionObject = 'http01';
|
|
@@ -283,7 +392,6 @@ export class CertProvisioner extends plugins.EventEmitter {
|
|
|
283
392
|
await this.port80Handler.renewCertificate(domain);
|
|
284
393
|
} else if (provision === 'dns01') {
|
|
285
394
|
// DNS-01 challenges would be handled by external mechanisms
|
|
286
|
-
// This is a placeholder for future implementation
|
|
287
395
|
console.log(`DNS-01 challenge requested for ${domain}`);
|
|
288
396
|
} else {
|
|
289
397
|
// Static certificate (e.g., DNS-01 provisioned) supports wildcards
|
|
@@ -294,7 +402,11 @@ export class CertProvisioner extends plugins.EventEmitter {
|
|
|
294
402
|
privateKey: certObj.privateKey,
|
|
295
403
|
expiryDate: new Date(certObj.validUntil),
|
|
296
404
|
source: 'static',
|
|
297
|
-
isRenewal: false
|
|
405
|
+
isRenewal: false,
|
|
406
|
+
routeReference: certRoute ? {
|
|
407
|
+
routeId: certRoute.route.name || domain,
|
|
408
|
+
routeName: certRoute.route.name
|
|
409
|
+
} : undefined
|
|
298
410
|
};
|
|
299
411
|
|
|
300
412
|
this.networkProxyBridge.applyExternalCertificate(certData);
|
|
@@ -304,23 +416,104 @@ export class CertProvisioner extends plugins.EventEmitter {
|
|
|
304
416
|
|
|
305
417
|
/**
|
|
306
418
|
* Add a new domain for certificate provisioning
|
|
419
|
+
*
|
|
307
420
|
* @param domain Domain to add
|
|
308
421
|
* @param options Domain configuration options
|
|
309
422
|
*/
|
|
310
423
|
public async addDomain(domain: string, options?: {
|
|
311
424
|
sslRedirect?: boolean;
|
|
312
425
|
acmeMaintenance?: boolean;
|
|
426
|
+
routeId?: string;
|
|
427
|
+
routeName?: string;
|
|
313
428
|
}): Promise<void> {
|
|
314
429
|
const domainOptions: IDomainOptions = {
|
|
315
430
|
domainName: domain,
|
|
316
|
-
sslRedirect: options?.sslRedirect
|
|
317
|
-
acmeMaintenance: options?.acmeMaintenance
|
|
431
|
+
sslRedirect: options?.sslRedirect ?? true,
|
|
432
|
+
acmeMaintenance: options?.acmeMaintenance ?? true,
|
|
433
|
+
routeReference: {
|
|
434
|
+
routeId: options?.routeId,
|
|
435
|
+
routeName: options?.routeName
|
|
436
|
+
}
|
|
318
437
|
};
|
|
319
438
|
|
|
320
439
|
this.port80Handler.addDomain(domainOptions);
|
|
321
|
-
|
|
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
|
+
}
|
|
322
515
|
}
|
|
323
516
|
}
|
|
324
517
|
|
|
325
|
-
//
|
|
326
|
-
export
|
|
518
|
+
// Type alias for backward compatibility
|
|
519
|
+
export type TSmartProxyCertProvisionObject = TCertProvisionObject;
|