Page MenuHomePhabricator

D12372.diff
No OneTemporary

D12372.diff

diff --git a/lib/handlers/peer-to-peer-message-handler.js b/lib/handlers/peer-to-peer-message-handler.js
deleted file mode 100644
--- a/lib/handlers/peer-to-peer-message-handler.js
+++ /dev/null
@@ -1,212 +0,0 @@
-// @flow
-
-import _isEqual from 'lodash/fp/isEqual.js';
-
-import {
- verifyAndGetDeviceList,
- removeDeviceFromDeviceList,
-} from '../shared/device-list-utils.js';
-import type {
- IdentityServiceClient,
- DeviceOlmInboundKeys,
-} from '../types/identity-service-types.js';
-import {
- peerToPeerMessageTypes,
- type PeerToPeerMessage,
-} from '../types/tunnelbroker/peer-to-peer-message-types.js';
-import { secondaryDeviceLogoutP2PMessageValidator } from '../types/tunnelbroker/user-actions-peer-to-peer-message-types.js';
-import { getConfig } from '../utils/config.js';
-import { getContentSigningKey } from '../utils/crypto-utils.js';
-import { getMessageForException } from '../utils/errors.js';
-import { hasHigherDeviceID, olmSessionErrors } from '../utils/olm-utils.js';
-import { getClientMessageIDFromTunnelbrokerMessageID } from '../utils/peer-to-peer-communication-utils.js';
-
-async function peerToPeerMessageHandler(
- message: PeerToPeerMessage,
- identityClient: IdentityServiceClient,
- messageID: string,
-): Promise<void> {
- const { olmAPI, sqliteAPI } = getConfig();
- if (message.type === peerToPeerMessageTypes.OUTBOUND_SESSION_CREATION) {
- const { senderInfo, encryptedData, sessionVersion } = message;
- const { userID: senderUserID, deviceID: senderDeviceID } = senderInfo;
-
- let deviceKeys: ?DeviceOlmInboundKeys = null;
- try {
- const { keys } = await identityClient.getInboundKeysForUser(senderUserID);
- deviceKeys = keys[senderDeviceID];
- } catch (e) {
- console.log(e.message);
- }
-
- if (!deviceKeys) {
- console.log(
- 'Error creating inbound session with device ' +
- `${senderDeviceID}: No keys for the device, ` +
- `session version: ${sessionVersion}`,
- );
- return;
- }
-
- try {
- await olmAPI.initializeCryptoAccount();
- const result = await olmAPI.contentInboundSessionCreator(
- deviceKeys.identityKeysBlob.primaryIdentityPublicKeys,
- encryptedData,
- sessionVersion,
- false,
- );
- console.log(
- 'Created inbound session with device ' +
- `${senderDeviceID}: ${result}, ` +
- `session version: ${sessionVersion}`,
- );
- } catch (e) {
- if (e.message?.includes(olmSessionErrors.alreadyCreated)) {
- console.log(
- 'Received session request with lower session version from ' +
- `${senderDeviceID}, session version: ${sessionVersion}`,
- );
- } else if (e.message?.includes(olmSessionErrors.raceCondition)) {
- const currentDeviceID = await getContentSigningKey();
- if (hasHigherDeviceID(currentDeviceID, senderDeviceID)) {
- console.log(
- 'Race condition while creating session with ' +
- `${senderDeviceID}, session version: ${sessionVersion}, ` +
- `this device has a higher deviceID and the session will be kept`,
- );
- } else {
- const result = await olmAPI.contentInboundSessionCreator(
- deviceKeys.identityKeysBlob.primaryIdentityPublicKeys,
- encryptedData,
- sessionVersion,
- true,
- );
- console.log(
- 'Overwrite session with device ' +
- `${senderDeviceID}: ${result}, ` +
- `session version: ${sessionVersion}`,
- );
- // Resend all not-yet confirmed messages that were encrypted
- // with overwrite session. Tracked in ENG-6982.
- }
- } else {
- console.log(
- 'Error creating inbound session with device ' +
- `${senderDeviceID}: ${e.message}, ` +
- `session version: ${sessionVersion}`,
- );
- }
- }
- } else if (message.type === peerToPeerMessageTypes.ENCRYPTED_MESSAGE) {
- try {
- await olmAPI.initializeCryptoAccount();
- const decrypted = await olmAPI.decryptSequentialAndPersist(
- message.encryptedData,
- message.senderInfo.deviceID,
- messageID,
- );
- console.log(
- 'Decrypted message from device ' +
- `${message.senderInfo.deviceID}: ${decrypted}`,
- );
-
- try {
- const parsedMessageToDevice = JSON.parse(decrypted);
- if (
- !secondaryDeviceLogoutP2PMessageValidator.is(parsedMessageToDevice)
- ) {
- return;
- }
- const { userID, deviceID: deviceIDToLogOut } = message.senderInfo;
- await removeDeviceFromDeviceList(
- identityClient,
- userID,
- deviceIDToLogOut,
- );
- // TODO: broadcast device list update here
- } catch (e) {
- console.log(e);
- }
- } catch (e) {
- if (e.message?.includes(olmSessionErrors.messageAlreadyDecrypted)) {
- console.log(
- 'Received already decrypted message from device ' +
- `${message.senderInfo.deviceID}.`,
- );
- } else if (e.message?.includes(olmSessionErrors.messageOutOfOrder)) {
- console.log(
- 'Received out-of-order message from device ' +
- `${message.senderInfo.deviceID}.`,
- );
- } else {
- console.log(
- 'Error decrypting message from device ' +
- `${message.senderInfo.deviceID}: ${e.message}`,
- );
- }
- }
- } else if (message.type === peerToPeerMessageTypes.REFRESH_KEY_REQUEST) {
- try {
- await olmAPI.initializeCryptoAccount();
- const oneTimeKeys = await olmAPI.getOneTimeKeys(message.numberOfKeys);
- await identityClient.uploadOneTimeKeys(oneTimeKeys);
- } catch (e) {
- console.log(`Error uploading one-time keys: ${e.message}`);
- }
- } else if (message.type === peerToPeerMessageTypes.DEVICE_LIST_UPDATED) {
- try {
- const result = await verifyAndGetDeviceList(
- identityClient,
- message.userID,
- null,
- );
- if (!result.valid) {
- console.log(
- `Received invalid device list update for user ${message.userID}. Reason: ${result.reason}`,
- );
- return;
- }
- console.log(
- `Received valid device list update for user ${message.userID}`,
- );
-
- if (message?.signedDeviceList?.rawDeviceList) {
- const receivedRawList = JSON.parse(
- message.signedDeviceList.rawDeviceList,
- );
-
- // additional check for broadcasted and Identity device list equality
- const listsAreEqual = _isEqual(result.deviceList)(receivedRawList);
- console.log(
- `Identity and received device lists are ${
- listsAreEqual ? '' : 'not'
- } equal.`,
- );
- }
- } catch (e) {
- console.log(
- `Error verifying device list for user ${message.userID}: ${e}`,
- );
- }
- } else if (message.type === peerToPeerMessageTypes.MESSAGE_PROCESSED) {
- try {
- const { deviceID, messageID: tunnelbrokerMessageID } = message;
- const clientMessageID = getClientMessageIDFromTunnelbrokerMessageID(
- tunnelbrokerMessageID,
- );
- await sqliteAPI.removeOutboundP2PMessagesOlderThan(
- clientMessageID,
- deviceID,
- );
- } catch (e) {
- console.log(
- `Error removing message after processing: ${
- getMessageForException(e) ?? 'unknown error'
- }`,
- );
- }
- }
-}
-
-export { peerToPeerMessageHandler };
diff --git a/lib/tunnelbroker/peer-to-peer-message-handler.js b/lib/tunnelbroker/peer-to-peer-message-handler.js
--- a/lib/tunnelbroker/peer-to-peer-message-handler.js
+++ b/lib/tunnelbroker/peer-to-peer-message-handler.js
@@ -1,11 +1,9 @@
// @flow
-import invariant from 'invariant';
import * as React from 'react';
import { useTunnelbroker } from './tunnelbroker-context.js';
-import { peerToPeerMessageHandler } from '../handlers/peer-to-peer-message-handler.js';
-import { IdentityClientContext } from '../shared/identity-client-context.js';
+import { usePeerToPeerMessageHandler } from './use-peer-to-peer-message-handler.js';
import type { MessageReceiveConfirmation } from '../types/tunnelbroker/message-receive-confirmation-types.js';
import {
tunnelbrokerMessageTypes,
@@ -25,10 +23,7 @@
const { socketSend, getSessionCounter, doesSocketExist } = props;
const { addListener, removeListener } = useTunnelbroker();
-
- const identityContext = React.useContext(IdentityClientContext);
- invariant(identityContext, 'Identity context should be set');
- const { identityClient } = identityContext;
+ const peerToPeerMessageHandler = usePeerToPeerMessageHandler();
const currentlyProcessedMessage = React.useRef<?Promise<mixed>>(null);
@@ -79,11 +74,7 @@
return;
}
try {
- await peerToPeerMessageHandler(
- peerToPeerMessage,
- identityClient,
- message.messageID,
- );
+ await peerToPeerMessageHandler(peerToPeerMessage, message.messageID);
} catch (e) {
console.log(e.message);
} finally {
@@ -97,7 +88,7 @@
}
})();
},
- [getSessionCounter, identityClient, doesSocketExist, socketSend],
+ [getSessionCounter, peerToPeerMessageHandler, doesSocketExist, socketSend],
);
React.useEffect(() => {
diff --git a/lib/tunnelbroker/use-peer-to-peer-message-handler.js b/lib/tunnelbroker/use-peer-to-peer-message-handler.js
new file mode 100644
--- /dev/null
+++ b/lib/tunnelbroker/use-peer-to-peer-message-handler.js
@@ -0,0 +1,225 @@
+// @flow
+
+import invariant from 'invariant';
+import _isEqual from 'lodash/fp/isEqual.js';
+import * as React from 'react';
+
+import {
+ verifyAndGetDeviceList,
+ removeDeviceFromDeviceList,
+} from '../shared/device-list-utils.js';
+import { IdentityClientContext } from '../shared/identity-client-context.js';
+import type { DeviceOlmInboundKeys } from '../types/identity-service-types.js';
+import {
+ peerToPeerMessageTypes,
+ type PeerToPeerMessage,
+} from '../types/tunnelbroker/peer-to-peer-message-types.js';
+import { secondaryDeviceLogoutP2PMessageValidator } from '../types/tunnelbroker/user-actions-peer-to-peer-message-types.js';
+import { getConfig } from '../utils/config.js';
+import { getContentSigningKey } from '../utils/crypto-utils.js';
+import { getMessageForException } from '../utils/errors.js';
+import { hasHigherDeviceID, olmSessionErrors } from '../utils/olm-utils.js';
+import { getClientMessageIDFromTunnelbrokerMessageID } from '../utils/peer-to-peer-communication-utils.js';
+
+function usePeerToPeerMessageHandler(): (
+ message: PeerToPeerMessage,
+ messageID: string,
+) => Promise<void> {
+ const { olmAPI, sqliteAPI } = getConfig();
+
+ const identityContext = React.useContext(IdentityClientContext);
+ invariant(identityContext, 'Identity context should be set');
+ const { identityClient } = identityContext;
+
+ return React.useCallback(
+ async (message: PeerToPeerMessage, messageID: string) => {
+ if (message.type === peerToPeerMessageTypes.OUTBOUND_SESSION_CREATION) {
+ const { senderInfo, encryptedData, sessionVersion } = message;
+ const { userID: senderUserID, deviceID: senderDeviceID } = senderInfo;
+
+ let deviceKeys: ?DeviceOlmInboundKeys = null;
+ try {
+ const { keys } =
+ await identityClient.getInboundKeysForUser(senderUserID);
+ deviceKeys = keys[senderDeviceID];
+ } catch (e) {
+ console.log(e.message);
+ }
+
+ if (!deviceKeys) {
+ console.log(
+ 'Error creating inbound session with device ' +
+ `${senderDeviceID}: No keys for the device, ` +
+ `session version: ${sessionVersion}`,
+ );
+ return;
+ }
+
+ try {
+ await olmAPI.initializeCryptoAccount();
+ const result = await olmAPI.contentInboundSessionCreator(
+ deviceKeys.identityKeysBlob.primaryIdentityPublicKeys,
+ encryptedData,
+ sessionVersion,
+ false,
+ );
+ console.log(
+ 'Created inbound session with device ' +
+ `${senderDeviceID}: ${result}, ` +
+ `session version: ${sessionVersion}`,
+ );
+ } catch (e) {
+ if (e.message?.includes(olmSessionErrors.alreadyCreated)) {
+ console.log(
+ 'Received session request with lower session version from ' +
+ `${senderDeviceID}, session version: ${sessionVersion}`,
+ );
+ } else if (e.message?.includes(olmSessionErrors.raceCondition)) {
+ const currentDeviceID = await getContentSigningKey();
+ if (hasHigherDeviceID(currentDeviceID, senderDeviceID)) {
+ console.log(
+ 'Race condition while creating session with ' +
+ `${senderDeviceID}, session version: ${sessionVersion}, ` +
+ `this device has a higher deviceID and the session will be kept`,
+ );
+ } else {
+ const result = await olmAPI.contentInboundSessionCreator(
+ deviceKeys.identityKeysBlob.primaryIdentityPublicKeys,
+ encryptedData,
+ sessionVersion,
+ true,
+ );
+ console.log(
+ 'Overwrite session with device ' +
+ `${senderDeviceID}: ${result}, ` +
+ `session version: ${sessionVersion}`,
+ );
+ // Resend all not-yet confirmed messages that were encrypted
+ // with overwrite session. Tracked in ENG-6982.
+ }
+ } else {
+ console.log(
+ 'Error creating inbound session with device ' +
+ `${senderDeviceID}: ${e.message}, ` +
+ `session version: ${sessionVersion}`,
+ );
+ }
+ }
+ } else if (message.type === peerToPeerMessageTypes.ENCRYPTED_MESSAGE) {
+ try {
+ await olmAPI.initializeCryptoAccount();
+ const decrypted = await olmAPI.decryptSequentialAndPersist(
+ message.encryptedData,
+ message.senderInfo.deviceID,
+ messageID,
+ );
+ console.log(
+ 'Decrypted message from device ' +
+ `${message.senderInfo.deviceID}: ${decrypted}`,
+ );
+
+ try {
+ const parsedMessageToDevice = JSON.parse(decrypted);
+ if (
+ !secondaryDeviceLogoutP2PMessageValidator.is(
+ parsedMessageToDevice,
+ )
+ ) {
+ return;
+ }
+ const { userID, deviceID: deviceIDToLogOut } = message.senderInfo;
+ await removeDeviceFromDeviceList(
+ identityClient,
+ userID,
+ deviceIDToLogOut,
+ );
+ // TODO: broadcast device list update here
+ } catch (e) {
+ console.log(e);
+ }
+ } catch (e) {
+ if (e.message?.includes(olmSessionErrors.messageAlreadyDecrypted)) {
+ console.log(
+ 'Received already decrypted message from device ' +
+ `${message.senderInfo.deviceID}.`,
+ );
+ } else if (e.message?.includes(olmSessionErrors.messageOutOfOrder)) {
+ console.log(
+ 'Received out-of-order message from device ' +
+ `${message.senderInfo.deviceID}.`,
+ );
+ } else {
+ console.log(
+ 'Error decrypting message from device ' +
+ `${message.senderInfo.deviceID}: ${e.message}`,
+ );
+ }
+ }
+ } else if (message.type === peerToPeerMessageTypes.REFRESH_KEY_REQUEST) {
+ try {
+ await olmAPI.initializeCryptoAccount();
+ const oneTimeKeys = await olmAPI.getOneTimeKeys(message.numberOfKeys);
+ await identityClient.uploadOneTimeKeys(oneTimeKeys);
+ } catch (e) {
+ console.log(`Error uploading one-time keys: ${e.message}`);
+ }
+ } else if (message.type === peerToPeerMessageTypes.DEVICE_LIST_UPDATED) {
+ try {
+ const result = await verifyAndGetDeviceList(
+ identityClient,
+ message.userID,
+ null,
+ );
+ if (!result.valid) {
+ console.log(
+ `Received invalid device list update for user ${message.userID}. Reason: ${result.reason}`,
+ );
+ return;
+ }
+ console.log(
+ `Received valid device list update for user ${message.userID}`,
+ );
+
+ if (message?.signedDeviceList?.rawDeviceList) {
+ const receivedRawList = JSON.parse(
+ message.signedDeviceList.rawDeviceList,
+ );
+
+ // additional check for broadcasted and Identity device
+ // list equality
+ const listsAreEqual = _isEqual(result.deviceList)(receivedRawList);
+ console.log(
+ `Identity and received device lists are ${
+ listsAreEqual ? '' : 'not'
+ } equal.`,
+ );
+ }
+ } catch (e) {
+ console.log(
+ `Error verifying device list for user ${message.userID}: ${e}`,
+ );
+ }
+ } else if (message.type === peerToPeerMessageTypes.MESSAGE_PROCESSED) {
+ try {
+ const { deviceID, messageID: tunnelbrokerMessageID } = message;
+ const clientMessageID = getClientMessageIDFromTunnelbrokerMessageID(
+ tunnelbrokerMessageID,
+ );
+ await sqliteAPI.removeOutboundP2PMessagesOlderThan(
+ clientMessageID,
+ deviceID,
+ );
+ } catch (e) {
+ console.log(
+ `Error removing message after processing: ${
+ getMessageForException(e) ?? 'unknown error'
+ }`,
+ );
+ }
+ }
+ },
+ [identityClient, olmAPI, sqliteAPI],
+ );
+}
+
+export { usePeerToPeerMessageHandler };

File Metadata

Mime Type
text/plain
Expires
Mon, Nov 25, 7:32 PM (22 h, 6 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2580806
Default Alt Text
D12372.diff (18 KB)

Event Timeline