diff --git a/lib/selectors/user-selectors.js b/lib/selectors/user-selectors.js --- a/lib/selectors/user-selectors.js +++ b/lib/selectors/user-selectors.js @@ -9,7 +9,10 @@ getRandomDefaultEmojiAvatar, } from '../shared/avatar-utils.js'; import { getSingleOtherUser } from '../shared/thread-utils.js'; -import { type AuxUserInfos } from '../types/aux-user-types.js'; +import { + type AuxUserInfos, + type AuxUserInfo, +} from '../types/aux-user-types.js'; import type { ClientEmojiAvatar } from '../types/avatar-types'; import type { RelativeMemberInfo, @@ -25,6 +28,7 @@ AccountUserInfo, CurrentUserInfo, } from '../types/user-types.js'; +import { entries } from '../utils/objects.js'; // Used for specific message payloads that include an array of user IDs, ie. // array of initial users, array of added users @@ -218,6 +222,26 @@ ), ); +// Foreign Peer Devices are all devices of users we are aware of, +// but not our own devices. +const getForeignPeerDevices: (state: BaseAppState<>) => $ReadOnlyArray = + createSelector( + (state: BaseAppState<>) => state.auxUserStore.auxUserInfos, + (state: BaseAppState<>) => + state.currentUserInfo && state.currentUserInfo.id, + ( + auxUserInfos: AuxUserInfos, + currentUserID: ?string, + ): $ReadOnlyArray => + entries(auxUserInfos) + .map(([userID, auxUserInfo]: [string, AuxUserInfo]) => + userID !== currentUserID && auxUserInfo.deviceList?.devices + ? auxUserInfo.deviceList.devices + : [], + ) + .flat(), + ); + export { userIDsToRelativeUserInfos, getRelativeMemberInfos, @@ -229,4 +253,5 @@ savedEmojiAvatarSelectorForCurrentUser, getRelativeUserIDs, usersWithMissingDeviceListSelector, + getForeignPeerDevices, }; diff --git a/lib/tunnelbroker/use-peer-to-peer-message-handler.js b/lib/tunnelbroker/use-peer-to-peer-message-handler.js --- a/lib/tunnelbroker/use-peer-to-peer-message-handler.js +++ b/lib/tunnelbroker/use-peer-to-peer-message-handler.js @@ -4,6 +4,11 @@ import _isEqual from 'lodash/fp/isEqual.js'; import * as React from 'react'; +import { + useBroadcastDeviceListUpdates, + useGetAndUpdateDeviceListsForUsers, +} from '../hooks/peer-list-hooks.js'; +import { getForeignPeerDevices } from '../selectors/user-selectors.js'; import { verifyAndGetDeviceList, removeDeviceFromDeviceList, @@ -20,6 +25,7 @@ import { getMessageForException } from '../utils/errors.js'; import { hasHigherDeviceID, olmSessionErrors } from '../utils/olm-utils.js'; import { getClientMessageIDFromTunnelbrokerMessageID } from '../utils/peer-to-peer-communication-utils.js'; +import { useSelector } from '../utils/redux-utils.js'; function usePeerToPeerMessageHandler(): ( message: PeerToPeerMessage, @@ -29,7 +35,11 @@ const identityContext = React.useContext(IdentityClientContext); invariant(identityContext, 'Identity context should be set'); - const { identityClient } = identityContext; + const { identityClient, getAuthMetadata } = identityContext; + + const foreignPeerDevices = useSelector(getForeignPeerDevices); + const broadcastDeviceListUpdates = useBroadcastDeviceListUpdates(); + const getAndUpdateDeviceListsForUsers = useGetAndUpdateDeviceListsForUsers(); return React.useCallback( async (message: PeerToPeerMessage, messageID: string) => { @@ -199,6 +209,26 @@ `Error verifying device list for user ${message.userID}: ${e}`, ); } + } else if ( + message.type === peerToPeerMessageTypes.IDENTITY_DEVICE_LIST_UPDATED + ) { + try { + const { userID } = await getAuthMetadata(); + if (!userID) { + return; + } + + await Promise.all([ + broadcastDeviceListUpdates(foreignPeerDevices), + getAndUpdateDeviceListsForUsers([userID]), + ]); + } catch (e) { + console.log( + `Error updating device list after Identity request: ${ + getMessageForException(e) ?? 'unknown error' + }`, + ); + } } else if (message.type === peerToPeerMessageTypes.MESSAGE_PROCESSED) { try { const { deviceID, messageID: tunnelbrokerMessageID } = message; @@ -218,7 +248,15 @@ } } }, - [identityClient, olmAPI, sqliteAPI], + [ + broadcastDeviceListUpdates, + foreignPeerDevices, + getAndUpdateDeviceListsForUsers, + getAuthMetadata, + identityClient, + olmAPI, + sqliteAPI, + ], ); }