@gridsuite/commons-ui 0.43.1 → 0.45.0

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.
@@ -11,9 +11,14 @@ import React from 'react';
11
11
  import { Button } from '@mui/material';
12
12
  import { FormattedMessage } from 'react-intl';
13
13
  import PropTypes from 'prop-types';
14
+ import { useThemeProps } from '@mui/material/styles';
14
15
  var CancelButton = function CancelButton(_ref) {
15
- var buttonProps = _extends({}, (_objectDestructuringEmpty(_ref), _ref));
16
- return /*#__PURE__*/React.createElement(Button, buttonProps, /*#__PURE__*/React.createElement(FormattedMessage, {
16
+ var inProps = _extends({}, (_objectDestructuringEmpty(_ref), _ref));
17
+ var props = useThemeProps({
18
+ props: inProps,
19
+ name: 'CancelButton'
20
+ });
21
+ return /*#__PURE__*/React.createElement(Button, props, /*#__PURE__*/React.createElement(FormattedMessage, {
17
22
  id: "cancel"
18
23
  }));
19
24
  };
@@ -12,34 +12,62 @@ import jwtDecode from 'jwt-decode';
12
12
 
13
13
  // set as a global variable to allow log level configuration at runtime
14
14
  window.OIDCLog = Log;
15
- var hackauthoritykey = 'oidc.hack.authority';
15
+ var hackAuthorityKey = 'oidc.hack.authority';
16
+ var oidcHackReloadedKey = 'gridsuite-oidc-hack-reloaded';
16
17
  var pathKey = 'powsybl-gridsuite-current-path';
18
+ function isIssuerErrorForCodeFlow(error) {
19
+ return error.message.includes('Invalid issuer in token');
20
+ }
21
+ function extractIssuerToSessionStorage(error) {
22
+ var issuer = error.message.split(' ').pop();
23
+ sessionStorage.setItem(hackAuthorityKey, issuer);
24
+ }
25
+ function reload() {
26
+ if (!sessionStorage.getItem(oidcHackReloadedKey)) {
27
+ sessionStorage.setItem(oidcHackReloadedKey, true);
28
+ console.log('Hack oidc, reload page to make login work');
29
+ window.location.reload();
30
+ }
31
+ }
32
+ function reloadTimerOnExpiresIn(user, userManager, expiresIn) {
33
+ // TODO: Can we stop doing it in the hash for implicit flow ? To make it common for both flows
34
+ user.expires_in = expiresIn;
35
+ userManager.storeUser(user).then(function () {
36
+ userManager.getUser();
37
+ });
38
+ }
17
39
  function handleSigninSilent(dispatch, userManager) {
18
40
  userManager.getUser().then(function (user) {
19
41
  if (user == null || getIdTokenExpiresIn(user) < 0) {
20
42
  return userManager.signinSilent()["catch"](function (error) {
21
43
  dispatch(setShowAuthenticationRouterLogin(true));
22
- var oidcHackReloaded = 'gridsuite-oidc-hack-reloaded';
23
- if (!sessionStorage.getItem(oidcHackReloaded) && error.message === 'authority mismatch on settings vs. signin state') {
24
- sessionStorage.setItem(oidcHackReloaded, true);
25
- console.log('Hack oidc, reload page to make login work');
26
- window.location.reload();
44
+ var errorIssuerCodeFlow = isIssuerErrorForCodeFlow(error);
45
+ var errorIssuerImplicitFlow = error.message === 'authority mismatch on settings vs. signin state';
46
+ if (errorIssuerCodeFlow) {
47
+ // Replacing authority for code flow only because it's done in the hash for implicit flow
48
+ // TODO: Can we stop doing it in the hash for implicit flow ? To make it common here for both flows
49
+ extractIssuerToSessionStorage(error);
50
+ }
51
+ if (errorIssuerCodeFlow || errorIssuerImplicitFlow) {
52
+ reload();
27
53
  }
28
54
  });
29
55
  }
30
56
  });
31
57
  }
32
- function initializeAuthenticationDev(dispatch, isSilentRenew, validateUser) {
58
+ function initializeAuthenticationDev(dispatch, isSilentRenew, validateUser, isSigninCallback) {
33
59
  var userManager = new UserManagerMock({});
34
60
  if (!isSilentRenew) {
35
61
  handleUser(dispatch, userManager, validateUser);
36
- handleSigninSilent(dispatch, userManager);
62
+ if (!isSigninCallback) {
63
+ handleSigninSilent(dispatch, userManager);
64
+ }
37
65
  }
38
66
  return Promise.resolve(userManager);
39
67
  }
40
68
  var accessTokenExpiringNotificationTime = 60; // seconds
41
69
 
42
- function initializeAuthenticationProd(dispatch, isSilentRenew, idpSettings, validateUser, authorizationCodeFlowEnabled) {
70
+ function initializeAuthenticationProd(dispatch, isSilentRenew, idpSettings, validateUser, authorizationCodeFlowEnabled, isSigninCallback) {
43
71
  return idpSettings.then(function (r) {
44
72
  return r.json();
45
73
  }).then(function (idpSettings) {
@@ -62,33 +90,16 @@ function initializeAuthenticationProd(dispatch, isSilentRenew, idpSettings, vali
62
90
  console.debug('Replacing authority in storedState. Before: ', storedState.authority, 'after: ', authority);
63
91
  storedState.authority = authority;
64
92
  localStorage.setItem('oidc.' + state, JSON.stringify(storedState));
65
- sessionStorage.setItem(hackauthoritykey, authority);
93
+ sessionStorage.setItem(hackAuthorityKey, authority);
66
94
  var matched_expires = window.location.hash.match(regexexpires);
67
95
  if (matched_expires != null) {
68
96
  var expires_in = parseInt(matched_expires[0].split('=')[1]);
69
- var now = parseInt(Date.now() / 1000);
70
- var exp = decoded.exp;
71
- var idTokenExpiresIn = exp - now;
72
- var minAccesstokenOrIdtokenOrIdpSettingsExpiresIn = expires_in;
73
- var newExpireReplaceReason;
74
- if (idTokenExpiresIn < minAccesstokenOrIdtokenOrIdpSettingsExpiresIn) {
75
- minAccesstokenOrIdtokenOrIdpSettingsExpiresIn = idTokenExpiresIn;
76
- newExpireReplaceReason = 'idtoken.exp is earlier';
77
- }
78
- if (idpSettings.maxExpiresIn && idpSettings.maxExpiresIn < minAccesstokenOrIdtokenOrIdpSettingsExpiresIn) {
79
- minAccesstokenOrIdtokenOrIdpSettingsExpiresIn = idpSettings.maxExpiresIn;
80
- newExpireReplaceReason = 'idpSettings.maxExpiresIn is smaller';
81
- }
82
- if (newExpireReplaceReason) {
83
- var newhash = window.location.hash.replace(matched_expires[0], 'expires_in=' + minAccesstokenOrIdtokenOrIdpSettingsExpiresIn);
84
- console.debug('Replacing expires_in in window.location.hash to ' + minAccesstokenOrIdtokenOrIdpSettingsExpiresIn + ' because ' + newExpireReplaceReason + '. ', 'debug:', 'original expires_in: ' + expires_in + ', ', 'idTokenExpiresIn: ' + idTokenExpiresIn + '(idtoken exp: ' + exp + '), ', 'idpSettings maxExpiresIn: ' + idpSettings.maxExpiresIn);
85
- window.location.hash = newhash;
86
- }
97
+ window.location.hash = window.location.hash.replace(matched_expires[0], 'expires_in=' + computeMinExpiresIn(expires_in, id_token, idpSettings.maxExpiresIn));
87
98
  }
88
99
  }
89
100
  }
90
101
  }
91
- authority = authority || sessionStorage.getItem(hackauthoritykey) || idpSettings.authority;
102
+ authority = authority || sessionStorage.getItem(hackAuthorityKey) || idpSettings.authority;
92
103
  var responseSettings = authorizationCodeFlowEnabled ? {
93
104
  response_type: 'code'
94
105
  } : {
@@ -107,9 +118,12 @@ function initializeAuthenticationProd(dispatch, isSilentRenew, idpSettings, vali
107
118
  }, responseSettings);
108
119
  var userManager = new UserManager(settings);
109
120
  userManager.idpSettings = idpSettings; //store our settings in there as well to use it later
121
+ userManager.authorizationCodeFlowEnabled = authorizationCodeFlowEnabled;
110
122
  if (!isSilentRenew) {
111
123
  handleUser(dispatch, userManager, validateUser);
112
- handleSigninSilent(dispatch, userManager);
124
+ if (!isSigninCallback) {
125
+ handleSigninSilent(dispatch, userManager);
126
+ }
113
127
  }
114
128
  return userManager;
115
129
  })["catch"](function (error) {
@@ -118,6 +132,25 @@ function initializeAuthenticationProd(dispatch, isSilentRenew, idpSettings, vali
118
132
  throw error;
119
133
  });
120
134
  }
135
+ function computeMinExpiresIn(expiresIn, idToken, maxExpiresIn) {
136
+ var now = parseInt(Date.now() / 1000);
137
+ var exp = jwtDecode(idToken).exp;
138
+ var idTokenExpiresIn = exp - now;
139
+ var newExpiresIn = expiresIn;
140
+ var newExpiresInReplaceReason;
141
+ if (expiresIn === undefined || idTokenExpiresIn < newExpiresIn) {
142
+ newExpiresIn = idTokenExpiresIn;
143
+ newExpiresInReplaceReason = 'idtoken.exp is earlier';
144
+ }
145
+ if (maxExpiresIn && maxExpiresIn < newExpiresIn) {
146
+ newExpiresIn = maxExpiresIn;
147
+ newExpiresInReplaceReason = 'idpSettings.maxExpiresIn is smaller';
148
+ }
149
+ if (newExpiresInReplaceReason) {
150
+ console.debug('Replacing expiresIn in user to ' + newExpiresIn + ' because ' + newExpiresInReplaceReason + '. ', 'debug:', 'original expires_in: ' + expiresIn + ', ', 'idTokenExpiresIn: ' + idTokenExpiresIn + ', idpSettings maxExpiresIn: ' + maxExpiresIn);
151
+ }
152
+ return newExpiresIn;
153
+ }
121
154
  function login(location, userManagerInstance) {
122
155
  sessionStorage.setItem(pathKey, location.pathname + location.search);
123
156
  return userManagerInstance.signinRedirect().then(function () {
@@ -125,7 +158,7 @@ function login(location, userManagerInstance) {
125
158
  });
126
159
  }
127
160
  function logout(dispatch, userManagerInstance) {
128
- sessionStorage.removeItem(hackauthoritykey); //To remove when hack is removed
161
+ sessionStorage.removeItem(hackAuthorityKey); //To remove when hack is removed
129
162
  return userManagerInstance.getUser().then(function (user) {
130
163
  if (user) {
131
164
  // We don't need to check if token is valid at this point
@@ -173,6 +206,12 @@ function dispatchUser(dispatch, userManagerInstance, validateUser) {
173
206
  return dispatch(setUnauthorizedUserInfo(user === null || user === void 0 ? void 0 : (_user$profile2 = user.profile) === null || _user$profile2 === void 0 ? void 0 : _user$profile2.name, {}));
174
207
  }
175
208
  console.debug('User has been successfully loaded from store.');
209
+
210
+ // In authorization code flow we have to make the oidc-client lib re-evaluate the date of the token renewal timers
211
+ // because it is not hacked at page loading on the fragment before oidc-client lib initialization
212
+ if (userManagerInstance.authorizationCodeFlowEnabled) {
213
+ reloadTimerOnExpiresIn(user, userManagerInstance, computeMinExpiresIn(user.expires_in, user.id_token, userManagerInstance.idpSettings.maxExpiresIn));
214
+ }
176
215
  return dispatch(setLoggedUser(user));
177
216
  })["catch"](function (e) {
178
217
  var _user$profile3;
@@ -189,11 +228,31 @@ function dispatchUser(dispatch, userManagerInstance, validateUser) {
189
228
  function getPreLoginPath() {
190
229
  return sessionStorage.getItem(pathKey);
191
230
  }
231
+ function navigateToPreLoginPath(navigate) {
232
+ var previousPath = getPreLoginPath();
233
+ navigate(previousPath);
234
+ }
192
235
  function handleSigninCallback(dispatch, navigate, userManagerInstance) {
193
- userManagerInstance.signinRedirectCallback().then(function () {
236
+ var reloadAfterNavigate = false;
237
+ userManagerInstance.signinRedirectCallback()["catch"](function (e) {
238
+ if (isIssuerErrorForCodeFlow(e)) {
239
+ // Replacing authority for code flow only because it's done in the hash for implicit flow
240
+ // TODO: Can we also do it here for the implicit flow ? To make it common here for both flows
241
+ extractIssuerToSessionStorage(e);
242
+ // After navigate, location will be out of a redirection route (sign-in-silent or sign-in-callback) so reloading the page will attempt a silent signin
243
+ // It will reload the user manager based on hacked authority at initialization with the new authority
244
+ // We do this because on Azure we only get to know the issuer of the user in the idtoken and so signingredirectcallback will always fail
245
+ // We could restart the whole login process from signin redirect with the correct issuer, but instead we just rely on the silent login after the reload which will work
246
+ reloadAfterNavigate = true;
247
+ } else {
248
+ throw e;
249
+ }
250
+ }).then(function () {
194
251
  dispatch(setSignInCallbackError(null));
195
- var previousPath = getPreLoginPath();
196
- navigate(previousPath);
252
+ navigateToPreLoginPath(navigate);
253
+ if (reloadAfterNavigate) {
254
+ reload();
255
+ }
197
256
  })["catch"](function (e) {
198
257
  dispatch(setSignInCallbackError(e));
199
258
  console.error(e);
@@ -209,8 +268,9 @@ function handleUser(dispatch, userManager, validateUser) {
209
268
  });
210
269
  userManager.events.addSilentRenewError(function (error) {
211
270
  console.debug(error);
212
- // wait for accessTokenExpiringNotificationTime so that the user is expired
213
- // otherwise the library tries to signin immediately when we do getUser()
271
+ // Wait for accessTokenExpiringNotificationTime so that the user is expired and not between expiring and expired
272
+ // otherwise the library will fire AccessTokenExpiring everytime we do getUser()
273
+ // Indeed, getUSer() => loadUser() => load() on events => if it's already expiring it will be init and triggerred again
214
274
  window.setTimeout(function () {
215
275
  userManager.getUser().then(function (user) {
216
276
  if (!user) {
@@ -229,16 +289,10 @@ function handleUser(dispatch, userManager, validateUser) {
229
289
  // TODO here attempt last chance login ? snackbar to notify the user ? Popup ?
230
290
  // for now we do the same thing as in the else block
231
291
  console.log('Error in silent renew, but idtoken ALMOST expiring (expiring in' + idTokenExpiresIn + ') => last chance, next error will logout', 'maxExpiresIn = ' + userManager.idpSettings.maxExpiresIn, 'last renew attempt in ' + idTokenExpiresIn - accessTokenExpiringNotificationTime + 'seconds', error);
232
- user.expires_in = idTokenExpiresIn;
233
- userManager.storeUser(user).then(function () {
234
- userManager.getUser();
235
- });
292
+ reloadTimerOnExpiresIn(user, userManager, idTokenExpiresIn);
236
293
  } else {
237
294
  console.log('Error in silent renew, but idtoken NOT expiring (expiring in' + idTokenExpiresIn + ') => postponing expiration to' + userManager.idpSettings.maxExpiresIn, error);
238
- user.expires_in = userManager.idpSettings.maxExpiresIn;
239
- userManager.storeUser(user).then(function () {
240
- userManager.getUser();
241
- });
295
+ reloadTimerOnExpiresIn(user, userManager, userManager.idpSettings.maxExpiresIn);
242
296
  }
243
297
  } else {
244
298
  console.log('Error in silent renew, unsupported configuration: token still valid for ' + idTokenExpiresIn + ' but maxExpiresIn is not configured:' + userManager.idpSettings.maxExpiresIn, error);
@@ -7,12 +7,14 @@
7
7
  import React from 'react';
8
8
  import LibraryBooksOutlinedIcon from '@mui/icons-material/LibraryBooksOutlined';
9
9
  import OfflineBoltIcon from '@mui/icons-material/OfflineBolt';
10
+ import NoteAltIcon from '@mui/icons-material/NoteAlt';
10
11
  import ArticleIcon from '@mui/icons-material/Article';
11
12
  import SettingsIcon from '@mui/icons-material/Settings';
12
13
  export var elementType = {
13
14
  DIRECTORY: 'DIRECTORY',
14
15
  STUDY: 'STUDY',
15
16
  FILTER: 'FILTER',
17
+ MODIFICATION: 'MODIFICATION',
16
18
  CONTINGENCY_LIST: 'CONTINGENCY_LIST',
17
19
  VOLTAGE_INIT_PARAMETERS: 'VOLTAGE_INIT_PARAMETERS'
18
20
  };
@@ -26,6 +28,10 @@ export function getFileIcon(type, style) {
26
28
  return /*#__PURE__*/React.createElement(OfflineBoltIcon, {
27
29
  sx: style
28
30
  });
31
+ case elementType.MODIFICATION:
32
+ return /*#__PURE__*/React.createElement(NoteAltIcon, {
33
+ sx: style
34
+ });
29
35
  case elementType.FILTER:
30
36
  return /*#__PURE__*/React.createElement(ArticleIcon, {
31
37
  sx: style
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gridsuite/commons-ui",
3
- "version": "0.43.1",
3
+ "version": "0.45.0",
4
4
  "description": "common react components for gridsuite applications",
5
5
  "engines": {
6
6
  "npm": ">=9",