Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F33309996
D10954.1768806535.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
12 KB
Referenced Files
None
Subscribers
None
D10954.1768806535.diff
View Options
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,11 +10,14 @@
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 { resolveKeyserverSessionInvalidation } from '../keyserver-conn/recovery-utils.js';
import { filterThreadIDsInFilterList } from '../reducers/calendar-filters-reducer.js';
import {
connectionSelector,
cookieSelector,
deviceTokenSelector,
+ urlPrefixSelector,
} from '../selectors/keyserver-selectors.js';
import { isLoggedInToKeyserver } from '../selectors/user-selectors.js';
import { IdentityClientContext } from '../shared/identity-client-context.js';
@@ -23,7 +26,7 @@
import { logInActionSources } from '../types/account-types.js';
import { authoritativeKeyserverID } from '../utils/authoritative-keyserver.js';
import { useDispatchActionPromise } from '../utils/redux-promise-utils.js';
-import { useSelector } from '../utils/redux-utils.js';
+import { useSelector, useDispatch } from '../utils/redux-utils.js';
import { usingCommServicesAccessToken } from '../utils/services-utils.js';
import sleep from '../utils/sleep.js';
@@ -191,12 +194,106 @@
olmSessionCreator,
]);
+ const sessionRecoveryInProgress = useSelector(
+ state =>
+ state.keyserverStore.keyserverInfos[keyserverID]?.connection
+ .sessionRecoveryInProgress,
+ );
+
+ const dispatch = useDispatch();
+ const urlPrefix = useSelector(urlPrefixSelector(keyserverID));
+ const performRecovery = React.useCallback(() => {
+ invariant(
+ urlPrefix,
+ `urlPrefix for ${keyserverID} should be set during performRecovery`,
+ );
+
+ setAuthInProgress(true);
+
+ let cancelled = false;
+ const cancel = () => {
+ cancelled = true;
+ setAuthInProgress(false);
+ };
+
+ const promise = (async () => {
+ try {
+ const sessionChange = await resolveKeyserverSessionInvalidation(
+ dispatch,
+ cookie,
+ urlPrefix,
+ logInActionSources.cookieInvalidationResolutionAttempt,
+ keyserverID,
+ );
+ if (cancelled) {
+ // TODO: cancellation won't work because above call handles Redux
+ // dispatch directly
+ throw new Error(CANCELLED_ERROR);
+ }
+ if (
+ !sessionChange ||
+ sessionChange.cookieInvalidated ||
+ !sessionChange.cookie ||
+ !sessionChange.cookie.startsWith('user=')
+ ) {
+ dispatch({
+ type: setSessionRecoveryInProgressActionType,
+ payload: { sessionRecoveryInProgress: false, keyserverID },
+ });
+ }
+ } catch (e) {
+ if (cancelled) {
+ return;
+ }
+
+ console.log(
+ `Error while recovering session with keyserver id ${keyserverID}`,
+ e,
+ );
+
+ dispatch({
+ type: setSessionRecoveryInProgressActionType,
+ payload: { sessionRecoveryInProgress: false, keyserverID },
+ });
+ } finally {
+ if (!cancelled) {
+ setAuthInProgress(false);
+ }
+ }
+ })();
+ return [promise, cancel];
+ }, [dispatch, cookie, urlPrefix, keyserverID]);
+
const cancelPendingAuth = React.useRef<?() => void>(null);
const prevPerformAuth = React.useRef(performAuth);
const isUserAuthenticated = useSelector(isLoggedInToKeyserver(keyserverID));
const hasAccessToken = useSelector(state => !!state.commServicesAccessToken);
+ const cancelPendingRecovery = React.useRef<?() => void>(null);
+ const prevPerformRecovery = React.useRef(performRecovery);
+
React.useEffect(() => {
+ if (sessionRecoveryInProgress && isUserAuthenticated) {
+ cancelPendingAuth.current?.();
+ cancelPendingAuth.current = null;
+
+ if (prevPerformRecovery.current !== performRecovery) {
+ cancelPendingRecovery.current?.();
+ cancelPendingRecovery.current = null;
+ prevPerformRecovery.current = performRecovery;
+ }
+
+ if (!authInProgress) {
+ const [, cancel] = performRecovery();
+ cancelPendingRecovery.current = cancel;
+ }
+
+ return;
+ }
+
+ cancelPendingRecovery.current?.();
+ cancelPendingRecovery.current = null;
+
if (!hasAccessToken) {
cancelPendingAuth.current?.();
cancelPendingAuth.current = null;
@@ -222,7 +319,14 @@
const [, cancel] = performAuth();
cancelPendingAuth.current = cancel;
- }, [authInProgress, hasAccessToken, isUserAuthenticated, performAuth]);
+ }, [
+ sessionRecoveryInProgress,
+ authInProgress,
+ performRecovery,
+ hasAccessToken,
+ isUserAuthenticated,
+ performAuth,
+ ]);
return <Socket {...socketProps} />;
}
diff --git a/lib/keyserver-conn/call-keyserver-endpoint-provider.react.js b/lib/keyserver-conn/call-keyserver-endpoint-provider.react.js
--- a/lib/keyserver-conn/call-keyserver-endpoint-provider.react.js
+++ b/lib/keyserver-conn/call-keyserver-endpoint-provider.react.js
@@ -5,17 +5,17 @@
import * as React from 'react';
import { createSelector } from 'reselect';
-import { useKeyserverCallInfos } from './keyserver-call-infos.js';
+import {
+ useKeyserverCallInfos,
+ type KeyserverCallInfo,
+} from './keyserver-call-infos.js';
import {
setNewSession,
type SingleKeyserverActionFunc,
type ActionFunc,
+ setSessionRecoveryInProgressActionType,
} from './keyserver-conn-types.js';
-import {
- canResolveKeyserverSessionInvalidation,
- resolveKeyserverSessionInvalidation,
-} from './recovery-utils.js';
-import { logInActionSources } from '../types/account-types.js';
+import { canResolveKeyserverSessionInvalidation } from './recovery-utils.js';
import type { PlatformDetails } from '../types/device-types.js';
import type { Endpoint, SocketAPIHandler } from '../types/endpoints.js';
import type { Dispatch } from '../types/redux-types.js';
@@ -114,6 +114,7 @@
sessionID,
currentUserInfo,
isSocketConnected,
+ sessionRecoveryInProgress,
canRecoverSession,
lastCommunicatedPlatformDetails,
keyserverID,
@@ -145,63 +146,20 @@
// just let the caller callSingleKeyserverEndpoint instance continue
return Promise.resolve(null);
}
- const ongoingRecoveryAttempt =
- ongoingRecoveryAttemptsRef.current.get(keyserverID);
- if (!ongoingRecoveryAttempt) {
+ if (!sessionRecoveryInProgress) {
// Our cookie seems to be valid
return Promise.resolve(null);
}
+ const recoveryAttempts = ongoingRecoveryAttemptsRef.current;
+ let keyserverRecoveryAttempts = recoveryAttempts.get(keyserverID);
+ if (!keyserverRecoveryAttempts) {
+ keyserverRecoveryAttempts = { waitingCalls: [] };
+ recoveryAttempts.set(keyserverID, keyserverRecoveryAttempts);
+ }
+ const ongoingRecoveryAttempts = keyserverRecoveryAttempts;
// Wait to run until we get our new cookie
return new Promise<?CallSingleKeyserverEndpoint>(r =>
- ongoingRecoveryAttempt.waitingCalls.push(r),
- );
- };
- // These functions are helpers for cookieInvalidationRecovery, defined below
- const attemptToResolveInvalidationHelper = async (
- sessionChange: ClientSessionChange,
- ) => {
- const newAnonymousCookie = sessionChange.cookie;
- const newSessionChange = await resolveKeyserverSessionInvalidation(
- dispatch,
- newAnonymousCookie,
- urlPrefix,
- logInActionSources.cookieInvalidationResolutionAttempt,
- keyserverID,
- );
-
- return newSessionChange
- ? bindCookieAndUtilsIntoCallSingleKeyserverEndpoint({
- ...params,
- cookie: newSessionChange.cookie,
- sessionID: newSessionChange.sessionID,
- currentUserInfo: newSessionChange.currentUserInfo,
- })
- : null;
- };
- const attemptToResolveInvalidation = (
- sessionChange: ClientSessionChange,
- ) => {
- return new Promise<?CallSingleKeyserverEndpoint>(
- // eslint-disable-next-line no-async-promise-executor
- async (resolve, reject) => {
- try {
- const newCallSingleKeyserverEndpoint =
- await attemptToResolveInvalidationHelper(sessionChange);
- const ongoingRecoveryAttempt =
- ongoingRecoveryAttemptsRef.current.get(keyserverID);
- ongoingRecoveryAttemptsRef.current.delete(keyserverID);
- const currentWaitingCalls =
- ongoingRecoveryAttempt?.waitingCalls ?? [];
-
- resolve(newCallSingleKeyserverEndpoint);
-
- for (const func of currentWaitingCalls) {
- func(newCallSingleKeyserverEndpoint);
- }
- } catch (e) {
- reject(e);
- }
- },
+ ongoingRecoveryAttempts.waitingCalls.push(r),
);
};
// If this function is called, callSingleKeyserverEndpoint got a response
@@ -226,15 +184,23 @@
// user to log-in after a cookieInvalidation while logged out
return Promise.resolve(null);
}
- const ongoingRecoveryAttempt =
- ongoingRecoveryAttemptsRef.current.get(keyserverID);
- if (ongoingRecoveryAttempt) {
- return new Promise<?CallSingleKeyserverEndpoint>(r =>
- ongoingRecoveryAttempt.waitingCalls.push(r),
- );
+
+ const recoveryAttempts = ongoingRecoveryAttemptsRef.current;
+ let keyserverRecoveryAttempts = recoveryAttempts.get(keyserverID);
+ if (!keyserverRecoveryAttempts) {
+ keyserverRecoveryAttempts = { waitingCalls: [] };
+ recoveryAttempts.set(keyserverID, keyserverRecoveryAttempts);
+ }
+ if (!sessionRecoveryInProgress) {
+ dispatch({
+ type: setSessionRecoveryInProgressActionType,
+ payload: { sessionRecoveryInProgress: true, keyserverID },
+ });
}
- ongoingRecoveryAttemptsRef.current.set(keyserverID, { waitingCalls: [] });
- return attemptToResolveInvalidation(sessionChange);
+ const ongoingRecoveryAttempts = keyserverRecoveryAttempts;
+ return new Promise<?CallSingleKeyserverEndpoint>(r =>
+ ongoingRecoveryAttempts.waitingCalls.push(r),
+ );
};
return (
@@ -311,7 +277,7 @@
[bindCookieAndUtilsIntoCallSingleKeyserverEndpoint],
);
- // SECTION 3: getBoundSingleKeyserverActionFunc
+ // SECTION 3: getCallSingleKeyserverEndpoint
const dispatch = useDispatch();
const currentUserInfo = useSelector(state => state.currentUserInfo);
@@ -351,6 +317,55 @@
],
);
+ // SECTION 4: flush waitingCalls when sessionRecoveryInProgress flips to false
+
+ const prevKeyserverCallInfosRef = React.useRef<{
+ +[keyserverID: string]: KeyserverCallInfo,
+ }>(keyserverCallInfos);
+ React.useEffect(() => {
+ const sessionRecoveriesConcluded = new Set<string>();
+ const prevKeyserverCallInfos = prevKeyserverCallInfosRef.current;
+ for (const keyserverID in keyserverCallInfos) {
+ const prevKeyserverCallInfo = prevKeyserverCallInfos[keyserverID];
+ if (!prevKeyserverCallInfo) {
+ continue;
+ }
+ const keyserverCallInfo = keyserverCallInfos[keyserverID];
+ if (
+ !keyserverCallInfo.sessionRecoveryInProgress &&
+ prevKeyserverCallInfo.sessionRecoveryInProgress
+ ) {
+ sessionRecoveriesConcluded.add(keyserverID);
+ }
+ }
+
+ for (const keyserverID of sessionRecoveriesConcluded) {
+ const recoveryAttempts = ongoingRecoveryAttemptsRef.current;
+ const keyserverRecoveryAttempts = recoveryAttempts.get(keyserverID);
+ if (!keyserverRecoveryAttempts) {
+ continue;
+ }
+ const { waitingCalls } = keyserverRecoveryAttempts;
+ if (waitingCalls.length === 0) {
+ continue;
+ }
+
+ const { cookie } = keyserverCallInfos[keyserverID];
+ const hasUserCookie = cookie && cookie.startsWith('user=');
+
+ const boundCallSingleKeyserverEndpoint = hasUserCookie
+ ? getCallSingleKeyserverEndpoint(keyserverID)
+ : null;
+ for (const waitingCall of waitingCalls) {
+ waitingCall(boundCallSingleKeyserverEndpoint);
+ }
+ }
+
+ prevKeyserverCallInfosRef.current = keyserverCallInfos;
+ }, [keyserverCallInfos, getCallSingleKeyserverEndpoint]);
+
+ // SECTION 5: getBoundSingleKeyserverActionFunc
+
const createBoundSingleKeyserverActionFuncSelector: CreateBoundSingleKeyserverActionFuncSelector =
React.useCallback(
actionFunc =>
@@ -396,7 +411,7 @@
],
);
- // SECTION 4: getBoundKeyserverActionFunc
+ // SECTION 6: getBoundKeyserverActionFunc
const callKeyserverEndpoint = React.useCallback(
(
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Jan 19, 7:08 AM (4 h, 7 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5955087
Default Alt Text
D10954.1768806535.diff (12 KB)
Attached To
Mode
D10954: [lib] Move CallKeyserverEndpoint session recovery to KeyserverConnectionHandler
Attached
Detach File
Event Timeline
Log In to Comment