@nauth-toolkit/client-angular 0.1.58 → 0.1.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/lib/auth.guard.mjs +58 -23
- package/esm2022/lib/social-redirect-callback.guard.mjs +28 -24
- package/esm2022/ngmodule/auth.service.mjs +40 -1
- package/esm2022/ngmodule/nauth.module.mjs +4 -1
- package/esm2022/standalone/nauth-toolkit-client-angular-standalone.mjs +1 -1
- package/esm2022/standalone/public-api.mjs +6 -10
- package/fesm2022/nauth-toolkit-client-angular-standalone.mjs +5 -1217
- package/fesm2022/nauth-toolkit-client-angular-standalone.mjs.map +1 -1
- package/fesm2022/nauth-toolkit-client-angular.mjs +181 -103
- package/fesm2022/nauth-toolkit-client-angular.mjs.map +1 -1
- package/lib/auth.guard.d.ts +39 -16
- package/lib/social-redirect-callback.guard.d.ts +2 -2
- package/ngmodule/auth.service.d.ts +36 -1
- package/package.json +2 -2
- package/standalone/public-api.d.ts +4 -7
- package/esm2022/standalone/auth.guard.mjs +0 -83
- package/esm2022/standalone/auth.interceptor.mjs +0 -158
- package/esm2022/standalone/auth.service.mjs +0 -777
- package/esm2022/standalone/http-adapter.mjs +0 -127
- package/esm2022/standalone/social-redirect-callback.guard.mjs +0 -81
- package/esm2022/standalone/tokens.mjs +0 -6
- package/standalone/auth.guard.d.ts +0 -64
- package/standalone/auth.interceptor.d.ts +0 -15
- package/standalone/auth.service.d.ts +0 -580
- package/standalone/http-adapter.d.ts +0 -53
- package/standalone/social-redirect-callback.guard.d.ts +0 -25
- package/standalone/tokens.d.ts +0 -6
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import { inject } from '@angular/core';
|
|
2
|
-
import { Router } from '@angular/router';
|
|
3
|
-
import { AuthService } from './auth.service';
|
|
4
|
-
/**
|
|
5
|
-
* Functional route guard for authentication (Angular 17+).
|
|
6
|
-
*
|
|
7
|
-
* Protects routes by checking if user is authenticated.
|
|
8
|
-
* Redirects to login page if not authenticated.
|
|
9
|
-
*
|
|
10
|
-
* @param redirectTo - Path to redirect to if not authenticated (default: '/login')
|
|
11
|
-
* @returns CanActivateFn guard function
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* ```typescript
|
|
15
|
-
* // In route configuration
|
|
16
|
-
* const routes: Routes = [
|
|
17
|
-
* {
|
|
18
|
-
* path: 'home',
|
|
19
|
-
* component: HomeComponent,
|
|
20
|
-
* canActivate: [authGuard()]
|
|
21
|
-
* },
|
|
22
|
-
* {
|
|
23
|
-
* path: 'admin',
|
|
24
|
-
* component: AdminComponent,
|
|
25
|
-
* canActivate: [authGuard('/admin/login')]
|
|
26
|
-
* }
|
|
27
|
-
* ];
|
|
28
|
-
* ```
|
|
29
|
-
*/
|
|
30
|
-
export function authGuard(redirectTo = '/login') {
|
|
31
|
-
return () => {
|
|
32
|
-
const auth = inject(AuthService);
|
|
33
|
-
const router = inject(Router);
|
|
34
|
-
if (auth.isAuthenticated()) {
|
|
35
|
-
return true;
|
|
36
|
-
}
|
|
37
|
-
return router.createUrlTree([redirectTo]);
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Class-based authentication guard for NgModule compatibility.
|
|
42
|
-
*
|
|
43
|
-
* @example
|
|
44
|
-
* ```typescript
|
|
45
|
-
* // In route configuration (NgModule)
|
|
46
|
-
* const routes: Routes = [
|
|
47
|
-
* {
|
|
48
|
-
* path: 'home',
|
|
49
|
-
* component: HomeComponent,
|
|
50
|
-
* canActivate: [AuthGuard]
|
|
51
|
-
* }
|
|
52
|
-
* ];
|
|
53
|
-
*
|
|
54
|
-
* // In module providers
|
|
55
|
-
* @NgModule({
|
|
56
|
-
* providers: [AuthGuard]
|
|
57
|
-
* })
|
|
58
|
-
* ```
|
|
59
|
-
*/
|
|
60
|
-
export class AuthGuard {
|
|
61
|
-
auth;
|
|
62
|
-
router;
|
|
63
|
-
/**
|
|
64
|
-
* @param auth - Authentication service
|
|
65
|
-
* @param router - Angular router
|
|
66
|
-
*/
|
|
67
|
-
constructor(auth, router) {
|
|
68
|
-
this.auth = auth;
|
|
69
|
-
this.router = router;
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Check if route can be activated.
|
|
73
|
-
*
|
|
74
|
-
* @returns True if authenticated, otherwise redirects to login
|
|
75
|
-
*/
|
|
76
|
-
canActivate() {
|
|
77
|
-
if (this.auth.isAuthenticated()) {
|
|
78
|
-
return true;
|
|
79
|
-
}
|
|
80
|
-
return this.router.createUrlTree(['/login']);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC5ndWFyZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3N0YW5kYWxvbmUvYXV0aC5ndWFyZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3ZDLE9BQU8sRUFBaUIsTUFBTSxFQUFXLE1BQU0saUJBQWlCLENBQUM7QUFDakUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRTdDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBeUJHO0FBQ0gsTUFBTSxVQUFVLFNBQVMsQ0FBQyxVQUFVLEdBQUcsUUFBUTtJQUM3QyxPQUFPLEdBQXNCLEVBQUU7UUFDN0IsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQ2pDLE1BQU0sTUFBTSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUU5QixJQUFJLElBQUksQ0FBQyxlQUFlLEVBQUUsRUFBRSxDQUFDO1lBQzNCLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUVELE9BQU8sTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7SUFDNUMsQ0FBQyxDQUFDO0FBQ0osQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBbUJHO0FBQ0gsTUFBTSxPQUFPLFNBQVM7SUFNVjtJQUNBO0lBTlY7OztPQUdHO0lBQ0gsWUFDVSxJQUFpQixFQUNqQixNQUFjO1FBRGQsU0FBSSxHQUFKLElBQUksQ0FBYTtRQUNqQixXQUFNLEdBQU4sTUFBTSxDQUFRO0lBQ3JCLENBQUM7SUFFSjs7OztPQUlHO0lBQ0gsV0FBVztRQUNULElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxlQUFlLEVBQUUsRUFBRSxDQUFDO1lBQ2hDLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUVELE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDO0lBQy9DLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGluamVjdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQ2FuQWN0aXZhdGVGbiwgUm91dGVyLCBVcmxUcmVlIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcbmltcG9ydCB7IEF1dGhTZXJ2aWNlIH0gZnJvbSAnLi9hdXRoLnNlcnZpY2UnO1xuXG4vKipcbiAqIEZ1bmN0aW9uYWwgcm91dGUgZ3VhcmQgZm9yIGF1dGhlbnRpY2F0aW9uIChBbmd1bGFyIDE3KykuXG4gKlxuICogUHJvdGVjdHMgcm91dGVzIGJ5IGNoZWNraW5nIGlmIHVzZXIgaXMgYXV0aGVudGljYXRlZC5cbiAqIFJlZGlyZWN0cyB0byBsb2dpbiBwYWdlIGlmIG5vdCBhdXRoZW50aWNhdGVkLlxuICpcbiAqIEBwYXJhbSByZWRpcmVjdFRvIC0gUGF0aCB0byByZWRpcmVjdCB0byBpZiBub3QgYXV0aGVudGljYXRlZCAoZGVmYXVsdDogJy9sb2dpbicpXG4gKiBAcmV0dXJucyBDYW5BY3RpdmF0ZUZuIGd1YXJkIGZ1bmN0aW9uXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIC8vIEluIHJvdXRlIGNvbmZpZ3VyYXRpb25cbiAqIGNvbnN0IHJvdXRlczogUm91dGVzID0gW1xuICogICB7XG4gKiAgICAgcGF0aDogJ2hvbWUnLFxuICogICAgIGNvbXBvbmVudDogSG9tZUNvbXBvbmVudCxcbiAqICAgICBjYW5BY3RpdmF0ZTogW2F1dGhHdWFyZCgpXVxuICogICB9LFxuICogICB7XG4gKiAgICAgcGF0aDogJ2FkbWluJyxcbiAqICAgICBjb21wb25lbnQ6IEFkbWluQ29tcG9uZW50LFxuICogICAgIGNhbkFjdGl2YXRlOiBbYXV0aEd1YXJkKCcvYWRtaW4vbG9naW4nKV1cbiAqICAgfVxuICogXTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gYXV0aEd1YXJkKHJlZGlyZWN0VG8gPSAnL2xvZ2luJyk6IENhbkFjdGl2YXRlRm4ge1xuICByZXR1cm4gKCk6IGJvb2xlYW4gfCBVcmxUcmVlID0+IHtcbiAgICBjb25zdCBhdXRoID0gaW5qZWN0KEF1dGhTZXJ2aWNlKTtcbiAgICBjb25zdCByb3V0ZXIgPSBpbmplY3QoUm91dGVyKTtcblxuICAgIGlmIChhdXRoLmlzQXV0aGVudGljYXRlZCgpKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICByZXR1cm4gcm91dGVyLmNyZWF0ZVVybFRyZWUoW3JlZGlyZWN0VG9dKTtcbiAgfTtcbn1cblxuLyoqXG4gKiBDbGFzcy1iYXNlZCBhdXRoZW50aWNhdGlvbiBndWFyZCBmb3IgTmdNb2R1bGUgY29tcGF0aWJpbGl0eS5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gSW4gcm91dGUgY29uZmlndXJhdGlvbiAoTmdNb2R1bGUpXG4gKiBjb25zdCByb3V0ZXM6IFJvdXRlcyA9IFtcbiAqICAge1xuICogICAgIHBhdGg6ICdob21lJyxcbiAqICAgICBjb21wb25lbnQ6IEhvbWVDb21wb25lbnQsXG4gKiAgICAgY2FuQWN0aXZhdGU6IFtBdXRoR3VhcmRdXG4gKiAgIH1cbiAqIF07XG4gKlxuICogLy8gSW4gbW9kdWxlIHByb3ZpZGVyc1xuICogQE5nTW9kdWxlKHtcbiAqICAgcHJvdmlkZXJzOiBbQXV0aEd1YXJkXVxuICogfSlcbiAqIGBgYFxuICovXG5leHBvcnQgY2xhc3MgQXV0aEd1YXJkIHtcbiAgLyoqXG4gICAqIEBwYXJhbSBhdXRoIC0gQXV0aGVudGljYXRpb24gc2VydmljZVxuICAgKiBAcGFyYW0gcm91dGVyIC0gQW5ndWxhciByb3V0ZXJcbiAgICovXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgYXV0aDogQXV0aFNlcnZpY2UsXG4gICAgcHJpdmF0ZSByb3V0ZXI6IFJvdXRlcixcbiAgKSB7fVxuXG4gIC8qKlxuICAgKiBDaGVjayBpZiByb3V0ZSBjYW4gYmUgYWN0aXZhdGVkLlxuICAgKlxuICAgKiBAcmV0dXJucyBUcnVlIGlmIGF1dGhlbnRpY2F0ZWQsIG90aGVyd2lzZSByZWRpcmVjdHMgdG8gbG9naW5cbiAgICovXG4gIGNhbkFjdGl2YXRlKCk6IGJvb2xlYW4gfCBVcmxUcmVlIHtcbiAgICBpZiAodGhpcy5hdXRoLmlzQXV0aGVudGljYXRlZCgpKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5yb3V0ZXIuY3JlYXRlVXJsVHJlZShbJy9sb2dpbiddKTtcbiAgfVxufVxuIl19
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
import { inject, PLATFORM_ID } from '@angular/core';
|
|
2
|
-
import { isPlatformBrowser } from '@angular/common';
|
|
3
|
-
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
|
|
4
|
-
import { Router } from '@angular/router';
|
|
5
|
-
import { catchError, switchMap, throwError, filter, take, BehaviorSubject, from } from 'rxjs';
|
|
6
|
-
import { NAUTH_CLIENT_CONFIG } from './tokens';
|
|
7
|
-
import { AuthService } from './auth.service';
|
|
8
|
-
/**
|
|
9
|
-
* Refresh state management.
|
|
10
|
-
* BehaviorSubject pattern is the industry-standard for token refresh.
|
|
11
|
-
*/
|
|
12
|
-
let isRefreshing = false;
|
|
13
|
-
const refreshTokenSubject = new BehaviorSubject(null);
|
|
14
|
-
/**
|
|
15
|
-
* Track retried requests to prevent infinite loops.
|
|
16
|
-
*/
|
|
17
|
-
const retriedRequests = new WeakSet();
|
|
18
|
-
/**
|
|
19
|
-
* Get CSRF token from cookie.
|
|
20
|
-
*/
|
|
21
|
-
function getCsrfToken(cookieName) {
|
|
22
|
-
if (typeof document === 'undefined')
|
|
23
|
-
return null;
|
|
24
|
-
const match = document.cookie.match(new RegExp(`(^| )${cookieName}=([^;]+)`));
|
|
25
|
-
return match ? decodeURIComponent(match[2]) : null;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Angular HTTP interceptor for nauth-toolkit.
|
|
29
|
-
*
|
|
30
|
-
* Handles:
|
|
31
|
-
* - Cookies mode: withCredentials + CSRF tokens + refresh via POST
|
|
32
|
-
* - JSON mode: refresh via SDK, retry with new token
|
|
33
|
-
*/
|
|
34
|
-
export const authInterceptor = (req, next) => {
|
|
35
|
-
const config = inject(NAUTH_CLIENT_CONFIG);
|
|
36
|
-
const http = inject(HttpClient);
|
|
37
|
-
const authService = inject(AuthService);
|
|
38
|
-
const platformId = inject(PLATFORM_ID);
|
|
39
|
-
const router = inject(Router);
|
|
40
|
-
const isBrowser = isPlatformBrowser(platformId);
|
|
41
|
-
if (!isBrowser) {
|
|
42
|
-
return next(req);
|
|
43
|
-
}
|
|
44
|
-
const tokenDelivery = config.tokenDelivery;
|
|
45
|
-
const baseUrl = config.baseUrl;
|
|
46
|
-
const endpoints = config.endpoints ?? {};
|
|
47
|
-
const refreshPath = endpoints.refresh ?? '/refresh';
|
|
48
|
-
const loginPath = endpoints.login ?? '/login';
|
|
49
|
-
const signupPath = endpoints.signup ?? '/signup';
|
|
50
|
-
const socialExchangePath = endpoints.socialExchange ?? '/social/exchange';
|
|
51
|
-
const refreshUrl = `${baseUrl}${refreshPath}`;
|
|
52
|
-
const isAuthApiRequest = req.url.includes(baseUrl);
|
|
53
|
-
const isRefreshEndpoint = req.url.includes(refreshPath);
|
|
54
|
-
const isPublicEndpoint = req.url.includes(loginPath) || req.url.includes(signupPath) || req.url.includes(socialExchangePath);
|
|
55
|
-
// Build request with credentials (cookies mode only)
|
|
56
|
-
let authReq = req;
|
|
57
|
-
if (tokenDelivery === 'cookies') {
|
|
58
|
-
authReq = authReq.clone({ withCredentials: true });
|
|
59
|
-
if (['POST', 'PUT', 'PATCH', 'DELETE'].includes(req.method)) {
|
|
60
|
-
const csrfCookieName = config.csrf?.cookieName ?? 'nauth_csrf_token';
|
|
61
|
-
const csrfHeaderName = config.csrf?.headerName ?? 'x-csrf-token';
|
|
62
|
-
const csrfToken = getCsrfToken(csrfCookieName);
|
|
63
|
-
if (csrfToken) {
|
|
64
|
-
authReq = authReq.clone({ setHeaders: { [csrfHeaderName]: csrfToken } });
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return next(authReq).pipe(catchError((error) => {
|
|
69
|
-
const shouldHandle = error instanceof HttpErrorResponse &&
|
|
70
|
-
error.status === 401 &&
|
|
71
|
-
isAuthApiRequest &&
|
|
72
|
-
!isRefreshEndpoint &&
|
|
73
|
-
!isPublicEndpoint &&
|
|
74
|
-
!retriedRequests.has(req);
|
|
75
|
-
if (!shouldHandle) {
|
|
76
|
-
return throwError(() => error);
|
|
77
|
-
}
|
|
78
|
-
if (config.debug) {
|
|
79
|
-
console.warn('[nauth-interceptor] 401 detected:', req.url);
|
|
80
|
-
}
|
|
81
|
-
if (!isRefreshing) {
|
|
82
|
-
isRefreshing = true;
|
|
83
|
-
refreshTokenSubject.next(null);
|
|
84
|
-
if (config.debug) {
|
|
85
|
-
console.warn('[nauth-interceptor] Starting refresh...');
|
|
86
|
-
}
|
|
87
|
-
// Refresh based on mode
|
|
88
|
-
const refresh$ = tokenDelivery === 'cookies'
|
|
89
|
-
? http.post(refreshUrl, {}, { withCredentials: true })
|
|
90
|
-
: from(authService.refresh());
|
|
91
|
-
return refresh$.pipe(switchMap((response) => {
|
|
92
|
-
if (config.debug) {
|
|
93
|
-
console.warn('[nauth-interceptor] Refresh successful');
|
|
94
|
-
}
|
|
95
|
-
isRefreshing = false;
|
|
96
|
-
// Get new token (JSON mode) or signal success (cookies mode)
|
|
97
|
-
const newToken = 'accessToken' in response ? response.accessToken : 'success';
|
|
98
|
-
refreshTokenSubject.next(newToken ?? 'success');
|
|
99
|
-
// Build retry request
|
|
100
|
-
const retryReq = buildRetryRequest(authReq, tokenDelivery, newToken);
|
|
101
|
-
retriedRequests.add(retryReq);
|
|
102
|
-
if (config.debug) {
|
|
103
|
-
console.warn('[nauth-interceptor] Retrying:', req.url);
|
|
104
|
-
}
|
|
105
|
-
return next(retryReq);
|
|
106
|
-
}), catchError((err) => {
|
|
107
|
-
if (config.debug) {
|
|
108
|
-
console.error('[nauth-interceptor] Refresh failed:', err);
|
|
109
|
-
}
|
|
110
|
-
isRefreshing = false;
|
|
111
|
-
refreshTokenSubject.next(null);
|
|
112
|
-
// Handle session expiration - redirect to configured URL
|
|
113
|
-
if (config.redirects?.sessionExpired) {
|
|
114
|
-
router.navigateByUrl(config.redirects.sessionExpired).catch((navError) => {
|
|
115
|
-
if (config.debug) {
|
|
116
|
-
console.error('[nauth-interceptor] Navigation failed:', navError);
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
return throwError(() => err);
|
|
121
|
-
}));
|
|
122
|
-
}
|
|
123
|
-
else {
|
|
124
|
-
// Wait for ongoing refresh
|
|
125
|
-
if (config.debug) {
|
|
126
|
-
console.warn('[nauth-interceptor] Waiting for refresh...');
|
|
127
|
-
}
|
|
128
|
-
return refreshTokenSubject.pipe(filter((token) => token !== null), take(1), switchMap((token) => {
|
|
129
|
-
if (config.debug) {
|
|
130
|
-
console.warn('[nauth-interceptor] Refresh done, retrying:', req.url);
|
|
131
|
-
}
|
|
132
|
-
const retryReq = buildRetryRequest(authReq, tokenDelivery, token);
|
|
133
|
-
retriedRequests.add(retryReq);
|
|
134
|
-
return next(retryReq);
|
|
135
|
-
}));
|
|
136
|
-
}
|
|
137
|
-
}));
|
|
138
|
-
};
|
|
139
|
-
/**
|
|
140
|
-
* Build retry request with appropriate auth.
|
|
141
|
-
*/
|
|
142
|
-
function buildRetryRequest(originalReq, tokenDelivery, newToken) {
|
|
143
|
-
if (tokenDelivery === 'json' && newToken && newToken !== 'success') {
|
|
144
|
-
return originalReq.clone({
|
|
145
|
-
setHeaders: { Authorization: `Bearer ${newToken}` },
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
return originalReq.clone();
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Class-based interceptor for NgModule compatibility.
|
|
152
|
-
*/
|
|
153
|
-
export class AuthInterceptor {
|
|
154
|
-
intercept(req, next) {
|
|
155
|
-
return authInterceptor(req, next);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC5pbnRlcmNlcHRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3N0YW5kYWxvbmUvYXV0aC5pbnRlcmNlcHRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLFdBQVcsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNwRCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNwRCxPQUFPLEVBQWlELFVBQVUsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ3BILE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUN6QyxPQUFPLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxlQUFlLEVBQUUsSUFBSSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzlGLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUMvQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFN0M7OztHQUdHO0FBQ0gsSUFBSSxZQUFZLEdBQUcsS0FBSyxDQUFDO0FBQ3pCLE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxlQUFlLENBQWdCLElBQUksQ0FBQyxDQUFDO0FBRXJFOztHQUVHO0FBQ0gsTUFBTSxlQUFlLEdBQUcsSUFBSSxPQUFPLEVBQXdCLENBQUM7QUFFNUQ7O0dBRUc7QUFDSCxTQUFTLFlBQVksQ0FBQyxVQUFrQjtJQUN0QyxJQUFJLE9BQU8sUUFBUSxLQUFLLFdBQVc7UUFBRSxPQUFPLElBQUksQ0FBQztJQUNqRCxNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLE1BQU0sQ0FBQyxRQUFRLFVBQVUsVUFBVSxDQUFDLENBQUMsQ0FBQztJQUM5RSxPQUFPLEtBQUssQ0FBQyxDQUFDLENBQUMsa0JBQWtCLENBQUMsS0FBSyxD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SSxRQUFRLEtBQUssU0FBUyxFQUFFLENBQUM7UUFDbkUsT0FBTyxXQUFXLENBQUMsS0FBSyxDQUFDO1lBQ3ZCLFVBQVUsRUFBRSxFQUFFLGFBQWEsRUFBRSxVQUFVLFFBQVEsRUFBRSxFQUFFO1NBQ3BELENBQUMsQ0FBQztJQUNMLENBQUM7SUFDRCxPQUFPLFdBQVcsQ0FBQyxLQUFLLEVBQUUsQ0FBQztBQUM3QixDQUFDO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLE9BQU8sZUFBZTtJQUMxQixTQUFTLENBQUMsR0FBeUIsRUFBRSxJQUFtQjtRQUN0RCxPQUFPLGVBQWUsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDcEMsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgaW5qZWN0LCBQTEFURk9STV9JRCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgaXNQbGF0Zm9ybUJyb3dzZXIgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgSHR0cEhhbmRsZXJGbiwgSHR0cEludGVyY2VwdG9yRm4sIEh0dHBSZXF1ZXN0LCBIdHRwQ2xpZW50LCBIdHRwRXJyb3JSZXNwb25zZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcbmltcG9ydCB7IFJvdXRlciB9IGZyb20gJ0Bhbmd1bGFyL3JvdXRlcic7XG5pbXBvcnQgeyBjYXRjaEVycm9yLCBzd2l0Y2hNYXAsIHRocm93RXJyb3IsIGZpbHRlciwgdGFrZSwgQmVoYXZpb3JTdWJqZWN0LCBmcm9tIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBOQVVUSF9DTElFTlRfQ09ORklHIH0gZnJvbSAnLi90b2tlbnMnO1xuaW1wb3J0IHsgQXV0aFNlcnZpY2UgfSBmcm9tICcuL2F1dGguc2VydmljZSc7XG5cbi8qKlxuICogUmVmcmVzaCBzdGF0ZSBtYW5hZ2VtZW50LlxuICogQmVoYXZpb3JTdWJqZWN0IHBhdHRlcm4gaXMgdGhlIGluZHVzdHJ5LXN0YW5kYXJkIGZvciB0b2tlbiByZWZyZXNoLlxuICovXG5sZXQgaXNSZWZyZXNoaW5nID0gZmFsc2U7XG5jb25zdCByZWZyZXNoVG9rZW5TdWJqZWN0ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxzdHJpbmcgfCBudWxsPihudWxsKTtcblxuLyoqXG4gKiBUcmFjayByZXRyaWVkIHJlcXVlc3RzIHRvIHByZXZlbnQgaW5maW5pdGUgbG9vcHMuXG4gKi9cbmNvbnN0IHJldHJpZWRSZXF1ZXN0cyA9IG5ldyBXZWFrU2V0PEh0dHBSZXF1ZXN0PHVua25vd24+PigpO1xuXG4vKipcbiAqIEdldCBDU1JGIHRva2VuIGZyb20gY29va2llLlxuICovXG5mdW5jdGlvbiBnZXRDc3JmVG9rZW4oY29va2llTmFtZTogc3RyaW5nKTogc3RyaW5nIHwgbnVsbCB7XG4gIGlmICh0eXBlb2YgZG9jdW1lbnQgPT09ICd1bmRlZmluZWQnKSByZXR1cm4gbnVsbDtcbiAgY29uc3QgbWF0Y2ggPSBkb2N1bWVudC5jb29raWUubWF0Y2gobmV3IFJlZ0V4cChgKF58ICkke2Nvb2tpZU5hbWV9PShbXjtdKylgKSk7XG4gIHJldHVybiBtYXRjaCA/IGRlY29kZVVSSUNvbXBvbmVudChtYXRjaFsyXSkgOiBudWxsO1xufVxuXG4vKipcbiAqIEFuZ3VsYXIgSFRUUCBpbnRlcmNlcHRvciBmb3IgbmF1dGgtdG9vbGtpdC5cbiAqXG4gKiBIYW5kbGVzOlxuICogLSBDb29raWVzIG1vZGU6IHdpdGhDcmVkZW50aWFscyArIENTUkYgdG9rZW5zICsgcmVmcmVzaCB2aWEgUE9TVFxuICogLSBKU09OIG1vZGU6IHJlZnJlc2ggdmlhIFNESywgcmV0cnkgd2l0aCBuZXcgdG9rZW5cbiAqL1xuZXhwb3J0IGNvbnN0IGF1dGhJbnRlcmNlcHRvcjogSHR0cEludGVyY2VwdG9yRm4gPSAocmVxOiBIdHRwUmVxdWVzdDx1bmtub3duPiwgbmV4dDogSHR0cEhhbmRsZXJGbikgPT4ge1xuICBjb25zdCBjb25maWcgPSBpbmplY3QoTkFVVEhfQ0xJRU5UX0NPTkZJRyk7XG4gIGNvbnN0IGh0dHAgPSBpbmplY3QoSHR0cENsaWVudCk7XG4gIGNvbnN0IGF1dGhTZXJ2aWNlID0gaW5qZWN0KEF1dGhTZXJ2aWNlKTtcbiAgY29uc3QgcGxhdGZvcm1JZCA9IGluamVjdChQTEFURk9STV9JRCk7XG4gIGNvbnN0IHJvdXRlciA9IGluamVjdChSb3V0ZXIpO1xuICBjb25zdCBpc0Jyb3dzZXIgPSBpc1BsYXRmb3JtQnJvd3NlcihwbGF0Zm9ybUlkKTtcblxuICBpZiAoIWlzQnJvd3Nlcikge1xuICAgIHJldHVybiBuZXh0KHJlcSk7XG4gIH1cblxuICBjb25zdCB0b2tlbkRlbGl2ZXJ5ID0gY29uZmlnLnRva2VuRGVsaXZlcnk7XG4gIGNvbnN0IGJhc2VVcmwgPSBjb25maWcuYmFzZVVybDtcbiAgY29uc3QgZW5kcG9pbnRzID0gY29uZmlnLmVuZHBvaW50cyA/PyB7fTtcbiAgY29uc3QgcmVmcmVzaFBhdGggPSBlbmRwb2ludHMucmVmcmVzaCA/PyAnL3JlZnJlc2gnO1xuICBjb25zdCBsb2dpblBhdGggPSBlbmRwb2ludHMubG9naW4gPz8gJy9sb2dpbic7XG4gIGNvbnN0IHNpZ251cFBhdGggPSBlbmRwb2ludHMuc2lnbnVwID8/ICcvc2lnbnVwJztcbiAgY29uc3Qgc29jaWFsRXhjaGFuZ2VQYXRoID0gZW5kcG9pbnRzLnNvY2lhbEV4Y2hhbmdlID8/ICcvc29jaWFsL2V4Y2hhbmdlJztcbiAgY29uc3QgcmVmcmVzaFVybCA9IGAke2Jhc2VVcmx9JHtyZWZyZXNoUGF0aH1gO1xuXG4gIGNvbnN0IGlzQXV0aEFwaVJlcXVlc3QgPSByZXEudXJsLmluY2x1ZGVzKGJhc2VVcmwpO1xuICBjb25zdCBpc1JlZnJlc2hFbmRwb2ludCA9IHJlcS51cmwuaW5jbHVkZXMocmVmcmVzaFBhdGgpO1xuICBjb25zdCBpc1B1YmxpY0VuZHBvaW50ID1cbiAgICByZXEudXJsLmluY2x1ZGVzKGxvZ2luUGF0aCkgfHwgcmVxLnVybC5pbmNsdWRlcyhzaWdudXBQYXRoKSB8fCByZXEudXJsLmluY2x1ZGVzKHNvY2lhbEV4Y2hhbmdlUGF0aCk7XG5cbiAgLy8gQnVpbGQgcmVxdWVzdCB3aXRoIGNyZWRlbnRpYWxzIChjb29raWVzIG1vZGUgb25seSlcbiAgbGV0IGF1dGhSZXEgPSByZXE7XG4gIGlmICh0b2tlbkRlbGl2ZXJ5ID09PSAnY29va2llcycpIHtcbiAgICBhdXRoUmVxID0gYXV0aFJlcS5jbG9uZSh7IHdpdGhDcmVkZW50aWFsczogdHJ1ZSB9KTtcblxuICAgIGlmIChbJ1BPU1QnLCAnUFVUJywgJ1BBVENIJywgJ0RFTEVURSddLmluY2x1ZGVzKHJlcS5tZXRob2QpKSB7XG4gICAgICBjb25zdCBjc3JmQ29va2llTmFtZSA9IGNvbmZpZy5jc3JmPy5jb29raWVOYW1lID8/ICduYXV0aF9jc3JmX3Rva2VuJztcbiAgICAgIGNvbnN0IGNzcmZIZWFkZXJOYW1lID0gY29uZmlnLmNzcmY/LmhlYWRlck5hbWUgPz8gJ3gtY3NyZi10b2tlbic7XG4gICAgICBjb25zdCBjc3JmVG9rZW4gPSBnZXRDc3JmVG9rZW4oY3NyZkNvb2tpZU5hbWUpO1xuICAgICAgaWYgKGNzcmZUb2tlbikge1xuICAgICAgICBhdXRoUmVxID0gYXV0aFJlcS5jbG9uZSh7IHNldEhlYWRlcnM6IHsgW2NzcmZIZWFkZXJOYW1lXTogY3NyZlRva2VuIH0gfSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIG5leHQoYXV0aFJlcSkucGlwZShcbiAgICBjYXRjaEVycm9yKChlcnJvcjogdW5rbm93bikgPT4ge1xuICAgICAgY29uc3Qgc2hvdWxkSGFuZGxlID1cbiAgICAgICAgZXJyb3IgaW5zdGFuY2VvZiBIdHRwRXJyb3JSZXNwb25zZSAmJlxuICAgICAgICBlcnJvci5zdGF0dXMgPT09IDQwMSAmJlxuICAgICAgICBpc0F1dGhBcGlSZXF1ZXN0ICYmXG4gICAgICAgICFpc1JlZnJlc2hFbmRwb2ludCAmJlxuICAgICAgICAhaXNQdWJsaWNFbmRwb2ludCAmJlxuICAgICAgICAhcmV0cmllZFJlcXVlc3RzLmhhcyhyZXEpO1xuXG4gICAgICBpZiAoIXNob3VsZEhhbmRsZSkge1xuICAgICAgICByZXR1cm4gdGhyb3dFcnJvcigoKSA9PiBlcnJvcik7XG4gICAgICB9XG5cbiAgICAgIGlmIChjb25maWcuZGVidWcpIHtcbiAgICAgICAgY29uc29sZS53YXJuKCdbbmF1dGgtaW50ZXJjZXB0b3JdIDQwMSBkZXRlY3RlZDonLCByZXEudXJsKTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFpc1JlZnJlc2hpbmcpIHtcbiAgICAgICAgaXNSZWZyZXNoaW5nID0gdHJ1ZTtcbiAgICAgICAgcmVmcmVzaFRva2VuU3ViamVjdC5uZXh0KG51bGwpO1xuXG4gICAgICAgIGlmIChjb25maWcuZGVidWcpIHtcbiAgICAgICAgICBjb25zb2xlLndhcm4oJ1tuYXV0aC1pbnRlcmNlcHRvcl0gU3RhcnRpbmcgcmVmcmVzaC4uLicpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gUmVmcmVzaCBiYXNlZCBvbiBtb2RlXG4gICAgICAgIGNvbnN0IHJlZnJlc2gkID1cbiAgICAgICAgICB0b2tlbkRlbGl2ZXJ5ID09PSAnY29va2llcydcbiAgICAgICAgICAgID8gaHR0cC5wb3N0PHsgYWNjZXNzVG9rZW4/OiBzdHJpbmcgfT4ocmVmcmVzaFVybCwge30sIHsgd2l0aENyZWRlbnRpYWxzOiB0cnVlIH0pXG4gICAgICAgICAgICA6IGZyb20oYXV0aFNlcnZpY2UucmVmcmVzaCgpKTtcblxuICAgICAgICByZXR1cm4gcmVmcmVzaCQucGlwZShcbiAgICAgICAgICBzd2l0Y2hNYXAoKHJlc3BvbnNlKSA9PiB7XG4gICAgICAgICAgICBpZiAoY29uZmlnLmRlYnVnKSB7XG4gICAgICAgICAgICAgIGNvbnNvbGUud2FybignW25hdXRoLWludGVyY2VwdG9yXSBSZWZyZXNoIHN1Y2Nlc3NmdWwnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlzUmVmcmVzaGluZyA9IGZhbHNlO1xuXG4gICAgICAgICAgICAvLyBHZXQgbmV3IHRva2VuIChKU09OIG1vZGUpIG9yIHNpZ25hbCBzdWNjZXNzIChjb29raWVzIG1vZGUpXG4gICAgICAgICAgICBjb25zdCBuZXdUb2tlbiA9ICdhY2Nlc3NUb2tlbicgaW4gcmVzcG9uc2UgPyByZXNwb25zZS5hY2Nlc3NUb2tlbiA6ICdzdWNjZXNzJztcbiAgICAgICAgICAgIHJlZnJlc2hUb2tlblN1YmplY3QubmV4dChuZXdUb2tlbiA/PyAnc3VjY2VzcycpO1xuXG4gICAgICAgICAgICAvLyBCdWlsZCByZXRyeSByZXF1ZXN0XG4gICAgICAgICAgICBjb25zdCByZXRyeVJlcSA9IGJ1aWxkUmV0cnlSZXF1ZXN0KGF1dGhSZXEsIHRva2VuRGVsaXZlcnksIG5ld1Rva2VuKTtcbiAgICAgICAgICAgIHJldHJpZWRSZXF1ZXN0cy5hZGQocmV0cnlSZXEpO1xuXG4gICAgICAgICAgICBpZiAoY29uZmlnLmRlYnVnKSB7XG4gICAgICAgICAgICAgIGNvbnNvbGUud2FybignW25hdXRoLWludGVyY2VwdG9yXSBSZXRyeWluZzonLCByZXEudXJsKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBuZXh0KHJldHJ5UmVxKTtcbiAgICAgICAgICB9KSxcbiAgICAgICAgICBjYXRjaEVycm9yKChlcnIpID0+IHtcbiAgICAgICAgICAgIGlmIChjb25maWcuZGVidWcpIHtcbiAgICAgICAgICAgICAgY29uc29sZS5lcnJvcignW25hdXRoLWludGVyY2VwdG9yXSBSZWZyZXNoIGZhaWxlZDonLCBlcnIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaXNSZWZyZXNoaW5nID0gZmFsc2U7XG4gICAgICAgICAgICByZWZyZXNoVG9rZW5TdWJqZWN0Lm5leHQobnVsbCk7XG5cbiAgICAgICAgICAgIC8vIEhhbmRsZSBzZXNzaW9uIGV4cGlyYXRpb24gLSByZWRpcmVjdCB0byBjb25maWd1cmVkIFVSTFxuICAgICAgICAgICAgaWYgKGNvbmZpZy5yZWRpcmVjdHM/LnNlc3Npb25FeHBpcmVkKSB7XG4gICAgICAgICAgICAgIHJvdXRlci5uYXZpZ2F0ZUJ5VXJsKGNvbmZpZy5yZWRpcmVjdHMuc2Vzc2lvbkV4cGlyZWQpLmNhdGNoKChuYXZFcnJvcikgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChjb25maWcuZGVidWcpIHtcbiAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ1tuYXV0aC1pbnRlcmNlcHRvcl0gTmF2aWdhdGlvbiBmYWlsZWQ6JywgbmF2RXJyb3IpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiB0aHJvd0Vycm9yKCgpID0+IGVycik7XG4gICAgICAgICAgfSksXG4gICAgICAgICk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBXYWl0IGZvciBvbmdvaW5nIHJlZnJlc2hcbiAgICAgICAgaWYgKGNvbmZpZy5kZWJ1Zykge1xuICAgICAgICAgIGNvbnNvbGUud2FybignW25hdXRoLWludGVyY2VwdG9yXSBXYWl0aW5nIGZvciByZWZyZXNoLi4uJyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlZnJlc2hUb2tlblN1YmplY3QucGlwZShcbiAgICAgICAgICBmaWx0ZXIoKHRva2VuKTogdG9rZW4gaXMgc3RyaW5nID0+IHRva2VuICE9PSBudWxsKSxcbiAgICAgICAgICB0YWtlKDEpLFxuICAgICAgICAgIHN3aXRjaE1hcCgodG9rZW4pID0+IHtcbiAgICAgICAgICAgIGlmIChjb25maWcuZGVidWcpIHtcbiAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdbbmF1dGgtaW50ZXJjZXB0b3JdIFJlZnJlc2ggZG9uZSwgcmV0cnlpbmc6JywgcmVxLnVybCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCByZXRyeVJlcSA9IGJ1aWxkUmV0cnlSZXF1ZXN0KGF1dGhSZXEsIHRva2VuRGVsaXZlcnksIHRva2VuKTtcbiAgICAgICAgICAgIHJldHJpZWRSZXF1ZXN0cy5hZGQocmV0cnlSZXEpO1xuICAgICAgICAgICAgcmV0dXJuIG5leHQocmV0cnlSZXEpO1xuICAgICAgICAgIH0pLFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH0pLFxuICApO1xufTtcblxuLyoqXG4gKiBCdWlsZCByZXRyeSByZXF1ZXN0IHdpdGggYXBwcm9wcmlhdGUgYXV0aC5cbiAqL1xuZnVuY3Rpb24gYnVpbGRSZXRyeVJlcXVlc3QoXG4gIG9yaWdpbmFsUmVxOiBIdHRwUmVxdWVzdDx1bmtub3duPixcbiAgdG9rZW5EZWxpdmVyeTogc3RyaW5nLFxuICBuZXdUb2tlbj86IHN0cmluZyxcbik6IEh0dHBSZXF1ZXN0PHVua25vd24+IHtcbiAgaWYgKHRva2VuRGVsaXZlcnkgPT09ICdqc29uJyAmJiBuZXdUb2tlbiAmJiBuZXdUb2tlbiAhPT0gJ3N1Y2Nlc3MnKSB7XG4gICAgcmV0dXJuIG9yaWdpbmFsUmVxLmNsb25lKHtcbiAgICAgIHNldEhlYWRlcnM6IHsgQXV0aG9yaXphdGlvbjogYEJlYXJlciAke25ld1Rva2VufWAgfSxcbiAgICB9KTtcbiAgfVxuICByZXR1cm4gb3JpZ2luYWxSZXEuY2xvbmUoKTtcbn1cblxuLyoqXG4gKiBDbGFzcy1iYXNlZCBpbnRlcmNlcHRvciBmb3IgTmdNb2R1bGUgY29tcGF0aWJpbGl0eS5cbiAqL1xuZXhwb3J0IGNsYXNzIEF1dGhJbnRlcmNlcHRvciB7XG4gIGludGVyY2VwdChyZXE6IEh0dHBSZXF1ZXN0PHVua25vd24+LCBuZXh0OiBIdHRwSGFuZGxlckZuKSB7XG4gICAgcmV0dXJuIGF1dGhJbnRlcmNlcHRvcihyZXEsIG5leHQpO1xuICB9XG59XG4iXX0=
|