angular-auth-oidc-client
Version:
Angular Lib for OpenID Connect & OAuth2
185 lines • 33.2 kB
JavaScript
import { DOCUMENT } from '@angular/common';
import { Injectable, NgZone, inject } from '@angular/core';
import { BehaviorSubject, Observable, of } from 'rxjs';
import { take } from 'rxjs/operators';
import { LoggerService } from '../logging/logger.service';
import { EventTypes } from '../public-events/event-types';
import { PublicEventsService } from '../public-events/public-events.service';
import { StoragePersistenceService } from '../storage/storage-persistence.service';
import { IFrameService } from './existing-iframe.service';
import * as i0 from "@angular/core";
const IFRAME_FOR_CHECK_SESSION_IDENTIFIER = 'myiFrameForCheckSession';
// http://openid.net/specs/openid-connect-session-1_0-ID4.html
export class CheckSessionService {
constructor() {
this.loggerService = inject(LoggerService);
this.storagePersistenceService = inject(StoragePersistenceService);
this.iFrameService = inject(IFrameService);
this.eventService = inject(PublicEventsService);
this.zone = inject(NgZone);
this.document = inject(DOCUMENT);
this.checkSessionReceived = false;
this.scheduledHeartBeatRunning = null;
this.lastIFrameRefresh = 0;
this.outstandingMessages = 0;
this.heartBeatInterval = 3000;
this.iframeRefreshInterval = 60000;
this.checkSessionChangedInternal$ = new BehaviorSubject(false);
}
get checkSessionChanged$() {
return this.checkSessionChangedInternal$.asObservable();
}
ngOnDestroy() {
this.stop();
const windowAsDefaultView = this.document.defaultView;
if (windowAsDefaultView && this.iframeMessageEventListener) {
windowAsDefaultView.removeEventListener('message', this.iframeMessageEventListener, false);
}
}
isCheckSessionConfigured(configuration) {
const { startCheckSession } = configuration;
return Boolean(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 Boolean(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);
// https://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html#Events-EventTarget-addEventListener
// If multiple identical EventListeners are registered on the same EventTarget with the same parameters the duplicate instances are discarded. They do not cause the EventListener to be called twice and since they are discarded they do not need to be removed with the removeEventListener method.
// this is done even if iframe exists for HMR to work, since iframe exists on service init
this.bindMessageEventToIframe(configuration);
const checkSessionIframe = authWellKnownEndPoints.checkSessionIframe;
const contentWindow = existingIframe.contentWindow;
if (!checkSessionIframe) {
this.loggerService.logWarning(configuration, 'CheckSession - init check session: checkSessionIframe is not configured to run');
}
if (!contentWindow) {
this.loggerService.logWarning(configuration, 'CheckSession - init check session: IFrame contentWindow does not exist');
}
else {
contentWindow.location.replace(checkSessionIframe);
}
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);
const contentWindow = existingIframe.contentWindow;
if (sessionState &&
authWellKnownEndPoints?.checkSessionIframe &&
contentWindow) {
const iframeOrigin = new URL(authWellKnownEndPoints.checkSessionIframe)?.origin;
this.outstandingMessages++;
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 =
this.document?.defaultView?.setTimeout(() => this.zone.run(pollServerSessionRecur), this.heartBeatInterval) ?? null;
});
});
};
pollServerSessionRecur();
}
clearScheduledHeartBeat() {
if (this.scheduledHeartBeatRunning !== null) {
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) {
this.iframeMessageEventListener = this.messageHandler.bind(this, configuration);
const defaultView = this.document.defaultView;
if (defaultView) {
defaultView.addEventListener('message', this.iframeMessageEventListener, false);
}
}
getOrCreateIframe(configuration) {
return (this.getExistingIframe() ||
this.iFrameService.addIFrameToWindowBody(IFRAME_FOR_CHECK_SESSION_IDENTIFIER, configuration));
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: CheckSessionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: CheckSessionService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: CheckSessionService, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hlY2stc2Vzc2lvbi5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYW5ndWxhci1hdXRoLW9pZGMtY2xpZW50L3NyYy9saWIvaWZyYW1lL2NoZWNrLXNlc3Npb24uc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDM0MsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQWEsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3RFLE9BQU8sRUFBRSxlQUFlLEVBQUUsVUFBVSxFQUFFLEVBQUUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN2RCxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFdEMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQzFELE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUMxRCxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQztBQUM3RSxPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQztBQUNuRixPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sMkJBQTJCLENBQUM7O0FBRTFELE1BQU0sbUNBQW1DLEdBQUcseUJBQXlCLENBQUM7QUFFdEUsOERBQThEO0FBRzlELE1BQU0sT0FBTyxtQkFBbUI7SUFEaEM7UUFFbUIsa0JBQWEsR0FBRyxNQUFNLENBQUMsYUFBYSxDQUFDLENBQUM7UUFFdEMsOEJBQXlCLEdBQUcsTUFBTSxDQUNqRCx5QkFBeUIsQ0FDMUIsQ0FBQztRQUVlLGtCQUFhLEdBQUcsTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBRXRDLGlCQUFZLEdBQUcsTUFBTSxDQUFDLG1CQUFtQixDQUFDLENBQUM7UUFFM0MsU0FBSSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENB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Q0FBQztZQUNoQixXQUFXLENBQUMsZ0JBQWdCLENBQzFCLFNBQVMsRUFDVCxJQUFJLENBQUMsMEJBQTBCLEVBQy9CLEtBQUssQ0FDTixDQUFDO1FBQ0osQ0FBQztJQUNILENBQUM7SUFFTyxpQkFBaUIsQ0FDdkIsYUFBa0M7UUFFbEMsT0FBTyxDQUNMLElBQUksQ0FBQyxpQkFBaUIsRUFBRTtZQUN4QixJQUFJLENBQUMsYUFBYSxDQUFDLHFCQUFxQixDQUN0QyxtQ0FBbUMsRUFDbkMsYUFBYSxDQUNkLENBQ0YsQ0FBQztJQUNKLENBQUM7OEdBM1NVLG1CQUFtQjtrSEFBbkIsbUJBQW1CLGNBRE4sTUFBTTs7MkZBQ25CLG1CQUFtQjtrQkFEL0IsVUFBVTttQkFBQyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBET0NVTUVOVCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XHJcbmltcG9ydCB7IEluamVjdGFibGUsIE5nWm9uZSwgT25EZXN0cm95LCBpbmplY3QgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBPYnNlcnZhYmxlLCBvZiB9IGZyb20gJ3J4anMnO1xyXG5pbXBvcnQgeyB0YWtlIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xyXG5pbXBvcnQgeyBPcGVuSWRDb25maWd1cmF0aW9uIH0gZnJvbSAnLi4vY29uZmlnL29wZW5pZC1jb25maWd1cmF0aW9uJztcclxuaW1wb3J0IHsgTG9nZ2VyU2VydmljZSB9IGZyb20gJy4uL2xvZ2dpbmcvbG9nZ2VyLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBFdmVudFR5cGVzIH0gZnJvbSAnLi4vcHVibGljLWV2ZW50cy9ldmVudC10eXBlcyc7XHJcbmltcG9ydCB7IFB1YmxpY0V2ZW50c1NlcnZpY2UgfSBmcm9tICcuLi9wdWJsaWMtZXZlbnRzL3B1YmxpYy1ldmVudHMuc2VydmljZSc7XHJcbmltcG9ydCB7IFN0b3JhZ2VQZXJzaXN0ZW5jZVNlcnZpY2UgfSBmcm9tICcuLi9zdG9yYWdlL3N0b3JhZ2UtcGVyc2lzdGVuY2Uuc2VydmljZSc7XHJcbmltcG9ydCB7IElGcmFtZVNlcnZpY2UgfSBmcm9tICcuL2V4aXN0aW5nLWlmcmFtZS5zZXJ2aWNlJztcclxuXHJcbmNvbnN0IElGUkFNRV9GT1JfQ0hFQ0tfU0VTU0lPTl9JREVOVElGSUVSID0gJ215aUZyYW1lRm9yQ2hlY2tTZXNzaW9uJztcclxuXHJcbi8vIGh0dHA6Ly9vcGVuaWQubmV0L3NwZWNzL29wZW5pZC1jb25uZWN0LXNlc3Npb24tMV8wLUlENC5odG1sXHJcblxyXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxyXG5leHBvcnQgY2xhc3MgQ2hlY2tTZXNzaW9uU2VydmljZSBpbXBsZW1lbnRzIE9uRGVzdHJveSB7XHJcbiAgcHJpdmF0ZSByZWFkb25seSBsb2dnZXJTZXJ2aWNlID0gaW5qZWN0KExvZ2dlclNlcnZpY2UpO1xyXG5cclxuICBwcml2YXRlIHJlYWRvbmx5IHN0b3JhZ2VQZXJzaXN0ZW5jZVNlcnZpY2UgPSBpbmplY3QoXHJcbiAgICBTdG9yYWdlUGVyc2lzdGVuY2VTZXJ2aWNlXHJcbiAgKTtcclxuXHJcbiAgcHJpdmF0ZSByZWFkb25seSBpRnJhbWVTZXJ2aWNlID0gaW5qZWN0KElGcmFtZVNlcnZpY2UpO1xyXG5cclxuICBwcml2YXRlIHJlYWRvbmx5IGV2ZW50U2VydmljZSA9IGluamVjdChQdWJsaWNFdmVudHNTZXJ2aWNlKTtcclxuXHJcbiAgcHJpdmF0ZSByZWFkb25seSB6b25lID0gaW5qZWN0KE5nWm9uZSk7XHJcblxyXG4gIHByaXZhdGUgcmVhZG9ubHkgZG9jdW1lbnQgPSBpbmplY3QoRE9DVU1FTlQpO1xyXG5cclxuICBwcml2YXRlIGNoZWNrU2Vzc2lvblJlY2VpdmVkID0gZmFsc2U7XHJcblxyXG4gIHByaXZhdGUgc2NoZWR1bGVkSGVhcnRCZWF0UnVubmluZzogbnVtYmVyIHwgbnVsbCA9IG51bGw7XHJcblxyXG4gIHByaXZhdGUgbGFzdElGcmFtZVJlZnJlc2ggPSAwO1xyXG5cclxuICBwcml2YXRlIG91dHN0YW5kaW5nTWVzc2FnZXMgPSAwO1xyXG5cclxuICBwcml2YXRlIHJlYWRvbmx5IGhlYXJ0QmVhdEludGVydmFsID0gMzAwMDtcclxuXHJcbiAgcHJpdmF0ZSByZWFkb25seSBpZnJhbWVSZWZyZXNoSW50ZXJ2YWwgPSA2MDAwMDtcclxuXHJcbiAgcHJpdmF0ZSByZWFkb25seSBjaGVja1Nlc3Npb25DaGFuZ2VkSW50ZXJuYWwkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxib29sZWFuPihcclxuICAgIGZhbHNlXHJcbiAgKTtcclxuXHJcbiAgcHJpdmF0ZSBpZnJhbWVNZXNzYWdlRXZlbnRMaXN0ZW5lcj86IChcclxuICAgIHRoaXM6IFdpbmRvdyxcclxuICAgIGV2OiBNZXNzYWdlRXZlbnQ8YW55PlxyXG4gICkgPT4gYW55O1xyXG5cclxuICBnZXQgY2hlY2tTZXNzaW9uQ2hhbmdlZCQoKTogT2JzZXJ2YWJsZTxib29sZWFuPiB7XHJcbiAgICByZXR1cm4gdGhpcy5jaGVja1Nlc3Npb25DaGFuZ2VkSW50ZXJuYWwkLmFzT2JzZXJ2YWJsZSgpO1xyXG4gIH1cclxuXHJcbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XHJcbiAgICB0aGlzLnN0b3AoKTtcclxuICAgIGNvbnN0IHdpbmRvd0FzRGVmYXVsdFZpZXcgPSB0aGlzLmRvY3VtZW50LmRlZmF1bHRWaWV3O1xyXG5cclxuICAgIGlmICh3aW5kb3dBc0RlZmF1bHRWaWV3ICYmIHRoaXMuaWZyYW1lTWVzc2FnZUV2ZW50TGlzdGVuZXIpIHtcclxuICAgICAgd2luZG93QXNEZWZhdWx0Vmlldy5yZW1vdmVFdmVudExpc3RlbmVyKFxyXG4gICAgICAgICdtZXNzYWdlJyxcclxuICAgICAgICB0aGlzLmlmcmFtZU1lc3NhZ2VFdmVudExpc3RlbmVyLFxyXG4gICAgICAgIGZhbHNlXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBpc0NoZWNrU2Vzc2lvbkNvbmZpZ3VyZWQoY29uZmlndXJhdGlvbjogT3BlbklkQ29uZmlndXJhdGlvbik6IGJvb2xlYW4ge1xyXG4gICAgY29uc3QgeyBzdGFydENoZWNrU2Vzc2lvbiB9ID0gY29uZmlndXJhdGlvbjtcclxuXHJcbiAgICByZXR1cm4gQm9vbGVhbihzdGFydENoZWNrU2Vzc2lvbik7XHJcbiAgfVxyXG5cclxuICBzdGFydChjb25maWd1cmF0aW9uOiBPcGVuSWRDb25maWd1cmF0aW9uKTogdm9pZCB7XHJcbiAgICBpZiAoISF0aGlzLnNjaGVkdWxlZEhlYXJ0QmVhdFJ1bm5pbmcpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHsgY2xpZW50SWQgfSA9IGNvbmZpZ3VyYXRpb247XHJcblxyXG4gICAgdGhpcy5wb2xsU2VydmVyU2Vzc2lvbihjbGllbnRJZCwgY29uZmlndXJhdGlvbik7XHJcbiAgfVxyXG5cclxuICBzdG9wKCk6IHZvaWQge1xyXG4gICAgaWYgKCF0aGlzLnNjaGVkdWxlZEhlYXJ0QmVhdFJ1bm5pbmcpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuY2xlYXJTY2hlZHVsZWRIZWFydEJlYXQoKTtcclxuICAgIHRoaXMuY2hlY2tTZXNzaW9uUmVjZWl2ZWQgPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIHNlcnZlclN0YXRlQ2hhbmdlZChjb25maWd1cmF0aW9uOiBPcGVuSWRDb25maWd1cmF0aW9uKTogYm9vbGVhbiB7XHJcbiAgICBjb25zdCB7IHN0YXJ0Q2hlY2tTZXNzaW9uIH0gPSBjb25maWd1cmF0aW9uO1xyXG5cclxuICAgIHJldHVybiBCb29sZWFuKHN0YXJ0Q2hlY2tTZXNzaW9uKSAmJiB0aGlzLmNoZWNrU2Vzc2lvblJlY2VpdmVkO1xyXG4gIH1cclxuXHJcbiAgZ2V0RXhpc3RpbmdJZnJhbWUoKTogSFRNTElGcmFtZUVsZW1lbnQgfCBudWxsIHtcclxuICAgIHJldHVybiB0aGlzLmlGcmFtZVNlcnZpY2UuZ2V0RXhpc3RpbmdJRnJhbWUoXHJcbiAgICAgIElGUkFNRV9GT1JfQ0hFQ0tfU0VTU0lPTl9JREVOVElGSUVSXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBpbml0KGNvbmZpZ3VyYXRpb246IE9wZW5JZENvbmZpZ3VyYXRpb24pOiBPYnNlcnZhYmxlPGFueT4ge1xyXG4gICAgaWYgKHRoaXMubGFzdElGcmFtZVJlZnJlc2ggKyB0aGlzLmlmcmFtZVJlZnJlc2hJbnRlcnZhbCA+IERhdGUubm93KCkpIHtcclxuICAgICAgcmV0dXJuIG9mKHVuZGVmaW5lZCk7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgYXV0aFdlbGxLbm93bkVuZFBvaW50cyA9IHRoaXMuc3RvcmFnZVBlcnNpc3RlbmNlU2VydmljZS5yZWFkKFxyXG4gICAgICAnYXV0aFdlbGxLbm93bkVuZFBvaW50cycsXHJcbiAgICAgIGNvbmZpZ3VyYXRpb25cclxuICAgICk7XHJcblxyXG4gICAgaWYgKCFhdXRoV2VsbEtub3duRW5kUG9pbnRzKSB7XHJcbiAgICAgIHRoaXMubG9nZ2VyU2VydmljZS5sb2dXYXJuaW5nKFxyXG4gICAgICAgIGNvbmZpZ3VyYXRpb24sXHJcbiAgICAgICAgJ0NoZWNrU2Vzc2lvbiAtIGluaXQgY2hlY2sgc2Vzc2lvbjogYXV0aFdlbGxLbm93bkVuZHBvaW50cyBpcyB1bmRlZmluZWQuIFJldHVybmluZy4nXHJcbiAgICAgICk7XHJcblxyXG4gICAgICByZXR1cm4gb2YoKTtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBleGlzdGluZ0lmcmFtZSA9IHRoaXMuZ2V0T3JDcmVhdGVJZnJhbWUoY29uZmlndXJhdGlvbik7XHJcblxyXG4gICAgLy8gaHR0cHM6Ly93d3cudzMub3JnL1RSLzIwMDAvUkVDLURPTS1MZXZlbC0yLUV2ZW50cy0yMDAwMTExMy9ldmVudHMuaHRtbCNFdmVudHMtRXZlbnRUYXJnZXQtYWRkRXZlbnRMaXN0ZW5lclxyXG4gICAgLy8gSWYgbXVsdGlwbGUgaWRlbnRpY2FsIEV2ZW50TGlzdGVuZXJzIGFyZSByZWdpc3RlcmVkIG9uIHRoZSBzYW1lIEV2ZW50VGFyZ2V0IHdpdGggdGhlIHNhbWUgcGFyYW1ldGVycyB0aGUgZHVwbGljYXRlIGluc3RhbmNlcyBhcmUgZGlzY2FyZGVkLiBUaGV5IGRvIG5vdCBjYXVzZSB0aGUgRXZlbnRMaXN0ZW5lciB0byBiZSBjYWxsZWQgdHdpY2UgYW5kIHNpbmNlIHRoZXkgYXJlIGRpc2NhcmRlZCB0aGV5IGRvIG5vdCBuZWVkIHRvIGJlIHJlbW92ZWQgd2l0aCB0aGUgcmVtb3ZlRXZlbnRMaXN0ZW5lciBtZXRob2QuXHJcbiAgICAvLyB0aGlzIGlzIGRvbmUgZXZlbiBpZiBpZnJhbWUgZXhpc3RzIGZvciBITVIgdG8gd29yaywgc2luY2UgaWZyYW1lIGV4aXN0cyBvbiBzZXJ2aWNlIGluaXRcclxuICAgIHRoaXMuYmluZE1lc3NhZ2VFdmVudFRvSWZyYW1lKGNvbmZpZ3VyYXRpb24pO1xyXG4gICAgY29uc3QgY2hlY2tTZXNzaW9uSWZyYW1lID0gYXV0aFdlbGxLbm93bkVuZFBvaW50cy5jaGVja1Nlc3Npb25JZnJhbWU7XHJcbiAgICBjb25zdCBjb250ZW50V2luZG93ID0gZXhpc3RpbmdJZnJhbWUuY29udGVudFdpbmRvdztcclxuXHJcbiAgICBpZiAoIWNoZWNrU2Vzc2lvbklmcmFtZSkge1xyXG4gICAgICB0aGlzLmxvZ2dlclNlcnZpY2UubG9nV2FybmluZyhcclxuICAgICAgICBjb25maWd1cmF0aW9uLFxyXG4gICAgICAgICdDaGVja1Nlc3Npb24gLSBpbml0IGNoZWNrIHNlc3Npb246IGNoZWNrU2Vzc2lvbklmcmFtZSBpcyBub3QgY29uZmlndXJlZCB0byBydW4nXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFjb250ZW50V2luZG93KSB7XHJcbiAgICAgIHRoaXMubG9nZ2VyU2VydmljZS5sb2dXYXJuaW5nKFxyXG4gICAgICAgIGNvbmZpZ3VyYXRpb24sXHJcbiAgICAgICAgJ0NoZWNrU2Vzc2lvbiAtIGluaXQgY2hlY2sgc2Vzc2lvbjogSUZyYW1lIGNvbnRlbnRXaW5kb3cgZG9lcyBub3QgZXhpc3QnXHJcbiAgICAgICk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBjb250ZW50V2luZG93LmxvY2F0aW9uLnJlcGxhY2UoY2hlY2tTZXNzaW9uSWZyYW1lKTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gbmV3IE9ic2VydmFibGUoKG9ic2VydmVyKSA9PiB7XHJcbiAgICAgIGV4aXN0aW5nSWZyYW1lLm9ubG9hZCA9ICgpOiB2b2lkID0+IHtcclxuICAgICAgICB0aGlzLmxhc3RJRnJhbWVSZWZyZXNoID0gRGF0ZS5ub3coKTtcclxuICAgICAgICBvYnNlcnZlci5uZXh0KCk7XHJcbiAgICAgICAgb2JzZXJ2ZXIuY29tcGxldGUoKTtcclxuICAgICAgfTtcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBwb2xsU2VydmVyU2Vzc2lvbihcclxuICAgIGNsaWVudElkOiBzdHJpbmcgfCB1bmRlZmluZWQsXHJcbiAgICBjb25maWd1cmF0aW9uOiBPcGVuSWRDb25maWd1cmF0aW9uXHJcbiAgKTogdm9pZCB7XHJcbiAgICB0aGlzLm91dHN0YW5kaW5nTWVzc2FnZXMgPSAwO1xyXG5cclxuICAgIGNvbnN0IHBvbGxTZXJ2ZXJTZXNzaW9uUmVjdXIgPSAoKTogdm9pZCA9PiB7XHJcbiAgICAgIHRoaXMuaW5pdChjb25maWd1cmF0aW9uKVxyXG4gICAgICAgIC5waXBlKHRha2UoMSkpXHJcbiAgICAgICAgLnN1YnNjcmliZSgoKSA9PiB7XHJcbiAgICAgICAgICBjb25zdCBleGlzdGluZ0lmcmFtZSA9IHRoaXMuZ2V0RXhpc3RpbmdJZnJhbWUoKTtcclxuXHJcbiAgICAgICAgICBpZiAoZXhpc3RpbmdJZnJhbWUgJiYgY2xpZW50SWQpIHtcclxuICAgICAgICAgICAgdGhpcy5sb2dnZXJTZXJ2aWNlLmxvZ0RlYnVnKFxyXG4gICAgICAgICAgICAgIGNvbmZpZ3VyYXRpb24sXHJcbiAgICAgICAgICAgICAgYENoZWNrU2Vzc2lvbiAtIGNsaWVudElkIDogJyR7Y2xpZW50SWR9JyAtIGV4aXN0aW5nSWZyYW1lOiAnJHtleGlzdGluZ0lmcmFtZX0nYFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgICBjb25zdCBzZXNzaW9uU3RhdGUgPSB0aGlzLnN0b3JhZ2VQZXJzaXN0ZW5jZVNlcnZpY2UucmVhZChcclxuICAgICAgICAgICAgICAnc2Vzc2lvbl9zdGF0ZScsXHJcbiAgICAgICAgICAgICAgY29uZmlndXJhdGlvblxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgICBjb25zdCBhdXRoV2VsbEtub3duRW5kUG9pbnRzID0gdGhpcy5zdG9yYWdlUGVyc2lzdGVuY2VTZXJ2aWNlLnJlYWQoXHJcbiAgICAgICAgICAgICAgJ2F1dGhXZWxsS25vd25FbmRQb2ludHMnLFxyXG4gICAgICAgICAgICAgIGNvbmZpZ3VyYXRpb25cclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgY29uc3QgY29udGVudFdpbmRvdyA9IGV4aXN0aW5nSWZyYW1lLmNvbnRlbnRXaW5kb3c7XHJcblxyXG4gICAgICAgICAgICBpZiAoXHJcbiAgICAgICAgICAgICAgc2Vzc2lvblN0YXRlICYmXHJcbiAgICAgICAgICAgICAgYXV0aFdlbGxLbm93bkVuZFBvaW50cz8uY2hlY2tTZXNzaW9uSWZyYW1lICYmXHJcbiAgICAgICAgICAgICAgY29udGVudFdpbmRvd1xyXG4gICAgICAgICAgICApIHtcclxuICAgICAgICAgICAgICBjb25zdCBpZnJhbWVPcmlnaW4gPSBuZXcgVVJMKFxyXG4gICAgICAgICAgICAgICAgYXV0aFdlbGxLbm93bkVuZFBvaW50cy5jaGVja1Nlc3Npb25JZnJhbWVcclxuICAgICAgICAgICAgICApPy5vcmlnaW47XHJcblxyXG4gICAgICAgICAgICAgIHRoaXMub3V0c3RhbmRpbmdNZXNzYWdlcysrO1xyXG4gICAgICAgICAgICAgIGNvbnRlbnRXaW5kb3cucG9zdE1lc3NhZ2UoXHJcbiAgICAgICAgICAgICAgICBjbGllbnRJZCArICcgJyArIHNlc3Npb25TdGF0ZSxcclxuICAgICAgICAgICAgICAgIGlmcmFtZU9yaWdpblxyXG4gICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgdGhpcy5sb2dnZXJTZXJ2aWNlLmxvZ0RlYnVnKFxyXG4gICAgICAgICAgICAgICAgY29uZmlndXJhdGlvbixcclxuICAgICAgICAgICAgICAgIGBDaGVja1Nlc3Npb24gLSBzZXNzaW9uX3N0YXRlIGlzICcke3Nlc3Npb25TdGF0ZX0nIC0gQXV0aFdlbGxLbm93bkVuZFBvaW50cyBpcyAnJHtKU09OLnN0cmluZ2lmeShcclxuICAgICAgICAgICAgICAgICAgYXV0aFdlbGxLbm93bkVuZFBvaW50cyxcclxuICAgICAgICAgICAgICAgICAgbnVsbCxcclxuICAgICAgICAgICAgICAgICAgMlxyXG4gICAgICAgICAgICAgICAgKX0nYFxyXG4gICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgdGhpcy5jaGVja1Nlc3Npb25DaGFuZ2VkSW50ZXJuYWwkLm5leHQodHJ1ZSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHRoaXMubG9nZ2VyU2VydmljZS5sb2dXYXJuaW5nKFxyXG4gICAgICAgICAgICAgIGNvbmZpZ3VyYXRpb24sXHJcbiAgICAgICAgICAgICAgYENoZWNrU2Vzc2lvbiAtIE9pZGNTZWN1cml0eUNoZWNrU2Vzc2lvbiBwb2xsU2VydmVyU2Vzc2lvbiBjaGVja1Nlc3Npb24gSUZyYW1lIGRvZXMgbm90IGV4aXN0OlxyXG4gICAgICAgICAgICAgICBjbGllbnRJZCA6ICcke2NsaWVudElkfScgLSBleGlzdGluZ0lmcmFtZTogJyR7ZXhpc3RpbmdJZnJhbWV9J2BcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAvLyBhZnRlciBzZW5kaW5nIHRocmVlIG1lc3NhZ2VzIHdpdGggbm8gcmVzcG9uc2UsIGZhaWwuXHJcbiAgICAgICAgICBpZiAodGhpcy5vdXRzdGFuZGluZ01lc3NhZ2VzID4gMykge1xyXG4gICAgICAgICAgICB0aGlzLmxvZ2dlclNlcnZpY2UubG9nRXJyb3IoXHJcbiAgICAgICAgICAgICAgY29uZmlndXJhdGlvbixcclxuICAgICAgICAgICAgICBgQ2hlY2tTZXNzaW9uIC0gT2lkY1NlY3VyaXR5Q2hlY2tTZXNzaW9uIG5vdCByZWNlaXZpbmcgY2hlY2sgc2Vzc2lvbiByZXNwb25zZSBtZXNzYWdlcy5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIE91dHN0YW5kaW5nIG1lc3NhZ2VzOiAnJHt0aGlzLm91dHN0YW5kaW5nTWVzc2FnZXN9Jy4gU2VydmVyIHVucmVhY2hhYmxlP2BcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICB0aGlzLnpvbmUucnVuT3V0c2lkZUFuZ3VsYXIoKCkgPT4ge1xyXG4gICAgICAgICAgICB0aGlzLnNjaGVkdWxlZEhlYXJ0QmVhdFJ1bm5pbmcgPVxyXG4gICAgICAgICAgICAgIHRoaXMuZG9jdW1lbnQ/LmRlZmF1bHRWaWV3Py5zZXRUaW1lb3V0KFxyXG4gICAgICAgICAgICAgICAgKCkgPT4gdGhpcy56b25lLnJ1bihwb2xsU2VydmVyU2Vzc2lvblJlY3VyKSxcclxuICAgICAgICAgICAgICAgIHRoaXMuaGVhcnRCZWF0SW50ZXJ2YWxcclxuICAgICAgICAgICAgICApID8/IG51bGw7XHJcbiAgICAgICAgICB9KTtcclxuICAgICAgICB9KTtcclxuICAgIH07XHJcblxyXG4gICAgcG9sbFNlcnZlclNlc3Npb25SZWN1cigpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBjbGVhclNjaGVkdWxlZEhlYXJ0QmVhdCgpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLnNjaGVkdWxlZEhlYXJ0QmVhdFJ1bm5pbmcgIT09IG51bGwpIHtcclxuICAgICAgY2xlYXJUaW1lb3V0KHRoaXMuc2NoZWR1bGVkSGVhcnRCZWF0UnVubmluZyk7XHJcbiAgICAgIHRoaXMuc2NoZWR1bGVkSGVhcnRCZWF0UnVubmluZyA9IG51bGw7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIG1lc3NhZ2VIYW5kbGVyKGNvbmZpZ3VyYXRpb246IE9wZW5JZENvbmZpZ3VyYXRpb24sIGU6IGFueSk6IHZvaWQge1xyXG4gICAgY29uc3QgZXhpc3RpbmdJRnJhbWUgPSB0aGlzLmdldEV4aXN0aW5nSWZyYW1lKCk7XHJcbiAgICBjb25zdCBhdXRoV2VsbEtub3duRW5kUG9pbnRzID0gdGhpcy5zdG9yYWdlUGVyc2lzdGVuY2VTZXJ2aWNlLnJlYWQoXHJcbiAgICAgICdhdXRoV2VsbEtub3duRW5kUG9pbnRzJyxcclxuICAgICAgY29uZmlndXJhdGlvblxyXG4gICAgKTtcclxuICAgIGNvbnN0IHN0YXJ0c1dpdGggPSAhIWF1dGhXZWxsS25vd25FbmRQb2ludHM/LmNoZWNrU2Vzc2lvbklmcmFtZT8uc3RhcnRzV2l0aChcclxuICAgICAgZS5vcmlnaW5cclxuICAgICk7XHJcblxyXG4gICAgdGhpcy5vdXRzdGFuZGluZ01lc3NhZ2VzID0gMDtcclxuXHJcbiAgICBpZiAoXHJcbiAgICAgIGV4aXN0aW5nSUZyYW1lICYmXHJcbiAgICAgIHN0YXJ0c1dpdGggJiZcclxuICAgICAgZS5zb3VyY2UgPT09IGV4aXN0aW5nSUZyYW1lLmNvbnRlbnRXaW5kb3dcclxuICAgICkge1xyXG4gICAgICBpZiAoZS5kYXRhID09PSAnZXJyb3InKSB7XHJcbiAgICAgICAgdGhpcy5sb2dnZXJTZXJ2aWNlLmxvZ1dhcm5pbmcoXHJcbiAgICAgICAgICBjb25maWd1cmF0aW9uLFxyXG4gICAgICAgICAgJ0NoZWNrU2Vzc2lvbiAtIGVycm9yIGZyb20gY2hlY2sgc2Vzc2lvbiBtZXNzYWdlSGFuZGxlcidcclxuICAgICAgICApO1xyXG4gICAgICB9IGVsc2UgaWYgKGUuZGF0YSA9PT0gJ2NoYW5nZWQnKSB7XHJcbiAgICAgICAgdGhpcy5sb2dnZXJTZXJ2aWNlLmxvZ0RlYnVnKFxyXG4gICAgICAgICAgY29uZmlndXJhdGlvbixcclxuICAgICAgICAgIGBDaGVja1Nlc3Npb24gLSAke2V9IGZyb20gY2hlY2sgc2Vzc2lvbiBtZXNzYWdlSGFuZGxlcmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHRoaXMuY2hlY2tTZXNzaW9uUmVjZWl2ZWQgPSB0cnVlO1xyXG4gICAgICAgIHRoaXMuZXZlbnRTZXJ2aWNlLmZpcmVFdmVudChFdmVudFR5cGVzLkNoZWNrU2Vzc2lvblJlY2VpdmVkLCBlLmRhdGEpO1xyXG4gICAgICAgIHRoaXMuY2hlY2tTZXNzaW9uQ2hhbmdlZEludGVybmFsJC5uZXh0KHRydWUpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRoaXMuZXZlbnRTZXJ2aWNlLmZpcmVFdmVudChFdmVudFR5cGVzLkNoZWNrU2Vzc2lvblJlY2VpdmVkLCBlLmRhdGEpO1xyXG4gICAgICAgIHRoaXMubG9nZ2VyU2VydmljZS5sb2dEZWJ1ZyhcclxuICAgICAgICAgIGNvbmZpZ3VyYXRpb24sXHJcbiAgICAgICAgICBgQ2hlY2tTZXNzaW9uIC0gJHtlLmRhdGF9IGZyb20gY2hlY2sgc2Vzc2lvbiBtZXNzYWdlSGFuZGxlcmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGJpbmRNZXNzYWdlRXZlbnRUb0lmcmFtZShjb25maWd1cmF0aW9uOiBPcGVuSWRDb25maWd1cmF0aW9uKTogdm9pZCB7XHJcbiAgICB0aGlzLmlmcmFtZU1lc3NhZ2VFdmVudExpc3RlbmVyID0gdGhpcy5tZXNzYWdlSGFuZGxlci5iaW5kKFxyXG4gICAgICB0aGlzLFxyXG4gICAgICBjb25maWd1cmF0aW9uXHJcbiAgICApO1xyXG5cclxuICAgIGNvbnN0IGRlZmF1bHRWaWV3ID0gdGhpcy5kb2N1bWVudC5kZWZhdWx0VmlldztcclxuXHJcbiAgICBpZiAoZGVmYXVsdFZpZXcpIHtcclxuICAgICAgZGVmYXVsdFZpZXcuYWRkRXZlbnRMaXN0ZW5lcihcclxuICAgICAgICAnbWVzc2FnZScsXHJcbiAgICAgICAgdGhpcy5pZnJhbWVNZXNzYWdlRXZlbnRMaXN0ZW5lcixcclxuICAgICAgICBmYWxzZVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBnZXRPckNyZWF0ZUlmcmFtZShcclxuICAgIGNvbmZpZ3VyYXRpb246IE9wZW5JZENvbmZpZ3VyYXRpb25cclxuICApOiBIVE1MSUZyYW1lRWxlbWVudCB7XHJcbiAgICByZXR1cm4gKFxyXG4gICAgICB0aGlzLmdldEV4aXN0aW5nSWZyYW1lKCkgfHxcclxuICAgICAgdGhpcy5pRnJhbWVTZXJ2aWNlLmFkZElGcmFtZVRvV2luZG93Qm9keShcclxuICAgICAgICBJRlJBTUVfRk9SX0NIRUNLX1NFU1NJT05fSURFTlRJRklFUixcclxuICAgICAgICBjb25maWd1cmF0aW9uXHJcbiAgICAgIClcclxuICAgICk7XHJcbiAgfVxyXG59XHJcbiJdfQ==