Page MenuHomePhabricator

D10202.id35336.diff
No OneTemporary

D10202.id35336.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
@@ -21,6 +21,7 @@
UpdateUserAvatarResponse,
} from '../types/avatar-types.js';
import type { RawEntryInfo, CalendarQuery } from '../types/entry-types.js';
+import type { IdentityServiceClient } from '../types/identity-service-types';
import type {
RawMessageInfo,
MessageTruncationStatuses,
@@ -159,6 +160,28 @@
return useKeyserverCall(deleteKeyserverAccount);
}
+const deleteIdentityAccountActionTypes = Object.freeze({
+ started: 'DELETE_IDENTITY_ACCOUNT_STARTED',
+ success: 'DELETE_IDENTITY_ACCOUNT_SUCCESS',
+ failed: 'DELETE_IDENTITY_ACCOUNT_FAILED',
+});
+
+function useDeleteIdentityAccount(
+ client: IdentityServiceClient,
+ deviceID: ?string,
+): () => Promise<void> {
+ const userID = useSelector(state => state.currentUserInfo?.id);
+ const accessToken = useSelector(state => state.commServicesAccessToken);
+ const deleteIdentityAccount = React.useCallback(async () => {
+ if (!userID || !accessToken || !deviceID) {
+ throw new Error('missing identity service auth metadata');
+ }
+ await client.deleteUser(userID, deviceID, accessToken);
+ }, [client, userID, deviceID, accessToken]);
+
+ return deleteIdentityAccount;
+}
+
const registerActionTypes = Object.freeze({
started: 'REGISTER_STARTED',
success: 'REGISTER_SUCCESS',
@@ -536,4 +559,6 @@
updateUserAvatar,
resetUserStateActionType,
setAccessTokenActionType,
+ deleteIdentityAccountActionTypes,
+ useDeleteIdentityAccount,
};
diff --git a/lib/types/identity-service-types.js b/lib/types/identity-service-types.js
--- a/lib/types/identity-service-types.js
+++ b/lib/types/identity-service-types.js
@@ -19,6 +19,14 @@
+oneTimeNotifPrekey: ?string,
};
+export interface IdentityServiceClient {
+ +deleteUser: (
+ userID: string,
+ deviceID: string,
+ accessToken: string,
+ ) => Promise<void>;
+}
+
export type IdentityServiceAuthLayer = {
+userID: string,
+deviceID: string,
diff --git a/lib/types/redux-types.js b/lib/types/redux-types.js
--- a/lib/types/redux-types.js
+++ b/lib/types/redux-types.js
@@ -230,6 +230,22 @@
+payload: LogOutResult,
+loadingInfo: LoadingInfo,
}
+ | {
+ +type: 'DELETE_IDENTITY_ACCOUNT_STARTED',
+ +payload?: void,
+ +loadingInfo: LoadingInfo,
+ }
+ | {
+ +type: 'DELETE_IDENTITY_ACCOUNT_FAILED',
+ +error: true,
+ +payload: Error,
+ +loadingInfo: LoadingInfo,
+ }
+ | {
+ +type: 'DELETE_IDENTITY_ACCOUNT_SUCCESS',
+ +payload: LogOutResult,
+ +loadingInfo: LoadingInfo,
+ }
| {
+type: 'CREATE_LOCAL_ENTRY',
+payload: RawEntryInfo,
diff --git a/native/profile/delete-account.react.js b/native/profile/delete-account.react.js
--- a/native/profile/delete-account.react.js
+++ b/native/profile/delete-account.react.js
@@ -5,24 +5,32 @@
import { ScrollView } from 'react-native-gesture-handler';
import {
+ deleteIdentityAccountActionTypes,
deleteKeyserverAccountActionTypes,
+ useDeleteIdentityAccount,
useDeleteKeyserverAccount,
} from 'lib/actions/user-actions.js';
import { preRequestUserStateSelector } from 'lib/selectors/account-selectors.js';
import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js';
import { useDispatchActionPromise } from 'lib/utils/action-utils.js';
+import { usingCommServicesAccessToken } from 'lib/utils/services-utils.js';
import type { ProfileNavigationProp } from './profile.react.js';
import { deleteNativeCredentialsFor } from '../account/native-credentials.js';
import Button from '../components/button.react.js';
+import { commRustModule } from '../native-modules.js';
import type { NavigationRoute } from '../navigation/route-names.js';
import { useSelector } from '../redux/redux-utils.js';
import { useStyles } from '../themes/colors.js';
import Alert from '../utils/alert.js';
+import { getContentSigningKey } from '../utils/crypto-utils.js';
-const loadingStatusSelector = createLoadingStatusSelector(
+const keyserverLoadingStatusSelector = createLoadingStatusSelector(
deleteKeyserverAccountActionTypes,
);
+const identityLoadingStatusSelector = createLoadingStatusSelector(
+ deleteIdentityAccountActionTypes,
+);
type Props = {
+navigation: ProfileNavigationProp<'DeleteAccount'>,
@@ -30,43 +38,87 @@
};
const DeleteAccount: React.ComponentType<Props> = React.memo<Props>(
function DeleteAccount() {
- const loadingStatus = useSelector(loadingStatusSelector);
+ const [deviceID, setDeviceID] = React.useState<?string>();
+ const keyserverLoadingStatus = useSelector(keyserverLoadingStatusSelector);
+ const identityLoadingStatus = useSelector(identityLoadingStatusSelector);
const preRequestUserState = useSelector(preRequestUserStateSelector);
+
+ React.useEffect(() => {
+ void (async () => {
+ const contentSigningKey = await getContentSigningKey();
+ setDeviceID(contentSigningKey);
+ })();
+ }, []);
const styles = useStyles(unboundStyles);
const dispatchActionPromise = useDispatchActionPromise();
- const callDeleteAccount = useDeleteKeyserverAccount();
+ const callDeleteKeyserverAccount = useDeleteKeyserverAccount();
+ const callDeleteIdentityAccount = useDeleteIdentityAccount(
+ commRustModule,
+ deviceID,
+ );
- const buttonContent =
- loadingStatus === 'loading' ? (
- <ActivityIndicator size="small" color="white" />
- ) : (
- <Text style={styles.saveText}>Delete account</Text>
- );
+ const isButtonDisabled =
+ !deviceID ||
+ keyserverLoadingStatus === 'loading' ||
+ identityLoadingStatus === 'loading';
+
+ const buttonContent = isButtonDisabled ? (
+ <ActivityIndicator size="small" color="white" />
+ ) : (
+ <Text style={styles.saveText}>Delete account</Text>
+ );
const noWayToReverseThisStyles = React.useMemo(
() => [styles.warningText, styles.lastWarningText],
[styles.warningText, styles.lastWarningText],
);
- const deleteAction = React.useCallback(async () => {
+ const deleteKeyserverAction = React.useCallback(async () => {
try {
await deleteNativeCredentialsFor();
- return await callDeleteAccount(preRequestUserState);
+ return await callDeleteKeyserverAccount(preRequestUserState);
} catch (e) {
- Alert.alert('Unknown error', 'Uhh... try again?', [{ text: 'OK' }], {
- cancelable: false,
- });
+ Alert.alert(
+ 'Unknown error deleting keyserver account',
+ 'Uhh... try again?',
+ [{ text: 'OK' }],
+ {
+ cancelable: false,
+ },
+ );
throw e;
}
- }, [callDeleteAccount, preRequestUserState]);
+ }, [callDeleteKeyserverAccount, preRequestUserState]);
+
+ const deleteIdentityAction = React.useCallback(async () => {
+ try {
+ return await callDeleteIdentityAccount();
+ } catch (e) {
+ Alert.alert(
+ 'Unknown error deleting account',
+ 'Uhh... try again?',
+ [{ text: 'OK' }],
+ {
+ cancelable: false,
+ },
+ );
+ throw e;
+ }
+ }, [callDeleteIdentityAccount]);
const onDelete = React.useCallback(() => {
void dispatchActionPromise(
deleteKeyserverAccountActionTypes,
- deleteAction(),
+ deleteKeyserverAction(),
);
- }, [dispatchActionPromise, deleteAction]);
+ if (usingCommServicesAccessToken) {
+ void dispatchActionPromise(
+ deleteIdentityAccountActionTypes,
+ deleteIdentityAction(),
+ );
+ }
+ }, [dispatchActionPromise, deleteKeyserverAction, deleteIdentityAction]);
return (
<ScrollView
@@ -83,7 +135,11 @@
There is no way to reverse this.
</Text>
</View>
- <Button onPress={onDelete} style={styles.deleteButton}>
+ <Button
+ onPress={onDelete}
+ style={styles.deleteButton}
+ disabled={isButtonDisabled}
+ >
{buttonContent}
</Button>
</ScrollView>

File Metadata

Mime Type
text/plain
Expires
Mon, Oct 7, 12:50 AM (22 h, 23 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2251765
Default Alt Text
D10202.id35336.diff (8 KB)

Event Timeline