@push.rocks/smartproxy 19.5.19 → 19.5.20
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 +0 -2
- package/dist_ts/core/utils/index.js +1 -3
- 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 +15 -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 +6 -2
- package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +1 -1
- package/dist_ts/proxies/smart-proxy/route-connection-handler.js +48 -25
- 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 +189 -1
- package/readme.plan.md +621 -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 +0 -2
- 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 +15 -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 +8 -2
- package/ts/proxies/smart-proxy/route-connection-handler.ts +58 -30
- 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
|
@@ -1,312 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Route matching utilities for SmartProxy components
|
|
3
|
-
*
|
|
4
|
-
* Contains shared logic for domain matching, path matching, and IP matching
|
|
5
|
-
* to be used by different proxy components throughout the system.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Match a domain pattern against a domain
|
|
10
|
-
*
|
|
11
|
-
* @param pattern Domain pattern with optional wildcards (e.g., "*.example.com")
|
|
12
|
-
* @param domain Domain to match against the pattern
|
|
13
|
-
* @returns Whether the domain matches the pattern
|
|
14
|
-
*/
|
|
15
|
-
export function matchDomain(pattern: string, domain: string): boolean {
|
|
16
|
-
// Handle exact match (case-insensitive)
|
|
17
|
-
if (pattern.toLowerCase() === domain.toLowerCase()) {
|
|
18
|
-
return true;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Handle wildcard pattern
|
|
22
|
-
if (pattern.includes('*')) {
|
|
23
|
-
const regexPattern = pattern
|
|
24
|
-
.replace(/\./g, '\\.') // Escape dots
|
|
25
|
-
.replace(/\*/g, '.*'); // Convert * to .*
|
|
26
|
-
|
|
27
|
-
const regex = new RegExp(`^${regexPattern}$`, 'i');
|
|
28
|
-
return regex.test(domain);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Match domains from a route against a given domain
|
|
36
|
-
*
|
|
37
|
-
* @param domains Array or single domain pattern to match against
|
|
38
|
-
* @param domain Domain to match
|
|
39
|
-
* @returns Whether the domain matches any of the patterns
|
|
40
|
-
*/
|
|
41
|
-
export function matchRouteDomain(domains: string | string[] | undefined, domain: string | undefined): boolean {
|
|
42
|
-
// If no domains specified in the route, match all domains
|
|
43
|
-
if (!domains) {
|
|
44
|
-
return true;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// If no domain in the request, can't match domain-specific routes
|
|
48
|
-
if (!domain) {
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const patterns = Array.isArray(domains) ? domains : [domains];
|
|
53
|
-
return patterns.some(pattern => matchDomain(pattern, domain));
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Match a path pattern against a path
|
|
58
|
-
*
|
|
59
|
-
* @param pattern Path pattern with optional wildcards
|
|
60
|
-
* @param path Path to match against the pattern
|
|
61
|
-
* @returns Whether the path matches the pattern
|
|
62
|
-
*/
|
|
63
|
-
export function matchPath(pattern: string, path: string): boolean {
|
|
64
|
-
// Handle exact match
|
|
65
|
-
if (pattern === path) {
|
|
66
|
-
return true;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Handle simple wildcard at the end (like /api/*)
|
|
70
|
-
if (pattern.endsWith('*')) {
|
|
71
|
-
const prefix = pattern.slice(0, -1);
|
|
72
|
-
return path.startsWith(prefix);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Handle more complex wildcard patterns
|
|
76
|
-
if (pattern.includes('*')) {
|
|
77
|
-
const regexPattern = pattern
|
|
78
|
-
.replace(/\./g, '\\.') // Escape dots
|
|
79
|
-
.replace(/\*/g, '.*') // Convert * to .*
|
|
80
|
-
.replace(/\//g, '\\/'); // Escape slashes
|
|
81
|
-
|
|
82
|
-
const regex = new RegExp(`^${regexPattern}$`);
|
|
83
|
-
return regex.test(path);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return false;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Parse CIDR notation into subnet and mask bits
|
|
91
|
-
*
|
|
92
|
-
* @param cidr CIDR string (e.g., "192.168.1.0/24")
|
|
93
|
-
* @returns Object with subnet and bits, or null if invalid
|
|
94
|
-
*/
|
|
95
|
-
export function parseCidr(cidr: string): { subnet: string; bits: number } | null {
|
|
96
|
-
try {
|
|
97
|
-
const [subnet, bitsStr] = cidr.split('/');
|
|
98
|
-
const bits = parseInt(bitsStr, 10);
|
|
99
|
-
|
|
100
|
-
if (isNaN(bits) || bits < 0 || bits > 32) {
|
|
101
|
-
return null;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return { subnet, bits };
|
|
105
|
-
} catch (e) {
|
|
106
|
-
return null;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Convert an IP address to a numeric value
|
|
112
|
-
*
|
|
113
|
-
* @param ip IPv4 address string (e.g., "192.168.1.1")
|
|
114
|
-
* @returns Numeric representation of the IP
|
|
115
|
-
*/
|
|
116
|
-
export function ipToNumber(ip: string): number {
|
|
117
|
-
// Handle IPv6-mapped IPv4 addresses (::ffff:192.168.1.1)
|
|
118
|
-
if (ip.startsWith('::ffff:')) {
|
|
119
|
-
ip = ip.slice(7);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const parts = ip.split('.').map(part => parseInt(part, 10));
|
|
123
|
-
return (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3];
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Match an IP against a CIDR pattern
|
|
128
|
-
*
|
|
129
|
-
* @param cidr CIDR pattern (e.g., "192.168.1.0/24")
|
|
130
|
-
* @param ip IP to match against the pattern
|
|
131
|
-
* @returns Whether the IP is in the CIDR range
|
|
132
|
-
*/
|
|
133
|
-
export function matchIpCidr(cidr: string, ip: string): boolean {
|
|
134
|
-
const parsed = parseCidr(cidr);
|
|
135
|
-
if (!parsed) {
|
|
136
|
-
return false;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
try {
|
|
140
|
-
const { subnet, bits } = parsed;
|
|
141
|
-
|
|
142
|
-
// Normalize IPv6-mapped IPv4 addresses
|
|
143
|
-
const normalizedIp = ip.startsWith('::ffff:') ? ip.substring(7) : ip;
|
|
144
|
-
const normalizedSubnet = subnet.startsWith('::ffff:') ? subnet.substring(7) : subnet;
|
|
145
|
-
|
|
146
|
-
// Convert IP addresses to numeric values
|
|
147
|
-
const ipNum = ipToNumber(normalizedIp);
|
|
148
|
-
const subnetNum = ipToNumber(normalizedSubnet);
|
|
149
|
-
|
|
150
|
-
// Calculate subnet mask
|
|
151
|
-
const maskNum = ~(2 ** (32 - bits) - 1);
|
|
152
|
-
|
|
153
|
-
// Check if IP is in subnet
|
|
154
|
-
return (ipNum & maskNum) === (subnetNum & maskNum);
|
|
155
|
-
} catch (e) {
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Match an IP pattern against an IP
|
|
162
|
-
*
|
|
163
|
-
* @param pattern IP pattern (exact, CIDR, or with wildcards)
|
|
164
|
-
* @param ip IP to match against the pattern
|
|
165
|
-
* @returns Whether the IP matches the pattern
|
|
166
|
-
*/
|
|
167
|
-
export function matchIpPattern(pattern: string, ip: string): boolean {
|
|
168
|
-
// Normalize IPv6-mapped IPv4 addresses
|
|
169
|
-
const normalizedIp = ip.startsWith('::ffff:') ? ip.substring(7) : ip;
|
|
170
|
-
const normalizedPattern = pattern.startsWith('::ffff:') ? pattern.substring(7) : pattern;
|
|
171
|
-
|
|
172
|
-
// Handle exact match with all variations
|
|
173
|
-
if (pattern === ip || normalizedPattern === normalizedIp ||
|
|
174
|
-
pattern === normalizedIp || normalizedPattern === ip) {
|
|
175
|
-
return true;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// Handle "all" wildcard
|
|
179
|
-
if (pattern === '*' || normalizedPattern === '*') {
|
|
180
|
-
return true;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Handle CIDR notation (e.g., 192.168.1.0/24)
|
|
184
|
-
if (pattern.includes('/')) {
|
|
185
|
-
return matchIpCidr(pattern, normalizedIp) ||
|
|
186
|
-
(normalizedPattern !== pattern && matchIpCidr(normalizedPattern, normalizedIp));
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Handle glob pattern (e.g., 192.168.1.*)
|
|
190
|
-
if (pattern.includes('*')) {
|
|
191
|
-
const regexPattern = pattern.replace(/\./g, '\\.').replace(/\*/g, '.*');
|
|
192
|
-
const regex = new RegExp(`^${regexPattern}$`);
|
|
193
|
-
if (regex.test(ip) || regex.test(normalizedIp)) {
|
|
194
|
-
return true;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// If pattern was normalized, also test with normalized pattern
|
|
198
|
-
if (normalizedPattern !== pattern) {
|
|
199
|
-
const normalizedRegexPattern = normalizedPattern.replace(/\./g, '\\.').replace(/\*/g, '.*');
|
|
200
|
-
const normalizedRegex = new RegExp(`^${normalizedRegexPattern}$`);
|
|
201
|
-
return normalizedRegex.test(ip) || normalizedRegex.test(normalizedIp);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
return false;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Match an IP against allowed and blocked IP patterns
|
|
210
|
-
*
|
|
211
|
-
* @param ip IP to check
|
|
212
|
-
* @param ipAllowList Array of allowed IP patterns
|
|
213
|
-
* @param ipBlockList Array of blocked IP patterns
|
|
214
|
-
* @returns Whether the IP is allowed
|
|
215
|
-
*/
|
|
216
|
-
export function isIpAuthorized(
|
|
217
|
-
ip: string,
|
|
218
|
-
ipAllowList: string[] = ['*'],
|
|
219
|
-
ipBlockList: string[] = []
|
|
220
|
-
): boolean {
|
|
221
|
-
// Check blocked IPs first
|
|
222
|
-
if (ipBlockList.length > 0) {
|
|
223
|
-
for (const pattern of ipBlockList) {
|
|
224
|
-
if (matchIpPattern(pattern, ip)) {
|
|
225
|
-
return false; // IP is blocked
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// If there are allowed IPs, check them
|
|
231
|
-
if (ipAllowList.length > 0) {
|
|
232
|
-
// Special case: if '*' is in allowed IPs, all non-blocked IPs are allowed
|
|
233
|
-
if (ipAllowList.includes('*')) {
|
|
234
|
-
return true;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
for (const pattern of ipAllowList) {
|
|
238
|
-
if (matchIpPattern(pattern, ip)) {
|
|
239
|
-
return true; // IP is allowed
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
return false; // IP not in allowed list
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// No allowed IPs specified, so IP is allowed by default
|
|
246
|
-
return true;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* Match an HTTP header pattern against a header value
|
|
251
|
-
*
|
|
252
|
-
* @param pattern Expected header value (string or RegExp)
|
|
253
|
-
* @param value Actual header value
|
|
254
|
-
* @returns Whether the header matches the pattern
|
|
255
|
-
*/
|
|
256
|
-
export function matchHeader(pattern: string | RegExp, value: string): boolean {
|
|
257
|
-
if (typeof pattern === 'string') {
|
|
258
|
-
return pattern === value;
|
|
259
|
-
} else if (pattern instanceof RegExp) {
|
|
260
|
-
return pattern.test(value);
|
|
261
|
-
}
|
|
262
|
-
return false;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Calculate route specificity score
|
|
267
|
-
* Higher score means more specific matching criteria
|
|
268
|
-
*
|
|
269
|
-
* @param match Match criteria to evaluate
|
|
270
|
-
* @returns Numeric specificity score
|
|
271
|
-
*/
|
|
272
|
-
export function calculateRouteSpecificity(match: {
|
|
273
|
-
domains?: string | string[];
|
|
274
|
-
path?: string;
|
|
275
|
-
clientIp?: string[];
|
|
276
|
-
tlsVersion?: string[];
|
|
277
|
-
headers?: Record<string, string | RegExp>;
|
|
278
|
-
}): number {
|
|
279
|
-
let score = 0;
|
|
280
|
-
|
|
281
|
-
// Path is very specific
|
|
282
|
-
if (match.path) {
|
|
283
|
-
// More specific if it doesn't use wildcards
|
|
284
|
-
score += match.path.includes('*') ? 3 : 4;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
// Domain is next most specific
|
|
288
|
-
if (match.domains) {
|
|
289
|
-
const domains = Array.isArray(match.domains) ? match.domains : [match.domains];
|
|
290
|
-
// More domains or more specific domains (without wildcards) increase specificity
|
|
291
|
-
score += domains.length;
|
|
292
|
-
// Add bonus for exact domains (without wildcards)
|
|
293
|
-
score += domains.some(d => !d.includes('*')) ? 1 : 0;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
// Headers are quite specific
|
|
297
|
-
if (match.headers) {
|
|
298
|
-
score += Object.keys(match.headers).length * 2;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
// Client IP adds some specificity
|
|
302
|
-
if (match.clientIp && match.clientIp.length > 0) {
|
|
303
|
-
score += 1;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// TLS version adds minimal specificity
|
|
307
|
-
if (match.tlsVersion && match.tlsVersion.length > 0) {
|
|
308
|
-
score += 1;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
return score;
|
|
312
|
-
}
|