diff --git a/native/profile/tunnelbroker-menu.react.js b/native/profile/tunnelbroker-menu.react.js index 8fbb83648..72550bd15 100644 --- a/native/profile/tunnelbroker-menu.react.js +++ b/native/profile/tunnelbroker-menu.react.js @@ -1,156 +1,176 @@ // @flow import * as React from 'react'; import { useState } from 'react'; import { Text, View } from 'react-native'; import { ScrollView } from 'react-native-gesture-handler'; import { useTunnelbroker } from 'lib/tunnelbroker/tunnelbroker-context.js'; import type { TunnelbrokerMessage } from 'lib/types/tunnelbroker/messages.js'; import type { ProfileNavigationProp } from './profile.react.js'; import Button from '../components/button.react.js'; import TextInput from '../components/text-input.react.js'; import type { NavigationRoute } from '../navigation/route-names.js'; import { useColors, useStyles } from '../themes/colors.js'; +import { createOlmSessionsWithOwnDevices } from '../utils/crypto-utils.js'; type Props = { +navigation: ProfileNavigationProp<'TunnelbrokerMenu'>, +route: NavigationRoute<'TunnelbrokerMenu'>, }; // eslint-disable-next-line no-unused-vars function TunnelbrokerMenu(props: Props): React.Node { const styles = useStyles(unboundStyles); const colors = useColors(); const { connected, addListener, sendMessage, removeListener } = useTunnelbroker(); const [messages, setMessages] = useState([]); const [recipient, setRecipient] = useState(''); const [message, setMessage] = useState(''); const listener = React.useCallback((msg: TunnelbrokerMessage) => { setMessages(prev => [...prev, msg]); }, []); React.useEffect(() => { addListener(listener); return () => removeListener(listener); }, [addListener, listener, removeListener]); const onSubmit = React.useCallback(async () => { try { await sendMessage({ deviceID: recipient, payload: message }); } catch (e) { - console.error(e.message); + console.log(e.message); } }, [message, recipient, sendMessage]); + const onCreateSessions = React.useCallback(async () => { + try { + await createOlmSessionsWithOwnDevices(sendMessage); + } catch (e) { + console.log(`Error creating olm sessions with own devices: ${e.message}`); + } + }, [sendMessage]); + return ( INFO Connected {connected.toString()} SEND MESSAGE Recipient Message + MESSAGES {messages.map(msg => ( {JSON.stringify(msg)} ))} ); } const unboundStyles = { scrollViewContentContainer: { paddingTop: 24, }, scrollView: { backgroundColor: 'panelBackground', }, section: { backgroundColor: 'panelForeground', borderBottomWidth: 1, borderColor: 'panelForegroundBorder', borderTopWidth: 1, marginBottom: 24, marginVertical: 2, }, header: { color: 'panelBackgroundLabel', fontSize: 12, fontWeight: '400', paddingBottom: 3, paddingHorizontal: 24, }, submenuButton: { flexDirection: 'row', paddingHorizontal: 24, paddingVertical: 10, alignItems: 'center', }, submenuText: { color: 'panelForegroundLabel', flex: 1, fontSize: 16, }, text: { color: 'panelForegroundLabel', fontSize: 16, }, row: { flexDirection: 'row', justifyContent: 'space-between', paddingHorizontal: 24, paddingVertical: 14, }, textInput: { color: 'modalBackgroundLabel', flex: 1, fontSize: 16, margin: 0, padding: 0, borderBottomColor: 'transparent', }, }; export default TunnelbrokerMenu; diff --git a/native/utils/crypto-utils.js b/native/utils/crypto-utils.js index 1b74d4531..ebfa12438 100644 --- a/native/utils/crypto-utils.js +++ b/native/utils/crypto-utils.js @@ -1,173 +1,176 @@ // @flow import { type ClientMessageToDevice } from 'lib/tunnelbroker/tunnelbroker-context.js'; import type { IdentityKeysBlob, OLMIdentityKeys, } from 'lib/types/crypto-types.js'; import type { OutboundKeyInfoResponse, InboundKeyInfoResponse, } from 'lib/types/identity-service-types'; import type { OlmSessionInitializationInfo } from 'lib/types/request-types.js'; import { type OutboundSessionCreation, peerToPeerMessageTypes, } from 'lib/types/tunnelbroker/peer-to-peer-message-types.js'; import { commCoreModule, commRustModule } from '../native-modules.js'; function nativeNotificationsSessionCreator( notificationsIdentityKeys: OLMIdentityKeys, notificationsInitializationInfo: OlmSessionInitializationInfo, ): Promise { const { prekey, prekeySignature, oneTimeKey } = notificationsInitializationInfo; return commCoreModule.initializeNotificationsSession( JSON.stringify(notificationsIdentityKeys), prekey, prekeySignature, oneTimeKey, ); } async function getContentSigningKey(): Promise { await commCoreModule.initializeCryptoAccount(); const { primaryIdentityPublicKeys: { ed25519 }, } = await commCoreModule.getUserPublicKey(); return ed25519; } async function nativeInboundContentSessionCreator( message: OutboundSessionCreation, ): Promise { const { senderInfo, encryptedContent } = message; const authMetadata = await commCoreModule.getCommServicesAuthMetadata(); const { userID, deviceID, accessToken } = authMetadata; if (!userID || !deviceID || !accessToken) { throw new Error('CommServicesAuthMetadata is missing'); } const keysResponse = await commRustModule.getInboundKeysForUser( userID, deviceID, accessToken, senderInfo.userID, ); const inboundKeys: InboundKeyInfoResponse[] = JSON.parse(keysResponse); const deviceKeys: ?InboundKeyInfoResponse = inboundKeys.find(keys => { const keysPayload: IdentityKeysBlob = JSON.parse(keys.payload); return ( keysPayload.primaryIdentityPublicKeys.ed25519 === senderInfo.deviceID ); }); if (!deviceKeys) { throw new Error( 'No keys for the device that requested creating a session, ' + `deviceID: ${senderInfo.deviceID}`, ); } const keysPayload: IdentityKeysBlob = JSON.parse(deviceKeys.payload); const identityKeys = JSON.stringify({ curve25519: keysPayload.primaryIdentityPublicKeys.curve25519, ed25519: keysPayload.primaryIdentityPublicKeys.ed25519, }); return commCoreModule.initializeContentInboundSession( identityKeys, encryptedContent, keysPayload.primaryIdentityPublicKeys.ed25519, ); } function nativeOutboundContentSessionCreator( contentIdentityKeys: OLMIdentityKeys, contentInitializationInfo: OlmSessionInitializationInfo, deviceID: string, ): Promise { const { prekey, prekeySignature, oneTimeKey } = contentInitializationInfo; const identityKeys = JSON.stringify({ curve25519: contentIdentityKeys.curve25519, ed25519: contentIdentityKeys.ed25519, }); return commCoreModule.initializeContentOutboundSession( identityKeys, prekey, prekeySignature, oneTimeKey, deviceID, ); } async function createOlmSessionsWithOwnDevices( sendMessage: (message: ClientMessageToDevice) => Promise, ): Promise { const authMetadata = await commCoreModule.getCommServicesAuthMetadata(); const { userID, deviceID, accessToken } = authMetadata; if (!userID || !deviceID || !accessToken) { throw new Error('CommServicesAuthMetadata is missing'); } const keysResponse = await commRustModule.getOutboundKeysForUser( userID, deviceID, accessToken, userID, ); const outboundKeys: OutboundKeyInfoResponse[] = JSON.parse(keysResponse); for (const deviceKeys: OutboundKeyInfoResponse of outboundKeys) { const keysPayload: IdentityKeysBlob = JSON.parse(deviceKeys.payload); if (keysPayload.primaryIdentityPublicKeys.ed25519 === deviceID) { continue; } const recipientDeviceID = keysPayload.primaryIdentityPublicKeys.ed25519; if (!deviceKeys.oneTimeContentPrekey) { console.log(`One-time key is missing for device ${recipientDeviceID}`); continue; } try { const encryptedContent = await nativeOutboundContentSessionCreator( keysPayload.primaryIdentityPublicKeys, { prekey: deviceKeys.contentPrekey, prekeySignature: deviceKeys.contentPrekeySignature, oneTimeKey: deviceKeys.oneTimeContentPrekey, }, recipientDeviceID, ); const sessionCreationMessage: OutboundSessionCreation = { type: peerToPeerMessageTypes.OUTBOUND_SESSION_CREATION, senderInfo: { userID, deviceID, }, encryptedContent, }; await sendMessage({ deviceID: recipientDeviceID, payload: JSON.stringify(sessionCreationMessage), }); + console.log( + `Request to create a session with device ${recipientDeviceID} sent.`, + ); } catch (e) { console.log( 'Error creating outbound session with ' + `device ${recipientDeviceID}: ${e.message}`, ); } } } export { getContentSigningKey, nativeNotificationsSessionCreator, nativeInboundContentSessionCreator, createOlmSessionsWithOwnDevices, };