UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

263 lines 30.2 kB
import { Injectable } from '@angular/core'; import { ApplicationType, GrantType, TenantLoginOptionsService, TenantLoginOptionType, UserManagementSource, UserService } from '@c8y/client'; import { get, pick } from 'lodash-es'; import { AppStateService } from './ui-state.service'; import { take } from 'rxjs/operators'; import { Permissions } from '../common/permissions.service'; import * as i0 from "@angular/core"; import * as i1 from "@c8y/client"; import * as i2 from "./ui-state.service"; /** The helper UI service for tenant related methods built upon client services. */ export class TenantUiService { constructor(userService, appStateService, tenantLoginOption) { this.userService = userService; this.appStateService = appStateService; this.tenantLoginOption = tenantLoginOption; this.MANAGEMENT = 'management'; this.ROLE_TENANT_MANAGEMENT_READ = Permissions.ROLE_TENANT_MANAGEMENT_READ; } /** * Returns current tenant */ get currentTenant() { return this.appStateService.currentTenant.value; } /** * Checks whether current tenant is the management tenant. * @returns True if current tenant is the management tenant. */ async isManagementTenant() { const currentTenant = this.appStateService.currentTenant.value; return this.isManagement(currentTenant); } /** * Checks whether current tenant is an enterprise tenant. * An enterprise tenant is a tenant which has subscribed: * - `branding` microservice or `feature-branding` feature app, * - `sslmanagement` microservice, * - `feature-user-hierarchy` feature app, * - `feature-broker` feature app. * * See https://cumulocity.com/guides/users-guide/enterprise-edition/ for details about such tenants. * * @returns True, if current tenant is an enterprise tenant. */ async isEnterpriseTenant() { const availableAppsOfUser = await this.appStateService.currentAppsOfUser .pipe(take(1)) .toPromise(); const brandingAvailable = this.hasApp(availableAppsOfUser, 'branding') || this.hasApp(availableAppsOfUser, 'feature-branding'); const requiredAppsAndFeaturesAvailable = brandingAvailable && this.hasApp(availableAppsOfUser, 'sslmanagement') && this.hasApp(availableAppsOfUser, 'feature-user-hierarchy') && this.hasApp(availableAppsOfUser, 'feature-broker'); return requiredAppsAndFeaturesAvailable; } /** * Checks whether the current user has read access to tenants, i.e.: * - the current tenant can create subtenants or it's the management tenant, * - the current user has ROLE_TENANT_MANAGEMENT_READ role. * @returns True, if the current user has read access to tenants. */ canReadTenants() { const currentTenant = this.appStateService.currentTenant.value; const currentUser = this.appStateService.currentUser.value; return ((this.isManagement(currentTenant) || currentTenant.allowCreateTenants) && this.userService.hasRole(currentUser, this.ROLE_TENANT_MANAGEMENT_READ)); } /** * Returns current tenant preferred login mode. */ getCurrentTenantPreferredLoginOption() { return this.getPreferredLoginOption(this.appStateService.state.loginOptions); } /** * Returns current user login mode. */ getCurrentUserLoginMode() { const preferredLoginOption = this.getCurrentTenantPreferredLoginOption(); const currentUser = this.appStateService.currentUser.value; if (currentUser.customProperties.userOrigin === 'OAUTH2') { return TenantLoginOptionType.OAUTH2; } return this.isBasic(preferredLoginOption) ? TenantLoginOptionType.BASIC : TenantLoginOptionType.OAUTH2_INTERNAL; } /** * Returns tenant login option which is preferred. * * @param loginOptions The list of all available tenant's login options. * * @returns Returns ITenantLoginOption. * * **Example** * ```typescript * * (() => { * const preferredLoginOption = tenantLoginOptionsService.getPreferredLoginOption(loginOptions); * })(); * ``` */ getPreferredLoginOption(loginOptions) { const defaultFallback = { type: TenantLoginOptionType.BASIC, userManagementSource: UserManagementSource.INTERNAL }; if (!loginOptions) { return defaultFallback; } else { const visibleLoginOptions = loginOptions.filter(this.isVisibleOnLoginPage); return (visibleLoginOptions.find(this.isOauthInternal) || visibleLoginOptions.find(this.isBasic) || visibleLoginOptions.find(this.isOauth2) || defaultFallback); } } /** * Returns Oauth2 login option if it can be used by UI. * * @param loginOptions The list of all available tenant's login options. * * @returns Returns ITenantLoginOption. * * **Example** * ```typescript * * (() => { * const oauth2 = tenantLoginOptionsService.getOauth2Option(loginOptions); * })(); * ``` */ getOauth2Option(loginOptions) { return loginOptions.find(loginOption => this.isVisibleOnLoginPage(loginOption) && this.isOauth2(loginOption)); } /** * Callback which checks if login option is visible on login page. * * @param loginOption The tenant login option. * * **Example** * ```typescript * * (() => { * const loginOptionsVisibleOnLoginPage = loginOptions.filter(tenantLoginOptionsService.isVisibleOnLoginPage); * })(); * ``` */ isVisibleOnLoginPage(loginOption) { return loginOption.visibleOnLoginPage; } /** * Callback which checks if login option type is 'OAUTH2_INTERNAL'. * * @param loginOption The tenant login option. * * **Example** * ```typescript * * (() => { * const oauth2InternalLoginOptions = loginOptions.filter(tenantLoginOptionsService.isOauthInternal); * })(); * ``` */ isOauthInternal(loginOption) { return loginOption.type === TenantLoginOptionType.OAUTH2_INTERNAL; } /** * Callback which checks if login option type is 'BASIC'. * * @param loginOption The tenant login option. * * **Example** * ```typescript * * (() => { * const basicLoginOptions = loginOptions.filter(tenantLoginOptionsService.isBasic); * })(); * ``` */ isBasic(loginOption) { return loginOption.type === TenantLoginOptionType.BASIC; } /** * Callback which checks if login option type is 'OAUTH2' and grantType is 'AUTHORIZATION_CODE'. * * @param loginOption The tenant login option. * * **Example** * ```typescript * * (() => { * const oauth2LoginOptions = loginOptions.filter(tenantLoginOptionsService.OAUTH2); * })(); * ``` */ isOauth2(loginOption) { return (loginOption.type === TenantLoginOptionType.OAUTH2 && loginOption.grantType === GrantType.AUTHORIZATION_CODE); } /** * Checks if application of type MICROSERVICE is subscribed to the current tenant. * It checks the application references of the currentTenant from the application state. * No additional request. * @param identifier application name or contextPath */ isMicroserviceSubscribedInCurrentTenant(identifier) { if (identifier?.length > 0) { const microservices = this.getSubscribedMicroservicesInCurrentTenant(); return microservices.some(({ name, contextPath }) => [name, contextPath].includes(identifier)); } return false; } /** * Gets all application of type MICROSERVICE subscribed to the current tenant. * It checks the application references of the currentTenant from the application state. * No additional request. */ getSubscribedMicroservicesInCurrentTenant() { const references = get(this.appStateService.currentTenant, 'value.applications.references', []); return references .map(appRef => appRef.application) .filter(app => app.type === ApplicationType.MICROSERVICE); } /** * Gets password constraints setting from loginOptions. * @returns Returns Promise<PasswordStrengthSettings> with password properties. */ async getPasswordStrengthSettings() { return this.tenantLoginOption.list({}).then(res => { const loginOptionWithPasswordSettings = res.data.find(({ type }) => [TenantLoginOptionType.BASIC, TenantLoginOptionType.OAUTH2_INTERNAL].includes(type)); if (!loginOptionWithPasswordSettings) { return { enforceStrength: true, greenMinLength: 8, strengthValidity: true }; } return pick(loginOptionWithPasswordSettings, [ 'enforceStrength', 'greenMinLength', 'strengthValidity' ]); }); } hasApp(apps, requiredAppName) { if (!apps?.length) { return false; } return apps.some(app => app.name === requiredAppName); } isManagement(currentTenant) { return currentTenant.name === this.MANAGEMENT; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TenantUiService, deps: [{ token: i1.UserService }, { token: i2.AppStateService }, { token: i1.TenantLoginOptionsService }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TenantUiService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TenantUiService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: i1.UserService }, { type: i2.AppStateService }, { type: i1.TenantLoginOptionsService }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVuYW50LXVpLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9jb3JlL2NvbW1vbi90ZW5hbnQtdWkuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNDLE9BQU8sRUFDTCxlQUFlLEVBQ2YsU0FBUyxFQUtULHlCQUF5QixFQUN6QixxQkFBcUIsRUFDckIsb0JBQW9CLEVBQ3BCLFdBQVcsRUFDWixNQUFNLGFBQWEsQ0FBQztBQUNyQixPQUFPLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUN0QyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDckQsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3RDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQzs7OztBQU01RCxtRkFBbUY7QUFFbkYsTUFBTSxPQUFPLGVBQWU7SUFJMUIsWUFDVSxXQUF3QixFQUN4QixlQUFnQyxFQUNoQyxpQkFBNEM7UUFGNUMsZ0JBQVcsR0FBWCxXQUFXLENBQWE7UUFDeEIsb0JBQWUsR0FBZixlQUFlLENBQWlCO1FBQ2hDLHNCQUFpQixHQUFqQixpQkFBaUIsQ0FBMkI7UUFON0MsZUFBVSxHQUFHLFlBQVksQ0FBQztRQUMxQixnQ0FBMkIsR0FBRyxXQUFXLENBQUMsMkJBQTJCLENBQUM7SUFNNUUsQ0FBQztJQUVKOztPQUVHO0lBQ0gsSUFBSSxhQUFhO1FBQ2YsT0FBTyxJQUFJLENBQUMsZUFBZSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUM7SUFDbEQsQ0FBQztJQUVEOzs7T0FHRztJQUNILEtBQUssQ0FBQyxrQkFBa0I7UUFDdEIsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDO1FBQy9ELE9BQU8sSUFB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QUFvQixFQUFFLGVBQXVCO1FBQzFELElBQUksQ0FBQyxJQUFJLEVBQUUsTUFBTSxFQUFFLENBQUM7WUFDbEIsT0FBTyxLQUFLLENBQUM7UUFDZixDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksS0FBSyxlQUFlLENBQUMsQ0FBQztJQUN4RCxDQUFDO0lBRU8sWUFBWSxDQUFDLGFBQTZCO1FBQ2hELE9BQU8sYUFBYSxDQUFDLElBQUksS0FBSyxJQUFJLENBQUMsVUFBVSxDQUFDO0lBQ2hELENBQUM7K0dBN1JVLGVBQWU7bUhBQWYsZUFBZSxjQURGLE1BQU07OzRGQUNuQixlQUFlO2tCQUQzQixVQUFVO21CQUFDLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7XG4gIEFwcGxpY2F0aW9uVHlwZSxcbiAgR3JhbnRUeXBlLFxuICBJQXBwbGljYXRpb24sXG4gIElBcHBsaWNhdGlvblJlZmVyZW5jZSxcbiAgSUN1cnJlbnRUZW5hbnQsXG4gIElUZW5hbnRMb2dpbk9wdGlvbixcbiAgVGVuYW50TG9naW5PcHRpb25zU2VydmljZSxcbiAgVGVuYW50TG9naW5PcHRpb25UeXBlLFxuICBVc2VyTWFuYWdlbWVudFNvdXJjZSxcbiAgVXNlclNlcnZpY2Vcbn0gZnJvbSAnQGM4eS9jbGllbnQnO1xuaW1wb3J0IHsgZ2V0LCBwaWNrIH0gZnJvbSAnbG9kYXNoLWVzJztcbmltcG9ydCB7IEFwcFN0YXRlU2VydmljZSB9IGZyb20gJy4vdWktc3RhdGUuc2VydmljZSc7XG5pbXBvcnQgeyB0YWtlIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgUGVybWlzc2lvbnMgfSBmcm9tICcuLi9jb21tb24vcGVybWlzc2lvbnMuc2VydmljZSc7XG5cbmV4cG9ydCB0eXBlIFBhc3N3b3JkU3RyZW5ndGhTZXR0aW5ncyA9IFJlcXVpcmVkPFxuICBQaWNrPElUZW5hbnRMb2dpbk9wdGlvbiwgJ2VuZm9yY2VTdHJlbmd0aCcgfCAnZ3JlZW5NaW5MZW5ndGgnIHwgJ3N0cmVuZ3RoVmFsaWRpdHknPlxuPjtcblxuLyoqIFRoZSBoZWxwZXIgVUkgc2VydmljZSBmb3IgdGVuYW50IHJlbGF0ZWQgbWV0aG9kcyBidWlsdCB1cG9uIGNsaWVudCBzZXJ2aWNlcy4gKi9cbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXG5leHBvcnQgY2xhc3MgVGVuYW50VWlTZXJ2aWNlIHtcbiAgcmVhZG9ubHkgTUFOQUdFTUVOVCA9ICdtYW5hZ2VtZW50JztcbiAgcmVhZG9ubHkgUk9MRV9URU5BTlRfTUFOQUdFTUVOVF9SRUFEID0gUGVybWlzc2lvbnMuUk9MRV9URU5BTlRfTUFOQUdFTUVOVF9SRUFEO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgdXNlclNlcnZpY2U6IFVzZXJTZXJ2aWNlLFxuICAgIHByaXZhdGUgYXBwU3RhdGVTZXJ2aWNlOiBBcHBTdGF0ZVNlcnZpY2UsXG4gICAgcHJpdmF0ZSB0ZW5hbnRMb2dpbk9wdGlvbjogVGVuYW50TG9naW5PcHRpb25zU2VydmljZVxuICApIHt9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgY3VycmVudCB0ZW5hbnRcbiAgICovXG4gIGdldCBjdXJyZW50VGVuYW50KCk6IElDdXJyZW50VGVuYW50IHtcbiAgICByZXR1cm4gdGhpcy5hcHBTdGF0ZVNlcnZpY2UuY3VycmVudFRlbmFudC52YWx1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVja3Mgd2hldGhlciBjdXJyZW50IHRlbmFudCBpcyB0aGUgbWFuYWdlbWVudCB0ZW5hbnQuXG4gICAqIEByZXR1cm5zIFRydWUgaWYgY3VycmVudCB0ZW5hbnQgaXMgdGhlIG1hbmFnZW1lbnQgdGVuYW50LlxuICAgKi9cbiAgYXN5bmMgaXNNYW5hZ2VtZW50VGVuYW50KCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IGN1cnJlbnRUZW5hbnQgPSB0aGlzLmFwcFN0YXRlU2VydmljZS5jdXJyZW50VGVuYW50LnZhbHVlO1xuICAgIHJldHVybiB0aGlzLmlzTWFuYWdlbWVudChjdXJyZW50VGVuYW50KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVja3Mgd2hldGhlciBjdXJyZW50IHRlbmFudCBpcyBhbiBlbnRlcnByaXNlIHRlbmFudC5cbiAgICogQW4gZW50ZXJwcmlzZSB0ZW5hbnQgaXMgYSB0ZW5hbnQgd2hpY2ggaGFzIHN1YnNjcmliZWQ6XG4gICAqIC0gYGJyYW5kaW5nYCBtaWNyb3NlcnZpY2Ugb3IgYGZlYXR1cmUtYnJhbmRpbmdgIGZlYXR1cmUgYXBwLFxuICAgKiAtIGBzc2xtYW5hZ2VtZW50YCBtaWNyb3NlcnZpY2UsXG4gICAqIC0gYGZlYXR1cmUtdXNlci1oaWVyYXJjaHlgIGZlYXR1cmUgYXBwLFxuICAgKiAtIGBmZWF0dXJlLWJyb2tlcmAgZmVhdHVyZSBhcHAuXG4gICAqXG4gICAqIFNlZSBodHRwczovL2N1bXVsb2NpdHkuY29tL2d1aWRlcy91c2Vycy1ndWlkZS9lbnRlcnByaXNlLWVkaXRpb24vIGZvciBkZXRhaWxzIGFib3V0IHN1Y2ggdGVuYW50cy5cbiAgICpcbiAgICogQHJldHVybnMgVHJ1ZSwgaWYgY3VycmVudCB0ZW5hbnQgaXMgYW4gZW50ZXJwcmlzZSB0ZW5hbnQuXG4gICAqL1xuICBhc3luYyBpc0VudGVycHJpc2VUZW5hbnQoKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgYXZhaWxhYmxlQXBwc09mVXNlciA9IGF3YWl0IHRoaXMuYXBwU3RhdGVTZXJ2aWNlLmN1cnJlbnRBcHBzT2ZVc2VyXG4gICAgICAucGlwZSh0YWtlKDEpKVxuICAgICAgLnRvUHJvbWlzZSgpO1xuXG4gICAgY29uc3QgYnJhbmRpbmdBdmFpbGFibGUgPVxuICAgICAgdGhpcy5oYXNBcHAoYXZhaWxhYmxlQXBwc09mVXNlciwgJ2JyYW5kaW5nJykgfHxcbiAgICAgIHRoaXMuaGFzQXBwKGF2YWlsYWJsZUFwcHNPZlVzZXIsICdmZWF0dXJlLWJyYW5kaW5nJyk7XG5cbiAgICBjb25zdCByZXF1aXJlZEFwcHNBbmRGZWF0dXJlc0F2YWlsYWJsZSA9XG4gICAgICBicmFuZGluZ0F2YWlsYWJsZSAmJlxuICAgICAgdGhpcy5oYXNBcHAoYXZhaWxhYmxlQXBwc09mVXNlciwgJ3NzbG1hbmFnZW1lbnQnKSAmJlxuICAgICAgdGhpcy5oYXNBcHAoYXZhaWxhYmxlQXBwc09mVXNlciwgJ2ZlYXR1cmUtdXNlci1oaWVyYXJjaHknKSAmJlxuICAgICAgdGhpcy5oYXNBcHAoYXZhaWxhYmxlQXBwc09mVXNlciwgJ2ZlYXR1cmUtYnJva2VyJyk7XG5cbiAgICByZXR1cm4gcmVxdWlyZWRBcHBzQW5kRmVhdHVyZXNBdmFpbGFibGU7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIHdoZXRoZXIgdGhlIGN1cnJlbnQgdXNlciBoYXMgcmVhZCBhY2Nlc3MgdG8gdGVuYW50cywgaS5lLjpcbiAgICogLSB0aGUgY3VycmVudCB0ZW5hbnQgY2FuIGNyZWF0ZSBzdWJ0ZW5hbnRzIG9yIGl0J3MgdGhlIG1hbmFnZW1lbnQgdGVuYW50LFxuICAgKiAtIHRoZSBjdXJyZW50IHVzZXIgaGFzIFJPTEVfVEVOQU5UX01BTkFHRU1FTlRfUkVBRCByb2xlLlxuICAgKiBAcmV0dXJucyBUcnVlLCBpZiB0aGUgY3VycmVudCB1c2VyIGhhcyByZWFkIGFjY2VzcyB0byB0ZW5hbnRzLlxuICAgKi9cbiAgY2FuUmVhZFRlbmFudHMoKTogYm9vbGVhbiB7XG4gICAgY29uc3QgY3VycmVudFRlbmFudCA9IHRoaXMuYXBwU3RhdGVTZXJ2aWNlLmN1cnJlbnRUZW5hbnQudmFsdWU7XG4gICAgY29uc3QgY3VycmVudFVzZXIgPSB0aGlzLmFwcFN0YXRlU2VydmljZS5jdXJyZW50VXNlci52YWx1ZTtcbiAgICByZXR1cm4gKFxuICAgICAgKHRoaXMuaXNNYW5hZ2VtZW50KGN1cnJlbnRUZW5hbnQpIHx8IGN1cnJlbnRUZW5hbnQuYWxsb3dDcmVhdGVUZW5hbnRzKSAmJlxuICAgICAgdGhpcy51c2VyU2VydmljZS5oYXNSb2xlKGN1cnJlbnRVc2VyLCB0aGlzLlJPTEVfVEVOQU5UX01BTkFHRU1FTlRfUkVBRClcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgY3VycmVudCB0ZW5hbnQgcHJlZmVycmVkIGxvZ2luIG1vZGUuXG4gICAqL1xuICBnZXRDdXJyZW50VGVuYW50UHJlZmVycmVkTG9naW5PcHRpb24oKTogSVRlbmFudExvZ2luT3B0aW9uIHtcbiAgICByZXR1cm4gdGhpcy5nZXRQcmVmZXJyZWRMb2dpbk9wdGlvbih0aGlzLmFwcFN0YXRlU2VydmljZS5zdGF0ZS5sb2dpbk9wdGlvbnMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgY3VycmVudCB1c2VyIGxvZ2luIG1vZGUuXG4gICAqL1xuICBnZXRDdXJyZW50VXNlckxvZ2luTW9kZSgpOiBUZW5hbnRMb2dpbk9wdGlvblR5cGUge1xuICAgIGNvbnN0IHByZWZlcnJlZExvZ2luT3B0aW9uID0gdGhpcy5nZXRDdXJyZW50VGVuYW50UHJlZmVycmVkTG9naW5PcHRpb24oKTtcbiAgICBjb25zdCBjdXJyZW50VXNlciA9IHRoaXMuYXBwU3RhdGVTZXJ2aWNlLmN1cnJlbnRVc2VyLnZhbHVlO1xuICAgIGlmIChjdXJyZW50VXNlci5jdXN0b21Qcm9wZXJ0aWVzLnVzZXJPcmlnaW4gPT09ICdPQVVUSDInKSB7XG4gICAgICByZXR1cm4gVGVuYW50TG9naW5PcHRpb25UeXBlLk9BVVRIMjtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuaXNCYXNpYyhwcmVmZXJyZWRMb2dpbk9wdGlvbilcbiAgICAgID8gVGVuYW50TG9naW5PcHRpb25UeXBlLkJBU0lDXG4gICAgICA6IFRlbmFudExvZ2luT3B0aW9uVHlwZS5PQVVUSDJfSU5URVJOQUw7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0ZW5hbnQgbG9naW4gb3B0aW9uIHdoaWNoIGlzIHByZWZlcnJlZC5cbiAgICpcbiAgICogQHBhcmFtIGxvZ2luT3B0aW9ucyBUaGUgbGlzdCBvZiBhbGwgYXZhaWxhYmxlIHRlbmFudCdzIGxvZ2luIG9wdGlvbnMuXG4gICAqXG4gICAqIEByZXR1cm5zIFJldHVybnMgSVRlbmFudExvZ2luT3B0aW9uLlxuICAgKlxuICAgKiAqKkV4YW1wbGUqKlxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqXG4gICAqICAgICgoKSA9PiB7XG4gICAqICAgICAgY29uc3QgcHJlZmVycmVkTG9naW5PcHRpb24gPSB0ZW5hbnRMb2dpbk9wdGlvbnNTZXJ2aWNlLmdldFByZWZlcnJlZExvZ2luT3B0aW9uKGxvZ2luT3B0aW9ucyk7XG4gICAqICAgfSkoKTtcbiAgICogYGBgXG4gICAqL1xuICBnZXRQcmVmZXJyZWRMb2dpbk9wdGlvbihsb2dpbk9wdGlvbnM6IElUZW5hbnRMb2dpbk9wdGlvbltdKTogSVRlbmFudExvZ2luT3B0aW9uIHtcbiAgICBjb25zdCBkZWZhdWx0RmFsbGJhY2sgPSB7XG4gICAgICB0eXBlOiBUZW5hbnRMb2dpbk9wdGlvblR5cGUuQkFTSUMsXG4gICAgICB1c2VyTWFuYWdlbWVudFNvdXJjZTogVXNlck1hbmFnZW1lbnRTb3VyY2UuSU5URVJOQUxcbiAgICB9O1xuICAgIGlmICghbG9naW5PcHRpb25zKSB7XG4gICAgICByZXR1cm4gZGVmYXVsdEZhbGxiYWNrO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCB2aXNpYmxlTG9naW5PcHRpb25zID0gbG9naW5PcHRpb25zLmZpbHRlcih0aGlzLmlzVmlzaWJsZU9uTG9naW5QYWdlKTtcblxuICAgICAgcmV0dXJuIChcbiAgICAgICAgdmlzaWJsZUxvZ2luT3B0aW9ucy5maW5kKHRoaXMuaXNPYXV0aEludGVybmFsKSB8fFxuICAgICAgICB2aXNpYmxlTG9naW5PcHRpb25zLmZpbmQodGhpcy5pc0Jhc2ljKSB8fFxuICAgICAgICB2aXNpYmxlTG9naW5PcHRpb25zLmZpbmQodGhpcy5pc09hdXRoMikgfHxcbiAgICAgICAgZGVmYXVsdEZhbGxiYWNrXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIE9hdXRoMiBsb2dpbiBvcHRpb24gaWYgaXQgY2FuIGJlIHVzZWQgYnkgVUkuXG4gICAqXG4gICAqIEBwYXJhbSBsb2dpbk9wdGlvbnMgVGhlIGxpc3Qgb2YgYWxsIGF2YWlsYWJsZSB0ZW5hbnQncyBsb2dpbiBvcHRpb25zLlxuICAgKlxuICAgKiBAcmV0dXJucyBSZXR1cm5zIElUZW5hbnRMb2dpbk9wdGlvbi5cbiAgICpcbiAgICogKipFeGFtcGxlKipcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKlxuICAgKiAgICAoKCkgPT4ge1xuICAgKiAgICAgIGNvbnN0IG9hdXRoMiA9IHRlbmFudExvZ2luT3B0aW9uc1NlcnZpY2UuZ2V0T2F1dGgyT3B0aW9uKGxvZ2luT3B0aW9ucyk7XG4gICAqICAgfSkoKTtcbiAgICogYGBgXG4gICAqL1xuICBnZXRPYXV0aDJPcHRpb24obG9naW5PcHRpb25zOiBJVGVuYW50TG9naW5PcHRpb25bXSk6IElUZW5hbnRMb2dpbk9wdGlvbiB7XG4gICAgcmV0dXJuIGxvZ2luT3B0aW9ucy5maW5kKFxuICAgICAgbG9naW5PcHRpb24gPT4gdGhpcy5pc1Zpc2libGVPbkxvZ2luUGFnZShsb2dpbk9wdGlvbikgJiYgdGhpcy5pc09hdXRoMihsb2dpbk9wdGlvbilcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIENhbGxiYWNrIHdoaWNoIGNoZWNrcyBpZiBsb2dpbiBvcHRpb24gaXMgdmlzaWJsZSBvbiBsb2dpbiBwYWdlLlxuICAgKlxuICAgKiBAcGFyYW0gbG9naW5PcHRpb24gVGhlIHRlbmFudCBsb2dpbiBvcHRpb24uXG4gICAqXG4gICAqICoqRXhhbXBsZSoqXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICpcbiAgICogICAgKCgpID0+IHtcbiAgICogICAgICBjb25zdCBsb2dpbk9wdGlvbnNWaXNpYmxlT25Mb2dpblBhZ2UgPSBsb2dpbk9wdGlvbnMuZmlsdGVyKHRlbmFudExvZ2luT3B0aW9uc1NlcnZpY2UuaXNWaXNpYmxlT25Mb2dpblBhZ2UpO1xuICAgKiAgIH0pKCk7XG4gICAqIGBgYFxuICAgKi9cbiAgaXNWaXNpYmxlT25Mb2dpblBhZ2UobG9naW5PcHRpb246IElUZW5hbnRMb2dpbk9wdGlvbik6IGJvb2xlYW4ge1xuICAgIHJldHVybiBsb2dpbk9wdGlvbi52aXNpYmxlT25Mb2dpblBhZ2U7XG4gIH1cblxuICAvKipcbiAgICogQ2FsbGJhY2sgd2hpY2ggY2hlY2tzIGlmIGxvZ2luIG9wdGlvbiB0eXBlIGlzICdPQVVUSDJfSU5URVJOQUwnLlxuICAgKlxuICAgKiBAcGFyYW0gbG9naW5PcHRpb24gVGhlIHRlbmFudCBsb2dpbiBvcHRpb24uXG4gICAqXG4gICAqICoqRXhhbXBsZSoqXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICpcbiAgICogICAgKCgpID0+IHtcbiAgICogICAgICBjb25zdCBvYXV0aDJJbnRlcm5hbExvZ2luT3B0aW9ucyA9IGxvZ2luT3B0aW9ucy5maWx0ZXIodGVuYW50TG9naW5PcHRpb25zU2VydmljZS5pc09hdXRoSW50ZXJuYWwpO1xuICAgKiAgIH0pKCk7XG4gICAqIGBgYFxuICAgKi9cbiAgaXNPYXV0aEludGVybmFsKGxvZ2luT3B0aW9uOiBJVGVuYW50TG9naW5PcHRpb24pOiBib29sZWFuIHtcbiAgICByZXR1cm4gbG9naW5PcHRpb24udHlwZSA9PT0gVGVuYW50TG9naW5PcHRpb25UeXBlLk9BVVRIMl9JTlRFUk5BTDtcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxsYmFjayB3aGljaCBjaGVja3MgaWYgbG9naW4gb3B0aW9uIHR5cGUgaXMgJ0JBU0lDJy5cbiAgICpcbiAgICogQHBhcmFtIGxvZ2luT3B0aW9uIFRoZSB0ZW5hbnQgbG9naW4gb3B0aW9uLlxuICAgKlxuICAgKiAqKkV4YW1wbGUqKlxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqXG4gICAqICAgICgoKSA9PiB7XG4gICAqICAgICAgY29uc3QgYmFzaWNMb2dpbk9wdGlvbnMgPSBsb2dpbk9wdGlvbnMuZmlsdGVyKHRlbmFudExvZ2luT3B0aW9uc1NlcnZpY2UuaXNCYXNpYyk7XG4gICAqICAgfSkoKTtcbiAgICogYGBgXG4gICAqL1xuICBpc0Jhc2ljKGxvZ2luT3B0aW9uOiBJVGVuYW50TG9naW5PcHRpb24pOiBib29sZWFuIHtcbiAgICByZXR1cm4gbG9naW5PcHRpb24udHlwZSA9PT0gVGVuYW50TG9naW5PcHRpb25UeXBlLkJBU0lDO1xuICB9XG5cbiAgLyoqXG4gICAqIENhbGxiYWNrIHdoaWNoIGNoZWNrcyBpZiBsb2dpbiBvcHRpb24gdHlwZSBpcyAnT0FVVEgyJyBhbmQgZ3JhbnRUeXBlIGlzICdBVVRIT1JJWkFUSU9OX0NPREUnLlxuICAgKlxuICAgKiBAcGFyYW0gbG9naW5PcHRpb24gVGhlIHRlbmFudCBsb2dpbiBvcHRpb24uXG4gICAqXG4gICAqICoqRXhhbXBsZSoqXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICpcbiAgICogICAgKCgpID0+IHtcbiAgICogICAgICBjb25zdCBvYXV0aDJMb2dpbk9wdGlvbnMgPSBsb2dpbk9wdGlvbnMuZmlsdGVyKHRlbmFudExvZ2luT3B0aW9uc1NlcnZpY2UuT0FVVEgyKTtcbiAgICogICB9KSgpO1xuICAgKiBgYGBcbiAgICovXG4gIGlzT2F1dGgyKGxvZ2luT3B0aW9uOiBJVGVuYW50TG9naW5PcHRpb24pOiBib29sZWFuIHtcbiAgICByZXR1cm4gKFxuICAgICAgbG9naW5PcHRpb24udHlwZSA9PT0gVGVuYW50TG9naW5PcHRpb25UeXBlLk9BVVRIMiAmJlxuICAgICAgbG9naW5PcHRpb24uZ3JhbnRUeXBlID09PSBHcmFudFR5cGUuQVVUSE9SSVpBVElPTl9DT0RFXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVja3MgaWYgYXBwbGljYXRpb24gb2YgdHlwZSBNSUNST1NFUlZJQ0UgaXMgc3Vic2NyaWJlZCB0byB0aGUgY3VycmVudCB0ZW5hbnQuXG4gICAqIEl0IGNoZWNrcyB0aGUgYXBwbGljYXRpb24gcmVmZXJlbmNlcyBvZiB0aGUgY3VycmVudFRlbmFudCBmcm9tIHRoZSBhcHBsaWNhdGlvbiBzdGF0ZS5cbiAgICogTm8gYWRkaXRpb25hbCByZXF1ZXN0LlxuICAgKiBAcGFyYW0gaWRlbnRpZmllciBhcHBsaWNhdGlvbiBuYW1lIG9yIGNvbnRleHRQYXRoXG4gICAqL1xuICBpc01pY3Jvc2VydmljZVN1YnNjcmliZWRJbkN1cnJlbnRUZW5hbnQoaWRlbnRpZmllcjogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgaWYgKGlkZW50aWZpZXI/Lmxlbmd0aCA+IDApIHtcbiAgICAgIGNvbnN0IG1pY3Jvc2VydmljZXMgPSB0aGlzLmdldFN1YnNjcmliZWRNaWNyb3NlcnZpY2VzSW5DdXJyZW50VGVuYW50KCk7XG4gICAgICByZXR1cm4gbWljcm9zZXJ2aWNlcy5zb21lKCh7IG5hbWUsIGNvbnRleHRQYXRoIH0pID0+XG4gICAgICAgIFtuYW1lLCBjb250ZXh0UGF0aF0uaW5jbHVkZXMoaWRlbnRpZmllcilcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIGFsbCBhcHBsaWNhdGlvbiBvZiB0eXBlIE1JQ1JPU0VSVklDRSBzdWJzY3JpYmVkIHRvIHRoZSBjdXJyZW50IHRlbmFudC5cbiAgICogSXQgY2hlY2tzIHRoZSBhcHBsaWNhdGlvbiByZWZlcmVuY2VzIG9mIHRoZSBjdXJyZW50VGVuYW50IGZyb20gdGhlIGFwcGxpY2F0aW9uIHN0YXRlLlxuICAgKiBObyBhZGRpdGlvbmFsIHJlcXVlc3QuXG4gICAqL1xuICBnZXRTdWJzY3JpYmVkTWljcm9zZXJ2aWNlc0luQ3VycmVudFRlbmFudCgpOiBJQXBwbGljYXRpb25bXSB7XG4gICAgY29uc3QgcmVmZXJlbmNlczogSUFwcGxpY2F0aW9uUmVmZXJlbmNlW10gPSBnZXQoXG4gICAgICB0aGlzLmFwcFN0YXRlU2VydmljZS5jdXJyZW50VGVuYW50LFxuICAgICAgJ3ZhbHVlLmFwcGxpY2F0aW9ucy5yZWZlcmVuY2VzJyxcbiAgICAgIFtdXG4gICAgKTtcbiAgICByZXR1cm4gcmVmZXJlbmNlc1xuICAgICAgLm1hcChhcHBSZWYgPT4gYXBwUmVmLmFwcGxpY2F0aW9uKVxuICAgICAgLmZpbHRlcihhcHAgPT4gYXBwLnR5cGUgPT09IEFwcGxpY2F0aW9uVHlwZS5NSUNST1NFUlZJQ0UpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgcGFzc3dvcmQgY29uc3RyYWludHMgc2V0dGluZyBmcm9tIGxvZ2luT3B0aW9ucy5cbiAgICogQHJldHVybnMgUmV0dXJucyBQcm9taXNlPFBhc3N3b3JkU3RyZW5ndGhTZXR0aW5ncz4gd2l0aCBwYXNzd29yZCBwcm9wZXJ0aWVzLlxuICAgKi9cbiAgYXN5bmMgZ2V0UGFzc3dvcmRTdHJlbmd0aFNldHRpbmdzKCk6IFByb21pc2U8UGFzc3dvcmRTdHJlbmd0aFNldHRpbmdzPiB7XG4gICAgcmV0dXJuIHRoaXMudGVuYW50TG9naW5PcHRpb24ubGlzdCh7fSkudGhlbihyZXMgPT4ge1xuICAgICAgY29uc3QgbG9naW5PcHRpb25XaXRoUGFzc3dvcmRTZXR0aW5ncyA9IHJlcy5kYXRhLmZpbmQoKHsgdHlwZSB9KSA9PlxuICAgICAgICBbVGVuYW50TG9naW5PcHRpb25UeXBlLkJBU0lDLCBUZW5hbnRMb2dpbk9wdGlvblR5cGUuT0FVVEgyX0lOVEVSTkFMXS5pbmNsdWRlcyh0eXBlKVxuICAgICAgKTtcblxuICAgICAgaWYgKCFsb2dpbk9wdGlvbldpdGhQYXNzd29yZFNldHRpbmdzKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgZW5mb3JjZVN0cmVuZ3RoOiB0cnVlLFxuICAgICAgICAgIGdyZWVuTWluTGVuZ3RoOiA4LFxuICAgICAgICAgIHN0cmVuZ3RoVmFsaWRpdHk6IHRydWVcbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHBpY2sobG9naW5PcHRpb25XaXRoUGFzc3dvcmRTZXR0aW5ncywgW1xuICAgICAgICAnZW5mb3JjZVN0cmVuZ3RoJyxcbiAgICAgICAgJ2dyZWVuTWluTGVuZ3RoJyxcbiAgICAgICAgJ3N0cmVuZ3RoVmFsaWRpdHknXG4gICAgICBdKTtcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgaGFzQXBwKGFwcHM6IElBcHBsaWNhdGlvbltdLCByZXF1aXJlZEFwcE5hbWU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIGlmICghYXBwcz8ubGVuZ3RoKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHJldHVybiBhcHBzLnNvbWUoYXBwID0+IGFwcC5uYW1lID09PSByZXF1aXJlZEFwcE5hbWUpO1xuICB9XG5cbiAgcHJpdmF0ZSBpc01hbmFnZW1lbnQoY3VycmVudFRlbmFudDogSUN1cnJlbnRUZW5hbnQpIHtcbiAgICByZXR1cm4gY3VycmVudFRlbmFudC5uYW1lID09PSB0aGlzLk1BTkFHRU1FTlQ7XG4gIH1cbn1cbiJdfQ==