matrix-react-sdk
Version:
SDK for matrix.org using React
428 lines (380 loc) • 55.5 kB
JavaScript
"use strict";
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
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 sdk = _interopRequireWildcard(require("../../../../index"));
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"));
/*
Copyright 2018-2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// 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
/*:: <IProps, IState>*/
{
constructor(props) {
super(props);
(0, _defineProperty2.default)(this, "fileUpload", /*#__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
/*: ChangeEvent<HTMLInputElement>*/
) => {
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 = null; // 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
/*: ChangeEvent<HTMLInputElement>*/
) => {
if (ev.target.files.length === 0) 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
/*: FormEvent<HTMLFormElement>*/
) => {
ev.preventDefault();
if (this.state.passPhrase.length <= 0) 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
});
}
});
(0, _defineProperty2.default)(this, "onRecoveryKeyNext", async (ev
/*: FormEvent<HTMLFormElement>*/
) => {
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
/*: ChangeEvent<HTMLInputElement>*/
) => {
this.setState({
passPhrase: ev.target.value,
keyMatches: null
});
});
(0, _defineProperty2.default)(this, "onResetAllClick", (ev
/*: React.MouseEvent<HTMLAnchorElement>*/
) => {
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.get();
await cli.bootstrapCrossSigning({
authUploadDeviceSigningKeys: async makeRequest => {
// XXX: Making this an import breaks the app.
const InteractiveAuthDialog = sdk.getComponent("views.dialogs.InteractiveAuthDialog");
const {
finished
} = _Modal.default.createTrackedDialog('Cross-signing keys dialog', '', InteractiveAuthDialog, {
title: (0, _languageHandler._t)("Setting up keys"),
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);
}, true);
} catch (e) {
console.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.get();
const decodedKey = cli.keyBackupKeyFromRecoveryKey(this.state.recoveryKey);
const correct = await cli.checkSecretStorageKey(decodedKey, this.props.keyInfo);
this.setState({
recoveryKeyValid: true,
recoveryKeyCorrect: correct
});
} catch (e) {
this.setState({
recoveryKeyValid: false,
recoveryKeyCorrect: false
});
}
}
getKeyValidationText()
/*: string*/
{
if (this.state.recoveryKeyFileError) {
return (0, _languageHandler._t)("Wrong file type");
} else if (this.state.recoveryKeyCorrect) {
return (0, _languageHandler._t)("Looks good!");
} else if (this.state.recoveryKeyValid) {
return (0, _languageHandler._t)("Wrong Security Key");
} else if (this.state.recoveryKeyValid === null) {
return '';
} else {
return (0, _languageHandler._t)("Invalid Security Key");
}
}
render() {
// Caution: Making these an import will break tests.
const BaseDialog = sdk.getComponent("views.dialogs.BaseDialog");
const DialogButtons = sdk.getComponent("views.elements.DialogButtons");
const hasPassphrase = this.props.keyInfo && this.props.keyInfo.passphrase && this.props.keyInfo.passphrase.salt && this.props.keyInfo.passphrase.iterations;
const resetButton = /*#__PURE__*/_react.default.createElement("div", {
className: "mx_AccessSecretStorageDialog_reset"
}, (0, _languageHandler._t)("Forgotten or lost all recovery methods? <a>Reset all</a>", null, {
a: sub => /*#__PURE__*/_react.default.createElement("a", {
href: "",
onClick: this.onResetAllClick,
className: "mx_AccessSecretStorageDialog_reset_link"
}, sub)
}));
let content;
let title;
let titleClass;
if (this.state.resetting) {
title = (0, _languageHandler._t)("Reset everything");
titleClass = ['mx_AccessSecretStorageDialog_titleWithIcon mx_AccessSecretStorageDialog_resetBadge'];
content = /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("Only do this if you have no other device to complete verification with.")), /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("If you reset everything, you will restart with no trusted sessions, no trusted users, and " + "might not be able to see past messages.")), /*#__PURE__*/_react.default.createElement(DialogButtons, {
primaryButton: (0, _languageHandler._t)('Reset'),
onPrimaryButtonClick: this.onConfirmResetAllClick,
hasCancel: true,
onCancel: this.onCancel,
focus: false,
primaryButtonClass: "danger"
}));
} else if (hasPassphrase && !this.state.forceRecoveryKey) {
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
title = (0, _languageHandler._t)("Security Phrase");
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)("Unable to access secret storage. " + "Please verify that you entered the correct Security Phrase."));
} 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)("Enter your Security Phrase or <button>Use your Security Key</button> to continue.", {}, {
button: s => /*#__PURE__*/_react.default.createElement(AccessibleButton, {
className: "mx_linkButton",
element: "span",
onClick: this.onUseRecoveryKeyClick
}, s)
})), /*#__PURE__*/_react.default.createElement("form", {
className: "mx_AccessSecretStorageDialog_primaryContainer",
onSubmit: this.onPassPhraseNext
}, /*#__PURE__*/_react.default.createElement("input", {
type: "password",
id: "mx_passPhraseInput",
className: "mx_AccessSecretStorageDialog_passPhraseInput",
onChange: this.onPassPhraseChange,
value: this.state.passPhrase,
autoFocus: true,
autoComplete: "new-password",
placeholder: (0, _languageHandler._t)("Security Phrase")
}), keyStatus, /*#__PURE__*/_react.default.createElement(DialogButtons, {
primaryButton: (0, _languageHandler._t)('Continue'),
onPrimaryButtonClick: this.onPassPhraseNext,
hasCancel: true,
onCancel: this.onCancel,
focus: false,
primaryDisabled: this.state.passPhrase.length === 0,
additive: resetButton
})));
} else {
title = (0, _languageHandler._t)("Security Key");
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)("Use your Security Key to continue.")), /*#__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",
label: (0, _languageHandler._t)('Security Key'),
value: this.state.recoveryKey,
onChange: this.onRecoveryKeyChange,
forceValidity: this.state.recoveryKeyCorrect,
autoComplete: "off"
})), /*#__PURE__*/_react.default.createElement("span", {
className: "mx_AccessSecretStorageDialog_recoveryKeyEntry_entryControlSeparatorText"
}, (0, _languageHandler._t)("or")), /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("input", {
type: "file",
className: "mx_AccessSecretStorageDialog_recoveryKeyEntry_fileInput",
ref: this.fileUpload,
onChange: this.onRecoveryKeyFileChange
}), /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, {
kind: "primary",
onClick: this.onRecoveryKeyFileUploadClick
}, (0, _languageHandler._t)("Upload")))), recoveryKeyFeedback, /*#__PURE__*/_react.default.createElement(DialogButtons, {
primaryButton: (0, _languageHandler._t)('Continue'),
onPrimaryButtonClick: this.onRecoveryKeyNext,
hasCancel: true,
cancelButton: (0, _languageHandler._t)("Go Back"),
cancelButtonClass: "danger",
onCancel: this.onCancel,
focus: false,
primaryDisabled: !this.state.recoveryKeyValid,
additive: resetButton
})));
}
return /*#__PURE__*/_react.default.createElement(BaseDialog, {
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,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL3ZpZXdzL2RpYWxvZ3Mvc2VjdXJpdHkvQWNjZXNzU2VjcmV0U3RvcmFnZURpYWxvZy50c3giXSwibmFtZXMiOlsiS0VZX0ZJTEVfTUFYX1NJWkUiLCJWQUxJREFUSU9OX1RIUk9UVExFX01TIiwiQWNjZXNzU2VjcmV0U3RvcmFnZURpYWxvZyIsIlJlYWN0IiwiUHVyZUNvbXBvbmVudCIsImNvbnN0cnVjdG9yIiwicHJvcHMiLCJjcmVhdGVSZWYiLCJzdGF0ZSIsInJlc2V0dGluZyIsInNldFN0YXRlIiwib25GaW5pc2hlZCIsImZvcmNlUmVjb3ZlcnlLZXkiLCJ2YWxpZGF0ZVJlY292ZXJ5S2V5IiwiZXYiLCJyZWNvdmVyeUtleSIsInRhcmdldCIsInZhbHVlIiwicmVjb3ZlcnlLZXlGaWxlRXJyb3IiLCJmaWxlVXBsb2FkIiwiY3VycmVudCIsInZhbGlkYXRlUmVjb3ZlcnlLZXlPbkNoYW5nZSIsImZpbGVzIiwibGVuZ3RoIiwiZiIsInNpemUiLCJyZWNvdmVyeUtleUNvcnJlY3QiLCJyZWNvdmVyeUtleVZhbGlkIiwiY29udGVudHMiLCJ0ZXh0IiwidGVzdCIsInRyaW0iLCJjbGljayIsInByZXZlbnREZWZhdWx0IiwicGFzc1BocmFzZSIsImtleU1hdGNoZXMiLCJpbnB1dCIsInBhc3NwaHJhc2UiLCJjaGVja1ByaXZhdGVLZXkiLCJNb2RhbCIsInRvZ2dsZUN1cnJlbnREaWFsb2dWaXNpYmlsaXR5IiwiY2xpIiwiTWF0cml4Q2xpZW50UGVnIiwiZ2V0IiwiYm9vdHN0cmFwQ3Jvc3NTaWduaW5nIiwiYXV0aFVwbG9hZERldmljZVNpZ25pbmdLZXlzIiwibWFrZVJlcXVlc3QiLCJJbnRlcmFjdGl2ZUF1dGhEaWFsb2ciLCJzZGsiLCJnZXRDb21wb25lbnQiLCJmaW5pc2hlZCIsImNyZWF0ZVRyYWNrZWREaWFsb2ciLCJ0aXRsZSIsIm1hdHJpeENsaWVudCIsImNvbmZpcm1lZCIsIkVycm9yIiwic2V0dXBOZXdDcm9zc1NpZ25pbmciLCJlIiwiY29uc29sZSIsImVycm9yIiwiZGVjb2RlZEtleSIsImtleUJhY2t1cEtleUZyb21SZWNvdmVyeUtleSIsImNvcnJlY3QiLCJjaGVja1NlY3JldFN0b3JhZ2VLZXkiLCJrZXlJbmZvIiwiZ2V0S2V5VmFsaWRhdGlvblRleHQiLCJyZW5kZXIiLCJCYXNlRGlhbG9nIiwiRGlhbG9nQnV0dG9ucyIsImhhc1Bhc3NwaHJhc2UiLCJzYWx0IiwiaXRlcmF0aW9ucyIsInJlc2V0QnV0dG9uIiwiYSIsInN1YiIsIm9uUmVzZXRBbGxDbGljayIsImNvbnRlbnQiLCJ0aXRsZUNsYXNzIiwib25Db25maXJtUmVzZXRBbGxDbGljayIsIm9uQ2FuY2VsIiwiQWNjZXNzaWJsZUJ1dHRvbiIsImtleVN0YXR1cyIsImJ1dHRvbiIsInMiLCJvblVzZVJlY292ZXJ5S2V5Q2xpY2siLCJvblBhc3NQaHJhc2VOZXh0Iiwib25QYXNzUGhyYXNlQ2hhbmdlIiwiZmVlZGJhY2tDbGFzc2VzIiwicmVjb3ZlcnlLZXlGZWVkYmFjayIsIm9uUmVjb3ZlcnlLZXlOZXh0Iiwib25SZWNvdmVyeUtleUNoYW5nZSIsIm9uUmVjb3ZlcnlLZXlGaWxlQ2hhbmdlIiwib25SZWNvdmVyeUtleUZpbGVVcGxvYWRDbGljayJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7OztBQWdCQTs7QUFDQTs7QUFDQTs7QUFHQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFFQTs7QUFDQTs7QUE1QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBZ0JBO0FBQ0E7QUFDQTtBQUNBLE1BQU1BLGlCQUFpQixHQUFHLEdBQTFCLEMsQ0FFQTs7QUFDQSxNQUFNQyxzQkFBc0IsR0FBRyxHQUEvQjs7QUFrQkE7QUFDQTtBQUNBO0FBQ2UsTUFBTUMseUJBQU4sU0FBd0NDLGVBQU1DO0FBQTlDO0FBQTRFO0FBR3ZGQyxFQUFBQSxXQUFXLENBQUND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QUFBLElBQUksRUFBQyxNQUFaO0FBQ0ksUUFBQSxTQUFTLEVBQUMseURBRGQ7QUFFSSxRQUFBLEdBQUcsRUFBRSxLQUFLUCxVQUZkO0FBR0ksUUFBQSxRQUFRLEVBQUUsS0FBS3dFO0FBSG5CLFFBREosZUFNSSw2QkFBQyx5QkFBRDtBQUFrQixRQUFBLElBQUksRUFBQyxTQUF2QjtBQUFpQyxRQUFBLE9BQU8sRUFBRSxLQUFLQztBQUEvQyxTQUNLLHlCQUFHLFFBQUgsQ0FETCxDQU5KLENBZEosQ0FOSixFQStCS0osbUJBL0JMLGVBZ0NJLDZCQUFDLGFBQUQ7QUFDSSxRQUFBLGFBQWEsRUFBRSx5QkFBRyxVQUFILENBRG5CO0FBRUksUUFBQSxvQkFBb0IsRUFBRSxLQUFLQyxpQkFGL0I7QUFHSSxRQUFBLFNBQVMsRUFBRSxJQUhmO0FBSUksUUFBQSxZQUFZLEVBQUUseUJBQUcsU0FBSCxDQUpsQjtBQUtJLFFBQUEsaUJBQWlCLEVBQUMsUUFMdEI7QUFNSSxRQUFBLFFBQVEsRUFBRSxLQUFLVixRQU5uQjtBQU9JLFFBQUEsS0FBSyxFQUFFLEtBUFg7QUFRSSxRQUFBLGVBQWUsRUFBRSxDQUFDLEtBQUt2RSxLQUFMLENBQVdtQixnQkFSakM7QUFTSSxRQUFBLFFBQVEsRUFBRTZDO0FBVGQsUUFoQ0osQ0FITSxDQUFWO0FBZ0RIOztBQUVELHdCQUNJLDZCQUFDLFVBQUQ7QUFBWSxNQUFBLFNBQVMsRUFBQyw4QkFBdEI7QUFDSSxNQUFBLFVBQVUsRUFBRSxLQUFLbEUsS0FBTCxDQUFXSyxVQUQzQjtBQUVJLE1BQUEsS0FBSyxFQUFFeUMsS0FGWDtBQUdJLE1BQUEsVUFBVSxFQUFFeUI7QUFIaEIsb0JBS0ksMENBQ0tELE9BREwsQ0FMSixDQURKO0FBV0g7O0FBaFlzRiIsInNvdXJjZXNDb250ZW50IjpbIi8qXG5Db3B5cmlnaHQgMjAxOC0yMDIxIFRoZSBNYXRyaXgub3JnIEZvdW5kYXRpb24gQy5JLkMuXG5cbkxpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG55b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG5Zb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcblxuICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuXG5Vbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG5kaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG5XSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cblNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbmxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuKi9cblxuaW1wb3J0IHtkZWJvdW5jZX0gZnJvbSBcImxvZGFzaFwiO1xuaW1wb3J0IGNsYXNzTmFtZXMgZnJvbSAnY2xhc3NuYW1lcyc7XG5pbXBvcnQgUmVhY3QsIHtDaGFuZ2VFdmVudCwgRm9ybUV2ZW50fSBmcm9tICdyZWFjdCc7XG5pbXBvcnQge0lTZWNyZXRTdG9yYWdlS2V5SW5mb30gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjXCI7XG5cbmltcG9ydCAqIGFzIHNkayBmcm9tICcuLi8uLi8uLi8uLi9pbmRleCc7XG5pbXBvcnQge01hdHJpeENsaWVudFBlZ30gZnJvbSAnLi4vLi4vLi4vLi4vTWF0cml4Q2xpZW50UGVnJztcbmltcG9ydCBGaWVsZCBmcm9tICcuLi8uLi9lbGVtZW50cy9GaWVsZCc7XG5pbXBvcnQgQWNjZXNzaWJsZUJ1dHRvbiBmcm9tICcuLi8uLi9lbGVtZW50cy9BY2Nlc3NpYmxlQnV0dG9uJztcbmltcG9ydCB7X3R9IGZyb20gJy4uLy4uLy4uLy4uL2xhbmd1YWdlSGFuZGxlcic7XG5pbXBvcnQge0lEaWFsb2dQcm9wc30gZnJvbSBcIi4uL0lEaWFsb2dQcm9wc1wiO1xuaW1wb3J0IHthY2Nlc3NTZWNyZXRTdG9yYWdlfSBmcm9tIFwiLi4vLi4vLi4vLi4vU2VjdXJpdHlNYW5hZ2VyXCI7XG5pbXBvcnQgTW9kYWwgZnJvbSBcIi4uLy4uLy4uLy4uL01vZGFsXCI7XG5cbi8vIE1heGltdW0gYWNjZXB0YWJsZSBzaXplIG9mIGEga2V5IGZpbGUuIEl0J3MgNTkgY2hhcmFjdGVycyBpbmNsdWRpbmcgdGhlIHNwYWNlcyB3ZSBlbmNvZGUsXG4vLyBzbyB0aGlzIHNob3VsZCBiZSBwbGVudHkgYW5kIGFsbG93IGZvciBwZW9wbGUgcHV0dGluZyBleHRyYSB3aGl0ZXNwYWNlIGluIHRoZSBmaWxlIGJlY2F1c2Vcbi8vIG1heWJlIHRoYXQncyBhIHRoaW5nIHBlb3BsZSB3b3VsZCBkbz9cbmNvbnN0IEtFWV9GSUxFX01BWF9TSVpFID0gMTI4O1xuXG4vLyBEb24ndCBzaG91dCBhdCB0aGUgdXNlciB0aGF0IHRoZWlyIGtleSBpcyBpbnZhbGlkIGV2ZXJ5IHRpbWUgdGhleSB0eXBlIGEga2V5OiB3YWl0IGEgc2hvcnQgdGltZVxuY29uc3QgVkFMSURBVElPTl9USFJPVFRMRV9NUyA9IDIwMDtcblxuaW50ZXJmYWNlIElQcm9wcyBleHRlbmRzIElEaWFsb2dQcm9wcyB7XG4gICAga2V5SW5mbzogSVNlY3JldFN0b3JhZ2VLZXlJbmZvO1xuICAgIGNoZWNrUHJpdmF0ZUtleTogKGs6IHtwYXNzcGhyYXNlPzogc3RyaW5nLCByZWNvdmVyeUtleT86IHN0cmluZ30pID0+IGJvb2xlYW47XG59XG5cbmludGVyZmFjZSBJU3RhdGUge1xuICAgIHJlY292ZXJ5S2V5OiBzdHJpbmc7XG4gICAgcmVjb3ZlcnlLZXlWYWxpZDogYm9vbGVhbiB8IG51bGw7XG4gICAgcmVjb3ZlcnlLZXlDb3JyZWN0OiBib29sZWFuIHwgbnVsbDtcbiAgICByZWNvdmVyeUtleUZpbGVFcnJvcjogYm9vbGVhbiB8IG51bGw7XG4gICAgZm9yY2VSZWNvdmVyeUtleTogYm9vbGVhbjtcbiAgICBwYXNzUGhyYXNlOiBzdHJpbmc7XG4gICAga2V5TWF0Y2hlczogYm9vbGVhbiB8IG51bGw7XG4gICAgcmVzZXR0aW5nOiBib29sZWFuO1xufVxuXG4vKlxuICogQWNjZXNzIFNlY3VyZSBTZWNyZXQgU3RvcmFnZSBieSByZXF1ZXN0aW5nIHRoZSB1c2VyJ3MgcGFzc3BocmFzZS5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQWNjZXNzU2VjcmV0U3RvcmFnZURpYWxvZyBleHRlbmRzIFJlYWN0LlB1cmVDb21wb25lbnQ8SVByb3BzLCBJU3RhdGU+IHtcbiAgICBwcml2YXRlIGZpbGVVcGxvYWQgPSBSZWFjdC5jcmVhdGVSZWY8SFRNTElucHV0RWxlbWVudD4oKTtcblxuICAgIGNvbnN0cnVjdG9yKHByb3BzKSB7XG4gICAgICAgIHN1cGVyKHByb3BzKTtcblxuICAgICAgICB0aGlzLnN0YXRlID0ge1xuICAgICAgICAgICAgcmVjb3ZlcnlLZXk6IFwiXCIsXG4gICAgICAgICAgICByZWNvdmVyeUtleVZhbGlkOiBudWxsLFxuICAgICAgICAgICAgcmVjb3ZlcnlLZXlDb3JyZWN0OiBudWxsLFxuICAgICAgICAgICAgcmVjb3ZlcnlLZXlGaWxlRXJyb3I6IG51bGwsXG4gICAgICAgICAgICBmb3JjZVJlY292ZXJ5S2V5OiBmYWxzZSxcbiAgICAgICAgICAgIHBhc3NQaHJhc2U6ICcnLFxuICAgICAgICAgICAga2V5TWF0Y2hlczogbnVsbCxcbiAgICAgICAgICAgIHJlc2V0dGluZzogZmFsc2UsXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvbkNhbmNlbCA9ICgpID0+IHtcbiAgICAgICAgaWYgKHRoaXMuc3RhdGUucmVzZXR0aW5nKSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtyZXNldHRpbmc6IGZhbHNlfSk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5wcm9wcy5vbkZpbmlzaGVkKGZhbHNlKTtcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBvblVzZVJlY292ZXJ5S2V5Q2xpY2sgPSAoKSA9PiB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgZm9yY2VSZWNvdmVyeUtleTogdHJ1ZSxcbiAgICAgICAgfSk7XG4gICAgfTtcblxuICAgIHByaXZhdGUgdmFsaWRhdGVSZWNvdmVyeUtleU9uQ2hhbmdlID0gZGVib3VuY2UoYXN5bmMgKCkgPT4ge1xuICAgICAgICBhd2FpdCB0aGlzLnZhbGlkYXRlUmVjb3ZlcnlLZXkoKTtcbiAgICB9LCBWQUxJREFUSU9OX1RIUk9UVExFX01TKTtcblxuICAgIHByaXZhdGUgYXN5bmMgdmFsaWRhdGVSZWNvdmVyeUtleSgpIHtcbiAgICAgICAgaWYgKHRoaXMuc3RhdGUucmVjb3ZlcnlLZXkgPT09ICcnKSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICByZWNvdmVyeUtleVZhbGlkOiBudWxsLFxuICAgICAgICAgICAgICAgIHJlY292ZXJ5S2V5Q29ycmVjdDogbnVsbCxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IGNsaSA9IE1hdHJpeENsaWVudFBlZy5nZXQoKTtcbiAgICAgICAgICAgIGNvbnN0IGRlY29kZWRLZXkgPSBjbGkua2V5QmFja3VwS2V5RnJvbVJlY292ZXJ5S2V5KHRoaXMuc3RhdGUucmVjb3ZlcnlLZXkpO1xuICAgICAgICAgICAgY29uc3QgY29ycmVjdCA9IGF3YWl0IGNsaS5jaGVja1NlY3JldFN0b3JhZ2VLZXkoXG4gICAgICAgICAgICAgICAgZGVjb2RlZEtleSwgdGhpcy5wcm9wcy5rZXlJbmZvLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgIHJlY292ZXJ5S2V5VmFsaWQ6IHRydWUsXG4gICAgICAgICAgICAgICAgcmVjb3ZlcnlLZXlDb3JyZWN0OiBjb3JyZWN0LFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgIHJlY292ZXJ5S2V5VmFsaWQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgIHJlY292ZXJ5S2V5Q29ycmVjdDogZmFsc2UsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgb25SZWNvdmVyeUtleUNoYW5nZSA9IChldjogQ2hhbmdlRXZlbnQ8SFRNTElucHV0RWxlbWVudD4pID0+IHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICByZWNvdmVyeUtleTogZXYudGFyZ2V0LnZhbHVlLFxuICAgICAgICAgICAgcmVjb3ZlcnlLZXlGaWxlRXJyb3I6IG51bGwsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIGFsc28gY2xlYXIgdGhlIGZpbGUgdXBsb2FkIGNvbnRyb2wgc28gdGhhdCB0aGUgdXNlciBjYW4gdXBsb2FkIHRoZSBzYW1lIGZpbGVcbiAgICAgICAgLy8gdGhlIGRpZCBiZWZvcmUgKG90aGVyd2lzZSB0aGUgb25jaGFuZ2Ugd291bGRuJ3QgZmlyZSlcbiAgICAgICAgaWYgKHRoaXMuZmlsZVVwbG9hZC5jdXJyZW50KSB0aGlzLmZpbGVVcGxvYWQuY3VycmVudC52YWx1ZSA9IG51bGw7XG5cbiAgICAgICAgLy8gV2UgZG9uJ3QgdXNlIEZpZWxkJ3MgdmFsaWRhdGlvbiBoZXJlIGJlY2F1c2UgYSkgd2Ugd2FudCBpdCBpbiBhIHNlcGFyYXRlIHBsYWNlIHJhdGhlclxuICAgICAgICAvLyB0aGFuIGluIGEgdG9vbHRpcCBhbmQgYikgd2Ugd2FudCBpdCB0byBkaXNwbGF5IGZlZWRiYWNrIGJhc2VkIG9uIHRoZSB1cGxvYWRlZCBmaWxlXG4gICAgICAgIC8vIGFzIHdlbGwgYXMgdGhlIHRleHQgYm94LiBJZGVhbGx5IHdlIHdvdWxkIHJlZmFjdG9yIEZpZWxkJ3MgdmFsaWRhdGlvbiBsb2dpYyBzbyB3ZSBjb3VsZFxuICAgICAgICAvLyByZS11c2Ugc29tZSBvZiBpdC5cbiAgICAgICAgdGhpcy52YWxpZGF0ZVJlY292ZXJ5S2V5T25DaGFuZ2UoKTtcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBvblJlY292ZXJ5S2V5RmlsZUNoYW5nZSA9IGFzeW5jIChldjogQ2hhbmdlRXZlbnQ8SFRNTElucHV0RWxlbWVudD4pID0+IHtcbiAgICAgICAgaWYgKGV2LnRhcmdldC5maWxlcy5sZW5ndGggPT09IDApIHJldHVybjtcblxuICAgICAgICBjb25zdCBmID0gZXYudGFyZ2V0LmZpbGVzWzBdO1xuXG4gICAgICAgIGlmIChmLnNpemUgPiBLRVlfRklMRV9NQVhfU0laRSkge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgcmVjb3ZlcnlLZXlGaWxlRXJyb3I6IHRydWUsXG4gICAgICAgICAgICAgICAgcmVjb3ZlcnlLZXlDb3JyZWN0OiBmYWxzZSxcbiAgICAgICAgICAgICAgICByZWNvdmVyeUtleVZhbGlkOiBmYWxzZSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc3QgY29udGVudHMgPSBhd2FpdCBmLnRleHQoKTtcbiAgICAgICAgICAgIC8vIHRlc3QgaXQncyB3aXRoaW4gdGhlIGJhc2U1OCBhbHBoYWJldC4gV2UgY291bGQgYmUgbW9yZSBzdHJpY3QgaGVyZSwgZWcuIHJlcXVpcmUgdGhlXG4gICAgICAgICAgICAvLyByaWdodCBudW1iZXIgb2YgY2hhcmFjdGVycywgYnV0IGl0J3MgcmVhbGx5IGp1c3QgdG8gbWFrZSBzdXJlIHRoYXQgd2hhdCB3ZSdyZSByZWFkaW5nIGlzXG4gICAgICAgICAgICAvLyB0ZXh0IGJlY2F1c2Ugd2UnbGwgcHV0IGl0IGluIHRoZSB0ZXh0IGZpZWxkLlxuICAgICAgICAgICAgaWYgKC9eWzEyMzQ1Njc4OUFCQ0RFRkdISktMTU5QUVJTVFVWV1hZWmFiY2RlZmdoaWprbW5vcHFyc3R1dnd4eXpcXHNdKyQvLnRlc3QoY29udGVudHMpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgICAgIHJlY292ZXJ5S2V5RmlsZUVycm9yOiBudWxsLFxuICAgICAgICAgICAgICAgICAgICByZWNvdmVyeUtleTogY29udGVudHMudHJpbSgpLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMudmFsaWRhdGVSZWNvdmVyeUtleSgpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICAgICAgcmVjb3ZlcnlLZXlGaWxlRXJyb3I6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgIHJlY292ZXJ5S2V5Q29ycmVjdDogZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgIHJlY292ZXJ5S2V5VmFsaWQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICByZWNvdmVyeUtleTogJycsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBvblJlY292ZXJ5S2V5RmlsZVVwbG9hZENsaWNrID0gKCkgPT4ge1xuICAgICAgICB0aGlzLmZpbGVVcGxvYWQuY3VycmVudC5jbGljaygpO1xuICAgIH1cblxuICAgIHByaXZhdGUgb25QYXNzUGhyYXNlTmV4dCA9IGFzeW5jIChldjogRm9ybUV2ZW50PEhUTUxGb3JtRWxlbWVudD4pID0+IHtcbiAgICAgICAgZXYucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgICBpZiAodGhpcy5zdGF0ZS5wYXNzUGhyYXNlLmxlbmd0aCA8PSAwKSByZXR1cm47XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7IGtleU1hdGNoZXM6IG51bGwgfSk7XG4gICAgICAgIGNvbnN0IGlucHV0ID0geyBwYXNzcGhyYXNlOiB0aGlzLnN0YXRlLnBhc3NQaHJhc2UgfTtcbiAgICAgICAgY29uc3Qga2V5TWF0Y2hlcyA9IGF3YWl0IHRoaXMucHJvcHMuY2hlY2tQcml2YXRlS2V5KGlucHV0KTtcbiAgICAgICAgaWYgKGtleU1hdGNoZXMpIHtcbiAgICAgICAgICAgIHRoaXMucHJvcHMub25GaW5pc2hlZChpbnB1dCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHsga2V5TWF0Y2hlcyB9KTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBwcml2YXRlIG9uUmVjb3ZlcnlLZXlOZXh0ID0gYXN5bmMgKGV2OiBGb3JtRXZlbnQ8SFRNTEZvcm1FbGVtZW50PikgPT4ge1xuICAgICAgICBldi5wcmV2ZW50RGVmYXVsdCgpO1xuXG4gICAgICAgIGlmICghdGhpcy5zdGF0ZS5yZWNvdmVyeUtleVZhbGlkKSByZXR1cm47XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7IGtleU1hdGNoZXM6IG51bGwgfSk7XG4gICAgICAgIGNvbnN0IGlucHV0ID0geyByZWNvdmVyeUtleTogdGhpcy5zdGF0ZS5yZWNvdmVyeUtleSB9O1xuICAgICAgICBjb25zdCBrZXlNYXRjaGVzID0gYXdhaXQgdGhpcy5wcm9wcy5jaGVja1ByaXZhdGVLZXkoaW5wdXQpO1xuICAgICAgICBpZiAoa2V5TWF0Y2hlcykge1xuICAgICAgICAgICAgdGhpcy5wcm9wcy5vbkZpbmlzaGVkKGlucHV0KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoeyBrZXlNYXRjaGVzIH0pO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHByaXZhdGUgb25QYXNzUGhyYXNlQ2hhbmdlID0gKGV2OiBDaGFuZ2VFdmVudDxIVE1MSW5wdXRFbGVtZW50PikgPT4ge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHBhc3NQaHJhc2U6IGV2LnRhcmdldC52YWx1ZSxcbiAgICAgICAgICAgIGtleU1hdGNoZXM6IG51bGwsXG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICBwcml2YXRlIG9uUmVzZXRBbGxDbGljayA9IChldjogUmVhY3QuTW91c2VFdmVudDxIVE1MQW5jaG9yRWxlbWVudD4pID0+IHtcbiAgICAgICAgZXYucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7cmVzZXR0aW5nOiB0cnVlfSk7XG4gICAgfTtcblxuICAgIHByaXZhdGUgb25Db25maXJtUmVzZXRBbGxDbGljayA9IGFzeW5jICgpID0+IHtcbiAgICAgICAgLy8gSGlkZSBvdXJzZWx2ZXMgc28gdGhlIHVzZXIgY2FuIGludGVyYWN0IHdpdGggdGhlIHJlc2V0IGRpYWxvZ3MuXG4gICAgICAgIC8vIFdlIGRvbid0IGNvbmNsdWRlIHRoZSBwcm9taXNlIGNoYWluIChvbkZpbmlzaGVkKSB5ZXQgdG8gYXZvaWQgY29uZnVzaW5nXG4gICAgICAgIC8vIGFueSB1cHN0cmVhbSBjb2RlIGZsb3dzLlxuICAgICAgICAvL1xuICAgICAgICAvLyBOb3RlOiB0aGlzIHdpbGwgdW5tb3VudCB1cywgc28gZG9uJ3QgY2FsbCBgc2V0U3RhdGVgIG9yIGFueXRoaW5nIGluIHRoZVxuICAgICAgICAvLyByZXN0IG9mIHRoaXMgZnVuY3Rpb24uXG4gICAgICAgIE1vZGFsLnRvZ2dsZUN1cnJlbnREaWFsb2dWaXNpYmlsaXR5KCk7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIC8vIEZvcmNlIHJlc2V0IHNlY3JldCBzdG9yYWdlICh3aGljaCByZXNldHMgdGhlIGtleSBiYWNrdXApXG4gICAgICAgICAgICBhd2FpdCBhY2Nlc3NTZWNyZXRTdG9yYWdlKGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgICAgICAvLyBOb3cgcmVzZXQgY3Jvc3Mtc2lnbmluZyBzbyBldmVyeXRoaW5nIEp1c3QgV29ya3PihKIgYWdhaW4uXG4gICAgICAgICAgICAgICAgY29uc3QgY2xpID0gTWF0cml4Q2xpZW50UGVnLmdldCgpO1xuICAgICAgICAgICAgICAgIGF3YWl0IGNsaS5ib290c3RyYXBDcm9zc1NpZ25pbmcoe1xuICAgICAgICAgICAgICAgICAgICBhdXRoVXBsb2FkRGV2aWNlU2lnbmluZ0tleXM6IGFzeW5jIChtYWtlUmVxdWVzdCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gWFhYOiBNYWtpbmcgdGhpcyBhbiBpbXBvcnQgYnJlYWtzIHRoZSBhcHAuXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBJbnRlcmFjdGl2ZUF1dGhEaWFsb2cgPSBzZGsuZ2V0Q29tcG9uZW50KFwidmlld3MuZGlhbG9ncy5JbnRlcmFjdGl2ZUF1dGhEaWFsb2dcIik7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB7ZmluaXNoZWR9ID0gTW9kYWwuY3JlYXRlVHJhY2tlZERpYWxvZyhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnQ3Jvc3Mtc2lnbmluZyBrZXlzIGRpYWxvZycsICcnLCBJbnRlcmFjdGl2ZUF1dGhEaWFsb2csXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZTogX3QoXCJTZXR0aW5nIHVwIGtleXNcIiksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hdHJpeENsaWVudDogY2xpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYWtlUmVxdWVzdCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IFtjb25maXJtZWRdID0gYXdhaXQgZmluaXNoZWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWNvbmZpcm1lZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkNyb3NzLXNpZ25pbmcga2V5IHVwbG9hZCBhdXRoIGNhbmNlbGVkXCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBzZXR1cE5ld0Nyb3NzU2lnbmluZzogdHJ1ZSxcbiAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgIC8vIE5vdyB3ZSBjYW4gaW5kaWNhdGUgdGhhdCB0aGUgdXNlciBpcyBkb25lIHByZXNzaW5nIGJ1dHRvbnMsIGZpbmFsbHkuXG4gICAgICAgICAgICAgICAgLy8gVXBzdHJlYW0gZmxvd3Mgd2lsbCBkZXRlY3QgdGhlIG5ldyBzZWNyZXQgc3RvcmFnZSwga2V5IGJhY2t1cCwgZXRjIGFuZCB1c2UgaXQuXG4gICAgICAgICAgICAgICAgdGhpcy5wcm9wcy5vbkZpbmlzaGVkKHRydWUpO1xuICAgICAgICAgICAgfSwgdHJ1ZSk7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZSk7XG4gICAgICAgICAgICB0aGlzLnByb3BzLm9uRmluaXNoZWQoZmFsc2UpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHByaXZhdGUgZ2V0S2V5VmFsaWRhdGlvblRleHQoKTogc3RyaW5nIHtcbiAgICAgICAgaWYgKHRoaXMuc3RhdGUucmVjb3ZlcnlLZXlGaWxlRXJyb3IpIHtcbiAgICAgICAgICAgIHJldHVybiBfdChcIldyb25nIGZpbGUgdHlwZVwiKTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLnJlY292ZXJ5S2V5Q29ycmVjdCkge1xuICAgICAgICAgICAgcmV0dXJuIF90KFwiTG9va3MgZ29vZCFcIik7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5yZWNvdmVyeUtleVZhbGlkKSB7XG4gICAgICAgICAgICByZXR1cm4gX3QoXCJXcm9uZyBTZWN1cml0eSBLZXlcIik7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5zdGF0ZS5yZWNvdmVyeUtleVZhbGlkID09PSBudWxsKSB7XG4gICAgICAgICAgICByZXR1cm4gJyc7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gX3QoXCJJbnZhbGlkIFNlY3VyaXR5IEtleVwiKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJlbmRlcigpIHtcbiAgICAgICAgLy8gQ2F1dGlvbjogTWFraW5nIHRoZXNlIGFuIGltcG9ydCB3aWxsIGJyZWFrIHRlc3RzLlxuICAgICAgICBjb25zdCBCYXNlRGlhbG9nID0gc2RrLmdldENvbXBvbmVudChcInZpZXdzLmRpYWxvZ3MuQmFzZURpYWxvZ1wiKTtcbiAgICAgICAgY29uc3QgRGlhbG9nQnV0dG9ucyA9IHNkay5nZXRDb21wb25lbnQoXCJ2aWV3cy5lbGVtZW50cy5EaWFsb2dCdXR0b25zXCIpO1xuXG4gICAgICAgIGNvbnN0IGhhc1Bhc3NwaHJhc2UgPSAoXG4gICAgICAgICAgICB0aGlzLnByb3BzLmtleUluZm8gJiZcbiAgICAgICAgICAgIHRoaXMucHJvcHMua2V5SW5mby5wYXNzcGhyYXNlICYmXG4gICAgICAgICAgICB0aGlzLnByb3BzLmtleUluZm8ucGFzc3BocmFzZS5zYWx0ICYmXG4gICAgICAgICAgICB0aGlzLnByb3BzLmtleUluZm8ucGFzc3BocmFzZS5pdGVyYXRpb25zXG4gICAgICAgICk7XG5cbiAgICAgICAgY29uc3QgcmVzZXRCdXR0b24gPSAoXG4gICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cIm14X0FjY2Vzc1NlY3JldFN0b3JhZ2VEaWFsb2dfcmVzZXRcIj5cbiAgICAgICAgICAgICAgICB7X3QoXCJGb3Jnb3R0ZW4gb3IgbG9zdCBhbGwgcmVjb3ZlcnkgbWV0aG9kcz8gPGE+UmVzZXQgYWxsPC9hPlwiLCBudWxsLCB7XG4gICAgICAgICAgICAgICAgICAgIGE6IChzdWIpID0+IDxhXG4gICAgICAgICAgICAgICAgICAgICAgICBocmVmPVwiXCIgb25DbGljaz17dGhpcy5vblJlc2V0QWxsQ2xpY2t9XG4gICAgICAgICAgICAgICAgICAgICAgICBjbGFzc05hbWU9XCJteF9BY2Nlc3NTZWNyZXRTdG9yYWdlRGlhbG9nX3Jlc2V0X2xpbmtcIj57c3VifTwvYT4sXG4gICAgICAgICAgICAgICAgfSl9XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgKTtcblxuICAgICAgICBsZXQgY29udGVudDtcbiAgICAgICAgbGV0IHRpdGxlO1xuICAgICAgICBsZXQgdGl0bGVDbGFzcztcbiAgICAgICAgaWYgKHRoaXMuc3RhdGUucmVzZXR0aW5nKSB7XG4gICAgICAgICAgICB0aXRsZSA9IF90KFwiUmVzZXQgZXZlcnl0aGluZ1wiKTtcbiAgICAgICAgICAgIHRpdGxlQ2xhc3MgPSBbJ214X0FjY2Vzc1NlY3JldFN0b3JhZ2VEaWFsb2dfdGl0bGVXaXRoSWNvbiBteF9BY2Nlc3NTZWNyZXRTdG9yYWdlRGlhbG9nX3Jlc2V0QmFkZ2UnXTtcbiAgICAgICAgICAgIGNvbnRlbnQgPSA8ZGl2PlxuICAgICAgICAgICAgICAgIDxwPntfdChcIk9ubHkgZG8gdGhpcyBpZiB5b3UgaGF2ZSBubyBvdGhlciBkZXZpY2UgdG8gY29tcGxldGUgdmVyaWZpY2F0aW9uIHdpdGguXCIpfTwvcD5cbiAgICAgICAgICAgICAgICA8cD57X3QoXCJJZiB5b3UgcmVzZXQgZXZlcnl0aGluZywgeW91IHdpbGwgcmVzdGFydCB3aXRoIG5vIHRydXN0ZWQgc2Vzc2lvbnMsIG5vIHRydXN0ZWQgdXNlcnMsIGFuZCBcIlxuICAgICAgICAgICAgICAgICAgICArIFwibWlnaHQgbm90IGJlIGFibGUgdG8gc2VlIHBhc3QgbWVzc2FnZXMuXCIpfTwvcD5cbiAgICAgICAgICAgICAgICA8RGlhbG9nQnV0dG9uc1xuICAgICAgICAgICAgICAgICAgICBwcmltYXJ5QnV0dG9uPXtfdCgnUmVzZXQnKX1cbiAgICAgICAgICAgICAgICAgICAgb25QcmltYXJ5QnV0dG9uQ2xpY2s9e3RoaXMub25Db25maXJtUmVzZXRBbGxDbGlja31cbiAgICAgICAgICAgICAgICAgICAgaGFzQ2FuY2VsPXt0cnVlfVxuICAgICAgICAgICAgICAgICAgICBvbkNhbmNlbD17dGhpcy5vbkNhbmNlbH1cbiAgICAgICAgICAgICAgICAgICAgZm9jdXM9e2ZhbHNlfVxuICAgICAgICAgICAgICAgICAgICBwcmltYXJ5QnV0dG9uQ2xhc3M9XCJkYW5nZXJcIlxuICAgICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICA8L2Rpdj47XG4gICAgICAgIH0gZWxzZSBpZiAoaGFzUGFzc3BocmFzZSAmJiAhdGhpcy5zdGF0ZS5mb3JjZVJlY292ZXJ5S2V5KSB7XG4gICAgICAgICAgICBjb25zdCBBY2Nlc3NpYmxlQnV0dG9uID0gc2RrLmdldENvbXBvbmVudCgnZWxlbWVudHMuQWNjZXNzaWJsZUJ1dHRvbicpO1xuICAgICAgICAgICAgdGl0bGUgPSBfdChcIlNlY3VyaXR5IFBocmFzZVwiKTtcbiAgICAgICAgICAgIHRpdGxlQ2xhc3MgPSBbJ214X0FjY2Vzc1NlY3JldFN0b3JhZ2VEaWFsb2dfdGl0bGVXaXRoSWNvbiBteF9BY2Nlc3NTZWNyZXRTdG9yYWdlRGlhbG9nX3NlY3VyZVBocmFzZVRpdGxlJ107XG5cbiAgICAgICAgICAgIGxldCBrZXlTdGF0dXM7XG4gICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5rZXlNYXRjaGVzID09PSBmYWxzZSkge1xuICAgICAgICAgICAgICAgIGtleVN0YXR1cyA9IDxkaXYgY2xhc3NOYW1lPVwibXhfQWNjZXNzU2VjcmV0U3RvcmFnZURpYWxvZ19rZXlTdGF0dXNcIj5cbiAgICAgICAgICAgICAgICAgICAge1wiXFx1RDgzRFxcdURDNEUgXCJ9e190KFxuICAgICAgICAgICAgICAgICAgICAgICAgXCJVbmFibGUgdG8gYWNjZXNzIHNlY3JldCBzdG9yYWdlLiBcIiArXG4gICAgICAgICAgICAgICAgICAgICAgICBcIlBsZWFzZSB2ZXJpZnkgdGhhdCB5b3UgZW50ZXJlZCB0aGUgY29ycmVjdCBTZWN1cml0eSBQaHJhc2UuXCIsXG4gICAgICAgICAgICAgICAgICAgICl9XG4gICAgICAgICAgICAgICAgPC9kaXY+O1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBrZXlTdGF0dXMgPSA8ZGl2IGNsYXNzTmFtZT1cIm14X0FjY2Vzc1NlY3JldFN0b3JhZ2VEaWFsb2dfa2V5U3RhdHVzXCIgLz47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnRlbnQgPSA8ZGl2PlxuICAgICAgICAgICAgICAgIDxwPntfdChcbiAgICAgICAgICAgICAgICAgICAgXCJFbnRlciB5b3VyIFNlY3VyaXR5IFBocmFzZSBvciA8YnV0dG9uPlVzZSB5b3VyIFNlY3VyaXR5IEtleTwvYnV0dG9uPiB0byBjb250aW51ZS5cIiwge30sXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJ1dHRvbjogcyA9PiA8QWNjZXNzaWJsZUJ1dHRvbiBjbGFzc05hbWU9XCJteF9saW5rQnV0dG9uXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50PVwic3BhblwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb25DbGljaz17dGhpcy5vblVzZVJlY292ZXJ5S2V5Q2xpY2t9XG4gICAgICAgICAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAge3N9XG4gICAgICAgICAgICAgICAgICAgICAgICA8L0FjY2Vzc2libGVCdXR0b24+LFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICl9PC9wPlxuXG4gICAgICAgICAgICAgICAgPGZvcm0gY2xhc3NOYW1lPVwibXhfQWNjZXNzU2VjcmV0U3RvcmFnZURpYWxvZ19wcmltYXJ5Q29udGFpbmVyXCIgb25TdWJtaXQ9e3RoaXMub25QYXNzUGhyYXNlTmV4dH0+XG4gICAgICAgICAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICAgICAgICAgICAgdHlwZT1cInBhc3N3b3JkXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlkPVwibXhfcGFzc1BocmFzZUlucHV0XCJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzTmFtZT1cIm14X0FjY2Vzc1NlY3JldFN0b3JhZ2VEaWFsb2dfcGFzc1BocmFzZUlucHV0XCJcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uQ2hhbmdlPXt0aGlzLm9uUGFzc1BocmFzZUNoYW5nZX1cbiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPXt0aGlzLnN0YXRlLnBhc3NQaHJhc2V9XG4gICAgICAgICAgICAgICAgICAgICAgICBhdXRvRm9jdXM9e3RydWV9XG4gICAgICAgICAgICAgICAgICAgICAgICBhdXRvQ29tcGxldGU9XCJuZXctcGFzc3dvcmRcIlxuICAgICAgICAgICAgICAgICA