Page MenuHomePhabricator

D12944.id43066.diff
No OneTemporary

D12944.id43066.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
@@ -3,7 +3,10 @@
import invariant from 'invariant';
import * as React from 'react';
-import { useBroadcastDeviceListUpdates } from '../hooks/peer-list-hooks.js';
+import {
+ useBroadcastDeviceListUpdates,
+ useBroadcastAccountDeletion,
+} from '../hooks/peer-list-hooks.js';
import type {
CallSingleKeyserverEndpoint,
CallSingleKeyserverEndpointOptions,
@@ -506,10 +509,17 @@
failed: 'DELETE_ACCOUNT_FAILED',
});
+const accountDeletionBroadcastOptions = Object.freeze({
+ broadcastToOwnDevices: true,
+});
function useDeleteAccount(): (password: ?string) => Promise<LogOutResult> {
const client = React.useContext(IdentityClientContext);
const identityClient = client?.identityClient;
+ const broadcastAccountDeletion = useBroadcastAccountDeletion(
+ accountDeletionBroadcastOptions,
+ );
+
const preRequestUserState = usePreRequestUserState();
const callKeyserverDeleteAccount = useKeyserverCall(deleteKeyserverAccount);
@@ -523,16 +533,16 @@
if (!identityClient) {
throw new Error('Identity service client is not initialized');
}
- if (
- !identityClient.deleteWalletUser ||
- !identityClient.deletePasswordUser
- ) {
+ const { deleteWalletUser, deletePasswordUser } = identityClient;
+ if (!deleteWalletUser || !deletePasswordUser) {
throw new Error('Delete user method unimplemented');
}
+
+ await broadcastAccountDeletion();
if (password) {
- await identityClient.deletePasswordUser(password);
+ await deletePasswordUser(password);
} else {
- await identityClient.deleteWalletUser();
+ await deleteWalletUser();
}
}
try {
@@ -565,6 +575,7 @@
};
},
[
+ broadcastAccountDeletion,
callKeyserverDeleteAccount,
commServicesAccessToken,
identityClient,
diff --git a/lib/hooks/peer-list-hooks.js b/lib/hooks/peer-list-hooks.js
--- a/lib/hooks/peer-list-hooks.js
+++ b/lib/hooks/peer-list-hooks.js
@@ -4,7 +4,10 @@
import * as React from 'react';
import { setPeerDeviceListsActionType } from '../actions/aux-user-actions.js';
-import { getAllPeerDevices } from '../selectors/user-selectors.js';
+import {
+ getAllPeerDevices,
+ getForeignPeerDevices,
+} from '../selectors/user-selectors.js';
import { IdentityClientContext } from '../shared/identity-client-context.js';
import { useTunnelbroker } from '../tunnelbroker/tunnelbroker-context.js';
import type {
@@ -15,9 +18,18 @@
} from '../types/identity-service-types.js';
import {
type DeviceListUpdated,
+ type EncryptedMessage,
peerToPeerMessageTypes,
} from '../types/tunnelbroker/peer-to-peer-message-types.js';
-import { getContentSigningKey } from '../utils/crypto-utils.js';
+import {
+ userActionsP2PMessageTypes,
+ type AccountDeletionP2PMessage,
+} from '../types/tunnelbroker/user-actions-peer-to-peer-message-types.js';
+import { getConfig } from '../utils/config.js';
+import {
+ getContentSigningKey,
+ createOlmSessionWithPeer,
+} from '../utils/crypto-utils.js';
import { convertSignedDeviceListsToRawDeviceLists } from '../utils/device-list-utils.js';
import { values } from '../utils/objects.js';
import { useDispatch, useSelector } from '../utils/redux-utils.js';
@@ -133,8 +145,86 @@
);
}
+function useBroadcastAccountDeletion(
+ options: { broadcastToOwnDevices?: boolean } = {},
+): () => Promise<void> {
+ const { broadcastToOwnDevices } = options;
+
+ const identityContext = React.useContext(IdentityClientContext);
+ if (!identityContext) {
+ throw new Error('Identity service client is not initialized');
+ }
+ const { sendMessageToDevice } = useTunnelbroker();
+
+ const devicesSelector = broadcastToOwnDevices
+ ? getAllPeerDevices
+ : getForeignPeerDevices;
+ const peerDevices = useSelector(devicesSelector);
+
+ return React.useCallback(async () => {
+ const { identityClient, getAuthMetadata } = identityContext;
+ const authMetadata = await getAuthMetadata();
+ const { userID, deviceID: thisDeviceID } = authMetadata;
+ if (!thisDeviceID || !userID) {
+ throw new Error('No auth metadata');
+ }
+ // create and send Olm Tunnelbroker messages to peers
+ const { olmAPI } = getConfig();
+ await olmAPI.initializeCryptoAccount();
+
+ const deletionMessage: AccountDeletionP2PMessage = {
+ type: userActionsP2PMessageTypes.ACCOUNT_DELETION,
+ };
+ const rawPayload = JSON.stringify(deletionMessage);
+
+ const recipientDeviceIDs = peerDevices.filter(
+ peerDeviceID => peerDeviceID !== thisDeviceID,
+ );
+ for (const deviceID of recipientDeviceIDs) {
+ try {
+ const encryptedData = await olmAPI.encrypt(rawPayload, deviceID);
+ const encryptedMessage: EncryptedMessage = {
+ type: peerToPeerMessageTypes.ENCRYPTED_MESSAGE,
+ senderInfo: { deviceID: thisDeviceID, userID },
+ encryptedData,
+ };
+ await sendMessageToDevice({
+ deviceID,
+ payload: JSON.stringify(encryptedMessage),
+ });
+ } catch {
+ try {
+ await createOlmSessionWithPeer(
+ authMetadata,
+ identityClient,
+ sendMessageToDevice,
+ userID,
+ deviceID,
+ );
+ const encryptedData = await olmAPI.encrypt(rawPayload, deviceID);
+ const encryptedMessage: EncryptedMessage = {
+ type: peerToPeerMessageTypes.ENCRYPTED_MESSAGE,
+ senderInfo: { deviceID: thisDeviceID, userID },
+ encryptedData,
+ };
+ await sendMessageToDevice({
+ deviceID,
+ payload: JSON.stringify(encryptedMessage),
+ });
+ } catch (err) {
+ console.warn(
+ `Error sending account deletion message to device ${deviceID}:`,
+ err,
+ );
+ }
+ }
+ }
+ }, [identityContext, peerDevices, sendMessageToDevice]);
+}
+
export {
useGetDeviceListsForUsers,
useBroadcastDeviceListUpdates,
useGetAndUpdateDeviceListsForUsers,
+ useBroadcastAccountDeletion,
};

File Metadata

Mime Type
text/plain
Expires
Sat, Sep 21, 1:29 AM (21 h, 36 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2155642
Default Alt Text
D12944.id43066.diff (6 KB)

Event Timeline