dev-sidecar/packages/mitmproxy/src/lib/proxy/tls/FakeServersCenter.js

114 lines
3.6 KiB
JavaScript

const https = require('https')
const tlsUtils = require('./tlsUtils')
const CertAndKeyContainer = require('./CertAndKeyContainer')
const forge = require('node-forge')
const pki = forge.pki
// const colors = require('colors')
const tls = require('tls')
const log = require('../../../utils/util.log')
module.exports = class FakeServersCenter {
constructor ({ maxLength = 256, requestHandler, upgradeHandler, caCert, caKey, getCertSocketTimeout }) {
this.queue = []
this.maxLength = maxLength
this.requestHandler = requestHandler
this.upgradeHandler = upgradeHandler
this.certAndKeyContainer = new CertAndKeyContainer({
getCertSocketTimeout,
caCert,
caKey
})
}
addServerPromise (serverPromiseObj) {
if (this.queue.length >= this.maxLength) {
const delServerObj = this.queue.shift()
try {
log.info('超过最大服务数量,删除旧服务', delServerObj)
delServerObj.serverObj.server.close()
} catch (e) {
log.info(e)
}
}
this.queue.push(serverPromiseObj)
return serverPromiseObj
}
getServerPromise (hostname, port) {
for (let i = 0; i < this.queue.length; i++) {
const serverPromiseObj = this.queue[i]
const mappingHostNames = serverPromiseObj.mappingHostNames
for (let j = 0; j < mappingHostNames.length; j++) {
const DNSName = mappingHostNames[j]
if (tlsUtils.isMappingHostName(DNSName, hostname)) {
this.reRankServer(i)
return serverPromiseObj.promise
}
}
}
const serverPromiseObj = {
mappingHostNames: [hostname] // temporary hostname
}
const promise = new Promise((resolve, reject) => {
(async () => {
const certObj = await this.certAndKeyContainer.getCertPromise(hostname, port)
const cert = certObj.cert
const key = certObj.key
const certPem = pki.certificateToPem(cert)
const keyPem = pki.privateKeyToPem(key)
const fakeServer = new https.Server({
key: keyPem,
cert: certPem,
SNICallback: (hostname, done) => {
(async () => {
const certObj = await this.certAndKeyContainer.getCertPromise(hostname, port)
log.info('sni callback:', hostname)
done(null, tls.createSecureContext({
key: pki.privateKeyToPem(certObj.key),
cert: pki.certificateToPem(certObj.cert)
}))
})()
}
})
const serverObj = {
cert,
key,
server: fakeServer,
port: 0 // if prot === 0 ,should listen server's `listening` event.
}
serverPromiseObj.serverObj = serverObj
fakeServer.listen(0, () => {
const address = fakeServer.address()
serverObj.port = address.port
})
fakeServer.on('request', (req, res) => {
const ssl = true
this.requestHandler(req, res, ssl)
})
fakeServer.on('error', (e) => {
log.error(e)
})
fakeServer.on('listening', () => {
const mappingHostNames = tlsUtils.getMappingHostNamesFromCert(certObj.cert)
serverPromiseObj.mappingHostNames = mappingHostNames
resolve(serverObj)
})
fakeServer.on('upgrade', (req, socket, head) => {
const ssl = true
this.upgradeHandler(req, socket, head, ssl)
})
})()
})
serverPromiseObj.promise = promise
return (this.addServerPromise(serverPromiseObj)).promise
}
reRankServer (index) {
// index ==> queue foot
this.queue.push((this.queue.splice(index, 1))[0])
}
}