@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
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: '
|
|
6
|
+
version: '13.1.2',
|
|
7
7
|
description: 'A powerful proxy package that effectively handles high traffic, with features such as SSL/TLS support, port proxying, WebSocket handling, dynamic routing with authentication options, and automatic ACME certificate management.'
|
|
8
8
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import type { IAcmeOptions } from '../models/certificate-types.js';
|
|
4
|
+
import { ensureCertificateDirectory } from '../utils/certificate-helpers.js';
|
|
5
|
+
// We'll need to update this import when we move the Port80Handler
|
|
6
|
+
import { Port80Handler } from '../../http/port80/port80-handler.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Factory to create a Port80Handler with common setup.
|
|
10
|
+
* Ensures the certificate store directory exists and instantiates the handler.
|
|
11
|
+
* @param options Port80Handler configuration options
|
|
12
|
+
* @returns A new Port80Handler instance
|
|
13
|
+
*/
|
|
14
|
+
export function buildPort80Handler(
|
|
15
|
+
options: IAcmeOptions
|
|
16
|
+
): Port80Handler {
|
|
17
|
+
if (options.certificateStore) {
|
|
18
|
+
ensureCertificateDirectory(options.certificateStore);
|
|
19
|
+
console.log(`Ensured certificate store directory: ${options.certificateStore}`);
|
|
20
|
+
}
|
|
21
|
+
return new Port80Handler(options);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Creates default ACME options with sensible defaults
|
|
26
|
+
* @param email Account email for ACME provider
|
|
27
|
+
* @param certificateStore Path to store certificates
|
|
28
|
+
* @param useProduction Whether to use production ACME servers
|
|
29
|
+
* @returns Configured ACME options
|
|
30
|
+
*/
|
|
31
|
+
export function createDefaultAcmeOptions(
|
|
32
|
+
email: string,
|
|
33
|
+
certificateStore: string,
|
|
34
|
+
useProduction: boolean = false
|
|
35
|
+
): IAcmeOptions {
|
|
36
|
+
return {
|
|
37
|
+
accountEmail: email,
|
|
38
|
+
enabled: true,
|
|
39
|
+
port: 80,
|
|
40
|
+
useProduction,
|
|
41
|
+
httpsRedirectPort: 443,
|
|
42
|
+
renewThresholdDays: 30,
|
|
43
|
+
renewCheckIntervalHours: 24,
|
|
44
|
+
autoRenew: true,
|
|
45
|
+
certificateStore,
|
|
46
|
+
skipConfiguredCerts: false
|
|
47
|
+
};
|
|
48
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
import type { IAcmeOptions, ICertificateData } from '../models/certificate-types.js';
|
|
3
|
+
import { CertificateEvents } from '../events/certificate-events.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Manages ACME challenges and certificate validation
|
|
7
|
+
*/
|
|
8
|
+
export class AcmeChallengeHandler extends plugins.EventEmitter {
|
|
9
|
+
private options: IAcmeOptions;
|
|
10
|
+
private client: any; // ACME client from plugins
|
|
11
|
+
private pendingChallenges: Map<string, any>;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Creates a new ACME challenge handler
|
|
15
|
+
* @param options ACME configuration options
|
|
16
|
+
*/
|
|
17
|
+
constructor(options: IAcmeOptions) {
|
|
18
|
+
super();
|
|
19
|
+
this.options = options;
|
|
20
|
+
this.pendingChallenges = new Map();
|
|
21
|
+
|
|
22
|
+
// Initialize ACME client if needed
|
|
23
|
+
// This is just a placeholder implementation since we don't use the actual
|
|
24
|
+
// client directly in this implementation - it's handled by Port80Handler
|
|
25
|
+
this.client = null;
|
|
26
|
+
console.log('Created challenge handler with options:',
|
|
27
|
+
options.accountEmail,
|
|
28
|
+
options.useProduction ? 'production' : 'staging'
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Gets or creates the ACME account key
|
|
34
|
+
*/
|
|
35
|
+
private getAccountKey(): Buffer {
|
|
36
|
+
// Implementation details would depend on plugin requirements
|
|
37
|
+
// This is a simplified version
|
|
38
|
+
if (!this.options.certificateStore) {
|
|
39
|
+
throw new Error('Certificate store is required for ACME challenges');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// This is just a placeholder - actual implementation would check for
|
|
43
|
+
// existing account key and create one if needed
|
|
44
|
+
return Buffer.from('account-key-placeholder');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Validates a domain using HTTP-01 challenge
|
|
49
|
+
* @param domain Domain to validate
|
|
50
|
+
* @param challengeToken ACME challenge token
|
|
51
|
+
* @param keyAuthorization Key authorization for the challenge
|
|
52
|
+
*/
|
|
53
|
+
public async handleHttpChallenge(
|
|
54
|
+
domain: string,
|
|
55
|
+
challengeToken: string,
|
|
56
|
+
keyAuthorization: string
|
|
57
|
+
): Promise<void> {
|
|
58
|
+
// Store challenge for response
|
|
59
|
+
this.pendingChallenges.set(challengeToken, keyAuthorization);
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
// Wait for challenge validation - this would normally be handled by the ACME client
|
|
63
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
64
|
+
this.emit(CertificateEvents.CERTIFICATE_ISSUED, {
|
|
65
|
+
domain,
|
|
66
|
+
success: true
|
|
67
|
+
});
|
|
68
|
+
} catch (error) {
|
|
69
|
+
this.emit(CertificateEvents.CERTIFICATE_FAILED, {
|
|
70
|
+
domain,
|
|
71
|
+
error: error instanceof Error ? error.message : String(error),
|
|
72
|
+
isRenewal: false
|
|
73
|
+
});
|
|
74
|
+
throw error;
|
|
75
|
+
} finally {
|
|
76
|
+
// Clean up the challenge
|
|
77
|
+
this.pendingChallenges.delete(challengeToken);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Responds to an HTTP-01 challenge request
|
|
83
|
+
* @param token Challenge token from the request path
|
|
84
|
+
* @returns The key authorization if found
|
|
85
|
+
*/
|
|
86
|
+
public getChallengeResponse(token: string): string | null {
|
|
87
|
+
return this.pendingChallenges.get(token) || null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Checks if a request path is an ACME challenge
|
|
92
|
+
* @param path Request path
|
|
93
|
+
* @returns True if this is an ACME challenge request
|
|
94
|
+
*/
|
|
95
|
+
public isAcmeChallenge(path: string): boolean {
|
|
96
|
+
return path.startsWith('/.well-known/acme-challenge/');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Extracts the challenge token from an ACME challenge path
|
|
101
|
+
* @param path Request path
|
|
102
|
+
* @returns The challenge token if valid
|
|
103
|
+
*/
|
|
104
|
+
public extractChallengeToken(path: string): string | null {
|
|
105
|
+
if (!this.isAcmeChallenge(path)) return null;
|
|
106
|
+
|
|
107
|
+
const parts = path.split('/');
|
|
108
|
+
return parts[parts.length - 1] || null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Certificate-related events emitted by certificate management components
|
|
3
|
+
*/
|
|
4
|
+
export enum CertificateEvents {
|
|
5
|
+
CERTIFICATE_ISSUED = 'certificate-issued',
|
|
6
|
+
CERTIFICATE_RENEWED = 'certificate-renewed',
|
|
7
|
+
CERTIFICATE_FAILED = 'certificate-failed',
|
|
8
|
+
CERTIFICATE_EXPIRING = 'certificate-expiring',
|
|
9
|
+
CERTIFICATE_APPLIED = 'certificate-applied',
|
|
10
|
+
// Events moved from Port80Handler for compatibility
|
|
11
|
+
MANAGER_STARTED = 'manager-started',
|
|
12
|
+
MANAGER_STOPPED = 'manager-stopped',
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Port80Handler-specific events including certificate-related ones
|
|
17
|
+
* @deprecated Use CertificateEvents and HttpEvents instead
|
|
18
|
+
*/
|
|
19
|
+
export enum Port80HandlerEvents {
|
|
20
|
+
CERTIFICATE_ISSUED = 'certificate-issued',
|
|
21
|
+
CERTIFICATE_RENEWED = 'certificate-renewed',
|
|
22
|
+
CERTIFICATE_FAILED = 'certificate-failed',
|
|
23
|
+
CERTIFICATE_EXPIRING = 'certificate-expiring',
|
|
24
|
+
MANAGER_STARTED = 'manager-started',
|
|
25
|
+
MANAGER_STOPPED = 'manager-stopped',
|
|
26
|
+
REQUEST_FORWARDED = 'request-forwarded',
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Certificate provider events
|
|
31
|
+
*/
|
|
32
|
+
export enum CertProvisionerEvents {
|
|
33
|
+
CERTIFICATE_ISSUED = 'certificate',
|
|
34
|
+
CERTIFICATE_RENEWED = 'certificate',
|
|
35
|
+
CERTIFICATE_FAILED = 'certificate-failed'
|
|
36
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Certificate management module for SmartProxy
|
|
3
|
+
* Provides certificate provisioning, storage, and management capabilities
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Certificate types and models
|
|
7
|
+
export * from './models/certificate-types.js';
|
|
8
|
+
|
|
9
|
+
// Certificate events
|
|
10
|
+
export * from './events/certificate-events.js';
|
|
11
|
+
|
|
12
|
+
// Certificate providers
|
|
13
|
+
export * from './providers/cert-provisioner.js';
|
|
14
|
+
|
|
15
|
+
// ACME related exports
|
|
16
|
+
export * from './acme/acme-factory.js';
|
|
17
|
+
export * from './acme/challenge-handler.js';
|
|
18
|
+
|
|
19
|
+
// Certificate utilities
|
|
20
|
+
export * from './utils/certificate-helpers.js';
|
|
21
|
+
|
|
22
|
+
// Certificate storage
|
|
23
|
+
export * from './storage/file-storage.js';
|
|
24
|
+
|
|
25
|
+
// Convenience function to create a certificate provisioner with common settings
|
|
26
|
+
import { CertProvisioner } from './providers/cert-provisioner.js';
|
|
27
|
+
import { buildPort80Handler } from './acme/acme-factory.js';
|
|
28
|
+
import type { IAcmeOptions, IDomainForwardConfig } from './models/certificate-types.js';
|
|
29
|
+
import type { IDomainConfig } from '../forwarding/config/domain-config.js';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Creates a complete certificate provisioning system with default settings
|
|
33
|
+
* @param domainConfigs Domain configurations
|
|
34
|
+
* @param acmeOptions ACME options for certificate provisioning
|
|
35
|
+
* @param networkProxyBridge Bridge to apply certificates to network proxy
|
|
36
|
+
* @param certProvider Optional custom certificate provider
|
|
37
|
+
* @returns Configured CertProvisioner
|
|
38
|
+
*/
|
|
39
|
+
export function createCertificateProvisioner(
|
|
40
|
+
domainConfigs: IDomainConfig[],
|
|
41
|
+
acmeOptions: IAcmeOptions,
|
|
42
|
+
networkProxyBridge: any, // Placeholder until NetworkProxyBridge is migrated
|
|
43
|
+
certProvider?: any // Placeholder until cert provider type is properly defined
|
|
44
|
+
): CertProvisioner {
|
|
45
|
+
// Build the Port80Handler for ACME challenges
|
|
46
|
+
const port80Handler = buildPort80Handler(acmeOptions);
|
|
47
|
+
|
|
48
|
+
// Extract ACME-specific configuration
|
|
49
|
+
const {
|
|
50
|
+
renewThresholdDays = 30,
|
|
51
|
+
renewCheckIntervalHours = 24,
|
|
52
|
+
autoRenew = true,
|
|
53
|
+
domainForwards = []
|
|
54
|
+
} = acmeOptions;
|
|
55
|
+
|
|
56
|
+
// Create and return the certificate provisioner
|
|
57
|
+
return new CertProvisioner(
|
|
58
|
+
domainConfigs,
|
|
59
|
+
port80Handler,
|
|
60
|
+
networkProxyBridge,
|
|
61
|
+
certProvider,
|
|
62
|
+
renewThresholdDays,
|
|
63
|
+
renewCheckIntervalHours,
|
|
64
|
+
autoRenew,
|
|
65
|
+
domainForwards
|
|
66
|
+
);
|
|
67
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Certificate data structure containing all necessary information
|
|
5
|
+
* about a certificate
|
|
6
|
+
*/
|
|
7
|
+
export interface ICertificateData {
|
|
8
|
+
domain: string;
|
|
9
|
+
certificate: string;
|
|
10
|
+
privateKey: string;
|
|
11
|
+
expiryDate: Date;
|
|
12
|
+
// Optional source and renewal information for event emissions
|
|
13
|
+
source?: 'static' | 'http01' | 'dns01';
|
|
14
|
+
isRenewal?: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Certificates pair (private and public keys)
|
|
19
|
+
*/
|
|
20
|
+
export interface ICertificates {
|
|
21
|
+
privateKey: string;
|
|
22
|
+
publicKey: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Certificate failure payload type
|
|
27
|
+
*/
|
|
28
|
+
export interface ICertificateFailure {
|
|
29
|
+
domain: string;
|
|
30
|
+
error: string;
|
|
31
|
+
isRenewal: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Certificate expiry payload type
|
|
36
|
+
*/
|
|
37
|
+
export interface ICertificateExpiring {
|
|
38
|
+
domain: string;
|
|
39
|
+
expiryDate: Date;
|
|
40
|
+
daysRemaining: number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Domain forwarding configuration
|
|
45
|
+
*/
|
|
46
|
+
export interface IForwardConfig {
|
|
47
|
+
ip: string;
|
|
48
|
+
port: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Domain-specific forwarding configuration for ACME challenges
|
|
53
|
+
*/
|
|
54
|
+
export interface IDomainForwardConfig {
|
|
55
|
+
domain: string;
|
|
56
|
+
forwardConfig?: IForwardConfig;
|
|
57
|
+
acmeForwardConfig?: IForwardConfig;
|
|
58
|
+
sslRedirect?: boolean;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Domain configuration options
|
|
63
|
+
*/
|
|
64
|
+
export interface IDomainOptions {
|
|
65
|
+
domainName: string;
|
|
66
|
+
sslRedirect: boolean; // if true redirects the request to port 443
|
|
67
|
+
acmeMaintenance: boolean; // tries to always have a valid cert for this domain
|
|
68
|
+
forward?: IForwardConfig; // forwards all http requests to that target
|
|
69
|
+
acmeForward?: IForwardConfig; // forwards letsencrypt requests to this config
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Unified ACME configuration options used across proxies and handlers
|
|
74
|
+
*/
|
|
75
|
+
export interface IAcmeOptions {
|
|
76
|
+
accountEmail?: string; // Email for Let's Encrypt account
|
|
77
|
+
enabled?: boolean; // Whether ACME is enabled
|
|
78
|
+
port?: number; // Port to listen on for ACME challenges (default: 80)
|
|
79
|
+
useProduction?: boolean; // Use production environment (default: staging)
|
|
80
|
+
httpsRedirectPort?: number; // Port to redirect HTTP requests to HTTPS (default: 443)
|
|
81
|
+
renewThresholdDays?: number; // Days before expiry to renew certificates
|
|
82
|
+
renewCheckIntervalHours?: number; // How often to check for renewals (in hours)
|
|
83
|
+
autoRenew?: boolean; // Whether to automatically renew certificates
|
|
84
|
+
certificateStore?: string; // Directory to store certificates
|
|
85
|
+
skipConfiguredCerts?: boolean; // Skip domains with existing certificates
|
|
86
|
+
domainForwards?: IDomainForwardConfig[]; // Domain-specific forwarding configs
|
|
87
|
+
}
|
|
88
|
+
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
import type { IDomainConfig } from '../../forwarding/config/domain-config.js';
|
|
3
|
+
import type { ICertificateData, IDomainForwardConfig, IDomainOptions } from '../models/certificate-types.js';
|
|
4
|
+
import { Port80HandlerEvents, CertProvisionerEvents } from '../events/certificate-events.js';
|
|
5
|
+
import { Port80Handler } from '../../http/port80/port80-handler.js';
|
|
6
|
+
// We need to define this interface until we migrate NetworkProxyBridge
|
|
7
|
+
interface INetworkProxyBridge {
|
|
8
|
+
applyExternalCertificate(certData: ICertificateData): void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// This will be imported after NetworkProxyBridge is migrated
|
|
12
|
+
// import type { NetworkProxyBridge } from '../../proxies/smart-proxy/network-proxy-bridge.js';
|
|
13
|
+
|
|
14
|
+
// For backward compatibility
|
|
15
|
+
export type TSmartProxyCertProvisionObject = plugins.tsclass.network.ICert | 'http01';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Type for static certificate provisioning
|
|
19
|
+
*/
|
|
20
|
+
export type TCertProvisionObject = plugins.tsclass.network.ICert | 'http01' | 'dns01';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* CertProvisioner manages certificate provisioning and renewal workflows,
|
|
24
|
+
* unifying static certificates and HTTP-01 challenges via Port80Handler.
|
|
25
|
+
*/
|
|
26
|
+
export class CertProvisioner extends plugins.EventEmitter {
|
|
27
|
+
private domainConfigs: IDomainConfig[];
|
|
28
|
+
private port80Handler: Port80Handler;
|
|
29
|
+
private networkProxyBridge: INetworkProxyBridge;
|
|
30
|
+
private certProvisionFunction?: (domain: string) => Promise<TCertProvisionObject>;
|
|
31
|
+
private forwardConfigs: IDomainForwardConfig[];
|
|
32
|
+
private renewThresholdDays: number;
|
|
33
|
+
private renewCheckIntervalHours: number;
|
|
34
|
+
private autoRenew: boolean;
|
|
35
|
+
private renewManager?: plugins.taskbuffer.TaskManager;
|
|
36
|
+
// Track provisioning type per domain
|
|
37
|
+
private provisionMap: Map<string, 'http01' | 'dns01' | 'static'>;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @param domainConfigs Array of domain configuration objects
|
|
41
|
+
* @param port80Handler HTTP-01 challenge handler instance
|
|
42
|
+
* @param networkProxyBridge Bridge for applying external certificates
|
|
43
|
+
* @param certProvider Optional callback returning a static cert or 'http01'
|
|
44
|
+
* @param renewThresholdDays Days before expiry to trigger renewals
|
|
45
|
+
* @param renewCheckIntervalHours Interval in hours to check for renewals
|
|
46
|
+
* @param autoRenew Whether to automatically schedule renewals
|
|
47
|
+
* @param forwardConfigs Domain forwarding configurations for ACME challenges
|
|
48
|
+
*/
|
|
49
|
+
constructor(
|
|
50
|
+
domainConfigs: IDomainConfig[],
|
|
51
|
+
port80Handler: Port80Handler,
|
|
52
|
+
networkProxyBridge: INetworkProxyBridge,
|
|
53
|
+
certProvider?: (domain: string) => Promise<TCertProvisionObject>,
|
|
54
|
+
renewThresholdDays: number = 30,
|
|
55
|
+
renewCheckIntervalHours: number = 24,
|
|
56
|
+
autoRenew: boolean = true,
|
|
57
|
+
forwardConfigs: IDomainForwardConfig[] = []
|
|
58
|
+
) {
|
|
59
|
+
super();
|
|
60
|
+
this.domainConfigs = domainConfigs;
|
|
61
|
+
this.port80Handler = port80Handler;
|
|
62
|
+
this.networkProxyBridge = networkProxyBridge;
|
|
63
|
+
this.certProvisionFunction = certProvider;
|
|
64
|
+
this.renewThresholdDays = renewThresholdDays;
|
|
65
|
+
this.renewCheckIntervalHours = renewCheckIntervalHours;
|
|
66
|
+
this.autoRenew = autoRenew;
|
|
67
|
+
this.provisionMap = new Map();
|
|
68
|
+
this.forwardConfigs = forwardConfigs;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Start initial provisioning and schedule renewals.
|
|
73
|
+
*/
|
|
74
|
+
public async start(): Promise<void> {
|
|
75
|
+
// Subscribe to Port80Handler certificate events
|
|
76
|
+
this.setupEventSubscriptions();
|
|
77
|
+
|
|
78
|
+
// Apply external forwarding for ACME challenges
|
|
79
|
+
this.setupForwardingConfigs();
|
|
80
|
+
|
|
81
|
+
// Initial provisioning for all domains
|
|
82
|
+
await this.provisionAllDomains();
|
|
83
|
+
|
|
84
|
+
// Schedule renewals if enabled
|
|
85
|
+
if (this.autoRenew) {
|
|
86
|
+
this.scheduleRenewals();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Set up event subscriptions for certificate events
|
|
92
|
+
*/
|
|
93
|
+
private setupEventSubscriptions(): void {
|
|
94
|
+
// We need to reimplement subscribeToPort80Handler here
|
|
95
|
+
this.port80Handler.on(Port80HandlerEvents.CERTIFICATE_ISSUED, (data: ICertificateData) => {
|
|
96
|
+
this.emit(CertProvisionerEvents.CERTIFICATE_ISSUED, { ...data, source: 'http01', isRenewal: false });
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
this.port80Handler.on(Port80HandlerEvents.CERTIFICATE_RENEWED, (data: ICertificateData) => {
|
|
100
|
+
this.emit(CertProvisionerEvents.CERTIFICATE_RENEWED, { ...data, source: 'http01', isRenewal: true });
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
this.port80Handler.on(Port80HandlerEvents.CERTIFICATE_FAILED, (error) => {
|
|
104
|
+
this.emit(CertProvisionerEvents.CERTIFICATE_FAILED, error);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Set up forwarding configurations for the Port80Handler
|
|
110
|
+
*/
|
|
111
|
+
private setupForwardingConfigs(): void {
|
|
112
|
+
for (const config of this.forwardConfigs) {
|
|
113
|
+
const domainOptions: IDomainOptions = {
|
|
114
|
+
domainName: config.domain,
|
|
115
|
+
sslRedirect: config.sslRedirect || false,
|
|
116
|
+
acmeMaintenance: false,
|
|
117
|
+
forward: config.forwardConfig,
|
|
118
|
+
acmeForward: config.acmeForwardConfig
|
|
119
|
+
};
|
|
120
|
+
this.port80Handler.addDomain(domainOptions);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Provision certificates for all configured domains
|
|
126
|
+
*/
|
|
127
|
+
private async provisionAllDomains(): Promise<void> {
|
|
128
|
+
const domains = this.domainConfigs.flatMap(cfg => cfg.domains);
|
|
129
|
+
|
|
130
|
+
for (const domain of domains) {
|
|
131
|
+
await this.provisionDomain(domain);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Provision a certificate for a single domain
|
|
137
|
+
* @param domain Domain to provision
|
|
138
|
+
*/
|
|
139
|
+
private async provisionDomain(domain: string): Promise<void> {
|
|
140
|
+
const isWildcard = domain.includes('*');
|
|
141
|
+
let provision: TCertProvisionObject = 'http01';
|
|
142
|
+
|
|
143
|
+
// Try to get a certificate from the provision function
|
|
144
|
+
if (this.certProvisionFunction) {
|
|
145
|
+
try {
|
|
146
|
+
provision = await this.certProvisionFunction(domain);
|
|
147
|
+
} catch (err) {
|
|
148
|
+
console.error(`certProvider error for ${domain}:`, err);
|
|
149
|
+
}
|
|
150
|
+
} else if (isWildcard) {
|
|
151
|
+
// No certProvider: cannot handle wildcard without DNS-01 support
|
|
152
|
+
console.warn(`Skipping wildcard domain without certProvisionFunction: ${domain}`);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Handle different provisioning methods
|
|
157
|
+
if (provision === 'http01') {
|
|
158
|
+
if (isWildcard) {
|
|
159
|
+
console.warn(`Skipping HTTP-01 for wildcard domain: ${domain}`);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
this.provisionMap.set(domain, 'http01');
|
|
164
|
+
this.port80Handler.addDomain({
|
|
165
|
+
domainName: domain,
|
|
166
|
+
sslRedirect: true,
|
|
167
|
+
acmeMaintenance: true
|
|
168
|
+
});
|
|
169
|
+
} else if (provision === 'dns01') {
|
|
170
|
+
// DNS-01 challenges would be handled by the certProvisionFunction
|
|
171
|
+
this.provisionMap.set(domain, 'dns01');
|
|
172
|
+
// DNS-01 handling would go here if implemented
|
|
173
|
+
} else {
|
|
174
|
+
// Static certificate (e.g., DNS-01 provisioned or user-provided)
|
|
175
|
+
this.provisionMap.set(domain, 'static');
|
|
176
|
+
const certObj = provision as plugins.tsclass.network.ICert;
|
|
177
|
+
const certData: ICertificateData = {
|
|
178
|
+
domain: certObj.domainName,
|
|
179
|
+
certificate: certObj.publicKey,
|
|
180
|
+
privateKey: certObj.privateKey,
|
|
181
|
+
expiryDate: new Date(certObj.validUntil),
|
|
182
|
+
source: 'static',
|
|
183
|
+
isRenewal: false
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
this.networkProxyBridge.applyExternalCertificate(certData);
|
|
187
|
+
this.emit(CertProvisionerEvents.CERTIFICATE_ISSUED, certData);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Schedule certificate renewals using a task manager
|
|
193
|
+
*/
|
|
194
|
+
private scheduleRenewals(): void {
|
|
195
|
+
this.renewManager = new plugins.taskbuffer.TaskManager();
|
|
196
|
+
|
|
197
|
+
const renewTask = new plugins.taskbuffer.Task({
|
|
198
|
+
name: 'CertificateRenewals',
|
|
199
|
+
taskFunction: async () => await this.performRenewals()
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
const hours = this.renewCheckIntervalHours;
|
|
203
|
+
const cronExpr = `0 0 */${hours} * * *`;
|
|
204
|
+
|
|
205
|
+
this.renewManager.addAndScheduleTask(renewTask, cronExpr);
|
|
206
|
+
this.renewManager.start();
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Perform renewals for all domains that need it
|
|
211
|
+
*/
|
|
212
|
+
private async performRenewals(): Promise<void> {
|
|
213
|
+
for (const [domain, type] of this.provisionMap.entries()) {
|
|
214
|
+
// Skip wildcard domains for HTTP-01 challenges
|
|
215
|
+
if (domain.includes('*') && type === 'http01') continue;
|
|
216
|
+
|
|
217
|
+
try {
|
|
218
|
+
await this.renewDomain(domain, type);
|
|
219
|
+
} catch (err) {
|
|
220
|
+
console.error(`Renewal error for ${domain}:`, err);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Renew a certificate for a specific domain
|
|
227
|
+
* @param domain Domain to renew
|
|
228
|
+
* @param provisionType Type of provisioning for this domain
|
|
229
|
+
*/
|
|
230
|
+
private async renewDomain(domain: string, provisionType: 'http01' | 'dns01' | 'static'): Promise<void> {
|
|
231
|
+
if (provisionType === 'http01') {
|
|
232
|
+
await this.port80Handler.renewCertificate(domain);
|
|
233
|
+
} else if ((provisionType === 'static' || provisionType === 'dns01') && this.certProvisionFunction) {
|
|
234
|
+
const provision = await this.certProvisionFunction(domain);
|
|
235
|
+
|
|
236
|
+
if (provision !== 'http01' && provision !== 'dns01') {
|
|
237
|
+
const certObj = provision as plugins.tsclass.network.ICert;
|
|
238
|
+
const certData: ICertificateData = {
|
|
239
|
+
domain: certObj.domainName,
|
|
240
|
+
certificate: certObj.publicKey,
|
|
241
|
+
privateKey: certObj.privateKey,
|
|
242
|
+
expiryDate: new Date(certObj.validUntil),
|
|
243
|
+
source: 'static',
|
|
244
|
+
isRenewal: true
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
this.networkProxyBridge.applyExternalCertificate(certData);
|
|
248
|
+
this.emit(CertProvisionerEvents.CERTIFICATE_RENEWED, certData);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Stop all scheduled renewal tasks.
|
|
255
|
+
*/
|
|
256
|
+
public async stop(): Promise<void> {
|
|
257
|
+
if (this.renewManager) {
|
|
258
|
+
this.renewManager.stop();
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Request a certificate on-demand for the given domain.
|
|
264
|
+
* @param domain Domain name to provision
|
|
265
|
+
*/
|
|
266
|
+
public async requestCertificate(domain: string): Promise<void> {
|
|
267
|
+
const isWildcard = domain.includes('*');
|
|
268
|
+
|
|
269
|
+
// Determine provisioning method
|
|
270
|
+
let provision: TCertProvisionObject = 'http01';
|
|
271
|
+
|
|
272
|
+
if (this.certProvisionFunction) {
|
|
273
|
+
provision = await this.certProvisionFunction(domain);
|
|
274
|
+
} else if (isWildcard) {
|
|
275
|
+
// Cannot perform HTTP-01 on wildcard without certProvider
|
|
276
|
+
throw new Error(`Cannot request certificate for wildcard domain without certProvisionFunction: ${domain}`);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (provision === 'http01') {
|
|
280
|
+
if (isWildcard) {
|
|
281
|
+
throw new Error(`Cannot request HTTP-01 certificate for wildcard domain: ${domain}`);
|
|
282
|
+
}
|
|
283
|
+
await this.port80Handler.renewCertificate(domain);
|
|
284
|
+
} else if (provision === 'dns01') {
|
|
285
|
+
// DNS-01 challenges would be handled by external mechanisms
|
|
286
|
+
// This is a placeholder for future implementation
|
|
287
|
+
console.log(`DNS-01 challenge requested for ${domain}`);
|
|
288
|
+
} else {
|
|
289
|
+
// Static certificate (e.g., DNS-01 provisioned) supports wildcards
|
|
290
|
+
const certObj = provision as plugins.tsclass.network.ICert;
|
|
291
|
+
const certData: ICertificateData = {
|
|
292
|
+
domain: certObj.domainName,
|
|
293
|
+
certificate: certObj.publicKey,
|
|
294
|
+
privateKey: certObj.privateKey,
|
|
295
|
+
expiryDate: new Date(certObj.validUntil),
|
|
296
|
+
source: 'static',
|
|
297
|
+
isRenewal: false
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
this.networkProxyBridge.applyExternalCertificate(certData);
|
|
301
|
+
this.emit(CertProvisionerEvents.CERTIFICATE_ISSUED, certData);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Add a new domain for certificate provisioning
|
|
307
|
+
* @param domain Domain to add
|
|
308
|
+
* @param options Domain configuration options
|
|
309
|
+
*/
|
|
310
|
+
public async addDomain(domain: string, options?: {
|
|
311
|
+
sslRedirect?: boolean;
|
|
312
|
+
acmeMaintenance?: boolean;
|
|
313
|
+
}): Promise<void> {
|
|
314
|
+
const domainOptions: IDomainOptions = {
|
|
315
|
+
domainName: domain,
|
|
316
|
+
sslRedirect: options?.sslRedirect || true,
|
|
317
|
+
acmeMaintenance: options?.acmeMaintenance || true
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
this.port80Handler.addDomain(domainOptions);
|
|
321
|
+
await this.provisionDomain(domain);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// For backward compatibility
|
|
326
|
+
export { CertProvisioner as CertificateProvisioner }
|