proxy-bridge: add keyring-based HTTP CONNECT proxy bridge
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
const http = require('http');
|
||||
const net = require('net');
|
||||
const { execSync } = require('child_process');
|
||||
const fs = require('fs');
|
||||
|
||||
// 1. CONFIGURATION
|
||||
const PROXY_HOST = 'PROXY_HOST_PLACEHOLDER';
|
||||
const PROXY_PORT = 8080;
|
||||
|
||||
// 2. FETCH SECRETS FROM KEYRING
|
||||
let USER, PASS;
|
||||
try {
|
||||
// Read the username we saved during setup
|
||||
USER = JSON.parse(fs.readFileSync('/opt/proxy-bridge/user.json')).username;
|
||||
// Query the Ubuntu Keyring for the password associated with this user/service
|
||||
PASS = execSync(`secret-tool lookup service proxy-bridge account ${USER}`).toString().trim();
|
||||
|
||||
if (!PASS) throw new Error("Password returned empty.");
|
||||
} catch (e) {
|
||||
console.error("CRITICAL: Could not retrieve credentials from keyring. Did you run setup.js?");
|
||||
console.error(e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 3. GENERATE AUTH
|
||||
const AUTH_HEADER = 'Basic ' + Buffer.from(`${USER}:${PASS}`).toString('base64');
|
||||
|
||||
const server = http.createServer();
|
||||
|
||||
server.on('connect', (req, clientSocket, head) => {
|
||||
console.log(`--> Connecting to ${req.url}`);
|
||||
|
||||
const serverSocket = net.connect(PROXY_PORT, PROXY_HOST, () => {
|
||||
serverSocket.write(`CONNECT ${req.url} HTTP/1.1\r\n` +
|
||||
`Host: ${req.url}\r\n` +
|
||||
`Proxy-Authorization: ${AUTH_HEADER}\r\n` +
|
||||
`Proxy-Connection: Keep-Alive\r\n\r\n`);
|
||||
serverSocket.write(head);
|
||||
});
|
||||
|
||||
serverSocket.once('data', (data) => {
|
||||
if (data.toString().includes('200')) {
|
||||
clientSocket.write('HTTP/1.1 200 Connection Established\r\n\r\n');
|
||||
serverSocket.pipe(clientSocket);
|
||||
clientSocket.pipe(serverSocket);
|
||||
} else {
|
||||
clientSocket.write(data);
|
||||
}
|
||||
});
|
||||
|
||||
serverSocket.on('error', () => clientSocket.end());
|
||||
clientSocket.on('error', () => serverSocket.end());
|
||||
});
|
||||
|
||||
server.listen(8888, '127.0.0.1', () => {
|
||||
console.log('Bridge active on http://127.0.0.1:8888 (Auth via Keyring)');
|
||||
});
|
||||
Executable
+70
@@ -0,0 +1,70 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Ensure the script is NOT run as root, so the user-level systemd service configures correctly
|
||||
if [ "$EUID" -eq 0 ]; then
|
||||
echo "❌ Please run this script as your standard user, not as root."
|
||||
echo "The script will prompt for sudo access automatically when needed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=== Proxy Bridge Installer ==="
|
||||
|
||||
# 1. Verify files exist
|
||||
if [ ! -f "bridge.js" ] || [ ! -f "setup.js" ]; then
|
||||
echo "❌ Error: bridge.js and/or setup.js not found in the current directory."
|
||||
echo "Please place this script in the same folder as your Node.js scripts."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 2. Install dependencies (requires sudo)
|
||||
echo "--> Installing required system packages (libsecret-tools)..."
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libsecret-tools
|
||||
|
||||
# 3. Setup application directory (requires sudo)
|
||||
echo "--> Creating /opt/proxy-bridge directory..."
|
||||
sudo mkdir -p /opt/proxy-bridge
|
||||
sudo chown -R $USER:$USER /opt/proxy-bridge
|
||||
|
||||
# 4. Copy files
|
||||
echo "--> Copying scripts to /opt/proxy-bridge..."
|
||||
cp bridge.js /opt/proxy-bridge/
|
||||
cp setup.js /opt/proxy-bridge/
|
||||
|
||||
# 5. Setup User-Level systemd Service
|
||||
echo "--> Configuring user-level systemd service..."
|
||||
mkdir -p ~/.config/systemd/user/
|
||||
|
||||
cat <<EOF > ~/.config/systemd/user/proxy-bridge.service
|
||||
[Unit]
|
||||
Description=Dumb Pipe Proxy Bridge (Keyring Auth)
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/bin/node /opt/proxy-bridge/bridge.js
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
EOF
|
||||
|
||||
# 6. Enable the service
|
||||
echo "--> Reloading systemd and enabling service..."
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user enable proxy-bridge.service
|
||||
|
||||
echo ""
|
||||
echo "✅ Installation Complete!"
|
||||
echo "=================================================="
|
||||
echo "Next Steps:"
|
||||
echo "1. Run the interactive setup to store your proxy credentials:"
|
||||
echo " node /opt/proxy-bridge/setup.js"
|
||||
echo ""
|
||||
echo "2. Start the background service:"
|
||||
echo " systemctl --user start proxy-bridge.service"
|
||||
echo ""
|
||||
echo "3. Check the logs to ensure it's running smoothly:"
|
||||
echo " journalctl --user -u proxy-bridge.service -f"
|
||||
echo "=================================================="
|
||||
@@ -0,0 +1,34 @@
|
||||
const readline = require('readline');
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
console.log("=== Proxy Bridge Keyring Setup ===");
|
||||
|
||||
rl.question('Enter your corporate username: ', (user) => {
|
||||
rl.question('Enter your corporate password: ', (pass) => {
|
||||
try {
|
||||
// Securely store the password in the Ubuntu Keyring using secret-tool
|
||||
// We use standard input to pass the password so it doesn't appear in process lists
|
||||
execSync(`secret-tool store --label="Proxy Bridge Credentials" service proxy-bridge account ${user}`, {
|
||||
input: pass
|
||||
});
|
||||
|
||||
// Store the username in a local config just so the bridge knows WHICH account to look up
|
||||
require('fs').writeFileSync('/opt/proxy-bridge/user.json', JSON.stringify({ username: user }));
|
||||
|
||||
console.log("\n✅ Credentials successfully stored in the system keyring.");
|
||||
} catch (error) {
|
||||
console.error("\n❌ Failed to store credentials in keyring:", error.message);
|
||||
}
|
||||
rl.close();
|
||||
});
|
||||
|
||||
// Hide typing for password (basic implementation)
|
||||
rl._writeToOutput = function _writeToOutput(stringToWrite) {
|
||||
if (rl.history.length === 0) rl.output.write("*");
|
||||
};
|
||||
});
|
||||
Reference in New Issue
Block a user