diff --git a/package.json b/package.json index 12106cf67..be837efb2 100644 --- a/package.json +++ b/package.json @@ -146,7 +146,7 @@ "webpack-dev-server": "^3.1.9" }, "optionalDependencies": { - "olm": "https://matrix.org/packages/npm/olm/olm-2.2.1.tgz" + "olm": "https://matrix.org/packages/npm/olm/olm-3.0.0.tgz" }, "build": { "appId": "im.riot.app", diff --git a/scripts/copy-res.js b/scripts/copy-res.js index 70a06411d..ff8ee4586 100755 --- a/scripts/copy-res.js +++ b/scripts/copy-res.js @@ -57,6 +57,11 @@ const COPY_LIST = [ ["res/themes/**", "webapp/themes"], ["node_modules/emojione/assets/svg/*", "webapp/emojione/svg/"], ["node_modules/emojione/assets/png/*", "webapp/emojione/png/"], + // XXX: This is tied quite heavily to the matching olm.js so it really should be + // in the bundle dir with the js to avoid caching issues giving us wasm that + // doesn't match our js, but I cannot find any way to get webpack to do this. + ["node_modules/olm/olm.wasm", "webapp", { directwatch: 1 }], + ["node_modules/olm/olm_legacy.js", "webapp", { directwatch: 1 }], ["./config.json", "webapp", { directwatch: 1 }], ]; diff --git a/src/vector/index.js b/src/vector/index.js index 1d47491e4..ee419eef6 100644 --- a/src/vector/index.js +++ b/src/vector/index.js @@ -54,6 +54,8 @@ import SettingsStore, {SettingLevel} from "matrix-react-sdk/lib/settings/Setting import Tinter from 'matrix-react-sdk/lib/Tinter'; import SdkConfig from "matrix-react-sdk/lib/SdkConfig"; +import Olm from 'olm'; + import rageshake from "matrix-react-sdk/lib/rageshake/rageshake"; import CallHandler from 'matrix-react-sdk/lib/CallHandler'; @@ -229,6 +231,8 @@ async function loadApp() { window.addEventListener('hashchange', onHashChange); + await loadOlm(); + await loadLanguage(); const fragparts = parseQsFromFragment(window.location); @@ -362,6 +366,42 @@ async function loadApp() { } } +function loadOlm() { + /* Load Olm. We try the WebAssembly version first, and then the legacy, + * asm.js version if that fails. For this reason we need to wait for this + * to finish before continuing to load the rest of the app. In future + * we could somehow pass a promise down to react-sdk and have it wait on + * that so olm can be loading in parallel with the rest of the app. + * + * We also need to tell the Olm js to look for its wasm file at the same + * level as index.html. It really should be in the same place as the js, + * ie. in the bundle directory, to avoid caching issues, but as far as I + * can tell this is completely impossible with webpack. + */ + return Olm.init({ + locateFile: () => 'olm.wasm', + }).then(() => { + console.log("Using WebAssembly Olm"); + }).catch((e) => { + console.log("Failed to load Olm: trying legacy version"); + return new Promise((resolve, reject) => { + const s = document.createElement('script'); + s.src = 'olm_legacy.js'; + s.onload = resolve; + s.onerror = reject; + document.body.appendChild(s); + }).then(() => { + // Init window.Olm, ie. the one just loaded by the script tag, + // not 'Olm' which is still the failed wasm version. + return window.Olm.init(); + }).then(() => { + console.log("Using legacy Olm"); + }).catch((e) => { + console.log("Both WebAssembly and asm.js Olm failed!", e); + }); + }); +} + async function loadLanguage() { const prefLang = SettingsStore.getValue("language", null, /*excludeDefault=*/true); let langs = []; diff --git a/src/vector/olm-loader.js b/src/vector/olm-loader.js deleted file mode 100644 index a62d05b40..000000000 --- a/src/vector/olm-loader.js +++ /dev/null @@ -1,41 +0,0 @@ -/* -Copyright 2016 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -/* a very thin shim for loading olm.js: just sets the global OLM_OPTIONS and - * requires the actual olm.js library. - * - * olm.js reads global.OLM_OPTIONS and defines global.Olm. The latter is fine for us, - * but we need to prepare the former. - * - * We can't use webpack's definePlugin to do this, because we tell webpack not - * to parse olm.js. We also can't put this code in index.js, because olm and - * index.js are loaded in parallel, and we need to make sure OLM_OPTIONS is set - * before olm.js is loaded. - */ - -/* total_memory must be a power of two, and at least twice the stack. - * - * We don't need a lot of stack, but we do need about 128K of heap to encrypt a - * 64K event (enough to store the ciphertext and the plaintext, bearing in mind - * that the plaintext can only be 48K because base64). We also have about 36K - * of statics. So let's have 256K of memory. - */ -global.OLM_OPTIONS = { - TOTAL_STACK: 64*1024, - TOTAL_MEMORY: 256*1024, -}; - -require('olm/olm.js'); diff --git a/webpack.config.js b/webpack.config.js index 8f7b2ea7b..f335aa3c1 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -15,15 +15,6 @@ module.exports = { "mobileguide": "./src/vector/mobile_guide/index.js", - // We ship olm.js as a separate lump of javascript. This makes it get - // loaded via a separate