@push.rocks/smartproxy 19.5.19 → 19.5.21
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/core/models/index.d.ts +2 -0
- package/dist_ts/core/models/index.js +3 -1
- package/dist_ts/core/models/socket-types.d.ts +14 -0
- package/dist_ts/core/models/socket-types.js +15 -0
- package/dist_ts/core/models/wrapped-socket.d.ts +34 -0
- package/dist_ts/core/models/wrapped-socket.js +82 -0
- package/dist_ts/core/routing/index.d.ts +11 -0
- package/dist_ts/core/routing/index.js +17 -0
- package/dist_ts/core/routing/matchers/domain.d.ts +34 -0
- package/dist_ts/core/routing/matchers/domain.js +91 -0
- package/dist_ts/core/routing/matchers/header.d.ts +32 -0
- package/dist_ts/core/routing/matchers/header.js +94 -0
- package/dist_ts/core/routing/matchers/index.d.ts +18 -0
- package/dist_ts/core/routing/matchers/index.js +20 -0
- package/dist_ts/core/routing/matchers/ip.d.ts +53 -0
- package/dist_ts/core/routing/matchers/ip.js +169 -0
- package/dist_ts/core/routing/matchers/path.d.ts +44 -0
- package/dist_ts/core/routing/matchers/path.js +148 -0
- package/dist_ts/core/routing/route-manager.d.ts +88 -0
- package/dist_ts/core/routing/route-manager.js +342 -0
- package/dist_ts/core/routing/route-utils.d.ts +28 -0
- package/dist_ts/core/routing/route-utils.js +67 -0
- package/dist_ts/core/routing/specificity.d.ts +30 -0
- package/dist_ts/core/routing/specificity.js +115 -0
- package/dist_ts/core/routing/types.d.ts +41 -0
- package/dist_ts/core/routing/types.js +5 -0
- package/dist_ts/core/utils/index.d.ts +1 -2
- package/dist_ts/core/utils/index.js +2 -3
- package/dist_ts/core/utils/proxy-protocol.d.ts +45 -0
- package/dist_ts/core/utils/proxy-protocol.js +201 -0
- package/dist_ts/core/utils/route-manager.d.ts +0 -30
- package/dist_ts/core/utils/route-manager.js +6 -47
- package/dist_ts/core/utils/route-utils.d.ts +2 -68
- package/dist_ts/core/utils/route-utils.js +21 -218
- package/dist_ts/core/utils/security-utils.js +4 -4
- package/dist_ts/index.d.ts +2 -5
- package/dist_ts/index.js +5 -11
- package/dist_ts/proxies/http-proxy/http-proxy.d.ts +0 -1
- package/dist_ts/proxies/http-proxy/http-proxy.js +15 -60
- package/dist_ts/proxies/http-proxy/models/types.d.ts +0 -90
- package/dist_ts/proxies/http-proxy/models/types.js +1 -242
- package/dist_ts/proxies/http-proxy/request-handler.d.ts +3 -5
- package/dist_ts/proxies/http-proxy/request-handler.js +20 -171
- package/dist_ts/proxies/http-proxy/websocket-handler.d.ts +2 -5
- package/dist_ts/proxies/http-proxy/websocket-handler.js +15 -23
- package/dist_ts/proxies/index.d.ts +2 -2
- package/dist_ts/proxies/index.js +4 -3
- package/dist_ts/proxies/smart-proxy/connection-manager.d.ts +3 -1
- package/dist_ts/proxies/smart-proxy/connection-manager.js +17 -7
- package/dist_ts/proxies/smart-proxy/http-proxy-bridge.d.ts +2 -1
- package/dist_ts/proxies/smart-proxy/http-proxy-bridge.js +5 -2
- package/dist_ts/proxies/smart-proxy/index.d.ts +1 -1
- package/dist_ts/proxies/smart-proxy/index.js +2 -2
- package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +7 -2
- package/dist_ts/proxies/smart-proxy/models/route-types.d.ts +1 -0
- package/dist_ts/proxies/smart-proxy/models/route-types.js +1 -1
- package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +1 -1
- package/dist_ts/proxies/smart-proxy/route-connection-handler.js +155 -35
- package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +1 -1
- package/dist_ts/proxies/smart-proxy/smart-proxy.js +15 -4
- package/dist_ts/proxies/smart-proxy/utils/route-utils.js +10 -43
- package/dist_ts/routing/router/http-router.d.ts +89 -0
- package/dist_ts/routing/router/http-router.js +205 -0
- package/dist_ts/routing/router/index.d.ts +2 -5
- package/dist_ts/routing/router/index.js +3 -4
- package/package.json +1 -1
- package/readme.delete.md +187 -0
- package/readme.hints.md +196 -1
- package/readme.plan.md +625 -0
- package/readme.proxy-chain-summary.md +112 -0
- package/readme.proxy-protocol-example.md +462 -0
- package/readme.proxy-protocol.md +415 -0
- package/readme.routing.md +341 -0
- package/ts/core/models/index.ts +2 -0
- package/ts/core/models/socket-types.ts +21 -0
- package/ts/core/models/wrapped-socket.ts +99 -0
- package/ts/core/routing/index.ts +21 -0
- package/ts/core/routing/matchers/domain.ts +119 -0
- package/ts/core/routing/matchers/header.ts +120 -0
- package/ts/core/routing/matchers/index.ts +22 -0
- package/ts/core/routing/matchers/ip.ts +207 -0
- package/ts/core/routing/matchers/path.ts +184 -0
- package/ts/core/{utils → routing}/route-manager.ts +7 -57
- package/ts/core/routing/route-utils.ts +88 -0
- package/ts/core/routing/specificity.ts +141 -0
- package/ts/core/routing/types.ts +49 -0
- package/ts/core/utils/index.ts +1 -2
- package/ts/core/utils/proxy-protocol.ts +246 -0
- package/ts/core/utils/security-utils.ts +3 -7
- package/ts/index.ts +4 -14
- package/ts/proxies/http-proxy/http-proxy.ts +13 -68
- package/ts/proxies/http-proxy/models/types.ts +0 -324
- package/ts/proxies/http-proxy/request-handler.ts +15 -186
- package/ts/proxies/http-proxy/websocket-handler.ts +15 -26
- package/ts/proxies/index.ts +3 -2
- package/ts/proxies/smart-proxy/connection-manager.ts +17 -7
- package/ts/proxies/smart-proxy/http-proxy-bridge.ts +6 -2
- package/ts/proxies/smart-proxy/index.ts +1 -1
- package/ts/proxies/smart-proxy/models/interfaces.ts +9 -2
- package/ts/proxies/smart-proxy/models/route-types.ts +3 -0
- package/ts/proxies/smart-proxy/route-connection-handler.ts +173 -42
- package/ts/proxies/smart-proxy/smart-proxy.ts +15 -3
- package/ts/proxies/smart-proxy/utils/route-utils.ts +11 -49
- package/ts/routing/router/http-router.ts +266 -0
- package/ts/routing/router/index.ts +3 -8
- package/readme.problems.md +0 -170
- package/ts/core/utils/route-utils.ts +0 -312
- package/ts/proxies/smart-proxy/route-manager.ts +0 -554
- package/ts/routing/router/proxy-router.ts +0 -437
- package/ts/routing/router/route-router.ts +0 -482
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IpMatcher provides comprehensive IP address matching functionality
|
|
3
|
+
* Supporting exact matches, CIDR notation, ranges, and wildcards
|
|
4
|
+
*/
|
|
5
|
+
export class IpMatcher {
|
|
6
|
+
/**
|
|
7
|
+
* Check if a value is a valid IPv4 address
|
|
8
|
+
*/
|
|
9
|
+
static isValidIpv4(ip) {
|
|
10
|
+
const parts = ip.split('.');
|
|
11
|
+
if (parts.length !== 4)
|
|
12
|
+
return false;
|
|
13
|
+
return parts.every(part => {
|
|
14
|
+
const num = parseInt(part, 10);
|
|
15
|
+
return !isNaN(num) && num >= 0 && num <= 255 && part === num.toString();
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Check if a value is a valid IPv6 address (simplified check)
|
|
20
|
+
*/
|
|
21
|
+
static isValidIpv6(ip) {
|
|
22
|
+
// Basic IPv6 validation - can be enhanced
|
|
23
|
+
const ipv6Regex = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|(([0-9a-fA-F]{1,4}:){1,7}|:):|(([0-9a-fA-F]{1,4}:){1,6}|::):[0-9a-fA-F]{1,4})$/;
|
|
24
|
+
return ipv6Regex.test(ip);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Convert IP address to numeric value for comparison
|
|
28
|
+
*/
|
|
29
|
+
static ipToNumber(ip) {
|
|
30
|
+
const parts = ip.split('.');
|
|
31
|
+
return parts.reduce((acc, part, index) => {
|
|
32
|
+
return acc + (parseInt(part, 10) << (8 * (3 - index)));
|
|
33
|
+
}, 0);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Match an IP against a CIDR notation pattern
|
|
37
|
+
*/
|
|
38
|
+
static matchCidr(cidr, ip) {
|
|
39
|
+
const [range, bits] = cidr.split('/');
|
|
40
|
+
if (!bits || !this.isValidIpv4(range) || !this.isValidIpv4(ip)) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
const rangeMask = parseInt(bits, 10);
|
|
44
|
+
if (isNaN(rangeMask) || rangeMask < 0 || rangeMask > 32) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
const rangeNum = this.ipToNumber(range);
|
|
48
|
+
const ipNum = this.ipToNumber(ip);
|
|
49
|
+
const mask = (-1 << (32 - rangeMask)) >>> 0;
|
|
50
|
+
return (rangeNum & mask) === (ipNum & mask);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Match an IP against a wildcard pattern
|
|
54
|
+
*/
|
|
55
|
+
static matchWildcard(pattern, ip) {
|
|
56
|
+
if (!this.isValidIpv4(ip))
|
|
57
|
+
return false;
|
|
58
|
+
const patternParts = pattern.split('.');
|
|
59
|
+
const ipParts = ip.split('.');
|
|
60
|
+
if (patternParts.length !== 4)
|
|
61
|
+
return false;
|
|
62
|
+
return patternParts.every((part, index) => {
|
|
63
|
+
if (part === '*')
|
|
64
|
+
return true;
|
|
65
|
+
return part === ipParts[index];
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Match an IP against a range (e.g., "192.168.1.1-192.168.1.100")
|
|
70
|
+
*/
|
|
71
|
+
static matchRange(range, ip) {
|
|
72
|
+
const [start, end] = range.split('-').map(s => s.trim());
|
|
73
|
+
if (!start || !end || !this.isValidIpv4(start) || !this.isValidIpv4(end) || !this.isValidIpv4(ip)) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
const startNum = this.ipToNumber(start);
|
|
77
|
+
const endNum = this.ipToNumber(end);
|
|
78
|
+
const ipNum = this.ipToNumber(ip);
|
|
79
|
+
return ipNum >= startNum && ipNum <= endNum;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Match an IP pattern against an IP address
|
|
83
|
+
* Supports multiple formats:
|
|
84
|
+
* - Exact match: "192.168.1.1"
|
|
85
|
+
* - CIDR: "192.168.1.0/24"
|
|
86
|
+
* - Wildcard: "192.168.1.*"
|
|
87
|
+
* - Range: "192.168.1.1-192.168.1.100"
|
|
88
|
+
*/
|
|
89
|
+
static match(pattern, ip, options = {}) {
|
|
90
|
+
// Handle null/undefined cases
|
|
91
|
+
if (!pattern || !ip) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
// Normalize inputs
|
|
95
|
+
const normalizedPattern = pattern.trim();
|
|
96
|
+
const normalizedIp = ip.trim();
|
|
97
|
+
// Extract IPv4 from IPv6-mapped addresses (::ffff:192.168.1.1)
|
|
98
|
+
const ipv4Match = normalizedIp.match(/::ffff:(\d+\.\d+\.\d+\.\d+)/i);
|
|
99
|
+
const testIp = ipv4Match ? ipv4Match[1] : normalizedIp;
|
|
100
|
+
// Exact match
|
|
101
|
+
if (normalizedPattern === testIp) {
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
// CIDR notation
|
|
105
|
+
if (options.allowCidr !== false && normalizedPattern.includes('/')) {
|
|
106
|
+
return this.matchCidr(normalizedPattern, testIp);
|
|
107
|
+
}
|
|
108
|
+
// Wildcard matching
|
|
109
|
+
if (normalizedPattern.includes('*')) {
|
|
110
|
+
return this.matchWildcard(normalizedPattern, testIp);
|
|
111
|
+
}
|
|
112
|
+
// Range matching
|
|
113
|
+
if (options.allowRanges !== false && normalizedPattern.includes('-')) {
|
|
114
|
+
return this.matchRange(normalizedPattern, testIp);
|
|
115
|
+
}
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Check if an IP is authorized based on allow and block lists
|
|
120
|
+
*/
|
|
121
|
+
static isAuthorized(ip, allowList = [], blockList = []) {
|
|
122
|
+
// If IP is in block list, deny
|
|
123
|
+
if (blockList.some(pattern => this.match(pattern, ip))) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
// If allow list is empty, allow all (except blocked)
|
|
127
|
+
if (allowList.length === 0) {
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
// If allow list exists, IP must match
|
|
131
|
+
return allowList.some(pattern => this.match(pattern, ip));
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Calculate the specificity of an IP pattern
|
|
135
|
+
* Higher values mean more specific patterns
|
|
136
|
+
*/
|
|
137
|
+
static calculateSpecificity(pattern) {
|
|
138
|
+
if (!pattern)
|
|
139
|
+
return 0;
|
|
140
|
+
let score = 0;
|
|
141
|
+
// Exact IPs are most specific
|
|
142
|
+
if (this.isValidIpv4(pattern) || this.isValidIpv6(pattern)) {
|
|
143
|
+
score += 100;
|
|
144
|
+
}
|
|
145
|
+
// CIDR notation
|
|
146
|
+
if (pattern.includes('/')) {
|
|
147
|
+
const [, bits] = pattern.split('/');
|
|
148
|
+
const maskBits = parseInt(bits, 10);
|
|
149
|
+
if (!isNaN(maskBits)) {
|
|
150
|
+
score += maskBits; // Higher mask = more specific
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// Wildcard patterns
|
|
154
|
+
const wildcards = (pattern.match(/\*/g) || []).length;
|
|
155
|
+
score -= wildcards * 20; // More wildcards = less specific
|
|
156
|
+
// Range patterns are somewhat specific
|
|
157
|
+
if (pattern.includes('-')) {
|
|
158
|
+
score += 30;
|
|
159
|
+
}
|
|
160
|
+
return score;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Instance method for interface compliance
|
|
164
|
+
*/
|
|
165
|
+
match(pattern, ip, options) {
|
|
166
|
+
return IpMatcher.match(pattern, ip, options);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaXAuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90cy9jb3JlL3JvdXRpbmcvbWF0Y2hlcnMvaXAudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUE7OztHQUdHO0FBQ0gsTUFBTSxPQUFPLFNBQVM7SUFDcEI7O09BRUc7SUFDSCxNQUFNLENBQUMsV0FBVyxDQUFDLEVBQVU7UUFDM0IsTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUM1QixJQUFJLEtBQUssQ0FBQyxNQUFNLEtBQUssQ0FBQztZQUFFLE9BQU8sS0FBSyxDQUFDO1FBRXJDLE9BQU8sS0FBSyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRTtZQUN4QixNQUFNLEdBQUcsR0FBRyxRQUFRLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQy9CLE9BQU8sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksR0FBRyxJQUFJLElBQUksS0FBSyxHQUFHLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDMUUsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxNQUFNLENBQUMsV0FBVyxDQUFDLEVBQVU7UUFDM0IsMENBQTBDO1FBQzFDLE1BQU0sU0FBUyxHQUFHLDRIQUE0SCxDQUFDO1FBQy9JLE9BQU8sU0FBUyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUM1QixDQUFDO0lBRUQ7O09BRUc7SUFDSyxNQUFNLENBQUMsVUFBVSxDQUFDLEVBQVU7UUFDbEMsTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUM1QixPQUFPLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFHLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxFQUFFO1lBQ3ZDLE9BQU8sR0FBRyxHQUFHLENBQUMsUUFB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
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { IMatcher, IPathMatchResult } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* PathMatcher provides comprehensive path matching functionality
|
|
4
|
+
* Supporting exact matches, wildcards, and parameter extraction
|
|
5
|
+
*/
|
|
6
|
+
export declare class PathMatcher implements IMatcher<IPathMatchResult> {
|
|
7
|
+
/**
|
|
8
|
+
* Convert a path pattern to a regex and extract parameter names
|
|
9
|
+
* Supports:
|
|
10
|
+
* - Exact paths: /api/users
|
|
11
|
+
* - Wildcards: /api/*
|
|
12
|
+
* - Parameters: /api/users/:id
|
|
13
|
+
* - Mixed: /api/users/:id/*
|
|
14
|
+
*/
|
|
15
|
+
private static patternToRegex;
|
|
16
|
+
/**
|
|
17
|
+
* Match a path pattern against a request path
|
|
18
|
+
* @param pattern The pattern to match
|
|
19
|
+
* @param path The request path to test
|
|
20
|
+
* @returns Match result with params and remainder
|
|
21
|
+
*/
|
|
22
|
+
static match(pattern: string, path: string): IPathMatchResult;
|
|
23
|
+
/**
|
|
24
|
+
* Check if a pattern contains parameters or wildcards
|
|
25
|
+
*/
|
|
26
|
+
static isDynamicPattern(pattern: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Calculate the specificity of a path pattern
|
|
29
|
+
* Higher values mean more specific patterns
|
|
30
|
+
*/
|
|
31
|
+
static calculateSpecificity(pattern: string): number;
|
|
32
|
+
/**
|
|
33
|
+
* Find all matching patterns from a list
|
|
34
|
+
* Returns patterns sorted by specificity (most specific first)
|
|
35
|
+
*/
|
|
36
|
+
static findAllMatches(patterns: string[], path: string): Array<{
|
|
37
|
+
pattern: string;
|
|
38
|
+
result: IPathMatchResult;
|
|
39
|
+
}>;
|
|
40
|
+
/**
|
|
41
|
+
* Instance method for interface compliance
|
|
42
|
+
*/
|
|
43
|
+
match(pattern: string, path: string): IPathMatchResult;
|
|
44
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PathMatcher provides comprehensive path matching functionality
|
|
3
|
+
* Supporting exact matches, wildcards, and parameter extraction
|
|
4
|
+
*/
|
|
5
|
+
export class PathMatcher {
|
|
6
|
+
/**
|
|
7
|
+
* Convert a path pattern to a regex and extract parameter names
|
|
8
|
+
* Supports:
|
|
9
|
+
* - Exact paths: /api/users
|
|
10
|
+
* - Wildcards: /api/*
|
|
11
|
+
* - Parameters: /api/users/:id
|
|
12
|
+
* - Mixed: /api/users/:id/*
|
|
13
|
+
*/
|
|
14
|
+
static patternToRegex(pattern) {
|
|
15
|
+
const paramNames = [];
|
|
16
|
+
let regexPattern = pattern;
|
|
17
|
+
// Escape special regex characters except : and *
|
|
18
|
+
regexPattern = regexPattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&');
|
|
19
|
+
// Handle path parameters (:param)
|
|
20
|
+
regexPattern = regexPattern.replace(/:(\w+)/g, (match, paramName) => {
|
|
21
|
+
paramNames.push(paramName);
|
|
22
|
+
return '([^/]+)'; // Match any non-slash characters
|
|
23
|
+
});
|
|
24
|
+
// Handle wildcards
|
|
25
|
+
regexPattern = regexPattern.replace(/\*/g, '(.*)');
|
|
26
|
+
// Ensure the pattern matches from start
|
|
27
|
+
regexPattern = `^${regexPattern}`;
|
|
28
|
+
// If pattern doesn't end with wildcard, ensure it matches to end
|
|
29
|
+
// But only for patterns that don't have parameters or wildcards
|
|
30
|
+
if (!pattern.includes('*') && !pattern.includes(':') && !pattern.endsWith('/')) {
|
|
31
|
+
regexPattern = `${regexPattern}$`;
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
regex: new RegExp(regexPattern),
|
|
35
|
+
paramNames
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Match a path pattern against a request path
|
|
40
|
+
* @param pattern The pattern to match
|
|
41
|
+
* @param path The request path to test
|
|
42
|
+
* @returns Match result with params and remainder
|
|
43
|
+
*/
|
|
44
|
+
static match(pattern, path) {
|
|
45
|
+
// Handle null/undefined cases
|
|
46
|
+
if (!pattern || !path) {
|
|
47
|
+
return { matches: false };
|
|
48
|
+
}
|
|
49
|
+
// Normalize paths (remove trailing slashes unless it's just "/")
|
|
50
|
+
const normalizedPattern = pattern === '/' ? '/' : pattern.replace(/\/$/, '');
|
|
51
|
+
const normalizedPath = path === '/' ? '/' : path.replace(/\/$/, '');
|
|
52
|
+
// Exact match (most common case)
|
|
53
|
+
if (normalizedPattern === normalizedPath) {
|
|
54
|
+
return {
|
|
55
|
+
matches: true,
|
|
56
|
+
pathMatch: normalizedPath,
|
|
57
|
+
pathRemainder: '',
|
|
58
|
+
params: {}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
// Pattern matching (wildcards and parameters)
|
|
62
|
+
const { regex, paramNames } = this.patternToRegex(normalizedPattern);
|
|
63
|
+
const match = normalizedPath.match(regex);
|
|
64
|
+
if (!match) {
|
|
65
|
+
return { matches: false };
|
|
66
|
+
}
|
|
67
|
+
// Extract parameters
|
|
68
|
+
const params = {};
|
|
69
|
+
paramNames.forEach((name, index) => {
|
|
70
|
+
params[name] = match[index + 1];
|
|
71
|
+
});
|
|
72
|
+
// Calculate path match and remainder
|
|
73
|
+
let pathMatch = match[0];
|
|
74
|
+
let pathRemainder = normalizedPath.substring(pathMatch.length);
|
|
75
|
+
// Handle wildcard captures
|
|
76
|
+
if (normalizedPattern.includes('*') && match.length > paramNames.length + 1) {
|
|
77
|
+
const wildcardCapture = match[match.length - 1];
|
|
78
|
+
if (wildcardCapture) {
|
|
79
|
+
pathRemainder = wildcardCapture;
|
|
80
|
+
pathMatch = normalizedPath.substring(0, normalizedPath.length - wildcardCapture.length);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Clean up path match (remove trailing slash if present)
|
|
84
|
+
if (pathMatch !== '/' && pathMatch.endsWith('/')) {
|
|
85
|
+
pathMatch = pathMatch.slice(0, -1);
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
matches: true,
|
|
89
|
+
pathMatch,
|
|
90
|
+
pathRemainder,
|
|
91
|
+
params
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Check if a pattern contains parameters or wildcards
|
|
96
|
+
*/
|
|
97
|
+
static isDynamicPattern(pattern) {
|
|
98
|
+
return pattern.includes(':') || pattern.includes('*');
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Calculate the specificity of a path pattern
|
|
102
|
+
* Higher values mean more specific patterns
|
|
103
|
+
*/
|
|
104
|
+
static calculateSpecificity(pattern) {
|
|
105
|
+
if (!pattern)
|
|
106
|
+
return 0;
|
|
107
|
+
let score = 0;
|
|
108
|
+
// Exact paths are most specific
|
|
109
|
+
if (!this.isDynamicPattern(pattern)) {
|
|
110
|
+
score += 100;
|
|
111
|
+
}
|
|
112
|
+
// Count path segments
|
|
113
|
+
const segments = pattern.split('/').filter(s => s.length > 0);
|
|
114
|
+
score += segments.length * 10;
|
|
115
|
+
// Count static segments (more static = more specific)
|
|
116
|
+
const staticSegments = segments.filter(s => !s.startsWith(':') && s !== '*');
|
|
117
|
+
score += staticSegments.length * 20;
|
|
118
|
+
// Penalize wildcards and parameters
|
|
119
|
+
const wildcards = (pattern.match(/\*/g) || []).length;
|
|
120
|
+
const params = (pattern.match(/:/g) || []).length;
|
|
121
|
+
score -= wildcards * 30; // Wildcards are very generic
|
|
122
|
+
score -= params * 10; // Parameters are somewhat generic
|
|
123
|
+
// Bonus for longer patterns
|
|
124
|
+
score += pattern.length;
|
|
125
|
+
return score;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Find all matching patterns from a list
|
|
129
|
+
* Returns patterns sorted by specificity (most specific first)
|
|
130
|
+
*/
|
|
131
|
+
static findAllMatches(patterns, path) {
|
|
132
|
+
const matches = patterns
|
|
133
|
+
.map(pattern => ({
|
|
134
|
+
pattern,
|
|
135
|
+
result: this.match(pattern, path)
|
|
136
|
+
}))
|
|
137
|
+
.filter(({ result }) => result.matches);
|
|
138
|
+
// Sort by specificity (highest first)
|
|
139
|
+
return matches.sort((a, b) => this.calculateSpecificity(b.pattern) - this.calculateSpecificity(a.pattern));
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Instance method for interface compliance
|
|
143
|
+
*/
|
|
144
|
+
match(pattern, path) {
|
|
145
|
+
return PathMatcher.match(pattern, path);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGF0aC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3RzL2NvcmUvcm91dGluZy9tYXRjaGVycy9wYXRoLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBOzs7R0FHRztBQUNILE1BQU0sT0FBTyxXQUFXO0lBQ3RCOzs7Ozs7O09BT0c7SUFDSyxNQUFNLENBQUMsY0FBYyxDQUFDLE9BQWU7UUFJM0MsTUFBTSxVQUFVLEdBQWEsRUFBRSxDQUFDO1FBQ2hDLElBQUksWUFBWSxHQUFHLE9BQU8sQ0FBQztRQUUzQixpREFBaUQ7UUFDakQsWUFBWSxHQUFHLFlBQVksQ0FBQyxPQUFPLENBQUMsb0JBQW9CLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFFbEUsa0NBQWtDO1FBQ2xDLFlBQVksR0FBRyxZQUFZLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBRSxDQUFDLEtBQUssRUFBRSxTQUFTLEVBQUUsRUFBRTtZQUNsRSxVQUFVLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBQzNCLE9BQU8sU0FBUyxDQUFDLENBQUMsaUNBQWlDO1FBQ3JELENBQUMsQ0FBQyxDQUFDO1FBRUgsbUJBQW1CO1FBQ25CLFlBQVksR0FBRyxZQUFZLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQztRQUVuRCx3Q0FBd0M7UUFDeEMsWUFBWSxHQUFHLElBQUksWUFBWSxFQUFFLENBQUM7UUFFbEMsaUVBQWlFO1FBQ2pFLGdFQUFnRTtRQUNoRSxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDL0UsWUFBWSxHQUFHLEdBQUcsWUFBWSxHQUFHLENBQUM7UUFDcEMsQ0FBQztRQUVELE9BQU87WUFDTCxLQUFLLEVBQUUsSUFBSSxNQUFNLENBQUMs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
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
import type { IRouteConfig, TPortRange, IRouteContext } from '../../proxies/smart-proxy/models/route-types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Result of route lookup
|
|
5
|
+
*/
|
|
6
|
+
export interface IRouteLookupResult {
|
|
7
|
+
route: IRouteConfig;
|
|
8
|
+
params?: Record<string, string>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Logger interface for RouteManager
|
|
12
|
+
*/
|
|
13
|
+
export interface ILogger {
|
|
14
|
+
info: (message: string, ...args: any[]) => void;
|
|
15
|
+
warn: (message: string, ...args: any[]) => void;
|
|
16
|
+
error: (message: string, ...args: any[]) => void;
|
|
17
|
+
debug?: (message: string, ...args: any[]) => void;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Shared RouteManager used by both SmartProxy and NetworkProxy
|
|
21
|
+
*
|
|
22
|
+
* This provides a unified implementation for route management,
|
|
23
|
+
* route matching, and port handling.
|
|
24
|
+
*/
|
|
25
|
+
export declare class SharedRouteManager extends plugins.EventEmitter {
|
|
26
|
+
private routes;
|
|
27
|
+
private portMap;
|
|
28
|
+
private logger;
|
|
29
|
+
private enableDetailedLogging;
|
|
30
|
+
/**
|
|
31
|
+
* Memoization cache for expanded port ranges
|
|
32
|
+
*/
|
|
33
|
+
private portRangeCache;
|
|
34
|
+
constructor(options: {
|
|
35
|
+
logger?: ILogger;
|
|
36
|
+
enableDetailedLogging?: boolean;
|
|
37
|
+
routes?: IRouteConfig[];
|
|
38
|
+
});
|
|
39
|
+
/**
|
|
40
|
+
* Update routes with new configuration
|
|
41
|
+
*/
|
|
42
|
+
updateRoutes(routes?: IRouteConfig[]): void;
|
|
43
|
+
/**
|
|
44
|
+
* Get all routes
|
|
45
|
+
*/
|
|
46
|
+
getRoutes(): IRouteConfig[];
|
|
47
|
+
/**
|
|
48
|
+
* Rebuild the port mapping for fast lookups
|
|
49
|
+
* Also logs information about the ports being listened on
|
|
50
|
+
*/
|
|
51
|
+
private rebuildPortMap;
|
|
52
|
+
/**
|
|
53
|
+
* Expand a port range specification into an array of individual ports
|
|
54
|
+
* Uses caching to improve performance for frequently used port ranges
|
|
55
|
+
*
|
|
56
|
+
* @public - Made public to allow external code to interpret port ranges
|
|
57
|
+
*/
|
|
58
|
+
expandPortRange(portRange: TPortRange): number[];
|
|
59
|
+
/**
|
|
60
|
+
* Get all ports that should be listened on
|
|
61
|
+
* This method automatically infers all required ports from route configurations
|
|
62
|
+
*/
|
|
63
|
+
getListeningPorts(): number[];
|
|
64
|
+
/**
|
|
65
|
+
* Get all routes for a given port
|
|
66
|
+
*/
|
|
67
|
+
getRoutesForPort(port: number): IRouteConfig[];
|
|
68
|
+
/**
|
|
69
|
+
* Find the matching route for a connection
|
|
70
|
+
*/
|
|
71
|
+
findMatchingRoute(context: IRouteContext): IRouteLookupResult | null;
|
|
72
|
+
/**
|
|
73
|
+
* Check if a route matches the given context
|
|
74
|
+
*/
|
|
75
|
+
private matchesRoute;
|
|
76
|
+
/**
|
|
77
|
+
* Validate the route configuration and return any warnings
|
|
78
|
+
*/
|
|
79
|
+
validateConfiguration(): string[];
|
|
80
|
+
/**
|
|
81
|
+
* Check if two route matches are similar (potential conflict)
|
|
82
|
+
*/
|
|
83
|
+
private areMatchesSimilar;
|
|
84
|
+
/**
|
|
85
|
+
* Check if a route is completely shadowed by a higher priority route
|
|
86
|
+
*/
|
|
87
|
+
private isRouteShadowed;
|
|
88
|
+
}
|