@masterteam/gateway-auth 0.0.20 → 0.0.22
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.
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { firstValueFrom, EMPTY, of, defer, from, isObservable, map, tap as tap$1, shareReplay, finalize, catchError as catchError$1, throwError, switchMap as switchMap$1 } from 'rxjs';
|
|
2
|
-
import { HttpClient, HttpContextToken, HttpBackend } from '@angular/common/http';
|
|
2
|
+
import { HttpClient, HttpContextToken, HttpBackend, HttpResponse } from '@angular/common/http';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
4
|
import { InjectionToken, inject, Injectable, computed, input, ChangeDetectionStrategy, Component, signal, effect } from '@angular/core';
|
|
5
5
|
import { Action, Selector, State, Store, select } from '@ngxs/store';
|
|
6
6
|
import { Router, ActivatedRoute } from '@angular/router';
|
|
7
7
|
import { ModalService } from '@masterteam/components/modal';
|
|
8
8
|
import { switchMap, mergeMap, catchError, tap } from 'rxjs/operators';
|
|
9
|
+
import { ToastService } from '@masterteam/components/toast';
|
|
9
10
|
import * as i2 from '@angular/common';
|
|
10
11
|
import { NgTemplateOutlet, CommonModule } from '@angular/common';
|
|
11
12
|
import * as i1 from '@angular/forms';
|
|
@@ -897,8 +898,9 @@ let GatewayAuthState = class GatewayAuthState {
|
|
|
897
898
|
},
|
|
898
899
|
});
|
|
899
900
|
const params = {};
|
|
900
|
-
|
|
901
|
-
|
|
901
|
+
const returnUrl = this.resolveLaunchReturnUrl(code, action.returnUrl);
|
|
902
|
+
if (returnUrl) {
|
|
903
|
+
params['returnUrl'] = returnUrl;
|
|
902
904
|
}
|
|
903
905
|
const deviceToken = this.deviceToken;
|
|
904
906
|
if (deviceToken) {
|
|
@@ -998,6 +1000,22 @@ let GatewayAuthState = class GatewayAuthState {
|
|
|
998
1000
|
delete next[code];
|
|
999
1001
|
return next;
|
|
1000
1002
|
}
|
|
1003
|
+
resolveLaunchReturnUrl(applicationCode, explicitReturnUrl) {
|
|
1004
|
+
const trimmedExplicit = explicitReturnUrl?.trim();
|
|
1005
|
+
if (trimmedExplicit) {
|
|
1006
|
+
return trimmedExplicit;
|
|
1007
|
+
}
|
|
1008
|
+
const fromOption = this.options
|
|
1009
|
+
.getApplicationLaunchReturnUrl?.(applicationCode)
|
|
1010
|
+
?.trim();
|
|
1011
|
+
if (fromOption) {
|
|
1012
|
+
return fromOption;
|
|
1013
|
+
}
|
|
1014
|
+
if (typeof window !== 'undefined' && window.location?.origin) {
|
|
1015
|
+
return window.location.origin;
|
|
1016
|
+
}
|
|
1017
|
+
return null;
|
|
1018
|
+
}
|
|
1001
1019
|
isRateLimitActive(ctx, scope) {
|
|
1002
1020
|
const lock = ctx.getState().rateLimit;
|
|
1003
1021
|
if (!lock || lock.scope !== scope) {
|
|
@@ -1735,6 +1753,200 @@ const gatewayAuthInterceptor = (req, next) => {
|
|
|
1735
1753
|
}));
|
|
1736
1754
|
};
|
|
1737
1755
|
|
|
1756
|
+
const CORRELATION_ID_HEADER = 'X-Correlation-ID';
|
|
1757
|
+
function generateCorrelationId() {
|
|
1758
|
+
if (typeof crypto !== 'undefined' && crypto.randomUUID) {
|
|
1759
|
+
return crypto.randomUUID();
|
|
1760
|
+
}
|
|
1761
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (char) => {
|
|
1762
|
+
const random = (Math.random() * 16) | 0;
|
|
1763
|
+
const value = char === 'x' ? random : (random & 0x3) | 0x8;
|
|
1764
|
+
return value.toString(16);
|
|
1765
|
+
});
|
|
1766
|
+
}
|
|
1767
|
+
const correlationIdInterceptor = (req, next) => {
|
|
1768
|
+
if (req.headers.has(CORRELATION_ID_HEADER)) {
|
|
1769
|
+
return next(req);
|
|
1770
|
+
}
|
|
1771
|
+
return next(req.clone({
|
|
1772
|
+
setHeaders: {
|
|
1773
|
+
[CORRELATION_ID_HEADER]: generateCorrelationId(),
|
|
1774
|
+
},
|
|
1775
|
+
}));
|
|
1776
|
+
};
|
|
1777
|
+
|
|
1778
|
+
const DEFAULT_EXCLUDED_PATHS = [
|
|
1779
|
+
'/health',
|
|
1780
|
+
'/auth/login',
|
|
1781
|
+
'/auth/refresh',
|
|
1782
|
+
'/auth/logout',
|
|
1783
|
+
'/auth/register',
|
|
1784
|
+
'/auth/sso',
|
|
1785
|
+
'/swagger',
|
|
1786
|
+
];
|
|
1787
|
+
const DEFAULT_METHODS = ['POST', 'PUT', 'PATCH', 'DELETE'];
|
|
1788
|
+
const DEFAULT_HEADER = 'X-Idempotency-Key';
|
|
1789
|
+
function generateUUID() {
|
|
1790
|
+
if (typeof crypto !== 'undefined' && crypto.randomUUID) {
|
|
1791
|
+
return crypto.randomUUID();
|
|
1792
|
+
}
|
|
1793
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
1794
|
+
const r = (Math.random() * 16) | 0;
|
|
1795
|
+
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
1796
|
+
return v.toString(16);
|
|
1797
|
+
});
|
|
1798
|
+
}
|
|
1799
|
+
function createIdempotencyInterceptor(options) {
|
|
1800
|
+
const excludedPaths = options?.excludedPaths ?? DEFAULT_EXCLUDED_PATHS;
|
|
1801
|
+
const methods = (options?.methods ?? DEFAULT_METHODS).map((m) => m.toUpperCase());
|
|
1802
|
+
const header = options?.headerName ?? DEFAULT_HEADER;
|
|
1803
|
+
const requiresKey = (req) => {
|
|
1804
|
+
if (!methods.includes(req.method.toUpperCase()))
|
|
1805
|
+
return false;
|
|
1806
|
+
if (req.url.includes('/assets/'))
|
|
1807
|
+
return false;
|
|
1808
|
+
if (excludedPaths.some((path) => req.url.includes(path)))
|
|
1809
|
+
return false;
|
|
1810
|
+
return true;
|
|
1811
|
+
};
|
|
1812
|
+
return (req, next) => {
|
|
1813
|
+
if (!requiresKey(req) || req.headers.has(header)) {
|
|
1814
|
+
return next(req);
|
|
1815
|
+
}
|
|
1816
|
+
return next(req.clone({
|
|
1817
|
+
setHeaders: { [header]: generateUUID() },
|
|
1818
|
+
}));
|
|
1819
|
+
};
|
|
1820
|
+
}
|
|
1821
|
+
const idempotencyInterceptor = createIdempotencyInterceptor();
|
|
1822
|
+
|
|
1823
|
+
function createLanguageInterceptor(options) {
|
|
1824
|
+
const header = options.headerName ?? 'Accept-Language';
|
|
1825
|
+
return (req, next) => {
|
|
1826
|
+
const lang = options.getLanguage();
|
|
1827
|
+
if (!lang) {
|
|
1828
|
+
return next(req);
|
|
1829
|
+
}
|
|
1830
|
+
return next(req.clone({
|
|
1831
|
+
setHeaders: { [header]: lang },
|
|
1832
|
+
}));
|
|
1833
|
+
};
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1836
|
+
const DEFAULT_MUTATING_METHODS = ['POST', 'PUT', 'PATCH', 'DELETE'];
|
|
1837
|
+
const DEFAULT_SILENT_ENDPOINTS = [
|
|
1838
|
+
'api/dashboards/chart',
|
|
1839
|
+
'api/home/recent/visit',
|
|
1840
|
+
'api/fetch/query',
|
|
1841
|
+
'api/workcenter/runtime',
|
|
1842
|
+
'api/search',
|
|
1843
|
+
'api/process-form-load',
|
|
1844
|
+
'/workspace-record-action-states',
|
|
1845
|
+
'/schedule/read',
|
|
1846
|
+
'/metadata/modules/properties',
|
|
1847
|
+
'/auth/logout',
|
|
1848
|
+
'/auth/login',
|
|
1849
|
+
'/auth/2fa',
|
|
1850
|
+
'/auth/sso',
|
|
1851
|
+
'/schedule/query',
|
|
1852
|
+
'/context/resolve',
|
|
1853
|
+
'read-state',
|
|
1854
|
+
'process-submit/validate',
|
|
1855
|
+
'api/formulas/validate',
|
|
1856
|
+
];
|
|
1857
|
+
const DEFAULT_NO_MESSAGE_HEADER = 'noMessage';
|
|
1858
|
+
function createMessageInterceptor(options) {
|
|
1859
|
+
const silentEndpoints = options?.silentEndpoints ?? DEFAULT_SILENT_ENDPOINTS;
|
|
1860
|
+
const mutating = (options?.mutatingMethods ?? DEFAULT_MUTATING_METHODS).map((m) => m.toUpperCase());
|
|
1861
|
+
const noMessageHeader = options?.noMessageHeader ?? DEFAULT_NO_MESSAGE_HEADER;
|
|
1862
|
+
return (req, next) => {
|
|
1863
|
+
const auth = inject(GatewayAuthFacade);
|
|
1864
|
+
const toast = inject(ToastService);
|
|
1865
|
+
return next(req).pipe(tap$1({
|
|
1866
|
+
next: (res) => {
|
|
1867
|
+
const body = res
|
|
1868
|
+
?.body;
|
|
1869
|
+
if (!body?.message)
|
|
1870
|
+
return;
|
|
1871
|
+
if (req.headers.get(noMessageHeader) === 'true')
|
|
1872
|
+
return;
|
|
1873
|
+
if (!mutating.includes(req.method.toUpperCase()))
|
|
1874
|
+
return;
|
|
1875
|
+
if (silentEndpoints.some((endpoint) => req.url.includes(endpoint)))
|
|
1876
|
+
return;
|
|
1877
|
+
toast.success(body.message);
|
|
1878
|
+
},
|
|
1879
|
+
error: (error) => {
|
|
1880
|
+
const errorMessage = error?.error?.message || error?.error?.Message || '';
|
|
1881
|
+
const errorCode = error?.status || error?.error?.status || error?.error?.code;
|
|
1882
|
+
const showError = (message) => {
|
|
1883
|
+
if (message)
|
|
1884
|
+
toast.error(message);
|
|
1885
|
+
};
|
|
1886
|
+
const canRefreshGateway = !!auth.refreshToken() &&
|
|
1887
|
+
!isExpired(auth.refreshTokenExpiresAt());
|
|
1888
|
+
const activeCode = auth.activeApplicationCode();
|
|
1889
|
+
const appSession = activeCode ? auth.getAppSession(activeCode) : null;
|
|
1890
|
+
const canRefreshApp = !!appSession?.refreshToken &&
|
|
1891
|
+
!isExpired(appSession.refreshTokenExpiresAt);
|
|
1892
|
+
switch (errorCode) {
|
|
1893
|
+
case 401:
|
|
1894
|
+
if (!isGatewayAuthRequestUrl(req.url) &&
|
|
1895
|
+
(canRefreshGateway || canRefreshApp)) {
|
|
1896
|
+
break;
|
|
1897
|
+
}
|
|
1898
|
+
auth.logout();
|
|
1899
|
+
showError(errorMessage);
|
|
1900
|
+
break;
|
|
1901
|
+
case 404:
|
|
1902
|
+
if (req?.responseType !== 'blob') {
|
|
1903
|
+
showError(errorMessage);
|
|
1904
|
+
}
|
|
1905
|
+
break;
|
|
1906
|
+
case 400: {
|
|
1907
|
+
const validationErrors = error?.error?.errors;
|
|
1908
|
+
if (validationErrors && typeof validationErrors === 'object') {
|
|
1909
|
+
const messages = Object.values(validationErrors)
|
|
1910
|
+
.flat()
|
|
1911
|
+
.filter((m) => typeof m === 'string');
|
|
1912
|
+
messages.forEach(showError);
|
|
1913
|
+
}
|
|
1914
|
+
else {
|
|
1915
|
+
showError(errorMessage);
|
|
1916
|
+
}
|
|
1917
|
+
break;
|
|
1918
|
+
}
|
|
1919
|
+
case 402:
|
|
1920
|
+
case 403:
|
|
1921
|
+
case 422:
|
|
1922
|
+
case 500:
|
|
1923
|
+
showError(errorMessage);
|
|
1924
|
+
break;
|
|
1925
|
+
default:
|
|
1926
|
+
if (req.headers.get(noMessageHeader) !== 'true') {
|
|
1927
|
+
showError(errorMessage);
|
|
1928
|
+
}
|
|
1929
|
+
break;
|
|
1930
|
+
}
|
|
1931
|
+
},
|
|
1932
|
+
}));
|
|
1933
|
+
};
|
|
1934
|
+
}
|
|
1935
|
+
const messageInterceptor = createMessageInterceptor();
|
|
1936
|
+
|
|
1937
|
+
function createCacheSessionInterceptor(options) {
|
|
1938
|
+
const field = options.field ?? 'cacheSession';
|
|
1939
|
+
return (req, next) => next(req).pipe(tap$1((event) => {
|
|
1940
|
+
if (!(event instanceof HttpResponse) || !event.body)
|
|
1941
|
+
return;
|
|
1942
|
+
const body = event.body;
|
|
1943
|
+
const value = body[field];
|
|
1944
|
+
if (typeof value === 'string' && value) {
|
|
1945
|
+
options.onCacheSession(value);
|
|
1946
|
+
}
|
|
1947
|
+
}));
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1738
1950
|
class GatewaySsoButtons {
|
|
1739
1951
|
authFacade = inject(GatewayAuthFacade);
|
|
1740
1952
|
options = inject(GATEWAY_AUTH_OPTIONS);
|
|
@@ -2080,5 +2292,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
2080
2292
|
* Generated bundle index. Do not edit.
|
|
2081
2293
|
*/
|
|
2082
2294
|
|
|
2083
|
-
export { AUTH_STATE_DEFAULTS, ClearAllAppSessions, ClearAppSession, ClearError, ClearPendingMfa, ClearRateLimit, ExchangeSsoCode, GATEWAY_AUTH_ACCESS_TOKEN_REFRESH_SKEW_MS, GATEWAY_AUTH_DEVICE_TOKEN, GATEWAY_AUTH_DEVICE_TOKEN_STORAGE_KEY, GATEWAY_AUTH_ENDPOINTS, GATEWAY_AUTH_NGSW_BYPASS_PARAM, GATEWAY_AUTH_OPTIONS, GATEWAY_AUTH_RETRY_CONTEXT, GATEWAY_RATE_LIMIT_ERROR_CODE, GATEWAY_RATE_LIMIT_STATUS, GatewayAuthFacade, GatewayAuthState, GatewayLoginPage, GatewayMfa, GatewaySsoButtons, GatewaySsoCallback, GatewaySsoSession, LaunchApplication, LoadApplications, LoadSsoProviders, Login, LoginFailure, LoginSuccess, Logout, ResendMfa, SetAppSession, SetApplications, SetRateLimit, StartSso, UpdateAppTokens, UpdateTokens, UpdateUserData, VerifyMfa, buildApplicationContextUrl, buildGatewayUrl, buildSsoStartUrl, clearApplicationContextCache, createSecureClientState, extractGatewayRateLimitInfo, fetchApplicationContextCode, gatewayAuthInterceptor, getGatewayErrorMessage, hasGatewayTokens, isExpired, isGatewayAuthRequestUrl, mapGatewayTokens, mapGatewayUser, normalizeGatewayBase, readPersistedGatewayAuthTokens, resolveAccessTokenRefreshSkewMs, resolveApiDateValue, resolveApplicationCodeOption, resolveGatewayAuthPath, resolveGatewayDeviceToken, sanitizePersistedAuthState, withGatewayAuthNgswBypass };
|
|
2295
|
+
export { AUTH_STATE_DEFAULTS, ClearAllAppSessions, ClearAppSession, ClearError, ClearPendingMfa, ClearRateLimit, ExchangeSsoCode, GATEWAY_AUTH_ACCESS_TOKEN_REFRESH_SKEW_MS, GATEWAY_AUTH_DEVICE_TOKEN, GATEWAY_AUTH_DEVICE_TOKEN_STORAGE_KEY, GATEWAY_AUTH_ENDPOINTS, GATEWAY_AUTH_NGSW_BYPASS_PARAM, GATEWAY_AUTH_OPTIONS, GATEWAY_AUTH_RETRY_CONTEXT, GATEWAY_RATE_LIMIT_ERROR_CODE, GATEWAY_RATE_LIMIT_STATUS, GatewayAuthFacade, GatewayAuthState, GatewayLoginPage, GatewayMfa, GatewaySsoButtons, GatewaySsoCallback, GatewaySsoSession, LaunchApplication, LoadApplications, LoadSsoProviders, Login, LoginFailure, LoginSuccess, Logout, ResendMfa, SetAppSession, SetApplications, SetRateLimit, StartSso, UpdateAppTokens, UpdateTokens, UpdateUserData, VerifyMfa, buildApplicationContextUrl, buildGatewayUrl, buildSsoStartUrl, clearApplicationContextCache, correlationIdInterceptor, createCacheSessionInterceptor, createIdempotencyInterceptor, createLanguageInterceptor, createMessageInterceptor, createSecureClientState, extractGatewayRateLimitInfo, fetchApplicationContextCode, gatewayAuthInterceptor, getGatewayErrorMessage, hasGatewayTokens, idempotencyInterceptor, isExpired, isGatewayAuthRequestUrl, mapGatewayTokens, mapGatewayUser, messageInterceptor, normalizeGatewayBase, readPersistedGatewayAuthTokens, resolveAccessTokenRefreshSkewMs, resolveApiDateValue, resolveApplicationCodeOption, resolveGatewayAuthPath, resolveGatewayDeviceToken, sanitizePersistedAuthState, withGatewayAuthNgswBypass };
|
|
2084
2296
|
//# sourceMappingURL=masterteam-gateway-auth.mjs.map
|