From 9e1f4899e6869c15523387149111794b8a7a1e94 Mon Sep 17 00:00:00 2001 From: Brandur Date: Wed, 22 Jan 2020 11:55:01 -0800 Subject: [PATCH] Gracefully handle a missing `subprocess` module As reported in #773, it seems that certain sandboxed environments like CloudFlare Workers don't provide a `subprocess` module, and that causes Node to throw when we try to require it. Because the only thing we need `subprocess` for is getting `uname`, here we extend the already-existing infrastructure built to gracefully handle errors to also be able to handle this new error case. Fixes #773. --- lib/utils.js | 20 +++++++++++++++++++- test/utils.spec.js | 16 ++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/lib/utils.js b/lib/utils.js index 818d98f790..06f5b4954e 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,12 +1,23 @@ 'use strict'; const EventEmitter = require('events').EventEmitter; -const exec = require('child_process').exec; const qs = require('qs'); const crypto = require('crypto'); const hasOwn = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop); +// Certain sandboxed environments (our known example right now are CloudFlare +// Workers) may make `child_process` unavailable. Because `exec` isn't critical +// to the operation of stripe-node, we handle this unavailability gracefully. +var exec = null; +try { + exec = require('child_process').exec; +} catch (e) { + if (e.code !== 'MODULE_NOT_FOUND') { + throw e; + } +} + const OPTIONS_KEYS = [ 'apiKey', 'idempotencyKey', @@ -340,6 +351,13 @@ const utils = (module.exports = { * This unifies that interface. */ safeExec: (cmd, cb) => { + // Occurs if we couldn't load the `child_process` module, which might + // happen in certain sandboxed environments like a CloudFlare Worker. + if (utils._exec === null) { + cb(new Error('exec not available'), null); + return; + } + try { utils._exec(cmd, cb); } catch (e) { diff --git a/test/utils.spec.js b/test/utils.spec.js index e9dc40c345..5ca1443db3 100644 --- a/test/utils.spec.js +++ b/test/utils.spec.js @@ -506,6 +506,22 @@ describe('utils', () => { utils.safeExec('hello', myCb); expect(calls).to.deep.equal([[myErr, null]]); }); + + it('handles being unable to require `child_process`', () => { + utils._exec = null; + + var actualErr = null; + var actualRes = null; + function myCb(err, res) { + actualErr = err; + actualRes = res; + } + utils.safeExec('hello', myCb); + expect(actualErr.toString()).to.equal( + new Error('exec not available').toString() + ); + expect(actualRes).to.equal(null); + }); }); describe('flattenAndStringify', () => {