UNPKG

@push.rocks/smartproxy

Version:

A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.

297 lines 27.8 kB
import * as plugins from '../../plugins.js'; import { logger } from '../../core/utils/logger.js'; const maxChallengeRelayMessageBytes = 1024 * 1024; const maxChallengeRelayIdBytes = 256; export class ChallengeProviderRelayServer { providers; providerTimeoutMs; maxActiveProviderOperations; maxUnsettledProviderOperations; activeProviderOperations = 0; unsettledProviderOperations = 0; server = null; socketPath; activeSockets = new Set(); startPromise; constructor(providers, optionsArg = {}) { this.providers = providers; this.socketPath = `/tmp/smartproxy-challenge-relay-${process.pid}-${plugins.crypto.randomBytes(8).toString('hex')}.sock`; this.providerTimeoutMs = Math.max(1, optionsArg.providerTimeoutMs ?? 5_000); this.maxActiveProviderOperations = Math.max(1, optionsArg.maxActiveProviderOperations ?? 1024); this.maxUnsettledProviderOperations = Math.max(1, optionsArg.maxUnsettledProviderOperations ?? this.maxActiveProviderOperations); } getSocketPath() { return this.socketPath; } async start() { if (this.server) return; if (this.startPromise) return this.startPromise; this.startPromise = this.startInternal(); try { await this.startPromise; } finally { this.startPromise = undefined; } } async startInternal() { try { await plugins.fs.promises.unlink(this.socketPath); } catch { // Ignore stale socket cleanup failures for missing files. } const server = plugins.net.createServer((socket) => { this.activeSockets.add(socket); socket.once('close', () => this.activeSockets.delete(socket)); this.handleConnection(socket); }); server.on('error', (err) => { logger.log('error', `ChallengeProviderRelayServer error: ${err.message}`, { component: 'challenge-provider-relay-server' }); }); await new Promise((resolve, reject) => { const handleError = (err) => reject(err); server.once('error', handleError); server.listen(this.socketPath, () => { server.off('error', handleError); this.server = server; logger.log('info', `ChallengeProviderRelayServer listening on ${this.socketPath}`, { component: 'challenge-provider-relay-server' }); resolve(); }); }).catch((err) => { server.close(); throw err; }); } async stop() { if (this.startPromise && !this.server) { await this.startPromise.catch(() => undefined); } for (const socket of this.activeSockets) { socket.destroy(); } this.activeSockets.clear(); const server = this.server; if (!server) return; this.server = null; await new Promise((resolve) => { server.close(() => { plugins.fs.unlink(this.socketPath, () => resolve()); }); }); } handleConnection(socket) { let buffer = Buffer.alloc(0); socket.setTimeout(Math.max(10_000, this.providerTimeoutMs + 1_000)); socket.on('timeout', () => socket.destroy()); socket.on('error', (err) => { logger.log('warn', `Challenge relay socket error: ${err.message}`, { component: 'challenge-provider-relay-server' }); }); socket.on('data', (chunk) => { buffer = buffer.length === 0 ? chunk : Buffer.concat([buffer, chunk], buffer.length + chunk.length); if (buffer.length > maxChallengeRelayMessageBytes) { socket.removeAllListeners('data'); this.writeResponse(socket, { success: false, error: 'Challenge relay request exceeds maximum size' }); buffer = Buffer.alloc(0); socket.end(); return; } const newlineIndex = buffer.indexOf(0x0a); if (newlineIndex === -1) return; const line = buffer.subarray(0, newlineIndex).toString('utf8'); socket.removeAllListeners('data'); this.dispatchLine(line) .then((response) => this.writeResponse(socket, response)) .catch((err) => this.writeResponse(socket, { success: false, error: err.message })) .finally(() => socket.end()); }); } async dispatchLine(lineArg) { let request; try { request = JSON.parse(lineArg); } catch { return { success: false, error: 'Invalid challenge relay JSON' }; } const provider = this.providers.get(request.providerId); if (!provider) { return { id: request.id, success: false, error: `Challenge provider '${request.providerId}' is not registered`, }; } switch (request.operation) { case 'assess': return { id: request.id, success: true, result: await this.withProviderTimeout(() => provider.assess(request.request), 'assess') }; case 'render': return { id: request.id, success: true, result: await this.withProviderTimeout(() => provider.render(request.request), 'render') }; case 'verify': return { id: request.id, success: true, result: await this.withProviderTimeout(() => provider.verify(request.request), 'verify') }; default: const operationValue = request.operation; return { id: request.id, success: false, error: `Unsupported challenge relay operation '${String(operationValue)}'` }; } } async withProviderTimeout(operationArg, operationNameArg) { if (this.activeProviderOperations >= this.maxActiveProviderOperations) { throw new Error(`Challenge provider ${operationNameArg} rejected because too many operations are active`); } if (this.unsettledProviderOperations >= this.maxUnsettledProviderOperations) { throw new Error(`Challenge provider ${operationNameArg} rejected because too many timed-out operations are still settling`); } let timer; let activeReleased = false; let unsettledReleased = false; const releaseActive = () => { if (!activeReleased) { activeReleased = true; this.activeProviderOperations -= 1; } }; const releaseUnsettled = () => { if (!unsettledReleased) { unsettledReleased = true; this.unsettledProviderOperations -= 1; } }; this.activeProviderOperations += 1; this.unsettledProviderOperations += 1; const providerPromise = Promise.resolve().then(operationArg); const trackedProviderPromise = providerPromise.then((result) => { releaseActive(); releaseUnsettled(); return result; }, (err) => { releaseActive(); releaseUnsettled(); throw err; }); trackedProviderPromise.catch(() => undefined); try { return await Promise.race([ trackedProviderPromise, new Promise((_resolve, reject) => { timer = setTimeout(() => { releaseActive(); reject(new Error(`Challenge provider ${operationNameArg} timed out after ${this.providerTimeoutMs}ms`)); }, this.providerTimeoutMs); }), ]); } finally { if (timer) clearTimeout(timer); } } writeResponse(socket, responseArg) { let response = responseArg; if (this.estimateJsonByteLength(response, maxChallengeRelayMessageBytes) === undefined) { response = this.createErrorResponse(responseArg.id, 'Challenge relay response exceeds maximum size'); } let serializedResponse; try { serializedResponse = JSON.stringify(response); } catch { serializedResponse = JSON.stringify(this.createErrorResponse(responseArg.id, 'Challenge relay response is not serializable')); } if (Buffer.byteLength(serializedResponse, 'utf8') > maxChallengeRelayMessageBytes) { serializedResponse = JSON.stringify({ success: false, error: 'Challenge relay response exceeds maximum size', }); } socket.write(`${serializedResponse}\n`); } createErrorResponse(idArg, errorArg) { const response = { success: false, error: errorArg, }; if (idArg && Buffer.byteLength(idArg, 'utf8') <= maxChallengeRelayIdBytes) { response.id = idArg; } return response; } estimateJsonByteLength(valueArg, maxBytesArg, seenArg = new Set()) { const bytes = this.estimateJsonByteLengthInternal(valueArg, maxBytesArg, seenArg); return bytes !== undefined && bytes <= maxBytesArg ? bytes : undefined; } estimateJsonByteLengthInternal(valueArg, maxBytesArg, seenArg) { if (valueArg === null) return 4; if (typeof valueArg === 'string') return this.estimateJsonStringByteLength(valueArg, maxBytesArg); if (typeof valueArg === 'number') return Number.isFinite(valueArg) ? String(valueArg).length : 4; if (typeof valueArg === 'boolean') return valueArg ? 4 : 5; if (typeof valueArg === 'undefined') return 4; if (typeof valueArg === 'bigint' || typeof valueArg === 'symbol' || typeof valueArg === 'function') return undefined; if (typeof valueArg !== 'object') return undefined; if (seenArg.has(valueArg)) return undefined; seenArg.add(valueArg); try { let totalBytes = 2; if (Array.isArray(valueArg)) { for (let i = 0; i < valueArg.length; i++) { const childBytes = this.estimateJsonByteLengthInternal(valueArg[i], maxBytesArg, seenArg); if (childBytes === undefined) return undefined; totalBytes += childBytes + (i > 0 ? 1 : 0); if (totalBytes > maxBytesArg) return undefined; } return totalBytes; } let propertyCount = 0; for (const [key, value] of Object.entries(valueArg)) { if (typeof value === 'undefined' || typeof value === 'function' || typeof value === 'symbol') continue; const keyBytes = this.estimateJsonStringByteLength(key, maxBytesArg); const valueBytes = this.estimateJsonByteLengthInternal(value, maxBytesArg, seenArg); if (keyBytes === undefined || valueBytes === undefined) return undefined; totalBytes += keyBytes + valueBytes + 1 + (propertyCount > 0 ? 1 : 0); propertyCount += 1; if (totalBytes > maxBytesArg) return undefined; } return totalBytes; } finally { seenArg.delete(valueArg); } } estimateJsonStringByteLength(valueArg, maxBytesArg) { let bytes = Buffer.byteLength(valueArg, 'utf8') + 2; if (bytes > maxBytesArg) return undefined; for (let i = 0; i < valueArg.length; i++) { const code = valueArg.charCodeAt(i); if (code === 0x22 || code === 0x5c) { bytes += 1; } else if (code === 0x08 || code === 0x09 || code === 0x0a || code === 0x0c || code === 0x0d) { bytes += 1; } else if (code < 0x20) { bytes += 5; } if (bytes > maxBytesArg) return undefined; } return bytes; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhbGxlbmdlLXByb3ZpZGVyLXJlbGF5LXNlcnZlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL3Byb3hpZXMvc21hcnQtcHJveHkvY2hhbGxlbmdlLXByb3ZpZGVyLXJlbGF5LXNlcnZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGtCQUFrQixDQUFDO0FBQzVDLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQWtCcEQsTUFBTSw2QkFBNkIsR0FBRyxJQUFJLEdBQUcsSUFBSSxDQUFDO0FBQ2xELE1BQU0sd0JBQXdCLEdBQUcsR0FBRyxDQUFDO0FBUXJDLE1BQU0sT0FBTyw0QkFBNEI7SUFZN0I7SUFYRixpQkFBaUIsQ0FBUztJQUMxQiwyQkFBMkIsQ0FBUztJQUNwQyw4QkFBOEIsQ0FBUztJQUN2Qyx3QkFBd0IsR0FBRyxDQUFDLENBQUM7SUFDN0IsMkJBQTJCLEdBQUcsQ0FBQyxDQUFDO0lBQ2hDLE1BQU0sR0FBOEIsSUFBSSxDQUFDO0lBQ3pDLFVBQVUsQ0FBUztJQUNuQixhQUFhLEdBQUcsSUFBSSxHQUFHLEVBQXNCLENBQUM7SUFDOUMsWUFBWSxDQUFpQjtJQUVyQyxZQUNVLFNBQWlFLEVBQ3pFLGFBQW1ELEVBQUU7UUFEN0MsY0FBUyxHQUFULFNBQVMsQ0FBd0Q7UUFHekUsSUFBSSxDQUFDLFVBQVUsR0FBRyxtQ0FBbUMsT0FBTyxDQUFDLEdBQUcsSUFBSSxPQUFPLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQztRQUN6SCxJQUFJLENBQUMsaUJBQWlCLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsVUFBVSxDQUFDLGlCQUFpQixJQUFJLEtBQUssQ0FBQyxDQUFDO1FBQzVFLElBQUksQ0FBQywyQkFBMkIsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFD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