1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-11-29 16:43:09 +03:00

Refactor device key upload

Use another-json instead of awful manual json building. Sign the device keys at
the point of upload, instead of having to keep the signed string in
memory. Only upload device keys once (they are correctly merged with the
one-time keys by synapse).
This commit is contained in:
Richard van der Hoff
2016-08-04 09:08:04 +01:00
parent e2d67db5d4
commit 24957a1445
4 changed files with 108 additions and 44 deletions

View File

@@ -24,6 +24,7 @@ var PushProcessor = require('./pushprocessor');
var EventEmitter = require("events").EventEmitter;
var q = require("q");
var url = require('url');
var anotherjson = require('another-json');
var httpApi = require("./http-api");
var MatrixEvent = require("./models/event").MatrixEvent;
@@ -126,31 +127,24 @@ function MatrixClient(opts) {
};
this._olmDevice = null;
this._cryptoAlgorithms = [];
if (CRYPTO_ENABLED && this.sessionStore !== null && userId !== null &&
this.deviceId !== null) {
this._olmDevice = new OlmDevice(opts.sessionStore);
this._cryptoAlgorithms.push(OLM_ALGORITHM);
var json = '{"algorithms":["' + OLM_ALGORITHM + '"]';
json += ',"device_id":"' + this.deviceId + '"';
json += ',"keys":';
json += '{"ed25519:' + this.deviceId + '":';
json += JSON.stringify(this._olmDevice.deviceEd25519Key);
json += ',"curve25519:' + this.deviceId + '":';
json += JSON.stringify(this._olmDevice.deviceCurve25519Key);
json += '}';
json += ',"user_id":' + JSON.stringify(userId);
json += '}';
var signature = this._olmDevice.sign(json);
this.deviceKeys = JSON.parse(json);
var signatures = {};
signatures[userId] = {};
signatures[userId]["ed25519:" + this.deviceId] = signature;
this.deviceKeys.signatures = signatures;
// build our device keys: these will later be uploaded
this._deviceKeys = {};
this._deviceKeys["ed25519:" + this.deviceId] =
this._olmDevice.deviceEd25519Key;
this._deviceKeys["curve25519:" + this.deviceId] =
this._olmDevice.deviceCurve25519Key;
// add our own deviceinfo to the sessionstore
var deviceInfo = {
keys: this.deviceKeys.keys,
algorithms: this.deviceKeys.algorithms,
keys: this._deviceKeys,
algorithms: this._cryptoAlgorithms,
verified: DeviceVerification.VERIFIED,
};
var myDevices = this.sessionStore.getEndToEndDevicesForUser(
@@ -160,8 +154,10 @@ function MatrixClient(opts) {
this.sessionStore.storeEndToEndDevicesForUser(
userId, myDevices
);
setupCryptoEventHandler(this);
}
this.scheduler = opts.scheduler;
if (this.scheduler) {
var self = this;
@@ -287,6 +283,9 @@ MatrixClient.prototype.retryImmediately = function() {
return this._syncApi.retryImmediately();
};
// Crypto bits
// ===========
/**
* Is end-to-end crypto enabled for this client.
* @return {boolean} True if end-to-end is enabled.
@@ -318,7 +317,7 @@ MatrixClient.prototype.getDeviceEd25519Key = function() {
*/
MatrixClient.prototype.uploadKeys = function(maxKeys, deferred) {
var self = this;
return _doKeyUpload(this).then(function(res) {
return _uploadDeviceKeys(this).then(function(res) {
var keyCount = res.one_time_key_counts.curve25519 || 0;
var maxOneTimeKeys = self._olmDevice.maxNumberOfOneTimeKeys();
var keyLimit = Math.floor(maxOneTimeKeys / 2);
@@ -332,12 +331,42 @@ MatrixClient.prototype.uploadKeys = function(maxKeys, deferred) {
}
self._olmDevice.generateOneTimeKeys(numberToGenerate);
return _doKeyUpload(self);
return _uploadOneTimeKeys(self);
});
};
// build the upload request, and return a promise which resolves to the response
function _doKeyUpload(client) {
// returns a promise which resolves to the response
function _uploadDeviceKeys(client) {
if (!client._olmDevice) {
return q.reject(new Error("End-to-end encryption disabled"));
}
var userId = client.credentials.userId;
var deviceId = client.deviceId;
var deviceKeys = {
algorithms: client._cryptoAlgorithms,
device_id: deviceId,
keys: client._deviceKeys,
user_id: userId,
signatures: {},
};
deviceKeys.signatures[userId] = {};
deviceKeys.signatures[userId]["ed25519:" + deviceId] =
client._olmDevice.sign(anotherjson.stringify(deviceKeys));
return client.uploadKeysRequest({
device_keys: deviceKeys,
}, {
// for now, we set the device id explicitly, as we may not be using the
// same one as used in login.
device_id: deviceId,
});
}
// returns a promise which resolves to the response
function _uploadOneTimeKeys(client) {
if (!client._olmDevice) {
return q.reject(new Error("End-to-end encryption disabled"));
}
@@ -350,14 +379,13 @@ function _doKeyUpload(client) {
oneTimeJson["curve25519:" + keyId] = oneTimeKeys.curve25519[keyId];
}
}
var content = {
device_keys: client.deviceKeys,
return client.uploadKeysRequest({
one_time_keys: oneTimeJson
};
var path = "/keys/upload/" + client.deviceId;
return client._http.authedRequestWithPrefix(
undefined, "POST", path, undefined, content, httpApi.PREFIX_UNSTABLE
).then(function(res) {
}, {
// for now, we set the device id explicitly, as we may not be using the
// same one as used in login.
device_id: client.deviceId,
}).then(function(res) {
client._olmDevice.markKeysAsPublished();
return res;
});
@@ -474,6 +502,10 @@ function _updateStoredDeviceKeysForUser(userId, userStore, userResult) {
deviceStore = userStore[deviceId];
if (deviceStore.keys["ed25519:" + deviceId] != signKey) {
// this should only happen if the list has been MITMed; we are
// best off sticking with the original keys.
//
// Should we warn the user about it somehow?
console.warn("Ed25519 key for device" + userId + ": " +
deviceId + " has changed");
continue;
@@ -852,6 +884,7 @@ MatrixClient.prototype.isRoomEncrypted = function(roomId) {
}
};
/**
* Get the room for the given room ID.
* This function will return a valid room for any room for which a Room event