matrix-react-sdk
Version:
SDK for matrix.org using React
232 lines (221 loc) • 30.8 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
exports.sendLoginRequest = sendLoginRequest;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _matrix = require("matrix-js-sdk/src/matrix");
var _logger = require("matrix-js-sdk/src/logger");
var _ModuleRunner = require("./modules/ModuleRunner");
var _registerClient = require("./utils/oidc/registerClient");
var _SdkConfig = _interopRequireDefault(require("./SdkConfig"));
var _isUserRegistrationSupported = require("./utils/oidc/isUserRegistrationSupported");
/*
Copyright 2024 New Vector Ltd.
Copyright 2015-2021 The Matrix.org Foundation C.I.C.
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
/**
* Login flows supported by this client
* LoginFlow type use the client API /login endpoint
* OidcNativeFlow is specific to this client
*/
class Login {
// memoize
constructor(hsUrl, isUrl, fallbackHsUrl, opts) {
(0, _defineProperty2.default)(this, "flows", []);
(0, _defineProperty2.default)(this, "defaultDeviceDisplayName", void 0);
(0, _defineProperty2.default)(this, "delegatedAuthentication", void 0);
(0, _defineProperty2.default)(this, "tempClient", null);
this.hsUrl = hsUrl;
this.isUrl = isUrl;
this.fallbackHsUrl = fallbackHsUrl;
this.defaultDeviceDisplayName = opts.defaultDeviceDisplayName;
this.delegatedAuthentication = opts.delegatedAuthentication;
}
getHomeserverUrl() {
return this.hsUrl;
}
getIdentityServerUrl() {
return this.isUrl;
}
setHomeserverUrl(hsUrl) {
this.tempClient = null; // clear memoization
this.hsUrl = hsUrl;
}
setIdentityServerUrl(isUrl) {
this.tempClient = null; // clear memoization
this.isUrl = isUrl;
}
/**
* Set delegated authentication config, clears tempClient.
* @param delegatedAuthentication delegated auth config, from ValidatedServerConfig
*/
setDelegatedAuthentication(delegatedAuthentication) {
this.tempClient = null; // clear memoization
this.delegatedAuthentication = delegatedAuthentication;
}
/**
* Get a temporary MatrixClient, which can be used for login or register
* requests.
* @returns {MatrixClient}
*/
createTemporaryClient() {
if (!this.tempClient) {
this.tempClient = (0, _matrix.createClient)({
baseUrl: this.hsUrl,
idBaseUrl: this.isUrl
});
}
return this.tempClient;
}
/**
* Get supported login flows
* @param isRegistration OPTIONAL used to verify registration is supported in delegated authentication config
* @returns Promise that resolves to supported login flows
*/
async getFlows(isRegistration) {
// try to use oidc native flow if we have delegated auth config
if (this.delegatedAuthentication) {
try {
const oidcFlow = await tryInitOidcNativeFlow(this.delegatedAuthentication, _SdkConfig.default.get().oidc_static_clients, isRegistration);
return [oidcFlow];
} catch (error) {
_logger.logger.error(error);
}
}
// oidc native flow not supported, continue with matrix login
const client = this.createTemporaryClient();
const {
flows
} = await client.loginFlows();
// If an m.login.sso flow is present which is also flagged as being for MSC3824 OIDC compatibility then we only
// return that flow as (per MSC3824) it is the only one that the user should be offered to give the best experience
const oidcCompatibilityFlow = flows.find(f => f.type === "m.login.sso" && _matrix.DELEGATED_OIDC_COMPATIBILITY.findIn(f));
this.flows = oidcCompatibilityFlow ? [oidcCompatibilityFlow] : flows;
return this.flows;
}
loginViaPassword(username, phoneCountry, phoneNumber, password) {
const isEmail = !!username && username.indexOf("@") > 0;
let identifier;
if (phoneCountry && phoneNumber) {
identifier = {
type: "m.id.phone",
country: phoneCountry,
phone: phoneNumber,
// XXX: Synapse historically wanted `number` and not `phone`
number: phoneNumber
};
} else if (isEmail) {
identifier = {
type: "m.id.thirdparty",
medium: "email",
address: username
};
} else {
identifier = {
type: "m.id.user",
user: username
};
}
const loginParams = {
password,
identifier,
initial_device_display_name: this.defaultDeviceDisplayName
};
const tryFallbackHs = originalError => {
return sendLoginRequest(this.fallbackHsUrl, this.isUrl, "m.login.password", loginParams).catch(fallbackError => {
_logger.logger.log("fallback HS login failed", fallbackError);
// throw the original error
throw originalError;
});
};
let originalLoginError = null;
return sendLoginRequest(this.hsUrl, this.isUrl, "m.login.password", loginParams).catch(error => {
originalLoginError = error;
if (error.httpStatus === 403) {
if (this.fallbackHsUrl) {
return tryFallbackHs(originalLoginError);
}
}
throw originalLoginError;
}).catch(error => {
_logger.logger.log("Login failed", error);
throw error;
});
}
}
/**
* Describes the OIDC native login flow
* Separate from js-sdk's `LoginFlow` as this does not use the same /login flow
* to which that type belongs.
*/
exports.default = Login;
/**
* Prepares an OidcNativeFlow for logging into the server.
*
* Finds a static clientId for configured issuer, or attempts dynamic registration with the OP, and wraps the
* results.
*
* @param delegatedAuthConfig Auth config from ValidatedServerConfig
* @param staticOidcClientIds static client config from config.json, used during client registration with OP
* @param isRegistration true when we are attempting registration
* @returns Promise<OidcNativeFlow> when oidc native authentication flow is supported and correctly configured
* @throws when client can't register with OP, or any unexpected error
*/
const tryInitOidcNativeFlow = async (delegatedAuthConfig, staticOidcClientIds, isRegistration) => {
// if registration is not supported, bail before attempting to get the clientId
if (isRegistration && !(0, _isUserRegistrationSupported.isUserRegistrationSupported)(delegatedAuthConfig)) {
throw new Error("Registration is not supported by OP");
}
const clientId = await (0, _registerClient.getOidcClientId)(delegatedAuthConfig, staticOidcClientIds);
const flow = {
type: "oidcNativeFlow",
clientId
};
return flow;
};
/**
* Send a login request to the given server, and format the response
* as a MatrixClientCreds
*
* @param {string} hsUrl the base url of the Homeserver used to log in.
* @param {string} isUrl the base url of the default identity server
* @param {string} loginType the type of login to do
* @param {ILoginParams} loginParams the parameters for the login
*
* @returns {IMatrixClientCreds}
*/
async function sendLoginRequest(hsUrl, isUrl, loginType, loginParams) {
const client = (0, _matrix.createClient)({
baseUrl: hsUrl,
idBaseUrl: isUrl
});
const data = await client.login(loginType, loginParams);
const wellknown = data.well_known;
if (wellknown) {
if (wellknown["m.homeserver"]?.["base_url"]) {
hsUrl = wellknown["m.homeserver"]["base_url"];
_logger.logger.log(`Overrode homeserver setting with ${hsUrl} from login response`);
}
if (wellknown["m.identity_server"]?.["base_url"]) {
// TODO: should we prompt here?
isUrl = wellknown["m.identity_server"]["base_url"];
_logger.logger.log(`Overrode IS setting with ${isUrl} from login response`);
}
}
const creds = {
homeserverUrl: hsUrl,
identityServerUrl: isUrl,
userId: data.user_id,
deviceId: data.device_id,
accessToken: data.access_token
};
_ModuleRunner.ModuleRunner.instance.extensions.cryptoSetup.examineLoginResponse(data, creds);
return creds;
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbWF0cml4IiwicmVxdWlyZSIsIl9sb2dnZXIiLCJfTW9kdWxlUnVubmVyIiwiX3JlZ2lzdGVyQ2xpZW50IiwiX1Nka0NvbmZpZyIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJfaXNVc2VyUmVnaXN0cmF0aW9uU3VwcG9ydGVkIiwiTG9naW4iLCJjb25zdHJ1Y3RvciIsImhzVXJsIiwiaXNVcmwiLCJmYWxsYmFja0hzVXJsIiwib3B0cyIsIl9kZWZpbmVQcm9wZXJ0eTIiLCJkZWZhdWx0IiwiZGVmYXVsdERldmljZURpc3BsYXlOYW1lIiwiZGVsZWdhdGVkQXV0aGVudGljYXRpb24iLCJnZXRIb21lc2VydmVyVXJsIiwiZ2V0SWRlbnRpdHlTZXJ2ZXJVcmwiLCJzZXRIb21lc2VydmVyVXJsIiwidGVtcENsaWVudCIsInNldElkZW50aXR5U2VydmVyVXJsIiwic2V0RGVsZWdhdGVkQXV0aGVudGljYXRpb24iLCJjcmVhdGVUZW1wb3JhcnlDbGllbnQiLCJjcmVhdGVDbGllbnQiLCJiYXNlVXJsIiwiaWRCYXNlVXJsIiwiZ2V0Rmxvd3MiLCJpc1JlZ2lzdHJhdGlvbiIsIm9pZGNGbG93IiwidHJ5SW5pdE9pZGNOYXRpdmVGbG93IiwiU2RrQ29uZmlnIiwiZ2V0Iiwib2lkY19zdGF0aWNfY2xpZW50cyIsImVycm9yIiwibG9nZ2VyIiwiY2xpZW50IiwiZmxvd3MiLCJsb2dpbkZsb3dzIiwib2lkY0NvbXBhdGliaWxpdHlGbG93IiwiZmluZCIsImYiLCJ0eXBlIiwiREVMRUdBVEVEX09JRENfQ09NUEFUSUJJTElUWSIsImZpbmRJbiIsImxvZ2luVmlhUGFzc3dvcmQiLCJ1c2VybmFtZSIsInBob25lQ291bnRyeSIsInBob25lTnVtYmVyIiwicGFzc3dvcmQiLCJpc0VtYWlsIiwiaW5kZXhPZiIsImlkZW50aWZpZXIiLCJjb3VudHJ5IiwicGhvbmUiLCJudW1iZXIiLCJtZWRpdW0iLCJhZGRyZXNzIiwidXNlciIsImxvZ2luUGFyYW1zIiwiaW5pdGlhbF9kZXZpY2VfZGlzcGxheV9uYW1lIiwidHJ5RmFsbGJhY2tIcyIsIm9yaWdpbmFsRXJyb3IiLCJzZW5kTG9naW5SZXF1ZXN0IiwiY2F0Y2giLCJmYWxsYmFja0Vycm9yIiwibG9nIiwib3JpZ2luYWxMb2dpbkVycm9yIiwiaHR0cFN0YXR1cyIsImV4cG9ydHMiLCJkZWxlZ2F0ZWRBdXRoQ29uZmlnIiwic3RhdGljT2lkY0NsaWVudElkcyIsImlzVXNlclJlZ2lzdHJhdGlvblN1cHBvcnRlZCIsIkVycm9yIiwiY2xpZW50SWQiLCJnZXRPaWRjQ2xpZW50SWQiLCJmbG93IiwibG9naW5UeXBlIiwiZGF0YSIsImxvZ2luIiwid2VsbGtub3duIiwid2VsbF9rbm93biIsImNyZWRzIiwiaG9tZXNlcnZlclVybCIsImlkZW50aXR5U2VydmVyVXJsIiwidXNlcklkIiwidXNlcl9pZCIsImRldmljZUlkIiwiZGV2aWNlX2lkIiwiYWNjZXNzVG9rZW4iLCJhY2Nlc3NfdG9rZW4iLCJNb2R1bGVSdW5uZXIiLCJpbnN0YW5jZSIsImV4dGVuc2lvbnMiLCJjcnlwdG9TZXR1cCIsImV4YW1pbmVMb2dpblJlc3BvbnNlIl0sInNvdXJjZXMiOlsiLi4vc3JjL0xvZ2luLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qXG5Db3B5cmlnaHQgMjAyNCBOZXcgVmVjdG9yIEx0ZC5cbkNvcHlyaWdodCAyMDE1LTIwMjEgVGhlIE1hdHJpeC5vcmcgRm91bmRhdGlvbiBDLkkuQy5cbkNvcHlyaWdodCAyMDE5IE1pY2hhZWwgVGVsYXR5bnNraSA8N3QzY2hndXlAZ21haWwuY29tPlxuXG5TUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQUdQTC0zLjAtb25seSBPUiBHUEwtMy4wLW9ubHlcblBsZWFzZSBzZWUgTElDRU5TRSBmaWxlcyBpbiB0aGUgcmVwb3NpdG9yeSByb290IGZvciBmdWxsIGRldGFpbHMuXG4qL1xuXG5pbXBvcnQge1xuICAgIGNyZWF0ZUNsaWVudCxcbiAgICBNYXRyaXhDbGllbnQsXG4gICAgTG9naW5GbG93LFxuICAgIERFTEVHQVRFRF9PSURDX0NPTVBBVElCSUxJVFksXG4gICAgSUxvZ2luRmxvdyxcbiAgICBMb2dpblJlcXVlc3QsXG4gICAgT2lkY0NsaWVudENvbmZpZyxcbn0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL21hdHJpeFwiO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL2xvZ2dlclwiO1xuXG5pbXBvcnQgeyBJTWF0cml4Q2xpZW50Q3JlZHMgfSBmcm9tIFwiLi9NYXRyaXhDbGllbnRQZWdcIjtcbmltcG9ydCB7IE1vZHVsZVJ1bm5lciB9IGZyb20gXCIuL21vZHVsZXMvTW9kdWxlUnVubmVyXCI7XG5pbXBvcnQgeyBnZXRPaWRjQ2xpZW50SWQgfSBmcm9tIFwiLi91dGlscy9vaWRjL3JlZ2lzdGVyQ2xpZW50XCI7XG5pbXBvcnQgeyBJQ29uZmlnT3B0aW9ucyB9IGZyb20gXCIuL0lDb25maWdPcHRpb25zXCI7XG5pbXBvcnQgU2RrQ29uZmlnIGZyb20gXCIuL1Nka0NvbmZpZ1wiO1xuaW1wb3J0IHsgaXNVc2VyUmVnaXN0cmF0aW9uU3VwcG9ydGVkIH0gZnJvbSBcIi4vdXRpbHMvb2lkYy9pc1VzZXJSZWdpc3RyYXRpb25TdXBwb3J0ZWRcIjtcblxuLyoqXG4gKiBMb2dpbiBmbG93cyBzdXBwb3J0ZWQgYnkgdGhpcyBjbGllbnRcbiAqIExvZ2luRmxvdyB0eXBlIHVzZSB0aGUgY2xpZW50IEFQSSAvbG9naW4gZW5kcG9pbnRcbiAqIE9pZGNOYXRpdmVGbG93IGlzIHNwZWNpZmljIHRvIHRoaXMgY2xpZW50XG4gKi9cbmV4cG9ydCB0eXBlIENsaWVudExvZ2luRmxvdyA9IExvZ2luRmxvdyB8IE9pZGNOYXRpdmVGbG93O1xuXG5pbnRlcmZhY2UgSUxvZ2luT3B0aW9ucyB7XG4gICAgZGVmYXVsdERldmljZURpc3BsYXlOYW1lPzogc3RyaW5nO1xuICAgIC8qKlxuICAgICAqIERlbGVnYXRlZCBhdXRoIGNvbmZpZyBmcm9tIHNlcnZlcidzIC53ZWxsLWtub3duLlxuICAgICAqXG4gICAgICogSWYgdGhpcyBwcm9wZXJ0eSBpcyBzZXQsIHdlIHdpbGwgYXR0ZW1wdCBhbiBPSURDIGxvZ2luIHVzaW5nIHRoZSBkZWxlZ2F0ZWQgYXV0aCBzZXR0aW5ncy5cbiAgICAgKiBUaGUgY2FsbGVyIGlzIHJlc3BvbnNpYmxlIGZvciBjaGVja2luZyB0aGF0IE9JREMgaXMgZW5hYmxlZCBpbiB0aGUgbGFicyBzZXR0aW5ncy5cbiAgICAgKi9cbiAgICBkZWxlZ2F0ZWRBdXRoZW50aWNhdGlvbj86IE9pZGNDbGllbnRDb25maWc7XG59XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIExvZ2luIHtcbiAgICBwcml2YXRlIGZsb3dzOiBBcnJheTxDbGllbnRMb2dpbkZsb3c+ID0gW107XG4gICAgcHJpdmF0ZSByZWFkb25seSBkZWZhdWx0RGV2aWNlRGlzcGxheU5hbWU/OiBzdHJpbmc7XG4gICAgcHJpdmF0ZSBkZWxlZ2F0ZWRBdXRoZW50aWNhdGlvbj86IE9pZGNDbGllbnRDb25maWc7XG4gICAgcHJpdmF0ZSB0ZW1wQ2xpZW50OiBNYXRyaXhDbGllbnQgfCBudWxsID0gbnVsbDsgLy8gbWVtb2l6ZVxuXG4gICAgcHVibGljIGNvbnN0cnVjdG9yKFxuICAgICAgICBwcml2YXRlIGhzVXJsOiBzdHJpbmcsXG4gICAgICAgIHByaXZhdGUgaXNVcmw6IHN0cmluZyxcbiAgICAgICAgcHJpdmF0ZSBmYWxsYmFja0hzVXJsOiBzdHJpbmcgfCBudWxsLFxuICAgICAgICBvcHRzOiBJTG9naW5PcHRpb25zLFxuICAgICkge1xuICAgICAgICB0aGlzLmRlZmF1bHREZXZpY2VEaXNwbGF5TmFtZSA9IG9wdHMuZGVmYXVsdERldmljZURpc3BsYXlOYW1lO1xuICAgICAgICB0aGlzLmRlbGVnYXRlZEF1dGhlbnRpY2F0aW9uID0gb3B0cy5kZWxlZ2F0ZWRBdXRoZW50aWNhdGlvbjtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0SG9tZXNlcnZlclVybCgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gdGhpcy5oc1VybDtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0SWRlbnRpdHlTZXJ2ZXJVcmwoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuaXNVcmw7XG4gICAgfVxuXG4gICAgcHVibGljIHNldEhvbWVzZXJ2ZXJVcmwoaHNVcmw6IHN0cmluZyk6IHZvaWQge1xuICAgICAgICB0aGlzLnRlbXBDbGllbnQgPSBudWxsOyAvLyBjbGVhciBtZW1vaXphdGlvblxuICAgICAgICB0aGlzLmhzVXJsID0gaHNVcmw7XG4gICAgfVxuXG4gICAgcHVibGljIHNldElkZW50aXR5U2VydmVyVXJsKGlzVXJsOiBzdHJpbmcpOiB2b2lkIHtcbiAgICAgICAgdGhpcy50ZW1wQ2xpZW50ID0gbnVsbDsgLy8gY2xlYXIgbWVtb2l6YXRpb25cbiAgICAgICAgdGhpcy5pc1VybCA9IGlzVXJsO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCBkZWxlZ2F0ZWQgYXV0aGVudGljYXRpb24gY29uZmlnLCBjbGVhcnMgdGVtcENsaWVudC5cbiAgICAgKiBAcGFyYW0gZGVsZWdhdGVkQXV0aGVudGljYXRpb24gZGVsZWdhdGVkIGF1dGggY29uZmlnLCBmcm9tIFZhbGlkYXRlZFNlcnZlckNvbmZpZ1xuICAgICAqL1xuICAgIHB1YmxpYyBzZXREZWxlZ2F0ZWRBdXRoZW50aWNhdGlvbihkZWxlZ2F0ZWRBdXRoZW50aWNhdGlvbj86IE9pZGNDbGllbnRDb25maWcpOiB2b2lkIHtcbiAgICAgICAgdGhpcy50ZW1wQ2xpZW50ID0gbnVsbDsgLy8gY2xlYXIgbWVtb2l6YXRpb25cbiAgICAgICAgdGhpcy5kZWxlZ2F0ZWRBdXRoZW50aWNhdGlvbiA9IGRlbGVnYXRlZEF1dGhlbnRpY2F0aW9uO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCBhIHRlbXBvcmFyeSBNYXRyaXhDbGllbnQsIHdoaWNoIGNhbiBiZSB1c2VkIGZvciBsb2dpbiBvciByZWdpc3RlclxuICAgICAqIHJlcXVlc3RzLlxuICAgICAqIEByZXR1cm5zIHtNYXRyaXhDbGllbnR9XG4gICAgICovXG4gICAgcHVibGljIGNyZWF0ZVRlbXBvcmFyeUNsaWVudCgpOiBNYXRyaXhDbGllbnQge1xuICAgICAgICBpZiAoIXRoaXMudGVtcENsaWVudCkge1xuICAgICAgICAgICAgdGhpcy50ZW1wQ2xpZW50ID0gY3JlYXRlQ2xpZW50KHtcbiAgICAgICAgICAgICAgICBiYXNlVXJsOiB0aGlzLmhzVXJsLFxuICAgICAgICAgICAgICAgIGlkQmFzZVVybDogdGhpcy5pc1VybCxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLnRlbXBDbGllbnQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IHN1cHBvcnRlZCBsb2dpbiBmbG93c1xuICAgICAqIEBwYXJhbSBpc1JlZ2lzdHJhdGlvbiBPUFRJT05BTCB1c2VkIHRvIHZlcmlmeSByZWdpc3RyYXRpb24gaXMgc3VwcG9ydGVkIGluIGRlbGVnYXRlZCBhdXRoZW50aWNhdGlvbiBjb25maWdcbiAgICAgKiBAcmV0dXJucyBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gc3VwcG9ydGVkIGxvZ2luIGZsb3dzXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIGdldEZsb3dzKGlzUmVnaXN0cmF0aW9uPzogYm9vbGVhbik6IFByb21pc2U8QXJyYXk8Q2xpZW50TG9naW5GbG93Pj4ge1xuICAgICAgICAvLyB0cnkgdG8gdXNlIG9pZGMgbmF0aXZlIGZsb3cgaWYgd2UgaGF2ZSBkZWxlZ2F0ZWQgYXV0aCBjb25maWdcbiAgICAgICAgaWYgKHRoaXMuZGVsZWdhdGVkQXV0aGVudGljYXRpb24pIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgY29uc3Qgb2lkY0Zsb3cgPSBhd2FpdCB0cnlJbml0T2lkY05hdGl2ZUZsb3coXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZGVsZWdhdGVkQXV0aGVudGljYXRpb24sXG4gICAgICAgICAgICAgICAgICAgIFNka0NvbmZpZy5nZXQoKS5vaWRjX3N0YXRpY19jbGllbnRzLFxuICAgICAgICAgICAgICAgICAgICBpc1JlZ2lzdHJhdGlvbixcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIHJldHVybiBbb2lkY0Zsb3ddO1xuICAgICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICBsb2dnZXIuZXJyb3IoZXJyb3IpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gb2lkYyBuYXRpdmUgZmxvdyBub3Qgc3VwcG9ydGVkLCBjb250aW51ZSB3aXRoIG1hdHJpeCBsb2dpblxuICAgICAgICBjb25zdCBjbGllbnQgPSB0aGlzLmNyZWF0ZVRlbXBvcmFyeUNsaWVudCgpO1xuICAgICAgICBjb25zdCB7IGZsb3dzIH06IHsgZmxvd3M6IExvZ2luRmxvd1tdIH0gPSBhd2FpdCBjbGllbnQubG9naW5GbG93cygpO1xuICAgICAgICAvLyBJZiBhbiBtLmxvZ2luLnNzbyBmbG93IGlzIHByZXNlbnQgd2hpY2ggaXMgYWxzbyBmbGFnZ2VkIGFzIGJlaW5nIGZvciBNU0MzODI0IE9JREMgY29tcGF0aWJpbGl0eSB0aGVuIHdlIG9ubHlcbiAgICAgICAgLy8gcmV0dXJuIHRoYXQgZmxvdyBhcyAocGVyIE1TQzM4MjQpIGl0IGlzIHRoZSBvbmx5IG9uZSB0aGF0IHRoZSB1c2VyIHNob3VsZCBiZSBvZmZlcmVkIHRvIGdpdmUgdGhlIGJlc3QgZXhwZXJpZW5jZVxuICAgICAgICBjb25zdCBvaWRjQ29tcGF0aWJpbGl0eUZsb3cgPSBmbG93cy5maW5kKFxuICAgICAgICAgICAgKGYpID0+IGYudHlwZSA9PT0gXCJtLmxvZ2luLnNzb1wiICYmIERFTEVHQVRFRF9PSURDX0NPTVBBVElCSUxJVFkuZmluZEluKGYpLFxuICAgICAgICApO1xuICAgICAgICB0aGlzLmZsb3dzID0gb2lkY0NvbXBhdGliaWxpdHlGbG93ID8gW29pZGNDb21wYXRpYmlsaXR5Rmxvd10gOiBmbG93cztcbiAgICAgICAgcmV0dXJuIHRoaXMuZmxvd3M7XG4gICAgfVxuXG4gICAgcHVibGljIGxvZ2luVmlhUGFzc3dvcmQoXG4gICAgICAgIHVzZXJuYW1lOiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gICAgICAgIHBob25lQ291bnRyeTogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICAgICAgICBwaG9uZU51bWJlcjogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICAgICAgICBwYXNzd29yZDogc3RyaW5nLFxuICAgICk6IFByb21pc2U8SU1hdHJpeENsaWVudENyZWRzPiB7XG4gICAgICAgIGNvbnN0IGlzRW1haWwgPSAhIXVzZXJuYW1lICYmIHVzZXJuYW1lLmluZGV4T2YoXCJAXCIpID4gMDtcblxuICAgICAgICBsZXQgaWRlbnRpZmllcjtcbiAgICAgICAgaWYgKHBob25lQ291bnRyeSAmJiBwaG9uZU51bWJlcikge1xuICAgICAgICAgICAgaWRlbnRpZmllciA9IHtcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm0uaWQucGhvbmVcIixcbiAgICAgICAgICAgICAgICBjb3VudHJ5OiBwaG9uZUNvdW50cnksXG4gICAgICAgICAgICAgICAgcGhvbmU6IHBob25lTnVtYmVyLFxuICAgICAgICAgICAgICAgIC8vIFhYWDogU3luYXBzZSBoaXN0b3JpY2FsbHkgd2FudGVkIGBudW1iZXJgIGFuZCBub3QgYHBob25lYFxuICAgICAgICAgICAgICAgIG51bWJlcjogcGhvbmVOdW1iZXIsXG4gICAgICAgICAgICB9O1xuICAgICAgICB9IGVsc2UgaWYgKGlzRW1haWwpIHtcbiAgICAgICAgICAgIGlkZW50aWZpZXIgPSB7XG4gICAgICAgICAgICAgICAgdHlwZTogXCJtLmlkLnRoaXJkcGFydHlcIixcbiAgICAgICAgICAgICAgICBtZWRpdW06IFwiZW1haWxcIixcbiAgICAgICAgICAgICAgICBhZGRyZXNzOiB1c2VybmFtZSxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpZGVudGlmaWVyID0ge1xuICAgICAgICAgICAgICAgIHR5cGU6IFwibS5pZC51c2VyXCIsXG4gICAgICAgICAgICAgICAgdXNlcjogdXNlcm5hbWUsXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgbG9naW5QYXJhbXMgPSB7XG4gICAgICAgICAgICBwYXNzd29yZCxcbiAgICAgICAgICAgIGlkZW50aWZpZXIsXG4gICAgICAgICAgICBpbml0aWFsX2RldmljZV9kaXNwbGF5X25hbWU6IHRoaXMuZGVmYXVsdERldmljZURpc3BsYXlOYW1lLFxuICAgICAgICB9O1xuXG4gICAgICAgIGNvbnN0IHRyeUZhbGxiYWNrSHMgPSAob3JpZ2luYWxFcnJvcjogRXJyb3IpOiBQcm9taXNlPElNYXRyaXhDbGllbnRDcmVkcz4gPT4ge1xuICAgICAgICAgICAgcmV0dXJuIHNlbmRMb2dpblJlcXVlc3QodGhpcy5mYWxsYmFja0hzVXJsISwgdGhpcy5pc1VybCwgXCJtLmxvZ2luLnBhc3N3b3JkXCIsIGxvZ2luUGFyYW1zKS5jYXRjaChcbiAgICAgICAgICAgICAgICAoZmFsbGJhY2tFcnJvcikgPT4ge1xuICAgICAgICAgICAgICAgICAgICBsb2dnZXIubG9nKFwiZmFsbGJhY2sgSFMgbG9naW4gZmFpbGVkXCIsIGZhbGxiYWNrRXJyb3IpO1xuICAgICAgICAgICAgICAgICAgICAvLyB0aHJvdyB0aGUgb3JpZ2luYWwgZXJyb3JcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgb3JpZ2luYWxFcnJvcjtcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfTtcblxuICAgICAgICBsZXQgb3JpZ2luYWxMb2dpbkVycm9yOiBFcnJvciB8IG51bGwgPSBudWxsO1xuICAgICAgICByZXR1cm4gc2VuZExvZ2luUmVxdWVzdCh0aGlzLmhzVXJsLCB0aGlzLmlzVXJsLCBcIm0ubG9naW4ucGFzc3dvcmRcIiwgbG9naW5QYXJhbXMpXG4gICAgICAgICAgICAuY2F0Y2goKGVycm9yKSA9PiB7XG4gICAgICAgICAgICAgICAgb3JpZ2luYWxMb2dpbkVycm9yID0gZXJyb3I7XG4gICAgICAgICAgICAgICAgaWYgKGVycm9yLmh0dHBTdGF0dXMgPT09IDQwMykge1xuICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5mYWxsYmFja0hzVXJsKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ5RmFsbGJhY2tIcyhvcmlnaW5hbExvZ2luRXJyb3IhKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB0aHJvdyBvcmlnaW5hbExvZ2luRXJyb3I7XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLmNhdGNoKChlcnJvcikgPT4ge1xuICAgICAgICAgICAgICAgIGxvZ2dlci5sb2coXCJMb2dpbiBmYWlsZWRcIiwgZXJyb3IpO1xuICAgICAgICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICAgICAgfSk7XG4gICAgfVxufVxuXG4vKipcbiAqIERlc2NyaWJlcyB0aGUgT0lEQyBuYXRpdmUgbG9naW4gZmxvd1xuICogU2VwYXJhdGUgZnJvbSBqcy1zZGsncyBgTG9naW5GbG93YCBhcyB0aGlzIGRvZXMgbm90IHVzZSB0aGUgc2FtZSAvbG9naW4gZmxvd1xuICogdG8gd2hpY2ggdGhhdCB0eXBlIGJlbG9uZ3MuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgT2lkY05hdGl2ZUZsb3cgZXh0ZW5kcyBJTG9naW5GbG93IHtcbiAgICB0eXBlOiBcIm9pZGNOYXRpdmVGbG93XCI7XG4gICAgLy8gdGhpcyBjbGllbnQncyBpZCBhcyByZWdpc3RlcmVkIHdpdGggdGhlIGNvbmZpZ3VyZWQgT0lEQyBPUFxuICAgIGNsaWVudElkOiBzdHJpbmc7XG59XG4vKipcbiAqIFByZXBhcmVzIGFuIE9pZGNOYXRpdmVGbG93IGZvciBsb2dnaW5nIGludG8gdGhlIHNlcnZlci5cbiAqXG4gKiBGaW5kcyBhIHN0YXRpYyBjbGllbnRJZCBmb3IgY29uZmlndXJlZCBpc3N1ZXIsIG9yIGF0dGVtcHRzIGR5bmFtaWMgcmVnaXN0cmF0aW9uIHdpdGggdGhlIE9QLCBhbmQgd3JhcHMgdGhlXG4gKiByZXN1bHRzLlxuICpcbiAqIEBwYXJhbSBkZWxlZ2F0ZWRBdXRoQ29uZmlnICBBdXRoIGNvbmZpZyBmcm9tIFZhbGlkYXRlZFNlcnZlckNvbmZpZ1xuICogQHBhcmFtIHN0YXRpY09pZGNDbGllbnRJZHMgc3RhdGljIGNsaWVudCBjb25maWcgZnJvbSBjb25maWcuanNvbiwgdXNlZCBkdXJpbmcgY2xpZW50IHJlZ2lzdHJhdGlvbiB3aXRoIE9QXG4gKiBAcGFyYW0gaXNSZWdpc3RyYXRpb24gdHJ1ZSB3aGVuIHdlIGFyZSBhdHRlbXB0aW5nIHJlZ2lzdHJhdGlvblxuICogQHJldHVybnMgUHJvbWlzZTxPaWRjTmF0aXZlRmxvdz4gd2hlbiBvaWRjIG5hdGl2ZSBhdXRoZW50aWNhdGlvbiBmbG93IGlzIHN1cHBvcnRlZCBhbmQgY29ycmVjdGx5IGNvbmZpZ3VyZWRcbiAqIEB0aHJvd3Mgd2hlbiBjbGllbnQgY2FuJ3QgcmVnaXN0ZXIgd2l0aCBPUCwgb3IgYW55IHVuZXhwZWN0ZWQgZXJyb3JcbiAqL1xuY29uc3QgdHJ5SW5pdE9pZGNOYXRpdmVGbG93ID0gYXN5bmMgKFxuICAgIGRlbGVnYXRlZEF1dGhDb25maWc6IE9pZGNDbGllbnRDb25maWcsXG4gICAgc3RhdGljT2lkY0NsaWVudElkcz86IElDb25maWdPcHRpb25zW1wib2lkY19zdGF0aWNfY2xpZW50c1wiXSxcbiAgICBpc1JlZ2lzdHJhdGlvbj86IGJvb2xlYW4sXG4pOiBQcm9taXNlPE9pZGNOYXRpdmVGbG93PiA9PiB7XG4gICAgLy8gaWYgcmVnaXN0cmF0aW9uIGlzIG5vdCBzdXBwb3J0ZWQsIGJhaWwgYmVmb3JlIGF0dGVtcHRpbmcgdG8gZ2V0IHRoZSBjbGllbnRJZFxuICAgIGlmIChpc1JlZ2lzdHJhdGlvbiAmJiAhaXNVc2VyUmVnaXN0cmF0aW9uU3VwcG9ydGVkKGRlbGVnYXRlZEF1dGhDb25maWcpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIlJlZ2lzdHJhdGlvbiBpcyBub3Qgc3VwcG9ydGVkIGJ5IE9QXCIpO1xuICAgIH1cbiAgICBjb25zdCBjbGllbnRJZCA9IGF3YWl0IGdldE9pZGNDbGllbnRJZChkZWxlZ2F0ZWRBdXRoQ29uZmlnLCBzdGF0aWNPaWRjQ2xpZW50SWRzKTtcblxuICAgIGNvbnN0IGZsb3cgPSB7XG4gICAgICAgIHR5cGU6IFwib2lkY05hdGl2ZUZsb3dcIixcbiAgICAgICAgY2xpZW50SWQsXG4gICAgfSBhcyBPaWRjTmF0aXZlRmxvdztcblxuICAgIHJldHVybiBmbG93O1xufTtcblxuLyoqXG4gKiBTZW5kIGEgbG9naW4gcmVxdWVzdCB0byB0aGUgZ2l2ZW4gc2VydmVyLCBhbmQgZm9ybWF0IHRoZSByZXNwb25zZVxuICogYXMgYSBNYXRyaXhDbGllbnRDcmVkc1xuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBoc1VybCAgIHRoZSBiYXNlIHVybCBvZiB0aGUgSG9tZXNlcnZlciB1c2VkIHRvIGxvZyBpbi5cbiAqIEBwYXJhbSB7c3RyaW5nfSBpc1VybCAgIHRoZSBiYXNlIHVybCBvZiB0aGUgZGVmYXVsdCBpZGVudGl0eSBzZXJ2ZXJcbiAqIEBwYXJhbSB7c3RyaW5nfSBsb2dpblR5cGUgdGhlIHR5cGUgb2YgbG9naW4gdG8gZG9cbiAqIEBwYXJhbSB7SUxvZ2luUGFyYW1zfSBsb2dpblBhcmFtcyB0aGUgcGFyYW1ldGVycyBmb3IgdGhlIGxvZ2luXG4gKlxuICogQHJldHVybnMge0lNYXRyaXhDbGllbnRDcmVkc31cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNlbmRMb2dpblJlcXVlc3QoXG4gICAgaHNVcmw6IHN0cmluZyxcbiAgICBpc1VybDogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICAgIGxvZ2luVHlwZTogc3RyaW5nLFxuICAgIGxvZ2luUGFyYW1zOiBPbWl0PExvZ2luUmVxdWVzdCwgXCJ0eXBlXCI+LFxuKTogUHJvbWlzZTxJTWF0cml4Q2xpZW50Q3JlZHM+IHtcbiAgICBjb25zdCBjbGllbnQgPSBjcmVhdGVDbGllbnQoe1xuICAgICAgICBiYXNlVXJsOiBoc1VybCxcbiAgICAgICAgaWRCYXNlVXJsOiBpc1VybCxcbiAgICB9KTtcblxuICAgIGNvbnN0IGRhdGEgPSBhd2FpdCBjbGllbnQubG9naW4obG9naW5UeXBlLCBsb2dpblBhcmFtcyk7XG5cbiAgICBjb25zdCB3ZWxsa25vd24gPSBkYXRhLndlbGxfa25vd247XG4gICAgaWYgKHdlbGxrbm93bikge1xuICAgICAgICBpZiAod2VsbGtub3duW1wibS5ob21lc2VydmVyXCJdPy5bXCJiYXNlX3VybFwiXSkge1xuICAgICAgICAgICAgaHNVcmwgPSB3ZWxsa25vd25bXCJtLmhvbWVzZXJ2ZXJcIl1bXCJiYXNlX3VybFwiXTtcbiAgICAgICAgICAgIGxvZ2dlci5sb2coYE92ZXJyb2RlIGhvbWVzZXJ2ZXIgc2V0dGluZyB3aXRoICR7aHNVcmx9IGZyb20gbG9naW4gcmVzcG9uc2VgKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAod2VsbGtub3duW1wibS5pZGVudGl0eV9zZXJ2ZXJcIl0/LltcImJhc2VfdXJsXCJdKSB7XG4gICAgICAgICAgICAvLyBUT0RPOiBzaG91bGQgd2UgcHJvbXB0IGhlcmU/XG4gICAgICAgICAgICBpc1VybCA9IHdlbGxrbm93bltcIm0uaWRlbnRpdHlfc2VydmVyXCJdW1wiYmFzZV91cmxcIl07XG4gICAgICAgICAgICBsb2dnZXIubG9nKGBPdmVycm9kZSBJUyBzZXR0aW5nIHdpdGggJHtpc1VybH0gZnJvbSBsb2dpbiByZXNwb25zZWApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgY29uc3QgY3JlZHM6IElNYXRyaXhDbGllbnRDcmVkcyA9IHtcbiAgICAgICAgaG9tZXNlcnZlclVybDogaHNVcmwsXG4gICAgICAgIGlkZW50aXR5U2VydmVyVXJsOiBpc1VybCxcbiAgICAgICAgdXNlcklkOiBkYXRhLnVzZXJfaWQsXG4gICAgICAgIGRldmljZUlkOiBkYXRhLmRldmljZV9pZCxcbiAgICAgICAgYWNjZXNzVG9rZW46IGRhdGEuYWNjZXNzX3Rva2VuLFxuICAgIH07XG5cbiAgICBNb2R1bGVSdW5uZXIuaW5zdGFuY2UuZXh0ZW5zaW9ucy5jcnlwdG9TZXR1cC5leGFtaW5lTG9naW5SZXNwb25zZShkYXRhLCBjcmVkcyk7XG5cbiAgICByZXR1cm4gY3JlZHM7XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7OztBQVNBLElBQUFBLE9BQUEsR0FBQUMsT0FBQTtBQVNBLElBQUFDLE9BQUEsR0FBQUQsT0FBQTtBQUdBLElBQUFFLGFBQUEsR0FBQUYsT0FBQTtBQUNBLElBQUFHLGVBQUEsR0FBQUgsT0FBQTtBQUVBLElBQUFJLFVBQUEsR0FBQUMsc0JBQUEsQ0FBQUwsT0FBQTtBQUNBLElBQUFNLDRCQUFBLEdBQUFOLE9BQUE7QUF6QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFvQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFjZSxNQUFNTyxLQUFLLENBQUM7RUFJeUI7O0VBRXpDQyxXQUFXQSxDQUNOQyxLQUFhLEVBQ2JDLEtBQWEsRUFDYkMsYUFBNEIsRUFDcENDLElBQW1CLEVBQ3JCO0lBQUEsSUFBQUMsZ0JBQUEsQ0FBQUMsT0FBQSxpQkFWc0MsRUFBRTtJQUFBLElBQUFELGdCQUFBLENBQUFDLE9BQUE7SUFBQSxJQUFBRCxnQkFBQSxDQUFBQyxPQUFBO0lBQUEsSUFBQUQsZ0JBQUEsQ0FBQUMsT0FBQSxzQkFHQSxJQUFJO0lBQUEsS0FHbENMLEtBQWEsR0FBYkEsS0FBYTtJQUFBLEtBQ2JDLEtBQWEsR0FBYkEsS0FBYTtJQUFBLEtBQ2JDLGFBQTRCLEdBQTVCQSxhQUE0QjtJQUdwQyxJQUFJLENBQUNJLHdCQUF3QixHQUFHSCxJQUFJLENBQUNHLHdCQUF3QjtJQUM3RCxJQUFJLENBQUNDLHVCQUF1QixHQUFHSixJQUFJLENBQUNJLHVCQUF1QjtFQUMvRDtFQUVPQyxnQkFBZ0JBLENBQUEs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