rentdynamics
Version:
Package to help facilitate communicating with the Rent Dynamics API
243 lines • 32 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ClientHelpers = exports.ClientOptions = exports.BASE_URL = exports.Client = void 0;
/**
* Client is a convenience class for interacting with the Rent Dynamics services.
*
* Note if this class does not suit your needs, it may be wise to roll your own implementation using
* the {@linkcode ClientHelpers} class.
*/
class Client {
constructor(options) {
this.helpers = new ClientHelpers(options);
}
/**
* get wraps a request library to work with the Rent Dynamics API.
* @param endpoint the path following the baseUrl.
* @example get('/foo');
*/
async get(endpoint) {
const fullUrl = this.helpers.baseUrl + endpoint;
const headers = await this.helpers.getHeaders(endpoint, undefined, this.authToken);
return fetch(fullUrl.replace(/\|/g, '%7C'), {
method: 'GET',
headers: Object.assign(Object.assign({}, headers), { 'Content-Type': 'application/json' })
});
}
/**
* put wraps a request library to work with the Rent Dynamics API.
* @param endpoint the path following the baseUrl.
* @param payload a JSON serializable object.
* @example put('/foo', { bar: 1 });
*/
async put(endpoint, payload) {
const fullUrl = this.helpers.baseUrl + endpoint;
const headers = await this.helpers.getHeaders(endpoint, payload, this.authToken);
return fetch(fullUrl, {
method: 'PUT',
headers: Object.assign(Object.assign({}, headers), { 'Content-Type': 'application/json' }),
body: JSON.stringify(payload)
});
}
/**
* post wraps a request library to work with the Rent Dynamics API.
* @param endpoint the path following the baseUrl.
* @param payload a JSON serializable object.
* @example post('/foo', { bar: 1 });
*/
async post(endpoint, payload) {
const fullUrl = this.helpers.baseUrl + endpoint;
const headers = await this.helpers.getHeaders(endpoint, payload, this.authToken);
return fetch(fullUrl, {
method: 'POST',
headers: Object.assign(Object.assign({}, headers), { 'Content-Type': 'application/json' }),
body: JSON.stringify(payload)
});
}
/**
* delete wraps a request library to work with the Rent Dynamics API.
* @param endpoint the path following the baseUrl.
* @example delete('/foo/1');
*/
async delete(endpoint) {
const fullUrl = this.helpers.baseUrl + endpoint;
const headers = await this.helpers.getHeaders(endpoint, undefined, this.authToken);
return fetch(fullUrl, {
method: 'DELETE',
headers: Object.assign(Object.assign({}, headers), { 'Content-Type': 'application/json' })
});
}
/**
* login enables an instance of {@linkcode Client} to make authenticated requests to the Rent
* Dynamics API.
*/
async login(username, password) {
const _password = await this.helpers.encryptPassword(password);
const endpoint = '/auth/login';
const result = await this.post(endpoint, { username, password: _password });
if (!result.ok) {
return result;
}
const { token } = await result.json();
this.authToken = token;
return result;
}
/** logout invalidates the users session generated by {@linkcode login}. */
async logout() {
const endpoint = '/auth/logout';
const result = await this.post(endpoint, { authToken: this.authToken });
if (!result.ok) {
return result;
}
this.authToken = undefined;
return result;
}
}
exports.Client = Client;
/** BASE_URL is a collection of base urls for each dev/prod Rent Dynamics service. */
var BASE_URL;
(function (BASE_URL) {
BASE_URL["DEV_RD"] = "https://api.rentdynamics.dev";
BASE_URL["PROD_RD"] = "https://api.rentdynamics.com";
BASE_URL["DEV_RP"] = "https://api-dev.rentplus.com";
BASE_URL["PROD_RP"] = "https://api.rentplus.com";
})(BASE_URL = exports.BASE_URL || (exports.BASE_URL = {}));
/** ClientOptions is consumed and updated by {@linkcode ClientHelpers}. */
class ClientOptions {
constructor() {
/**
* baseUrl is the base request url. The default is the development rentdynamics api. A custom
* string may be provided beyond the {@linkcode BASE_URL} options.
*/
this.baseUrl = BASE_URL.DEV_RD;
/**
* getEncoder is used to encode text. The encoder can be overridden as needed. For example in a
* node environment.
* @example
* const options = new ClientOptions();
* options.getEncoder = async () => new (await import('util')).TextEncoder();
*/
this.getEncoder = async () => new TextEncoder();
/**
* getCryptographer is used for cryptography. The cryptographer can be overridden as needed. For
* example in a node environment.
* @example
* const options = new ClientOptions();
* options.getCryptographer = async () => (await import('crypto')).subtle;
*/
this.getCryptographer = async () => crypto.subtle;
}
}
exports.ClientOptions = ClientOptions;
/**
* ClientHelpers is a collection of utilities consumed by {@linkcode Client}. ClientHelpers can be
* used to calculate headers in case a consumer wants to build their own API client.
*/
class ClientHelpers {
constructor(options) {
this.options = options;
}
/**
* baseUrl is the base url used throughout the {@linkcode ClientHelpers} instance. It is initially
* configured through {@linkcode ClientOptions}.
*/
get baseUrl() {
return this.options.baseUrl;
}
/**
* getTimestamp is used to calculate the timestamp header. This method is not likely to be called
* on it's own. Instead, it is typically used to mock the current time.
*/
getTimestamp() {
return Date.now();
}
/**
* getHeaders creates headers for the given params. If an auth token is included, this method will
* generate an `Authorization` header.
*/
async getHeaders(endpoint, payload, authToken) {
const headers = {};
if (this.options.apiKey && this.options.apiSecretKey) {
if (!payload || !Object.keys(payload).length) {
payload = undefined;
}
if (typeof payload !== 'undefined') {
payload = JSON.stringify(this.formatPayload(payload));
}
const timestamp = this.getTimestamp();
const nonce = await this.getNonce(timestamp, endpoint, payload);
if (authToken) {
headers.Authorization = 'TOKEN ' + authToken;
}
headers['x-rd-api-key'] = this.options.apiKey;
headers['x-rd-api-nonce'] = nonce;
headers['x-rd-timestamp'] = timestamp.toString();
return headers;
}
return headers;
}
/** formatPayload formats the payload for nonce calculation. */
formatPayload(payload) {
let formattedPayload = {};
if (payload === undefined || payload === null) {
formattedPayload = null;
}
else if (payload !== Object(payload)) {
formattedPayload = payload;
}
else if (Array.isArray(payload)) {
formattedPayload = [];
payload.forEach((_, index) => {
formattedPayload[index] = this.formatPayload(payload[index]);
});
}
else {
Object.keys(payload)
.sort()
.forEach(k => {
if (typeof payload[k] === 'object') {
formattedPayload[k] = this.formatPayload(payload[k]);
}
else if (typeof payload[k] === 'string') {
formattedPayload[k] = payload[k].replace(/ /g, '');
}
else {
formattedPayload[k] = payload[k];
}
});
}
return formattedPayload;
}
/** getNonce calculates the nonce for the given params. */
async getNonce(timestamp, url, payloadStr) {
if (!this.options.apiSecretKey)
return Promise.resolve('');
const encodedUrl = encodeURI(url)
.replace(/%7[Cc]/g, '|')
.replace(/%20/g, ' ');
const nonceStr = typeof payloadStr !== 'undefined'
? timestamp + encodedUrl + payloadStr
: timestamp + encodedUrl;
const cryptographer = await this.options.getCryptographer();
const encoder = await this.options.getEncoder();
const key = encoder.encode(this.options.apiSecretKey);
const data = encoder.encode(nonceStr);
const algorithm = { name: 'HMAC', hash: 'SHA-1' };
const hmac = await cryptographer.importKey('raw', key, algorithm, false, ['sign']);
const signed = await cryptographer.sign(algorithm.name, hmac, data);
return _hexDigest(signed);
}
/** encryptPassword encrypts the password for login. */
async encryptPassword(password) {
const cryptographer = await this.options.getCryptographer();
const encoder = await this.options.getEncoder();
const encodedPassword = encoder.encode(password);
const digestedPassword = await cryptographer.digest('SHA-1', encodedPassword);
return _hexDigest(digestedPassword);
}
}
exports.ClientHelpers = ClientHelpers;
const _hexDigest = (buf) => Array.from(new Uint8Array(buf))
.map(b => b.toString(16).padStart(2, '0'))
.join('');
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9saWIvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBSUE7Ozs7O0dBS0c7QUFDSCxNQUFhLE1BQU07SUFRakIsWUFBWSxPQUFzQjtRQUNoQyxJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksYUFBYSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQzVDLENBQUM7SUFFRDs7OztPQUlHO0lBQ0ksS0FBSyxDQUFDLEdBQUcsQ0FBQyxRQUFnQjtRQUMvQixNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sR0FBRyxRQUFRLENBQUM7UUFDaEQsTUFBTSxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxRQUFRLEVBQUUsU0FBUyxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUNuRixPQUFPLEtBQUssQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsRUFBRTtZQUMxQyxNQUFNLEVBQUUsS0FBSztZQUNiLE9BQU8sa0NBQ0YsT0FBTyxLQUNWLGNBQWMsRUFBRSxrQkFBa0IsR0FDbkM7U0FDRixDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSSxLQUFLLENBQUMsR0FBRyxDQUFDLFFBQWdCLEVBQUUsT0FBZ0I7UUFDakQsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEdBQUcsUUFBUSxDQUFDO1FBQ2hELE1BQU0sT0FBTyxHQUFHLE1BQU0sSUFBSSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsUUFBUSxFQUFFLE9BQU8sRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDakYsT0FBTyxLQUFLLENBQUMsT0FBTyxFQUFFO1lBQ3BCLE1BQU0sRUFBRSxLQUFLO1lBQ2IsT0FBTyxrQ0FDRixPQUFPLEtBQ1YsY0FBYyxFQUFFLGtCQUFrQixH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LENBQUMsSUFBSSxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUM7S0FDNUIsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0tBQ3pDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKiBQYXlsb2FkIGlzIGtub3duIGFzIHRoZSBcImJvZHlcIiBvZiBhIFJlcXVlc3QuIFRoZSBwYXlsb2FkIG11c3QgYmUgSlNPTiBzZXJpYWxpemFibGUuICovXG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueVxudHlwZSBQYXlsb2FkID0gYW55O1xuXG4vKipcbiAqIENsaWVudCBpcyBhIGNvbnZlbmllbmNlIGNsYXNzIGZvciBpbnRlcmFjdGluZyB3aXRoIHRoZSBSZW50IER5bmFtaWNzIHNlcnZpY2VzLlxuICpcbiAqIE5vdGUgaWYgdGhpcyBjbGFzcyBkb2VzIG5vdCBzdWl0IHlvdXIgbmVlZHMsIGl0IG1heSBiZSB3aXNlIHRvIHJvbGwgeW91ciBvd24gaW1wbGVtZW50YXRpb24gdXNpbmdcbiAqIHRoZSB7QGxpbmtjb2RlIENsaWVudEhlbHBlcnN9IGNsYXNzLlxuICovXG5leHBvcnQgY2xhc3MgQ2xpZW50IHtcbiAgLyoqXG4gICAqIGF1dGhUb2tlbiBpZiBkZWZpbmVkLCBhdXRoVG9rZW4gaXMgdXNlZCB0byBtYWtlIGF1dGhlbnRpY2F0ZWQgcmVxdWVzdHMuIE5vdGUgYXV0aFRva2VuIGlzIG5vdFxuICAgKiB0eXBpY2FsbHkgZ2V0L3NldCBtYW51YWxseSwgYnV0IGluc3RlYWQgaXMgbWFuYWdlZCB0aHJvdWdoIHRoZSBsb2dpbi9sb2dvdXQgbWV0aG9kcy5cbiAgICovXG4gIHB1YmxpYyBhdXRoVG9rZW46IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgcHJpdmF0ZSByZWFkb25seSBoZWxwZXJzOiBDbGllbnRIZWxwZXJzO1xuXG4gIGNvbnN0cnVjdG9yKG9wdGlvbnM6IENsaWVudE9wdGlvbnMpIHtcbiAgICB0aGlzLmhlbHBlcnMgPSBuZXcgQ2xpZW50SGVscGVycyhvcHRpb25zKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBnZXQgd3JhcHMgYSByZXF1ZXN0IGxpYnJhcnkgdG8gd29yayB3aXRoIHRoZSBSZW50IER5bmFtaWNzIEFQSS5cbiAgICogQHBhcmFtIGVuZHBvaW50IHRoZSBwYXRoIGZvbGxvd2luZyB0aGUgYmFzZVVybC5cbiAgICogQGV4YW1wbGUgZ2V0KCcvZm9vJyk7XG4gICAqL1xuICBwdWJsaWMgYXN5bmMgZ2V0KGVuZHBvaW50OiBzdHJpbmcpIHtcbiAgICBjb25zdCBmdWxsVXJsID0gdGhpcy5oZWxwZXJzLmJhc2VVcmwgKyBlbmRwb2ludDtcbiAgICBjb25zdCBoZWFkZXJzID0gYXdhaXQgdGhpcy5oZWxwZXJzLmdldEhlYWRlcnMoZW5kcG9pbnQsIHVuZGVmaW5lZCwgdGhpcy5hdXRoVG9rZW4pO1xuICAgIHJldHVybiBmZXRjaChmdWxsVXJsLnJlcGxhY2UoL1xcfC9nLCAnJTdDJyksIHtcbiAgICAgIG1ldGhvZDogJ0dFVCcsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgIC4uLmhlYWRlcnMsXG4gICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbidcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBwdXQgd3JhcHMgYSByZXF1ZXN0IGxpYnJhcnkgdG8gd29yayB3aXRoIHRoZSBSZW50IER5bmFtaWNzIEFQSS5cbiAgICogQHBhcmFtIGVuZHBvaW50IHRoZSBwYXRoIGZvbGxvd2luZyB0aGUgYmFzZVVybC5cbiAgICogQHBhcmFtIHBheWxvYWQgYSBKU09OIHNlcmlhbGl6YWJsZSBvYmplY3QuXG4gICAqIEBleGFtcGxlIHB1dCgnL2ZvbycsIHsgYmFyOiAxIH0pO1xuICAgKi9cbiAgcHVibGljIGFzeW5jIHB1dChlbmRwb2ludDogc3RyaW5nLCBwYXlsb2FkOiBQYXlsb2FkKSB7XG4gICAgY29uc3QgZnVsbFVybCA9IHRoaXMuaGVscGVycy5iYXNlVXJsICsgZW5kcG9pbnQ7XG4gICAgY29uc3QgaGVhZGVycyA9IGF3YWl0IHRoaXMuaGVscGVycy5nZXRIZWFkZXJzKGVuZHBvaW50LCBwYXlsb2FkLCB0aGlzLmF1dGhUb2tlbik7XG4gICAgcmV0dXJuIGZldGNoKGZ1bGxVcmwsIHtcbiAgICAgIG1ldGhvZDogJ1BVVCcsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgIC4uLmhlYWRlcnMsXG4gICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbidcbiAgICAgIH0sXG4gICAgICBib2R5OiBKU09OLnN0cmluZ2lmeShwYXlsb2FkKVxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIHBvc3Qgd3JhcHMgYSByZXF1ZXN0IGxpYnJhcnkgdG8gd29yayB3aXRoIHRoZSBSZW50IER5bmFtaWNzIEFQSS5cbiAgICogQHBhcmFtIGVuZHBvaW50IHRoZSBwYXRoIGZvbGxvd2luZyB0aGUgYmFzZVVybC5cbiAgICogQHBhcmFtIHBheWxvYWQgYSBKU09OIHNlcmlhbGl6YWJsZSBvYmplY3QuXG4gICAqIEBleGFtcGxlIHBvc3QoJy9mb28nLCB7IGJhcjogMSB9KTtcbiAgICovXG4gIHB1YmxpYyBhc3luYyBwb3N0KGVuZHBvaW50OiBzdHJpbmcsIHBheWxvYWQ6IFBheWxvYWQpIHtcbiAgICBjb25zdCBmdWxsVXJsID0gdGhpcy5oZWxwZXJzLmJhc2VVcmwgKyBlbmRwb2ludDtcbiAgICBjb25zdCBoZWFkZXJzID0gYXdhaXQgdGhpcy5oZWxwZXJzLmdldEhlYWRlcnMoZW5kcG9pbnQsIHBheWxvYWQsIHRoaXMuYXV0aFRva2VuKTtcbiAgICByZXR1cm4gZmV0Y2goZnVsbFVybCwge1xuICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgIC4uLmhlYWRlcnMsXG4gICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbidcbiAgICAgIH0sXG4gICAgICBib2R5OiBKU09OLnN0cmluZ2lmeShwYXlsb2FkKVxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIGRlbGV0ZSB3cmFwcyBhIHJlcXVlc3QgbGlicmFyeSB0byB3b3JrIHdpdGggdGhlIFJlbnQgRHluYW1pY3MgQVBJLlxuICAgKiBAcGFyYW0gZW5kcG9pbnQgdGhlIHBhdGggZm9sbG93aW5nIHRoZSBiYXNlVXJsLlxuICAgKiBAZXhhbXBsZSBkZWxldGUoJy9mb28vMScpO1xuICAgKi9cbiAgcHVibGljIGFzeW5jIGRlbGV0ZShlbmRwb2ludDogc3RyaW5nKSB7XG4gICAgY29uc3QgZnVsbFVybCA9IHRoaXMuaGVscGVycy5iYXNlVXJsICsgZW5kcG9pbnQ7XG4gICAgY29uc3QgaGVhZGVycyA9IGF3YWl0IHRoaXMuaGVscGVycy5nZXRIZWFkZXJzKGVuZHBvaW50LCB1bmRlZmluZWQsIHRoaXMuYXV0aFRva2VuKTtcbiAgICByZXR1cm4gZmV0Y2goZnVsbFVybCwge1xuICAgICAgbWV0aG9kOiAnREVMRVRFJyxcbiAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgLi4uaGVhZGVycyxcbiAgICAgICAgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJ1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIGxvZ2luIGVuYWJsZXMgYW4gaW5zdGFuY2Ugb2Yge0BsaW5rY29kZSBDbGllbnR9IHRvIG1ha2UgYXV0aGVudGljYXRlZCByZXF1ZXN0cyB0byB0aGUgUmVudFxuICAgKiBEeW5hbWljcyBBUEkuXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgbG9naW4odXNlcm5hbWU6IHN0cmluZywgcGFzc3dvcmQ6IHN0cmluZykge1xuICAgIGNvbnN0IF9wYXNzd29yZCA9IGF3YWl0IHRoaXMuaGVscGVycy5lbmNyeXB0UGFzc3dvcmQocGFzc3dvcmQpO1xuICAgIGNvbnN0IGVuZHBvaW50ID0gJy9hdXRoL2xvZ2luJztcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLnBvc3QoZW5kcG9pbnQsIHsgdXNlcm5hbWUsIHBhc3N3b3JkOiBfcGFzc3dvcmQgfSk7XG4gICAgaWYgKCFyZXN1bHQub2spIHtcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuICAgIGNvbnN0IHsgdG9rZW4gfSA9IGF3YWl0IHJlc3VsdC5qc29uKCk7XG4gICAgdGhpcy5hdXRoVG9rZW4gPSB0b2tlbjtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgLyoqIGxvZ291dCBpbnZhbGlkYXRlcyB0aGUgdXNlcnMgc2Vzc2lvbiBnZW5lcmF0ZWQgYnkge0BsaW5rY29kZSBsb2dpbn0uICovXG4gIHB1YmxpYyBhc3luYyBsb2dvdXQoKSB7XG4gICAgY29uc3QgZW5kcG9pbnQgPSAnL2F1dGgvbG9nb3V0JztcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLnBvc3QoZW5kcG9pbnQsIHsgYXV0aFRva2VuOiB0aGlzLmF1dGhUb2tlbiB9KTtcbiAgICBpZiAoIXJlc3VsdC5vaykge1xuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG4gICAgdGhpcy5hdXRoVG9rZW4gPSB1bmRlZmluZWQ7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxufVxuXG4vKiogQkFTRV9VUkwgaXMgYSBjb2xsZWN0aW9uIG9mIGJhc2UgdXJscyBmb3IgZWFjaCBkZXYvcHJvZCBSZW50IER5bmFtaWNzIHNlcnZpY2UuICovXG5leHBvcnQgZW51bSBCQVNFX1VSTCB7XG4gIERFVl9SRCA9ICdodHRwczovL2FwaS5yZW50ZHluYW1pY3MuZGV2JyxcbiAgUFJPRF9SRCA9ICdodHRwczovL2FwaS5yZW50ZHluYW1pY3MuY29tJyxcbiAgREVWX1JQID0gJ2h0dHBzOi8vYXBpLWRldi5yZW50cGx1cy5jb20nLFxuICBQUk9EX1JQID0gJ2h0dHBzOi8vYXBpLnJlbnRwbHVzLmNvbSdcbn1cblxuZXhwb3J0IHR5cGUgUmRFbmNvZGVyID0gUGljazxUZXh0RW5jb2RlciwgJ2VuY29kZSc+O1xuXG5leHBvcnQgdHlwZSBSZENyeXB0b2dyYXBoZXIgPSBQaWNrPFN1YnRsZUNyeXB0bywgJ2ltcG9ydEtleSc+ICZcbiAgUGljazxTdWJ0bGVDcnlwdG8sICdzaWduJz4gJlxuICBQaWNrPFN1YnRsZUNyeXB0bywgJ2RpZ2VzdCc+O1xuXG4vKiogQ2xpZW50T3B0aW9ucyBpcyBjb25zdW1lZCBhbmQgdXBkYXRlZCBieSB7QGxpbmtjb2RlIENsaWVudEhlbHBlcnN9LiAqL1xuZXhwb3J0IGNsYXNzIENsaWVudE9wdGlvbnMge1xuICAvKiogYXBpS2V5IGlmIGRlZmluZWQgYXBpS2V5IGlzIHVzZWQgdG8gY2FsY3VsYXRlIGF1dGggaGVhZGVycy4gKi9cbiAgcHVibGljIGFwaUtleTogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAvKiogYXBpU2VjcmV0S2V5IGlmIGRlZmluZWQgYXBpU2VjcmV0S2V5IGlzIHVzZWQgdG8gY2FsY3VsYXRlIGF1dGggaGVhZGVycy4gICovXG4gIHB1YmxpYyBhcGlTZWNyZXRLZXk6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgLyoqXG4gICAqIGJhc2VVcmwgaXMgdGhlIGJhc2UgcmVxdWVzdCB1cmwuIFRoZSBkZWZhdWx0IGlzIHRoZSBkZXZlbG9wbWVudCByZW50ZHluYW1pY3MgYXBpLiBBIGN1c3RvbVxuICAgKiBzdHJpbmcgbWF5IGJlIHByb3ZpZGVkIGJleW9uZCB0aGUge0BsaW5rY29kZSBCQVNFX1VSTH0gb3B0aW9ucy5cbiAgICovXG4gIHB1YmxpYyBiYXNlVXJsOiBCQVNFX1VSTCB8IHN0cmluZyA9IEJBU0VfVVJMLkRFVl9SRDtcblxuICAvKipcbiAgICogZ2V0RW5jb2RlciBpcyB1c2VkIHRvIGVuY29kZSB0ZXh0LiBUaGUgZW5jb2RlciBjYW4gYmUgb3ZlcnJpZGRlbiBhcyBuZWVkZWQuIEZvciBleGFtcGxlIGluIGFcbiAgICogbm9kZSBlbnZpcm9ubWVudC5cbiAgICogQGV4YW1wbGVcbiAgICogY29uc3Qgb3B0aW9ucyA9IG5ldyBDbGllbnRPcHRpb25zKCk7XG4gICAqIG9wdGlvbnMuZ2V0RW5jb2RlciA9IGFzeW5jICgpID0+IG5ldyAoYXdhaXQgaW1wb3J0KCd1dGlsJykpLlRleHRFbmNvZGVyKCk7XG4gICAqL1xuICBwdWJsaWMgZ2V0RW5jb2RlciA9IGFzeW5jICgpOiBQcm9taXNlPFJkRW5jb2Rlcj4gPT4gbmV3IFRleHRFbmNvZGVyKCk7XG5cbiAgLyoqXG4gICAqIGdldENyeXB0b2dyYXBoZXIgaXMgdXNlZCBmb3IgY3J5cHRvZ3JhcGh5LiBUaGUgY3J5cHRvZ3JhcGhlciBjYW4gYmUgb3ZlcnJpZGRlbiBhcyBuZWVkZWQuIEZvclxuICAgKiBleGFtcGxlIGluIGEgbm9kZSBlbnZpcm9ubWVudC5cbiAgICogQGV4YW1wbGVcbiAgICogY29uc3Qgb3B0aW9ucyA9IG5ldyBDbGllbnRPcHRpb25zKCk7XG4gICAqIG9wdGlvbnMuZ2V0Q3J5cHRvZ3JhcGhlciA9IGFzeW5jICgpID0+IChhd2FpdCBpbXBvcnQoJ2NyeXB0bycpKS5zdWJ0bGU7XG4gICAqL1xuICBwdWJsaWMgZ2V0Q3J5cHRvZ3JhcGhlciA9IGFzeW5jICgpOiBQcm9taXNlPFJkQ3J5cHRvZ3JhcGhlcj4gPT4gY3J5cHRvLnN1YnRsZTtcbn1cblxuLyoqXG4gKiBDbGllbnRIZWxwZXJzIGlzIGEgY29sbGVjdGlvbiBvZiB1dGlsaXRpZXMgY29uc3VtZWQgYnkge0BsaW5rY29kZSBDbGllbnR9LiBDbGllbnRIZWxwZXJzIGNhbiBiZVxuICogdXNlZCB0byBjYWxjdWxhdGUgaGVhZGVycyBpbiBjYXNlIGEgY29uc3VtZXIgd2FudHMgdG8gYnVpbGQgdGhlaXIgb3duIEFQSSBjbGllbnQuXG4gKi9cbmV4cG9ydCBjbGFzcyBDbGllbnRIZWxwZXJzIHtcbiAgcHJpdmF0ZSBvcHRpb25zOiBDbGllbnRPcHRpb25zO1xuXG4gIGNvbnN0cnVjdG9yKG9wdGlvbnM6IENsaWVudE9wdGlvbnMpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSBvcHRpb25zO1xuICB9XG5cbiAgLyoqXG4gICAqIGJhc2VVcmwgaXMgdGhlIGJhc2UgdXJsIHVzZWQgdGhyb3VnaG91dCB0aGUge0BsaW5rY29kZSBDbGllbnRIZWxwZXJzfSBpbnN0YW5jZS4gSXQgaXMgaW5pdGlhbGx5XG4gICAqIGNvbmZpZ3VyZWQgdGhyb3VnaCB7QGxpbmtjb2RlIENsaWVudE9wdGlvbnN9LlxuICAgKi9cbiAgZ2V0IGJhc2VVcmwoKSB7XG4gICAgcmV0dXJuIHRoaXMub3B0aW9ucy5iYXNlVXJsO1xuICB9XG5cbiAgLyoqXG4gICAqIGdldFRpbWVzdGFtcCBpcyB1c2VkIHRvIGNhbGN1bGF0ZSB0aGUgdGltZXN0YW1wIGhlYWRlci4gVGhpcyBtZXRob2QgaXMgbm90IGxpa2VseSB0byBiZSBjYWxsZWRcbiAgICogb24gaXQncyBvd24uIEluc3RlYWQsIGl0IGlzIHR5cGljYWxseSB1c2VkIHRvIG1vY2sgdGhlIGN1cnJlbnQgdGltZS5cbiAgICovXG4gIHB1YmxpYyBnZXRUaW1lc3RhbXAoKSB7XG4gICAgcmV0dXJuIERhdGUubm93KCk7XG4gIH1cblxuICAvKipcbiAgICogZ2V0SGVhZGVycyBjcmVhdGVzIGhlYWRlcnMgZm9yIHRoZSBnaXZlbiBwYXJhbXMuIElmIGFuIGF1dGggdG9rZW4gaXMgaW5jbHVkZWQsIHRoaXMgbWV0aG9kIHdpbGxcbiAgICogZ2VuZXJhdGUgYW4gYEF1dGhvcml6YXRpb25gIGhlYWRlci5cbiAgICovXG4gIHB1YmxpYyBhc3luYyBnZXRIZWFkZXJzKFxuICAgIGVuZHBvaW50OiBzdHJpbmcsXG4gICAgcGF5bG9hZD86IFBheWxvYWQgfCB1bmRlZmluZWQsXG4gICAgYXV0aFRva2VuPzogc3RyaW5nIHwgdW5kZWZpbmVkXG4gICkge1xuICAgIGNvbnN0IGhlYWRlcnM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fTtcbiAgICBpZiAodGhpcy5vcHRpb25zLmFwaUtleSAmJiB0aGlzLm9wdGlvbnMuYXBpU2VjcmV0S2V5KSB7XG4gICAgICBpZiAoIXBheWxvYWQgfHwgIU9iamVjdC5rZXlzKHBheWxvYWQpLmxlbmd0aCkge1xuICAgICAgICBwYXlsb2FkID0gdW5kZWZpbmVkO1xuICAgICAgfVxuICAgICAgaWYgKHR5cGVvZiBwYXlsb2FkICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICBwYXlsb2FkID0gSlNPTi5zdHJpbmdpZnkodGhpcy5mb3JtYXRQYXlsb2FkKHBheWxvYWQpKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHRpbWVzdGFtcCA9IHRoaXMuZ2V0VGltZXN0YW1wKCk7XG4gICAgICBjb25zdCBub25jZSA9IGF3YWl0IHRoaXMuZ2V0Tm9uY2UodGltZXN0YW1wLCBlbmRwb2ludCwgcGF5bG9hZCk7XG4gICAgICBpZiAoYXV0aFRva2VuKSB7XG4gICAgICAgIGhlYWRlcnMuQXV0aG9yaXphdGlvbiA9ICdUT0tFTiAnICsgYXV0aFRva2VuO1xuICAgICAgfVxuICAgICAgaGVhZGVyc1sneC1yZC1hcGkta2V5J10gPSB0aGlzLm9wdGlvbnMuYXBpS2V5O1xuICAgICAgaGVhZGVyc1sneC1yZC1hcGktbm9uY2UnXSA9IG5vbmNlO1xuICAgICAgaGVhZGVyc1sneC1yZC10aW1lc3RhbXAnXSA9IHRpbWVzdGFtcC50b1N0cmluZygpO1xuICAgICAgcmV0dXJuIGhlYWRlcnM7XG4gICAgfVxuICAgIHJldHVybiBoZWFkZXJzO1xuICB9XG5cbiAgLyoqIGZvcm1hdFBheWxvYWQgZm9ybWF0cyB0aGUgcGF5bG9hZCBmb3Igbm9uY2UgY2FsY3VsYXRpb24uICovXG4gIHB1YmxpYyBmb3JtYXRQYXlsb2FkKHBheWxvYWQ6IFBheWxvYWQpOiBQYXlsb2FkIHtcbiAgICBsZXQgZm9ybWF0dGVkUGF5bG9hZDogUGF5bG9hZCA9IHt9O1xuICAgIGlmIChwYXlsb2FkID09PSB1bmRlZmluZWQgfHwgcGF5bG9hZCA9PT0gbnVsbCkge1xuICAgICAgZm9ybWF0dGVkUGF5bG9hZCA9IG51bGw7XG4gICAgfSBlbHNlIGlmIChwYXlsb2FkICE9PSBPYmplY3QocGF5bG9hZCkpIHtcbiAgICAgIGZvcm1hdHRlZFBheWxvYWQgPSBwYXlsb2FkO1xuICAgIH0gZWxzZSBpZiAoQXJyYXkuaXNBcnJheShwYXlsb2FkKSkge1xuICAgICAgZm9ybWF0dGVkUGF5bG9hZCA9IFtdO1xuICAgICAgcGF5bG9hZC5mb3JFYWNoKChfLCBpbmRleCkgPT4ge1xuICAgICAgICBmb3JtYXR0ZWRQYXlsb2FkW2luZGV4XSA9IHRoaXMuZm9ybWF0UGF5bG9hZChwYXlsb2FkW2luZGV4XSk7XG4gICAgICB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgT2JqZWN0LmtleXMocGF5bG9hZClcbiAgICAgICAgLnNvcnQoKVxuICAgICAgICAuZm9yRWFjaChrID0+IHtcbiAgICAgICAgICBpZiAodHlwZW9mIHBheWxvYWRba10gPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICBmb3JtYXR0ZWRQYXlsb2FkW2tdID0gdGhpcy5mb3JtYXRQYXlsb2FkKHBheWxvYWRba10pO1xuICAgICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIHBheWxvYWRba10gPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICBmb3JtYXR0ZWRQYXlsb2FkW2tdID0gcGF5bG9hZFtrXS5yZXBsYWNlKC8gL2csICcnKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZm9ybWF0dGVkUGF5bG9hZFtrXSA9IHBheWxvYWRba107XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG4gICAgcmV0dXJuIGZvcm1hdHRlZFBheWxvYWQ7XG4gIH1cblxuICAvKiogZ2V0Tm9uY2UgY2FsY3VsYXRlcyB0aGUgbm9uY2UgZm9yIHRoZSBnaXZlbiBwYXJhbXMuICovXG4gIHB1YmxpYyBhc3luYyBnZXROb25jZSh0aW1lc3RhbXA6IG51bWJlciwgdXJsOiBzdHJpbmcsIHBheWxvYWRTdHI/OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGlmICghdGhpcy5vcHRpb25zLmFwaVNlY3JldEtleSkgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgnJyk7XG4gICAgY29uc3QgZW5jb2RlZFVybCA9IGVuY29kZVVSSSh1cmwpXG4gICAgICAucmVwbGFjZSgvJTdbQ2NdL2csICd8JylcbiAgICAgIC5yZXBsYWNlKC8lMjAvZywgJyAnKTtcbiAgICBjb25zdCBub25jZVN0ciA9XG4gICAgICB0eXBlb2YgcGF5bG9hZFN0ciAhPT0gJ3VuZGVmaW5lZCdcbiAgICAgICAgPyB0aW1lc3RhbXAgKyBlbmNvZGVkVXJsICsgcGF5bG9hZFN0clxuICAgICAgICA6IHRpbWVzdGFtcCArIGVuY29kZWRVcmw7XG4gICAgY29uc3QgY3J5cHRvZ3JhcGhlciA9IGF3YWl0IHRoaXMub3B0aW9ucy5nZXRDcnlwdG9ncmFwaGVyKCk7XG4gICAgY29uc3QgZW5jb2RlciA9IGF3YWl0IHRoaXMub3B0aW9ucy5nZXRFbmNvZGVyKCk7XG4gICAgY29uc3Qga2V5ID0gZW5jb2Rlci5lbmNvZGUodGhpcy5vcHRpb25zLmFwaVNlY3JldEtleSk7XG4gICAgY29uc3QgZGF0YSA9IGVuY29kZXIuZW5jb2RlKG5vbmNlU3RyKTtcbiAgICBjb25zdCBhbGdvcml0aG0gPSB7IG5hbWU6ICdITUFDJywgaGFzaDogJ1NIQS0xJyB9O1xuICAgIGNvbnN0IGhtYWMgPSBhd2FpdCBjcnlwdG9ncmFwaGVyLmltcG9ydEtleSgncmF3Jywga2V5LCBhbGdvcml0aG0sIGZhbHNlLCBbJ3NpZ24nXSk7XG4gICAgY29uc3Qgc2lnbmVkID0gYXdhaXQgY3J5cHRvZ3JhcGhlci5zaWduKGFsZ29yaXRobS5uYW1lLCBobWFjLCBkYXRhKTtcbiAgICByZXR1cm4gX2hleERpZ2VzdChzaWduZWQpO1xuICB9XG5cbiAgLyoqIGVuY3J5cHRQYXNzd29yZCBlbmNyeXB0cyB0aGUgcGFzc3dvcmQgZm9yIGxvZ2luLiAqL1xuICBwdWJsaWMgYXN5bmMgZW5jcnlwdFBhc3N3b3JkKHBhc3N3b3JkOiBzdHJpbmcpIHtcbiAgICBjb25zdCBjcnlwdG9ncmFwaGVyID0gYXdhaXQgdGhpcy5vcHRpb25zLmdldENyeXB0b2dyYXBoZXIoKTtcbiAgICBjb25zdCBlbmNvZGVyID0gYXdhaXQgdGhpcy5vcHRpb25zLmdldEVuY29kZXIoKTtcbiAgICBjb25zdCBlbmNvZGVkUGFzc3dvcmQgPSBlbmNvZGVyLmVuY29kZShwYXNzd29yZCk7XG4gICAgY29uc3QgZGlnZXN0ZWRQYXNzd29yZCA9IGF3YWl0IGNyeXB0b2dyYXBoZXIuZGlnZXN0KCdTSEEtMScsIGVuY29kZWRQYXNzd29yZCk7XG4gICAgcmV0dXJuIF9oZXhEaWdlc3QoZGlnZXN0ZWRQYXNzd29yZCk7XG4gIH1cbn1cblxuY29uc3QgX2hleERpZ2VzdCA9IChidWY6IEFycmF5QnVmZmVyKTogc3RyaW5nID0+XG4gIEFycmF5LmZyb20obmV3IFVpbnQ4QXJyYXkoYnVmKSlcbiAgICAubWFwKGIgPT4gYi50b1N0cmluZygxNikucGFkU3RhcnQoMiwgJzAnKSlcbiAgICAuam9pbignJyk7XG4iXX0=