matrix-react-sdk
Version:
SDK for matrix.org using React
379 lines (372 loc) • 60.6 kB
JavaScript
"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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