Page MenuHomePhabricator

D11845.id39721.diff
No OneTemporary

D11845.id39721.diff

diff --git a/lib/actions/user-actions.js b/lib/actions/user-actions.js
--- a/lib/actions/user-actions.js
+++ b/lib/actions/user-actions.js
@@ -132,7 +132,9 @@
if (!usingCommServicesAccessToken) {
return;
}
- invariant(identityClient, 'Identity client should be set');
+ if (!identityClient) {
+ throw new Error('Identity service client is not initialized');
+ }
try {
await Promise.race([
identityClient.logOut(),
@@ -168,6 +170,42 @@
);
}
+function useIdentityLogOut(): () => Promise<LogOutResult> {
+ const client = React.useContext(IdentityClientContext);
+ const identityClient = client?.identityClient;
+
+ const preRequestUserState = usePreRequestUserState();
+ const commServicesAccessToken = useSelector(
+ state => state.commServicesAccessToken,
+ );
+
+ return React.useCallback(async () => {
+ invariant(
+ usingCommServicesAccessToken,
+ 'identityLogOut can only be called when usingCommServicesAccessToken',
+ );
+ if (!identityClient) {
+ throw new Error('Identity service client is not initialized');
+ }
+ try {
+ await Promise.race([
+ identityClient.logOut(),
+ (async () => {
+ await sleep(500);
+ throw new Error('identity log_out took more than 500ms');
+ })(),
+ ]);
+ } catch {}
+ return {
+ currentUserInfo: null,
+ preRequestUserState: {
+ ...preRequestUserState,
+ commServicesAccessToken,
+ },
+ };
+ }, [commServicesAccessToken, identityClient, preRequestUserState]);
+}
+
const claimUsernameActionTypes = Object.freeze({
started: 'CLAIM_USERNAME_STARTED',
success: 'CLAIM_USERNAME_SUCCESS',
@@ -285,6 +323,54 @@
]);
}
+// Unlike useDeleteAccount, we always dispatch a success here (never throw).
+// That's because useDeleteAccount is used in a scenario where the user is
+// visibly logged-in, and we don't want to log them out unless we succeeded in
+// deleting their account. On the other hand, useDeleteDiscardedIdentityAccount
+// is used in a scenario where the user is visibly logged-out, and it's only
+// used to reset state (eg. Redux, SQLite) to a logged-out state. The state
+// reset only occurs when a success action is dispatched, so we always dispatch
+// a success.
+function useDeleteDiscardedIdentityAccount(): () => Promise<LogOutResult> {
+ const client = React.useContext(IdentityClientContext);
+ const identityClient = client?.identityClient;
+
+ const preRequestUserState = usePreRequestUserState();
+ const commServicesAccessToken = useSelector(
+ state => state.commServicesAccessToken,
+ );
+
+ return React.useCallback(async () => {
+ invariant(
+ usingCommServicesAccessToken,
+ 'deleteDiscardedIdentityAccount can only be called when ' +
+ 'usingCommServicesAccessToken',
+ );
+ if (!identityClient) {
+ throw new Error('Identity service client is not initialized');
+ }
+ if (!identityClient.deleteWalletUser) {
+ throw new Error('Delete wallet user method unimplemented');
+ }
+ try {
+ await Promise.race([
+ identityClient.deleteWalletUser(),
+ (async () => {
+ await sleep(500);
+ throw new Error('identity delete_wallet_user took more than 500ms');
+ })(),
+ ]);
+ } catch {}
+ return {
+ currentUserInfo: null,
+ preRequestUserState: {
+ ...preRequestUserState,
+ commServicesAccessToken,
+ },
+ };
+ }, [commServicesAccessToken, identityClient, preRequestUserState]);
+}
+
const legacyKeyserverRegisterActionTypes = Object.freeze({
started: 'LEGACY_KEYSERVER_REGISTER_STARTED',
success: 'LEGACY_KEYSERVER_REGISTER_SUCCESS',
@@ -871,6 +957,7 @@
useLegacyLogIn,
legacyLogInActionTypes,
useLogOut,
+ useIdentityLogOut,
logOutActionTypes,
legacyKeyserverRegister,
legacyKeyserverRegisterActionTypes,
@@ -888,6 +975,7 @@
updateUserAvatar,
deleteAccountActionTypes,
useDeleteAccount,
+ useDeleteDiscardedIdentityAccount,
keyserverAuthActionTypes,
keyserverAuth as keyserverAuthRawAction,
identityRegisterActionTypes,
diff --git a/lib/hooks/login-hooks.js b/lib/hooks/login-hooks.js
--- a/lib/hooks/login-hooks.js
+++ b/lib/hooks/login-hooks.js
@@ -7,6 +7,8 @@
identityLogInActionTypes,
useIdentityPasswordLogIn,
useIdentityWalletLogIn,
+ logOutActionTypes,
+ useIdentityLogOut,
} from '../actions/user-actions.js';
import { useKeyserverAuth } from '../keyserver-conn/keyserver-auth.js';
import { logInActionSources } from '../types/account-types.js';
@@ -98,6 +100,10 @@
!state.currentUserInfo.anonymous,
);
+ // We call identityLogOut in order to reset state if identity auth succeeds
+ // but authoritative keyserver auth fails
+ const identityLogOut = useIdentityLogOut();
+
const registeringOnAuthoritativeKeyserverRef = React.useRef(false);
const dispatch = useDispatch();
React.useEffect(() => {
@@ -128,13 +134,21 @@
});
resolve();
} catch (e) {
+ void dispatchActionPromise(logOutActionTypes, identityLogOut());
reject(e);
} finally {
setCurrentStep(inactiveStep);
registeringOnAuthoritativeKeyserverRef.current = false;
}
})();
- }, [currentStep, isRegisteredOnIdentity, keyserverAuth, dispatch]);
+ }, [
+ currentStep,
+ isRegisteredOnIdentity,
+ keyserverAuth,
+ dispatch,
+ dispatchActionPromise,
+ identityLogOut,
+ ]);
return returnedFunc;
}
diff --git a/native/account/registration/registration-server-call.js b/native/account/registration/registration-server-call.js
--- a/native/account/registration/registration-server-call.js
+++ b/native/account/registration/registration-server-call.js
@@ -9,6 +9,8 @@
legacyKeyserverRegister,
useIdentityPasswordRegister,
identityRegisterActionTypes,
+ deleteAccountActionTypes,
+ useDeleteDiscardedIdentityAccount,
} from 'lib/actions/user-actions.js';
import { useKeyserverAuth } from 'lib/keyserver-conn/keyserver-auth.js';
import { useLegacyAshoatKeyserverCall } from 'lib/keyserver-conn/legacy-keyserver-call.js';
@@ -314,6 +316,10 @@
!state.currentUserInfo.anonymous,
);
+ // We call deleteDiscardedIdentityAccount in order to reset state if identity
+ // registration succeeds but authoritative keyserver auth fails
+ const deleteDiscardedIdentityAccount = useDeleteDiscardedIdentityAccount();
+
const registeringOnAuthoritativeKeyserverRef = React.useRef(false);
React.useEffect(() => {
if (
@@ -349,14 +355,37 @@
resolve,
reject,
});
- } catch (e) {
- reject(e);
+ } catch (keyserverAuthException) {
+ const discardIdentityAccountPromise = (async () => {
+ try {
+ return await deleteDiscardedIdentityAccount();
+ } catch (deleteException) {
+ Alert.alert(
+ 'Account created but login failed',
+ 'We were able to create your account, but were unable to log ' +
+ 'you in. Try going back to the login screen and logging in ' +
+ 'with your new credentials.',
+ );
+ throw deleteException;
+ }
+ })();
+ void dispatchActionPromise(
+ deleteAccountActionTypes,
+ discardIdentityAccountPromise,
+ );
+ reject(keyserverAuthException);
setCurrentStep(inactiveStep);
} finally {
registeringOnAuthoritativeKeyserverRef.current = false;
}
})();
- }, [currentStep, isRegisteredOnIdentity, keyserverAuth]);
+ }, [
+ currentStep,
+ isRegisteredOnIdentity,
+ keyserverAuth,
+ dispatchActionPromise,
+ deleteDiscardedIdentityAccount,
+ ]);
// STEP 3: SETTING AVATAR

File Metadata

Mime Type
text/plain
Expires
Thu, Dec 26, 8:24 PM (10 h, 31 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2705350
Default Alt Text
D11845.id39721.diff (7 KB)

Event Timeline