@push.rocks/smartproxy 22.4.2 → 23.0.0
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/changelog.md +36 -0
- package/dist_rust/rustproxy +0 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/index.d.ts +1 -6
- package/dist_ts/index.js +3 -11
- package/dist_ts/protocols/common/fragment-handler.js +5 -1
- package/dist_ts/proxies/index.d.ts +1 -6
- package/dist_ts/proxies/index.js +2 -8
- package/dist_ts/proxies/smart-proxy/index.d.ts +5 -10
- package/dist_ts/proxies/smart-proxy/index.js +7 -13
- package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +5 -2
- package/dist_ts/proxies/smart-proxy/models/route-types.js +1 -1
- package/dist_ts/proxies/smart-proxy/route-preprocessor.d.ts +37 -0
- package/dist_ts/proxies/smart-proxy/route-preprocessor.js +103 -0
- package/dist_ts/proxies/smart-proxy/rust-binary-locator.d.ts +23 -0
- package/dist_ts/proxies/smart-proxy/rust-binary-locator.js +104 -0
- package/dist_ts/proxies/smart-proxy/rust-metrics-adapter.d.ts +74 -0
- package/dist_ts/proxies/smart-proxy/rust-metrics-adapter.js +146 -0
- package/dist_ts/proxies/smart-proxy/rust-proxy-bridge.d.ts +49 -0
- package/dist_ts/proxies/smart-proxy/rust-proxy-bridge.js +259 -0
- package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +39 -157
- package/dist_ts/proxies/smart-proxy/smart-proxy.js +224 -621
- package/dist_ts/proxies/smart-proxy/socket-handler-server.d.ts +45 -0
- package/dist_ts/proxies/smart-proxy/socket-handler-server.js +253 -0
- package/dist_ts/routing/index.d.ts +1 -1
- package/dist_ts/routing/index.js +3 -3
- package/dist_ts/routing/models/http-types.d.ts +119 -4
- package/dist_ts/routing/models/http-types.js +93 -5
- package/package.json +1 -1
- package/readme.md +444 -219
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/index.ts +4 -15
- package/ts/protocols/common/fragment-handler.ts +4 -0
- package/ts/proxies/index.ts +1 -12
- package/ts/proxies/smart-proxy/index.ts +6 -13
- package/ts/proxies/smart-proxy/models/interfaces.ts +6 -4
- package/ts/proxies/smart-proxy/models/route-types.ts +0 -2
- package/ts/proxies/smart-proxy/route-preprocessor.ts +122 -0
- package/ts/proxies/smart-proxy/rust-binary-locator.ts +112 -0
- package/ts/proxies/smart-proxy/rust-metrics-adapter.ts +161 -0
- package/ts/proxies/smart-proxy/rust-proxy-bridge.ts +310 -0
- package/ts/proxies/smart-proxy/smart-proxy.ts +282 -798
- package/ts/proxies/smart-proxy/socket-handler-server.ts +279 -0
- package/ts/routing/index.ts +2 -2
- package/ts/routing/models/http-types.ts +147 -4
- package/dist_ts/proxies/nftables-proxy/index.d.ts +0 -6
- package/dist_ts/proxies/nftables-proxy/index.js +0 -7
- package/dist_ts/proxies/nftables-proxy/models/errors.d.ts +0 -15
- package/dist_ts/proxies/nftables-proxy/models/errors.js +0 -28
- package/dist_ts/proxies/nftables-proxy/models/index.d.ts +0 -5
- package/dist_ts/proxies/nftables-proxy/models/index.js +0 -6
- package/dist_ts/proxies/nftables-proxy/models/interfaces.d.ts +0 -75
- package/dist_ts/proxies/nftables-proxy/models/interfaces.js +0 -5
- package/dist_ts/proxies/nftables-proxy/nftables-proxy.d.ts +0 -124
- package/dist_ts/proxies/nftables-proxy/nftables-proxy.js +0 -1374
- package/dist_ts/proxies/nftables-proxy/utils/index.d.ts +0 -9
- package/dist_ts/proxies/nftables-proxy/utils/index.js +0 -12
- package/dist_ts/proxies/nftables-proxy/utils/nft-command-executor.d.ts +0 -66
- package/dist_ts/proxies/nftables-proxy/utils/nft-command-executor.js +0 -131
- package/dist_ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.d.ts +0 -39
- package/dist_ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.js +0 -112
- package/dist_ts/proxies/nftables-proxy/utils/nft-rule-validator.d.ts +0 -59
- package/dist_ts/proxies/nftables-proxy/utils/nft-rule-validator.js +0 -130
- package/ts/proxies/http-proxy/connection-pool.ts +0 -228
- package/ts/proxies/http-proxy/context-creator.ts +0 -145
- package/ts/proxies/http-proxy/default-certificates.ts +0 -150
- package/ts/proxies/http-proxy/function-cache.ts +0 -279
- package/ts/proxies/http-proxy/handlers/index.ts +0 -5
- package/ts/proxies/http-proxy/http-proxy.ts +0 -669
- package/ts/proxies/http-proxy/http-request-handler.ts +0 -331
- package/ts/proxies/http-proxy/http2-request-handler.ts +0 -255
- package/ts/proxies/http-proxy/index.ts +0 -18
- package/ts/proxies/http-proxy/models/http-types.ts +0 -148
- package/ts/proxies/http-proxy/models/index.ts +0 -5
- package/ts/proxies/http-proxy/models/types.ts +0 -125
- package/ts/proxies/http-proxy/request-handler.ts +0 -878
- package/ts/proxies/http-proxy/security-manager.ts +0 -413
- package/ts/proxies/http-proxy/websocket-handler.ts +0 -581
- package/ts/proxies/nftables-proxy/index.ts +0 -6
- package/ts/proxies/nftables-proxy/models/errors.ts +0 -30
- package/ts/proxies/nftables-proxy/models/index.ts +0 -5
- package/ts/proxies/nftables-proxy/models/interfaces.ts +0 -94
- package/ts/proxies/nftables-proxy/nftables-proxy.ts +0 -1754
- package/ts/proxies/nftables-proxy/utils/index.ts +0 -38
- package/ts/proxies/nftables-proxy/utils/nft-command-executor.ts +0 -162
- package/ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.ts +0 -125
- package/ts/proxies/nftables-proxy/utils/nft-rule-validator.ts +0 -156
- package/ts/proxies/smart-proxy/acme-state-manager.ts +0 -112
- package/ts/proxies/smart-proxy/cert-store.ts +0 -92
- package/ts/proxies/smart-proxy/certificate-manager.ts +0 -895
- package/ts/proxies/smart-proxy/connection-manager.ts +0 -809
- package/ts/proxies/smart-proxy/http-proxy-bridge.ts +0 -213
- package/ts/proxies/smart-proxy/metrics-collector.ts +0 -453
- package/ts/proxies/smart-proxy/nftables-manager.ts +0 -271
- package/ts/proxies/smart-proxy/port-manager.ts +0 -358
- package/ts/proxies/smart-proxy/route-connection-handler.ts +0 -1712
- package/ts/proxies/smart-proxy/route-orchestrator.ts +0 -297
- package/ts/proxies/smart-proxy/security-manager.ts +0 -269
- package/ts/proxies/smart-proxy/throughput-tracker.ts +0 -138
- package/ts/proxies/smart-proxy/timeout-manager.ts +0 -196
- package/ts/proxies/smart-proxy/tls-manager.ts +0 -171
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
import * as plugins from '../../plugins.js';
|
|
2
|
-
import { type IHttpProxyOptions, type IConnectionEntry, type ILogger, createLogger } from './models/types.js';
|
|
3
|
-
import { cleanupSocket } from '../../core/utils/socket-utils.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Manages a pool of backend connections for efficient reuse
|
|
7
|
-
*/
|
|
8
|
-
export class ConnectionPool {
|
|
9
|
-
private connectionPool: Map<string, Array<IConnectionEntry>> = new Map();
|
|
10
|
-
private roundRobinPositions: Map<string, number> = new Map();
|
|
11
|
-
private logger: ILogger;
|
|
12
|
-
|
|
13
|
-
constructor(private options: IHttpProxyOptions) {
|
|
14
|
-
this.logger = createLogger(options.logLevel || 'info');
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Get a connection from the pool or create a new one
|
|
19
|
-
*/
|
|
20
|
-
public getConnection(host: string, port: number): Promise<plugins.net.Socket> {
|
|
21
|
-
return new Promise((resolve, reject) => {
|
|
22
|
-
const poolKey = `${host}:${port}`;
|
|
23
|
-
const connectionList = this.connectionPool.get(poolKey) || [];
|
|
24
|
-
|
|
25
|
-
// Look for an idle connection
|
|
26
|
-
const idleConnectionIndex = connectionList.findIndex(c => c.isIdle);
|
|
27
|
-
|
|
28
|
-
if (idleConnectionIndex >= 0) {
|
|
29
|
-
// Get existing connection from pool
|
|
30
|
-
const connection = connectionList[idleConnectionIndex];
|
|
31
|
-
connection.isIdle = false;
|
|
32
|
-
connection.lastUsed = Date.now();
|
|
33
|
-
this.logger.debug(`Reusing connection from pool for ${poolKey}`);
|
|
34
|
-
|
|
35
|
-
// Update the pool
|
|
36
|
-
this.connectionPool.set(poolKey, connectionList);
|
|
37
|
-
|
|
38
|
-
resolve(connection.socket);
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// No idle connection available, create a new one if pool isn't full
|
|
43
|
-
const poolSize = this.options.connectionPoolSize || 50;
|
|
44
|
-
if (connectionList.length < poolSize) {
|
|
45
|
-
this.logger.debug(`Creating new connection to ${host}:${port}`);
|
|
46
|
-
|
|
47
|
-
try {
|
|
48
|
-
const socket = plugins.net.connect({
|
|
49
|
-
host,
|
|
50
|
-
port,
|
|
51
|
-
keepAlive: true,
|
|
52
|
-
keepAliveInitialDelay: 30000 // 30 seconds
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
socket.once('connect', () => {
|
|
56
|
-
// Add to connection pool
|
|
57
|
-
const connection = {
|
|
58
|
-
socket,
|
|
59
|
-
lastUsed: Date.now(),
|
|
60
|
-
isIdle: false
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
connectionList.push(connection);
|
|
64
|
-
this.connectionPool.set(poolKey, connectionList);
|
|
65
|
-
|
|
66
|
-
// Setup cleanup when the connection is closed
|
|
67
|
-
socket.once('close', () => {
|
|
68
|
-
const idx = connectionList.findIndex(c => c.socket === socket);
|
|
69
|
-
if (idx >= 0) {
|
|
70
|
-
connectionList.splice(idx, 1);
|
|
71
|
-
this.connectionPool.set(poolKey, connectionList);
|
|
72
|
-
this.logger.debug(`Removed closed connection from pool for ${poolKey}`);
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
resolve(socket);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
socket.once('error', (err) => {
|
|
80
|
-
this.logger.error(`Error creating connection to ${host}:${port}`, err);
|
|
81
|
-
reject(err);
|
|
82
|
-
});
|
|
83
|
-
} catch (err) {
|
|
84
|
-
this.logger.error(`Failed to create connection to ${host}:${port}`, err);
|
|
85
|
-
reject(err);
|
|
86
|
-
}
|
|
87
|
-
} else {
|
|
88
|
-
// Pool is full, wait for an idle connection or reject
|
|
89
|
-
this.logger.warn(`Connection pool for ${poolKey} is full (${connectionList.length})`);
|
|
90
|
-
reject(new Error(`Connection pool for ${poolKey} is full`));
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Return a connection to the pool for reuse
|
|
97
|
-
*/
|
|
98
|
-
public returnConnection(socket: plugins.net.Socket, host: string, port: number): void {
|
|
99
|
-
const poolKey = `${host}:${port}`;
|
|
100
|
-
const connectionList = this.connectionPool.get(poolKey) || [];
|
|
101
|
-
|
|
102
|
-
// Find this connection in the pool
|
|
103
|
-
const connectionIndex = connectionList.findIndex(c => c.socket === socket);
|
|
104
|
-
|
|
105
|
-
if (connectionIndex >= 0) {
|
|
106
|
-
// Mark as idle and update last used time
|
|
107
|
-
connectionList[connectionIndex].isIdle = true;
|
|
108
|
-
connectionList[connectionIndex].lastUsed = Date.now();
|
|
109
|
-
|
|
110
|
-
this.logger.debug(`Returned connection to pool for ${poolKey}`);
|
|
111
|
-
} else {
|
|
112
|
-
this.logger.warn(`Attempted to return unknown connection to pool for ${poolKey}`);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Cleanup the connection pool by removing idle connections
|
|
118
|
-
* or reducing pool size if it exceeds the configured maximum
|
|
119
|
-
*/
|
|
120
|
-
public cleanupConnectionPool(): void {
|
|
121
|
-
const now = Date.now();
|
|
122
|
-
const idleTimeout = this.options.keepAliveTimeout || 120000; // 2 minutes default
|
|
123
|
-
|
|
124
|
-
for (const [host, connections] of this.connectionPool.entries()) {
|
|
125
|
-
// Sort by last used time (oldest first)
|
|
126
|
-
connections.sort((a, b) => a.lastUsed - b.lastUsed);
|
|
127
|
-
|
|
128
|
-
// Remove idle connections older than the idle timeout
|
|
129
|
-
let removed = 0;
|
|
130
|
-
while (connections.length > 0) {
|
|
131
|
-
const connection = connections[0];
|
|
132
|
-
|
|
133
|
-
// Remove if idle and exceeds timeout, or if pool is too large
|
|
134
|
-
if ((connection.isIdle && now - connection.lastUsed > idleTimeout) ||
|
|
135
|
-
connections.length > (this.options.connectionPoolSize || 50)) {
|
|
136
|
-
|
|
137
|
-
cleanupSocket(connection.socket, `pool-${host}-idle`, { immediate: true }).catch(() => {});
|
|
138
|
-
|
|
139
|
-
connections.shift(); // Remove from pool
|
|
140
|
-
removed++;
|
|
141
|
-
} else {
|
|
142
|
-
break; // Stop removing if we've reached active or recent connections
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (removed > 0) {
|
|
147
|
-
this.logger.debug(`Removed ${removed} idle connections from pool for ${host}, ${connections.length} remaining`);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// Update the pool with the remaining connections
|
|
151
|
-
if (connections.length === 0) {
|
|
152
|
-
this.connectionPool.delete(host);
|
|
153
|
-
} else {
|
|
154
|
-
this.connectionPool.set(host, connections);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Close all connections in the pool
|
|
161
|
-
*/
|
|
162
|
-
public closeAllConnections(): void {
|
|
163
|
-
for (const [host, connections] of this.connectionPool.entries()) {
|
|
164
|
-
this.logger.debug(`Closing ${connections.length} connections to ${host}`);
|
|
165
|
-
|
|
166
|
-
for (const connection of connections) {
|
|
167
|
-
cleanupSocket(connection.socket, `pool-${host}-close`, { immediate: true }).catch(() => {});
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
this.connectionPool.clear();
|
|
172
|
-
this.roundRobinPositions.clear();
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Get load balancing target using round-robin
|
|
177
|
-
*/
|
|
178
|
-
public getNextTarget(targets: string[], port: number): { host: string, port: number } {
|
|
179
|
-
const targetKey = targets.join(',');
|
|
180
|
-
|
|
181
|
-
// Initialize position if not exists
|
|
182
|
-
if (!this.roundRobinPositions.has(targetKey)) {
|
|
183
|
-
this.roundRobinPositions.set(targetKey, 0);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Get current position and increment for next time
|
|
187
|
-
const currentPosition = this.roundRobinPositions.get(targetKey)!;
|
|
188
|
-
const nextPosition = (currentPosition + 1) % targets.length;
|
|
189
|
-
this.roundRobinPositions.set(targetKey, nextPosition);
|
|
190
|
-
|
|
191
|
-
// Return the selected target
|
|
192
|
-
return {
|
|
193
|
-
host: targets[currentPosition],
|
|
194
|
-
port
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Gets the connection pool status
|
|
200
|
-
*/
|
|
201
|
-
public getPoolStatus(): Record<string, { total: number, idle: number }> {
|
|
202
|
-
return Object.fromEntries(
|
|
203
|
-
Array.from(this.connectionPool.entries()).map(([host, connections]) => [
|
|
204
|
-
host,
|
|
205
|
-
{
|
|
206
|
-
total: connections.length,
|
|
207
|
-
idle: connections.filter(c => c.isIdle).length
|
|
208
|
-
}
|
|
209
|
-
])
|
|
210
|
-
);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Setup a periodic cleanup task
|
|
215
|
-
*/
|
|
216
|
-
public setupPeriodicCleanup(interval: number = 60000): NodeJS.Timeout {
|
|
217
|
-
const timer = setInterval(() => {
|
|
218
|
-
this.cleanupConnectionPool();
|
|
219
|
-
}, interval);
|
|
220
|
-
|
|
221
|
-
// Don't prevent process exit
|
|
222
|
-
if (timer.unref) {
|
|
223
|
-
timer.unref();
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
return timer;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
import * as plugins from '../../plugins.js';
|
|
2
|
-
import '../../core/models/socket-augmentation.js';
|
|
3
|
-
import type { IRouteContext, IHttpRouteContext, IHttp2RouteContext } from '../../core/models/route-context.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Context creator for NetworkProxy
|
|
7
|
-
* Creates route contexts for matching and function evaluation
|
|
8
|
-
*/
|
|
9
|
-
export class ContextCreator {
|
|
10
|
-
/**
|
|
11
|
-
* Create a route context from HTTP request information
|
|
12
|
-
*/
|
|
13
|
-
public createHttpRouteContext(req: any, options: {
|
|
14
|
-
tlsVersion?: string;
|
|
15
|
-
connectionId: string;
|
|
16
|
-
clientIp: string;
|
|
17
|
-
serverIp: string;
|
|
18
|
-
}): IHttpRouteContext {
|
|
19
|
-
// Parse headers
|
|
20
|
-
const headers: Record<string, string> = {};
|
|
21
|
-
for (const [key, value] of Object.entries(req.headers)) {
|
|
22
|
-
if (typeof value === 'string') {
|
|
23
|
-
headers[key.toLowerCase()] = value;
|
|
24
|
-
} else if (Array.isArray(value) && value.length > 0) {
|
|
25
|
-
headers[key.toLowerCase()] = value[0];
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Parse domain from Host header
|
|
30
|
-
const domain = headers['host']?.split(':')[0] || '';
|
|
31
|
-
|
|
32
|
-
// Parse URL
|
|
33
|
-
const url = new URL(`http://${domain}${req.url || '/'}`);
|
|
34
|
-
|
|
35
|
-
return {
|
|
36
|
-
// Connection basics
|
|
37
|
-
port: req.socket.localPort || 0,
|
|
38
|
-
domain,
|
|
39
|
-
clientIp: options.clientIp,
|
|
40
|
-
serverIp: options.serverIp,
|
|
41
|
-
|
|
42
|
-
// HTTP specifics
|
|
43
|
-
path: url.pathname,
|
|
44
|
-
query: url.search ? url.search.substring(1) : '',
|
|
45
|
-
headers,
|
|
46
|
-
|
|
47
|
-
// TLS information
|
|
48
|
-
isTls: !!req.socket.encrypted,
|
|
49
|
-
tlsVersion: options.tlsVersion,
|
|
50
|
-
|
|
51
|
-
// Request objects
|
|
52
|
-
req,
|
|
53
|
-
|
|
54
|
-
// Metadata
|
|
55
|
-
timestamp: Date.now(),
|
|
56
|
-
connectionId: options.connectionId
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Create a route context from HTTP/2 stream and headers
|
|
62
|
-
*/
|
|
63
|
-
public createHttp2RouteContext(
|
|
64
|
-
stream: plugins.http2.ServerHttp2Stream,
|
|
65
|
-
headers: plugins.http2.IncomingHttpHeaders,
|
|
66
|
-
options: {
|
|
67
|
-
connectionId: string;
|
|
68
|
-
clientIp: string;
|
|
69
|
-
serverIp: string;
|
|
70
|
-
}
|
|
71
|
-
): IHttp2RouteContext {
|
|
72
|
-
// Parse headers, excluding HTTP/2 pseudo-headers
|
|
73
|
-
const processedHeaders: Record<string, string> = {};
|
|
74
|
-
for (const [key, value] of Object.entries(headers)) {
|
|
75
|
-
if (!key.startsWith(':') && typeof value === 'string') {
|
|
76
|
-
processedHeaders[key.toLowerCase()] = value;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Get domain from :authority pseudo-header
|
|
81
|
-
const authority = headers[':authority'] as string || '';
|
|
82
|
-
const domain = authority.split(':')[0];
|
|
83
|
-
|
|
84
|
-
// Get path from :path pseudo-header
|
|
85
|
-
const path = headers[':path'] as string || '/';
|
|
86
|
-
|
|
87
|
-
// Parse the path to extract query string
|
|
88
|
-
const pathParts = path.split('?');
|
|
89
|
-
const pathname = pathParts[0];
|
|
90
|
-
const query = pathParts.length > 1 ? pathParts[1] : '';
|
|
91
|
-
|
|
92
|
-
// Get the socket from the session
|
|
93
|
-
const socket = (stream.session as any)?.socket;
|
|
94
|
-
|
|
95
|
-
return {
|
|
96
|
-
// Connection basics
|
|
97
|
-
port: socket?.localPort || 0,
|
|
98
|
-
domain,
|
|
99
|
-
clientIp: options.clientIp,
|
|
100
|
-
serverIp: options.serverIp,
|
|
101
|
-
|
|
102
|
-
// HTTP specifics
|
|
103
|
-
path: pathname,
|
|
104
|
-
query,
|
|
105
|
-
headers: processedHeaders,
|
|
106
|
-
|
|
107
|
-
// HTTP/2 specific properties
|
|
108
|
-
method: headers[':method'] as string,
|
|
109
|
-
stream,
|
|
110
|
-
|
|
111
|
-
// TLS information - HTTP/2 is always on TLS in browsers
|
|
112
|
-
isTls: true,
|
|
113
|
-
tlsVersion: socket?.getTLSVersion?.() || 'TLSv1.3',
|
|
114
|
-
|
|
115
|
-
// Metadata
|
|
116
|
-
timestamp: Date.now(),
|
|
117
|
-
connectionId: options.connectionId
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Create a basic route context from socket information
|
|
123
|
-
*/
|
|
124
|
-
public createSocketRouteContext(socket: plugins.net.Socket, options: {
|
|
125
|
-
domain?: string;
|
|
126
|
-
tlsVersion?: string;
|
|
127
|
-
connectionId: string;
|
|
128
|
-
}): IRouteContext {
|
|
129
|
-
return {
|
|
130
|
-
// Connection basics
|
|
131
|
-
port: socket.localPort || 0,
|
|
132
|
-
domain: options.domain,
|
|
133
|
-
clientIp: socket.remoteAddress?.replace('::ffff:', '') || '0.0.0.0',
|
|
134
|
-
serverIp: socket.localAddress?.replace('::ffff:', '') || '0.0.0.0',
|
|
135
|
-
|
|
136
|
-
// TLS information
|
|
137
|
-
isTls: options.tlsVersion !== undefined,
|
|
138
|
-
tlsVersion: options.tlsVersion,
|
|
139
|
-
|
|
140
|
-
// Metadata
|
|
141
|
-
timestamp: Date.now(),
|
|
142
|
-
connectionId: options.connectionId
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
}
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import * as plugins from '../../plugins.js';
|
|
2
|
-
import * as fs from 'fs';
|
|
3
|
-
import * as path from 'path';
|
|
4
|
-
import { fileURLToPath } from 'url';
|
|
5
|
-
import { AsyncFileSystem } from '../../core/utils/fs-utils.js';
|
|
6
|
-
import type { ILogger, ICertificateEntry } from './models/types.js';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Interface for default certificate data
|
|
10
|
-
*/
|
|
11
|
-
export interface IDefaultCertificates {
|
|
12
|
-
key: string;
|
|
13
|
-
cert: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Provides default SSL certificates for HttpProxy.
|
|
18
|
-
* This is a minimal replacement for the deprecated CertificateManager.
|
|
19
|
-
*
|
|
20
|
-
* For production certificate management, use SmartCertManager instead.
|
|
21
|
-
*/
|
|
22
|
-
export class DefaultCertificateProvider {
|
|
23
|
-
private defaultCertificates: IDefaultCertificates | null = null;
|
|
24
|
-
private certificateCache: Map<string, ICertificateEntry> = new Map();
|
|
25
|
-
private initialized = false;
|
|
26
|
-
|
|
27
|
-
constructor(private logger?: ILogger) {}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Load default certificates asynchronously (preferred)
|
|
31
|
-
*/
|
|
32
|
-
public async loadDefaultCertificatesAsync(): Promise<IDefaultCertificates> {
|
|
33
|
-
if (this.defaultCertificates) {
|
|
34
|
-
return this.defaultCertificates;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
38
|
-
const certPath = path.join(__dirname, '..', '..', '..', 'assets', 'certs');
|
|
39
|
-
|
|
40
|
-
try {
|
|
41
|
-
const [key, cert] = await Promise.all([
|
|
42
|
-
AsyncFileSystem.readFile(path.join(certPath, 'key.pem')),
|
|
43
|
-
AsyncFileSystem.readFile(path.join(certPath, 'cert.pem'))
|
|
44
|
-
]);
|
|
45
|
-
|
|
46
|
-
this.defaultCertificates = { key, cert };
|
|
47
|
-
this.logger?.info?.('Loaded default certificates from filesystem');
|
|
48
|
-
this.initialized = true;
|
|
49
|
-
return this.defaultCertificates;
|
|
50
|
-
} catch (error) {
|
|
51
|
-
this.logger?.warn?.(`Failed to load default certificates: ${error}`);
|
|
52
|
-
this.defaultCertificates = this.generateFallbackCertificate();
|
|
53
|
-
this.initialized = true;
|
|
54
|
-
return this.defaultCertificates;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Load default certificates synchronously (for backward compatibility)
|
|
60
|
-
* @deprecated Use loadDefaultCertificatesAsync instead
|
|
61
|
-
*/
|
|
62
|
-
public loadDefaultCertificatesSync(): IDefaultCertificates {
|
|
63
|
-
if (this.defaultCertificates) {
|
|
64
|
-
return this.defaultCertificates;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
68
|
-
const certPath = path.join(__dirname, '..', '..', '..', 'assets', 'certs');
|
|
69
|
-
|
|
70
|
-
try {
|
|
71
|
-
this.defaultCertificates = {
|
|
72
|
-
key: fs.readFileSync(path.join(certPath, 'key.pem'), 'utf8'),
|
|
73
|
-
cert: fs.readFileSync(path.join(certPath, 'cert.pem'), 'utf8')
|
|
74
|
-
};
|
|
75
|
-
this.logger?.info?.('Loaded default certificates from filesystem (sync)');
|
|
76
|
-
} catch (error) {
|
|
77
|
-
this.logger?.warn?.(`Failed to load default certificates: ${error}`);
|
|
78
|
-
this.defaultCertificates = this.generateFallbackCertificate();
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
this.initialized = true;
|
|
82
|
-
return this.defaultCertificates;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Gets the default certificates (loads synchronously if not already loaded)
|
|
87
|
-
*/
|
|
88
|
-
public getDefaultCertificates(): IDefaultCertificates {
|
|
89
|
-
if (!this.defaultCertificates) {
|
|
90
|
-
return this.loadDefaultCertificatesSync();
|
|
91
|
-
}
|
|
92
|
-
return this.defaultCertificates;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Updates a certificate in the cache
|
|
97
|
-
*/
|
|
98
|
-
public updateCertificate(domain: string, cert: string, key: string): void {
|
|
99
|
-
this.certificateCache.set(domain, {
|
|
100
|
-
cert,
|
|
101
|
-
key,
|
|
102
|
-
expires: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000) // 90 days
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
this.logger?.info?.(`Certificate updated for ${domain}`);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Gets a cached certificate
|
|
110
|
-
*/
|
|
111
|
-
public getCachedCertificate(domain: string): ICertificateEntry | null {
|
|
112
|
-
return this.certificateCache.get(domain) || null;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Gets statistics for metrics
|
|
117
|
-
*/
|
|
118
|
-
public getStats(): { cachedCertificates: number; defaultCertEnabled: boolean } {
|
|
119
|
-
return {
|
|
120
|
-
cachedCertificates: this.certificateCache.size,
|
|
121
|
-
defaultCertEnabled: this.defaultCertificates !== null
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Generate a fallback self-signed certificate placeholder
|
|
127
|
-
* Note: This is just a placeholder - real apps should provide proper certificates
|
|
128
|
-
*/
|
|
129
|
-
private generateFallbackCertificate(): IDefaultCertificates {
|
|
130
|
-
this.logger?.warn?.('Using fallback self-signed certificate placeholder');
|
|
131
|
-
|
|
132
|
-
// Minimal self-signed certificate for fallback only
|
|
133
|
-
// In production, proper certificates should be provided via SmartCertManager
|
|
134
|
-
const selfSignedCert = `-----BEGIN CERTIFICATE-----
|
|
135
|
-
MIIBkTCB+wIJAKHHIgIIA0/cMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNVBAYTAlVT
|
|
136
|
-
MB4XDTE0MDEwMTAwMDAwMFoXDTI0MDEwMTAwMDAwMFowDTELMAkGA1UEBhMCVVMw
|
|
137
|
-
gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMRiH0VwnOH3jCV7c6JFZWYrvuqy
|
|
138
|
-
-----END CERTIFICATE-----`;
|
|
139
|
-
|
|
140
|
-
const selfSignedKey = `-----BEGIN PRIVATE KEY-----
|
|
141
|
-
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMRiH0VwnOH3jCV7
|
|
142
|
-
c6JFZWYrvuqyALCLXj0pcr1iqNdHjegNXnkl5zjdaUjq4edNOKl7M1AlFiYjG2xk
|
|
143
|
-
-----END PRIVATE KEY-----`;
|
|
144
|
-
|
|
145
|
-
return {
|
|
146
|
-
key: selfSignedKey,
|
|
147
|
-
cert: selfSignedCert
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
}
|