From c09cc931035709ef06a547c2056ef52701bc5e00 Mon Sep 17 00:00:00 2001 From: Arunendra21 <156455722+Arunendra21@users.noreply.github.com> Date: Sun, 23 Aug 2026 18:06:35 +0530 Subject: [PATCH] fix: pass proxy credentials to binary download browserstack-local-nodejs accepts proxyUser/proxyPass and forwards them to the BrowserStackLocal binary, but LocalBinary.download() built the HttpsProxyAgent with only host and port. Behind a proxy that requires authentication the binary download failed with 407 even when valid credentials were supplied. Include the credentials via the agent's auth option when both proxyUser and proxyPass are present, and add tests for the authenticated and unauthenticated cases. Fixes #164 --- lib/LocalBinary.js | 8 ++++++-- test/local.js | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/lib/LocalBinary.js b/lib/LocalBinary.js index 8d694b2..a553559 100644 --- a/lib/LocalBinary.js +++ b/lib/LocalBinary.js @@ -218,10 +218,14 @@ function LocalBinary(){ var options = url.parse(this.httpPath); if(conf.proxyHost && conf.proxyPort) { - options.agent = new HttpsProxyAgent({ + var proxyOptions = { host: conf.proxyHost, port: conf.proxyPort - }); + }; + if(conf.proxyUser && conf.proxyPass) { + proxyOptions.auth = conf.proxyUser + ':' + conf.proxyPass; + } + options.agent = new HttpsProxyAgent(proxyOptions); } if (conf.useCaCertificate) { try { diff --git a/test/local.js b/test/local.js index 576ad79..e0886f7 100644 --- a/test/local.js +++ b/test/local.js @@ -482,6 +482,52 @@ describe('LocalBinary', function () { }); }); + it('should pass proxy authentication to the binary download when proxyUser/proxyPass are set', function () { + var https = require('https'); + var getDownloadPathStub = sinon.stub(binary, 'getDownloadPath', function (conf, retries, cb) { + cb(null, 'https://bstack-downloads.example/BrowserStackLocal'); + }); + var httpsGetStub = sinon.stub(https, 'get').returns({ on: function () { return this; } }); + + try { + var conf = { + proxyHost: '127.0.0.1', + proxyPort: proxyPort, + proxyUser: 'user', + proxyPass: 'pass' + }; + binary.download(conf, tempDownloadPath, function () {}); + + expect(httpsGetStub.calledOnce).to.equal(true); + var passedOptions = httpsGetStub.firstCall.args[0]; + expect(passedOptions.agent).to.be.an('object'); + expect(passedOptions.agent.proxy.auth).to.equal('user:pass'); + } finally { + httpsGetStub.restore(); + getDownloadPathStub.restore(); + } + }); + + it('should not set proxy authentication when only host/port are provided', function () { + var https = require('https'); + var getDownloadPathStub = sinon.stub(binary, 'getDownloadPath', function (conf, retries, cb) { + cb(null, 'https://bstack-downloads.example/BrowserStackLocal'); + }); + var httpsGetStub = sinon.stub(https, 'get').returns({ on: function () { return this; } }); + + try { + var conf = { proxyHost: '127.0.0.1', proxyPort: proxyPort }; + binary.download(conf, tempDownloadPath, function () {}); + + var passedOptions = httpsGetStub.firstCall.args[0]; + expect(passedOptions.agent).to.be.an('object'); + expect(passedOptions.agent.proxy.auth).to.equal(undefined); + } finally { + httpsGetStub.restore(); + getDownloadPathStub.restore(); + } + }); + it('should download binaries in sync', function () { this.timeout(MAX_TIMEOUT); var conf = {};