diff --git a/src/settings/RefreshTokenRotation.js b/src/settings/RefreshTokenRotation.js index 626c7f00..bf7b91ac 100644 --- a/src/settings/RefreshTokenRotation.js +++ b/src/settings/RefreshTokenRotation.js @@ -1,70 +1,79 @@ -import { useEffect, useState } from 'react'; +import { merge } from 'lodash'; import PropTypes from 'prop-types'; +import { useCallback, useEffect, useState } from 'react'; +import { Field, Form } from 'react-final-form'; import { FormattedMessage } from 'react-intl'; -import { - getTokenExpiry, - setTokenExpiry, -} from '@folio/stripes/core'; - -import { - Button, - LoadingPane, - Pane, - PaneHeader, -} from '@folio/stripes/components'; +import { getTokenExpiry } from '@folio/stripes/core'; +import { Button, LoadingPane, Pane, PaneHeader, TextField } from '@folio/stripes/components'; /** * manipulate AT/RT expiration dates in storage in order to test RTR. * @returns */ -const RefreshTokenRotation = () => { +const RefreshTokenRotation = ({ stripes }) => { + // why WHY copy this string here instead of importing it from stripes-core? + // + // RTR_FORCE_REFRESH_EVENT will be present in stripes-core 10.2.0 (stripes + // 9.2.0). Importing it would force the stripes peer depedency to bump from + // ^9.1.0 to ^9.2.0.If we copy the string instead of importing it, we can + // remain compatible with 9.1.0. + // + // OK, compatibility is nice. But it's still gross, right? Yep, super gross. + // Aren't you nauseated? Yes, yes I am. 🤢🧼🛁 + const RTR_FORCE_REFRESH_EVENT = '@folio/stripes/core::RTRForceRefresh'; + const [isLoading, setIsLoading] = useState(true); const [tokenExpiration, setTokenExpiration] = useState({}); useEffect(() => { - getTokenExpiry() - .then(te => { - setTokenExpiration(te ?? { atExpires: -1, rtExpires: -1 }); - setIsLoading(false); - }); + setIsLoading(true); + getTokenExpiry().then((te) => { + setTokenExpiration(te ?? { atExpires: -1, rtExpires: -1 }); + setIsLoading(false); + }); }, []); /** - * invalidateAT - * return a promise to expire the AT in local storage + * forceRefresh + * dispatch an event to force a token rotation */ - const invalidateAT = () => { - return getTokenExpiry() - .then(te => { - const expiration = { ...te }; - expiration.atExpires = -1; - - return setTokenExpiry(expiration); - }); - }; + const forceRefresh = useCallback( + () => window.dispatchEvent(new Event(RTR_FORCE_REFRESH_EVENT)), + [], + ); /** - * invalidateRT - * return a promise to expire the AT and RT in local storage + * saveRtrConfig + * update stripes.config.rtr from form */ - const invalidateRT = () => { - const expiration = { - atExpires: -1, - rtExpires: -1, - }; + const saveRtrConfig = useCallback( + (values) => { + merge(stripes.config.rtr, { + idleSessionTTL: values.idleSessionTTL, + idleModalTTL: values.idleModalTTL, + fixedLengthSessionWarningTTL: values.fixedLengthSessionWarningTTL, + rotationIntervalFraction: Number(values.rotationIntervalFraction), + activityEvents: values.activityEvents.split(',').map((e) => e.trim()), + }); - return setTokenExpiry(expiration); - }; + forceRefresh(); + }, + [stripes, forceRefresh], + ); if (!isLoading) { return ( } />} + renderHeader={(renderProps) => ( + } /> + )} >
    -
  • stripes logs RTR events in the category rtr
  • +
  • + stripes logs RTR events in the category rtr +
{!isLoading && (
@@ -75,8 +84,53 @@ const RefreshTokenRotation = () => {
)}
- - + + +
+ {({ handleSubmit, pristine, submitting }) => ( + + } + /> + } + /> + } + /> + } + type="number" + step={0.01} + min={0} + /> + } + /> + + + )} +
); @@ -89,7 +143,15 @@ RefreshTokenRotation.propTypes = { stripes: PropTypes.shape({ okapi: PropTypes.shape({ tenant: PropTypes.string, - }) + }), + config: PropTypes.shape({ + rtr: PropTypes.shape({ + idleSessionTTL: PropTypes.string, + idleModalTTL: PropTypes.string, + rotationIntervalFraction: PropTypes.number, + activityEvents: PropTypes.arrayOf(PropTypes.string), + }), + }), }).isRequired, }; diff --git a/translations/ui-developer/en.json b/translations/ui-developer/en.json index 6323ba00..c04d63b2 100644 --- a/translations/ui-developer/en.json +++ b/translations/ui-developer/en.json @@ -168,8 +168,12 @@ "userLocale.numberingSystem": "Numbering system (override locale's default; details)", "rtr": "Refresh token rotation", - "rtr.invalidateAT": "Invalidate access token", - "rtr.invalidateRT": "Invalidate refresh token", + "rtr.forceRefresh": "Force refresh", + "rtr.idleSessionTTL": "idleSessionTTL: duration an idle session lasts before being killed (e.g. 1h, 1m, 5s, 10ms)", + "rtr.idleModalTTL": "idleModalTTL: duration the idle modal should be shown before session is killed (e.g. 1h, 1m, 5s, 10ms)", + "rtr.fixedLengthSessionWarningTTL": "fixedLengthSessionWarningTTL: how long the “your session is going to die!” warning should be shown before the session is killed (e.g. 1h, 1m, 5s, 10ms)", + "rtr.rotationIntervalFraction": "rotationIntervalFraction: decimal fraction of how early to refresh the access token (e.g. 0.6 is 60% into the lifetime of the token)", + "rtr.activityEvents": "activityEvents: which DOM events constitute user activity (comma-separated, e.g. 'mousemove,keydown')", "rtr.registerServiceWorker": "Register the service worker", "rtr.unregisterServiceWorker": "Unregister the service worker", @@ -192,5 +196,4 @@ "permission.settings.okapiConsole.modules": "Settings (developer): Can use the Okapi console's Modules tab", "permission.settings.userLocale": "Settings (developer): Can edit locale entries for any user", "permission.settings.okapiTimers": "Settings (developer): Can view okapi timers" - }