mirror of
https://github.com/vector-im/element-web.git
synced 2024-11-16 13:14:58 +08:00
Merge pull request #3913 from matrix-org/jryans/negotiate-e2e-dms
Enable encryption in DMs with device keys
This commit is contained in:
commit
e3027d3086
@ -961,9 +961,9 @@ export default createReactClass({
|
|||||||
const CreateRoomDialog = sdk.getComponent('dialogs.CreateRoomDialog');
|
const CreateRoomDialog = sdk.getComponent('dialogs.CreateRoomDialog');
|
||||||
const modal = Modal.createTrackedDialog('Create Room', '', CreateRoomDialog);
|
const modal = Modal.createTrackedDialog('Create Room', '', CreateRoomDialog);
|
||||||
|
|
||||||
const [shouldCreate, createOpts] = await modal.finished;
|
const [shouldCreate, opts] = await modal.finished;
|
||||||
if (shouldCreate) {
|
if (shouldCreate) {
|
||||||
createRoom({createOpts});
|
createRoom(opts);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>
|
Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>
|
||||||
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -44,13 +45,13 @@ export default createReactClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_roomCreateOptions() {
|
_roomCreateOptions() {
|
||||||
const createOpts = {};
|
const opts = {};
|
||||||
|
const createOpts = opts.createOpts = {};
|
||||||
createOpts.name = this.state.name;
|
createOpts.name = this.state.name;
|
||||||
if (this.state.isPublic) {
|
if (this.state.isPublic) {
|
||||||
createOpts.visibility = "public";
|
createOpts.visibility = "public";
|
||||||
createOpts.preset = "public_chat";
|
createOpts.preset = "public_chat";
|
||||||
// to prevent createRoom from enabling guest access
|
opts.guestAccess = false;
|
||||||
createOpts['initial_state'] = [];
|
|
||||||
const {alias} = this.state;
|
const {alias} = this.state;
|
||||||
const localPart = alias.substr(1, alias.indexOf(":") - 1);
|
const localPart = alias.substr(1, alias.indexOf(":") - 1);
|
||||||
createOpts['room_alias_name'] = localPart;
|
createOpts['room_alias_name'] = localPart;
|
||||||
@ -61,7 +62,7 @@ export default createReactClass({
|
|||||||
if (this.state.noFederate) {
|
if (this.state.noFederate) {
|
||||||
createOpts.creation_content = {'m.federate': false};
|
createOpts.creation_content = {'m.federate': false};
|
||||||
}
|
}
|
||||||
return createOpts;
|
return opts;
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
@ -33,6 +33,7 @@ import Modal from "../../../Modal";
|
|||||||
import {humanizeTime} from "../../../utils/humanize";
|
import {humanizeTime} from "../../../utils/humanize";
|
||||||
import createRoom from "../../../createRoom";
|
import createRoom from "../../../createRoom";
|
||||||
import {inviteMultipleToRoom} from "../../../RoomInvite";
|
import {inviteMultipleToRoom} from "../../../RoomInvite";
|
||||||
|
import SettingsStore from '../../../settings/SettingsStore';
|
||||||
|
|
||||||
export const KIND_DM = "dm";
|
export const KIND_DM = "dm";
|
||||||
export const KIND_INVITE = "invite";
|
export const KIND_INVITE = "invite";
|
||||||
@ -493,7 +494,7 @@ export default class InviteDialog extends React.PureComponent {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_startDm = () => {
|
_startDm = async () => {
|
||||||
this.setState({busy: true});
|
this.setState({busy: true});
|
||||||
const targetIds = this.state.targets.map(t => t.userId);
|
const targetIds = this.state.targets.map(t => t.userId);
|
||||||
|
|
||||||
@ -510,14 +511,31 @@ export default class InviteDialog extends React.PureComponent {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const createRoomOptions = {};
|
||||||
|
|
||||||
|
if (SettingsStore.isFeatureEnabled("feature_cross_signing")) {
|
||||||
|
// 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;
|
||||||
|
});
|
||||||
|
if (allHaveDeviceKeys) {
|
||||||
|
createRoomOptions.encryption = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if it's a traditional DM and create the room if required.
|
// Check if it's a traditional DM and create the room if required.
|
||||||
// TODO: [Canonical DMs] Remove this check and instead just create the multi-person DM
|
// TODO: [Canonical DMs] Remove this check and instead just create the multi-person DM
|
||||||
let createRoomPromise = Promise.resolve();
|
let createRoomPromise = Promise.resolve();
|
||||||
if (targetIds.length === 1) {
|
if (targetIds.length === 1) {
|
||||||
createRoomPromise = createRoom({dmUserId: targetIds[0]});
|
createRoomOptions.dmUserId = targetIds[0];
|
||||||
|
createRoomPromise = createRoom(createRoomOptions);
|
||||||
} else {
|
} else {
|
||||||
// Create a boring room and try to invite the targets manually.
|
// Create a boring room and try to invite the targets manually.
|
||||||
createRoomPromise = createRoom().then(roomId => {
|
createRoomPromise = createRoom(createRoomOptions).then(roomId => {
|
||||||
return inviteMultipleToRoom(roomId, targetIds);
|
return inviteMultipleToRoom(roomId, targetIds);
|
||||||
}).then(result => {
|
}).then(result => {
|
||||||
if (this._shouldAbortAfterInviteError(result)) {
|
if (this._shouldAbortAfterInviteError(result)) {
|
||||||
|
@ -82,7 +82,7 @@ const _getE2EStatus = (cli, userId, devices) => {
|
|||||||
return "warning";
|
return "warning";
|
||||||
};
|
};
|
||||||
|
|
||||||
function openDMForUser(matrixClient, userId) {
|
async function openDMForUser(matrixClient, userId) {
|
||||||
const dmRooms = DMRoomMap.shared().getDMRoomsForUserId(userId);
|
const dmRooms = DMRoomMap.shared().getDMRoomsForUserId(userId);
|
||||||
const lastActiveRoom = dmRooms.reduce((lastActiveRoom, roomId) => {
|
const lastActiveRoom = dmRooms.reduce((lastActiveRoom, roomId) => {
|
||||||
const room = matrixClient.getRoom(roomId);
|
const room = matrixClient.getRoom(roomId);
|
||||||
@ -100,9 +100,27 @@ function openDMForUser(matrixClient, userId) {
|
|||||||
action: 'view_room',
|
action: 'view_room',
|
||||||
room_id: lastActiveRoom.roomId,
|
room_id: lastActiveRoom.roomId,
|
||||||
});
|
});
|
||||||
} else {
|
return;
|
||||||
createRoom({dmUserId: userId});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const createRoomOptions = {
|
||||||
|
dmUserId: userId,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (SettingsStore.isFeatureEnabled("feature_cross_signing")) {
|
||||||
|
// Check whether all users have uploaded device keys before.
|
||||||
|
// If so, enable encryption in the new room.
|
||||||
|
const usersToDevicesMap = await matrixClient.downloadKeys([userId]);
|
||||||
|
const allHaveDeviceKeys = Object.values(usersToDevicesMap).every(devices => {
|
||||||
|
// `devices` is an object of the form { deviceId: deviceInfo, ... }.
|
||||||
|
return Object.keys(devices).length > 0;
|
||||||
|
});
|
||||||
|
if (allHaveDeviceKeys) {
|
||||||
|
createRoomOptions.encryption = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createRoom(createRoomOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
function useIsEncrypted(cli, room) {
|
function useIsEncrypted(cli, room) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Copyright 2015, 2016 OpenMarket Ltd
|
Copyright 2015, 2016 OpenMarket Ltd
|
||||||
Copyright 2019 The Matrix.org Foundation C.I.C.
|
Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -32,6 +32,10 @@ import {getAddressType} from "./UserAddress";
|
|||||||
* @param {object=} opts.createOpts set of options to pass to createRoom call.
|
* @param {object=} opts.createOpts set of options to pass to createRoom call.
|
||||||
* @param {bool=} opts.spinner True to show a modal spinner while the room is created.
|
* @param {bool=} opts.spinner True to show a modal spinner while the room is created.
|
||||||
* Default: True
|
* Default: True
|
||||||
|
* @param {bool=} opts.guestAccess Whether to enable guest access.
|
||||||
|
* Default: True
|
||||||
|
* @param {bool=} opts.encryption Whether to enable encryption.
|
||||||
|
* Default: False
|
||||||
*
|
*
|
||||||
* @returns {Promise} which resolves to the room id, or null if the
|
* @returns {Promise} which resolves to the room id, or null if the
|
||||||
* action was aborted or failed.
|
* action was aborted or failed.
|
||||||
@ -39,6 +43,8 @@ import {getAddressType} from "./UserAddress";
|
|||||||
export default function createRoom(opts) {
|
export default function createRoom(opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
if (opts.spinner === undefined) opts.spinner = true;
|
if (opts.spinner === undefined) opts.spinner = true;
|
||||||
|
if (opts.guestAccess === undefined) opts.guestAccess = true;
|
||||||
|
if (opts.encryption === undefined) opts.encryption = false;
|
||||||
|
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
const Loader = sdk.getComponent("elements.Spinner");
|
const Loader = sdk.getComponent("elements.Spinner");
|
||||||
@ -77,18 +83,30 @@ export default function createRoom(opts) {
|
|||||||
opts.andView = true;
|
opts.andView = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createOpts.initial_state = createOpts.initial_state || [];
|
||||||
|
|
||||||
// Allow guests by default since the room is private and they'd
|
// Allow guests by default since the room is private and they'd
|
||||||
// need an invite. This means clicking on a 3pid invite email can
|
// need an invite. This means clicking on a 3pid invite email can
|
||||||
// actually drop you right in to a chat.
|
// actually drop you right in to a chat.
|
||||||
createOpts.initial_state = createOpts.initial_state || [
|
if (opts.guestAccess) {
|
||||||
{
|
createOpts.initial_state.push({
|
||||||
|
type: 'm.room.guest_access',
|
||||||
|
state_key: '',
|
||||||
content: {
|
content: {
|
||||||
guest_access: 'can_join',
|
guest_access: 'can_join',
|
||||||
},
|
},
|
||||||
type: 'm.room.guest_access',
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.encryption) {
|
||||||
|
createOpts.initial_state.push({
|
||||||
|
type: 'm.room.encryption',
|
||||||
state_key: '',
|
state_key: '',
|
||||||
},
|
content: {
|
||||||
];
|
algorithm: 'm.megolm.v1.aes-sha2',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let modal;
|
let modal;
|
||||||
if (opts.spinner) modal = Modal.createDialog(Loader, null, 'mx_Dialog_spinner');
|
if (opts.spinner) modal = Modal.createDialog(Loader, null, 'mx_Dialog_spinner');
|
||||||
|
Loading…
Reference in New Issue
Block a user