signing.mjs 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /*
  2. * MinIO Javascript Library for Amazon S3 Compatible Cloud Storage, (C) 2016 MinIO, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. import * as crypto from "crypto";
  17. import * as errors from "./errors.mjs";
  18. import { PRESIGN_EXPIRY_DAYS_MAX } from "./helpers.mjs";
  19. import { getScope, isNumber, isObject, isString, makeDateLong, makeDateShort, uriEscape } from "./internal/helper.mjs";
  20. const signV4Algorithm = 'AWS4-HMAC-SHA256';
  21. // getCanonicalRequest generate a canonical request of style.
  22. //
  23. // canonicalRequest =
  24. // <HTTPMethod>\n
  25. // <CanonicalURI>\n
  26. // <CanonicalQueryString>\n
  27. // <CanonicalHeaders>\n
  28. // <SignedHeaders>\n
  29. // <HashedPayload>
  30. //
  31. function getCanonicalRequest(method, path, headers, signedHeaders, hashedPayload) {
  32. if (!isString(method)) {
  33. throw new TypeError('method should be of type "string"');
  34. }
  35. if (!isString(path)) {
  36. throw new TypeError('path should be of type "string"');
  37. }
  38. if (!isObject(headers)) {
  39. throw new TypeError('headers should be of type "object"');
  40. }
  41. if (!Array.isArray(signedHeaders)) {
  42. throw new TypeError('signedHeaders should be of type "array"');
  43. }
  44. if (!isString(hashedPayload)) {
  45. throw new TypeError('hashedPayload should be of type "string"');
  46. }
  47. const headersArray = signedHeaders.reduce((acc, i) => {
  48. // Trim spaces from the value (required by V4 spec)
  49. const val = `${headers[i]}`.replace(/ +/g, ' ');
  50. acc.push(`${i.toLowerCase()}:${val}`);
  51. return acc;
  52. }, []);
  53. const requestResource = path.split('?')[0];
  54. let requestQuery = path.split('?')[1];
  55. if (!requestQuery) {
  56. requestQuery = '';
  57. }
  58. if (requestQuery) {
  59. requestQuery = requestQuery.split('&').sort().map(element => !element.includes('=') ? element + '=' : element).join('&');
  60. }
  61. return [method.toUpperCase(), requestResource, requestQuery, headersArray.join('\n') + '\n', signedHeaders.join(';').toLowerCase(), hashedPayload].join('\n');
  62. }
  63. // generate a credential string
  64. function getCredential(accessKey, region, requestDate, serviceName = 's3') {
  65. if (!isString(accessKey)) {
  66. throw new TypeError('accessKey should be of type "string"');
  67. }
  68. if (!isString(region)) {
  69. throw new TypeError('region should be of type "string"');
  70. }
  71. if (!isObject(requestDate)) {
  72. throw new TypeError('requestDate should be of type "object"');
  73. }
  74. return `${accessKey}/${getScope(region, requestDate, serviceName)}`;
  75. }
  76. // Returns signed headers array - alphabetically sorted
  77. function getSignedHeaders(headers) {
  78. if (!isObject(headers)) {
  79. throw new TypeError('request should be of type "object"');
  80. }
  81. // Excerpts from @lsegal - https://github.com/aws/aws-sdk-js/issues/659#issuecomment-120477258
  82. //
  83. // User-Agent:
  84. //
  85. // This is ignored from signing because signing this causes problems with generating pre-signed URLs
  86. // (that are executed by other agents) or when customers pass requests through proxies, which may
  87. // modify the user-agent.
  88. //
  89. // Content-Length:
  90. //
  91. // This is ignored from signing because generating a pre-signed URL should not provide a content-length
  92. // constraint, specifically when vending a S3 pre-signed PUT URL. The corollary to this is that when
  93. // sending regular requests (non-pre-signed), the signature contains a checksum of the body, which
  94. // implicitly validates the payload length (since changing the number of bytes would change the checksum)
  95. // and therefore this header is not valuable in the signature.
  96. //
  97. // Content-Type:
  98. //
  99. // Signing this header causes quite a number of problems in browser environments, where browsers
  100. // like to modify and normalize the content-type header in different ways. There is more information
  101. // on this in https://github.com/aws/aws-sdk-js/issues/244. Avoiding this field simplifies logic
  102. // and reduces the possibility of future bugs
  103. //
  104. // Authorization:
  105. //
  106. // Is skipped for obvious reasons
  107. const ignoredHeaders = ['authorization', 'content-length', 'content-type', 'user-agent'];
  108. return Object.keys(headers).filter(header => !ignoredHeaders.includes(header)).sort();
  109. }
  110. // returns the key used for calculating signature
  111. function getSigningKey(date, region, secretKey, serviceName = 's3') {
  112. if (!isObject(date)) {
  113. throw new TypeError('date should be of type "object"');
  114. }
  115. if (!isString(region)) {
  116. throw new TypeError('region should be of type "string"');
  117. }
  118. if (!isString(secretKey)) {
  119. throw new TypeError('secretKey should be of type "string"');
  120. }
  121. const dateLine = makeDateShort(date);
  122. const hmac1 = crypto.createHmac('sha256', 'AWS4' + secretKey).update(dateLine).digest(),
  123. hmac2 = crypto.createHmac('sha256', hmac1).update(region).digest(),
  124. hmac3 = crypto.createHmac('sha256', hmac2).update(serviceName).digest();
  125. return crypto.createHmac('sha256', hmac3).update('aws4_request').digest();
  126. }
  127. // returns the string that needs to be signed
  128. function getStringToSign(canonicalRequest, requestDate, region, serviceName = 's3') {
  129. if (!isString(canonicalRequest)) {
  130. throw new TypeError('canonicalRequest should be of type "string"');
  131. }
  132. if (!isObject(requestDate)) {
  133. throw new TypeError('requestDate should be of type "object"');
  134. }
  135. if (!isString(region)) {
  136. throw new TypeError('region should be of type "string"');
  137. }
  138. const hash = crypto.createHash('sha256').update(canonicalRequest).digest('hex');
  139. const scope = getScope(region, requestDate, serviceName);
  140. const stringToSign = [signV4Algorithm, makeDateLong(requestDate), scope, hash];
  141. return stringToSign.join('\n');
  142. }
  143. // calculate the signature of the POST policy
  144. export function postPresignSignatureV4(region, date, secretKey, policyBase64) {
  145. if (!isString(region)) {
  146. throw new TypeError('region should be of type "string"');
  147. }
  148. if (!isObject(date)) {
  149. throw new TypeError('date should be of type "object"');
  150. }
  151. if (!isString(secretKey)) {
  152. throw new TypeError('secretKey should be of type "string"');
  153. }
  154. if (!isString(policyBase64)) {
  155. throw new TypeError('policyBase64 should be of type "string"');
  156. }
  157. const signingKey = getSigningKey(date, region, secretKey);
  158. return crypto.createHmac('sha256', signingKey).update(policyBase64).digest('hex').toLowerCase();
  159. }
  160. // Returns the authorization header
  161. export function signV4(request, accessKey, secretKey, region, requestDate, sha256sum, serviceName = 's3') {
  162. if (!isObject(request)) {
  163. throw new TypeError('request should be of type "object"');
  164. }
  165. if (!isString(accessKey)) {
  166. throw new TypeError('accessKey should be of type "string"');
  167. }
  168. if (!isString(secretKey)) {
  169. throw new TypeError('secretKey should be of type "string"');
  170. }
  171. if (!isString(region)) {
  172. throw new TypeError('region should be of type "string"');
  173. }
  174. if (!accessKey) {
  175. throw new errors.AccessKeyRequiredError('accessKey is required for signing');
  176. }
  177. if (!secretKey) {
  178. throw new errors.SecretKeyRequiredError('secretKey is required for signing');
  179. }
  180. const signedHeaders = getSignedHeaders(request.headers);
  181. const canonicalRequest = getCanonicalRequest(request.method, request.path, request.headers, signedHeaders, sha256sum);
  182. const serviceIdentifier = serviceName || 's3';
  183. const stringToSign = getStringToSign(canonicalRequest, requestDate, region, serviceIdentifier);
  184. const signingKey = getSigningKey(requestDate, region, secretKey, serviceIdentifier);
  185. const credential = getCredential(accessKey, region, requestDate, serviceIdentifier);
  186. const signature = crypto.createHmac('sha256', signingKey).update(stringToSign).digest('hex').toLowerCase();
  187. return `${signV4Algorithm} Credential=${credential}, SignedHeaders=${signedHeaders.join(';').toLowerCase()}, Signature=${signature}`;
  188. }
  189. export function signV4ByServiceName(request, accessKey, secretKey, region, requestDate, contentSha256, serviceName = 's3') {
  190. return signV4(request, accessKey, secretKey, region, requestDate, contentSha256, serviceName);
  191. }
  192. // returns a presigned URL string
  193. export function presignSignatureV4(request, accessKey, secretKey, sessionToken, region, requestDate, expires) {
  194. if (!isObject(request)) {
  195. throw new TypeError('request should be of type "object"');
  196. }
  197. if (!isString(accessKey)) {
  198. throw new TypeError('accessKey should be of type "string"');
  199. }
  200. if (!isString(secretKey)) {
  201. throw new TypeError('secretKey should be of type "string"');
  202. }
  203. if (!isString(region)) {
  204. throw new TypeError('region should be of type "string"');
  205. }
  206. if (!accessKey) {
  207. throw new errors.AccessKeyRequiredError('accessKey is required for presigning');
  208. }
  209. if (!secretKey) {
  210. throw new errors.SecretKeyRequiredError('secretKey is required for presigning');
  211. }
  212. if (expires && !isNumber(expires)) {
  213. throw new TypeError('expires should be of type "number"');
  214. }
  215. if (expires && expires < 1) {
  216. throw new errors.ExpiresParamError('expires param cannot be less than 1 seconds');
  217. }
  218. if (expires && expires > PRESIGN_EXPIRY_DAYS_MAX) {
  219. throw new errors.ExpiresParamError('expires param cannot be greater than 7 days');
  220. }
  221. const iso8601Date = makeDateLong(requestDate);
  222. const signedHeaders = getSignedHeaders(request.headers);
  223. const credential = getCredential(accessKey, region, requestDate);
  224. const hashedPayload = 'UNSIGNED-PAYLOAD';
  225. const requestQuery = [];
  226. requestQuery.push(`X-Amz-Algorithm=${signV4Algorithm}`);
  227. requestQuery.push(`X-Amz-Credential=${uriEscape(credential)}`);
  228. requestQuery.push(`X-Amz-Date=${iso8601Date}`);
  229. requestQuery.push(`X-Amz-Expires=${expires}`);
  230. requestQuery.push(`X-Amz-SignedHeaders=${uriEscape(signedHeaders.join(';').toLowerCase())}`);
  231. if (sessionToken) {
  232. requestQuery.push(`X-Amz-Security-Token=${uriEscape(sessionToken)}`);
  233. }
  234. const resource = request.path.split('?')[0];
  235. let query = request.path.split('?')[1];
  236. if (query) {
  237. query = query + '&' + requestQuery.join('&');
  238. } else {
  239. query = requestQuery.join('&');
  240. }
  241. const path = resource + '?' + query;
  242. const canonicalRequest = getCanonicalRequest(request.method, path, request.headers, signedHeaders, hashedPayload);
  243. const stringToSign = getStringToSign(canonicalRequest, requestDate, region);
  244. const signingKey = getSigningKey(requestDate, region, secretKey);
  245. const signature = crypto.createHmac('sha256', signingKey).update(stringToSign).digest('hex').toLowerCase();
  246. return request.protocol + '//' + request.headers.host + path + `&X-Amz-Signature=${signature}`;
  247. }
  248. //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJjcnlwdG8iLCJlcnJvcnMiLCJQUkVTSUdOX0VYUElSWV9EQVlTX01BWCIsImdldFNjb3BlIiwiaXNOdW1iZXIiLCJpc09iamVjdCIsImlzU3RyaW5nIiwibWFrZURhdGVMb25nIiwibWFrZURhdGVTaG9ydCIsInVyaUVzY2FwZSIsInNpZ25WNEFsZ29yaXRobSIsImdldENhbm9uaWNhbFJlcXVlc3QiLCJtZXRob2QiLCJwYXRoIiwiaGVhZGVycyIsInNpZ25lZEhlYWRlcnMiLCJoYXNoZWRQYXlsb2FkIiwiVHlwZUVycm9yIiwiQXJyYXkiLCJpc0FycmF5IiwiaGVhZGVyc0FycmF5IiwicmVkdWNlIiwiYWNjIiwiaSIsInZhbCIsInJlcGxhY2UiLCJwdXNoIiwidG9Mb3dlckNhc2UiLCJyZXF1ZXN0UmVzb3VyY2UiLCJzcGxpdCIsInJlcXVlc3RRdWVyeSIsInNvcnQiLCJtYXAiLCJlbGVtZW50IiwiaW5jbHVkZXMiLCJqb2luIiwidG9VcHBlckNhc2UiLCJnZXRDcmVkZW50aWFsIiwiYWNjZXNzS2V5IiwicmVnaW9uIiwicmVxdWVzdERhdGUiLCJzZXJ2aWNlTmFtZSIsImdldFNpZ25lZEhlYWRlcnMiLCJpZ25vcmVkSGVhZGVycyIsIk9iamVjdCIsImtleXMiLCJmaWx0ZXIiLCJoZWFkZXIiLCJnZXRTaWduaW5nS2V5IiwiZGF0ZSIsInNlY3JldEtleSIsImRhdGVMaW5lIiwiaG1hYzEiLCJjcmVhdGVIbWFjIiwidXBkYXRlIiwiZGlnZXN0IiwiaG1hYzIiLCJobWFjMyIsImdldFN0cmluZ1RvU2lnbiIsImNhbm9uaWNhbFJlcXVlc3QiLCJoYXNoIiwiY3JlYXRlSGFzaCIsInNjb3BlIiwic3RyaW5nVG9TaWduIiwicG9zdFByZXNpZ25TaWduYXR1cmVWNCIsInBvbGljeUJhc2U2NCIsInNpZ25pbmdLZXkiLCJzaWduVjQiLCJyZXF1ZXN0Iiwic2hhMjU2c3VtIiwiQWNjZXNzS2V5UmVxdWlyZWRFcnJvciIsIlNlY3JldEtleVJlcXVpcmVkRXJyb3IiLCJzZXJ2aWNlSWRlbnRpZmllciIsImNyZWRlbnRpYWwiLCJzaWduYXR1cmUiLCJzaWduVjRCeVNlcnZpY2VOYW1lIiwiY29udGVudFNoYTI1NiIsInByZXNpZ25TaWduYXR1cmVWNCIsInNlc3Npb25Ub2tlbiIsImV4cGlyZXMiLCJFeHBpcmVzUGFyYW1FcnJvciIsImlzbzg2MDFEYXRlIiwicmVzb3VyY2UiLCJxdWVyeSIsInByb3RvY29sIiwiaG9zdCJdLCJzb3VyY2VzIjpbInNpZ25pbmcudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIE1pbklPIEphdmFzY3JpcHQgTGlicmFyeSBmb3IgQW1hem9uIFMzIENvbXBhdGlibGUgQ2xvdWQgU3RvcmFnZSwgKEMpIDIwMTYgTWluSU8sIEluYy5cbiAqXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG4gKlxuICogICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKi9cblxuaW1wb3J0ICogYXMgY3J5cHRvIGZyb20gJ25vZGU6Y3J5cHRvJ1xuXG5pbXBvcnQgKiBhcyBlcnJvcnMgZnJvbSAnLi9lcnJvcnMudHMnXG5pbXBvcnQgeyBQUkVTSUdOX0VYUElSWV9EQVlTX01BWCB9IGZyb20gJy4vaGVscGVycy50cydcbmltcG9ydCB7IGdldFNjb3BlLCBpc051bWJlciwgaXNPYmplY3QsIGlzU3RyaW5nLCBtYWtlRGF0ZUxvbmcsIG1ha2VEYXRlU2hvcnQsIHVyaUVzY2FwZSB9IGZyb20gJy4vaW50ZXJuYWwvaGVscGVyLnRzJ1xuaW1wb3J0IHR5cGUgeyBJQ2Fub25pY2FsUmVxdWVzdCwgSVJlcXVlc3QsIFJlcXVlc3RIZWFkZXJzIH0gZnJvbSAnLi9pbnRlcm5hbC90eXBlLnRzJ1xuXG5jb25zdCBzaWduVjRBbGdvcml0aG0gPSAnQVdTNC1ITUFDLVNIQTI1NidcblxuLy8gZ2V0Q2Fub25pY2FsUmVxdWVzdCBnZW5lcmF0ZSBhIGNhbm9uaWNhbCByZXF1ZXN0IG9mIHN0eWxlLlxuLy9cbi8vIGNhbm9uaWNhbFJlcXVlc3QgPVxuLy8gIDxIVFRQTWV0aG9kPlxcblxuLy8gIDxDYW5vbmljYWxVUkk+XFxuXG4vLyAgPENhbm9uaWNhbFF1ZXJ5U3RyaW5nPlxcblxuLy8gIDxDYW5vbmljYWxIZWFkZXJzPlxcblxuLy8gIDxTaWduZWRIZWFkZXJzPlxcblxuLy8gIDxIYXNoZWRQYXlsb2FkPlxuLy9cbmZ1bmN0aW9uIGdldENhbm9uaWNhbFJlcXVlc3QoXG4gIG1ldGhvZDogc3RyaW5nLFxuICBwYXRoOiBzdHJpbmcsXG4gIGhlYWRlcnM6IFJlcXVlc3RIZWFkZXJzLFxuICBzaWduZWRIZWFkZXJzOiBzdHJpbmdbXSxcbiAgaGFzaGVkUGF5bG9hZDogc3RyaW5nLFxuKTogSUNhbm9uaWNhbFJlcXVlc3Qge1xuICBpZiAoIWlzU3RyaW5nKG1ldGhvZCkpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdtZXRob2Qgc2hvdWxkIGJlIG9mIHR5cGUgXCJzdHJpbmdcIicpXG4gIH1cbiAgaWYgKCFpc1N0cmluZyhwYXRoKSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ3BhdGggc2hvdWxkIGJlIG9mIHR5cGUgXCJzdHJpbmdcIicpXG4gIH1cbiAgaWYgKCFpc09iamVjdChoZWFkZXJzKSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ2hlYWRlcnMgc2hvdWxkIGJlIG9mIHR5cGUgXCJvYmplY3RcIicpXG4gIH1cbiAgaWYgKCFBcnJheS5pc0FycmF5KHNpZ25lZEhlYWRlcnMpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignc2lnbmVkSGVhZGVycyBzaG91bGQgYmUgb2YgdHlwZSBcImFycmF5XCInKVxuICB9XG4gIGlmICghaXNTdHJpbmcoaGFzaGVkUGF5bG9hZCkpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdoYXNoZWRQYXlsb2FkIHNob3VsZCBiZSBvZiB0eXBlIFwic3RyaW5nXCInKVxuICB9XG5cbiAgY29uc3QgaGVhZGVyc0FycmF5ID0gc2lnbmVkSGVhZGVycy5yZWR1Y2UoKGFjYywgaSkgPT4ge1xuICAgIC8vIFRyaW0gc3BhY2VzIGZyb20gdGhlIHZhbHVlIChyZXF1aXJlZCBieSBWNCBzcGVjKVxuICAgIGNvbnN0IHZhbCA9IGAke2hlYWRlcnNbaV19YC5yZXBsYWNlKC8gKy9nLCAnICcpXG4gICAgYWNjLnB1c2goYCR7aS50b0xvd2VyQ2FzZSgpfToke3ZhbH1gKVxuICAgIHJldHVybiBhY2NcbiAgfSwgW10gYXMgc3RyaW5nW10pXG5cbiAgY29uc3QgcmVxdWVzdFJlc291cmNlID0gcGF0aC5zcGxpdCgnPycpWzBdXG4gIGxldCByZXF1ZXN0UXVlcnkgPSBwYXRoLnNwbGl0KCc/JylbMV1cbiAgaWYgKCFyZXF1ZXN0UXVlcnkpIHtcbiAgICByZXF1ZXN0UXVlcnkgPSAnJ1xuICB9XG5cbiAgaWYgKHJlcXVlc3RRdWVyeSkge1xuICAgIHJlcXVlc3RRdWVyeSA9IHJlcXVlc3RRdWVyeVxuICAgICAgLnNwbGl0KCcmJylcbiAgICAgIC5zb3J0KClcbiAgICAgIC5tYXAoKGVsZW1lbnQpID0+ICghZWxlbWVudC5pbmNsdWRlcygnPScpID8gZWxlbWVudCArICc9JyA6IGVsZW1lbnQpKVxuICAgICAgLmpvaW4oJyYnKVxuICB9XG5cbiAgcmV0dXJuIFtcbiAgICBtZXRob2QudG9VcHBlckNhc2UoKSxcbiAgICByZXF1ZXN0UmVzb3VyY2UsXG4gICAgcmVxdWVzdFF1ZXJ5LFxuICAgIGhlYWRlcnNBcnJheS5qb2luKCdcXG4nKSArICdcXG4nLFxuICAgIHNpZ25lZEhlYWRlcnMuam9pbignOycpLnRvTG93ZXJDYXNlKCksXG4gICAgaGFzaGVkUGF5bG9hZCxcbiAgXS5qb2luKCdcXG4nKVxufVxuXG4vLyBnZW5lcmF0ZSBhIGNyZWRlbnRpYWwgc3RyaW5nXG5mdW5jdGlvbiBnZXRDcmVkZW50aWFsKGFjY2Vzc0tleTogc3RyaW5nLCByZWdpb246IHN0cmluZywgcmVxdWVzdERhdGU/OiBEYXRlLCBzZXJ2aWNlTmFtZSA9ICdzMycpIHtcbiAgaWYgKCFpc1N0cmluZyhhY2Nlc3NLZXkpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignYWNjZXNzS2V5IHNob3VsZCBiZSBvZiB0eXBlIFwic3RyaW5nXCInKVxuICB9XG4gIGlmICghaXNTdHJpbmcocmVnaW9uKSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ3JlZ2lvbiBzaG91bGQgYmUgb2YgdHlwZSBcInN0cmluZ1wiJylcbiAgfVxuICBpZiAoIWlzT2JqZWN0KHJlcXVlc3REYXRlKSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ3JlcXVlc3REYXRlIHNob3VsZCBiZSBvZiB0eXBlIFwib2JqZWN0XCInKVxuICB9XG4gIHJldHVybiBgJHthY2Nlc3NLZXl9LyR7Z2V0U2NvcGUocmVnaW9uLCByZXF1ZXN0RGF0ZSwgc2VydmljZU5hbWUpfWBcbn1cblxuLy8gUmV0dXJucyBzaWduZWQgaGVhZGVycyBhcnJheSAtIGFscGhhYmV0aWNhbGx5IHNvcnRlZFxuZnVuY3Rpb24gZ2V0U2lnbmVkSGVhZGVycyhoZWFkZXJzOiBSZXF1ZXN0SGVhZGVycyk6IHN0cmluZ1tdIHtcbiAgaWYgKCFpc09iamVjdChoZWFkZXJzKSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ3JlcXVlc3Qgc2hvdWxkIGJlIG9mIHR5cGUgXCJvYmplY3RcIicpXG4gIH1cbiAgLy8gRXhjZXJwdHMgZnJvbSBAbHNlZ2FsIC0gaHR0cHM6Ly9naXRodWIuY29tL2F3cy9hd3Mtc2RrLWpzL2lzc3Vlcy82NTkjaXNzdWVjb21tZW50LTEyMDQ3NzI1OFxuICAvL1xuICAvLyAgVXNlci1BZ2VudDpcbiAgLy9cbiAgLy8gICAgICBUaGlzIGlzIGlnbm9yZWQgZnJvbSBzaWduaW5nIGJlY2F1c2Ugc2lnbmluZyB0aGlzIGNhdXNlcyBwcm9ibGVtcyB3aXRoIGdlbmVyYXRpbmcgcHJlLXNpZ25lZCBVUkxzXG4gIC8vICAgICAgKHRoYXQgYXJlIGV4ZWN1dGVkIGJ5IG90aGVyIGFnZW50cykgb3Igd2hlbiBjdXN0b21lcnMgcGFzcyByZXF1ZXN0cyB0aHJvdWdoIHByb3hpZXMsIHdoaWNoIG1heVxuICAvLyAgICAgIG1vZGlmeSB0aGUgdXNlci1hZ2VudC5cbiAgLy9cbiAgLy8gIENvbnRlbnQtTGVuZ3RoOlxuICAvL1xuICAvLyAgICAgIFRoaXMgaXMgaWdub3JlZCBmcm9tIHNpZ25pbmcgYmVjYXVzZSBnZW5lcmF0aW5nIGEgcHJlLXNpZ25lZCBVUkwgc2hvdWxkIG5vdCBwcm92aWRlIGEgY29udGVudC1sZW5ndGhcbiAgLy8gICAgICBjb25zdHJhaW50LCBzcGVjaWZpY2FsbHkgd2hlbiB2ZW5kaW5nIGEgUzMgcHJlLXNpZ25lZCBQVVQgVVJMLiBUaGUgY29yb2xsYXJ5IHRvIHRoaXMgaXMgdGhhdCB3aGVuXG4gIC8vICAgICAgc2VuZGluZyByZWd1bGFyIHJlcXVlc3RzIChub24tcHJlLXNpZ25lZCksIHRoZSBzaWduYXR1cmUgY29udGFpbnMgYSBjaGVja3N1bSBvZiB0aGUgYm9keSwgd2hpY2hcbiAgLy8gICAgICBpbXBsaWNpdGx5IHZhbGlkYXRlcyB0aGUgcGF5bG9hZCBsZW5ndGggKHNpbmNlIGNoYW5naW5nIHRoZSBudW1iZXIgb2YgYnl0ZXMgd291bGQgY2hhbmdlIHRoZSBjaGVja3N1bSlcbiAgLy8gICAgICBhbmQgdGhlcmVmb3JlIHRoaXMgaGVhZGVyIGlzIG5vdCB2YWx1YWJsZSBpbiB0aGUgc2lnbmF0dXJlLlxuICAvL1xuICAvLyAgQ29udGVudC1UeXBlOlxuICAvL1xuICAvLyAgICAgIFNpZ25pbmcgdGhpcyBoZWFkZXIgY2F1c2VzIHF1aXRlIGEgbnVtYmVyIG9mIHByb2JsZW1zIGluIGJyb3dzZXIgZW52aXJvbm1lbnRzLCB3aGVyZSBicm93c2Vyc1xuICAvLyAgICAgIGxpa2UgdG8gbW9kaWZ5IGFuZCBub3JtYWxpemUgdGhlIGNvbnRlbnQtdHlwZSBoZWFkZXIgaW4gZGlmZmVyZW50IHdheXMuIFRoZXJlIGlzIG1vcmUgaW5mb3JtYXRpb25cbiAgLy8gICAgICBvbiB0aGlzIGluIGh0dHBzOi8vZ2l0aHViLmNvbS9hd3MvYXdzLXNkay1qcy9pc3N1ZXMvMjQ0LiBBdm9pZGluZyB0aGlzIGZpZWxkIHNpbXBsaWZpZXMgbG9naWNcbiAgLy8gICAgICBhbmQgcmVkdWNlcyB0aGUgcG9zc2liaWxpdHkgb2YgZnV0dXJlIGJ1Z3NcbiAgLy9cbiAgLy8gIEF1dGhvcml6YXRpb246XG4gIC8vXG4gIC8vICAgICAgSXMgc2tpcHBlZCBmb3Igb2J2aW91cyByZWFzb25zXG5cbiAgY29uc3QgaWdub3JlZEhlYWRlcnMgPSBbJ2F1dGhvcml6YXRpb24nLCAnY29udGVudC1sZW5ndGgnLCAnY29udGVudC10eXBlJywgJ3VzZXItYWdlbnQnXVxuICByZXR1cm4gT2JqZWN0LmtleXMoaGVhZGVycylcbiAgICAuZmlsdGVyKChoZWFkZXIpID0+ICFpZ25vcmVkSGVhZGVycy5pbmNsdWRlcyhoZWFkZXIpKVxuICAgIC5zb3J0KClcbn1cblxuLy8gcmV0dXJucyB0aGUga2V5IHVzZWQgZm9yIGNhbGN1bGF0aW5nIHNpZ25hdHVyZVxuZnVuY3Rpb24gZ2V0U2lnbmluZ0tleShkYXRlOiBEYXRlLCByZWdpb246IHN0cmluZywgc2VjcmV0S2V5OiBzdHJpbmcsIHNlcnZpY2VOYW1lID0gJ3MzJykge1xuICBpZiAoIWlzT2JqZWN0KGRhdGUpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignZGF0ZSBzaG91bGQgYmUgb2YgdHlwZSBcIm9iamVjdFwiJylcbiAgfVxuICBpZiAoIWlzU3RyaW5nKHJlZ2lvbikpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdyZWdpb24gc2hvdWxkIGJlIG9mIHR5cGUgXCJzdHJpbmdcIicpXG4gIH1cbiAgaWYgKCFpc1N0cmluZyhzZWNyZXRLZXkpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignc2VjcmV0S2V5IHNob3VsZCBiZSBvZiB0eXBlIFwic3RyaW5nXCInKVxuICB9XG4gIGNvbnN0IGRhdGVMaW5lID0gbWFrZURhdGVTaG9ydChkYXRlKVxuICBjb25zdCBobWFjMSA9IGNyeXB0b1xuICAgICAgLmNyZWF0ZUhtYWMoJ3NoYTI1NicsICdBV1M0JyArIHNlY3JldEtleSlcbiAgICAgIC51cGRhdGUoZGF0ZUxpbmUpXG4gICAgICAuZGlnZXN0KCksXG4gICAgaG1hYzIgPSBjcnlwdG8uY3JlYXRlSG1hYygnc2hhMjU2JywgaG1hYzEpLnVwZGF0ZShyZWdpb24pLmRpZ2VzdCgpLFxuICAgIGhtYWMzID0gY3J5cHRvLmNyZWF0ZUhtYWMoJ3NoYTI1NicsIGhtYWMyKS51cGRhdGUoc2VydmljZU5hbWUpLmRpZ2VzdCgpXG4gIHJldHVybiBjcnlwdG8uY3JlYXRlSG1hYygnc2hhMjU2JywgaG1hYzMpLnVwZGF0ZSgnYXdzNF9yZXF1ZXN0JykuZGlnZXN0KClcbn1cblxuLy8gcmV0dXJucyB0aGUgc3RyaW5nIHRoYXQgbmVlZHMgdG8gYmUgc2lnbmVkXG5mdW5jdGlvbiBnZXRTdHJpbmdUb1NpZ24oY2Fub25pY2FsUmVxdWVzdDogSUNhbm9uaWNhbFJlcXVlc3QsIHJlcXVlc3REYXRlOiBEYXRlLCByZWdpb246IHN0cmluZywgc2VydmljZU5hbWUgPSAnczMnKSB7XG4gIGlmICghaXNTdHJpbmcoY2Fub25pY2FsUmVxdWVzdCkpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdjYW5vbmljYWxSZXF1ZXN0IHNob3VsZCBiZSBvZiB0eXBlIFwic3RyaW5nXCInKVxuICB9XG4gIGlmICghaXNPYmplY3QocmVxdWVzdERhdGUpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcigncmVxdWVzdERhdGUgc2hvdWxkIGJlIG9mIHR5cGUgXCJvYmplY3RcIicpXG4gIH1cbiAgaWYgKCFpc1N0cmluZyhyZWdpb24pKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcigncmVnaW9uIHNob3VsZCBiZSBvZiB0eXBlIFwic3RyaW5nXCInKVxuICB9XG4gIGNvbnN0IGhhc2ggPSBjcnlwdG8uY3JlYXRlSGFzaCgnc2hhMjU2JykudXBkYXRlKGNhbm9uaWNhbFJlcXVlc3QpLmRpZ2VzdCgnaGV4JylcbiAgY29uc3Qgc2NvcGUgPSBnZXRTY29wZShyZWdpb24sIHJlcXVlc3REYXRlLCBzZXJ2aWNlTmFtZSlcbiAgY29uc3Qgc3RyaW5nVG9TaWduID0gW3NpZ25WNEFsZ29yaXRobSwgbWFrZURhdGVMb25nKHJlcXVlc3REYXRlKSwgc2NvcGUsIGhhc2hdXG5cbiAgcmV0dXJuIHN0cmluZ1RvU2lnbi5qb2luKCdcXG4nKVxufVxuXG4vLyBjYWxjdWxhdGUgdGhlIHNpZ25hdHVyZSBvZiB0aGUgUE9TVCBwb2xpY3lcbmV4cG9ydCBmdW5jdGlvbiBwb3N0UHJlc2lnblNpZ25hdHVyZVY0KHJlZ2lvbjogc3RyaW5nLCBkYXRlOiBEYXRlLCBzZWNyZXRLZXk6IHN0cmluZywgcG9saWN5QmFzZTY0OiBzdHJpbmcpOiBzdHJpbmcge1xuICBpZiAoIWlzU3RyaW5nKHJlZ2lvbikpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdyZWdpb24gc2hvdWxkIGJlIG9mIHR5cGUgXCJzdHJpbmdcIicpXG4gIH1cbiAgaWYgKCFpc09iamVjdChkYXRlKSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ2RhdGUgc2hvdWxkIGJlIG9mIHR5cGUgXCJvYmplY3RcIicpXG4gIH1cbiAgaWYgKCFpc1N0cmluZyhzZWNyZXRLZXkpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignc2VjcmV0S2V5IHNob3VsZCBiZSBvZiB0eXBlIFwic3RyaW5nXCInKVxuICB9XG4gIGlmICghaXNTdHJpbmcocG9saWN5QmFzZTY0KSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ3BvbGljeUJhc2U2NCBzaG91bGQgYmUgb2YgdHlwZSBcInN0cmluZ1wiJylcbiAgfVxuICBjb25zdCBzaWduaW5nS2V5ID0gZ2V0U2lnbmluZ0tleShkYXRlLCByZWdpb24sIHNlY3JldEtleSlcbiAgcmV0dXJuIGNyeXB0by5jcmVhdGVIbWFjKCdzaGEyNTYnLCBzaWduaW5nS2V5KS51cGRhdGUocG9saWN5QmFzZTY0KS5kaWdlc3QoJ2hleCcpLnRvTG93ZXJDYXNlKClcbn1cblxuLy8gUmV0dXJucyB0aGUgYXV0aG9yaXphdGlvbiBoZWFkZXJcbmV4cG9ydCBmdW5jdGlvbiBzaWduVjQoXG4gIHJlcXVlc3Q6IElSZXF1ZXN0LFxuICBhY2Nlc3NLZXk6IHN0cmluZyxcbiAgc2VjcmV0S2V5OiBzdHJpbmcsXG4gIHJlZ2lvbjogc3RyaW5nLFxuICByZXF1ZXN0RGF0ZTogRGF0ZSxcbiAgc2hhMjU2c3VtOiBzdHJpbmcsXG4gIHNlcnZpY2VOYW1lID0gJ3MzJyxcbikge1xuICBpZiAoIWlzT2JqZWN0KHJlcXVlc3QpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcigncmVxdWVzdCBzaG91bGQgYmUgb2YgdHlwZSBcIm9iamVjdFwiJylcbiAgfVxuICBpZiAoIWlzU3RyaW5nKGFjY2Vzc0tleSkpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdhY2Nlc3NLZXkgc2hvdWxkIGJlIG9mIHR5cGUgXCJzdHJpbmdcIicpXG4gIH1cbiAgaWYgKCFpc1N0cmluZyhzZWNyZXRLZXkpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignc2VjcmV0S2V5IHNob3VsZCBiZSBvZiB0eXBlIFwic3RyaW5nXCInKVxuICB9XG4gIGlmICghaXNTdHJpbmcocmVnaW9uKSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ3JlZ2lvbiBzaG91bGQgYmUgb2YgdHlwZSBcInN0cmluZ1wiJylcbiAgfVxuXG4gIGlmICghYWNjZXNzS2V5KSB7XG4gICAgdGhyb3cgbmV3IGVycm9ycy5BY2Nlc3NLZXlSZXF1aXJlZEVycm9yKCdhY2Nlc3NLZXkgaXMgcmVxdWlyZWQgZm9yIHNpZ25pbmcnKVxuICB9XG4gIGlmICghc2VjcmV0S2V5KSB7XG4gICAgdGhyb3cgbmV3IGVycm9ycy5TZWNyZXRLZXlSZXF1aXJlZEVycm9yKCdzZWNyZXRLZXkgaXMgcmVxdWlyZWQgZm9yIHNpZ25pbmcnKVxuICB9XG5cbiAgY29uc3Qgc2lnbmVkSGVhZGVycyA9IGdldFNpZ25lZEhlYWRlcnMocmVxdWVzdC5oZWFkZXJzKVxuICBjb25zdCBjYW5vbmljYWxSZXF1ZXN0ID0gZ2V0Q2Fub25pY2FsUmVxdWVzdChyZXF1ZXN0Lm1ldGhvZCwgcmVxdWVzdC5wYXRoLCByZXF1ZXN0LmhlYWRlcnMsIHNpZ25lZEhlYWRlcnMsIHNoYTI1NnN1bSlcbiAgY29uc3Qgc2VydmljZUlkZW50aWZpZXIgPSBzZXJ2aWNlTmFtZSB8fCAnczMnXG4gIGNvbnN0IHN0cmluZ1RvU2lnbiA9IGdldFN0cmluZ1RvU2lnbihjYW5vbmljYWxSZXF1ZXN0LCByZXF1ZXN0RGF0ZSwgcmVnaW9uLCBzZXJ2aWNlSWRlbnRpZmllcilcbiAgY29uc3Qgc2lnbmluZ0tleSA9IGdldFNpZ25pbmdLZXkocmVxdWVzdERhdGUsIHJlZ2lvbiwgc2VjcmV0S2V5LCBzZXJ2aWNlSWRlbnRpZmllcilcbiAgY29uc3QgY3JlZGVudGlhbCA9IGdldENyZWRlbnRpYWwoYWNjZXNzS2V5LCByZWdpb24sIHJlcXVlc3REYXRlLCBzZXJ2aWNlSWRlbnRpZmllcilcbiAgY29uc3Qgc2lnbmF0dXJlID0gY3J5cHRvLmNyZWF0ZUhtYWMoJ3NoYTI1NicsIHNpZ25pbmdLZXkpLnVwZGF0ZShzdHJpbmdUb1NpZ24pLmRpZ2VzdCgnaGV4JykudG9Mb3dlckNhc2UoKVxuXG4gIHJldHVybiBgJHtzaWduVjRBbGdvcml0aG19IENyZWRlbnRpYWw9JHtjcmVkZW50aWFsfSwgU2lnbmVkSGVhZGVycz0ke3NpZ25lZEhlYWRlcnNcbiAgICAuam9pbignOycpXG4gICAgLnRvTG93ZXJDYXNlKCl9LCBTaWduYXR1cmU9JHtzaWduYXR1cmV9YFxufVxuXG5leHBvcnQgZnVuY3Rpb24gc2lnblY0QnlTZXJ2aWNlTmFtZShcbiAgcmVxdWVzdDogSVJlcXVlc3QsXG4gIGFjY2Vzc0tleTogc3RyaW5nLFxuICBzZWNyZXRLZXk6IHN0cmluZyxcbiAgcmVnaW9uOiBzdHJpbmcsXG4gIHJlcXVlc3REYXRlOiBEYXRlLFxuICBjb250ZW50U2hhMjU2OiBzdHJpbmcsXG4gIHNlcnZpY2VOYW1lID0gJ3MzJyxcbik6IHN0cmluZyB7XG4gIHJldHVybiBzaWduVjQocmVxdWVzdCwgYWNjZXNzS2V5LCBzZWNyZXRLZXksIHJlZ2lvbiwgcmVxdWVzdERhdGUsIGNvbnRlbnRTaGEyNTYsIHNlcnZpY2VOYW1lKVxufVxuXG4vLyByZXR1cm5zIGEgcHJlc2lnbmVkIFVSTCBzdHJpbmdcbmV4cG9ydCBmdW5jdGlvbiBwcmVzaWduU2lnbmF0dXJlVjQoXG4gIHJlcXVlc3Q6IElSZXF1ZXN0LFxuICBhY2Nlc3NLZXk6IHN0cmluZyxcbiAgc2VjcmV0S2V5OiBzdHJpbmcsXG4gIHNlc3Npb25Ub2tlbjogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICByZWdpb246IHN0cmluZyxcbiAgcmVxdWVzdERhdGU6IERhdGUsXG4gIGV4cGlyZXM6IG51bWJlciB8IHVuZGVmaW5lZCxcbikge1xuICBpZiAoIWlzT2JqZWN0KHJlcXVlc3QpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcigncmVxdWVzdCBzaG91bGQgYmUgb2YgdHlwZSBcIm9iamVjdFwiJylcbiAgfVxuICBpZiAoIWlzU3RyaW5nKGFjY2Vzc0tleSkpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdhY2Nlc3NLZXkgc2hvdWxkIGJlIG9mIHR5cGUgXCJzdHJpbmdcIicpXG4gIH1cbiAgaWYgKCFpc1N0cmluZyhzZWNyZXRLZXkpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignc2VjcmV0S2V5IHNob3VsZCBiZSBvZiB0eXBlIFwic3RyaW5nXCInKVxuICB9XG4gIGlmICghaXNTdHJpbmcocmVnaW9uKSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ3JlZ2lvbiBzaG91bGQgYmUgb2YgdHlwZSBcInN0cmluZ1wiJylcbiAgfVxuXG4gIGlmICghYWNjZXNzS2V5KSB7XG4gICAgdGhyb3cgbmV3IGVycm9ycy5BY2Nlc3NLZXlSZXF1aXJlZEVycm9yKCdhY2Nlc3NLZXkgaXMgcmVxdWlyZWQgZm9yIHByZXNpZ25pbmcnKVxuICB9XG4gIGlmICghc2VjcmV0S2V5KSB7XG4gICAgdGhyb3cgbmV3IGVycm9ycy5TZWNyZXRLZXlSZXF1aXJlZEVycm9yKCdzZWNyZXRLZXkgaXMgcmVxdWlyZWQgZm9yIHByZXNpZ25pbmcnKVxuICB9XG5cbiAgaWYgKGV4cGlyZXMgJiYgIWlzTnVtYmVyKGV4cGlyZXMpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignZXhwaXJlcyBzaG91bGQgYmUgb2YgdHlwZSBcIm51bWJlclwiJylcbiAgfVxuICBpZiAoZXhwaXJlcyAmJiBleHBpcmVzIDwgMSkge1xuICAgIHRocm93IG5ldyBlcnJvcnMuRXhwaXJlc1BhcmFtRXJyb3IoJ2V4cGlyZXMgcGFyYW0gY2Fubm90IGJlIGxlc3MgdGhhbiAxIHNlY29uZHMnKVxuICB9XG4gIGlmIChleHBpcmVzICYmIGV4cGlyZXMgPiBQUkVTSUdOX0VYUElSWV9EQVlTX01BWCkge1xuICAgIHRocm93IG5ldyBlcnJvcnMuRXhwaXJlc1BhcmFtRXJyb3IoJ2V4cGlyZXMgcGFyYW0gY2Fubm90IGJlIGdyZWF0ZXIgdGhhbiA3IGRheXMnKVxuICB9XG5cbiAgY29uc3QgaXNvODYwMURhdGUgPSBtYWtlRGF0ZUxvbmcocmVxdWVzdERhdGUpXG4gIGNvbnN0IHNpZ25lZEhlYWRlcnMgPSBnZXRTaWduZWRIZWFkZXJzKHJlcXVlc3QuaGVhZGVycylcbiAgY29uc3QgY3JlZGVudGlhbCA9IGdldENyZWRlbnRpYWwoYWNjZXNzS2V5LCByZWdpb24sIHJlcXVlc3REYXRlKVxuICBjb25zdCBoYXNoZWRQYXlsb2FkID0gJ1VOU0lHTkVELVBBWUxPQUQnXG5cbiAgY29uc3QgcmVxdWVzdFF1ZXJ5OiBzdHJpbmdbXSA9IFtdXG4gIHJlcXVlc3RRdWVyeS5wdXNoKGBYLUFtei1BbGdvcml0aG09JHtzaWduVjRBbGdvcml0aG19YClcbiAgcmVxdWVzdFF1ZXJ5LnB1c2goYFgtQW16LUNyZWRlbnRpYWw9JHt1cmlFc2NhcGUoY3JlZGVudGlhbCl9YClcbiAgcmVxdWVzdFF1ZXJ5LnB1c2goYFgtQW16LURhdGU9JHtpc284NjAxRGF0ZX1gKVxuICByZXF1ZXN0UXVlcnkucHVzaChgWC1BbXotRXhwaXJlcz0ke2V4cGlyZXN9YClcbiAgcmVxdWVzdFF1ZXJ5LnB1c2goYFgtQW16LVNpZ25lZEhlYWRlcnM9JHt1cmlFc2NhcGUoc2lnbmVkSGVhZGVycy5qb2luKCc7JykudG9Mb3dlckNhc2UoKSl9YClcbiAgaWYgKHNlc3Npb25Ub2tlbikge1xuICAgIHJlcXVlc3RRdWVyeS5wdXNoKGBYLUFtei1TZWN1cml0eS1Ub2tlbj0ke3VyaUVzY2FwZShzZXNzaW9uVG9rZW4pfWApXG4gIH1cblxuICBjb25zdCByZXNvdXJjZSA9IHJlcXVlc3QucGF0aC5zcGxpdCgnPycpWzBdXG4gIGxldCBxdWVyeSA9IHJlcXVlc3QucGF0aC5zcGxpdCgnPycpWzFdXG4gIGlmIChxdWVyeSkge1xuICAgIHF1ZXJ5ID0gcXVlcnkgKyAnJicgKyByZXF1ZXN0UXVlcnkuam9pbignJicpXG4gIH0gZWxzZSB7XG4gICAgcXVlcnkgPSByZXF1ZXN0UXVlcnkuam9pbignJicpXG4gIH1cblxuICBjb25zdCBwYXRoID0gcmVzb3VyY2UgKyAnPycgKyBxdWVyeVxuXG4gIGNvbnN0IGNhbm9uaWNhbFJlcXVlc3QgPSBnZXRDYW5vbmljYWxSZXF1ZXN0KHJlcXVlc3QubWV0aG9kLCBwYXRoLCByZXF1ZXN0LmhlYWRlcnMsIHNpZ25lZEhlYWRlcnMsIGhhc2hlZFBheWxvYWQpXG5cbiAgY29uc3Qgc3RyaW5nVG9TaWduID0gZ2V0U3RyaW5nVG9TaWduKGNhbm9uaWNhbFJlcXVlc3QsIHJlcXVlc3REYXRlLCByZWdpb24pXG4gIGNvbnN0IHNpZ25pbmdLZXkgPSBnZXRTaWduaW5nS2V5KHJlcXVlc3REYXRlLCByZWdpb24sIHNlY3JldEtleSlcbiAgY29uc3Qgc2lnbmF0dXJlID0gY3J5cHRvLmNyZWF0ZUhtYWMoJ3NoYTI1NicsIHNpZ25pbmdLZXkpLnVwZGF0ZShzdHJpbmdUb1NpZ24pLmRpZ2VzdCgnaGV4JykudG9Mb3dlckNhc2UoKVxuICByZXR1cm4gcmVxdWVzdC5wcm90b2NvbCArICcvLycgKyByZXF1ZXN0LmhlYWRlcnMuaG9zdCArIHBhdGggKyBgJlgtQW16LVNpZ25hdHVyZT0ke3NpZ25hdHVyZX1gXG59XG4iXSwibWFwcGluZ3MiOiJBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxPQUFPLEtBQUtBLE1BQU07QUFFbEIsT0FBTyxLQUFLQyxNQUFNLE1BQU0sY0FBYTtBQUNyQyxTQUFTQyx1QkFBdUIsUUFBUSxlQUFjO0FBQ3RELFNBQVNDLFFBQVEsRUFBRUMsUUFBUSxFQUFFQyxRQUFRLEVBQUVDLFFBQVEsRUFBRUMsWUFBWSxFQUFFQyxhQUFhLEVBQUVDLFNBQVMsUUFBUSx1QkFBc0I7QUFHckgsTUFBTUMsZUFBZSxHQUFHLGtCQUFrQjs7QUFFMUM7QUFDQTtBQUNBO0FBQ0E7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