matrix-react-sdk
Version:
SDK for matrix.org using React
251 lines (194 loc) • 28.2 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.SetupEncryptionStore = exports.PHASE_FINISHED = exports.PHASE_CONFIRM_SKIP = exports.PHASE_DONE = exports.PHASE_BUSY = exports.PHASE_INTRO = exports.PHASE_LOADING = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _events = _interopRequireDefault(require("events"));
var _MatrixClientPeg = require("../MatrixClientPeg");
var _SecurityManager = require("../SecurityManager");
var _VerificationRequest = require("matrix-js-sdk/src/crypto/verification/request/VerificationRequest");
/*
Copyright 2020 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.
*/
const PHASE_LOADING = 0;
exports.PHASE_LOADING = PHASE_LOADING;
const PHASE_INTRO = 1;
exports.PHASE_INTRO = PHASE_INTRO;
const PHASE_BUSY = 2;
exports.PHASE_BUSY = PHASE_BUSY;
const PHASE_DONE = 3; //final done stage, but still showing UX
exports.PHASE_DONE = PHASE_DONE;
const PHASE_CONFIRM_SKIP = 4;
exports.PHASE_CONFIRM_SKIP = PHASE_CONFIRM_SKIP;
const PHASE_FINISHED = 5; //UX can be closed
exports.PHASE_FINISHED = PHASE_FINISHED;
class SetupEncryptionStore extends _events.default {
constructor(...args) {
super(...args);
(0, _defineProperty2.default)(this, "_onUserTrustStatusChanged", userId => {
if (userId !== _MatrixClientPeg.MatrixClientPeg.get().getUserId()) return;
const publicKeysTrusted = _MatrixClientPeg.MatrixClientPeg.get().getCrossSigningId();
if (publicKeysTrusted) {
this.phase = PHASE_DONE;
this.emit("update");
}
});
(0, _defineProperty2.default)(this, "onVerificationRequest", request => {
this._setActiveVerificationRequest(request);
});
(0, _defineProperty2.default)(this, "onVerificationRequestChange", () => {
if (this.verificationRequest.cancelled) {
this.verificationRequest.off("change", this.onVerificationRequestChange);
this.verificationRequest = null;
this.emit("update");
} else if (this.verificationRequest.phase === _VerificationRequest.PHASE_DONE) {
this.verificationRequest.off("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 = _MatrixClientPeg.MatrixClientPeg.get().getCrossSigningId();
this.phase = publicKeysTrusted ? PHASE_DONE : PHASE_BUSY;
this.emit("update");
}
});
}
static sharedInstance() {
if (!global.mx_SetupEncryptionStore) global.mx_SetupEncryptionStore = new SetupEncryptionStore();
return global.mx_SetupEncryptionStore;
}
start() {
if (this._started) {
return;
}
this._started = true;
this.phase = PHASE_LOADING;
this.verificationRequest = null;
this.backupInfo = null; // ID of the key that the secrets we want are encrypted with
this.keyId = null; // Descriptor of the key that the secrets we want are encrypted with
this.keyInfo = null;
const cli = _MatrixClientPeg.MatrixClientPeg.get();
cli.on("crypto.verification.request", this.onVerificationRequest);
cli.on('userTrustStatusChanged', this._onUserTrustStatusChanged);
const requestsInProgress = cli.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;
if (this.verificationRequest) {
this.verificationRequest.off("change", this.onVerificationRequestChange);
}
if (_MatrixClientPeg.MatrixClientPeg.get()) {
_MatrixClientPeg.MatrixClientPeg.get().removeListener("crypto.verification.request", this.onVerificationRequest);
_MatrixClientPeg.MatrixClientPeg.get().removeListener('userTrustStatusChanged', this._onUserTrustStatusChanged);
}
}
async fetchKeyInfo() {
const cli = _MatrixClientPeg.MatrixClientPeg.get();
const keys = await cli.isSecretStored('m.cross_signing.master', false);
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 devices which are E2EE which we can verify against?
const dehydratedDevice = await cli.getDehydratedDevice();
this.hasDevicesToVerifyAgainst = cli.getStoredDevicesForUser(cli.getUserId()).some(device => device.getIdentityKey() && (!dehydratedDevice || device.deviceId != dehydratedDevice.device_id));
if (!this.hasDevicesToVerifyAgainst && !this.keyInfo) {
// skip before we can even render anything.
this.phase = PHASE_FINISHED;
} else {
this.phase = PHASE_INTRO;
}
this.emit("update");
}
async usePassPhrase() {
this.phase = PHASE_BUSY;
this.emit("update");
const cli = _MatrixClientPeg.MatrixClientPeg.get();
try {
const backupInfo = await cli.getKeyBackupVersion();
this.backupInfo = backupInfo;
this.emit("update"); // The control flow is fairly twisted here...
// For the purposes of completing security, we only wait on getting
// as far as the trust check and then show a green shield.
// We also begin the key backup restore as well, which we're
// awaiting inside `accessSecretStorage` only so that it keeps your
// passphase cached for that work. This dialog itself will only wait
// on the first trust check, and the key backup restore will happen
// in the background.
await new Promise((resolve, reject) => {
(0, _SecurityManager.accessSecretStorage)(async () => {
await cli.checkOwnCrossSigningTrust();
resolve();
if (backupInfo) {
// A complete restore can take many minutes for large
// accounts / slow servers, so we allow the dialog
// to advance before this.
await cli.restoreKeyBackupWithSecretStorage(backupInfo);
}
}).catch(reject);
});
if (cli.getCrossSigningId()) {
this.phase = PHASE_DONE;
this.emit("update");
}
} catch (e) {
if (!(e instanceof _SecurityManager.AccessCancelledError)) {
console.log(e);
} // this will throw if the user hits cancel, so ignore
this.phase = PHASE_INTRO;
this.emit("update");
}
}
skip() {
this.phase = PHASE_CONFIRM_SKIP;
this.emit("update");
}
skipConfirm() {
this.phase = PHASE_FINISHED;
this.emit("update");
}
returnAfterSkip() {
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.get()._crypto.cancelAndResendAllOutgoingKeyRequests();
}
async _setActiveVerificationRequest(request) {
if (request.otherUserId !== _MatrixClientPeg.MatrixClientPeg.get().getUserId()) return;
if (this.verificationRequest) {
this.verificationRequest.off("change", this.onVerificationRequestChange);
}
this.verificationRequest = request;
await request.accept();
request.on("change", this.onVerificationRequestChange);
this.emit("update");
}
}
exports.SetupEncryptionStore = SetupEncryptionStore;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zdG9yZXMvU2V0dXBFbmNyeXB0aW9uU3RvcmUuanMiXSwibmFtZXMiOlsiUEhBU0VfTE9BRElORyIsIlBIQVNFX0lOVFJPIiwiUEhBU0VfQlVTWSIsIlBIQVNFX0RPTkUiLCJQSEFTRV9DT05GSVJNX1NLSVAiLCJQSEFTRV9GSU5JU0hFRCIsIlNldHVwRW5jcnlwdGlvblN0b3JlIiwiRXZlbnRFbWl0dGVyIiwidXNlcklkIiwiTWF0cml4Q2xpZW50UGVnIiwiZ2V0IiwiZ2V0VXNlcklkIiwicHVibGljS2V5c1RydXN0ZWQiLCJnZXRDcm9zc1NpZ25pbmdJZCIsInBoYXNlIiwiZW1pdCIsInJlcXVlc3QiLCJfc2V0QWN0aXZlVmVyaWZpY2F0aW9uUmVxdWVzdCIsInZlcmlmaWNhdGlvblJlcXVlc3QiLCJjYW5jZWxsZWQiLCJvZmYiLCJvblZlcmlmaWNhdGlvblJlcXVlc3RDaGFuZ2UiLCJWRVJJRl9QSEFTRV9ET05FIiwic2hhcmVkSW5zdGFuY2UiLCJnbG9iYWwiLCJteF9TZXR1cEVuY3J5cHRpb25TdG9yZSIsInN0YXJ0IiwiX3N0YXJ0ZWQiLCJiYWNrdXBJbmZvIiwia2V5SWQiLCJrZXlJbmZvIiwiY2xpIiwib24iLCJvblZlcmlmaWNhdGlvblJlcXVlc3QiLCJfb25Vc2VyVHJ1c3RTdGF0dXNDaGFuZ2VkIiwicmVxdWVzdHNJblByb2dyZXNzIiwiZ2V0VmVyaWZpY2F0aW9uUmVxdWVzdHNUb0RldmljZUluUHJvZ3Jlc3MiLCJsZW5ndGgiLCJmZXRjaEtleUluZm8iLCJzdG9wIiwicmVtb3ZlTGlzdGVuZXIiLCJrZXlzIiwiaXNTZWNyZXRTdG9yZWQiLCJPYmplY3QiLCJkZWh5ZHJhdGVkRGV2aWNlIiwiZ2V0RGVoeWRyYXRlZERldmljZSIsImhhc0RldmljZXNUb1ZlcmlmeUFnYWluc3QiLCJnZXRTdG9yZWREZXZpY2VzRm9yVXNlciIsInNvbWUiLCJkZXZpY2UiLCJnZXRJZGVudGl0eUtleSIsImRldmljZUlkIiwiZGV2aWNlX2lkIiwidXNlUGFzc1BocmFzZSIsImdldEtleUJhY2t1cFZlcnNpb24iLCJQcm9taXNlIiwicmVzb2x2ZSIsInJlamVjdCIsImNoZWNrT3duQ3Jvc3NTaWduaW5nVHJ1c3QiLCJyZXN0b3JlS2V5QmFja3VwV2l0aFNlY3JldFN0b3JhZ2UiLCJjYXRjaCIsImUiLCJBY2Nlc3NDYW5jZWxsZWRFcnJvciIsImNvbnNvbGUiLCJsb2ciLCJza2lwIiwic2tpcENvbmZpcm0iLCJyZXR1cm5BZnRlclNraXAiLCJkb25lIiwiX2NyeXB0byIsImNhbmNlbEFuZFJlc2VuZEFsbE91dGdvaW5nS2V5UmVxdWVzdHMiLCJvdGhlclVzZXJJZCIsImFjY2VwdCJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7QUFnQkE7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBbkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQU9PLE1BQU1BLGFBQWEsR0FBRyxDQUF0Qjs7QUFDQSxNQUFNQyxXQUFXLEdBQUcsQ0FBcEI7O0FBQ0EsTUFBTUMsVUFBVSxHQUFHLENBQW5COztBQUNBLE1BQU1DLFVBQVUsR0FBRyxDQUFuQixDLENBQXlCOzs7QUFDekIsTUFBTUMsa0JBQWtCLEdBQUcsQ0FBM0I7O0FBQ0EsTUFBTUMsY0FBYyxHQUFHLENBQXZCLEMsQ0FBMEI7Ozs7QUFFMUIsTUFBTUMsb0JBQU4sU0FBbUNDLGVBQW5DLENBQWdEO0FBQUE7QUFBQTtBQUFBLHFFQXlIdEJDLE1BQUQsSUFBWTtBQUNwQyxVQUFJQSxNQUFNLEtBQUtDLGlDQUFnQkMsR0FBaEIsR0FBc0JDLFNBQXRCLEVBQWYsRUFBa0Q7O0FBQ2xELFlBQU1DLGlCQUFpQixHQUFHSCxpQ0FBZ0JDLEdBQWhCLEdBQXNCRyxpQkFBdEIsRUFBMUI7O0FBQ0EsVUFBSUQsaUJBQUosRUFBdUI7QUFDbkIsYUFBS0UsS0FBTCxHQUFhWCxVQUFiO0FBQ0EsYUFBS1ksSUFBTCxDQUFVLFFBQVY7QUFDSDtBQUNKLEtB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YjtBQUNBLFNBQUtVLElBQUwsQ0FBVSxRQUFWO0FBQ0g7O0FBRURvRCxFQUFBQSxlQUFlLEdBQUc7QUFDZCxTQUFLckQsS0FBTCxHQUFhYixXQUFiO0FBQ0EsU0FBS2MsSUFBTCxDQUFVLFFBQVY7QUFDSDs7QUFFRHFELEVBQUFBLElBQUksR0FBRztBQUNILFNBQUt0RCxLQUFMLEdBQWFULGNBQWI7QUFDQSxTQUFLVSxJQUFMLENBQVUsUUFBVixFQUZHLENBR0g7O0FBQ0FOLHFDQUFnQkMsR0FBaEIsR0FBc0IyRCxPQUF0QixDQUE4QkMscUNBQTlCO0FBQ0g7O0FBRUQsUUFBTXJELDZCQUFOLENBQW9DRCxPQUFwQyxFQUE2QztBQUN6QyxRQUFJQSxPQUFPLENBQUN1RCxXQUFSLEtBQXdCOUQsaUNBQWdCQyxHQUFoQixHQUFzQkMsU0FBdEIsRUFBNUIsRUFBK0Q7O0FBRS9ELFFBQUksS0FBS08sbUJBQVQsRUFBOEI7QUFDMUIsV0FBS0EsbUJBQUwsQ0FBeUJFLEdBQXpCLENBQTZCLFFBQTdCLEVBQXVDLEtBQUtDLDJCQUE1QztBQUNIOztBQUNELFNBQUtILG1CQUFMLEdBQTJCRixPQUEzQjtBQUNBLFVBQU1BLE9BQU8sQ0FBQ3dELE1BQVIsRUFBTjtBQUNBeEQsSUFBQUEsT0FBTyxDQUFDZ0IsRUFBUixDQUFXLFFBQVgsRUFBcUIsS0FBS1gsMkJBQTFCO0FBQ0EsU0FBS04sSUFBTCxDQUFVLFFBQVY7QUFDSDs7QUF2TGtEIiwic291cmNlc0NvbnRlbnQiOlsiLypcbkNvcHlyaWdodCAyMDIwIFRoZSBNYXRyaXgub3JnIEZvdW5kYXRpb24gQy5JLkMuXG5cbkxpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG55b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG5Zb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcblxuICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuXG5Vbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG5kaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG5XSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cblNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbmxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuKi9cblxuaW1wb3J0IEV2ZW50RW1pdHRlciBmcm9tICdldmVudHMnO1xuaW1wb3J0IHsgTWF0cml4Q2xpZW50UGVnIH0gZnJvbSAnLi4vTWF0cml4Q2xpZW50UGVnJztcbmltcG9ydCB7IGFjY2Vzc1NlY3JldFN0b3JhZ2UsIEFjY2Vzc0NhbmNlbGxlZEVycm9yIH0gZnJvbSAnLi4vU2VjdXJpdHlNYW5hZ2VyJztcbmltcG9ydCB7IFBIQVNFX0RPTkUgYXMgVkVSSUZfUEhBU0VfRE9ORSB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9jcnlwdG8vdmVyaWZpY2F0aW9uL3JlcXVlc3QvVmVyaWZpY2F0aW9uUmVxdWVzdFwiO1xuXG5leHBvcnQgY29uc3QgUEhBU0VfTE9BRElORyA9IDA7XG5leHBvcnQgY29uc3QgUEhBU0VfSU5UUk8gPSAxO1xuZXhwb3J0IGNvbnN0IFBIQVNFX0JVU1kgPSAyO1xuZXhwb3J0IGNvbnN0IFBIQVNFX0RPTkUgPSAzOyAgICAvL2ZpbmFsIGRvbmUgc3RhZ2UsIGJ1dCBzdGlsbCBzaG93aW5nIFVYXG5leHBvcnQgY29uc3QgUEhBU0VfQ09ORklSTV9TS0lQID0gNDtcbmV4cG9ydCBjb25zdCBQSEFTRV9GSU5JU0hFRCA9IDU7IC8vVVggY2FuIGJlIGNsb3NlZFxuXG5leHBvcnQgY2xhc3MgU2V0dXBFbmNyeXB0aW9uU3RvcmUgZXh0ZW5kcyBFdmVudEVtaXR0ZXIge1xuICAgIHN0YXRpYyBzaGFyZWRJbnN0YW5jZSgpIHtcbiAgICAgICAgaWYgKCFnbG9iYWwubXhfU2V0dXBFbmNyeXB0aW9uU3RvcmUpIGdsb2JhbC5teF9TZXR1cEVuY3J5cHRpb25TdG9yZSA9IG5ldyBTZXR1cEVuY3J5cHRpb25TdG9yZSgpO1xuICAgICAgICByZXR1cm4gZ2xvYmFsLm14X1NldHVwRW5jcnlwdGlvblN0b3JlO1xuICAgIH1cblxuICAgIHN0YXJ0KCkge1xuICAgICAgICBpZiAodGhpcy5fc3RhcnRlZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuX3N0YXJ0ZWQgPSB0cnVlO1xuICAgICAgICB0aGlzLnBoYXNlID0gUEhBU0VfTE9BRElORztcbiAgICAgICAgdGhpcy52ZXJpZmljYXRpb25SZXF1ZXN0ID0gbnVsbDtcbiAgICAgICAgdGhpcy5iYWNrdXBJbmZvID0gbnVsbDtcblxuICAgICAgICAvLyBJRCBvZiB0aGUga2V5IHRoYXQgdGhlIHNlY3JldHMgd2Ugd2FudCBhcmUgZW5jcnlwdGVkIHdpdGhcbiAgICAgICAgdGhpcy5rZXlJZCA9IG51bGw7XG4gICAgICAgIC8vIERlc2NyaXB0b3Igb2YgdGhlIGtleSB0aGF0IHRoZSBzZWNyZXRzIHdlIHdhbnQgYXJlIGVuY3J5cHRlZCB3aXRoXG4gICAgICAgIHRoaXMua2V5SW5mbyA9IG51bGw7XG5cbiAgICAgICAgY29uc3QgY2xpID0gTWF0cml4Q2xpZW50UGVnLmdldCgpO1xuICAgICAgICBjbGkub24oXCJjcnlwdG8udmVyaWZpY2F0aW9uLnJlcXVlc3RcIiwgdGhpcy5vblZlcmlmaWNhdGlvblJlcXVlc3QpO1xuICAgICAgICBjbGkub24oJ3VzZXJUcnVzdFN0YXR1c0NoYW5nZWQnLCB0aGlzLl9vblVzZXJUcnVzdFN0YXR1c0NoYW5nZWQpO1xuXG4gICAgICAgIGNvbnN0IHJlcXVlc3RzSW5Qcm9ncmVzcyA9IGNsaS5nZXRWZXJpZmljYXRpb25SZXF1ZXN0c1RvRGV2aWNlSW5Qcm9ncmVzcyhjbGkuZ2V0VXNlcklkKCkpO1xuICAgICAgICBpZiAocmVxdWVzdHNJblByb2dyZXNzLmxlbmd0aCkge1xuICAgICAgICAgICAgLy8gSWYgdGhlcmUgYXJlIG11bHRpcGxlLCB3ZSB0YWtlIHRoZSBtb3N0IHJlY2VudC4gRXF1YWxseSBpZiB0aGUgdXNlciBzZW5kcyBhbm90aGVyIHJlcXVlc3QgZnJvbVxuICAgICAgICAgICAgLy8gYW5vdGhlciBkZXZpY2UgYWZ0ZXIgdGhpcyBzY3JlZW4gaGFzIGJlZW4gc2hvd24sIHdlJ2xsIHN3aXRjaCB0byB0aGUgbmV3IG9uZSwgc28gdGhpc1xuICAgICAgICAgICAgLy8gZ2VuZXJhbGx5IGRvZXNuJ3Qgc3VwcG9ydCBtdWx0aXBsZSByZXF1ZXN0cy5cbiAgICAgICAgICAgIHRoaXMuX3NldEFjdGl2ZVZlcmlmaWNhdGlvblJlcXVlc3QocmVxdWVzdHNJblByb2dyZXNzW3JlcXVlc3RzSW5Qcm9ncmVzcy5sZW5ndGggLSAxXSk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmZldGNoS2V5SW5mbygpO1xuICAgIH1cblxuICAgIHN0b3AoKSB7XG4gICAgICAgIGlmICghdGhpcy5fc3RhcnRlZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuX3N0YXJ0ZWQgPSBmYWxzZTtcbiAgICAgICAgaWYgKHRoaXMudmVyaWZpY2F0aW9uUmVxdWVzdCkge1xuICAgICAgICAgICAgdGhpcy52ZXJpZmljYXRpb25SZXF1ZXN0Lm9mZihcImNoYW5nZVwiLCB0aGlzLm9uVmVyaWZpY2F0aW9uUmVxdWVzdENoYW5nZSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKE1hdHJpeENsaWVudFBlZy5nZXQoKSkge1xuICAgICAgICAgICAgTWF0cml4Q2xpZW50UGVnLmdldCgpLnJlbW92ZUxpc3RlbmVyKFwiY3J5cHRvLnZlcmlmaWNhdGlvbi5yZXF1ZXN0XCIsIHRoaXMub25WZXJpZmljYXRpb25SZXF1ZXN0KTtcbiAgICAgICAgICAgIE1hdHJpeENsaWVudFBlZy5nZXQoKS5yZW1vdmVMaXN0ZW5lcigndXNlclRydXN0U3RhdHVzQ2hhbmdlZCcsIHRoaXMuX29uVXNlclRydXN0U3RhdHVzQ2hhbmdlZCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBhc3luYyBmZXRjaEtleUluZm8oKSB7XG4gICAgICAgIGNvbnN0IGNsaSA9IE1hdHJpeENsaWVudFBlZy5nZXQoKTtcbiAgICAgICAgY29uc3Qga2V5cyA9IGF3YWl0IGNsaS5pc1NlY3JldFN0b3JlZCgnbS5jcm9zc19zaWduaW5nLm1hc3RlcicsIGZhbHNlKTtcbiAgICAgICAgaWYgKGtleXMgPT09IG51bGwgfHwgT2JqZWN0LmtleXMoa2V5cykubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICB0aGlzLmtleUlkID0gbnVsbDtcbiAgICAgICAgICAgIHRoaXMua2V5SW5mbyA9IG51bGw7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBJZiB0aGUgc2VjcmV0IGlzIHN0b3JlZCB1bmRlciBtb3JlIHRoYW4gb25lIGtleSwgd2UganVzdCBwaWNrIGFuIGFyYml0cmFyeSBvbmVcbiAgICAgICAgICAgIHRoaXMua2V5SWQgPSBPYmplY3Qua2V5cyhrZXlzKVswXTtcbiAgICAgICAgICAgIHRoaXMua2V5SW5mbyA9IGtleXNbdGhpcy5rZXlJZF07XG4gICAgICAgIH1cblxuICAgICAgICAvLyBkbyB3ZSBoYXZlIGFueSBvdGhlciBkZXZpY2VzIHdoaWNoIGFyZSBFMkVFIHdoaWNoIHdlIGNhbiB2ZXJpZnkgYWdhaW5zdD9cbiAgICAgICAgY29uc3QgZGVoeWRyYXRlZERldmljZSA9IGF3YWl0IGNsaS5nZXREZWh5ZHJhdGVkRGV2aWNlKCk7XG4gICAgICAgIHRoaXMuaGFzRGV2aWNlc1RvVmVyaWZ5QWdhaW5zdCA9IGNsaS5nZXRTdG9yZWREZXZpY2VzRm9yVXNlcihjbGkuZ2V0VXNlcklkKCkpLnNvbWUoXG4gICAgICAgICAgICBkZXZpY2UgPT5cbiAgICAgICAgICAgICAgICBkZXZpY2UuZ2V0SWRlbnRpdHlLZXkoKSAmJlxuICAgICAgICAgICAgICAgICghZGVoeWRyYXRlZERldmljZSB8fCAoZGV2aWNlLmRldmljZUlkICE9IGRlaHlkcmF0ZWREZXZpY2UuZGV2aWNlX2lkKSksXG4gICAgICAgICk7XG5cbiAgICAgICAgaWYgKCF0aGlzLmhhc0RldmljZXNUb1ZlcmlmeUFnYWluc3QgJiYgIXRoaXMua2V5SW5mbykge1xuICAgICAgICAgICAgLy8gc2tpcCBiZWZvcmUgd2UgY2FuIGV2ZW4gcmVuZGVyIGFueXRoaW5nLlxuICAgICAgICAgICAgdGhpcy5waGFzZSA9IFBIQVNFX0ZJTklTSEVEO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5waGFzZSA9IFBIQVNFX0lOVFJPO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuZW1pdChcInVwZGF0ZVwiKTtcbiAgICB9XG5cbiAgICBhc3luYyB1c2VQYXNzUGhyYXNlKCkge1xuICAgICAgICB0aGlzLnBoYXNlID0gUEhBU0VfQlVTWTtcbiAgICAgICAgdGhpcy5lbWl0KFwidXBkYXRlXCIpO1xuICAgICAgICBjb25zdCBjbGkgPSBNYXRyaXhDbGllbnRQZWcuZ2V0KCk7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBiYWNrdXBJbmZvID0gYXdhaXQgY2xpLmdldEtleUJhY2t1cFZlcnNpb24oKTtcbiAgICAgICAgICAgIHRoaXMuYmFja3VwSW5mbyA9IGJhY2t1cEluZm87XG4gICAgICAgICAgICB0aGlzLmVtaXQoXCJ1cGRhdGVcIik7XG4gICAgICAgICAgICAvLyBUaGUgY29udHJvbCBmbG93IGlzIGZhaXJseSB0d2lzdGVkIGhlcmUuLi5cbiAgICAgICAgICAgIC8vIEZvciB0aGUgcHVycG9zZXMgb2YgY29tcGxldGluZyBzZWN1cml0eSwgd2Ugb25seSB3YWl0IG9uIGdldHRpbmdcbiAgICAgICAgICAgIC8vIGFzIGZhciBhcyB0aGUgdHJ1c3QgY2hlY2sgYW5kIHRoZW4gc2hvdyBhIGdyZWVuIHNoaWVsZC5cbiAgICAgICAgICAgIC8vIFdlIGFsc28gYmVnaW4gdGhlIGtleSBiYWNrdXAgcmVzdG9yZSBhcyB3ZWxsLCB3aGljaCB3ZSdyZVxuICAgICAgICAgICAgLy8gYXdhaXRpbmcgaW5zaWRlIGBhY2Nlc3NTZWNyZXRTdG9yYWdlYCBvbmx5IHNvIHRoYXQgaXQga2VlcHMgeW91clxuICAgICAgICAgICAgLy8gcGFzc3BoYXNlIGNhY2hlZCBmb3IgdGhhdCB3b3JrLiBUaGlzIGRpYWxvZyBpdHNlbGYgd2lsbCBvbmx5IHdhaXRcbiAgICAgICAgICAgIC8vIG9uIHRoZSBmaXJzdCB0cnVzdCBjaGVjaywgYW5kIHRoZSBrZXkgYmFja3VwIHJlc3RvcmUgd2lsbCBoYXBwZW5cbiAgICAgICAgICAgIC8vIGluIHRoZSBiYWNrZ3JvdW5kLlxuICAgICAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgICAgICAgIGFjY2Vzc1NlY3JldFN0b3JhZ2UoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBhd2FpdCBjbGkuY2hlY2tPd25Dcm9zc1NpZ25pbmdUcnVzdCgpO1xuICAgICAgICAgICAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChiYWNrdXBJbmZvKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBBIGNvbXBsZXRlIHJlc3RvcmUgY2FuIHRha2UgbWFueSBtaW51dGVzIGZvciBsYXJnZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYWNjb3VudHMgLyBzbG93IHNlcnZlcnMsIHNvIHdlIGFsbG93IHRoZSBkaWFsb2dcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRvIGFkdmFuY2UgYmVmb3JlIHRoaXMuXG4gICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCBjbGkucmVzdG9yZUtleUJhY2t1cFdpdGhTZWNyZXRTdG9yYWdlKGJhY2t1cEluZm8pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSkuY2F0Y2gocmVqZWN0KTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICBpZiAoY2xpLmdldENyb3NzU2lnbmluZ0lkKCkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnBoYXNlID0gUEhBU0VfRE9ORTtcbiAgICAgICAgICAgICAgICB0aGlzLmVtaXQoXCJ1cGRhdGVcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGlmICghKGUgaW5zdGFuY2VvZiBBY2Nlc3NDYW5jZWxsZWRFcnJvcikpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIHRoaXMgd2lsbCB0aHJvdyBpZiB0aGUgdXNlciBoaXRzIGNhbmNlbCwgc28gaWdub3JlXG4gICAgICAgICAgICB0aGlzLnBoYXNlID0gUEhBU0VfSU5UUk87XG4gICAgICAgICAgICB0aGlzLmVtaXQoXCJ1cGRhdGVcIik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBfb25Vc2VyVHJ1c3RTdGF0dXNDaGFuZ2VkID0gKHVzZXJJZCkgPT4ge1xuICAgICAgICBpZiAodXNlcklkICE9PSBNYXRyaXhDbGllbnRQZWcuZ2V0KCkuZ2V0VXNlcklkKCkpIHJldHVybjtcbiAgICAgICAgY29uc3QgcHVibGljS2V5c1RydXN0ZWQgPSBNYXRyaXhDbGllbnRQZWcuZ2V0KCkuZ2V0Q3Jvc3NTaWduaW5nSWQoKTtcbiAgICAgICAgaWYgKHB1YmxpY0tleXNUcnVzdGVkKSB7XG4gICAgICAgICAgICB0aGlzLnBoYXNlID0gUEhBU0VfRE9ORTtcbiAgICAgICAgICAgIHRoaXMuZW1pdChcInVwZGF0ZVwiKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIG9uVmVyaWZpY2F0aW9uUmVxdWVzdCA9IChyZXF1ZXN0KSA9PiB7XG4gICAgICAgIHRoaXMuX3NldEFjdGl2ZVZlcmlmaWNhdGlvblJlcXVlc3QocmVxdWVzdCk7XG4gICAgfVxuXG4gICAgb25WZXJpZmljYXRpb25SZXF1ZXN0Q2hhbmdlID0gKCkgPT4ge1xuICAgICAgICBpZiAodGhpcy52ZXJpZmljYXRpb25SZXF1ZXN0LmNhbmNlbGxlZCkge1xuICAgICAgICAgICAgdGhpcy52ZXJpZmljYXRpb25SZXF1ZXN0Lm9mZihcImNoYW5nZVwiLCB0aGlzLm9uVmVyaWZpY2F0aW9uUmVxdWVzdENoYW5nZSk7XG4gICAgICAgICAgICB0aGlzLnZlcmlmaWNhdGlvblJlcXVlc3QgPSBudWxsO1xuICAgICAgICAgICAgdGhpcy5lbWl0KFwidXBkYXRlXCIpO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMudmVyaWZpY2F0aW9uUmVxdWVzdC5waGFzZSA9PT0gVkVSSUZfUEhBU0VfRE9ORSkge1xuICAgICAgICAgICAgdGhpcy52ZXJpZmljYXRpb25SZXF1ZXN0Lm9mZihcImNoYW5nZVwiLCB0aGlzLm9uVmVyaWZpY2F0aW9uUmVxdWVzdENoYW5nZSk7XG4gICAgICAgICAgICB0aGlzLnZlcmlmaWNhdGlvblJlcXVlc3QgPSBudWxsO1xuICAgICAgICAgICAgLy8gQXQgdGhpcyBwb2ludCwgdGhlIHZlcmlmaWNhdGlvbiBoYXMgZmluaXNoZWQsIHdlIGp1c3QgbmVlZCB0byB3YWl0IGZvclxuICAgICAgICAgICAgLy8gY3Jvc3Mgc2lnbmluZyB0byBiZSByZWFkeSB0byB1c2UsIHNvIHdhaXQgZm9yIHRoZSB1c2VyIHRydXN0IHN0YXR1cyB0b1xuICAgICAgICAgICAgLy8gY2hhbmdlIChvciBjaGFuZ2UgdG8gRE9ORSBpZiBpdCdzIGFscmVhZHkgcmVhZHkpLlxuICAgICAgICAgICAgY29uc3QgcHVibGljS2V5c1RydXN0ZWQgPSBNYXRyaXhDbGllbnRQZWcuZ2V0KCkuZ2V0Q3Jvc3NTaWduaW5nSWQoKTtcbiAgICAgICAgICAgIHRoaXMucGhhc2UgPSBwdWJsaWNLZXlzVHJ1c3RlZCA/IFBIQVNFX0RPTkUgOiBQSEFTRV9CVVNZO1xuICAgICAgICAgICAgdGhpcy5lbWl0KFwidXBkYXRlXCIpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgc2tpcCgpIHtcbiAgICAgICAgdGhpcy5waGFzZSA9IFBIQVNFX0NPTkZJUk1fU0tJUDtcbiAgICAgICAgdGhpcy5lbWl0KFwidXBkYXRlXCIpO1xuICAgIH1cblxuICAgIHNraXBDb25maXJtKCkge1xuICAgICAgICB0aGlzLnBoYXNlID0gUEhBU0VfRklOSVNIRUQ7XG4gICAgICAgIHRoaXMuZW1pdChcInVwZGF0ZVwiKTtcbiAgICB9XG5cbiAgICByZXR1cm5BZnRlclNraXAoKSB7XG4gICAgICAgIHRoaXMucGhhc2UgPSBQSEFTRV9JTlRSTztcbiAgICAgICAgdGhpcy5lbWl0KFwidXBkYXRlXCIpO1xuICAgIH1cblxuICAgIGRvbmUoKSB7XG4gICAgICAgIHRoaXMucGhhc2UgPSBQSEFTRV9GSU5JU0hFRDtcbiAgICAgICAgdGhpcy5lbWl0KFwidXBkYXRlXCIpO1xuICAgICAgICAvLyBhc3luYyAtIGFzayBvdGhlciBjbGllbnRzIGZvciBrZXlzLCBpZiBuZWNlc3NhcnlcbiAgICAgICAgTWF0cml4Q2xpZW50UGVnLmdldCgpLl9jcnlwdG8uY2FuY2VsQW5kUmVzZW5kQWxsT3V0Z29pbmdLZXlSZXF1ZXN0cygpO1xuICAgIH1cblxuICAgIGFzeW5jIF9zZXRBY3RpdmVWZXJpZmljYXRpb25SZXF1ZXN0KHJlcXVlc3QpIHtcbiAgICAgICAgaWYgKHJlcXVlc3Qub3RoZXJVc2VySWQgIT09IE1hdHJpeENsaWVudFBlZy5nZXQoKS5nZXRVc2VySWQoKSkgcmV0dXJuO1xuXG4gICAgICAgIGlmICh0aGlzLnZlcmlmaWNhdGlvblJlcXVlc3QpIHtcbiAgICAgICAgICAgIHRoaXMudmVyaWZpY2F0aW9uUmVxdWVzdC5vZmYoXCJjaGFuZ2VcIiwgdGhpcy5vblZlcmlmaWNhdGlvblJlcXVlc3RDaGFuZ2UpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMudmVyaWZpY2F0aW9uUmVxdWVzdCA9IHJlcXVlc3Q7XG4gICAgICAgIGF3YWl0IHJlcXVlc3QuYWNjZXB0KCk7XG4gICAgICAgIHJlcXVlc3Qub24oXCJjaGFuZ2VcIiwgdGhpcy5vblZlcmlmaWNhdGlvblJlcXVlc3RDaGFuZ2UpO1xuICAgICAgICB0aGlzLmVtaXQoXCJ1cGRhdGVcIik7XG4gICAgfVxufVxuIl19