angular-simple-oidc
Version:
Angular Library implementing Open Id Connect specification. Code Flow, Refresh Tokens, Session Management, Discovery Document.
150 lines • 32.4 kB
JavaScript
import { Injectable, Inject } from '@angular/core';
import { WINDOW_REF, AUTH_CONFIG_SERVICE } from './providers';
import { tap, switchMap, take, map, withLatestFrom } from 'rxjs/operators';
import { TokenStorageService } from './token-storage.service';
import { TokenValidationService, TokenUrlService, AuthorizationCallbackFormatError, } from 'angular-simple-oidc/core';
import { urlJoin } from './utils/url-join';
import { OidcDiscoveryDocClient } from './discovery-document/oidc-discovery-doc-client.service';
import { TokenEndpointClientService } from './token-endpoint-client.service';
import { TokensValidatedEvent, TokensReadyEvent } from './auth.events';
import { DynamicIframeService } from './dynamic-iframe/dynamic-iframe.service';
import { switchTap } from 'angular-simple-oidc/operators';
import { ConfigService } from 'angular-simple-oidc/config';
import { EventsService, SimpleOidcInfoEvent } from 'angular-simple-oidc/events';
// @dynamic
export class OidcCodeFlowClient {
constructor(window, config, discoveryDocumentClient, tokenStorage, tokenValidation, tokenUrl, tokenEndpointClient, events, dynamicIframe) {
this.window = window;
this.config = config;
this.discoveryDocumentClient = discoveryDocumentClient;
this.tokenStorage = tokenStorage;
this.tokenValidation = tokenValidation;
this.tokenUrl = tokenUrl;
this.tokenEndpointClient = tokenEndpointClient;
this.events = events;
this.dynamicIframe = dynamicIframe;
}
startCodeFlow(options = {}) {
const opts = Object.assign({}, options);
if (!opts.returnUrlAfterCallback) {
opts.returnUrlAfterCallback = this.window.location.href;
}
return this.config.current$
.pipe(map(config => urlJoin(config.baseUrl, config.tokenCallbackRoute)), switchMap(redirectUri => this.generateCodeFlowMetadata({ redirectUri })), tap(() => this.events.dispatch(new SimpleOidcInfoEvent(`Starting Code Flow`))), switchMap((result) => {
this.events.dispatch(new SimpleOidcInfoEvent(`Authorize URL generated`, result));
return this.tokenStorage.storePreAuthorizationState({
nonce: result.nonce,
state: result.state,
codeVerifier: result.codeVerifier,
preRedirectUrl: opts.returnUrlAfterCallback
}).pipe(tap((state) => {
this.events.dispatch(new SimpleOidcInfoEvent(`Pre-authorize state stored`, state));
this.redirectToUrl(result.url);
}));
}), take(1));
}
generateCodeFlowMetadata(params) {
return this.discoveryDocumentClient.current$
.pipe(withLatestFrom(this.config.current$), map(([discoveryDocument, config]) => this.tokenUrl.createAuthorizeUrl(discoveryDocument.authorization_endpoint, Object.assign(Object.assign({ clientId: config.clientId, scope: config.scope, responseType: 'code' }, config.acrValues && { acrValues: config.acrValues }), params))), take(1));
}
parseCodeFlowCallbackParams(href) {
try {
const result = this.tokenUrl.parseAuthorizeCallbackParamsFromUrl(href);
return Object.assign(Object.assign({}, result), { href });
}
catch (error) {
throw new AuthorizationCallbackFormatError(error);
}
}
validateCodeFlowCallback(params, localState) {
const { href, code, state, error } = params;
this.events.dispatch(new SimpleOidcInfoEvent(`Validating URL params`, { code, state, error, href }));
this.tokenValidation.validateAuthorizeCallbackFormat(code, state, error, href);
this.events.dispatch(new SimpleOidcInfoEvent(`Validating state vs local state`, { localState, state }));
this.tokenValidation.validateAuthorizeCallbackState(localState, state);
this.events.dispatch(new SimpleOidcInfoEvent(`Obtained authorization code.`, { code, state }));
}
codeFlowCallback(href, redirectUri, metadata) {
const params = this.parseCodeFlowCallbackParams(href);
this.validateCodeFlowCallback(params, metadata.state);
return this.tokenStorage.storeAuthorizationCode(params.code, params.sessionState)
.pipe(switchMap(() => this.config.current$), switchMap(authConfig => {
const payload = this.tokenUrl.createAuthorizationCodeRequestPayload({
clientId: authConfig.clientId,
clientSecret: authConfig.clientSecret,
scope: authConfig.scope,
redirectUri,
code: params.code,
codeVerifier: metadata.codeVerifier,
});
return this.requestTokenWithAuthCode(payload, metadata.nonce);
}));
}
currentWindowCodeFlowCallback() {
return this.tokenStorage.currentState$
.pipe(take(1), // we will be trigger currentState$ below
tap(() => this.events.dispatch(new SimpleOidcInfoEvent(`Starting Code Flow callback`))), withLatestFrom(this.config.current$), map(([localState, config]) => {
const redirectUri = urlJoin(config.baseUrl, config.tokenCallbackRoute);
return {
localState,
redirectUri
};
}), switchMap(({ localState, redirectUri }) => this.codeFlowCallback(this.window.location.href, redirectUri, localState).pipe(tap(() => this.historyChangeUrl(localState.preRedirectUrl)))), take(1));
}
requestTokenWithAuthCode(payload, nonce) {
// The discovery document for issuer
const discoveryDocument$ = this.discoveryDocumentClient.current$
.pipe(take(1));
// JWT Keys to validate id token signature
const jwtKeys$ = this.discoveryDocumentClient.jwtKeys$
.pipe(take(1));
return this.tokenEndpointClient.call(payload)
.pipe(tap(() => this.events.dispatch(new SimpleOidcInfoEvent(`Requesting token using authorization code`, payload))), withLatestFrom(discoveryDocument$, jwtKeys$, this.config.current$), take(1), tap(([result, discoveryDocument, jwtKeys, config]) => {
this.events.dispatch(new SimpleOidcInfoEvent('Validating identity token..', {
result, nonce, discoveryDocument, jwtKeys
}));
this.tokenValidation.validateIdToken(config.clientId, result.idToken, result.decodedIdToken, nonce, discoveryDocument, jwtKeys, config.tokenValidation);
}), tap(([result]) => {
this.events.dispatch(new SimpleOidcInfoEvent('Validating access token..', result));
this.tokenValidation.validateAccessToken(result.accessToken, result.decodedIdToken.at_hash);
}), switchTap(() => {
this.events.dispatch(new SimpleOidcInfoEvent('Clearing pre-authorize state..'));
return this.tokenStorage.clearPreAuthorizationState();
}), switchTap(([result]) => {
this.events.dispatch(new TokensValidatedEvent(result));
this.events.dispatch(new SimpleOidcInfoEvent('Storing tokens..', result));
return this.tokenStorage.storeTokens(result);
}), switchTap(([result]) => {
this.events.dispatch(new SimpleOidcInfoEvent('Storing original Identity Token..', result.idToken));
return this.tokenStorage.storeOriginalIdToken(result.idToken);
}), map(([result]) => result), tap((result) => this.events.dispatch(new TokensReadyEvent(result))));
}
redirectToUrl(url) {
this.events.dispatch(new SimpleOidcInfoEvent(`Redirecting`, url));
this.window.location.href = url;
}
historyChangeUrl(url) {
if (this.window.history) {
this.events.dispatch(new SimpleOidcInfoEvent(`Changing URL with history API`, url));
this.window.history.pushState({}, null, url);
}
else {
this.redirectToUrl(url);
}
}
}
OidcCodeFlowClient.decorators = [
{ type: Injectable }
];
OidcCodeFlowClient.ctorParameters = () => [
{ type: Window, decorators: [{ type: Inject, args: [WINDOW_REF,] }] },
{ type: ConfigService, decorators: [{ type: Inject, args: [AUTH_CONFIG_SERVICE,] }] },
{ type: OidcDiscoveryDocClient },
{ type: TokenStorageService },
{ type: TokenValidationService },
{ type: TokenUrlService },
{ type: TokenEndpointClientService },
{ type: EventsService },
{ type: DynamicIframeService }
];
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib2lkYy1jb2RlLWZsb3ctY2xpZW50LnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9hbmd1bGFyLXNpbXBsZS1vaWRjL3NyYy9saWIvb2lkYy1jb2RlLWZsb3ctY2xpZW50LnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDbkQsT0FBTyxFQUFFLFVBQVUsRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUM5RCxPQUFPLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLGNBQWMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzNFLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQzlELE9BQU8sRUFDSCxzQkFBc0IsRUFDdEIsZUFBZSxFQUNmLGdDQUFnQyxHQUluQyxNQUFNLDBCQUEwQixDQUFDO0FBQ2xDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUMzQyxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSx3REFBd0QsQ0FBQztBQUNoRyxPQUFPLEVBQUUsMEJBQTBCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUM3RSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFdkUsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0seUNBQXlDLENBQUM7QUFDL0UsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQzFELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUUzRCxPQUFPLEVBQUUsYUFBYSxFQUFFLG1CQUFtQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFHaEYsV0FBVztBQUVYLE1BQU0sT0FBTyxrQkFBa0I7SUFD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bEMsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRTtZQUNyQixJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxJQUFJLG1CQUFtQixDQUFDLCtCQUErQixFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7WUFDcEYsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsRUFBRSxJQUFJLEVBQUUsR0FBRyxDQUFDLENBQUM7U0FDaEQ7YUFBTTtZQUNILElBQUksQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLENBQUM7U0FDM0I7SUFDTCxDQUFDOzs7WUEzTUosVUFBVTs7O1lBSXdCLE1BQU0sdUJBRGhDLE1BQU0sU0FBQyxVQUFVO1lBVGpCLGFBQWEsdUJBV2IsTUFBTSxTQUFDLG1CQUFtQjtZQWpCMUIsc0JBQXNCO1lBVnRCLG1CQUFtQjtZQUV4QixzQkFBc0I7WUFDdEIsZUFBZTtZQVFWLDBCQUEwQjtZQU8xQixhQUFhO1lBSmIsb0JBQW9CIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSwgSW5qZWN0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBXSU5ET1dfUkVGLCBBVVRIX0NPTkZJR19TRVJWSUNFIH0gZnJvbSAnLi9wcm92aWRlcnMnO1xuaW1wb3J0IHsgdGFwLCBzd2l0Y2hNYXAsIHRha2UsIG1hcCwgd2l0aExhdGVzdEZyb20gfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBUb2tlblN0b3JhZ2VTZXJ2aWNlIH0gZnJvbSAnLi90b2tlbi1zdG9yYWdlLnNlcnZpY2UnO1xuaW1wb3J0IHtcbiAgICBUb2tlblZhbGlkYXRpb25TZXJ2aWNlLFxuICAgIFRva2VuVXJsU2VydmljZSxcbiAgICBBdXRob3JpemF0aW9uQ2FsbGJhY2tGb3JtYXRFcnJvcixcbiAgICBMb2NhbFN0YXRlLFxuICAgIFRva2VuUmVxdWVzdFJlc3VsdCxcbiAgICBDcmVhdGVBdXRob3JpemVVcmxQYXJhbXMsXG59IGZyb20gJ2FuZ3VsYXItc2ltcGxlLW9pZGMvY29yZSc7XG5pbXBvcnQgeyB1cmxKb2luIH0gZnJvbSAnLi91dGlscy91cmwtam9pbic7XG5pbXBvcnQgeyBPaWRjRGlzY292ZXJ5RG9jQ2xpZW50IH0gZnJvbSAnLi9kaXNjb3ZlcnktZG9jdW1lbnQvb2lkYy1kaXNjb3ZlcnktZG9jLWNsaWVudC5zZXJ2aWNlJztcbmltcG9ydCB7IFRva2VuRW5kcG9pbnRDbGllbnRTZXJ2aWNlIH0gZnJvbSAnLi90b2tlbi1lbmRwb2ludC1jbGllbnQuc2VydmljZSc7XG5pbXBvcnQgeyBUb2tlbnNWYWxpZGF0ZWRFdmVudCwgVG9rZW5zUmVhZHlFdmVudCB9IGZyb20gJy4vYXV0aC5ldmVudHMnO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgRHluYW1pY0lmcmFtZVNlcnZpY2UgfSBmcm9tICcuL2R5bmFtaWMtaWZyYW1lL2R5bmFtaWMtaWZyYW1lLnNlcnZpY2UnO1xuaW1wb3J0IHsgc3dpdGNoVGFwIH0gZnJvbSAnYW5ndWxhci1zaW1wbGUtb2lkYy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgQ29uZmlnU2VydmljZSB9IGZyb20gJ2FuZ3VsYXItc2ltcGxlLW9pZGMvY29uZmlnJztcbmltcG9ydCB7IEF1dGhDb25maWcgfSBmcm9tICcuL2NvbmZpZy9tb2RlbHMnO1xuaW1wb3J0IHsgRXZlbnRzU2VydmljZSwgU2ltcGxlT2lkY0luZm9FdmVudCB9IGZyb20gJ2FuZ3VsYXItc2ltcGxlLW9pZGMvZXZlbnRzJztcbmltcG9ydCB7IFN0YXJ0Q29kZUZsb3dQYXJhbWV0ZXJzIH0gZnJvbSAnLi9tb2RlbHMnO1xuXG4vLyBAZHluYW1pY1xuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIE9pZGNDb2RlRmxvd0NsaWVudCB7XG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIEBJbmplY3QoV0lORE9XX1JFRilcbiAgICAgICAgcHJvdGVjdGVkIHJlYWRvbmx5IHdpbmRvdzogV2luZG93LFxuICAgICAgICBASW5qZWN0KEFVVEhfQ09ORklHX1NFUlZJQ0UpXG4gICAgICAgIHByb3RlY3RlZCByZWFkb25seSBjb25maWc6IENvbmZpZ1NlcnZpY2U8QXV0aENvbmZpZz4sXG4gICAgICAgIHByb3RlY3RlZCByZWFkb25seSBkaXNjb3ZlcnlEb2N1bWVudENsaWVudDogT2lkY0Rpc2NvdmVyeURvY0NsaWVudCxcbiAgICAgICAgcHJvdGVjdGVkIHJlYWRvbmx5IHRva2VuU3RvcmFnZTogVG9rZW5TdG9yYWdlU2VydmljZSxcbiAgICAgICAgcHJvdGVjdGVkIHJlYWRvbmx5IHRva2VuVmFsaWRhdGlvbjogVG9rZW5WYWxpZGF0aW9uU2VydmljZSxcbiAgICAgICAgcHJvdGVjdGVkIHJlYWRvbmx5IHRva2VuVXJsOiBUb2tlblVybFNlcnZpY2UsXG4gICAgICAgIHByb3RlY3RlZCByZWFkb25seSB0b2tlbkVuZHBvaW50Q2xpZW50OiBUb2tlbkVuZHBvaW50Q2xpZW50U2VydmljZSxcbiAgICAgICAgcHJvdGVjdGVkIHJlYWRvbmx5IGV2ZW50czogRXZlbnRzU2VydmljZSxcbiAgICAgICAgcHJvdGVjdGVkIHJlYWRvbmx5IGR5bmFtaWNJZnJhbWU6IER5bmFtaWNJZnJhbWVTZXJ2aWNlXG4gICAgKSB7IH1cblxuICAgIHB1YmxpYyBzdGFydENvZGVGbG93KG9wdGlvbnM6IFN0YXJ0Q29kZUZsb3dQYXJhbWV0ZXJzID0ge30pOiBPYnNlcnZhYmxlPExvY2FsU3RhdGU+IHtcbiAgICAgICAgY29uc3Qgb3B0czogU3RhcnRDb2RlRmxvd1BhcmFtZXRlcnMgPSB7XG4gICAgICAgICAgICAuLi5vcHRpb25zLFxuICAgICAgICB9O1xuXG4gICAgICAgIGlmICghb3B0cy5yZXR1cm5VcmxBZnRlckNhbGxiYWNrKSB7XG4gICAgICAgICAgICBvcHRzLnJldHVyblVybEFmdGVyQ2FsbGJhY2sgPSB0aGlzLndpbmRvdy5sb2NhdGlvbi5ocmVmO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuY29uZmlnLmN1cnJlbnQkXG4gICAgICAgICAgICAucGlwZShcbiAgICAgICAgICAgICAgICBtYXAoY29uZmlnID0+IHVybEpvaW4oY29uZmlnLmJhc2VVcmwsIGNvbmZpZy50b2tlbkNhbGxiYWNrUm91dGUpKSxcbiAgICAgICAgICAgICAgICBzd2l0Y2hNYXAocmVkaXJlY3RVcmkgPT4gdGhpcy5nZW5lcmF0ZUNvZGVGbG93TWV0YWRhdGEoeyByZWRpcmVjdFVyaSB9KSksXG4gICAgICAgICAgICAgICAgdGFwKCgpID0+IHRoaXMuZXZlbnRzLmRpc3BhdGNoKG5ldyBTaW1wbGVPaWRjSW5mb0V2ZW50KGBTdGFydGluZyBDb2RlIEZsb3dgKSkpLFxuICAgICAgICAgICAgICAgIHN3aXRjaE1hcCgocmVzdWx0KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZXZlbnRzLmRpc3BhdGNoKG5ldyBTaW1wbGVPaWRjSW5mb0V2ZW50KGBBdXRob3JpemUgVVJMIGdlbmVyYXRlZGAsIHJlc3VsdCkpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy50b2tlblN0b3JhZ2Uuc3RvcmVQcmVBdXRob3JpemF0aW9uU3RhdGUoe1xuICAgICAgICAgICAgICAgICAgICAgICAgbm9uY2U6IHJlc3VsdC5ub25jZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRlOiByZXN1bHQuc3RhdGUsXG4gICAgICAgICAgICAgICAgICAgICAgICBjb2RlVmVyaWZpZXI6IHJlc3VsdC5jb2RlVmVyaWZpZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICBwcmVSZWRpcmVjdFVybDogb3B0cy5yZXR1cm5VcmxBZnRlckNhbGxiYWNrXG4gICAgICAgICAgICAgICAgICAgIH0pLnBpcGUodGFwKChzdGF0ZSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5ldmVudHMuZGlzcGF0Y2gobmV3IFNpbXBsZU9pZGNJbmZvRXZlbnQoYFByZS1hdXRob3JpemUgc3RhdGUgc3RvcmVkYCwgc3RhdGUpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucmVkaXJlY3RUb1VybChyZXN1bHQudXJsKTtcbiAgICAgICAgICAgICAgICAgICAgfSkpO1xuICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgIHRha2UoMSlcbiAgICAgICAgICAgICk7XG4gICAgfVxuXG4gICAgcHVibGljIGdlbmVyYXRlQ29kZUZsb3dNZXRhZGF0YShcbiAgICAgICAgcGFyYW1zOiBPbWl0PENyZWF0ZUF1dGhvcml6ZVVybFBhcmFtcywgJ2NsaWVudElkJyB8ICdzY29wZScgfCAncmVzcG9uc2VUeXBlJz4pIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZGlzY292ZXJ5RG9jdW1lbnRDbGllbnQuY3VycmVudCRcbiAgICAgICAgICAgIC5waXBlKFxuICAgICAgICAgICAgICAgIHdpdGhMYXRlc3RGcm9tKHRoaXMuY29uZmlnLmN1cnJlbnQkKSxcbiAgICAgICAgICAgICAgICBtYXAoKFtkaXNjb3ZlcnlEb2N1bWVudCwgY29uZmlnXSkgPT4gdGhpcy50b2tlblVybC5jcmVhdGVBdXRob3JpemVVcmwoXG4gICAgICAgICAgICAgICAgICAgIGRpc2NvdmVyeURvY3VtZW50LmF1dGhvcml6YXRpb25fZW5kcG9pbnQsIHtcbiAgICAgICAgICAgICAgICAgICAgY2xpZW50SWQ6IGNvbmZpZy5jbGllbnRJZCxcbiAgICAgICAgICAgICAgICAgICAgc2NvcGU6IGNvbmZpZy5zY29wZSxcbiAgICAgICAgICAgICAgICAgICAgcmVzcG9uc2VUeXBlOiAnY29kZScsXG4gICAgICAgICAgICAgICAgICAgIC4uLmNvbmZpZy5hY3JWYWx1ZXMgJiYgeyBhY3JWYWx1ZXM6IGNvbmZpZy5hY3JWYWx1ZXMgfSxcbiAgICAgICAgICAgICAgICAgICAgLi4ucGFyYW1zLFxuICAgICAgICAgICAgICAgIH0pKSxcbiAgICAgICAgICAgICAgICB0YWtlKDEpLFxuICAgICAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgcGFyc2VDb2RlRmxvd0NhbGxiYWNrUGFyYW1zKGhyZWY6IHN0cmluZykge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0gdGhpcy50b2tlblVybC5wYXJzZUF1dGhvcml6ZUNhbGxiYWNrUGFyYW1zRnJvbVVybChocmVmKTtcbiAgICAgICAgICAgIHJldHVybiB7IC4uLnJlc3VsdCwgaHJlZiB9O1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEF1dGhvcml6YXRpb25DYWxsYmFja0Zvcm1hdEVycm9yKGVycm9yKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyB2YWxpZGF0ZUNvZGVGbG93Q2FsbGJhY2soXG4gICAgICAgIHBhcmFtczogeyBocmVmOiBzdHJpbmcsIGNvZGU6IHN0cmluZywgc3RhdGU6IHN0cmluZywgZXJyb3I6IHN0cmluZyB9LFxuICAgICAgICBsb2NhbFN0YXRlOiBzdHJpbmcpIHtcblxuICAgICAgICBjb25zdCB7IGhyZWYsIGNvZGUsIHN0YXRlLCBlcnJvciB9ID0gcGFyYW1zO1xuXG4gICAgICAgIHRoaXMuZXZlbnRzLmRpc3BhdGNoKG5ldyBTaW1wbGVPaWRjSW5mb0V2ZW50KGBWYWxpZGF0aW5nIFVSTCBwYXJhbXNgLFxuICAgICAgICAgICAgeyBjb2RlLCBzdGF0ZSwgZXJyb3IsIGhyZWYgfSkpO1xuICAgICAgICB0aGlzLnRva2VuVmFsaWRhdGlvbi52YWxpZGF0ZUF1dGhvcml6ZUNhbGxiYWNrRm9ybWF0KGNvZGUsIHN0YXRlLCBlcnJvciwgaHJlZik7XG5cbiAgICAgICAgdGhpcy5ldmVudHMuZGlzcGF0Y2gobmV3IFNpbXBsZU9pZGNJbmZvRXZlbnQoYFZhbGlkYXRpbmcgc3RhdGUgdnMgbG9jYWwgc3RhdGVgLFxuICAgICAgICAgICAgeyBsb2NhbFN0YXRlLCBzdGF0ZSB9KSk7XG5cbiAgICAgICAgdGhpcy50b2tlblZhbGlkYXRpb24udmFsaWRhdGVBdXRob3JpemVDYWxsYmFja1N0YXRlKGxvY2FsU3RhdGUsIHN0YXRlKTtcblxuICAgICAgICB0aGlzLmV2ZW50cy5kaXNwYXRjaChuZXcgU2ltcGxlT2lkY0luZm9FdmVudChgT2J0YWluZWQgYXV0aG9yaXphdGlvbiBjb2RlLmAsXG4gICAgICAgICAgICB7IGNvZGUsIHN0YXRlIH0pKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgY29kZUZsb3dDYWxsYmFjayhcbiAgICAgICAgaHJlZjogc3RyaW5nLFxuICAgICAgICByZWRpcmVjdFVyaTogc3RyaW5nLFxuICAgICAgICBtZXRhZGF0YTogeyBzdGF0ZTogc3RyaW5nLCBub25jZTogc3RyaW5nLCBjb2RlVmVyaWZpZXI6IHN0cmluZyB9KSB7XG5cbiAgICAgICAgY29uc3QgcGFyYW1zID0gdGhpcy5wYXJzZUNvZGVGbG93Q2FsbGJhY2tQYXJhbXMoaHJlZik7XG4gICAgICAgIHRoaXMudmFsaWRhdGVDb2RlRmxvd0NhbGxiYWNrKHBhcmFtcywgbWV0YWRhdGEuc3RhdGUpO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnRva2VuU3RvcmFnZS5zdG9yZUF1dGhvcml6YXRpb25Db2RlKHBhcmFtcy5jb2RlLCBwYXJhbXMuc2Vzc2lvblN0YXRlKVxuICAgICAgICAgICAgLnBpcGUoXG4gICAgICAgICAgICAgICAgc3dpdGNoTWFwKCgpID0+IHRoaXMuY29uZmlnLmN1cnJlbnQkKSxcbiAgICAgICAgICAgICAgICBzd2l0Y2hNYXAoYXV0aENvbmZpZyA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHBheWxvYWQgPSB0aGlzLnRva2VuVXJsLmNyZWF0ZUF1dGhvcml6YXRpb25Db2RlUmVxdWVzdFBheWxvYWQoe1xuICAgICAgICAgICAgICAgICAgICAgICAgY2xpZW50SWQ6IGF1dGhDb25maWcuY2xpZW50SWQsXG4gICAgICAgICAgICAgICAgICAgICAgICBjbGllbnRTZWNyZXQ6IGF1dGhDb25maWcuY2xpZW50U2VjcmV0LFxuICAgICAgICAgICAgICAgICAgICAgICAgc2NvcGU6IGF1dGhDb25maWcuc2NvcGUsXG4gICAgICAgICAgICAgICAgICAgICAgICByZWRpcmVjdFVyaSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvZGU6IHBhcmFtcy5jb2RlLFxuICAgICAgICAgICAgICAgICAgICAgICAgY29kZVZlcmlmaWVyOiBtZXRhZGF0YS5jb2RlVmVyaWZpZXIsXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLnJlcXVlc3RUb2tlbldpdGhBdXRoQ29kZShwYXlsb2FkLCBtZXRhZGF0YS5ub25jZSk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICk7XG4gICAgfVxuXG4gICAgcHVibGljIGN1cnJlbnRXaW5kb3dDb2RlRmxvd0NhbGxiYWNrKCk6IE9ic2VydmFibGU8VG9rZW5SZXF1ZXN0UmVzdWx0PiB7XG4gICAgICAgIHJldHVybiB0aGlzLnRva2VuU3RvcmFnZS5jdXJyZW50U3RhdGUkXG4gICAgICAgICAgICAucGlwZShcbiAgICAgICAgICAgICAgICB0YWtlKDEpLCAvLyB3ZSB3aWxsIGJlIHRyaWdnZXIgY3VycmVudFN0YXRlJCBiZWxvd1xuICAgICAgICAgICAgICAgIHRhcCgoKSA9PiB0aGlzLmV2ZW50cy5kaXNwYXRjaChuZXcgU2ltcGxlT2lkY0luZm9FdmVudChgU3RhcnRpbmcgQ29kZSBGbG93IGNhbGxiYWNrYCkpKSxcbiAgICAgICAgICAgICAgICB3aXRoTGF0ZXN0RnJvbSh0aGlzLmNvbmZpZy5jdXJyZW50JCksXG4gICAgICAgICAgICAgICAgbWFwKChbbG9jYWxTdGF0ZSwgY29uZmlnXSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCByZWRpcmVjdFVyaSA9IHVybEpvaW4oY29uZmlnLmJhc2VVcmwsIGNvbmZpZy50b2tlbkNhbGxiYWNrUm91dGUpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgbG9jYWxTdGF0ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlZGlyZWN0VXJpXG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgc3dpdGNoTWFwKCh7IGxvY2FsU3RhdGUsIHJlZGlyZWN0VXJpIH0pID0+XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY29kZUZsb3dDYWxsYmFjayh0aGlzLndpbmRvdy5sb2NhdGlvbi5ocmVmLCByZWRpcmVjdFVyaSwgbG9jYWxTdGF0ZSkucGlwZShcbiAgICAgICAgICAgICAgICAgICAgICAgIHRhcCgoKSA9PiB0aGlzLmhpc3RvcnlDaGFuZ2VVcmwobG9jYWxTdGF0ZS5wcmVSZWRpcmVjdFVybCkpXG4gICAgICAgICAgICAgICAgICAgICkpLFxuICAgICAgICAgICAgICAgIHRha2UoMSksXG4gICAgICAgICAgICApO1xuICAgIH1cblxuICAgIHB1YmxpYyByZXF1ZXN0VG9rZW5XaXRoQXV0aENvZGUocGF5bG9hZDogc3RyaW5nLCBub25jZTogc3RyaW5nKTogT2JzZXJ2YWJsZTxUb2tlblJlcXVlc3RSZXN1bHQ+IHtcblxuICAgICAgICAvLyBUaGUgZGlzY292ZXJ5IGRvY3VtZW50IGZvciBpc3N1ZXJcbiAgICAgICAgY29uc3QgZGlzY292ZXJ5RG9jdW1lbnQkID0gdGhpcy5kaXNjb3ZlcnlEb2N1bWVudENsaWVudC5jdXJyZW50JFxuICAgICAgICAgICAgLnBpcGUodGFrZSgxKSk7XG5cbiAgICAgICAgLy8gSldUIEtleXMgdG8gdmFsaWRhdGUgaWQgdG9rZW4gc2lnbmF0dXJlXG4gICAgICAgIGNvbnN0IGp3dEtleXMkID0gdGhpcy5kaXNjb3ZlcnlEb2N1bWVudENsaWVudC5qd3RLZXlzJFxuICAgICAgICAgICAgLnBpcGUodGFrZSgxKSk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMudG9rZW5FbmRwb2ludENsaWVudC5jYWxsKHBheWxvYWQpXG4gICAgICAgICAgICAucGlwZShcbiAgICAgICAgICAgICAgICB0YXAoKCkgPT4gdGhpcy5ldmVudHMuZGlzcGF0Y2gobmV3IFNpbXBsZU9pZGNJbmZvRXZlbnQoYFJlcXVlc3RpbmcgdG9rZW4gdXNpbmcgYXV0aG9yaXphdGlvbiBjb2RlYCwgcGF5bG9hZCkpKSxcbiAgICAgICAgICAgICAgICB3aXRoTGF0ZXN0RnJvbShkaXNjb3ZlcnlEb2N1bWVudCQsIGp3dEtleXMkLCB0aGlzLmNvbmZpZy5jdXJyZW50JCksXG4gICAgICAgICAgICAgICAgdGFrZSgxKSxcbiAgICAgICAgICAgICAgICB0YXAoKFtyZXN1bHQsIGRpc2NvdmVyeURvY3VtZW50LCBqd3RLZXlzLCBjb25maWddKSA9PiB7XG5cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5ldmVudHMuZGlzcGF0Y2gobmV3IFNpbXBsZU9pZGNJbmZvRXZlbnQoJ1ZhbGlkYXRpbmcgaWRlbnRpdHkgdG9rZW4uLicsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdCwgbm9uY2UsIGRpc2NvdmVyeURvY3VtZW50LCBqd3RLZXlzXG4gICAgICAgICAgICAgICAgICAgIH0pKTtcblxuICAgICAgICAgICAgICAgICAgICB0aGlzLnRva2VuVmFsaWRhdGlvbi52YWxpZGF0ZUlkVG9rZW4oXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25maWcuY2xpZW50SWQsXG4gICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQuaWRUb2tlbixcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdC5kZWNvZGVkSWRUb2tlbixcbiAgICAgICAgICAgICAgICAgICAgICAgIG5vbmNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgZGlzY292ZXJ5RG9jdW1lbnQsXG4gICAgICAgICAgICAgICAgICAgICAgICBqd3RLZXlzLFxuICAgICAgICAgICAgICAgICAgICAgICAgY29uZmlnLnRva2VuVmFsaWRhdGlvbik7XG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgdGFwKChbcmVzdWx0XSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmV2ZW50cy5kaXNwYXRjaChuZXcgU2ltcGxlT2lkY0luZm9FdmVudCgnVmFsaWRhdGluZyBhY2Nlc3MgdG9rZW4uLicsIHJlc3VsdCkpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnRva2VuVmFsaWRhdGlvbi52YWxpZGF0ZUFjY2Vzc1Rva2VuKHJlc3VsdC5hY2Nlc3NUb2tlbixcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdC5kZWNvZGVkSWRUb2tlbi5hdF9oYXNoKTtcbiAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgICBzd2l0Y2hUYXAoKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmV2ZW50cy5kaXNwYXRjaChuZXcgU2ltcGxlT2lkY0luZm9FdmVudCgnQ2xlYXJpbmcgcHJlLWF1dGhvcml6ZSBzdGF0ZS4uJykpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy50b2tlblN0b3JhZ2UuY2xlYXJQcmVBdXRob3JpemF0aW9uU3RhdGUoKTtcbiAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgICBzd2l0Y2hUYXAoKFtyZXN1bHRdKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZXZlbnRzLmRpc3BhdGNoKG5ldyBUb2tlbnNWYWxpZGF0ZWRFdmVudChyZXN1bHQpKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5ldmVudHMuZGlzcGF0Y2gobmV3IFNpbXBsZU9pZGNJbmZvRXZlbnQoJ1N0b3JpbmcgdG9rZW5zLi4nLCByZXN1bHQpKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMudG9rZW5TdG9yYWdlLnN0b3JlVG9rZW5zKHJlc3VsdCk7XG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgc3dpdGNoVGFwKChbcmVzdWx0XSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmV2ZW50cy5kaXNwYXRjaChuZXcgU2ltcGxlT2lkY0luZm9FdmVudCgnU3RvcmluZyBvcmlnaW5hbCBJZGVudGl0eSBUb2tlbi4uJywgcmVzdWx0LmlkVG9rZW4pKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMudG9rZW5TdG9yYWdlLnN0b3JlT3JpZ2luYWxJZFRva2VuKHJlc3VsdC5pZFRva2VuKTtcbiAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgICBtYXAoKFtyZXN1bHRdKSA9PiByZXN1bHQpLFxuICAgICAgICAgICAgICAgIHRhcCgocmVzdWx0KSA9PiB0aGlzLmV2ZW50cy5kaXNwYXRjaChuZXcgVG9rZW5zUmVhZHlFdmVudChyZXN1bHQpKSksXG4gICAgICAgICAgICApO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCByZWRpcmVjdFRvVXJsKHVybDogc3RyaW5nKSB7XG4gICAgICAgIHRoaXMuZXZlbnRzLmRpc3BhdGNoKG5ldyBTaW1wbGVPaWRjSW5mb0V2ZW50KGBSZWRpcmVjdGluZ2AsIHVybCkpO1xuICAgICAgICB0aGlzLndpbmRvdy5sb2NhdGlvbi5ocmVmID0gdXJsO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBoaXN0b3J5Q2hhbmdlVXJsKHVybDogc3RyaW5nKSB7XG4gICAgICAgIGlmICh0aGlzLndpbmRvdy5oaXN0b3J5KSB7XG4gICAgICAgICAgICB0aGlzLmV2ZW50cy5kaXNwYXRjaChuZXcgU2ltcGxlT2lkY0luZm9FdmVudChgQ2hhbmdpbmcgVVJMIHdpdGggaGlzdG9yeSBBUElgLCB1cmwpKTtcbiAgICAgICAgICAgIHRoaXMud2luZG93Lmhpc3RvcnkucHVzaFN0YXRlKHt9LCBudWxsLCB1cmwpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5yZWRpcmVjdFRvVXJsKHVybCk7XG4gICAgICAgIH1cbiAgICB9XG59XG4iXX0=