UNPKG

matrix-react-sdk

Version:
379 lines (372 loc) 60.6 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _lodash = require("lodash"); var _classnames = _interopRequireDefault(require("classnames")); var _react = _interopRequireDefault(require("react")); var _logger = require("matrix-js-sdk/src/logger"); var _cryptoApi = require("matrix-js-sdk/src/crypto-api"); var _MatrixClientPeg = require("../../../../MatrixClientPeg"); var _Field = _interopRequireDefault(require("../../elements/Field")); var _AccessibleButton = _interopRequireDefault(require("../../elements/AccessibleButton")); var _languageHandler = require("../../../../languageHandler"); var _SecurityManager = require("../../../../SecurityManager"); var _Modal = _interopRequireDefault(require("../../../../Modal")); var _InteractiveAuthDialog = _interopRequireDefault(require("../InteractiveAuthDialog")); var _DialogButtons = _interopRequireDefault(require("../../elements/DialogButtons")); var _BaseDialog = _interopRequireDefault(require("../BaseDialog")); var _BrowserWorkarounds = require("../../../../utils/BrowserWorkarounds"); /* Copyright 2024 New Vector Ltd. Copyright 2018-2021 The Matrix.org Foundation C.I.C. SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ // Maximum acceptable size of a key file. It's 59 characters including the spaces we encode, // so this should be plenty and allow for people putting extra whitespace in the file because // maybe that's a thing people would do? const KEY_FILE_MAX_SIZE = 128; // Don't shout at the user that their key is invalid every time they type a key: wait a short time const VALIDATION_THROTTLE_MS = 200; /* * Access Secure Secret Storage by requesting the user's passphrase. */ class AccessSecretStorageDialog extends _react.default.PureComponent { constructor(props) { super(props); (0, _defineProperty2.default)(this, "fileUpload", /*#__PURE__*/_react.default.createRef()); (0, _defineProperty2.default)(this, "inputRef", /*#__PURE__*/_react.default.createRef()); (0, _defineProperty2.default)(this, "onCancel", () => { if (this.state.resetting) { this.setState({ resetting: false }); } this.props.onFinished(false); }); (0, _defineProperty2.default)(this, "onUseRecoveryKeyClick", () => { this.setState({ forceRecoveryKey: true }); }); (0, _defineProperty2.default)(this, "validateRecoveryKeyOnChange", (0, _lodash.debounce)(async () => { await this.validateRecoveryKey(); }, VALIDATION_THROTTLE_MS)); (0, _defineProperty2.default)(this, "onRecoveryKeyChange", ev => { this.setState({ recoveryKey: ev.target.value, recoveryKeyFileError: null }); // also clear the file upload control so that the user can upload the same file // the did before (otherwise the onchange wouldn't fire) if (this.fileUpload.current) this.fileUpload.current.value = ""; // We don't use Field's validation here because a) we want it in a separate place rather // than in a tooltip and b) we want it to display feedback based on the uploaded file // as well as the text box. Ideally we would refactor Field's validation logic so we could // re-use some of it. this.validateRecoveryKeyOnChange(); }); (0, _defineProperty2.default)(this, "onRecoveryKeyFileChange", async ev => { if (!ev.target.files?.length) return; const f = ev.target.files[0]; if (f.size > KEY_FILE_MAX_SIZE) { this.setState({ recoveryKeyFileError: true, recoveryKeyCorrect: false, recoveryKeyValid: false }); } else { const contents = await f.text(); // test it's within the base58 alphabet. We could be more strict here, eg. require the // right number of characters, but it's really just to make sure that what we're reading is // text because we'll put it in the text field. if (/^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz\s]+$/.test(contents)) { this.setState({ recoveryKeyFileError: null, recoveryKey: contents.trim() }); await this.validateRecoveryKey(); } else { this.setState({ recoveryKeyFileError: true, recoveryKeyCorrect: false, recoveryKeyValid: false, recoveryKey: "" }); } } }); (0, _defineProperty2.default)(this, "onRecoveryKeyFileUploadClick", () => { this.fileUpload.current?.click(); }); (0, _defineProperty2.default)(this, "onPassPhraseNext", async ev => { ev.preventDefault(); if (this.state.passPhrase.length <= 0) { this.inputRef.current?.focus(); return; } this.setState({ keyMatches: null }); const input = { passphrase: this.state.passPhrase }; const keyMatches = await this.props.checkPrivateKey(input); if (keyMatches) { this.props.onFinished(input); } else { this.setState({ keyMatches }); this.inputRef.current?.focus(); } }); (0, _defineProperty2.default)(this, "onRecoveryKeyNext", async ev => { ev.preventDefault(); if (!this.state.recoveryKeyValid) return; this.setState({ keyMatches: null }); const input = { recoveryKey: this.state.recoveryKey }; const keyMatches = await this.props.checkPrivateKey(input); if (keyMatches) { this.props.onFinished(input); } else { this.setState({ keyMatches }); } }); (0, _defineProperty2.default)(this, "onPassPhraseChange", ev => { this.setState({ passPhrase: ev.target.value, keyMatches: null }); }); (0, _defineProperty2.default)(this, "onResetAllClick", ev => { ev.preventDefault(); this.setState({ resetting: true }); }); (0, _defineProperty2.default)(this, "onConfirmResetAllClick", async () => { // Hide ourselves so the user can interact with the reset dialogs. // We don't conclude the promise chain (onFinished) yet to avoid confusing // any upstream code flows. // // Note: this will unmount us, so don't call `setState` or anything in the // rest of this function. _Modal.default.toggleCurrentDialogVisibility(); try { // Force reset secret storage (which resets the key backup) await (0, _SecurityManager.accessSecretStorage)(async () => { // Now reset cross-signing so everything Just Works™ again. const cli = _MatrixClientPeg.MatrixClientPeg.safeGet(); await cli.bootstrapCrossSigning({ authUploadDeviceSigningKeys: async makeRequest => { const { finished } = _Modal.default.createDialog(_InteractiveAuthDialog.default, { title: (0, _languageHandler._t)("encryption|bootstrap_title"), matrixClient: cli, makeRequest }); const [confirmed] = await finished; if (!confirmed) { throw new Error("Cross-signing key upload auth canceled"); } }, setupNewCrossSigning: true }); // Now we can indicate that the user is done pressing buttons, finally. // Upstream flows will detect the new secret storage, key backup, etc and use it. this.props.onFinished({}); }, true); } catch (e) { _logger.logger.error(e); this.props.onFinished(false); } }); this.state = { recoveryKey: "", recoveryKeyValid: null, recoveryKeyCorrect: null, recoveryKeyFileError: null, forceRecoveryKey: false, passPhrase: "", keyMatches: null, resetting: false }; } async validateRecoveryKey() { if (this.state.recoveryKey === "") { this.setState({ recoveryKeyValid: null, recoveryKeyCorrect: null }); return; } try { const cli = _MatrixClientPeg.MatrixClientPeg.safeGet(); const decodedKey = (0, _cryptoApi.decodeRecoveryKey)(this.state.recoveryKey); const correct = await cli.secretStorage.checkKey(decodedKey, this.props.keyInfo); this.setState({ recoveryKeyValid: true, recoveryKeyCorrect: correct }); } catch (e) { this.setState({ recoveryKeyValid: false, recoveryKeyCorrect: false }); } } getKeyValidationText() { if (this.state.recoveryKeyFileError) { return (0, _languageHandler._t)("encryption|access_secret_storage_dialog|key_validation_text|wrong_file_type"); } else if (this.state.recoveryKeyCorrect) { return (0, _languageHandler._t)("encryption|access_secret_storage_dialog|key_validation_text|recovery_key_is_correct"); } else if (this.state.recoveryKeyValid) { return (0, _languageHandler._t)("encryption|access_secret_storage_dialog|key_validation_text|wrong_security_key"); } else if (this.state.recoveryKeyValid === null) { return ""; } else { return (0, _languageHandler._t)("encryption|access_secret_storage_dialog|key_validation_text|invalid_security_key"); } } render() { const hasPassphrase = this.props.keyInfo?.passphrase?.salt && this.props.keyInfo?.passphrase?.iterations; const resetLine = /*#__PURE__*/_react.default.createElement("strong", { className: "mx_AccessSecretStorageDialog_reset" }, (0, _languageHandler._t)("encryption|reset_all_button", undefined, { a: sub => /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { kind: "link_inline", onClick: this.onResetAllClick, className: "mx_AccessSecretStorageDialog_reset_link" }, sub) })); let content; let title; let titleClass; if (this.state.resetting) { title = (0, _languageHandler._t)("encryption|access_secret_storage_dialog|reset_title"); titleClass = ["mx_AccessSecretStorageDialog_titleWithIcon mx_AccessSecretStorageDialog_resetBadge"]; content = /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("encryption|access_secret_storage_dialog|reset_warning_1")), /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("encryption|access_secret_storage_dialog|reset_warning_2")), /*#__PURE__*/_react.default.createElement(_DialogButtons.default, { primaryButton: (0, _languageHandler._t)("action|reset"), onPrimaryButtonClick: this.onConfirmResetAllClick, hasCancel: true, onCancel: this.onCancel, focus: false, primaryButtonClass: "danger" })); } else if (hasPassphrase && !this.state.forceRecoveryKey) { title = (0, _languageHandler._t)("encryption|access_secret_storage_dialog|security_phrase_title"); titleClass = ["mx_AccessSecretStorageDialog_titleWithIcon mx_AccessSecretStorageDialog_securePhraseTitle"]; let keyStatus; if (this.state.keyMatches === false) { keyStatus = /*#__PURE__*/_react.default.createElement("div", { className: "mx_AccessSecretStorageDialog_keyStatus" }, "\uD83D\uDC4E ", (0, _languageHandler._t)("encryption|access_secret_storage_dialog|security_phrase_incorrect_error")); } else { keyStatus = /*#__PURE__*/_react.default.createElement("div", { className: "mx_AccessSecretStorageDialog_keyStatus" }); } content = /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("encryption|access_secret_storage_dialog|enter_phrase_or_key_prompt", {}, { button: s => /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { kind: "link_inline", onClick: this.onUseRecoveryKeyClick }, s) })), /*#__PURE__*/_react.default.createElement("form", { className: "mx_AccessSecretStorageDialog_primaryContainer", onSubmit: this.onPassPhraseNext }, /*#__PURE__*/_react.default.createElement(_Field.default, { inputRef: this.inputRef, id: "mx_passPhraseInput", className: "mx_AccessSecretStorageDialog_passPhraseInput", type: "password", label: (0, _languageHandler._t)("encryption|access_secret_storage_dialog|security_phrase_title"), value: this.state.passPhrase, onChange: this.onPassPhraseChange, autoFocus: true, autoComplete: "new-password" }), keyStatus, /*#__PURE__*/_react.default.createElement(_DialogButtons.default, { primaryButton: (0, _languageHandler._t)("action|continue"), onPrimaryButtonClick: this.onPassPhraseNext, hasCancel: true, onCancel: this.onCancel, focus: false, primaryDisabled: this.state.passPhrase.length === 0, additive: resetLine }))); } else { title = (0, _languageHandler._t)("encryption|access_secret_storage_dialog|security_key_title"); titleClass = ["mx_AccessSecretStorageDialog_titleWithIcon mx_AccessSecretStorageDialog_secureBackupTitle"]; const feedbackClasses = (0, _classnames.default)({ "mx_AccessSecretStorageDialog_recoveryKeyFeedback": true, "mx_AccessSecretStorageDialog_recoveryKeyFeedback--valid": this.state.recoveryKeyCorrect === true, "mx_AccessSecretStorageDialog_recoveryKeyFeedback--invalid": this.state.recoveryKeyCorrect === false }); const recoveryKeyFeedback = /*#__PURE__*/_react.default.createElement("div", { className: feedbackClasses }, this.getKeyValidationText()); content = /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("encryption|access_secret_storage_dialog|use_security_key_prompt")), /*#__PURE__*/_react.default.createElement("form", { className: "mx_AccessSecretStorageDialog_primaryContainer", onSubmit: this.onRecoveryKeyNext, spellCheck: false, autoComplete: "off" }, /*#__PURE__*/_react.default.createElement("div", { className: "mx_AccessSecretStorageDialog_recoveryKeyEntry" }, /*#__PURE__*/_react.default.createElement("div", { className: "mx_AccessSecretStorageDialog_recoveryKeyEntry_textInput" }, /*#__PURE__*/_react.default.createElement(_Field.default, { type: "password", id: "mx_securityKey", label: (0, _languageHandler._t)("encryption|access_secret_storage_dialog|security_key_title"), value: this.state.recoveryKey, onChange: this.onRecoveryKeyChange, autoFocus: true, forceValidity: this.state.recoveryKeyCorrect ?? undefined, autoComplete: "off" })), /*#__PURE__*/_react.default.createElement("span", { className: "mx_AccessSecretStorageDialog_recoveryKeyEntry_entryControlSeparatorText" }, (0, _languageHandler._t)("encryption|access_secret_storage_dialog|separator", { recoveryFile: "", securityKey: "" })), /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("input", { type: "file", className: "mx_AccessSecretStorageDialog_recoveryKeyEntry_fileInput", ref: this.fileUpload, onClick: _BrowserWorkarounds.chromeFileInputFix, onChange: this.onRecoveryKeyFileChange }), /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { kind: "primary", onClick: this.onRecoveryKeyFileUploadClick }, (0, _languageHandler._t)("action|upload")))), recoveryKeyFeedback, /*#__PURE__*/_react.default.createElement(_DialogButtons.default, { primaryButton: (0, _languageHandler._t)("action|continue"), onPrimaryButtonClick: this.onRecoveryKeyNext, hasCancel: true, cancelButton: (0, _languageHandler._t)("action|go_back"), cancelButtonClass: "warning", onCancel: this.onCancel, focus: false, primaryDisabled: !this.state.recoveryKeyValid, additive: resetLine }))); } return /*#__PURE__*/_react.default.createElement(_BaseDialog.default, { className: "mx_AccessSecretStorageDialog", onFinished: this.props.onFinished, title: title, titleClass: titleClass }, /*#__PURE__*/_react.default.createElement("div", null, content)); } } exports.default = AccessSecretStorageDialog; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbG9kYXNoIiwicmVxdWlyZSIsIl9jbGFzc25hbWVzIiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsIl9yZWFjdCIsIl9sb2dnZXIiLCJfY3J5cHRvQXBpIiwiX01hdHJpeENsaWVudFBlZyIsIl9GaWVsZCIsIl9BY2Nlc3NpYmxlQnV0dG9uIiwiX2xhbmd1YWdlSGFuZGxlciIsIl9TZWN1cml0eU1hbmFnZXIiLCJfTW9kYWwiLCJfSW50ZXJhY3RpdmVBdXRoRGlhbG9nIiwiX0RpYWxvZ0J1dHRvbnMiLCJfQmFzZURpYWxvZyIsIl9Ccm93c2VyV29ya2Fyb3VuZHMiLCJLRVlfRklMRV9NQVhfU0laRSIsIlZBTElEQVRJT05fVEhST1RUTEVfTVMiLCJBY2Nlc3NTZWNyZXRTdG9yYWdlRGlhbG9nIiwiUmVhY3QiLCJQdXJlQ29tcG9uZW50IiwiY29uc3RydWN0b3IiLCJwcm9wcyIsIl9kZWZpbmVQcm9wZXJ0eTIiLCJkZWZhdWx0IiwiY3JlYXRlUmVmIiwic3RhdGUiLCJyZXNldHRpbmciLCJzZXRTdGF0ZSIsIm9uRmluaXNoZWQiLCJmb3JjZVJlY292ZXJ5S2V5IiwiZGVib3VuY2UiLCJ2YWxpZGF0ZVJlY292ZXJ5S2V5IiwiZXYiLCJyZWNvdmVyeUtleSIsInRhcmdldCIsInZhbHVlIiwicmVjb3ZlcnlLZXlGaWxlRXJyb3IiLCJmaWxlVXBsb2FkIiwiY3VycmVudCIsInZhbGlkYXRlUmVjb3ZlcnlLZXlPbkNoYW5nZSIsImZpbGVzIiwibGVuZ3RoIiwiZiIsInNpemUiLCJyZWNvdmVyeUtleUNvcnJlY3QiLCJyZWNvdmVyeUtleVZhbGlkIiwiY29udGVudHMiLCJ0ZXh0IiwidGVzdCIsInRyaW0iLCJjbGljayIsInByZXZlbnREZWZhdWx0IiwicGFzc1BocmFzZSIsImlucHV0UmVmIiwiZm9jdXMiLCJrZXlNYXRjaGVzIiwiaW5wdXQiLCJwYXNzcGhyYXNlIiwiY2hlY2tQcml2YXRlS2V5IiwiTW9kYWwiLCJ0b2dnbGVDdXJyZW50RGlhbG9nVmlzaWJpbGl0eSIsImFjY2Vzc1NlY3JldFN0b3JhZ2UiLCJjbGkiLCJNYXRyaXhDbGllbnRQZWciLCJzYWZlR2V0IiwiYm9vdHN0cmFwQ3Jvc3NTaWduaW5nIiwiYXV0aFVwbG9hZERldmljZVNpZ25pbmdLZXlzIiwibWFrZVJlcXVlc3QiLCJmaW5pc2hlZCIsImNyZWF0ZURpYWxvZyIsIkludGVyYWN0aXZlQXV0aERpYWxvZyIsInRpdGxlIiwiX3QiLCJtYXRyaXhDbGllbnQiLCJjb25maXJtZWQiLCJFcnJvciIsInNldHVwTmV3Q3Jvc3NTaWduaW5nIiwiZSIsImxvZ2dlciIsImVycm9yIiwiZGVjb2RlZEtleSIsImRlY29kZVJlY292ZXJ5S2V5IiwiY29ycmVjdCIsInNlY3JldFN0b3JhZ2UiLCJjaGVja0tleSIsImtleUluZm8iLCJnZXRLZXlWYWxpZGF0aW9uVGV4dCIsInJlbmRlciIsImhhc1Bhc3NwaHJhc2UiLCJzYWx0IiwiaXRlcmF0aW9ucyIsInJlc2V0TGluZSIsImNyZWF0ZUVsZW1lbnQiLCJjbGFzc05hbWUiLCJ1bmRlZmluZWQiLCJhIiwic3ViIiwia2luZCIsIm9uQ2xpY2siLCJvblJlc2V0QWxsQ2xpY2siLCJjb250ZW50IiwidGl0bGVDbGFzcyIsInByaW1hcnlCdXR0b24iLCJvblByaW1hcnlCdXR0b25DbGljayIsIm9uQ29uZmlybVJlc2V0QWxsQ2xpY2siLCJoYXNDYW5jZWwiLCJvbkNhbmNlbCIsInByaW1hcnlCdXR0b25DbGFzcyIsImtleVN0YXR1cyIsImJ1dHRvbiIsInMiLCJvblVzZVJlY292ZXJ5S2V5Q2xpY2siLCJvblN1Ym1pdCIsIm9uUGFzc1BocmFzZU5leHQiLCJpZCIsInR5cGUiLCJsYWJlbCIsIm9uQ2hhbmdlIiwib25QYXNzUGhyYXNlQ2hhbmdlIiwiYXV0b0ZvY3VzIiwiYXV0b0NvbXBsZXRlIiwicHJpbWFyeURpc2FibGVkIiwiYWRkaXRpdmUiLCJmZWVkYmFja0NsYXNzZXMiLCJjbGFzc05hbWVzIiwicmVjb3ZlcnlLZXlGZWVkYmFjayIsIm9uUmVjb3ZlcnlLZXlOZXh0Iiwic3BlbGxDaGVjayIsIm9uUmVjb3ZlcnlLZXlDaGFuZ2UiLCJmb3JjZVZhbGlkaXR5IiwicmVjb3ZlcnlGaWxlIiwic2VjdXJpdHlLZXkiLCJyZWYiLCJjaHJvbWVGaWxlSW5wdXRGaXgiLCJvblJlY292ZXJ5S2V5RmlsZUNoYW5nZSIsIm9uUmVjb3ZlcnlLZXlGaWxlVXBsb2FkQ2xpY2siLCJjYW5jZWxCdXR0b24iLCJjYW5jZWxCdXR0b25DbGFzcyIsImV4cG9ydHMiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvY29tcG9uZW50cy92aWV3cy9kaWFsb2dzL3NlY3VyaXR5L0FjY2Vzc1NlY3JldFN0b3JhZ2VEaWFsb2cudHN4Il0sInNvdXJjZXNDb250ZW50IjpbIi8qXG5Db3B5cmlnaHQgMjAyNCBOZXcgVmVjdG9yIEx0ZC5cbkNvcHlyaWdodCAyMDE4LTIwMjEgVGhlIE1hdHJpeC5vcmcgRm91bmRhdGlvbiBDLkkuQy5cblxuU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFHUEwtMy4wLW9ubHkgT1IgR1BMLTMuMC1vbmx5XG5QbGVhc2Ugc2VlIExJQ0VOU0UgZmlsZXMgaW4gdGhlIHJlcG9zaXRvcnkgcm9vdCBmb3IgZnVsbCBkZXRhaWxzLlxuKi9cblxuaW1wb3J0IHsgZGVib3VuY2UgfSBmcm9tIFwibG9kYXNoXCI7XG5pbXBvcnQgY2xhc3NOYW1lcyBmcm9tIFwiY2xhc3NuYW1lc1wiO1xuaW1wb3J0IFJlYWN0LCB7IENoYW5nZUV2ZW50LCBGb3JtRXZlbnQgfSBmcm9tIFwicmVhY3RcIjtcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9sb2dnZXJcIjtcbmltcG9ydCB7IGRlY29kZVJlY292ZXJ5S2V5IH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL2NyeXB0by1hcGlcIjtcbmltcG9ydCB7IFNlY3JldFN0b3JhZ2UgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvbWF0cml4XCI7XG5cbmltcG9ydCB7IE1hdHJpeENsaWVudFBlZyB9IGZyb20gXCIuLi8uLi8uLi8uLi9NYXRyaXhDbGllbnRQZWdcIjtcbmltcG9ydCBGaWVsZCBmcm9tIFwiLi4vLi4vZWxlbWVudHMvRmllbGRcIjtcbmltcG9ydCBBY2Nlc3NpYmxlQnV0dG9uLCB7IEJ1dHRvbkV2ZW50IH0gZnJvbSBcIi4uLy4uL2VsZW1lbnRzL0FjY2Vzc2libGVCdXR0b25cIjtcbmltcG9ydCB7IF90IH0gZnJvbSBcIi4uLy4uLy4uLy4uL2xhbmd1YWdlSGFuZGxlclwiO1xuaW1wb3J0IHsgYWNjZXNzU2VjcmV0U3RvcmFnZSB9IGZyb20gXCIuLi8uLi8uLi8uLi9TZWN1cml0eU1hbmFnZXJcIjtcbmltcG9ydCBNb2RhbCBmcm9tIFwiLi4vLi4vLi4vLi4vTW9kYWxcIjtcbmltcG9ydCBJbnRlcmFjdGl2ZUF1dGhEaWFsb2cgZnJvbSBcIi4uL0ludGVyYWN0aXZlQXV0aERpYWxvZ1wiO1xuaW1wb3J0IERpYWxvZ0J1dHRvbnMgZnJvbSBcIi4uLy4uL2VsZW1lbnRzL0RpYWxvZ0J1dHRvbnNcIjtcbmltcG9ydCBCYXNlRGlhbG9nIGZyb20gXCIuLi9CYXNlRGlhbG9nXCI7XG5pbXBvcnQgeyBjaHJvbWVGaWxlSW5wdXRGaXggfSBmcm9tIFwiLi4vLi4vLi4vLi4vdXRpbHMvQnJvd3Nlcldvcmthcm91bmRzXCI7XG5cbi8vIE1heGltdW0gYWNjZXB0YWJsZSBzaXplIG9mIGEga2V5IGZpbGUuIEl0J3MgNTkgY2hhcmFjdGVycyBpbmNsdWRpbmcgdGhlIHNwYWNlcyB3ZSBlbmNvZGUsXG4vLyBzbyB0aGlzIHNob3VsZCBiZSBwbGVudHkgYW5kIGFsbG93IGZvciBwZW9wbGUgcHV0dGluZyBleHRyYSB3aGl0ZXNwYWNlIGluIHRoZSBmaWxlIGJlY2F1c2Vcbi8vIG1heWJlIHRoYXQncyBhIHRoaW5nIHBlb3BsZSB3b3VsZCBkbz9cbmNvbnN0IEtFWV9GSUxFX01BWF9TSVpFID0gMTI4O1xuXG4vLyBEb24ndCBzaG91dCBhdCB0aGUgdXNlciB0aGF0IHRoZWlyIGtleSBpcyBpbnZhbGlkIGV2ZXJ5IHRpbWUgdGhleSB0eXBlIGEga2V5OiB3YWl0IGEgc2hvcnQgdGltZVxuY29uc3QgVkFMSURBVElPTl9USFJPVFRMRV9NUyA9IDIwMDtcblxuZXhwb3J0IHR5cGUgS2V5UGFyYW1zID0geyBwYXNzcGhyYXNlPzogc3RyaW5nOyByZWNvdmVyeUtleT86IHN0cmluZyB9O1xuXG5pbnRlcmZhY2UgSVByb3BzIHtcbiAgICBrZXlJbmZvOiBTZWNyZXRTdG9yYWdlLlNlY3JldFN0b3JhZ2VLZXlEZXNjcmlwdGlvbjtcbiAgICBjaGVja1ByaXZhdGVLZXk6IChrOiBLZXlQYXJhbXMpID0+IFByb21pc2U8Ym9vbGVhbj47XG4gICAgb25GaW5pc2hlZChyZXN1bHQ/OiBmYWxzZSB8IEtleVBhcmFtcyk6IHZvaWQ7XG59XG5cbmludGVyZmFjZSBJU3RhdGUge1xuICAgIHJlY292ZXJ5S2V5OiBzdHJpbmc7XG4gICAgcmVjb3ZlcnlLZXlWYWxpZDogYm9vbGVhbiB8IG51bGw7XG4gICAgcmVjb3ZlcnlLZXlDb3JyZWN0OiBib29sZWFuIHwgbnVsbDtcbiAgICByZWNvdmVyeUtleUZpbGVFcnJvcjogYm9vbGVhbiB8IG51bGw7XG4gICAgZm9yY2VSZWNvdmVyeUtleTogYm9vbGVhbjtcbiAgICBwYXNzUGhyYXNlOiBzdHJpbmc7XG4gICAga2V5TWF0Y2hlczogYm9vbGVhbiB8IG51bGw7XG4gICAgcmVzZXR0aW5nOiBib29sZWFuO1xufVxuXG4vKlxuICogQWNjZXNzIFNlY3VyZSBTZWNyZXQgU3RvcmFnZSBieSByZXF1ZXN0aW5nIHRoZSB1c2VyJ3MgcGFzc3BocmFzZS5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQWNjZXNzU2VjcmV0U3RvcmFnZURpYWxvZyBleHRlbmRzIFJlYWN0LlB1cmVDb21wb25lbnQ8SVByb3BzLCBJU3RhdGU+IHtcbiAgICBwcml2YXRlIGZpbGVVcGxvYWQgPSBSZWFjdC5jcmVhdGVSZWY8SFRNTElucHV0RWxlbWVudD4oKTtcbiAgICBwcml2YXRlIGlucHV0UmVmID0gUmVhY3QuY3JlYXRlUmVmPEhUTUxJbnB1dEVsZW1lbnQ+KCk7XG5cbiAgICBwdWJsaWMgY29uc3RydWN0b3IocHJvcHM6IElQcm9wcykge1xuICAgICAgICBzdXBlcihwcm9wcyk7XG5cbiAgICAgICAgdGhpcy5zdGF0ZSA9IHtcbiAgICAgICAgICAgIHJlY292ZXJ5S2V5OiBcIlwiLFxuICAgICAgICAgICAgcmVjb3ZlcnlLZXlWYWxpZDogbnVsbCxcbiAgICAgICAgICAgIHJlY292ZXJ5S2V5Q29ycmVjdDogbnVsbCxcbiAgICAgICAgICAgIHJlY292ZXJ5S2V5RmlsZUVycm9yOiBudWxsLFxuICAgICAgICAgICAgZm9yY2VSZWNvdmVyeUtleTogZmFsc2UsXG4gICAgICAgICAgICBwYXNzUGhyYXNlOiBcIlwiLFxuICAgICAgICAgICAga2V5TWF0Y2hlczogbnVsbCxcbiAgICAgICAgICAgIHJlc2V0dGluZzogZmFsc2UsXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvbkNhbmNlbCA9ICgpOiB2b2lkID0+IHtcbiAgICAgICAgaWYgKHRoaXMuc3RhdGUucmVzZXR0aW5nKSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHsgcmVzZXR0aW5nOiBmYWxzZSB9KTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnByb3BzLm9uRmluaXNoZWQoZmFsc2UpO1xuICAgIH07XG5cbiAgICBwcml2YXRlIG9uVXNlUmVjb3ZlcnlLZXlDbGljayA9ICgpOiB2b2lkID0+IHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBmb3JjZVJlY292ZXJ5S2V5OiB0cnVlLFxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSB2YWxpZGF0ZVJlY292ZXJ5S2V5T25DaGFuZ2UgPSBkZWJvdW5jZShhc3luYyAoKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgIGF3YWl0IHRoaXMudmFsaWRhdGVSZWNvdmVyeUtleSgpO1xuICAgIH0sIFZBTElEQVRJT05fVEhST1RUTEVfTVMpO1xuXG4gICAgcHJpdmF0ZSBhc3luYyB2YWxpZGF0ZVJlY292ZXJ5S2V5KCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAodGhpcy5zdGF0ZS5yZWNvdmVyeUtleSA9PT0gXCJcIikge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgcmVjb3ZlcnlLZXlWYWxpZDogbnVsbCxcbiAgICAgICAgICAgICAgICByZWNvdmVyeUtleUNvcnJlY3Q6IG51bGwsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBjbGkgPSBNYXRyaXhDbGllbnRQZWcuc2FmZUdldCgpO1xuICAgICAgICAgICAgY29uc3QgZGVjb2RlZEtleSA9IGRlY29kZVJlY292ZXJ5S2V5KHRoaXMuc3RhdGUucmVjb3ZlcnlLZXkpO1xuICAgICAgICAgICAgY29uc3QgY29ycmVjdCA9IGF3YWl0IGNsaS5zZWNyZXRTdG9yYWdlLmNoZWNrS2V5KGRlY29kZWRLZXksIHRoaXMucHJvcHMua2V5SW5mbyk7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICByZWNvdmVyeUtleVZhbGlkOiB0cnVlLFxuICAgICAgICAgICAgICAgIHJlY292ZXJ5S2V5Q29ycmVjdDogY29ycmVjdCxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICByZWNvdmVyeUtleVZhbGlkOiBmYWxzZSxcbiAgICAgICAgICAgICAgICByZWNvdmVyeUtleUNvcnJlY3Q6IGZhbHNlLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIG9uUmVjb3ZlcnlLZXlDaGFuZ2UgPSAoZXY6IENoYW5nZUV2ZW50PEhUTUxJbnB1dEVsZW1lbnQ+KTogdm9pZCA9PiB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgcmVjb3ZlcnlLZXk6IGV2LnRhcmdldC52YWx1ZSxcbiAgICAgICAgICAgIHJlY292ZXJ5S2V5RmlsZUVycm9yOiBudWxsLFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBhbHNvIGNsZWFyIHRoZSBmaWxlIHVwbG9hZCBjb250cm9sIHNvIHRoYXQgdGhlIHVzZXIgY2FuIHVwbG9hZCB0aGUgc2FtZSBmaWxlXG4gICAgICAgIC8vIHRoZSBkaWQgYmVmb3JlIChvdGhlcndpc2UgdGhlIG9uY2hhbmdlIHdvdWxkbid0IGZpcmUpXG4gICAgICAgIGlmICh0aGlzLmZpbGVVcGxvYWQuY3VycmVudCkgdGhpcy5maWxlVXBsb2FkLmN1cnJlbnQudmFsdWUgPSBcIlwiO1xuXG4gICAgICAgIC8vIFdlIGRvbid0IHVzZSBGaWVsZCdzIHZhbGlkYXRpb24gaGVyZSBiZWNhdXNlIGEpIHdlIHdhbnQgaXQgaW4gYSBzZXBhcmF0ZSBwbGFjZSByYXRoZXJcbiAgICAgICAgLy8gdGhhbiBpbiBhIHRvb2x0aXAgYW5kIGIpIHdlIHdhbnQgaXQgdG8gZGlzcGxheSBmZWVkYmFjayBiYXNlZCBvbiB0aGUgdXBsb2FkZWQgZmlsZVxuICAgICAgICAvLyBhcyB3ZWxsIGFzIHRoZSB0ZXh0IGJveC4gSWRlYWxseSB3ZSB3b3VsZCByZWZhY3RvciBGaWVsZCdzIHZhbGlkYXRpb24gbG9naWMgc28gd2UgY291bGRcbiAgICAgICAgLy8gcmUtdXNlIHNvbWUgb2YgaXQuXG4gICAgICAgIHRoaXMudmFsaWRhdGVSZWNvdmVyeUtleU9uQ2hhbmdlKCk7XG4gICAgfTtcblxuICAgIHByaXZhdGUgb25SZWNvdmVyeUtleUZpbGVDaGFuZ2UgPSBhc3luYyAoZXY6IENoYW5nZUV2ZW50PEhUTUxJbnB1dEVsZW1lbnQ+KTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgIGlmICghZXYudGFyZ2V0LmZpbGVzPy5sZW5ndGgpIHJldHVybjtcblxuICAgICAgICBjb25zdCBmID0gZXYudGFyZ2V0LmZpbGVzWzBdO1xuXG4gICAgICAgIGlmIChmLnNpemUgPiBLRVlfRklMRV9NQVhfU0laRSkge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgcmVjb3ZlcnlLZXlGaWxlRXJyb3I6IHRydWUsXG4gICAgICAgICAgICAgICAgcmVjb3ZlcnlLZXlDb3JyZWN0OiBmYWxzZSxcbiAgICAgICAgICAgICAgICByZWNvdmVyeUtleVZhbGlkOiBmYWxzZSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc3QgY29udGVudHMgPSBhd2FpdCBmLnRleHQoKTtcbiAgICAgICAgICAgIC8vIHRlc3QgaXQncyB3aXRoaW4gdGhlIGJhc2U1OCBhbHBoYWJldC4gV2UgY291bGQgYmUgbW9yZSBzdHJpY3QgaGVyZSwgZWcuIHJlcXVpcmUgdGhlXG4gICAgICAgICAgICAvLyByaWdodCBudW1iZXIgb2YgY2hhcmFjdGVycywgYnV0IGl0J3MgcmVhbGx5IGp1c3QgdG8gbWFrZSBzdXJlIHRoYXQgd2hhdCB3ZSdyZSByZWFkaW5nIGlzXG4gICAgICAgICAgICAvLyB0ZXh0IGJlY2F1c2Ugd2UnbGwgcHV0IGl0IGluIHRoZSB0ZXh0IGZpZWxkLlxuICAgICAgICAgICAgaWYgKC9eWzEyMzQ1Njc4OUFCQ0RFRkdISktMTU5QUVJTVFVWV1hZWmFiY2RlZmdoaWprbW5vcHFyc3R1dnd4eXpcXHNdKyQvLnRlc3QoY29udGVudHMpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgICAgIHJlY292ZXJ5S2V5RmlsZUVycm9yOiBudWxsLFxuICAgICAgICAgICAgICAgICAgICByZWNvdmVyeUtleTogY29udGVudHMudHJpbSgpLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMudmFsaWRhdGVSZWNvdmVyeUtleSgpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICAgICAgcmVjb3ZlcnlLZXlGaWxlRXJyb3I6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgIHJlY292ZXJ5S2V5Q29ycmVjdDogZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgIHJlY292ZXJ5S2V5VmFsaWQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICByZWNvdmVyeUtleTogXCJcIixcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBwcml2YXRlIG9uUmVjb3ZlcnlLZXlGaWxlVXBsb2FkQ2xpY2sgPSAoKTogdm9pZCA9PiB7XG4gICAgICAgIHRoaXMuZmlsZVVwbG9hZC5jdXJyZW50Py5jbGljaygpO1xuICAgIH07XG5cbiAgICBwcml2YXRlIG9uUGFzc1BocmFzZU5leHQgPSBhc3luYyAoZXY6IEZvcm1FdmVudDxIVE1MRm9ybUVsZW1lbnQ+IHwgUmVhY3QuTW91c2VFdmVudCk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgICBldi5wcmV2ZW50RGVmYXVsdCgpO1xuXG4gICAgICAgIGlmICh0aGlzLnN0YXRlLnBhc3NQaHJhc2UubGVuZ3RoIDw9IDApIHtcbiAgICAgICAgICAgIHRoaXMuaW5wdXRSZWYuY3VycmVudD8uZm9jdXMoKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2V0U3RhdGUoeyBrZXlNYXRjaGVzOiBudWxsIH0pO1xuICAgICAgICBjb25zdCBpbnB1dCA9IHsgcGFzc3BocmFzZTogdGhpcy5zdGF0ZS5wYXNzUGhyYXNlIH07XG4gICAgICAgIGNvbnN0IGtleU1hdGNoZXMgPSBhd2FpdCB0aGlzLnByb3BzLmNoZWNrUHJpdmF0ZUtleShpbnB1dCk7XG4gICAgICAgIGlmIChrZXlNYXRjaGVzKSB7XG4gICAgICAgICAgICB0aGlzLnByb3BzLm9uRmluaXNoZWQoaW5wdXQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7IGtleU1hdGNoZXMgfSk7XG4gICAgICAgICAgICB0aGlzLmlucHV0UmVmLmN1cnJlbnQ/LmZvY3VzKCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBvblJlY292ZXJ5S2V5TmV4dCA9IGFzeW5jIChldjogRm9ybUV2ZW50PEhUTUxGb3JtRWxlbWVudD4gfCBSZWFjdC5Nb3VzZUV2ZW50KTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgIGV2LnByZXZlbnREZWZhdWx0KCk7XG5cbiAgICAgICAgaWYgKCF0aGlzLnN0YXRlLnJlY292ZXJ5S2V5VmFsaWQpIHJldHVybjtcblxuICAgICAgICB0aGlzLnNldFN0YXRlKHsga2V5TWF0Y2hlczogbnVsbCB9KTtcbiAgICAgICAgY29uc3QgaW5wdXQgPSB7IHJlY292ZXJ5S2V5OiB0aGlzLnN0YXRlLnJlY292ZXJ5S2V5IH07XG4gICAgICAgIGNvbnN0IGtleU1hdGNoZXMgPSBhd2FpdCB0aGlzLnByb3BzLmNoZWNrUHJpdmF0ZUtleShpbnB1dCk7XG4gICAgICAgIGlmIChrZXlNYXRjaGVzKSB7XG4gICAgICAgICAgICB0aGlzLnByb3BzLm9uRmluaXNoZWQoaW5wdXQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7IGtleU1hdGNoZXMgfSk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBvblBhc3NQaHJhc2VDaGFuZ2UgPSAoZXY6IENoYW5nZUV2ZW50PEhUTUxJbnB1dEVsZW1lbnQ+KTogdm9pZCA9PiB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgcGFzc1BocmFzZTogZXYudGFyZ2V0LnZhbHVlLFxuICAgICAgICAgICAga2V5TWF0Y2hlczogbnVsbCxcbiAgICAgICAgfSk7XG4gICAgfTtcblxuICAgIHByaXZhdGUgb25SZXNldEFsbENsaWNrID0gKGV2OiBCdXR0b25FdmVudCk6IHZvaWQgPT4ge1xuICAgICAgICBldi5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHsgcmVzZXR0aW5nOiB0cnVlIH0pO1xuICAgIH07XG5cbiAgICBwcml2YXRlIG9uQ29uZmlybVJlc2V0QWxsQ2xpY2sgPSBhc3luYyAoKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgIC8vIEhpZGUgb3Vyc2VsdmVzIHNvIHRoZSB1c2VyIGNhbiBpbnRlcmFjdCB3aXRoIHRoZSByZXNldCBkaWFsb2dzLlxuICAgICAgICAvLyBXZSBkb24ndCBjb25jbHVkZSB0aGUgcHJvbWlzZSBjaGFpbiAob25GaW5pc2hlZCkgeWV0IHRvIGF2b2lkIGNvbmZ1c2luZ1xuICAgICAgICAvLyBhbnkgdXBzdHJlYW0gY29kZSBmbG93cy5cbiAgICAgICAgLy9cbiAgICAgICAgLy8gTm90ZTogdGhpcyB3aWxsIHVubW91bnQgdXMsIHNvIGRvbid0IGNhbGwgYHNldFN0YXRlYCBvciBhbnl0aGluZyBpbiB0aGVcbiAgICAgICAgLy8gcmVzdCBvZiB0aGlzIGZ1bmN0aW9uLlxuICAgICAgICBNb2RhbC50b2dnbGVDdXJyZW50RGlhbG9nVmlzaWJpbGl0eSgpO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICAvLyBGb3JjZSByZXNldCBzZWNyZXQgc3RvcmFnZSAod2hpY2ggcmVzZXRzIHRoZSBrZXkgYmFja3VwKVxuICAgICAgICAgICAgYXdhaXQgYWNjZXNzU2VjcmV0U3RvcmFnZShhc3luYyAoKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgICAgICAgICAgLy8gTm93IHJlc2V0IGNyb3NzLXNpZ25pbmcgc28gZXZlcnl0aGluZyBKdXN0IFdvcmtz4oSiIGFnYWluLlxuICAgICAgICAgICAgICAgIGNvbnN0IGNsaSA9IE1hdHJpeENsaWVudFBlZy5zYWZlR2V0KCk7XG4gICAgICAgICAgICAgICAgYXdhaXQgY2xpLmJvb3RzdHJhcENyb3NzU2lnbmluZyh7XG4gICAgICAgICAgICAgICAgICAgIGF1dGhVcGxvYWREZXZpY2VTaWduaW5nS2V5czogYXN5bmMgKG1ha2VSZXF1ZXN0KTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB7IGZpbmlzaGVkIH0gPSBNb2RhbC5jcmVhdGVEaWFsb2coSW50ZXJhY3RpdmVBdXRoRGlhbG9nLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGU6IF90KFwiZW5jcnlwdGlvbnxib290c3RyYXBfdGl0bGVcIiksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF0cml4Q2xpZW50OiBjbGksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFrZVJlcXVlc3QsXG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IFtjb25maXJtZWRdID0gYXdhaXQgZmluaXNoZWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWNvbmZpcm1lZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkNyb3NzLXNpZ25pbmcga2V5IHVwbG9hZCBhdXRoIGNhbmNlbGVkXCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBzZXR1cE5ld0Nyb3NzU2lnbmluZzogdHJ1ZSxcbiAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgIC8vIE5vdyB3ZSBjYW4gaW5kaWNhdGUgdGhhdCB0aGUgdXNlciBpcyBkb25lIHByZXNzaW5nIGJ1dHRvbnMsIGZpbmFsbHkuXG4gICAgICAgICAgICAgICAgLy8gVXBzdHJlYW0gZmxvd3Mgd2lsbCBkZXRlY3QgdGhlIG5ldyBzZWNyZXQgc3RvcmFnZSwga2V5IGJhY2t1cCwgZXRjIGFuZCB1c2UgaXQuXG4gICAgICAgICAgICAgICAgdGhpcy5wcm9wcy5vbkZpbmlzaGVkKHt9KTtcbiAgICAgICAgICAgIH0sIHRydWUpO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBsb2dnZXIuZXJyb3IoZSk7XG4gICAgICAgICAgICB0aGlzLnByb3BzLm9uRmluaXNoZWQoZmFsc2UpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHByaXZhdGUgZ2V0S2V5VmFsaWRhdGlvblRleHQoKTogc3RyaW5nIHtcbiAgICAgICAgaWYgKHRoaXMuc3RhdGUucmVjb3ZlcnlLZXlGaWxlRXJyb3IpIHtcbiAgICAgICAgICAgIHJldHVybiBfdChcImVuY3J5cHRpb258YWNjZXNzX3NlY3JldF9zdG9yYWdlX2RpYWxvZ3xrZXlfdmFsaWRhdGlvbl90ZXh0fHdyb25nX2ZpbGVfdHlwZVwiKTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLnJlY292ZXJ5S2V5Q29ycmVjdCkge1xuICAgICAgICAgICAgcmV0dXJuIF90KFwiZW5jcnlwdGlvbnxhY2Nlc3Nfc2VjcmV0X3N0b3JhZ2VfZGlhbG9nfGtleV92YWxpZGF0aW9uX3RleHR8cmVjb3Zlcnlfa2V5X2lzX2NvcnJlY3RcIik7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5yZWNvdmVyeUtleVZhbGlkKSB7XG4gICAgICAgICAgICByZXR1cm4gX3QoXCJlbmNyeXB0aW9ufGFjY2Vzc19zZWNyZXRfc3RvcmFnZV9kaWFsb2d8a2V5X3ZhbGlkYXRpb25fdGV4dHx3cm9uZ19zZWN1cml0eV9rZXlcIik7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5yZWNvdmVyeUtleVZhbGlkID09PSBudWxsKSB7XG4gICAgICAgICAgICByZXR1cm4gXCJcIjtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBfdChcImVuY3J5cHRpb258YWNjZXNzX3NlY3JldF9zdG9yYWdlX2RpYWxvZ3xrZXlfdmFsaWRhdGlvbl90ZXh0fGludmFsaWRfc2VjdXJpdHlfa2V5XCIpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIHJlbmRlcigpOiBSZWFjdC5SZWFjdE5vZGUge1xuICAgICAgICBjb25zdCBoYXNQYXNzcGhyYXNlID0gdGhpcy5wcm9wcy5rZXlJbmZvPy5wYXNzcGhyYXNlPy5zYWx0ICYmIHRoaXMucHJvcHMua2V5SW5mbz8ucGFzc3BocmFzZT8uaXRlcmF0aW9ucztcblxuICAgICAgICBjb25zdCByZXNldExpbmUgPSAoXG4gICAgICAgICAgICA8c3Ryb25nIGNsYXNzTmFtZT1cIm14X0FjY2Vzc1NlY3JldFN0b3JhZ2VEaWFsb2dfcmVzZXRcIj5cbiAgICAgICAgICAgICAgICB7X3QoXCJlbmNyeXB0aW9ufHJlc2V0X2FsbF9idXR0b25cIiwgdW5kZWZpbmVkLCB7XG4gICAgICAgICAgICAgICAgICAgIGE6IChzdWIpID0+IChcbiAgICAgICAgICAgICAgICAgICAgICAgIDxBY2Nlc3NpYmxlQnV0dG9uXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAga2luZD1cImxpbmtfaW5saW5lXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbkNsaWNrPXt0aGlzLm9uUmVzZXRBbGxDbGlja31cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGFzc05hbWU9XCJteF9BY2Nlc3NTZWNyZXRTdG9yYWdlRGlhbG9nX3Jlc2V0X2xpbmtcIlxuICAgICAgICAgICAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtzdWJ9XG4gICAgICAgICAgICAgICAgICAgICAgICA8L0FjY2Vzc2libGVCdXR0b24+XG4gICAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgfSl9XG4gICAgICAgICAgICA8L3N0cm9uZz5cbiAgICAgICAgKTtcblxuICAgICAgICBsZXQgY29udGVudDtcbiAgICAgICAgbGV0IHRpdGxlO1xuICAgICAgICBsZXQgdGl0bGVDbGFzcztcbiAgICAgICAgaWYgKHRoaXMuc3RhdGUucmVzZXR0aW5nKSB7XG4gICAgICAgICAgICB0aXRsZSA9IF90KFwiZW5jcnlwdGlvbnxhY2Nlc3Nfc2VjcmV0X3N0b3JhZ2VfZGlhbG9nfHJlc2V0X3RpdGxlXCIpO1xuICAgICAgICAgICAgdGl0bGVDbGFzcyA9IFtcIm14X0FjY2Vzc1NlY3JldFN0b3JhZ2VEaWFsb2dfdGl0bGVXaXRoSWNvbiBteF9BY2Nlc3NTZWNyZXRTdG9yYWdlRGlhbG9nX3Jlc2V0QmFkZ2VcIl07XG4gICAgICAgICAgICBjb250ZW50ID0gKFxuICAgICAgICAgICAgICAgIDxkaXY+XG4gICAgICAgICAgICAgICAgICAgIDxwPntfdChcImVuY3J5cHRpb258YWNjZXNzX3NlY3JldF9zdG9yYWdlX2RpYWxvZ3xyZXNldF93YXJuaW5nXzFcIil9PC9wPlxuICAgICAgICAgICAgICAgICAgICA8cD57X3QoXCJlbmNyeXB0aW9ufGFjY2Vzc19zZWNyZXRfc3RvcmFnZV9kaWFsb2d8cmVzZXRfd2FybmluZ18yXCIpfTwvcD5cbiAgICAgICAgICAgICAgICAgICAgPERpYWxvZ0J1dHRvbnNcbiAgICAgICAgICAgICAgICAgICAgICAgIHByaW1hcnlCdXR0b249e190KFwiYWN0aW9ufHJlc2V0XCIpfVxuICAgICAgICAgICAgICAgICAgICAgICAgb25QcmltYXJ5QnV0dG9uQ2xpY2s9e3RoaXMub25Db25maXJtUmVzZXRBbGxDbGlja31cbiAgICAgICAgICAgICAgICAgICAgICAgIGhhc0NhbmNlbD17dHJ1ZX1cbiAgICAgICAgICAgICAgICAgICAgICAgIG9uQ2FuY2VsPXt0aGlzLm9uQ2FuY2VsfVxuICAgICAgICAgICAgICAgICAgICAgICAgZm9jdXM9e2ZhbHNlfVxuICAgICAgICAgICAgICAgICAgICAgICAgcHJpbWFyeUJ1dHRvbkNsYXNzPVwiZGFuZ2VyXCJcbiAgICAgICAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSBpZiAoaGFzUGFzc3BocmFzZSAmJiAhdGhpcy5zdGF0ZS5mb3JjZVJlY292ZXJ5S2V5KSB7XG4gICAgICAgICAgICB0aXRsZSA9IF90KFwiZW5jcnlwdGlvbnxhY2Nlc3Nfc2VjcmV0X3N0b3JhZ2VfZGlhbG9nfHNlY3VyaXR5X3BocmFzZV90aXRsZVwiKTtcbiAgICAgICAgICAgIHRpdGxlQ2xhc3MgPSBbXCJteF9BY2Nlc3NTZWNyZXRTdG9yYWdlRGlhbG9nX3RpdGxlV2l0aEljb24gbXhfQWNjZXNzU2VjcmV0U3RvcmFnZURpYWxvZ19zZWN1cmVQaHJhc2VUaXRsZVwiXTtcblxuICAgICAgICAgICAgbGV0IGtleVN0YXR1cztcbiAgICAgICAgICAgIGlmICh0aGlzLnN0YXRlLmtleU1hdGNoZXMgPT09IGZhbHNlKSB7XG4gICAgICAgICAgICAgICAga2V5U3RhdHVzID0gKFxuICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cIm14X0FjY2Vzc1NlY3JldFN0b3JhZ2VEaWFsb2dfa2V5U3RhdHVzXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICB7XCJcXHVEODNEXFx1REM0RSBcIn1cbiAgICAgICAgICAgICAgICAgICAgICAgIHtfdChcImVuY3J5cHRpb258YWNjZXNzX3NlY3JldF9zdG9yYWdlX2RpYWxvZ3xzZWN1cml0eV9waHJhc2VfaW5jb3JyZWN0X2Vycm9yXCIpfVxuICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBrZXlTdGF0dXMgPSA8ZGl2IGNsYXNzTmFtZT1cIm14X0FjY2Vzc1NlY3JldFN0b3JhZ2VEaWFsb2dfa2V5U3RhdHVzXCIgLz47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnRlbnQgPSAoXG4gICAgICAgICAgICAgICAgPGRpdj5cbiAgICAgICAgICAgICAgICAgICAgPHA+XG4gICAgICAgICAgICAgICAgICAgICAgICB7X3QoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJlbmNyeXB0aW9ufGFjY2Vzc19zZWNyZXRfc3RvcmFnZV9kaWFsb2d8ZW50ZXJfcGhyYXNlX29yX2tleV9wcm9tcHRcIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7fSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ1dHRvbjogKHMpID0+IChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxBY2Nlc3NpYmxlQnV0dG9uIGtpbmQ9XCJsaW5rX2lubGluZVwiIG9uQ2xpY2s9e3RoaXMub25Vc2VSZWNvdmVyeUtleUNsaWNrfT5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7c31cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvQWNjZXNzaWJsZUJ1dHRvbj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgKX1cbiAgICAgICAgICAgICAgICAgICAgPC9wPlxuXG4gICAgICAgICAgICAgICAgICAgIDxmb3JtIGNsYXNzTmFtZT1cIm14X0FjY2Vzc1NlY3JldFN0b3JhZ2VEaWFsb2dfcHJpbWFyeUNvbnRhaW5lclwiIG9uU3VibWl0PXt0aGlzLm9uUGFzc1BocmFzZU5leHR9PlxuICAgICAgICAgICAgICAgICAgICAgICAgPEZpZWxkXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5wdXRSZWY9e3RoaXMuaW5wdXRSZWZ9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWQ9XCJteF9wYXNzUGhyYXNlSW5wdXRcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzTmFtZT1cIm14X0FjY2Vzc1NlY3JldFN0b3JhZ2VEaWFsb2dfcGFzc1BocmFzZUlucHV0XCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlPVwicGFzc3dvcmRcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPXtfdChcImVuY3J5cHRpb258YWNjZXNzX3NlY3JldF9zdG9yYWdlX2RpYWxvZ3xzZWN1cml0eV9waHJhc2VfdGl0bGVcIil9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU9e3RoaXMuc3RhdGUucGFzc1BocmFzZX1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbkNoYW5nZT17dGhpcy5vblBhc3NQaHJhc2VDaGFuZ2V9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYXV0b0ZvY3VzPXt0cnVlfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF1dG9Db21wbGV0ZT1cIm5ldy1wYXNzd29yZFwiXG4gICAgICAgICAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICAgICAgICAgICAge2tleVN0YXR1c31cbiAgICAgICAgICAgICAgICAgICAgICAgIDxEaWFsb2dCdXR0b25zXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpbWFyeUJ1dHRvbj17X3QoXCJhY3Rpb258Y29udGludWVcIil9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb25QcmltYXJ5QnV0dG9uQ2xpY2s9e3RoaXMub25QYXNzUGhyYXNlTmV4dH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBoYXNDYW5jZWw9e3RydWV9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb25DYW5jZWw9e3RoaXMub25DYW5jZWx9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9jdXM9e2ZhbHNlfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByaW1hcnlEaXNhYmxlZD17dGhpcy5zdGF0ZS5wYXNzUGhyYXNlLmxlbmd0aCA9PT0gMH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZGRpdGl2ZT17cmVzZXRMaW5lfVxuICAgICAgICAgICAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAgICAgICAgPC9mb3JtPlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRpdGxlID0gX3QoXCJlbmNyeXB0aW9ufGFjY2Vzc19zZWNyZXRfc3RvcmFnZV9kaWFsb2d8c2VjdXJpdHlfa2V5X3RpdGxlXCIpO1xuICAgICAgICAgICAgdGl0bGVDbGFzcyA9IFtcIm14X0FjY2Vzc1NlY3JldFN0b3JhZ2VEaWFsb2dfdGl0bGVXaXRoSWNvbiBteF9BY2Nlc3NTZWNyZXRTdG9yYWdlRGlhbG9nX3NlY3VyZUJhY2t1cFRpdGxlXCJdO1xuXG4gICAgICAgICAgICBjb25zdCBmZWVkYmFja0NsYXNzZXMgPSBjbGFzc05hbWVzKHtcbiAgICAgICAgICAgICAgICBcIm14X0FjY2Vzc1NlY3JldFN0b3JhZ2VEaWFsb2dfcmVjb3ZlcnlLZXlGZWVkYmFja1wiOiB0cnVlLFxuICAgICAgICAgICAgICAgIFwibXhfQWNjZXNzU2VjcmV0U3RvcmFnZURpYWxvZ19yZWNvdmVyeUtleUZlZWRiYWNrLS12YWxpZFwiOiB0aGlzLnN0YXRlLnJlY292ZXJ5S2V5Q29ycmVjdCA9PT0gdHJ1ZSxcbiAgICAgICAgICAgICAgICBcIm14X0FjY2Vzc1NlY3JldFN0b3JhZ2VEaWFsb2dfcmVjb3ZlcnlLZXlGZWVkYmFjay0taW52YWxpZFwiOiB0aGlzLnN0YXRlLnJlY292ZXJ5S2V5Q29ycmVjdCA9PT0gZmFsc2UsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGNvbnN0IHJlY292ZXJ5S2V5RmVlZGJhY2sgPSA8ZGl2IGNsYXNzTmFtZT17ZmVlZGJhY2tDbGFzc2VzfT57dGhpcy5nZXRLZXlWYWxpZGF0aW9uVGV4dCgpfTwvZGl2PjtcblxuICAgICAgICAgICAgY29udGVudCA9IChcbiAgICAgICAgICAgICAgICA8ZGl2PlxuICAgICAgICAgICAgICAgICAgICA8cD57X3QoXCJlbmNyeXB0aW9ufGFjY2Vzc19zZWNyZXRfc3RvcmFnZV9kaWFsb2d8dXNlX3NlY3VyaXR5X2tleV9wcm9tcHRcIil9PC9wPlxuXG4gICAgICAgICAgICAgICAgICAgIDxmb3JtXG4gICAgICAgICAgICAgICAgICAgICAgICBjbGFzc05hbWU9XCJteF9BY2Nlc3NTZWNyZXRTdG9yYWdlRGlhbG9nX3ByaW1hcnlDb250YWluZXJcIlxuICAgICAgICAgICAgICAgICAgICAgICAgb25TdWJtaXQ9e3RoaXMub25SZWNvdmVyeUtleU5leHR9XG4gICAgICAgICAgICAgICAgICAgICAgICBzcGVsbENoZWNrPXtmYWxzZX1cbiAgICAgICAgICAgICAgICAgICAgICAgIGF1dG9Db21wbGV0ZT1cIm9mZlwiXG4gICAgICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPVwibXhfQWNjZXNzU2VjcmV0U3RvcmFnZURpYWxvZ19yZWNvdmVyeUtleUVudHJ5XCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJteF9BY2Nlc3NTZWNyZXRTdG9yYWdlRGlhbG9nX3JlY292ZXJ5S2V5RW50cnlfdGV4dElucHV0XCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxGaWVsZFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZT1cInBhc3N3b3JkXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlkPVwibXhfc2VjdXJpdHlLZXlcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWw9e190KFwiZW5jcnlwdGlvbnxhY2Nlc3Nfc2VjcmV0X3N0b3JhZ2VfZGlhbG9nfHNlY3VyaXR5X2tleV90aXRsZVwiKX1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPXt0aGlzLnN0YXRlLnJlY292ZXJ5S2V5fVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb25DaGFuZ2U9e3RoaXMub25SZWNvdmVyeUtleUNoYW5nZX1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF1dG9Gb2N1cz17dHJ1ZX1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcmNlVmFsaWRpdHk9e3RoaXMuc3RhdGUucmVjb3ZlcnlLZXlDb3JyZWN0ID8/IHVuZGVmaW5lZH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF1dG9Db21wbGV0ZT1cIm9mZlwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3NOYW1lPVwibXhfQWNjZXNzU2VjcmV0U3RvcmFnZURpYWxvZ19yZWNvdmVyeUtleUVudHJ5X2VudHJ5Q29udHJvbFNlcGFyYXRvclRleHRcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge190KFwiZW5jcnlwdGlvbnxhY2Nlc3Nfc2VjcmV0X3N0b3JhZ2VfZGlhbG9nfHNlcGFyYXRvclwiLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWNvdmVyeUZpbGU6IFwiXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWN1cml0eUtleTogXCJcIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSl9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXY+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZT1cImZpbGVcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3NOYW1lPVwibXhfQWNjZXNzU2VjcmV0U3RvcmFnZURpYWxvZ19yZWNvdmVyeUtleUVudHJ5X2ZpbGVJbnB1dFwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWY9e3RoaXMuZmlsZVVwbG9hZH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uQ2xpY2s9e2Nocm9tZUZpbGVJbnB1dEZpeH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uQ2hhbmdlPXt0aGlzLm9uUmVjb3ZlcnlLZXlGaWxlQ2hhbmdlfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8QWNjZXNzaWJsZUJ1dHRvbiBraW5kPVwicHJpbWFyeVwiIG9uQ2xpY2s9e3RoaXMub25SZWNvdmVyeUtleUZpbGVVcGxvYWRDbGlja30+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7X3QoXCJhY3Rpb258dXBsb2FkXCIpfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L0FjY2Vzc2libGVCdXR0b24+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgICAgIHtyZWNvdmVyeUtleUZlZWRiYWNrfVxuICAgICAgICAgICAgICAgICAgICAgICAgPERpYWxvZ0J1dHRvbnNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmltYXJ5QnV0dG9uPXtfdChcImFjdGlvbnxjb250aW51ZVwiKX1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvblByaW1hcnlCdXR0b25DbGljaz17dGhpcy5vblJlY292ZXJ5S2V5TmV4dH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBoYXNDYW5jZWw9e3RydWV9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FuY2VsQnV0dG9uPXtfdChcImFjdGlvbnxnb19iYWNrXCIpfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhbmNlbEJ1dHRvbkNsYXNzPVwid2FybmluZ1wiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb25DYW5jZWw9e3RoaXMub25DYW5jZWx9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9jdXM9e2ZhbHNlfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByaW1hcnlEaXNhYmxlZD17IXRoaXMuc3RhdGUucmVjb3ZlcnlLZXlWYWxpZH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZGRpdGl2ZT17cmVzZXRMaW5lfVxuICAgICAgICAgICAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAgICAgICAgPC9mb3JtPlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICA8QmFzZURpYWxvZ1xuICAgICAgICAgICAgICAgIGNsYXNzTmFtZT1cIm14X0FjY2Vzc1NlY3JldFN0b3JhZ2VEaWFsb2dcIlxuICAgICAgICAgICAgICAgIG9uRmluaXNoZWQ9e3RoaXMucHJvcHMub25GaW5pc2hlZH1cbiAgICAgICAgICAgICAgICB0aXRsZT17dGl0bGV9XG4gICAgICAgICAgICAgICAgdGl0bGVDbGFzcz17dGl0bGVDbGFzc31cbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICA8ZGl2Pntjb250ZW50fTwvZGl2PlxuICAgICAgICAgICAgPC9CYXNlRGlhbG9nPlxuICAgICAgICApO1xuICAgIH1cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7QUFRQSxJQUFBQSxPQUFBLEdBQUFDLE9BQUE7QUFDQSxJQUFBQyxXQUFBLEdBQUFDLHNCQUFBLENBQUFGLE9BQUE7QUFDQSxJQUFBRyxNQUFBLEdBQUFELHNCQUFBLENBQUFGLE9BQUE7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