@nauth-toolkit/client-angular 0.1.64 → 0.1.66
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-interceptor.shared.mjs +165 -0
- package/esm2022/lib/auth.interceptor.mjs +4 -263
- package/esm2022/ngmodule/auth.interceptor.class.mjs +10 -63
- package/esm2022/ngmodule/auth.service.mjs +54 -1
- package/fesm2022/nauth-toolkit-client-angular.mjs +216 -312
- package/fesm2022/nauth-toolkit-client-angular.mjs.map +1 -1
- package/lib/auth-interceptor.shared.d.ts +13 -0
- package/ngmodule/auth.service.d.ts +14 -0
- package/package.json +2 -2
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { HttpErrorResponse } from '@angular/common/http';
|
|
2
|
+
import { BehaviorSubject, catchError, finalize, from, map, of, shareReplay, switchMap, throwError, } from 'rxjs';
|
|
3
|
+
/**
|
|
4
|
+
* Shared interceptor logic for both:
|
|
5
|
+
* - Functional interceptor (Angular 17+ standalone)
|
|
6
|
+
* - Class-based interceptor (NgModule apps)
|
|
7
|
+
*
|
|
8
|
+
* WHY:
|
|
9
|
+
* - Keep one implementation for cookies + json mode behavior.
|
|
10
|
+
* - Avoid divergence between standalone and NgModule integrations.
|
|
11
|
+
*/
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Refresh state management (module-level)
|
|
14
|
+
// ============================================================================
|
|
15
|
+
let isRefreshing = false;
|
|
16
|
+
const refreshTokenSubject = new BehaviorSubject(null);
|
|
17
|
+
let refreshInFlight$ = null;
|
|
18
|
+
const retriedRequests = new WeakSet();
|
|
19
|
+
/**
|
|
20
|
+
* Get CSRF token from cookie.
|
|
21
|
+
*/
|
|
22
|
+
function getCsrfToken(cookieName) {
|
|
23
|
+
if (typeof document === 'undefined')
|
|
24
|
+
return null;
|
|
25
|
+
const match = document.cookie.match(new RegExp(`(^| )${cookieName}=([^;]+)`));
|
|
26
|
+
return match ? decodeURIComponent(match[2]) : null;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Build retry request with appropriate auth.
|
|
30
|
+
*
|
|
31
|
+
* In cookies mode: Browser automatically sends updated httpOnly cookies (access/refresh tokens).
|
|
32
|
+
* We must re-read CSRF token after refresh to avoid stale headers.
|
|
33
|
+
*
|
|
34
|
+
* In JSON mode: Clones the request and adds the new Bearer token.
|
|
35
|
+
*/
|
|
36
|
+
function buildRetryRequest(originalReq, tokenDelivery, newToken, csrfConfig) {
|
|
37
|
+
if (tokenDelivery === 'json' && newToken && newToken !== 'success') {
|
|
38
|
+
return originalReq.clone({ setHeaders: { Authorization: `Bearer ${newToken}` } });
|
|
39
|
+
}
|
|
40
|
+
if (tokenDelivery === 'cookies' && ['POST', 'PUT', 'PATCH', 'DELETE'].includes(originalReq.method)) {
|
|
41
|
+
const csrfCookieName = csrfConfig?.cookieName ?? 'nauth_csrf_token';
|
|
42
|
+
const csrfHeaderName = csrfConfig?.headerName ?? 'x-csrf-token';
|
|
43
|
+
const freshCsrfToken = getCsrfToken(csrfCookieName);
|
|
44
|
+
if (freshCsrfToken) {
|
|
45
|
+
return originalReq.clone({ setHeaders: { [csrfHeaderName]: freshCsrfToken } });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return originalReq;
|
|
49
|
+
}
|
|
50
|
+
export function createNAuthAuthHttpInterceptor(params) {
|
|
51
|
+
const { config, authService, router, next, req } = params;
|
|
52
|
+
const tokenDelivery = config.tokenDelivery;
|
|
53
|
+
const baseUrl = config.baseUrl;
|
|
54
|
+
const endpoints = config.endpoints ?? {};
|
|
55
|
+
const authPathPrefix = config.authPathPrefix;
|
|
56
|
+
// Build refresh path with authPathPrefix if configured (matches core client buildUrl logic exactly)
|
|
57
|
+
// Use default '/refresh' if endpoints.refresh is not defined
|
|
58
|
+
const refreshPath = endpoints?.refresh ?? '/refresh';
|
|
59
|
+
const normalizedRefreshPath = refreshPath.startsWith('/') ? refreshPath : `/${refreshPath}`;
|
|
60
|
+
// Check if baseUrl already ends with authPathPrefix to avoid double-prefixing
|
|
61
|
+
// This must match the core client's buildUrl logic exactly
|
|
62
|
+
const baseUrlEndsWithPrefix = authPathPrefix && baseUrl.endsWith(authPathPrefix);
|
|
63
|
+
const shouldAddPrefix = authPathPrefix && !baseUrlEndsWithPrefix && !normalizedRefreshPath.startsWith(authPathPrefix);
|
|
64
|
+
const effectiveRefreshPath = shouldAddPrefix ? `${authPathPrefix}${normalizedRefreshPath}` : normalizedRefreshPath;
|
|
65
|
+
const loginPath = endpoints.login ?? '/login';
|
|
66
|
+
const signupPath = endpoints.signup ?? '/signup';
|
|
67
|
+
const socialExchangePath = endpoints.socialExchange ?? '/social/exchange';
|
|
68
|
+
const isAuthApiRequest = req.url.includes(baseUrl);
|
|
69
|
+
// Check if request is to refresh endpoint (using effective path with authPathPrefix)
|
|
70
|
+
const isRefreshEndpoint = req.url.includes(effectiveRefreshPath);
|
|
71
|
+
const isPublicEndpoint = req.url.includes(loginPath) || req.url.includes(signupPath) || req.url.includes(socialExchangePath);
|
|
72
|
+
const shouldIntercept = isAuthApiRequest && !isRefreshEndpoint && !isPublicEndpoint;
|
|
73
|
+
// ============================================================================
|
|
74
|
+
// Build request for cookies mode (withCredentials + CSRF)
|
|
75
|
+
// ============================================================================
|
|
76
|
+
let authReq = req;
|
|
77
|
+
if (tokenDelivery === 'cookies') {
|
|
78
|
+
authReq = authReq.clone({ withCredentials: true });
|
|
79
|
+
if (['POST', 'PUT', 'PATCH', 'DELETE'].includes(req.method)) {
|
|
80
|
+
const csrfCookieName = config.csrf?.cookieName ?? 'nauth_csrf_token';
|
|
81
|
+
const csrfHeaderName = config.csrf?.headerName ?? 'x-csrf-token';
|
|
82
|
+
const csrfToken = getCsrfToken(csrfCookieName);
|
|
83
|
+
if (csrfToken) {
|
|
84
|
+
authReq = authReq.clone({ setHeaders: { [csrfHeaderName]: csrfToken } });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// ============================================================================
|
|
89
|
+
// JSON mode: attach Authorization header for HttpClient calls
|
|
90
|
+
// ============================================================================
|
|
91
|
+
// Simple approach: attach token if available, let backend validate
|
|
92
|
+
// Handle 401 reactively (matches old working implementation)
|
|
93
|
+
const attachJsonAuth$ = tokenDelivery === 'json' && shouldIntercept && !authReq.headers.has('Authorization')
|
|
94
|
+
? from(authService.getAccessToken()).pipe(switchMap((token) => {
|
|
95
|
+
if (token) {
|
|
96
|
+
return of(authReq.clone({ setHeaders: { Authorization: `Bearer ${token}` } }));
|
|
97
|
+
}
|
|
98
|
+
return of(authReq);
|
|
99
|
+
}))
|
|
100
|
+
: of(authReq);
|
|
101
|
+
// ============================================================================
|
|
102
|
+
// Refresh coordination
|
|
103
|
+
// ============================================================================
|
|
104
|
+
const getOrStartRefresh$ = () => {
|
|
105
|
+
if (refreshInFlight$)
|
|
106
|
+
return refreshInFlight$;
|
|
107
|
+
// WHY: We want to ensure only one refresh request is in flight at any time.
|
|
108
|
+
// All requests (including those that haven't hit the backend yet) should wait for
|
|
109
|
+
// the same refresh result to avoid a burst of 401s and potential WAF/rate-limit issues.
|
|
110
|
+
isRefreshing = true;
|
|
111
|
+
refreshTokenSubject.next(null);
|
|
112
|
+
// WHY: Always refresh via the core client.
|
|
113
|
+
// - Ensures authPathPrefix + default endpoints are applied consistently (fixes /refresh vs /auth/refresh).
|
|
114
|
+
// - Centralizes CSRF + credentials handling in one place.
|
|
115
|
+
const refreshRequest$ = from(authService.getClient().refreshTokens());
|
|
116
|
+
refreshInFlight$ = refreshRequest$.pipe(map((response) => {
|
|
117
|
+
// Cookies mode: success is enough (tokens are in httpOnly cookies).
|
|
118
|
+
// JSON mode: we need the new access token to retry + unblock queued requests.
|
|
119
|
+
const newToken = tokenDelivery === 'json' ? response.accessToken : 'success';
|
|
120
|
+
if (tokenDelivery === 'json' && (!newToken || newToken === 'success')) {
|
|
121
|
+
// ⚠️ WARNING: Without an access token we cannot safely retry requests in JSON mode.
|
|
122
|
+
throw new Error('Token refresh did not return an access token');
|
|
123
|
+
}
|
|
124
|
+
refreshTokenSubject.next(newToken ?? 'success');
|
|
125
|
+
return newToken ?? 'success';
|
|
126
|
+
}), catchError((err) => {
|
|
127
|
+
refreshTokenSubject.next(null);
|
|
128
|
+
// Refresh failed -> redirect if configured
|
|
129
|
+
if (config.redirects?.sessionExpired) {
|
|
130
|
+
router.navigateByUrl(config.redirects.sessionExpired).catch(() => {
|
|
131
|
+
// Ignore navigation errors
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return throwError(() => err);
|
|
135
|
+
}), finalize(() => {
|
|
136
|
+
isRefreshing = false;
|
|
137
|
+
refreshInFlight$ = null;
|
|
138
|
+
}), shareReplay({ bufferSize: 1, refCount: false }));
|
|
139
|
+
return refreshInFlight$;
|
|
140
|
+
};
|
|
141
|
+
// ============================================================================
|
|
142
|
+
// Pre-request gating: block requests while refresh is in-flight
|
|
143
|
+
// ============================================================================
|
|
144
|
+
// WHY: Prevent multiple requests from hitting the backend with an expired token and returning 401.
|
|
145
|
+
// We queue all auth API calls during refresh and release them once refresh succeeds.
|
|
146
|
+
if (shouldIntercept && isRefreshing && refreshInFlight$) {
|
|
147
|
+
return refreshInFlight$.pipe(switchMap((token) => {
|
|
148
|
+
const gatedReq = buildRetryRequest(authReq, tokenDelivery, token, config.csrf);
|
|
149
|
+
return next(gatedReq);
|
|
150
|
+
}));
|
|
151
|
+
}
|
|
152
|
+
return attachJsonAuth$.pipe(switchMap((requestWithAuth) => next(requestWithAuth).pipe(catchError((error) => {
|
|
153
|
+
const shouldHandle = error instanceof HttpErrorResponse && error.status === 401 && shouldIntercept && !retriedRequests.has(req);
|
|
154
|
+
if (!shouldHandle) {
|
|
155
|
+
return throwError(() => error);
|
|
156
|
+
}
|
|
157
|
+
retriedRequests.add(req);
|
|
158
|
+
return getOrStartRefresh$().pipe(switchMap((token) => {
|
|
159
|
+
const retryReq = buildRetryRequest(requestWithAuth, tokenDelivery, token, config.csrf);
|
|
160
|
+
retriedRequests.add(retryReq);
|
|
161
|
+
return next(retryReq);
|
|
162
|
+
}));
|
|
163
|
+
}))));
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC1pbnRlcmNlcHRvci5zaGFyZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL2F1dGgtaW50ZXJjZXB0b3Iuc2hhcmVkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBYyxpQkFBaUIsRUFBeUMsTUFBTSxzQkFBc0IsQ0FBQztBQUU1RyxPQUFPLEVBQ0wsZUFBZSxFQUVmLFVBQVUsRUFDVixRQUFRLEVBQ1IsSUFBSSxFQUNKLEdBQUcsRUFDSCxFQUFFLEVBQ0YsV0FBVyxFQUNYLFNBQVMsRUFDVCxVQUFVLEdBQ1gsTUFBTSxNQUFNLENBQUM7QUFJZDs7Ozs7Ozs7R0FRRztBQUVILCtFQUErRTtBQUMvRSwwQ0FBMEM7QUFDMUMsK0VBQStFO0FBQy9FLElBQUksWUFBWSxHQUFHLEtBQUssQ0FBQztBQUN6QixNQUFNLG1CQUFtQixHQUFHLElBQUksZUFBZSxDQUFnQixJQUFJLENBQUMsQ0FBQztBQUNyRSxJQUFJLGdCQUFnQixHQUE4QixJQUFJLENBQUM7QUFDdkQsTUFBTSxlQUFlLEdBQUcsSUFBSSxPQUFPLEVBQXdCLENBQUM7QUFFNUQ7O0dBRUc7QUFDSCxTQUFTLFlBQVksQ0FBQyxVQUFrQjtJQUN0QyxJQUFJLE9BQU8sUUFBUSxLQUFLLFdBQVc7UUFBRSxPQUFPLElBQUksQ0FBQztJQUNqRCxNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLE1BQU0sQ0FBQyxRQUFRLFVBQVUsVUFBVSxDQUFDLENBQUMsQ0FBQztJQUM5RSxPQUFPLEtBQUssQ0FBQyxDQUFDLENBQUMsa0JBQWtCLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztBQUNyRCxDQUFDO0FBRUQ7Ozs7Ozs7R0FPRztBQUNILFNBQVMsaUJBQWlCLENBQ3hCLFdBQWlDLEVBQ2pDLGFBQXFCLEVBQ3JCLFFBQXdCLEVBQ3hCLFVBQXlEO0lB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b3JSZXNwb25zZSwgSHR0cEV2ZW50LCBIdHRwSGFuZGxlckZuLCBIdHRwUmVxdWVzdCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcbmltcG9ydCB7IFJvdXRlciB9IGZyb20gJ0Bhbmd1bGFyL3JvdXRlcic7XG5pbXBvcnQge1xuICBCZWhhdmlvclN1YmplY3QsXG4gIE9ic2VydmFibGUsXG4gIGNhdGNoRXJyb3IsXG4gIGZpbmFsaXplLFxuICBmcm9tLFxuICBtYXAsXG4gIG9mLFxuICBzaGFyZVJlcGxheSxcbiAgc3dpdGNoTWFwLFxuICB0aHJvd0Vycm9yLFxufSBmcm9tICdyeGpzJztcbmltcG9ydCB0eXBlIHsgTkF1dGhDbGllbnRDb25maWcgfSBmcm9tICdAbmF1dGgtdG9vbGtpdC9jbGllbnQnO1xuaW1wb3J0IHsgQXV0aFNlcnZpY2UgfSBmcm9tICcuLi9uZ21vZHVsZS9hdXRoLnNlcnZpY2UnO1xuXG4vKipcbiAqIFNoYXJlZCBpbnRlcmNlcHRvciBsb2dpYyBmb3IgYm90aDpcbiAqIC0gRnVuY3Rpb25hbCBpbnRlcmNlcHRvciAoQW5ndWxhciAxNysgc3RhbmRhbG9uZSlcbiAqIC0gQ2xhc3MtYmFzZWQgaW50ZXJjZXB0b3IgKE5nTW9kdWxlIGFwcHMpXG4gKlxuICogV0hZOlxuICogLSBLZWVwIG9uZSBpbXBsZW1lbnRhdGlvbiBmb3IgY29va2llcyArIGpzb24gbW9kZSBiZWhhdmlvci5cbiAqIC0gQXZvaWQgZGl2ZXJnZW5jZSBiZXR3ZWVuIHN0YW5kYWxvbmUgYW5kIE5nTW9kdWxlIGludGVncmF0aW9ucy5cbiAqL1xuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBSZWZyZXNoIHN0YXRlIG1hbmFnZW1lbnQgKG1vZHVsZS1sZXZlbClcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbmxldCBpc1JlZnJlc2hpbmcgPSBmYWxzZTtcbmNvbnN0IHJlZnJlc2hUb2tlblN1YmplY3QgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PHN0cmluZyB8IG51bGw+KG51bGwpO1xubGV0IHJlZnJlc2hJbkZsaWdodCQ6IE9ic2VydmFibGU8c3RyaW5nPiB8IG51bGwgPSBudWxsO1xuY29uc3QgcmV0cmllZFJlcXVlc3RzID0gbmV3IFdlYWtTZXQ8SHR0cFJlcXVlc3Q8dW5rbm93bj4+KCk7XG5cbi8qKlxuICogR2V0IENTUkYgdG9rZW4gZnJvbSBjb29raWUuXG4gKi9cbmZ1bmN0aW9uIGdldENzcmZUb2tlbihjb29raWVOYW1lOiBzdHJpbmcpOiBzdHJpbmcgfCBudWxsIHtcbiAgaWYgKHR5cGVvZiBkb2N1bWVudCA9PT0gJ3VuZGVmaW5lZCcpIHJldHVybiBudWxsO1xuICBjb25zdCBtYXRjaCA9IGRvY3VtZW50LmNvb2tpZS5tYXRjaChuZXcgUmVnRXhwKGAoXnwgKSR7Y29va2llTmFtZX09KFteO10rKWApKTtcbiAgcmV0dXJuIG1hdGNoID8gZGVjb2RlVVJJQ29tcG9uZW50KG1hdGNoWzJdKSA6IG51bGw7XG59XG5cbi8qKlxuICogQnVpbGQgcmV0cnkgcmVxdWVzdCB3aXRoIGFwcHJvcHJpYXRlIGF1dGguXG4gKlxuICogSW4gY29va2llcyBtb2RlOiBCcm93c2VyIGF1dG9tYXRpY2FsbHkgc2VuZHMgdXBkYXRlZCBodHRwT25seSBjb29raWVzIChhY2Nlc3MvcmVmcmVzaCB0b2tlbnMpLlxuICogV2UgbXVzdCByZS1yZWFkIENTUkYgdG9rZW4gYWZ0ZXIgcmVmcmVzaCB0byBhdm9pZCBzdGFsZSBoZWFkZXJzLlxuICpcbiAqIEluIEpTT04gbW9kZTogQ2xvbmVzIHRoZSByZXF1ZXN0IGFuZCBhZGRzIHRoZSBuZXcgQmVhcmVyIHRva2VuLlxuICovXG5mdW5jdGlvbiBidWlsZFJldHJ5UmVxdWVzdChcbiAgb3JpZ2luYWxSZXE6IEh0dHBSZXF1ZXN0PHVua25vd24+LFxuICB0b2tlbkRlbGl2ZXJ5OiBzdHJpbmcsXG4gIG5ld1Rva2VuPzogc3RyaW5nIHwgbnVsbCxcbiAgY3NyZkNvbmZpZz86IHsgY29va2llTmFtZT86IHN0cmluZzsgaGVhZGVyTmFtZT86IHN0cmluZyB9LFxuKTogSHR0cFJlcXVlc3Q8dW5rbm93bj4ge1xuICBpZiAodG9rZW5EZWxpdmVyeSA9PT0gJ2pzb24nICYmIG5ld1Rva2VuICYmIG5ld1Rva2VuICE9PSAnc3VjY2VzcycpIHtcbiAgICByZXR1cm4gb3JpZ2luYWxSZXEuY2xvbmUoeyBzZXRIZWFkZXJzOiB7IEF1dGhvcml6YXRpb246IGBCZWFyZXIgJHtuZXdUb2tlbn1gIH0gfSk7XG4gIH1cblxuICBpZiAodG9rZW5EZWxpdmVyeSA9PT0gJ2Nvb2tpZXMnICYmIFsnUE9TVCcsICdQVVQnLCAnUEFUQ0gnLCAnREVMRVRFJ10uaW5jbHVkZXMob3JpZ2luYWxSZXEubWV0aG9kKSkge1xuICAgIGNvbnN0IGNzcmZDb29raWVOYW1lID0gY3NyZkNvbmZpZz8uY29va2llTmFtZSA/PyAnbmF1dGhfY3NyZl90b2tlbic7XG4gICAgY29uc3QgY3NyZkhlYWRlck5hbWUgPSBjc3JmQ29uZmlnPy5oZWFkZXJOYW1lID8/ICd4LWNzcmYtdG9rZW4nO1xuICAgIGNvbnN0IGZyZXNoQ3NyZlRva2VuID0gZ2V0Q3NyZlRva2VuKGNzcmZDb29raWVOYW1lKTtcbiAgICBpZiAoZnJlc2hDc3JmVG9rZW4pIHtcbiAgICAgIHJldHVybiBvcmlnaW5hbFJlcS5jbG9uZSh7IHNldEhlYWRlcnM6IHsgW2NzcmZIZWFkZXJOYW1lXTogZnJlc2hDc3JmVG9rZW4gfSB9KTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gb3JpZ2luYWxSZXE7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVOQXV0aEF1dGhIdHRwSW50ZXJjZXB0b3IocGFyYW1zOiB7XG4gIGNvbmZpZzogTkF1dGhDbGllbnRDb25maWc7XG4gIGh0dHA6IEh0dHBDbGllbnQ7XG4gIGF1dGhTZXJ2aWNlOiBBdXRoU2VydmljZTtcbiAgcm91dGVyOiBSb3V0ZXI7XG4gIG5leHQ6IEh0dHBIYW5kbGVyRm47XG4gIHJlcTogSHR0cFJlcXVlc3Q8dW5rbm93bj47XG59KTogT2JzZXJ2YWJsZTxIdHRwRXZlbnQ8dW5rbm93bj4+IHtcbiAgY29uc3QgeyBjb25maWcsIGF1dGhTZXJ2aWNlLCByb3V0ZXIsIG5leHQsIHJlcSB9ID0gcGFyYW1zO1xuXG4gIGNvbnN0IHRva2VuRGVsaXZlcnkgPSBjb25maWcudG9rZW5EZWxpdmVyeTtcbiAgY29uc3QgYmFzZVVybCA9IGNvbmZpZy5iYXNlVXJsO1xuICBjb25zdCBlbmRwb2ludHMgPSBjb25maWcuZW5kcG9pbnRzID8/IHt9O1xuICBjb25zdCBhdXRoUGF0aFByZWZpeCA9IGNvbmZpZy5hdXRoUGF0aFByZWZpeDtcblxuICAvLyBCdWlsZCByZWZyZXNoIHBhdGggd2l0aCBhdXRoUGF0aFByZWZpeCBpZiBjb25maWd1cmVkIChtYXRjaGVzIGNvcmUgY2xpZW50IGJ1aWxkVXJsIGxvZ2ljIGV4YWN0bHkpXG4gIC8vIFVzZSBkZWZhdWx0ICcvcmVmcmVzaCcgaWYgZW5kcG9pbnRzLnJlZnJlc2ggaXMgbm90IGRlZmluZWRcbiAgY29uc3QgcmVmcmVzaFBhdGggPSBlbmRwb2ludHM/LnJlZnJlc2ggPz8gJy9yZWZyZXNoJztcbiAgY29uc3Qgbm9ybWFsaXplZFJlZnJlc2hQYXRoID0gcmVmcmVzaFBhdGguc3RhcnRzV2l0aCgnLycpID8gcmVmcmVzaFBhdGggOiBgLyR7cmVmcmVzaFBhdGh9YDtcblxuICAvLyBDaGVjayBpZiBiYXNlVXJsIGFscmVhZHkgZW5kcyB3aXRoIGF1dGhQYXRoUHJlZml4IHRvIGF2b2lkIGRvdWJsZS1wcmVmaXhpbmdcbiAgLy8gVGhpcyBtdXN0IG1hdGNoIHRoZSBjb3JlIGNsaWVudCdzIGJ1aWxkVXJsIGxvZ2ljIGV4YWN0bHlcbiAgY29uc3QgYmFzZVVybEVuZHNXaXRoUHJlZml4ID0gYXV0aFBhdGhQcmVmaXggJiYgYmFzZVVybC5lbmRzV2l0aChhdXRoUGF0aFByZWZpeCk7XG5cbiAgY29uc3Qgc2hvdWxkQWRkUHJlZml4ID0gYXV0aFBhdGhQcmVmaXggJiYgIWJhc2VVcmxFbmRzV2l0aFByZWZpeCAmJiAhbm9ybWFsaXplZFJlZnJlc2hQYXRoLnN0YXJ0c1dpdGgoYXV0aFBhdGhQcmVmaXgpO1xuICBjb25zdCBlZmZlY3RpdmVSZWZyZXNoUGF0aCA9IHNob3VsZEFkZFByZWZpeCA/IGAke2F1dGhQYXRoUHJlZml4fSR7bm9ybWFsaXplZFJlZnJlc2hQYXRofWAgOiBub3JtYWxpemVkUmVmcmVzaFBhdGg7XG5cbiAgY29uc3QgbG9naW5QYXRoID0gZW5kcG9pbnRzLmxvZ2luID8/ICcvbG9naW4nO1xuICBjb25zdCBzaWdudXBQYXRoID0gZW5kcG9pbnRzLnNpZ251cCA/PyAnL3NpZ251cCc7XG4gIGNvbnN0IHNvY2lhbEV4Y2hhbmdlUGF0aCA9IGVuZHBvaW50cy5zb2NpYWxFeGNoYW5nZSA/PyAnL3NvY2lhbC9leGNoYW5nZSc7XG5cbiAgY29uc3QgaXNBdXRoQXBpUmVxdWVzdCA9IHJlcS51cmwuaW5jbHVkZXMoYmFzZVVybCk7XG4gIC8vIENoZWNrIGlmIHJlcXVlc3QgaXMgdG8gcmVmcmVzaCBlbmRwb2ludCAodXNpbmcgZWZmZWN0aXZlIHBhdGggd2l0aCBhdXRoUGF0aFByZWZpeClcbiAgY29uc3QgaXNSZWZyZXNoRW5kcG9pbnQgPSByZXEudXJsLmluY2x1ZGVzKGVmZmVjdGl2ZVJlZnJlc2hQYXRoKTtcbiAgY29uc3QgaXNQdWJsaWNFbmRwb2ludCA9XG4gICAgcmVxLnVybC5pbmNsdWRlcyhsb2dpblBhdGgpIHx8IHJlcS51cmwuaW5jbHVkZXMoc2lnbnVwUGF0aCkgfHwgcmVxLnVybC5pbmNsdWRlcyhzb2NpYWxFeGNoYW5nZVBhdGgpO1xuICBjb25zdCBzaG91bGRJbnRlcmNlcHQgPSBpc0F1dGhBcGlSZXF1ZXN0ICYmICFpc1JlZnJlc2hFbmRwb2ludCAmJiAhaXNQdWJsaWNFbmRwb2ludDtcblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIEJ1aWxkIHJlcXVlc3QgZm9yIGNvb2tpZXMgbW9kZSAod2l0aENyZWRlbnRpYWxzICsgQ1NSRilcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICBsZXQgYXV0aFJlcSA9IHJlcTtcbiAgaWYgKHRva2VuRGVsaXZlcnkgPT09ICdjb29raWVzJykge1xuICAgIGF1dGhSZXEgPSBhdXRoUmVxLmNsb25lKHsgd2l0aENyZWRlbnRpYWxzOiB0cnVlIH0pO1xuICAgIGlmIChbJ1BPU1QnLCAnUFVUJywgJ1BBVENIJywgJ0RFTEVURSddLmluY2x1ZGVzKHJlcS5tZXRob2QpKSB7XG4gICAgICBjb25zdCBjc3JmQ29va2llTmFtZSA9IGNvbmZpZy5jc3JmPy5jb29raWVOYW1lID8/ICduYXV0aF9jc3JmX3Rva2VuJztcbiAgICAgIGNvbnN0IGNzcmZIZWFkZXJOYW1lID0gY29uZmlnLmNzcmY/LmhlYWRlck5hbWUgPz8gJ3gtY3NyZi10b2tlbic7XG4gICAgICBjb25zdCBjc3JmVG9rZW4gPSBnZXRDc3JmVG9rZW4oY3NyZkNvb2tpZU5hbWUpO1xuICAgICAgaWYgKGNzcmZUb2tlbikge1xuICAgICAgICBhdXRoUmVxID0gYXV0aFJlcS5jbG9uZSh7IHNldEhlYWRlcnM6IHsgW2NzcmZIZWFkZXJOYW1lXTogY3NyZlRva2VuIH0gfSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvLyBKU09OIG1vZGU6IGF0dGFjaCBBdXRob3JpemF0aW9uIGhlYWRlciBmb3IgSHR0cENsaWVudCBjYWxsc1xuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIFNpbXBsZSBhcHByb2FjaDogYXR0YWNoIHRva2VuIGlmIGF2YWlsYWJsZSwgbGV0IGJhY2tlbmQgdmFsaWRhdGVcbiAgLy8gSGFuZGxlIDQwMSByZWFjdGl2ZWx5IChtYXRjaGVzIG9sZCB3b3JraW5nIGltcGxlbWVudGF0aW9uKVxuICBjb25zdCBhdHRhY2hKc29uQXV0aCQgPVxuICAgIHRva2VuRGVsaXZlcnkgPT09ICdqc29uJyAmJiBzaG91bGRJbnRlcmNlcHQgJiYgIWF1dGhSZXEuaGVhZGVycy5oYXMoJ0F1dGhvcml6YXRpb24nKVxuICAgICAgPyBmcm9tKGF1dGhTZXJ2aWNlLmdldEFjY2Vzc1Rva2VuKCkpLnBpcGUoXG4gICAgICAgICAgc3dpdGNoTWFwKCh0b2tlbikgPT4ge1xuICAgICAgICAgICAgaWYgKHRva2VuKSB7XG4gICAgICAgICAgICAgIHJldHVybiBvZihhdXRoUmVxLmNsb25lKHsgc2V0SGVhZGVyczogeyBBdXRob3JpemF0aW9uOiBgQmVhcmVyICR7dG9rZW59YCB9IH0pKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBvZihhdXRoUmVxKTtcbiAgICAgICAgICB9KSxcbiAgICAgICAgKVxuICAgICAgOiBvZihhdXRoUmVxKTtcblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIFJlZnJlc2ggY29vcmRpbmF0aW9uXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgY29uc3QgZ2V0T3JTdGFydFJlZnJlc2gkID0gKCk6IE9ic2VydmFibGU8c3RyaW5nPiA9PiB7XG4gICAgaWYgKHJlZnJlc2hJbkZsaWdodCQpIHJldHVybiByZWZyZXNoSW5GbGlnaHQkO1xuXG4gICAgLy8gV0hZOiBXZSB3YW50IHRvIGVuc3VyZSBvbmx5IG9uZSByZWZyZXNoIHJlcXVlc3QgaXMgaW4gZmxpZ2h0IGF0IGFueSB0aW1lLlxuICAgIC8vIEFsbCByZXF1ZXN0cyAoaW5jbHVkaW5nIHRob3NlIHRoYXQgaGF2ZW4ndCBoaXQgdGhlIGJhY2tlbmQgeWV0KSBzaG91bGQgd2FpdCBmb3JcbiAgICAvLyB0aGUgc2FtZSByZWZyZXNoIHJlc3VsdCB0byBhdm9pZCBhIGJ1cnN0IG9mIDQwMXMgYW5kIHBvdGVudGlhbCBXQUYvcmF0ZS1saW1pdCBpc3N1ZXMuXG4gICAgaXNSZWZyZXNoaW5nID0gdHJ1ZTtcbiAgICByZWZyZXNoVG9rZW5TdWJqZWN0Lm5leHQobnVsbCk7XG5cbiAgICAvLyBXSFk6IEFsd2F5cyByZWZyZXNoIHZpYSB0aGUgY29yZSBjbGllbnQuXG4gICAgLy8gLSBFbnN1cmVzIGF1dGhQYXRoUHJlZml4ICsgZGVmYXVsdCBlbmRwb2ludHMgYXJlIGFwcGxpZWQgY29uc2lzdGVudGx5IChmaXhlcyAvcmVmcmVzaCB2cyAvYXV0aC9yZWZyZXNoKS5cbiAgICAvLyAtIENlbnRyYWxpemVzIENTUkYgKyBjcmVkZW50aWFscyBoYW5kbGluZyBpbiBvbmUgcGxhY2UuXG4gICAgY29uc3QgcmVmcmVzaFJlcXVlc3QkID0gZnJvbShhdXRoU2VydmljZS5nZXRDbGllbnQoKS5yZWZyZXNoVG9rZW5zKCkpO1xuXG4gICAgcmVmcmVzaEluRmxpZ2h0JCA9IHJlZnJlc2hSZXF1ZXN0JC5waXBlKFxuICAgICAgbWFwKChyZXNwb25zZSkgPT4ge1xuICAgICAgICAvLyBDb29raWVzIG1vZGU6IHN1Y2Nlc3MgaXMgZW5vdWdoICh0b2tlbnMgYXJlIGluIGh0dHBPbmx5IGNvb2tpZXMpLlxuICAgICAgICAvLyBKU09OIG1vZGU6IHdlIG5lZWQgdGhlIG5ldyBhY2Nlc3MgdG9rZW4gdG8gcmV0cnkgKyB1bmJsb2NrIHF1ZXVlZCByZXF1ZXN0cy5cbiAgICAgICAgY29uc3QgbmV3VG9rZW4gPSB0b2tlbkRlbGl2ZXJ5ID09PSAnanNvbicgPyByZXNwb25zZS5hY2Nlc3NUb2tlbiA6ICdzdWNjZXNzJztcblxuICAgICAgICBpZiAodG9rZW5EZWxpdmVyeSA9PT0gJ2pzb24nICYmICghbmV3VG9rZW4gfHwgbmV3VG9rZW4gPT09ICdzdWNjZXNzJykpIHtcbiAgICAgICAgICAvLyDimqDvuI8gV0FSTklORzogV2l0aG91dCBhbiBhY2Nlc3MgdG9rZW4gd2UgY2Fubm90IHNhZmVseSByZXRyeSByZXF1ZXN0cyBpbiBKU09OIG1vZGUuXG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdUb2tlbiByZWZyZXNoIGRpZCBub3QgcmV0dXJuIGFuIGFjY2VzcyB0b2tlbicpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmVmcmVzaFRva2VuU3ViamVjdC5uZXh0KG5ld1Rva2VuID8/ICdzdWNjZXNzJyk7XG4gICAgICAgIHJldHVybiBuZXdUb2tlbiA/PyAnc3VjY2Vzcyc7XG4gICAgICB9KSxcbiAgICAgIGNhdGNoRXJyb3IoKGVycikgPT4ge1xuICAgICAgICByZWZyZXNoVG9rZW5TdWJqZWN0Lm5leHQobnVsbCk7XG5cbiAgICAgICAgLy8gUmVmcmVzaCBmYWlsZWQgLT4gcmVkaXJlY3QgaWYgY29uZmlndXJlZFxuICAgICAgICBpZiAoY29uZmlnLnJlZGlyZWN0cz8uc2Vzc2lvbkV4cGlyZWQpIHtcbiAgICAgICAgICByb3V0ZXIubmF2aWdhdGVCeVVybChjb25maWcucmVkaXJlY3RzLnNlc3Npb25FeHBpcmVkKS5jYXRjaCgoKSA9PiB7XG4gICAgICAgICAgICAvLyBJZ25vcmUgbmF2aWdhdGlvbiBlcnJvcnNcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aHJvd0Vycm9yKCgpID0+IGVycik7XG4gICAgICB9KSxcbiAgICAgIGZpbmFsaXplKCgpID0+IHtcbiAgICAgICAgaXNSZWZyZXNoaW5nID0gZmFsc2U7XG4gICAgICAgIHJlZnJlc2hJbkZsaWdodCQgPSBudWxsO1xuICAgICAgfSksXG4gICAgICBzaGFyZVJlcGxheSh7IGJ1ZmZlclNpemU6IDEsIHJlZkNvdW50OiBmYWxzZSB9KSxcbiAgICApO1xuXG4gICAgcmV0dXJuIHJlZnJlc2hJbkZsaWdodCQ7XG4gIH07XG5cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvLyBQcmUtcmVxdWVzdCBnYXRpbmc6IGJsb2NrIHJlcXVlc3RzIHdoaWxlIHJlZnJlc2ggaXMgaW4tZmxpZ2h0XG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gV0hZOiBQcmV2ZW50IG11bHRpcGxlIHJlcXVlc3RzIGZyb20gaGl0dGluZyB0aGUgYmFja2VuZCB3aXRoIGFuIGV4cGlyZWQgdG9rZW4gYW5kIHJldHVybmluZyA0MDEuXG4gIC8vIFdlIHF1ZXVlIGFsbCBhdXRoIEFQSSBjYWxscyBkdXJpbmcgcmVmcmVzaCBhbmQgcmVsZWFzZSB0aGVtIG9uY2UgcmVmcmVzaCBzdWNjZWVkcy5cbiAgaWYgKHNob3VsZEludGVyY2VwdCAmJiBpc1JlZnJlc2hpbmcgJiYgcmVmcmVzaEluRmxpZ2h0JCkge1xuICAgIHJldHVybiByZWZyZXNoSW5GbGlnaHQkLnBpcGUoXG4gICAgICBzd2l0Y2hNYXAoKHRva2VuKSA9PiB7XG4gICAgICAgIGNvbnN0IGdhdGVkUmVxID0gYnVpbGRSZXRyeVJlcXVlc3QoYXV0aFJlcSwgdG9rZW5EZWxpdmVyeSwgdG9rZW4sIGNvbmZpZy5jc3JmKTtcbiAgICAgICAgcmV0dXJuIG5leHQoZ2F0ZWRSZXEpO1xuICAgICAgfSksXG4gICAgKTtcbiAgfVxuXG4gIHJldHVybiBhdHRhY2hKc29uQXV0aCQucGlwZShcbiAgICBzd2l0Y2hNYXAoKHJlcXVlc3RXaXRoQXV0aCkgPT5cbiAgICAgIG5leHQocmVxdWVzdFdpdGhBdXRoKS5waXBlKFxuICAgICAgICBjYXRjaEVycm9yKChlcnJvcjogdW5rbm93bikgPT4ge1xuICAgICAgICAgIGNvbnN0IHNob3VsZEhhbmRsZSA9XG4gICAgICAgICAgICBlcnJvciBpbnN0YW5jZW9mIEh0dHBFcnJvclJlc3BvbnNlICYmIGVycm9yLnN0YXR1cyA9PT0gNDAxICYmIHNob3VsZEludGVyY2VwdCAmJiAhcmV0cmllZFJlcXVlc3RzLmhhcyhyZXEpO1xuXG4gICAgICAgICAgaWYgKCFzaG91bGRIYW5kbGUpIHtcbiAgICAgICAgICAgIHJldHVybiB0aHJvd0Vycm9yKCgpID0+IGVycm9yKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXRyaWVkUmVxdWVzdHMuYWRkKHJlcSk7XG5cbiAgICAgICAgICByZXR1cm4gZ2V0T3JTdGFydFJlZnJlc2gkKCkucGlwZShcbiAgICAgICAgICAgIHN3aXRjaE1hcCgodG9rZW4pID0+IHtcbiAgICAgICAgICAgICAgY29uc3QgcmV0cnlSZXEgPSBidWlsZFJldHJ5UmVxdWVzdChyZXF1ZXN0V2l0aEF1dGgsIHRva2VuRGVsaXZlcnksIHRva2VuLCBjb25maWcuY3NyZik7XG4gICAgICAgICAgICAgIHJldHJpZWRSZXF1ZXN0cy5hZGQocmV0cnlSZXEpO1xuICAgICAgICAgICAgICByZXR1cm4gbmV4dChyZXRyeVJlcSk7XG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICApO1xuICAgICAgICB9KSxcbiAgICAgICksXG4gICAgKSxcbiAgKTtcbn1cbiJdfQ==
|
|
@@ -1,29 +1,10 @@
|
|
|
1
1
|
import { inject, PLATFORM_ID } from '@angular/core';
|
|
2
2
|
import { isPlatformBrowser } from '@angular/common';
|
|
3
|
-
import { HttpClient
|
|
3
|
+
import { HttpClient } from '@angular/common/http';
|
|
4
4
|
import { Router } from '@angular/router';
|
|
5
|
-
import { catchError, switchMap, throwError, filter, take, BehaviorSubject, from } from 'rxjs';
|
|
6
5
|
import { NAUTH_CLIENT_CONFIG } from '../ngmodule/tokens';
|
|
7
6
|
import { AuthService } from '../ngmodule/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
|
-
}
|
|
7
|
+
import { createNAuthAuthHttpInterceptor } from './auth-interceptor.shared';
|
|
27
8
|
/**
|
|
28
9
|
* Angular HTTP interceptor for nauth-toolkit.
|
|
29
10
|
*
|
|
@@ -41,248 +22,8 @@ export const authInterceptor = (req, next) => {
|
|
|
41
22
|
if (!isBrowser) {
|
|
42
23
|
return next(req);
|
|
43
24
|
}
|
|
44
|
-
|
|
45
|
-
if (req.url.includes('/profile') && req.method === 'PUT') {
|
|
46
|
-
fetch('http://127.0.0.1:7242/ingest/97f9fe53-6a8b-43e2-ae9b-4b2d0f725816', {
|
|
47
|
-
method: 'POST',
|
|
48
|
-
headers: { 'Content-Type': 'application/json' },
|
|
49
|
-
body: JSON.stringify({
|
|
50
|
-
location: 'auth.interceptor.ts:entry',
|
|
51
|
-
message: 'Original request entry',
|
|
52
|
-
data: { reqBody: req.body, reqBodyType: typeof req.body, reqMethod: req.method, reqUrl: req.url },
|
|
53
|
-
timestamp: Date.now(),
|
|
54
|
-
sessionId: 'debug-session',
|
|
55
|
-
hypothesisId: 'A',
|
|
56
|
-
}),
|
|
57
|
-
}).catch(() => { });
|
|
58
|
-
}
|
|
59
|
-
// #endregion
|
|
60
|
-
const tokenDelivery = config.tokenDelivery;
|
|
61
|
-
const baseUrl = config.baseUrl;
|
|
62
|
-
const endpoints = config.endpoints ?? {};
|
|
63
|
-
const refreshPath = endpoints.refresh ?? '/refresh';
|
|
64
|
-
const loginPath = endpoints.login ?? '/login';
|
|
65
|
-
const signupPath = endpoints.signup ?? '/signup';
|
|
66
|
-
const socialExchangePath = endpoints.socialExchange ?? '/social/exchange';
|
|
67
|
-
const refreshUrl = `${baseUrl}${refreshPath}`;
|
|
68
|
-
const isAuthApiRequest = req.url.includes(baseUrl);
|
|
69
|
-
const isRefreshEndpoint = req.url.includes(refreshPath);
|
|
70
|
-
const isPublicEndpoint = req.url.includes(loginPath) || req.url.includes(signupPath) || req.url.includes(socialExchangePath);
|
|
71
|
-
// Build request with credentials (cookies mode only)
|
|
72
|
-
let authReq = req;
|
|
73
|
-
if (tokenDelivery === 'cookies') {
|
|
74
|
-
authReq = authReq.clone({ withCredentials: true });
|
|
75
|
-
if (['POST', 'PUT', 'PATCH', 'DELETE'].includes(req.method)) {
|
|
76
|
-
const csrfCookieName = config.csrf?.cookieName ?? 'nauth_csrf_token';
|
|
77
|
-
const csrfHeaderName = config.csrf?.headerName ?? 'x-csrf-token';
|
|
78
|
-
const csrfToken = getCsrfToken(csrfCookieName);
|
|
79
|
-
if (csrfToken) {
|
|
80
|
-
authReq = authReq.clone({ setHeaders: { [csrfHeaderName]: csrfToken } });
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return next(authReq).pipe(catchError((error) => {
|
|
85
|
-
const shouldHandle = error instanceof HttpErrorResponse &&
|
|
86
|
-
error.status === 401 &&
|
|
87
|
-
isAuthApiRequest &&
|
|
88
|
-
!isRefreshEndpoint &&
|
|
89
|
-
!isPublicEndpoint &&
|
|
90
|
-
!retriedRequests.has(req);
|
|
91
|
-
if (!shouldHandle) {
|
|
92
|
-
return throwError(() => error);
|
|
93
|
-
}
|
|
94
|
-
// Mark original request as retried to prevent infinite loops
|
|
95
|
-
retriedRequests.add(req);
|
|
96
|
-
if (config.debug) {
|
|
97
|
-
console.warn('[nauth-interceptor] 401 detected:', req.url);
|
|
98
|
-
}
|
|
99
|
-
if (!isRefreshing) {
|
|
100
|
-
isRefreshing = true;
|
|
101
|
-
refreshTokenSubject.next(null);
|
|
102
|
-
if (config.debug) {
|
|
103
|
-
console.warn('[nauth-interceptor] Starting refresh...');
|
|
104
|
-
}
|
|
105
|
-
// Refresh based on mode
|
|
106
|
-
const refresh$ = tokenDelivery === 'cookies'
|
|
107
|
-
? http.post(refreshUrl, {}, { withCredentials: true })
|
|
108
|
-
: from(authService.refresh());
|
|
109
|
-
return refresh$.pipe(switchMap((response) => {
|
|
110
|
-
if (config.debug) {
|
|
111
|
-
console.warn('[nauth-interceptor] Refresh successful');
|
|
112
|
-
}
|
|
113
|
-
isRefreshing = false;
|
|
114
|
-
// Get new token (JSON mode) or signal success (cookies mode)
|
|
115
|
-
const newToken = 'accessToken' in response ? response.accessToken : 'success';
|
|
116
|
-
refreshTokenSubject.next(newToken ?? 'success');
|
|
117
|
-
// #region agent log
|
|
118
|
-
fetch('http://127.0.0.1:7242/ingest/97f9fe53-6a8b-43e2-ae9b-4b2d0f725816', {
|
|
119
|
-
method: 'POST',
|
|
120
|
-
headers: { 'Content-Type': 'application/json' },
|
|
121
|
-
body: JSON.stringify({
|
|
122
|
-
location: 'auth.interceptor.ts:125',
|
|
123
|
-
message: 'Before buildRetryRequest',
|
|
124
|
-
data: {
|
|
125
|
-
authReqBody: authReq.body,
|
|
126
|
-
authReqMethod: authReq.method,
|
|
127
|
-
authReqUrl: authReq.url,
|
|
128
|
-
authReqBodyType: typeof authReq.body,
|
|
129
|
-
},
|
|
130
|
-
timestamp: Date.now(),
|
|
131
|
-
sessionId: 'debug-session',
|
|
132
|
-
hypothesisId: 'A',
|
|
133
|
-
}),
|
|
134
|
-
}).catch(() => { });
|
|
135
|
-
// #endregion
|
|
136
|
-
// Build retry request with fresh CSRF token (re-read from cookie after refresh)
|
|
137
|
-
const retryReq = buildRetryRequest(authReq, tokenDelivery, newToken, config.csrf);
|
|
138
|
-
// #region agent log
|
|
139
|
-
fetch('http://127.0.0.1:7242/ingest/97f9fe53-6a8b-43e2-ae9b-4b2d0f725816', {
|
|
140
|
-
method: 'POST',
|
|
141
|
-
headers: { 'Content-Type': 'application/json' },
|
|
142
|
-
body: JSON.stringify({
|
|
143
|
-
location: 'auth.interceptor.ts:130',
|
|
144
|
-
message: 'After buildRetryRequest',
|
|
145
|
-
data: {
|
|
146
|
-
retryReqBody: retryReq.body,
|
|
147
|
-
retryReqMethod: retryReq.method,
|
|
148
|
-
retryReqUrl: retryReq.url,
|
|
149
|
-
retryReqBodyType: typeof retryReq.body,
|
|
150
|
-
headersKeys: retryReq.headers.keys(),
|
|
151
|
-
},
|
|
152
|
-
timestamp: Date.now(),
|
|
153
|
-
sessionId: 'debug-session',
|
|
154
|
-
hypothesisId: 'B',
|
|
155
|
-
}),
|
|
156
|
-
}).catch(() => { });
|
|
157
|
-
// #endregion
|
|
158
|
-
if (config.debug) {
|
|
159
|
-
console.warn('[nauth-interceptor] Retrying:', req.url);
|
|
160
|
-
}
|
|
161
|
-
// Retry the request with fresh token/CSRF
|
|
162
|
-
// IMPORTANT: Errors from the retry (e.g., 400 validation) should NOT trigger
|
|
163
|
-
// session expiration redirect. Only the refresh failure should redirect.
|
|
164
|
-
return next(retryReq).pipe(catchError((retryErr) => {
|
|
165
|
-
// Retry failed (could be 400, 403, 500, etc.)
|
|
166
|
-
// Just propagate the error - don't redirect to login
|
|
167
|
-
if (config.debug) {
|
|
168
|
-
console.warn('[nauth-interceptor] Retry request failed:', retryErr);
|
|
169
|
-
}
|
|
170
|
-
return throwError(() => retryErr);
|
|
171
|
-
}));
|
|
172
|
-
}), catchError((err) => {
|
|
173
|
-
// This only catches REFRESH failures, not retry failures
|
|
174
|
-
if (config.debug) {
|
|
175
|
-
console.error('[nauth-interceptor] Refresh failed:', err);
|
|
176
|
-
}
|
|
177
|
-
isRefreshing = false;
|
|
178
|
-
refreshTokenSubject.next(null);
|
|
179
|
-
// Handle session expiration - redirect to configured URL
|
|
180
|
-
// Only redirect if refresh itself failed (not if retry failed)
|
|
181
|
-
if (config.redirects?.sessionExpired) {
|
|
182
|
-
router.navigateByUrl(config.redirects.sessionExpired).catch((navError) => {
|
|
183
|
-
if (config.debug) {
|
|
184
|
-
console.error('[nauth-interceptor] Navigation failed:', navError);
|
|
185
|
-
}
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
return throwError(() => err);
|
|
189
|
-
}));
|
|
190
|
-
}
|
|
191
|
-
else {
|
|
192
|
-
// Wait for ongoing refresh
|
|
193
|
-
if (config.debug) {
|
|
194
|
-
console.warn('[nauth-interceptor] Waiting for refresh...');
|
|
195
|
-
}
|
|
196
|
-
return refreshTokenSubject.pipe(filter((token) => token !== null), take(1), switchMap((token) => {
|
|
197
|
-
if (config.debug) {
|
|
198
|
-
console.warn('[nauth-interceptor] Refresh done, retrying:', req.url);
|
|
199
|
-
}
|
|
200
|
-
const retryReq = buildRetryRequest(authReq, tokenDelivery, token, config.csrf);
|
|
201
|
-
// Retry the request - errors here should propagate normally
|
|
202
|
-
// without triggering session expiration redirect
|
|
203
|
-
return next(retryReq).pipe(catchError((retryErr) => {
|
|
204
|
-
if (config.debug) {
|
|
205
|
-
console.warn('[nauth-interceptor] Retry request failed:', retryErr);
|
|
206
|
-
}
|
|
207
|
-
return throwError(() => retryErr);
|
|
208
|
-
}));
|
|
209
|
-
}));
|
|
210
|
-
}
|
|
211
|
-
}));
|
|
25
|
+
return createNAuthAuthHttpInterceptor({ config, http, authService, router, next, req });
|
|
212
26
|
};
|
|
213
|
-
/**
|
|
214
|
-
* Build retry request with appropriate auth.
|
|
215
|
-
*
|
|
216
|
-
* CRITICAL FIX: In cookies mode, after refresh the server may send updated cookies.
|
|
217
|
-
* We MUST re-read the CSRF token from the cookie before retrying to ensure we have
|
|
218
|
-
* the current CSRF token that matches what the server expects.
|
|
219
|
-
*
|
|
220
|
-
* In JSON mode: Clones the request and adds the new Bearer token.
|
|
221
|
-
*
|
|
222
|
-
* @param originalReq - The base request (already has withCredentials if cookies mode)
|
|
223
|
-
* @param tokenDelivery - 'cookies' or 'json'
|
|
224
|
-
* @param newToken - The new access token (JSON mode only)
|
|
225
|
-
* @param csrfConfig - CSRF configuration to re-read token from cookie
|
|
226
|
-
* @returns The request ready for retry with fresh auth
|
|
227
|
-
*/
|
|
228
|
-
function buildRetryRequest(originalReq, tokenDelivery, newToken, csrfConfig) {
|
|
229
|
-
if (tokenDelivery === 'json' && newToken && newToken !== 'success') {
|
|
230
|
-
return originalReq.clone({
|
|
231
|
-
setHeaders: { Authorization: `Bearer ${newToken}` },
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
// Cookies mode: Browser automatically sends updated httpOnly cookies (access/refresh tokens).
|
|
235
|
-
// However, CSRF token must match the cookie value at the moment of retry.
|
|
236
|
-
// We ALWAYS re-read from document.cookie here (using defaults when csrfConfig
|
|
237
|
-
// is not provided) to avoid stale header values after refresh or across tabs.
|
|
238
|
-
if (tokenDelivery === 'cookies' && ['POST', 'PUT', 'PATCH', 'DELETE'].includes(originalReq.method)) {
|
|
239
|
-
const csrfCookieName = csrfConfig?.cookieName ?? 'nauth_csrf_token';
|
|
240
|
-
const csrfHeaderName = csrfConfig?.headerName ?? 'x-csrf-token';
|
|
241
|
-
const freshCsrfToken = getCsrfToken(csrfCookieName);
|
|
242
|
-
// #region agent log
|
|
243
|
-
fetch('http://127.0.0.1:7242/ingest/97f9fe53-6a8b-43e2-ae9b-4b2d0f725816', {
|
|
244
|
-
method: 'POST',
|
|
245
|
-
headers: { 'Content-Type': 'application/json' },
|
|
246
|
-
body: JSON.stringify({
|
|
247
|
-
location: 'auth.interceptor.ts:buildRetryRequest',
|
|
248
|
-
message: 'Inside buildRetryRequest cookies branch',
|
|
249
|
-
data: {
|
|
250
|
-
originalReqBody: originalReq.body,
|
|
251
|
-
originalReqBodyType: typeof originalReq.body,
|
|
252
|
-
freshCsrfToken: freshCsrfToken?.substring(0, 8),
|
|
253
|
-
method: originalReq.method,
|
|
254
|
-
},
|
|
255
|
-
timestamp: Date.now(),
|
|
256
|
-
sessionId: 'debug-session',
|
|
257
|
-
hypothesisId: 'C',
|
|
258
|
-
}),
|
|
259
|
-
}).catch(() => { });
|
|
260
|
-
// #endregion
|
|
261
|
-
if (freshCsrfToken) {
|
|
262
|
-
// Clone with fresh CSRF token in header
|
|
263
|
-
const cloned = originalReq.clone({
|
|
264
|
-
setHeaders: { [csrfHeaderName]: freshCsrfToken },
|
|
265
|
-
});
|
|
266
|
-
// #region agent log
|
|
267
|
-
fetch('http://127.0.0.1:7242/ingest/97f9fe53-6a8b-43e2-ae9b-4b2d0f725816', {
|
|
268
|
-
method: 'POST',
|
|
269
|
-
headers: { 'Content-Type': 'application/json' },
|
|
270
|
-
body: JSON.stringify({
|
|
271
|
-
location: 'auth.interceptor.ts:buildRetryRequest:afterClone',
|
|
272
|
-
message: 'After clone with setHeaders',
|
|
273
|
-
data: { clonedBody: cloned.body, clonedBodyType: typeof cloned.body, originalBody: originalReq.body },
|
|
274
|
-
timestamp: Date.now(),
|
|
275
|
-
sessionId: 'debug-session',
|
|
276
|
-
hypothesisId: 'D',
|
|
277
|
-
}),
|
|
278
|
-
}).catch(() => { });
|
|
279
|
-
// #endregion
|
|
280
|
-
return cloned;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
// No changes needed (GET request or no CSRF token available)
|
|
284
|
-
return originalReq;
|
|
285
|
-
}
|
|
286
27
|
/**
|
|
287
28
|
* Class-based interceptor for NgModule compatibility.
|
|
288
29
|
*/
|
|
@@ -291,4 +32,4 @@ export class AuthInterceptor {
|
|
|
291
32
|
return authInterceptor(req, next);
|
|
292
33
|
}
|
|
293
34
|
}
|
|
294
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC5pbnRlcmNlcHRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvYXV0aC5pbnRlcmNlcHRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLFdBQVcsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNwRCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNwRCxPQUFPLEVBQWlELFVBQVUsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ3BILE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUN6QyxPQUFPLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxlQUFlLEVBQUUsSUFBSSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzlGLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ3pELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUV2RDs7O0dBR0c7QUFDSCxJQUFJLFlBQVksR0FBRyxLQUFLLENBQUM7QUFDekIsTUFBTSxtQkFBbUIsR0FBRyxJQUFJLGVBQWUsQ0FBZ0IsSUFBSSxDQUFDLENBQUM7QUFFckU7O0dBRUc7QUFDSCxNQUFNLGVBQWUsR0FBRyxJQUFJLE9BQU8sRUFBd0IsQ0FBQztBQUU1RDs7R0FFRztBQUNILFNBQVMsWUFBWSxDQUFDLFVBQWtCO0lBQ3RDLElBQUksT0FBTyxRQUFRLEtBQUssV0FBVztRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQ2pELE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksTUFBTSxDQUFDLFFBQVEsVUFBVSxVQUFVLENBQUMsQ0FBQyxDQUFDO0lBQzlFLE9BQU8sS0FBSyxDQUFDLENBQUMsQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLLENB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QUUsVUFBVSxFQUFFLE1BQU0sQ0FBQyxJQUFJLEVBQUUsY0FBYyxFQUFFLE9BQU8sTUFBTSxDQUFDLElBQUksRUFBRSxZQUFZLEVBQUUsV0FBVyxDQUFDLElBQUksRUFBRTtvQkFDckcsU0FBUyxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUU7b0JBQ3JCLFNBQVMsRUFBRSxlQUFlO29CQUMxQixZQUFZLEVBQUUsR0FBRztpQkFDbEIsQ0FBQzthQUNILENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLEdBQUUsQ0FBQyxDQUFDLENBQUM7WUFDbkIsYUFBYTtZQUViLE9BQU8sTUFBTSxDQUFDO1FBQ2hCLENBQUM7SUFDSCxDQUFDO0lBRUQsNkRBQTZEO0lBQzdELE9BQU8sV0FBVyxDQUFDO0FBQ3JCLENBQUM7QUFFRDs7R0FFRztBQUNILE1BQU0sT0FBTyxlQUFlO0lBQzFCLFNBQVMsQ0FBQyxHQUF5QixFQUFFLElBQW1CO1FBQ3RELE9BQU8sZUFBZSxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsQ0FBQztJQUNwQyxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBpbmplY3QsIFBMQVRGT1JNX0lEIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBpc1BsYXRmb3JtQnJvd3NlciB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBIdHRwSGFuZGxlckZuLCBIdHRwSW50ZXJjZXB0b3JGbiwgSHR0cFJlcXVlc3QsIEh0dHBDbGllbnQsIEh0dHBFcnJvclJlc3BvbnNlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xuaW1wb3J0IHsgUm91dGVyIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcbmltcG9ydCB7IGNhdGNoRXJyb3IsIHN3aXRjaE1hcCwgdGhyb3dFcnJvciwgZmlsdGVyLCB0YWtlLCBCZWhhdmlvclN1YmplY3QsIGZyb20gfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IE5BVVRIX0NMSUVOVF9DT05GSUcgfSBmcm9tICcuLi9uZ21vZHVsZS90b2tlbnMnO1xuaW1wb3J0IHsgQXV0aFNlcnZpY2UgfSBmcm9tICcuLi9uZ21vZHVsZS9hdXRoLnNlcnZpY2UnO1xuXG4vKipcbiAqIFJlZnJlc2ggc3RhdGUgbWFuYWdlbWVudC5cbiAqIEJlaGF2aW9yU3ViamVjdCBwYXR0ZXJuIGlzIHRoZSBpbmR1c3RyeS1zdGFuZGFyZCBmb3IgdG9rZW4gcmVmcmVzaC5cbiAqL1xubGV0IGlzUmVmcmVzaGluZyA9IGZhbHNlO1xuY29uc3QgcmVmcmVzaFRva2VuU3ViamVjdCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8c3RyaW5nIHwgbnVsbD4obnVsbCk7XG5cbi8qKlxuICogVHJhY2sgcmV0cmllZCByZXF1ZXN0cyB0byBwcmV2ZW50IGluZmluaXRlIGxvb3BzLlxuICovXG5jb25zdCByZXRyaWVkUmVxdWVzdHMgPSBuZXcgV2Vha1NldDxIdHRwUmVxdWVzdDx1bmtub3duPj4oKTtcblxuLyoqXG4gKiBHZXQgQ1NSRiB0b2tlbiBmcm9tIGNvb2tpZS5cbiAqL1xuZnVuY3Rpb24gZ2V0Q3NyZlRva2VuKGNvb2tpZU5hbWU6IHN0cmluZyk6IHN0cmluZyB8IG51bGwge1xuICBpZiAodHlwZW9mIGRvY3VtZW50ID09PSAndW5kZWZpbmVkJykgcmV0dXJuIG51bGw7XG4gIGNvbnN0IG1hdGNoID0gZG9jdW1lbnQuY29va2llLm1hdGNoKG5ldyBSZWdFeHAoYChefCApJHtjb29raWVOYW1lfT0oW147XSspYCkpO1xuICByZXR1cm4gbWF0Y2ggPyBkZWNvZGVVUklDb21wb25lbnQobWF0Y2hbMl0pIDogbnVsbDtcbn1cblxuLyoqXG4gKiBBbmd1bGFyIEhUVFAgaW50ZXJjZXB0b3IgZm9yIG5hdXRoLXRvb2xraXQuXG4gKlxuICogSGFuZGxlczpcbiAqIC0gQ29va2llcyBtb2RlOiB3aXRoQ3JlZGVudGlhbHMgKyBDU1JGIHRva2VucyArIHJlZnJlc2ggdmlhIFBPU1RcbiAqIC0gSlNPTiBtb2RlOiByZWZyZXNoIHZpYSBTREssIHJldHJ5IHdpdGggbmV3IHRva2VuXG4gKi9cbmV4cG9ydCBjb25zdCBhdXRoSW50ZXJjZXB0b3I6IEh0dHBJbnRlcmNlcHRvckZuID0gKHJlcTogSHR0cFJlcXVlc3Q8dW5rbm93bj4sIG5leHQ6IEh0dHBIYW5kbGVyRm4pID0+IHtcbiAgY29uc3QgY29uZmlnID0gaW5qZWN0KE5BVVRIX0NMSUVOVF9DT05GSUcpO1xuICBjb25zdCBodHRwID0gaW5qZWN0KEh0dHBDbGllbnQpO1xuICBjb25zdCBhdXRoU2VydmljZSA9IGluamVjdChBdXRoU2VydmljZSk7XG4gIGNvbnN0IHBsYXRmb3JtSWQgPSBpbmplY3QoUExBVEZPUk1fSUQpO1xuICBjb25zdCByb3V0ZXIgPSBpbmplY3QoUm91dGVyKTtcbiAgY29uc3QgaXNCcm93c2VyID0gaXNQbGF0Zm9ybUJyb3dzZXIocGxhdGZvcm1JZCk7XG5cbiAgaWYgKCFpc0Jyb3dzZXIpIHtcbiAgICByZXR1cm4gbmV4dChyZXEpO1xuICB9XG5cbiAgLy8gI3JlZ2lvbiBhZ2VudCBsb2dcbiAgaWYgKHJlcS51cmwuaW5jbHVkZXMoJy9wcm9maWxlJykgJiYgcmVxLm1ldGhvZCA9PT0gJ1BVVCcpIHtcbiAgICBmZXRjaCgnaHR0cDovLzEyNy4wLjAuMTo3MjQyL2luZ2VzdC85N2Y5ZmU1My02YThiLTQzZTItYWU5Yi00YjJkMGY3MjU4MTYnLCB7XG4gICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgIGhlYWRlcnM6IHsgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyB9LFxuICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICBsb2NhdGlvbjogJ2F1dGguaW50ZXJjZXB0b3IudHM6ZW50cnknLFxuICAgICAgICBtZXNzYWdlOiAnT3JpZ2luYWwgcmVxdWVzdCBlbnRyeScsXG4gICAgICAgIGRhdGE6IHsgcmVxQm9keTogcmVxLmJvZHksIHJlcUJvZHlUeXBlOiB0eXBlb2YgcmVxLmJvZHksIHJlcU1ldGhvZDogcmVxLm1ldGhvZCwgcmVxVXJsOiByZXEudXJsIH0sXG4gICAgICAgIHRpbWVzdGFtcDogRGF0ZS5ub3coKSxcbiAgICAgICAgc2Vzc2lvbklkOiAnZGVidWctc2Vzc2lvbicsXG4gICAgICAgIGh5cG90aGVzaXNJZDogJ0EnLFxuICAgICAgfSksXG4gICAgfSkuY2F0Y2goKCkgPT4ge30pO1xuICB9XG4gIC8vICNlbmRyZWdpb25cblxuICBjb25zdCB0b2tlbkRlbGl2ZXJ5ID0gY29uZmlnLnRva2VuRGVsaXZlcnk7XG4gIGNvbnN0IGJhc2VVcmwgPSBjb25maWcuYmFzZVVybDtcbiAgY29uc3QgZW5kcG9pbnRzID0gY29uZmlnLmVuZHBvaW50cyA/PyB7fTtcbiAgY29uc3QgcmVmcmVzaFBhdGggPSBlbmRwb2ludHMucmVmcmVzaCA/PyAnL3JlZnJlc2gnO1xuICBjb25zdCBsb2dpblBhdGggPSBlbmRwb2ludHMubG9naW4gPz8gJy9sb2dpbic7XG4gIGNvbnN0IHNpZ251cFBhdGggPSBlbmRwb2ludHMuc2lnbnVwID8/ICcvc2lnbnVwJztcbiAgY29uc3Qgc29jaWFsRXhjaGFuZ2VQYXRoID0gZW5kcG9pbnRzLnNvY2lhbEV4Y2hhbmdlID8/ICcvc29jaWFsL2V4Y2hhbmdlJztcbiAgY29uc3QgcmVmcmVzaFVybCA9IGAke2Jhc2VVcmx9JHtyZWZyZXNoUGF0aH1gO1xuXG4gIGNvbnN0IGlzQXV0aEFwaVJlcXVlc3QgPSByZXEudXJsLmluY2x1ZGVzKGJhc2VVcmwpO1xuICBjb25zdCBpc1JlZnJlc2hFbmRwb2ludCA9IHJlcS51cmwuaW5jbHVkZXMocmVmcmVzaFBhdGgpO1xuICBjb25zdCBpc1B1YmxpY0VuZHBvaW50ID1cbiAgICByZXEudXJsLmluY2x1ZGVzKGxvZ2luUGF0aCkgfHwgcmVxLnVybC5pbmNsdWRlcyhzaWdudXBQYXRoKSB8fCByZXEudXJsLmluY2x1ZGVzKHNvY2lhbEV4Y2hhbmdlUGF0aCk7XG5cbiAgLy8gQnVpbGQgcmVxdWVzdCB3aXRoIGNyZWRlbnRpYWxzIChjb29raWVzIG1vZGUgb25seSlcbiAgbGV0IGF1dGhSZXEgPSByZXE7XG4gIGlmICh0b2tlbkRlbGl2ZXJ5ID09PSAnY29va2llcycpIHtcbiAgICBhdXRoUmVxID0gYXV0aFJlcS5jbG9uZSh7IHdpdGhDcmVkZW50aWFsczogdHJ1ZSB9KTtcblxuICAgIGlmIChbJ1BPU1QnLCAnUFVUJywgJ1BBVENIJywgJ0RFTEVURSddLmluY2x1ZGVzKHJlcS5tZXRob2QpKSB7XG4gICAgICBjb25zdCBjc3JmQ29va2llTmFtZSA9IGNvbmZpZy5jc3JmPy5jb29raWVOYW1lID8/ICduYXV0aF9jc3JmX3Rva2VuJztcbiAgICAgIGNvbnN0IGNzcmZIZWFkZXJOYW1lID0gY29uZmlnLmNzcmY/LmhlYWRlck5hbWUgPz8gJ3gtY3NyZi10b2tlbic7XG4gICAgICBjb25zdCBjc3JmVG9rZW4gPSBnZXRDc3JmVG9rZW4oY3NyZkNvb2tpZU5hbWUpO1xuICAgICAgaWYgKGNzcmZUb2tlbikge1xuICAgICAgICBhdXRoUmVxID0gYXV0aFJlcS5jbG9uZSh7IHNldEhlYWRlcnM6IHsgW2NzcmZIZWFkZXJOYW1lXTogY3NyZlRva2VuIH0gfSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIG5leHQoYXV0aFJlcSkucGlwZShcbiAgICBjYXRjaEVycm9yKChlcnJvcjogdW5rbm93bikgPT4ge1xuICAgICAgY29uc3Qgc2hvdWxkSGFuZGxlID1cbiAgICAgICAgZXJyb3IgaW5zdGFuY2VvZiBIdHRwRXJyb3JSZXNwb25zZSAmJlxuICAgICAgICBlcnJvci5zdGF0dXMgPT09IDQwMSAmJlxuICAgICAgICBpc0F1dGhBcGlSZXF1ZXN0ICYmXG4gICAgICAgICFpc1JlZnJlc2hFbmRwb2ludCAmJlxuICAgICAgICAhaXNQdWJsaWNFbmRwb2ludCAmJlxuICAgICAgICAhcmV0cmllZFJlcXVlc3RzLmhhcyhyZXEpO1xuXG4gICAgICBpZiAoIXNob3VsZEhhbmRsZSkge1xuICAgICAgICByZXR1cm4gdGhyb3dFcnJvcigoKSA9PiBlcnJvcik7XG4gICAgICB9XG5cbiAgICAgIC8vIE1hcmsgb3JpZ2luYWwgcmVxdWVzdCBhcyByZXRyaWVkIHRvIHByZXZlbnQgaW5maW5pdGUgbG9vcHNcbiAgICAgIHJldHJpZWRSZXF1ZXN0cy5hZGQocmVxKTtcblxuICAgICAgaWYgKGNvbmZpZy5kZWJ1Zykge1xuICAgICAgICBjb25zb2xlLndhcm4oJ1tuYXV0aC1pbnRlcmNlcHRvcl0gNDAxIGRldGVjdGVkOicsIHJlcS51cmwpO1xuICAgICAgfVxuXG4gICAgICBpZiAoIWlzUmVmcmVzaGluZykge1xuICAgICAgICBpc1JlZnJlc2hpbmcgPSB0cnVlO1xuICAgICAgICByZWZyZXNoVG9rZW5TdWJqZWN0Lm5leHQobnVsbCk7XG5cbiAgICAgICAgaWYgKGNvbmZpZy5kZWJ1Zykge1xuICAgICAgICAgIGNvbnNvbGUud2FybignW25hdXRoLWludGVyY2VwdG9yXSBTdGFydGluZyByZWZyZXNoLi4uJyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBSZWZyZXNoIGJhc2VkIG9uIG1vZGVcbiAgICAgICAgY29uc3QgcmVmcmVzaCQgPVxuICAgICAgICAgIHRva2VuRGVsaXZlcnkgPT09ICdjb29raWVzJ1xuICAgICAgICAgICAgPyBodHRwLnBvc3Q8eyBhY2Nlc3NUb2tlbj86IHN0cmluZyB9PihyZWZyZXNoVXJsLCB7fSwgeyB3aXRoQ3JlZGVudGlhbHM6IHRydWUgfSlcbiAgICAgICAgICAgIDogZnJvbShhdXRoU2VydmljZS5yZWZyZXNoKCkpO1xuXG4gICAgICAgIHJldHVybiByZWZyZXNoJC5waXBlKFxuICAgICAgICAgIHN3aXRjaE1hcCgocmVzcG9uc2UpID0+IHtcbiAgICAgICAgICAgIGlmIChjb25maWcuZGVidWcpIHtcbiAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdbbmF1dGgtaW50ZXJjZXB0b3JdIFJlZnJlc2ggc3VjY2Vzc2Z1bCcpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaXNSZWZyZXNoaW5nID0gZmFsc2U7XG5cbiAgICAgICAgICAgIC8vIEdldCBuZXcgdG9rZW4gKEpTT04gbW9kZSkgb3Igc2lnbmFsIHN1Y2Nlc3MgKGNvb2tpZXMgbW9kZSlcbiAgICAgICAgICAgIGNvbnN0IG5ld1Rva2VuID0gJ2FjY2Vzc1Rva2VuJyBpbiByZXNwb25zZSA/IHJlc3BvbnNlLmFjY2Vzc1Rva2VuIDogJ3N1Y2Nlc3MnO1xuICAgICAgICAgICAgcmVmcmVzaFRva2VuU3ViamVjdC5uZXh0KG5ld1Rva2VuID8/ICdzdWNjZXNzJyk7XG5cbiAgICAgICAgICAgIC8vICNyZWdpb24gYWdlbnQgbG9nXG4gICAgICAgICAgICBmZXRjaCgnaHR0cDovLzEyNy4wLjAuMTo3MjQyL2luZ2VzdC85N2Y5ZmU1My02YThiLTQzZTItYWU5Yi00YjJkMGY3MjU4MTYnLCB7XG4gICAgICAgICAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgICAgICAgICBoZWFkZXJzOiB7ICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicgfSxcbiAgICAgICAgICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgICAgICAgIGxvY2F0aW9uOiAnYXV0aC5pbnRlcmNlcHRvci50czoxMjUnLFxuICAgICAgICAgICAgICAgIG1lc3NhZ2U6ICdCZWZvcmUgYnVpbGRSZXRyeVJlcXVlc3QnLFxuICAgICAgICAgICAgICAgIGRhdGE6IHtcbiAgICAgICAgICAgICAgICAgIGF1dGhSZXFCb2R5OiBhdXRoUmVxLmJvZHksXG4gICAgICAgICAgICAgICAgICBhdXRoUmVxTWV0aG9kOiBhdXRoUmVxLm1ldGhvZCxcbiAgICAgICAgICAgICAgICAgIGF1dGhSZXFVcmw6IGF1dGhSZXEudXJsLFxuICAgICAgICAgICAgICAgICAgYXV0aFJlcUJvZHlUeXBlOiB0eXBlb2YgYXV0aFJlcS5ib2R5LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgdGltZXN0YW1wOiBEYXRlLm5vdygpLFxuICAgICAgICAgICAgICAgIHNlc3Npb25JZDogJ2RlYnVnLXNlc3Npb24nLFxuICAgICAgICAgICAgICAgIGh5cG90aGVzaXNJZDogJ0EnLFxuICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgIH0pLmNhdGNoKCgpID0+IHt9KTtcbiAgICAgICAgICAgIC8vICNlbmRyZWdpb25cblxuICAgICAgICAgICAgLy8gQnVpbGQgcmV0cnkgcmVxdWVzdCB3aXRoIGZyZXNoIENTUkYgdG9rZW4gKHJlLXJlYWQgZnJvbSBjb29raWUgYWZ0ZXIgcmVmcmVzaClcbiAgICAgICAgICAgIGNvbnN0IHJldHJ5UmVxID0gYnVpbGRSZXRyeVJlcXVlc3QoYXV0aFJlcSwgdG9rZW5EZWxpdmVyeSwgbmV3VG9rZW4sIGNvbmZpZy5jc3JmKTtcblxuICAgICAgICAgICAgLy8gI3JlZ2lvbiBhZ2VudCBsb2dcbiAgICAgICAgICAgIGZldGNoKCdodHRwOi8vMTI3LjAuMC4xOjcyNDIvaW5nZXN0Lzk3ZjlmZTUzLTZhOGItNDNlMi1hZTliLTRiMmQwZjcyNTgxNicsIHtcbiAgICAgICAgICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICAgICAgICAgIGhlYWRlcnM6IHsgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyB9LFxuICAgICAgICAgICAgICBib2R5OiBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICAgICAgbG9jYXRpb246ICdhdXRoLmludGVyY2VwdG9yLnRzOjEzMCcsXG4gICAgICAgICAgICAgICAgbWVzc2FnZTogJ0FmdGVyIGJ1aWxkUmV0cnlSZXF1ZXN0JyxcbiAgICAgICAgICAgICAgICBkYXRhOiB7XG4gICAgICAgICAgICAgICAgICByZXRyeVJlcUJvZHk6IHJldHJ5UmVxLmJvZHksXG4gICAgICAgICAgICAgICAgICByZXRyeVJlcU1ldGhvZDogcmV0cnlSZXEubWV0aG9kLFxuICAgICAgICAgICAgICAgICAgcmV0cnlSZXFVcmw6IHJldHJ5UmVxLnVybCxcbiAgICAgICAgICAgICAgICAgIHJldHJ5UmVxQm9keVR5cGU6IHR5cGVvZiByZXRyeVJlcS5ib2R5LFxuICAgICAgICAgICAgICAgICAgaGVhZGVyc0tleXM6IHJldHJ5UmVxLmhlYWRlcnMua2V5cygpLFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgdGltZXN0YW1wOiBEYXRlLm5vdygpLFxuICAgICAgICAgICAgICAgIHNlc3Npb25JZDogJ2RlYnVnLXNlc3Npb24nLFxuICAgICAgICAgICAgICAgIGh5cG90aGVzaXNJZDogJ0InLFxuICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgIH0pLmNhdGNoKCgpID0+IHt9KTtcbiAgICAgICAgICAgIC8vICNlbmRyZWdpb25cblxuICAgICAgICAgICAgaWYgKGNvbmZpZy5kZWJ1Zykge1xuICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ1tuYXV0aC1pbnRlcmNlcHRvcl0gUmV0cnlpbmc6JywgcmVxLnVybCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIFJldHJ5IHRoZSByZXF1ZXN0IHdpdGggZnJlc2ggdG9rZW4vQ1NSRlxuICAgICAgICAgICAgLy8gSU1QT1JUQU5UOiBFcnJvcnMgZnJvbSB0aGUgcmV0cnkgKGUuZy4sIDQwMCB2YWxpZGF0aW9uKSBzaG91bGQgTk9UIHRyaWdnZXJcbiAgICAgICAgICAgIC8vIHNlc3Npb24gZXhwaXJhdGlvbiByZWRpcmVjdC4gT25seSB0aGUgcmVmcmVzaCBmYWlsdXJlIHNob3VsZCByZWRpcmVjdC5cbiAgICAgICAgICAgIHJldHVybiBuZXh0KHJldHJ5UmVxKS5waXBlKFxuICAgICAgICAgICAgICBjYXRjaEVycm9yKChyZXRyeUVycikgPT4ge1xuICAgICAgICAgICAgICAgIC8vIFJldHJ5IGZhaWxlZCAoY291bGQgYmUgNDAwLCA0MDMsIDUwMCwgZXRjLilcbiAgICAgICAgICAgICAgICAvLyBKdXN0IHByb3BhZ2F0ZSB0aGUgZXJyb3IgLSBkb24ndCByZWRpcmVjdCB0byBsb2dpblxuICAgICAgICAgICAgICAgIGlmIChjb25maWcuZGVidWcpIHtcbiAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybignW25hdXRoLWludGVyY2VwdG9yXSBSZXRyeSByZXF1ZXN0IGZhaWxlZDonLCByZXRyeUVycik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybiB0aHJvd0Vycm9yKCgpID0+IHJldHJ5RXJyKTtcbiAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0pLFxuICAgICAgICAgIGNhdGNoRXJyb3IoKGVycikgPT4ge1xuICAgICAgICAgICAgLy8gVGhpcyBvbmx5IGNhdGNoZXMgUkVGUkVTSCBmYWlsdXJlcywgbm90IHJldHJ5IGZhaWx1cmVzXG4gICAgICAgICAgICBpZiAoY29uZmlnLmRlYnVnKSB7XG4gICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ1tuYXV0aC1pbnRlcmNlcHRvcl0gUmVmcmVzaCBmYWlsZWQ6JywgZXJyKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlzUmVmcmVzaGluZyA9IGZhbHNlO1xuICAgICAgICAgICAgcmVmcmVzaFRva2VuU3ViamVjdC5uZXh0KG51bGwpO1xuXG4gICAgICAgICAgICAvLyBIYW5kbGUgc2Vzc2lvbiBleHBpcmF0aW9uIC0gcmVkaXJlY3QgdG8gY29uZmlndXJlZCBVUkxcbiAgICAgICAgICAgIC8vIE9ubHkgcmVkaXJlY3QgaWYgcmVmcmVzaCBpdHNlbGYgZmFpbGVkIChub3QgaWYgcmV0cnkgZmFpbGVkKVxuICAgICAgICAgICAgaWYgKGNvbmZpZy5yZWRpcmVjdHM/LnNlc3Npb25FeHBpcmVkKSB7XG4gICAgICAgICAgICAgIHJvdXRlci5uYXZpZ2F0ZUJ5VXJsKGNvbmZpZy5yZWRpcmVjdHMuc2Vzc2lvbkV4cGlyZWQpLmNhdGNoKChuYXZFcnJvcikgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChjb25maWcuZGVidWcpIHtcbiAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ1tuYXV0aC1pbnRlcmNlcHRvcl0gTmF2aWdhdGlvbiBmYWlsZWQ6JywgbmF2RXJyb3IpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiB0aHJvd0Vycm9yKCgpID0+IGVycik7XG4gICAgICAgICAgfSksXG4gICAgICAgICk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBXYWl0IGZvciBvbmdvaW5nIHJlZnJlc2hcbiAgICAgICAgaWYgKGNvbmZpZy5kZWJ1Zykge1xuICAgICAgICAgIGNvbnNvbGUud2FybignW25hdXRoLWludGVyY2VwdG9yXSBXYWl0aW5nIGZvciByZWZyZXNoLi4uJyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlZnJlc2hUb2tlblN1YmplY3QucGlwZShcbiAgICAgICAgICBmaWx0ZXIoKHRva2VuKTogdG9rZW4gaXMgc3RyaW5nID0+IHRva2VuICE9PSBudWxsKSxcbiAgICAgICAgICB0YWtlKDEpLFxuICAgICAgICAgIHN3aXRjaE1hcCgodG9rZW4pID0+IHtcbiAgICAgICAgICAgIGlmIChjb25maWcuZGVidWcpIHtcbiAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdbbmF1dGgtaW50ZXJjZXB0b3JdIFJlZnJlc2ggZG9uZSwgcmV0cnlpbmc6JywgcmVxLnVybCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCByZXRyeVJlcSA9IGJ1aWxkUmV0cnlSZXF1ZXN0KGF1dGhSZXEsIHRva2VuRGVsaXZlcnksIHRva2VuLCBjb25maWcuY3NyZik7XG5cbiAgICAgICAgICAgIC8vIFJldHJ5IHRoZSByZXF1ZXN0IC0gZXJyb3JzIGhlcmUgc2hvdWxkIHByb3BhZ2F0ZSBub3JtYWxseVxuICAgICAgICAgICAgLy8gd2l0aG91dCB0cmlnZ2VyaW5nIHNlc3Npb24gZXhwaXJhdGlvbiByZWRpcmVjdFxuICAgICAgICAgICAgcmV0dXJuIG5leHQocmV0cnlSZXEpLnBpcGUoXG4gICAgICAgICAgICAgIGNhdGNoRXJyb3IoKHJldHJ5RXJyKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKGNvbmZpZy5kZWJ1Zykge1xuICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdbbmF1dGgtaW50ZXJjZXB0b3JdIFJldHJ5IHJlcXVlc3QgZmFpbGVkOicsIHJldHJ5RXJyKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRocm93RXJyb3IoKCkgPT4gcmV0cnlFcnIpO1xuICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfSksXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfSksXG4gICk7XG59O1xuXG4vKipcbiAqIEJ1aWxkIHJldHJ5IHJlcXVlc3Qgd2l0aCBhcHByb3ByaWF0ZSBhdXRoLlxuICpcbiAqIENSSVRJQ0FMIEZJWDogSW4gY29va2llcyBtb2RlLCBhZnRlciByZWZyZXNoIHRoZSBzZXJ2ZXIgbWF5IHNlbmQgdXBkYXRlZCBjb29raWVzLlxuICogV2UgTVVTVCByZS1yZWFkIHRoZSBDU1JGIHRva2VuIGZyb20gdGhlIGNvb2tpZSBiZWZvcmUgcmV0cnlpbmcgdG8gZW5zdXJlIHdlIGhhdmVcbiAqIHRoZSBjdXJyZW50IENTUkYgdG9rZW4gdGhhdCBtYXRjaGVzIHdoYXQgdGhlIHNlcnZlciBleHBlY3RzLlxuICpcbiAqIEluIEpTT04gbW9kZTogQ2xvbmVzIHRoZSByZXF1ZXN0IGFuZCBhZGRzIHRoZSBuZXcgQmVhcmVyIHRva2VuLlxuICpcbiAqIEBwYXJhbSBvcmlnaW5hbFJlcSAtIFRoZSBiYXNlIHJlcXVlc3QgKGFscmVhZHkgaGFzIHdpdGhDcmVkZW50aWFscyBpZiBjb29raWVzIG1vZGUpXG4gKiBAcGFyYW0gdG9rZW5EZWxpdmVyeSAtICdjb29raWVzJyBvciAnanNvbidcbiAqIEBwYXJhbSBuZXdUb2tlbiAtIFRoZSBuZXcgYWNjZXNzIHRva2VuIChKU09OIG1vZGUgb25seSlcbiAqIEBwYXJhbSBjc3JmQ29uZmlnIC0gQ1NSRiBjb25maWd1cmF0aW9uIHRvIHJlLXJlYWQgdG9rZW4gZnJvbSBjb29raWVcbiAqIEByZXR1cm5zIFRoZSByZXF1ZXN0IHJlYWR5IGZvciByZXRyeSB3aXRoIGZyZXNoIGF1dGhcbiAqL1xuZnVuY3Rpb24gYnVpbGRSZXRyeVJlcXVlc3QoXG4gIG9yaWdpbmFsUmVxOiBIdHRwUmVxdWVzdDx1bmtub3duPixcbiAgdG9rZW5EZWxpdmVyeTogc3RyaW5nLFxuICBuZXdUb2tlbj86IHN0cmluZyxcbiAgY3NyZkNvbmZpZz86IHsgY29va2llTmFtZT86IHN0cmluZzsgaGVhZGVyTmFtZT86IHN0cmluZyB9LFxuKTogSHR0cFJlcXVlc3Q8dW5rbm93bj4ge1xuICBpZiAodG9rZW5EZWxpdmVyeSA9PT0gJ2pzb24nICYmIG5ld1Rva2VuICYmIG5ld1Rva2VuICE9PSAnc3VjY2VzcycpIHtcbiAgICByZXR1cm4gb3JpZ2luYWxSZXEuY2xvbmUoe1xuICAgICAgc2V0SGVhZGVyczogeyBBdXRob3JpemF0aW9uOiBgQmVhcmVyICR7bmV3VG9rZW59YCB9LFxuICAgIH0pO1xuICB9XG5cbiAgLy8gQ29va2llcyBtb2RlOiBCcm93c2VyIGF1dG9tYXRpY2FsbHkgc2VuZHMgdXBkYXRlZCBodHRwT25seSBjb29raWVzIChhY2Nlc3MvcmVmcmVzaCB0b2tlbnMpLlxuICAvLyBIb3dldmVyLCBDU1JGIHRva2VuIG11c3QgbWF0Y2ggdGhlIGNvb2tpZSB2YWx1ZSBhdCB0aGUgbW9tZW50IG9mIHJldHJ5LlxuICAvLyBXZSBBTFdBWVMgcmUtcmVhZCBmcm9tIGRvY3VtZW50LmNvb2tpZSBoZXJlICh1c2luZyBkZWZhdWx0cyB3aGVuIGNzcmZDb25maWdcbiAgLy8gaXMgbm90IHByb3ZpZGVkKSB0byBhdm9pZCBzdGFsZSBoZWFkZXIgdmFsdWVzIGFmdGVyIHJlZnJlc2ggb3IgYWNyb3NzIHRhYnMuXG4gIGlmICh0b2tlbkRlbGl2ZXJ5ID09PSAnY29va2llcycgJiYgWydQT1NUJywgJ1BVVCcsICdQQVRDSCcsICdERUxFVEUnXS5pbmNsdWRlcyhvcmlnaW5hbFJlcS5tZXRob2QpKSB7XG4gICAgY29uc3QgY3NyZkNvb2tpZU5hbWUgPSBjc3JmQ29uZmlnPy5jb29raWVOYW1lID8/ICduYXV0aF9jc3JmX3Rva2VuJztcbiAgICBjb25zdCBjc3JmSGVhZGVyTmFtZSA9IGNzcmZDb25maWc/LmhlYWRlck5hbWUgPz8gJ3gtY3NyZi10b2tlbic7XG4gICAgY29uc3QgZnJlc2hDc3JmVG9rZW4gPSBnZXRDc3JmVG9rZW4oY3NyZkNvb2tpZU5hbWUpO1xuXG4gICAgLy8gI3JlZ2lvbiBhZ2VudCBsb2dcbiAgICBmZXRjaCgnaHR0cDovLzEyNy4wLjAuMTo3MjQyL2luZ2VzdC85N2Y5ZmU1My02YThiLTQzZTItYWU5Yi00YjJkMGY3MjU4MTYnLCB7XG4gICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgIGhlYWRlcnM6IHsgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyB9LFxuICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICBsb2NhdGlvbjogJ2F1dGguaW50ZXJjZXB0b3IudHM6YnVpbGRSZXRyeVJlcXVlc3QnLFxuICAgICAgICBtZXNzYWdlOiAnSW5zaWRlIGJ1aWxkUmV0cnlSZXF1ZXN0IGNvb2tpZXMgYnJhbmNoJyxcbiAgICAgICAgZGF0YToge1xuICAgICAgICAgIG9yaWdpbmFsUmVxQm9keTogb3JpZ2luYWxSZXEuYm9keSxcbiAgICAgICAgICBvcmlnaW5hbFJlcUJvZHlUeXBlOiB0eXBlb2Ygb3JpZ2luYWxSZXEuYm9keSxcbiAgICAgICAgICBmcmVzaENzcmZUb2tlbjogZnJlc2hDc3JmVG9rZW4/LnN1YnN0cmluZygwLCA4KSxcbiAgICAgICAgICBtZXRob2Q6IG9yaWdpbmFsUmVxLm1ldGhvZCxcbiAgICAgICAgfSxcbiAgICAgICAgdGltZXN0YW1wOiBEYXRlLm5vdygpLFxuICAgICAgICBzZXNzaW9uSWQ6ICdkZWJ1Zy1zZXNzaW9uJyxcbiAgICAgICAgaHlwb3RoZXNpc0lkOiAnQycsXG4gICAgICB9KSxcbiAgICB9KS5jYXRjaCgoKSA9PiB7fSk7XG4gICAgLy8gI2VuZHJlZ2lvblxuXG4gICAgaWYgKGZyZXNoQ3NyZlRva2VuKSB7XG4gICAgICAvLyBDbG9uZSB3aXRoIGZyZXNoIENTUkYgdG9rZW4gaW4gaGVhZGVyXG4gICAgICBjb25zdCBjbG9uZWQgPSBvcmlnaW5hbFJlcS5jbG9uZSh7XG4gICAgICAgIHNldEhlYWRlcnM6IHsgW2NzcmZIZWFkZXJOYW1lXTogZnJlc2hDc3JmVG9rZW4gfSxcbiAgICAgIH0pO1xuXG4gICAgICAvLyAjcmVnaW9uIGFnZW50IGxvZ1xuICAgICAgZmV0Y2goJ2h0dHA6Ly8xMjcuMC4wLjE6NzI0Mi9pbmdlc3QvOTdmOWZlNTMtNmE4Yi00M2UyLWFlOWItNGIyZDBmNzI1ODE2Jywge1xuICAgICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgICAgaGVhZGVyczogeyAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nIH0sXG4gICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICBsb2NhdGlvbjogJ2F1dGguaW50ZXJjZXB0b3IudHM6YnVpbGRSZXRyeVJlcXVlc3Q6YWZ0ZXJDbG9uZScsXG4gICAgICAgICAgbWVzc2FnZTogJ0FmdGVyIGNsb25lIHdpdGggc2V0SGVhZGVycycsXG4gICAgICAgICAgZGF0YTogeyBjbG9uZWRCb2R5OiBjbG9uZWQuYm9keSwgY2xvbmVkQm9keVR5cGU6IHR5cGVvZiBjbG9uZWQuYm9keSwgb3JpZ2luYWxCb2R5OiBvcmlnaW5hbFJlcS5ib2R5IH0sXG4gICAgICAgICAgdGltZXN0YW1wOiBEYXRlLm5vdygpLFxuICAgICAgICAgIHNlc3Npb25JZDogJ2RlYnVnLXNlc3Npb24nLFxuICAgICAgICAgIGh5cG90aGVzaXNJZDogJ0QnLFxuICAgICAgICB9KSxcbiAgICAgIH0pLmNhdGNoKCgpID0+IHt9KTtcbiAgICAgIC8vICNlbmRyZWdpb25cblxuICAgICAgcmV0dXJuIGNsb25lZDtcbiAgICB9XG4gIH1cblxuICAvLyBObyBjaGFuZ2VzIG5lZWRlZCAoR0VUIHJlcXVlc3Qgb3Igbm8gQ1NSRiB0b2tlbiBhdmFpbGFibGUpXG4gIHJldHVybiBvcmlnaW5hbFJlcTtcbn1cblxuLyoqXG4gKiBDbGFzcy1iYXNlZCBpbnRlcmNlcHRvciBmb3IgTmdNb2R1bGUgY29tcGF0aWJpbGl0eS5cbiAqL1xuZXhwb3J0IGNsYXNzIEF1dGhJbnRlcmNlcHRvciB7XG4gIGludGVyY2VwdChyZXE6IEh0dHBSZXF1ZXN0PHVua25vd24+LCBuZXh0OiBIdHRwSGFuZGxlckZuKSB7XG4gICAgcmV0dXJuIGF1dGhJbnRlcmNlcHRvcihyZXEsIG5leHQpO1xuICB9XG59XG4iXX0=
|
|
35
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC5pbnRlcmNlcHRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvYXV0aC5pbnRlcmNlcHRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLFdBQVcsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNwRCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNwRCxPQUFPLEVBQWlELFVBQVUsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ2pHLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUN6QyxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUN6RCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDdkQsT0FBTyxFQUFFLDhCQUE4QixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFM0U7Ozs7OztHQU1HO0FBQ0gsTUFBTSxDQUFDLE1BQU0sZUFBZSxHQUFzQixDQUFDLEdBQXlCLEVBQUUsSUFBbUIsRUFBRSxFQUFFO0lBQ25HLE1BQU0sTUFBTSxHQUFHLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO0lBQzNDLE1BQU0sSUFBSSxHQUFHLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUNoQyxNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDeEMsTUFBTSxVQUFVLEdBQUcsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQ3ZDLE1BQU0sTUFBTSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUM5QixNQUFNLFNBQVMsR0FBRyxpQkFBaUIsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUVoRCxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDZixPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNuQixDQUFDO0lBRUQsT0FBTyw4QkFBOEIsQ0FBQyxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsV0FBVyxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQztBQUMxRixDQUFDLENBQUM7QUFFRjs7R0FFRztBQUNILE1BQU0sT0FBTyxlQUFlO0lBQzFCLFNBQVMsQ0FBQyxHQUF5QixFQUFFLElBQW1CO1FBQ3RELE9BQU8sZUFBZSxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsQ0FBQztJQUNwQyxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBpbmplY3QsIFBMQVRGT1JNX0lEIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBpc1BsYXRmb3JtQnJvd3NlciB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBIdHRwSGFuZGxlckZuLCBIdHRwSW50ZXJjZXB0b3JGbiwgSHR0cFJlcXVlc3QsIEh0dHBDbGllbnQgfSBmcm9tICdAYW5ndWxhci9jb21tb24vaHR0cCc7XG5pbXBvcnQgeyBSb3V0ZXIgfSBmcm9tICdAYW5ndWxhci9yb3V0ZXInO1xuaW1wb3J0IHsgTkFVVEhfQ0xJRU5UX0NPTkZJRyB9IGZyb20gJy4uL25nbW9kdWxlL3Rva2Vucyc7XG5pbXBvcnQgeyBBdXRoU2VydmljZSB9IGZyb20gJy4uL25nbW9kdWxlL2F1dGguc2VydmljZSc7XG5pbXBvcnQgeyBjcmVhdGVOQXV0aEF1dGhIdHRwSW50ZXJjZXB0b3IgfSBmcm9tICcuL2F1dGgtaW50ZXJjZXB0b3Iuc2hhcmVkJztcblxuLyoqXG4gKiBBbmd1bGFyIEhUVFAgaW50ZXJjZXB0b3IgZm9yIG5hdXRoLXRvb2xraXQuXG4gKlxuICogSGFuZGxlczpcbiAqIC0gQ29va2llcyBtb2RlOiB3aXRoQ3JlZGVudGlhbHMgKyBDU1JGIHRva2VucyArIHJlZnJlc2ggdmlhIFBPU1RcbiAqIC0gSlNPTiBtb2RlOiByZWZyZXNoIHZpYSBTREssIHJldHJ5IHdpdGggbmV3IHRva2VuXG4gKi9cbmV4cG9ydCBjb25zdCBhdXRoSW50ZXJjZXB0b3I6IEh0dHBJbnRlcmNlcHRvckZuID0gKHJlcTogSHR0cFJlcXVlc3Q8dW5rbm93bj4sIG5leHQ6IEh0dHBIYW5kbGVyRm4pID0+IHtcbiAgY29uc3QgY29uZmlnID0gaW5qZWN0KE5BVVRIX0NMSUVOVF9DT05GSUcpO1xuICBjb25zdCBodHRwID0gaW5qZWN0KEh0dHBDbGllbnQpO1xuICBjb25zdCBhdXRoU2VydmljZSA9IGluamVjdChBdXRoU2VydmljZSk7XG4gIGNvbnN0IHBsYXRmb3JtSWQgPSBpbmplY3QoUExBVEZPUk1fSUQpO1xuICBjb25zdCByb3V0ZXIgPSBpbmplY3QoUm91dGVyKTtcbiAgY29uc3QgaXNCcm93c2VyID0gaXNQbGF0Zm9ybUJyb3dzZXIocGxhdGZvcm1JZCk7XG5cbiAgaWYgKCFpc0Jyb3dzZXIpIHtcbiAgICByZXR1cm4gbmV4dChyZXEpO1xuICB9XG5cbiAgcmV0dXJuIGNyZWF0ZU5BdXRoQXV0aEh0dHBJbnRlcmNlcHRvcih7IGNvbmZpZywgaHR0cCwgYXV0aFNlcnZpY2UsIHJvdXRlciwgbmV4dCwgcmVxIH0pO1xufTtcblxuLyoqXG4gKiBDbGFzcy1iYXNlZCBpbnRlcmNlcHRvciBmb3IgTmdNb2R1bGUgY29tcGF0aWJpbGl0eS5cbiAqL1xuZXhwb3J0IGNsYXNzIEF1dGhJbnRlcmNlcHRvciB7XG4gIGludGVyY2VwdChyZXE6IEh0dHBSZXF1ZXN0PHVua25vd24+LCBuZXh0OiBIdHRwSGFuZGxlckZuKSB7XG4gICAgcmV0dXJuIGF1dGhJbnRlcmNlcHRvcihyZXEsIG5leHQpO1xuICB9XG59XG4iXX0=
|