@push.rocks/smartproxy 19.2.3 → 19.2.4
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/proxies/smart-proxy/certificate-manager.d.ts +3 -1
- package/dist_ts/proxies/smart-proxy/certificate-manager.js +88 -48
- package/package.json +1 -1
- package/readme.plan.md +101 -65
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/proxies/smart-proxy/certificate-manager.ts +76 -29
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/smartproxy',
|
|
6
|
-
version: '19.2.
|
|
6
|
+
version: '19.2.4',
|
|
7
7
|
description: 'A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.'
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx3QkFBd0I7SUFDOUIsT0FBTyxFQUFFLFFBQVE7SUFDakIsV0FBVyxFQUFFLHFQQUFxUDtDQUNuUSxDQUFBIn0=
|
|
@@ -29,6 +29,8 @@ export declare class SmartCertManager {
|
|
|
29
29
|
private certStatus;
|
|
30
30
|
private globalAcmeDefaults;
|
|
31
31
|
private updateRoutesCallback?;
|
|
32
|
+
private challengeRouteActive;
|
|
33
|
+
private isProvisioning;
|
|
32
34
|
constructor(routes: IRouteConfig[], certDir?: string, acmeOptions?: {
|
|
33
35
|
email?: string;
|
|
34
36
|
useProduction?: boolean;
|
|
@@ -54,7 +56,7 @@ export declare class SmartCertManager {
|
|
|
54
56
|
/**
|
|
55
57
|
* Provision certificate for a single route
|
|
56
58
|
*/
|
|
57
|
-
provisionCertificate(route: IRouteConfig): Promise<void>;
|
|
59
|
+
provisionCertificate(route: IRouteConfig, allowConcurrent?: boolean): Promise<void>;
|
|
58
60
|
/**
|
|
59
61
|
* Provision ACME certificate
|
|
60
62
|
*/
|
|
@@ -15,6 +15,10 @@ export class SmartCertManager {
|
|
|
15
15
|
this.certStatus = new Map();
|
|
16
16
|
// Global ACME defaults from top-level configuration
|
|
17
17
|
this.globalAcmeDefaults = null;
|
|
18
|
+
// Flag to track if challenge route is currently active
|
|
19
|
+
this.challengeRouteActive = false;
|
|
20
|
+
// Flag to track if provisioning is in progress
|
|
21
|
+
this.isProvisioning = false;
|
|
18
22
|
this.certStore = new CertStore(certDir);
|
|
19
23
|
}
|
|
20
24
|
setNetworkProxy(networkProxy) {
|
|
@@ -53,6 +57,9 @@ export class SmartCertManager {
|
|
|
53
57
|
challengeHandlers: [http01Handler]
|
|
54
58
|
});
|
|
55
59
|
await this.smartAcme.start();
|
|
60
|
+
// Add challenge route once at initialization
|
|
61
|
+
console.log('Adding ACME challenge route during initialization');
|
|
62
|
+
await this.addChallengeRoute();
|
|
56
63
|
}
|
|
57
64
|
// Provision certificates for all routes
|
|
58
65
|
await this.provisionAllCertificates();
|
|
@@ -65,23 +72,35 @@ export class SmartCertManager {
|
|
|
65
72
|
async provisionAllCertificates() {
|
|
66
73
|
const certRoutes = this.routes.filter(r => r.action.tls?.mode === 'terminate' ||
|
|
67
74
|
r.action.tls?.mode === 'terminate-and-reencrypt');
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
// Set provisioning flag to prevent concurrent operations
|
|
76
|
+
this.isProvisioning = true;
|
|
77
|
+
try {
|
|
78
|
+
for (const route of certRoutes) {
|
|
79
|
+
try {
|
|
80
|
+
await this.provisionCertificate(route, true); // Allow concurrent since we're managing it here
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
console.error(`Failed to provision certificate for route ${route.name}: ${error}`);
|
|
84
|
+
}
|
|
74
85
|
}
|
|
75
86
|
}
|
|
87
|
+
finally {
|
|
88
|
+
this.isProvisioning = false;
|
|
89
|
+
}
|
|
76
90
|
}
|
|
77
91
|
/**
|
|
78
92
|
* Provision certificate for a single route
|
|
79
93
|
*/
|
|
80
|
-
async provisionCertificate(route) {
|
|
94
|
+
async provisionCertificate(route, allowConcurrent = false) {
|
|
81
95
|
const tls = route.action.tls;
|
|
82
96
|
if (!tls || (tls.mode !== 'terminate' && tls.mode !== 'terminate-and-reencrypt')) {
|
|
83
97
|
return;
|
|
84
98
|
}
|
|
99
|
+
// Check if provisioning is already in progress (prevent concurrent provisioning)
|
|
100
|
+
if (!allowConcurrent && this.isProvisioning) {
|
|
101
|
+
console.log(`Certificate provisioning already in progress, skipping ${route.name}`);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
85
104
|
const domains = this.extractDomainsFromRoute(route);
|
|
86
105
|
if (domains.length === 0) {
|
|
87
106
|
console.warn(`Route ${route.name} has TLS termination but no domains`);
|
|
@@ -124,42 +143,30 @@ export class SmartCertManager {
|
|
|
124
143
|
console.log(`Requesting ACME certificate for ${domains.join(', ')} (renew ${renewThreshold} days before expiry)`);
|
|
125
144
|
this.updateCertStatus(routeName, 'pending', 'acme');
|
|
126
145
|
try {
|
|
127
|
-
//
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
console.log(`Successfully provisioned ACME certificate for ${primaryDomain}`);
|
|
149
|
-
}
|
|
150
|
-
catch (error) {
|
|
151
|
-
console.error(`Failed to provision ACME certificate for ${primaryDomain}: ${error}`);
|
|
152
|
-
this.updateCertStatus(routeName, 'error', 'acme', undefined, error.message);
|
|
153
|
-
throw error;
|
|
154
|
-
}
|
|
155
|
-
finally {
|
|
156
|
-
// Always remove challenge route after provisioning
|
|
157
|
-
await this.removeChallengeRoute();
|
|
158
|
-
}
|
|
146
|
+
// Challenge route should already be active from initialization
|
|
147
|
+
// No need to add it for each certificate
|
|
148
|
+
// Use smartacme to get certificate
|
|
149
|
+
const cert = await this.smartAcme.getCertificateForDomain(primaryDomain);
|
|
150
|
+
// SmartAcme's Cert object has these properties:
|
|
151
|
+
// - publicKey: The certificate PEM string
|
|
152
|
+
// - privateKey: The private key PEM string
|
|
153
|
+
// - csr: Certificate signing request
|
|
154
|
+
// - validUntil: Timestamp in milliseconds
|
|
155
|
+
// - domainName: The domain name
|
|
156
|
+
const certData = {
|
|
157
|
+
cert: cert.publicKey,
|
|
158
|
+
key: cert.privateKey,
|
|
159
|
+
ca: cert.publicKey, // Use same as cert for now
|
|
160
|
+
expiryDate: new Date(cert.validUntil),
|
|
161
|
+
issueDate: new Date(cert.created)
|
|
162
|
+
};
|
|
163
|
+
await this.certStore.saveCertificate(routeName, certData);
|
|
164
|
+
await this.applyCertificate(primaryDomain, certData);
|
|
165
|
+
this.updateCertStatus(routeName, 'valid', 'acme', certData);
|
|
166
|
+
console.log(`Successfully provisioned ACME certificate for ${primaryDomain}`);
|
|
159
167
|
}
|
|
160
168
|
catch (error) {
|
|
161
|
-
|
|
162
|
-
console.error(`Failed to setup ACME challenge for ${primaryDomain}: ${error}`);
|
|
169
|
+
console.error(`Failed to provision ACME certificate for ${primaryDomain}: ${error}`);
|
|
163
170
|
this.updateCertStatus(routeName, 'error', 'acme', undefined, error.message);
|
|
164
171
|
throw error;
|
|
165
172
|
}
|
|
@@ -251,6 +258,10 @@ export class SmartCertManager {
|
|
|
251
258
|
* Add challenge route to SmartProxy
|
|
252
259
|
*/
|
|
253
260
|
async addChallengeRoute() {
|
|
261
|
+
if (this.challengeRouteActive) {
|
|
262
|
+
console.log('Challenge route already active, skipping');
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
254
265
|
if (!this.updateRoutesCallback) {
|
|
255
266
|
throw new Error('No route update callback set');
|
|
256
267
|
}
|
|
@@ -258,18 +269,43 @@ export class SmartCertManager {
|
|
|
258
269
|
throw new Error('Challenge route not initialized');
|
|
259
270
|
}
|
|
260
271
|
const challengeRoute = this.challengeRoute;
|
|
261
|
-
|
|
262
|
-
|
|
272
|
+
try {
|
|
273
|
+
const updatedRoutes = [...this.routes, challengeRoute];
|
|
274
|
+
await this.updateRoutesCallback(updatedRoutes);
|
|
275
|
+
this.challengeRouteActive = true;
|
|
276
|
+
console.log('ACME challenge route successfully added');
|
|
277
|
+
}
|
|
278
|
+
catch (error) {
|
|
279
|
+
console.error('Failed to add challenge route:', error);
|
|
280
|
+
if (error.code === 'EADDRINUSE') {
|
|
281
|
+
throw new Error(`Port ${this.globalAcmeDefaults?.port || 80} is already in use for ACME challenges`);
|
|
282
|
+
}
|
|
283
|
+
throw error;
|
|
284
|
+
}
|
|
263
285
|
}
|
|
264
286
|
/**
|
|
265
287
|
* Remove challenge route from SmartProxy
|
|
266
288
|
*/
|
|
267
289
|
async removeChallengeRoute() {
|
|
290
|
+
if (!this.challengeRouteActive) {
|
|
291
|
+
console.log('Challenge route not active, skipping removal');
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
268
294
|
if (!this.updateRoutesCallback) {
|
|
269
295
|
return;
|
|
270
296
|
}
|
|
271
|
-
|
|
272
|
-
|
|
297
|
+
try {
|
|
298
|
+
const filteredRoutes = this.routes.filter(r => r.name !== 'acme-challenge');
|
|
299
|
+
await this.updateRoutesCallback(filteredRoutes);
|
|
300
|
+
this.challengeRouteActive = false;
|
|
301
|
+
console.log('ACME challenge route successfully removed');
|
|
302
|
+
}
|
|
303
|
+
catch (error) {
|
|
304
|
+
console.error('Failed to remove challenge route:', error);
|
|
305
|
+
// Reset the flag even on error to avoid getting stuck
|
|
306
|
+
this.challengeRouteActive = false;
|
|
307
|
+
throw error;
|
|
308
|
+
}
|
|
273
309
|
}
|
|
274
310
|
/**
|
|
275
311
|
* Start renewal timer
|
|
@@ -401,13 +437,17 @@ export class SmartCertManager {
|
|
|
401
437
|
clearInterval(this.renewalTimer);
|
|
402
438
|
this.renewalTimer = null;
|
|
403
439
|
}
|
|
440
|
+
// Always remove challenge route on shutdown
|
|
441
|
+
if (this.challengeRoute) {
|
|
442
|
+
console.log('Removing ACME challenge route during shutdown');
|
|
443
|
+
await this.removeChallengeRoute();
|
|
444
|
+
}
|
|
404
445
|
if (this.smartAcme) {
|
|
405
446
|
await this.smartAcme.stop();
|
|
406
447
|
}
|
|
407
|
-
//
|
|
448
|
+
// Clear any pending challenges
|
|
408
449
|
if (this.pendingChallenges.size > 0) {
|
|
409
450
|
this.pendingChallenges.clear();
|
|
410
|
-
await this.removeChallengeRoute();
|
|
411
451
|
}
|
|
412
452
|
}
|
|
413
453
|
/**
|
|
@@ -417,4 +457,4 @@ export class SmartCertManager {
|
|
|
417
457
|
return this.acmeOptions;
|
|
418
458
|
}
|
|
419
459
|
}
|
|
420
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2VydGlmaWNhdGUtbWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL3Byb3hpZXMvc21hcnQtcHJveHkvY2VydGlmaWNhdGUtbWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGtCQUFrQixDQUFDO0FBQzVDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUd6RCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFtQjVDLE1BQU0sT0FBTyxnQkFBZ0I7SUFpQjNCLFlBQ1UsTUFBc0IsRUFDdEIsVUFBa0IsU0FBUyxFQUMzQixXQUlQO1FBTk8sV0FBTSxHQUFOLE1BQU0sQ0FBZ0I7UUFDdEIsWUFBTyxHQUFQLE9BQU8sQ0FBb0I7UUFDM0IsZ0JBQVcsR0FBWCxXQUFXLENBSWxCO1FBdEJLLGNBQVMsR0FBdUMsSUFBSSxDQUFDO1FBQ3JELGlCQUFZLEdBQXdCLElBQUksQ0FBQztRQUN6QyxpQkFBWSxHQUEwQixJQUFJLENBQUM7UUFDM0Msc0JBQWlCLEdBQXdCLElBQUksR0FBRyxFQUFFLENBQUM7UUFDbkQsbUJBQWMsR0FBd0IsSUFBSSxDQUFDO1FBRW5ELHlDQUF5QztRQUNqQyxlQUFVLEdBQTZCLElBQUksR0FBRyxFQUFFLENBQUM7UUFFekQsb0RBQW9EO1FBQzVDLHVCQUFrQixHQUF3QixJQUFJLENBQUM7UUFjckQsSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUMxQyxDQUFDO0lBRU0sZUFBZSxDQUFDLFlBQTBCO1FBQy9DLElBQUksQ0FBQyxZQUFZLEdBQUcsWUFBWSxDQUFDO0lBQ25DLENBQUM7SUFFRDs7T0FFRztJQUNJLHFCQUFxQixDQUFDLFFBQXNCO1FBQ2pELElBQUksQ0FBQyxrQkFBa0IsR0FBRyxRQUFRLENBQUM7SUFDckMsQ0FBQztJQUVEOztPQUVHO0lB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
|
|
460
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2VydGlmaWNhdGUtbWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL3Byb3hpZXMvc21hcnQtcHJveHkvY2VydGlmaWNhdGUtbWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGtCQUFrQixDQUFDO0FBQzVDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUd6RCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFtQjVDLE1BQU0sT0FBTyxnQkFBZ0I7SUF1QjNCLFlBQ1UsTUFBc0IsRUFDdEIsVUFBa0IsU0FBUyxFQUMzQixXQUlQO1FBTk8sV0FBTSxHQUFOLE1BQU0sQ0FBZ0I7UUFDdEIsWUFBTyxHQUFQLE9BQU8sQ0FBb0I7UUFDM0IsZ0JBQVcsR0FBWCxXQUFXLENBSWxCO1FBNUJLLGNBQVMsR0FBdUMsSUFBSSxDQUFDO1FBQ3JELGlCQUFZLEdBQXdCLElBQUksQ0FBQztRQUN6QyxpQkFBWSxHQUEwQixJQUFJLENBQUM7UUFDM0Msc0JBQWlCLEdBQXdCLElBQUksR0FBRyxFQUFFLENBQUM7UUFDbkQsbUJBQWMsR0FBd0IsSUFBSSxDQUFDO1FBRW5ELHlDQUF5QztRQUNqQyxlQUFVLEdBQTZCLElBQUksR0FBRyxFQUFFLENBQUM7UUFFekQsb0RBQW9EO1FBQzVDLHVCQUFrQixHQUF3QixJQUFJLENBQUM7UUFLdkQsdURBQXVEO1FBQy9DLHlCQUFvQixHQUFZLEtBQUssQ0FBQztRQUU5QywrQ0FBK0M7UUFDdkMsbUJBQWMsR0FBWSxLQUFLLENBQUM7UUFXdEMsSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUMxQyxDQUFDO0lBRU0sZUFBZSxDQUFDLFlBQTBCO1FBQy9DLElBQUksQ0FBQyxZQUFZLEdBQUcsWUFBWSxDQUFDO0lBQ25DLENBQUM7SUFFRDs7T0FFRztJQUNJ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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@push.rocks/smartproxy",
|
|
3
|
-
"version": "19.2.
|
|
3
|
+
"version": "19.2.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.",
|
|
6
6
|
"main": "dist_ts/index.js",
|
package/readme.plan.md
CHANGED
|
@@ -2,100 +2,136 @@
|
|
|
2
2
|
|
|
3
3
|
cat /home/philkunz/.claude/CLAUDE.md
|
|
4
4
|
|
|
5
|
-
## Critical Bug Fix:
|
|
5
|
+
## Critical Bug Fix: Port 80 EADDRINUSE with ACME Challenge Routes
|
|
6
6
|
|
|
7
7
|
### Problem Statement
|
|
8
|
-
SmartProxy
|
|
8
|
+
SmartProxy encounters an "EADDRINUSE" error on port 80 when provisioning multiple ACME certificates. The issue occurs because the certificate manager adds and removes the challenge route for each certificate individually, causing race conditions when multiple certificates are provisioned concurrently.
|
|
9
9
|
|
|
10
10
|
### Root Cause
|
|
11
|
-
|
|
11
|
+
The `SmartCertManager` class adds the ACME challenge route (port 80) before provisioning each certificate and removes it afterward. When multiple certificates are provisioned:
|
|
12
|
+
1. Each provisioning cycle adds its own challenge route
|
|
13
|
+
2. This triggers `updateRoutes()` which calls `PortManager.updatePorts()`
|
|
14
|
+
3. Port 80 is repeatedly added/removed, causing binding conflicts
|
|
12
15
|
|
|
13
16
|
### Implementation Plan
|
|
14
17
|
|
|
15
|
-
#### Phase 1:
|
|
16
|
-
1. **
|
|
17
|
-
- [ ] Add
|
|
18
|
-
- [ ]
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
- [ ]
|
|
25
|
-
- [ ]
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
- [ ]
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
18
|
+
#### Phase 1: Refactor Challenge Route Lifecycle
|
|
19
|
+
1. **Modify challenge route handling** in `SmartCertManager`
|
|
20
|
+
- [ ] Add challenge route once during initialization if ACME is configured
|
|
21
|
+
- [ ] Keep challenge route active throughout entire certificate provisioning
|
|
22
|
+
- [ ] Remove challenge route only after all certificates are provisioned
|
|
23
|
+
- [ ] Add concurrency control to prevent multiple simultaneous route updates
|
|
24
|
+
|
|
25
|
+
#### Phase 2: Update Certificate Provisioning Flow
|
|
26
|
+
2. **Refactor certificate provisioning methods**
|
|
27
|
+
- [ ] Separate challenge route management from individual certificate provisioning
|
|
28
|
+
- [ ] Update `provisionAcmeCertificate()` to not add/remove challenge routes
|
|
29
|
+
- [ ] Modify `provisionAllCertificates()` to handle challenge route lifecycle
|
|
30
|
+
- [ ] Add error handling for challenge route initialization failures
|
|
31
|
+
|
|
32
|
+
#### Phase 3: Implement Concurrency Controls
|
|
33
|
+
3. **Add synchronization mechanisms**
|
|
34
|
+
- [ ] Implement mutex/lock for challenge route operations
|
|
35
|
+
- [ ] Ensure certificate provisioning is properly serialized
|
|
36
|
+
- [ ] Add safeguards against duplicate challenge routes
|
|
37
|
+
- [ ] Handle edge cases (shutdown during provisioning, renewal conflicts)
|
|
38
|
+
|
|
39
|
+
#### Phase 4: Enhance Error Handling
|
|
40
|
+
4. **Improve error handling and recovery**
|
|
41
|
+
- [ ] Add specific error types for port conflicts
|
|
42
|
+
- [ ] Implement retry logic for transient port binding issues
|
|
43
|
+
- [ ] Add detailed logging for challenge route lifecycle
|
|
44
|
+
- [ ] Ensure proper cleanup on errors
|
|
45
|
+
|
|
46
|
+
#### Phase 5: Create Comprehensive Tests
|
|
47
|
+
5. **Write tests for challenge route management**
|
|
48
|
+
- [ ] Test concurrent certificate provisioning
|
|
49
|
+
- [ ] Test challenge route persistence during provisioning
|
|
50
|
+
- [ ] Test error scenarios (port already in use)
|
|
51
|
+
- [ ] Test cleanup after provisioning
|
|
52
|
+
- [ ] Test renewal scenarios with existing challenge routes
|
|
53
|
+
|
|
54
|
+
#### Phase 6: Update Documentation
|
|
55
|
+
6. **Document the new behavior**
|
|
56
|
+
- [ ] Update certificate management documentation
|
|
57
|
+
- [ ] Add troubleshooting guide for port conflicts
|
|
58
|
+
- [ ] Document the challenge route lifecycle
|
|
59
|
+
- [ ] Include examples of proper ACME configuration
|
|
38
60
|
|
|
39
61
|
### Technical Details
|
|
40
62
|
|
|
41
63
|
#### Specific Code Changes
|
|
42
|
-
|
|
64
|
+
|
|
65
|
+
1. In `SmartCertManager.initialize()`:
|
|
66
|
+
```typescript
|
|
67
|
+
// Add challenge route once at initialization
|
|
68
|
+
if (hasAcmeRoutes && this.acmeOptions?.email) {
|
|
69
|
+
await this.addChallengeRoute();
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
2. Modify `provisionAcmeCertificate()`:
|
|
43
74
|
```typescript
|
|
44
|
-
//
|
|
45
|
-
this.
|
|
46
|
-
|
|
47
|
-
|
|
75
|
+
// Remove these lines:
|
|
76
|
+
// await this.addChallengeRoute();
|
|
77
|
+
// await this.removeChallengeRoute();
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
3. Update `stop()` method:
|
|
81
|
+
```typescript
|
|
82
|
+
// Always remove challenge route on shutdown
|
|
83
|
+
if (this.challengeRoute) {
|
|
84
|
+
await this.removeChallengeRoute();
|
|
85
|
+
}
|
|
48
86
|
```
|
|
49
87
|
|
|
50
|
-
|
|
88
|
+
4. Add concurrency control:
|
|
51
89
|
```typescript
|
|
52
|
-
private
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
await this.updateRoutes(routes);
|
|
90
|
+
private challengeRouteLock = new AsyncLock();
|
|
91
|
+
|
|
92
|
+
private async manageChallengeRoute(operation: 'add' | 'remove'): Promise<void> {
|
|
93
|
+
await this.challengeRouteLock.acquire('challenge-route', async () => {
|
|
94
|
+
if (operation === 'add') {
|
|
95
|
+
await this.addChallengeRoute();
|
|
96
|
+
} else {
|
|
97
|
+
await this.removeChallengeRoute();
|
|
98
|
+
}
|
|
62
99
|
});
|
|
63
|
-
|
|
64
|
-
if (this.networkProxyBridge.getNetworkProxy()) {
|
|
65
|
-
certManager.setNetworkProxy(this.networkProxyBridge.getNetworkProxy());
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return certManager;
|
|
69
100
|
}
|
|
70
101
|
```
|
|
71
102
|
|
|
72
103
|
### Success Criteria
|
|
73
|
-
- [x]
|
|
74
|
-
- [x]
|
|
104
|
+
- [x] No EADDRINUSE errors when provisioning multiple certificates
|
|
105
|
+
- [x] Challenge route remains active during entire provisioning cycle
|
|
106
|
+
- [x] Port 80 is only bound once per SmartProxy instance
|
|
107
|
+
- [x] Proper cleanup on shutdown or error
|
|
75
108
|
- [x] All tests pass
|
|
76
109
|
- [x] Documentation clearly explains the behavior
|
|
77
|
-
- [x] Code is more maintainable and less prone to regression
|
|
78
110
|
|
|
79
111
|
### Implementation Summary
|
|
80
112
|
|
|
81
|
-
The
|
|
113
|
+
The port 80 EADDRINUSE issue has been successfully fixed through the following changes:
|
|
82
114
|
|
|
83
|
-
1. **
|
|
84
|
-
2. **
|
|
85
|
-
3. **
|
|
86
|
-
4. **
|
|
115
|
+
1. **Challenge Route Lifecycle**: Modified to add challenge route once during initialization and keep it active throughout certificate provisioning
|
|
116
|
+
2. **Concurrency Control**: Added flags to prevent concurrent provisioning and duplicate challenge route operations
|
|
117
|
+
3. **Error Handling**: Enhanced error messages for port conflicts and proper cleanup on errors
|
|
118
|
+
4. **Tests**: Created comprehensive test suite for challenge route lifecycle scenarios
|
|
119
|
+
5. **Documentation**: Updated certificate management guide with troubleshooting section for port conflicts
|
|
87
120
|
|
|
88
|
-
The fix ensures that
|
|
121
|
+
The fix ensures that port 80 is only bound once, preventing EADDRINUSE errors during concurrent certificate provisioning operations.
|
|
89
122
|
|
|
90
123
|
### Timeline
|
|
91
|
-
- Phase 1:
|
|
92
|
-
- Phase 2:
|
|
93
|
-
- Phase 3:
|
|
94
|
-
- Phase 4:
|
|
124
|
+
- Phase 1: 2 hours (Challenge route lifecycle)
|
|
125
|
+
- Phase 2: 1 hour (Provisioning flow)
|
|
126
|
+
- Phase 3: 2 hours (Concurrency controls)
|
|
127
|
+
- Phase 4: 1 hour (Error handling)
|
|
128
|
+
- Phase 5: 2 hours (Testing)
|
|
129
|
+
- Phase 6: 1 hour (Documentation)
|
|
95
130
|
|
|
96
|
-
Total estimated time:
|
|
131
|
+
Total estimated time: 9 hours
|
|
97
132
|
|
|
98
133
|
### Notes
|
|
99
|
-
- This is a critical bug
|
|
100
|
-
- The fix
|
|
101
|
-
-
|
|
134
|
+
- This is a critical bug affecting ACME certificate provisioning
|
|
135
|
+
- The fix requires careful handling of concurrent operations
|
|
136
|
+
- Backward compatibility must be maintained
|
|
137
|
+
- Consider impact on renewal operations and edge cases
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/smartproxy',
|
|
6
|
-
version: '19.2.
|
|
6
|
+
version: '19.2.4',
|
|
7
7
|
description: 'A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.'
|
|
8
8
|
}
|
|
@@ -38,6 +38,12 @@ export class SmartCertManager {
|
|
|
38
38
|
// Callback to update SmartProxy routes for challenges
|
|
39
39
|
private updateRoutesCallback?: (routes: IRouteConfig[]) => Promise<void>;
|
|
40
40
|
|
|
41
|
+
// Flag to track if challenge route is currently active
|
|
42
|
+
private challengeRouteActive: boolean = false;
|
|
43
|
+
|
|
44
|
+
// Flag to track if provisioning is in progress
|
|
45
|
+
private isProvisioning: boolean = false;
|
|
46
|
+
|
|
41
47
|
constructor(
|
|
42
48
|
private routes: IRouteConfig[],
|
|
43
49
|
private certDir: string = './certs',
|
|
@@ -96,6 +102,10 @@ export class SmartCertManager {
|
|
|
96
102
|
});
|
|
97
103
|
|
|
98
104
|
await this.smartAcme.start();
|
|
105
|
+
|
|
106
|
+
// Add challenge route once at initialization
|
|
107
|
+
console.log('Adding ACME challenge route during initialization');
|
|
108
|
+
await this.addChallengeRoute();
|
|
99
109
|
}
|
|
100
110
|
|
|
101
111
|
// Provision certificates for all routes
|
|
@@ -114,24 +124,37 @@ export class SmartCertManager {
|
|
|
114
124
|
r.action.tls?.mode === 'terminate-and-reencrypt'
|
|
115
125
|
);
|
|
116
126
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
127
|
+
// Set provisioning flag to prevent concurrent operations
|
|
128
|
+
this.isProvisioning = true;
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
for (const route of certRoutes) {
|
|
132
|
+
try {
|
|
133
|
+
await this.provisionCertificate(route, true); // Allow concurrent since we're managing it here
|
|
134
|
+
} catch (error) {
|
|
135
|
+
console.error(`Failed to provision certificate for route ${route.name}: ${error}`);
|
|
136
|
+
}
|
|
122
137
|
}
|
|
138
|
+
} finally {
|
|
139
|
+
this.isProvisioning = false;
|
|
123
140
|
}
|
|
124
141
|
}
|
|
125
142
|
|
|
126
143
|
/**
|
|
127
144
|
* Provision certificate for a single route
|
|
128
145
|
*/
|
|
129
|
-
public async provisionCertificate(route: IRouteConfig): Promise<void> {
|
|
146
|
+
public async provisionCertificate(route: IRouteConfig, allowConcurrent: boolean = false): Promise<void> {
|
|
130
147
|
const tls = route.action.tls;
|
|
131
148
|
if (!tls || (tls.mode !== 'terminate' && tls.mode !== 'terminate-and-reencrypt')) {
|
|
132
149
|
return;
|
|
133
150
|
}
|
|
134
151
|
|
|
152
|
+
// Check if provisioning is already in progress (prevent concurrent provisioning)
|
|
153
|
+
if (!allowConcurrent && this.isProvisioning) {
|
|
154
|
+
console.log(`Certificate provisioning already in progress, skipping ${route.name}`);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
135
158
|
const domains = this.extractDomainsFromRoute(route);
|
|
136
159
|
if (domains.length === 0) {
|
|
137
160
|
console.warn(`Route ${route.name} has TLS termination but no domains`);
|
|
@@ -186,13 +209,12 @@ export class SmartCertManager {
|
|
|
186
209
|
this.updateCertStatus(routeName, 'pending', 'acme');
|
|
187
210
|
|
|
188
211
|
try {
|
|
189
|
-
//
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
try {
|
|
193
|
-
// Use smartacme to get certificate
|
|
194
|
-
const cert = await this.smartAcme.getCertificateForDomain(primaryDomain);
|
|
212
|
+
// Challenge route should already be active from initialization
|
|
213
|
+
// No need to add it for each certificate
|
|
195
214
|
|
|
215
|
+
// Use smartacme to get certificate
|
|
216
|
+
const cert = await this.smartAcme.getCertificateForDomain(primaryDomain);
|
|
217
|
+
|
|
196
218
|
// SmartAcme's Cert object has these properties:
|
|
197
219
|
// - publicKey: The certificate PEM string
|
|
198
220
|
// - privateKey: The private key PEM string
|
|
@@ -211,18 +233,9 @@ export class SmartCertManager {
|
|
|
211
233
|
await this.applyCertificate(primaryDomain, certData);
|
|
212
234
|
this.updateCertStatus(routeName, 'valid', 'acme', certData);
|
|
213
235
|
|
|
214
|
-
|
|
215
|
-
} catch (error) {
|
|
216
|
-
console.error(`Failed to provision ACME certificate for ${primaryDomain}: ${error}`);
|
|
217
|
-
this.updateCertStatus(routeName, 'error', 'acme', undefined, error.message);
|
|
218
|
-
throw error;
|
|
219
|
-
} finally {
|
|
220
|
-
// Always remove challenge route after provisioning
|
|
221
|
-
await this.removeChallengeRoute();
|
|
222
|
-
}
|
|
236
|
+
console.log(`Successfully provisioned ACME certificate for ${primaryDomain}`);
|
|
223
237
|
} catch (error) {
|
|
224
|
-
|
|
225
|
-
console.error(`Failed to setup ACME challenge for ${primaryDomain}: ${error}`);
|
|
238
|
+
console.error(`Failed to provision ACME certificate for ${primaryDomain}: ${error}`);
|
|
226
239
|
this.updateCertStatus(routeName, 'error', 'acme', undefined, error.message);
|
|
227
240
|
throw error;
|
|
228
241
|
}
|
|
@@ -337,6 +350,11 @@ export class SmartCertManager {
|
|
|
337
350
|
* Add challenge route to SmartProxy
|
|
338
351
|
*/
|
|
339
352
|
private async addChallengeRoute(): Promise<void> {
|
|
353
|
+
if (this.challengeRouteActive) {
|
|
354
|
+
console.log('Challenge route already active, skipping');
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
|
|
340
358
|
if (!this.updateRoutesCallback) {
|
|
341
359
|
throw new Error('No route update callback set');
|
|
342
360
|
}
|
|
@@ -346,20 +364,44 @@ export class SmartCertManager {
|
|
|
346
364
|
}
|
|
347
365
|
const challengeRoute = this.challengeRoute;
|
|
348
366
|
|
|
349
|
-
|
|
350
|
-
|
|
367
|
+
try {
|
|
368
|
+
const updatedRoutes = [...this.routes, challengeRoute];
|
|
369
|
+
await this.updateRoutesCallback(updatedRoutes);
|
|
370
|
+
this.challengeRouteActive = true;
|
|
371
|
+
console.log('ACME challenge route successfully added');
|
|
372
|
+
} catch (error) {
|
|
373
|
+
console.error('Failed to add challenge route:', error);
|
|
374
|
+
if ((error as any).code === 'EADDRINUSE') {
|
|
375
|
+
throw new Error(`Port ${this.globalAcmeDefaults?.port || 80} is already in use for ACME challenges`);
|
|
376
|
+
}
|
|
377
|
+
throw error;
|
|
378
|
+
}
|
|
351
379
|
}
|
|
352
380
|
|
|
353
381
|
/**
|
|
354
382
|
* Remove challenge route from SmartProxy
|
|
355
383
|
*/
|
|
356
384
|
private async removeChallengeRoute(): Promise<void> {
|
|
385
|
+
if (!this.challengeRouteActive) {
|
|
386
|
+
console.log('Challenge route not active, skipping removal');
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
|
|
357
390
|
if (!this.updateRoutesCallback) {
|
|
358
391
|
return;
|
|
359
392
|
}
|
|
360
393
|
|
|
361
|
-
|
|
362
|
-
|
|
394
|
+
try {
|
|
395
|
+
const filteredRoutes = this.routes.filter(r => r.name !== 'acme-challenge');
|
|
396
|
+
await this.updateRoutesCallback(filteredRoutes);
|
|
397
|
+
this.challengeRouteActive = false;
|
|
398
|
+
console.log('ACME challenge route successfully removed');
|
|
399
|
+
} catch (error) {
|
|
400
|
+
console.error('Failed to remove challenge route:', error);
|
|
401
|
+
// Reset the flag even on error to avoid getting stuck
|
|
402
|
+
this.challengeRouteActive = false;
|
|
403
|
+
throw error;
|
|
404
|
+
}
|
|
363
405
|
}
|
|
364
406
|
|
|
365
407
|
/**
|
|
@@ -512,14 +554,19 @@ export class SmartCertManager {
|
|
|
512
554
|
this.renewalTimer = null;
|
|
513
555
|
}
|
|
514
556
|
|
|
557
|
+
// Always remove challenge route on shutdown
|
|
558
|
+
if (this.challengeRoute) {
|
|
559
|
+
console.log('Removing ACME challenge route during shutdown');
|
|
560
|
+
await this.removeChallengeRoute();
|
|
561
|
+
}
|
|
562
|
+
|
|
515
563
|
if (this.smartAcme) {
|
|
516
564
|
await this.smartAcme.stop();
|
|
517
565
|
}
|
|
518
566
|
|
|
519
|
-
//
|
|
567
|
+
// Clear any pending challenges
|
|
520
568
|
if (this.pendingChallenges.size > 0) {
|
|
521
569
|
this.pendingChallenges.clear();
|
|
522
|
-
await this.removeChallengeRoute();
|
|
523
570
|
}
|
|
524
571
|
}
|
|
525
572
|
|