Skip to content

Instantly share code, notes, and snippets.

@nondanee
Last active February 13, 2022 17:30
Show Gist options
  • Save nondanee/b50d6107cdafa2460c81d929b2b2f91f to your computer and use it in GitHub Desktop.
Save nondanee/b50d6107cdafa2460c81d929b2b2f91f to your computer and use it in GitHub Desktop.
a simple proxy server with https tunnel and basic authentication
const fs = require('fs')
/*
module.exports = {
key: fs.readFileSync('domain.key'),
cert: fs.readFileSync('fullchain.cer'),
}
*/
#!/usr/bin/env node
const net = require('net')
const URL = require('url')
const http = require('http')
const https = require('https')
const config = require('./config')
const PORT = process.argv[2] || 8080
const CREDENTIALS = process.argv[3] || 'app:test'
const server = (config ? https : http).createServer(config).listen(PORT)
const close = socket => (socket.end(), socket.destroy())
const verify = (headers, socket) => {
const token = (headers['proxy-authorization'] || '').slice(6)
const credentials = (Buffer.from(token, 'base64')).toString()
if (credentials === CREDENTIALS) return true
socket.write('HTTP/1.1 407 Proxy Auth Required\r\nProxy-Authenticate: Basic realm="simple"\r\n\r\n')
}
const mock = (res) => {
const headers = { 'Server': 'nginx', 'Content-Type': 'text/html' }
const html = '<html>\n<head><title>404 Not Found</title></head>\n<body>\n<center><h1>404 Not Found</h1></center>\n<hr><center>nginx</center>\n</body>\n</html>\n<!-- a padding to disable MSIE and Chrome friendly error page -->\n<!-- a padding to disable MSIE and Chrome friendly error page -->\n<!-- a padding to disable MSIE and Chrome friendly error page -->\n<!-- a padding to disable MSIE and Chrome friendly error page -->\n<!-- a padding to disable MSIE and Chrome friendly error page -->\n<!-- a padding to disable MSIE and Chrome friendly error page -->\n'
res.writeHead(404, headers)
res.end(html)
return
}
const log = (...payload) => {
if (!process.env.LOG) return
console.log(...payload)
}
// MITM Mode
server.on('request', (req, res) => {
const { method, url, headers, socket } = req
if (!url.startsWith('http://')) return mock(res)
if (!verify(headers, socket)) return close(socket)
const target = URL.parse(url)
log('MITM', '>', target.hostname)
const proxyReq = http.request(Object.assign(target, { method, headers }))
.on('response', proxyRes => {
res.writeHead(proxyRes.statusCode, proxyRes.headers)
proxyRes.pipe(res)
})
.on('error', () => close(socket))
req.pipe(proxyReq).on('error', () => close(socket))
})
// Tunnel Mode
server.on('connect', (req, socket, head) => {
const { url, headers } = req
if (!verify(headers, socket)) return close(socket)
const { port, hostname } = URL.parse('https://' + url)
log('TUNNEL', '>', hostname)
const proxySocket = net.connect(port, hostname)
.on('connect', () => {
socket.write('HTTP/1.1 200 Connection established\r\n\r\n')
proxySocket.write(head)
proxySocket.pipe(socket)
socket.pipe(proxySocket)
})
.on('error', () => close(socket))
socket.on('error', () => close(socket))
})
console.log(`Server ${CREDENTIALS} running @ ${server.cert ? 'https' : 'http'}://0.0.0.0:${PORT}`)
{
"name": "simple-proxy",
"version": "0.1.3",
"main": "index.js",
"bin": "./index.js",
"author": "nondanee"
}
@nondanee
Copy link
Author

nondanee commented Sep 11, 2018

@nondanee
Copy link
Author

tarampampam/node:alpine
npx https://gist.github.com/nondanee/b50d6107cdafa2460c81d929b2b2f91f

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment