@masterteam/gateway-auth 0.0.17 → 0.0.19

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,11 @@
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';
1
2
  import { HttpClient, HttpContextToken, HttpBackend } from '@angular/common/http';
2
3
  import * as i0 from '@angular/core';
3
4
  import { InjectionToken, inject, Injectable, computed, input, ChangeDetectionStrategy, Component, signal, effect } from '@angular/core';
4
- import { EMPTY, of, isObservable, from, firstValueFrom, map, tap as tap$1, shareReplay, finalize, catchError as catchError$1, throwError, switchMap } from 'rxjs';
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
- import { mergeMap, catchError, tap } from 'rxjs/operators';
8
+ import { switchMap, mergeMap, catchError, tap } from 'rxjs/operators';
9
9
  import * as i2 from '@angular/common';
10
10
  import { NgTemplateOutlet, CommonModule } from '@angular/common';
11
11
  import * as i1 from '@angular/forms';
@@ -66,6 +66,48 @@ function resolveApplicationCodeOption(applicationCode) {
66
66
  const normalized = value?.trim();
67
67
  return normalized ? normalized : null;
68
68
  }
69
+ const applicationContextCache = new Map();
70
+ function buildApplicationContextUrl(applicationApiBaseUrl) {
71
+ if (!applicationApiBaseUrl) {
72
+ return null;
73
+ }
74
+ const base = normalizeGatewayBase(applicationApiBaseUrl);
75
+ if (!base) {
76
+ return null;
77
+ }
78
+ const path = GATEWAY_AUTH_ENDPOINTS.applicationContext;
79
+ if (/\/api\/?$/i.test(base)) {
80
+ return `${base.replace(/\/+$/, '')}/${path}`;
81
+ }
82
+ return `${base}/api/${path}`;
83
+ }
84
+ function clearApplicationContextCache(applicationApiBaseUrl) {
85
+ if (applicationApiBaseUrl) {
86
+ applicationContextCache.delete(applicationApiBaseUrl);
87
+ return;
88
+ }
89
+ applicationContextCache.clear();
90
+ }
91
+ async function fetchApplicationContextCode(http, applicationApiBaseUrl) {
92
+ const url = buildApplicationContextUrl(applicationApiBaseUrl);
93
+ if (!url || !applicationApiBaseUrl) {
94
+ return null;
95
+ }
96
+ const cacheKey = applicationApiBaseUrl;
97
+ const cached = applicationContextCache.get(cacheKey);
98
+ if (cached) {
99
+ return cached;
100
+ }
101
+ const promise = firstValueFrom(http.get(url))
102
+ .then((response) => response?.data?.applicationCode?.trim() || null)
103
+ .catch(() => null);
104
+ applicationContextCache.set(cacheKey, promise);
105
+ const code = await promise;
106
+ if (!code) {
107
+ applicationContextCache.delete(cacheKey);
108
+ }
109
+ return code;
110
+ }
69
111
  function resolveGatewayDeviceToken(deviceToken) {
70
112
  const configuredToken = typeof deviceToken === 'function' ? deviceToken() : deviceToken;
71
113
  const normalizedConfiguredToken = configuredToken?.trim();
@@ -438,6 +480,7 @@ const AUTH_STATE_DEFAULTS = {
438
480
  applicationsLoading: false,
439
481
  appSessions: {},
440
482
  appLaunchLoading: {},
483
+ activeApplicationCode: null,
441
484
  };
442
485
  function pruneRateLimit(rateLimit) {
443
486
  if (!rateLimit) {
@@ -482,6 +525,7 @@ function sanitizePersistedAuthState(obj) {
482
525
  applicationsLoading: false,
483
526
  appSessions: pruneAppSessions(obj?.appSessions ?? null),
484
527
  appLaunchLoading: {},
528
+ activeApplicationCode: obj?.activeApplicationCode ?? null,
485
529
  };
486
530
  }
487
531
 
@@ -557,6 +601,9 @@ let GatewayAuthState = class GatewayAuthState {
557
601
  static appLaunchLoading(state) {
558
602
  return state.appLaunchLoading;
559
603
  }
604
+ static activeApplicationCode(state) {
605
+ return state.activeApplicationCode;
606
+ }
560
607
  login(ctx, action) {
561
608
  if (this.isRateLimitActive(ctx, 'login')) {
562
609
  return EMPTY;
@@ -567,26 +614,37 @@ let GatewayAuthState = class GatewayAuthState {
567
614
  pendingMfa: null,
568
615
  twoFactorRequired: false,
569
616
  });
570
- const applicationCode = action.payload.applicationCode ??
571
- resolveApplicationCodeOption(this.options.applicationCode) ??
572
- undefined;
573
- return this.http
617
+ return this.resolveApplicationCode$(action.payload.applicationCode).pipe(switchMap((applicationCode) => this.http
574
618
  .post(this.gatewayAuthMutationUrl(GATEWAY_AUTH_ENDPOINTS.login), {
575
619
  userName: action.payload.userName,
576
620
  password: action.payload.password,
577
- applicationCode,
621
+ applicationCode: applicationCode ?? undefined,
578
622
  isEncrypted: action.payload.isEncrypted ?? false,
579
623
  deviceToken: action.payload.deviceToken || this.deviceToken,
580
624
  recaptchaToken: action.payload.recaptchaToken,
581
625
  recaptchaAction: action.payload.recaptchaAction,
582
626
  })
583
- .pipe(mergeMap((response) => this.handleLoginResponse(ctx, response.data)), catchError((error) => {
627
+ .pipe(mergeMap((response) => this.handleLoginResponse(ctx, response.data, applicationCode)), catchError((error) => {
584
628
  if (this.handleRateLimit(ctx, error, 'login')) {
585
629
  return of(null);
586
630
  }
587
631
  ctx.dispatch(new LoginFailure(getGatewayErrorMessage(error, 'Login failed')));
588
632
  return of(null);
589
- }));
633
+ }))));
634
+ }
635
+ resolveApplicationCode$(explicitCode) {
636
+ if (explicitCode) {
637
+ return of(explicitCode);
638
+ }
639
+ const configured = resolveApplicationCodeOption(this.options.applicationCode);
640
+ if (configured) {
641
+ return of(configured);
642
+ }
643
+ const applicationApiBaseUrl = this.options.getApplicationApiBaseUrl?.();
644
+ if (!applicationApiBaseUrl) {
645
+ return of(null);
646
+ }
647
+ return defer(() => from(fetchApplicationContextCode(this.http, applicationApiBaseUrl)));
590
648
  }
591
649
  verifyMfa(ctx, action) {
592
650
  const pendingMfa = ctx.getState().pendingMfa;
@@ -736,6 +794,7 @@ let GatewayAuthState = class GatewayAuthState {
736
794
  applications: [],
737
795
  appSessions: {},
738
796
  appLaunchLoading: {},
797
+ activeApplicationCode: null,
739
798
  });
740
799
  }
741
800
  logout(ctx, action) {
@@ -871,6 +930,7 @@ let GatewayAuthState = class GatewayAuthState {
871
930
  [data.applicationCode]: session,
872
931
  },
873
932
  appLaunchLoading: this.removeLoadingFlag(ctx, code),
933
+ activeApplicationCode: data.applicationCode,
874
934
  });
875
935
  if (action.navigate && session.launchUrl) {
876
936
  try {
@@ -918,10 +978,20 @@ let GatewayAuthState = class GatewayAuthState {
918
978
  clearAppSession(ctx, action) {
919
979
  const sessions = { ...ctx.getState().appSessions };
920
980
  delete sessions[action.applicationCode];
921
- ctx.patchState({ appSessions: sessions });
981
+ const state = ctx.getState();
982
+ ctx.patchState({
983
+ appSessions: sessions,
984
+ activeApplicationCode: state.activeApplicationCode === action.applicationCode
985
+ ? null
986
+ : state.activeApplicationCode,
987
+ });
922
988
  }
923
989
  clearAllAppSessions(ctx) {
924
- ctx.patchState({ appSessions: {}, applications: [] });
990
+ ctx.patchState({
991
+ appSessions: {},
992
+ applications: [],
993
+ activeApplicationCode: null,
994
+ });
925
995
  }
926
996
  removeLoadingFlag(ctx, code) {
927
997
  const next = { ...ctx.getState().appLaunchLoading };
@@ -955,7 +1025,7 @@ let GatewayAuthState = class GatewayAuthState {
955
1025
  }));
956
1026
  return true;
957
1027
  }
958
- handleLoginResponse(ctx, session) {
1028
+ handleLoginResponse(ctx, session, resolvedApplicationCode) {
959
1029
  if (session.requiresTwoFactor) {
960
1030
  ctx.patchState({
961
1031
  user: null,
@@ -993,18 +1063,20 @@ let GatewayAuthState = class GatewayAuthState {
993
1063
  twoFactorRequired: false,
994
1064
  appSessions: {},
995
1065
  appLaunchLoading: {},
1066
+ activeApplicationCode: null,
996
1067
  });
997
- return this.toObservable(this.options.afterLogin?.(session, ctx)).pipe(mergeMap(() => this.maybeAutoLaunchApplication(ctx)), tap(() => {
1068
+ return this.toObservable(this.options.afterLogin?.(session, ctx)).pipe(mergeMap(() => this.maybeAutoLaunchApplication(ctx, resolvedApplicationCode)), tap(() => {
998
1069
  this.router.navigateByUrl(this.resolveAuthenticatedRoute(), {
999
1070
  replaceUrl: true,
1000
1071
  });
1001
1072
  }));
1002
1073
  }
1003
- maybeAutoLaunchApplication(ctx) {
1074
+ maybeAutoLaunchApplication(ctx, resolvedApplicationCode) {
1004
1075
  if (!this.options.autoLaunchApplicationOnLogin) {
1005
1076
  return of(null);
1006
1077
  }
1007
- const code = resolveApplicationCodeOption(this.options.applicationCode);
1078
+ const code = resolvedApplicationCode ??
1079
+ resolveApplicationCodeOption(this.options.applicationCode);
1008
1080
  if (!code) {
1009
1081
  return of(null);
1010
1082
  }
@@ -1185,6 +1257,9 @@ __decorate([
1185
1257
  __decorate([
1186
1258
  Selector()
1187
1259
  ], GatewayAuthState, "appLaunchLoading", null);
1260
+ __decorate([
1261
+ Selector()
1262
+ ], GatewayAuthState, "activeApplicationCode", null);
1188
1263
  GatewayAuthState = __decorate([
1189
1264
  State({
1190
1265
  name: 'auth',
@@ -1217,6 +1292,7 @@ class GatewayAuthFacade {
1217
1292
  applicationsLoading = select(GatewayAuthState.applicationsLoading);
1218
1293
  appSessions = select(GatewayAuthState.appSessions);
1219
1294
  appLaunchLoading = select(GatewayAuthState.appLaunchLoading);
1295
+ activeApplicationCode = select(GatewayAuthState.activeApplicationCode);
1220
1296
  hasError = computed(() => this.error() !== null, ...(ngDevMode ? [{ debugName: "hasError" }] : /* istanbul ignore next */ []));
1221
1297
  isReady = computed(() => !this.loading() && this.error() === null, ...(ngDevMode ? [{ debugName: "isReady" }] : /* istanbul ignore next */ []));
1222
1298
  userDisplayName = computed(() => this.user()?.user?.displayName || '', ...(ngDevMode ? [{ debugName: "userDisplayName" }] : /* istanbul ignore next */ []));
@@ -1523,8 +1599,14 @@ const prepareRequest = (req, token, markRetried, baseUrl) => {
1523
1599
  }
1524
1600
  return modifiedReq;
1525
1601
  };
1526
- const resolveRequestScope = (req, options, auth) => {
1527
- const useGatewayBaseUrl = options.shouldUseGatewayApiBaseUrl?.(req) ?? false;
1602
+ const urlMatchesBase = (url, baseUrl) => {
1603
+ if (!baseUrl || !isAbsoluteUrl(url)) {
1604
+ return false;
1605
+ }
1606
+ return url.startsWith(normalizeBase(baseUrl));
1607
+ };
1608
+ const resolveRequestScope = (req, options, auth, gatewayApiBaseUrl) => {
1609
+ // 1. Per-request override wins.
1528
1610
  const explicitCode = options.resolveApplicationCodeForRequest?.(req);
1529
1611
  if (explicitCode) {
1530
1612
  const session = auth.getAppSession(explicitCode);
@@ -1532,13 +1614,21 @@ const resolveRequestScope = (req, options, auth) => {
1532
1614
  scope: 'application',
1533
1615
  applicationCode: explicitCode,
1534
1616
  session,
1535
- useGatewayBaseUrl,
1617
+ useGatewayBaseUrl: false,
1536
1618
  };
1537
1619
  }
1538
- if (useGatewayBaseUrl) {
1620
+ // 2. Caller hint via request context.
1621
+ if (options.shouldUseGatewayApiBaseUrl?.(req)) {
1539
1622
  return { scope: 'gateway', useGatewayBaseUrl: true };
1540
1623
  }
1541
- const defaultCode = resolveApplicationCodeOption(options.applicationCode);
1624
+ // 3. Absolute URL pointing at the Gateway base must use GatewaySession.
1625
+ // Covers /api/auth/*, /api/auth/me/applications, /api/applications/{code}/launch.
1626
+ if (urlMatchesBase(req.url, gatewayApiBaseUrl)) {
1627
+ return { scope: 'gateway', useGatewayBaseUrl: false };
1628
+ }
1629
+ // 4. Otherwise treat as app scope when a session exists.
1630
+ const defaultCode = resolveApplicationCodeOption(options.applicationCode) ??
1631
+ auth.activeApplicationCode();
1542
1632
  if (defaultCode) {
1543
1633
  const session = auth.getAppSession(defaultCode);
1544
1634
  if (session) {
@@ -1546,11 +1636,12 @@ const resolveRequestScope = (req, options, auth) => {
1546
1636
  scope: 'application',
1547
1637
  applicationCode: defaultCode,
1548
1638
  session,
1549
- useGatewayBaseUrl,
1639
+ useGatewayBaseUrl: false,
1550
1640
  };
1551
1641
  }
1552
1642
  }
1553
- return { scope: 'gateway', useGatewayBaseUrl };
1643
+ // 5. No app session known yet — fall back to GatewaySession.
1644
+ return { scope: 'gateway', useGatewayBaseUrl: false };
1554
1645
  };
1555
1646
  const gatewayAuthInterceptor = (req, next) => {
1556
1647
  if (isAssetRequest(req.url)) {
@@ -1565,7 +1656,7 @@ const gatewayAuthInterceptor = (req, next) => {
1565
1656
  const refreshSkewMs = resolveAccessTokenRefreshSkewMs(options.accessTokenRefreshSkewMs);
1566
1657
  const isAuthRequest = isGatewayAuthRequestUrl(req.url, gatewayApiBaseUrl);
1567
1658
  const alreadyRetried = req.context.get(GATEWAY_AUTH_RETRY_CONTEXT);
1568
- const resolved = resolveRequestScope(req, options, auth);
1659
+ const resolved = resolveRequestScope(req, options, auth, gatewayApiBaseUrl);
1569
1660
  const baseUrl = resolved.useGatewayBaseUrl
1570
1661
  ? gatewayApiBaseUrl
1571
1662
  : appApiBaseUrl;
@@ -1607,7 +1698,7 @@ const gatewayAuthInterceptor = (req, next) => {
1607
1698
  auth.logout();
1608
1699
  }
1609
1700
  return throwError(() => refreshError);
1610
- }), switchMap((tokens) => next(prepareRequest(req, tokens.accessToken, true, baseUrl))));
1701
+ }), switchMap$1((tokens) => next(prepareRequest(req, tokens.accessToken, true, baseUrl))));
1611
1702
  }
1612
1703
  return next(prepareRequest(req, tokenToAttach, false, baseUrl)).pipe(catchError$1((error) => {
1613
1704
  if (error?.status !== 401 || isAuthRequest || alreadyRetried) {
@@ -1640,7 +1731,7 @@ const gatewayAuthInterceptor = (req, next) => {
1640
1731
  auth.logout();
1641
1732
  }
1642
1733
  return throwError(() => refreshError);
1643
- }), switchMap((tokens) => next(prepareRequest(req, tokens.accessToken, true, baseUrl))));
1734
+ }), switchMap$1((tokens) => next(prepareRequest(req, tokens.accessToken, true, baseUrl))));
1644
1735
  }));
1645
1736
  };
1646
1737
 
@@ -1989,5 +2080,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
1989
2080
  * Generated bundle index. Do not edit.
1990
2081
  */
1991
2082
 
1992
- 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, buildGatewayUrl, buildSsoStartUrl, createSecureClientState, extractGatewayRateLimitInfo, gatewayAuthInterceptor, getGatewayErrorMessage, hasGatewayTokens, isExpired, isGatewayAuthRequestUrl, mapGatewayTokens, mapGatewayUser, normalizeGatewayBase, readPersistedGatewayAuthTokens, resolveAccessTokenRefreshSkewMs, resolveApiDateValue, resolveApplicationCodeOption, resolveGatewayAuthPath, resolveGatewayDeviceToken, sanitizePersistedAuthState, withGatewayAuthNgswBypass };
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 };
1993
2084
  //# sourceMappingURL=masterteam-gateway-auth.mjs.map