@push.rocks/smartproxy 12.0.0 → 13.1.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/acme/acme-factory.d.ts +17 -0
- package/dist_ts/certificate/acme/acme-factory.js +40 -0
- package/dist_ts/certificate/acme/challenge-handler.d.ts +44 -0
- package/dist_ts/certificate/acme/challenge-handler.js +92 -0
- package/dist_ts/certificate/acme/index.d.ts +4 -0
- package/dist_ts/certificate/acme/index.js +5 -0
- package/dist_ts/certificate/events/certificate-events.d.ts +33 -0
- package/dist_ts/certificate/events/certificate-events.js +38 -0
- package/dist_ts/certificate/index.d.ts +24 -0
- package/dist_ts/certificate/index.js +39 -0
- package/dist_ts/certificate/models/certificate-types.d.ts +77 -0
- package/dist_ts/certificate/models/certificate-types.js +2 -0
- package/dist_ts/certificate/providers/cert-provisioner.d.ts +93 -0
- package/dist_ts/certificate/providers/cert-provisioner.js +262 -0
- package/dist_ts/certificate/providers/index.d.ts +4 -0
- package/dist_ts/certificate/providers/index.js +5 -0
- package/dist_ts/certificate/storage/file-storage.d.ts +66 -0
- package/dist_ts/certificate/storage/file-storage.js +194 -0
- package/dist_ts/certificate/storage/index.d.ts +4 -0
- package/dist_ts/certificate/storage/index.js +5 -0
- package/dist_ts/certificate/utils/certificate-helpers.d.ts +17 -0
- package/dist_ts/certificate/utils/certificate-helpers.js +45 -0
- package/dist_ts/common/eventUtils.d.ts +1 -1
- package/dist_ts/common/port80-adapter.d.ts +1 -1
- package/dist_ts/core/events/index.d.ts +4 -0
- package/dist_ts/core/events/index.js +5 -0
- package/dist_ts/core/index.d.ts +6 -0
- package/dist_ts/core/index.js +8 -0
- package/dist_ts/core/models/common-types.d.ts +82 -0
- package/dist_ts/core/models/common-types.js +15 -0
- package/dist_ts/core/models/index.d.ts +4 -0
- package/dist_ts/core/models/index.js +5 -0
- package/dist_ts/core/utils/event-utils.d.ts +15 -0
- package/dist_ts/core/utils/event-utils.js +19 -0
- package/dist_ts/core/utils/index.d.ts +6 -0
- package/dist_ts/core/utils/index.js +7 -0
- package/dist_ts/core/utils/ip-utils.d.ts +53 -0
- package/dist_ts/core/utils/ip-utils.js +153 -0
- package/dist_ts/core/utils/validation-utils.d.ts +61 -0
- package/dist_ts/core/utils/validation-utils.js +149 -0
- package/dist_ts/forwarding/config/domain-config.d.ts +12 -0
- package/dist_ts/forwarding/config/domain-config.js +12 -0
- package/dist_ts/forwarding/config/domain-manager.d.ts +86 -0
- package/dist_ts/forwarding/config/domain-manager.js +242 -0
- package/dist_ts/forwarding/config/forwarding-types.d.ts +104 -0
- package/dist_ts/forwarding/config/forwarding-types.js +50 -0
- package/dist_ts/forwarding/config/index.d.ts +6 -0
- package/dist_ts/forwarding/config/index.js +7 -0
- package/dist_ts/forwarding/factory/forwarding-factory.d.ts +25 -0
- package/dist_ts/forwarding/factory/forwarding-factory.js +138 -0
- package/dist_ts/forwarding/factory/index.d.ts +4 -0
- package/dist_ts/forwarding/factory/index.js +5 -0
- package/dist_ts/forwarding/handlers/base-handler.d.ts +55 -0
- package/dist_ts/forwarding/handlers/base-handler.js +94 -0
- package/dist_ts/forwarding/handlers/http-handler.d.ts +30 -0
- package/dist_ts/forwarding/handlers/http-handler.js +131 -0
- package/dist_ts/forwarding/handlers/https-passthrough-handler.d.ts +29 -0
- package/dist_ts/forwarding/handlers/https-passthrough-handler.js +162 -0
- package/dist_ts/forwarding/handlers/https-terminate-to-http-handler.d.ts +36 -0
- package/dist_ts/forwarding/handlers/https-terminate-to-http-handler.js +229 -0
- package/dist_ts/forwarding/handlers/https-terminate-to-https-handler.d.ts +35 -0
- package/dist_ts/forwarding/handlers/https-terminate-to-https-handler.js +254 -0
- package/dist_ts/forwarding/handlers/index.d.ts +8 -0
- package/dist_ts/forwarding/handlers/index.js +9 -0
- package/dist_ts/forwarding/index.d.ts +19 -0
- package/dist_ts/forwarding/index.js +25 -0
- package/dist_ts/http/index.d.ts +15 -0
- package/dist_ts/http/index.js +20 -0
- package/dist_ts/http/models/http-types.d.ts +81 -0
- package/dist_ts/http/models/http-types.js +62 -0
- package/dist_ts/http/port80/acme-interfaces.d.ts +78 -0
- package/dist_ts/http/port80/acme-interfaces.js +6 -0
- package/dist_ts/http/port80/challenge-responder.d.ts +53 -0
- package/dist_ts/http/port80/challenge-responder.js +203 -0
- package/dist_ts/http/port80/index.d.ts +6 -0
- package/dist_ts/http/port80/index.js +9 -0
- package/dist_ts/http/port80/port80-handler.d.ts +121 -0
- package/dist_ts/http/port80/port80-handler.js +554 -0
- package/dist_ts/http/redirects/index.d.ts +4 -0
- package/dist_ts/http/redirects/index.js +5 -0
- package/dist_ts/http/router/index.d.ts +4 -0
- package/dist_ts/http/router/index.js +5 -0
- package/dist_ts/http/router/proxy-router.d.ts +115 -0
- package/dist_ts/http/router/proxy-router.js +325 -0
- package/dist_ts/index.d.ts +15 -8
- package/dist_ts/index.js +26 -10
- package/dist_ts/networkproxy/classes.np.certificatemanager.js +2 -2
- package/dist_ts/networkproxy/index.d.ts +1 -6
- package/dist_ts/networkproxy/index.js +4 -8
- package/dist_ts/plugins.d.ts +2 -1
- package/dist_ts/plugins.js +3 -2
- package/dist_ts/port80handler/classes.port80handler.d.ts +8 -136
- package/dist_ts/port80handler/classes.port80handler.js +14 -567
- package/dist_ts/proxies/index.d.ts +6 -0
- package/dist_ts/proxies/index.js +8 -0
- package/dist_ts/proxies/network-proxy/certificate-manager.d.ts +77 -0
- package/dist_ts/proxies/network-proxy/certificate-manager.js +373 -0
- package/dist_ts/proxies/network-proxy/connection-pool.d.ts +47 -0
- package/dist_ts/proxies/network-proxy/connection-pool.js +210 -0
- package/dist_ts/proxies/network-proxy/index.d.ts +10 -0
- package/dist_ts/proxies/network-proxy/index.js +12 -0
- package/dist_ts/proxies/network-proxy/models/index.d.ts +4 -0
- package/dist_ts/proxies/network-proxy/models/index.js +5 -0
- package/dist_ts/proxies/network-proxy/models/types.d.ts +80 -0
- package/dist_ts/proxies/network-proxy/models/types.js +35 -0
- package/dist_ts/proxies/network-proxy/network-proxy.d.ts +118 -0
- package/dist_ts/proxies/network-proxy/network-proxy.js +387 -0
- package/dist_ts/proxies/network-proxy/request-handler.d.ts +57 -0
- package/dist_ts/proxies/network-proxy/request-handler.js +394 -0
- package/dist_ts/proxies/network-proxy/websocket-handler.d.ts +38 -0
- package/dist_ts/proxies/network-proxy/websocket-handler.js +188 -0
- package/dist_ts/proxies/nftables-proxy/index.d.ts +5 -0
- package/dist_ts/proxies/nftables-proxy/index.js +6 -0
- package/dist_ts/proxies/nftables-proxy/models/errors.d.ts +15 -0
- package/dist_ts/proxies/nftables-proxy/models/errors.js +28 -0
- package/dist_ts/proxies/nftables-proxy/models/index.d.ts +5 -0
- package/dist_ts/proxies/nftables-proxy/models/index.js +6 -0
- package/dist_ts/proxies/nftables-proxy/models/interfaces.d.ts +75 -0
- package/dist_ts/proxies/nftables-proxy/models/interfaces.js +5 -0
- package/dist_ts/proxies/nftables-proxy/nftables-proxy.d.ts +136 -0
- package/dist_ts/proxies/nftables-proxy/nftables-proxy.js +1516 -0
- package/dist_ts/proxies/smart-proxy/connection-handler.d.ts +39 -0
- package/dist_ts/proxies/smart-proxy/connection-handler.js +894 -0
- package/dist_ts/proxies/smart-proxy/connection-manager.d.ts +78 -0
- package/dist_ts/proxies/smart-proxy/connection-manager.js +378 -0
- package/dist_ts/proxies/smart-proxy/domain-config-manager.d.ts +95 -0
- package/dist_ts/proxies/smart-proxy/domain-config-manager.js +255 -0
- package/dist_ts/proxies/smart-proxy/index.d.ts +13 -0
- package/dist_ts/proxies/smart-proxy/index.js +17 -0
- package/dist_ts/proxies/smart-proxy/models/index.d.ts +4 -0
- package/dist_ts/proxies/smart-proxy/models/index.js +5 -0
- package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +107 -0
- package/dist_ts/proxies/smart-proxy/models/interfaces.js +2 -0
- package/dist_ts/proxies/smart-proxy/network-proxy-bridge.d.ts +62 -0
- package/dist_ts/proxies/smart-proxy/network-proxy-bridge.js +316 -0
- package/dist_ts/proxies/smart-proxy/port-range-manager.d.ts +56 -0
- package/dist_ts/proxies/smart-proxy/port-range-manager.js +176 -0
- package/dist_ts/proxies/smart-proxy/security-manager.d.ts +64 -0
- package/dist_ts/proxies/smart-proxy/security-manager.js +149 -0
- package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +63 -0
- package/dist_ts/proxies/smart-proxy/smart-proxy.js +523 -0
- package/dist_ts/proxies/smart-proxy/timeout-manager.d.ts +47 -0
- package/dist_ts/proxies/smart-proxy/timeout-manager.js +154 -0
- package/dist_ts/proxies/smart-proxy/tls-manager.d.ts +57 -0
- package/dist_ts/proxies/smart-proxy/tls-manager.js +132 -0
- package/dist_ts/smartproxy/classes.pp.networkproxybridge.d.ts +2 -2
- package/dist_ts/smartproxy/classes.pp.networkproxybridge.js +1 -1
- package/dist_ts/smartproxy/classes.pp.tlsmanager.js +2 -2
- package/dist_ts/smartproxy/classes.smartproxy.js +3 -3
- package/dist_ts/tls/alerts/index.d.ts +4 -0
- package/dist_ts/tls/alerts/index.js +5 -0
- package/dist_ts/tls/alerts/tls-alert.d.ts +150 -0
- package/dist_ts/tls/alerts/tls-alert.js +226 -0
- package/dist_ts/tls/index.d.ts +18 -0
- package/dist_ts/tls/index.js +27 -0
- package/dist_ts/tls/sni/client-hello-parser.d.ts +100 -0
- package/dist_ts/tls/sni/client-hello-parser.js +463 -0
- package/dist_ts/tls/sni/index.d.ts +4 -0
- package/dist_ts/tls/sni/index.js +5 -0
- package/dist_ts/tls/sni/sni-extraction.d.ts +58 -0
- package/dist_ts/tls/sni/sni-extraction.js +275 -0
- package/dist_ts/tls/sni/sni-handler.d.ts +154 -0
- package/dist_ts/tls/sni/sni-handler.js +191 -0
- package/dist_ts/tls/utils/index.d.ts +4 -0
- package/dist_ts/tls/utils/index.js +5 -0
- package/dist_ts/tls/utils/tls-utils.d.ts +158 -0
- package/dist_ts/tls/utils/tls-utils.js +187 -0
- package/package.json +1 -1
- package/readme.md +89 -21
- package/readme.plan.md +253 -469
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/certificate/acme/acme-factory.ts +48 -0
- package/ts/certificate/acme/challenge-handler.ts +110 -0
- package/ts/certificate/acme/index.ts +3 -0
- package/ts/certificate/events/certificate-events.ts +36 -0
- package/ts/certificate/index.ts +67 -0
- package/ts/certificate/models/certificate-types.ts +88 -0
- package/ts/certificate/providers/cert-provisioner.ts +326 -0
- package/ts/certificate/providers/index.ts +3 -0
- package/ts/certificate/storage/file-storage.ts +234 -0
- package/ts/certificate/storage/index.ts +3 -0
- package/ts/certificate/utils/certificate-helpers.ts +50 -0
- package/ts/common/eventUtils.ts +1 -1
- package/ts/common/port80-adapter.ts +1 -1
- package/ts/core/events/index.ts +3 -0
- package/ts/core/index.ts +8 -0
- package/ts/core/models/common-types.ts +91 -0
- package/ts/core/models/index.ts +5 -0
- package/ts/core/utils/event-utils.ts +34 -0
- package/ts/core/utils/index.ts +7 -0
- package/ts/core/utils/ip-utils.ts +175 -0
- package/ts/core/utils/validation-utils.ts +177 -0
- package/ts/{smartproxy/forwarding → forwarding/config}/domain-config.ts +1 -1
- package/ts/{smartproxy/forwarding → forwarding/config}/domain-manager.ts +8 -8
- package/ts/{smartproxy/types/forwarding.types.ts → forwarding/config/forwarding-types.ts} +6 -6
- package/ts/forwarding/config/index.ts +7 -0
- package/ts/{smartproxy/forwarding/forwarding.factory.ts → forwarding/factory/forwarding-factory.ts} +12 -11
- package/ts/forwarding/factory/index.ts +5 -0
- package/ts/{smartproxy/forwarding/forwarding.handler.ts → forwarding/handlers/base-handler.ts} +2 -2
- package/ts/{smartproxy/forwarding/http.handler.ts → forwarding/handlers/http-handler.ts} +13 -4
- package/ts/{smartproxy/forwarding/https-passthrough.handler.ts → forwarding/handlers/https-passthrough-handler.ts} +13 -4
- package/ts/{smartproxy/forwarding/https-terminate-to-http.handler.ts → forwarding/handlers/https-terminate-to-http-handler.ts} +3 -3
- package/ts/{smartproxy/forwarding/https-terminate-to-https.handler.ts → forwarding/handlers/https-terminate-to-https-handler.ts} +3 -3
- package/ts/forwarding/handlers/index.ts +9 -0
- package/ts/forwarding/index.ts +34 -0
- package/ts/http/index.ts +23 -0
- package/ts/http/models/http-types.ts +105 -0
- package/ts/http/port80/acme-interfaces.ts +85 -0
- package/ts/http/port80/challenge-responder.ts +246 -0
- package/ts/http/port80/index.ts +13 -0
- package/ts/{port80handler/classes.port80handler.ts → http/port80/port80-handler.ts} +164 -161
- package/ts/http/redirects/index.ts +3 -0
- package/ts/http/router/index.ts +5 -0
- package/ts/{classes.router.ts → http/router/proxy-router.ts} +27 -20
- package/ts/index.ts +32 -9
- package/ts/plugins.ts +2 -1
- package/ts/proxies/index.ts +8 -0
- package/ts/{networkproxy/classes.np.certificatemanager.ts → proxies/network-proxy/certificate-manager.ts} +17 -16
- package/ts/{networkproxy/classes.np.connectionpool.ts → proxies/network-proxy/connection-pool.ts} +3 -3
- package/ts/proxies/network-proxy/index.ts +13 -0
- package/ts/proxies/network-proxy/models/index.ts +4 -0
- package/ts/{networkproxy/classes.np.types.ts → proxies/network-proxy/models/types.ts} +7 -11
- package/ts/{networkproxy/classes.np.networkproxy.ts → proxies/network-proxy/network-proxy.ts} +31 -24
- package/ts/{networkproxy/classes.np.requesthandler.ts → proxies/network-proxy/request-handler.ts} +12 -7
- package/ts/{networkproxy/classes.np.websockethandler.ts → proxies/network-proxy/websocket-handler.ts} +6 -6
- package/ts/proxies/nftables-proxy/index.ts +5 -0
- package/ts/proxies/nftables-proxy/models/errors.ts +30 -0
- package/ts/proxies/nftables-proxy/models/index.ts +5 -0
- package/ts/proxies/nftables-proxy/models/interfaces.ts +94 -0
- package/ts/{nfttablesproxy/classes.nftablesproxy.ts → proxies/nftables-proxy/nftables-proxy.ts} +24 -126
- package/ts/{smartproxy/classes.pp.connectionhandler.ts → proxies/smart-proxy/connection-handler.ts} +12 -12
- package/ts/{smartproxy/classes.pp.connectionmanager.ts → proxies/smart-proxy/connection-manager.ts} +8 -8
- package/ts/{smartproxy/classes.pp.domainconfigmanager.ts → proxies/smart-proxy/domain-config-manager.ts} +15 -14
- package/ts/proxies/smart-proxy/index.ts +18 -0
- package/ts/proxies/smart-proxy/models/index.ts +4 -0
- package/ts/{smartproxy/classes.pp.interfaces.ts → proxies/smart-proxy/models/interfaces.ts} +12 -8
- package/ts/{smartproxy/classes.pp.networkproxybridge.ts → proxies/smart-proxy/network-proxy-bridge.ts} +14 -14
- package/ts/{smartproxy/classes.pp.portrangemanager.ts → proxies/smart-proxy/port-range-manager.ts} +1 -1
- package/ts/{smartproxy/classes.pp.securitymanager.ts → proxies/smart-proxy/security-manager.ts} +3 -3
- package/ts/{smartproxy/classes.smartproxy.ts → proxies/smart-proxy/smart-proxy.ts} +29 -24
- package/ts/{smartproxy/classes.pp.timeoutmanager.ts → proxies/smart-proxy/timeout-manager.ts} +3 -3
- package/ts/{smartproxy/classes.pp.tlsmanager.ts → proxies/smart-proxy/tls-manager.ts} +3 -3
- package/ts/tls/alerts/index.ts +3 -0
- package/ts/{smartproxy/classes.pp.tlsalert.ts → tls/alerts/tls-alert.ts} +44 -43
- package/ts/tls/index.ts +33 -0
- package/ts/tls/sni/client-hello-parser.ts +629 -0
- package/ts/tls/sni/index.ts +3 -0
- package/ts/tls/sni/sni-extraction.ts +353 -0
- package/ts/tls/sni/sni-handler.ts +264 -0
- package/ts/tls/utils/index.ts +3 -0
- package/ts/tls/utils/tls-utils.ts +201 -0
- package/ts/common/acmeFactory.ts +0 -23
- package/ts/helpers.certificates.ts +0 -30
- package/ts/networkproxy/index.ts +0 -7
- package/ts/smartproxy/classes.pp.certprovisioner.ts +0 -200
- package/ts/smartproxy/classes.pp.snihandler.ts +0 -1281
- package/ts/smartproxy/forwarding/index.ts +0 -52
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as plugins from '../../plugins.js';
|
|
4
|
+
import type { ICertificateData, ICertificates } from '../models/certificate-types.js';
|
|
5
|
+
import { ensureCertificateDirectory } from '../utils/certificate-helpers.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* FileStorage provides file system storage for certificates
|
|
9
|
+
*/
|
|
10
|
+
export class FileStorage {
|
|
11
|
+
private storageDir: string;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Creates a new file storage provider
|
|
15
|
+
* @param storageDir Directory to store certificates
|
|
16
|
+
*/
|
|
17
|
+
constructor(storageDir: string) {
|
|
18
|
+
this.storageDir = path.resolve(storageDir);
|
|
19
|
+
ensureCertificateDirectory(this.storageDir);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Save a certificate to the file system
|
|
24
|
+
* @param domain Domain name
|
|
25
|
+
* @param certData Certificate data to save
|
|
26
|
+
*/
|
|
27
|
+
public async saveCertificate(domain: string, certData: ICertificateData): Promise<void> {
|
|
28
|
+
const sanitizedDomain = this.sanitizeDomain(domain);
|
|
29
|
+
const certDir = path.join(this.storageDir, sanitizedDomain);
|
|
30
|
+
ensureCertificateDirectory(certDir);
|
|
31
|
+
|
|
32
|
+
const certPath = path.join(certDir, 'fullchain.pem');
|
|
33
|
+
const keyPath = path.join(certDir, 'privkey.pem');
|
|
34
|
+
const metaPath = path.join(certDir, 'metadata.json');
|
|
35
|
+
|
|
36
|
+
// Write certificate and private key
|
|
37
|
+
await fs.promises.writeFile(certPath, certData.certificate, 'utf8');
|
|
38
|
+
await fs.promises.writeFile(keyPath, certData.privateKey, 'utf8');
|
|
39
|
+
|
|
40
|
+
// Write metadata
|
|
41
|
+
const metadata = {
|
|
42
|
+
domain: certData.domain,
|
|
43
|
+
expiryDate: certData.expiryDate.toISOString(),
|
|
44
|
+
source: certData.source || 'unknown',
|
|
45
|
+
issuedAt: new Date().toISOString()
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
await fs.promises.writeFile(
|
|
49
|
+
metaPath,
|
|
50
|
+
JSON.stringify(metadata, null, 2),
|
|
51
|
+
'utf8'
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Load a certificate from the file system
|
|
57
|
+
* @param domain Domain name
|
|
58
|
+
* @returns Certificate data if found, null otherwise
|
|
59
|
+
*/
|
|
60
|
+
public async loadCertificate(domain: string): Promise<ICertificateData | null> {
|
|
61
|
+
const sanitizedDomain = this.sanitizeDomain(domain);
|
|
62
|
+
const certDir = path.join(this.storageDir, sanitizedDomain);
|
|
63
|
+
|
|
64
|
+
if (!fs.existsSync(certDir)) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const certPath = path.join(certDir, 'fullchain.pem');
|
|
69
|
+
const keyPath = path.join(certDir, 'privkey.pem');
|
|
70
|
+
const metaPath = path.join(certDir, 'metadata.json');
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
// Check if all required files exist
|
|
74
|
+
if (!fs.existsSync(certPath) || !fs.existsSync(keyPath)) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Read certificate and private key
|
|
79
|
+
const certificate = await fs.promises.readFile(certPath, 'utf8');
|
|
80
|
+
const privateKey = await fs.promises.readFile(keyPath, 'utf8');
|
|
81
|
+
|
|
82
|
+
// Try to read metadata if available
|
|
83
|
+
let expiryDate = new Date();
|
|
84
|
+
let source: 'static' | 'http01' | 'dns01' | undefined;
|
|
85
|
+
|
|
86
|
+
if (fs.existsSync(metaPath)) {
|
|
87
|
+
const metaContent = await fs.promises.readFile(metaPath, 'utf8');
|
|
88
|
+
const metadata = JSON.parse(metaContent);
|
|
89
|
+
|
|
90
|
+
if (metadata.expiryDate) {
|
|
91
|
+
expiryDate = new Date(metadata.expiryDate);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (metadata.source) {
|
|
95
|
+
source = metadata.source as 'static' | 'http01' | 'dns01';
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
domain,
|
|
101
|
+
certificate,
|
|
102
|
+
privateKey,
|
|
103
|
+
expiryDate,
|
|
104
|
+
source
|
|
105
|
+
};
|
|
106
|
+
} catch (error) {
|
|
107
|
+
console.error(`Error loading certificate for ${domain}:`, error);
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Delete a certificate from the file system
|
|
114
|
+
* @param domain Domain name
|
|
115
|
+
*/
|
|
116
|
+
public async deleteCertificate(domain: string): Promise<boolean> {
|
|
117
|
+
const sanitizedDomain = this.sanitizeDomain(domain);
|
|
118
|
+
const certDir = path.join(this.storageDir, sanitizedDomain);
|
|
119
|
+
|
|
120
|
+
if (!fs.existsSync(certDir)) {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
// Recursively delete the certificate directory
|
|
126
|
+
await this.deleteDirectory(certDir);
|
|
127
|
+
return true;
|
|
128
|
+
} catch (error) {
|
|
129
|
+
console.error(`Error deleting certificate for ${domain}:`, error);
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* List all domains with stored certificates
|
|
136
|
+
* @returns Array of domain names
|
|
137
|
+
*/
|
|
138
|
+
public async listCertificates(): Promise<string[]> {
|
|
139
|
+
try {
|
|
140
|
+
const entries = await fs.promises.readdir(this.storageDir, { withFileTypes: true });
|
|
141
|
+
return entries
|
|
142
|
+
.filter(entry => entry.isDirectory())
|
|
143
|
+
.map(entry => entry.name);
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.error('Error listing certificates:', error);
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Check if a certificate is expiring soon
|
|
152
|
+
* @param domain Domain name
|
|
153
|
+
* @param thresholdDays Days threshold to consider expiring
|
|
154
|
+
* @returns Information about expiring certificate or null
|
|
155
|
+
*/
|
|
156
|
+
public async isExpiringSoon(
|
|
157
|
+
domain: string,
|
|
158
|
+
thresholdDays: number = 30
|
|
159
|
+
): Promise<{ domain: string; expiryDate: Date; daysRemaining: number } | null> {
|
|
160
|
+
const certData = await this.loadCertificate(domain);
|
|
161
|
+
|
|
162
|
+
if (!certData) {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const now = new Date();
|
|
167
|
+
const expiryDate = certData.expiryDate;
|
|
168
|
+
const timeRemaining = expiryDate.getTime() - now.getTime();
|
|
169
|
+
const daysRemaining = Math.floor(timeRemaining / (1000 * 60 * 60 * 24));
|
|
170
|
+
|
|
171
|
+
if (daysRemaining <= thresholdDays) {
|
|
172
|
+
return {
|
|
173
|
+
domain,
|
|
174
|
+
expiryDate,
|
|
175
|
+
daysRemaining
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Check all certificates for expiration
|
|
184
|
+
* @param thresholdDays Days threshold to consider expiring
|
|
185
|
+
* @returns List of expiring certificates
|
|
186
|
+
*/
|
|
187
|
+
public async getExpiringCertificates(
|
|
188
|
+
thresholdDays: number = 30
|
|
189
|
+
): Promise<Array<{ domain: string; expiryDate: Date; daysRemaining: number }>> {
|
|
190
|
+
const domains = await this.listCertificates();
|
|
191
|
+
const expiringCerts = [];
|
|
192
|
+
|
|
193
|
+
for (const domain of domains) {
|
|
194
|
+
const expiring = await this.isExpiringSoon(domain, thresholdDays);
|
|
195
|
+
if (expiring) {
|
|
196
|
+
expiringCerts.push(expiring);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return expiringCerts;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Delete a directory recursively
|
|
205
|
+
* @param directoryPath Directory to delete
|
|
206
|
+
*/
|
|
207
|
+
private async deleteDirectory(directoryPath: string): Promise<void> {
|
|
208
|
+
if (fs.existsSync(directoryPath)) {
|
|
209
|
+
const entries = await fs.promises.readdir(directoryPath, { withFileTypes: true });
|
|
210
|
+
|
|
211
|
+
for (const entry of entries) {
|
|
212
|
+
const fullPath = path.join(directoryPath, entry.name);
|
|
213
|
+
|
|
214
|
+
if (entry.isDirectory()) {
|
|
215
|
+
await this.deleteDirectory(fullPath);
|
|
216
|
+
} else {
|
|
217
|
+
await fs.promises.unlink(fullPath);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
await fs.promises.rmdir(directoryPath);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Sanitize a domain name for use as a directory name
|
|
227
|
+
* @param domain Domain name
|
|
228
|
+
* @returns Sanitized domain name
|
|
229
|
+
*/
|
|
230
|
+
private sanitizeDomain(domain: string): string {
|
|
231
|
+
// Replace wildcard and any invalid filesystem characters
|
|
232
|
+
return domain.replace(/\*/g, '_wildcard_').replace(/[/\\:*?"<>|]/g, '_');
|
|
233
|
+
}
|
|
234
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import type { ICertificates } from '../models/certificate-types.js';
|
|
5
|
+
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Loads the default SSL certificates from the assets directory
|
|
10
|
+
* @returns The certificate key pair
|
|
11
|
+
*/
|
|
12
|
+
export function loadDefaultCertificates(): ICertificates {
|
|
13
|
+
try {
|
|
14
|
+
// Need to adjust path from /ts/certificate/utils to /assets/certs
|
|
15
|
+
const certPath = path.join(__dirname, '..', '..', '..', 'assets', 'certs');
|
|
16
|
+
const privateKey = fs.readFileSync(path.join(certPath, 'key.pem'), 'utf8');
|
|
17
|
+
const publicKey = fs.readFileSync(path.join(certPath, 'cert.pem'), 'utf8');
|
|
18
|
+
|
|
19
|
+
if (!privateKey || !publicKey) {
|
|
20
|
+
throw new Error('Failed to load default certificates');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
privateKey,
|
|
25
|
+
publicKey
|
|
26
|
+
};
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.error('Error loading default certificates:', error);
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Checks if a certificate file exists at the specified path
|
|
35
|
+
* @param certPath Path to check for certificate
|
|
36
|
+
* @returns True if the certificate exists, false otherwise
|
|
37
|
+
*/
|
|
38
|
+
export function certificateExists(certPath: string): boolean {
|
|
39
|
+
return fs.existsSync(certPath);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Ensures the certificate directory exists
|
|
44
|
+
* @param dirPath Path to the certificate directory
|
|
45
|
+
*/
|
|
46
|
+
export function ensureCertificateDirectory(dirPath: string): void {
|
|
47
|
+
if (!fs.existsSync(dirPath)) {
|
|
48
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
49
|
+
}
|
|
50
|
+
}
|
package/ts/common/eventUtils.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Port80Handler } from '../
|
|
1
|
+
import type { Port80Handler } from '../http/port80/port80-handler.js';
|
|
2
2
|
import { Port80HandlerEvents } from './types.js';
|
|
3
3
|
import type { ICertificateData, ICertificateFailure, ICertificateExpiring } from './types.js';
|
|
4
4
|
|
package/ts/core/index.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Shared types for certificate management and domain options
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Domain forwarding configuration
|
|
9
|
+
*/
|
|
10
|
+
export interface IForwardConfig {
|
|
11
|
+
ip: string;
|
|
12
|
+
port: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Domain configuration options
|
|
17
|
+
*/
|
|
18
|
+
export interface IDomainOptions {
|
|
19
|
+
domainName: string;
|
|
20
|
+
sslRedirect: boolean; // if true redirects the request to port 443
|
|
21
|
+
acmeMaintenance: boolean; // tries to always have a valid cert for this domain
|
|
22
|
+
forward?: IForwardConfig; // forwards all http requests to that target
|
|
23
|
+
acmeForward?: IForwardConfig; // forwards letsencrypt requests to this config
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Certificate data that can be emitted via events or set from outside
|
|
28
|
+
*/
|
|
29
|
+
export interface ICertificateData {
|
|
30
|
+
domain: string;
|
|
31
|
+
certificate: string;
|
|
32
|
+
privateKey: string;
|
|
33
|
+
expiryDate: Date;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Events emitted by the Port80Handler
|
|
38
|
+
*/
|
|
39
|
+
export enum Port80HandlerEvents {
|
|
40
|
+
CERTIFICATE_ISSUED = 'certificate-issued',
|
|
41
|
+
CERTIFICATE_RENEWED = 'certificate-renewed',
|
|
42
|
+
CERTIFICATE_FAILED = 'certificate-failed',
|
|
43
|
+
CERTIFICATE_EXPIRING = 'certificate-expiring',
|
|
44
|
+
MANAGER_STARTED = 'manager-started',
|
|
45
|
+
MANAGER_STOPPED = 'manager-stopped',
|
|
46
|
+
REQUEST_FORWARDED = 'request-forwarded',
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Certificate failure payload type
|
|
51
|
+
*/
|
|
52
|
+
export interface ICertificateFailure {
|
|
53
|
+
domain: string;
|
|
54
|
+
error: string;
|
|
55
|
+
isRenewal: boolean;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Certificate expiry payload type
|
|
60
|
+
*/
|
|
61
|
+
export interface ICertificateExpiring {
|
|
62
|
+
domain: string;
|
|
63
|
+
expiryDate: Date;
|
|
64
|
+
daysRemaining: number;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Forwarding configuration for specific domains in ACME setup
|
|
68
|
+
*/
|
|
69
|
+
export interface IDomainForwardConfig {
|
|
70
|
+
domain: string;
|
|
71
|
+
forwardConfig?: IForwardConfig;
|
|
72
|
+
acmeForwardConfig?: IForwardConfig;
|
|
73
|
+
sslRedirect?: boolean;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Unified ACME configuration options used across proxies and handlers
|
|
78
|
+
*/
|
|
79
|
+
export interface IAcmeOptions {
|
|
80
|
+
accountEmail?: string; // Email for Let's Encrypt account
|
|
81
|
+
enabled?: boolean; // Whether ACME is enabled
|
|
82
|
+
port?: number; // Port to listen on for ACME challenges (default: 80)
|
|
83
|
+
useProduction?: boolean; // Use production environment (default: staging)
|
|
84
|
+
httpsRedirectPort?: number; // Port to redirect HTTP requests to HTTPS (default: 443)
|
|
85
|
+
renewThresholdDays?: number; // Days before expiry to renew certificates
|
|
86
|
+
renewCheckIntervalHours?: number; // How often to check for renewals (in hours)
|
|
87
|
+
autoRenew?: boolean; // Whether to automatically renew certificates
|
|
88
|
+
certificateStore?: string; // Directory to store certificates
|
|
89
|
+
skipConfiguredCerts?: boolean; // Skip domains with existing certificates
|
|
90
|
+
domainForwards?: IDomainForwardConfig[]; // Domain-specific forwarding configs
|
|
91
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Port80Handler } from '../../http/port80/port80-handler.js';
|
|
2
|
+
import { Port80HandlerEvents } from '../models/common-types.js';
|
|
3
|
+
import type { ICertificateData, ICertificateFailure, ICertificateExpiring } from '../models/common-types.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Subscribers callback definitions for Port80Handler events
|
|
7
|
+
*/
|
|
8
|
+
export interface IPort80HandlerSubscribers {
|
|
9
|
+
onCertificateIssued?: (data: ICertificateData) => void;
|
|
10
|
+
onCertificateRenewed?: (data: ICertificateData) => void;
|
|
11
|
+
onCertificateFailed?: (data: ICertificateFailure) => void;
|
|
12
|
+
onCertificateExpiring?: (data: ICertificateExpiring) => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Subscribes to Port80Handler events based on provided callbacks
|
|
17
|
+
*/
|
|
18
|
+
export function subscribeToPort80Handler(
|
|
19
|
+
handler: Port80Handler,
|
|
20
|
+
subscribers: IPort80HandlerSubscribers
|
|
21
|
+
): void {
|
|
22
|
+
if (subscribers.onCertificateIssued) {
|
|
23
|
+
handler.on(Port80HandlerEvents.CERTIFICATE_ISSUED, subscribers.onCertificateIssued);
|
|
24
|
+
}
|
|
25
|
+
if (subscribers.onCertificateRenewed) {
|
|
26
|
+
handler.on(Port80HandlerEvents.CERTIFICATE_RENEWED, subscribers.onCertificateRenewed);
|
|
27
|
+
}
|
|
28
|
+
if (subscribers.onCertificateFailed) {
|
|
29
|
+
handler.on(Port80HandlerEvents.CERTIFICATE_FAILED, subscribers.onCertificateFailed);
|
|
30
|
+
}
|
|
31
|
+
if (subscribers.onCertificateExpiring) {
|
|
32
|
+
handler.on(Port80HandlerEvents.CERTIFICATE_EXPIRING, subscribers.onCertificateExpiring);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Utility class for IP address operations
|
|
5
|
+
*/
|
|
6
|
+
export class IpUtils {
|
|
7
|
+
/**
|
|
8
|
+
* Check if the IP matches any of the glob patterns
|
|
9
|
+
*
|
|
10
|
+
* This method checks IP addresses against glob patterns and handles IPv4/IPv6 normalization.
|
|
11
|
+
* It's used to implement IP filtering based on security configurations.
|
|
12
|
+
*
|
|
13
|
+
* @param ip - The IP address to check
|
|
14
|
+
* @param patterns - Array of glob patterns
|
|
15
|
+
* @returns true if IP matches any pattern, false otherwise
|
|
16
|
+
*/
|
|
17
|
+
public static isGlobIPMatch(ip: string, patterns: string[]): boolean {
|
|
18
|
+
if (!ip || !patterns || patterns.length === 0) return false;
|
|
19
|
+
|
|
20
|
+
// Normalize the IP being checked
|
|
21
|
+
const normalizedIPVariants = this.normalizeIP(ip);
|
|
22
|
+
if (normalizedIPVariants.length === 0) return false;
|
|
23
|
+
|
|
24
|
+
// Normalize the pattern IPs for consistent comparison
|
|
25
|
+
const expandedPatterns = patterns.flatMap(pattern => this.normalizeIP(pattern));
|
|
26
|
+
|
|
27
|
+
// Check for any match between normalized IP variants and patterns
|
|
28
|
+
return normalizedIPVariants.some((ipVariant) =>
|
|
29
|
+
expandedPatterns.some((pattern) => plugins.minimatch(ipVariant, pattern))
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Normalize IP addresses for consistent comparison
|
|
35
|
+
*
|
|
36
|
+
* @param ip The IP address to normalize
|
|
37
|
+
* @returns Array of normalized IP forms
|
|
38
|
+
*/
|
|
39
|
+
public static normalizeIP(ip: string): string[] {
|
|
40
|
+
if (!ip) return [];
|
|
41
|
+
|
|
42
|
+
// Handle IPv4-mapped IPv6 addresses (::ffff:127.0.0.1)
|
|
43
|
+
if (ip.startsWith('::ffff:')) {
|
|
44
|
+
const ipv4 = ip.slice(7);
|
|
45
|
+
return [ip, ipv4];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Handle IPv4 addresses by also checking IPv4-mapped form
|
|
49
|
+
if (/^\d{1,3}(\.\d{1,3}){3}$/.test(ip)) {
|
|
50
|
+
return [ip, `::ffff:${ip}`];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return [ip];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Check if an IP is authorized using security rules
|
|
58
|
+
*
|
|
59
|
+
* @param ip - The IP address to check
|
|
60
|
+
* @param allowedIPs - Array of allowed IP patterns
|
|
61
|
+
* @param blockedIPs - Array of blocked IP patterns
|
|
62
|
+
* @returns true if IP is authorized, false if blocked
|
|
63
|
+
*/
|
|
64
|
+
public static isIPAuthorized(ip: string, allowedIPs: string[] = [], blockedIPs: string[] = []): boolean {
|
|
65
|
+
// Skip IP validation if no rules are defined
|
|
66
|
+
if (!ip || (allowedIPs.length === 0 && blockedIPs.length === 0)) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// First check if IP is blocked - blocked IPs take precedence
|
|
71
|
+
if (blockedIPs.length > 0 && this.isGlobIPMatch(ip, blockedIPs)) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Then check if IP is allowed (if no allowed IPs are specified, all non-blocked IPs are allowed)
|
|
76
|
+
return allowedIPs.length === 0 || this.isGlobIPMatch(ip, allowedIPs);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Check if an IP address is a private network address
|
|
81
|
+
*
|
|
82
|
+
* @param ip The IP address to check
|
|
83
|
+
* @returns true if the IP is a private network address, false otherwise
|
|
84
|
+
*/
|
|
85
|
+
public static isPrivateIP(ip: string): boolean {
|
|
86
|
+
if (!ip) return false;
|
|
87
|
+
|
|
88
|
+
// Handle IPv4-mapped IPv6 addresses
|
|
89
|
+
if (ip.startsWith('::ffff:')) {
|
|
90
|
+
ip = ip.slice(7);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Check IPv4 private ranges
|
|
94
|
+
if (/^\d{1,3}(\.\d{1,3}){3}$/.test(ip)) {
|
|
95
|
+
const parts = ip.split('.').map(Number);
|
|
96
|
+
|
|
97
|
+
// Check common private ranges
|
|
98
|
+
// 10.0.0.0/8
|
|
99
|
+
if (parts[0] === 10) return true;
|
|
100
|
+
|
|
101
|
+
// 172.16.0.0/12
|
|
102
|
+
if (parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31) return true;
|
|
103
|
+
|
|
104
|
+
// 192.168.0.0/16
|
|
105
|
+
if (parts[0] === 192 && parts[1] === 168) return true;
|
|
106
|
+
|
|
107
|
+
// 127.0.0.0/8 (localhost)
|
|
108
|
+
if (parts[0] === 127) return true;
|
|
109
|
+
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// IPv6 local addresses
|
|
114
|
+
return ip === '::1' || ip.startsWith('fc00:') || ip.startsWith('fd00:') || ip.startsWith('fe80:');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Check if an IP address is a public network address
|
|
119
|
+
*
|
|
120
|
+
* @param ip The IP address to check
|
|
121
|
+
* @returns true if the IP is a public network address, false otherwise
|
|
122
|
+
*/
|
|
123
|
+
public static isPublicIP(ip: string): boolean {
|
|
124
|
+
return !this.isPrivateIP(ip);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Convert a subnet CIDR to an IP range for filtering
|
|
129
|
+
*
|
|
130
|
+
* @param cidr The CIDR notation (e.g., "192.168.1.0/24")
|
|
131
|
+
* @returns Array of glob patterns that match the CIDR range
|
|
132
|
+
*/
|
|
133
|
+
public static cidrToGlobPatterns(cidr: string): string[] {
|
|
134
|
+
if (!cidr || !cidr.includes('/')) return [];
|
|
135
|
+
|
|
136
|
+
const [ipPart, prefixPart] = cidr.split('/');
|
|
137
|
+
const prefix = parseInt(prefixPart, 10);
|
|
138
|
+
|
|
139
|
+
if (isNaN(prefix) || prefix < 0 || prefix > 32) return [];
|
|
140
|
+
|
|
141
|
+
// For IPv4 only for now
|
|
142
|
+
if (!/^\d{1,3}(\.\d{1,3}){3}$/.test(ipPart)) return [];
|
|
143
|
+
|
|
144
|
+
const ipParts = ipPart.split('.').map(Number);
|
|
145
|
+
const fullMask = Math.pow(2, 32 - prefix) - 1;
|
|
146
|
+
|
|
147
|
+
// Convert IP to a numeric value
|
|
148
|
+
const ipNum = (ipParts[0] << 24) | (ipParts[1] << 16) | (ipParts[2] << 8) | ipParts[3];
|
|
149
|
+
|
|
150
|
+
// Calculate network address (IP & ~fullMask)
|
|
151
|
+
const networkNum = ipNum & ~fullMask;
|
|
152
|
+
|
|
153
|
+
// For large ranges, return wildcard patterns
|
|
154
|
+
if (prefix <= 8) {
|
|
155
|
+
return [`${(networkNum >>> 24) & 255}.*.*.*`];
|
|
156
|
+
} else if (prefix <= 16) {
|
|
157
|
+
return [`${(networkNum >>> 24) & 255}.${(networkNum >>> 16) & 255}.*.*`];
|
|
158
|
+
} else if (prefix <= 24) {
|
|
159
|
+
return [`${(networkNum >>> 24) & 255}.${(networkNum >>> 16) & 255}.${(networkNum >>> 8) & 255}.*`];
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// For small ranges, create individual IP patterns
|
|
163
|
+
const patterns = [];
|
|
164
|
+
const maxAddresses = Math.min(256, Math.pow(2, 32 - prefix));
|
|
165
|
+
|
|
166
|
+
for (let i = 0; i < maxAddresses; i++) {
|
|
167
|
+
const currentIpNum = networkNum + i;
|
|
168
|
+
patterns.push(
|
|
169
|
+
`${(currentIpNum >>> 24) & 255}.${(currentIpNum >>> 16) & 255}.${(currentIpNum >>> 8) & 255}.${currentIpNum & 255}`
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return patterns;
|
|
174
|
+
}
|
|
175
|
+
}
|