UNPKG

angular-auth-oidc-client

Version:
466 lines 81.7 kB
import { HttpParams } from '@angular/common/http'; import { Injectable, inject } from '@angular/core'; import { of } from 'rxjs'; import { map } from 'rxjs/operators'; import { FlowsDataService } from '../../flows/flows-data.service'; import { LoggerService } from '../../logging/logger.service'; import { StoragePersistenceService } from '../../storage/storage-persistence.service'; import { JwtWindowCryptoService } from '../../validation/jwt-window-crypto.service'; import { FlowHelper } from '../flowHelper/flow-helper.service'; import { UriEncoder } from './uri-encoder'; import * as i0 from "@angular/core"; const CALLBACK_PARAMS_TO_CHECK = ['code', 'state', 'token', 'id_token']; const AUTH0_ENDPOINT = 'auth0.com'; export class UrlService { constructor() { this.loggerService = inject(LoggerService); this.flowsDataService = inject(FlowsDataService); this.flowHelper = inject(FlowHelper); this.storagePersistenceService = inject(StoragePersistenceService); this.jwtWindowCryptoService = inject(JwtWindowCryptoService); } getUrlParameter(urlToCheck, name) { if (!urlToCheck) { return ''; } if (!name) { return ''; } name = name.replace(/[[]/, '\\[').replace(/[\]]/, '\\]'); const regex = new RegExp('[\\?&#]' + name + '=([^&#]*)'); const results = regex.exec(urlToCheck); return results === null ? '' : decodeURIComponent(results[1]); } getUrlWithoutQueryParameters(url) { const u = new URL(url.toString()); const keys = []; for (const key of u.searchParams.keys()) { keys.push(key); } keys.forEach((key) => { u.searchParams.delete(key); }); return u; } queryParametersExist(expected, actual) { let r = true; expected.forEach((v, k) => { if (!actual.has(k)) { r = false; } }); return r; } isCallbackFromSts(currentUrl, config) { if (config && config.checkRedirectUrlWhenCheckingIfIsCallback) { const currentUrlInstance = new URL(currentUrl); const redirectUrl = this.getRedirectUrl(config); if (!redirectUrl) { this.loggerService.logError(config, `UrlService.isCallbackFromSts: could not get redirectUrl from config, was: `, redirectUrl); return false; } const redirectUriUrlInstance = new URL(redirectUrl); const redirectUriWithoutQueryParams = this.getUrlWithoutQueryParameters(redirectUriUrlInstance).toString(); const currentUrlWithoutQueryParams = this.getUrlWithoutQueryParameters(currentUrlInstance).toString(); const redirectUriQueryParamsArePresentInCurrentUrl = this.queryParametersExist(redirectUriUrlInstance.searchParams, currentUrlInstance.searchParams); if (redirectUriWithoutQueryParams !== currentUrlWithoutQueryParams || !redirectUriQueryParamsArePresentInCurrentUrl) { return false; } } return CALLBACK_PARAMS_TO_CHECK.some((x) => !!this.getUrlParameter(currentUrl, x)); } getRefreshSessionSilentRenewUrl(config, customParams) { if (this.flowHelper.isCurrentFlowCodeFlow(config)) { return this.createUrlCodeFlowWithSilentRenew(config, customParams); } return of(this.createUrlImplicitFlowWithSilentRenew(config, customParams)); } getAuthorizeParUrl(requestUri, configuration) { const authWellKnownEndPoints = this.storagePersistenceService.read('authWellKnownEndPoints', configuration); if (!authWellKnownEndPoints) { this.loggerService.logError(configuration, 'authWellKnownEndpoints is undefined'); return null; } const authorizationEndpoint = authWellKnownEndPoints.authorizationEndpoint; if (!authorizationEndpoint) { this.loggerService.logError(configuration, `Can not create an authorize URL when authorizationEndpoint is '${authorizationEndpoint}'`); return null; } const { clientId } = configuration; if (!clientId) { this.loggerService.logError(configuration, `getAuthorizeParUrl could not add clientId because it was: `, clientId); return null; } const urlParts = authorizationEndpoint.split('?'); const authorizationUrl = urlParts[0]; const existingParams = urlParts[1]; let params = this.createHttpParams(existingParams); params = params.set('request_uri', requestUri); params = params.append('client_id', clientId); return `${authorizationUrl}?${params}`; } getAuthorizeUrl(config, authOptions) { if (!config) { return of(null); } if (this.flowHelper.isCurrentFlowCodeFlow(config)) { return this.createUrlCodeFlowAuthorize(config, authOptions); } return of(this.createUrlImplicitFlowAuthorize(config, authOptions) || ''); } getEndSessionEndpoint(configuration) { const authWellKnownEndPoints = this.storagePersistenceService.read('authWellKnownEndPoints', configuration); const endSessionEndpoint = authWellKnownEndPoints?.endSessionEndpoint; if (!endSessionEndpoint) { return { url: '', existingParams: '', }; } const urlParts = endSessionEndpoint.split('?'); const url = urlParts[0]; const existingParams = urlParts[1] ?? ''; return { url, existingParams, }; } getEndSessionUrl(configuration, customParams) { if (!configuration) { return null; } const idToken = this.storagePersistenceService.getIdToken(configuration); const { customParamsEndSessionRequest } = configuration; const mergedParams = { ...customParamsEndSessionRequest, ...customParams }; return this.createEndSessionUrl(idToken, configuration, mergedParams); } createRevocationEndpointBodyAccessToken(token, configuration) { const clientId = this.getClientId(configuration); if (!clientId) { return null; } let params = this.createHttpParams(); params = params.set('client_id', clientId); params = params.set('token', token); params = params.set('token_type_hint', 'access_token'); return params.toString(); } createRevocationEndpointBodyRefreshToken(token, configuration) { const clientId = this.getClientId(configuration); if (!clientId) { return null; } let params = this.createHttpParams(); params = params.set('client_id', clientId); params = params.set('token', token); params = params.set('token_type_hint', 'refresh_token'); return params.toString(); } getRevocationEndpointUrl(configuration) { const authWellKnownEndPoints = this.storagePersistenceService.read('authWellKnownEndPoints', configuration); const revocationEndpoint = authWellKnownEndPoints?.revocationEndpoint; if (!revocationEndpoint) { return null; } const urlParts = revocationEndpoint.split('?'); return urlParts[0]; } createBodyForCodeFlowCodeRequest(code, configuration, customTokenParams) { const clientId = this.getClientId(configuration); if (!clientId) { return null; } let params = this.createHttpParams(); params = params.set('grant_type', 'authorization_code'); params = params.set('client_id', clientId); if (!configuration.disablePkce) { const codeVerifier = this.flowsDataService.getCodeVerifier(configuration); if (!codeVerifier) { this.loggerService.logError(configuration, `CodeVerifier is not set `, codeVerifier); return null; } params = params.set('code_verifier', codeVerifier); } params = params.set('code', code); if (customTokenParams) { params = this.appendCustomParams({ ...customTokenParams }, params); } const silentRenewUrl = this.getSilentRenewUrl(configuration); if (this.flowsDataService.isSilentRenewRunning(configuration) && silentRenewUrl) { params = params.set('redirect_uri', silentRenewUrl); return params.toString(); } const redirectUrl = this.getRedirectUrl(configuration); if (!redirectUrl) { return null; } params = params.set('redirect_uri', redirectUrl); return params.toString(); } createBodyForCodeFlowRefreshTokensRequest(refreshToken, configuration, customParamsRefresh) { const clientId = this.getClientId(configuration); if (!clientId) { return null; } let params = this.createHttpParams(); params = params.set('grant_type', 'refresh_token'); params = params.set('client_id', clientId); params = params.set('refresh_token', refreshToken); if (customParamsRefresh) { params = this.appendCustomParams({ ...customParamsRefresh }, params); } return params.toString(); } createBodyForParCodeFlowRequest(configuration, authOptions) { const redirectUrl = this.getRedirectUrl(configuration, authOptions); if (!redirectUrl) { return of(null); } const state = this.flowsDataService.getExistingOrCreateAuthStateControl(configuration); const nonce = this.flowsDataService.createNonce(configuration); this.loggerService.logDebug(configuration, 'Authorize created. adding myautostate: ' + state); // code_challenge with "S256" const codeVerifier = this.flowsDataService.createCodeVerifier(configuration); return this.jwtWindowCryptoService.generateCodeChallenge(codeVerifier).pipe(map((codeChallenge) => { const { clientId, responseType, scope, hdParam, customParamsAuthRequest, } = configuration; let params = this.createHttpParams(''); params = params.set('client_id', clientId ?? ''); params = params.append('redirect_uri', redirectUrl); params = params.append('response_type', responseType ?? ''); params = params.append('scope', scope ?? ''); params = params.append('nonce', nonce); params = params.append('state', state); params = params.append('code_challenge', codeChallenge); params = params.append('code_challenge_method', 'S256'); if (hdParam) { params = params.append('hd', hdParam); } if (customParamsAuthRequest) { params = this.appendCustomParams({ ...customParamsAuthRequest }, params); } if (authOptions?.customParams) { params = this.appendCustomParams({ ...authOptions.customParams }, params); } return params.toString(); })); } getPostLogoutRedirectUrl(configuration) { const { postLogoutRedirectUri } = configuration; if (!postLogoutRedirectUri) { this.loggerService.logError(configuration, `could not get postLogoutRedirectUri, was: `, postLogoutRedirectUri); return null; } return postLogoutRedirectUri; } createEndSessionUrl(idTokenHint, configuration, customParamsEndSession) { // Auth0 needs a special logout url // See https://auth0.com/docs/api/authentication#logout if (this.isAuth0Endpoint(configuration)) { return this.composeAuth0Endpoint(configuration); } const { url, existingParams } = this.getEndSessionEndpoint(configuration); if (!url) { return null; } let params = this.createHttpParams(existingParams); if (!!idTokenHint) { params = params.set('id_token_hint', idTokenHint); } const postLogoutRedirectUri = this.getPostLogoutRedirectUrl(configuration); if (postLogoutRedirectUri) { params = params.append('post_logout_redirect_uri', postLogoutRedirectUri); } if (customParamsEndSession) { params = this.appendCustomParams({ ...customParamsEndSession }, params); } return `${url}?${params}`; } createAuthorizeUrl(codeChallenge, redirectUrl, nonce, state, configuration, prompt, customRequestParams) { const authWellKnownEndPoints = this.storagePersistenceService.read('authWellKnownEndPoints', configuration); const authorizationEndpoint = authWellKnownEndPoints?.authorizationEndpoint; if (!authorizationEndpoint) { this.loggerService.logError(configuration, `Can not create an authorize URL when authorizationEndpoint is '${authorizationEndpoint}'`); return ''; } const { clientId, responseType, scope, hdParam, customParamsAuthRequest } = configuration; if (!clientId) { this.loggerService.logError(configuration, `createAuthorizeUrl could not add clientId because it was: `, clientId); return ''; } if (!responseType) { this.loggerService.logError(configuration, `createAuthorizeUrl could not add responseType because it was: `, responseType); return ''; } if (!scope) { this.loggerService.logError(configuration, `createAuthorizeUrl could not add scope because it was: `, scope); return ''; } const urlParts = authorizationEndpoint.split('?'); const authorizationUrl = urlParts[0]; const existingParams = urlParts[1]; let params = this.createHttpParams(existingParams); params = params.set('client_id', clientId); params = params.append('redirect_uri', redirectUrl); params = params.append('response_type', responseType); params = params.append('scope', scope); params = params.append('nonce', nonce); params = params.append('state', state); if (this.flowHelper.isCurrentFlowCodeFlow(configuration)) { params = params.append('code_challenge', codeChallenge); params = params.append('code_challenge_method', 'S256'); } const mergedParams = { ...customParamsAuthRequest, ...customRequestParams }; if (Object.keys(mergedParams).length > 0) { params = this.appendCustomParams({ ...mergedParams }, params); } if (prompt) { params = this.overWriteParam(params, 'prompt', prompt); } if (hdParam) { params = params.append('hd', hdParam); } return `${authorizationUrl}?${params}`; } createUrlImplicitFlowWithSilentRenew(configuration, customParams) { const state = this.flowsDataService.getExistingOrCreateAuthStateControl(configuration); const nonce = this.flowsDataService.createNonce(configuration); const silentRenewUrl = this.getSilentRenewUrl(configuration); if (!silentRenewUrl) { return null; } this.loggerService.logDebug(configuration, 'RefreshSession created. adding myautostate: ', state); const authWellKnownEndPoints = this.storagePersistenceService.read('authWellKnownEndPoints', configuration); if (authWellKnownEndPoints) { return this.createAuthorizeUrl('', silentRenewUrl, nonce, state, configuration, 'none', customParams); } this.loggerService.logError(configuration, 'authWellKnownEndpoints is undefined'); return null; } createUrlCodeFlowWithSilentRenew(configuration, customParams) { const state = this.flowsDataService.getExistingOrCreateAuthStateControl(configuration); const nonce = this.flowsDataService.createNonce(configuration); this.loggerService.logDebug(configuration, 'RefreshSession created. adding myautostate: ' + state); // code_challenge with "S256" const codeVerifier = this.flowsDataService.createCodeVerifier(configuration); return this.jwtWindowCryptoService.generateCodeChallenge(codeVerifier).pipe(map((codeChallenge) => { const silentRenewUrl = this.getSilentRenewUrl(configuration); if (!silentRenewUrl) { return ''; } const authWellKnownEndPoints = this.storagePersistenceService.read('authWellKnownEndPoints', configuration); if (authWellKnownEndPoints) { return this.createAuthorizeUrl(codeChallenge, silentRenewUrl, nonce, state, configuration, 'none', customParams); } this.loggerService.logWarning(configuration, 'authWellKnownEndpoints is undefined'); return ''; })); } createUrlImplicitFlowAuthorize(configuration, authOptions) { const state = this.flowsDataService.getExistingOrCreateAuthStateControl(configuration); const nonce = this.flowsDataService.createNonce(configuration); this.loggerService.logDebug(configuration, 'Authorize created. adding myautostate: ' + state); const redirectUrl = this.getRedirectUrl(configuration, authOptions); if (!redirectUrl) { return null; } const authWellKnownEndPoints = this.storagePersistenceService.read('authWellKnownEndPoints', configuration); if (authWellKnownEndPoints) { const { customParams } = authOptions || {}; return this.createAuthorizeUrl('', redirectUrl, nonce, state, configuration, '', customParams); } this.loggerService.logError(configuration, 'authWellKnownEndpoints is undefined'); return null; } createUrlCodeFlowAuthorize(config, authOptions) { const state = this.flowsDataService.getExistingOrCreateAuthStateControl(config); const nonce = this.flowsDataService.createNonce(config); this.loggerService.logDebug(config, 'Authorize created. adding myautostate: ' + state); const redirectUrl = this.getRedirectUrl(config, authOptions); if (!redirectUrl) { return of(null); } return this.getCodeChallenge(config).pipe(map((codeChallenge) => { const authWellKnownEndPoints = this.storagePersistenceService.read('authWellKnownEndPoints', config); if (authWellKnownEndPoints) { const { customParams } = authOptions || {}; return this.createAuthorizeUrl(codeChallenge, redirectUrl, nonce, state, config, '', customParams); } this.loggerService.logError(config, 'authWellKnownEndpoints is undefined'); return ''; })); } getCodeChallenge(config) { if (config.disablePkce) { return of(''); } // code_challenge with "S256" const codeVerifier = this.flowsDataService.createCodeVerifier(config); return this.jwtWindowCryptoService.generateCodeChallenge(codeVerifier); } getRedirectUrl(configuration, authOptions) { let { redirectUrl } = configuration; if (authOptions?.redirectUrl) { // override by redirectUrl from authOptions redirectUrl = authOptions.redirectUrl; } if (!redirectUrl) { this.loggerService.logError(configuration, `could not get redirectUrl, was: `, redirectUrl); return null; } return redirectUrl; } getSilentRenewUrl(configuration) { const { silentRenewUrl } = configuration; if (!silentRenewUrl) { this.loggerService.logError(configuration, `could not get silentRenewUrl, was: `, silentRenewUrl); return null; } return silentRenewUrl; } getClientId(configuration) { const { clientId } = configuration; if (!clientId) { this.loggerService.logError(configuration, `could not get clientId, was: `, clientId); return null; } return clientId; } appendCustomParams(customParams, params) { for (const [key, value] of Object.entries({ ...customParams })) { params = params.append(key, value.toString()); } return params; } overWriteParam(params, key, value) { return params.set(key, value); } createHttpParams(existingParams) { existingParams = existingParams ?? ''; return new HttpParams({ fromString: existingParams, encoder: new UriEncoder(), }); } isAuth0Endpoint(configuration) { const { authority, useCustomAuth0Domain } = configuration; if (!authority) { return false; } return authority.endsWith(AUTH0_ENDPOINT) || Boolean(useCustomAuth0Domain); } composeAuth0Endpoint(configuration) { // format: https://YOUR_DOMAIN/v2/logout?client_id=YOUR_CLIENT_ID&returnTo=LOGOUT_URL const { authority, clientId } = configuration; const postLogoutRedirectUrl = this.getPostLogoutRedirectUrl(configuration); return `${authority}/v2/logout?client_id=${clientId}&returnTo=${postLogoutRedirectUrl}`; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: UrlService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: UrlService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: UrlService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXJsLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9hbmd1bGFyLWF1dGgtb2lkYy1jbGllbnQvc3JjL2xpYi91dGlscy91cmwvdXJsLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ25ELE9BQU8sRUFBYyxFQUFFLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDdEMsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBR3JDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQ2xFLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUM3RCxPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSwyQ0FBMkMsQ0FBQztBQUN0RixPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSw0Q0FBNEMsQ0FBQztBQUNwRixPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFDL0QsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQzs7QUFFM0MsTUFBTSx3QkFBd0IsR0FBRyxDQUFDLE1BQU0sRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLFVBQVUsQ0FBQyxDQUFDO0FBQ3hFLE1BQU0sY0FBYyxHQUFHLFdBQVcsQ0FBQztBQUduQyxNQUFNLE9BQU8sVUFBVTtJQUR2QjtRQUVtQixrQkFBYSxHQUFHLE1BQU0sQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUV0QyxxQkFBZ0IsR0FBRyxNQUFNLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztRQUU1QyxlQUFVLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBRWhDLDhCQUF5QixHQUFHLE1BQU0sQ0FD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QUFPLEVBQUUsSUFBSSxVQUFVLEVBQUU7U0FDMUIsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVPLGVBQWUsQ0FBQyxhQUFrQztRQUN4RCxNQUFNLEVBQUUsU0FBUyxFQUFFLG9CQUFvQixFQUFFLEdBQUcsYUFBYSxDQUFDO1FBRTFELElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUNmLE9BQU8sS0FBSyxDQUFDO1FBQ2YsQ0FBQztRQUVELE9BQU8sU0FBUyxDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUMsSUFBSSxPQUFPLENBQUMsb0JBQW9CLENBQUMsQ0FBQztJQUM3RSxDQUFDO0lBRU8sb0JBQW9CLENBQUMsYUFBa0M7UUFDN0QscUZBQXFGO1FBQ3JGLE1BQU0sRUFBRSxTQUFTLEVBQUUsUUFBUSxFQUFFLEdBQUcsYUFBYSxDQUFDO1FBQzlDLE1BQU0scUJBQXFCLEdBQUcsSUFBSSxDQUFDLHdCQUF3QixDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBRTNFLE9BQU8sR0FBRyxTQUFTLHdCQUF3QixRQUFRLGFBQWEscUJBQXFCLEVBQUUsQ0FBQztJQUMxRixDQUFDOzhHQXQyQlUsVUFBVTtrSEFBVixVQUFVLGNBREcsTUFBTTs7MkZBQ25CLFVBQVU7a0JBRHRCLFVBQVU7bUJBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSHR0cFBhcmFtcyB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcclxuaW1wb3J0IHsgSW5qZWN0YWJsZSwgaW5qZWN0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IE9ic2VydmFibGUsIG9mIH0gZnJvbSAncnhqcyc7XHJcbmltcG9ydCB7IG1hcCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcclxuaW1wb3J0IHsgQXV0aE9wdGlvbnMgfSBmcm9tICcuLi8uLi9hdXRoLW9wdGlvbnMnO1xyXG5pbXBvcnQgeyBPcGVuSWRDb25maWd1cmF0aW9uIH0gZnJvbSAnLi4vLi4vY29uZmlnL29wZW5pZC1jb25maWd1cmF0aW9uJztcclxuaW1wb3J0IHsgRmxvd3NEYXRhU2VydmljZSB9IGZyb20gJy4uLy4uL2Zsb3dzL2Zsb3dzLWRhdGEuc2VydmljZSc7XHJcbmltcG9ydCB7IExvZ2dlclNlcnZpY2UgfSBmcm9tICcuLi8uLi9sb2dnaW5nL2xvZ2dlci5zZXJ2aWNlJztcclxuaW1wb3J0IHsgU3RvcmFnZVBlcnNpc3RlbmNlU2VydmljZSB9IGZyb20gJy4uLy4uL3N0b3JhZ2Uvc3RvcmFnZS1wZXJzaXN0ZW5jZS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgSnd0V2luZG93Q3J5cHRvU2VydmljZSB9IGZyb20gJy4uLy4uL3ZhbGlkYXRpb24vand0LXdpbmRvdy1jcnlwdG8uc2VydmljZSc7XHJcbmltcG9ydCB7IEZsb3dIZWxwZXIgfSBmcm9tICcuLi9mbG93SGVscGVyL2Zsb3ctaGVscGVyLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBVcmlFbmNvZGVyIH0gZnJvbSAnLi91cmktZW5jb2Rlcic7XHJcblxyXG5jb25zdCBDQUxMQkFDS19QQVJBTVNfVE9fQ0hFQ0sgPSBbJ2NvZGUnLCAnc3RhdGUnLCAndG9rZW4nLCAnaWRfdG9rZW4nXTtcclxuY29uc3QgQVVUSDBfRU5EUE9JTlQgPSAnYXV0aDAuY29tJztcclxuXHJcbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXHJcbmV4cG9ydCBjbGFzcyBVcmxTZXJ2aWNlIHtcclxuICBwcml2YXRlIHJlYWRvbmx5IGxvZ2dlclNlcnZpY2UgPSBpbmplY3QoTG9nZ2VyU2VydmljZSk7XHJcblxyXG4gIHByaXZhdGUgcmVhZG9ubHkgZmxvd3NEYXRhU2VydmljZSA9IGluamVjdChGbG93c0RhdGFTZXJ2aWNlKTtcclxuXHJcbiAgcHJpdmF0ZSByZWFkb25seSBmbG93SGVscGVyID0gaW5qZWN0KEZsb3dIZWxwZXIpO1xyXG5cclxuICBwcml2YXRlIHJlYWRvbmx5IHN0b3JhZ2VQZXJzaXN0ZW5jZVNlcnZpY2UgPSBpbmplY3QoXHJcbiAgICBTdG9yYWdlUGVyc2lzdGVuY2VTZXJ2aWNlXHJcbiAgKTtcclxuXHJcbiAgcHJpdmF0ZSByZWFkb25seSBqd3RXaW5kb3dDcnlwdG9TZXJ2aWNlID0gaW5qZWN0KEp3dFdpbmRvd0NyeXB0b1NlcnZpY2UpO1xyXG5cclxuICBnZXRVcmxQYXJhbWV0ZXIodXJsVG9DaGVjazogc3RyaW5nLCBuYW1lOiBzdHJpbmcpOiBzdHJpbmcge1xyXG4gICAgaWYgKCF1cmxUb0NoZWNrKSB7XHJcbiAgICAgIHJldHVybiAnJztcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIW5hbWUpIHtcclxuICAgICAgcmV0dXJuICcnO1xyXG4gICAgfVxyXG5cclxuICAgIG5hbWUgPSBuYW1lLnJlcGxhY2UoL1tbXS8sICdcXFxcWycpLnJlcGxhY2UoL1tcXF1dLywgJ1xcXFxdJyk7XHJcbiAgICBjb25zdCByZWdleCA9IG5ldyBSZWdFeHAoJ1tcXFxcPyYjXScgKyBuYW1lICsgJz0oW14mI10qKScpO1xyXG4gICAgY29uc3QgcmVzdWx0cyA9IHJlZ2V4LmV4ZWModXJsVG9DaGVjayk7XHJcblxyXG4gICAgcmV0dXJuIHJlc3VsdHMgPT09IG51bGwgPyAnJyA6IGRlY29kZVVSSUNvbXBvbmVudChyZXN1bHRzWzFdKTtcclxuICB9XHJcblxyXG4gIGdldFVybFdpdGhvdXRRdWVyeVBhcmFtZXRlcnModXJsOiBVUkwpOiBVUkwge1xyXG4gICAgY29uc3QgdSA9IG5ldyBVUkwodXJsLnRvU3RyaW5nKCkpO1xyXG5cclxuICAgIGNvbnN0IGtleXMgPSBbXTtcclxuXHJcbiAgICBmb3IgKGNvbnN0IGtleSBvZiB1LnNlYXJjaFBhcmFtcy5rZXlzKCkpIHtcclxuICAgICAga2V5cy5wdXNoKGtleSk7XHJcbiAgICB9XHJcblxyXG4gICAga2V5cy5mb3JFYWNoKChrZXkpID0+IHtcclxuICAgICAgdS5zZWFyY2hQYXJhbXMuZGVsZXRlKGtleSk7XHJcbiAgICB9KTtcclxuXHJcbiAgICByZXR1cm4gdTtcclxuICB9XHJcblxyXG4gIHF1ZXJ5UGFyYW1ldGVyc0V4aXN0KGV4cGVjdGVkOiBVUkxTZWFyY2hQYXJhbXMsIGFjdHVhbDogVVJMU2VhcmNoUGFyYW1zKTogYm9vbGVhbiB7XHJcbiAgICBsZXQgciA9IHRydWU7XHJcblxyXG4gICAgZXhwZWN0ZWQuZm9yRWFjaCgodiwgaykgPT4ge1xyXG4gICAgICBpZiAoIWFjdHVhbC5oYXMoaykpIHtcclxuICAgICAgICByID0gZmFsc2U7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIHJldHVybiByO1xyXG4gIH1cclxuXHJcbiAgaXNDYWxsYmFja0Zyb21TdHMoY3VycmVudFVybDogc3RyaW