Files
admin 875c7f9b91 feat: Complete zCode CLI X with Telegram bot integration
- Add full Telegram bot functionality with Z.AI API integration
- Implement 4 tools: Bash, FileEdit, WebSearch, Git
- Add 3 agents: Code Reviewer, Architect, DevOps Engineer
- Add 6 skills for common coding tasks
- Add systemd service file for 24/7 operation
- Add nginx configuration for HTTPS webhook
- Add comprehensive documentation
- Implement WebSocket server for real-time updates
- Add logging system with Winston
- Add environment validation

🤖 zCode CLI X - Agentic coder with Z.AI + Telegram integration
2026-05-05 09:01:26 +00:00

154 lines
6.6 KiB
JavaScript

import { createServer } from '@pondwader/socks5-server';
import { logForDebugging } from '../utils/debug.js';
import { connectViaParentProxy, dialDirect, isValidHost, selectParentProxyUrl, shouldBypassParentProxy, } from './parent-proxy.js';
export function createSocksProxyServer(options) {
const socksServer = createServer();
socksServer.setRulesetValidator(async (conn) => {
try {
const hostname = conn.destAddress;
const port = conn.destPort;
// SOCKS5 DOMAINNAME is a raw length-prefixed byte string with zero
// validation from the protocol or the library. Reject control chars
// (null bytes, CRLF) here so they never reach the allowlist matcher,
// where string suffix matching would be trivially fooled.
if (!isValidHost(hostname)) {
logForDebugging(`Rejecting malformed SOCKS host: ${JSON.stringify(hostname)}`, { level: 'error' });
return false;
}
logForDebugging(`Connection request to ${hostname}:${port}`);
const allowed = await options.filter(port, hostname);
if (!allowed) {
logForDebugging(`Connection blocked to ${hostname}:${port}`, {
level: 'error',
});
return false;
}
logForDebugging(`Connection allowed to ${hostname}:${port}`);
return true;
}
catch (error) {
logForDebugging(`Error validating connection: ${error}`, {
level: 'error',
});
return false;
}
});
// Override the default connection handler so we can route through a parent
// HTTP proxy when one is configured. The default handler does a straight
// net.connect() which fails when direct egress is blocked.
socksServer.setConnectionHandler((conn, sendStatus) => {
const host = conn.destAddress;
const port = conn.destPort;
// Track client liveness so we can abort the upstream dial if they bail.
let clientGone = false;
let upstreamRef;
conn.socket.once('close', () => {
clientGone = true;
upstreamRef?.destroy();
});
conn.socket.on('error', () => upstreamRef?.destroy());
// SOCKS is an opaque TCP tunnel — semantically identical to HTTP
// CONNECT — so always prefer HTTPS_PROXY if set, regardless of dest port.
const parentUrl = options.parentProxy && !shouldBypassParentProxy(options.parentProxy, host)
? selectParentProxyUrl(options.parentProxy, { isHttps: true })
: undefined;
const open = parentUrl
? connectViaParentProxy(parentUrl, host, port)
: dialDirect(host, port);
open
.then(upstream => {
upstreamRef = upstream;
upstream.on('error', () => conn.socket.destroy());
if (clientGone) {
upstream.destroy();
return;
}
sendStatus('REQUEST_GRANTED');
upstream.pipe(conn.socket);
conn.socket.pipe(upstream);
upstream.on('close', () => conn.socket.destroy());
})
.catch(err => {
logForDebugging(`SOCKS connect to ${host}:${port} failed: ${err.message}`, { level: 'error' });
if (!clientGone) {
try {
sendStatus('HOST_UNREACHABLE');
}
catch {
// socket may have closed between the check and the write
}
}
});
});
return {
server: socksServer,
getPort() {
// Access the internal server to get the port
// We need to use type assertion here as the server property is private
try {
const serverInternal = socksServer?.server;
if (serverInternal && typeof serverInternal?.address === 'function') {
const address = serverInternal.address();
if (address && typeof address === 'object' && 'port' in address) {
return address.port;
}
}
}
catch (error) {
// Server might not be listening yet or property access failed
logForDebugging(`Error getting port: ${error}`, { level: 'error' });
}
return undefined;
},
listen(port, hostname) {
return new Promise((resolve, reject) => {
const serverInternal = socksServer?.server;
serverInternal?.once('error', reject);
const listeningCallback = () => {
serverInternal?.removeListener('error', reject);
const actualPort = this.getPort();
if (actualPort) {
logForDebugging(`SOCKS proxy listening on ${hostname}:${actualPort}`);
resolve(actualPort);
}
else {
reject(new Error('Failed to get SOCKS proxy server port'));
}
};
socksServer.listen(port, hostname, listeningCallback);
});
},
async close() {
return new Promise((resolve, reject) => {
socksServer.close(error => {
if (error) {
// Only reject for actual errors, not for "already closed" states
// Check for common "already closed" error patterns
const errorMessage = error.message?.toLowerCase() || '';
const isAlreadyClosed = errorMessage.includes('not running') ||
errorMessage.includes('already closed') ||
errorMessage.includes('not listening');
if (!isAlreadyClosed) {
reject(error);
return;
}
}
resolve();
});
});
},
unref() {
// Access the internal server to call unref
try {
const serverInternal = socksServer?.server;
if (serverInternal && typeof serverInternal?.unref === 'function') {
serverInternal.unref();
}
}
catch (error) {
logForDebugging(`Error calling unref: ${error}`, { level: 'error' });
}
},
};
}
//# sourceMappingURL=socks-proxy.js.map