You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-11-29 16:43:09 +03:00
Use to-device events for key sharing
Synapse now supports out-of-band messages, so use them instead of sending the key-sharing messages in-band.
This commit is contained in:
@@ -66,8 +66,9 @@ function MatrixBaseApis(opts) {
|
||||
extraParams: opts.queryParams
|
||||
};
|
||||
this._http = new httpApi.MatrixHttpApi(this, httpOpts);
|
||||
}
|
||||
|
||||
this._txnCtr = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Homeserver URL of this client
|
||||
@@ -100,6 +101,15 @@ MatrixBaseApis.prototype.isLoggedIn = function() {
|
||||
return this._http.opts.accessToken !== undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Make up a new transaction id
|
||||
*
|
||||
* @return {string} a new, unique, transaction id
|
||||
*/
|
||||
MatrixBaseApis.prototype.makeTxnId = function() {
|
||||
return "m" + new Date().getTime() + "." + (this._txnCtr++);
|
||||
};
|
||||
|
||||
|
||||
// Registration/Login operations
|
||||
// =============================
|
||||
@@ -970,6 +980,39 @@ MatrixBaseApis.prototype.lookupThreePid = function(medium, address, callback) {
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
// Direct-to-device messaging
|
||||
// ==========================
|
||||
|
||||
/**
|
||||
* Send an event to a specific list of devices
|
||||
*
|
||||
* @param {string} eventType type of event to send
|
||||
* @param {Object.<string, Object<string, Object>>} contentMap
|
||||
* content to send. Map from user_id to device_id to content object.
|
||||
* @param {string=} txnId transaction id. One will be made up if not
|
||||
* supplied.
|
||||
* @return {module:client.Promise} Resolves to the result object
|
||||
*/
|
||||
MatrixBaseApis.prototype.sendToDevice = function(
|
||||
eventType, contentMap, txnId
|
||||
) {
|
||||
var path = utils.encodeUri("/sendToDevice/$eventType/$txnId", {
|
||||
$eventType: eventType,
|
||||
$txnId: txnId ? txnId : this.makeTxnId(),
|
||||
});
|
||||
|
||||
var body = {
|
||||
messages: contentMap,
|
||||
};
|
||||
|
||||
return this._http.authedRequestWithPrefix(
|
||||
undefined, "PUT", path, undefined, body,
|
||||
httpApi.PREFIX_UNSTABLE
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* MatrixBaseApis object
|
||||
*/
|
||||
|
||||
@@ -144,7 +144,6 @@ function MatrixClient(opts) {
|
||||
this._peekSync = null;
|
||||
this._isGuest = false;
|
||||
this._ongoingScrollbacks = {};
|
||||
this._txnCtr = 0;
|
||||
this.timelineSupport = Boolean(opts.timelineSupport);
|
||||
this.urlPreviewCache = {};
|
||||
|
||||
@@ -424,6 +423,12 @@ function setupCryptoEventHandler(client) {
|
||||
});
|
||||
client.on("RoomMember.membership",
|
||||
client._crypto.onRoomMembership.bind(client._crypto));
|
||||
|
||||
client.on("toDeviceEvent", function(event) {
|
||||
if (event.getType() == "m.room_key") {
|
||||
client._crypto.onRoomKeyEvent(event);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function onCryptoEvent(client, event) {
|
||||
@@ -438,20 +443,6 @@ function onCryptoEvent(client, event) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* handle a room key event
|
||||
*
|
||||
* @private
|
||||
*
|
||||
* @param {MatrixEvent} event
|
||||
*/
|
||||
MatrixClient.prototype._onRoomKeyEvent = function(event) {
|
||||
if (!this._crypto) {
|
||||
return;
|
||||
}
|
||||
this._crypto.onRoomKeyEvent(event);
|
||||
};
|
||||
|
||||
/**
|
||||
* Enable end-to-end encryption for a room.
|
||||
* @param {string} roomId The room ID to enable encryption in.
|
||||
@@ -820,7 +811,7 @@ MatrixClient.prototype.sendEvent = function(roomId, eventType, content, txnId,
|
||||
if (utils.isFunction(txnId)) { callback = txnId; txnId = undefined; }
|
||||
|
||||
if (!txnId) {
|
||||
txnId = "m" + new Date().getTime() + "." + (this._txnCtr++);
|
||||
txnId = this.makeTxnId();
|
||||
}
|
||||
|
||||
// we always construct a MatrixEvent when sending because the store and
|
||||
@@ -921,11 +912,13 @@ function _updatePendingEventStatus(room, event, newStatus) {
|
||||
}
|
||||
|
||||
function _sendEventHttpRequest(client, event) {
|
||||
var txnId = event._txnId ? event._txnId : client.makeTxnId();
|
||||
|
||||
var pathParams = {
|
||||
$roomId: event.getRoomId(),
|
||||
$eventType: event.getWireType(),
|
||||
$stateKey: event.getStateKey(),
|
||||
$txnId: event._txnId ? event._txnId : new Date().getTime()
|
||||
$txnId: txnId,
|
||||
};
|
||||
|
||||
var path;
|
||||
@@ -2663,13 +2656,6 @@ function _PojoToMatrixEventMapper(client) {
|
||||
clearData = _decryptMessage(client, plainOldJsObject);
|
||||
}
|
||||
var matrixEvent = new MatrixEvent(plainOldJsObject, clearData);
|
||||
|
||||
// XXXX massive hack to deal with the fact that megolm keys are in the
|
||||
// room for now, and we need to handle them before attempting to
|
||||
// decrypt the following megolm messages.
|
||||
if (matrixEvent.getType() == "m.room_key") {
|
||||
client._onRoomKeyEvent(matrixEvent);
|
||||
}
|
||||
return matrixEvent;
|
||||
}
|
||||
return mapper;
|
||||
|
||||
@@ -96,17 +96,15 @@ MegolmEncryption.prototype._ensureOutboundSession = function(room) {
|
||||
).then(function(res) {
|
||||
return self._crypto.ensureOlmSessionsForUsers(roomMembers);
|
||||
}).then(function(devicemap) {
|
||||
// TODO: send OOB messages. for now, send an in-band message. Each
|
||||
// encrypted copy of the key takes up about 1K, so we'll only manage
|
||||
// about 60 copies before we hit the event size limit; but ultimately the
|
||||
// OOB messaging API will solve that problem for us.
|
||||
var contentMap = {};
|
||||
|
||||
var participantKeys = [];
|
||||
for (var userId in devicemap) {
|
||||
if (!devicemap.hasOwnProperty(userId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
contentMap[userId] = {};
|
||||
|
||||
var devices = devicemap[userId];
|
||||
|
||||
for (var deviceId in devices) {
|
||||
@@ -115,29 +113,18 @@ MegolmEncryption.prototype._ensureOutboundSession = function(room) {
|
||||
}
|
||||
|
||||
var deviceInfo = devices[deviceId].device;
|
||||
participantKeys.push(deviceInfo.getIdentityKey());
|
||||
contentMap[userId][deviceId] =
|
||||
olmlib.encryptMessageForDevices(
|
||||
self._deviceId,
|
||||
self._olmDevice,
|
||||
[deviceInfo.getIdentityKey()],
|
||||
payload
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
var encryptedContent = olmlib.encryptMessageForDevices(
|
||||
self._deviceId,
|
||||
self._olmDevice,
|
||||
participantKeys,
|
||||
payload
|
||||
);
|
||||
|
||||
var txnId = '' + (new Date().getTime());
|
||||
var path = utils.encodeUri(
|
||||
"/rooms/$roomId/send/m.room.encrypted/$txnId", {
|
||||
$roomId: self._roomId,
|
||||
$txnId: txnId,
|
||||
}
|
||||
);
|
||||
|
||||
// TODO: retries
|
||||
return self._baseApis._http.authedRequest(
|
||||
undefined, "PUT", path, undefined, encryptedContent
|
||||
);
|
||||
return self._baseApis.sendToDevice("m.room.encrypted", contentMap);
|
||||
}).then(function() {
|
||||
if (self._discardNewSession) {
|
||||
// we've had cause to reset the session_id since starting this process.
|
||||
|
||||
74
lib/sync.js
74
lib/sync.js
@@ -496,36 +496,6 @@ SyncApi.prototype._sync = function(syncOptions) {
|
||||
|
||||
this._currentSyncRequest.done(function(data) {
|
||||
self._syncConnectionLost = false;
|
||||
// data looks like:
|
||||
// {
|
||||
// next_batch: $token,
|
||||
// presence: { events: [] },
|
||||
// rooms: {
|
||||
// invite: {
|
||||
// $roomid: {
|
||||
// invite_state: { events: [] }
|
||||
// }
|
||||
// },
|
||||
// join: {
|
||||
// $roomid: {
|
||||
// state: { events: [] },
|
||||
// timeline: { events: [], prev_batch: $token, limited: true },
|
||||
// ephemeral: { events: [] },
|
||||
// account_data: { events: [] },
|
||||
// unread_notifications: {
|
||||
// highlight_count: 0,
|
||||
// notification_count: 0,
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// leave: {
|
||||
// $roomid: {
|
||||
// state: { events: [] },
|
||||
// timeline: { events: [], prev_batch: $token }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// set the sync token NOW *before* processing the events. We do this so
|
||||
// if something barfs on an event we can skip it rather than constantly
|
||||
@@ -585,6 +555,39 @@ SyncApi.prototype._processSyncResponse = function(syncToken, data) {
|
||||
var client = this.client;
|
||||
var self = this;
|
||||
|
||||
// data looks like:
|
||||
// {
|
||||
// next_batch: $token,
|
||||
// presence: { events: [] },
|
||||
// account_data: { events: [] },
|
||||
// to_device: { events: [] },
|
||||
// rooms: {
|
||||
// invite: {
|
||||
// $roomid: {
|
||||
// invite_state: { events: [] }
|
||||
// }
|
||||
// },
|
||||
// join: {
|
||||
// $roomid: {
|
||||
// state: { events: [] },
|
||||
// timeline: { events: [], prev_batch: $token, limited: true },
|
||||
// ephemeral: { events: [] },
|
||||
// account_data: { events: [] },
|
||||
// unread_notifications: {
|
||||
// highlight_count: 0,
|
||||
// notification_count: 0,
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// leave: {
|
||||
// $roomid: {
|
||||
// state: { events: [] },
|
||||
// timeline: { events: [], prev_batch: $token }
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// }
|
||||
|
||||
// TODO-arch:
|
||||
// - Each event we pass through needs to be emitted via 'event', can we
|
||||
// do this in one place?
|
||||
@@ -622,6 +625,17 @@ SyncApi.prototype._processSyncResponse = function(syncToken, data) {
|
||||
);
|
||||
}
|
||||
|
||||
// handle to-device events
|
||||
if (data.to_device && utils.isArray(data.to_device.events)) {
|
||||
data.to_device.events
|
||||
.map(client.getEventMapper())
|
||||
.forEach(
|
||||
function(toDeviceEvent) {
|
||||
client.emit("toDeviceEvent", toDeviceEvent);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// the returned json structure is a bit crap, so make it into a
|
||||
// nicer form (array) after applying sanity to make sure we don't fail
|
||||
// on missing keys (on the off chance)
|
||||
|
||||
Reference in New Issue
Block a user