UNPKG

matrix-react-sdk

Version:
276 lines (272 loc) 44 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.SetupEncryptionStore = exports.Phase = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _events = _interopRequireDefault(require("events")); var _cryptoApi = require("matrix-js-sdk/src/crypto-api"); var _logger = require("matrix-js-sdk/src/logger"); var _crypto = require("matrix-js-sdk/src/crypto"); var _MatrixClientPeg = require("../MatrixClientPeg"); var _SecurityManager = require("../SecurityManager"); var _Modal = _interopRequireDefault(require("../Modal")); var _InteractiveAuthDialog = _interopRequireDefault(require("../components/views/dialogs/InteractiveAuthDialog")); var _languageHandler = require("../languageHandler"); var _SDKContext = require("../contexts/SDKContext"); var _arrays = require("../utils/arrays"); var _dehydration = require("../utils/device/dehydration"); /* Copyright 2024 New Vector Ltd. Copyright 2020-2024 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. */ let Phase = exports.Phase = /*#__PURE__*/function (Phase) { Phase[Phase["Loading"] = 0] = "Loading"; Phase[Phase["Intro"] = 1] = "Intro"; Phase[Phase["Busy"] = 2] = "Busy"; Phase[Phase["Done"] = 3] = "Done"; Phase[Phase["ConfirmSkip"] = 4] = "ConfirmSkip"; Phase[Phase["Finished"] = 5] = "Finished"; Phase[Phase["ConfirmReset"] = 6] = "ConfirmReset"; return Phase; }({}); class SetupEncryptionStore extends _events.default { constructor(...args) { super(...args); (0, _defineProperty2.default)(this, "started", void 0); (0, _defineProperty2.default)(this, "phase", void 0); (0, _defineProperty2.default)(this, "verificationRequest", null); (0, _defineProperty2.default)(this, "backupInfo", null); // ID of the key that the secrets we want are encrypted with (0, _defineProperty2.default)(this, "keyId", null); // Descriptor of the key that the secrets we want are encrypted with (0, _defineProperty2.default)(this, "keyInfo", null); (0, _defineProperty2.default)(this, "hasDevicesToVerifyAgainst", void 0); (0, _defineProperty2.default)(this, "onUserTrustStatusChanged", async userId => { if (userId !== _MatrixClientPeg.MatrixClientPeg.safeGet().getSafeUserId()) return; const publicKeysTrusted = await _MatrixClientPeg.MatrixClientPeg.safeGet().getCrypto()?.getCrossSigningKeyId(); if (publicKeysTrusted) { this.phase = Phase.Done; this.emit("update"); } }); (0, _defineProperty2.default)(this, "onVerificationRequest", request => { this.setActiveVerificationRequest(request); }); (0, _defineProperty2.default)(this, "onVerificationRequestChange", async () => { if (this.verificationRequest?.phase === _cryptoApi.VerificationPhase.Cancelled) { this.verificationRequest.off(_cryptoApi.VerificationRequestEvent.Change, this.onVerificationRequestChange); this.verificationRequest = null; this.emit("update"); } else if (this.verificationRequest?.phase === _cryptoApi.VerificationPhase.Done) { this.verificationRequest.off(_cryptoApi.VerificationRequestEvent.Change, this.onVerificationRequestChange); this.verificationRequest = null; // At this point, the verification has finished, we just need to wait for // cross signing to be ready to use, so wait for the user trust status to // change (or change to DONE if it's already ready). const publicKeysTrusted = await _MatrixClientPeg.MatrixClientPeg.safeGet().getCrypto()?.getCrossSigningKeyId(); this.phase = publicKeysTrusted ? Phase.Done : Phase.Busy; this.emit("update"); } }); } static sharedInstance() { if (!window.mxSetupEncryptionStore) window.mxSetupEncryptionStore = new SetupEncryptionStore(); return window.mxSetupEncryptionStore; } start() { if (this.started) { return; } this.started = true; this.phase = Phase.Loading; const cli = _MatrixClientPeg.MatrixClientPeg.safeGet(); cli.on(_crypto.CryptoEvent.VerificationRequestReceived, this.onVerificationRequest); cli.on(_crypto.CryptoEvent.UserTrustStatusChanged, this.onUserTrustStatusChanged); const requestsInProgress = cli.getCrypto().getVerificationRequestsToDeviceInProgress(cli.getUserId()); if (requestsInProgress.length) { // If there are multiple, we take the most recent. Equally if the user sends another request from // another device after this screen has been shown, we'll switch to the new one, so this // generally doesn't support multiple requests. this.setActiveVerificationRequest(requestsInProgress[requestsInProgress.length - 1]); } this.fetchKeyInfo(); } stop() { if (!this.started) { return; } this.started = false; this.verificationRequest?.off(_cryptoApi.VerificationRequestEvent.Change, this.onVerificationRequestChange); const cli = _MatrixClientPeg.MatrixClientPeg.get(); if (!!cli) { cli.removeListener(_crypto.CryptoEvent.VerificationRequestReceived, this.onVerificationRequest); cli.removeListener(_crypto.CryptoEvent.UserTrustStatusChanged, this.onUserTrustStatusChanged); } } async fetchKeyInfo() { if (!this.started) return; // bail if we were stopped const cli = _MatrixClientPeg.MatrixClientPeg.safeGet(); const keys = await cli.secretStorage.isStored("m.cross_signing.master"); if (keys === null || Object.keys(keys).length === 0) { this.keyId = null; this.keyInfo = null; } else { // If the secret is stored under more than one key, we just pick an arbitrary one this.keyId = Object.keys(keys)[0]; this.keyInfo = keys[this.keyId]; } // do we have any other verified devices which are E2EE which we can verify against? const dehydratedDevice = await cli.getDehydratedDevice(); const ownUserId = cli.getUserId(); const crypto = cli.getCrypto(); const userDevices = (await crypto.getUserDeviceInfo([ownUserId])).get(ownUserId)?.values() ?? []; this.hasDevicesToVerifyAgainst = await (0, _arrays.asyncSome)(userDevices, async device => { // Ignore dehydrated devices. `dehydratedDevice` is set by the // implementation of MSC2697, whereas MSC3814 proposes that devices // should set a `dehydrated` flag in the device key. We ignore // both types of dehydrated devices. if (dehydratedDevice && device.deviceId == dehydratedDevice?.device_id) return false; if (device.dehydrated) return false; // ignore devices without an identity key if (!device.getIdentityKey()) return false; const verificationStatus = await crypto.getDeviceVerificationStatus(ownUserId, device.deviceId); return !!verificationStatus?.signedByOwner; }); this.phase = Phase.Intro; this.emit("update"); } async usePassPhrase() { _logger.logger.debug("SetupEncryptionStore.usePassphrase"); this.phase = Phase.Busy; this.emit("update"); try { const cli = _MatrixClientPeg.MatrixClientPeg.safeGet(); const backupInfo = await cli.getKeyBackupVersion(); this.backupInfo = backupInfo; this.emit("update"); await new Promise((resolve, reject) => { (0, _SecurityManager.accessSecretStorage)(async () => { // `accessSecretStorage` will call `boostrapCrossSigning` and `bootstrapSecretStorage`, so that // should be enough to ensure that our device is correctly cross-signed. // // The remaining tasks (device dehydration and restoring key backup) may take some time due to // processing many to-device messages in the case of device dehydration, or having many keys to // restore in the case of key backups, so we allow the dialog to advance before this. // // However, we need to keep the 4S key cached, so we stay inside `accessSecretStorage`. _logger.logger.debug("SetupEncryptionStore.usePassphrase: cross-signing and secret storage set up; checking " + "dehydration and backup in the background"); resolve(); await (0, _dehydration.initialiseDehydration)(); if (backupInfo) { await cli.restoreKeyBackupWithSecretStorage(backupInfo); } }).catch(reject); }); if (await cli.getCrypto()?.getCrossSigningKeyId()) { _logger.logger.debug("SetupEncryptionStore.usePassphrase: done"); this.phase = Phase.Done; this.emit("update"); } } catch (e) { if (e instanceof _SecurityManager.AccessCancelledError) { _logger.logger.debug("SetupEncryptionStore.usePassphrase: user cancelled access to secret storage"); } else { _logger.logger.log("SetupEncryptionStore.usePassphrase: error", e); } this.phase = Phase.Intro; this.emit("update"); } } skip() { this.phase = Phase.ConfirmSkip; this.emit("update"); } skipConfirm() { this.phase = Phase.Finished; this.emit("update"); } returnAfterSkip() { this.phase = Phase.Intro; this.emit("update"); } reset() { this.phase = Phase.ConfirmReset; this.emit("update"); } async resetConfirm() { try { // If we've gotten here, the user presumably lost their // secret storage key if they had one. Start by resetting // secret storage and setting up a new recovery key, then // create new cross-signing keys once that succeeds. await (0, _SecurityManager.accessSecretStorage)(async () => { const cli = _MatrixClientPeg.MatrixClientPeg.safeGet(); await cli.getCrypto()?.bootstrapCrossSigning({ authUploadDeviceSigningKeys: async makeRequest => { const cachedPassword = _SDKContext.SdkContextClass.instance.accountPasswordStore.getPassword(); if (cachedPassword) { await makeRequest({ type: "m.login.password", identifier: { type: "m.id.user", user: cli.getSafeUserId() }, user: cli.getSafeUserId(), password: cachedPassword }); return; } 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 }); await (0, _dehydration.initialiseDehydration)(true); this.phase = Phase.Finished; }, true); } catch (e) { _logger.logger.error("Error resetting cross-signing", e); this.phase = Phase.Intro; } this.emit("update"); } returnAfterReset() { this.phase = Phase.Intro; this.emit("update"); } done() { this.phase = Phase.Finished; this.emit("update"); // async - ask other clients for keys, if necessary _MatrixClientPeg.MatrixClientPeg.safeGet().crypto?.cancelAndResendAllOutgoingKeyRequests(); } async setActiveVerificationRequest(request) { if (!this.started) return; // bail if we were stopped if (request.otherUserId !== _MatrixClientPeg.MatrixClientPeg.safeGet().getUserId()) return; if (this.verificationRequest) { this.verificationRequest.off(_cryptoApi.VerificationRequestEvent.Change, this.onVerificationRequestChange); } this.verificationRequest = request; await request.accept(); request.on(_cryptoApi.VerificationRequestEvent.Change, this.onVerificationRequestChange); this.emit("update"); } lostKeys() { return !this.hasDevicesToVerifyAgainst && !this.keyInfo; } } exports.SetupEncryptionStore = SetupEncryptionStore; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfZXZlbnRzIiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfY3J5cHRvQXBpIiwiX2xvZ2dlciIsIl9jcnlwdG8iLCJfTWF0cml4Q2xpZW50UGVnIiwiX1NlY3VyaXR5TWFuYWdlciIsIl9Nb2RhbCIsIl9JbnRlcmFjdGl2ZUF1dGhEaWFsb2ciLCJfbGFuZ3VhZ2VIYW5kbGVyIiwiX1NES0NvbnRleHQiLCJfYXJyYXlzIiwiX2RlaHlkcmF0aW9uIiwiUGhhc2UiLCJleHBvcnRzIiwiU2V0dXBFbmNyeXB0aW9uU3RvcmUiLCJFdmVudEVtaXR0ZXIiLCJjb25zdHJ1Y3RvciIsImFyZ3MiLCJfZGVmaW5lUHJvcGVydHkyIiwiZGVmYXVsdCIsInVzZXJJZCIsIk1hdHJpeENsaWVudFBlZyIsInNhZmVHZXQiLCJnZXRTYWZlVXNlcklkIiwicHVibGljS2V5c1RydXN0ZWQiLCJnZXRDcnlwdG8iLCJnZXRDcm9zc1NpZ25pbmdLZXlJZCIsInBoYXNlIiwiRG9uZSIsImVtaXQiLCJyZXF1ZXN0Iiwic2V0QWN0aXZlVmVyaWZpY2F0aW9uUmVxdWVzdCIsInZlcmlmaWNhdGlvblJlcXVlc3QiLCJWZXJpZmljYXRpb25QaGFzZSIsIkNhbmNlbGxlZCIsIm9mZiIsIlZlcmlmaWNhdGlvblJlcXVlc3RFdmVudCIsIkNoYW5nZSIsIm9uVmVyaWZpY2F0aW9uUmVxdWVzdENoYW5nZSIsIkJ1c3kiLCJzaGFyZWRJbnN0YW5jZSIsIndpbmRvdyIsIm14U2V0dXBFbmNyeXB0aW9uU3RvcmUiLCJzdGFydCIsInN0YXJ0ZWQiLCJMb2FkaW5nIiwiY2xpIiwib24iLCJDcnlwdG9FdmVudCIsIlZlcmlmaWNhdGlvblJlcXVlc3RSZWNlaXZlZCIsIm9uVmVyaWZpY2F0aW9uUmVxdWVzdCIsIlVzZXJUcnVzdFN0YXR1c0NoYW5nZWQiLCJvblVzZXJUcnVzdFN0YXR1c0NoYW5nZWQiLCJyZXF1ZXN0c0luUHJvZ3Jlc3MiLCJnZXRWZXJpZmljYXRpb25SZXF1ZXN0c1RvRGV2aWNlSW5Qcm9ncmVzcyIsImdldFVzZXJJZCIsImxlbmd0aCIsImZldGNoS2V5SW5mbyIsInN0b3AiLCJnZXQiLCJyZW1vdmVMaXN0ZW5lciIsImtleXMiLCJzZWNyZXRTdG9yYWdlIiwiaXNTdG9yZWQiLCJPYmplY3QiLCJrZXlJZCIsImtleUluZm8iLCJkZWh5ZHJhdGVkRGV2aWNlIiwiZ2V0RGVoeWRyYXRlZERldmljZSIsIm93blVzZXJJZCIsImNyeXB0byIsInVzZXJEZXZpY2VzIiwiZ2V0VXNlckRldmljZUluZm8iLCJ2YWx1ZXMiLCJoYXNEZXZpY2VzVG9WZXJpZnlBZ2FpbnN0IiwiYXN5bmNTb21lIiwiZGV2aWNlIiwiZGV2aWNlSWQiLCJkZXZpY2VfaWQiLCJkZWh5ZHJhdGVkIiwiZ2V0SWRlbnRpdHlLZXkiLCJ2ZXJpZmljYXRpb25TdGF0dXMiLCJnZXREZXZpY2VWZXJpZmljYXRpb25TdGF0dXMiLCJzaWduZWRCeU93bmVyIiwiSW50cm8iLCJ1c2VQYXNzUGhyYXNlIiwibG9nZ2VyIiwiZGVidWciLCJiYWNrdXBJbmZvIiwiZ2V0S2V5QmFja3VwVmVyc2lvbiIsIlByb21pc2UiLCJyZXNvbHZlIiwicmVqZWN0IiwiYWNjZXNzU2VjcmV0U3RvcmFnZSIsImluaXRpYWxpc2VEZWh5ZHJhdGlvbiIsInJlc3RvcmVLZXlCYWNrdXBXaXRoU2VjcmV0U3RvcmFnZSIsImNhdGNoIiwiZSIsIkFjY2Vzc0NhbmNlbGxlZEVycm9yIiwibG9nIiwic2tpcCIsIkNvbmZpcm1Ta2lwIiwic2tpcENvbmZpcm0iLCJGaW5pc2hlZCIsInJldHVybkFmdGVyU2tpcCIsInJlc2V0IiwiQ29uZmlybVJlc2V0IiwicmVzZXRDb25maXJtIiwiYm9vdHN0cmFwQ3Jvc3NTaWduaW5nIiwiYXV0aFVwbG9hZERldmljZVNpZ25pbmdLZXlzIiwibWFrZVJlcXVlc3QiLCJjYWNoZWRQYXNzd29yZCIsIlNka0NvbnRleHRDbGFzcyIsImluc3RhbmNlIiwiYWNjb3VudFBhc3N3b3JkU3RvcmUiLCJnZXRQYXNzd29yZCIsInR5cGUiLCJpZGVudGlmaWVyIiwidXNlciIsInBhc3N3b3JkIiwiZmluaXNoZWQiLCJNb2RhbCIsImNyZWF0ZURpYWxvZyIsIkludGVyYWN0aXZlQXV0aERpYWxvZyIsInRpdGxlIiwiX3QiLCJtYXRyaXhDbGllbnQiLCJjb25maXJtZWQiLCJFcnJvciIsInNldHVwTmV3Q3Jvc3NTaWduaW5nIiwiZXJyb3IiLCJyZXR1cm5BZnRlclJlc2V0IiwiZG9uZSIsImNhbmNlbEFuZFJlc2VuZEFsbE91dGdvaW5nS2V5UmVxdWVzdHMiLCJvdGhlclVzZXJJZCIsImFjY2VwdCIsImxvc3RLZXlzIl0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL3N0b3Jlcy9TZXR1cEVuY3J5cHRpb25TdG9yZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuQ29weXJpZ2h0IDIwMjQgTmV3IFZlY3RvciBMdGQuXG5Db3B5cmlnaHQgMjAyMC0yMDI0IFRoZSBNYXRyaXgub3JnIEZvdW5kYXRpb24gQy5JLkMuXG5cblNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBR1BMLTMuMC1vbmx5IE9SIEdQTC0zLjAtb25seVxuUGxlYXNlIHNlZSBMSUNFTlNFIGZpbGVzIGluIHRoZSByZXBvc2l0b3J5IHJvb3QgZm9yIGZ1bGwgZGV0YWlscy5cbiovXG5cbmltcG9ydCBFdmVudEVtaXR0ZXIgZnJvbSBcImV2ZW50c1wiO1xuaW1wb3J0IHtcbiAgICBLZXlCYWNrdXBJbmZvLFxuICAgIFZlcmlmaWNhdGlvblBoYXNlLFxuICAgIFZlcmlmaWNhdGlvblJlcXVlc3QsXG4gICAgVmVyaWZpY2F0aW9uUmVxdWVzdEV2ZW50LFxufSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvY3J5cHRvLWFwaVwiO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL2xvZ2dlclwiO1xuaW1wb3J0IHsgQ3J5cHRvRXZlbnQgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvY3J5cHRvXCI7XG5pbXBvcnQgeyBEZXZpY2UsIFNlY3JldFN0b3JhZ2UgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvbWF0cml4XCI7XG5cbmltcG9ydCB7IE1hdHJpeENsaWVudFBlZyB9IGZyb20gXCIuLi9NYXRyaXhDbGllbnRQZWdcIjtcbmltcG9ydCB7IEFjY2Vzc0NhbmNlbGxlZEVycm9yLCBhY2Nlc3NTZWNyZXRTdG9yYWdlIH0gZnJvbSBcIi4uL1NlY3VyaXR5TWFuYWdlclwiO1xuaW1wb3J0IE1vZGFsIGZyb20gXCIuLi9Nb2RhbFwiO1xuaW1wb3J0IEludGVyYWN0aXZlQXV0aERpYWxvZyBmcm9tIFwiLi4vY29tcG9uZW50cy92aWV3cy9kaWFsb2dzL0ludGVyYWN0aXZlQXV0aERpYWxvZ1wiO1xuaW1wb3J0IHsgX3QgfSBmcm9tIFwiLi4vbGFuZ3VhZ2VIYW5kbGVyXCI7XG5pbXBvcnQgeyBTZGtDb250ZXh0Q2xhc3MgfSBmcm9tIFwiLi4vY29udGV4dHMvU0RLQ29udGV4dFwiO1xuaW1wb3J0IHsgYXN5bmNTb21lIH0gZnJvbSBcIi4uL3V0aWxzL2FycmF5c1wiO1xuaW1wb3J0IHsgaW5pdGlhbGlzZURlaHlkcmF0aW9uIH0gZnJvbSBcIi4uL3V0aWxzL2RldmljZS9kZWh5ZHJhdGlvblwiO1xuXG5leHBvcnQgZW51bSBQaGFzZSB7XG4gICAgTG9hZGluZyA9IDAsXG4gICAgSW50cm8gPSAxLFxuICAgIEJ1c3kgPSAyLFxuICAgIERvbmUgPSAzLCAvLyBmaW5hbCBkb25lIHN0YWdlLCBidXQgc3RpbGwgc2hvd2luZyBVWFxuICAgIENvbmZpcm1Ta2lwID0gNCxcbiAgICBGaW5pc2hlZCA9IDUsIC8vIFVYIGNhbiBiZSBjbG9zZWRcbiAgICBDb25maXJtUmVzZXQgPSA2LFxufVxuXG5leHBvcnQgY2xhc3MgU2V0dXBFbmNyeXB0aW9uU3RvcmUgZXh0ZW5kcyBFdmVudEVtaXR0ZXIge1xuICAgIHByaXZhdGUgc3RhcnRlZD86IGJvb2xlYW47XG4gICAgcHVibGljIHBoYXNlPzogUGhhc2U7XG4gICAgcHVibGljIHZlcmlmaWNhdGlvblJlcXVlc3Q6IFZlcmlmaWNhdGlvblJlcXVlc3QgfCBudWxsID0gbnVsbDtcbiAgICBwdWJsaWMgYmFja3VwSW5mbzogS2V5QmFja3VwSW5mbyB8IG51bGwgPSBudWxsO1xuICAgIC8vIElEIG9mIHRoZSBrZXkgdGhhdCB0aGUgc2VjcmV0cyB3ZSB3YW50IGFyZSBlbmNyeXB0ZWQgd2l0aFxuICAgIHB1YmxpYyBrZXlJZDogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG4gICAgLy8gRGVzY3JpcHRvciBvZiB0aGUga2V5IHRoYXQgdGhlIHNlY3JldHMgd2Ugd2FudCBhcmUgZW5jcnlwdGVkIHdpdGhcbiAgICBwdWJsaWMga2V5SW5mbzogU2VjcmV0U3RvcmFnZS5TZWNyZXRTdG9yYWdlS2V5RGVzY3JpcHRpb24gfCBudWxsID0gbnVsbDtcbiAgICBwdWJsaWMgaGFzRGV2aWNlc1RvVmVyaWZ5QWdhaW5zdD86IGJvb2xlYW47XG5cbiAgICBwdWJsaWMgc3RhdGljIHNoYXJlZEluc3RhbmNlKCk6IFNldHVwRW5jcnlwdGlvblN0b3JlIHtcbiAgICAgICAgaWYgKCF3aW5kb3cubXhTZXR1cEVuY3J5cHRpb25TdG9yZSkgd2luZG93Lm14U2V0dXBFbmNyeXB0aW9uU3RvcmUgPSBuZXcgU2V0dXBFbmNyeXB0aW9uU3RvcmUoKTtcbiAgICAgICAgcmV0dXJuIHdpbmRvdy5teFNldHVwRW5jcnlwdGlvblN0b3JlO1xuICAgIH1cblxuICAgIHB1YmxpYyBzdGFydCgpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMuc3RhcnRlZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuc3RhcnRlZCA9IHRydWU7XG4gICAgICAgIHRoaXMucGhhc2UgPSBQaGFzZS5Mb2FkaW5nO1xuXG4gICAgICAgIGNvbnN0IGNsaSA9IE1hdHJpeENsaWVudFBlZy5zYWZlR2V0KCk7XG4gICAgICAgIGNsaS5vbihDcnlwdG9FdmVudC5WZXJpZmljYXRpb25SZXF1ZXN0UmVjZWl2ZWQsIHRoaXMub25WZXJpZmljYXRpb25SZXF1ZXN0KTtcbiAgICAgICAgY2xpLm9uKENyeXB0b0V2ZW50LlVzZXJUcnVzdFN0YXR1c0NoYW5nZWQsIHRoaXMub25Vc2VyVHJ1c3RTdGF0dXNDaGFuZ2VkKTtcblxuICAgICAgICBjb25zdCByZXF1ZXN0c0luUHJvZ3Jlc3MgPSBjbGkuZ2V0Q3J5cHRvKCkhLmdldFZlcmlmaWNhdGlvblJlcXVlc3RzVG9EZXZpY2VJblByb2dyZXNzKGNsaS5nZXRVc2VySWQoKSEpO1xuICAgICAgICBpZiAocmVxdWVzdHNJblByb2dyZXNzLmxlbmd0aCkge1xuICAgICAgICAgICAgLy8gSWYgdGhlcmUgYXJlIG11bHRpcGxlLCB3ZSB0YWtlIHRoZSBtb3N0IHJlY2VudC4gRXF1YWxseSBpZiB0aGUgdXNlciBzZW5kcyBhbm90aGVyIHJlcXVlc3QgZnJvbVxuICAgICAgICAgICAgLy8gYW5vdGhlciBkZXZpY2UgYWZ0ZXIgdGhpcyBzY3JlZW4gaGFzIGJlZW4gc2hvd24sIHdlJ2xsIHN3aXRjaCB0byB0aGUgbmV3IG9uZSwgc28gdGhpc1xuICAgICAgICAgICAgLy8gZ2VuZXJhbGx5IGRvZXNuJ3Qgc3VwcG9ydCBtdWx0aXBsZSByZXF1ZXN0cy5cbiAgICAgICAgICAgIHRoaXMuc2V0QWN0aXZlVmVyaWZpY2F0aW9uUmVxdWVzdChyZXF1ZXN0c0luUHJvZ3Jlc3NbcmVxdWVzdHNJblByb2dyZXNzLmxlbmd0aCAtIDFdKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuZmV0Y2hLZXlJbmZvKCk7XG4gICAgfVxuXG4gICAgcHVibGljIHN0b3AoKTogdm9pZCB7XG4gICAgICAgIGlmICghdGhpcy5zdGFydGVkKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5zdGFydGVkID0gZmFsc2U7XG4gICAgICAgIHRoaXMudmVyaWZpY2F0aW9uUmVxdWVzdD8ub2ZmKFZlcmlmaWNhdGlvblJlcXVlc3RFdmVudC5DaGFuZ2UsIHRoaXMub25WZXJpZmljYXRpb25SZXF1ZXN0Q2hhbmdlKTtcblxuICAgICAgICBjb25zdCBjbGkgPSBNYXRyaXhDbGllbnRQZWcuZ2V0KCk7XG4gICAgICAgIGlmICghIWNsaSkge1xuICAgICAgICAgICAgY2xpLnJlbW92ZUxpc3RlbmVyKENyeXB0b0V2ZW50LlZlcmlmaWNhdGlvblJlcXVlc3RSZWNlaXZlZCwgdGhpcy5vblZlcmlmaWNhdGlvblJlcXVlc3QpO1xuICAgICAgICAgICAgY2xpLnJlbW92ZUxpc3RlbmVyKENyeXB0b0V2ZW50LlVzZXJUcnVzdFN0YXR1c0NoYW5nZWQsIHRoaXMub25Vc2VyVHJ1c3RTdGF0dXNDaGFuZ2VkKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBmZXRjaEtleUluZm8oKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICghdGhpcy5zdGFydGVkKSByZXR1cm47IC8vIGJhaWwgaWYgd2Ugd2VyZSBzdG9wcGVkXG4gICAgICAgIGNvbnN0IGNsaSA9IE1hdHJpeENsaWVudFBlZy5zYWZlR2V0KCk7XG4gICAgICAgIGNvbnN0IGtleXMgPSBhd2FpdCBjbGkuc2VjcmV0U3RvcmFnZS5pc1N0b3JlZChcIm0uY3Jvc3Nfc2lnbmluZy5tYXN0ZXJcIik7XG4gICAgICAgIGlmIChrZXlzID09PSBudWxsIHx8IE9iamVjdC5rZXlzKGtleXMpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgdGhpcy5rZXlJZCA9IG51bGw7XG4gICAgICAgICAgICB0aGlzLmtleUluZm8gPSBudWxsO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gSWYgdGhlIHNlY3JldCBpcyBzdG9yZWQgdW5kZXIgbW9yZSB0aGFuIG9uZSBrZXksIHdlIGp1c3QgcGljayBhbiBhcmJpdHJhcnkgb25lXG4gICAgICAgICAgICB0aGlzLmtleUlkID0gT2JqZWN0LmtleXMoa2V5cylbMF07XG4gICAgICAgICAgICB0aGlzLmtleUluZm8gPSBrZXlzW3RoaXMua2V5SWRdO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZG8gd2UgaGF2ZSBhbnkgb3RoZXIgdmVyaWZpZWQgZGV2aWNlcyB3aGljaCBhcmUgRTJFRSB3aGljaCB3ZSBjYW4gdmVyaWZ5IGFnYWluc3Q/XG4gICAgICAgIGNvbnN0IGRlaHlkcmF0ZWREZXZpY2UgPSBhd2FpdCBjbGkuZ2V0RGVoeWRyYXRlZERldmljZSgpO1xuICAgICAgICBjb25zdCBvd25Vc2VySWQgPSBjbGkuZ2V0VXNlcklkKCkhO1xuICAgICAgICBjb25zdCBjcnlwdG8gPSBjbGkuZ2V0Q3J5cHRvKCkhO1xuICAgICAgICBjb25zdCB1c2VyRGV2aWNlczogSXRlcmFibGU8RGV2aWNlPiA9XG4gICAgICAgICAgICAoYXdhaXQgY3J5cHRvLmdldFVzZXJEZXZpY2VJbmZvKFtvd25Vc2VySWRdKSkuZ2V0KG93blVzZXJJZCk/LnZhbHVlcygpID8/IFtdO1xuICAgICAgICB0aGlzLmhhc0RldmljZXNUb1ZlcmlmeUFnYWluc3QgPSBhd2FpdCBhc3luY1NvbWUodXNlckRldmljZXMsIGFzeW5jIChkZXZpY2UpID0+IHtcbiAgICAgICAgICAgIC8vIElnbm9yZSBkZWh5ZHJhdGVkIGRldmljZXMuICBgZGVoeWRyYXRlZERldmljZWAgaXMgc2V0IGJ5IHRoZVxuICAgICAgICAgICAgLy8gaW1wbGVtZW50YXRpb24gb2YgTVNDMjY5Nywgd2hlcmVhcyBNU0MzODE0IHByb3Bvc2VzIHRoYXQgZGV2aWNlc1xuICAgICAgICAgICAgLy8gc2hvdWxkIHNldCBhIGBkZWh5ZHJhdGVkYCBmbGFnIGluIHRoZSBkZXZpY2Uga2V5LiAgV2UgaWdub3JlXG4gICAgICAgICAgICAvLyBib3RoIHR5cGVzIG9mIGRlaHlkcmF0ZWQgZGV2aWNlcy5cbiAgICAgICAgICAgIGlmIChkZWh5ZHJhdGVkRGV2aWNlICYmIGRldmljZS5kZXZpY2VJZCA9PSBkZWh5ZHJhdGVkRGV2aWNlPy5kZXZpY2VfaWQpIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIGlmIChkZXZpY2UuZGVoeWRyYXRlZCkgcmV0dXJuIGZhbHNlO1xuXG4gICAgICAgICAgICAvLyBpZ25vcmUgZGV2aWNlcyB3aXRob3V0IGFuIGlkZW50aXR5IGtleVxuICAgICAgICAgICAgaWYgKCFkZXZpY2UuZ2V0SWRlbnRpdHlLZXkoKSkgcmV0dXJuIGZhbHNlO1xuXG4gICAgICAgICAgICBjb25zdCB2ZXJpZmljYXRpb25TdGF0dXMgPSBhd2FpdCBjcnlwdG8uZ2V0RGV2aWNlVmVyaWZpY2F0aW9uU3RhdHVzKG93blVzZXJJZCwgZGV2aWNlLmRldmljZUlkKTtcbiAgICAgICAgICAgIHJldHVybiAhIXZlcmlmaWNhdGlvblN0YXR1cz8uc2lnbmVkQnlPd25lcjtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5waGFzZSA9IFBoYXNlLkludHJvO1xuICAgICAgICB0aGlzLmVtaXQoXCJ1cGRhdGVcIik7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHVzZVBhc3NQaHJhc2UoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhcIlNldHVwRW5jcnlwdGlvblN0b3JlLnVzZVBhc3NwaHJhc2VcIik7XG4gICAgICAgIHRoaXMucGhhc2UgPSBQaGFzZS5CdXN5O1xuICAgICAgICB0aGlzLmVtaXQoXCJ1cGRhdGVcIik7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBjbGkgPSBNYXRyaXhDbGllbnRQZWcuc2FmZUdldCgpO1xuICAgICAgICAgICAgY29uc3QgYmFja3VwSW5mbyA9IGF3YWl0IGNsaS5nZXRLZXlCYWNrdXBWZXJzaW9uKCk7XG4gICAgICAgICAgICB0aGlzLmJhY2t1cEluZm8gPSBiYWNrdXBJbmZvO1xuICAgICAgICAgICAgdGhpcy5lbWl0KFwidXBkYXRlXCIpO1xuXG4gICAgICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZTogKHZhbHVlPzogdW5rbm93bikgPT4gdm9pZCwgcmVqZWN0OiAocmVhc29uPzogYW55KSA9PiB2b2lkKSA9PiB7XG4gICAgICAgICAgICAgICAgYWNjZXNzU2VjcmV0U3RvcmFnZShhc3luYyAoKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGBhY2Nlc3NTZWNyZXRTdG9yYWdlYCB3aWxsIGNhbGwgYGJvb3N0cmFwQ3Jvc3NTaWduaW5nYCBhbmQgYGJvb3RzdHJhcFNlY3JldFN0b3JhZ2VgLCBzbyB0aGF0XG4gICAgICAgICAgICAgICAgICAgIC8vIHNob3VsZCBiZSBlbm91Z2ggdG8gZW5zdXJlIHRoYXQgb3VyIGRldmljZSBpcyBjb3JyZWN0bHkgY3Jvc3Mtc2lnbmVkLlxuICAgICAgICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgICAgICAgICAvLyBUaGUgcmVtYWluaW5nIHRhc2tzIChkZXZpY2UgZGVoeWRyYXRpb24gYW5kIHJlc3RvcmluZyBrZXkgYmFja3VwKSBtYXkgdGFrZSBzb21lIHRpbWUgZHVlIHRvXG4gICAgICAgICAgICAgICAgICAgIC8vIHByb2Nlc3NpbmcgbWFueSB0by1kZXZpY2UgbWVzc2FnZXMgaW4gdGhlIGNhc2Ugb2YgZGV2aWNlIGRlaHlkcmF0aW9uLCBvciBoYXZpbmcgbWFueSBrZXlzIHRvXG4gICAgICAgICAgICAgICAgICAgIC8vIHJlc3RvcmUgaW4gdGhlIGNhc2Ugb2Yga2V5IGJhY2t1cHMsIHNvIHdlIGFsbG93IHRoZSBkaWFsb2cgdG8gYWR2YW5jZSBiZWZvcmUgdGhpcy5cbiAgICAgICAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgICAgICAgLy8gSG93ZXZlciwgd2UgbmVlZCB0byBrZWVwIHRoZSA0UyBrZXkgY2FjaGVkLCBzbyB3ZSBzdGF5IGluc2lkZSBgYWNjZXNzU2VjcmV0U3RvcmFnZWAuXG4gICAgICAgICAgICAgICAgICAgIGxvZ2dlci5kZWJ1ZyhcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiU2V0dXBFbmNyeXB0aW9uU3RvcmUudXNlUGFzc3BocmFzZTogY3Jvc3Mtc2lnbmluZyBhbmQgc2VjcmV0IHN0b3JhZ2Ugc2V0IHVwOyBjaGVja2luZyBcIiArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJkZWh5ZHJhdGlvbiBhbmQgYmFja3VwIGluIHRoZSBiYWNrZ3JvdW5kXCIsXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIHJlc29sdmUoKTtcblxuICAgICAgICAgICAgICAgICAgICBhd2FpdCBpbml0aWFsaXNlRGVoeWRyYXRpb24oKTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAoYmFja3VwSW5mbykge1xuICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgY2xpLnJlc3RvcmVLZXlCYWNrdXBXaXRoU2VjcmV0U3RvcmFnZShiYWNrdXBJbmZvKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pLmNhdGNoKHJlamVjdCk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgaWYgKGF3YWl0IGNsaS5nZXRDcnlwdG8oKT8uZ2V0Q3Jvc3NTaWduaW5nS2V5SWQoKSkge1xuICAgICAgICAgICAgICAgIGxvZ2dlci5kZWJ1ZyhcIlNldHVwRW5jcnlwdGlvblN0b3JlLnVzZVBhc3NwaHJhc2U6IGRvbmVcIik7XG4gICAgICAgICAgICAgICAgdGhpcy5waGFzZSA9IFBoYXNlLkRvbmU7XG4gICAgICAgICAgICAgICAgdGhpcy5lbWl0KFwidXBkYXRlXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBpZiAoZSBpbnN0YW5jZW9mIEFjY2Vzc0NhbmNlbGxlZEVycm9yKSB7XG4gICAgICAgICAgICAgICAgbG9nZ2VyLmRlYnVnKFwiU2V0dXBFbmNyeXB0aW9uU3RvcmUudXNlUGFzc3BocmFzZTogdXNlciBjYW5jZWxsZWQgYWNjZXNzIHRvIHNlY3JldCBzdG9yYWdlXCIpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBsb2dnZXIubG9nKFwiU2V0dXBFbmNyeXB0aW9uU3RvcmUudXNlUGFzc3BocmFzZTogZXJyb3JcIiwgZSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMucGhhc2UgPSBQaGFzZS5JbnRybztcbiAgICAgICAgICAgIHRoaXMuZW1pdChcInVwZGF0ZVwiKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgb25Vc2VyVHJ1c3RTdGF0dXNDaGFuZ2VkID0gYXN5bmMgKHVzZXJJZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgIGlmICh1c2VySWQgIT09IE1hdHJpeENsaWVudFBlZy5zYWZlR2V0KCkuZ2V0U2FmZVVzZXJJZCgpKSByZXR1cm47XG4gICAgICAgIGNvbnN0IHB1YmxpY0tleXNUcnVzdGVkID0gYXdhaXQgTWF0cml4Q2xpZW50UGVnLnNhZmVHZXQoKS5nZXRDcnlwdG8oKT8uZ2V0Q3Jvc3NTaWduaW5nS2V5SWQoKTtcbiAgICAgICAgaWYgKHB1YmxpY0tleXNUcnVzdGVkKSB7XG4gICAgICAgICAgICB0aGlzLnBoYXNlID0gUGhhc2UuRG9uZTtcbiAgICAgICAgICAgIHRoaXMuZW1pdChcInVwZGF0ZVwiKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBwdWJsaWMgb25WZXJpZmljYXRpb25SZXF1ZXN0ID0gKHJlcXVlc3Q6IFZlcmlmaWNhdGlvblJlcXVlc3QpOiB2b2lkID0+IHtcbiAgICAgICAgdGhpcy5zZXRBY3RpdmVWZXJpZmljYXRpb25SZXF1ZXN0KHJlcXVlc3QpO1xuICAgIH07XG5cbiAgICBwdWJsaWMgb25WZXJpZmljYXRpb25SZXF1ZXN0Q2hhbmdlID0gYXN5bmMgKCk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgICBpZiAodGhpcy52ZXJpZmljYXRpb25SZXF1ZXN0Py5waGFzZSA9PT0gVmVyaWZpY2F0aW9uUGhhc2UuQ2FuY2VsbGVkKSB7XG4gICAgICAgICAgICB0aGlzLnZlcmlmaWNhdGlvblJlcXVlc3Qub2ZmKFZlcmlmaWNhdGlvblJlcXVlc3RFdmVudC5DaGFuZ2UsIHRoaXMub25WZXJpZmljYXRpb25SZXF1ZXN0Q2hhbmdlKTtcbiAgICAgICAgICAgIHRoaXMudmVyaWZpY2F0aW9uUmVxdWVzdCA9IG51bGw7XG4gICAgICAgICAgICB0aGlzLmVtaXQoXCJ1cGRhdGVcIik7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy52ZXJpZmljYXRpb25SZXF1ZXN0Py5waGFzZSA9PT0gVmVyaWZpY2F0aW9uUGhhc2UuRG9uZSkge1xuICAgICAgICAgICAgdGhpcy52ZXJpZmljYXRpb25SZXF1ZXN0Lm9mZihWZXJpZmljYXRpb25SZXF1ZXN0RXZlbnQuQ2hhbmdlLCB0aGlzLm9uVmVyaWZpY2F0aW9uUmVxdWVzdENoYW5nZSk7XG4gICAgICAgICAgICB0aGlzLnZlcmlmaWNhdGlvblJlcXVlc3QgPSBudWxsO1xuICAgICAgICAgICAgLy8gQXQgdGhpcyBwb2ludCwgdGhlIHZlcmlmaWNhdGlvbiBoYXMgZmluaXNoZWQsIHdlIGp1c3QgbmVlZCB0byB3YWl0IGZvclxuICAgICAgICAgICAgLy8gY3Jvc3Mgc2lnbmluZyB0byBiZSByZWFkeSB0byB1c2UsIHNvIHdhaXQgZm9yIHRoZSB1c2VyIHRydXN0IHN0YXR1cyB0b1xuICAgICAgICAgICAgLy8gY2hhbmdlIChvciBjaGFuZ2UgdG8gRE9ORSBpZiBpdCdzIGFscmVhZHkgcmVhZHkpLlxuICAgICAgICAgICAgY29uc3QgcHVibGljS2V5c1RydXN0ZWQgPSBhd2FpdCBNYXRyaXhDbGllbnRQZWcuc2FmZUdldCgpLmdldENyeXB0bygpPy5nZXRDcm9zc1NpZ25pbmdLZXlJZCgpO1xuICAgICAgICAgICAgdGhpcy5waGFzZSA9IHB1YmxpY0tleXNUcnVzdGVkID8gUGhhc2UuRG9uZSA6IFBoYXNlLkJ1c3k7XG4gICAgICAgICAgICB0aGlzLmVtaXQoXCJ1cGRhdGVcIik7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcHVibGljIHNraXAoKTogdm9pZCB7XG4gICAgICAgIHRoaXMucGhhc2UgPSBQaGFzZS5Db25maXJtU2tpcDtcbiAgICAgICAgdGhpcy5lbWl0KFwidXBkYXRlXCIpO1xuICAgIH1cblxuICAgIHB1YmxpYyBza2lwQ29uZmlybSgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5waGFzZSA9IFBoYXNlLkZpbmlzaGVkO1xuICAgICAgICB0aGlzLmVtaXQoXCJ1cGRhdGVcIik7XG4gICAgfVxuXG4gICAgcHVibGljIHJldHVybkFmdGVyU2tpcCgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5waGFzZSA9IFBoYXNlLkludHJvO1xuICAgICAgICB0aGlzLmVtaXQoXCJ1cGRhdGVcIik7XG4gICAgfVxuXG4gICAgcHVibGljIHJlc2V0KCk6IHZvaWQge1xuICAgICAgICB0aGlzLnBoYXNlID0gUGhhc2UuQ29uZmlybVJlc2V0O1xuICAgICAgICB0aGlzLmVtaXQoXCJ1cGRhdGVcIik7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHJlc2V0Q29uZmlybSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIC8vIElmIHdlJ3ZlIGdvdHRlbiBoZXJlLCB0aGUgdXNlciBwcmVzdW1hYmx5IGxvc3QgdGhlaXJcbiAgICAgICAgICAgIC8vIHNlY3JldCBzdG9yYWdlIGtleSBpZiB0aGV5IGhhZCBvbmUuIFN0YXJ0IGJ5IHJlc2V0dGluZ1xuICAgICAgICAgICAgLy8gc2VjcmV0IHN0b3JhZ2UgYW5kIHNldHRpbmcgdXAgYSBuZXcgcmVjb3Zlcnkga2V5LCB0aGVuXG4gICAgICAgICAgICAvLyBjcmVhdGUgbmV3IGNyb3NzLXNpZ25pbmcga2V5cyBvbmNlIHRoYXQgc3VjY2VlZHMuXG4gICAgICAgICAgICBhd2FpdCBhY2Nlc3NTZWNyZXRTdG9yYWdlKGFzeW5jICgpOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBjbGkgPSBNYXRyaXhDbGllbnRQZWcuc2FmZUdldCgpO1xuICAgICAgICAgICAgICAgIGF3YWl0IGNsaS5nZXRDcnlwdG8oKT8uYm9vdHN0cmFwQ3Jvc3NTaWduaW5nKHtcbiAgICAgICAgICAgICAgICAgICAgYXV0aFVwbG9hZERldmljZVNpZ25pbmdLZXlzOiBhc3luYyAobWFrZVJlcXVlc3QpOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGNhY2hlZFBhc3N3b3JkID0gU2RrQ29udGV4dENsYXNzLmluc3RhbmNlLmFjY291bnRQYXNzd29yZFN0b3JlLmdldFBhc3N3b3JkKCk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjYWNoZWRQYXNzd29yZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IG1ha2VSZXF1ZXN0KHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZTogXCJtLmxvZ2luLnBhc3N3b3JkXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlkZW50aWZpZXI6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6IFwibS5pZC51c2VyXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VyOiBjbGkuZ2V0U2FmZVVzZXJJZCgpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VyOiBjbGkuZ2V0U2FmZVVzZXJJZCgpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXNzd29yZDogY2FjaGVkUGFzc3dvcmQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB7IGZpbmlzaGVkIH0gPSBNb2RhbC5jcmVhdGVEaWFsb2coSW50ZXJhY3RpdmVBdXRoRGlhbG9nLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGU6IF90KFwiZW5jcnlwdGlvbnxib290c3RyYXBfdGl0bGVcIiksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF0cml4Q2xpZW50OiBjbGksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFrZVJlcXVlc3QsXG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IFtjb25maXJtZWRdID0gYXdhaXQgZmluaXNoZWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWNvbmZpcm1lZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkNyb3NzLXNpZ25pbmcga2V5IHVwbG9hZCBhdXRoIGNhbmNlbGVkXCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBzZXR1cE5ld0Nyb3NzU2lnbmluZzogdHJ1ZSxcbiAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgIGF3YWl0IGluaXRpYWxpc2VEZWh5ZHJhdGlvbih0cnVlKTtcblxuICAgICAgICAgICAgICAgIHRoaXMucGhhc2UgPSBQaGFzZS5GaW5pc2hlZDtcbiAgICAgICAgICAgIH0sIHRydWUpO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBsb2dnZXIuZXJyb3IoXCJFcnJvciByZXNldHRpbmcgY3Jvc3Mtc2lnbmluZ1wiLCBlKTtcbiAgICAgICAgICAgIHRoaXMucGhhc2UgPSBQaGFzZS5JbnRybztcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmVtaXQoXCJ1cGRhdGVcIik7XG4gICAgfVxuXG4gICAgcHVibGljIHJldHVybkFmdGVyUmVzZXQoKTogdm9pZCB7XG4gICAgICAgIHRoaXMucGhhc2UgPSBQaGFzZS5JbnRybztcbiAgICAgICAgdGhpcy5lbWl0KFwidXBkYXRlXCIpO1xuICAgIH1cblxuICAgIHB1YmxpYyBkb25lKCk6IHZvaWQge1xuICAgICAgICB0aGlzLnBoYXNlID0gUGhhc2UuRmluaXNoZWQ7XG4gICAgICAgIHRoaXMuZW1pdChcInVwZGF0ZVwiKTtcbiAgICAgICAgLy8gYXN5bmMgLSBhc2sgb3RoZXIgY2xpZW50cyBmb3Iga2V5cywgaWYgbmVjZXNzYXJ5XG4gICAgICAgIE1hdHJpeENsaWVudFBlZy5zYWZlR2V0KCkuY3J5cHRvPy5jYW5jZWxBbmRSZXNlbmRBbGxPdXRnb2luZ0tleVJlcXVlc3RzKCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBzZXRBY3RpdmVWZXJpZmljYXRpb25SZXF1ZXN0KHJlcXVlc3Q6IFZlcmlmaWNhdGlvblJlcXVlc3QpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgaWYgKCF0aGlzLnN0YXJ0ZWQpIHJldHVybjsgLy8gYmFpbCBpZiB3ZSB3ZXJlIHN0b3BwZWRcbiAgICAgICAgaWYgKHJlcXVlc3Qub3RoZXJVc2VySWQgIT09IE1hdHJpeENsaWVudFBlZy5zYWZlR2V0KCkuZ2V0VXNlcklkKCkpIHJldHVybjtcblxuICAgICAgICBpZiAodGhpcy52ZXJpZmljYXRpb25SZXF1ZXN0KSB7XG4gICAgICAgICAgICB0aGlzLnZlcmlmaWNhdGlvblJlcXVlc3Qub2ZmKFZlcmlmaWNhdGlvblJlcXVlc3RFdmVudC5DaGFuZ2UsIHRoaXMub25WZXJpZmljYXRpb25SZXF1ZXN0Q2hhbmdlKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnZlcmlmaWNhdGlvblJlcXVlc3QgPSByZXF1ZXN0O1xuICAgICAgICBhd2FpdCByZXF1ZXN0LmFjY2VwdCgpO1xuICAgICAgICByZXF1ZXN0Lm9uKFZlcmlmaWNhdGlvblJlcXVlc3RFdmVudC5DaGFuZ2UsIHRoaXMub25WZXJpZmljYXRpb25SZXF1ZXN0Q2hhbmdlKTtcbiAgICAgICAgdGhpcy5lbWl0KFwidXBkYXRlXCIpO1xuICAgIH1cblxuICAgIHB1YmxpYyBsb3N0S2V5cygpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuICF0aGlzLmhhc0RldmljZXNUb1ZlcmlmeUFnYWluc3QgJiYgIXRoaXMua2V5SW5mbztcbiAgICB9XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7O0FBUUEsSUFBQUEsT0FBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUMsVUFBQSxHQUFBRCxPQUFBO0FBTUEsSUFBQUUsT0FBQSxHQUFBRixPQUFBO0FBQ0EsSUFBQUcsT0FBQSxHQUFBSCxPQUFBO0FBR0EsSUFBQUksZ0JBQUEsR0FBQUosT0FBQTtBQUNBLElBQUFLLGdCQUFBLEdBQUFMLE9BQUE7QUFDQSxJQUFBTSxNQUFBLEdBQUFQLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBTyxzQkFBQSxHQUFBUixzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQVEsZ0JBQUEsR0FBQVIsT0FBQTtBQUNBLElBQUFTLFdBQUEsR0FBQVQsT0FBQTtBQUNBLElBQUFVLE9BQUEsR0FBQVYsT0FBQTtBQUNBLElBQUFXLFlBQUEsR0FBQVgsT0FBQTtBQTFCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQU5BLElBNEJZWSxLQUFLLEdBQUFDLE9BQUEsQ0FBQUQsS0FBQSwwQkFBTEEsS0FBSztFQUFMQSxLQUFLLENBQUxBLEtBQUs7RUFBTEEsS0FBSyxDQUFMQSxLQUFLO0VBQUxBLEtBQUssQ0FBTEEsS0FBSztFQUFMQSxLQUFLLENBQUxBLEtBQUs7RUFBTEEsS0FBSyxDQUFMQSxLQUFLO0VBQUxBLEtBQUssQ0FBTEEsS0FBSztFQUFMQSxLQUFLLENBQUxBLEtBQUs7RUFBQSxPQUFMQSxLQUFLO0FBQUE7QUFVVixNQUFNRSxvQkFBb0IsU0FBU0MsZUFBWSxDQUFDO0VBQUFDLFlBQUEsR0FBQUMsSUFBQTtJQUFBLFNBQUFBLElBQUE7SUFBQSxJQUFBQyxnQkFBQSxDQUFBQyxPQUFBO0lBQUEsSUFBQUQsZ0JBQUEsQ0FBQUMsT0FBQTtJQUFBLElBQUFELGdCQUFBLENBQUFDLE9BQUEsK0JBR00sSUFBSTtJQUFBLElBQUFELGdCQUFBLENBQUFD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