UNPKG

matrix-react-sdk

Version:
392 lines (389 loc) 62.1 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 _react = _interopRequireDefault(require("react")); var _matrix = require("matrix-js-sdk/src/matrix"); var _cryptoApi = require("matrix-js-sdk/src/crypto-api"); var _logger = require("matrix-js-sdk/src/logger"); var _MatrixClientPeg = require("../../../../MatrixClientPeg"); var _languageHandler = require("../../../../languageHandler"); var _SecurityManager = require("../../../../SecurityManager"); var _Spinner = _interopRequireDefault(require("../../elements/Spinner")); var _DialogButtons = _interopRequireDefault(require("../../elements/DialogButtons")); var _AccessibleButton = _interopRequireDefault(require("../../elements/AccessibleButton")); var _BaseDialog = _interopRequireDefault(require("../BaseDialog")); /* Copyright 2024 New Vector Ltd. Copyright 2020 The Matrix.org Foundation C.I.C. Copyright 2018, 2019 New Vector Ltd SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ var RestoreType = /*#__PURE__*/function (RestoreType) { RestoreType["Passphrase"] = "passphrase"; RestoreType["RecoveryKey"] = "recovery_key"; RestoreType["SecretStorage"] = "secret_storage"; return RestoreType; }(RestoreType || {}); var ProgressState = /*#__PURE__*/function (ProgressState) { ProgressState["PreFetch"] = "prefetch"; ProgressState["Fetch"] = "fetch"; ProgressState["LoadKeys"] = "load_keys"; return ProgressState; }(ProgressState || {}); /* * Dialog for restoring e2e keys from a backup and the user's recovery key */ class RestoreKeyBackupDialog extends _react.default.PureComponent { constructor(props) { super(props); (0, _defineProperty2.default)(this, "onCancel", () => { this.props.onFinished(false); }); (0, _defineProperty2.default)(this, "onDone", () => { this.props.onFinished(true); }); (0, _defineProperty2.default)(this, "onUseRecoveryKeyClick", () => { this.setState({ forceRecoveryKey: true }); }); (0, _defineProperty2.default)(this, "progressCallback", data => { this.setState({ progress: data }); }); (0, _defineProperty2.default)(this, "onResetRecoveryClick", () => { this.props.onFinished(false); (0, _SecurityManager.accessSecretStorage)(async () => {}, /* forceReset = */true); }); (0, _defineProperty2.default)(this, "onRecoveryKeyChange", e => { this.setState({ recoveryKey: e.target.value, recoveryKeyValid: this.isValidRecoveryKey(e.target.value) }); }); (0, _defineProperty2.default)(this, "onPassPhraseNext", async () => { if (!this.state.backupInfo) return; this.setState({ loading: true, restoreError: null, restoreType: RestoreType.Passphrase }); try { // We do still restore the key backup: we must ensure that the key backup key // is the right one and restoring it is currently the only way we can do this. const recoverInfo = await _MatrixClientPeg.MatrixClientPeg.safeGet().restoreKeyBackupWithPassword(this.state.passPhrase, undefined, undefined, this.state.backupInfo, { progressCallback: this.progressCallback }); if (this.props.keyCallback) { const key = await _MatrixClientPeg.MatrixClientPeg.safeGet().keyBackupKeyFromPassword(this.state.passPhrase, this.state.backupInfo); this.props.keyCallback(key); } if (!this.props.showSummary) { this.props.onFinished(true); return; } this.setState({ loading: false, recoverInfo }); } catch (e) { _logger.logger.log("Error restoring backup", e); this.setState({ loading: false, restoreError: e }); } }); (0, _defineProperty2.default)(this, "onRecoveryKeyNext", async () => { if (!this.state.recoveryKeyValid || !this.state.backupInfo) return; this.setState({ loading: true, restoreError: null, restoreType: RestoreType.RecoveryKey }); try { const recoverInfo = await _MatrixClientPeg.MatrixClientPeg.safeGet().restoreKeyBackupWithRecoveryKey(this.state.recoveryKey, undefined, undefined, this.state.backupInfo, { progressCallback: this.progressCallback }); if (this.props.keyCallback) { const key = (0, _cryptoApi.decodeRecoveryKey)(this.state.recoveryKey); this.props.keyCallback(key); } if (!this.props.showSummary) { this.props.onFinished(true); return; } this.setState({ loading: false, recoverInfo }); } catch (e) { _logger.logger.log("Error restoring backup", e); this.setState({ loading: false, restoreError: e }); } }); (0, _defineProperty2.default)(this, "onPassPhraseChange", e => { this.setState({ passPhrase: e.target.value }); }); this.state = { backupInfo: null, backupKeyStored: null, loading: false, loadError: null, restoreError: null, recoveryKey: "", recoverInfo: null, recoveryKeyValid: false, forceRecoveryKey: false, passPhrase: "", restoreType: null, progress: { stage: ProgressState.PreFetch } }; } componentDidMount() { this.loadBackupStatus(); } /** * Check if the recovery key is valid * @param recoveryKey * @private */ isValidRecoveryKey(recoveryKey) { try { (0, _cryptoApi.decodeRecoveryKey)(recoveryKey); return true; } catch (e) { return false; } } async restoreWithSecretStorage() { this.setState({ loading: true, restoreError: null, restoreType: RestoreType.SecretStorage }); try { // `accessSecretStorage` may prompt for storage access as needed. await (0, _SecurityManager.accessSecretStorage)(async () => { if (!this.state.backupInfo) return; await _MatrixClientPeg.MatrixClientPeg.safeGet().restoreKeyBackupWithSecretStorage(this.state.backupInfo, undefined, undefined, { progressCallback: this.progressCallback }); }); this.setState({ loading: false }); } catch (e) { _logger.logger.log("Error restoring backup", e); this.setState({ restoreError: e, loading: false }); } } async restoreWithCachedKey(backupInfo) { if (!backupInfo) return false; try { const recoverInfo = await _MatrixClientPeg.MatrixClientPeg.safeGet().restoreKeyBackupWithCache(undefined /* targetRoomId */, undefined /* targetSessionId */, backupInfo, { progressCallback: this.progressCallback }); this.setState({ recoverInfo }); return true; } catch (e) { _logger.logger.log("restoreWithCachedKey failed:", e); return false; } } async loadBackupStatus() { this.setState({ loading: true, loadError: null }); try { const cli = _MatrixClientPeg.MatrixClientPeg.safeGet(); const backupInfo = await cli.getKeyBackupVersion(); const has4S = await cli.hasSecretStorageKey(); const backupKeyStored = has4S ? await cli.isKeyBackupKeyStored() : null; this.setState({ backupInfo, backupKeyStored }); const gotCache = await this.restoreWithCachedKey(backupInfo); if (gotCache) { _logger.logger.log("RestoreKeyBackupDialog: found cached backup key"); this.setState({ loading: false }); return; } // If the backup key is stored, we can proceed directly to restore. if (backupKeyStored) { return this.restoreWithSecretStorage(); } this.setState({ loadError: null, loading: false }); } catch (e) { _logger.logger.log("Error loading backup status", e); this.setState({ loadError: true, loading: false }); } } render() { const backupHasPassphrase = this.state.backupInfo && this.state.backupInfo.auth_data && this.state.backupInfo.auth_data.private_key_salt && this.state.backupInfo.auth_data.private_key_iterations; let content; let title; if (this.state.loading) { title = (0, _languageHandler._t)("encryption|access_secret_storage_dialog|restoring"); let details; if (this.state.progress.stage === ProgressState.Fetch) { details = (0, _languageHandler._t)("restore_key_backup_dialog|key_fetch_in_progress"); } else if (this.state.progress.stage === ProgressState.LoadKeys) { const { total, successes, failures } = this.state.progress; details = (0, _languageHandler._t)("restore_key_backup_dialog|load_keys_progress", { total, completed: (successes ?? 0) + (failures ?? 0) }); } else if (this.state.progress.stage === ProgressState.PreFetch) { details = (0, _languageHandler._t)("restore_key_backup_dialog|key_fetch_in_progress"); } content = /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("div", null, details), /*#__PURE__*/_react.default.createElement(_Spinner.default, null)); } else if (this.state.loadError) { title = (0, _languageHandler._t)("common|error"); content = (0, _languageHandler._t)("restore_key_backup_dialog|load_error_content"); } else if (this.state.restoreError) { if (this.state.restoreError instanceof _matrix.MatrixError && this.state.restoreError.errcode === _matrix.MatrixClient.RESTORE_BACKUP_ERROR_BAD_KEY) { if (this.state.restoreType === RestoreType.RecoveryKey) { title = (0, _languageHandler._t)("restore_key_backup_dialog|recovery_key_mismatch_title"); content = /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("restore_key_backup_dialog|recovery_key_mismatch_description"))); } else { title = (0, _languageHandler._t)("restore_key_backup_dialog|incorrect_security_phrase_title"); content = /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("restore_key_backup_dialog|incorrect_security_phrase_dialog"))); } } else { title = (0, _languageHandler._t)("common|error"); content = (0, _languageHandler._t)("restore_key_backup_dialog|restore_failed_error"); } } else if (this.state.backupInfo === null) { title = (0, _languageHandler._t)("common|error"); content = (0, _languageHandler._t)("restore_key_backup_dialog|no_backup_error"); } else if (this.state.recoverInfo) { title = (0, _languageHandler._t)("restore_key_backup_dialog|keys_restored_title"); let failedToDecrypt; if (this.state.recoverInfo.total > this.state.recoverInfo.imported) { failedToDecrypt = /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("restore_key_backup_dialog|count_of_decryption_failures", { failedCount: this.state.recoverInfo.total - this.state.recoverInfo.imported })); } content = /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("restore_key_backup_dialog|count_of_successfully_restored_keys", { sessionCount: this.state.recoverInfo.imported })), failedToDecrypt, /*#__PURE__*/_react.default.createElement(_DialogButtons.default, { primaryButton: (0, _languageHandler._t)("action|ok"), onPrimaryButtonClick: this.onDone, hasCancel: false, focus: true })); } else if (backupHasPassphrase && !this.state.forceRecoveryKey) { title = (0, _languageHandler._t)("restore_key_backup_dialog|enter_phrase_title"); content = /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("restore_key_backup_dialog|key_backup_warning", {}, { b: sub => /*#__PURE__*/_react.default.createElement("strong", null, sub) })), /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("restore_key_backup_dialog|enter_phrase_description")), /*#__PURE__*/_react.default.createElement("form", { className: "mx_RestoreKeyBackupDialog_primaryContainer" }, /*#__PURE__*/_react.default.createElement("input", { type: "password", className: "mx_RestoreKeyBackupDialog_passPhraseInput", onChange: this.onPassPhraseChange, value: this.state.passPhrase, autoFocus: true }), /*#__PURE__*/_react.default.createElement(_DialogButtons.default, { primaryButton: (0, _languageHandler._t)("action|next"), onPrimaryButtonClick: this.onPassPhraseNext, primaryIsSubmit: true, hasCancel: true, onCancel: this.onCancel, focus: false })), (0, _languageHandler._t)("restore_key_backup_dialog|phrase_forgotten_text", {}, { button1: s => /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { kind: "link_inline", onClick: this.onUseRecoveryKeyClick }, s), button2: s => /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { kind: "link_inline", onClick: this.onResetRecoveryClick }, s) })); } else { title = (0, _languageHandler._t)("restore_key_backup_dialog|enter_key_title"); let keyStatus; if (this.state.recoveryKey.length === 0) { keyStatus = /*#__PURE__*/_react.default.createElement("div", { className: "mx_RestoreKeyBackupDialog_keyStatus" }); } else if (this.state.recoveryKeyValid) { keyStatus = /*#__PURE__*/_react.default.createElement("div", { className: "mx_RestoreKeyBackupDialog_keyStatus" }, "\uD83D\uDC4D ", (0, _languageHandler._t)("restore_key_backup_dialog|key_is_valid")); } else { keyStatus = /*#__PURE__*/_react.default.createElement("div", { className: "mx_RestoreKeyBackupDialog_keyStatus" }, "\uD83D\uDC4E ", (0, _languageHandler._t)("restore_key_backup_dialog|key_is_invalid")); } content = /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("restore_key_backup_dialog|key_backup_warning", {}, { b: sub => /*#__PURE__*/_react.default.createElement("strong", null, sub) })), /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("restore_key_backup_dialog|enter_key_description")), /*#__PURE__*/_react.default.createElement("div", { className: "mx_RestoreKeyBackupDialog_primaryContainer" }, /*#__PURE__*/_react.default.createElement("input", { className: "mx_RestoreKeyBackupDialog_recoveryKeyInput", onChange: this.onRecoveryKeyChange, value: this.state.recoveryKey, autoFocus: true }), keyStatus, /*#__PURE__*/_react.default.createElement(_DialogButtons.default, { primaryButton: (0, _languageHandler._t)("action|next"), onPrimaryButtonClick: this.onRecoveryKeyNext, hasCancel: true, onCancel: this.onCancel, focus: false, primaryDisabled: !this.state.recoveryKeyValid })), (0, _languageHandler._t)("restore_key_backup_dialog|key_forgotten_text", {}, { button: s => /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { kind: "link_inline", onClick: this.onResetRecoveryClick }, s) })); } return /*#__PURE__*/_react.default.createElement(_BaseDialog.default, { className: "mx_RestoreKeyBackupDialog", onFinished: this.props.onFinished, title: title }, /*#__PURE__*/_react.default.createElement("div", { className: "mx_RestoreKeyBackupDialog_content" }, content)); } } exports.default = RestoreKeyBackupDialog; (0, _defineProperty2.default)(RestoreKeyBackupDialog, "defaultProps", { showSummary: true }); //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVhY3QiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIl9tYXRyaXgiLCJfY3J5cHRvQXBpIiwiX2xvZ2dlciIsIl9NYXRyaXhDbGllbnRQZWciLCJfbGFuZ3VhZ2VIYW5kbGVyIiwiX1NlY3VyaXR5TWFuYWdlciIsIl9TcGlubmVyIiwiX0RpYWxvZ0J1dHRvbnMiLCJfQWNjZXNzaWJsZUJ1dHRvbiIsIl9CYXNlRGlhbG9nIiwiUmVzdG9yZVR5cGUiLCJQcm9ncmVzc1N0YXRlIiwiUmVzdG9yZUtleUJhY2t1cERpYWxvZyIsIlJlYWN0IiwiUHVyZUNvbXBvbmVudCIsImNvbnN0cnVjdG9yIiwicHJvcHMiLCJfZGVmaW5lUHJvcGVydHkyIiwiZGVmYXVsdCIsIm9uRmluaXNoZWQiLCJzZXRTdGF0ZSIsImZvcmNlUmVjb3ZlcnlLZXkiLCJkYXRhIiwicHJvZ3Jlc3MiLCJhY2Nlc3NTZWNyZXRTdG9yYWdlIiwiZSIsInJlY292ZXJ5S2V5IiwidGFyZ2V0IiwidmFsdWUiLCJyZWNvdmVyeUtleVZhbGlkIiwiaXNWYWxpZFJlY292ZXJ5S2V5Iiwic3RhdGUiLCJiYWNrdXBJbmZvIiwibG9hZGluZyIsInJlc3RvcmVFcnJvciIsInJlc3RvcmVUeXBlIiwiUGFzc3BocmFzZSIsInJlY292ZXJJbmZvIiwiTWF0cml4Q2xpZW50UGVnIiwic2FmZUdldCIsInJlc3RvcmVLZXlCYWNrdXBXaXRoUGFzc3dvcmQiLCJwYXNzUGhyYXNlIiwidW5kZWZpbmVkIiwicHJvZ3Jlc3NDYWxsYmFjayIsImtleUNhbGxiYWNrIiwia2V5Iiwia2V5QmFja3VwS2V5RnJvbVBhc3N3b3JkIiwic2hvd1N1bW1hcnkiLCJsb2dnZXIiLCJsb2ciLCJSZWNvdmVyeUtleSIsInJlc3RvcmVLZXlCYWNrdXBXaXRoUmVjb3ZlcnlLZXkiLCJkZWNvZGVSZWNvdmVyeUtleSIsImJhY2t1cEtleVN0b3JlZCIsImxvYWRFcnJvciIsInN0YWdlIiwiUHJlRmV0Y2giLCJjb21wb25lbnREaWRNb3VudCIsImxvYWRCYWNrdXBTdGF0dXMiLCJyZXN0b3JlV2l0aFNlY3JldFN0b3JhZ2UiLCJTZWNyZXRTdG9yYWdlIiwicmVzdG9yZUtleUJhY2t1cFdpdGhTZWNyZXRTdG9yYWdlIiwicmVzdG9yZVdpdGhDYWNoZWRLZXkiLCJyZXN0b3JlS2V5QmFja3VwV2l0aENhY2hlIiwiY2xpIiwiZ2V0S2V5QmFja3VwVmVyc2lvbiIsImhhczRTIiwiaGFzU2VjcmV0U3RvcmFnZUtleSIsImlzS2V5QmFja3VwS2V5U3RvcmVkIiwiZ290Q2FjaGUiLCJyZW5kZXIiLCJiYWNrdXBIYXNQYXNzcGhyYXNlIiwiYXV0aF9kYXRhIiwicHJpdmF0ZV9rZXlfc2FsdCIsInByaXZhdGVfa2V5X2l0ZXJhdGlvbnMiLCJjb250ZW50IiwidGl0bGUiLCJfdCIsImRldGFpbHMiLCJGZXRjaCIsIkxvYWRLZXlzIiwidG90YWwiLCJzdWNjZXNzZXMiLCJmYWlsdXJlcyIsImNvbXBsZXRlZCIsImNyZWF0ZUVsZW1lbnQiLCJNYXRyaXhFcnJvciIsImVycmNvZGUiLCJNYXRyaXhDbGllbnQiLCJSRVNUT1JFX0JBQ0tVUF9FUlJPUl9CQURfS0VZIiwiZmFpbGVkVG9EZWNyeXB0IiwiaW1wb3J0ZWQiLCJmYWlsZWRDb3VudCIsInNlc3Npb25Db3VudCIsInByaW1hcnlCdXR0b24iLCJvblByaW1hcnlCdXR0b25DbGljayIsIm9uRG9uZSIsImhhc0NhbmNlbCIsImZvY3VzIiwiYiIsInN1YiIsImNsYXNzTmFtZSIsInR5cGUiLCJvbkNoYW5nZSIsIm9uUGFzc1BocmFzZUNoYW5nZSIsImF1dG9Gb2N1cyIsIm9uUGFzc1BocmFzZU5leHQiLCJwcmltYXJ5SXNTdWJtaXQiLCJvbkNhbmNlbCIsImJ1dHRvbjEiLCJzIiwia2luZCIsIm9uQ2xpY2siLCJvblVzZVJlY292ZXJ5S2V5Q2xpY2siLCJidXR0b24yIiwib25SZXNldFJlY292ZXJ5Q2xpY2siLCJrZXlTdGF0dXMiLCJsZW5ndGgiLCJvblJlY292ZXJ5S2V5Q2hhbmdlIiwib25SZWNvdmVyeUtleU5leHQiLCJwcmltYXJ5RGlzYWJsZWQiLCJidXR0b24iLCJleHBvcnRzIl0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvdmlld3MvZGlhbG9ncy9zZWN1cml0eS9SZXN0b3JlS2V5QmFja3VwRGlhbG9nLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuQ29weXJpZ2h0IDIwMjQgTmV3IFZlY3RvciBMdGQuXG5Db3B5cmlnaHQgMjAyMCBUaGUgTWF0cml4Lm9yZyBGb3VuZGF0aW9uIEMuSS5DLlxuQ29weXJpZ2h0IDIwMTgsIDIwMTkgTmV3IFZlY3RvciBMdGRcblxuU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFHUEwtMy4wLW9ubHkgT1IgR1BMLTMuMC1vbmx5XG5QbGVhc2Ugc2VlIExJQ0VOU0UgZmlsZXMgaW4gdGhlIHJlcG9zaXRvcnkgcm9vdCBmb3IgZnVsbCBkZXRhaWxzLlxuKi9cblxuaW1wb3J0IFJlYWN0LCB7IENoYW5nZUV2ZW50IH0gZnJvbSBcInJlYWN0XCI7XG5pbXBvcnQgeyBNYXRyaXhDbGllbnQsIE1hdHJpeEVycm9yLCBTZWNyZXRTdG9yYWdlIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL21hdHJpeFwiO1xuaW1wb3J0IHsgZGVjb2RlUmVjb3ZlcnlLZXksIEtleUJhY2t1cEluZm8gfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvY3J5cHRvLWFwaVwiO1xuaW1wb3J0IHsgSUtleUJhY2t1cFJlc3RvcmVSZXN1bHQgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvY3J5cHRvL2tleWJhY2t1cFwiO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL2xvZ2dlclwiO1xuXG5pbXBvcnQgeyBNYXRyaXhDbGllbnRQZWcgfSBmcm9tIFwiLi4vLi4vLi4vLi4vTWF0cml4Q2xpZW50UGVnXCI7XG5pbXBvcnQgeyBfdCB9IGZyb20gXCIuLi8uLi8uLi8uLi9sYW5ndWFnZUhhbmRsZXJcIjtcbmltcG9ydCB7IGFjY2Vzc1NlY3JldFN0b3JhZ2UgfSBmcm9tIFwiLi4vLi4vLi4vLi4vU2VjdXJpdHlNYW5hZ2VyXCI7XG5pbXBvcnQgU3Bpbm5lciBmcm9tIFwiLi4vLi4vZWxlbWVudHMvU3Bpbm5lclwiO1xuaW1wb3J0IERpYWxvZ0J1dHRvbnMgZnJvbSBcIi4uLy4uL2VsZW1lbnRzL0RpYWxvZ0J1dHRvbnNcIjtcbmltcG9ydCBBY2Nlc3NpYmxlQnV0dG9uIGZyb20gXCIuLi8uLi9lbGVtZW50cy9BY2Nlc3NpYmxlQnV0dG9uXCI7XG5pbXBvcnQgQmFzZURpYWxvZyBmcm9tIFwiLi4vQmFzZURpYWxvZ1wiO1xuXG5lbnVtIFJlc3RvcmVUeXBlIHtcbiAgICBQYXNzcGhyYXNlID0gXCJwYXNzcGhyYXNlXCIsXG4gICAgUmVjb3ZlcnlLZXkgPSBcInJlY292ZXJ5X2tleVwiLFxuICAgIFNlY3JldFN0b3JhZ2UgPSBcInNlY3JldF9zdG9yYWdlXCIsXG59XG5cbmVudW0gUHJvZ3Jlc3NTdGF0ZSB7XG4gICAgUHJlRmV0Y2ggPSBcInByZWZldGNoXCIsXG4gICAgRmV0Y2ggPSBcImZldGNoXCIsXG4gICAgTG9hZEtleXMgPSBcImxvYWRfa2V5c1wiLFxufVxuXG5pbnRlcmZhY2UgSVByb3BzIHtcbiAgICAvLyBpZiBmYWxzZSwgd2lsbCBjbG9zZSB0aGUgZGlhbG9nIGFzIHNvb24gYXMgdGhlIHJlc3RvcmUgY29tcGxldGVzIHN1Y2Nlc3NmdWxseVxuICAgIC8vIGRlZmF1bHQ6IHRydWVcbiAgICBzaG93U3VtbWFyeT86IGJvb2xlYW47XG4gICAgLy8gSWYgc3BlY2lmaWVkLCBnYXRoZXIgdGhlIGtleSBmcm9tIHRoZSB1c2VyIGJ1dCB0aGVuIGNhbGwgdGhlIGZ1bmN0aW9uIHdpdGggdGhlIGJhY2t1cFxuICAgIC8vIGtleSByYXRoZXIgdGhhbiBhY3R1YWxseSAobmVjZXNzYXJpbHkpIHJlc3RvcmluZyB0aGUgYmFja3VwLlxuICAgIGtleUNhbGxiYWNrPzogKGtleTogVWludDhBcnJheSkgPT4gdm9pZDtcbiAgICBvbkZpbmlzaGVkKGRvbmU/OiBib29sZWFuKTogdm9pZDtcbn1cblxuaW50ZXJmYWNlIElTdGF0ZSB7XG4gICAgYmFja3VwSW5mbzogS2V5QmFja3VwSW5mbyB8IG51bGw7XG4gICAgYmFja3VwS2V5U3RvcmVkOiBSZWNvcmQ8c3RyaW5nLCBTZWNyZXRTdG9yYWdlLlNlY3JldFN0b3JhZ2VLZXlEZXNjcmlwdGlvbj4gfCBudWxsO1xuICAgIGxvYWRpbmc6IGJvb2xlYW47XG4gICAgbG9hZEVycm9yOiBib29sZWFuIHwgbnVsbDtcbiAgICByZXN0b3JlRXJyb3I6IHVua25vd24gfCBudWxsO1xuICAgIHJlY292ZXJ5S2V5OiBzdHJpbmc7XG4gICAgcmVjb3ZlckluZm86IElLZXlCYWNrdXBSZXN0b3JlUmVzdWx0IHwgbnVsbDtcbiAgICByZWNvdmVyeUtleVZhbGlkOiBib29sZWFuO1xuICAgIGZvcmNlUmVjb3ZlcnlLZXk6IGJvb2xlYW47XG4gICAgcGFzc1BocmFzZTogc3RyaW5nO1xuICAgIHJlc3RvcmVUeXBlOiBSZXN0b3JlVHlwZSB8IG51bGw7XG4gICAgcHJvZ3Jlc3M6IHtcbiAgICAgICAgc3RhZ2U6IFByb2dyZXNzU3RhdGUgfCBzdHJpbmc7XG4gICAgICAgIHRvdGFsPzogbnVtYmVyO1xuICAgICAgICBzdWNjZXNzZXM/OiBudW1iZXI7XG4gICAgICAgIGZhaWx1cmVzPzogbnVtYmVyO1xuICAgIH07XG59XG5cbi8qXG4gKiBEaWFsb2cgZm9yIHJlc3RvcmluZyBlMmUga2V5cyBmcm9tIGEgYmFja3VwIGFuZCB0aGUgdXNlcidzIHJlY292ZXJ5IGtleVxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBSZXN0b3JlS2V5QmFja3VwRGlhbG9nIGV4dGVuZHMgUmVhY3QuUHVyZUNvbXBvbmVudDxJUHJvcHMsIElTdGF0ZT4ge1xuICAgIHB1YmxpYyBzdGF0aWMgZGVmYXVsdFByb3BzOiBQYXJ0aWFsPElQcm9wcz4gPSB7XG4gICAgICAgIHNob3dTdW1tYXJ5OiB0cnVlLFxuICAgIH07XG5cbiAgICBwdWJsaWMgY29uc3RydWN0b3IocHJvcHM6IElQcm9wcykge1xuICAgICAgICBzdXBlcihwcm9wcyk7XG4gICAgICAgIHRoaXMuc3RhdGUgPSB7XG4gICAgICAgICAgICBiYWNrdXBJbmZvOiBudWxsLFxuICAgICAgICAgICAgYmFja3VwS2V5U3RvcmVkOiBudWxsLFxuICAgICAgICAgICAgbG9hZGluZzogZmFsc2UsXG4gICAgICAgICAgICBsb2FkRXJyb3I6IG51bGwsXG4gICAgICAgICAgICByZXN0b3JlRXJyb3I6IG51bGwsXG4gICAgICAgICAgICByZWNvdmVyeUtleTogXCJcIixcbiAgICAgICAgICAgIHJlY292ZXJJbmZvOiBudWxsLFxuICAgICAgICAgICAgcmVjb3ZlcnlLZXlWYWxpZDogZmFsc2UsXG4gICAgICAgICAgICBmb3JjZVJlY292ZXJ5S2V5OiBmYWxzZSxcbiAgICAgICAgICAgIHBhc3NQaHJhc2U6IFwiXCIsXG4gICAgICAgICAgICByZXN0b3JlVHlwZTogbnVsbCxcbiAgICAgICAgICAgIHByb2dyZXNzOiB7IHN0YWdlOiBQcm9ncmVzc1N0YXRlLlByZUZldGNoIH0sXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgcHVibGljIGNvbXBvbmVudERpZE1vdW50KCk6IHZvaWQge1xuICAgICAgICB0aGlzLmxvYWRCYWNrdXBTdGF0dXMoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIG9uQ2FuY2VsID0gKCk6IHZvaWQgPT4ge1xuICAgICAgICB0aGlzLnByb3BzLm9uRmluaXNoZWQoZmFsc2UpO1xuICAgIH07XG5cbiAgICBwcml2YXRlIG9uRG9uZSA9ICgpOiB2b2lkID0+IHtcbiAgICAgICAgdGhpcy5wcm9wcy5vbkZpbmlzaGVkKHRydWUpO1xuICAgIH07XG5cbiAgICBwcml2YXRlIG9uVXNlUmVjb3ZlcnlLZXlDbGljayA9ICgpOiB2b2lkID0+IHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBmb3JjZVJlY292ZXJ5S2V5OiB0cnVlLFxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBwcm9ncmVzc0NhbGxiYWNrID0gKGRhdGE6IElTdGF0ZVtcInByb2dyZXNzXCJdKTogdm9pZCA9PiB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgcHJvZ3Jlc3M6IGRhdGEsXG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICBwcml2YXRlIG9uUmVzZXRSZWNvdmVyeUNsaWNrID0gKCk6IHZvaWQgPT4ge1xuICAgICAgICB0aGlzLnByb3BzLm9uRmluaXNoZWQoZmFsc2UpO1xuICAgICAgICBhY2Nlc3NTZWNyZXRTdG9yYWdlKGFzeW5jICgpOiBQcm9taXNlPHZvaWQ+ID0+IHt9LCAvKiBmb3JjZVJlc2V0ID0gKi8gdHJ1ZSk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIENoZWNrIGlmIHRoZSByZWNvdmVyeSBrZXkgaXMgdmFsaWRcbiAgICAgKiBAcGFyYW0gcmVjb3ZlcnlLZXlcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHByaXZhdGUgaXNWYWxpZFJlY292ZXJ5S2V5KHJlY292ZXJ5S2V5OiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGRlY29kZVJlY292ZXJ5S2V5KHJlY292ZXJ5S2V5KTtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIG9uUmVjb3ZlcnlLZXlDaGFuZ2UgPSAoZTogQ2hhbmdlRXZlbnQ8SFRNTElucHV0RWxlbWVudD4pOiB2b2lkID0+IHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICByZWNvdmVyeUtleTogZS50YXJnZXQudmFsdWUsXG4gICAgICAgICAgICByZWNvdmVyeUtleVZhbGlkOiB0aGlzLmlzVmFsaWRSZWNvdmVyeUtleShlLnRhcmdldC52YWx1ZSksXG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICBwcml2YXRlIG9uUGFzc1BocmFzZU5leHQgPSBhc3luYyAoKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgIGlmICghdGhpcy5zdGF0ZS5iYWNrdXBJbmZvKSByZXR1cm47XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgbG9hZGluZzogdHJ1ZSxcbiAgICAgICAgICAgIHJlc3RvcmVFcnJvcjogbnVsbCxcbiAgICAgICAgICAgIHJlc3RvcmVUeXBlOiBSZXN0b3JlVHlwZS5QYXNzcGhyYXNlLFxuICAgICAgICB9KTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIC8vIFdlIGRvIHN0aWxsIHJlc3RvcmUgdGhlIGtleSBiYWNrdXA6IHdlIG11c3QgZW5zdXJlIHRoYXQgdGhlIGtleSBiYWNrdXAga2V5XG4gICAgICAgICAgICAvLyBpcyB0aGUgcmlnaHQgb25lIGFuZCByZXN0b3JpbmcgaXQgaXMgY3VycmVudGx5IHRoZSBvbmx5IHdheSB3ZSBjYW4gZG8gdGhpcy5cbiAgICAgICAgICAgIGNvbnN0IHJlY292ZXJJbmZvID0gYXdhaXQgTWF0cml4Q2xpZW50UGVnLnNhZmVHZXQoKS5yZXN0b3JlS2V5QmFja3VwV2l0aFBhc3N3b3JkKFxuICAgICAgICAgICAgICAgIHRoaXMuc3RhdGUucGFzc1BocmFzZSxcbiAgICAgICAgICAgICAgICB1bmRlZmluZWQsXG4gICAgICAgICAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgIHRoaXMuc3RhdGUuYmFja3VwSW5mbyxcbiAgICAgICAgICAgICAgICB7IHByb2dyZXNzQ2FsbGJhY2s6IHRoaXMucHJvZ3Jlc3NDYWxsYmFjayB9LFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGlmICh0aGlzLnByb3BzLmtleUNhbGxiYWNrKSB7XG4gICAgICAgICAgICAgICAgY29uc3Qga2V5ID0gYXdhaXQgTWF0cml4Q2xpZW50UGVnLnNhZmVHZXQoKS5rZXlCYWNrdXBLZXlGcm9tUGFzc3dvcmQoXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc3RhdGUucGFzc1BocmFzZSxcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zdGF0ZS5iYWNrdXBJbmZvLFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgdGhpcy5wcm9wcy5rZXlDYWxsYmFjayhrZXkpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoIXRoaXMucHJvcHMuc2hvd1N1bW1hcnkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnByb3BzLm9uRmluaXNoZWQodHJ1ZSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgbG9hZGluZzogZmFsc2UsXG4gICAgICAgICAgICAgICAgcmVjb3ZlckluZm8sXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgbG9nZ2VyLmxvZyhcIkVycm9yIHJlc3RvcmluZyBiYWNrdXBcIiwgZSk7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICBsb2FkaW5nOiBmYWxzZSxcbiAgICAgICAgICAgICAgICByZXN0b3JlRXJyb3I6IGUsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBwcml2YXRlIG9uUmVjb3ZlcnlLZXlOZXh0ID0gYXN5bmMgKCk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgICBpZiAoIXRoaXMuc3RhdGUucmVjb3ZlcnlLZXlWYWxpZCB8fCAhdGhpcy5zdGF0ZS5iYWNrdXBJbmZvKSByZXR1cm47XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBsb2FkaW5nOiB0cnVlLFxuICAgICAgICAgICAgcmVzdG9yZUVycm9yOiBudWxsLFxuICAgICAgICAgICAgcmVzdG9yZVR5cGU6IFJlc3RvcmVUeXBlLlJlY292ZXJ5S2V5LFxuICAgICAgICB9KTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IHJlY292ZXJJbmZvID0gYXdhaXQgTWF0cml4Q2xpZW50UGVnLnNhZmVHZXQoKS5yZXN0b3JlS2V5QmFja3VwV2l0aFJlY292ZXJ5S2V5KFxuICAgICAgICAgICAgICAgIHRoaXMuc3RhdGUucmVjb3ZlcnlLZXksXG4gICAgICAgICAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgIHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgICB0aGlzLnN0YXRlLmJhY2t1cEluZm8sXG4gICAgICAgICAgICAgICAgeyBwcm9ncmVzc0NhbGxiYWNrOiB0aGlzLnByb2dyZXNzQ2FsbGJhY2sgfSxcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBpZiAodGhpcy5wcm9wcy5rZXlDYWxsYmFjaykge1xuICAgICAgICAgICAgICAgIGNvbnN0IGtleSA9IGRlY29kZVJlY292ZXJ5S2V5KHRoaXMuc3RhdGUucmVjb3ZlcnlLZXkpO1xuICAgICAgICAgICAgICAgIHRoaXMucHJvcHMua2V5Q2FsbGJhY2soa2V5KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghdGhpcy5wcm9wcy5zaG93U3VtbWFyeSkge1xuICAgICAgICAgICAgICAgIHRoaXMucHJvcHMub25GaW5pc2hlZCh0cnVlKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICBsb2FkaW5nOiBmYWxzZSxcbiAgICAgICAgICAgICAgICByZWNvdmVySW5mbyxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBsb2dnZXIubG9nKFwiRXJyb3IgcmVzdG9yaW5nIGJhY2t1cFwiLCBlKTtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgIGxvYWRpbmc6IGZhbHNlLFxuICAgICAgICAgICAgICAgIHJlc3RvcmVFcnJvcjogZSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHByaXZhdGUgb25QYXNzUGhyYXNlQ2hhbmdlID0gKGU6IENoYW5nZUV2ZW50PEhUTUxJbnB1dEVsZW1lbnQ+KTogdm9pZCA9PiB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgcGFzc1BocmFzZTogZS50YXJnZXQudmFsdWUsXG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICBwcml2YXRlIGFzeW5jIHJlc3RvcmVXaXRoU2VjcmV0U3RvcmFnZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBsb2FkaW5nOiB0cnVlLFxuICAgICAgICAgICAgcmVzdG9yZUVycm9yOiBudWxsLFxuICAgICAgICAgICAgcmVzdG9yZVR5cGU6IFJlc3RvcmVUeXBlLlNlY3JldFN0b3JhZ2UsXG4gICAgICAgIH0pO1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgLy8gYGFjY2Vzc1NlY3JldFN0b3JhZ2VgIG1heSBwcm9tcHQgZm9yIHN0b3JhZ2UgYWNjZXNzIGFzIG5lZWRlZC5cbiAgICAgICAgICAgIGF3YWl0IGFjY2Vzc1NlY3JldFN0b3JhZ2UoYXN5bmMgKCk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgICAgICAgICAgIGlmICghdGhpcy5zdGF0ZS5iYWNrdXBJbmZvKSByZXR1cm47XG4gICAgICAgICAgICAgICAgYXdhaXQgTWF0cml4Q2xpZW50UGVnLnNhZmVHZXQoKS5yZXN0b3JlS2V5QmFja3VwV2l0aFNlY3JldFN0b3JhZ2UoXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc3RhdGUuYmFja3VwSW5mbyxcbiAgICAgICAgICAgICAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgICAgICB1bmRlZmluZWQsXG4gICAgICAgICAgICAgICAgICAgIHsgcHJvZ3Jlc3NDYWxsYmFjazogdGhpcy5wcm9ncmVzc0NhbGxiYWNrIH0sXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgbG9hZGluZzogZmFsc2UsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgbG9nZ2VyLmxvZyhcIkVycm9yIHJlc3RvcmluZyBiYWNrdXBcIiwgZSk7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICByZXN0b3JlRXJyb3I6IGUsXG4gICAgICAgICAgICAgICAgbG9hZGluZzogZmFsc2UsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgcmVzdG9yZVdpdGhDYWNoZWRLZXkoYmFja3VwSW5mbzogS2V5QmFja3VwSW5mbyB8IG51bGwpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICAgICAgaWYgKCFiYWNrdXBJbmZvKSByZXR1cm4gZmFsc2U7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCByZWNvdmVySW5mbyA9IGF3YWl0IE1hdHJpeENsaWVudFBlZy5zYWZlR2V0KCkucmVzdG9yZUtleUJhY2t1cFdpdGhDYWNoZShcbiAgICAgICAgICAgICAgICB1bmRlZmluZWQgLyogdGFyZ2V0Um9vbUlkICovLFxuICAgICAgICAgICAgICAgIHVuZGVmaW5lZCAvKiB0YXJnZXRTZXNzaW9uSWQgKi8sXG4gICAgICAgICAgICAgICAgYmFja3VwSW5mbyxcbiAgICAgICAgICAgICAgICB7IHByb2dyZXNzQ2FsbGJhY2s6IHRoaXMucHJvZ3Jlc3NDYWxsYmFjayB9LFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgIHJlY292ZXJJbmZvLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgbG9nZ2VyLmxvZyhcInJlc3RvcmVXaXRoQ2FjaGVkS2V5IGZhaWxlZDpcIiwgZSk7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIGxvYWRCYWNrdXBTdGF0dXMoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgbG9hZGluZzogdHJ1ZSxcbiAgICAgICAgICAgIGxvYWRFcnJvcjogbnVsbCxcbiAgICAgICAgfSk7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBjbGkgPSBNYXRyaXhDbGllbnRQZWcuc2FmZUdldCgpO1xuICAgICAgICAgICAgY29uc3QgYmFja3VwSW5mbyA9IGF3YWl0IGNsaS5nZXRLZXlCYWNrdXBWZXJzaW9uKCk7XG4gICAgICAgICAgICBjb25zdCBoYXM0UyA9IGF3YWl0IGNsaS5oYXNTZWNyZXRTdG9yYWdlS2V5KCk7XG4gICAgICAgICAgICBjb25zdCBiYWNrdXBLZXlTdG9yZWQgPSBoYXM0UyA/IGF3YWl0IGNsaS5pc0tleUJhY2t1cEtleVN0b3JlZCgpIDogbnVsbDtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgIGJhY2t1cEluZm8sXG4gICAgICAgICAgICAgICAgYmFja3VwS2V5U3RvcmVkLFxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIGNvbnN0IGdvdENhY2hlID0gYXdhaXQgdGhpcy5yZXN0b3JlV2l0aENhY2hlZEtleShiYWNrdXBJbmZvKTtcbiAgICAgICAgICAgIGlmIChnb3RDYWNoZSkge1xuICAgICAgICAgICAgICAgIGxvZ2dlci5sb2coXCJSZXN0b3JlS2V5QmFja3VwRGlhbG9nOiBmb3VuZCBjYWNoZWQgYmFja3VwIGtleVwiKTtcbiAgICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICAgICAgbG9hZGluZzogZmFsc2UsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBJZiB0aGUgYmFja3VwIGtleSBpcyBzdG9yZWQsIHdlIGNhbiBwcm9jZWVkIGRpcmVjdGx5IHRvIHJlc3RvcmUuXG4gICAgICAgICAgICBpZiAoYmFja3VwS2V5U3RvcmVkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMucmVzdG9yZVdpdGhTZWNyZXRTdG9yYWdlKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgIGxvYWRFcnJvcjogbnVsbCxcbiAgICAgICAgICAgICAgICBsb2FkaW5nOiBmYWxzZSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBsb2dnZXIubG9nKFwiRXJyb3IgbG9hZGluZyBiYWNrdXAgc3RhdHVzXCIsIGUpO1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgbG9hZEVycm9yOiB0cnVlLFxuICAgICAgICAgICAgICAgIGxvYWRpbmc6IGZhbHNlLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgcmVuZGVyKCk6IFJlYWN0LlJlYWN0Tm9kZSB7XG4gICAgICAgIGNvbnN0IGJhY2t1cEhhc1Bhc3NwaHJhc2UgPVxuICAgICAgICAgICAgdGhpcy5zdGF0ZS5iYWNrdXBJbmZvICYmXG4gICAgICAgICAgICB0aGlzLnN0YXRlLmJhY2t1cEluZm8uYXV0aF9kYXRhICYmXG4gICAgICAgICAgICB0aGlzLnN0YXRlLmJhY2t1cEluZm8uYXV0aF9kYXRhLnByaXZhdGVfa2V5X3NhbHQgJiZcbiAgICAgICAgICAgIHRoaXMuc3RhdGUuYmFja3VwSW5mby5hdXRoX2RhdGEucHJpdmF0ZV9rZXlfaXRlcmF0aW9ucztcblxuICAgICAgICBsZXQgY29udGVudDtcbiAgICAgICAgbGV0IHRpdGxlO1xuICAgICAgICBpZiAodGhpcy5zdGF0ZS5sb2FkaW5nKSB7XG4gICAgICAgICAgICB0aXRsZSA9IF90KFwiZW5jcnlwdGlvbnxhY2Nlc3Nfc2VjcmV0X3N0b3JhZ2VfZGlhbG9nfHJlc3RvcmluZ1wiKTtcbiAgICAgICAgICAgIGxldCBkZXRhaWxzO1xuICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUucHJvZ3Jlc3Muc3RhZ2UgPT09IFByb2dyZXNzU3RhdGUuRmV0Y2gpIHtcbiAgICAgICAgICAgICAgICBkZXRhaWxzID0gX3QoXCJyZXN0b3JlX2tleV9iYWNrdXBfZGlhbG9nfGtleV9mZXRjaF9pbl9wcm9ncmVzc1wiKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5wcm9ncmVzcy5zdGFnZSA9PT0gUHJvZ3Jlc3NTdGF0ZS5Mb2FkS2V5cykge1xuICAgICAgICAgICAgICAgIGNvbnN0IHsgdG90YWwsIHN1Y2Nlc3NlcywgZmFpbHVyZXMgfSA9IHRoaXMuc3RhdGUucHJvZ3Jlc3M7XG4gICAgICAgICAgICAgICAgZGV0YWlscyA9IF90KFwicmVzdG9yZV9rZXlfYmFja3VwX2RpYWxvZ3xsb2FkX2tleXNfcHJvZ3Jlc3NcIiwge1xuICAgICAgICAgICAgICAgICAgICB0b3RhbCxcbiAgICAgICAgICAgICAgICAgICAgY29tcGxldGVkOiAoc3VjY2Vzc2VzID8/IDApICsgKGZhaWx1cmVzID8/IDApLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLnByb2dyZXNzLnN0YWdlID09PSBQcm9ncmVzc1N0YXRlLlByZUZldGNoKSB7XG4gICAgICAgICAgICAgICAgZGV0YWlscyA9IF90KFwicmVzdG9yZV9rZXlfYmFja3VwX2RpYWxvZ3xrZXlfZmV0Y2hfaW5fcHJvZ3Jlc3NcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb250ZW50ID0gKFxuICAgICAgICAgICAgICAgIDxkaXY+XG4gICAgICAgICAgICAgICAgICAgIDxkaXY+e2RldGFpbHN9PC9kaXY+XG4gICAgICAgICAgICAgICAgICAgIDxTcGlubmVyIC8+XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICApO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUubG9hZEVycm9yKSB7XG4gICAgICAgICAgICB0aXRsZSA9IF90KFwiY29tbW9ufGVycm9yXCIpO1xuICAgICAgICAgICAgY29udGVudCA9IF90KFwicmVzdG9yZV9rZXlfYmFja3VwX2RpYWxvZ3xsb2FkX2Vycm9yX2NvbnRlbnRcIik7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5yZXN0b3JlRXJyb3IpIHtcbiAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICB0aGlzLnN0YXRlLnJlc3RvcmVFcnJvciBpbnN0YW5jZW9mIE1hdHJpeEVycm9yICYmXG4gICAgICAgICAgICAgICAgdGhpcy5zdGF0ZS5yZXN0b3JlRXJyb3IuZXJyY29kZSA9PT0gTWF0cml4Q2xpZW50LlJFU1RPUkVfQkFDS1VQX0VSUk9SX0JBRF9LRVlcbiAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLnN0YXRlLnJlc3RvcmVUeXBlID09PSBSZXN0b3JlVHlwZS5SZWNvdmVyeUtleSkge1xuICAgICAgICAgICAgICAgICAgICB0aXRsZSA9IF90KFwicmVzdG9yZV9rZXlfYmFja3VwX2RpYWxvZ3xyZWNvdmVyeV9rZXlfbWlzbWF0Y2hfdGl0bGVcIik7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRlbnQgPSAoXG4gICAgICAgICAgICAgICAgICAgICAgICA8ZGl2PlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxwPntfdChcInJlc3RvcmVfa2V5X2JhY2t1cF9kaWFsb2d8cmVjb3Zlcnlfa2V5X21pc21hdGNoX2Rlc2NyaXB0aW9uXCIpfTwvcD5cbiAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRpdGxlID0gX3QoXCJyZXN0b3JlX2tleV9iYWNrdXBfZGlhbG9nfGluY29ycmVjdF9zZWN1cml0eV9waHJhc2VfdGl0bGVcIik7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRlbnQgPSAoXG4gICAgICAgICAgICAgICAgICAgICAgICA8ZGl2PlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxwPntfdChcInJlc3RvcmVfa2V5X2JhY2t1cF9kaWFsb2d8aW5jb3JyZWN0X3NlY3VyaXR5X3BocmFzZV9kaWFsb2dcIil9PC9wPlxuICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aXRsZSA9IF90KFwiY29tbW9ufGVycm9yXCIpO1xuICAgICAgICAgICAgICAgIGNvbnRlbnQgPSBfdChcInJlc3RvcmVfa2V5X2JhY2t1cF9kaWFsb2d8cmVzdG9yZV9mYWlsZWRfZXJyb3JcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5iYWNrdXBJbmZvID09PSBudWxsKSB7XG4gICAgICAgICAgICB0aXRsZSA9IF90KFwiY29tbW9ufGVycm9yXCIpO1xuICAgICAgICAgICAgY29udGVudCA9IF90KFwicmVzdG9yZV9rZXlfYmFja3VwX2RpYWxvZ3xub19iYWNrdXBfZXJyb3JcIik7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5yZWNvdmVySW5mbykge1xuICAgICAgICAgICAgdGl0bGUgPSBfdChcInJlc3RvcmVfa2V5X2JhY2t1cF9kaWFsb2d8a2V5c19yZXN0b3JlZF90aXRsZVwiKTtcbiAgICAgICAgICAgIGxldCBmYWlsZWRUb0RlY3J5cHQ7XG4gICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5yZWNvdmVySW5mby50b3RhbCA+IHRoaXMuc3RhdGUucmVjb3ZlckluZm8uaW1wb3J0ZWQpIHtcbiAgICAgICAgICAgICAgICBmYWlsZWRUb0RlY3J5cHQgPSAoXG4gICAgICAgICAgICAgICAgICAgIDxwPlxuICAgICAgICAgICAgICAgICAgICAgICAge190KFwicmVzdG9yZV9rZXlfYmFja3VwX2RpYWxvZ3xjb3VudF9vZl9kZWNyeXB0aW9uX2ZhaWx1cmVzXCIsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWlsZWRDb3VudDogdGhpcy5zdGF0ZS5yZWNvdmVySW5mby50b3RhbCAtIHRoaXMuc3RhdGUucmVjb3ZlckluZm8uaW1wb3J0ZWQsXG4gICAgICAgICAgICAgICAgICAgICAgICB9KX1cbiAgICAgICAgICAgICAgICAgICAgPC9wPlxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb250ZW50ID0gKFxuICAgICAgICAgICAgICAgIDxkaXY+XG4gICAgICAgICAgICAgICAgICAgIDxwPlxuICAgICAgICAgICAgICAgICAgICAgICAge190KFwicmVzdG9yZV9rZXlfYmFja3VwX2RpYWxvZ3xjb3VudF9vZl9zdWNjZXNzZnVsbHlfcmVzdG9yZWRfa2V5c1wiLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2Vzc2lvbkNvdW50OiB0aGlzLnN0YXRlLnJlY292ZXJJbmZvLmltcG9ydGVkLFxuICAgICAgICAgICAgICAgICAgICAgICAgfSl9XG4gICAgICAgICAgICAgICAgICAgIDwvcD5cbiAgICAgICAgICAgICAgICAgICAge2ZhaWxlZFRvRGVjcnlwdH1cbiAgICAgICAgICAgICAgICAgICAgPERpYWxvZ0J1dHRvbnNcbiAgICAgICAgICAgICAgICAgICAgICAgIHByaW1hcnlCdXR0b249e190KFwiYWN0aW9ufG9rXCIpfVxuICAgICAgICAgICAgICAgICAgICAgICAgb25QcmltYXJ5QnV0dG9uQ2xpY2s9e3RoaXMub25Eb25lfVxuICAgICAgICAgICAgICAgICAgICAgICAgaGFzQ2FuY2VsPXtmYWxzZX1cbiAgICAgICAgICAgICAgICAgICAgICAgIGZvY3VzPXt0cnVlfVxuICAgICAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgKTtcbiAgICAgICAgfSBlbHNlIGlmIChiYWNrdXBIYXNQYXNzcGhyYXNlICYmICF0aGlzLnN0YXRlLmZvcmNlUmVjb3ZlcnlLZXkpIHtcbiAgICAgICAgICAgIHRpdGxlID0gX3QoXCJyZXN0b3JlX2tleV9iYWNrdXBfZGlhbG9nfGVudGVyX3BocmFzZV90aXRsZVwiKTtcbiAgICAgICAgICAgIGNvbnRlbnQgPSAoXG4gICAgICAgICAgICAgICAgPGRpdj5cbiAgICAgICAgICAgICAgICAgICAgPHA+XG4gICAgICAgICAgICAgICAgICAgICAgICB7X3QoXCJyZXN0b3JlX2tleV9iYWNrdXBfZGlhbG9nfGtleV9iYWNrdXBfd2FybmluZ1wiLCB7fSwgeyBiOiAoc3ViKSA9PiA8c3Ryb25nPntzdWJ9PC9zdHJvbmc+IH0pfVxuICAgICAgICAgICAgICAgICAgICA8L3A+XG4gICAgICAgICAgICAgICAgICAgIDxwPntfdChcInJlc3RvcmVfa2V5X2JhY2t1cF9kaWFsb2d8ZW50ZXJfcGhyYXNlX2Rlc2NyaXB0aW9uXCIpfTwvcD5cblxuICAgICAgICAgICAgICAgICAgICA8Zm9ybSBjbGFzc05hbWU9XCJteF9SZXN0b3JlS2V5QmFja3VwRGlhbG9nX3ByaW1hcnlDb250YWluZXJcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU9XCJwYXNzd29yZFwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3NOYW1lPVwibXhfUmVzdG9yZUtleUJhY2t1cERpYWxvZ19wYXNzUGhyYXNlSW5wdXRcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uQ2hhbmdlPXt0aGlzLm9uUGFzc1BocmFzZUNoYW5nZX1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZT17dGhpcy5zdGF0ZS5wYXNzUGhyYXNlfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF1dG9Gb2N1cz17dHJ1ZX1cbiAgICAgICAgICAgICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICAgICAgICAgICAgICA8RGlhbG9nQnV0dG9uc1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByaW1hcnlCdXR0b249e190KFwiYWN0aW9ufG5leHRcIil9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb25QcmltYXJ5QnV0dG9uQ2xpY2s9e3RoaXMub25QYXNzUGhyYXNlTmV4dH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmltYXJ5SXNTdWJtaXQ9e3RydWV9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaGFzQ2FuY2VsPXt0cnVlfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uQ2FuY2VsPXt0aGlzLm9uQ2FuY2VsfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvY3VzPXtmYWxzZX1cbiAgICAgICAgICAgICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICAgICAgICAgIDwvZm9ybT5cbiAgICAgICAgICAgICAgICAgICAge190KFxuICAgICAgICAgICAgICAgICAgICAgICAgXCJyZXN0b3JlX2tleV9iYWNrdXBfZGlhbG9nfHBocmFzZV9mb3Jnb3R0ZW5fdGV4dFwiLFxuICAgICAgICAgICAgICAgICAgICAgICAge30sXG4gICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYnV0dG9uMTogKHMpID0+IChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPEFjY2Vzc2libGVCdXR0b24ga2luZD1cImxpbmtfaW5saW5lXCIgb25DbGljaz17dGhpcy5vblVzZVJlY292ZXJ5S2V5Q2xpY2t9PlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge3N9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvQWNjZXNzaWJsZUJ1dHRvbj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ1dHRvbjI6IChzKSA9PiAoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxBY2Nlc3NpYmxlQnV0dG9uIGtpbmQ9XCJsaW5rX2lubGluZVwiIG9uQ2xpY2s9e3RoaXMub25SZXNldFJlY292ZXJ5Q2xpY2t9PlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge3N9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvQWNjZXNzaWJsZUJ1dHRvbj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgKX1cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aXRsZSA9IF90KFwicmVzdG9yZV9rZXlfYmFja3VwX2RpYWxvZ3xlbnRlcl9rZXlfdGl0bGVcIik7XG5cbiAgICAgICAgICAgIGxldCBrZXlTdGF0dXM7XG4gICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5yZWNvdmVyeUtleS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgICBrZXlTdGF0dXMgPSA8ZGl2IGNsYXNzTmFtZT1cIm14X1Jlc3RvcmVLZXlCYWNrdXBEaWFsb2dfa2V5U3RhdHVzXCIgLz47XG4gICAgICAgICAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUucmVjb3ZlcnlLZXlWYWxpZCkge1xuICAgICAgICAgICAgICAgIGtleVN0YXR1cyA9IChcbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJteF9SZXN0b3JlS2V5QmFja3VwRGlhbG9nX2tleVN0YXR1c1wiPlxuICAgICAgICAgICAgICAgICAgICAgICAge1wiXFx1RDgzRFxcdURDNEQgXCJ9XG4gICAgICAgICAgICAgICAgICAgICAgICB7X3QoXCJyZXN0b3JlX2tleV9iYWNrdXBfZGlhbG9nfGtleV9pc192YWxpZFwiKX1cbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAga2V5U3RhdHVzID0gKFxuICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cIm14X1Jlc3RvcmVLZXlCYWNrdXBEaWFsb2dfa2V5U3RhdHVzXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICB7XCJcXHVEODNEXFx1REM0RSBcIn1cbiAgICAgICAgICAgICAgICAgICAgICAgIHtfdChcInJlc3RvcmVfa2V5X2JhY2t1cF9kaWFsb2d8a2V5X2lzX2ludmFsaWRcIil9XG4gICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnRlbnQgPSAoXG4gICAgICAgICAgICAgICAgPGRpdj5cbiAgICAgICAgICAgICAgICAgICAgPHA+XG4gICAgICAgICAgICAgICAgICAgICAgICB7X3QoXCJyZXN0b3JlX2tleV9iYWNrdXBfZGlhbG9nfGtleV9iYWNrdXBfd2FybmluZ1wiLCB7fSwgeyBiOiAoc3ViKSA9PiA8c3Ryb25nPntzdWJ9PC9zdHJvbmc+IH0pfVxuICAgICAgICAgICAgICAgICAgICA8L3A+XG4gICAgICAgICAgICAgICAgICAgIDxwPntfdChcInJlc3RvcmVfa2V5X2JhY2t1cF9kaWFsb2d8ZW50ZXJfa2V5X2Rlc2NyaXB0aW9uXCIpfTwvcD5cblxuICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cIm14X1Jlc3RvcmVLZXlCYWNrdXBEaWFsb2dfcHJpbWFyeUNvbnRhaW5lclwiPlxuICAgICAgICAgICAgICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3NOYW1lPVwibXhfUmVzdG9yZUtleUJhY2t1cERpYWxvZ19yZWNvdmVyeUtleUlucHV0XCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbkNoYW5nZT17dGhpcy5vblJlY292ZXJ5S2V5Q2hhbmdlfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPXt0aGlzLnN0YXRlLnJlY292ZXJ5S2V5fVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF1dG9Gb2N1cz17dHJ1ZX1cbiAgICAgICAgICAgICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICAgICAgICAgICAgICB7a2V5U3RhdHVzfVxuICAgICAgICAgICAgICAgICAgICAgICAgPERpYWxvZ0J1dHRvbnNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmltYXJ5QnV0dG9uPXtfdChcImFjdGlvbnxuZXh0XCIpfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uUHJpbWFyeUJ1dHRvbkNsaWNrPXt0aGlzLm9uUmVjb3ZlcnlLZXlOZXh0fVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhhc0NhbmNlbD17dHJ1ZX1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbkNhbmNlbD17dGhpcy5vbkNhbmNlbH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb2N1cz17ZmFsc2V9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpbWFyeURpc2FibGVkPXshdGhpcy5zdGF0ZS5yZWNvdmVyeUtleVZhbGlkfVxuICAgICAgICAgICAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgIHtfdChcbiAgICAgICAgICAgICAgICAgICAgICAgIFwicmVzdG9yZV9rZXlfYmFja3VwX2RpYWxvZ3xrZXlfZm9yZ290dGVuX3RleHRcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIHt9LFxuICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ1dHRvbjogKHMpID0+IChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPEFjY2Vzc2libGVCdXR0b24ga2luZD1cImxpbmtfaW5saW5lXCIgb25DbGljaz17dGhpcy5vblJlc2V0UmVjb3ZlcnlDbGlja30+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7c31cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9BY2Nlc3NpYmxlQnV0dG9uPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICApfVxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICA8QmFzZURpYWxvZyBjbGFzc05hbWU9XCJteF9SZXN0b3JlS2V5QmFja3VwRGlhbG9nXCIgb25GaW5pc2hlZD17dGhpcy5wcm9wcy5vbkZpbmlzaGVkfSB0aXRsZT17dGl0bGV9PlxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPVwibXhfUmVzdG9yZUtleUJhY2t1cERpYWxvZ19jb250ZW50XCI+e2NvbnRlbnR9PC9kaXY+XG4gICAgICAgICAgICA8L0Jhc2VEaWFsb2c+XG4gICAgICAgICk7XG4gICAgfVxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7OztBQVNBLElBQUFBLE1BQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLE9BQUEsR0FBQUQsT0FBQTtBQUNBLElBQUFFLFVBQUEsR0FBQUYsT0FB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