diff --git a/cli/lib/tasks/download.js b/cli/lib/tasks/download.js index 2c9f4f29f390..c21d311c2f51 100644 --- a/cli/lib/tasks/download.js +++ b/cli/lib/tasks/download.js @@ -54,6 +54,28 @@ const getBaseUrl = () => { return defaultBaseUrl } +const getCA = () => { + return new Promise((resolve) => { + if (!util.getEnv('CYPRESS_DOWNLOAD_USE_CA')) { + resolve() + } + + if (process.env.npm_config_ca) { + resolve(process.env.npm_config_ca) + } else if (process.env.npm_config_cafile) { + fs.readFile(process.env.npm_config_cafile, 'utf8') + .then((cafileContent) => { + resolve(cafileContent) + }) + .catch(() => { + resolve() + }) + } else { + resolve() + } + }) +} + const prepend = (urlPath) => { const endpoint = url.resolve(getBaseUrl(), urlPath) const platform = os.platform() @@ -181,7 +203,7 @@ const verifyDownloadedFile = (filename, expectedSize, expectedChecksum) => { // downloads from given url // return an object with // {filename: ..., downloaded: true} -const downloadFromUrl = ({ url, downloadDestination, progress }) => { +const downloadFromUrl = ({ url, downloadDestination, progress, ca }) => { return new Promise((resolve, reject) => { const proxy = getProxyUrl() @@ -193,7 +215,7 @@ const downloadFromUrl = ({ url, downloadDestination, progress }) => { let redirectVersion - const req = request({ + const reqOptions = { url, proxy, followRedirect (response) { @@ -210,7 +232,14 @@ const downloadFromUrl = ({ url, downloadDestination, progress }) => { // yes redirect return true }, - }) + } + + if (ca) { + debug('using custom CA details from npm config') + reqOptions.agentOptions = { ca } + } + + const req = request(reqOptions) // closure let started = null @@ -315,7 +344,10 @@ const start = (opts) => { // ensure download dir exists return fs.ensureDirAsync(path.dirname(downloadDestination)) .then(() => { - return downloadFromUrl({ url, downloadDestination, progress }) + return getCA() + }) + .then((ca) => { + return downloadFromUrl({ url, downloadDestination, progress, ca }) }) .catch((err) => { return prettyDownloadErr(err, version) @@ -326,4 +358,5 @@ module.exports = { start, getUrl, getProxyUrl, + getCA, } diff --git a/cli/test/fixture/cafile.pem b/cli/test/fixture/cafile.pem new file mode 100644 index 000000000000..5716ca5987cb --- /dev/null +++ b/cli/test/fixture/cafile.pem @@ -0,0 +1 @@ +bar diff --git a/cli/test/lib/tasks/download_spec.js b/cli/test/lib/tasks/download_spec.js index 4b237ac7916e..fe5a4ebce3ad 100644 --- a/cli/test/lib/tasks/download_spec.js +++ b/cli/test/lib/tasks/download_spec.js @@ -337,4 +337,47 @@ describe('lib/tasks/download', function () { expect(download.getProxyUrl()).to.eq('baz') }) }) + + context('with CA and CAFILE env vars', () => { + beforeEach(function () { + this.env = _.clone(process.env) + }) + + afterEach(function () { + process.env = this.env + }) + + it('returns undefined if not set', () => { + return download.getCA().then((ca) => { + expect(ca).to.be.undefined + }) + }) + + it('returns CA from npm_config_ca', () => { + process.env.CYPRESS_DOWNLOAD_USE_CA = 'true' + process.env.npm_config_ca = 'foo' + + return download.getCA().then((ca) => { + expect(ca).to.eqls('foo') + }) + }) + + it('returns CA from npm_config_cafile', () => { + process.env.CYPRESS_DOWNLOAD_USE_CA = 'true' + process.env.npm_config_cafile = 'test/fixture/cafile.pem' + + return download.getCA().then((ca) => { + expect(ca).to.eqls('bar\n') + }) + }) + + it('returns undefined if failed reading npm_config_cafile', () => { + process.env.CYPRESS_DOWNLOAD_USE_CA = 'true' + process.env.npm_config_cafile = 'test/fixture/not-exists.pem' + + return download.getCA().then((ca) => { + expect(ca).to.be.undefined + }) + }) + }) })