From ce64328cb7c3d9e7acc19fe530dd455390a97e21 Mon Sep 17 00:00:00 2001 From: Alexander Chen Date: Fri, 12 Feb 2016 00:48:45 -0800 Subject: [PATCH] Add socks5 proxy --- lib/helpers.js | 47 --- lib/request.js | 23 ++ lib/streaming-api-connection.js | 9 +- lib/twitter.js | 100 ++++-- package.json | 3 +- tests/rest.js | 6 +- yarn.lock | 540 ++++++++++++++++++++++++++++++++ 7 files changed, 647 insertions(+), 81 deletions(-) create mode 100644 lib/request.js create mode 100644 yarn.lock diff --git a/lib/helpers.js b/lib/helpers.js index 394d277b..757d1e3a 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -1,5 +1,4 @@ var querystring = require('querystring'); -var request = require('request'); var endpoints = require('./endpoints'); @@ -80,49 +79,3 @@ exports.makeTwitError = function (message) { err.twitterReply = null return err } - -/** - * Get a bearer token for OAuth2 - * @param {String} consumer_key - * @param {String} consumer_secret - * @param {Function} cb - * - * Calls `cb` with Error, String - * - * Error (if it exists) is guaranteed to be Twit error-formatted. - * String (if it exists) is the bearer token received from Twitter. - */ -exports.getBearerToken = function (consumer_key, consumer_secret, cb) { - // use OAuth 2 for app-only auth (Twitter requires this) - // get a bearer token using our app's credentials - var b64Credentials = new Buffer(consumer_key + ':' + consumer_secret).toString('base64'); - request.post({ - url: endpoints.API_HOST + 'oauth2/token', - headers: { - 'Authorization': 'Basic ' + b64Credentials, - 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' - }, - body: 'grant_type=client_credentials', - json: true, - }, function (err, res, body) { - if (err) { - var error = exports.makeTwitError(err.toString()); - exports.attachBodyInfoToError(error, body); - return cb(error, body, res); - } - - if ( !body ) { - var error = exports.makeTwitError('Not valid reply from Twitter upon obtaining bearer token'); - exports.attachBodyInfoToError(error, body); - return cb(error, body, res); - } - - if (body.token_type !== 'bearer') { - var error = exports.makeTwitError('Unexpected reply from Twitter upon obtaining bearer token'); - exports.attachBodyInfoToError(error, body); - return cb(error, body, res); - } - - return cb(err, body.access_token); - }) -} diff --git a/lib/request.js b/lib/request.js new file mode 100644 index 00000000..bfe4556a --- /dev/null +++ b/lib/request.js @@ -0,0 +1,23 @@ +const request = require('request'); +const socks = require('socksv5'); + +module.exports = function (config) { + var proxyConfig = config.proxy; + + if (proxyConfig) { + return request.defaults({ + agentClass: socks.HttpsAgent, + agentOptions: { + proxyHost: proxyConfig.host, + proxyPort: proxyConfig.port, + auths: [ + proxyConfig.auth ? + socks.auth.UserPassword(proxyConfig.auth.username, proxyConfig.auth.password) : + socks.auth.None() + ] + } + }); + } + + return request; +}; diff --git a/lib/streaming-api-connection.js b/lib/streaming-api-connection.js index e05bff86..1faf3ca2 100644 --- a/lib/streaming-api-connection.js +++ b/lib/streaming-api-connection.js @@ -4,14 +4,13 @@ var util = require('util'); var helpers = require('./helpers') var Parser = require('./parser'); -var request = require('request'); +var request = require('./request'); var STATUS_CODES_TO_ABORT_ON = require('./settings').STATUS_CODES_TO_ABORT_ON -var StreamingAPIConnection = function (reqOpts, twitOptions) { - this.reqOpts = reqOpts - this.twitOptions = twitOptions +var StreamingAPIConnection = function (config) { this._twitter_time_minus_local_time_ms = 0 + this._request = request(config) EventEmitter.call(this) } @@ -66,7 +65,7 @@ StreamingAPIConnection.prototype._startPersistentConnection = function () { self._resetStallAbortTimeout(); self._setOauthTimestamp(); this.reqOpts.encoding = 'utf8' - self.request = request.post(this.reqOpts); + this.request = self._request.post(this.reqOpts); self.emit('connect', self.request); self.request.on('response', function (response) { self._updateOauthTimestampOffsetFromResponse(response) diff --git a/lib/twitter.js b/lib/twitter.js index 9540857e..9dd79ac0 100644 --- a/lib/twitter.js +++ b/lib/twitter.js @@ -3,7 +3,7 @@ // var assert = require('assert'); var Promise = require('bluebird'); -var request = require('request'); +var request = require('./request'); var util = require('util'); var endpoints = require('./endpoints'); var FileUploader = require('./file_uploader'); @@ -57,6 +57,7 @@ var Twitter = function (config) { this._validateConfigOrThrow(config); this.config = config; + this._request = request(config); this._twitter_time_minus_local_time_ms = 0; } @@ -104,23 +105,9 @@ Twitter.prototype.request = function (method, path, params, callback) { self._updateClockOffsetFromResponse(resp); var peerCertificate = resp && resp.socket && resp.socket.getPeerCertificate(); - if (self.config.trusted_cert_fingerprints && peerCertificate) { - if (!resp.socket.authorized) { - // The peer certificate was not signed by one of the authorized CA's. - var authErrMsg = resp.socket.authorizationError.toString(); - var err = helpers.makeTwitError('The peer certificate was not signed; ' + authErrMsg); - _returnErrorToUser(err); - return; - } - var fingerprint = peerCertificate.fingerprint; - var trustedFingerprints = self.config.trusted_cert_fingerprints; - if (trustedFingerprints.indexOf(fingerprint) === -1) { - var errMsg = util.format('Certificate untrusted. Trusted fingerprints are: %s. Got fingerprint: %s.', - trustedFingerprints.join(','), fingerprint); - var err = new Error(errMsg); - _returnErrorToUser(err); - return; - } + if (err) { + _returnErrorToUser(err); + return; } if (callback && typeof callback === 'function') { @@ -317,7 +304,8 @@ Twitter.prototype._buildReqOpts = function (method, path, params, isStreaming, c * @return {Undefined} */ Twitter.prototype._doRestApiRequest = function (reqOpts, twitOptions, method, callback) { - var request_method = request[method.toLowerCase()]; + var self = this; + var request_method = this._request[method.toLowerCase()]; var req = request_method(reqOpts); var body = ''; @@ -352,8 +340,28 @@ Twitter.prototype._doRestApiRequest = function (reqOpts, twitOptions, method, ca callback(err, body, response) } - req.on('response', function (res) { - response = res + req.on('response', function (resp) { + response = resp + + if (self.config.trusted_cert_fingerprints) { + if (!resp.socket.authorized) { + // The peer certificate was not signed by one of the authorized CA's. + var authErrMsg = resp.socket.authorizationError.toString(); + var err = helpers.makeTwitError('The peer certificate was not signed; ' + authErrMsg); + callback(err, body, response); + return; + } + var fingerprint = resp.socket.getPeerCertificate().fingerprint; + var trustedFingerprints = self.config.trusted_cert_fingerprints; + if (trustedFingerprints.indexOf(fingerprint) === -1) { + var errMsg = util.format('Certificate untrusted. Trusted fingerprints are: %s. Got fingerprint: %s.', + trustedFingerprints.join(','), fingerprint); + var err = new Error(errMsg); + callback(err, body, response); + return; + } + } + // read data from `request` object which contains the decompressed HTTP response body, // `response` is the unmodified http.IncomingMessage object which may contain compressed data req.on('data', function (chunk) { @@ -397,7 +405,7 @@ Twitter.prototype.stream = function (path, params) { var self = this; var twitOptions = (params && params.twit_options) || {}; - var streamingConnection = new StreamingAPIConnection() + var streamingConnection = new StreamingAPIConnection(this.config) self._buildReqOpts('POST', path, params, true, function (err, reqOpts) { if (err) { // we can get an error if we fail to obtain a bearer token or construct reqOpts @@ -429,7 +437,53 @@ Twitter.prototype._getBearerToken = function (callback) { return callback(null, self._bearerToken) } - helpers.getBearerToken(self.config.consumer_key, self.config.consumer_secret, + /** + * Get a bearer token for OAuth2 + * @param {String} consumer_key + * @param {String} consumer_secret + * @param {Function} cb + * + * Calls `cb` with Error, String + * + * Error (if it exists) is guaranteed to be Twit error-formatted. + * String (if it exists) is the bearer token received from Twitter. + */ + var getBearerToken = function (consumer_key, consumer_secret, cb) { + // use OAuth 2 for app-only auth (Twitter requires this) + // get a bearer token using our app's credentials + var b64Credentials = new Buffer(consumer_key + ':' + consumer_secret).toString('base64'); + request.post({ + url: endpoints.API_HOST + 'oauth2/token', + headers: { + 'Authorization': 'Basic ' + b64Credentials, + 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' + }, + body: 'grant_type=client_credentials', + json: true, + }, function (err, res, body) { + if (err) { + var error = exports.makeTwitError(err.toString()); + exports.attachBodyInfoToError(error, body); + return cb(error, body, res); + } + + if ( !body ) { + var error = exports.makeTwitError('Not valid reply from Twitter upon obtaining bearer token'); + exports.attachBodyInfoToError(error, body); + return cb(error, body, res); + } + + if (body.token_type !== 'bearer') { + var error = exports.makeTwitError('Unexpected reply from Twitter upon obtaining bearer token'); + exports.attachBodyInfoToError(error, body); + return cb(error, body, res); + } + + return cb(err, body.access_token); + }) + } + + getBearerToken(self.config.consumer_key, self.config.consumer_secret, function (err, bearerToken) { if (err) { // return the fully-qualified Twit Error object to caller diff --git a/package.json b/package.json index 4c430f43..1374b31c 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "dependencies": { "bluebird": "^3.1.5", "mime": "^1.3.4", - "request": "^2.68.0" + "request": "^2.68.0", + "socksv5": "0.0.6" }, "devDependencies": { "async": "0.2.9", diff --git a/tests/rest.js b/tests/rest.js index 63fcbdbf..9ede5b80 100644 --- a/tests/rest.js +++ b/tests/rest.js @@ -640,9 +640,6 @@ describe('REST API', function () { assert(err.message.match(/token/)) assert(err.twitterReply) assert(err.allErrors) - assert(res) - assert(res.headers) - assert.equal(res.statusCode, 401) done() }) }) @@ -680,8 +677,7 @@ describe('REST API', function () { return fakeRequest } - var request = require('request') - var stubGet = sinon.stub(request, 'get', stubGet) + var stubGet = sinon.stub(twit._request, 'get', stubGet) twit.get('account/verify_credentials', function (err, reply, res) { assert(err === fakeError) diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 00000000..1af65f13 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,540 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +ajv@^5.1.0: + version "5.5.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +async@0.2.9: + version "0.2.9" + resolved "https://registry.yarnpkg.com/async/-/async-0.2.9.tgz#df63060fbf3d33286a76aaf6d55a2986d9ff8619" + +async@0.2.x: + version "0.2.10" + resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + +aws4@^1.6.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.7.0.tgz#d4d0e9b9dbfca77bf08eeb0a8a471550fe39e289" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +bcrypt-pbkdf@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" + dependencies: + tweetnacl "^0.14.3" + +bluebird@^3.1.5: + version "3.5.1" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + +cli@0.4.x: + version "0.4.5" + resolved "https://registry.yarnpkg.com/cli/-/cli-0.4.5.tgz#78f9485cd161b566e9a6c72d7170c4270e81db61" + dependencies: + glob ">= 3.1.4" + +cliff@0.1.x: + version "0.1.10" + resolved "https://registry.yarnpkg.com/cliff/-/cliff-0.1.10.tgz#53be33ea9f59bec85609ee300ac4207603e52013" + dependencies: + colors "~1.0.3" + eyes "~0.1.8" + winston "0.8.x" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +colors@0.6.x: + version "0.6.2" + resolved "https://registry.yarnpkg.com/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" + +colors@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + +combined-stream@1.0.6, combined-stream@~1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" + dependencies: + delayed-stream "~1.0.0" + +commander@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" + +commander@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" + +commander@2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.6.0.tgz#9df7e52fb2a0cb0fb89058ee80c3104225f37e1d" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +core-util-is@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +cycle@1.0.x: + version "1.0.3" + resolved "https://registry.yarnpkg.com/cycle/-/cycle-1.0.3.tgz#21e80b2be8580f98b468f379430662b046c34ad2" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +debug@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.0.0.tgz#89bd9df6732b51256bc6705342bba02ed12131ef" + dependencies: + ms "0.6.2" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +diff@1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/diff/-/diff-1.0.8.tgz#343276308ec991b7bc82267ed55bc1411f971666" + +ecc-jsbn@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + dependencies: + jsbn "~0.1.0" + +escape-string-regexp@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" + +extend@~3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + +eyes@0.1.x, eyes@~0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" + +fast-deep-equal@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@~2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099" + dependencies: + asynckit "^0.4.0" + combined-stream "1.0.6" + mime-types "^2.1.12" + +formatio@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/formatio/-/formatio-1.1.1.tgz#5ed3ccd636551097383465d996199100e86161e9" + dependencies: + samsam "~1.1" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + dependencies: + assert-plus "^1.0.0" + +glob@3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.3.tgz#e313eeb249c7affaa5c475286b0e115b59839467" + dependencies: + graceful-fs "~2.0.0" + inherits "2" + minimatch "~0.2.11" + +"glob@>= 3.1.4": + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +graceful-fs@~2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-2.0.3.tgz#7cd2cdb228a4a3f36e95efa6cc142de7d1a136d0" + +growl@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.8.1.tgz#4b2dec8d907e93db336624dcec0183502f8c9428" + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + +har-validator@~5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" + dependencies: + ajv "^5.1.0" + har-schema "^2.0.0" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + +ipv6@*: + version "3.1.3" + resolved "https://registry.yarnpkg.com/ipv6/-/ipv6-3.1.3.tgz#4d9064f9c2dafa0dd10b8b7d76ffca4aad31b3b9" + dependencies: + cli "0.4.x" + cliff "0.1.x" + sprintf "0.1.x" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +isstream@0.1.x, isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +jade@0.26.3: + version "0.26.3" + resolved "https://registry.yarnpkg.com/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c" + dependencies: + commander "0.6.1" + mkdirp "0.3.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +lolex@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/lolex/-/lolex-1.1.0.tgz#5dbbbc850395e7523c74b3586f7fbd2626d25b1b" + +lru-cache@2: + version "2.7.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" + +mime-db@~1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" + +mime-types@^2.1.12, mime-types@~2.1.17: + version "2.1.18" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" + dependencies: + mime-db "~1.33.0" + +mime@^1.3.4: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +minimatch@~0.2.11: + version "0.2.14" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a" + dependencies: + lru-cache "2" + sigmund "~1.0.0" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +mkdirp@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" + +mkdirp@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" + dependencies: + minimist "0.0.8" + +mocha@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-2.1.0.tgz#77752fe592fb9092756827af46cd3eae1b83671c" + dependencies: + commander "2.3.0" + debug "2.0.0" + diff "1.0.8" + escape-string-regexp "1.0.2" + glob "3.2.3" + growl "1.8.1" + jade "0.26.3" + mkdirp "0.5.0" + +ms@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.6.2.tgz#d89c2124c6fdc1353d65a8b77bf1aac4b193708c" + +oauth-sign@~0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + +pkginfo@0.3.x: + version "0.3.1" + resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.3.1.tgz#5b29f6a81f70717142e09e765bbeab97b4f81e21" + +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +qs@~6.5.1: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + +request@^2.68.0: + version "2.87.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.6.0" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.1" + forever-agent "~0.6.1" + form-data "~2.3.1" + har-validator "~5.0.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.17" + oauth-sign "~0.8.2" + performance-now "^2.1.0" + qs "~6.5.1" + safe-buffer "^5.1.1" + tough-cookie "~2.3.3" + tunnel-agent "^0.6.0" + uuid "^3.1.0" + +rewire@2.3.4: + version "2.3.4" + resolved "https://registry.yarnpkg.com/rewire/-/rewire-2.3.4.tgz#f3a40bc40af704bca740a1de5d53f636ee2d601c" + +safe-buffer@^5.0.1, safe-buffer@^5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + +samsam@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.1.2.tgz#bec11fdc83a9fda063401210e40176c3024d1567" + +samsam@~1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.1.3.tgz#9f5087419b4d091f232571e7fa52e90b0f552621" + +sigmund@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" + +sinon@1.15.4: + version "1.15.4" + resolved "https://registry.yarnpkg.com/sinon/-/sinon-1.15.4.tgz#0315f174ce5b31792aea2e3a2afc5bb7804c7a6a" + dependencies: + formatio "1.1.1" + lolex "1.1.0" + samsam "1.1.2" + util ">=0.10.3 <1" + +socksv5@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/socksv5/-/socksv5-0.0.6.tgz#1327235ff7e8de21ac434a0a579dc69c3f071061" + dependencies: + ipv6 "*" + +sprintf@0.1.x: + version "0.1.5" + resolved "https://registry.yarnpkg.com/sprintf/-/sprintf-0.1.5.tgz#8f83e39a9317c1a502cb7db8050e51c679f6edcf" + +sshpk@^1.7.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.14.1.tgz#130f5975eddad963f1d56f92b9ac6c51fa9f83eb" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + +stack-trace@0.0.x: + version "0.0.10" + resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" + +tough-cookie@~2.3.3: + version "2.3.4" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" + dependencies: + punycode "^1.4.1" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + +"util@>=0.10.3 <1": + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + dependencies: + inherits "2.0.1" + +uuid@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +winston@0.8.x: + version "0.8.3" + resolved "https://registry.yarnpkg.com/winston/-/winston-0.8.3.tgz#64b6abf4cd01adcaefd5009393b1d8e8bec19db0" + dependencies: + async "0.2.x" + colors "0.6.x" + cycle "1.0.x" + eyes "0.1.x" + isstream "0.1.x" + pkginfo "0.3.x" + stack-trace "0.0.x" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"