// One single CONNECT attempt with candidate creds against the upstream proxy. // Used by install.js (credential setup) and proxyctl.js (reauth). NEVER retries, // NEVER logs the password, resolves: 'ok' | 'authfail' | 'unreachable' const net = require('net'); function verifyProxyCredentials(host, port, username, password, timeoutMs = 10000) { return new Promise((resolve) => { const socket = net.connect(Number(port), host); let buf = Buffer.alloc(0); const finish = (r) => { try { socket.destroy(); } catch {} resolve(r); }; socket.setTimeout(timeoutMs, () => finish('unreachable')); socket.once('connect', () => { const auth = 'Basic ' + Buffer.from(`${username}:${password}`).toString('base64'); socket.write(`CONNECT 127.0.0.1:443 HTTP/1.1\r\nHost: 127.0.0.1:443\r\nProxy-Authorization: ${auth}\r\n\r\n`); }); socket.on('data', (d) => { buf = Buffer.concat([buf, d]); const head = buf.toString('latin1').split('\r\n')[0] || ''; const m = head.match(/^HTTP\/\d\.\d\s+(\d{3})/i); if (m || buf.includes('\r\n\r\n')) { const code = m ? Number(m[1]) : 0; // 200/4xx non-407 (e.g. 403 for the probe target) = creds accepted; 407 = rejected. finish(code === 407 ? 'authfail' : (code > 0 ? 'ok' : 'unreachable')); } }); socket.once('error', () => finish('unreachable')); socket.once('end', () => { if (buf.length === 0) finish('unreachable'); }); }); } module.exports = { verifyProxyCredentials };