From 164b355ffea785f69c683ede1137bb3926378dc9 Mon Sep 17 00:00:00 2001 From: Zoe Date: Tue, 18 Feb 2020 11:25:19 +0000 Subject: [PATCH] abstract out the check for available target devices --- src/components/views/dialogs/InviteDialog.js | 6 +--- src/createRoom.js | 20 ++++++++---- test/createRoom-test.js | 33 +++++++++++++++++++- 3 files changed, 47 insertions(+), 12 deletions(-) diff --git a/src/components/views/dialogs/InviteDialog.js b/src/components/views/dialogs/InviteDialog.js index 8fec2437f6..5a5f2233bf 100644 --- a/src/components/views/dialogs/InviteDialog.js +++ b/src/components/views/dialogs/InviteDialog.js @@ -535,11 +535,7 @@ export default class InviteDialog extends React.PureComponent { // Check whether all users have uploaded device keys before. // If so, enable encryption in the new room. const client = MatrixClientPeg.get(); - const usersToDevicesMap = await client.downloadKeys(targetIds); - const allHaveDeviceKeys = Object.values(usersToDevicesMap).every(devices => { - // `devices` is an object of the form { deviceId: deviceInfo, ... }. - return Object.keys(devices).length > 0; - }); + const allHaveDeviceKeys = await createRoom.canEncryptToAllUsers(client, targetIds); if (allHaveDeviceKeys) { createRoomOptions.encryption = true; } diff --git a/src/createRoom.js b/src/createRoom.js index 8924808024..07eaee3e8f 100644 --- a/src/createRoom.js +++ b/src/createRoom.js @@ -199,6 +199,19 @@ export async function _waitForMember(client, roomId, userId, opts = { timeout: 1 }); } +/* + * Ensure that for every user in a room, there is at least one device that we + * can encrypt to. + */ +export async function canEncryptToAllUsers(client, userIds) { + const usersDeviceMap = await client.downloadKeys(userIds); + // { "@user:host": { "DEVICE": {...}, ... }, ... } + return Object.values(usersDeviceMap).every((userDevices) => + // { "DEVICE": {...}, ... } + Object.keys(userDevices).length > 0, + ); +} + export async function ensureDMExists(client, userId) { const existingDMRoom = findDMForUser(client, userId); let roomId; @@ -207,12 +220,7 @@ export async function ensureDMExists(client, userId) { } else { let encryption; if (SettingsStore.isFeatureEnabled("feature_cross_signing")) { - /* If the user's devices can all do encryption, start an encrypted DM */ - const userDeviceMap = await client.downloadKeys([userId]); - // => { "@userId:host": { DEVICE: DeviceInfo, ... }} - const userDevices = Object.values(userDeviceMap[userId]); - // => [DeviceInfo, DeviceInfo...] - encryption = userDevices.every((device) => device.keys); + encryption = canEncryptToAllUsers(client, [userId]); } roomId = await createRoom({encryption, dmUserId: userId, spinner: false, andView: false}); await _waitForMember(client, roomId, userId); diff --git a/test/createRoom-test.js b/test/createRoom-test.js index 5955395c48..f7e8617c3f 100644 --- a/test/createRoom-test.js +++ b/test/createRoom-test.js @@ -1,4 +1,4 @@ -import {_waitForMember} from '../src/createRoom'; +import {_waitForMember, canEncryptToAllUsers} from '../src/createRoom'; import {EventEmitter} from 'events'; /* Shorter timeout, we've got tests to run */ @@ -39,3 +39,34 @@ describe("waitForMember", () => { client.emit("RoomState.newMember", undefined, undefined, { roomId, userId }); }); }); + +describe("canEncryptToAllUsers", () => { + const trueUser = { + "@goodUser:localhost": { + "DEV1": {}, + "DEV2": {}, + }, + }; + const falseUser = { + "@badUser:localhost": {}, + }; + + it("returns true if all devices have crypto", async (done) => { + const client = { + downloadKeys: async function(userIds) { return trueUser; }, + }; + const response = await canEncryptToAllUsers(client, ["@goodUser:localhost"]); + expect(response).toBe(true); + done(); + }); + + + it("returns false if not all users have crypto", async (done) => { + const client = { + downloadKeys: async function(userIds) { return {...trueUser, ...falseUser}; }, + }; + const response = await canEncryptToAllUsers(client, ["@goodUser:localhost", "@badUser:localhost"]); + expect(response).toBe(false); + done(); + }); +});