Skip to content

Commit

Permalink
Merge pull request matrix-org#743 from matrix-org/dbkr/wasm
Browse files Browse the repository at this point in the history
Update to WebAssembly-powered Olm
  • Loading branch information
dbkr committed Oct 25, 2018
2 parents cec8936 + 59070c2 commit 870e96a
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 64 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -319,13 +319,13 @@ To provide the Olm library in a browser application:

To provide the Olm library in a node.js application:

* ``npm install https://matrix.org/packages/npm/olm/olm-2.2.2.tgz``
* ``npm install https://matrix.org/packages/npm/olm/olm-3.0.0.tgz``
(replace the URL with the latest version you want to use from
https://matrix.org/packages/npm/olm/)
* ``global.Olm = require('olm');`` *before* loading ``matrix-js-sdk``.

If you want to package Olm as dependency for your node.js application, you
can use ``npm install https://matrix.org/packages/npm/olm/olm-2.2.2.tgz
can use ``npm install https://matrix.org/packages/npm/olm/olm-3.0.0.tgz
--save-optional`` (if your application also works without e2e crypto enabled)
or ``--save`` (if it doesn't) to do so.

Expand Down
15 changes: 9 additions & 6 deletions spec/unit/crypto.spec.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@

"use strict";
import 'source-map-support/register';
import Crypto from '../../lib/crypto';
import expect from 'expect';

const sdk = require("../..");
let Crypto;
if (sdk.CRYPTO_ENABLED) {
Crypto = require("../../lib/crypto");
}

import expect from 'expect';
const Olm = global.Olm;

describe("Crypto", function() {
if (!sdk.CRYPTO_ENABLED) {
return;
}

beforeEach(function(done) {
Olm.init().then(done);
});

it("Crypto exposes the correct olm library version", function() {
expect(Crypto.getOlmVersion()[0]).toEqual(2);
expect(Crypto.getOlmVersion()[0]).toEqual(3);
});
});
17 changes: 7 additions & 10 deletions spec/unit/crypto/algorithms/megolm.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,16 @@ import WebStorageSessionStore from '../../../../lib/store/session/webstorage';
import MemoryCryptoStore from '../../../../lib/crypto/store/memory-crypto-store.js';
import MockStorageApi from '../../../MockStorageApi';
import testUtils from '../../../test-utils';

// Crypto and OlmDevice won't import unless we have global.Olm
let OlmDevice;
let Crypto;
if (global.Olm) {
OlmDevice = require('../../../../lib/crypto/OlmDevice');
Crypto = require('../../../../lib/crypto');
}
import OlmDevice from '../../../../lib/crypto/OlmDevice';
import Crypto from '../../../../lib/crypto';

const MatrixEvent = sdk.MatrixEvent;
const MegolmDecryption = algorithms.DECRYPTION_CLASSES['m.megolm.v1.aes-sha2'];

const ROOM_ID = '!ROOM:ID';

const Olm = global.Olm;

describe("MegolmDecryption", function() {
if (!global.Olm) {
console.warn('Not running megolm unit tests: libolm not present');
Expand Down Expand Up @@ -69,7 +65,8 @@ describe("MegolmDecryption", function() {

describe('receives some keys:', function() {
let groupSession;
beforeEach(function() {
beforeEach(async function() {
await Olm.init();
groupSession = new global.Olm.OutboundGroupSession();
groupSession.create();

Expand Down Expand Up @@ -98,7 +95,7 @@ describe("MegolmDecryption", function() {
},
};

return event.attemptDecryption(mockCrypto).then(() => {
await event.attemptDecryption(mockCrypto).then(() => {
megolmDecryption.onRoomKeyEvent(event);
});
});
Expand Down
35 changes: 16 additions & 19 deletions src/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,20 +45,16 @@ const ContentHelpers = require("./content-helpers");
import ReEmitter from './ReEmitter';
import RoomList from './crypto/RoomList';

import Crypto from './crypto';
import { isCryptoAvailable } from './crypto';

// Disable warnings for now: we use deprecated bluebird functions
// and need to migrate, but they spam the console with warnings.
Promise.config({warnings: false});


const SCROLLBACK_DELAY_MS = 3000;
let CRYPTO_ENABLED = false;

try {
var Crypto = require("./crypto");
CRYPTO_ENABLED = true;
} catch (e) {
console.warn("Unable to load crypto module: crypto will be disabled: " + e);
}
const CRYPTO_ENABLED = isCryptoAvailable();

/**
* Construct a Matrix Client. Only directly construct this if you want to use
Expand Down Expand Up @@ -133,6 +129,8 @@ function MatrixClient(opts) {

MatrixBaseApis.call(this, opts);

this.olmVersion = null; // Populated after initCrypto is done

this.reEmitter = new ReEmitter(this);

this.store = opts.store || new StubStore();
Expand Down Expand Up @@ -185,10 +183,6 @@ function MatrixClient(opts) {

this._forceTURN = opts.forceTURN || false;

if (CRYPTO_ENABLED) {
this.olmVersion = Crypto.getOlmVersion();
}

// List of which rooms have encryption enabled: separate from crypto because
// we still want to know which rooms are encrypted even if crypto is disabled:
// we don't want to start sending unencrypted events to them.
Expand Down Expand Up @@ -378,6 +372,13 @@ MatrixClient.prototype.setNotifTimelineSet = function(notifTimelineSet) {
* successfully initialised.
*/
MatrixClient.prototype.initCrypto = async function() {
if (!isCryptoAvailable()) {
throw new Error(
`End-to-end encryption not supported in this js-sdk build: did ` +
`you remember to load the olm library?`,
);
}

if (this._crypto) {
console.warn("Attempt to re-initialise e2e encryption on MatrixClient");
return;
Expand All @@ -395,13 +396,6 @@ MatrixClient.prototype.initCrypto = async function() {
// initialise the list of encrypted rooms (whether or not crypto is enabled)
await this._roomList.init();

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?`,
);
}

const userId = this.getUserId();
if (userId === null) {
throw new Error(
Expand Down Expand Up @@ -433,6 +427,9 @@ MatrixClient.prototype.initCrypto = async function() {

await crypto.init();

this.olmVersion = Crypto.getOlmVersion();


// if crypto initialisation was successful, tell it to attach its event
// handlers.
crypto.registerEventHandlers(this);
Expand Down
33 changes: 11 additions & 22 deletions src/crypto/OlmDevice.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,6 @@ limitations under the License.
import logger from '../logger';
import IndexedDBCryptoStore from './store/indexeddb-crypto-store';

/**
* olm.js wrapper
*
* @module crypto/OlmDevice
*/
const Olm = global.Olm;
if (!Olm) {
throw new Error("global.Olm is not defined");
}


// The maximum size of an event is 65K, and we base64 the content, so this is a
// reasonable approximation to the biggest plaintext we can encrypt.
const MAX_PLAINTEXT_LENGTH = 65536 * 3 / 4;
Expand Down Expand Up @@ -128,7 +117,7 @@ OlmDevice.prototype.init = async function() {
await this._migrateFromSessionStore();

let e2eKeys;
const account = new Olm.Account();
const account = new global.Olm.Account();
try {
await _initialiseAccount(
this._sessionStore, this._cryptoStore, this._pickleKey, account,
Expand Down Expand Up @@ -162,7 +151,7 @@ async function _initialiseAccount(sessionStore, cryptoStore, pickleKey, account)
* @return {array} The version of Olm.
*/
OlmDevice.getOlmVersion = function() {
return Olm.get_library_version();
return global.Olm.get_library_version();
};

OlmDevice.prototype._migrateFromSessionStore = async function() {
Expand Down Expand Up @@ -269,7 +258,7 @@ OlmDevice.prototype._migrateFromSessionStore = async function() {
*/
OlmDevice.prototype._getAccount = function(txn, func) {
this._cryptoStore.getAccount(txn, (pickledAccount) => {
const account = new Olm.Account();
const account = new global.Olm.Account();
try {
account.unpickle(this._pickleKey, pickledAccount);
func(account);
Expand Down Expand Up @@ -322,7 +311,7 @@ OlmDevice.prototype._getSession = function(deviceKey, sessionId, txn, func) {
* @private
*/
OlmDevice.prototype._unpickleSession = function(pickledSession, func) {
const session = new Olm.Session();
const session = new global.Olm.Session();
try {
session.unpickle(this._pickleKey, pickledSession);
func(session);
Expand Down Expand Up @@ -355,7 +344,7 @@ OlmDevice.prototype._saveSession = function(deviceKey, session, txn) {
* @private
*/
OlmDevice.prototype._getUtility = function(func) {
const utility = new Olm.Utility();
const utility = new global.Olm.Utility();
try {
return func(utility);
} finally {
Expand Down Expand Up @@ -467,7 +456,7 @@ OlmDevice.prototype.createOutboundSession = async function(
],
(txn) => {
this._getAccount(txn, (account) => {
const session = new Olm.Session();
const session = new global.Olm.Session();
try {
session.create_outbound(account, theirIdentityKey, theirOneTimeKey);
newSessionId = session.session_id();
Expand Down Expand Up @@ -511,7 +500,7 @@ OlmDevice.prototype.createInboundSession = async function(
],
(txn) => {
this._getAccount(txn, (account) => {
const session = new Olm.Session();
const session = new global.Olm.Session();
try {
session.create_inbound_from(
account, theirDeviceIdentityKey, ciphertext,
Expand Down Expand Up @@ -729,7 +718,7 @@ OlmDevice.prototype._getOutboundGroupSession = function(sessionId, func) {
throw new Error("Unknown outbound group session " + sessionId);
}

const session = new Olm.OutboundGroupSession();
const session = new global.Olm.OutboundGroupSession();
try {
session.unpickle(this._pickleKey, pickled);
return func(session);
Expand All @@ -745,7 +734,7 @@ OlmDevice.prototype._getOutboundGroupSession = function(sessionId, func) {
* @return {string} sessionId for the outbound session.
*/
OlmDevice.prototype.createOutboundGroupSession = function() {
const session = new Olm.OutboundGroupSession();
const session = new global.Olm.OutboundGroupSession();
try {
session.create();
this._saveOutboundGroupSession(session);
Expand Down Expand Up @@ -817,7 +806,7 @@ OlmDevice.prototype.getOutboundGroupSessionKey = function(sessionId) {
* @return {*} result of func
*/
OlmDevice.prototype._unpickleInboundGroupSession = function(sessionData, func) {
const session = new Olm.InboundGroupSession();
const session = new global.Olm.InboundGroupSession();
try {
session.unpickle(this._pickleKey, sessionData.session);
return func(session);
Expand Down Expand Up @@ -898,7 +887,7 @@ OlmDevice.prototype.addInboundGroupSession = async function(
}

// new session.
const session = new Olm.InboundGroupSession();
const session = new global.Olm.InboundGroupSession();
try {
if (exportFormat) {
session.import_session(sessionKey);
Expand Down
11 changes: 7 additions & 4 deletions src/crypto/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ const DeviceList = require('./DeviceList').default;
import OutgoingRoomKeyRequestManager from './OutgoingRoomKeyRequestManager';
import IndexedDBCryptoStore from './store/indexeddb-crypto-store';

export function isCryptoAvailable() {
return Boolean(global.Olm);
}

/**
* Cryptography bits
*
Expand All @@ -63,7 +67,7 @@ import IndexedDBCryptoStore from './store/indexeddb-crypto-store';
*
* @param {RoomList} roomList An initialised RoomList object
*/
function Crypto(baseApis, sessionStore, userId, deviceId,
export default function Crypto(baseApis, sessionStore, userId, deviceId,
clientStore, cryptoStore, roomList) {
this._baseApis = baseApis;
this._sessionStore = sessionStore;
Expand Down Expand Up @@ -125,6 +129,8 @@ utils.inherits(Crypto, EventEmitter);
* Returns a promise which resolves once the crypto module is ready for use.
*/
Crypto.prototype.init = async function() {
await global.Olm.init();

const sessionStoreHasAccount = Boolean(this._sessionStore.getEndToEndAccount());
let cryptoStoreHasAccount;
await this._cryptoStore.doTxn(
Expand Down Expand Up @@ -1519,6 +1525,3 @@ class IncomingRoomKeyRequestCancellation {
* @event module:client~MatrixClient#"crypto.warning"
* @param {string} type One of the strings listed above
*/

/** */
module.exports = Crypto;
2 changes: 1 addition & 1 deletion travis.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ set -ex
npm run lint

# install Olm so that we can run the crypto tests.
npm install https://matrix.org/packages/npm/olm/olm-2.2.2.tgz
npm install https://matrix.org/packages/npm/olm/olm-3.0.0.tgz

npm run test

Expand Down

0 comments on commit 870e96a

Please sign in to comment.