diff --git a/lib/components/keyserver-connection-handler.js b/lib/components/keyserver-connection-handler.js --- a/lib/components/keyserver-connection-handler.js +++ b/lib/components/keyserver-connection-handler.js @@ -10,19 +10,21 @@ useLogOut, } from '../actions/user-actions.js'; import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js'; -import { setSessionRecoveryInProgressActionType } from '../keyserver-conn/keyserver-conn-types.js'; +import { setNewSession } from '../keyserver-conn/keyserver-conn-types.js'; import { resolveKeyserverSessionInvalidation } from '../keyserver-conn/recovery-utils.js'; import { filterThreadIDsInFilterList } from '../reducers/calendar-filters-reducer.js'; import { connectionSelector, cookieSelector, deviceTokenSelector, + sessionIDSelector, } from '../selectors/keyserver-selectors.js'; import { isLoggedInToKeyserver } from '../selectors/user-selectors.js'; import { IdentityClientContext } from '../shared/identity-client-context.js'; import { OlmSessionCreatorContext } from '../shared/olm-session-creator-context.js'; import type { BaseSocketProps } from '../socket/socket.react.js'; import { logInActionSources } from '../types/account-types.js'; +import { genericCookieInvalidation } from '../types/session-types.js'; import { authoritativeKeyserverID } from '../utils/authoritative-keyserver.js'; import { useDispatchActionPromise } from '../utils/redux-promise-utils.js'; import { useSelector, useDispatch } from '../utils/redux-utils.js'; @@ -199,6 +201,30 @@ .sessionRecoveryInProgress, ); + const preRequestUserInfo = useSelector(state => state.currentUserInfo); + const sessionID = useSelector(sessionIDSelector(keyserverID)); + const preRequestUserState = React.useMemo( + () => ({ + currentUserInfo: preRequestUserInfo, + cookiesAndSessions: { + [keyserverID]: { + cookie, + sessionID, + }, + }, + }), + [preRequestUserInfo, keyserverID, cookie, sessionID], + ); + + // We only need to do a "spot check" on this value below. + // - To avoid regenerating performRecovery whenever it changes, we want to + // make sure it's not in that function's dep list. + // - If we exclude it from that function's dep list, we'll end up binding in + // the value of preRequestUserState at the time performRecovery is updated. + // Instead, by assigning to a ref, we are able to use the latest value. + const preRequestUserStateRef = React.useRef(preRequestUserState); + preRequestUserStateRef.current = preRequestUserState; + const dispatch = useDispatch(); const urlPrefix = useSelector( state => state.keyserverStore.keyserverInfos[keyserverID]?.urlPrefix, @@ -218,8 +244,9 @@ }; const promise = (async () => { + const userStateBeforeRecovery = preRequestUserStateRef.current; try { - const sessionChange = await resolveKeyserverSessionInvalidation( + const recoverySessionChange = await resolveKeyserverSessionInvalidation( dispatch, cookie, urlPrefix, @@ -231,16 +258,21 @@ // dispatch directly throw new Error(CANCELLED_ERROR); } + const sessionChange = + recoverySessionChange ?? genericCookieInvalidation; if ( - !sessionChange || sessionChange.cookieInvalidated || !sessionChange.cookie || !sessionChange.cookie.startsWith('user=') ) { - dispatch({ - type: setSessionRecoveryInProgressActionType, - payload: { sessionRecoveryInProgress: false, keyserverID }, - }); + setNewSession( + dispatch, + sessionChange, + userStateBeforeRecovery, + null, + logInActionSources.cookieInvalidationResolutionAttempt, + keyserverID, + ); } } catch (e) { if (cancelled) { @@ -252,10 +284,14 @@ e, ); - dispatch({ - type: setSessionRecoveryInProgressActionType, - payload: { sessionRecoveryInProgress: false, keyserverID }, - }); + setNewSession( + dispatch, + genericCookieInvalidation, + userStateBeforeRecovery, + null, + logInActionSources.cookieInvalidationResolutionAttempt, + keyserverID, + ); } finally { if (!cancelled) { setAuthInProgress(false); diff --git a/lib/shared/session-utils.js b/lib/shared/session-utils.js --- a/lib/shared/session-utils.js +++ b/lib/shared/session-utils.js @@ -102,6 +102,10 @@ 'COOKIE_INVALIDATION_RESOLUTION_ATTEMPT or ' + 'SOCKET_AUTH_ERROR_RESOLUTION_ATTEMPT login is dispatched', ); + if (actionCurrentUserInfo.anonymous) { + // It's not a session recovery if the CurrentUserInfo is anonymous + return false; + } return ( !currentReduxState.dataLoaded || currentReduxState.currentUserInfo?.id !== actionCurrentUserInfo.id diff --git a/lib/types/session-types.js b/lib/types/session-types.js --- a/lib/types/session-types.js +++ b/lib/types/session-types.js @@ -62,9 +62,16 @@ +cookieInvalidated: true, +currentUserInfo: LoggedOutUserInfo, +sessionID?: null | string, - +cookie?: string, + +cookie?: null | string, }; +export const genericCookieInvalidation: ClientSessionChange = { + cookieInvalidated: true, + currentUserInfo: { anonymous: true }, + sessionID: null, + cookie: null, +}; + export type PreRequestUserKeyserverSessionInfo = { +cookie: ?string, +sessionID: ?string,