@push.rocks/smartproxy 18.0.2 → 18.2.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/certificate/certificate-manager.d.ts +150 -0
- package/dist_ts/certificate/certificate-manager.js +505 -0
- package/dist_ts/certificate/events/simplified-events.d.ts +56 -0
- package/dist_ts/certificate/events/simplified-events.js +13 -0
- package/dist_ts/certificate/models/certificate-errors.d.ts +69 -0
- package/dist_ts/certificate/models/certificate-errors.js +141 -0
- package/dist_ts/certificate/models/certificate-strategy.d.ts +60 -0
- package/dist_ts/certificate/models/certificate-strategy.js +73 -0
- package/dist_ts/certificate/simplified-certificate-manager.d.ts +150 -0
- package/dist_ts/certificate/simplified-certificate-manager.js +501 -0
- package/dist_ts/http/index.d.ts +1 -9
- package/dist_ts/http/index.js +5 -11
- package/dist_ts/plugins.d.ts +3 -1
- package/dist_ts/plugins.js +4 -2
- package/dist_ts/proxies/network-proxy/network-proxy.js +3 -1
- package/dist_ts/proxies/network-proxy/simplified-certificate-bridge.d.ts +48 -0
- package/dist_ts/proxies/network-proxy/simplified-certificate-bridge.js +76 -0
- package/dist_ts/proxies/network-proxy/websocket-handler.js +41 -4
- package/dist_ts/proxies/smart-proxy/cert-store.d.ts +10 -0
- package/dist_ts/proxies/smart-proxy/cert-store.js +70 -0
- package/dist_ts/proxies/smart-proxy/certificate-manager.d.ts +116 -0
- package/dist_ts/proxies/smart-proxy/certificate-manager.js +401 -0
- package/dist_ts/proxies/smart-proxy/legacy-smart-proxy.d.ts +168 -0
- package/dist_ts/proxies/smart-proxy/legacy-smart-proxy.js +642 -0
- package/dist_ts/proxies/smart-proxy/models/route-types.d.ts +26 -0
- package/dist_ts/proxies/smart-proxy/models/route-types.js +1 -1
- package/dist_ts/proxies/smart-proxy/models/simplified-smartproxy-config.d.ts +65 -0
- package/dist_ts/proxies/smart-proxy/models/simplified-smartproxy-config.js +31 -0
- package/dist_ts/proxies/smart-proxy/models/smartproxy-options.d.ts +102 -0
- package/dist_ts/proxies/smart-proxy/models/smartproxy-options.js +73 -0
- package/dist_ts/proxies/smart-proxy/network-proxy-bridge.d.ts +10 -44
- package/dist_ts/proxies/smart-proxy/network-proxy-bridge.js +66 -202
- package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +4 -0
- package/dist_ts/proxies/smart-proxy/route-connection-handler.js +62 -2
- package/dist_ts/proxies/smart-proxy/simplified-smart-proxy.d.ts +41 -0
- package/dist_ts/proxies/smart-proxy/simplified-smart-proxy.js +132 -0
- package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +18 -13
- package/dist_ts/proxies/smart-proxy/smart-proxy.js +79 -196
- package/package.json +7 -5
- package/readme.md +224 -10
- package/readme.plan.md +1405 -617
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/http/index.ts +5 -12
- package/ts/plugins.ts +4 -1
- package/ts/proxies/network-proxy/network-proxy.ts +3 -0
- package/ts/proxies/network-proxy/websocket-handler.ts +38 -3
- package/ts/proxies/smart-proxy/cert-store.ts +86 -0
- package/ts/proxies/smart-proxy/certificate-manager.ts +506 -0
- package/ts/proxies/smart-proxy/models/route-types.ts +33 -3
- package/ts/proxies/smart-proxy/network-proxy-bridge.ts +86 -239
- package/ts/proxies/smart-proxy/route-connection-handler.ts +74 -1
- package/ts/proxies/smart-proxy/smart-proxy.ts +105 -222
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
import { NetworkProxy } from '../network-proxy/index.js';
|
|
3
|
+
import { CertStore } from './cert-store.js';
|
|
4
|
+
export class SmartCertManager {
|
|
5
|
+
constructor(routes, certDir = './certs', acmeOptions) {
|
|
6
|
+
this.routes = routes;
|
|
7
|
+
this.certDir = certDir;
|
|
8
|
+
this.acmeOptions = acmeOptions;
|
|
9
|
+
this.smartAcme = null;
|
|
10
|
+
this.networkProxy = null;
|
|
11
|
+
this.renewalTimer = null;
|
|
12
|
+
this.pendingChallenges = new Map();
|
|
13
|
+
this.challengeRoute = null;
|
|
14
|
+
// Track certificate status by route name
|
|
15
|
+
this.certStatus = new Map();
|
|
16
|
+
this.certStore = new CertStore(certDir);
|
|
17
|
+
}
|
|
18
|
+
setNetworkProxy(networkProxy) {
|
|
19
|
+
this.networkProxy = networkProxy;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Set callback for updating routes (used for challenge routes)
|
|
23
|
+
*/
|
|
24
|
+
setUpdateRoutesCallback(callback) {
|
|
25
|
+
this.updateRoutesCallback = callback;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Initialize certificate manager and provision certificates for all routes
|
|
29
|
+
*/
|
|
30
|
+
async initialize() {
|
|
31
|
+
// Create certificate directory if it doesn't exist
|
|
32
|
+
await this.certStore.initialize();
|
|
33
|
+
// Initialize SmartAcme if we have any ACME routes
|
|
34
|
+
const hasAcmeRoutes = this.routes.some(r => r.action.tls?.certificate === 'auto');
|
|
35
|
+
if (hasAcmeRoutes && this.acmeOptions?.email) {
|
|
36
|
+
// Create HTTP-01 challenge handler
|
|
37
|
+
const http01Handler = new plugins.smartacme.handlers.Http01MemoryHandler();
|
|
38
|
+
// Set up challenge handler integration with our routing
|
|
39
|
+
this.setupChallengeHandler(http01Handler);
|
|
40
|
+
// Create SmartAcme instance with built-in MemoryCertManager and HTTP-01 handler
|
|
41
|
+
this.smartAcme = new plugins.smartacme.SmartAcme({
|
|
42
|
+
accountEmail: this.acmeOptions.email,
|
|
43
|
+
environment: this.acmeOptions.useProduction ? 'production' : 'integration',
|
|
44
|
+
certManager: new plugins.smartacme.certmanagers.MemoryCertManager(),
|
|
45
|
+
challengeHandlers: [http01Handler]
|
|
46
|
+
});
|
|
47
|
+
await this.smartAcme.start();
|
|
48
|
+
}
|
|
49
|
+
// Provision certificates for all routes
|
|
50
|
+
await this.provisionAllCertificates();
|
|
51
|
+
// Start renewal timer
|
|
52
|
+
this.startRenewalTimer();
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Provision certificates for all routes that need them
|
|
56
|
+
*/
|
|
57
|
+
async provisionAllCertificates() {
|
|
58
|
+
const certRoutes = this.routes.filter(r => r.action.tls?.mode === 'terminate' ||
|
|
59
|
+
r.action.tls?.mode === 'terminate-and-reencrypt');
|
|
60
|
+
for (const route of certRoutes) {
|
|
61
|
+
try {
|
|
62
|
+
await this.provisionCertificate(route);
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
console.error(`Failed to provision certificate for route ${route.name}: ${error}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Provision certificate for a single route
|
|
71
|
+
*/
|
|
72
|
+
async provisionCertificate(route) {
|
|
73
|
+
const tls = route.action.tls;
|
|
74
|
+
if (!tls || (tls.mode !== 'terminate' && tls.mode !== 'terminate-and-reencrypt')) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const domains = this.extractDomainsFromRoute(route);
|
|
78
|
+
if (domains.length === 0) {
|
|
79
|
+
console.warn(`Route ${route.name} has TLS termination but no domains`);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const primaryDomain = domains[0];
|
|
83
|
+
if (tls.certificate === 'auto') {
|
|
84
|
+
// ACME certificate
|
|
85
|
+
await this.provisionAcmeCertificate(route, domains);
|
|
86
|
+
}
|
|
87
|
+
else if (typeof tls.certificate === 'object') {
|
|
88
|
+
// Static certificate
|
|
89
|
+
await this.provisionStaticCertificate(route, primaryDomain, tls.certificate);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Provision ACME certificate
|
|
94
|
+
*/
|
|
95
|
+
async provisionAcmeCertificate(route, domains) {
|
|
96
|
+
if (!this.smartAcme) {
|
|
97
|
+
throw new Error('SmartAcme not initialized');
|
|
98
|
+
}
|
|
99
|
+
const primaryDomain = domains[0];
|
|
100
|
+
const routeName = route.name || primaryDomain;
|
|
101
|
+
// Check if we already have a valid certificate
|
|
102
|
+
const existingCert = await this.certStore.getCertificate(routeName);
|
|
103
|
+
if (existingCert && this.isCertificateValid(existingCert)) {
|
|
104
|
+
console.log(`Using existing valid certificate for ${primaryDomain}`);
|
|
105
|
+
await this.applyCertificate(primaryDomain, existingCert);
|
|
106
|
+
this.updateCertStatus(routeName, 'valid', 'acme', existingCert);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
console.log(`Requesting ACME certificate for ${domains.join(', ')}`);
|
|
110
|
+
this.updateCertStatus(routeName, 'pending', 'acme');
|
|
111
|
+
try {
|
|
112
|
+
// Add challenge route before requesting certificate
|
|
113
|
+
await this.addChallengeRoute();
|
|
114
|
+
try {
|
|
115
|
+
// Use smartacme to get certificate
|
|
116
|
+
const cert = await this.smartAcme.getCertificateForDomain(primaryDomain);
|
|
117
|
+
// SmartAcme's Cert object has these properties:
|
|
118
|
+
// - publicKey: The certificate PEM string
|
|
119
|
+
// - privateKey: The private key PEM string
|
|
120
|
+
// - csr: Certificate signing request
|
|
121
|
+
// - validUntil: Timestamp in milliseconds
|
|
122
|
+
// - domainName: The domain name
|
|
123
|
+
const certData = {
|
|
124
|
+
cert: cert.publicKey,
|
|
125
|
+
key: cert.privateKey,
|
|
126
|
+
ca: cert.publicKey, // Use same as cert for now
|
|
127
|
+
expiryDate: new Date(cert.validUntil),
|
|
128
|
+
issueDate: new Date(cert.created)
|
|
129
|
+
};
|
|
130
|
+
await this.certStore.saveCertificate(routeName, certData);
|
|
131
|
+
await this.applyCertificate(primaryDomain, certData);
|
|
132
|
+
this.updateCertStatus(routeName, 'valid', 'acme', certData);
|
|
133
|
+
console.log(`Successfully provisioned ACME certificate for ${primaryDomain}`);
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
console.error(`Failed to provision ACME certificate for ${primaryDomain}: ${error}`);
|
|
137
|
+
this.updateCertStatus(routeName, 'error', 'acme', undefined, error.message);
|
|
138
|
+
throw error;
|
|
139
|
+
}
|
|
140
|
+
finally {
|
|
141
|
+
// Always remove challenge route after provisioning
|
|
142
|
+
await this.removeChallengeRoute();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
// Handle outer try-catch from adding challenge route
|
|
147
|
+
console.error(`Failed to setup ACME challenge for ${primaryDomain}: ${error}`);
|
|
148
|
+
this.updateCertStatus(routeName, 'error', 'acme', undefined, error.message);
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Provision static certificate
|
|
154
|
+
*/
|
|
155
|
+
async provisionStaticCertificate(route, domain, certConfig) {
|
|
156
|
+
const routeName = route.name || domain;
|
|
157
|
+
try {
|
|
158
|
+
let key = certConfig.key;
|
|
159
|
+
let cert = certConfig.cert;
|
|
160
|
+
// Load from files if paths are provided
|
|
161
|
+
if (certConfig.keyFile) {
|
|
162
|
+
const keyFile = await plugins.smartfile.SmartFile.fromFilePath(certConfig.keyFile);
|
|
163
|
+
key = keyFile.contents.toString();
|
|
164
|
+
}
|
|
165
|
+
if (certConfig.certFile) {
|
|
166
|
+
const certFile = await plugins.smartfile.SmartFile.fromFilePath(certConfig.certFile);
|
|
167
|
+
cert = certFile.contents.toString();
|
|
168
|
+
}
|
|
169
|
+
// Parse certificate to get dates
|
|
170
|
+
// Parse certificate to get dates - for now just use defaults
|
|
171
|
+
// TODO: Implement actual certificate parsing if needed
|
|
172
|
+
const certInfo = { validTo: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000), validFrom: new Date() };
|
|
173
|
+
const certData = {
|
|
174
|
+
cert,
|
|
175
|
+
key,
|
|
176
|
+
expiryDate: certInfo.validTo,
|
|
177
|
+
issueDate: certInfo.validFrom
|
|
178
|
+
};
|
|
179
|
+
// Save to store for consistency
|
|
180
|
+
await this.certStore.saveCertificate(routeName, certData);
|
|
181
|
+
await this.applyCertificate(domain, certData);
|
|
182
|
+
this.updateCertStatus(routeName, 'valid', 'static', certData);
|
|
183
|
+
console.log(`Successfully loaded static certificate for ${domain}`);
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
console.error(`Failed to provision static certificate for ${domain}: ${error}`);
|
|
187
|
+
this.updateCertStatus(routeName, 'error', 'static', undefined, error.message);
|
|
188
|
+
throw error;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Apply certificate to NetworkProxy
|
|
193
|
+
*/
|
|
194
|
+
async applyCertificate(domain, certData) {
|
|
195
|
+
if (!this.networkProxy) {
|
|
196
|
+
console.warn('NetworkProxy not set, cannot apply certificate');
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
// Apply certificate to NetworkProxy
|
|
200
|
+
this.networkProxy.updateCertificate(domain, certData.cert, certData.key);
|
|
201
|
+
// Also apply for wildcard if it's a subdomain
|
|
202
|
+
if (domain.includes('.') && !domain.startsWith('*.')) {
|
|
203
|
+
const parts = domain.split('.');
|
|
204
|
+
if (parts.length >= 2) {
|
|
205
|
+
const wildcardDomain = `*.${parts.slice(-2).join('.')}`;
|
|
206
|
+
this.networkProxy.updateCertificate(wildcardDomain, certData.cert, certData.key);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Extract domains from route configuration
|
|
212
|
+
*/
|
|
213
|
+
extractDomainsFromRoute(route) {
|
|
214
|
+
if (!route.match.domains) {
|
|
215
|
+
return [];
|
|
216
|
+
}
|
|
217
|
+
const domains = Array.isArray(route.match.domains)
|
|
218
|
+
? route.match.domains
|
|
219
|
+
: [route.match.domains];
|
|
220
|
+
// Filter out wildcards and patterns
|
|
221
|
+
return domains.filter(d => !d.includes('*') &&
|
|
222
|
+
!d.includes('{') &&
|
|
223
|
+
d.includes('.'));
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Check if certificate is valid
|
|
227
|
+
*/
|
|
228
|
+
isCertificateValid(cert) {
|
|
229
|
+
const now = new Date();
|
|
230
|
+
const expiryThreshold = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000); // 30 days
|
|
231
|
+
return cert.expiryDate > expiryThreshold;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Add challenge route to SmartProxy
|
|
235
|
+
*/
|
|
236
|
+
async addChallengeRoute() {
|
|
237
|
+
if (!this.updateRoutesCallback) {
|
|
238
|
+
throw new Error('No route update callback set');
|
|
239
|
+
}
|
|
240
|
+
if (!this.challengeRoute) {
|
|
241
|
+
throw new Error('Challenge route not initialized');
|
|
242
|
+
}
|
|
243
|
+
const challengeRoute = this.challengeRoute;
|
|
244
|
+
const updatedRoutes = [...this.routes, challengeRoute];
|
|
245
|
+
await this.updateRoutesCallback(updatedRoutes);
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Remove challenge route from SmartProxy
|
|
249
|
+
*/
|
|
250
|
+
async removeChallengeRoute() {
|
|
251
|
+
if (!this.updateRoutesCallback) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
const filteredRoutes = this.routes.filter(r => r.name !== 'acme-challenge');
|
|
255
|
+
await this.updateRoutesCallback(filteredRoutes);
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Start renewal timer
|
|
259
|
+
*/
|
|
260
|
+
startRenewalTimer() {
|
|
261
|
+
// Check for renewals every 12 hours
|
|
262
|
+
this.renewalTimer = setInterval(() => {
|
|
263
|
+
this.checkAndRenewCertificates();
|
|
264
|
+
}, 12 * 60 * 60 * 1000);
|
|
265
|
+
// Also do an immediate check
|
|
266
|
+
this.checkAndRenewCertificates();
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Check and renew certificates that are expiring
|
|
270
|
+
*/
|
|
271
|
+
async checkAndRenewCertificates() {
|
|
272
|
+
for (const route of this.routes) {
|
|
273
|
+
if (route.action.tls?.certificate === 'auto') {
|
|
274
|
+
const routeName = route.name || this.extractDomainsFromRoute(route)[0];
|
|
275
|
+
const cert = await this.certStore.getCertificate(routeName);
|
|
276
|
+
if (cert && !this.isCertificateValid(cert)) {
|
|
277
|
+
console.log(`Certificate for ${routeName} needs renewal`);
|
|
278
|
+
try {
|
|
279
|
+
await this.provisionCertificate(route);
|
|
280
|
+
}
|
|
281
|
+
catch (error) {
|
|
282
|
+
console.error(`Failed to renew certificate for ${routeName}: ${error}`);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Update certificate status
|
|
290
|
+
*/
|
|
291
|
+
updateCertStatus(routeName, status, source, certData, error) {
|
|
292
|
+
this.certStatus.set(routeName, {
|
|
293
|
+
domain: routeName,
|
|
294
|
+
status,
|
|
295
|
+
source,
|
|
296
|
+
expiryDate: certData?.expiryDate,
|
|
297
|
+
issueDate: certData?.issueDate,
|
|
298
|
+
error
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Get certificate status for a route
|
|
303
|
+
*/
|
|
304
|
+
getCertificateStatus(routeName) {
|
|
305
|
+
return this.certStatus.get(routeName);
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Force renewal of a certificate
|
|
309
|
+
*/
|
|
310
|
+
async renewCertificate(routeName) {
|
|
311
|
+
const route = this.routes.find(r => r.name === routeName);
|
|
312
|
+
if (!route) {
|
|
313
|
+
throw new Error(`Route ${routeName} not found`);
|
|
314
|
+
}
|
|
315
|
+
// Remove existing certificate to force renewal
|
|
316
|
+
await this.certStore.deleteCertificate(routeName);
|
|
317
|
+
await this.provisionCertificate(route);
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Setup challenge handler integration with SmartProxy routing
|
|
321
|
+
*/
|
|
322
|
+
setupChallengeHandler(http01Handler) {
|
|
323
|
+
// Create a challenge route that delegates to SmartAcme's HTTP-01 handler
|
|
324
|
+
const challengeRoute = {
|
|
325
|
+
name: 'acme-challenge',
|
|
326
|
+
priority: 1000, // High priority
|
|
327
|
+
match: {
|
|
328
|
+
ports: 80,
|
|
329
|
+
path: '/.well-known/acme-challenge/*'
|
|
330
|
+
},
|
|
331
|
+
action: {
|
|
332
|
+
type: 'static',
|
|
333
|
+
handler: async (context) => {
|
|
334
|
+
// Extract the token from the path
|
|
335
|
+
const token = context.path?.split('/').pop();
|
|
336
|
+
if (!token) {
|
|
337
|
+
return { status: 404, body: 'Not found' };
|
|
338
|
+
}
|
|
339
|
+
// Create mock request/response objects for SmartAcme
|
|
340
|
+
const mockReq = {
|
|
341
|
+
url: context.path,
|
|
342
|
+
method: 'GET',
|
|
343
|
+
headers: context.headers || {}
|
|
344
|
+
};
|
|
345
|
+
let responseData = null;
|
|
346
|
+
const mockRes = {
|
|
347
|
+
statusCode: 200,
|
|
348
|
+
setHeader: (name, value) => { },
|
|
349
|
+
end: (data) => {
|
|
350
|
+
responseData = data;
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
// Use SmartAcme's handler
|
|
354
|
+
const handled = await new Promise((resolve) => {
|
|
355
|
+
http01Handler.handleRequest(mockReq, mockRes, () => {
|
|
356
|
+
resolve(false);
|
|
357
|
+
});
|
|
358
|
+
// Give it a moment to process
|
|
359
|
+
setTimeout(() => resolve(true), 100);
|
|
360
|
+
});
|
|
361
|
+
if (handled && responseData) {
|
|
362
|
+
return {
|
|
363
|
+
status: mockRes.statusCode,
|
|
364
|
+
headers: { 'Content-Type': 'text/plain' },
|
|
365
|
+
body: responseData
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
return { status: 404, body: 'Not found' };
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
};
|
|
374
|
+
// Store the challenge route to add it when needed
|
|
375
|
+
this.challengeRoute = challengeRoute;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Stop certificate manager
|
|
379
|
+
*/
|
|
380
|
+
async stop() {
|
|
381
|
+
if (this.renewalTimer) {
|
|
382
|
+
clearInterval(this.renewalTimer);
|
|
383
|
+
this.renewalTimer = null;
|
|
384
|
+
}
|
|
385
|
+
if (this.smartAcme) {
|
|
386
|
+
await this.smartAcme.stop();
|
|
387
|
+
}
|
|
388
|
+
// Remove any active challenge routes
|
|
389
|
+
if (this.pendingChallenges.size > 0) {
|
|
390
|
+
this.pendingChallenges.clear();
|
|
391
|
+
await this.removeChallengeRoute();
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Get ACME options (for recreating after route updates)
|
|
396
|
+
*/
|
|
397
|
+
getAcmeOptions() {
|
|
398
|
+
return this.acmeOptions;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2VydGlmaWNhdGUtbWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL3Byb3hpZXMvc21hcnQtcHJveHkvY2VydGlmaWNhdGUtbWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGtCQUFrQixDQUFDO0FBQzVDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUV6RCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFtQjVDLE1BQU0sT0FBTyxnQkFBZ0I7SUFjM0IsWUFDVSxNQUFzQixFQUN0QixVQUFrQixTQUFTLEVBQzNCLFdBSVA7UUFOTyxXQUFNLEdBQU4sTUFBTSxDQUFnQjtRQUN0QixZQUFPLEdBQVAsT0FBTyxDQUFvQjtRQUMzQixnQkFBVyxHQUFYLFdBQVcsQ0FJbEI7UUFuQkssY0FBUyxHQUF1QyxJQUFJLENBQUM7UUFDckQsaUJBQVksR0FBd0IsSUFBSSxDQUFDO1FBQ3pDLGlCQUFZLEdBQTBCLElBQUksQ0FBQztRQUMzQyxzQkFBaUIsR0FBd0IsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUNuRCxtQkFBYyxHQUF3QixJQUFJLENBQUM7UUFFbkQseUNBQXlDO1FBQ2pDLGVBQVUsR0FBNkIsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQWN2RCxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksU0FBUyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQzFDLENBQUM7SUFFTSxlQUFlLENBQUMsWUFBMEI7UUFDL0MsSUFBSSxDQUFDLFlBQVksR0FBRyxZQUFZLENBQUM7SUFDbkMsQ0FBQztJQUVEOztPQUVHO0lBQ0ksdUJBQXVCLENBQUMsUUFBbUQ7UUFDaEYsSUFBSSxDQUFDLG9CQUFvQixHQUFHLFFBQVEsQ0FBQztJQUN2QyxDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsVUFBVTtRQUNyQixtREFBbUQ7UUFDbkQsTUFBTSxJ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
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
import { RouteManager } from './route-manager.js';
|
|
3
|
+
import type { ISmartProxyOptions } from './models/interfaces.js';
|
|
4
|
+
import type { IRouteConfig } from './models/route-types.js';
|
|
5
|
+
/**
|
|
6
|
+
* SmartProxy - Pure route-based API
|
|
7
|
+
*
|
|
8
|
+
* SmartProxy is a unified proxy system that works with routes to define connection handling behavior.
|
|
9
|
+
* Each route contains matching criteria (ports, domains, etc.) and an action to take (forward, redirect, block).
|
|
10
|
+
*
|
|
11
|
+
* Configuration is provided through a set of routes, with each route defining:
|
|
12
|
+
* - What to match (ports, domains, paths, client IPs)
|
|
13
|
+
* - What to do with matching traffic (forward, redirect, block)
|
|
14
|
+
* - How to handle TLS (passthrough, terminate, terminate-and-reencrypt)
|
|
15
|
+
* - Security settings (IP restrictions, connection limits)
|
|
16
|
+
* - Advanced options (timeout, headers, etc.)
|
|
17
|
+
*/
|
|
18
|
+
export declare class SmartProxy extends plugins.EventEmitter {
|
|
19
|
+
private portManager;
|
|
20
|
+
private connectionLogger;
|
|
21
|
+
private isShuttingDown;
|
|
22
|
+
private connectionManager;
|
|
23
|
+
private securityManager;
|
|
24
|
+
private tlsManager;
|
|
25
|
+
private networkProxyBridge;
|
|
26
|
+
private timeoutManager;
|
|
27
|
+
routeManager: RouteManager;
|
|
28
|
+
private routeConnectionHandler;
|
|
29
|
+
private nftablesManager;
|
|
30
|
+
private port80Handler;
|
|
31
|
+
private certProvisioner?;
|
|
32
|
+
/**
|
|
33
|
+
* Constructor for SmartProxy
|
|
34
|
+
*
|
|
35
|
+
* @param settingsArg Configuration options containing routes and other settings
|
|
36
|
+
* Routes define how traffic is matched and handled, with each route having:
|
|
37
|
+
* - match: criteria for matching traffic (ports, domains, paths, IPs)
|
|
38
|
+
* - action: what to do with matched traffic (forward, redirect, block)
|
|
39
|
+
*
|
|
40
|
+
* Example:
|
|
41
|
+
* ```ts
|
|
42
|
+
* const proxy = new SmartProxy({
|
|
43
|
+
* routes: [
|
|
44
|
+
* {
|
|
45
|
+
* match: {
|
|
46
|
+
* ports: 443,
|
|
47
|
+
* domains: ['example.com', '*.example.com']
|
|
48
|
+
* },
|
|
49
|
+
* action: {
|
|
50
|
+
* type: 'forward',
|
|
51
|
+
* target: { host: '10.0.0.1', port: 8443 },
|
|
52
|
+
* tls: { mode: 'passthrough' }
|
|
53
|
+
* }
|
|
54
|
+
* }
|
|
55
|
+
* ],
|
|
56
|
+
* defaults: {
|
|
57
|
+
* target: { host: 'localhost', port: 8080 },
|
|
58
|
+
* security: { ipAllowList: ['*'] }
|
|
59
|
+
* }
|
|
60
|
+
* });
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
constructor(settingsArg: ISmartProxyOptions);
|
|
64
|
+
/**
|
|
65
|
+
* The settings for the SmartProxy
|
|
66
|
+
*/
|
|
67
|
+
settings: ISmartProxyOptions;
|
|
68
|
+
/**
|
|
69
|
+
* Initialize the Port80Handler for ACME certificate management
|
|
70
|
+
*/
|
|
71
|
+
private initializePort80Handler;
|
|
72
|
+
/**
|
|
73
|
+
* Start the proxy server with support for both configuration types
|
|
74
|
+
*/
|
|
75
|
+
start(): Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* Extract domain configurations from routes for certificate provisioning
|
|
78
|
+
*
|
|
79
|
+
* Note: This method has been removed as we now work directly with routes
|
|
80
|
+
*/
|
|
81
|
+
/**
|
|
82
|
+
* Stop the proxy server
|
|
83
|
+
*/
|
|
84
|
+
stop(): Promise<void>;
|
|
85
|
+
/**
|
|
86
|
+
* Updates the domain configurations for the proxy
|
|
87
|
+
*
|
|
88
|
+
* Note: This legacy method has been removed. Use updateRoutes instead.
|
|
89
|
+
*/
|
|
90
|
+
updateDomainConfigs(): Promise<void>;
|
|
91
|
+
/**
|
|
92
|
+
* Update routes with new configuration
|
|
93
|
+
*
|
|
94
|
+
* This method replaces the current route configuration with the provided routes.
|
|
95
|
+
* It also provisions certificates for routes that require TLS termination and have
|
|
96
|
+
* `certificate: 'auto'` set in their TLS configuration.
|
|
97
|
+
*
|
|
98
|
+
* @param newRoutes Array of route configurations to use
|
|
99
|
+
*
|
|
100
|
+
* Example:
|
|
101
|
+
* ```ts
|
|
102
|
+
* proxy.updateRoutes([
|
|
103
|
+
* {
|
|
104
|
+
* match: { ports: 443, domains: 'secure.example.com' },
|
|
105
|
+
* action: {
|
|
106
|
+
* type: 'forward',
|
|
107
|
+
* target: { host: '10.0.0.1', port: 8443 },
|
|
108
|
+
* tls: { mode: 'terminate', certificate: 'auto' }
|
|
109
|
+
* }
|
|
110
|
+
* }
|
|
111
|
+
* ]);
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
updateRoutes(newRoutes: IRouteConfig[]): Promise<void>;
|
|
115
|
+
/**
|
|
116
|
+
* Request a certificate for a specific domain
|
|
117
|
+
*
|
|
118
|
+
* @param domain The domain to request a certificate for
|
|
119
|
+
* @param routeName Optional route name to associate with the certificate
|
|
120
|
+
*/
|
|
121
|
+
requestCertificate(domain: string, routeName?: string): Promise<boolean>;
|
|
122
|
+
/**
|
|
123
|
+
* Validates if a domain name is valid for certificate issuance
|
|
124
|
+
*/
|
|
125
|
+
private isValidDomain;
|
|
126
|
+
/**
|
|
127
|
+
* Add a new listening port without changing the route configuration
|
|
128
|
+
*
|
|
129
|
+
* This allows you to add a port listener without updating routes.
|
|
130
|
+
* Useful for preparing to listen on a port before adding routes for it.
|
|
131
|
+
*
|
|
132
|
+
* @param port The port to start listening on
|
|
133
|
+
* @returns Promise that resolves when the port is listening
|
|
134
|
+
*/
|
|
135
|
+
addListeningPort(port: number): Promise<void>;
|
|
136
|
+
/**
|
|
137
|
+
* Stop listening on a specific port without changing the route configuration
|
|
138
|
+
*
|
|
139
|
+
* This allows you to stop a port listener without updating routes.
|
|
140
|
+
* Useful for temporary maintenance or port changes.
|
|
141
|
+
*
|
|
142
|
+
* @param port The port to stop listening on
|
|
143
|
+
* @returns Promise that resolves when the port is closed
|
|
144
|
+
*/
|
|
145
|
+
removeListeningPort(port: number): Promise<void>;
|
|
146
|
+
/**
|
|
147
|
+
* Get a list of all ports currently being listened on
|
|
148
|
+
*
|
|
149
|
+
* @returns Array of port numbers
|
|
150
|
+
*/
|
|
151
|
+
getListeningPorts(): number[];
|
|
152
|
+
/**
|
|
153
|
+
* Get statistics about current connections
|
|
154
|
+
*/
|
|
155
|
+
getStatistics(): any;
|
|
156
|
+
/**
|
|
157
|
+
* Get a list of eligible domains for ACME certificates
|
|
158
|
+
*/
|
|
159
|
+
getEligibleDomainsForCertificates(): string[];
|
|
160
|
+
/**
|
|
161
|
+
* Get NFTables status
|
|
162
|
+
*/
|
|
163
|
+
getNfTablesStatus(): Promise<Record<string, any>>;
|
|
164
|
+
/**
|
|
165
|
+
* Get status of certificates managed by Port80Handler
|
|
166
|
+
*/
|
|
167
|
+
getCertificateStatus(): any;
|
|
168
|
+
}
|