@push.rocks/smartproxy 4.2.6 → 5.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/classes.nftablesproxy.d.ts +219 -0
- package/dist_ts/classes.nftablesproxy.js +1542 -0
- package/dist_ts/classes.port80handler.d.ts +20 -0
- package/dist_ts/classes.port80handler.js +95 -10
- package/dist_ts/index.d.ts +1 -1
- package/dist_ts/index.js +1 -1
- package/package.json +1 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.nftablesproxy.ts +2045 -0
- package/ts/classes.port80handler.ts +102 -9
- package/ts/index.ts +1 -1
- package/ts/classes.iptablesproxy.ts +0 -901
|
@@ -118,6 +118,7 @@ export interface ICertificateExpiring {
|
|
|
118
118
|
|
|
119
119
|
/**
|
|
120
120
|
* Port80Handler with ACME certificate management and request forwarding capabilities
|
|
121
|
+
* Now with glob pattern support for domain matching
|
|
121
122
|
*/
|
|
122
123
|
export class Port80Handler extends plugins.EventEmitter {
|
|
123
124
|
private domainCertificates: Map<string, IDomainCertificate>;
|
|
@@ -180,6 +181,12 @@ export class Port80Handler extends plugins.EventEmitter {
|
|
|
180
181
|
|
|
181
182
|
// Start certificate process for domains with acmeMaintenance enabled
|
|
182
183
|
for (const [domain, domainInfo] of this.domainCertificates.entries()) {
|
|
184
|
+
// Skip glob patterns for certificate issuance
|
|
185
|
+
if (this.isGlobPattern(domain)) {
|
|
186
|
+
console.log(`Skipping initial certificate for glob pattern: ${domain}`);
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
|
|
183
190
|
if (domainInfo.options.acmeMaintenance && !domainInfo.certObtained && !domainInfo.obtainingInProgress) {
|
|
184
191
|
this.obtainCertificate(domain).catch(err => {
|
|
185
192
|
console.error(`Error obtaining initial certificate for ${domain}:`, err);
|
|
@@ -252,8 +259,8 @@ export class Port80Handler extends plugins.EventEmitter {
|
|
|
252
259
|
hasAcmeForward: !!options.acmeForward
|
|
253
260
|
});
|
|
254
261
|
|
|
255
|
-
// If acmeMaintenance is enabled, start certificate process immediately
|
|
256
|
-
if (options.acmeMaintenance && this.server) {
|
|
262
|
+
// If acmeMaintenance is enabled and not a glob pattern, start certificate process immediately
|
|
263
|
+
if (options.acmeMaintenance && this.server && !this.isGlobPattern(domainName)) {
|
|
257
264
|
this.obtainCertificate(domainName).catch(err => {
|
|
258
265
|
console.error(`Error obtaining initial certificate for ${domainName}:`, err);
|
|
259
266
|
});
|
|
@@ -288,6 +295,11 @@ export class Port80Handler extends plugins.EventEmitter {
|
|
|
288
295
|
throw new Port80HandlerError('Domain, certificate and privateKey are required');
|
|
289
296
|
}
|
|
290
297
|
|
|
298
|
+
// Don't allow setting certificates for glob patterns
|
|
299
|
+
if (this.isGlobPattern(domain)) {
|
|
300
|
+
throw new Port80HandlerError('Cannot set certificate for glob pattern domains');
|
|
301
|
+
}
|
|
302
|
+
|
|
291
303
|
let domainInfo = this.domainCertificates.get(domain);
|
|
292
304
|
|
|
293
305
|
if (!domainInfo) {
|
|
@@ -334,6 +346,11 @@ export class Port80Handler extends plugins.EventEmitter {
|
|
|
334
346
|
* @param domain The domain to get the certificate for
|
|
335
347
|
*/
|
|
336
348
|
public getCertificate(domain: string): ICertificateData | null {
|
|
349
|
+
// Can't get certificates for glob patterns
|
|
350
|
+
if (this.isGlobPattern(domain)) {
|
|
351
|
+
return null;
|
|
352
|
+
}
|
|
353
|
+
|
|
337
354
|
const domainInfo = this.domainCertificates.get(domain);
|
|
338
355
|
|
|
339
356
|
if (!domainInfo || !domainInfo.certObtained || !domainInfo.certificate || !domainInfo.privateKey) {
|
|
@@ -348,6 +365,65 @@ export class Port80Handler extends plugins.EventEmitter {
|
|
|
348
365
|
};
|
|
349
366
|
}
|
|
350
367
|
|
|
368
|
+
/**
|
|
369
|
+
* Check if a domain is a glob pattern
|
|
370
|
+
* @param domain Domain to check
|
|
371
|
+
* @returns True if the domain is a glob pattern
|
|
372
|
+
*/
|
|
373
|
+
private isGlobPattern(domain: string): boolean {
|
|
374
|
+
return domain.includes('*');
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Get domain info for a specific domain, using glob pattern matching if needed
|
|
379
|
+
* @param requestDomain The actual domain from the request
|
|
380
|
+
* @returns The domain info or null if not found
|
|
381
|
+
*/
|
|
382
|
+
private getDomainInfoForRequest(requestDomain: string): { domainInfo: IDomainCertificate, pattern: string } | null {
|
|
383
|
+
// Try direct match first
|
|
384
|
+
if (this.domainCertificates.has(requestDomain)) {
|
|
385
|
+
return {
|
|
386
|
+
domainInfo: this.domainCertificates.get(requestDomain)!,
|
|
387
|
+
pattern: requestDomain
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Then try glob patterns
|
|
392
|
+
for (const [pattern, domainInfo] of this.domainCertificates.entries()) {
|
|
393
|
+
if (this.isGlobPattern(pattern) && this.domainMatchesPattern(requestDomain, pattern)) {
|
|
394
|
+
return { domainInfo, pattern };
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
return null;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Check if a domain matches a glob pattern
|
|
403
|
+
* @param domain The domain to check
|
|
404
|
+
* @param pattern The pattern to match against
|
|
405
|
+
* @returns True if the domain matches the pattern
|
|
406
|
+
*/
|
|
407
|
+
private domainMatchesPattern(domain: string, pattern: string): boolean {
|
|
408
|
+
// Handle different glob pattern styles
|
|
409
|
+
if (pattern.startsWith('*.')) {
|
|
410
|
+
// *.example.com matches any subdomain
|
|
411
|
+
const suffix = pattern.substring(2);
|
|
412
|
+
return domain.endsWith(suffix) && domain.includes('.') && domain !== suffix;
|
|
413
|
+
} else if (pattern.endsWith('.*')) {
|
|
414
|
+
// example.* matches any TLD
|
|
415
|
+
const prefix = pattern.substring(0, pattern.length - 2);
|
|
416
|
+
const domainParts = domain.split('.');
|
|
417
|
+
return domain.startsWith(prefix + '.') && domainParts.length >= 2;
|
|
418
|
+
} else if (pattern === '*') {
|
|
419
|
+
// Wildcard matches everything
|
|
420
|
+
return true;
|
|
421
|
+
} else {
|
|
422
|
+
// Exact match (shouldn't reach here as we check exact matches first)
|
|
423
|
+
return domain === pattern;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
351
427
|
/**
|
|
352
428
|
* Lazy initialization of the ACME client
|
|
353
429
|
* @returns An ACME client instance
|
|
@@ -397,14 +473,16 @@ export class Port80Handler extends plugins.EventEmitter {
|
|
|
397
473
|
// Extract domain (ignoring any port in the Host header)
|
|
398
474
|
const domain = hostHeader.split(':')[0];
|
|
399
475
|
|
|
400
|
-
//
|
|
401
|
-
|
|
476
|
+
// Get domain config, using glob pattern matching if needed
|
|
477
|
+
const domainMatch = this.getDomainInfoForRequest(domain);
|
|
478
|
+
|
|
479
|
+
if (!domainMatch) {
|
|
402
480
|
res.statusCode = 404;
|
|
403
481
|
res.end('Domain not configured');
|
|
404
482
|
return;
|
|
405
483
|
}
|
|
406
484
|
|
|
407
|
-
const domainInfo =
|
|
485
|
+
const { domainInfo, pattern } = domainMatch;
|
|
408
486
|
const options = domainInfo.options;
|
|
409
487
|
|
|
410
488
|
// If the request is for an ACME HTTP-01 challenge, handle it
|
|
@@ -415,8 +493,11 @@ export class Port80Handler extends plugins.EventEmitter {
|
|
|
415
493
|
return;
|
|
416
494
|
}
|
|
417
495
|
|
|
418
|
-
|
|
419
|
-
|
|
496
|
+
// Only handle ACME challenges for non-glob patterns
|
|
497
|
+
if (!this.isGlobPattern(pattern)) {
|
|
498
|
+
this.handleAcmeChallenge(req, res, domain);
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
420
501
|
}
|
|
421
502
|
|
|
422
503
|
// Check if we should forward non-ACME requests
|
|
@@ -426,7 +507,8 @@ export class Port80Handler extends plugins.EventEmitter {
|
|
|
426
507
|
}
|
|
427
508
|
|
|
428
509
|
// If certificate exists and sslRedirect is enabled, redirect to HTTPS
|
|
429
|
-
|
|
510
|
+
// (Skip for glob patterns as they won't have certificates)
|
|
511
|
+
if (!this.isGlobPattern(pattern) && domainInfo.certObtained && options.sslRedirect) {
|
|
430
512
|
const httpsPort = this.options.httpsRedirectPort;
|
|
431
513
|
const portSuffix = httpsPort === 443 ? '' : `:${httpsPort}`;
|
|
432
514
|
const redirectUrl = `https://${domain}${portSuffix}${req.url || '/'}`;
|
|
@@ -438,7 +520,8 @@ export class Port80Handler extends plugins.EventEmitter {
|
|
|
438
520
|
}
|
|
439
521
|
|
|
440
522
|
// Handle case where certificate maintenance is enabled but not yet obtained
|
|
441
|
-
|
|
523
|
+
// (Skip for glob patterns as they can't have certificates)
|
|
524
|
+
if (!this.isGlobPattern(pattern) && options.acmeMaintenance && !domainInfo.certObtained) {
|
|
442
525
|
// Trigger certificate issuance if not already running
|
|
443
526
|
if (!domainInfo.obtainingInProgress) {
|
|
444
527
|
this.obtainCertificate(domain).catch(err => {
|
|
@@ -559,6 +642,11 @@ export class Port80Handler extends plugins.EventEmitter {
|
|
|
559
642
|
* @param isRenewal Whether this is a renewal attempt
|
|
560
643
|
*/
|
|
561
644
|
private async obtainCertificate(domain: string, isRenewal: boolean = false): Promise<void> {
|
|
645
|
+
// Don't allow certificate issuance for glob patterns
|
|
646
|
+
if (this.isGlobPattern(domain)) {
|
|
647
|
+
throw new CertificateError('Cannot obtain certificates for glob pattern domains', domain, isRenewal);
|
|
648
|
+
}
|
|
649
|
+
|
|
562
650
|
// Get the domain info
|
|
563
651
|
const domainInfo = this.domainCertificates.get(domain);
|
|
564
652
|
if (!domainInfo) {
|
|
@@ -752,6 +840,11 @@ export class Port80Handler extends plugins.EventEmitter {
|
|
|
752
840
|
const renewThresholdMs = this.options.renewThresholdDays * 24 * 60 * 60 * 1000;
|
|
753
841
|
|
|
754
842
|
for (const [domain, domainInfo] of this.domainCertificates.entries()) {
|
|
843
|
+
// Skip glob patterns
|
|
844
|
+
if (this.isGlobPattern(domain)) {
|
|
845
|
+
continue;
|
|
846
|
+
}
|
|
847
|
+
|
|
755
848
|
// Skip domains with acmeMaintenance disabled
|
|
756
849
|
if (!domainInfo.options.acmeMaintenance) {
|
|
757
850
|
continue;
|
package/ts/index.ts
CHANGED