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
Add MatrixClient.initCrypto
initialising the crypto layer needs to become asynchronous. Rather than making `sdk.createClient` asynchronous, which would break every single app in the world, add `initCrypto`, which will only break those attempting to do e2e (and in a way which will fall back to only supporting unencrypted events).
This commit is contained in:
16
README.md
16
README.md
@@ -245,21 +245,27 @@ The SDK supports end-to-end encryption via the Olm and Megolm protocols, using
|
||||
[libolm](http://matrix.org/git/olm). It is left up to the application to make
|
||||
libolm available, via the ``Olm`` global.
|
||||
|
||||
If the ``Olm`` global is not available, the SDK will show a warning:
|
||||
It is also necessry to call ``matrixClient.initCrypto()`` after creating a new
|
||||
``MatrixClient`` (but **before** calling ``matrixClient.startClient()``) to
|
||||
initialise the crypto layer.
|
||||
|
||||
If the ``Olm`` global is not available, the SDK will show a warning, as shown
|
||||
below; ``initCrypto()`` will also fail.
|
||||
|
||||
```
|
||||
Unable to load crypto module: crypto will be disabled: Error: global.Olm is not defined
|
||||
```
|
||||
|
||||
The SDK will continue to work for unencrypted rooms, but it will not support
|
||||
the E2E parts of the Matrix specification.
|
||||
If the crypto layer is not (successfully) initialised, the SDK will continue to
|
||||
work for unencrypted rooms, but it will not support the E2E parts of the Matrix
|
||||
specification.
|
||||
|
||||
To enable E2E support in a browser application:
|
||||
To provide the Olm library in a browser application:
|
||||
|
||||
* download the transpiled libolm (from https://matrix.org/packages/npm/olm/).
|
||||
* load ``olm.js`` as a ``<script>`` *before* ``browser-matrix.js``.
|
||||
|
||||
To enable E2E support in a node.js application:
|
||||
To provide the Olm library in a node.js application:
|
||||
|
||||
* ``npm install https://matrix.org/packages/npm/olm/olm-2.2.2.tgz``
|
||||
(replace the URL with the latest version you want to use from
|
||||
|
||||
@@ -388,11 +388,14 @@ describe("MatrixClient crypto", function() {
|
||||
return;
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(async function() {
|
||||
testUtils.beforeEach(this); // eslint-disable-line no-invalid-this
|
||||
|
||||
aliTestClient = new TestClient(aliUserId, aliDeviceId, aliAccessToken);
|
||||
await aliTestClient.client.initCrypto();
|
||||
|
||||
bobTestClient = new TestClient(bobUserId, bobDeviceId, bobAccessToken);
|
||||
await bobTestClient.client.initCrypto();
|
||||
|
||||
aliMessages = [];
|
||||
bobMessages = [];
|
||||
|
||||
@@ -305,6 +305,10 @@ describe("MatrixClient", function() {
|
||||
return;
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
return client.initCrypto();
|
||||
});
|
||||
|
||||
it("should do an HTTP request and then store the keys", function(done) {
|
||||
const ed25519key = "7wG2lzAqbjcyEkOP7O4gU7ItYcn+chKzh5sT/5r2l78";
|
||||
// ed25519key = client.getDeviceEd25519Key();
|
||||
|
||||
@@ -280,12 +280,13 @@ describe("megolm", function() {
|
||||
return claimResponse;
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(async function() {
|
||||
testUtils.beforeEach(this); // eslint-disable-line no-invalid-this
|
||||
|
||||
aliceTestClient = new TestClient(
|
||||
"@alice:localhost", "xzcvb", "akjgkrgjs",
|
||||
);
|
||||
await aliceTestClient.client.initCrypto();
|
||||
|
||||
testOlmAccount = new Olm.Account();
|
||||
testOlmAccount.create();
|
||||
@@ -1079,10 +1080,10 @@ describe("megolm", function() {
|
||||
aliceTestClient = new TestClient(
|
||||
"@alice:localhost", "device2", "access_token2",
|
||||
);
|
||||
|
||||
return aliceTestClient.client.initCrypto().then(() => {
|
||||
aliceTestClient.client.importRoomKeys(exported);
|
||||
|
||||
return aliceTestClient.start();
|
||||
});
|
||||
}).then(function() {
|
||||
const syncResponse = {
|
||||
next_batch: 1,
|
||||
|
||||
@@ -161,21 +161,9 @@ function MatrixClient(opts) {
|
||||
|
||||
this._crypto = null;
|
||||
this._cryptoStore = opts.cryptoStore;
|
||||
if (CRYPTO_ENABLED && Boolean(opts.sessionStore) &&
|
||||
Boolean(this._cryptoStore) &&
|
||||
userId !== null && this.deviceId !== null) {
|
||||
this._crypto = new Crypto(
|
||||
this, this,
|
||||
opts.sessionStore,
|
||||
userId, this.deviceId,
|
||||
this.store,
|
||||
opts.cryptoStore,
|
||||
);
|
||||
reEmit(this, this._crypto, [
|
||||
"crypto.roomKeyRequest",
|
||||
"crypto.roomKeyRequestCancellation",
|
||||
]);
|
||||
this._sessionStore = opts.sessionStore;
|
||||
|
||||
if (CRYPTO_ENABLED) {
|
||||
this.olmVersion = Crypto.getOlmVersion();
|
||||
}
|
||||
}
|
||||
@@ -323,6 +311,72 @@ MatrixClient.prototype.setNotifTimelineSet = function(notifTimelineSet) {
|
||||
// Crypto bits
|
||||
// ===========
|
||||
|
||||
/**
|
||||
* Initialise support for end-to-end encryption in this client
|
||||
*
|
||||
* You should call this method after creating the matrixclient, but *before*
|
||||
* calling `startClient`, if you want to support end-to-end encryption.
|
||||
*
|
||||
* It will return a Promise which will resolve when the crypto layer has been
|
||||
* successfully initialised.
|
||||
*/
|
||||
MatrixClient.prototype.initCrypto = async function() {
|
||||
if (this._crypto) {
|
||||
console.warn("Attempt to re-initialise e2e encryption on MatrixClient");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CRYPTO_ENABLED) {
|
||||
throw new Error(
|
||||
`End-to-end encryption not supported in this js-sdk build: did ` +
|
||||
`you remember to load the olm library?`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!this._sessionStore) {
|
||||
// this is temporary, the sessionstore is supposed to be going away
|
||||
throw new Error(`Cannot enable encryption: no sessionStore provided`);
|
||||
}
|
||||
if (!this._cryptoStore) {
|
||||
// the cryptostore is provided by sdk.createClient, so this shouldn't happen
|
||||
throw new Error(`Cannot enable encryption: no cryptoStore provided`);
|
||||
}
|
||||
|
||||
const userId = this.getUserId();
|
||||
if (userId === null) {
|
||||
throw new Error(
|
||||
`Cannot enable encryption on MatrixClient with unknown userId: ` +
|
||||
`ensure userId is passed in createClient().`,
|
||||
);
|
||||
}
|
||||
if (this.deviceId === null) {
|
||||
throw new Error(
|
||||
`Cannot enable encryption on MatrixClient with unknown deviceId: ` +
|
||||
`ensure deviceId is passed in createClient().`,
|
||||
);
|
||||
}
|
||||
|
||||
const crypto = new Crypto(
|
||||
this,
|
||||
this._sessionStore,
|
||||
userId, this.deviceId,
|
||||
this.store,
|
||||
this._cryptoStore,
|
||||
);
|
||||
|
||||
reEmit(this, crypto, [
|
||||
"crypto.roomKeyRequest",
|
||||
"crypto.roomKeyRequestCancellation",
|
||||
]);
|
||||
|
||||
await crypto.init();
|
||||
|
||||
// if crypto initialisation was sucessful, tell it to attach its event handlers.
|
||||
crypto.registerEventHandlers(this);
|
||||
this._crypto = crypto;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Is end-to-end crypto enabled for this client.
|
||||
* @return {boolean} True if end-to-end is enabled.
|
||||
|
||||
@@ -37,13 +37,14 @@ import OutgoingRoomKeyRequestManager from './OutgoingRoomKeyRequestManager';
|
||||
/**
|
||||
* Cryptography bits
|
||||
*
|
||||
* This module is internal to the js-sdk; the public API is via MatrixClient.
|
||||
*
|
||||
* @constructor
|
||||
* @alias module:crypto
|
||||
*
|
||||
* @param {module:base-apis~MatrixBaseApis} baseApis base matrix api interface
|
||||
* @internal
|
||||
*
|
||||
* @param {external:EventEmitter} eventEmitter event source where we can register
|
||||
* for event notifications
|
||||
* @param {module:base-apis~MatrixBaseApis} baseApis base matrix api interface
|
||||
*
|
||||
* @param {module:store/session/webstorage~WebStorageSessionStore} sessionStore
|
||||
* Store to be used for end-to-end crypto session data
|
||||
@@ -57,7 +58,7 @@ import OutgoingRoomKeyRequestManager from './OutgoingRoomKeyRequestManager';
|
||||
* @param {module:crypto/store/base~CryptoStore} cryptoStore
|
||||
* storage for the crypto layer.
|
||||
*/
|
||||
function Crypto(baseApis, eventEmitter, sessionStore, userId, deviceId,
|
||||
function Crypto(baseApis, sessionStore, userId, deviceId,
|
||||
clientStore, cryptoStore) {
|
||||
this._baseApis = baseApis;
|
||||
this._sessionStore = sessionStore;
|
||||
@@ -85,8 +86,9 @@ function Crypto(baseApis, eventEmitter, sessionStore, userId, deviceId,
|
||||
algorithms.DECRYPTION_CLASSES,
|
||||
);
|
||||
|
||||
// build our device keys: these will later be uploaded
|
||||
this._deviceKeys = {};
|
||||
|
||||
// build our device keys: these will later be uploaded
|
||||
this._deviceKeys["ed25519:" + this._deviceId] =
|
||||
this._olmDevice.deviceEd25519Key;
|
||||
this._deviceKeys["curve25519:" + this._deviceId] =
|
||||
@@ -125,13 +127,24 @@ function Crypto(baseApis, eventEmitter, sessionStore, userId, deviceId,
|
||||
this._userId, myDevices,
|
||||
);
|
||||
}
|
||||
|
||||
_registerEventHandlers(this, eventEmitter);
|
||||
}
|
||||
utils.inherits(Crypto, EventEmitter);
|
||||
|
||||
/**
|
||||
* Initialise the crypto module so that it is ready for use
|
||||
*/
|
||||
Crypto.prototype.init = async function() {
|
||||
};
|
||||
|
||||
function _registerEventHandlers(crypto, eventEmitter) {
|
||||
/**
|
||||
* Tell the crypto module to register for MatrixClient events which it needs to
|
||||
* listen for
|
||||
*
|
||||
* @param {external:EventEmitter} eventEmitter event source where we can register
|
||||
* for event notifications
|
||||
*/
|
||||
Crypto.prototype.registerEventHandlers = function(eventEmitter) {
|
||||
const crypto = this;
|
||||
eventEmitter.on("sync", function(syncState, oldState, data) {
|
||||
try {
|
||||
if (syncState === "SYNCING") {
|
||||
@@ -173,7 +186,8 @@ function _registerEventHandlers(crypto, eventEmitter) {
|
||||
console.error("Error handling crypto event:", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Start background processes related to crypto */
|
||||
Crypto.prototype.start = function() {
|
||||
|
||||
Reference in New Issue
Block a user