diff --git a/lib/client.js b/lib/client.js index ad74f58af..bc377f130 100644 --- a/lib/client.js +++ b/lib/client.js @@ -49,6 +49,12 @@ try { var OLM_ALGORITHM = "m.olm.v1.curve25519-aes-sha2"; +var DeviceVerification = { + VERIFIED: 1, + UNVERIFIED: 0, + BLOCKED: -1, +}; + /** * Construct a Matrix Client. Only directly construct this if you want to use * custom modules. Normally, {@link createClient} should be used @@ -133,7 +139,7 @@ function MatrixClient(opts) { var deviceInfo = { keys: this.deviceKeys.keys, algorithms: this.deviceKeys.algorithms, - verified: true, + verified: DeviceVerification.VERIFIED, }; var myDevices = this.sessionStore.getEndToEndDevicesForUser( opts.userId @@ -378,7 +384,7 @@ function _doKeyUpload(client) { * @typedef {Object} DeviceInfo * @property {string[]} list of algorithms supported by this device * @property {Object} keys a map from <key type>:<id> -> key - * @property {boolean} verified true if the device has been verified by the user + * @property {DeviceVerification} whether the device has been verified by the user */ /** @@ -488,7 +494,7 @@ function _updateStoredDeviceKeysForUser(userId, userStore, userResult) { } } else { userStore[deviceId] = deviceStore = { - verified: false, + verified: DeviceVerification.UNVERIFIED }; } @@ -508,7 +514,8 @@ function _updateStoredDeviceKeysForUser(userId, userStore, userResult) { * * @param {string} userId the user to list keys for. * - * @return {object[]} list of devices with "id", "verified", and "key" parameters. + * @return {object[]} list of devices with "id", "verified", "blocked", and + * "key" parameters. */ MatrixClient.prototype.listDeviceKeys = function(userId) { if (!this.sessionStore) { @@ -532,8 +539,9 @@ MatrixClient.prototype.listDeviceKeys = function(userId) { if (ed25519Key) { result.push({ id: deviceId, - verified: device.verified, key: ed25519Key, + verified: device.verified == DeviceVerification.VERIFIED, + blocked: device.verified == DeviceVerification.BLOCKED, }); } } @@ -550,31 +558,67 @@ MatrixClient.prototype.listDeviceKeys = function(userId) { * @param {boolean=} verified whether to mark the device as verified. defaults * to 'true'. * - * @fires module:client~event:MatrixClient"deviceVerified" + * @fires module:client~event:MatrixClient"deviceVerificationChanged" */ MatrixClient.prototype.setDeviceVerified = function(userId, deviceId, verified) { if (verified === undefined) { verified = true; } + _setDeviceVerification(this, userId, deviceId, verified, null); +}; - if (!this.sessionStore) { + +/** + * Mark the given device as blocked/unblocked + * + * @param {string} userId owner of the device + * @param {string} deviceId unique identifier for the device + * + * @param {boolean=} blocked whether to mark the device as blocked. defaults + * to 'true'. + * + * @fires module:client~event:MatrixClient"deviceVerificationChanged" + */ +MatrixClient.prototype.setDeviceBlocked = function(userId, deviceId, blocked) { + if (blocked === undefined) { + blocked = true; + } + _setDeviceVerification(this, userId, deviceId, null, blocked); +}; + +function _setDeviceVerification(client, userId, deviceId, verified, blocked) { + if (!client.sessionStore) { throw new Error("End-to-End encryption disabled"); } - var devices = this.sessionStore.getEndToEndDevicesForUser(userId); + var devices = client.sessionStore.getEndToEndDevicesForUser(userId); if (!devices || !devices[deviceId]) { throw new Error("Unknown device " + userId + ":" + deviceId); } var dev = devices[deviceId]; - if (dev.verified === verified) { + var verificationStatus = dev.verified; + + if (verified) { + verificationStatus = DeviceVerification.VERIFIED; + } else if (verified !== null && verificationStatus == DeviceVerification.VERIFIED) { + verificationStatus = DeviceVerification.UNVERIFIED; + } + + if (blocked) { + verificationStatus = DeviceVerification.BLOCKED; + } else if (blocked !== null && verificationStatus == DeviceVerification.BLOCKED) { + verificationStatus = DeviceVerification.UNVERIFIED; + } + + if (dev.verified === verificationStatus) { return; } - dev.verified = verified; - this.sessionStore.storeEndToEndDevicesForUser(userId, devices); + dev.verified = verificationStatus; + client.sessionStore.storeEndToEndDevicesForUser(userId, devices); - this.emit("deviceVerified", userId, deviceId, dev); -}; + client.emit("deviceVerificationChanged", userId, deviceId, dev); +} /** @@ -623,7 +667,7 @@ MatrixClient.prototype.isEventSenderVerified = function(event) { } var deviceKey = device.keys[keyId]; if (deviceKey == sender_key) { - return Boolean(device.verified); + return device.verified == DeviceVerification.VERIFIED; } } } @@ -1223,10 +1267,14 @@ function _encryptMessage(client, roomId, e2eRoomInfo, eventType, content) { var devices = client.sessionStore.getEndToEndDevicesForUser(userId); for (var deviceId in devices) { if (devices.hasOwnProperty(deviceId)) { - var keys = devices[deviceId]; - for (var keyId in keys.keys) { + var dev = devices[deviceId]; + if (dev.verified === DeviceVerification.BLOCKED) { + continue; + } + + for (var keyId in dev.keys) { if (keyId.indexOf("curve25519:") === 0) { - participantKeys.push(keys.keys[keyId]); + participantKeys.push(dev.keys[keyId]); } } } @@ -3773,10 +3821,11 @@ module.exports.CRYPTO_ENABLED = CRYPTO_ENABLED; */ /** - * Fires when a device is marked as verified by {@link - * module:client~MatrixClient#setDeviceVerified|MatrixClient.setDeviceVerified}. + * Fires when a device is marked as verified/unverified/blocked/unblocked by + * {@link module:client~MatrixClient#setDeviceVerified|MatrixClient.setDeviceVerified} or + * {@link module:client~MatrixClient#setDeviceBlocked|MatrixClient.setDeviceBlocked}. * - * @event module:client~MatrixClient#"deviceVerified" + * @event module:client~MatrixClient#"deviceVerificationChanged" * @param {string} userId the owner of the verified device * @param {module:client~DeviceInfo} device information about the verified device */