angular-auth-oidc-client
Version:
Angular Lib for OpenID Connect & OAuth2
165 lines • 27.9 kB
JavaScript
import { DOCUMENT } from '@angular/common';
import { Inject, Injectable } from '@angular/core';
import { BehaviorSubject, Observable, of } from 'rxjs';
import { take } from 'rxjs/operators';
import { EventTypes } from '../public-events/event-types';
import * as i0 from "@angular/core";
import * as i1 from "../storage/storage-persistence.service";
import * as i2 from "../logging/logger.service";
import * as i3 from "./existing-iframe.service";
import * as i4 from "../public-events/public-events.service";
const IFRAME_FOR_CHECK_SESSION_IDENTIFIER = 'myiFrameForCheckSession';
// http://openid.net/specs/openid-connect-session-1_0-ID4.html
export class CheckSessionService {
constructor(storagePersistenceService, loggerService, iFrameService, eventService, zone, document) {
this.storagePersistenceService = storagePersistenceService;
this.loggerService = loggerService;
this.iFrameService = iFrameService;
this.eventService = eventService;
this.zone = zone;
this.document = document;
this.checkSessionReceived = false;
this.lastIFrameRefresh = 0;
this.outstandingMessages = 0;
this.heartBeatInterval = 3000;
this.iframeRefreshInterval = 60000;
this.checkSessionChangedInternal$ = new BehaviorSubject(false);
}
get checkSessionChanged$() {
return this.checkSessionChangedInternal$.asObservable();
}
isCheckSessionConfigured(configuration) {
const { startCheckSession } = configuration;
return startCheckSession;
}
start(configuration) {
if (!!this.scheduledHeartBeatRunning) {
return;
}
const { clientId } = configuration;
this.pollServerSession(clientId, configuration);
}
stop() {
if (!this.scheduledHeartBeatRunning) {
return;
}
this.clearScheduledHeartBeat();
this.checkSessionReceived = false;
}
serverStateChanged(configuration) {
const { startCheckSession } = configuration;
return startCheckSession && this.checkSessionReceived;
}
getExistingIframe() {
return this.iFrameService.getExistingIFrame(IFRAME_FOR_CHECK_SESSION_IDENTIFIER);
}
init(configuration) {
if (this.lastIFrameRefresh + this.iframeRefreshInterval > Date.now()) {
return of(undefined);
}
const authWellKnownEndPoints = this.storagePersistenceService.read('authWellKnownEndPoints', configuration);
if (!authWellKnownEndPoints) {
this.loggerService.logWarning(configuration, 'CheckSession - init check session: authWellKnownEndpoints is undefined. Returning.');
return of();
}
const existingIframe = this.getOrCreateIframe(configuration);
const checkSessionIframe = authWellKnownEndPoints.checkSessionIframe;
if (checkSessionIframe) {
existingIframe.contentWindow.location.replace(checkSessionIframe);
}
else {
this.loggerService.logWarning(configuration, 'CheckSession - init check session: checkSessionIframe is not configured to run');
}
return new Observable((observer) => {
existingIframe.onload = () => {
this.lastIFrameRefresh = Date.now();
observer.next();
observer.complete();
};
});
}
pollServerSession(clientId, configuration) {
this.outstandingMessages = 0;
const pollServerSessionRecur = () => {
this.init(configuration)
.pipe(take(1))
.subscribe(() => {
const existingIframe = this.getExistingIframe();
if (existingIframe && clientId) {
this.loggerService.logDebug(configuration, `CheckSession - clientId : '${clientId}' - existingIframe: '${existingIframe}'`);
const sessionState = this.storagePersistenceService.read('session_state', configuration);
const authWellKnownEndPoints = this.storagePersistenceService.read('authWellKnownEndPoints', configuration);
if (sessionState && authWellKnownEndPoints?.checkSessionIframe) {
const iframeOrigin = new URL(authWellKnownEndPoints.checkSessionIframe)?.origin;
this.outstandingMessages++;
existingIframe.contentWindow.postMessage(clientId + ' ' + sessionState, iframeOrigin);
}
else {
this.loggerService.logDebug(configuration, `CheckSession - session_state is '${sessionState}' - AuthWellKnownEndPoints is '${JSON.stringify(authWellKnownEndPoints, null, 2)}'`);
this.checkSessionChangedInternal$.next(true);
}
}
else {
this.loggerService.logWarning(configuration, `CheckSession - OidcSecurityCheckSession pollServerSession checkSession IFrame does not exist:
clientId : '${clientId}' - existingIframe: '${existingIframe}'`);
}
// after sending three messages with no response, fail.
if (this.outstandingMessages > 3) {
this.loggerService.logError(configuration, `CheckSession - OidcSecurityCheckSession not receiving check session response messages.
Outstanding messages: '${this.outstandingMessages}'. Server unreachable?`);
}
this.zone.runOutsideAngular(() => {
this.scheduledHeartBeatRunning = setTimeout(() => this.zone.run(pollServerSessionRecur), this.heartBeatInterval);
});
});
};
pollServerSessionRecur();
}
clearScheduledHeartBeat() {
clearTimeout(this.scheduledHeartBeatRunning);
this.scheduledHeartBeatRunning = null;
}
messageHandler(configuration, e) {
const existingIFrame = this.getExistingIframe();
const authWellKnownEndPoints = this.storagePersistenceService.read('authWellKnownEndPoints', configuration);
const startsWith = !!authWellKnownEndPoints?.checkSessionIframe?.startsWith(e.origin);
this.outstandingMessages = 0;
if (existingIFrame && startsWith && e.source === existingIFrame.contentWindow) {
if (e.data === 'error') {
this.loggerService.logWarning(configuration, 'CheckSession - error from check session messageHandler');
}
else if (e.data === 'changed') {
this.loggerService.logDebug(configuration, `CheckSession - ${e} from check session messageHandler`);
this.checkSessionReceived = true;
this.eventService.fireEvent(EventTypes.CheckSessionReceived, e.data);
this.checkSessionChangedInternal$.next(true);
}
else {
this.eventService.fireEvent(EventTypes.CheckSessionReceived, e.data);
this.loggerService.logDebug(configuration, `CheckSession - ${e.data} from check session messageHandler`);
}
}
}
bindMessageEventToIframe(configuration) {
const iframeMessageEvent = this.messageHandler.bind(this, configuration);
this.document.defaultView.addEventListener('message', iframeMessageEvent, false);
}
getOrCreateIframe(configuration) {
const existingIframe = this.getExistingIframe();
if (!existingIframe) {
const frame = this.iFrameService.addIFrameToWindowBody(IFRAME_FOR_CHECK_SESSION_IDENTIFIER, configuration);
this.bindMessageEventToIframe(configuration);
return frame;
}
return existingIframe;
}
}
CheckSessionService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.0", ngImport: i0, type: CheckSessionService, deps: [{ token: i1.StoragePersistenceService }, { token: i2.LoggerService }, { token: i3.IFrameService }, { token: i4.PublicEventsService }, { token: i0.NgZone }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Injectable });
CheckSessionService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.1.0", ngImport: i0, type: CheckSessionService });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.0", ngImport: i0, type: CheckSessionService, decorators: [{
type: Injectable
}], ctorParameters: function () { return [{ type: i1.StoragePersistenceService }, { type: i2.LoggerService }, { type: i3.IFrameService }, { type: i4.PublicEventsService }, { type: i0.NgZone }, { type: undefined, decorators: [{
type: Inject,
args: [DOCUMENT]
}] }]; } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hlY2stc2Vzc2lvbi5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYW5ndWxhci1hdXRoLW9pZGMtY2xpZW50L3NyYy9saWIvaWZyYW1lL2NoZWNrLXNlc3Npb24uc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDM0MsT0FBTyxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQVUsTUFBTSxlQUFlLENBQUM7QUFDM0QsT0FBTyxFQUFFLGVBQWUsRUFBRSxVQUFVLEVBQUUsRUFBRSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3ZELE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUV0QyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sOEJBQThCLENBQUM7Ozs7OztBQU0xRCxNQUFNLG1DQUFtQyxHQUFHLHlCQUF5QixDQUFDO0FBRXRFLDhEQUE4RDtBQUc5RCxNQUFNLE9BQU8sbUJBQW1CO0lBbUI5QixZQUNtQix5QkFBb0QsRUFDcEQsYUFBNEIsRUFDNUIsYUFBNEIsRUFDNUIsWUFBaUMsRUFDakMsSUFBWSxFQUNNLFFBQWE7UUFML0IsOEJBQXlCLEdBQXpCLHlCQUF5QixDQUEyQjtRQUNwRCxrQkFBYSxHQUFiLGFBQWEsQ0FBZTtRQUM1QixrQkFBYSxHQUFiLGFBQWEsQ0FBZTtRQUM1QixpQkFBWSxHQUFaLFlBQVksQ0FBcUI7UUFDakMsU0FBSSxHQUFKLElBQUksQ0FBUTtRQUNNLGFBQVEsR0FBUixRQUFRLENBQUs7UUF4QjFDLHlCQUFvQixHQUFHLEtBQUssQ0FBQztRQUk3QixzQkFBaUIsR0FBRyxDQUFDLENBQUM7UUFFdEIsd0JBQW1CLEdBQUcsQ0FBQyxDQUFDO1FBRWYsc0JBQWlCLEdBQUcsSUFBSSxDQUFDO1FBRXpCLDBCQUFxQixHQUFHLEtBQUssQ0FBQztRQUU5QixpQ0FBNEIs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LEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxxQkFBcUIsQ0FBQyxtQ0FBbUMsRUFBRSxhQUFhLENBQUMsQ0FBQztZQUUzRyxJQUFJLENBQUMsd0JBQXdCLENBQUMsYUFBYSxDQUFDLENBQUM7WUFFN0MsT0FBTyxLQUFLLENBQUM7U0FDZDtRQUVELE9BQU8sY0FBYyxDQUFDO0lBQ3hCLENBQUM7O2dIQW5NVSxtQkFBbUIsOEtBeUJwQixRQUFRO29IQXpCUCxtQkFBbUI7MkZBQW5CLG1CQUFtQjtrQkFEL0IsVUFBVTs7MEJBMEJOLE1BQU07MkJBQUMsUUFBUSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IERPQ1VNRU5UIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcclxuaW1wb3J0IHsgSW5qZWN0LCBJbmplY3RhYmxlLCBOZ1pvbmUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBPYnNlcnZhYmxlLCBvZiB9IGZyb20gJ3J4anMnO1xyXG5pbXBvcnQgeyB0YWtlIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xyXG5pbXBvcnQgeyBMb2dnZXJTZXJ2aWNlIH0gZnJvbSAnLi4vbG9nZ2luZy9sb2dnZXIuc2VydmljZSc7XHJcbmltcG9ydCB7IEV2ZW50VHlwZXMgfSBmcm9tICcuLi9wdWJsaWMtZXZlbnRzL2V2ZW50LXR5cGVzJztcclxuaW1wb3J0IHsgUHVibGljRXZlbnRzU2VydmljZSB9IGZyb20gJy4uL3B1YmxpYy1ldmVudHMvcHVibGljLWV2ZW50cy5zZXJ2aWNlJztcclxuaW1wb3J0IHsgU3RvcmFnZVBlcnNpc3RlbmNlU2VydmljZSB9IGZyb20gJy4uL3N0b3JhZ2Uvc3RvcmFnZS1wZXJzaXN0ZW5jZS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgT3BlbklkQ29uZmlndXJhdGlvbiB9IGZyb20gJy4vLi4vY29uZmlnL29wZW5pZC1jb25maWd1cmF0aW9uJztcclxuaW1wb3J0IHsgSUZyYW1lU2VydmljZSB9IGZyb20gJy4vZXhpc3RpbmctaWZyYW1lLnNlcnZpY2UnO1xyXG5cclxuY29uc3QgSUZSQU1FX0ZPUl9DSEVDS19TRVNTSU9OX0lERU5USUZJRVIgPSAnbXlpRnJhbWVGb3JDaGVja1Nlc3Npb24nO1xyXG5cclxuLy8gaHR0cDovL29wZW5pZC5uZXQvc3BlY3Mvb3BlbmlkLWNvbm5lY3Qtc2Vzc2lvbi0xXzAtSUQ0Lmh0bWxcclxuXHJcbkBJbmplY3RhYmxlKClcclxuZXhwb3J0IGNsYXNzIENoZWNrU2Vzc2lvblNlcnZpY2Uge1xyXG4gIHByaXZhdGUgY2hlY2tTZXNzaW9uUmVjZWl2ZWQgPSBmYWxzZTtcclxuXHJcbiAgcHJpdmF0ZSBzY2hlZHVsZWRIZWFydEJlYXRSdW5uaW5nOiBhbnk7XHJcblxyXG4gIHByaXZhdGUgbGFzdElGcmFtZVJlZnJlc2ggPSAwO1xyXG5cclxuICBwcml2YXRlIG91dHN0YW5kaW5nTWVzc2FnZXMgPSAwO1xyXG5cclxuICBwcml2YXRlIHJlYWRvbmx5IGhlYXJ0QmVhdEludGVydmFsID0gMzAwMDtcclxuXHJcbiAgcHJpdmF0ZSByZWFkb25seSBpZnJhbWVSZWZyZXNoSW50ZXJ2YWwgPSA2MDAwMDtcclxuXHJcbiAgcHJpdmF0ZSByZWFkb25seSBjaGVja1Nlc3Npb25DaGFuZ2VkSW50ZXJuYWwkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxib29sZWFuPihmYWxzZSk7XHJcblxyXG4gIGdldCBjaGVja1Nlc3Npb25DaGFuZ2VkJCgpOiBPYnNlcnZhYmxlPGJvb2xlYW4+IHtcclxuICAgIHJldHVybiB0aGlzLmNoZWNrU2Vzc2lvbkNoYW5nZWRJbnRlcm5hbCQuYXNPYnNlcnZhYmxlKCk7XHJcbiAgfVxyXG5cclxuICBjb25zdHJ1Y3RvcihcclxuICAgIHByaXZhdGUgcmVhZG9ubHkgc3RvcmFnZVBlcnNpc3RlbmNlU2VydmljZTogU3RvcmFnZVBlcnNpc3RlbmNlU2VydmljZSxcclxuICAgIHByaXZhdGUgcmVhZG9ubHkgbG9nZ2VyU2VydmljZTogTG9nZ2VyU2VydmljZSxcclxuICAgIHByaXZhdGUgcmVhZG9ubHkgaUZyYW1lU2VydmljZTogSUZyYW1lU2VydmljZSxcclxuICAgIHByaXZhdGUgcmVhZG9ubHkgZXZlbnRTZXJ2aWNlOiBQdWJsaWNFdmVudHNTZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSByZWFkb25seSB6b25lOiBOZ1pvbmUsXHJcbiAgICBASW5qZWN0KERPQ1VNRU5UKSBwcml2YXRlIHJlYWRvbmx5IGRvY3VtZW50OiBhbnlcclxuICApIHt9XHJcblxyXG4gIGlzQ2hlY2tTZXNzaW9uQ29uZmlndXJlZChjb25maWd1cmF0aW9uOiBPcGVuSWRDb25maWd1cmF0aW9uKTogYm9vbGVhbiB7XHJcbiAgICBjb25zdCB7IHN0YXJ0Q2hlY2tTZXNzaW9uIH0gPSBjb25maWd1cmF0aW9uO1xyXG5cclxuICAgIHJldHVybiBzdGFydENoZWNrU2Vzc2lvbjtcclxuICB9XHJcblxyXG4gIHN0YXJ0KGNvbmZpZ3VyYXRpb246IE9wZW5JZENvbmZpZ3VyYXRpb24pOiB2b2lkIHtcclxuICAgIGlmICghIXRoaXMuc2NoZWR1bGVkSGVhcnRCZWF0UnVubmluZykge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgeyBjbGllbnRJZCB9ID0gY29uZmlndXJhdGlvbjtcclxuXHJcbiAgICB0aGlzLnBvbGxTZXJ2ZXJTZXNzaW9uKGNsaWVudElkLCBjb25maWd1cmF0aW9uKTtcclxuICB9XHJcblxyXG4gIHN0b3AoKTogdm9pZCB7XHJcbiAgICBpZiAoIXRoaXMuc2NoZWR1bGVkSGVhcnRCZWF0UnVubmluZykge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5jbGVhclNjaGVkdWxlZEhlYXJ0QmVhdCgpO1xyXG4gICAgdGhpcy5jaGVja1Nlc3Npb25SZWNlaXZlZCA9IGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgc2VydmVyU3RhdGVDaGFuZ2VkKGNvbmZpZ3VyYXRpb246IE9wZW5JZENvbmZpZ3VyYXRpb24pOiBib29sZWFuIHtcclxuICAgIGNvbnN0IHsgc3RhcnRDaGVja1Nlc3Npb24gfSA9IGNvbmZpZ3VyYXRpb247XHJcblxyXG4gICAgcmV0dXJuIHN0YXJ0Q2hlY2tTZXNzaW9uICYmIHRoaXMuY2hlY2tTZXNzaW9uUmVjZWl2ZWQ7XHJcbiAgfVxyXG5cclxuICBnZXRFeGlzdGluZ0lmcmFtZSgpOiBIVE1MSUZyYW1lRWxlbWVudCB7XHJcbiAgICByZXR1cm4gdGhpcy5pRnJhbWVTZXJ2aWNlLmdldEV4aXN0aW5nSUZyYW1lKElGUkFNRV9GT1JfQ0hFQ0tfU0VTU0lPTl9JREVOVElGSUVSKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgaW5pdChjb25maWd1cmF0aW9uOiBPcGVuSWRDb25maWd1cmF0aW9uKTogT2JzZXJ2YWJsZTxhbnk+IHtcclxuICAgIGlmICh0aGlzLmxhc3RJRnJhbWVSZWZyZXNoICsgdGhpcy5pZnJhbWVSZWZyZXNoSW50ZXJ2YWwgPiBEYXRlLm5vdygpKSB7XHJcbiAgICAgIHJldHVybiBvZih1bmRlZmluZWQpO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IGF1dGhXZWxsS25vd25FbmRQb2ludHMgPSB0aGlzLnN0b3JhZ2VQZXJzaXN0ZW5jZVNlcnZpY2UucmVhZCgnYXV0aFdlbGxLbm93bkVuZFBvaW50cycsIGNvbmZpZ3VyYXRpb24pO1xyXG5cclxuICAgIGlmICghYXV0aFdlbGxLbm93bkVuZFBvaW50cykge1xyXG4gICAgICB0aGlzLmxvZ2dlclNlcnZpY2UubG9nV2FybmluZyhjb25maWd1cmF0aW9uLCAnQ2hlY2tTZXNzaW9uIC0gaW5pdCBjaGVjayBzZXNzaW9uOiBhdXRoV2VsbEtub3duRW5kcG9pbnRzIGlzIHVuZGVmaW5lZC4gUmV0dXJuaW5nLicpO1xyXG5cclxuICAgICAgcmV0dXJuIG9mKCk7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgZXhpc3RpbmdJZnJhbWUgPSB0aGlzLmdldE9yQ3JlYXRlSWZyYW1lKGNvbmZpZ3VyYXRpb24pO1xyXG4gICAgY29uc3QgY2hlY2tTZXNzaW9uSWZyYW1lID0gYXV0aFdlbGxLbm93bkVuZFBvaW50cy5jaGVja1Nlc3Npb25JZnJhbWU7XHJcblxyXG4gICAgaWYgKGNoZWNrU2Vzc2lvbklmcmFtZSkge1xyXG4gICAgICBleGlzdGluZ0lmcmFtZS5jb250ZW50V2luZG93LmxvY2F0aW9uLnJlcGxhY2UoY2hlY2tTZXNzaW9uSWZyYW1lKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRoaXMubG9nZ2VyU2VydmljZS5sb2dXYXJuaW5nKGNvbmZpZ3VyYXRpb24sICdDaGVja1Nlc3Npb24gLSBpbml0IGNoZWNrIHNlc3Npb246IGNoZWNrU2Vzc2lvbklmcmFtZSBpcyBub3QgY29uZmlndXJlZCB0byBydW4nKTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gbmV3IE9ic2VydmFibGUoKG9ic2VydmVyKSA9PiB7XHJcbiAgICAgIGV4aXN0aW5nSWZyYW1lLm9ubG9hZCA9ICgpOiB2b2lkID0+IHtcclxuICAgICAgICB0aGlzLmxhc3RJRnJhbWVSZWZyZXNoID0gRGF0ZS5ub3coKTtcclxuICAgICAgICBvYnNlcnZlci5uZXh0KCk7XHJcbiAgICAgICAgb2JzZXJ2ZXIuY29tcGxldGUoKTtcclxuICAgICAgfTtcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBwb2xsU2VydmVyU2Vzc2lvbihjbGllbnRJZDogc3RyaW5nLCBjb25maWd1cmF0aW9uOiBPcGVuSWRDb25maWd1cmF0aW9uKTogdm9pZCB7XHJcbiAgICB0aGlzLm91dHN0YW5kaW5nTWVzc2FnZXMgPSAwO1xyXG5cclxuICAgIGNvbnN0IHBvbGxTZXJ2ZXJTZXNzaW9uUmVjdXIgPSAoKTogdm9pZCA9PiB7XHJcbiAgICAgIHRoaXMuaW5pdChjb25maWd1cmF0aW9uKVxyXG4gICAgICAgIC5waXBlKHRha2UoMSkpXHJcbiAgICAgICAgLnN1YnNjcmliZSgoKSA9PiB7XHJcbiAgICAgICAgICBjb25zdCBleGlzdGluZ0lmcmFtZSA9IHRoaXMuZ2V0RXhpc3RpbmdJZnJhbWUoKTtcclxuXHJcbiAgICAgICAgICBpZiAoZXhpc3RpbmdJZnJhbWUgJiYgY2xpZW50SWQpIHtcclxuICAgICAgICAgICAgdGhpcy5sb2dnZXJTZXJ2aWNlLmxvZ0RlYnVnKGNvbmZpZ3VyYXRpb24sIGBDaGVja1Nlc3Npb24gLSBjbGllbnRJZCA6ICcke2NsaWVudElkfScgLSBleGlzdGluZ0lmcmFtZTogJyR7ZXhpc3RpbmdJZnJhbWV9J2ApO1xyXG4gICAgICAgICAgICBjb25zdCBzZXNzaW9uU3RhdGUgPSB0aGlzLnN0b3JhZ2VQZXJzaXN0ZW5jZVNlcnZpY2UucmVhZCgnc2Vzc2lvbl9zdGF0ZScsIGNvbmZpZ3VyYXRpb24pO1xyXG4gICAgICAgICAgICBjb25zdCBhdXRoV2VsbEtub3duRW5kUG9pbnRzID0gdGhpcy5zdG9yYWdlUGVyc2lzdGVuY2VTZXJ2aWNlLnJlYWQoJ2F1dGhXZWxsS25vd25FbmRQb2ludHMnLCBjb25maWd1cmF0aW9uKTtcclxuXHJcbiAgICAgICAgICAgIGlmIChzZXNzaW9uU3RhdGUgJiYgYXV0aFdlbGxLbm93bkVuZFBvaW50cz8uY2hlY2tTZXNzaW9uSWZyYW1lKSB7XHJcbiAgICAgICAgICAgICAgY29uc3QgaWZyYW1lT3JpZ2luID0gbmV3IFVSTChhdXRoV2VsbEtub3duRW5kUG9pbnRzLmNoZWNrU2Vzc2lvbklmcmFtZSk/Lm9yaWdpbjtcclxuXHJcbiAgICAgICAgICAgICAgdGhpcy5vdXRzdGFuZGluZ01lc3NhZ2VzKys7XHJcbiAgICAgICAgICAgICAgZXhpc3RpbmdJZnJhbWUuY29udGVudFdpbmRvdy5wb3N0TWVzc2FnZShjbGllbnRJZCArICcgJyArIHNlc3Npb25TdGF0ZSwgaWZyYW1lT3JpZ2luKTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICB0aGlzLmxvZ2dlclNlcnZpY2UubG9nRGVidWcoXHJcbiAgICAgICAgICAgICAgICBjb25maWd1cmF0aW9uLFxyXG4gICAgICAgICAgICAgICAgYENoZWNrU2Vzc2lvbiAtIHNlc3Npb25fc3RhdGUgaXMgJyR7c2Vzc2lvblN0YXRlfScgLSBBdXRoV2VsbEtub3duRW5kUG9pbnRzIGlzICcke0pTT04uc3RyaW5naWZ5KFxyXG4gICAgICAgICAgICAgICAgICBhdXRoV2VsbEtub3duRW5kUG9pbnRzLFxyXG4gICAgICAgICAgICAgICAgICBudWxsLFxyXG4gICAgICAgICAgICAgICAgICAyXHJcbiAgICAgICAgICAgICAgICApfSdgXHJcbiAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICB0aGlzLmNoZWNrU2Vzc2lvbkNoYW5nZWRJbnRlcm5hbCQubmV4dCh0cnVlKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgdGhpcy5sb2dnZXJTZXJ2aWNlLmxvZ1dhcm5pbmcoXHJcbiAgICAgICAgICAgICAgY29uZmlndXJhdGlvbixcclxuICAgICAgICAgICAgICBgQ2hlY2tTZXNzaW9uIC0gT2lkY1NlY3VyaXR5Q2hlY2tTZXNzaW9uIHBvbGxTZXJ2ZXJTZXNzaW9uIGNoZWNrU2Vzc2lvbiBJRnJhbWUgZG9lcyBub3QgZXhpc3Q6XHJcbiAgICAgICAgICAgICAgIGNsaWVudElkIDogJyR7Y2xpZW50SWR9JyAtIGV4aXN0aW5nSWZyYW1lOiAnJHtleGlzdGluZ0lmcmFtZX0nYFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIC8vIGFmdGVyIHNlbmRpbmcgdGhyZWUgbWVzc2FnZXMgd2l0aCBubyByZXNwb25zZSwgZmFpbC5cclxuICAgICAgICAgIGlmICh0aGlzLm91dHN0YW5kaW5nTWVzc2FnZXMgPiAzKSB7XHJcbiAgICAgICAgICAgIHRoaXMubG9nZ2VyU2VydmljZS5sb2dFcnJvcihcclxuICAgICAgICAgICAgICBjb25maWd1cmF0aW9uLFxyXG4gICAgICAgICAgICAgIGBDaGVja1Nlc3Npb24gLSBPaWRjU2VjdXJpdHlDaGVja1Nlc3Npb24gbm90IHJlY2VpdmluZyBjaGVjayBzZXNzaW9uIHJlc3BvbnNlIG1lc3NhZ2VzLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgT3V0c3RhbmRpbmcgbWVzc2FnZXM6ICcke3RoaXMub3V0c3RhbmRpbmdNZXNzYWdlc30nLiBTZXJ2ZXIgdW5yZWFjaGFibGU/YFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIHRoaXMuem9uZS5ydW5PdXRzaWRlQW5ndWxhcigoKSA9PiB7XHJcbiAgICAgICAgICAgIHRoaXMuc2NoZWR1bGVkSGVhcnRCZWF0UnVubmluZyA9IHNldFRpbWVvdXQoKCkgPT4gdGhpcy56b25lLnJ1bihwb2xsU2VydmVyU2Vzc2lvblJlY3VyKSwgdGhpcy5oZWFydEJlYXRJbnRlcnZhbCk7XHJcbiAgICAgICAgICB9KTtcclxuICAgICAgICB9KTtcclxuICAgIH07XHJcblxyXG4gICAgcG9sbFNlcnZlclNlc3Npb25SZWN1cigpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBjbGVhclNjaGVkdWxlZEhlYXJ0QmVhdCgpOiB2b2lkIHtcclxuICAgIGNsZWFyVGltZW91dCh0aGlzLnNjaGVkdWxlZEhlYXJ0QmVhdFJ1bm5pbmcpO1xyXG4gICAgdGhpcy5zY2hlZHVsZWRIZWFydEJlYXRSdW5uaW5nID0gbnVsbDtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgbWVzc2FnZUhhbmRsZXIoY29uZmlndXJhdGlvbjogT3BlbklkQ29uZmlndXJhdGlvbiwgZTogYW55KTogdm9pZCB7XHJcbiAgICBjb25zdCBleGlzdGluZ0lGcmFtZSA9IHRoaXMuZ2V0RXhpc3RpbmdJZnJhbWUoKTtcclxuICAgIGNvbnN0IGF1dGhXZWxsS25vd25FbmRQb2ludHMgPSB0aGlzLnN0b3JhZ2VQZXJzaXN0ZW5jZVNlcnZpY2UucmVhZCgnYXV0aFdlbGxLbm93bkVuZFBvaW50cycsIGNvbmZpZ3VyYXRpb24pO1xyXG4gICAgY29uc3Qgc3RhcnRzV2l0aCA9ICEhYXV0aFdlbGxLbm93bkVuZFBvaW50cz8uY2hlY2tTZXNzaW9uSWZyYW1lPy5zdGFydHNXaXRoKGUub3JpZ2luKTtcclxuXHJcbiAgICB0aGlzLm91dHN0YW5kaW5nTWVzc2FnZXMgPSAwO1xyXG5cclxuICAgIGlmIChleGlzdGluZ0lGcmFtZSAmJiBzdGFydHNXaXRoICYmIGUuc291cmNlID09PSBleGlzdGluZ0lGcmFtZS5jb250ZW50V2luZG93KSB7XHJcbiAgICAgIGlmIChlLmRhdGEgPT09ICdlcnJvcicpIHtcclxuICAgICAgICB0aGlzLmxvZ2dlclNlcnZpY2UubG9nV2FybmluZyhjb25maWd1cmF0aW9uLCAnQ2hlY2tTZXNzaW9uIC0gZXJyb3IgZnJvbSBjaGVjayBzZXNzaW9uIG1lc3NhZ2VIYW5kbGVyJyk7XHJcbiAgICAgIH0gZWxzZSBpZiAoZS5kYXRhID09PSAnY2hhbmdlZCcpIHtcclxuICAgICAgICB0aGlzLmxvZ2dlclNlcnZpY2UubG9nRGVidWcoY29uZmlndXJhdGlvbiwgYENoZWNrU2Vzc2lvbiAtICR7ZX0gZnJvbSBjaGVjayBzZXNzaW9uIG1lc3NhZ2VIYW5kbGVyYCk7XHJcbiAgICAgICAgdGhpcy5jaGVja1Nlc3Npb25SZWNlaXZlZCA9IHRydWU7XHJcbiAgICAgICAgdGhpcy5ldmVudFNlcnZpY2UuZmlyZUV2ZW50KEV2ZW50VHlwZXMuQ2hlY2tTZXNzaW9uUmVjZWl2ZWQsIGUuZGF0YSk7XHJcbiAgICAgICAgdGhpcy5jaGVja1Nlc3Npb25DaGFuZ2VkSW50ZXJuYWwkLm5leHQodHJ1ZSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgdGhpcy5ldmVudFNlcnZpY2UuZmlyZUV2ZW50KEV2ZW50VHlwZXMuQ2hlY2tTZXNzaW9uUmVjZWl2ZWQsIGUuZGF0YSk7XHJcbiAgICAgICAgdGhpcy5sb2dnZXJTZXJ2aWNlLmxvZ0RlYnVnKGNvbmZpZ3VyYXRpb24sIGBDaGVja1Nlc3Npb24gLSAke2UuZGF0YX0gZnJvbSBjaGVjayBzZXNzaW9uIG1lc3NhZ2VIYW5kbGVyYCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgYmluZE1lc3NhZ2VFdmVudFRvSWZyYW1lKGNvbmZpZ3VyYXRpb246IE9wZW5JZENvbmZpZ3VyYXRpb24pOiB2b2lkIHtcclxuICAgIGNvbnN0IGlmcmFtZU1lc3NhZ2VFdmVudCA9IHRoaXMubWVzc2FnZUhhbmRsZXIuYmluZCh0aGlzLCBjb25maWd1cmF0aW9uKTtcclxuXHJcbiAgICB0aGlzLmRvY3VtZW50LmRlZmF1bHRWaWV3LmFkZEV2ZW50TGlzdGVuZXIoJ21lc3NhZ2UnLCBpZnJhbWVNZXNzYWdlRXZlbnQsIGZhbHNlKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgZ2V0T3JDcmVhdGVJZnJhbWUoY29uZmlndXJhdGlvbjogT3BlbklkQ29uZmlndXJhdGlvbik6IEhUTUxJRnJhbWVFbGVtZW50IHtcclxuICAgIGNvbnN0IGV4aXN0aW5nSWZyYW1lID0gdGhpcy5nZXRFeGlzdGluZ0lmcmFtZSgpO1xyXG5cclxuICAgIGlmICghZXhpc3RpbmdJZnJhbWUpIHtcclxuICAgICAgY29uc3QgZnJhbWUgPSB0aGlzLmlGcmFtZVNlcnZpY2UuYWRkSUZyYW1lVG9XaW5kb3dCb2R5KElGUkFNRV9GT1JfQ0hFQ0tfU0VTU0lPTl9JREVOVElGSUVSLCBjb25maWd1cmF0aW9uKTtcclxuXHJcbiAgICAgIHRoaXMuYmluZE1lc3NhZ2VFdmVudFRvSWZyYW1lKGNvbmZpZ3VyYXRpb24pO1xyXG5cclxuICAgICAgcmV0dXJuIGZyYW1lO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBleGlzdGluZ0lmcmFtZTtcclxuICB9XHJcbn1cclxuIl19