@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
- if (action.returnUrl) {
901
- params['returnUrl'] = action.returnUrl;
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