UNPKG

eligible-node

Version:

Eligible Node.js bindings https://eligible.com

227 lines (195 loc) 5.86 kB
var Promise = require('bluebird'), extend = require('extend'), util = require('util'), https = require('https'), debug = util.debuglog('eligible'), Config = require('./config'), errors = require('../errors'), pkg = require('../../package.json'), os = require('os'); var request = require('request').defaults({ headers: getDefaultHeaders(), }); // Certificate fingerprints for gds.eligibleapi.com var FINGERPRINTS = [ 'AD:10:DB:FD:53:6A:0D:05:4B:02:A7:D3:0C:11:AA:1E:B5:DB:FB:41', 'B4:22:5E:E5:9D:C7:ED:E4:D6:8E:7B:2C:75:C6:E6:AC:79:64:94:16', '1A:1B:7D:4F:AA:43:EC:DE:AB:40:CC:8D:20:35:83:62:4D:59:17:F4', '1F:E0:41:61:ED:65:7B:55:AC:29:A0:C4:8D:A4:CF:24:6F:8E:65:7B' ]; function handleResponse(response, body) { var error; // Try parsing JSON try { body = JSON.parse(body); } catch (e) { // Invalid JSON for 200 status if (response.statusCode === 200 && response.req.path.indexOf('x12') === -1) { return new Promise.reject( new errors.APIResponseError(e.message, response.statusCode, body) ); } } if (response.statusCode === 401) { error = new Promise.reject( new errors.AuthenticationError('Authentication' + ' or authorization error. Mostly due to invalid api_key or provider' + ' need enrollment with payer.',response.statusCode, body) ); } else if (response.statusCode === 404) { error = new Promise.reject( new errors.InvalidRequestError( 'Not Found', response.statusCode, body )); } else if (response.statusCode === 400) { error = new Promise.reject( new errors.InvalidRequestError( 'Bad request, invalid or missing parameters.', response.statusCode, body )); } else if (response.statusCode !== 200) { error = new Promise.reject( new errors.APIError( body, response.statusCode, body )); } if (error) { return error; } // Valid JSON response for 200 status // Sometimes, for 200 status code, there are errors for invalid parameters if ((body.errors || body.error) && !body.success) { return new Promise.reject( new errors.InvalidRequestError( 'Bad request, invalid or missing parameters.', 400, body )); } return new Promise.resolve(body); } function getDefaultHeaders() { var headers = {}; headers.Accept = 'application/json'; headers['Accept-Charset'] = 'UTF-8'; headers['X-Eligible-Client-User-Agent'] = JSON.stringify({ 'os.name': os.platform(), 'os.arch': os.arch(), 'os.version': os.release(), 'node.version': process.version, lang: 'nodejs', }); return headers; } function getHeaders(config) { var headers = {}; headers['User-Agent'] = 'eligible-node/' + pkg.version ; headers['Eligible-Version'] = config.getApiVersion(); return headers; } function verifyFingerprint(response) { // Skip fingerprint verification for testing // Because `nock` doesn't save socker certs if (process.env.NODE_ENV === 'testing') { return; } var fingerprint = response.socket.getPeerCertificate().fingerprint; debug('fingerprint %s', fingerprint); if (FINGERPRINTS.indexOf(fingerprint) === -1) { response.request.abort(); throw new errors.APIConnectionError('SSL fingerprint mismatch.'); } } module.exports = function(method, uri, params, config) { params = params || {}; if (!(config instanceof Config) || !config.getApiKey()) { return new Promise.reject( new errors.AuthenticationError('No API key provided.', 0) ); } var url = config.getApiBase() + '/' + config.getApiVersion() + '/' + uri; // jshint camelcase: false // jscs:disable requireCamelCaseOrUpperCaseIdentifiers extend(params, { api_key: config.getApiKey(), test: String(config.isTest()), }); var options = { headers: getHeaders(config), agent: new https.Agent({ maxCachedSessions: 0 }), strictSSL: true, }; return module.exports[method](url, params, options); }; module.exports.request = function(options) { debug('request params:', options); return new Promise(function(resolve, reject) { request(options, function(error, response, body) { if (error) { return reject(new errors.APIConnectionError(error.message)); } return resolve(handleResponse(response, body)); }) .on('response', function(response) { try { verifyFingerprint(response); } catch (e) { reject(e); } }); }); }; module.exports.get = function(url, params, options) { options.qs = params; options.url = url; options.method = 'GET'; return module.exports.request(options); }; module.exports.post = function(url, params, options) { options.body = JSON.stringify(params); options.url = url; options.method = 'POST'; return module.exports.request(options); }; module.exports.put = function(url, params, options) { options.body = JSON.stringify(params); options.url = url; options.method = 'PUT'; return module.exports.request(options); }; module.exports.delete = function(url, params, options) { options.qs = params; options.url = url; options.method = 'DELETE'; return module.exports.request(options); }; module.exports.download = function(url, params, options) { options.qs = params; options.url = url; options.method = 'GET'; return new Promise(function(resolve, reject) { request(options) .on('response', function(response) { response.pause(); try { verifyFingerprint(response); return resolve(response); } catch (err) { return reject(err); } }) .on('error', function(err) { return reject(new errors.APIConnectionError(err.message)); }); }); }; module.exports.getHeaders = getHeaders;