Skip to content

Commit

Permalink
[lib] Refactor useLogOut to auto-detect logout flow
Browse files Browse the repository at this point in the history
Summary:
Address [[ https://linear.app/comm/issue/ENG-10015/decide-how-to-handle-v1-uselogout-calls-for-signed-device-list-users | ENG-10015 ]]

- Renamed `useLogOut` to `useBaseLogOut`
  - Made options required
- Created new `useLogOut` without arguments, which automatically chooses correct logout flow basing on `usingRestoreFlow` and `isPrimaryDevice`

Test Plan:
For both old- and new-flow account, checked that correct logout protocol is chosen when:
- Pressing logout button
- Triggering a crash

Reviewers: tomek, kamil

Reviewed By: kamil

Subscribers: ashoat

Differential Revision: https://phab.comm.dev/D14179
  • Loading branch information
barthap committed Jan 9, 2025
1 parent a3dcf5a commit 3da407d
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 19 deletions.
44 changes: 38 additions & 6 deletions lib/actions/user-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
useBroadcastDeviceListUpdates,
useBroadcastAccountDeletion,
} from '../hooks/peer-list-hooks.js';
import { useCheckIfPrimaryDevice } from '../hooks/primary-device-hooks.js';
import type {
CallSingleKeyserverEndpoint,
CallSingleKeyserverEndpointOptions,
Expand Down Expand Up @@ -97,7 +98,10 @@ import { getConfig } from '../utils/config.js';
import { getMessageForException } from '../utils/errors.js';
import { useDispatchActionPromise } from '../utils/redux-promise-utils.js';
import { useSelector } from '../utils/redux-utils.js';
import { usingCommServicesAccessToken } from '../utils/services-utils.js';
import {
usingCommServicesAccessToken,
usingRestoreFlow,
} from '../utils/services-utils.js';
import sleep from '../utils/sleep.js';

const loggedOutUserInfo: LoggedOutUserInfo = {
Expand Down Expand Up @@ -143,13 +147,13 @@ const keyserverLogOut =
};

type UseLogOutOptions = {
+logOutType?: 'legacy' | 'primary_device' | 'secondary_device',
+logOutType: 'legacy' | 'primary_device' | 'secondary_device',
+skipIdentityLogOut?: boolean,
+handleUseNewFlowResponse?: () => void,
};

function useLogOut(
options: UseLogOutOptions = {},
function useBaseLogOut(
options: UseLogOutOptions,
): (keyserverIDs?: $ReadOnlyArray<string>) => Promise<LogOutResult> {
const client = React.useContext(IdentityClientContext);
const identityClient = client?.identityClient;
Expand Down Expand Up @@ -259,6 +263,33 @@ function useLogOut(
);
}

const legacyLogOutOptions: UseLogOutOptions = Object.freeze({
logOutType: 'legacy',
});
function useLogOut(): () => Promise<LogOutResult> {
const callLegacyLogOut = useBaseLogOut(legacyLogOutOptions);
const callPrimaryDeviceLogOut = usePrimaryDeviceLogOut();
const callSecondaryDeviceLogOut = useSecondaryDeviceLogOut();

const checkIfPrimaryDevice = useCheckIfPrimaryDevice();

return React.useCallback(async () => {
if (usingRestoreFlow) {
const isPrimaryDevice = await checkIfPrimaryDevice();
return isPrimaryDevice
? callPrimaryDeviceLogOut()
: callSecondaryDeviceLogOut();
} else {
return callLegacyLogOut();
}
}, [
callLegacyLogOut,
callPrimaryDeviceLogOut,
callSecondaryDeviceLogOut,
checkIfPrimaryDevice,
]);
}

function useIdentityLogOut(): () => Promise<LogOutResult> {
const client = React.useContext(IdentityClientContext);
const identityClient = client?.identityClient;
Expand Down Expand Up @@ -342,7 +373,7 @@ function usePrimaryDeviceLogOut(): () => Promise<LogOutResult> {
const { broadcastEphemeralMessage } = usePeerToPeerCommunication();
const foreignPeerDevices = useSelector(getForeignPeerDeviceIDs);

const logOut = useLogOut(primaryDeviceLogOutOptions);
const logOut = useBaseLogOut(primaryDeviceLogOutOptions);
return React.useCallback(async () => {
const { identityClient, getAuthMetadata } = identityContext;
const authMetadata = await getAuthMetadata();
Expand Down Expand Up @@ -437,7 +468,7 @@ const secondaryDeviceLogOutOptions = Object.freeze({
});

function useSecondaryDeviceLogOut(): () => Promise<LogOutResult> {
const logOut = useLogOut(secondaryDeviceLogOutOptions);
const logOut = useBaseLogOut(secondaryDeviceLogOutOptions);
const sendLogoutMessage = useSendLogoutMessageToPrimaryDevice();

return React.useCallback(async () => {
Expand Down Expand Up @@ -1506,6 +1537,7 @@ export {
useIdentitySecondaryDeviceLogIn,
useLegacyLogIn,
legacyLogInActionTypes,
useBaseLogOut,
useLogOut,
useIdentityLogOut,
usePrimaryDeviceLogOut,
Expand Down
11 changes: 8 additions & 3 deletions lib/tunnelbroker/use-peer-to-peer-message-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import uuid from 'uuid';
import { useResendPeerToPeerMessages } from './use-resend-peer-to-peer-messages.js';
import { removePeerUsersActionType } from '../actions/aux-user-actions.js';
import { invalidateTunnelbrokerDeviceTokenActionType } from '../actions/tunnelbroker-actions.js';
import { logOutActionTypes, useLogOut } from '../actions/user-actions.js';
import { logOutActionTypes, useBaseLogOut } from '../actions/user-actions.js';
import { usePeerOlmSessionsCreatorContext } from '../components/peer-olm-session-creator-provider.react.js';
import {
useBroadcastDeviceListUpdates,
Expand Down Expand Up @@ -51,7 +51,10 @@ import { useDispatch, useSelector } from '../utils/redux-utils.js';

// When logout is requested by primary device, logging out of Identity Service
// is already handled by the primary device
const primaryRequestLogoutOptions = Object.freeze({ skipIdentityLogOut: true });
const primaryRequestLogoutOptions = Object.freeze({
logOutType: 'secondary_device',
skipIdentityLogOut: true,
});

// When re-broadcasting, we want to do it only to foreign peers
// to avoid a vicious circle of deletion messages sent by own devices.
Expand All @@ -75,7 +78,9 @@ function useHandleOlmMessageToDevice(): (

const dispatch = useDispatch();
const dispatchActionPromise = useDispatchActionPromise();
const primaryDeviceRequestedLogOut = useLogOut(primaryRequestLogoutOptions);
const primaryDeviceRequestedLogOut = useBaseLogOut(
primaryRequestLogoutOptions,
);
const runDeviceListUpdate = useDeviceListUpdate();

const processDMOperation = useProcessDMOperation();
Expand Down
9 changes: 5 additions & 4 deletions native/profile/profile-screen.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import uuid from 'uuid';

import {
logOutActionTypes,
useLogOut,
useBaseLogOut,
usePrimaryDeviceLogOut,
useSecondaryDeviceLogOut,
} from 'lib/actions/user-actions.js';
Expand Down Expand Up @@ -570,13 +570,14 @@ const ConnectedProfileScreen: React.ComponentType<BaseProps> =
const checkIfPrimaryDevice = useCheckIfPrimaryDevice();

const showVersionUnsupportedAlert = useShowVersionUnsupportedAlert(false);
const logOutOptions = React.useMemo(
const legacyLogOutOptions = React.useMemo(
() => ({
logOutType: 'legacy',
handleUseNewFlowResponse: showVersionUnsupportedAlert,
}),
[showVersionUnsupportedAlert],
);
const callLogOut = useLogOut(logOutOptions);
const callLegayLogOut = useBaseLogOut(legacyLogOutOptions);

const userID = useSelector(
state => state.currentUserInfo && state.currentUserInfo.id,
Expand Down Expand Up @@ -620,7 +621,7 @@ const ConnectedProfileScreen: React.ComponentType<BaseProps> =
logOutLoading={logOutLoading}
colors={colors}
styles={styles}
logOut={callLogOut}
logOut={callLegayLogOut}
logOutPrimaryDevice={callPrimaryDeviceLogOut}
logOutSecondaryDevice={callSecondaryDeviceLogOut}
dispatchActionPromise={dispatchActionPromise}
Expand Down
15 changes: 9 additions & 6 deletions web/settings/account-settings.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import * as React from 'react';
import uuid from 'uuid';

import {
useLogOut,
useBaseLogOut,
logOutActionTypes,
useSecondaryDeviceLogOut,
} from 'lib/actions/user-actions.js';
Expand Down Expand Up @@ -44,13 +44,16 @@ import { useStaffCanSee } from '../utils/staff-utils.js';
function AccountSettings(): React.Node {
const { pushModal, popModal } = useModalContext();

const logOutOptions = React.useMemo(() => {
const legacyLogOutOptions = React.useMemo(() => {
const showVersionUnsupportedModal = () => {
pushModal(<VersionUnsupportedModal />);
};
return { handleUseNewFlowResponse: showVersionUnsupportedModal };
return {
logOutType: 'legacy',
handleUseNewFlowResponse: showVersionUnsupportedModal,
};
}, [pushModal]);
const sendLogoutRequest = useLogOut(logOutOptions);
const sendLegacyLogoutRequest = useBaseLogOut(legacyLogOutOptions);

const sendSecondaryDeviceLogoutRequest = useSecondaryDeviceLogOut();
const dispatchActionPromise = useDispatchActionPromise();
Expand All @@ -61,10 +64,10 @@ function AccountSettings(): React.Node {
sendSecondaryDeviceLogoutRequest(),
);
}
return dispatchActionPromise(logOutActionTypes, sendLogoutRequest());
return dispatchActionPromise(logOutActionTypes, sendLegacyLogoutRequest());
}, [
dispatchActionPromise,
sendLogoutRequest,
sendLegacyLogoutRequest,
sendSecondaryDeviceLogoutRequest,
]);

Expand Down

0 comments on commit 3da407d

Please sign in to comment.