jscrambler
Version:
Jscrambler Code Integrity API client.
282 lines (276 loc) • 9.2 kB
JavaScript
;
require("core-js/modules/es.regexp.exec.js");
require("core-js/modules/es.string.replace.js");
require("core-js/modules/es.string.trim.js");
require("core-js/modules/web.dom-collections.iterator.js");
var _lodash = _interopRequireDefault(require("lodash.defaults"));
var _fs = _interopRequireDefault(require("fs"));
var _lodash2 = _interopRequireDefault(require("lodash.keys"));
var _axios = _interopRequireDefault(require("axios"));
var _zlib = require("zlib");
var _url = _interopRequireDefault(require("url"));
var _https = _interopRequireDefault(require("https"));
var _http = _interopRequireDefault(require("http"));
var _httpsProxyAgent = require("https-proxy-agent");
var _httpProxyAgent = require("http-proxy-agent");
var _config = _interopRequireDefault(require("./config"));
var _generateSignedParams = _interopRequireDefault(require("./generate-signed-params"));
var _constants = require("./constants");
var _package = require("../package.json");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
const debug = !!process.env.DEBUG;
const metrics = !!process.env.METRICS;
const noCompression = !!process.env.NO_COMPRESSION;
class ClientError extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
}
}
/**
* @class JScramblerClient
* @param {Object} options
* @param {String} options.accessKey
* @param {String} options.secretKey
* @param {String} [options.host=api.jscrambler.com]
* @param {String} [options.port=443]
* @param {String} [options.basePath]
* @param {String} [options.clientId=0]
* @author Jscrambler
* @license MIT <http://opensource.org/licenses/MIT>
*/
function JScramblerClient(options) {
// Sluggish hack for backwards compatibility
if (options && !options.keys && (options.accessKey || options.secretKey)) {
options.keys = {};
options.keys.accessKey = options.accessKey;
options.keys.secretKey = options.secretKey;
}
options.keys = (0, _lodash.default)(options.keys || {}, _config.default.keys);
/**
* @member
*/
this.options = (0, _lodash.default)(options || {}, _config.default);
const {
jscramblerVersion,
clientId
} = this.options;
this.axiosInstance = _axios.default.create({
headers: {
jscramblerVersion,
clientId
},
transformRequest: _axios.default.defaults.transformRequest.concat(function (data, headers) {
// gzip request with more than 1KiB
if (!noCompression && typeof data === 'string' && data.length > 1024) {
headers['Content-Encoding'] = 'gzip';
data = (0, _zlib.gzipSync)(data);
if (metrics) {
process.stdout.write("[gzip ".concat(data.length, "B] "));
}
}
return data;
})
});
}
/**
* Delete request.
* @param {String} path
* @param {Object} params
* @param {Callback} callback
*/
JScramblerClient.prototype.delete = function (path, params) {
return this.request('DELETE', path, params);
};
/**
* Get request.
* @param {String} path
* @param {Object} params
* @param {Callback} callback
*/
JScramblerClient.prototype.get = function (path, params) {
let isJSON = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
return this.request('GET', path, params, isJSON);
};
/**
* HTTP request.
* @param {String} method
* @param {String} path
* @param {Object} params
* @param {Callback} callback
*/
JScramblerClient.prototype.request = function (method, path) {
let params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
let isJSON = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
let signedData;
if (this.options.useHeaderAuth) {
if (!this.token) {
throw new Error('Generating auth token when useHeaderAuth === true is not yet supported. You need to set the jscramblerClient token property explicitly.');
}
} else {
if (this.token) {
params.token = this.token;
} else {
if (!this.options.keys.accessKey) {
throw new Error('Required *accessKey* not provided');
}
if (!this.options.keys.secretKey) {
throw new Error('Required *secretKey* not provided');
}
}
}
const _keys = (0, _lodash2.default)(params);
for (let i = 0, l = _keys.length; i < l; i++) {
if (params[_keys[i]] instanceof Array) {
params[_keys[i]] = params[_keys[i]].join(',');
}
}
// If post sign data and set the request as multipart
if (this.options.keys.accessKey && this.options.keys.secretKey) {
signedData = (0, _generateSignedParams.default)(method, path, this.options.host, this.options.keys, params, this.options.utc);
} else {
signedData = params;
}
let {
protocol,
port,
proxy
} = this.options;
if (!port && !protocol) {
port = 443;
protocol = 'https';
}
if (!port) {
port = protocol === 'https' ? 443 : 80;
}
if (!protocol) {
protocol = port === 443 ? 'https' : 'http';
}
const formattedUrl = _url.default.format({
hostname: this.options.host,
port,
pathname: this.options.basePath + path,
protocol
});
let data;
const settings = {};
// Internal CA
let agentOptions = {};
if (this.options.cafile) {
agentOptions = {
ca: _fs.default.readFileSync(this.options.cafile)
};
}
if (proxy || typeof proxy === 'object') {
const {
host,
port = 8080,
auth
} = proxy;
if (!host) {
throw new Error('Required *proxy.host* not provided');
}
let username;
let password;
if (auth) {
({
username,
password
} = auth);
if (!username || !password) {
throw new Error('Required *proxy.auth* username or/and password not provided');
}
}
settings.proxy = false;
const proxyConfig = {
host,
port,
username,
password,
protocol: "".concat(proxy.protocol || 'http', ":")
};
settings.httpsAgent = new _httpsProxyAgent.HttpsProxyAgent(proxyConfig, agentOptions);
settings.httpAgent = new _httpProxyAgent.HttpProxyAgent(proxyConfig, agentOptions);
} else if (agentOptions) {
settings.httpsAgent = new _https.default.Agent(agentOptions);
settings.httpAgent = new _http.default.Agent(agentOptions);
}
if (!isJSON) {
settings.responseType = 'arraybuffer';
}
let promise;
if (method === 'GET' || method === 'DELETE') {
settings.params = signedData;
promise = this.axiosInstance[method.toLowerCase()](formattedUrl, settings);
} else {
data = signedData;
promise = this.axiosInstance[method.toLowerCase()](formattedUrl, data, settings);
}
const start = Date.now();
return promise.then(res => {
if (metrics || debug) {
console.log("".concat(method, " ").concat(path, " ").concat(((data || settings.params).query || '').split('(')[0].trim().replace(' ', '-'), " ").concat(JSON.stringify(data || settings.params).length, "B ").concat(Date.now() - start, "ms"));
}
return res.data;
}).catch(err => {
let errorMessage = 'Unexpected Response: ';
let statusCode = 500;
if (err.response) {
if (debug) {
console.error(err.response);
}
errorMessage += "".concat(err.response.status, " ").concat(err.response.statusText);
statusCode = err.response.status;
let incompatibleApi = false;
if (statusCode === _constants.HTTP_STATUS_CODES.UNAUTHORIZED && /Invalid Signature/i.test(err.response.data.message)) {
incompatibleApi = err.response.data.errorCode !== _constants.JSCRAMBLER_ERROR_CODES.INVALID_SIGNATURE;
}
if (incompatibleApi) {
errorMessage = "Incompatible jscrambler CLI version (".concat(_package.version, "). Please downgrade to: \n\t$ npm install ").concat(_constants.CLIENT_PACKAGES[this.options.clientId], "@5");
} else if (
// For when we have API error messages
err.response.data && err.response.data.error && err.response.data.message) {
errorMessage += " - ".concat(err.response.data.message);
} else if (err.response.data && err.response.data.errors && err.response.data.errors.length > 0) {
errorMessage += " - ".concat(err.response.data.errors);
}
} else {
errorMessage += err.message;
}
throw new ClientError(errorMessage, statusCode);
});
};
/**
* Post request.
* @param {String} path
* @param {Object} params
* @param {Callback} callback
*/
JScramblerClient.prototype.post = function (path, params) {
return this.request('POST', path, params);
};
/**
* Patch request.
* @param {string} path
* @param {object} params
*/
JScramblerClient.prototype.patch = function (path, params) {
return this.request('PATCH', path, params);
};
let _token;
Object.defineProperty(JScramblerClient.prototype, 'token', {
get() {
return _token;
},
set(value) {
_token = value;
if (value) {
if (this.options.useHeaderAuth) {
this.axiosInstance.defaults.headers['x-user-authentication'] = _token;
}
} else {
delete this.axiosInstance.defaults.headers['x-user-authentication'];
}
}
});
exports = module.exports = JScramblerClient;