From 721bb0a6d4ee7b5fc7606a7b4f51fc3cf9c34166 Mon Sep 17 00:00:00 2001 From: zefie Date: Thu, 23 Apr 2026 16:18:07 -0400 Subject: [PATCH] https workaround for bitdefender mitm ssl proxy --- .../includes/classes/WTVHTTP.js | 22 +++++++-- zefie_wtvp_minisrv/includes/classes/WTVSSL.js | 45 +++++++++++++++++++ zefie_wtvp_minisrv/includes/config.json | 3 +- 3 files changed, 65 insertions(+), 5 deletions(-) diff --git a/zefie_wtvp_minisrv/includes/classes/WTVHTTP.js b/zefie_wtvp_minisrv/includes/classes/WTVHTTP.js index b20250e7..68b0eab8 100644 --- a/zefie_wtvp_minisrv/includes/classes/WTVHTTP.js +++ b/zefie_wtvp_minisrv/includes/classes/WTVHTTP.js @@ -77,10 +77,6 @@ class WTVHTTP { // configure connection to remote socks proxy const { SocksProxyAgent }= require('socks-proxy-agent'); options.agent = new SocksProxyAgent("socks://" + (minisrv_config.services[request_type].external_proxy_host || "127.0.0.1") + ":" + minisrv_config.services[request_type].external_proxy_port); - options.agents = { - "http": options.agent, - "https": options.agent - } } else { // configure connection to remote http proxy this.proxy_agent = this.http; @@ -97,6 +93,24 @@ class WTVHTTP { options.headers.Connection = 'close' } } + if (this.minisrv_config.services[request_type].support_bitdefender_self_signed_proxy) { + try { + const WTVSSL = require('./WTVSSL.js'); + const ssl = new WTVSSL(); + const bitdefenderCACert = ssl.getBitdefenderCACert(); + if (bitdefenderCACert) { + options.ca = [bitdefenderCACert]; + // this sucks, but bitdefender's cert is weird and doesn't seem to work properly with Node's TLS implementation + // even when added to the trusted store, so we have to disable rejection of unauthorized certs + // when the Bitdefender CA cert is present. At least this way we can still allow it without + // completely breaking SSL proxying for Bitdefender users. + // This will only trigger on Windows if support_bitdefender_self_signed_proxy is true, and the Bitdefender CA file exists + options.rejectUnauthorized = false; + } + } catch (err) { + console.warn(" * Failed to load Bitdefender CA certificate:", err.message); + } + } const req = this.proxy_agent.request(options, (res) => { let total_data = 0; diff --git a/zefie_wtvp_minisrv/includes/classes/WTVSSL.js b/zefie_wtvp_minisrv/includes/classes/WTVSSL.js index d3ea0906..0e89633f 100644 --- a/zefie_wtvp_minisrv/includes/classes/WTVSSL.js +++ b/zefie_wtvp_minisrv/includes/classes/WTVSSL.js @@ -13,6 +13,51 @@ class WTVSSL { } return this.wtvshared.fs.readFileSync(caCertFile); } + + derToPem(derBuffer) { + const base64 = derBuffer.toString("base64"); + const pem = [ + "-----BEGIN CERTIFICATE-----", + base64.match(/.{1,64}/g).join("\n"), + "-----END CERTIFICATE-----" + ].join("\n"); + + return pem; + } + + wrapBase664ToPem(text) {; + const pem = [ + "-----BEGIN CERTIFICATE-----", + text, + "-----END CERTIFICATE-----" + ].join("\n"); + return pem; + } + + normalizeCert(cert) { + if (Buffer.isBuffer(cert)) { + // assume DER + return this.derToPem(cert); + } + const text = cert.toString().trim(); + if (text.includes("BEGIN CERTIFICATE")) { + return text; // already PEM + } + // assume Base64 DER + return this.wrapBase664ToPem(text); + } + + getBitdefenderCACert() { + // return the Bitdefender CA cert + if (process.platform !== 'win32') { + return false; + } + const caCertFile = "C:\\Program Files\\Bitdefender\\Bitdefender Security\\mitm_cache\\fake-ca.crt" + if (!this.wtvshared.fs.existsSync(caCertFile)) { + return false; + } + return this.normalizeCert(this.wtvshared.fs.readFileSync(caCertFile)); + } } module.exports = WTVSSL; \ No newline at end of file diff --git a/zefie_wtvp_minisrv/includes/config.json b/zefie_wtvp_minisrv/includes/config.json index b97b49b2..e5e68bec 100644 --- a/zefie_wtvp_minisrv/includes/config.json +++ b/zefie_wtvp_minisrv/includes/config.json @@ -330,7 +330,8 @@ "disallow_no_slash": true, "handler_module": "WTVHTTP", "handler_extra_vars": ["http", "sendToClient"], - "allow_self_signed_ssl": true // If true, will allow self-signed SSL certificates via the proxy. + "allow_self_signed_ssl": false, // If true, will allow self-signed SSL certificates via the proxy. + "support_bitdefender_self_signed_proxy": true // If the user has bitdefender installed, it is intercepting SSL connections and re-signing them with its own self-signed certificate. Enabling this will add the Bitdefender certificate to the trusted store for the https service, allowing it to proxy https connections without errors. }, "proto": { // ProtoWeb Proxy