@kephas/ngx-oidc
Version:
Provides the integration of the OIDC API with Kephas and Angular 12+.
125 lines • 19.9 kB
JavaScript
import { Component } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { BehaviorSubject } from 'rxjs';
import { AuthenticationResultStatus, AuthenticationService } from '../authentication.service';
import { AuthenticationSettingsProvider, LoginActions, QueryParameterNames } from '../authentication.settings';
import * as i0 from "@angular/core";
import * as i1 from "../authentication.service";
import * as i2 from "@angular/router";
import * as i3 from "../authentication.settings";
import * as i4 from "@angular/common";
// The main responsibility of this component is to handle the user's login process.
// This is the starting point for the login process. Any component that needs to authenticate
// a user can simply perform a redirect to this component with a returnUrl query parameter and
// let the component perform the login and return back to the return url.
export class LoginComponent {
constructor(authenticationService, activatedRoute, router, authSettingsProvider) {
this.authenticationService = authenticationService;
this.activatedRoute = activatedRoute;
this.router = router;
this.authSettingsProvider = authSettingsProvider;
this.message = new BehaviorSubject(null);
}
async ngOnInit() {
const action = this.activatedRoute.snapshot.url[1];
switch (action.path) {
case LoginActions.Login:
await this.login(this.getReturnUrl());
break;
case LoginActions.LoginCallback:
await this.processLoginCallback();
break;
case LoginActions.LoginFailed:
const message = this.activatedRoute.snapshot.queryParamMap.get(QueryParameterNames.Message);
this.message.next(message);
break;
case LoginActions.Profile:
this.redirectToProfile();
break;
case LoginActions.Register:
this.redirectToRegister();
break;
default:
throw new Error(`Invalid action '${action}'`);
}
}
async login(returnUrl) {
const state = { returnUrl };
const result = await this.authenticationService.signIn(state);
this.message.next(null);
const applicationPaths = this.authSettingsProvider.settings.applicationPaths;
switch (result.status) {
case AuthenticationResultStatus.Redirect:
break;
case AuthenticationResultStatus.Success:
await this.navigateToReturnUrl(returnUrl);
break;
case AuthenticationResultStatus.Fail:
await this.router.navigate(applicationPaths.LoginFailedPathComponents, {
queryParams: { [QueryParameterNames.Message]: result.message }
});
break;
default:
throw new Error(`Invalid status result ${result.status}.`);
}
}
async processLoginCallback() {
const url = window.location.href;
const result = await this.authenticationService.completeSignIn(url);
switch (result.status) {
case AuthenticationResultStatus.Redirect:
// There should not be any redirects as completeSignIn never redirects.
throw new Error('Should not redirect.');
case AuthenticationResultStatus.Success:
await this.navigateToReturnUrl(this.getReturnUrl(result.state));
break;
case AuthenticationResultStatus.Fail:
this.message.next(result.message);
break;
}
}
redirectToRegister() {
const applicationPaths = this.authSettingsProvider.settings.applicationPaths;
this.redirectToApiAuthorizationPath(`${applicationPaths.IdentityRegisterPath}?returnUrl=${encodeURI('/' + applicationPaths.Login)}`);
}
redirectToProfile() {
const applicationPaths = this.authSettingsProvider.settings.applicationPaths;
this.redirectToApiAuthorizationPath(applicationPaths.IdentityManagePath);
}
async navigateToReturnUrl(returnUrl) {
// It's important that we do a replace here so that we remove the callback uri with the
// fragment containing the tokens from the browser history.
await this.router.navigateByUrl(returnUrl, {
replaceUrl: true
});
}
getReturnUrl(state) {
const applicationPaths = this.authSettingsProvider.settings.applicationPaths;
const fromQuery = this.activatedRoute.snapshot.queryParams.returnUrl;
// If the url is comming from the query string, check that is either
// a relative url or an absolute url
if (fromQuery &&
!(fromQuery.startsWith(`${window.location.origin}/`) ||
/\/[^\/].*/.test(fromQuery))) {
// This is an extra check to prevent open redirects.
throw new Error('Invalid return url. The return url needs to have the same origin as the current page.');
}
return (state && state.returnUrl) ||
fromQuery ||
applicationPaths.DefaultLoginRedirectPath;
}
redirectToApiAuthorizationPath(apiAuthorizationPath) {
// It's important that we do a replace here so that when the user hits the back arrow on the
// browser they get sent back to where it was on the app instead of to an endpoint on this
// component.
const redirectUrl = `${window.location.origin}${apiAuthorizationPath}`;
window.location.replace(redirectUrl);
}
}
LoginComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.0", ngImport: i0, type: LoginComponent, deps: [{ token: i1.AuthenticationService }, { token: i2.ActivatedRoute }, { token: i2.Router }, { token: i3.AuthenticationSettingsProvider }], target: i0.ɵɵFactoryTarget.Component });
LoginComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.1.0", type: LoginComponent, selector: "app-login", ngImport: i0, template: "<p>{{ message | async }}</p>", styles: [""], pipes: { "async": i4.AsyncPipe } });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.0", ngImport: i0, type: LoginComponent, decorators: [{
type: Component,
args: [{ selector: 'app-login', template: "<p>{{ message | async }}</p>", styles: [""] }]
}], ctorParameters: function () { return [{ type: i1.AuthenticationService }, { type: i2.ActivatedRoute }, { type: i2.Router }, { type: i3.AuthenticationSettingsProvider }]; } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9naW4uY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMva2VwaGFzL25neC1vaWRjL3NyYy9saWIvbG9naW4vbG9naW4uY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMva2VwaGFzL25neC1vaWRjL3NyYy9saWIvbG9naW4vbG9naW4uY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBVSxNQUFNLGVBQWUsQ0FBQztBQUNsRCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ3pELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDdkMsT0FBTyxFQUFFLDBCQUEwQixFQUFFLHFCQUFxQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDOUYsT0FBTyxFQUFFLDhCQUE4QixFQUFFLFlBQVksRUFBRSxtQkFBbUIsRUFBRSxNQUFNLDRCQUE0QixDQUFDOzs7Ozs7QUFHL0csbUZBQW1GO0FBQ25GLDZGQUE2RjtBQUM3Riw4RkFBOEY7QUFDOUYseUVBQXlFO0FBTXpFLE1BQU0sT0FBTyxjQUFjO0lBR3pCLFlBQ1UscUJBQTRDLEVBQzVDLGNBQThCLEVBQzlCLE1BQWMsRUFDZCxvQkFBb0Q7UUFIcEQsMEJBQXFCLEdBQXJCLHFCQUFxQixDQUF1QjtRQUM1QyxtQkFBYyxHQUFkLGNBQWMsQ0FBZ0I7UUFDOUIsV0FBTSxHQUFOLE1BQU0sQ0FBUTtRQUNkLHlCQUFvQixHQUFwQixvQkFBb0IsQ0FBZ0M7UUFOdkQsWUFBTyxHQUFHLElBQUksZUFBZSxDQUF3QixJQUFJLENBQUMsQ0FBQztJQU1BLENBQUM7SUFFbkUsS0FBSyxDQUFDLFFBQVE7UUFDWixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxD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QXVGLENBQUMsQ0FBQztTQUMxRztRQUNELE9BQU8sQ0FBQyxLQUFLLElBQUksS0FBSyxDQUFDLFNBQVMsQ0FBQztZQUMvQixTQUFTO1lBQ1QsZ0JBQWdCLENBQUMsd0JBQXdCLENBQUM7SUFDOUMsQ0FBQztJQUVPLDhCQUE4QixDQUFDLG9CQUE0QjtRQUNqRSw0RkFBNEY7UUFDNUYsMEZBQTBGO1FBQzFGLGFBQWE7UUFDYixNQUFNLFdBQVcsR0FBRyxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUMsTUFBTSxHQUFHLG9CQUFvQixFQUFFLENBQUM7UUFDdkUsTUFBTSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDdkMsQ0FBQzs7MkdBaEhVLGNBQWM7K0ZBQWQsY0FBYyxpRENoQjNCLDhCQUE0QjsyRkRnQmYsY0FBYztrQkFMMUIsU0FBUzsrQkFDRSxXQUFXIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBPbkluaXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgQWN0aXZhdGVkUm91dGUsIFJvdXRlciB9IGZyb20gJ0Bhbmd1bGFyL3JvdXRlcic7XHJcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCB9IGZyb20gJ3J4anMnO1xyXG5pbXBvcnQgeyBBdXRoZW50aWNhdGlvblJlc3VsdFN0YXR1cywgQXV0aGVudGljYXRpb25TZXJ2aWNlIH0gZnJvbSAnLi4vYXV0aGVudGljYXRpb24uc2VydmljZSc7XHJcbmltcG9ydCB7IEF1dGhlbnRpY2F0aW9uU2V0dGluZ3NQcm92aWRlciwgTG9naW5BY3Rpb25zLCBRdWVyeVBhcmFtZXRlck5hbWVzIH0gZnJvbSAnLi4vYXV0aGVudGljYXRpb24uc2V0dGluZ3MnO1xyXG5pbXBvcnQgeyBOYXZpZ2F0aW9uU3RhdGUgfSBmcm9tICcuLi9uYXZpZ2F0aW9uU3RhdGUnO1xyXG5cclxuLy8gVGhlIG1haW4gcmVzcG9uc2liaWxpdHkgb2YgdGhpcyBjb21wb25lbnQgaXMgdG8gaGFuZGxlIHRoZSB1c2VyJ3MgbG9naW4gcHJvY2Vzcy5cclxuLy8gVGhpcyBpcyB0aGUgc3RhcnRpbmcgcG9pbnQgZm9yIHRoZSBsb2dpbiBwcm9jZXNzLiBBbnkgY29tcG9uZW50IHRoYXQgbmVlZHMgdG8gYXV0aGVudGljYXRlXHJcbi8vIGEgdXNlciBjYW4gc2ltcGx5IHBlcmZvcm0gYSByZWRpcmVjdCB0byB0aGlzIGNvbXBvbmVudCB3aXRoIGEgcmV0dXJuVXJsIHF1ZXJ5IHBhcmFtZXRlciBhbmRcclxuLy8gbGV0IHRoZSBjb21wb25lbnQgcGVyZm9ybSB0aGUgbG9naW4gYW5kIHJldHVybiBiYWNrIHRvIHRoZSByZXR1cm4gdXJsLlxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ2FwcC1sb2dpbicsXHJcbiAgdGVtcGxhdGVVcmw6ICcuL2xvZ2luLmNvbXBvbmVudC5odG1sJyxcclxuICBzdHlsZVVybHM6IFsnLi9sb2dpbi5jb21wb25lbnQuY3NzJ11cclxufSlcclxuZXhwb3J0IGNsYXNzIExvZ2luQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0IHtcclxuICBwdWJsaWMgbWVzc2FnZSA9IG5ldyBCZWhhdmlvclN1YmplY3Q8c3RyaW5nIHwgRXJyb3IgfCBudWxsPihudWxsKTtcclxuXHJcbiAgY29uc3RydWN0b3IoXHJcbiAgICBwcml2YXRlIGF1dGhlbnRpY2F0aW9uU2VydmljZTogQXV0aGVudGljYXRpb25TZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSBhY3RpdmF0ZWRSb3V0ZTogQWN0aXZhdGVkUm91dGUsXHJcbiAgICBwcml2YXRlIHJvdXRlcjogUm91dGVyLFxyXG4gICAgcHJpdmF0ZSBhdXRoU2V0dGluZ3NQcm92aWRlcjogQXV0aGVudGljYXRpb25TZXR0aW5nc1Byb3ZpZGVyKSB7IH1cclxuXHJcbiAgYXN5bmMgbmdPbkluaXQoKSB7XHJcbiAgICBjb25zdCBhY3Rpb24gPSB0aGlzLmFjdGl2YXRlZFJvdXRlLnNuYXBzaG90LnVybFsxXTtcclxuICAgIHN3aXRjaCAoYWN0aW9uLnBhdGgpIHtcclxuICAgICAgY2FzZSBMb2dpbkFjdGlvbnMuTG9naW46XHJcbiAgICAgICAgYXdhaXQgdGhpcy5sb2dpbih0aGlzLmdldFJldHVyblVybCgpKTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgY2FzZSBMb2dpbkFjdGlvbnMuTG9naW5DYWxsYmFjazpcclxuICAgICAgICBhd2FpdCB0aGlzLnByb2Nlc3NMb2dpbkNhbGxiYWNrKCk7XHJcbiAgICAgICAgYnJlYWs7XHJcbiAgICAgIGNhc2UgTG9naW5BY3Rpb25zLkxvZ2luRmFpbGVkOlxyXG4gICAgICAgIGNvbnN0IG1lc3NhZ2UgPSB0aGlzLmFjdGl2YXRlZFJvdXRlLnNuYXBzaG90LnF1ZXJ5UGFyYW1NYXAuZ2V0KFF1ZXJ5UGFyYW1ldGVyTmFtZXMuTWVzc2FnZSk7XHJcbiAgICAgICAgdGhpcy5tZXNzYWdlLm5leHQobWVzc2FnZSk7XHJcbiAgICAgICAgYnJlYWs7XHJcbiAgICAgIGNhc2UgTG9naW5BY3Rpb25zLlByb2ZpbGU6XHJcbiAgICAgICAgdGhpcy5yZWRpcmVjdFRvUHJvZmlsZSgpO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICBjYXNlIExvZ2luQWN0aW9ucy5SZWdpc3RlcjpcclxuICAgICAgICB0aGlzLnJlZGlyZWN0VG9SZWdpc3RlcigpO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICBkZWZhdWx0OlxyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBhY3Rpb24gJyR7YWN0aW9ufSdgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgYXN5bmMgbG9naW4ocmV0dXJuVXJsOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgIGNvbnN0IHN0YXRlOiBOYXZpZ2F0aW9uU3RhdGUgPSB7IHJldHVyblVybCB9O1xyXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5hdXRoZW50aWNhdGlvblNlcnZpY2Uuc2lnbkluKHN0YXRlKTtcclxuICAgIHRoaXMubWVzc2FnZS5uZXh0KG51bGwpO1xyXG5cclxuICAgIGNvbnN0IGFwcGxpY2F0aW9uUGF0aHMgPSB0aGlzLmF1dGhTZXR0aW5nc1Byb3ZpZGVyLnNldHRpbmdzLmFwcGxpY2F0aW9uUGF0aHM7XHJcbiAgICBzd2l0Y2ggKHJlc3VsdC5zdGF0dXMpIHtcclxuICAgICAgY2FzZSBBdXRoZW50aWNhdGlvblJlc3VsdFN0YXR1cy5SZWRpcmVjdDpcclxuICAgICAgICBicmVhaztcclxuICAgICAgY2FzZSBBdXRoZW50aWNhdGlvblJlc3VsdFN0YXR1cy5TdWNjZXNzOlxyXG4gICAgICAgIGF3YWl0IHRoaXMubmF2aWdhdGVUb1JldHVyblVybChyZXR1cm5VcmwpO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICBjYXNlIEF1dGhlbnRpY2F0aW9uUmVzdWx0U3RhdHVzLkZhaWw6XHJcbiAgICAgICAgYXdhaXQgdGhpcy5yb3V0ZXIubmF2aWdhdGUoYXBwbGljYXRpb25QYXRocy5Mb2dpbkZhaWxlZFBhdGhDb21wb25lbnRzLCB7XHJcbiAgICAgICAgICBxdWVyeVBhcmFtczogeyBbUXVlcnlQYXJhbWV0ZXJOYW1lcy5NZXNzYWdlXTogcmVzdWx0Lm1lc3NhZ2UgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICBkZWZhdWx0OlxyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBzdGF0dXMgcmVzdWx0ICR7KHJlc3VsdCBhcyBhbnkpLnN0YXR1c30uYCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGFzeW5jIHByb2Nlc3NMb2dpbkNhbGxiYWNrKCk6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgY29uc3QgdXJsID0gd2luZG93LmxvY2F0aW9uLmhyZWY7XHJcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLmF1dGhlbnRpY2F0aW9uU2VydmljZS5jb21wbGV0ZVNpZ25Jbih1cmwpO1xyXG4gICAgc3dpdGNoIChyZXN1bHQuc3RhdHVzKSB7XHJcbiAgICAgIGNhc2UgQXV0aGVudGljYXRpb25SZXN1bHRTdGF0dXMuUmVkaXJlY3Q6XHJcbiAgICAgICAgLy8gVGhlcmUgc2hvdWxkIG5vdCBiZSBhbnkgcmVkaXJlY3RzIGFzIGNvbXBsZXRlU2lnbkluIG5ldmVyIHJlZGlyZWN0cy5cclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1Nob3VsZCBub3QgcmVkaXJlY3QuJyk7XHJcbiAgICAgIGNhc2UgQXV0aGVudGljYXRpb25SZXN1bHRTdGF0dXMuU3VjY2VzczpcclxuICAgICAgICBhd2FpdCB0aGlzLm5hdmlnYXRlVG9SZXR1cm5VcmwodGhpcy5nZXRSZXR1cm5VcmwocmVzdWx0LnN0YXRlKSk7XHJcbiAgICAgICAgYnJlYWs7XHJcbiAgICAgIGNhc2UgQXV0aGVudGljYXRpb25SZXN1bHRTdGF0dXMuRmFpbDpcclxuICAgICAgICB0aGlzLm1lc3NhZ2UubmV4dChyZXN1bHQubWVzc2FnZSk7XHJcbiAgICAgICAgYnJlYWs7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHJlZGlyZWN0VG9SZWdpc3RlcigpOiBhbnkge1xyXG4gICAgY29uc3QgYXBwbGljYXRpb25QYXRocyA9IHRoaXMuYXV0aFNldHRpbmdzUHJvdmlkZXIuc2V0dGluZ3MuYXBwbGljYXRpb25QYXRocztcclxuICAgIHRoaXMucmVkaXJlY3RUb0FwaUF1dGhvcml6YXRpb25QYXRoKFxyXG4gICAgICBgJHthcHBsaWNhdGlvblBhdGhzLklkZW50aXR5UmVnaXN0ZXJQYXRofT9yZXR1cm5Vcmw9JHtlbmNvZGVVUkkoJy8nICsgYXBwbGljYXRpb25QYXRocy5Mb2dpbil9YCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHJlZGlyZWN0VG9Qcm9maWxlKCk6IHZvaWQge1xyXG4gICAgY29uc3QgYXBwbGljYXRpb25QYXRocyA9IHRoaXMuYXV0aFNldHRpbmdzUHJvdmlkZXIuc2V0dGluZ3MuYXBwbGljYXRpb25QYXRocztcclxuICAgIHRoaXMucmVkaXJlY3RUb0FwaUF1dGhvcml6YXRpb25QYXRoKGFwcGxpY2F0aW9uUGF0aHMuSWRlbnRpdHlNYW5hZ2VQYXRoKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgYXN5bmMgbmF2aWdhdGVUb1JldHVyblVybChyZXR1cm5Vcmw6IHN0cmluZykge1xyXG4gICAgLy8gSXQncyBpbXBvcnRhbnQgdGhhdCB3ZSBkbyBhIHJlcGxhY2UgaGVyZSBzbyB0aGF0IHdlIHJlbW92ZSB0aGUgY2FsbGJhY2sgdXJpIHdpdGggdGhlXHJcbiAgICAvLyBmcmFnbWVudCBjb250YWluaW5nIHRoZSB0b2tlbnMgZnJvbSB0aGUgYnJvd3NlciBoaXN0b3J5LlxyXG4gICAgYXdhaXQgdGhpcy5yb3V0ZXIubmF2aWdhdGVCeVVybChyZXR1cm5VcmwsIHtcclxuICAgICAgcmVwbGFjZVVybDogdHJ1ZVxyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGdldFJldHVyblVybChzdGF0ZT86IE5hdmlnYXRpb25TdGF0ZSk6IHN0cmluZyB7XHJcbiAgICBjb25zdCBhcHBsaWNhdGlvblBhdGhzID0gdGhpcy5hdXRoU2V0dGluZ3NQcm92aWRlci5zZXR0aW5ncy5hcHBsaWNhdGlvblBhdGhzO1xyXG4gICAgY29uc3QgZnJvbVF1ZXJ5ID0gKHRoaXMuYWN0aXZhdGVkUm91dGUuc25hcHNob3QucXVlcnlQYXJhbXMgYXMgTmF2aWdhdGlvblN0YXRlKS5yZXR1cm5Vcmw7XHJcbiAgICAvLyBJZiB0aGUgdXJsIGlzIGNvbW1pbmcgZnJvbSB0aGUgcXVlcnkgc3RyaW5nLCBjaGVjayB0aGF0IGlzIGVpdGhlclxyXG4gICAgLy8gYSByZWxhdGl2ZSB1cmwgb3IgYW4gYWJzb2x1dGUgdXJsXHJcbiAgICBpZiAoZnJvbVF1ZXJ5ICYmXHJcbiAgICAgICEoZnJvbVF1ZXJ5LnN0YXJ0c1dpdGgoYCR7d2luZG93LmxvY2F0aW9uLm9yaWdpbn0vYCkgfHxcclxuICAgICAgICAvXFwvW15cXC9dLiovLnRlc3QoZnJvbVF1ZXJ5KSkpIHtcclxuICAgICAgLy8gVGhpcyBpcyBhbiBleHRyYSBjaGVjayB0byBwcmV2ZW50IG9wZW4gcmVkaXJlY3RzLlxyXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgcmV0dXJuIHVybC4gVGhlIHJldHVybiB1cmwgbmVlZHMgdG8gaGF2ZSB0aGUgc2FtZSBvcmlnaW4gYXMgdGhlIGN1cnJlbnQgcGFnZS4nKTtcclxuICAgIH1cclxuICAgIHJldHVybiAoc3RhdGUgJiYgc3RhdGUucmV0dXJuVXJsKSB8fFxyXG4gICAgICBmcm9tUXVlcnkgfHxcclxuICAgICAgYXBwbGljYXRpb25QYXRocy5EZWZhdWx0TG9naW5SZWRpcmVjdFBhdGg7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHJlZGlyZWN0VG9BcGlBdXRob3JpemF0aW9uUGF0aChhcGlBdXRob3JpemF0aW9uUGF0aDogc3RyaW5nKSB7XHJcbiAgICAvLyBJdCdzIGltcG9ydGFudCB0aGF0IHdlIGRvIGEgcmVwbGFjZSBoZXJlIHNvIHRoYXQgd2hlbiB0aGUgdXNlciBoaXRzIHRoZSBiYWNrIGFycm93IG9uIHRoZVxyXG4gICAgLy8gYnJvd3NlciB0aGV5IGdldCBzZW50IGJhY2sgdG8gd2hlcmUgaXQgd2FzIG9uIHRoZSBhcHAgaW5zdGVhZCBvZiB0byBhbiBlbmRwb2ludCBvbiB0aGlzXHJcbiAgICAvLyBjb21wb25lbnQuXHJcbiAgICBjb25zdCByZWRpcmVjdFVybCA9IGAke3dpbmRvdy5sb2NhdGlvbi5vcmlnaW59JHthcGlBdXRob3JpemF0aW9uUGF0aH1gO1xyXG4gICAgd2luZG93LmxvY2F0aW9uLnJlcGxhY2UocmVkaXJlY3RVcmwpO1xyXG4gIH1cclxufVxyXG4iLCI8cD57eyBtZXNzYWdlIHwgYXN5bmMgfX08L3A+Il19