Skip to content

Commit

Permalink
Merge branch 'master' into STCOR-897-clear-cookie
Browse files Browse the repository at this point in the history
  • Loading branch information
julianladisch authored Oct 15, 2024
2 parents dc6d9ea + cc8ef65 commit 5534467
Show file tree
Hide file tree
Showing 44 changed files with 398 additions and 181 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
* Include optional okapi interfaces, `consortia`, `roles`, `users-keycloak`. Refs STCOR-889.
* useUserTenantPermissions hook - provide `isFetched` property. Refs STCOR-890.
* Reword error message "Error: server is forbidden, unreachable or down. Clear the cookies? Use incognito mode? VPN issue?". Refs STCOR-893, STCOR-897.
* Move session timeout banner to the bottom of the page. Refs STCOR-883.
* Wait longer before declaring a rotation request to be stale. Refs STCOR-895.

## [10.1.1](https://github.com/folio-org/stripes-core/tree/v10.1.1) (2024-03-25)
[Full Changelog](https://github.com/folio-org/stripes-core/compare/v10.1.0...v10.1.1)
Expand Down
6 changes: 6 additions & 0 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import configureLogger from './configureLogger';
import configureStore from './configureStore';
import gatherActions from './gatherActions';
import { destroyStore } from './mainActions';
import css from './components/SessionEventContainer/style.css';

import Root from './components/Root';
import { eventsPortal } from './constants';

const StrictWrapper = ({ children }) => {
if (config.disableStrictMode) {
Expand Down Expand Up @@ -58,6 +60,10 @@ export default class StripesCore extends Component {

return (
<StrictWrapper>
<div
id={eventsPortal}
className={css.eventsContainer}
/>
<Root
store={this.store}
epics={this.epics}
Expand Down
14 changes: 0 additions & 14 deletions src/RootWithIntl.test.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,7 @@
/* shhhh, eslint, it's ok. we need "unused" imports for mocks */
/* eslint-disable no-unused-vars */

import { render, screen } from '@folio/jest-config-stripes/testing-library/react';
import { Router as DefaultRouter } from 'react-router-dom';
import { createMemoryHistory } from 'history';

import AuthnLogin from './components/AuthnLogin';
import {
Login,
MainNav,
MainContainer,
ModuleContainer,
OverlayContainer,
StaleBundleWarning,
SessionEventContainer,
} from './components';

import RootWithIntl from './RootWithIntl';
import Stripes from './Stripes';

Expand Down
15 changes: 14 additions & 1 deletion src/components/Root/token-util.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { isEmpty } from 'lodash';
import ms from 'ms';

import { getTokenExpiry, setTokenExpiry } from '../../loginServices';
import { RTRError, UnexpectedResourceError } from './Errors';
Expand All @@ -18,6 +19,18 @@ export const RTR_IS_ROTATING = '@folio/stripes/core::rtrIsRotating';
* RTR_MAX_AGE (int)
* How long do we let a refresh request last before we consider it stale?
*
* WARNING: The implementation described below is naive and short timeouts
* (e.g. 2 seconds) have led to problems in production where slow responses
* are interpreted as stale, leading to a second request, which then fails
* when the first (slooooow) request completes. This looks like a token-
* replay attack from the backend's view, so it will then terminate all
* active sessions for a given user. A better approach would be to handle
* rotation in a worker thread, allowing more careful tracking of the
* rotation request since it would only be happening in a single thread.
* But ... that's a lot more work. The quick fix is to use a long value,
* which might not provide an ideal UX, but at least it won't be a broken
* UX.
*
* When RTR begins, the current time in milliseconds (i.e. Date.now()) is
* cached in localStorage and the existence of that value is used as a flag
* in subsequent requests to indicate that they just need to wait for the
Expand All @@ -32,7 +45,7 @@ export const RTR_IS_ROTATING = '@folio/stripes/core::rtrIsRotating';
*
* Time in milliseconds
*/
export const RTR_MAX_AGE = 2000;
export const RTR_MAX_AGE = ms('20s');

/**
* resourceMapper
Expand Down
4 changes: 2 additions & 2 deletions src/components/Root/token-util.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ describe('rtr', () => {

expect(ex).toBe(null);
// expect(window.removeEventListener).toHaveBeenCalled();
});
}, 25000); // timeout must be longer than token-util's RTR_MAX_AGE

it('multiple window (storage event)', async () => {
const logger = {
Expand Down Expand Up @@ -214,7 +214,7 @@ describe('rtr', () => {

expect(ex).toBe(null);
// expect(window.removeEventListener).toHaveBeenCalledWith('monkey')
});
}, 25000); // timeout must be longer than token-util's RTR_MAX_AGE
});

it('on known error, throws error', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from '@folio/stripes-components';

import { useStripes } from '../../StripesContext';
import css from './style.css';

/**
* FixedLengthSessionWarning
Expand Down Expand Up @@ -48,7 +49,7 @@ const FixedLengthSessionWarning = () => {
return '00:00';
};

return <MessageBanner type="warning" show><FormattedMessage id="stripes-core.rtr.fixedLengthSession.timeRemaining" /> {timestampFormatter()}</MessageBanner>;
return <MessageBanner show contentClassName={css.fixedSessionBanner}><FormattedMessage id="stripes-core.rtr.fixedLengthSession.timeRemaining" />{timestampFormatter()}</MessageBanner>;
};

export default FixedLengthSessionWarning;
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import PropTypes from 'prop-types';
import createInactivityTimer from 'inactivity-timer';
import ms from 'ms';
Expand All @@ -15,6 +16,7 @@ import {
} from '../Root/constants';
import { toggleRtrModal } from '../../okapiActions';
import FixedLengthSessionWarning from './FixedLengthSessionWarning';
import { eventsPortal } from '../../constants';

//
// event listeners
Expand Down Expand Up @@ -278,7 +280,7 @@ const SessionEventContainer = ({ history }) => {
renderList.push(<FixedLengthSessionWarning key="FixedLengthSessionWarning" />);
}

return renderList.length ? renderList : null;
return renderList.length ? createPortal(renderList, document.getElementById(eventsPortal)) : null;
};

SessionEventContainer.propTypes = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
import { RTR_TIMEOUT_EVENT } from '../Root/constants';

import { toggleRtrModal } from '../../okapiActions';
import { eventsPortal } from '../../constants';

jest.mock('./KeepWorkingModal', () => (() => <div>KeepWorkingModal</div>));
jest.mock('../../loginServices');
Expand All @@ -37,6 +38,11 @@ const stripes = {
};

describe('SessionEventContainer', () => {
beforeAll(() => {
const eventsPortalElement = document.createElement('div');
eventsPortalElement.id = eventsPortal;
document.body.appendChild(eventsPortalElement);
});
it('Renders nothing if useSecureTokens is false', async () => {
const insecureStripes = {
config: {
Expand Down
Empty file.
14 changes: 14 additions & 0 deletions src/components/SessionEventContainer/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@import '@folio/stripes-components/lib/variables.css';

.eventsContainer {
position: absolute;
bottom: 0;
z-index: 100000;
left: 50%;
transform: translate(-50%);
border: none
}

.fixedSessionBanner {
background-color: var(--warn);
}
3 changes: 3 additions & 0 deletions src/constants/eventsPortal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const EVENTS_PORTAL = 'events-portal';

export default EVENTS_PORTAL;
1 change: 1 addition & 0 deletions src/constants/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export { default as ssoErrorCodes } from './ssoErrorCodes';
export { default as defaultErrors } from './defaultErrors';
export { default as packageName } from './packageName';
export { default as delimiters } from './delimiters';
export { default as eventsPortal } from './eventsPortal';
10 changes: 8 additions & 2 deletions translations/stripes-core/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,17 @@
"placeholder.forgotPassword": "Enter email or phone",
"placeholder.forgotUsername": "Enter email or phone",
"title.cookieEnabled": "Cookies are required to login. Please enable cookies and try again.",
"errors.sso.session.failed": "SSO Login failed. Please try again",
"logoutPending": "Log out in process...",
"rtr.idleSession.modalHeader": "Your session will expire soon!",
"rtr.idleSession.timeRemaining": "Time remaining",
"rtr.idleSession.keepWorking": "Keep working",
"rtr.idleSession.sessionExpiredSoSad": "Your session expired due to inactivity.",
"rtr.idleSession.logInAgain": "Log in again"
"rtr.idleSession.logInAgain": "Log in again",
"title.logout": "Log out",
"about.applicationCount": "{count} applications",
"about.applicationsVersionsTitle": "Applications/modules/interfaces",
"tenantChoose": "Select your tenant/library",
"tenantLibrary": "Tenant/Library",
"errors.saml.missingToken": "No <code>code</code> query parameter.",
"rtr.fixedLengthSession.timeRemaining": "Your session will end soon! Time remaining:"
}
12 changes: 9 additions & 3 deletions translations/stripes-core/ber.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"about.paneTitle": "Software versions",
"about.userInterface": "User interface",
"about.foundation": "Foundation",
"about.okapiServices": "Okapi services",
"about.okapiServices": "API gateway services",
"about.unknown": "Unknown",
"about.version": "Version {version}",
"about.forTenant": "For tenant {tenant}",
Expand Down Expand Up @@ -146,11 +146,17 @@
"placeholder.forgotPassword": "Enter email or phone",
"placeholder.forgotUsername": "Enter email or phone",
"title.cookieEnabled": "Cookies are required to login. Please enable cookies and try again.",
"errors.sso.session.failed": "SSO Login failed. Please try again",
"logoutPending": "Log out in process...",
"rtr.idleSession.modalHeader": "Your session will expire soon!",
"rtr.idleSession.timeRemaining": "Time remaining",
"rtr.idleSession.keepWorking": "Keep working",
"rtr.idleSession.sessionExpiredSoSad": "Your session expired due to inactivity.",
"rtr.idleSession.logInAgain": "Log in again"
"rtr.idleSession.logInAgain": "Log in again",
"title.logout": "Log out",
"about.applicationCount": "{count} applications",
"about.applicationsVersionsTitle": "Applications/modules/interfaces",
"tenantChoose": "Select your tenant/library",
"tenantLibrary": "Tenant/Library",
"errors.saml.missingToken": "No <code>code</code> query parameter.",
"rtr.fixedLengthSession.timeRemaining": "Your session will end soon! Time remaining:"
}
12 changes: 9 additions & 3 deletions translations/stripes-core/ca.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"about.paneTitle": "Software versions",
"about.userInterface": "User interface",
"about.foundation": "Foundation",
"about.okapiServices": "Okapi services",
"about.okapiServices": "API gateway services",
"about.unknown": "Unknown",
"about.version": "Version {version}",
"about.forTenant": "For tenant {tenant}",
Expand Down Expand Up @@ -146,11 +146,17 @@
"placeholder.forgotPassword": "Enter email or phone",
"placeholder.forgotUsername": "Enter email or phone",
"title.cookieEnabled": "Cookies are required to login. Please enable cookies and try again.",
"errors.sso.session.failed": "SSO Login failed. Please try again",
"logoutPending": "Log out in process...",
"rtr.idleSession.modalHeader": "Your session will expire soon!",
"rtr.idleSession.timeRemaining": "Time remaining",
"rtr.idleSession.keepWorking": "Keep working",
"rtr.idleSession.sessionExpiredSoSad": "Your session expired due to inactivity.",
"rtr.idleSession.logInAgain": "Log in again"
"rtr.idleSession.logInAgain": "Log in again",
"title.logout": "Log out",
"about.applicationCount": "{count} applications",
"about.applicationsVersionsTitle": "Applications/modules/interfaces",
"tenantChoose": "Select your tenant/library",
"tenantLibrary": "Tenant/Library",
"errors.saml.missingToken": "No <code>code</code> query parameter.",
"rtr.fixedLengthSession.timeRemaining": "Your session will end soon! Time remaining:"
}
12 changes: 9 additions & 3 deletions translations/stripes-core/cs_CZ.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"about.paneTitle": "Verze softwaru",
"about.userInterface": "Uživatelské rozhraní",
"about.foundation": "Základní",
"about.okapiServices": "Služby Okapi",
"about.okapiServices": "Služby brány API",
"about.unknown": "Neznámý",
"about.version": "Verze {version}",
"about.forTenant": "Pro nájemce {tenant}",
Expand Down Expand Up @@ -146,11 +146,17 @@
"placeholder.forgotPassword": "Zadejte e-mail nebo telefon",
"placeholder.forgotUsername": "Zadejte e-mail nebo telefon",
"title.cookieEnabled": "Pro přihlášení jsou vyžadovány soubory cookie. Povolte soubory cookie a zkuste to znovu prosím.",
"errors.sso.session.failed": "Problém komunikace se serverem. Prosím zkuste to znovu",
"logoutPending": "Probíhá odhlašování...",
"rtr.idleSession.modalHeader": "Vaše relace brzy vyprší!",
"rtr.idleSession.timeRemaining": "Zbývající čas",
"rtr.idleSession.keepWorking": "Pokračovat v práci",
"rtr.idleSession.sessionExpiredSoSad": "Vaše relace vypršela z důvodu nečinnosti.",
"rtr.idleSession.logInAgain": "Znovu se přihlásit"
"rtr.idleSession.logInAgain": "Znovu se přihlásit",
"title.logout": "Odhlásit se",
"about.applicationCount": "{count} aplikací",
"about.applicationsVersionsTitle": "Aplikace/moduly/rozhraní",
"tenantChoose": "Vybrat nájemce/knihovnu",
"tenantLibrary": "Nájemce/Knihovna",
"errors.saml.missingToken": "No <code>code</code> query parameter.",
"rtr.fixedLengthSession.timeRemaining": "Vaše relace brzy skončí! Zbývající čas:"
}
12 changes: 9 additions & 3 deletions translations/stripes-core/da.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"about.paneTitle": "Softwareversioner",
"about.userInterface": "Brugergrænseflade",
"about.foundation": "Foundation",
"about.okapiServices": "Okapi services",
"about.okapiServices": "API gateway services",
"about.unknown": "Ukendt",
"about.version": "Version {version}",
"about.forTenant": "For tenant {tenant}",
Expand Down Expand Up @@ -146,11 +146,17 @@
"placeholder.forgotPassword": "Enter email or phone",
"placeholder.forgotUsername": "Enter email or phone",
"title.cookieEnabled": "Cookies are required to login. Please enable cookies and try again.",
"errors.sso.session.failed": "SSO Login failed. Please try again",
"logoutPending": "Log out in process...",
"rtr.idleSession.modalHeader": "Your session will expire soon!",
"rtr.idleSession.timeRemaining": "Time remaining",
"rtr.idleSession.keepWorking": "Keep working",
"rtr.idleSession.sessionExpiredSoSad": "Your session expired due to inactivity.",
"rtr.idleSession.logInAgain": "Log in again"
"rtr.idleSession.logInAgain": "Log in again",
"title.logout": "Log out",
"about.applicationCount": "{count} applications",
"about.applicationsVersionsTitle": "Applications/modules/interfaces",
"tenantChoose": "Select your tenant/library",
"tenantLibrary": "Tenant/Library",
"errors.saml.missingToken": "No <code>code</code> query parameter.",
"rtr.fixedLengthSession.timeRemaining": "Your session will end soon! Time remaining:"
}
10 changes: 8 additions & 2 deletions translations/stripes-core/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,17 @@
"placeholder.forgotPassword": "E-Mail oder Telefonnummer eingeben",
"placeholder.forgotUsername": "E-Mail oder Telefonnummer eingeben",
"title.cookieEnabled": "Für die Anmeldung werden Cookies benötigt. Bitte Cookies aktivieren und erneut versuchen.",
"errors.sso.session.failed": "SSO-Anmeldung fehlgeschlagen. Bitte erneut versuchen",
"logoutPending": "Abmeldung läuft...",
"rtr.idleSession.modalHeader": "Sitzung wird bald ablaufen!",
"rtr.idleSession.timeRemaining": "Verbleibende Zeit",
"rtr.idleSession.keepWorking": "Weiter arbeiten",
"rtr.idleSession.sessionExpiredSoSad": "Sitzung ist aufgrund von Inaktivität abgelaufen.",
"rtr.idleSession.logInAgain": "Erneut anmelden"
"rtr.idleSession.logInAgain": "Erneut anmelden",
"title.logout": "Log out",
"about.applicationCount": "{count} applications",
"about.applicationsVersionsTitle": "Applications/modules/interfaces",
"tenantChoose": "Select your tenant/library",
"tenantLibrary": "Tenant/Library",
"errors.saml.missingToken": "No <code>code</code> query parameter.",
"rtr.fixedLengthSession.timeRemaining": "Your session will end soon! Time remaining:"
}
13 changes: 9 additions & 4 deletions translations/stripes-core/en_GB.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"about.paneTitle": "Software versions",
"about.userInterface": "User interface",
"about.foundation": "Foundation",
"about.okapiServices": "Okapi services",
"about.okapiServices": "API gateway services",
"about.unknown": "Unknown",
"about.version": "Version {version}",
"about.forTenant": "For tenant {tenant}",
Expand Down Expand Up @@ -64,7 +64,6 @@
"title.forgotUsername": "Forgot username?",
"title.checkEmail": "Check your email",
"title.changePassword": "Change password",
"title.cookieEnabled": "Cookies are required to login. Please enable cookies and try again.",
"button.hidePassword": "Hide password",
"button.showPassword": "Show password",
"button.forgotPassword": "Forgot password?",
Expand Down Expand Up @@ -147,11 +146,17 @@
"placeholder.forgotPassword": "Enter email or phone",
"placeholder.forgotUsername": "Enter email or phone",
"title.cookieEnabled": "Cookies are required to login. Please enable cookies and try again.",
"errors.sso.session.failed": "SSO Login failed. Please try again",
"logoutPending": "Log out in process...",
"rtr.idleSession.modalHeader": "Your session will expire soon!",
"rtr.idleSession.timeRemaining": "Time remaining",
"rtr.idleSession.keepWorking": "Keep working",
"rtr.idleSession.sessionExpiredSoSad": "Your session expired due to inactivity.",
"rtr.idleSession.logInAgain": "Log in again"
"rtr.idleSession.logInAgain": "Log in again",
"title.logout": "Log out",
"about.applicationCount": "{count} applications",
"about.applicationsVersionsTitle": "Applications/modules/interfaces",
"tenantChoose": "Select your tenant/library",
"tenantLibrary": "Tenant/Library",
"errors.saml.missingToken": "No <code>code</code> query parameter.",
"rtr.fixedLengthSession.timeRemaining": "Your session will end soon! Time remaining:"
}
Loading

0 comments on commit 5534467

Please sign in to comment.