angular-auth-oidc-client
Version:
Angular Lib for OpenID Connect & OAuth2
466 lines • 81.7 kB
JavaScript
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