From 093856671aaa461f14c11b341d5dcc6e52ba8828 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Mon, 31 Oct 2022 22:29:38 +0000 Subject: [PATCH] Encode the WASM as base64 Some nasty hackery to get around the nastiness of the JS ecosystem --- bindings/matrix-sdk-crypto-js/package.json | 7 +-- .../matrix-sdk-crypto-js/scripts/build.sh | 32 +++++++++++++ bindings/matrix-sdk-crypto-js/unbase64.js | 48 +++++++++++++++++++ 3 files changed, 82 insertions(+), 5 deletions(-) create mode 100755 bindings/matrix-sdk-crypto-js/scripts/build.sh create mode 100644 bindings/matrix-sdk-crypto-js/unbase64.js diff --git a/bindings/matrix-sdk-crypto-js/package.json b/bindings/matrix-sdk-crypto-js/package.json index 70c2a428a..2d8d0a524 100644 --- a/bindings/matrix-sdk-crypto-js/package.json +++ b/bindings/matrix-sdk-crypto-js/package.json @@ -37,12 +37,9 @@ "node": ">= 10" }, "scripts": { - "build": "cross-env RUSTFLAGS='-C opt-level=z' WASM_BINDGEN_WEAKREF=1 wasm-pack build --release --target nodejs --scope matrix-org --out-dir ./pkg", + "build": "./scripts/build.sh", "test": "jest --verbose", "doc": "typedoc --tsconfig .", - "prepack": "npm run build && npm run test", - "pack": "wasm-pack pack", - "prepublish": "npm run pack", - "publish": "wasm-pack publish" + "prepack": "npm run build && npm run test" } } diff --git a/bindings/matrix-sdk-crypto-js/scripts/build.sh b/bindings/matrix-sdk-crypto-js/scripts/build.sh new file mode 100755 index 000000000..fc6c57a08 --- /dev/null +++ b/bindings/matrix-sdk-crypto-js/scripts/build.sh @@ -0,0 +1,32 @@ +#!/bin/bash +# +# Build the javascript modules +# +# This script is really a workaround for https://github.com/rustwasm/wasm-pack/issues/1074. +# +# Currently, the only reliable way to load webassembly in all the JS +# environments we want to target (web-via-webpack, web-via-browserify, jest) +# seems to be to pack the WASM into base64, and then unpack it and instantiate +# it at runtime. +# +# Hopefully one day, https://github.com/rustwasm/wasm-pack/issues/1074 will be +# fixed and this will be unnecessary. + +set -e + +RUSTFLAGS='-C opt-level=z' WASM_BINDGEN_WEAKREF=1 wasm-pack build --release --target nodejs --scope matrix-org --out-dir ./pkg + +# convert the wasm into a js file that exports the b64'ed wasm +{ + echo 'module.exports = `' + base64 pkg/matrix_sdk_crypto_js_bg.wasm + echo '`;' +} > pkg/matrix_sdk_crypto_js_bg.wasm.js + +# In the javascript: +# 1. replace the lines that load the wasm +# 2. remove the imports of TextDecoder and TextEncoder. We rely on the global defaults. +loadwasm='const bytes = require("../unbase64.js")(require("./matrix_sdk_crypto_js_bg.wasm.js"));' +sed -i -e "/^const path = /,+1 c$loadwasm" \ + -e '/= require(`util`)/d' \ + pkg/matrix_sdk_crypto_js.js diff --git a/bindings/matrix-sdk-crypto-js/unbase64.js b/bindings/matrix-sdk-crypto-js/unbase64.js new file mode 100644 index 000000000..28818efa8 --- /dev/null +++ b/bindings/matrix-sdk-crypto-js/unbase64.js @@ -0,0 +1,48 @@ +// Javascript module which exports a function which will un-base64 a string +// +// From the code at https://developer.mozilla.org/en-US/docs/Glossary/Base64#solution_2_%E2%80%93_rewriting_atob_and_btoa_using_typedarrays_and_utf-8 + +function b64ToUint6(nChr) { + return nChr > 64 && nChr < 91 + ? nChr - 65 + : nChr > 96 && nChr < 123 + ? nChr - 71 + : nChr > 47 && nChr < 58 + ? nChr + 4 + : nChr === 43 + ? 62 + : nChr === 47 + ? 63 + : 0; +} + +function base64DecToArr(sBase64, nBlocksSize) { + const sB64Enc = sBase64.replace(/[^A-Za-z0-9+/]/g, ""); + const nInLen = sB64Enc.length; + const nOutLen = nBlocksSize + ? Math.ceil(((nInLen * 3 + 1) >> 2) / nBlocksSize) * nBlocksSize + : (nInLen * 3 + 1) >> 2; + const taBytes = new Uint8Array(nOutLen); + + let nMod3; + let nMod4; + let nUint24 = 0; + let nOutIdx = 0; + for (let nInIdx = 0; nInIdx < nInLen; nInIdx++) { + nMod4 = nInIdx & 3; + nUint24 |= b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << (6 * (3 - nMod4)); + if (nMod4 === 3 || nInLen - nInIdx === 1) { + nMod3 = 0; + while (nMod3 < 3 && nOutIdx < nOutLen) { + taBytes[nOutIdx] = (nUint24 >>> ((16 >>> nMod3) & 24)) & 255; + nMod3++; + nOutIdx++; + } + nUint24 = 0; + } + } + + return taBytes; +} + +module.exports = base64DecToArr;