angular-auth-oidc-client
Version:
Angular Lib for OpenID Connect & OAuth2
405 lines • 69.9 kB
JavaScript
import { HttpParams } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { of } from 'rxjs';
import { map } from 'rxjs/operators';
import { UriEncoder } from './uri-encoder';
import * as i0 from "@angular/core";
import * as i1 from "../../logging/logger.service";
import * as i2 from "../../flows/flows-data.service";
import * as i3 from "../flowHelper/flow-helper.service";
import * as i4 from "../../storage/storage-persistence.service";
import * as i5 from "../../validation/jwt-window-crypto.service";
const CALLBACK_PARAMS_TO_CHECK = ['code', 'state', 'token', 'id_token'];
const AUTH0_ENDPOINT = 'auth0.com';
export class UrlService {
constructor(loggerService, flowsDataService, flowHelper, storagePersistenceService, jwtWindowCryptoService) {
this.loggerService = loggerService;
this.flowsDataService = flowsDataService;
this.flowHelper = flowHelper;
this.storagePersistenceService = storagePersistenceService;
this.jwtWindowCryptoService = 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]);
}
isCallbackFromSts(currentUrl) {
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 (this.flowHelper.isCurrentFlowCodeFlow(config)) {
return this.createUrlCodeFlowAuthorize(config, authOptions);
}
return of(this.createUrlImplicitFlowAuthorize(config, authOptions) || '');
}
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 authWellKnownEndPoints = this.storagePersistenceService.read('authWellKnownEndPoints', configuration);
const endSessionEndpoint = authWellKnownEndPoints?.endSessionEndpoint;
if (!endSessionEndpoint) {
return null;
}
const urlParts = endSessionEndpoint.split('?');
const authorizationEndSessionUrl = urlParts[0];
const existingParams = urlParts[1];
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 `${authorizationEndSessionUrl}?${params}`;
}
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('?');
const revocationEndpointUrl = urlParts[0];
return revocationEndpointUrl;
}
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, customParamsRequest) {
const redirectUrl = this.getRedirectUrl(configuration);
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 (customParamsRequest) {
params = this.appendCustomParams({ ...customParamsRequest }, params);
}
return params.toString();
}));
}
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 null;
}
const { clientId, responseType, scope, hdParam, customParamsAuthRequest } = configuration;
if (!clientId) {
this.loggerService.logError(configuration, `createAuthorizeUrl could not add clientId because it was: `, clientId);
return null;
}
if (!responseType) {
this.loggerService.logError(configuration, `createAuthorizeUrl could not add responseType because it was: `, responseType);
return null;
}
if (!scope) {
this.loggerService.logError(configuration, `createAuthorizeUrl could not add scope because it was: `, scope);
return null;
}
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) && codeChallenge !== null) {
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 null;
}));
}
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, null, 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, null, customParams);
}
this.loggerService.logError(config, 'authWellKnownEndpoints is undefined');
return '';
}));
}
getCodeChallenge(config) {
if (config.disablePkce) {
return of(null);
}
// 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;
}
getPostLogoutRedirectUrl(configuration) {
const { postLogoutRedirectUri } = configuration;
if (!postLogoutRedirectUri) {
this.loggerService.logError(configuration, `could not get postLogoutRedirectUri, was: `, postLogoutRedirectUri);
return null;
}
return postLogoutRedirectUri;
}
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 ?? '';
const params = new HttpParams({
fromString: existingParams,
encoder: new UriEncoder(),
});
return params;
}
isAuth0Endpoint(configuration) {
const { authority } = configuration;
if (!authority) {
return false;
}
return authority.endsWith(AUTH0_ENDPOINT);
}
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}`;
}
}
UrlService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.0", ngImport: i0, type: UrlService, deps: [{ token: i1.LoggerService }, { token: i2.FlowsDataService }, { token: i3.FlowHelper }, { token: i4.StoragePersistenceService }, { token: i5.JwtWindowCryptoService }], target: i0.ɵɵFactoryTarget.Injectable });
UrlService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.1.0", ngImport: i0, type: UrlService });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.0", ngImport: i0, type: UrlService, decorators: [{
type: Injectable
}], ctorParameters: function () { return [{ type: i1.LoggerService }, { type: i2.FlowsDataService }, { type: i3.FlowHelper }, { type: i4.StoragePersistenceService }, { type: i5.JwtWindowCryptoService }]; } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXJsLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9hbmd1bGFyLWF1dGgtb2lkYy1jbGllbnQvc3JjL2xpYi91dGlscy91cmwvdXJsLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0MsT0FBTyxFQUFjLEVBQUUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN0QyxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFRckMsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQzs7Ozs7OztBQUUzQyxNQUFNLHdCQUF3QixHQUFHLENBQUMsTUFBTSxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsVUFBVSxDQUFDLENBQUM7QUFDeEUsTUFBTSxjQUFjLEdBQUcsV0FBVyxDQUFDO0FBR25DLE1BQU0sT0FBTyxVQUFVO0lBQ3JCLFlBQ21CLGFBQTRCLEVBQzVCLGdCQUFrQyxFQUNsQyxVQUFzQixFQUN0Qix5QkFBb0QsRUFDcEQsc0JBQThDO1FBSjlDLGtCQUFhLEdBQWIsYUFBYSxDQUFlO1FBQzVCLHFCQUFnQixHQUFoQixnQkFBZ0IsQ0FBa0I7UUFDbEMsZUFBVSxHQUFWLFVBQVUsQ0FBWTtRQUN0Qiw4QkFBeUIsR0FBekIseUJBQXlCLENBQTJCO1FBQ3BELDJCQUFzQixHQUF0QixzQkFBc0IsQ0FBd0I7SUFDOUQsQ0FBQztJQUVKLGVBQWUsQ0FBQyxVQUFlLEVBQUUsSUFBUztRQUN4QyxJQUFJLENBQUMsVUFBVSxFQUFFO1lBQ2YsT0FBTyxFQUFFLENBQUM7U0FDWDtRQUVELElBQUksQ0FBQyxJQUFJLEVBQUU7WUFDVCxPQUFPLEVBQUUsQ0FBQztTQUNYO1FBRUQsSUFBSSxHQUFHLElBQUksQ0FBQyxP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U0FBUyxFQUFFLEdBQUcsYUFBYSxDQUFDO1FBRXBDLElBQUksQ0FBQyxTQUFTLEVBQUU7WUFDZCxPQUFPLEtBQUssQ0FBQztTQUNkO1FBRUQsT0FBTyxTQUFTLENBQUMsUUFBUSxDQUFDLGNBQWMsQ0FBQyxDQUFDO0lBQzVDLENBQUM7SUFFTyxvQkFBb0IsQ0FBQyxhQUFrQztRQUM3RCxxRkFBcUY7UUFDckYsTUFBTSxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsR0FBRyxhQUFhLENBQUM7UUFDOUMsTUFBTSxxQkFBcUIsR0FBRyxJQUFJLENBQUMsd0JBQXdCLENBQUMsYUFBYSxDQUFDLENBQUM7UUFFM0UsT0FBTyxHQUFHLFNBQVMsd0JBQXdCLFFBQVEsYUFBYSxxQkFBcUIsRUFBRSxDQUFDO0lBQzFGLENBQUM7O3VHQS9rQlUsVUFBVTsyR0FBVixVQUFVOzJGQUFWLFVBQVU7a0JBRHRCLFVBQVUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBIdHRwUGFyYW1zIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xyXG5pbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IE9ic2VydmFibGUsIG9mIH0gZnJvbSAncnhqcyc7XHJcbmltcG9ydCB7IG1hcCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcclxuaW1wb3J0IHsgQXV0aE9wdGlvbnMgfSBmcm9tICcuLi8uLi9hdXRoLW9wdGlvbnMnO1xyXG5pbXBvcnQgeyBPcGVuSWRDb25maWd1cmF0aW9uIH0gZnJvbSAnLi4vLi4vY29uZmlnL29wZW5pZC1jb25maWd1cmF0aW9uJztcclxuaW1wb3J0IHsgRmxvd3NEYXRhU2VydmljZSB9IGZyb20gJy4uLy4uL2Zsb3dzL2Zsb3dzLWRhdGEuc2VydmljZSc7XHJcbmltcG9ydCB7IExvZ2dlclNlcnZpY2UgfSBmcm9tICcuLi8uLi9sb2dnaW5nL2xvZ2dlci5zZXJ2aWNlJztcclxuaW1wb3J0IHsgU3RvcmFnZVBlcnNpc3RlbmNlU2VydmljZSB9IGZyb20gJy4uLy4uL3N0b3JhZ2Uvc3RvcmFnZS1wZXJzaXN0ZW5jZS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgSnd0V2luZG93Q3J5cHRvU2VydmljZSB9IGZyb20gJy4uLy4uL3ZhbGlkYXRpb24vand0LXdpbmRvdy1jcnlwdG8uc2VydmljZSc7XHJcbmltcG9ydCB7IEZsb3dIZWxwZXIgfSBmcm9tICcuLi9mbG93SGVscGVyL2Zsb3ctaGVscGVyLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBVcmlFbmNvZGVyIH0gZnJvbSAnLi91cmktZW5jb2Rlcic7XHJcblxyXG5jb25zdCBDQUxMQkFDS19QQVJBTVNfVE9fQ0hFQ0sgPSBbJ2NvZGUnLCAnc3RhdGUnLCAndG9rZW4nLCAnaWRfdG9rZW4nXTtcclxuY29uc3QgQVVUSDBfRU5EUE9JTlQgPSAnYXV0aDAuY29tJztcclxuXHJcbkBJbmplY3RhYmxlKClcclxuZXhwb3J0IGNsYXNzIFVybFNlcnZpY2Uge1xyXG4gIGNvbnN0cnVjdG9yKFxyXG4gICAgcHJpdmF0ZSByZWFkb25seSBsb2dnZXJTZXJ2aWNlOiBMb2dnZXJTZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSByZWFkb25seSBmbG93c0RhdGFTZXJ2aWNlOiBGbG93c0RhdGFTZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSByZWFkb25seSBmbG93SGVscGVyOiBGbG93SGVscGVyLFxyXG4gICAgcHJpdmF0ZSByZWFkb25seSBzdG9yYWdlUGVyc2lzdGVuY2VTZXJ2aWNlOiBTdG9yYWdlUGVyc2lzdGVuY2VTZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSByZWFkb25seSBqd3RXaW5kb3dDcnlwdG9TZXJ2aWNlOiBKd3RXaW5kb3dDcnlwdG9TZXJ2aWNlXHJcbiAgKSB7fVxyXG5cclxuICBnZXRVcmxQYXJhbWV0ZXIodXJsVG9DaGVjazogYW55LCBuYW1lOiBhbnkpOiBzdHJpbmcge1xyXG4gICAgaWYgKCF1cmxUb0NoZWNrKSB7XHJcbiAgICAgIHJldHVybiAnJztcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIW5hbWUpIHtcclxuICAgICAgcmV0dXJuICcnO1xyXG4gICAgfVxyXG5cclxuICAgIG5hbWUgPSBuYW1lLnJlcGxhY2UoL1tbXS8sICdcXFxcWycpLnJlcGxhY2UoL1tcXF1dLywgJ1xcXFxdJyk7XHJcbiAgICBjb25zdCByZWdleCA9IG5ldyBSZWdFeHAoJ1tcXFxcPyYjXScgKyBuYW1lICsgJz0oW14mI10qKScpO1xyXG4gICAgY29uc3QgcmVzdWx0cyA9IHJlZ2V4LmV4ZWModXJsVG9DaGVjayk7XHJcblxyXG4gICAgcmV0dXJuIHJlc3VsdHMgPT09IG51bGwgPyAnJyA6IGRlY29kZVVSSUNvbXBvbmVudChyZXN1bHRzWzFdKTtcclxuICB9XHJcblxyXG4gIGlzQ2FsbGJhY2tGcm9tU3RzKGN1cnJlbnRVcmw6IHN0cmluZyk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIENBTExCQUNLX1BBUkFNU19UT19DSEVDSy5zb21lKCh4KSA9PiAhIXRoaXMuZ2V0VXJsUGFyYW1ldGVyKGN1cnJlbnRVcmwsIHgpKTtcclxuICB9XHJcblxyXG4gIGdldFJlZnJlc2hTZXNzaW9uU2lsZW50UmVuZXdVcmwoXHJcbiAgICBjb25maWc6IE9wZW5JZENvbmZpZ3VyYXRpb24sXHJcbiAgICBjdXN0b21QYXJhbXM/OiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4gfVxyXG4gICk6IE9ic2VydmFibGU8c3RyaW5nPiB7XHJcbiAgICBpZiAodGhpcy5mbG93SGVscGVyLmlzQ3VycmVudEZsb3dDb2RlRmxvdyhjb25maWcpKSB7XHJcbiAgICAgIHJldHVybiB0aGlzLmNyZWF0ZVVybENvZGVGbG93V2l0aFNpbGVudFJlbmV3KGNvbmZpZywgY3VzdG9tUGFyYW1zKTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gb2YodGhpcy5jcmVhdGVVcmxJbXBsaWNpdEZsb3dXaXRoU2lsZW50UmVuZXcoY29uZmlnLCBjdXN0b21QYXJhbXMpIHx8ICcnKTtcclxuICB9XHJcblxyXG4gIGdldEF1dGhvcml6ZVBhclVybChyZXF1ZXN0VXJpOiBzdHJpbmcsIGNvbmZpZ3VyYXRpb246IE9wZW5JZENvbmZpZ3VyYXRpb24pOiBzdHJpbmcge1xyXG4gICAgY29uc3QgYXV0aFdlbGxLbm93bkVuZFBvaW50cyA9IHRoaXMuc3RvcmFnZVBlcnNpc3RlbmNlU2VydmljZS5yZWFkKCdhdXRoV2VsbEtub3duRW5kUG9pbnRzJywgY29uZmlndXJhdGlvbik7XHJcblxyXG4gICAgaWYgKCFhdXRoV2VsbEtub3duRW5kUG9pbnRzKSB7XHJcbiAgICAgIHRoaXMubG9nZ2VyU2VydmljZS5sb2dFcnJvcihjb25maWd1cmF0aW9uLCAnYXV0aFdlbGxLbm93bkVuZHBvaW50cyBpcyB1bmRlZmluZWQnKTtcclxuXHJcbiAgICAgIHJldHVybiBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IGF1dGhvcml6YXRpb25FbmRwb2ludCA9IGF1dGhXZWxsS25vd25FbmRQb2ludHMuYXV0aG9yaXphdGlvbkVuZHBvaW50O1xyXG5cclxuICAgIGlmICghYXV0aG9yaXphdGlvbkVuZHBvaW50KSB7XHJcbiAgICAgIHRoaXMubG9nZ2VyU2VydmljZS5sb2dFcnJvcihcclxuICAgICAgICBjb25maWd1cmF0aW9uLFxyXG4gICAgICAgIGBDYW4gbm90IGNyZWF0ZSBhbiBhdXRob3JpemUgVVJMIHdoZW4gYXV0aG9yaXphdGlvbkVuZHBvaW50IGlzICcke2F1dGhvcml6YXRpb25FbmRwb2ludH0nYFxyXG4gICAgICApO1xyXG5cclxuICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgeyBjbGllbnRJZCB9ID0gY29uZmlndXJhdGlvbjtcclxuXHJcbiAgICBpZiAoIWNsaWVudElkKSB7XHJcbiAgICAgIHRoaXMubG9nZ2VyU2VydmljZS5sb2dFcnJvcihjb25maWd1cmF0aW9uLCBgZ2V0QXV0aG9yaXplUGFyVXJsIGNvdWxkIG5vdCBhZGQgY2xpZW50SWQgYmVjYXVzZSBpdCB3YXM6IGAsIGNsaWVudElkKTtcclxuXHJcbiAgICAgIHJldHVybiBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHVybFBhcnRzID0gYXV0aG9yaXphdGlvbkVuZHBvaW50LnNwbGl0KCc/Jyk7XHJcbiAgICBjb25zdCBhdXRob3JpemF0aW9uVXJsID0gdXJsUGFydHNbMF07XHJcbiAgICBjb25zdCBleGlzdGluZ1BhcmFtcyA9IHVybFBhcnRzWzFdO1xyXG4gICAgbGV0IHBhcmFtcyA9IHRoaXMuY3JlYXRlSHR0cFBhcmFtcyhleGlzdGluZ1BhcmFtcyk7XHJcblxyXG4gICAgcGFyYW1zID0gcGFyYW1zLnNldCgncmVxdWVzdF91cmknLCByZXF1ZXN0VXJpKTtcclxuICAgIHBhcmFtcyA9IHBhcmFtcy5hcHBlbmQoJ2NsaWVudF9pZCcsIGNsaWVudElkKTtcclxuXHJcbiAgICByZXR1cm4gYCR7YXV0aG9yaXphdGlvblVybH0/JHtwYXJhbXN9YDtcclxuICB9XHJcblxyXG4gIGdldEF1dGhvcml6ZVVybChjb25maWc6IE9wZW5JZENvbmZpZ3VyYXRpb24sIGF1dGhPcHRpb25zPzogQXV0aE9wdGlvbnMpOiBPYnNlcnZhYmxlPHN0cmluZz4ge1xyXG4gICAgaWYgKHRoaXMuZmxvd0hlbHBlci5pc0N1cnJlbnRGbG93Q29kZUZsb3coY29uZmlnKSkge1xyXG4gICAgICByZXR1cm4gdGhpcy5jcmVhdGVVcmxDb2RlRmxvd0F1dGhvcml6ZShjb25maWcsIGF1dGhPcHRpb25zKTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gb2YodGhpcy5jcmVhdGVVcmxJbXBsaWNpdEZsb3dBdXRob3JpemUoY29uZmlnLCBhdXRoT3B0aW9ucykgfHwgJycpO1xyXG4gIH1cclxuXHJcbiAgY3JlYXRlRW5kU2Vzc2lvblVybChcclxuICAgIGlkVG9rZW5IaW50OiBzdHJpbmcsXHJcbiAgICBjb25maWd1cmF0aW9uOiBPcGVuSWRDb25maWd1cmF0aW9uLFxyXG4gICAgY3VzdG9tUGFyYW1zRW5kU2Vzc2lvbj86IHsgW3A6IHN0cmluZ106IHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4gfVxyXG4gICk6IHN0cmluZyB7XHJcbiAgICAvLyBBdXRoMCBuZWVkcyBhIHNwZWNpYWwgbG9nb3V0IHVybFxyXG4gICAgLy8gU2VlIGh0dHBzOi8vYXV0aDAuY29tL2RvY3MvYXBpL2F1dGhlbnRpY2F0aW9uI2xvZ291dFxyXG5cclxuICAgIGlmICh0aGlzLmlzQXV0aDBFbmRwb2ludChjb25maWd1cmF0aW9uKSkge1xyXG4gICAgICByZXR1cm4gdGhpcy5jb21wb3NlQXV0aDBFbmRwb2ludChjb25maWd1cmF0aW9uKTtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBhdXRoV2VsbEtub3duRW5kUG9pbnRzID0gdGhpcy5zdG9yYWdlUGVyc2lzdGVuY2VTZXJ2aWNlLnJlYWQoJ2F1dGhXZWxsS25vd25FbmRQb2ludHMnLCBjb25maWd1cmF0aW9uKTtcclxuICAgIGNvbnN0IGVuZFNlc3Npb25FbmRwb2ludCA9IGF1dGhXZWxsS25vd25FbmRQb2ludHM/LmVuZFNlc3Npb25FbmRwb2ludDtcclxuXHJcbiAgICBpZiAoIWVuZFNlc3Npb25FbmRwb2ludCkge1xyXG4gICAgICByZXR1cm4gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB1cmxQYXJ0cyA9IGVuZFNlc3Npb25FbmRwb2ludC5zcGxpdCgnPycpO1xyXG4gICAgY29uc3QgYXV0aG9yaXphdGlvbkVuZFNlc3Npb25VcmwgPSB1cmxQYXJ0c1swXTtcclxuICAgIGNvbnN0IGV4aXN0aW5nUGFyYW1zID0gdXJsUGFydHNbMV07XHJcbiAgICBsZXQgcGFyYW1zID0gdGhpcy5jcmVhdGVIdHRwUGFyYW1zKGV4aXN0aW5nUGFyYW1zKTtcclxuXHJcbiAgICBpZiAoISFpZFRva2VuSGludCkge1xyXG4gICAgICBwYXJhbXMgPSBwYXJhbXMuc2V0KCdpZF90b2tlbl9oaW50JywgaWRUb2tlbkhpbnQpO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHBvc3RMb2dvdXRSZWRpcmVjdFVyaSA9IHRoaXMuZ2V0UG9zdExvZ291dFJlZGlyZWN0VXJsKGNvbmZpZ3VyYXRpb24pO1xyXG5cclxuICAgIGlmIChwb3N0TG9nb3V0UmVkaXJlY3RVcmkpIHtcclxuICAgICAgcGFyYW1zID0gcGFyYW1zLmFwcGVuZCgncG9zdF9sb2dvdXRfcmVkaXJlY3RfdXJpJywgcG9zdExvZ291dFJlZGlyZWN0VXJpKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoY3VzdG9tUGFyYW1zRW5kU2Vzc2lvbikge1xyXG4gICAgICBwYXJhbXMgPSB0aGlzLmFwcGVuZEN1c3RvbVBhcmFtcyh7IC4uLmN1c3RvbVBhcmFtc0VuZFNlc3Npb24gfSwgcGFyYW1zKTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gYCR7YXV0aG9yaXphdGlvbkVuZFNlc3Npb25Vcmx9PyR7cGFyYW1zfWA7XHJcbiAgfVxyXG5cclxuICBjcmVhdGVSZXZvY2F0aW9uRW5kcG9pbnRCb2R5QWNjZXNzVG9rZW4odG9rZW46IGFueSwgY29uZmlndXJhdGlvbjogT3BlbklkQ29uZmlndXJhdGlvbik6IHN0cmluZyB7XHJcbiAgICBjb25zdCBjbGllbnRJZCA9IHRoaXMuZ2V0Q2xpZW50SWQoY29uZmlndXJhdGlvbik7XHJcblxyXG4gICAgaWYgKCFjbGllbnRJZCkge1xyXG4gICAgICByZXR1cm4gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICBsZXQgcGFyYW1zID0gdGhpcy5jcmVhdGVIdHRwUGFyYW1zKCk7XHJcblxyXG4gICAgcGFyYW1zID0gcGFyYW1zLnNldCgnY2xpZW50X2lkJywgY2xpZW50SWQpO1xyXG4gICAgcGFyYW1zID0gcGFyYW1zLnNldCgndG9rZW4nLCB0b2tlbik7XHJcbiAgICBwYXJhbXMgPSBwYXJhbXMuc2V0KCd0b2tlbl90eXBlX2hpbnQnLCAnYWNjZXNzX3Rva2VuJyk7XHJcblxyXG4gICAgcmV0dXJuIHBhcmFtcy50b1N0cmluZygpO1xyXG4gIH1cclxuXHJcbiAgY3JlYXRlUmV2b2NhdGlvbkVuZHBvaW50Qm9keVJlZnJlc2hUb2tlbih0b2tlbjogYW55LCBjb25maWd1cmF0aW9uOiBPcGVuSWRDb25maWd1cmF0aW9uKTogc3RyaW5nIHtcclxuICAgIGNvbnN0IGNsaWVudElkID0gdGhpcy5nZXRDbGllbnRJZChjb25maWd1cmF0aW9uKTtcclxuXHJcbiAgICBpZiAoIWNsaWVudElkKSB7XHJcbiAgICAgIHJldHVybiBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIGxldCBwYXJhbXMgPSB0aGlzLmNyZWF0ZUh0dHBQYXJhbXMoKTtcclxuXHJcbiAgICBwYXJhbXMgPSBwYXJhbXMuc2V0KCdjbGllbnRfaWQnLCBjbGllbnRJZCk7XHJcbiAgICBwYXJhbXMgPSBwYXJhbXMuc2V0KCd0b2tlbicsIHRva2VuKTtcclxuICAgIHBhcmFtcyA9IHBhcmFtcy5zZXQoJ3Rva2VuX3R5cGVfaGludCcsICdyZWZyZXNoX3Rva2VuJyk7XHJcblxyXG4gICAgcmV0dXJuIHBhcmFtcy50b1N0cmluZygpO1xyXG4gIH1cclxuXHJcbiAgZ2V0UmV2b2NhdGlvbkVuZHBvaW50VXJsKGNvbmZpZ3VyYXRpb246IE9wZW5JZENvbmZpZ3VyYXRpb24pOiBzdHJpbmcge1xyXG4gICAgY29uc3QgYXV0aFdlbGxLbm93bkVuZFBvaW50cyA9IHRoaXMuc3RvcmFnZVBlcnNpc3RlbmNlU2VydmljZS5yZWFkKCdhdXRoV2VsbEtub3duRW5kUG9pbnRzJywgY29uZmlndXJhdGlvbik7XHJcbiAgICBjb25zdCByZXZvY2F0