// Shared apt proxy audit logic — used by install.js (Legacy section) and doctor mode. const fs = require('fs'); const path = require('path'); const BRIDGE_MARK = '127.0.0.1:8888'; // One finding per file that declares Acquire proxy directives. // severity: 'ok' (bridge URL, sorted before-or-at our file, no creds) // 'overrides' (proxy directives in a file sorting AFTER 80proxy-bridge → apt last-wins) // 'creds' (embedded userinfo — plaintext-leak + stale-cred hammering risk) // 'external' (points at a non-bridge proxy; may be intentional, but defeats the bridge) function scanAptProxies(aptConfDir, bridgeFileName = '80proxy-bridge') { const findings = []; const files = []; try { for (const f of fs.readdirSync(aptConfDir)) { const p = path.join(aptConfDir, f); try { if (fs.statSync(p).isFile()) files.push(f); } catch {} } } catch { return { findings, error: `cannot read ${aptConfDir}` }; } const bridgeRank = bridgeFileName; const bridgeFilePresent = files.includes(bridgeRank); for (const f of files.sort()) { const p = path.join(aptConfDir, f); let content = ''; try { content = fs.readFileSync(p, 'utf8'); } catch { continue; } const proxyLines = content.split('\n') .map(l => l.trim()) .filter(l => /^(Acquire::(http|https)::Proxy)\s/i.test(l)); if (proxyLines.length === 0) continue; const hasCreds = proxyLines.some(l => /:\/\/[^/\s"]+:[^@\s"]+@/.test(l)); const allBridge = proxyLines.every(l => l.includes(BRIDGE_MARK)); const sortsAfterBridge = f > bridgeRank; // apt merges alphabetically; later wins let severity = 'ok'; if (f === bridgeRank) severity = allBridge && !hasCreds ? 'ok' : (hasCreds ? 'creds' : 'external'); else if (hasCreds) severity = 'creds'; else if (sortsAfterBridge && bridgeFilePresent) severity = 'overrides'; else if (sortsAfterBridge && allBridge) severity = 'ok'; // redundant bridge copy, harmless else if (!allBridge) severity = 'external'; // sorted BEFORE us and external -> harmless but noteworthy; we still report as external findings.push({ file: p, name: f, severity, directives: proxyLines.length, creds: hasCreds, bridge: allBridge, sortsAfterBridge, }); } return { findings }; } function summarizeAptFindings(findings) { const bad = findings.filter(f => f.severity !== 'ok'); const bridgeFile = findings.find(f => f.severity === 'ok' && f.bridge); return { bridgePresent: !!bridgeFile, threats: bad }; } module.exports = { scanAptProxies, summarizeAptFindings, BRIDGE_MARK };