diff --git a/keyserver/src/socket/tunnelbroker.js b/keyserver/src/socket/tunnelbroker.js --- a/keyserver/src/socket/tunnelbroker.js +++ b/keyserver/src/socket/tunnelbroker.js @@ -253,7 +253,7 @@ this.closeConnection(); return; } - await this.sendMessage({ + await this.sendMessageToDevice({ deviceID: primaryDeviceID, payload: JSON.stringify(payload), }); @@ -384,9 +384,9 @@ { leading: true, trailing: true }, ); - sendMessage: (message: TunnelbrokerClientMessageToDevice) => Promise = ( + sendMessageToDevice: ( message: TunnelbrokerClientMessageToDevice, - ) => { + ) => Promise = (message: TunnelbrokerClientMessageToDevice) => { if (!this.connected) { throw new Error('Tunnelbroker not connected'); } 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 @@ -265,7 +265,7 @@ throw new Error('Identity service client is not initialized'); } - const { sendMessage } = useTunnelbroker(); + const { sendMessageToDevice } = useTunnelbroker(); const broadcastDeviceListUpdates = useBroadcastDeviceListUpdates(); const foreignPeerDevices = useSelector(getForeignPeerDevices); @@ -301,7 +301,7 @@ senderInfo: { deviceID: thisDeviceID, userID }, encryptedData, }; - await sendMessage({ + await sendMessageToDevice({ deviceID, payload: JSON.stringify(encryptedMessage), }); @@ -310,7 +310,7 @@ await createOlmSessionWithPeer( authMetadata, identityClient, - sendMessage, + sendMessageToDevice, userID, deviceID, ); @@ -323,7 +323,7 @@ senderInfo: { deviceID: thisDeviceID, userID }, encryptedData, }; - await sendMessage({ + await sendMessageToDevice({ deviceID, payload: JSON.stringify(encryptedMessage), }); @@ -350,7 +350,7 @@ foreignPeerDevices, identityContext, logOut, - sendMessage, + sendMessageToDevice, ]); } @@ -359,7 +359,7 @@ }); function useSecondaryDeviceLogOut(): () => Promise { - const { sendMessage } = useTunnelbroker(); + const { sendMessageToDevice } = useTunnelbroker(); const logOut = useLogOut(secondaryDeviceLogOutOptions); const identityContext = React.useContext(IdentityClientContext); @@ -398,7 +398,7 @@ senderInfo: { deviceID, userID }, encryptedData, }; - await sendMessage({ + await sendMessageToDevice({ deviceID: primaryDeviceID, payload: JSON.stringify(encryptedMessage), }); @@ -407,7 +407,7 @@ await createOlmSessionWithPeer( authMetadata, identityClient, - sendMessage, + sendMessageToDevice, userID, primaryDeviceID, ); @@ -420,7 +420,7 @@ senderInfo: { deviceID, userID }, encryptedData, }; - await sendMessage({ + await sendMessageToDevice({ deviceID: primaryDeviceID, payload: JSON.stringify(encryptedMessage), }); @@ -431,7 +431,7 @@ // log out of identity service, keyserver and visually return logOut(); - }, [identityContext, sendMessage, logOut]); + }, [identityContext, sendMessageToDevice, logOut]); } const claimUsernameActionTypes = Object.freeze({ diff --git a/lib/components/qr-auth-provider.react.js b/lib/components/qr-auth-provider.react.js --- a/lib/components/qr-auth-provider.react.js +++ b/lib/components/qr-auth-provider.react.js @@ -70,7 +70,7 @@ addListener, removeListener, socketState, - sendMessage, + sendMessageToDevice, } = useTunnelbroker(); const identityContext = React.useContext(IdentityClientContext); @@ -120,13 +120,13 @@ type: qrCodeAuthMessageTypes.SECONDARY_DEVICE_REGISTRATION_SUCCESS, requestBackupKeys: true, }); - await sendMessage({ + await sendMessageToDevice({ deviceID: primaryDeviceID, payload: JSON.stringify(message), }); })(); }, [ - sendMessage, + sendMessageToDevice, primaryDeviceID, qrData, socketState, diff --git a/lib/handlers/db-ops-handler.react.js b/lib/handlers/db-ops-handler.react.js --- a/lib/handlers/db-ops-handler.react.js +++ b/lib/handlers/db-ops-handler.react.js @@ -25,7 +25,7 @@ const { processDBStoreOperations } = props; const queueFront = useSelector(state => state.dbOpsStore.queuedOps[0]); const prevQueueFront = React.useRef(null); - const { sendMessage } = useTunnelbroker(); + const { sendMessageToDevice } = useTunnelbroker(); const { processOutboundMessages } = usePeerToPeerCommunication(); const dispatch = useDispatch(); @@ -59,7 +59,7 @@ messageID, deviceID, }; - await sendMessage({ + await sendMessageToDevice({ deviceID: senderDeviceID, payload: JSON.stringify(message), }); @@ -77,7 +77,7 @@ queueFront, dispatch, processDBStoreOperations, - sendMessage, + sendMessageToDevice, sqliteAPI, processOutboundMessages, ]); 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 @@ -99,7 +99,7 @@ deviceIDs: $ReadOnlyArray, signedDeviceList?: SignedDeviceList, ) => Promise { - const { sendMessage } = useTunnelbroker(); + const { sendMessageToDevice } = useTunnelbroker(); const identityContext = React.useContext(IdentityClientContext); invariant(identityContext, 'identity context not set'); @@ -122,14 +122,14 @@ const payload = JSON.stringify(messageToPeer); const promises = deviceIDs.map((deviceID: string) => - sendMessage({ + sendMessageToDevice({ deviceID, payload, }), ); await Promise.all(promises); }, - [identityContext, sendMessage], + [identityContext, sendMessageToDevice], ); } diff --git a/lib/tunnelbroker/peer-to-peer-context.js b/lib/tunnelbroker/peer-to-peer-context.js --- a/lib/tunnelbroker/peer-to-peer-context.js +++ b/lib/tunnelbroker/peer-to-peer-context.js @@ -152,7 +152,7 @@ const processingQueue = React.useRef>>([]); const promiseRunning = React.useRef(false); - const { sendMessage } = useTunnelbroker(); + const { sendMessageToDevice } = useTunnelbroker(); const identityContext = React.useContext(IdentityClientContext); invariant(identityContext, 'Identity context should be set'); @@ -166,7 +166,7 @@ const nextMessageIDs = processingQueue.current.shift(); try { await processOutboundP2PMessages( - sendMessage, + sendMessageToDevice, identityContext, nextMessageIDs, ); @@ -182,7 +182,7 @@ })(); } }, - [identityContext, sendMessage], + [identityContext, sendMessageToDevice], ); React.useEffect(() => { diff --git a/lib/tunnelbroker/secondary-tunnelbroker-connection.js b/lib/tunnelbroker/secondary-tunnelbroker-connection.js --- a/lib/tunnelbroker/secondary-tunnelbroker-connection.js +++ b/lib/tunnelbroker/secondary-tunnelbroker-connection.js @@ -1,32 +1,15 @@ // @flow -import type { MessageToDeviceRequest } from '../types/tunnelbroker/message-to-device-request-types.js'; -import type { MessageToTunnelbrokerRequest } from '../types/tunnelbroker/message-to-tunnelbroker-request-types.js'; -import type { - TunnelbrokerAPNsNotif, - TunnelbrokerFCMNotif, -} from '../types/tunnelbroker/notif-types.js'; +import { type DeviceToTunnelbrokerRequest } from '../types/tunnelbroker/messages.js'; type RemoveCallback = () => void; export type SecondaryTunnelbrokerConnection = { // Used by an inactive tab to send messages - +sendMessage: ( - message: - | MessageToDeviceRequest - | MessageToTunnelbrokerRequest - | TunnelbrokerAPNsNotif - | TunnelbrokerFCMNotif, - ) => mixed, + +sendMessage: (message: DeviceToTunnelbrokerRequest) => mixed, // Active tab receives messages from inactive tabs +onSendMessage: ( - ( - message: - | MessageToDeviceRequest - | MessageToTunnelbrokerRequest - | TunnelbrokerAPNsNotif - | TunnelbrokerFCMNotif, - ) => mixed, + (message: DeviceToTunnelbrokerRequest) => mixed, ) => RemoveCallback, // Active tab sets the message status of messages from inactive tabs diff --git a/lib/tunnelbroker/tunnelbroker-context.js b/lib/tunnelbroker/tunnelbroker-context.js --- a/lib/tunnelbroker/tunnelbroker-context.js +++ b/lib/tunnelbroker/tunnelbroker-context.js @@ -20,6 +20,7 @@ tunnelbrokerToDeviceMessageTypes, tunnelbrokerToDeviceMessageValidator, type TunnelbrokerToDeviceMessage, + type DeviceToTunnelbrokerRequest, } from '../types/tunnelbroker/messages.js'; import type { TunnelbrokerAPNsNotif, @@ -61,7 +62,7 @@ }; type TunnelbrokerContextType = { - +sendMessage: ( + +sendMessageToDevice: ( message: TunnelbrokerClientMessageToDevice, messageID: ?string, ) => Promise, @@ -320,34 +321,29 @@ socketState.connected, ]); - const sendMessageToDeviceRequest: ( - request: - | MessageToDeviceRequest - | MessageToTunnelbrokerRequest - | TunnelbrokerAPNsNotif - | TunnelbrokerFCMNotif, - ) => Promise = React.useCallback( - request => { - return new Promise((resolve, reject) => { - const socketActive = socketState.connected && socket.current; - if (!shouldBeClosed && !socketActive) { - throw new Error('Tunnelbroker not connected'); - } - promises.current[request.clientMessageID] = { - resolve, - reject, - }; - if (socketActive) { - socket.current?.send(JSON.stringify(request)); - } else { - secondaryTunnelbrokerConnection?.sendMessage(request); - } - }); - }, - [socketState, secondaryTunnelbrokerConnection, shouldBeClosed], - ); + const sendMessage: (request: DeviceToTunnelbrokerRequest) => Promise = + React.useCallback( + request => { + return new Promise((resolve, reject) => { + const socketActive = socketState.connected && socket.current; + if (!shouldBeClosed && !socketActive) { + throw new Error('Tunnelbroker not connected'); + } + promises.current[request.clientMessageID] = { + resolve, + reject, + }; + if (socketActive) { + socket.current?.send(JSON.stringify(request)); + } else { + secondaryTunnelbrokerConnection?.sendMessage(request); + } + }); + }, + [socketState, secondaryTunnelbrokerConnection, shouldBeClosed], + ); - const sendMessage: ( + const sendMessageToDevice: ( message: TunnelbrokerClientMessageToDevice, messageID: ?string, ) => Promise = React.useCallback( @@ -360,9 +356,9 @@ payload: message.payload, }; - return sendMessageToDeviceRequest(messageToDevice); + return sendMessage(messageToDevice); }, - [sendMessageToDeviceRequest], + [sendMessage], ); const sendMessageToTunnelbroker: (payload: string) => Promise = @@ -374,9 +370,9 @@ clientMessageID, payload, }; - return sendMessageToDeviceRequest(messageToTunnelbroker); + return sendMessage(messageToTunnelbroker); }, - [sendMessageToDeviceRequest], + [sendMessage], ); React.useEffect( @@ -389,7 +385,7 @@ void (async () => { try { - await sendMessageToDeviceRequest(message); + await sendMessage(message); secondaryTunnelbrokerConnection.setMessageStatus( message.clientMessageID, ); @@ -401,11 +397,7 @@ } })(); }), - [ - secondaryTunnelbrokerConnection, - sendMessageToDeviceRequest, - shouldBeClosed, - ], + [secondaryTunnelbrokerConnection, sendMessage, shouldBeClosed], ); React.useEffect( @@ -448,17 +440,17 @@ const value: TunnelbrokerContextType = React.useMemo( () => ({ - sendMessage, + sendMessageToDevice, sendMessageToTunnelbroker, - sendNotif: sendMessageToDeviceRequest, + sendNotif: sendMessage, socketState, addListener, removeListener, setUnauthorizedDeviceID, }), [ + sendMessageToDevice, sendMessage, - sendMessageToDeviceRequest, sendMessageToTunnelbroker, socketState, addListener, diff --git a/lib/types/tunnelbroker/messages.js b/lib/types/tunnelbroker/messages.js --- a/lib/types/tunnelbroker/messages.js +++ b/lib/types/tunnelbroker/messages.js @@ -64,6 +64,16 @@ | MessageToTunnelbrokerRequest | Heartbeat; +// Types having `clientMessageID` prop. +// When using this type, it is possible to use Promise abstraction, +// and await sending a message until Tunnelbroker responds that +// the request was processed. +export type DeviceToTunnelbrokerRequest = + | TunnelbrokerAPNsNotif + | TunnelbrokerFCMNotif + | MessageToDeviceRequest + | MessageToTunnelbrokerRequest; + // Messages sent from Tunnelbroker to Device. export const tunnelbrokerToDeviceMessageTypes = Object.freeze({ CONNECTION_INITIALIZATION_RESPONSE: 'ConnectionInitializationResponse', diff --git a/native/profile/secondary-device-qr-code-scanner.react.js b/native/profile/secondary-device-qr-code-scanner.react.js --- a/native/profile/secondary-device-qr-code-scanner.react.js +++ b/native/profile/secondary-device-qr-code-scanner.react.js @@ -159,7 +159,7 @@ ...backupKeys, }, ); - await tunnelbrokerContext.sendMessage({ + await tunnelbrokerContext.sendMessageToDevice({ deviceID: targetDeviceID, payload: JSON.stringify(backupKeyMessage), }); @@ -225,7 +225,7 @@ userID, primaryDeviceID, }); - await tunnelbrokerContext.sendMessage({ + await tunnelbrokerContext.sendMessageToDevice({ deviceID: targetDeviceID, payload: JSON.stringify(message), }); diff --git a/native/profile/tunnelbroker-menu.react.js b/native/profile/tunnelbroker-menu.react.js --- a/native/profile/tunnelbroker-menu.react.js +++ b/native/profile/tunnelbroker-menu.react.js @@ -42,7 +42,7 @@ ); const identityContext = React.useContext(IdentityClientContext); - const { socketState, addListener, sendMessage, removeListener } = + const { socketState, addListener, sendMessageToDevice, removeListener } = useTunnelbroker(); const [messages, setMessages] = useState([]); const [recipient, setRecipient] = useState(''); @@ -67,11 +67,11 @@ const onSubmit = React.useCallback(async () => { try { - await sendMessage({ deviceID: recipient, payload: message }); + await sendMessageToDevice({ deviceID: recipient, payload: message }); } catch (e) { console.log(e.message); } - }, [message, recipient, sendMessage]); + }, [message, recipient, sendMessageToDevice]); const onCreateSessions = React.useCallback(async () => { if (!identityContext) { @@ -82,12 +82,12 @@ await createOlmSessionsWithOwnDevices( authMetadata, identityContext.identityClient, - sendMessage, + sendMessageToDevice, ); } catch (e) { console.log(`Error creating olm sessions with own devices: ${e.message}`); } - }, [identityContext, sendMessage]); + }, [identityContext, sendMessageToDevice]); const onSendEncryptedMessage = React.useCallback(async () => { try { @@ -105,14 +105,14 @@ }, encryptedData, }; - await sendMessage({ + await sendMessageToDevice({ deviceID: recipient, payload: JSON.stringify(encryptedMessage), }); } catch (e) { console.log(`Error sending encrypted content to device: ${e.message}`); } - }, [message, currentUserID, recipient, sendMessage]); + }, [message, currentUserID, recipient, sendMessageToDevice]); return ( pushModal( - , + , ), - [popModal, pushModal, sendMessage], + [popModal, pushModal, sendMessageToDevice], ); const openTunnelbrokerMessagesModal = React.useCallback( @@ -116,12 +119,12 @@ await createOlmSessionsWithOwnDevices( authMetadata, identityContext.identityClient, - sendMessage, + sendMessageToDevice, ); } catch (e) { console.log(`Error creating olm sessions with own devices: ${e.message}`); } - }, [identityContext, sendMessage]); + }, [identityContext, sendMessageToDevice]); const openBackupTestRestoreModal = React.useCallback( () => pushModal(), diff --git a/web/settings/tunnelbroker-test.react.js b/web/settings/tunnelbroker-test.react.js --- a/web/settings/tunnelbroker-test.react.js +++ b/web/settings/tunnelbroker-test.react.js @@ -18,12 +18,14 @@ import { useSelector } from '../redux/redux-utils.js'; type Props = { - +sendMessage: (message: TunnelbrokerClientMessageToDevice) => Promise, + +sendMessageToDevice: ( + message: TunnelbrokerClientMessageToDevice, + ) => Promise, +onClose: () => void, }; function TunnelbrokerTestScreen(props: Props): React.Node { - const { sendMessage, onClose } = props; + const { sendMessageToDevice, onClose } = props; const [recipient, setRecipient] = React.useState(''); const [message, setMessage] = React.useState(''); const [loading, setLoading] = React.useState(false); @@ -41,13 +43,13 @@ setLoading(true); try { - await sendMessage({ deviceID: recipient, payload: message }); + await sendMessageToDevice({ deviceID: recipient, payload: message }); } catch (e) { setErrorMessage(e.message); } setLoading(false); }, - [message, recipient, sendMessage], + [message, recipient, sendMessageToDevice], ); const onSubmitEncrypted = React.useCallback( @@ -71,7 +73,7 @@ }, encryptedData, }; - await sendMessage({ + await sendMessageToDevice({ deviceID: recipient, payload: JSON.stringify(encryptedMessage), }); @@ -80,7 +82,7 @@ } setLoading(false); }, - [message, currentUserID, recipient, sendMessage], + [message, currentUserID, recipient, sendMessageToDevice], ); let errorMsg;