Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes to delegate access reauthentication #49375

Merged
merged 6 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/libs/Authentication.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import CONFIG from '@src/CONFIG';
import CONST from '@src/CONST';
import type Response from '@src/types/onyx/Response';
import * as Delegate from './actions/Delegate';
import updateSessionAuthTokens from './actions/Session/updateSessionAuthTokens';
import redirectToSignIn from './actions/SignInRedirect';
import * as ErrorUtils from './ErrorUtils';
Expand Down Expand Up @@ -84,6 +85,14 @@ function reauthenticate(command = ''): Promise<void> {
return;
}

// If we reauthenticated due to an expired delegate token, restore the delegate's original account.
// This is because the credentials used to reauthenticate were for the delegate's original account, and not for the account they were connected as.
if (Delegate.isConnectedAsDelegate()) {
Log.info('Reauthenticated while connected as a delegate. Restoring original account.');
Delegate.restoreDelegateSession(response);
return;
}

// Update authToken in Onyx and in our local variables so that API requests will use the new authToken
updateSessionAuthTokens(response.authToken, response.encryptedAuthToken);

Expand Down
34 changes: 32 additions & 2 deletions src/libs/actions/Delegate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ import * as SequentialQueue from '@libs/Network/SequentialQueue';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Delegate, DelegatedAccess, DelegateRole} from '@src/types/onyx/Account';
import type Response from '@src/types/onyx/Response';
import {confirmReadyToOpenApp, openApp} from './App';
import updateSessionAuthTokens from './Session/updateSessionAuthTokens';
import updateSessionUser from './Session/updateSessionUser';

let delegatedAccess: DelegatedAccess;
Onyx.connect({
Expand All @@ -21,7 +23,18 @@ Onyx.connect({
},
});

const KEYS_TO_PRESERVE_DELEGATE_ACCESS = [ONYXKEYS.NVP_TRY_FOCUS_MODE, ONYXKEYS.PREFERRED_THEME, ONYXKEYS.NVP_PREFERRED_LOCALE, ONYXKEYS.SESSION, ONYXKEYS.IS_LOADING_APP];
const KEYS_TO_PRESERVE_DELEGATE_ACCESS = [
ONYXKEYS.NVP_TRY_FOCUS_MODE,
ONYXKEYS.PREFERRED_THEME,
ONYXKEYS.NVP_PREFERRED_LOCALE,
ONYXKEYS.SESSION,
ONYXKEYS.IS_LOADING_APP,
ONYXKEYS.CREDENTIALS,

// We need to preserve the sidebar loaded state since we never unrender the sidebar when connecting as a delegate
// This allows the report screen to load correctly when the delegate token expires and the delegate is returned to their original account.
ONYXKEYS.IS_SIDEBAR_LOADED,
];

function connect(email: string) {
if (!delegatedAccess?.delegators) {
Expand Down Expand Up @@ -313,6 +326,10 @@ function clearAddDelegateErrors(email: string, fieldName: string) {
});
}

function isConnectedAsDelegate() {
return !!delegatedAccess?.delegate;
}

function removePendingDelegate(email: string) {
if (!delegatedAccess?.delegates) {
return;
Expand All @@ -325,4 +342,17 @@ function removePendingDelegate(email: string) {
});
}

export {connect, disconnect, clearDelegatorErrors, addDelegate, requestValidationCode, clearAddDelegateErrors, removePendingDelegate};
function restoreDelegateSession(authenticateResponse: Response) {
Onyx.clear(KEYS_TO_PRESERVE_DELEGATE_ACCESS).then(() => {
updateSessionAuthTokens(authenticateResponse?.authToken, authenticateResponse?.encryptedAuthToken);
updateSessionUser(authenticateResponse?.accountID, authenticateResponse?.email);

NetworkStore.setAuthToken(authenticateResponse.authToken ?? null);
NetworkStore.setIsAuthenticating(false);

confirmReadyToOpenApp();
openApp();
});
}

export {connect, disconnect, clearDelegatorErrors, addDelegate, requestValidationCode, clearAddDelegateErrors, removePendingDelegate, restoreDelegateSession, isConnectedAsDelegate};
6 changes: 6 additions & 0 deletions src/libs/actions/Session/updateSessionUser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import Onyx from 'react-native-onyx';
import ONYXKEYS from '@src/ONYXKEYS';

export default function updateSessionUser(accountID?: number, email?: string) {
Onyx.merge(ONYXKEYS.SESSION, {accountID, email});
}
6 changes: 6 additions & 0 deletions src/types/onyx/Response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ type Response = {
/** Base64 key to decrypt messages from Pusher encrypted channels */
// eslint-disable-next-line @typescript-eslint/naming-convention
shared_secret?: string;

/** The accountID of the user */
accountID?: number;

/** The email of the user */
email?: string;
};

export default Response;
Loading