You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-11-28 05:03:59 +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
|
extraParams: opts.queryParams
|
||||||
};
|
};
|
||||||
this._http = new httpApi.MatrixHttpApi(this, httpOpts);
|
this._http = new httpApi.MatrixHttpApi(this, httpOpts);
|
||||||
}
|
|
||||||
|
|
||||||
|
this._txnCtr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the Homeserver URL of this client
|
* Get the Homeserver URL of this client
|
||||||
@@ -100,6 +101,15 @@ MatrixBaseApis.prototype.isLoggedIn = function() {
|
|||||||
return this._http.opts.accessToken !== undefined;
|
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
|
// 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
|
* MatrixBaseApis object
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -144,7 +144,6 @@ function MatrixClient(opts) {
|
|||||||
this._peekSync = null;
|
this._peekSync = null;
|
||||||
this._isGuest = false;
|
this._isGuest = false;
|
||||||
this._ongoingScrollbacks = {};
|
this._ongoingScrollbacks = {};
|
||||||
this._txnCtr = 0;
|
|
||||||
this.timelineSupport = Boolean(opts.timelineSupport);
|
this.timelineSupport = Boolean(opts.timelineSupport);
|
||||||
this.urlPreviewCache = {};
|
this.urlPreviewCache = {};
|
||||||
|
|
||||||
@@ -424,6 +423,12 @@ function setupCryptoEventHandler(client) {
|
|||||||
});
|
});
|
||||||
client.on("RoomMember.membership",
|
client.on("RoomMember.membership",
|
||||||
client._crypto.onRoomMembership.bind(client._crypto));
|
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) {
|
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.
|
* Enable end-to-end encryption for a room.
|
||||||
* @param {string} roomId The room ID to enable encryption in.
|
* @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 (utils.isFunction(txnId)) { callback = txnId; txnId = undefined; }
|
||||||
|
|
||||||
if (!txnId) {
|
if (!txnId) {
|
||||||
txnId = "m" + new Date().getTime() + "." + (this._txnCtr++);
|
txnId = this.makeTxnId();
|
||||||
}
|
}
|
||||||
|
|
||||||
// we always construct a MatrixEvent when sending because the store and
|
// we always construct a MatrixEvent when sending because the store and
|
||||||
@@ -921,11 +912,13 @@ function _updatePendingEventStatus(room, event, newStatus) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _sendEventHttpRequest(client, event) {
|
function _sendEventHttpRequest(client, event) {
|
||||||
|
var txnId = event._txnId ? event._txnId : client.makeTxnId();
|
||||||
|
|
||||||
var pathParams = {
|
var pathParams = {
|
||||||
$roomId: event.getRoomId(),
|
$roomId: event.getRoomId(),
|
||||||
$eventType: event.getWireType(),
|
$eventType: event.getWireType(),
|
||||||
$stateKey: event.getStateKey(),
|
$stateKey: event.getStateKey(),
|
||||||
$txnId: event._txnId ? event._txnId : new Date().getTime()
|
$txnId: txnId,
|
||||||
};
|
};
|
||||||
|
|
||||||
var path;
|
var path;
|
||||||
@@ -2663,13 +2656,6 @@ function _PojoToMatrixEventMapper(client) {
|
|||||||
clearData = _decryptMessage(client, plainOldJsObject);
|
clearData = _decryptMessage(client, plainOldJsObject);
|
||||||
}
|
}
|
||||||
var matrixEvent = new MatrixEvent(plainOldJsObject, clearData);
|
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 matrixEvent;
|
||||||
}
|
}
|
||||||
return mapper;
|
return mapper;
|
||||||
|
|||||||
@@ -96,17 +96,15 @@ MegolmEncryption.prototype._ensureOutboundSession = function(room) {
|
|||||||
).then(function(res) {
|
).then(function(res) {
|
||||||
return self._crypto.ensureOlmSessionsForUsers(roomMembers);
|
return self._crypto.ensureOlmSessionsForUsers(roomMembers);
|
||||||
}).then(function(devicemap) {
|
}).then(function(devicemap) {
|
||||||
// TODO: send OOB messages. for now, send an in-band message. Each
|
var contentMap = {};
|
||||||
// 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 participantKeys = [];
|
|
||||||
for (var userId in devicemap) {
|
for (var userId in devicemap) {
|
||||||
if (!devicemap.hasOwnProperty(userId)) {
|
if (!devicemap.hasOwnProperty(userId)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
contentMap[userId] = {};
|
||||||
|
|
||||||
var devices = devicemap[userId];
|
var devices = devicemap[userId];
|
||||||
|
|
||||||
for (var deviceId in devices) {
|
for (var deviceId in devices) {
|
||||||
@@ -115,29 +113,18 @@ MegolmEncryption.prototype._ensureOutboundSession = function(room) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var deviceInfo = devices[deviceId].device;
|
var deviceInfo = devices[deviceId].device;
|
||||||
participantKeys.push(deviceInfo.getIdentityKey());
|
contentMap[userId][deviceId] =
|
||||||
}
|
olmlib.encryptMessageForDevices(
|
||||||
}
|
|
||||||
|
|
||||||
var encryptedContent = olmlib.encryptMessageForDevices(
|
|
||||||
self._deviceId,
|
self._deviceId,
|
||||||
self._olmDevice,
|
self._olmDevice,
|
||||||
participantKeys,
|
[deviceInfo.getIdentityKey()],
|
||||||
payload
|
payload
|
||||||
);
|
);
|
||||||
|
|
||||||
var txnId = '' + (new Date().getTime());
|
|
||||||
var path = utils.encodeUri(
|
|
||||||
"/rooms/$roomId/send/m.room.encrypted/$txnId", {
|
|
||||||
$roomId: self._roomId,
|
|
||||||
$txnId: txnId,
|
|
||||||
}
|
}
|
||||||
);
|
}
|
||||||
|
|
||||||
// TODO: retries
|
// TODO: retries
|
||||||
return self._baseApis._http.authedRequest(
|
return self._baseApis.sendToDevice("m.room.encrypted", contentMap);
|
||||||
undefined, "PUT", path, undefined, encryptedContent
|
|
||||||
);
|
|
||||||
}).then(function() {
|
}).then(function() {
|
||||||
if (self._discardNewSession) {
|
if (self._discardNewSession) {
|
||||||
// we've had cause to reset the session_id since starting this process.
|
// 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) {
|
this._currentSyncRequest.done(function(data) {
|
||||||
self._syncConnectionLost = false;
|
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
|
// 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
|
// 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 client = this.client;
|
||||||
var self = this;
|
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:
|
// TODO-arch:
|
||||||
// - Each event we pass through needs to be emitted via 'event', can we
|
// - Each event we pass through needs to be emitted via 'event', can we
|
||||||
// do this in one place?
|
// 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
|
// 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
|
// nicer form (array) after applying sanity to make sure we don't fail
|
||||||
// on missing keys (on the off chance)
|
// on missing keys (on the off chance)
|
||||||
|
|||||||
Reference in New Issue
Block a user