UNPKG

oidc-client-rx

Version:

ReactiveX enhanced OIDC and OAuth2 protocol support for browser-based JavaScript applications

158 lines (157 loc) 9.39 kB
import { Injectable, inject } from "@outposts/injection-js"; import { BehaviorSubject, Observable, of } from "rxjs"; import { take } from "rxjs/operators"; import { DOCUMENT } from "../dom/index.js"; import { LoggerService } from "../logging/logger.service.js"; import { EventTypes } from "../public-events/event-types.js"; import { PublicEventsService } from "../public-events/public-events.service.js"; import { DESTORY_REF } from "../resources/index.js"; import { StoragePersistenceService } from "../storage/storage-persistence.service.js"; import { IFrameService } from "./existing-iframe.service.js"; function _ts_decorate(decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : null === desc ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if ("object" == typeof Reflect && "function" == typeof Reflect.decorate) r = Reflect.decorate(decorators, target, key, desc); else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; } function _ts_metadata(k, v) { if ("object" == typeof Reflect && "function" == typeof Reflect.metadata) return Reflect.metadata(k, v); } const IFRAME_FOR_CHECK_SESSION_IDENTIFIER = 'myiFrameForCheckSession'; class CheckSessionService { get checkSessionChanged$() { return this.checkSessionChangedInternal$.asObservable(); } 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(void 0); const authWellKnownEndPoints = this.storagePersistenceService.read('authWellKnownEndPoints', configuration); if (!authWellKnownEndPoints) { this.loggerService.logWarning(configuration, 'CheckSession - init check session: authWellKnownEndpoints is undefined. Returning.'); return of(void 0); } const existingIframe = this.getOrCreateIframe(configuration); 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'); return of(void 0); } if (contentWindow) contentWindow.location.replace(checkSessionIframe); else this.loggerService.logWarning(configuration, 'CheckSession - init check session: IFrame contentWindow does not exist'); return new Observable((observer)=>{ existingIframe.onload = ()=>{ this.lastIFrameRefresh = Date.now(); observer.next(void 0); observer.complete(); }; }); } pollServerSession(clientId, configuration) { this.outstandingMessages = 0; const pollServerSessionRecur = ()=>{ this.init(configuration).pipe(take(1)).subscribe(()=>{ var _this_document_defaultView, _this_document; 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 && (null == authWellKnownEndPoints ? void 0 : authWellKnownEndPoints.checkSessionIframe) && contentWindow) { var _this; const iframeOrigin = (_this = new URL(authWellKnownEndPoints.checkSessionIframe), void 0 === _this) ? void 0 : _this.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}'`); if (this.outstandingMessages > 3) this.loggerService.logError(configuration, `CheckSession - OidcSecurityCheckSession not receiving check session response messages. Outstanding messages: '${this.outstandingMessages}'. Server unreachable?`); this.scheduledHeartBeatRunning = (null == (_this_document = this.document) ? void 0 : null == (_this_document_defaultView = _this_document.defaultView) ? void 0 : _this_document_defaultView.setTimeout(pollServerSessionRecur, this.heartBeatInterval)) ?? null; }); }; pollServerSessionRecur(); } clearScheduledHeartBeat() { if (null !== this.scheduledHeartBeatRunning) { clearTimeout(this.scheduledHeartBeatRunning); this.scheduledHeartBeatRunning = null; } } messageHandler(configuration, e) { var _authWellKnownEndPoints_checkSessionIframe; const existingIFrame = this.getExistingIframe(); const authWellKnownEndPoints = this.storagePersistenceService.read('authWellKnownEndPoints', configuration); const startsWith = !!(null == authWellKnownEndPoints ? void 0 : null == (_authWellKnownEndPoints_checkSessionIframe = authWellKnownEndPoints.checkSessionIframe) ? void 0 : _authWellKnownEndPoints_checkSessionIframe.startsWith(e.origin)); this.outstandingMessages = 0; if (existingIFrame && startsWith && e.source === existingIFrame.contentWindow) if ('error' === e.data) this.loggerService.logWarning(configuration, 'CheckSession - error from check session messageHandler'); else if ('changed' === e.data) { 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); } constructor(){ this.destoryRef$ = inject(DESTORY_REF); this.loggerService = inject(LoggerService); this.storagePersistenceService = inject(StoragePersistenceService); this.iFrameService = inject(IFrameService); this.eventService = inject(PublicEventsService); 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); this.destoryRef$.subscribe(()=>{ this.stop(); const windowAsDefaultView = this.document.defaultView; if (windowAsDefaultView && this.iframeMessageEventListener) windowAsDefaultView.removeEventListener('message', this.iframeMessageEventListener, false); }); } } CheckSessionService = _ts_decorate([ Injectable(), _ts_metadata("design:type", Function), _ts_metadata("design:paramtypes", []) ], CheckSessionService); export { CheckSessionService };