minio
Version:
S3 Compatible Cloud Storage client
258 lines (248 loc) • 40.8 kB
JavaScript
/*
* MinIO Javascript Library for Amazon S3 Compatible Cloud Storage, (C) 2016 MinIO, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as crypto from "crypto";
import * as errors from "./errors.mjs";
import { PRESIGN_EXPIRY_DAYS_MAX } from "./helpers.mjs";
import { getScope, isNumber, isObject, isString, makeDateLong, makeDateShort, uriEscape } from "./internal/helper.mjs";
const signV4Algorithm = 'AWS4-HMAC-SHA256';
// getCanonicalRequest generate a canonical request of style.
//
// canonicalRequest =
// <HTTPMethod>\n
// <CanonicalURI>\n
// <CanonicalQueryString>\n
// <CanonicalHeaders>\n
// <SignedHeaders>\n
// <HashedPayload>
//
function getCanonicalRequest(method, path, headers, signedHeaders, hashedPayload) {
if (!isString(method)) {
throw new TypeError('method should be of type "string"');
}
if (!isString(path)) {
throw new TypeError('path should be of type "string"');
}
if (!isObject(headers)) {
throw new TypeError('headers should be of type "object"');
}
if (!Array.isArray(signedHeaders)) {
throw new TypeError('signedHeaders should be of type "array"');
}
if (!isString(hashedPayload)) {
throw new TypeError('hashedPayload should be of type "string"');
}
const headersArray = signedHeaders.reduce((acc, i) => {
// Trim spaces from the value (required by V4 spec)
const val = `${headers[i]}`.replace(/ +/g, ' ');
acc.push(`${i.toLowerCase()}:${val}`);
return acc;
}, []);
const requestResource = path.split('?')[0];
let requestQuery = path.split('?')[1];
if (!requestQuery) {
requestQuery = '';
}
if (requestQuery) {
requestQuery = requestQuery.split('&').sort().map(element => !element.includes('=') ? element + '=' : element).join('&');
}
return [method.toUpperCase(), requestResource, requestQuery, headersArray.join('\n') + '\n', signedHeaders.join(';').toLowerCase(), hashedPayload].join('\n');
}
// generate a credential string
function getCredential(accessKey, region, requestDate, serviceName = 's3') {
if (!isString(accessKey)) {
throw new TypeError('accessKey should be of type "string"');
}
if (!isString(region)) {
throw new TypeError('region should be of type "string"');
}
if (!isObject(requestDate)) {
throw new TypeError('requestDate should be of type "object"');
}
return `${accessKey}/${getScope(region, requestDate, serviceName)}`;
}
// Returns signed headers array - alphabetically sorted
function getSignedHeaders(headers) {
if (!isObject(headers)) {
throw new TypeError('request should be of type "object"');
}
// Excerpts from @lsegal - https://github.com/aws/aws-sdk-js/issues/659#issuecomment-120477258
//
// User-Agent:
//
// This is ignored from signing because signing this causes problems with generating pre-signed URLs
// (that are executed by other agents) or when customers pass requests through proxies, which may
// modify the user-agent.
//
// Content-Length:
//
// This is ignored from signing because generating a pre-signed URL should not provide a content-length
// constraint, specifically when vending a S3 pre-signed PUT URL. The corollary to this is that when
// sending regular requests (non-pre-signed), the signature contains a checksum of the body, which
// implicitly validates the payload length (since changing the number of bytes would change the checksum)
// and therefore this header is not valuable in the signature.
//
// Content-Type:
//
// Signing this header causes quite a number of problems in browser environments, where browsers
// like to modify and normalize the content-type header in different ways. There is more information
// on this in https://github.com/aws/aws-sdk-js/issues/244. Avoiding this field simplifies logic
// and reduces the possibility of future bugs
//
// Authorization:
//
// Is skipped for obvious reasons
const ignoredHeaders = ['authorization', 'content-length', 'content-type', 'user-agent'];
return Object.keys(headers).filter(header => !ignoredHeaders.includes(header)).sort();
}
// returns the key used for calculating signature
function getSigningKey(date, region, secretKey, serviceName = 's3') {
if (!isObject(date)) {
throw new TypeError('date should be of type "object"');
}
if (!isString(region)) {
throw new TypeError('region should be of type "string"');
}
if (!isString(secretKey)) {
throw new TypeError('secretKey should be of type "string"');
}
const dateLine = makeDateShort(date);
const hmac1 = crypto.createHmac('sha256', 'AWS4' + secretKey).update(dateLine).digest(),
hmac2 = crypto.createHmac('sha256', hmac1).update(region).digest(),
hmac3 = crypto.createHmac('sha256', hmac2).update(serviceName).digest();
return crypto.createHmac('sha256', hmac3).update('aws4_request').digest();
}
// returns the string that needs to be signed
function getStringToSign(canonicalRequest, requestDate, region, serviceName = 's3') {
if (!isString(canonicalRequest)) {
throw new TypeError('canonicalRequest should be of type "string"');
}
if (!isObject(requestDate)) {
throw new TypeError('requestDate should be of type "object"');
}
if (!isString(region)) {
throw new TypeError('region should be of type "string"');
}
const hash = crypto.createHash('sha256').update(canonicalRequest).digest('hex');
const scope = getScope(region, requestDate, serviceName);
const stringToSign = [signV4Algorithm, makeDateLong(requestDate), scope, hash];
return stringToSign.join('\n');
}
// calculate the signature of the POST policy
export function postPresignSignatureV4(region, date, secretKey, policyBase64) {
if (!isString(region)) {
throw new TypeError('region should be of type "string"');
}
if (!isObject(date)) {
throw new TypeError('date should be of type "object"');
}
if (!isString(secretKey)) {
throw new TypeError('secretKey should be of type "string"');
}
if (!isString(policyBase64)) {
throw new TypeError('policyBase64 should be of type "string"');
}
const signingKey = getSigningKey(date, region, secretKey);
return crypto.createHmac('sha256', signingKey).update(policyBase64).digest('hex').toLowerCase();
}
// Returns the authorization header
export function signV4(request, accessKey, secretKey, region, requestDate, sha256sum, serviceName = 's3') {
if (!isObject(request)) {
throw new TypeError('request should be of type "object"');
}
if (!isString(accessKey)) {
throw new TypeError('accessKey should be of type "string"');
}
if (!isString(secretKey)) {
throw new TypeError('secretKey should be of type "string"');
}
if (!isString(region)) {
throw new TypeError('region should be of type "string"');
}
if (!accessKey) {
throw new errors.AccessKeyRequiredError('accessKey is required for signing');
}
if (!secretKey) {
throw new errors.SecretKeyRequiredError('secretKey is required for signing');
}
const signedHeaders = getSignedHeaders(request.headers);
const canonicalRequest = getCanonicalRequest(request.method, request.path, request.headers, signedHeaders, sha256sum);
const serviceIdentifier = serviceName || 's3';
const stringToSign = getStringToSign(canonicalRequest, requestDate, region, serviceIdentifier);
const signingKey = getSigningKey(requestDate, region, secretKey, serviceIdentifier);
const credential = getCredential(accessKey, region, requestDate, serviceIdentifier);
const signature = crypto.createHmac('sha256', signingKey).update(stringToSign).digest('hex').toLowerCase();
return `${signV4Algorithm} Credential=${credential}, SignedHeaders=${signedHeaders.join(';').toLowerCase()}, Signature=${signature}`;
}
export function signV4ByServiceName(request, accessKey, secretKey, region, requestDate, contentSha256, serviceName = 's3') {
return signV4(request, accessKey, secretKey, region, requestDate, contentSha256, serviceName);
}
// returns a presigned URL string
export function presignSignatureV4(request, accessKey, secretKey, sessionToken, region, requestDate, expires) {
if (!isObject(request)) {
throw new TypeError('request should be of type "object"');
}
if (!isString(accessKey)) {
throw new TypeError('accessKey should be of type "string"');
}
if (!isString(secretKey)) {
throw new TypeError('secretKey should be of type "string"');
}
if (!isString(region)) {
throw new TypeError('region should be of type "string"');
}
if (!accessKey) {
throw new errors.AccessKeyRequiredError('accessKey is required for presigning');
}
if (!secretKey) {
throw new errors.SecretKeyRequiredError('secretKey is required for presigning');
}
if (expires && !isNumber(expires)) {
throw new TypeError('expires should be of type "number"');
}
if (expires && expires < 1) {
throw new errors.ExpiresParamError('expires param cannot be less than 1 seconds');
}
if (expires && expires > PRESIGN_EXPIRY_DAYS_MAX) {
throw new errors.ExpiresParamError('expires param cannot be greater than 7 days');
}
const iso8601Date = makeDateLong(requestDate);
const signedHeaders = getSignedHeaders(request.headers);
const credential = getCredential(accessKey, region, requestDate);
const hashedPayload = 'UNSIGNED-PAYLOAD';
const requestQuery = [];
requestQuery.push(`X-Amz-Algorithm=${signV4Algorithm}`);
requestQuery.push(`X-Amz-Credential=${uriEscape(credential)}`);
requestQuery.push(`X-Amz-Date=${iso8601Date}`);
requestQuery.push(`X-Amz-Expires=${expires}`);
requestQuery.push(`X-Amz-SignedHeaders=${uriEscape(signedHeaders.join(';').toLowerCase())}`);
if (sessionToken) {
requestQuery.push(`X-Amz-Security-Token=${uriEscape(sessionToken)}`);
}
const resource = request.path.split('?')[0];
let query = request.path.split('?')[1];
if (query) {
query = query + '&' + requestQuery.join('&');
} else {
query = requestQuery.join('&');
}
const path = resource + '?' + query;
const canonicalRequest = getCanonicalRequest(request.method, path, request.headers, signedHeaders, hashedPayload);
const stringToSign = getStringToSign(canonicalRequest, requestDate, region);
const signingKey = getSigningKey(requestDate, region, secretKey);
const signature = crypto.createHmac('sha256', signingKey).update(stringToSign).digest('hex').toLowerCase();
return request.protocol + '//' + request.headers.host + path + `&X-Amz-Signature=${signature}`;
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJjcnlwdG8iLCJlcnJvcnMiLCJQUkVTSUdOX0VYUElSWV9EQVlTX01BWCIsImdldFNjb3BlIiwiaXNOdW1iZXIiLCJpc09iamVjdCIsImlzU3RyaW5nIiwibWFrZURhdGVMb25nIiwibWFrZURhdGVTaG9ydCIsInVyaUVzY2FwZSIsInNpZ25WNEFsZ29yaXRobSIsImdldENhbm9uaWNhbFJlcXVlc3QiLCJtZXRob2QiLCJwYXRoIiwiaGVhZGVycyIsInNpZ25lZEhlYWRlcnMiLCJoYXNoZWRQYXlsb2FkIiwiVHlwZUVycm9yIiwiQXJyYXkiLCJpc0FycmF5IiwiaGVhZGVyc0FycmF5IiwicmVkdWNlIiwiYWNjIiwiaSIsInZhbCIsInJlcGxhY2UiLCJwdXNoIiwidG9Mb3dlckNhc2UiLCJyZXF1ZXN0UmVzb3VyY2UiLCJzcGxpdCIsInJlcXVlc3RRdWVyeSIsInNvcnQiLCJtYXAiLCJlbGVtZW50IiwiaW5jbHVkZXMiLCJqb2luIiwidG9VcHBlckNhc2UiLCJnZXRDcmVkZW50aWFsIiwiYWNjZXNzS2V5IiwicmVnaW9uIiwicmVxdWVzdERhdGUiLCJzZXJ2aWNlTmFtZSIsImdldFNpZ25lZEhlYWRlcnMiLCJpZ25vcmVkSGVhZGVycyIsIk9iamVjdCIsImtleXMiLCJmaWx0ZXIiLCJoZWFkZXIiLCJnZXRTaWduaW5nS2V5IiwiZGF0ZSIsInNlY3JldEtleSIsImRhdGVMaW5lIiwiaG1hYzEiLCJjcmVhdGVIbWFjIiwidXBkYXRlIiwiZGlnZXN0IiwiaG1hYzIiLCJobWFjMyIsImdldFN0cmluZ1RvU2lnbiIsImNhbm9uaWNhbFJlcXVlc3QiLCJoYXNoIiwiY3JlYXRlSGFzaCIsInNjb3BlIiwic3RyaW5nVG9TaWduIiwicG9zdFByZXNpZ25TaWduYXR1cmVWNCIsInBvbGljeUJhc2U2NCIsInNpZ25pbmdLZXkiLCJzaWduVjQiLCJyZXF1ZXN0Iiwic2hhMjU2c3VtIiwiQWNjZXNzS2V5UmVxdWlyZWRFcnJvciIsIlNlY3JldEtleVJlcXVpcmVkRXJyb3IiLCJzZXJ2aWNlSWRlbnRpZmllciIsImNyZWRlbnRpYWwiLCJzaWduYXR1cmUiLCJzaWduVjRCeVNlcnZpY2VOYW1lIiwiY29udGVudFNoYTI1NiIsInByZXNpZ25TaWduYXR1cmVWNCIsInNlc3Npb25Ub2tlbiIsImV4cGlyZXMiLCJFeHBpcmVzUGFyYW1FcnJvciIsImlzbzg2MDFEYXRlIiwicmVzb3VyY2UiLCJxdWVyeSIsInByb3RvY29sIiwiaG9zdCJdLCJzb3VyY2VzIjpbInNpZ25pbmcudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIE1pbklPIEphdmFzY3JpcHQgTGlicmFyeSBmb3IgQW1hem9uIFMzIENvbXBhdGlibGUgQ2xvdWQgU3RvcmFnZSwgKEMpIDIwMTYgTWluSU8sIEluYy5cbiAqXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG4gKlxuICogICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKi9cblxuaW1wb3J0ICogYXMgY3J5cHRvIGZyb20gJ25vZGU6Y3J5cHRvJ1xuXG5pbXBvcnQgKiBhcyBlcnJvcnMgZnJvbSAnLi9lcnJvcnMudHMnXG5pbXBvcnQgeyBQUkVTSUdOX0VYUElSWV9EQVlTX01BWCB9IGZyb20gJy4vaGVscGVycy50cydcbmltcG9ydCB7IGdldFNjb3BlLCBpc051bWJlciwgaXNPYmplY3QsIGlzU3RyaW5nLCBtYWtlRGF0ZUxvbmcsIG1ha2VEYXRlU2hvcnQsIHVyaUVzY2FwZSB9IGZyb20gJy4vaW50ZXJuYWwvaGVscGVyLnRzJ1xuaW1wb3J0IHR5cGUgeyBJQ2Fub25pY2FsUmVxdWVzdCwgSVJlcXVlc3QsIFJlcXVlc3RIZWFkZXJzIH0gZnJvbSAnLi9pbnRlcm5hbC90eXBlLnRzJ1xuXG5jb25zdCBzaWduVjRBbGdvcml0aG0gPSAnQVdTNC1ITUFDLVNIQTI1NidcblxuLy8gZ2V0Q2Fub25pY2FsUmVxdWVzdCBnZW5lcmF0ZSBhIGNhbm9uaWNhbCByZXF1ZXN0IG9mIHN0eWxlLlxuLy9cbi8vIGNhbm9uaWNhbFJlcXVlc3QgPVxuLy8gIDxIVFRQTWV0aG9kPlxcblxuLy8gIDxDYW5vbmljYWxVUkk+XFxuXG4vLyAgPENhbm9uaWNhbFF1ZXJ5U3RyaW5nPlxcblxuLy8gIDxDYW5vbmljYWxIZWFkZXJzPlxcblxuLy8gIDxTaWduZWRIZWFkZXJzPlxcblxuLy8gIDxIYXNoZWRQYXlsb2FkPlxuLy9cbmZ1bmN0aW9uIGdldENhbm9uaWNhbFJlcXVlc3QoXG4gIG1ldGhvZDogc3RyaW5nLFxuICBwYXRoOiBzdHJpbmcsXG4gIGhlYWRlcnM6IFJlcXVlc3RIZWFkZXJzLFxuICBzaWduZWRIZWFkZXJzOiBzdHJpbmdbXSxcbiAgaGFzaGVkUGF5bG9hZDogc3RyaW5nLFxuKTogSUNhbm9uaWNhbFJlcXVlc3Qge1xuICBpZiAoIWlzU3RyaW5nKG1ldGhvZCkpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdtZXRob2Qgc2hvdWxkIGJlIG9mIHR5cGUgXCJzdHJpbmdcIicpXG4gIH1cbiAgaWYgKCFpc1N0cmluZyhwYXRoKSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ3BhdGggc2hvdWxkIGJlIG9mIHR5cGUgXCJzdHJpbmdcIicpXG4gIH1cbiAgaWYgKCFpc09iamVjdChoZWFkZXJzKSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ2hlYWRlcnMgc2hvdWxkIGJlIG9mIHR5cGUgXCJvYmplY3RcIicpXG4gIH1cbiAgaWYgKCFBcnJheS5pc0FycmF5KHNpZ25lZEhlYWRlcnMpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignc2lnbmVkSGVhZGVycyBzaG91bGQgYmUgb2YgdHlwZSBcImFycmF5XCInKVxuICB9XG4gIGlmICghaXNTdHJpbmcoaGFzaGVkUGF5bG9hZCkpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdoYXNoZWRQYXlsb2FkIHNob3VsZCBiZSBvZiB0eXBlIFwic3RyaW5nXCInKVxuICB9XG5cbiAgY29uc3QgaGVhZGVyc0FycmF5ID0gc2lnbmVkSGVhZGVycy5yZWR1Y2UoKGFjYywgaSkgPT4ge1xuICAgIC8vIFRyaW0gc3BhY2VzIGZyb20gdGhlIHZhbHVlIChyZXF1aXJlZCBieSBWNCBzcGVjKVxuICAgIGNvbnN0IHZhbCA9IGAke2hlYWRlcnNbaV19YC5yZXBsYWNlKC8gKy9nLCAnICcpXG4gICAgYWNjLnB1c2goYCR7aS50b0xvd2VyQ2FzZSgpfToke3ZhbH1gKVxuICAgIHJldHVybiBhY2NcbiAgfSwgW10gYXMgc3RyaW5nW10pXG5cbiAgY29uc3QgcmVxdWVzdFJlc291cmNlID0gcGF0aC5zcGxpdCgnPycpWzBdXG4gIGxldCByZXF1ZXN0UXVlcnkgPSBwYXRoLnNwbGl0KCc/JylbMV1cbiAgaWYgKCFyZXF1ZXN0UXVlcnkpIHtcbiAgICByZXF1ZXN0UXVlcnkgPSAnJ1xuICB9XG5cbiAgaWYgKHJlcXVlc3RRdWVyeSkge1xuICAgIHJlcXVlc3RRdWVyeSA9IHJlcXVlc3RRdWVyeVxuICAgICAgLnNwbGl0KCcmJylcbiAgICAgIC5zb3J0KClcbiAgICAgIC5tYXAoKGVsZW1lbnQpID0+ICghZWxlbWVudC5pbmNsdWRlcygnPScpID8gZWxlbWVudCArICc9JyA6IGVsZW1lbnQpKVxuICAgICAgLmpvaW4oJyYnKVxuICB9XG5cbiAgcmV0dXJuIFtcbiAgICBtZXRob2QudG9VcHBlckNhc2UoKSxcbiAgICByZXF1ZXN0UmVzb3VyY2UsXG4gICAgcmVxdWVzdFF1ZXJ5LFxuICAgIGhlYWRlcnNBcnJheS5qb2luKCdcXG4nKSArICdcXG4nLFxuICAgIHNpZ25lZEhlYWRlcnMuam9pbignOycpLnRvTG93ZXJDYXNlKCksXG4gICAgaGFzaGVkUGF5bG9hZCxcbiAgXS5qb2luKCdcXG4nKVxufVxuXG4vLyBnZW5lcmF0ZSBhIGNyZWRlbnRpYWwgc3RyaW5nXG5mdW5jdGlvbiBnZXRDcmVkZW50aWFsKGFjY2Vzc0tleTogc3RyaW5nLCByZWdpb246IHN0cmluZywgcmVxdWVzdERhdGU/OiBEYXRlLCBzZXJ2aWNlTmFtZSA9ICdzMycpIHtcbiAgaWYgKCFpc1N0cmluZyhhY2Nlc3NLZXkpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignYWNjZXNzS2V5IHNob3VsZCBiZSBvZiB0eXBlIFwic3RyaW5nXCInKVxuICB9XG4gIGlmICghaXNTdHJpbmcocmVnaW9uKSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ3JlZ2lvbiBzaG91bGQgYmUgb2YgdHlwZSBcInN0cmluZ1wiJylcbiAgfVxuICBpZiAoIWlzT2JqZWN0KHJlcXVlc3REYXRlKSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ3JlcXVlc3REYXRlIHNob3VsZCBiZSBvZiB0eXBlIFwib2JqZWN0XCInKVxuICB9XG4gIHJldHVybiBgJHthY2Nlc3NLZXl9LyR7Z2V0U2NvcGUocmVnaW9uLCByZXF1ZXN0RGF0ZSwgc2VydmljZU5hbWUpfWBcbn1cblxuLy8gUmV0dXJucyBzaWduZWQgaGVhZGVycyBhcnJheSAtIGFscGhhYmV0aWNhbGx5IHNvcnRlZFxuZnVuY3Rpb24gZ2V0U2lnbmVkSGVhZGVycyhoZWFkZXJzOiBSZXF1ZXN0SGVhZGVycyk6IHN0cmluZ1tdIHtcbiAgaWYgKCFpc09iamVjdChoZWFkZXJzKSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ3JlcXVlc3Qgc2hvdWxkIGJlIG9mIHR5cGUgXCJvYmplY3RcIicpXG4gIH1cbiAgLy8gRXhjZXJwdHMgZnJvbSBAbHNlZ2FsIC0gaHR0cHM6Ly9naXRodWIuY29tL2F3cy9hd3Mtc2RrLWpzL2lzc3Vlcy82NTkjaXNzdWVjb21tZW50LTEyMDQ3NzI1OFxuICAvL1xuICAvLyAgVXNlci1BZ2VudDpcbiAgLy9cbiAgLy8gICAgICBUaGlzIGlzIGlnbm9yZWQgZnJvbSBzaWduaW5nIGJlY2F1c2Ugc2lnbmluZyB0aGlzIGNhdXNlcyBwcm9ibGVtcyB3aXRoIGdlbmVyYXRpbmcgcHJlLXNpZ25lZCBVUkxzXG4gIC8vICAgICAgKHRoYXQgYXJlIGV4ZWN1dGVkIGJ5IG90aGVyIGFnZW50cykgb3Igd2hlbiBjdXN0b21lcnMgcGFzcyByZXF1ZXN0cyB0aHJvdWdoIHByb3hpZXMsIHdoaWNoIG1heVxuICAvLyAgICAgIG1vZGlmeSB0aGUgdXNlci1hZ2VudC5cbiAgLy9cbiAgLy8gIENvbnRlbnQtTGVuZ3RoOlxuICAvL1xuICAvLyAgICAgIFRoaXMgaXMgaWdub3JlZCBmcm9tIHNpZ25pbmcgYmVjYXVzZSBnZW5lcmF0aW5nIGEgcHJlLXNpZ25lZCBVUkwgc2hvdWxkIG5vdCBwcm92aWRlIGEgY29udGVudC1sZW5ndGhcbiAgLy8gICAgICBjb25zdHJhaW50LCBzcGVjaWZpY2FsbHkgd2hlbiB2ZW5kaW5nIGEgUzMgcHJlLXNpZ25lZCBQVVQgVVJMLiBUaGUgY29yb2xsYXJ5IHRvIHRoaXMgaXMgdGhhdCB3aGVuXG4gIC8vICAgICAgc2VuZGluZyByZWd1bGFyIHJlcXVlc3RzIChub24tcHJlLXNpZ25lZCksIHRoZSBzaWduYXR1cmUgY29udGFpbnMgYSBjaGVja3N1bSBvZiB0aGUgYm9keSwgd2hpY2hcbiAgLy8gICAgICBpbXBsaWNpdGx5IHZhbGlkYXRlcyB0aGUgcGF5bG9hZCBsZW5ndGggKHNpbmNlIGNoYW5naW5nIHRoZSBudW1iZXIgb2YgYnl0ZXMgd291bGQgY2hhbmdlIHRoZSBjaGVja3N1bSlcbiAgLy8gICAgICBhbmQgdGhlcmVmb3JlIHRoaXMgaGVhZGVyIGlzIG5vdCB2YWx1YWJsZSBpbiB0aGUgc2lnbmF0dXJlLlxuICAvL1xuICAvLyAgQ29udGVudC1UeXBlOlxuICAvL1xuICAvLyAgICAgIFNpZ25pbmcgdGhpcyBoZWFkZXIgY2F1c2VzIHF1aXRlIGEgbnVtYmVyIG9mIHByb2JsZW1zIGluIGJyb3dzZXIgZW52aXJvbm1lbnRzLCB3aGVyZSBicm93c2Vyc1xuICAvLyAgICAgIGxpa2UgdG8gbW9kaWZ5IGFuZCBub3JtYWxpemUgdGhlIGNvbnRlbnQtdHlwZSBoZWFkZXIgaW4gZGlmZmVyZW50IHdheXMuIFRoZXJlIGlzIG1vcmUgaW5mb3JtYXRpb25cbiAgLy8gICAgICBvbiB0aGlzIGluIGh0dHBzOi8vZ2l0aHViLmNvbS9hd3MvYXdzLXNkay1qcy9pc3N1ZXMvMjQ0LiBBdm9pZGluZyB0aGlzIGZpZWxkIHNpbXBsaWZpZXMgbG9naWNcbiAgLy8gICAgICBhbmQgcmVkdWNlcyB0aGUgcG9zc2liaWxpdHkgb2YgZnV0dXJlIGJ1Z3NcbiAgLy9cbiAgLy8gIEF1dGhvcml6YXRpb246XG4gIC8vXG4gIC8vICAgICAgSXMgc2tpcHBlZCBmb3Igb2J2aW91cyByZWFzb25zXG5cbiAgY29uc3QgaWdub3JlZEhlYWRlcnMgPSBbJ2F1dGhvcml6YXRpb24nLCAnY29udGVudC1sZW5ndGgnLCAnY29udGVudC10eXBlJywgJ3VzZXItYWdlbnQnXVxuICByZXR1cm4gT2JqZWN0LmtleXMoaGVhZGVycylcbiAgICAuZmlsdGVyKChoZWFkZXIpID0+ICFpZ25vcmVkSGVhZGVycy5pbmNsdWRlcyhoZWFkZXIpKVxuICAgIC5zb3J0KClcbn1cblxuLy8gcmV0dXJucyB0aGUga2V5IHVzZWQgZm9yIGNhbGN1bGF0aW5nIHNpZ25hdHVyZVxuZnVuY3Rpb24gZ2V0U2lnbmluZ0tleShkYXRlOiBEYXRlLCByZWdpb246IHN0cmluZywgc2VjcmV0S2V5OiBzdHJpbmcsIHNlcnZpY2VOYW1lID0gJ3MzJykge1xuICBpZiAoIWlzT2JqZWN0KGRhdGUpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignZGF0ZSBzaG91bGQgYmUgb2YgdHlwZSBcIm9iamVjdFwiJylcbiAgfVxuICBpZiAoIWlzU3RyaW5nKHJlZ2lvbikpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdyZWdpb24gc2hvdWxkIGJlIG9mIHR5cGUgXCJzdHJpbmdcIicpXG4gIH1cbiAgaWYgKCFpc1N0cmluZyhzZWNyZXRLZXkpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignc2VjcmV0S2V5IHNob3VsZCBiZSBvZiB0eXBlIFwic3RyaW5nXCInKVxuICB9XG4gIGNvbnN0IGRhdGVMaW5lID0gbWFrZURhdGVTaG9ydChkYXRlKVxuICBjb25zdCBobWFjMSA9IGNyeXB0b1xuICAgICAgLmNyZWF0ZUhtYWMoJ3NoYTI1NicsICdBV1M0JyArIHNlY3JldEtleSlcbiAgICAgIC51cGRhdGUoZGF0ZUxpbmUpXG4gICAgICAuZGlnZXN0KCksXG4gICAgaG1hYzIgPSBjcnlwdG8uY3JlYXRlSG1hYygnc2hhMjU2JywgaG1hYzEpLnVwZGF0ZShyZWdpb24pLmRpZ2VzdCgpLFxuICAgIGhtYWMzID0gY3J5cHRvLmNyZWF0ZUhtYWMoJ3NoYTI1NicsIGhtYWMyKS51cGRhdGUoc2VydmljZU5hbWUpLmRpZ2VzdCgpXG4gIHJldHVybiBjcnlwdG8uY3JlYXRlSG1hYygnc2hhMjU2JywgaG1hYzMpLnVwZGF0ZSgnYXdzNF9yZXF1ZXN0JykuZGlnZXN0KClcbn1cblxuLy8gcmV0dXJucyB0aGUgc3RyaW5nIHRoYXQgbmVlZHMgdG8gYmUgc2lnbmVkXG5mdW5jdGlvbiBnZXRTdHJpbmdUb1NpZ24oY2Fub25pY2FsUmVxdWVzdDogSUNhbm9uaWNhbFJlcXVlc3QsIHJlcXVlc3REYXRlOiBEYXRlLCByZWdpb246IHN0cmluZywgc2VydmljZU5hbWUgPSAnczMnKSB7XG4gIGlmICghaXNTdHJpbmcoY2Fub25pY2FsUmVxdWVzdCkpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdjYW5vbmljYWxSZXF1ZXN0IHNob3VsZCBiZSBvZiB0eXBlIFwic3RyaW5nXCInKVxuICB9XG4gIGlmICghaXNPYmplY3QocmVxdWVzdERhdGUpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcigncmVxdWVzdERhdGUgc2hvdWxkIGJlIG9mIHR5cGUgXCJvYmplY3RcIicpXG4gIH1cbiAgaWYgKCFpc1N0cmluZyhyZWdpb24pKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcigncmVnaW9uIHNob3VsZCBiZSBvZiB0eXBlIFwic3RyaW5nXCInKVxuICB9XG4gIGNvbnN0IGhhc2ggPSBjcnlwdG8uY3JlYXRlSGFzaCgnc2hhMjU2JykudXBkYXRlKGNhbm9uaWNhbFJlcXVlc3QpLmRpZ2VzdCgnaGV4JylcbiAgY29uc3Qgc2NvcGUgPSBnZXRTY29wZShyZWdpb24sIHJlcXVlc3REYXRlLCBzZXJ2aWNlTmFtZSlcbiAgY29uc3Qgc3RyaW5nVG9TaWduID0gW3NpZ25WNEFsZ29yaXRobSwgbWFrZURhdGVMb25nKHJlcXVlc3REYXRlKSwgc2NvcGUsIGhhc2hdXG5cbiAgcmV0dXJuIHN0cmluZ1RvU2lnbi5qb2luKCdcXG4nKVxufVxuXG4vLyBjYWxjdWxhdGUgdGhlIHNpZ25hdHVyZSBvZiB0aGUgUE9TVCBwb2xpY3lcbmV4cG9ydCBmdW5jdGlvbiBwb3N0UHJlc2lnblNpZ25hdHVyZVY0KHJlZ2lvbjogc3RyaW5nLCBkYXRlOiBEYXRlLCBzZWNyZXRLZXk6IHN0cmluZywgcG9saWN5QmFzZTY0OiBzdHJpbmcpOiBzdHJpbmcge1xuICBpZiAoIWlzU3RyaW5nKHJlZ2lvbikpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdyZWdpb24gc2hvdWxkIGJlIG9mIHR5cGUgXCJzdHJpbmdcIicpXG4gIH1cbiAgaWYgKCFpc09iamVjdChkYXRlKSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ2RhdGUgc2hvdWxkIGJlIG9mIHR5cGUgXCJvYmplY3RcIicpXG4gIH1cbiAgaWYgKCFpc1N0cmluZyhzZWNyZXRLZXkpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignc2VjcmV0S2V5IHNob3VsZCBiZSBvZiB0eXBlIFwic3RyaW5nXCInKVxuICB9XG4gIGlmICghaXNTdHJpbmcocG9saWN5QmFzZTY0KSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ3BvbGljeUJhc2U2NCBzaG91bGQgYmUgb2YgdHlwZSBcInN0cmluZ1wiJylcbiAgfVxuICBjb25zdCBzaWduaW5nS2V5ID0gZ2V0U2lnbmluZ0tleShkYXRlLCByZWdpb24sIHNlY3JldEtleSlcbiAgcmV0dXJuIGNyeXB0by5jcmVhdGVIbWFjKCdzaGEyNTYnLCBzaWduaW5nS2V5KS51cGRhdGUocG9saWN5QmFzZTY0KS5kaWdlc3QoJ2hleCcpLnRvTG93ZXJDYXNlKClcbn1cblxuLy8gUmV0dXJucyB0aGUgYXV0aG9yaXphdGlvbiBoZWFkZXJcbmV4cG9ydCBmdW5jdGlvbiBzaWduVjQoXG4gIHJlcXVlc3Q6IElSZXF1ZXN0LFxuICBhY2Nlc3NLZXk6IHN0cmluZyxcbiAgc2VjcmV0S2V5OiBzdHJpbmcsXG4gIHJlZ2lvbjogc3RyaW5nLFxuICByZXF1ZXN0RGF0ZTogRGF0ZSxcbiAgc2hhMjU2c3VtOiBzdHJpbmcsXG4gIHNlcnZpY2VOYW1lID0gJ3MzJyxcbikge1xuICBpZiAoIWlzT2JqZWN0KHJlcXVlc3QpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcigncmVxdWVzdCBzaG91bGQgYmUgb2YgdHlwZSBcIm9iamVjdFwiJylcbiAgfVxuICBpZiAoIWlzU3RyaW5nKGFjY2Vzc0tleSkpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdhY2Nlc3NLZXkgc2hvdWxkIGJlIG9mIHR5cGUgXCJzdHJpbmdcIicpXG4gIH1cbiAgaWYgKCFpc1N0cmluZyhzZWNyZXRLZXkpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignc2VjcmV0S2V5IHNob3VsZCBiZSBvZiB0eXBlIFwic3RyaW5nXCInKVxuICB9XG4gIGlmICghaXNTdHJpbmcocmVnaW9uKSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ3JlZ2lvbiBzaG91bGQgYmUgb2YgdHlwZSBcInN0cmluZ1wiJylcbiAgfVxuXG4gIGlmICghYWNjZXNzS2V5KSB7XG4gICAgdGhyb3cgbmV3IGVycm9ycy5BY2Nlc3NLZXlSZXF1aXJlZEVycm9yKCdhY2Nlc3NLZXkgaXMgcmVxdWlyZWQgZm9yIHNpZ25pbmcnKVxuICB9XG4gIGlmICghc2VjcmV0S2V5KSB7XG4gICAgdGhyb3cgbmV3IGVycm9ycy5TZWNyZXRLZXlSZXF1aXJlZEVycm9yKCdzZWNyZXRLZXkgaXMgcmVxdWlyZWQgZm9yIHNpZ25pbmcnKVxuICB9XG5cbiAgY29uc3Qgc2lnbmVkSGVhZGVycyA9IGdldFNpZ25lZEhlYWRlcnMocmVxdWVzdC5oZWFkZXJzKVxuICBjb25zdCBjYW5vbmljYWxSZXF1ZXN0ID0gZ2V0Q2Fub25pY2FsUmVxdWVzdChyZXF1ZXN0Lm1ldGhvZCwgcmVxdWVzdC5wYXRoLCByZXF1ZXN0LmhlYWRlcnMsIHNpZ25lZEhlYWRlcnMsIHNoYTI1NnN1bSlcbiAgY29uc3Qgc2VydmljZUlkZW50aWZpZXIgPSBzZXJ2aWNlTmFtZSB8fCAnczMnXG4gIGNvbnN0IHN0cmluZ1RvU2lnbiA9IGdldFN0cmluZ1RvU2lnbihjYW5vbmljYWxSZXF1ZXN0LCByZXF1ZXN0RGF0ZSwgcmVnaW9uLCBzZXJ2aWNlSWRlbnRpZmllcilcbiAgY29uc3Qgc2lnbmluZ0tleSA9IGdldFNpZ25pbmdLZXkocmVxdWVzdERhdGUsIHJlZ2lvbiwgc2VjcmV0S2V5LCBzZXJ2aWNlSWRlbnRpZmllcilcbiAgY29uc3QgY3JlZGVudGlhbCA9IGdldENyZWRlbnRpYWwoYWNjZXNzS2V5LCByZWdpb24sIHJlcXVlc3REYXRlLCBzZXJ2aWNlSWRlbnRpZmllcilcbiAgY29uc3Qgc2lnbmF0dXJlID0gY3J5cHRvLmNyZWF0ZUhtYWMoJ3NoYTI1NicsIHNpZ25pbmdLZXkpLnVwZGF0ZShzdHJpbmdUb1NpZ24pLmRpZ2VzdCgnaGV4JykudG9Mb3dlckNhc2UoKVxuXG4gIHJldHVybiBgJHtzaWduVjRBbGdvcml0aG19IENyZWRlbnRpYWw9JHtjcmVkZW50aWFsfSwgU2lnbmVkSGVhZGVycz0ke3NpZ25lZEhlYWRlcnNcbiAgICAuam9pbignOycpXG4gICAgLnRvTG93ZXJDYXNlKCl9LCBTaWduYXR1cmU9JHtzaWduYXR1cmV9YFxufVxuXG5leHBvcnQgZnVuY3Rpb24gc2lnblY0QnlTZXJ2aWNlTmFtZShcbiAgcmVxdWVzdDogSVJlcXVlc3QsXG4gIGFjY2Vzc0tleTogc3RyaW5nLFxuICBzZWNyZXRLZXk6IHN0cmluZyxcbiAgcmVnaW9uOiBzdHJpbmcsXG4gIHJlcXVlc3REYXRlOiBEYXRlLFxuICBjb250ZW50U2hhMjU2OiBzdHJpbmcsXG4gIHNlcnZpY2VOYW1lID0gJ3MzJyxcbik6IHN0cmluZyB7XG4gIHJldHVybiBzaWduVjQocmVxdWVzdCwgYWNjZXNzS2V5LCBzZWNyZXRLZXksIHJlZ2lvbiwgcmVxdWVzdERhdGUsIGNvbnRlbnRTaGEyNTYsIHNlcnZpY2VOYW1lKVxufVxuXG4vLyByZXR1cm5zIGEgcHJlc2lnbmVkIFVSTCBzdHJpbmdcbmV4cG9ydCBmdW5jdGlvbiBwcmVzaWduU2lnbmF0dXJlVjQoXG4gIHJlcXVlc3Q6IElSZXF1ZXN0LFxuICBhY2Nlc3NLZXk6IHN0cmluZyxcbiAgc2VjcmV0S2V5OiBzdHJpbmcsXG4gIHNlc3Npb25Ub2tlbjogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICByZWdpb246IHN0cmluZyxcbiAgcmVxdWVzdERhdGU6IERhdGUsXG4gIGV4cGlyZXM6IG51bWJlciB8IHVuZGVmaW5lZCxcbikge1xuICBpZiAoIWlzT2JqZWN0KHJlcXVlc3QpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcigncmVxdWVzdCBzaG91bGQgYmUgb2YgdHlwZSBcIm9iamVjdFwiJylcbiAgfVxuICBpZiAoIWlzU3RyaW5nKGFjY2Vzc0tleSkpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdhY2Nlc3NLZXkgc2hvdWxkIGJlIG9mIHR5cGUgXCJzdHJpbmdcIicpXG4gIH1cbiAgaWYgKCFpc1N0cmluZyhzZWNyZXRLZXkpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignc2VjcmV0S2V5IHNob3VsZCBiZSBvZiB0eXBlIFwic3RyaW5nXCInKVxuICB9XG4gIGlmICghaXNTdHJpbmcocmVnaW9uKSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ3JlZ2lvbiBzaG91bGQgYmUgb2YgdHlwZSBcInN0cmluZ1wiJylcbiAgfVxuXG4gIGlmICghYWNjZXNzS2V5KSB7XG4gICAgdGhyb3cgbmV3IGVycm9ycy5BY2Nlc3NLZXlSZXF1aXJlZEVycm9yKCdhY2Nlc3NLZXkgaXMgcmVxdWlyZWQgZm9yIHByZXNpZ25pbmcnKVxuICB9XG4gIGlmICghc2VjcmV0S2V5KSB7XG4gICAgdGhyb3cgbmV3IGVycm9ycy5TZWNyZXRLZXlSZXF1aXJlZEVycm9yKCdzZWNyZXRLZXkgaXMgcmVxdWlyZWQgZm9yIHByZXNpZ25pbmcnKVxuICB9XG5cbiAgaWYgKGV4cGlyZXMgJiYgIWlzTnVtYmVyKGV4cGlyZXMpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignZXhwaXJlcyBzaG91bGQgYmUgb2YgdHlwZSBcIm51bWJlclwiJylcbiAgfVxuICBpZiAoZXhwaXJlcyAmJiBleHBpcmVzIDwgMSkge1xuICAgIHRocm93IG5ldyBlcnJvcnMuRXhwaXJlc1BhcmFtRXJyb3IoJ2V4cGlyZXMgcGFyYW0gY2Fubm90IGJlIGxlc3MgdGhhbiAxIHNlY29uZHMnKVxuICB9XG4gIGlmIChleHBpcmVzICYmIGV4cGlyZXMgPiBQUkVTSUdOX0VYUElSWV9EQVlTX01BWCkge1xuICAgIHRocm93IG5ldyBlcnJvcnMuRXhwaXJlc1BhcmFtRXJyb3IoJ2V4cGlyZXMgcGFyYW0gY2Fubm90IGJlIGdyZWF0ZXIgdGhhbiA3IGRheXMnKVxuICB9XG5cbiAgY29uc3QgaXNvODYwMURhdGUgPSBtYWtlRGF0ZUxvbmcocmVxdWVzdERhdGUpXG4gIGNvbnN0IHNpZ25lZEhlYWRlcnMgPSBnZXRTaWduZWRIZWFkZXJzKHJlcXVlc3QuaGVhZGVycylcbiAgY29uc3QgY3JlZGVudGlhbCA9IGdldENyZWRlbnRpYWwoYWNjZXNzS2V5LCByZWdpb24sIHJlcXVlc3REYXRlKVxuICBjb25zdCBoYXNoZWRQYXlsb2FkID0gJ1VOU0lHTkVELVBBWUxPQUQnXG5cbiAgY29uc3QgcmVxdWVzdFF1ZXJ5OiBzdHJpbmdbXSA9IFtdXG4gIHJlcXVlc3RRdWVyeS5wdXNoKGBYLUFtei1BbGdvcml0aG09JHtzaWduVjRBbGdvcml0aG19YClcbiAgcmVxdWVzdFF1ZXJ5LnB1c2goYFgtQW16LUNyZWRlbnRpYWw9JHt1cmlFc2NhcGUoY3JlZGVudGlhbCl9YClcbiAgcmVxdWVzdFF1ZXJ5LnB1c2goYFgtQW16LURhdGU9JHtpc284NjAxRGF0ZX1gKVxuICByZXF1ZXN0UXVlcnkucHVzaChgWC1BbXotRXhwaXJlcz0ke2V4cGlyZXN9YClcbiAgcmVxdWVzdFF1ZXJ5LnB1c2goYFgtQW16LVNpZ25lZEhlYWRlcnM9JHt1cmlFc2NhcGUoc2lnbmVkSGVhZGVycy5qb2luKCc7JykudG9Mb3dlckNhc2UoKSl9YClcbiAgaWYgKHNlc3Npb25Ub2tlbikge1xuICAgIHJlcXVlc3RRdWVyeS5wdXNoKGBYLUFtei1TZWN1cml0eS1Ub2tlbj0ke3VyaUVzY2FwZShzZXNzaW9uVG9rZW4pfWApXG4gIH1cblxuICBjb25zdCByZXNvdXJjZSA9IHJlcXVlc3QucGF0aC5zcGxpdCgnPycpWzBdXG4gIGxldCBxdWVyeSA9IHJlcXVlc3QucGF0aC5zcGxpdCgnPycpWzFdXG4gIGlmIChxdWVyeSkge1xuICAgIHF1ZXJ5ID0gcXVlcnkgKyAnJicgKyByZXF1ZXN0UXVlcnkuam9pbignJicpXG4gIH0gZWxzZSB7XG4gICAgcXVlcnkgPSByZXF1ZXN0UXVlcnkuam9pbignJicpXG4gIH1cblxuICBjb25zdCBwYXRoID0gcmVzb3VyY2UgKyAnPycgKyBxdWVyeVxuXG4gIGNvbnN0IGNhbm9uaWNhbFJlcXVlc3QgPSBnZXRDYW5vbmljYWxSZXF1ZXN0KHJlcXVlc3QubWV0aG9kLCBwYXRoLCByZXF1ZXN0LmhlYWRlcnMsIHNpZ25lZEhlYWRlcnMsIGhhc2hlZFBheWxvYWQpXG5cbiAgY29uc3Qgc3RyaW5nVG9TaWduID0gZ2V0U3RyaW5nVG9TaWduKGNhbm9uaWNhbFJlcXVlc3QsIHJlcXVlc3REYXRlLCByZWdpb24pXG4gIGNvbnN0IHNpZ25pbmdLZXkgPSBnZXRTaWduaW5nS2V5KHJlcXVlc3REYXRlLCByZWdpb24sIHNlY3JldEtleSlcbiAgY29uc3Qgc2lnbmF0dXJlID0gY3J5cHRvLmNyZWF0ZUhtYWMoJ3NoYTI1NicsIHNpZ25pbmdLZXkpLnVwZGF0ZShzdHJpbmdUb1NpZ24pLmRpZ2VzdCgnaGV4JykudG9Mb3dlckNhc2UoKVxuICByZXR1cm4gcmVxdWVzdC5wcm90b2NvbCArICcvLycgKyByZXF1ZXN0LmhlYWRlcnMuaG9zdCArIHBhdGggKyBgJlgtQW16LVNpZ25hdHVyZT0ke3NpZ25hdHVyZX1gXG59XG4iXSwibWFwcGluZ3MiOiJBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxPQUFPLEtBQUtBLE1BQU07QUFFbEIsT0FBTyxLQUFLQyxNQUFNLE1BQU0sY0FBYTtBQUNyQyxTQUFTQyx1QkFBdUIsUUFBUSxlQUFjO0FBQ3RELFNBQVNDLFFBQVEsRUFBRUMsUUFBUSxFQUFFQyxRQUFRLEVBQUVDLFFBQVEsRUFBRUMsWUFBWSxFQUFFQyxhQUFhLEVBQUVDLFNBQVMsUUFBUSx1QkFBc0I7QUFHckgsTUFBTUMsZUFBZSxHQUFHLGtCQUFrQjs7QUFFMUM7QUFDQTtBQUNBO0FBQ0E7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