@push.rocks/smartproxy 15.0.2 → 16.0.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/index.d.ts +10 -4
- package/dist_ts/certificate/index.js +5 -7
- package/dist_ts/certificate/models/certificate-types.d.ts +35 -15
- package/dist_ts/certificate/providers/cert-provisioner.d.ts +41 -15
- package/dist_ts/certificate/providers/cert-provisioner.js +201 -41
- package/dist_ts/forwarding/config/forwarding-types.d.ts +40 -76
- package/dist_ts/forwarding/config/forwarding-types.js +19 -18
- package/dist_ts/forwarding/config/index.d.ts +4 -2
- package/dist_ts/forwarding/config/index.js +5 -3
- package/dist_ts/forwarding/handlers/base-handler.js +3 -1
- package/dist_ts/forwarding/index.d.ts +5 -6
- package/dist_ts/forwarding/index.js +3 -3
- package/dist_ts/http/models/http-types.js +1 -1
- package/dist_ts/http/port80/acme-interfaces.d.ts +30 -0
- package/dist_ts/http/port80/acme-interfaces.js +46 -1
- package/dist_ts/http/port80/port80-handler.d.ts +17 -2
- package/dist_ts/http/port80/port80-handler.js +49 -11
- package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +2 -61
- package/dist_ts/proxies/smart-proxy/models/interfaces.js +5 -4
- package/dist_ts/proxies/smart-proxy/models/route-types.d.ts +118 -4
- package/dist_ts/proxies/smart-proxy/network-proxy-bridge.d.ts +70 -4
- package/dist_ts/proxies/smart-proxy/network-proxy-bridge.js +193 -43
- package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +2 -5
- package/dist_ts/proxies/smart-proxy/route-connection-handler.js +25 -146
- package/dist_ts/proxies/smart-proxy/route-helpers/index.d.ts +7 -0
- package/dist_ts/proxies/smart-proxy/route-helpers/index.js +9 -0
- package/dist_ts/proxies/smart-proxy/route-helpers.d.ts +54 -1
- package/dist_ts/proxies/smart-proxy/route-helpers.js +102 -1
- package/dist_ts/proxies/smart-proxy/route-manager.d.ts +3 -9
- package/dist_ts/proxies/smart-proxy/route-manager.js +3 -115
- package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +72 -10
- package/dist_ts/proxies/smart-proxy/smart-proxy.js +135 -268
- package/dist_ts/proxies/smart-proxy/timeout-manager.js +3 -3
- package/dist_ts/proxies/smart-proxy/utils/index.d.ts +12 -0
- package/dist_ts/proxies/smart-proxy/utils/index.js +19 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers.d.ts +174 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers.js +332 -0
- package/dist_ts/proxies/smart-proxy/utils/route-migration-utils.d.ts +51 -0
- package/dist_ts/proxies/smart-proxy/utils/route-migration-utils.js +124 -0
- package/dist_ts/proxies/smart-proxy/utils/route-patterns.d.ts +131 -0
- package/dist_ts/proxies/smart-proxy/utils/route-patterns.js +217 -0
- package/dist_ts/proxies/smart-proxy/utils/route-utils.d.ts +79 -0
- package/dist_ts/proxies/smart-proxy/utils/route-utils.js +266 -0
- package/dist_ts/proxies/smart-proxy/utils/route-validators.d.ts +73 -0
- package/dist_ts/proxies/smart-proxy/utils/route-validators.js +242 -0
- package/package.json +1 -1
- package/readme.md +139 -111
- package/readme.plan.md +164 -312
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/certificate/index.ts +17 -9
- package/ts/certificate/models/certificate-types.ts +37 -16
- package/ts/certificate/providers/cert-provisioner.ts +247 -54
- package/ts/forwarding/config/forwarding-types.ts +79 -107
- package/ts/forwarding/config/index.ts +4 -2
- package/ts/forwarding/handlers/base-handler.ts +4 -2
- package/ts/forwarding/index.ts +3 -2
- package/ts/http/models/http-types.ts +0 -1
- package/ts/http/port80/acme-interfaces.ts +84 -0
- package/ts/http/port80/port80-handler.ts +61 -15
- package/ts/proxies/smart-proxy/models/interfaces.ts +7 -64
- package/ts/proxies/smart-proxy/models/route-types.ts +152 -22
- package/ts/proxies/smart-proxy/network-proxy-bridge.ts +226 -55
- package/ts/proxies/smart-proxy/route-connection-handler.ts +36 -205
- package/ts/proxies/smart-proxy/route-helpers/index.ts +9 -0
- package/ts/proxies/smart-proxy/route-helpers.ts +165 -11
- package/ts/proxies/smart-proxy/route-manager.ts +3 -130
- package/ts/proxies/smart-proxy/smart-proxy.ts +157 -329
- package/ts/proxies/smart-proxy/timeout-manager.ts +2 -2
- package/ts/proxies/smart-proxy/utils/index.ts +40 -0
- package/ts/proxies/smart-proxy/utils/route-helpers.ts +455 -0
- package/ts/proxies/smart-proxy/utils/route-migration-utils.ts +165 -0
- package/ts/proxies/smart-proxy/utils/route-patterns.ts +309 -0
- package/ts/proxies/smart-proxy/utils/route-utils.ts +330 -0
- package/ts/proxies/smart-proxy/utils/route-validators.ts +269 -0
- package/ts/forwarding/config/domain-config.ts +0 -28
- package/ts/forwarding/config/domain-manager.ts +0 -283
- package/ts/proxies/smart-proxy/connection-handler.ts +0 -1240
- package/ts/proxies/smart-proxy/port-range-manager.ts +0 -211
- /package/ts/proxies/smart-proxy/{domain-config-manager.ts → domain-config-manager.ts.bak} +0 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route Validators
|
|
3
|
+
*
|
|
4
|
+
* This file provides utility functions for validating route configurations.
|
|
5
|
+
* These validators help ensure that route configurations are valid and correctly structured.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { IRouteConfig, IRouteMatch, IRouteAction, TPortRange } from '../models/route-types.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Validates a port range or port number
|
|
12
|
+
* @param port Port number or port range
|
|
13
|
+
* @returns True if valid, false otherwise
|
|
14
|
+
*/
|
|
15
|
+
export function isValidPort(port: TPortRange): boolean {
|
|
16
|
+
if (typeof port === 'number') {
|
|
17
|
+
return port > 0 && port < 65536; // Valid port range is 1-65535
|
|
18
|
+
} else if (Array.isArray(port)) {
|
|
19
|
+
return port.every(p => typeof p === 'number' && p > 0 && p < 65536);
|
|
20
|
+
}
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Validates a domain string
|
|
26
|
+
* @param domain Domain string to validate
|
|
27
|
+
* @returns True if valid, false otherwise
|
|
28
|
+
*/
|
|
29
|
+
export function isValidDomain(domain: string): boolean {
|
|
30
|
+
// Basic domain validation regex - allows wildcards (*.example.com)
|
|
31
|
+
const domainRegex = /^(\*\.)?([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/;
|
|
32
|
+
return domainRegex.test(domain);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Validates a route match configuration
|
|
37
|
+
* @param match Route match configuration to validate
|
|
38
|
+
* @returns { valid: boolean, errors: string[] } Validation result
|
|
39
|
+
*/
|
|
40
|
+
export function validateRouteMatch(match: IRouteMatch): { valid: boolean; errors: string[] } {
|
|
41
|
+
const errors: string[] = [];
|
|
42
|
+
|
|
43
|
+
// Validate ports
|
|
44
|
+
if (match.ports !== undefined) {
|
|
45
|
+
if (!isValidPort(match.ports)) {
|
|
46
|
+
errors.push('Invalid port number or port range in match.ports');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Validate domains
|
|
51
|
+
if (match.domains !== undefined) {
|
|
52
|
+
if (typeof match.domains === 'string') {
|
|
53
|
+
if (!isValidDomain(match.domains)) {
|
|
54
|
+
errors.push(`Invalid domain format: ${match.domains}`);
|
|
55
|
+
}
|
|
56
|
+
} else if (Array.isArray(match.domains)) {
|
|
57
|
+
for (const domain of match.domains) {
|
|
58
|
+
if (!isValidDomain(domain)) {
|
|
59
|
+
errors.push(`Invalid domain format: ${domain}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
errors.push('Domains must be a string or an array of strings');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Validate path
|
|
68
|
+
if (match.path !== undefined) {
|
|
69
|
+
if (typeof match.path !== 'string' || !match.path.startsWith('/')) {
|
|
70
|
+
errors.push('Path must be a string starting with /');
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
valid: errors.length === 0,
|
|
76
|
+
errors
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Validates a route action configuration
|
|
82
|
+
* @param action Route action configuration to validate
|
|
83
|
+
* @returns { valid: boolean, errors: string[] } Validation result
|
|
84
|
+
*/
|
|
85
|
+
export function validateRouteAction(action: IRouteAction): { valid: boolean; errors: string[] } {
|
|
86
|
+
const errors: string[] = [];
|
|
87
|
+
|
|
88
|
+
// Validate action type
|
|
89
|
+
if (!action.type) {
|
|
90
|
+
errors.push('Action type is required');
|
|
91
|
+
} else if (!['forward', 'redirect', 'static', 'block'].includes(action.type)) {
|
|
92
|
+
errors.push(`Invalid action type: ${action.type}`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Validate target for 'forward' action
|
|
96
|
+
if (action.type === 'forward') {
|
|
97
|
+
if (!action.target) {
|
|
98
|
+
errors.push('Target is required for forward action');
|
|
99
|
+
} else {
|
|
100
|
+
// Validate target host
|
|
101
|
+
if (!action.target.host) {
|
|
102
|
+
errors.push('Target host is required');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Validate target port
|
|
106
|
+
if (!action.target.port || !isValidPort(action.target.port)) {
|
|
107
|
+
errors.push('Valid target port is required');
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Validate TLS options for forward actions
|
|
112
|
+
if (action.tls) {
|
|
113
|
+
if (!['passthrough', 'terminate', 'terminate-and-reencrypt'].includes(action.tls.mode)) {
|
|
114
|
+
errors.push(`Invalid TLS mode: ${action.tls.mode}`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// For termination modes, validate certificate
|
|
118
|
+
if (['terminate', 'terminate-and-reencrypt'].includes(action.tls.mode)) {
|
|
119
|
+
if (action.tls.certificate !== 'auto' &&
|
|
120
|
+
(!action.tls.certificate || !action.tls.certificate.key || !action.tls.certificate.cert)) {
|
|
121
|
+
errors.push('Certificate must be "auto" or an object with key and cert properties');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Validate redirect for 'redirect' action
|
|
128
|
+
if (action.type === 'redirect') {
|
|
129
|
+
if (!action.redirect) {
|
|
130
|
+
errors.push('Redirect configuration is required for redirect action');
|
|
131
|
+
} else {
|
|
132
|
+
if (!action.redirect.to) {
|
|
133
|
+
errors.push('Redirect target (to) is required');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (action.redirect.status &&
|
|
137
|
+
![301, 302, 303, 307, 308].includes(action.redirect.status)) {
|
|
138
|
+
errors.push('Invalid redirect status code');
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Validate static file config for 'static' action
|
|
144
|
+
if (action.type === 'static') {
|
|
145
|
+
if (!action.static) {
|
|
146
|
+
errors.push('Static file configuration is required for static action');
|
|
147
|
+
} else {
|
|
148
|
+
if (!action.static.root) {
|
|
149
|
+
errors.push('Static file root directory is required');
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return {
|
|
155
|
+
valid: errors.length === 0,
|
|
156
|
+
errors
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Validates a complete route configuration
|
|
162
|
+
* @param route Route configuration to validate
|
|
163
|
+
* @returns { valid: boolean, errors: string[] } Validation result
|
|
164
|
+
*/
|
|
165
|
+
export function validateRouteConfig(route: IRouteConfig): { valid: boolean; errors: string[] } {
|
|
166
|
+
const errors: string[] = [];
|
|
167
|
+
|
|
168
|
+
// Check for required properties
|
|
169
|
+
if (!route.match) {
|
|
170
|
+
errors.push('Route match configuration is required');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (!route.action) {
|
|
174
|
+
errors.push('Route action configuration is required');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Validate match configuration
|
|
178
|
+
if (route.match) {
|
|
179
|
+
const matchValidation = validateRouteMatch(route.match);
|
|
180
|
+
if (!matchValidation.valid) {
|
|
181
|
+
errors.push(...matchValidation.errors.map(err => `Match: ${err}`));
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Validate action configuration
|
|
186
|
+
if (route.action) {
|
|
187
|
+
const actionValidation = validateRouteAction(route.action);
|
|
188
|
+
if (!actionValidation.valid) {
|
|
189
|
+
errors.push(...actionValidation.errors.map(err => `Action: ${err}`));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Ensure the route has a unique identifier
|
|
194
|
+
if (!route.id && !route.name) {
|
|
195
|
+
errors.push('Route should have either an id or a name for identification');
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
valid: errors.length === 0,
|
|
200
|
+
errors
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Validate an array of route configurations
|
|
206
|
+
* @param routes Array of route configurations to validate
|
|
207
|
+
* @returns { valid: boolean, errors: { index: number, errors: string[] }[] } Validation result
|
|
208
|
+
*/
|
|
209
|
+
export function validateRoutes(routes: IRouteConfig[]): {
|
|
210
|
+
valid: boolean;
|
|
211
|
+
errors: { index: number; errors: string[] }[]
|
|
212
|
+
} {
|
|
213
|
+
const results: { index: number; errors: string[] }[] = [];
|
|
214
|
+
|
|
215
|
+
routes.forEach((route, index) => {
|
|
216
|
+
const validation = validateRouteConfig(route);
|
|
217
|
+
if (!validation.valid) {
|
|
218
|
+
results.push({
|
|
219
|
+
index,
|
|
220
|
+
errors: validation.errors
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
valid: results.length === 0,
|
|
227
|
+
errors: results
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Check if a route configuration has the required properties for a specific action type
|
|
233
|
+
* @param route Route configuration to check
|
|
234
|
+
* @param actionType Expected action type
|
|
235
|
+
* @returns True if the route has the necessary properties, false otherwise
|
|
236
|
+
*/
|
|
237
|
+
export function hasRequiredPropertiesForAction(route: IRouteConfig, actionType: string): boolean {
|
|
238
|
+
if (!route.action || route.action.type !== actionType) {
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
switch (actionType) {
|
|
243
|
+
case 'forward':
|
|
244
|
+
return !!route.action.target && !!route.action.target.host && !!route.action.target.port;
|
|
245
|
+
case 'redirect':
|
|
246
|
+
return !!route.action.redirect && !!route.action.redirect.to;
|
|
247
|
+
case 'static':
|
|
248
|
+
return !!route.action.static && !!route.action.static.root;
|
|
249
|
+
case 'block':
|
|
250
|
+
return true; // Block action doesn't require additional properties
|
|
251
|
+
default:
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Throws an error if the route config is invalid, returns the config if valid
|
|
258
|
+
* Useful for immediate validation when creating routes
|
|
259
|
+
* @param route Route configuration to validate
|
|
260
|
+
* @returns The validated route configuration
|
|
261
|
+
* @throws Error if the route configuration is invalid
|
|
262
|
+
*/
|
|
263
|
+
export function assertValidRoute(route: IRouteConfig): IRouteConfig {
|
|
264
|
+
const validation = validateRouteConfig(route);
|
|
265
|
+
if (!validation.valid) {
|
|
266
|
+
throw new Error(`Invalid route configuration: ${validation.errors.join(', ')}`);
|
|
267
|
+
}
|
|
268
|
+
return route;
|
|
269
|
+
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { IForwardConfig } from './forwarding-types.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Domain configuration with unified forwarding configuration
|
|
5
|
-
*/
|
|
6
|
-
export interface IDomainConfig {
|
|
7
|
-
// Core properties - domain patterns
|
|
8
|
-
domains: string[];
|
|
9
|
-
|
|
10
|
-
// Unified forwarding configuration
|
|
11
|
-
forwarding: IForwardConfig;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Helper function to create a domain configuration
|
|
16
|
-
*/
|
|
17
|
-
export function createDomainConfig(
|
|
18
|
-
domains: string | string[],
|
|
19
|
-
forwarding: IForwardConfig
|
|
20
|
-
): IDomainConfig {
|
|
21
|
-
// Normalize domains to an array
|
|
22
|
-
const domainArray = Array.isArray(domains) ? domains : [domains];
|
|
23
|
-
|
|
24
|
-
return {
|
|
25
|
-
domains: domainArray,
|
|
26
|
-
forwarding
|
|
27
|
-
};
|
|
28
|
-
}
|
|
@@ -1,283 +0,0 @@
|
|
|
1
|
-
import * as plugins from '../../plugins.js';
|
|
2
|
-
import type { IDomainConfig } from './domain-config.js';
|
|
3
|
-
import { ForwardingHandler } from '../handlers/base-handler.js';
|
|
4
|
-
import { ForwardingHandlerEvents } from './forwarding-types.js';
|
|
5
|
-
import { ForwardingHandlerFactory } from '../factory/forwarding-factory.js';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Events emitted by the DomainManager
|
|
9
|
-
*/
|
|
10
|
-
export enum DomainManagerEvents {
|
|
11
|
-
DOMAIN_ADDED = 'domain-added',
|
|
12
|
-
DOMAIN_REMOVED = 'domain-removed',
|
|
13
|
-
DOMAIN_MATCHED = 'domain-matched',
|
|
14
|
-
DOMAIN_MATCH_FAILED = 'domain-match-failed',
|
|
15
|
-
CERTIFICATE_NEEDED = 'certificate-needed',
|
|
16
|
-
CERTIFICATE_LOADED = 'certificate-loaded',
|
|
17
|
-
ERROR = 'error'
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Manages domains and their forwarding handlers
|
|
22
|
-
*/
|
|
23
|
-
export class DomainManager extends plugins.EventEmitter {
|
|
24
|
-
private domainConfigs: IDomainConfig[] = [];
|
|
25
|
-
private domainHandlers: Map<string, ForwardingHandler> = new Map();
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Create a new DomainManager
|
|
29
|
-
* @param initialDomains Optional initial domain configurations
|
|
30
|
-
*/
|
|
31
|
-
constructor(initialDomains?: IDomainConfig[]) {
|
|
32
|
-
super();
|
|
33
|
-
|
|
34
|
-
if (initialDomains) {
|
|
35
|
-
this.setDomainConfigs(initialDomains);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Set or replace all domain configurations
|
|
41
|
-
* @param configs Array of domain configurations
|
|
42
|
-
*/
|
|
43
|
-
public async setDomainConfigs(configs: IDomainConfig[]): Promise<void> {
|
|
44
|
-
// Clear existing handlers
|
|
45
|
-
this.domainHandlers.clear();
|
|
46
|
-
|
|
47
|
-
// Store new configurations
|
|
48
|
-
this.domainConfigs = [...configs];
|
|
49
|
-
|
|
50
|
-
// Initialize handlers for each domain
|
|
51
|
-
for (const config of this.domainConfigs) {
|
|
52
|
-
await this.createHandlersForDomain(config);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Add a new domain configuration
|
|
58
|
-
* @param config The domain configuration to add
|
|
59
|
-
*/
|
|
60
|
-
public async addDomainConfig(config: IDomainConfig): Promise<void> {
|
|
61
|
-
// Check if any of these domains already exist
|
|
62
|
-
for (const domain of config.domains) {
|
|
63
|
-
if (this.domainHandlers.has(domain)) {
|
|
64
|
-
// Remove existing handler for this domain
|
|
65
|
-
this.domainHandlers.delete(domain);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Add the new configuration
|
|
70
|
-
this.domainConfigs.push(config);
|
|
71
|
-
|
|
72
|
-
// Create handlers for the new domain
|
|
73
|
-
await this.createHandlersForDomain(config);
|
|
74
|
-
|
|
75
|
-
this.emit(DomainManagerEvents.DOMAIN_ADDED, {
|
|
76
|
-
domains: config.domains,
|
|
77
|
-
forwardingType: config.forwarding.type
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Remove a domain configuration
|
|
83
|
-
* @param domain The domain to remove
|
|
84
|
-
* @returns True if the domain was found and removed
|
|
85
|
-
*/
|
|
86
|
-
public removeDomainConfig(domain: string): boolean {
|
|
87
|
-
// Find the config that includes this domain
|
|
88
|
-
const index = this.domainConfigs.findIndex(config =>
|
|
89
|
-
config.domains.includes(domain)
|
|
90
|
-
);
|
|
91
|
-
|
|
92
|
-
if (index === -1) {
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Get the config
|
|
97
|
-
const config = this.domainConfigs[index];
|
|
98
|
-
|
|
99
|
-
// Remove all handlers for this config
|
|
100
|
-
for (const domainName of config.domains) {
|
|
101
|
-
this.domainHandlers.delete(domainName);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Remove the config
|
|
105
|
-
this.domainConfigs.splice(index, 1);
|
|
106
|
-
|
|
107
|
-
this.emit(DomainManagerEvents.DOMAIN_REMOVED, {
|
|
108
|
-
domains: config.domains
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
return true;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Find the handler for a domain
|
|
116
|
-
* @param domain The domain to find a handler for
|
|
117
|
-
* @returns The handler or undefined if no match
|
|
118
|
-
*/
|
|
119
|
-
public findHandlerForDomain(domain: string): ForwardingHandler | undefined {
|
|
120
|
-
// Try exact match
|
|
121
|
-
if (this.domainHandlers.has(domain)) {
|
|
122
|
-
return this.domainHandlers.get(domain);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Try wildcard matches
|
|
126
|
-
const wildcardHandler = this.findWildcardHandler(domain);
|
|
127
|
-
if (wildcardHandler) {
|
|
128
|
-
return wildcardHandler;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// No match found
|
|
132
|
-
return undefined;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Handle a connection for a domain
|
|
137
|
-
* @param domain The domain
|
|
138
|
-
* @param socket The client socket
|
|
139
|
-
* @returns True if the connection was handled
|
|
140
|
-
*/
|
|
141
|
-
public handleConnection(domain: string, socket: plugins.net.Socket): boolean {
|
|
142
|
-
const handler = this.findHandlerForDomain(domain);
|
|
143
|
-
|
|
144
|
-
if (!handler) {
|
|
145
|
-
this.emit(DomainManagerEvents.DOMAIN_MATCH_FAILED, {
|
|
146
|
-
domain,
|
|
147
|
-
remoteAddress: socket.remoteAddress
|
|
148
|
-
});
|
|
149
|
-
return false;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
this.emit(DomainManagerEvents.DOMAIN_MATCHED, {
|
|
153
|
-
domain,
|
|
154
|
-
handlerType: handler.constructor.name,
|
|
155
|
-
remoteAddress: socket.remoteAddress
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
// Handle the connection
|
|
159
|
-
handler.handleConnection(socket);
|
|
160
|
-
return true;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Handle an HTTP request for a domain
|
|
165
|
-
* @param domain The domain
|
|
166
|
-
* @param req The HTTP request
|
|
167
|
-
* @param res The HTTP response
|
|
168
|
-
* @returns True if the request was handled
|
|
169
|
-
*/
|
|
170
|
-
public handleHttpRequest(domain: string, req: plugins.http.IncomingMessage, res: plugins.http.ServerResponse): boolean {
|
|
171
|
-
const handler = this.findHandlerForDomain(domain);
|
|
172
|
-
|
|
173
|
-
if (!handler) {
|
|
174
|
-
this.emit(DomainManagerEvents.DOMAIN_MATCH_FAILED, {
|
|
175
|
-
domain,
|
|
176
|
-
remoteAddress: req.socket.remoteAddress
|
|
177
|
-
});
|
|
178
|
-
return false;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
this.emit(DomainManagerEvents.DOMAIN_MATCHED, {
|
|
182
|
-
domain,
|
|
183
|
-
handlerType: handler.constructor.name,
|
|
184
|
-
remoteAddress: req.socket.remoteAddress
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
// Handle the request
|
|
188
|
-
handler.handleHttpRequest(req, res);
|
|
189
|
-
return true;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Create handlers for a domain configuration
|
|
194
|
-
* @param config The domain configuration
|
|
195
|
-
*/
|
|
196
|
-
private async createHandlersForDomain(config: IDomainConfig): Promise<void> {
|
|
197
|
-
try {
|
|
198
|
-
// Create a handler for this forwarding configuration
|
|
199
|
-
const handler = ForwardingHandlerFactory.createHandler(config.forwarding);
|
|
200
|
-
|
|
201
|
-
// Initialize the handler
|
|
202
|
-
await handler.initialize();
|
|
203
|
-
|
|
204
|
-
// Set up event forwarding
|
|
205
|
-
this.setupHandlerEvents(handler, config);
|
|
206
|
-
|
|
207
|
-
// Store the handler for each domain in the config
|
|
208
|
-
for (const domain of config.domains) {
|
|
209
|
-
this.domainHandlers.set(domain, handler);
|
|
210
|
-
}
|
|
211
|
-
} catch (error) {
|
|
212
|
-
this.emit(DomainManagerEvents.ERROR, {
|
|
213
|
-
domains: config.domains,
|
|
214
|
-
error: error instanceof Error ? error.message : String(error)
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Set up event forwarding from a handler
|
|
221
|
-
* @param handler The handler
|
|
222
|
-
* @param config The domain configuration for this handler
|
|
223
|
-
*/
|
|
224
|
-
private setupHandlerEvents(handler: ForwardingHandler, config: IDomainConfig): void {
|
|
225
|
-
// Forward relevant events
|
|
226
|
-
handler.on(ForwardingHandlerEvents.CERTIFICATE_NEEDED, (data) => {
|
|
227
|
-
this.emit(DomainManagerEvents.CERTIFICATE_NEEDED, {
|
|
228
|
-
...data,
|
|
229
|
-
domains: config.domains
|
|
230
|
-
});
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
handler.on(ForwardingHandlerEvents.CERTIFICATE_LOADED, (data) => {
|
|
234
|
-
this.emit(DomainManagerEvents.CERTIFICATE_LOADED, {
|
|
235
|
-
...data,
|
|
236
|
-
domains: config.domains
|
|
237
|
-
});
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
handler.on(ForwardingHandlerEvents.ERROR, (data) => {
|
|
241
|
-
this.emit(DomainManagerEvents.ERROR, {
|
|
242
|
-
...data,
|
|
243
|
-
domains: config.domains
|
|
244
|
-
});
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Find a handler for a domain using wildcard matching
|
|
250
|
-
* @param domain The domain to find a handler for
|
|
251
|
-
* @returns The handler or undefined if no match
|
|
252
|
-
*/
|
|
253
|
-
private findWildcardHandler(domain: string): ForwardingHandler | undefined {
|
|
254
|
-
// Exact match already checked in findHandlerForDomain
|
|
255
|
-
|
|
256
|
-
// Try subdomain wildcard (*.example.com)
|
|
257
|
-
if (domain.includes('.')) {
|
|
258
|
-
const parts = domain.split('.');
|
|
259
|
-
if (parts.length > 2) {
|
|
260
|
-
const wildcardDomain = `*.${parts.slice(1).join('.')}`;
|
|
261
|
-
if (this.domainHandlers.has(wildcardDomain)) {
|
|
262
|
-
return this.domainHandlers.get(wildcardDomain);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// Try full wildcard
|
|
268
|
-
if (this.domainHandlers.has('*')) {
|
|
269
|
-
return this.domainHandlers.get('*');
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// No match found
|
|
273
|
-
return undefined;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Get all domain configurations
|
|
278
|
-
* @returns Array of domain configurations
|
|
279
|
-
*/
|
|
280
|
-
public getDomainConfigs(): IDomainConfig[] {
|
|
281
|
-
return [...this.domainConfigs];
|
|
282
|
-
}
|
|
283
|
-
}
|