diff --git a/src/client.js b/src/client.js index 4e78c01c1..c28cd2a5a 100644 --- a/src/client.js +++ b/src/client.js @@ -403,6 +403,21 @@ function _setDeviceVerification(client, userId, deviceId, verified, blocked) { client.emit("deviceVerificationChanged", userId, deviceId); } +/** + * Set the global override for whether the client should ever send encrypted + * messages to unverified devices. If false, it can still be overridden + * per-room. If true, it overrides the per-room settings. + * + * @param {boolean} value whether to unilaterally blacklist all + * unverified devices + */ +MatrixClient.prototype.setGlobalBlacklistUnverifiedDevices = function(value) { + if (this._crypto === null) { + throw new Error("End-to-end encryption disabled"); + } + this._crypto.setGlobalBlacklistUnverifiedDevices(value); +}; + /** * Get e2e information on the device that sent an event * diff --git a/src/crypto/algorithms/megolm.js b/src/crypto/algorithms/megolm.js index 8803d31d1..7ad303a1e 100644 --- a/src/crypto/algorithms/megolm.js +++ b/src/crypto/algorithms/megolm.js @@ -476,7 +476,7 @@ MegolmEncryption.prototype._getDevicesInRoom = function(room) { // XXX: what if the cache is stale, and the user left the room we had in common // and then added new devices before joining this one? --Matthew return this._crypto.downloadKeys(roomMembers, false).then(function(devices) { - // remove any blocked devices + // remove any blocked (aka blacklisted) devices for (const userId in devices) { if (!devices.hasOwnProperty(userId)) { continue; @@ -487,7 +487,11 @@ MegolmEncryption.prototype._getDevicesInRoom = function(room) { if (!userDevices.hasOwnProperty(deviceId)) { continue; } - if (userDevices[deviceId].isBlocked()) { + + if (userDevices[deviceId].isBlocked() || + (userDevices[deviceId].isUnverified() && + room.getBlacklistUnverifiedDevices())) + { delete userDevices[deviceId]; } } diff --git a/src/crypto/index.js b/src/crypto/index.js index 822184c48..a71417f94 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -79,6 +79,8 @@ function Crypto(baseApis, eventEmitter, sessionStore, userId, deviceId) { this._deviceKeys["curve25519:" + this._deviceId] = this._olmDevice.deviceCurve25519Key; + this._globalBlacklistUnverifiedDevices = false; + let myDevices = this._sessionStore.getEndToEndDevicesForUser( this._userId ); @@ -169,6 +171,25 @@ Crypto.prototype.getDeviceEd25519Key = function() { return this._olmDevice.deviceEd25519Key; }; +/** + * Set the global override for whether the client should ever send encrypted + * messages to unverified devices. If false, it can still be overridden + * per-room. If true, it overrides the per-room settings. + * + * @param {boolean} value whether to unilaterally blacklist all + * unverified devices + */ +Crypto.prototype.setGlobalBlacklistUnverifiedDevices = function(value) { + this._globalBlacklistUnverifiedDevices = value; +}; + +/** + * @return {boolean} whether to unilaterally blacklist all unverified devices + */ +Crypto.prototype.getGlobalBlacklistUnverifiedDevices = function() { + return this._globalBlacklistUnverifiedDevices; +}; + /** * Upload the device keys to the homeserver and ensure that the * homeserver has enough one-time keys. diff --git a/src/models/room.js b/src/models/room.js index a7faddba5..eb7dc6bd2 100644 --- a/src/models/room.js +++ b/src/models/room.js @@ -165,6 +165,8 @@ function Room(roomId, opts) { if (this._opts.pendingEventOrdering == "detached") { this._pendingEventList = []; } + + this._blacklistUnverifiedDevices = false; // read by megolm } utils.inherits(Room, EventEmitter); @@ -294,6 +296,24 @@ Room.prototype.setUnreadNotificationCount = function(type, count) { this._notificationCounts[type] = count; }; +/** + * Whether to send encrypted messages to devices within this room. + * Will be ignored if MatrixClient's blacklistUnverifiedDevices setting is true. + * @param {boolean} value if true, blacklist unverified devices. + */ +Room.prototype.setBlacklistUnverifiedDevices = function(value) { + this._blacklistUnverifiedDevices = value; +}; + +/** + * Whether to send encrypted messages to devices within this room. + * Will be ignored if MatrixClient's blacklistUnverifiedDevices setting is true. + * @return {boolean} true if blacklisting unverified devices. + */ +Room.prototype.getBlacklistUnverifiedDevices = function() { + return this._blacklistUnverifiedDevices; +}; + /** * Get the avatar URL for a room if one was set. * @param {String} baseUrl The homeserver base URL. See diff --git a/src/sync.js b/src/sync.js index a7da42353..7a6503bfc 100644 --- a/src/sync.js +++ b/src/sync.js @@ -93,6 +93,7 @@ SyncApi.prototype.createRoom = function(roomId) { pendingEventOrdering: this.opts.pendingEventOrdering, timelineSupport: client.timelineSupport, }); + reEmit(client, room, ["Room.name", "Room.timeline", "Room.redaction", "Room.receipt", "Room.tags", "Room.timelineReset",