@push.rocks/smartproxy 19.6.13 → 19.6.15
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/utils/log-deduplicator.d.ts +39 -0
- package/dist_ts/core/utils/log-deduplicator.js +297 -0
- package/dist_ts/core/utils/shared-security-manager.d.ts +2 -1
- package/dist_ts/core/utils/shared-security-manager.js +22 -2
- package/dist_ts/proxies/http-proxy/http-proxy.d.ts +1 -0
- package/dist_ts/proxies/http-proxy/http-proxy.js +94 -9
- package/dist_ts/proxies/http-proxy/models/types.d.ts +2 -0
- package/dist_ts/proxies/http-proxy/models/types.js +1 -1
- package/dist_ts/proxies/http-proxy/security-manager.d.ts +42 -1
- package/dist_ts/proxies/http-proxy/security-manager.js +121 -2
- package/dist_ts/proxies/smart-proxy/connection-manager.d.ts +14 -0
- package/dist_ts/proxies/smart-proxy/connection-manager.js +86 -32
- package/dist_ts/proxies/smart-proxy/http-proxy-bridge.js +5 -1
- package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +1 -0
- package/dist_ts/proxies/smart-proxy/route-connection-handler.js +25 -9
- package/dist_ts/proxies/smart-proxy/security-manager.d.ts +9 -0
- package/dist_ts/proxies/smart-proxy/security-manager.js +63 -1
- package/dist_ts/proxies/smart-proxy/smart-proxy.js +4 -1
- package/package.json +1 -1
- package/readme.hints.md +113 -1
- package/readme.plan.md +34 -353
- package/ts/core/utils/log-deduplicator.ts +361 -0
- package/ts/core/utils/shared-security-manager.ts +24 -1
- package/ts/proxies/http-proxy/http-proxy.ts +129 -9
- package/ts/proxies/http-proxy/models/types.ts +4 -0
- package/ts/proxies/http-proxy/security-manager.ts +136 -1
- package/ts/proxies/smart-proxy/connection-manager.ts +113 -36
- package/ts/proxies/smart-proxy/http-proxy-bridge.ts +5 -0
- package/ts/proxies/smart-proxy/models/interfaces.ts +1 -0
- package/ts/proxies/smart-proxy/route-connection-handler.ts +52 -15
- package/ts/proxies/smart-proxy/security-manager.ts +76 -1
- package/ts/proxies/smart-proxy/smart-proxy.ts +4 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log deduplication utility to reduce log spam for repetitive events
|
|
3
|
+
*/
|
|
4
|
+
export declare class LogDeduplicator {
|
|
5
|
+
private globalFlushTimer?;
|
|
6
|
+
private aggregatedEvents;
|
|
7
|
+
private flushInterval;
|
|
8
|
+
private maxBatchSize;
|
|
9
|
+
private rapidEventThreshold;
|
|
10
|
+
private lastRapidCheck;
|
|
11
|
+
constructor(flushInterval?: number);
|
|
12
|
+
/**
|
|
13
|
+
* Log a deduplicated event
|
|
14
|
+
* @param key - Aggregation key (e.g., 'connection-rejected', 'cleanup-batch')
|
|
15
|
+
* @param level - Log level
|
|
16
|
+
* @param message - Log message template
|
|
17
|
+
* @param data - Additional data
|
|
18
|
+
* @param dedupeKey - Deduplication key within the aggregation (e.g., IP address, reason)
|
|
19
|
+
*/
|
|
20
|
+
log(key: string, level: 'info' | 'warn' | 'error' | 'debug', message: string, data?: any, dedupeKey?: string): void;
|
|
21
|
+
/**
|
|
22
|
+
* Flush aggregated events for a specific key
|
|
23
|
+
*/
|
|
24
|
+
flush(key: string): void;
|
|
25
|
+
/**
|
|
26
|
+
* Flush all pending events
|
|
27
|
+
*/
|
|
28
|
+
flushAll(): void;
|
|
29
|
+
private flushConnectionRejections;
|
|
30
|
+
private flushConnectionCleanups;
|
|
31
|
+
private flushConnectionTerminations;
|
|
32
|
+
private flushIPRejections;
|
|
33
|
+
private flushGeneric;
|
|
34
|
+
/**
|
|
35
|
+
* Cleanup and stop deduplication
|
|
36
|
+
*/
|
|
37
|
+
cleanup(): void;
|
|
38
|
+
}
|
|
39
|
+
export declare const connectionLogDeduplicator: LogDeduplicator;
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { logger } from './logger.js';
|
|
2
|
+
/**
|
|
3
|
+
* Log deduplication utility to reduce log spam for repetitive events
|
|
4
|
+
*/
|
|
5
|
+
export class LogDeduplicator {
|
|
6
|
+
constructor(flushInterval) {
|
|
7
|
+
this.aggregatedEvents = new Map();
|
|
8
|
+
this.flushInterval = 5000; // 5 seconds
|
|
9
|
+
this.maxBatchSize = 100;
|
|
10
|
+
this.rapidEventThreshold = 50; // Flush early if this many events in 1 second
|
|
11
|
+
this.lastRapidCheck = Date.now();
|
|
12
|
+
if (flushInterval) {
|
|
13
|
+
this.flushInterval = flushInterval;
|
|
14
|
+
}
|
|
15
|
+
// Set up global periodic flush to ensure logs are emitted regularly
|
|
16
|
+
this.globalFlushTimer = setInterval(() => {
|
|
17
|
+
this.flushAll();
|
|
18
|
+
}, this.flushInterval * 2); // Flush everything every 2x the normal interval
|
|
19
|
+
if (this.globalFlushTimer.unref) {
|
|
20
|
+
this.globalFlushTimer.unref();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Log a deduplicated event
|
|
25
|
+
* @param key - Aggregation key (e.g., 'connection-rejected', 'cleanup-batch')
|
|
26
|
+
* @param level - Log level
|
|
27
|
+
* @param message - Log message template
|
|
28
|
+
* @param data - Additional data
|
|
29
|
+
* @param dedupeKey - Deduplication key within the aggregation (e.g., IP address, reason)
|
|
30
|
+
*/
|
|
31
|
+
log(key, level, message, data, dedupeKey) {
|
|
32
|
+
const eventKey = dedupeKey || message;
|
|
33
|
+
const now = Date.now();
|
|
34
|
+
if (!this.aggregatedEvents.has(key)) {
|
|
35
|
+
this.aggregatedEvents.set(key, {
|
|
36
|
+
key,
|
|
37
|
+
events: new Map(),
|
|
38
|
+
flushTimer: undefined
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
const aggregated = this.aggregatedEvents.get(key);
|
|
42
|
+
if (aggregated.events.has(eventKey)) {
|
|
43
|
+
const event = aggregated.events.get(eventKey);
|
|
44
|
+
event.count++;
|
|
45
|
+
event.lastSeen = now;
|
|
46
|
+
if (data) {
|
|
47
|
+
event.data = { ...event.data, ...data };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
aggregated.events.set(eventKey, {
|
|
52
|
+
level,
|
|
53
|
+
message,
|
|
54
|
+
data,
|
|
55
|
+
count: 1,
|
|
56
|
+
firstSeen: now,
|
|
57
|
+
lastSeen: now
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
// Check for rapid events (many events in short time)
|
|
61
|
+
const totalEvents = Array.from(aggregated.events.values()).reduce((sum, e) => sum + e.count, 0);
|
|
62
|
+
// If we're getting flooded with events, flush more frequently
|
|
63
|
+
if (now - this.lastRapidCheck < 1000 && totalEvents >= this.rapidEventThreshold) {
|
|
64
|
+
this.flush(key);
|
|
65
|
+
this.lastRapidCheck = now;
|
|
66
|
+
}
|
|
67
|
+
else if (aggregated.events.size >= this.maxBatchSize) {
|
|
68
|
+
// Check if we should flush due to size
|
|
69
|
+
this.flush(key);
|
|
70
|
+
}
|
|
71
|
+
else if (!aggregated.flushTimer) {
|
|
72
|
+
// Schedule flush
|
|
73
|
+
aggregated.flushTimer = setTimeout(() => {
|
|
74
|
+
this.flush(key);
|
|
75
|
+
}, this.flushInterval);
|
|
76
|
+
if (aggregated.flushTimer.unref) {
|
|
77
|
+
aggregated.flushTimer.unref();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Update rapid check time
|
|
81
|
+
if (now - this.lastRapidCheck >= 1000) {
|
|
82
|
+
this.lastRapidCheck = now;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Flush aggregated events for a specific key
|
|
87
|
+
*/
|
|
88
|
+
flush(key) {
|
|
89
|
+
const aggregated = this.aggregatedEvents.get(key);
|
|
90
|
+
if (!aggregated || aggregated.events.size === 0) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (aggregated.flushTimer) {
|
|
94
|
+
clearTimeout(aggregated.flushTimer);
|
|
95
|
+
aggregated.flushTimer = undefined;
|
|
96
|
+
}
|
|
97
|
+
// Emit aggregated log based on the key
|
|
98
|
+
switch (key) {
|
|
99
|
+
case 'connection-rejected':
|
|
100
|
+
this.flushConnectionRejections(aggregated);
|
|
101
|
+
break;
|
|
102
|
+
case 'connection-cleanup':
|
|
103
|
+
this.flushConnectionCleanups(aggregated);
|
|
104
|
+
break;
|
|
105
|
+
case 'connection-terminated':
|
|
106
|
+
this.flushConnectionTerminations(aggregated);
|
|
107
|
+
break;
|
|
108
|
+
case 'ip-rejected':
|
|
109
|
+
this.flushIPRejections(aggregated);
|
|
110
|
+
break;
|
|
111
|
+
default:
|
|
112
|
+
this.flushGeneric(aggregated);
|
|
113
|
+
}
|
|
114
|
+
// Clear events
|
|
115
|
+
aggregated.events.clear();
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Flush all pending events
|
|
119
|
+
*/
|
|
120
|
+
flushAll() {
|
|
121
|
+
for (const key of this.aggregatedEvents.keys()) {
|
|
122
|
+
this.flush(key);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
flushConnectionRejections(aggregated) {
|
|
126
|
+
const totalCount = Array.from(aggregated.events.values()).reduce((sum, e) => sum + e.count, 0);
|
|
127
|
+
const byReason = new Map();
|
|
128
|
+
for (const [, event] of aggregated.events) {
|
|
129
|
+
const reason = event.data?.reason || 'unknown';
|
|
130
|
+
byReason.set(reason, (byReason.get(reason) || 0) + event.count);
|
|
131
|
+
}
|
|
132
|
+
const reasonSummary = Array.from(byReason.entries())
|
|
133
|
+
.sort((a, b) => b[1] - a[1])
|
|
134
|
+
.map(([reason, count]) => `${reason}: ${count}`)
|
|
135
|
+
.join(', ');
|
|
136
|
+
const duration = Date.now() - Math.min(...Array.from(aggregated.events.values()).map(e => e.firstSeen));
|
|
137
|
+
logger.log('warn', `[SUMMARY] Rejected ${totalCount} connections in ${Math.round(duration / 1000)}s`, {
|
|
138
|
+
reasons: reasonSummary,
|
|
139
|
+
uniqueIPs: aggregated.events.size,
|
|
140
|
+
component: 'connection-dedup'
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
flushConnectionCleanups(aggregated) {
|
|
144
|
+
const totalCount = Array.from(aggregated.events.values()).reduce((sum, e) => sum + e.count, 0);
|
|
145
|
+
const byReason = new Map();
|
|
146
|
+
for (const [, event] of aggregated.events) {
|
|
147
|
+
const reason = event.data?.reason || 'normal';
|
|
148
|
+
byReason.set(reason, (byReason.get(reason) || 0) + event.count);
|
|
149
|
+
}
|
|
150
|
+
const reasonSummary = Array.from(byReason.entries())
|
|
151
|
+
.sort((a, b) => b[1] - a[1])
|
|
152
|
+
.slice(0, 5) // Top 5 reasons
|
|
153
|
+
.map(([reason, count]) => `${reason}: ${count}`)
|
|
154
|
+
.join(', ');
|
|
155
|
+
logger.log('info', `Cleaned up ${totalCount} connections`, {
|
|
156
|
+
reasons: reasonSummary,
|
|
157
|
+
duration: Date.now() - Math.min(...Array.from(aggregated.events.values()).map(e => e.firstSeen)),
|
|
158
|
+
component: 'connection-dedup'
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
flushConnectionTerminations(aggregated) {
|
|
162
|
+
const totalCount = Array.from(aggregated.events.values()).reduce((sum, e) => sum + e.count, 0);
|
|
163
|
+
const byReason = new Map();
|
|
164
|
+
const byIP = new Map();
|
|
165
|
+
let lastActiveCount = 0;
|
|
166
|
+
for (const [, event] of aggregated.events) {
|
|
167
|
+
const reason = event.data?.reason || 'unknown';
|
|
168
|
+
const ip = event.data?.remoteIP || 'unknown';
|
|
169
|
+
byReason.set(reason, (byReason.get(reason) || 0) + event.count);
|
|
170
|
+
// Track by IP
|
|
171
|
+
if (ip !== 'unknown') {
|
|
172
|
+
byIP.set(ip, (byIP.get(ip) || 0) + event.count);
|
|
173
|
+
}
|
|
174
|
+
// Track the last active connection count
|
|
175
|
+
if (event.data?.activeConnections !== undefined) {
|
|
176
|
+
lastActiveCount = event.data.activeConnections;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
const reasonSummary = Array.from(byReason.entries())
|
|
180
|
+
.sort((a, b) => b[1] - a[1])
|
|
181
|
+
.slice(0, 5) // Top 5 reasons
|
|
182
|
+
.map(([reason, count]) => `${reason}: ${count}`)
|
|
183
|
+
.join(', ');
|
|
184
|
+
// Show top IPs if there are many different ones
|
|
185
|
+
let ipInfo = '';
|
|
186
|
+
if (byIP.size > 3) {
|
|
187
|
+
const topIPs = Array.from(byIP.entries())
|
|
188
|
+
.sort((a, b) => b[1] - a[1])
|
|
189
|
+
.slice(0, 3)
|
|
190
|
+
.map(([ip, count]) => `${ip} (${count})`)
|
|
191
|
+
.join(', ');
|
|
192
|
+
ipInfo = `, from ${byIP.size} IPs (top: ${topIPs})`;
|
|
193
|
+
}
|
|
194
|
+
else if (byIP.size > 0) {
|
|
195
|
+
ipInfo = `, IPs: ${Array.from(byIP.keys()).join(', ')}`;
|
|
196
|
+
}
|
|
197
|
+
const duration = Date.now() - Math.min(...Array.from(aggregated.events.values()).map(e => e.firstSeen));
|
|
198
|
+
// Special handling for localhost connections (HttpProxy)
|
|
199
|
+
const localhostCount = byIP.get('::ffff:127.0.0.1') || 0;
|
|
200
|
+
if (localhostCount > 0 && byIP.size === 1) {
|
|
201
|
+
// All connections are from localhost (HttpProxy)
|
|
202
|
+
logger.log('info', `[SUMMARY] ${totalCount} HttpProxy connections terminated in ${Math.round(duration / 1000)}s`, {
|
|
203
|
+
reasons: reasonSummary,
|
|
204
|
+
activeConnections: lastActiveCount,
|
|
205
|
+
component: 'connection-dedup'
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
logger.log('info', `[SUMMARY] ${totalCount} connections terminated in ${Math.round(duration / 1000)}s`, {
|
|
210
|
+
reasons: reasonSummary,
|
|
211
|
+
activeConnections: lastActiveCount,
|
|
212
|
+
uniqueReasons: byReason.size,
|
|
213
|
+
...(ipInfo ? { ips: ipInfo } : {}),
|
|
214
|
+
component: 'connection-dedup'
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
flushIPRejections(aggregated) {
|
|
219
|
+
const byIP = new Map();
|
|
220
|
+
for (const [ip, event] of aggregated.events) {
|
|
221
|
+
if (!byIP.has(ip)) {
|
|
222
|
+
byIP.set(ip, { count: 0, reasons: new Set() });
|
|
223
|
+
}
|
|
224
|
+
const ipData = byIP.get(ip);
|
|
225
|
+
ipData.count += event.count;
|
|
226
|
+
if (event.data?.reason) {
|
|
227
|
+
ipData.reasons.add(event.data.reason);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
// Log top offenders
|
|
231
|
+
const topOffenders = Array.from(byIP.entries())
|
|
232
|
+
.sort((a, b) => b[1].count - a[1].count)
|
|
233
|
+
.slice(0, 10)
|
|
234
|
+
.map(([ip, data]) => `${ip} (${data.count}x, ${Array.from(data.reasons).join('/')})`)
|
|
235
|
+
.join(', ');
|
|
236
|
+
const totalRejections = Array.from(byIP.values()).reduce((sum, data) => sum + data.count, 0);
|
|
237
|
+
const duration = Date.now() - Math.min(...Array.from(aggregated.events.values()).map(e => e.firstSeen));
|
|
238
|
+
logger.log('warn', `[SUMMARY] Rejected ${totalRejections} connections from ${byIP.size} IPs in ${Math.round(duration / 1000)}s`, {
|
|
239
|
+
topOffenders,
|
|
240
|
+
component: 'ip-dedup'
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
flushGeneric(aggregated) {
|
|
244
|
+
const totalCount = Array.from(aggregated.events.values()).reduce((sum, e) => sum + e.count, 0);
|
|
245
|
+
const level = aggregated.events.values().next().value?.level || 'info';
|
|
246
|
+
// Special handling for IP cleanup events
|
|
247
|
+
if (aggregated.key === 'ip-cleanup') {
|
|
248
|
+
const totalCleaned = Array.from(aggregated.events.values()).reduce((sum, e) => {
|
|
249
|
+
return sum + (e.data?.cleanedIPs || 0) + (e.data?.cleanedRateLimits || 0);
|
|
250
|
+
}, 0);
|
|
251
|
+
if (totalCleaned > 0) {
|
|
252
|
+
logger.log(level, `IP tracking cleanup: removed ${totalCleaned} entries across ${totalCount} cleanup cycles`, {
|
|
253
|
+
duration: Date.now() - Math.min(...Array.from(aggregated.events.values()).map(e => e.firstSeen)),
|
|
254
|
+
component: 'log-dedup'
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
logger.log(level, `${aggregated.key}: ${totalCount} events`, {
|
|
260
|
+
uniqueEvents: aggregated.events.size,
|
|
261
|
+
duration: Date.now() - Math.min(...Array.from(aggregated.events.values()).map(e => e.firstSeen)),
|
|
262
|
+
component: 'log-dedup'
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Cleanup and stop deduplication
|
|
268
|
+
*/
|
|
269
|
+
cleanup() {
|
|
270
|
+
this.flushAll();
|
|
271
|
+
if (this.globalFlushTimer) {
|
|
272
|
+
clearInterval(this.globalFlushTimer);
|
|
273
|
+
this.globalFlushTimer = undefined;
|
|
274
|
+
}
|
|
275
|
+
for (const aggregated of this.aggregatedEvents.values()) {
|
|
276
|
+
if (aggregated.flushTimer) {
|
|
277
|
+
clearTimeout(aggregated.flushTimer);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
this.aggregatedEvents.clear();
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
// Global instance for connection-related log deduplication
|
|
284
|
+
export const connectionLogDeduplicator = new LogDeduplicator(5000); // 5 second batches
|
|
285
|
+
// Ensure logs are flushed on process exit
|
|
286
|
+
process.on('beforeExit', () => {
|
|
287
|
+
connectionLogDeduplicator.flushAll();
|
|
288
|
+
});
|
|
289
|
+
process.on('SIGINT', () => {
|
|
290
|
+
connectionLogDeduplicator.cleanup();
|
|
291
|
+
process.exit(0);
|
|
292
|
+
});
|
|
293
|
+
process.on('SIGTERM', () => {
|
|
294
|
+
connectionLogDeduplicator.cleanup();
|
|
295
|
+
process.exit(0);
|
|
296
|
+
});
|
|
297
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9nLWRlZHVwbGljYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL2NvcmUvdXRpbHMvbG9nLWRlZHVwbGljYXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBaUJyQzs7R0FFRztBQUNILE1BQU0sT0FBTyxlQUFlO0lBUTFCLFlBQVksYUFBc0I7UUFOMUIscUJBQWdCLEdBQWtDLElBQUksR0FBRyxFQUFFLENBQUM7UUFDNUQsa0JBQWEsR0FBVyxJQUFJLENBQUMsQ0FBQyxZQUFZO1FBQzFDLGlCQUFZLEdBQVcsR0FBRyxDQUFDO1FBQzNCLHdCQUFtQixHQUFXLEVBQUUsQ0FBQyxDQUFDLDhDQUE4QztRQUNoRixtQkFBYyxHQUFXLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUcxQyxJQUFJLGFBQWEsRUFBRSxDQUFDO1lBQ2xCLElBQUksQ0FBQyxhQUFhLEdBQUcsYUFBYSxDQUFDO1FBQ3JDLENBQUM7UUFFRCxvRUFBb0U7UUFDcEUsSUFBSSxDQUFDLGdCQUFnQixHQUFHLFdBQVcsQ0FBQyxHQUFHLEVBQUU7WUFDdkMsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ2xCLENBQUMsRUFBRSxJQUFJLENBQUMsYUFBYSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsZ0RBQWdEO1FBRTVFLElBQUksSUFBSSxDQUFDLGdCQUFnQixDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ2hDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNoQyxDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7Ozs7O09BT0c7SUFDSSxHQUFHLENBQ1IsR0FBVyxFQUNYLEtBQTBDLEVBQzFDLE9BQWUsRUFDZixJQUFVLEVBQ1YsU0FBa0I7UUFFbEIsTUFBTSxRQUFRLEdBQUcsU0FBUyxJQUFJLE9BQU8sQ0FBQztRQUN0QyxNQUFNLEdBQUcsR0FBRyxJQUFJLENB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TSxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQztRQUMvRixNQUFNLFFBQVEsR0FBRyxJQUFJLEdBQUcsRUFBa0IsQ0FBQztRQUUzQyxLQUFLLE1BQU0sQ0FBQyxFQUFFLEtBQUssQ0FBQyxJQUFJLFVBQVUsQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUMxQyxNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsSUFBSSxFQUFFLE1BQU0sSUFBSSxTQUFTLENBQUM7WUFDL0MsUUFBUSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNsRSxDQUFDO1FBRUQsTUFBTSxhQUFhLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxFQUFFLENBQUM7YUFDakQsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQzthQUMzQixHQUFHLENBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxLQUFLLENBQUMsRUFBRSxFQUFFLENBQUMsR0FBRyxNQUFNLEtBQUssS0FBSyxFQUFFLENBQUM7YUFDL0MsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBRWQsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQztRQUN4RyxNQUFNLENBQUMsR0FB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
|
|
@@ -66,9 +66,10 @@ export declare class SharedSecurityManager {
|
|
|
66
66
|
*
|
|
67
67
|
* @param route - The route to check
|
|
68
68
|
* @param context - The request context
|
|
69
|
+
* @param routeConnectionCount - Current connection count for this route (optional)
|
|
69
70
|
* @returns Whether access is allowed
|
|
70
71
|
*/
|
|
71
|
-
isAllowed(route: IRouteConfig, context: IRouteContext): boolean;
|
|
72
|
+
isAllowed(route: IRouteConfig, context: IRouteContext, routeConnectionCount?: number): boolean;
|
|
72
73
|
/**
|
|
73
74
|
* Check if a client IP is allowed for a route
|
|
74
75
|
*
|
|
@@ -101,9 +101,10 @@ export class SharedSecurityManager {
|
|
|
101
101
|
*
|
|
102
102
|
* @param route - The route to check
|
|
103
103
|
* @param context - The request context
|
|
104
|
+
* @param routeConnectionCount - Current connection count for this route (optional)
|
|
104
105
|
* @returns Whether access is allowed
|
|
105
106
|
*/
|
|
106
|
-
isAllowed(route, context) {
|
|
107
|
+
isAllowed(route, context, routeConnectionCount) {
|
|
107
108
|
if (!route.security) {
|
|
108
109
|
return true; // No security restrictions
|
|
109
110
|
}
|
|
@@ -112,6 +113,13 @@ export class SharedSecurityManager {
|
|
|
112
113
|
this.logger?.debug?.(`IP ${context.clientIp} is blocked for route ${route.name || 'unnamed'}`);
|
|
113
114
|
return false;
|
|
114
115
|
}
|
|
116
|
+
// --- Route-level connection limit ---
|
|
117
|
+
if (route.security.maxConnections !== undefined && routeConnectionCount !== undefined) {
|
|
118
|
+
if (routeConnectionCount >= route.security.maxConnections) {
|
|
119
|
+
this.logger?.debug?.(`Route connection limit (${route.security.maxConnections}) exceeded for route ${route.name || 'unnamed'}`);
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
115
123
|
// --- Rate limiting ---
|
|
116
124
|
if (route.security.rateLimit?.enabled && !this.isWithinRateLimit(route, context)) {
|
|
117
125
|
this.logger?.debug?.(`Rate limit exceeded for route ${route.name || 'unnamed'}`);
|
|
@@ -225,6 +233,18 @@ export class SharedSecurityManager {
|
|
|
225
233
|
cleanupCaches() {
|
|
226
234
|
// Clean up rate limits
|
|
227
235
|
cleanupExpiredRateLimits(this.rateLimits, this.logger);
|
|
236
|
+
// Clean up IP connection tracking
|
|
237
|
+
let cleanedIPs = 0;
|
|
238
|
+
for (const [ip, info] of this.connectionsByIP.entries()) {
|
|
239
|
+
// Remove IPs with no active connections and no recent timestamps
|
|
240
|
+
if (info.connections.size === 0 && info.timestamps.length === 0) {
|
|
241
|
+
this.connectionsByIP.delete(ip);
|
|
242
|
+
cleanedIPs++;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (cleanedIPs > 0 && this.logger?.debug) {
|
|
246
|
+
this.logger.debug(`Cleaned up ${cleanedIPs} IPs with no active connections`);
|
|
247
|
+
}
|
|
228
248
|
// IP filter cache doesn't need cleanup (tied to routes)
|
|
229
249
|
}
|
|
230
250
|
/**
|
|
@@ -249,4 +269,4 @@ export class SharedSecurityManager {
|
|
|
249
269
|
this.ipFilterCache.clear();
|
|
250
270
|
}
|
|
251
271
|
}
|
|
252
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
272
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2hhcmVkLXNlY3VyaXR5LW1hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9jb3JlL3V0aWxzL3NoYXJlZC1zZWN1cml0eS1tYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFRNUMsT0FBTyxFQUNMLGNBQWMsRUFDZCxtQkFBbUIsRUFDbkIsbUJBQW1CLEVBQ25CLGVBQWUsRUFDZixnQkFBZ0IsRUFDaEIsd0JBQXdCLEVBQ3hCLG9CQUFvQixFQUNyQixNQUFNLHFCQUFxQixDQUFDO0FBRTdCOzs7R0FHRztBQUNILE1BQU0sT0FBTyxxQkFBcUI7SUFpQmhDOzs7OztPQUtHO0lBQ0gsWUFBWSxPQUtYLEVBQVUsTUFBd0I7UUFBeEIsV0FBTSxHQUFOLE1BQU0sQ0FBa0I7UUEzQm5DLHlCQUF5QjtRQUNqQixvQkFBZSxHQUFtQyxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBRXBFLCtCQUErQjtRQUN2QixlQUFVLEdBQTZDLElBQUksR0FBRyxFQUFFLENBQUM7UUFFekUsOERBQThEO1FBQ3RELGtCQUFhLEdBQXNDLElBQUksR0FBRyxFQUFFLENBQUM7UUFNckUseUJBQXlCO1FBQ2pCLG9CQUFlLEdBQTBCLElBQUksQ0FBQztRQWNwRCxJQUFJLENBQUMsbUJBQW1CLEdBQUcsT0FBTyxDQUFDLG1CQUFtQixJQUFJLEdBQUcsQ0FBQztRQUM5RCxJQUFJLENBQUMsNEJBQTRCLEdBQUcsT0FBTyxDQUFDLDRCQUE0QixJQUFJLEdBQUcsQ0FBQztRQUVoRiw4Q0FBOEM7UUFDOUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLElBQUk7WUFDdEIsSUFBSSxFQUFFLE9BQU8sQ0FBQyxHQUFHO1lBQ2pCLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSTtZQUNsQixLQUFLLEVBQUUsT0FBTyxDQUFDLEtBQUs7U0FDckIsQ0FBQztRQUVGLGdDQUFnQztRQUNoQyxNQUFN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
|
|
@@ -19,6 +19,7 @@ export declare class HttpProxy implements IMetricsTracker {
|
|
|
19
19
|
private router;
|
|
20
20
|
private routeManager;
|
|
21
21
|
private functionCache;
|
|
22
|
+
private securityManager;
|
|
22
23
|
socketMap: plugins.lik.ObjectMap<plugins.net.Socket>;
|
|
23
24
|
activeContexts: Set<string>;
|
|
24
25
|
connectedClients: number;
|