UNPKG

ng-smart-on-fhir

Version:

[![SRDC](https://www.srdc.com.tr/wp-content/uploads/2014/12/srdc-wp.png)](https://srdc.com.tr/en)

220 lines 32 kB
import { Inject, Injectable } from '@angular/core'; import * as FHIR from "fhirclient"; import { firstValueFrom, Subject } from "rxjs"; import * as i0 from "@angular/core"; /** * SMART Authentication Service * Handles authentication/authorization using the fhirclient library (or offline via SHC/SHL), and stores the state */ export class SmartAuthService { constructor(config = {}) { this.config = config; // selected login method this.method = 'offline'; // selected client this.selectedClient = undefined; // auth enabled (not public) this.enabled = true; this.SAVED_SESSION_KEY = 'SMART_APPS_SESSION'; this.client$ = new Subject(); this.clientPromise = firstValueFrom(this.client$); this.LAUNCHED_URL = 'SMART_APPS_LAUNCHED_URL'; } isLoggedIn() { return !!this.patient || (this.selectedClient?.scope?.includes('launch/patient') ? false : !!this.user); } /** * Login * @param config - selected client's config * @param patient - selected patient, if applicable */ login(config, patient) { this.method = 'login'; this.selectedClient = config; this.enabled = !config.isPublic; this.patient = patient; this.saveSession(); if (!config.isPublic) { FHIR.oauth2.authorize({ iss: config.iss, redirectUri: config.redirectUri, clientId: config.clientId, scope: config.scope, noRedirect: true }).then(redirectUrl => { const [url, params] = redirectUrl.split('?'); let queryParams = params.split('&'); if (config.aud) { queryParams = queryParams.filter(param => !param.startsWith('aud=')); queryParams.push('aud=' + config.aud); } if (config.promptLogin) { queryParams.push('prompt=login'); } window.location.href = [url, queryParams.join('&')].join('?'); }, console.error); } else if (patient) { this.client$.next(FHIR.client(config.iss)); } } // get public client without authentication publicClient(iss) { return FHIR.client(iss); } // launch with selected issuer launch(iss, launch, clientConfig) { const clientId = this.config.clientId || (this.config.clientIds && this.config.clientIds[iss]); this.method = 'launch'; this.selectedClient = clientConfig; this.enabled = true; this.saveSession({ [this.LAUNCHED_URL]: window.location.href }); FHIR.oauth2.authorize({ clientId, iss, launch, redirectUri: this.config.redirectUrl }); } // start auth flow async start() { const sessionContext = this.restoreSession(); if (sessionContext?.method === 'offline') { this.offline(sessionContext.patient, sessionContext.shc || []); } else if (sessionContext?.selectedClient?.isPublic) { this.client$.next(this.publicClient((sessionContext?.selectedClient).iss)); } else { await FHIR.oauth2.ready().then(async (client) => { this.checkPatientInToken(client); if (this.config.authStorage === 'localStorage') { const smartKey = sessionStorage.getItem('SMART_KEY'); if (smartKey) { localStorage.setItem('SMART_KEY', smartKey); localStorage.setItem(smartKey, sessionStorage.getItem(smartKey)); } } this.user = (await client.user.read().catch(() => undefined)); this.patient = await client.patient.read().catch(() => undefined); this.client$.next(client); }); } return sessionContext; } // offline mode with SHCs offline(patient, shc) { this.patient = patient; this.user = undefined; this.method = 'offline'; this.selectedClient = undefined; this.client$.next(undefined); this.saveSession({ shc }); } // store session in the session storage saveSession(params) { sessionStorage.setItem(this.SAVED_SESSION_KEY, JSON.stringify({ patient: this.patient, user: this.user, method: this.method, selectedClient: this.selectedClient, enabled: this.enabled, ...(params || {}) })); if (this.config.authStorage === 'localStorage') { localStorage.setItem(this.SAVED_SESSION_KEY, sessionStorage.getItem(this.SAVED_SESSION_KEY)); } } // restore session from the local storage restoreSession() { if (this.config.authStorage === 'localStorage' && !sessionStorage.getItem(this.SAVED_SESSION_KEY) && localStorage.getItem(this.SAVED_SESSION_KEY)) { sessionStorage.setItem(this.SAVED_SESSION_KEY, localStorage.getItem(this.SAVED_SESSION_KEY)); if (localStorage.getItem('SMART_KEY')) { const smartKey = localStorage.getItem('SMART_KEY'); sessionStorage.setItem('SMART_KEY', smartKey); sessionStorage.setItem(smartKey, localStorage.getItem(smartKey)); } } const saved = sessionStorage.getItem(this.SAVED_SESSION_KEY); if (saved) { const { patient, user, method, selectedClient, enabled, ...rest } = JSON.parse(saved); this.patient = patient; this.user = user; this.method = method; this.selectedClient = selectedClient; this.enabled = enabled; return { patient, user, method, selectedClient, enabled, ...rest }; } return null; } // if the patient is not received properly from the response, but exists in the token, add it to the response checkPatientInToken(client) { const sessionId = sessionStorage['SMART_KEY'] && JSON.parse(sessionStorage['SMART_KEY']); if (sessionId && sessionStorage[sessionId]) { const session = JSON.parse(sessionStorage[sessionId]); const token = session.tokenResponse?.access_token; const id_token = session.tokenResponse?.id_token; const parsed = JSON.parse(atob(token.split('.')[1])); let changed = false; if (!client.user?.id && id_token) { const parts = id_token.split('.'); const parsedIdToken = JSON.parse(atob(parts[1])); parsedIdToken.fhirUser = 'Practitioner/' + parsedIdToken.sub; session.tokenResponse.id_token = [parts[0], btoa(JSON.stringify(parsedIdToken)), parts[2]].join('.'); changed = true; } if (!client.getPatientId() && parsed.patient) { session.tokenResponse.patient = parsed.patient; changed = true; } if (changed) { sessionStorage[sessionId] = JSON.stringify(session); window.location.reload(); } } } getClient() { return this.clientPromise; } getClientConfig() { return this.selectedClient; } logout() { this.clearSession(); this.getClient().then(client => { const loginClient = this.config?.loginClients?.find(lc => lc.iss === client?.state.serverUrl); if (loginClient?.logoutUri) { window.location.href = loginClient.logoutUri; } else { window.location.href = window.location.href.split('#')[0].replace(/shc$/, 'login'); } }, err => window.location.reload()); } clearSession() { sessionStorage.clear(); if (this.config.authStorage === 'localStorage') { localStorage.clear(); } this.method = 'offline'; this.patient = this.user = undefined; this.selectedClient = undefined; this.enabled = true; } async getPatient() { if (this.patient) return this.patient; await this.getClient(); return this.patient; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SmartAuthService, deps: [{ token: 'sofConfig' }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SmartAuthService }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SmartAuthService, decorators: [{ type: Injectable }], ctorParameters: () => [{ type: undefined, decorators: [{ type: Inject, args: ['sofConfig'] }] }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnQtYXV0aC5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvc21hcnQtb24tZmhpci9zcmMvbGliL3NlcnZpY2VzL3NtYXJ0LWF1dGguc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUMsTUFBTSxFQUFFLFVBQVUsRUFBQyxNQUFNLGVBQWUsQ0FBQztBQUtqRCxPQUFPLEtBQUssSUFBSSxNQUFNLFlBQVksQ0FBQztBQUNuQyxPQUFPLEVBQUMsY0FBYyxFQUFFLE9BQU8sRUFBQyxNQUFNLE1BQU0sQ0FBQzs7QUFFN0M7OztHQUdHO0FBRUgsTUFBTSxPQUFPLGdCQUFnQjtJQWtCM0IsWUFBd0MsU0FBNEIsRUFBRTtRQUE5QixXQUFNLEdBQU4sTUFBTSxDQUF3QjtRQWhCdEUsd0JBQXdCO1FBQ2hCLFdBQU0sR0FBK0IsU0FBUyxDQUFDO1FBQ3ZELGtCQUFrQjtRQUNWLG1CQUFjLEdBQW1ELFNBQVMsQ0FBQztRQUNuRiw0QkFBNEI7UUFDcEIsWUFBTyxHQUFHLElBQUksQ0FBQztRQU1mLHNCQUFpQixHQUFXLG9CQUFvQixDQUFDO1FBQ2pELFlBQU8sR0FBRyxJQUFJLE9BQU8sRUFBb0IsQ0FBQTtRQUN6QyxrQkFBYSxHQUFHLGNBQWMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUE7UUFDNUMsaUJBQVksR0FBRyx5QkFBeUIsQ0FBQztJQUdqRCxDQUFDO0lBRUQsVUFBVTtRQUNSLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLElBQUksQ0FBcUIsSUFBSSxDQUFDLGNBQWUsRUFBRSxLQUFLLEVBQUUsUUFBUSxDQUFDLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUMvSCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILEtBQUssQ0FBQyxNQUF5QixF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QUFDLFNBQVMsRUFBRSxDQUFDO1FBQ3ZCLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQztJQUN0QixDQUFDOytHQXhOVSxnQkFBZ0Isa0JBa0JQLFdBQVc7bUhBbEJwQixnQkFBZ0I7OzRGQUFoQixnQkFBZ0I7a0JBRDVCLFVBQVU7OzBCQW1CSSxNQUFNOzJCQUFDLFdBQVciLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0luamVjdCwgSW5qZWN0YWJsZX0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7TG9naW5DbGllbnRDb25maWd9IGZyb20gXCIuLi9tb2RlbC9sb2dpbi1jbGllbnQuY29uZmlnXCI7XHJcbmltcG9ydCB7TGF1bmNoQ2xpZW50Q29uZmlnfSBmcm9tIFwiLi4vbW9kZWwvbGF1bmNoLWNsaWVudC5jb25maWdcIjtcclxuaW1wb3J0IHtTbWFydE9uRmhpckNvbmZpZ30gZnJvbSBcIi4uL21vZGVsL3NtYXJ0LW9uLWZoaXIuY29uZmlnXCI7XHJcbmltcG9ydCBDbGllbnQgZnJvbSBcImZoaXJjbGllbnQvbGliL0NsaWVudFwiO1xyXG5pbXBvcnQgKiBhcyBGSElSIGZyb20gXCJmaGlyY2xpZW50XCI7XHJcbmltcG9ydCB7Zmlyc3RWYWx1ZUZyb20sIFN1YmplY3R9IGZyb20gXCJyeGpzXCI7XHJcblxyXG4vKipcclxuICogU01BUlQgQXV0aGVudGljYXRpb24gU2VydmljZVxyXG4gKiBIYW5kbGVzIGF1dGhlbnRpY2F0aW9uL2F1dGhvcml6YXRpb24gdXNpbmcgdGhlIGZoaXJjbGllbnQgbGlicmFyeSAob3Igb2ZmbGluZSB2aWEgU0hDL1NITCksIGFuZCBzdG9yZXMgdGhlIHN0YXRlXHJcbiAqL1xyXG5ASW5qZWN0YWJsZSgpXHJcbmV4cG9ydCBjbGFzcyBTbWFydEF1dGhTZXJ2aWNlIHtcclxuXHJcbiAgLy8gc2VsZWN0ZWQgbG9naW4gbWV0aG9kXHJcbiAgcHJpdmF0ZSBtZXRob2Q6ICdvZmZsaW5lJ3wnbG9naW4nfCdsYXVuY2gnID0gJ29mZmxpbmUnO1xyXG4gIC8vIHNlbGVjdGVkIGNsaWVudFxyXG4gIHByaXZhdGUgc2VsZWN0ZWRDbGllbnQ6IExvZ2luQ2xpZW50Q29uZmlnfExhdW5jaENsaWVudENvbmZpZ3x1bmRlZmluZWQgPSB1bmRlZmluZWQ7XHJcbiAgLy8gYXV0aCBlbmFibGVkIChub3QgcHVibGljKVxyXG4gIHByaXZhdGUgZW5hYmxlZCA9IHRydWU7XHJcbiAgLy8gYXV0aGVudGljYXRlZCB1c2VyXHJcbiAgcHJpdmF0ZSB1c2VyOiBmaGlyNC5QcmFjdGl0aW9uZXJ8dW5kZWZpbmVkO1xyXG4gIC8vIHNlbGVjdGVkL2F1dGhlbnRpY2F0ZWQgcGF0aWVudFxyXG4gIHByaXZhdGUgcGF0aWVudDogZmhpcjQuUGF0aWVudHx1bmRlZmluZWQ7XHJcblxyXG4gIHByaXZhdGUgU0FWRURfU0VTU0lPTl9LRVk6IHN0cmluZyA9ICdTTUFSVF9BUFBTX1NFU1NJT04nO1xyXG4gIHByaXZhdGUgY2xpZW50JCA9IG5ldyBTdWJqZWN0PENsaWVudHx1bmRlZmluZWQ+KClcclxuICBwcml2YXRlIGNsaWVudFByb21pc2UgPSBmaXJzdFZhbHVlRnJvbSh0aGlzLmNsaWVudCQpXHJcbiAgcHJpdmF0ZSBMQVVOQ0hFRF9VUkwgPSAnU01BUlRfQVBQU19MQVVOQ0hFRF9VUkwnO1xyXG5cclxuICBjb25zdHJ1Y3RvcihASW5qZWN0KCdzb2ZDb25maWcnKSBwdWJsaWMgY29uZmlnOiBTbWFydE9uRmhpckNvbmZpZyA9IHt9KSB7XHJcbiAgfVxyXG5cclxuICBpc0xvZ2dlZEluKCkge1xyXG4gICAgcmV0dXJuICEhdGhpcy5wYXRpZW50IHx8ICgoPExvZ2luQ2xpZW50Q29uZmlnPnRoaXMuc2VsZWN0ZWRDbGllbnQpPy5zY29wZT8uaW5jbHVkZXMoJ2xhdW5jaC9wYXRpZW50JykgPyBmYWxzZSA6ICEhdGhpcy51c2VyKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIExvZ2luXHJcbiAgICogQHBhcmFtIGNvbmZpZyAtIHNlbGVjdGVkIGNsaWVudCdzIGNvbmZpZ1xyXG4gICAqIEBwYXJhbSBwYXRpZW50IC0gc2VsZWN0ZWQgcGF0aWVudCwgaWYgYXBwbGljYWJsZVxyXG4gICAqL1xyXG4gIGxvZ2luKGNvbmZpZzogTG9naW5DbGllbnRDb25maWcsIHBhdGllbnQ/OiBmaGlyNC5QYXRpZW50KSB7XHJcbiAgICB0aGlzLm1ldGhvZCA9ICdsb2dpbidcclxuICAgIHRoaXMuc2VsZWN0ZWRDbGllbnQgPSBjb25maWdcclxuICAgIHRoaXMuZW5hYmxlZCA9ICFjb25maWcuaXNQdWJsaWNcclxuICAgIHRoaXMucGF0aWVudCA9IHBhdGllbnQ7XHJcbiAgICB0aGlzLnNhdmVTZXNzaW9uKClcclxuICAgIGlmICghY29uZmlnLmlzUHVibGljKSB7XHJcbiAgICAgIEZISVIub2F1dGgyLmF1dGhvcml6ZSh7XHJcbiAgICAgICAgaXNzOiBjb25maWcuaXNzLFxyXG4gICAgICAgIHJlZGlyZWN0VXJpOiBjb25maWcucmVkaXJlY3RVcmksXHJcbiAgICAgICAgY2xpZW50SWQ6IGNvbmZpZy5jbGllbnRJZCxcclxuICAgICAgICBzY29wZTogY29uZmlnLnNjb3BlLFxyXG4gICAgICAgIG5vUmVkaXJlY3Q6IHRydWVcclxuICAgICAgfSkudGhlbihyZWRpcmVjdFVybCA9PiB7XHJcbiAgICAgICAgY29uc3QgW3VybCwgcGFyYW1zXSA9ICg8c3RyaW5nPnJlZGlyZWN0VXJsKS5zcGxpdCgnPycpXHJcbiAgICAgICAgbGV0IHF1ZXJ5UGFyYW1zID0gcGFyYW1zLnNwbGl0KCcmJylcclxuICAgICAgICBpZiAoY29uZmlnLmF1ZCkge1xyXG4gICAgICAgICAgcXVlcnlQYXJhbXMgPSBxdWVyeVBhcmFtcy5maWx0ZXIocGFyYW0gPT4gIXBhcmFtLnN0YXJ0c1dpdGgoJ2F1ZD0nKSlcclxuICAgICAgICAgIHF1ZXJ5UGFyYW1zLnB1c2goJ2F1ZD0nICsgY29uZmlnLmF1ZClcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKGNvbmZpZy5wcm9tcHRMb2dpbikge1xyXG4gICAgICAgICAgcXVlcnlQYXJhbXMucHVzaCgncHJvbXB0PWxvZ2luJylcclxuICAgICAgICB9XHJcbiAgICAgICAgd2luZG93LmxvY2F0aW9uLmhyZWYgPSBbdXJsLCBxdWVyeVBhcmFtcy5qb2luKCcmJyldLmpvaW4oJz8nKVxyXG4gICAgICB9LCBjb25zb2xlLmVycm9yKVxyXG4gICAgfSBlbHNlIGlmKHBhdGllbnQpIHtcclxuICAgICAgdGhpcy5jbGllbnQkLm5leHQoRkhJUi5jbGllbnQoY29uZmlnLmlzcykpXHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBnZXQgcHVibGljIGNsaWVudCB3aXRob3V0IGF1dGhlbnRpY2F0aW9uXHJcbiAgcHVibGljQ2xpZW50KGlzczogc3RyaW5nKSB7XHJcbiAgICByZXR1cm4gRkhJUi5jbGllbnQoaXNzKTtcclxuICB9XHJcblxyXG4gIC8vIGxhdW5jaCB3aXRoIHNlbGVjdGVkIGlzc3VlclxyXG4gIGxhdW5jaChpc3M6IHN0cmluZywgbGF1bmNoOiBzdHJpbmcsIGNsaWVudENvbmZpZz86IExhdW5jaENsaWVudENvbmZpZykge1xyXG4gICAgY29uc3QgY2xpZW50SWQgPSB0aGlzLmNvbmZpZy5jbGllbnRJZCB8fCAodGhpcy5jb25maWcuY2xpZW50SWRzICYmIHRoaXMuY29uZmlnLmNsaWVudElkc1tpc3NdKVxyXG4gICAgdGhpcy5tZXRob2QgPSAnbGF1bmNoJ1xyXG4gICAgdGhpcy5zZWxlY3RlZENsaWVudCA9IGNsaWVudENvbmZpZ1xyXG4gICAgdGhpcy5lbmFibGVkID0gdHJ1ZVxyXG4gICAgdGhpcy5zYXZlU2Vzc2lvbih7XHJcbiAgICAgIFt0aGlzLkxBVU5DSEVEX1VSTF06IHdpbmRvdy5sb2NhdGlvbi5ocmVmXHJcbiAgICB9KVxyXG4gICAgRkhJUi5vYXV0aDIuYXV0aG9yaXplKHtcclxuICAgICAgY2xpZW50SWQsIGlzcywgbGF1bmNoLFxyXG4gICAgICByZWRpcmVjdFVyaTogdGhpcy5jb25maWcucmVkaXJlY3RVcmxcclxuICAgIH0pXHJcbiAgfVxyXG5cclxuICAvLyBzdGFydCBhdXRoIGZsb3dcclxuICBhc3luYyBzdGFydCgpOiBQcm9taXNlPGFueT4ge1xyXG4gICAgY29uc3Qgc2Vzc2lvbkNvbnRleHQgPSB0aGlzLnJlc3RvcmVTZXNzaW9uKClcclxuICAgIGlmIChzZXNzaW9uQ29udGV4dD8ubWV0aG9kID09PSAnb2ZmbGluZScpIHtcclxuICAgICAgdGhpcy5vZmZsaW5lKHNlc3Npb25Db250ZXh0LnBhdGllbnQsIHNlc3Npb25Db250ZXh0LnNoYyB8fCBbXSlcclxuICAgIH0gZWxzZSBpZiAoKDxMb2dpbkNsaWVudENvbmZpZz5zZXNzaW9uQ29udGV4dD8uc2VsZWN0ZWRDbGllbnQpPy5pc1B1YmxpYykge1xyXG4gICAgICB0aGlzLmNsaWVudCQubmV4dCh0aGlzLnB1YmxpY0NsaWVudCgoPExvZ2luQ2xpZW50Q29uZmlnPnNlc3Npb25Db250ZXh0Py5zZWxlY3RlZENsaWVudCkuaXNzKSlcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGF3YWl0IEZISVIub2F1dGgyLnJlYWR5KCkudGhlbihhc3luYyBjbGllbnQgPT4ge1xyXG4gICAgICAgIHRoaXMuY2hlY2tQYXRpZW50SW5Ub2tlbihjbGllbnQpXHJcbiAgICAgICAgaWYgKHRoaXMuY29uZmlnLmF1dGhTdG9yYWdlID09PSAnbG9jYWxTdG9yYWdlJykge1xyXG4gICAgICAgICAgY29uc3Qgc21hcnRLZXkgPSBzZXNzaW9uU3RvcmFnZS5nZXRJdGVtKCdTTUFSVF9LRVknKVxyXG4gICAgICAgICAgaWYgKHNtYXJ0S2V5KSB7XHJcbiAgICAgICAgICAgIGxvY2FsU3RvcmFnZS5zZXRJdGVtKCdTTUFSVF9LRVknLCBzbWFydEtleSlcclxuICAgICAgICAgICAgbG9jYWxTdG9yYWdlLnNldEl0ZW0oc21hcnRLZXksIDxzdHJpbmc+c2Vzc2lvblN0b3JhZ2UuZ2V0SXRlbShzbWFydEtleSkpXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMudXNlciA9IDxmaGlyNC5QcmFjdGl0aW9uZXJ8dW5kZWZpbmVkPihhd2FpdCBjbGllbnQudXNlci5yZWFkKCkuY2F0Y2goKCkgPT4gdW5kZWZpbmVkKSlcclxuICAgICAgICB0aGlzLnBhdGllbnQgPSBhd2FpdCBjbGllbnQucGF0aWVudC5yZWFkKCkuY2F0Y2goKCkgPT4gdW5kZWZpbmVkKVxyXG4gICAgICAgIHRoaXMuY2xpZW50JC5uZXh0KGNsaWVudCk7XHJcbiAgICAgIH0pXHJcbiAgICB9XHJcbiAgICByZXR1cm4gc2Vzc2lvbkNvbnRleHQ7XHJcbiAgfVxyXG5cclxuICAvLyBvZmZsaW5lIG1vZGUgd2l0aCBTSENzXHJcbiAgb2ZmbGluZShwYXRpZW50OiBmaGlyNC5QYXRpZW50LCBzaGM6IHN0cmluZ1tdKSB7XHJcbiAgICB0aGlzLnBhdGllbnQgPSBwYXRpZW50O1xyXG4gICAgdGhpcy51c2VyID0gdW5kZWZpbmVkO1xyXG4gICAgdGhpcy5tZXRob2QgPSAnb2ZmbGluZSc7XHJcbiAgICB0aGlzLnNlbGVjdGVkQ2xpZW50ID0gdW5kZWZpbmVkO1xyXG4gICAgdGhpcy5jbGllbnQkLm5leHQodW5kZWZpbmVkKVxyXG4gICAgdGhpcy5zYXZlU2Vzc2lvbih7c2hjfSk7XHJcbiAgfVxyXG5cclxuICAvLyBzdG9yZSBzZXNzaW9uIGluIHRoZSBzZXNzaW9uIHN0b3JhZ2VcclxuICBzYXZlU2Vzc2lvbihwYXJhbXM/OiBPYmplY3QpIHtcclxuICAgIHNlc3Npb25TdG9yYWdlLnNldEl0ZW0odGhpcy5TQVZFRF9TRVNTSU9OX0tFWSwgSlNPTi5zdHJpbmdpZnkoe1xyXG4gICAgICBwYXRpZW50OiB0aGlzLnBhdGllbnQsXHJcbiAgICAgIHVzZXI6IHRoaXMudXNlcixcclxuICAgICAgbWV0aG9kOiB0aGlzLm1ldGhvZCxcclxuICAgICAgc2VsZWN0ZWRDbGllbnQ6IHRoaXMuc2VsZWN0ZWRDbGllbnQsXHJcbiAgICAgIGVuYWJsZWQ6IHRoaXMuZW5hYmxlZCxcclxuICAgICAgLi4uKHBhcmFtcyB8fCB7fSlcclxuICAgIH0pKVxyXG4gICAgaWYgKHRoaXMuY29uZmlnLmF1dGhTdG9yYWdlID09PSAnbG9jYWxTdG9yYWdlJykge1xyXG4gICAgICBsb2NhbFN0b3JhZ2Uuc2V0SXRlbSh0aGlzLlNBVkVEX1NFU1NJT05fS0VZLCA8c3RyaW5nPnNlc3Npb25TdG9yYWdlLmdldEl0ZW0odGhpcy5TQVZFRF9TRVNTSU9OX0tFWSkpXHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyByZXN0b3JlIHNlc3Npb24gZnJvbSB0aGUgbG9jYWwgc3RvcmFnZVxyXG4gIHJlc3RvcmVTZXNzaW9uKCkge1xyXG4gICAgaWYgKHRoaXMuY29uZmlnLmF1dGhTdG9yYWdlID09PSAnbG9jYWxTdG9yYWdlJyAmJiAhc2Vzc2lvblN0b3JhZ2UuZ2V0SXRlbSh0aGlzLlNBVkVEX1NFU1NJT05fS0VZKVxyXG4gICAgICAmJiBsb2NhbFN0b3JhZ2UuZ2V0SXRlbSh0aGlzLlNBVkVEX1NFU1NJT05fS0VZKSkge1xyXG4gICAgICBzZXNzaW9uU3RvcmFnZS5zZXRJdGVtKHRoaXMuU0FWRURfU0VTU0lPTl9LRVksIDxzdHJpbmc+bG9jYWxTdG9yYWdlLmdldEl0ZW0odGhpcy5TQVZFRF9TRVNTSU9OX0tFWSkpXHJcbiAgICAgIGlmIChsb2NhbFN0b3JhZ2UuZ2V0SXRlbSgnU01BUlRfS0VZJykpIHtcclxuICAgICAgICBjb25zdCBzbWFydEtleSA9IDxzdHJpbmc+bG9jYWxTdG9yYWdlLmdldEl0ZW0oJ1NNQVJUX0tFWScpXHJcbiAgICAgICAgc2Vzc2lvblN0b3JhZ2Uuc2V0SXRlbSgnU01BUlRfS0VZJywgc21hcnRLZXkpXHJcbiAgICAgICAgc2Vzc2lvblN0b3JhZ2Uuc2V0SXRlbShzbWFydEtleSwgPHN0cmluZz5sb2NhbFN0b3JhZ2UuZ2V0SXRlbShzbWFydEtleSkpXHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIGNvbnN0IHNhdmVkID0gc2Vzc2lvblN0b3JhZ2UuZ2V0SXRlbSh0aGlzLlNBVkVEX1NFU1NJT05fS0VZKTtcclxuICAgIGlmIChzYXZlZCkge1xyXG4gICAgICBjb25zdCB7IHBhdGllbnQsIHVzZXIsIG1ldGhvZCwgc2VsZWN0ZWRDbGllbnQsIGVuYWJsZWQsIC4uLnJlc3QgfSA9IEpTT04ucGFyc2Uoc2F2ZWQpO1xyXG4gICAgICB0aGlzLnBhdGllbnQgPSBwYXRpZW50O1xyXG4gICAgICB0aGlzLnVzZXIgPSB1c2VyO1xyXG4gICAgICB0aGlzLm1ldGhvZCA9IG1ldGhvZDtcclxuICAgICAgdGhpcy5zZWxlY3RlZENsaWVudCA9IHNlbGVjdGVkQ2xpZW50O1xyXG4gICAgICB0aGlzLmVuYWJsZWQgPSBlbmFibGVkO1xyXG4gICAgICByZXR1cm4geyBwYXRpZW50LCB1c2VyLCBtZXRob2QsIHNlbGVjdGVkQ2xpZW50LCBlbmFibGVkLCAuLi5yZXN0IH07XHJcbiAgICB9XHJcbiAgICByZXR1cm4gbnVsbDtcclxuICB9XHJcblxyXG4gIC8vIGlmIHRoZSBwYXRpZW50IGlzIG5vdCByZWNlaXZlZCBwcm9wZXJseSBmcm9tIHRoZSByZXNwb25zZSwgYnV0IGV4aXN0cyBpbiB0aGUgdG9rZW4sIGFkZCBpdCB0byB0aGUgcmVzcG9uc2VcclxuICBwcml2YXRlIGNoZWNrUGF0aWVudEluVG9rZW4oY2xpZW50OiBDbGllbnQpIHtcclxuICAgIGNvbnN0IHNlc3Npb25JZCA9IHNlc3Npb25TdG9yYWdlWydTTUFSVF9LRVknXSAgJiYgSlNPTi5wYXJzZShzZXNzaW9uU3RvcmFnZVsnU01BUlRfS0VZJ10pXHJcbiAgICBpZiAoc2Vzc2lvbklkICYmIHNlc3Npb25TdG9yYWdlW3Nlc3Npb25JZF0pIHtcclxuICAgICAgY29uc3Qgc2Vzc2lvbiA9IEpTT04ucGFyc2Uoc2Vzc2lvblN0b3JhZ2Vbc2Vzc2lvbklkXSlcclxuICAgICAgY29uc3QgdG9rZW4gPSBzZXNzaW9uLnRva2VuUmVzcG9uc2U/LmFjY2Vzc190b2tlblxyXG4gICAgICBjb25zdCBpZF90b2tlbiA9IHNlc3Npb24udG9rZW5SZXNwb25zZT8uaWRfdG9rZW5cclxuICAgICAgY29uc3QgcGFyc2VkID0gSlNPTi5wYXJzZShhdG9iKHRva2VuLnNwbGl0KCcuJylbMV0pKVxyXG4gICAgICBsZXQgY2hhbmdlZCA9IGZhbHNlO1xyXG4gICAgICBpZiAoIWNsaWVudC51c2VyPy5pZCAmJiBpZF90b2tlbikge1xyXG4gICAgICAgIGNvbnN0IHBhcnRzID0gaWRfdG9rZW4uc3BsaXQoJy4nKVxyXG4gICAgICAgIGNvbnN0IHBhcnNlZElkVG9rZW4gPSBKU09OLnBhcnNlKGF0b2IocGFydHNbMV0pKVxyXG4gICAgICAgIHBhcnNlZElkVG9rZW4uZmhpclVzZXIgPSAnUHJhY3RpdGlvbmVyLycgKyBwYXJzZWRJZFRva2VuLnN1YjtcclxuICAgICAgICBzZXNzaW9uLnRva2VuUmVzcG9uc2UuaWRfdG9rZW4gPSBbcGFydHNbMF0sIGJ0b2EoSlNPTi5zdHJpbmdpZnkocGFyc2VkSWRUb2tlbikpLCBwYXJ0c1syXV0uam9pbignLicpO1xyXG4gICAgICAgIGNoYW5nZWQgPSB0cnVlO1xyXG4gICAgICB9XHJcbiAgICAgIGlmICghY2xpZW50LmdldFBhdGllbnRJZCgpICYmIHBhcnNlZC5wYXRpZW50KSB7XHJcbiAgICAgICAgc2Vzc2lvbi50b2tlblJlc3BvbnNlLnBhdGllbnQgPSBwYXJzZWQucGF0aWVudFxyXG4gICAgICAgIGNoYW5nZWQgPSB0cnVlO1xyXG4gICAgICB9XHJcbiAgICAgIGlmIChjaGFuZ2VkKSB7XHJcbiAgICAgICAgc2Vzc2lvblN0b3JhZ2Vbc2Vzc2lvbklkXSA9IEpTT04uc3RyaW5naWZ5KHNlc3Npb24pXHJcbiAgICAgICAgd2luZG93LmxvY2F0aW9uLnJlbG9hZCgpXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIGdldENsaWVudCgpIHtcclxuICAgIHJldHVybiB0aGlzLmNsaWVudFByb21pc2U7XHJcbiAgfVxyXG5cclxuICBnZXRDbGllbnRDb25maWcoKSB7XHJcbiAgICByZXR1cm4gdGhpcy5zZWxlY3RlZENsaWVudDtcclxuICB9XHJcblxyXG4gIGxvZ291dCgpIHtcclxuICAgIHRoaXMuY2xlYXJTZXNzaW9uKCk7XHJcbiAgICB0aGlzLmdldENsaWVudCgpLnRoZW4oY2xpZW50ID0+IHtcclxuICAgICAgY29uc3QgbG9naW5DbGllbnQgPSB0aGlzLmNvbmZpZz8ubG9naW5DbGllbnRzPy5maW5kKGxjID0+IGxjLmlzcyA9PT0gY2xpZW50Py5zdGF0ZS5zZXJ2ZXJVcmwpO1xyXG4gICAgICBpZiAoKDxhbnk+bG9naW5DbGllbnQpPy5sb2dvdXRVcmkpIHtcclxuICAgICAgICB3aW5kb3cubG9jYXRpb24uaHJlZiA9ICg8YW55PmxvZ2luQ2xpZW50KS5sb2dvdXRVcmlcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB3aW5kb3cubG9jYXRpb24uaHJlZiA9IHdpbmRvdy5sb2NhdGlvbi5ocmVmLnNwbGl0KCcjJylbMF0ucmVwbGFjZSgvc2hjJC8sICdsb2dpbicpXHJcbiAgICAgIH1cclxuICAgIH0sIGVyciA9PiB3aW5kb3cubG9jYXRpb24ucmVsb2FkKCkpXHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGNsZWFyU2Vzc2lvbigpIHtcclxuICAgIHNlc3Npb25TdG9yYWdlLmNsZWFyKClcclxuICAgIGlmICh0aGlzLmNvbmZpZy5hdXRoU3RvcmFnZSA9PT0gJ2xvY2FsU3RvcmFnZScpIHtcclxuICAgICAgbG9jYWxTdG9yYWdlLmNsZWFyKClcclxuICAgIH1cclxuICAgIHRoaXMubWV0aG9kID0gJ29mZmxpbmUnO1xyXG4gICAgdGhpcy5wYXRpZW50ID0gdGhpcy51c2VyID0gdW5kZWZpbmVkO1xyXG4gICAgdGhpcy5zZWxlY3RlZENsaWVudCA9IHVuZGVmaW5lZDtcclxuICAgIHRoaXMuZW5hYmxlZCA9IHRydWU7XHJcbiAgfVxyXG5cclxuICBhc3luYyBnZXRQYXRpZW50KCkge1xyXG4gICAgaWYgKHRoaXMucGF0aWVudCkgcmV0dXJuIHRoaXMucGF0aWVudDtcclxuICAgIGF3YWl0IHRoaXMuZ2V0Q2xpZW50KCk7XHJcbiAgICByZXR1cm4gdGhpcy5wYXRpZW50O1xyXG4gIH1cclxufVxyXG4iXX0=