From b6cc4ef8cf9fe447823cea18d1099f1347a61008 Mon Sep 17 00:00:00 2001 From: ansuz Date: Mon, 2 Aug 2021 17:36:51 +0530 Subject: [PATCH] test browser-dependent SharedArrayBuffer support in checkup include debugging information in final report for when browser vendors inevitably break APIs again --- www/checkup/app-checkup.less | 17 ++++++- www/checkup/checkup-tools.js | 36 +++++++++++++ www/checkup/main.js | 97 ++++++++++++++++++++++++++++++++++-- www/checkup/sandbox/main.js | 24 ++++++++- 4 files changed, 166 insertions(+), 8 deletions(-) create mode 100644 www/checkup/checkup-tools.js diff --git a/www/checkup/app-checkup.less b/www/checkup/app-checkup.less index a475d5983..df8cef8d8 100644 --- a/www/checkup/app-checkup.less +++ b/www/checkup/app-checkup.less @@ -14,11 +14,15 @@ html, body { .report { font-size: 30px; - max-width: 50%; + max-width: 26em; margin: auto; padding-top: 15px; } + .summary, .failure, .error, .success { + margin-bottom: 1em; + } + .pending { border: 1px solid @cryptpad_text_col; .fa { @@ -46,6 +50,10 @@ html, body { td { padding: 5px; border: 1px solid @cryptpad_text_col; + font-size: 60%; + } + td:nth-child(2) { + word-break: break-word; } } @@ -72,7 +80,12 @@ html, body { color: @cryptpad_color_link; } } - .cp-app-checkup-version { + + .cp-notice-browser, .cp-notice-details, .cp-notice-other { + font-size: 70%; + } + + .cp-app-checkup-version, .cp-app-checkup-browser { text-decoration: underline; } diff --git a/www/checkup/checkup-tools.js b/www/checkup/checkup-tools.js new file mode 100644 index 000000000..79fe1c4b3 --- /dev/null +++ b/www/checkup/checkup-tools.js @@ -0,0 +1,36 @@ +define([ +], function () { + var Tools = {}; + Tools.supportsSharedArrayBuffers = function () { + try { + return Object.prototype.toString.call(new window.WebAssembly.Memory({ + shared: true, + initial: 0, + maximum: 0, + }).buffer) === '[object SharedArrayBuffer]'; + } catch (err) { + console.error(err); + } + return false; + }; + + + Tools.isSafari = function () { + return navigator.vendor.match(/apple/i); + }; + + Tools.isChrome = function () { + return navigator.vendor.match(/google/i); + }; + + Tools.guessBrowser = function () { + if (Tools.isChrome()) { return 'chrome/blink'; } + if (Tools.isSafari()) { return 'safari/webkit'; } + if (navigator.userAgent.match(/firefox\//i)) { return 'firefox/gecko'; } + if (navigator.userAgent.match(/edge\//i)) { return 'edge/edgehtml'; } + if (navigator.userAgent.match(/trident\//i)) { return 'ie/trident'; } + return navigator.userAgent + "\n" + navigator.vendor; + }; + + return Tools; +}); diff --git a/www/checkup/main.js b/www/checkup/main.js index 4413d3b18..0addabaa2 100644 --- a/www/checkup/main.js +++ b/www/checkup/main.js @@ -13,13 +13,14 @@ define([ '/common/pinpad.js', '/common/outer/network-config.js', '/customize/pages.js', + '/checkup/checkup-tools.js', '/bower_components/tweetnacl/nacl-fast.min.js', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', 'less!/checkup/app-checkup.less', ], function ($, ApiConfig, Assertions, h, Messages, DomReady, nThen, SFCommonO, Login, Hash, Util, Pinpad, - NetConfig, Pages) { + NetConfig, Pages, Tools) { var Assert = Assertions(); var trimSlashes = function (s) { if (typeof(s) !== 'string') { return s; } @@ -703,6 +704,81 @@ define([ }); }); + var safariGripe = function () { + return h('p.cp-notice-other', 'This is expected because Safari and platforms that use its engine lack commonly supported functionality.'); + }; + + var chromeGripe = function () { + return h('p.cp-notice-other', "This is expected because the developers of Google chrome's engine intentionally disabled support in cross-origin contexts. We are working on an alternate solution."); + }; + + var browserIssue = function () { + return h('p.cp-notice-other', 'This test checks for the presence of features in your browser and is not necessarily caused by server misconfiguration.'); + }; + + assert(function (cb, msg) { + cb = Util.once(cb); + setWarningClass(msg); + var notice = h('span', [ + h('p', 'It appears that some features required for Office file format conversion are not present.'), + ]); + + msg.appendChild(notice); + + var expected = [ + 'Atomics', + 'SharedArrayBuffer', + 'WebAssembly', + ['WebAssembly', 'Memory'], + ['WebAssembly', 'instantiate'], + ['WebAssembly', 'instantiateStreaming'], + ['Buffer', 'from'], + + 'SharedWorker', + 'worker', + 'crossOriginIsolated', + ]; + + var responses = {}; + + nThen(function (w) { + deferredPostMessage({ + command: 'CHECK_JS_APIS', + content: { + globals: expected, + }, + }, w(function (response) { + Util.extend(responses, response); + })); + + deferredPostMessage({ + command: 'FANCY_API_CHECKS', + content: { + }, + }, w(function (response) { + Util.extend(responses, response); + })); + }).nThen(function () { + if (!responses.Atomics || !responses.WebAssembly) { + return void cb(responses); + } + if (responses.SharedArrayBuffer || responses.SharedArrayBufferFallback) { + return cb(true); + } + + if (Tools.isSafari()) { + notice.appendChild(safariGripe()); + } + if (Tools.isChrome()) { + notice.appendChild(chromeGripe()); + } + + notice.appendChild(browserIssue()); + + return void cb(response); + }); + }); + var isHTTPS = function (host) { return /^https:\/\//.test(host); }; @@ -831,7 +907,7 @@ define([ var failureReport = function (obj) { var printableValue = obj.output; try { - printableValue = JSON.stringify(obj.output); + printableValue = JSON.stringify(obj.output, null, ' '); } catch (err) { console.error(err); } @@ -840,7 +916,7 @@ define([ h('h5', obj.message), h('table', [ row(["Failed test number", obj.test + 1]), - row(["Returned value", code(printableValue)]), + row(["Returned value", h('pre', code(printableValue))]), ]), ]); }; @@ -849,7 +925,7 @@ define([ var $progress = $('#cp-progress'); var versionStatement = function () { - return h('p', [ + return h('p.cp--notice-version', [ "This instance is running ", h('span.cp-app-checkup-version',[ "CryptPad", @@ -860,6 +936,16 @@ define([ ]); }; + var browserStatement = function () { + var name = Tools.guessBrowser(); + if (!name) { return; } + return h('p.cp-notice-browser', [ + "You appear to be using a ", + h('span.cp-app-checkup-browser', name), + ' browser to view this page.', + ]); + }; + Assert.run(function (state) { var errors = state.errors; var failed = errors.length; @@ -870,10 +956,11 @@ define([ var failedDetails = "Details found below"; var successDetails = "This checkup only tests the most common configuration issues. You may still experience errors or incorrect behaviour."; - var details = h('p', failed? failedDetails: successDetails); + var details = h('p.cp-notice-details', failed? failedDetails: successDetails); var summary = h('div.summary.' + statusClass, [ versionStatement(), + browserStatement(), h('p', Messages._getKey('assert_numberOfTestsPassed', [ state.passed, state.total diff --git a/www/checkup/sandbox/main.js b/www/checkup/sandbox/main.js index e11aa1d52..272db91a4 100644 --- a/www/checkup/sandbox/main.js +++ b/www/checkup/sandbox/main.js @@ -1,10 +1,12 @@ define([ 'jquery', + '/common/common-util.js', + '/checkup/checkup-tools.js', '/bower_components/tweetnacl/nacl-fast.min.js', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', 'less!/checkup/app-checkup.less', -], function ($) { +], function ($, Util, Tools) { var postMessage = function (content) { window.parent.postMessage(JSON.stringify(content), '*'); }; @@ -26,6 +28,26 @@ define([ }); }; + COMMANDS.CHECK_JS_APIS = function (content, cb) { + var globalAPIs = content['globals'] || []; + var response = {}; + globalAPIs.forEach(function (key) { + if (Array.isArray(key)) { + response[key.join('.')] = Boolean(Util.find(window, key)); + return; + } + + response[key] = Boolean(window[key]); + }); + cb(response); + }; + + COMMANDS.FANCY_API_CHECKS = function (content, cb) { + cb({ + SharedArrayBufferFallback: Tools.supportsSharedArrayBuffers(), + }); + }; + window.addEventListener("message", function (event) { var txid, command; if (event && event.data) {