define([ 'jquery', '/api/config', '/assert/assertions.js', '/common/hyperscript.js', '/customize/messages.js', '/common/dom-ready.js', '/bower_components/nthen/index.js', '/common/sframe-common-outer.js', '/customize/login.js', '/common/common-hash.js', '/common/common-util.js', '/common/pinpad.js', '/common/outer/network-config.js', '/bower_components/tweetnacl/nacl-fast.min.js', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', 'less!/customize/src/less2/pages/page-checkup.less', ], function ($, ApiConfig, Assertions, h, Messages, DomReady, nThen, SFCommonO, Login, Hash, Util, Pinpad, NetConfig) { var assert = Assertions(); var trimSlashes = function (s) { if (typeof(s) !== 'string') { return s; } return s.replace(/\/+$/, ''); }; var _alert = function (content) { return h('span.advisory-text', content); }; var trimmedSafe = trimSlashes(ApiConfig.httpSafeOrigin); var trimmedUnsafe = trimSlashes(ApiConfig.httpUnsafeOrigin); assert(function (cb) { //console.error(trimmedSafe, trimmedUnsafe); cb(Boolean(trimmedSafe && trimmedUnsafe)); }, _alert("Sandbox configuration: ensure that both httpUnsafeOrigin and httpSafeOrigin are defined")); assert(function (cb) { return void cb(trimmedSafe !== trimmedUnsafe); }, _alert('Sandbox configuration: httpUnsafeOrigin !== httpSafeOrigin')); assert(function (cb) { cb(trimmedSafe === ApiConfig.httpSafeOrigin); }, "httpSafeOrigin must not have a trailing slash"); assert(function (cb) { var origin = window.location.origin; return void cb(ApiConfig.httpUnsafeOrigin === origin); }, _alert('Sandbox configuration: loading via httpUnsafeOrigin')); var checkAvailability = function (url, cb) { $.ajax({ url: url, data: {}, complete: function (xhr) { cb(xhr.status === 200); }, }); }; assert(function (cb) { checkAvailability(trimmedUnsafe, cb); }, _alert("Main domain is not available")); // Try loading an iframe on the safe domain assert(function (cb) { var to; nThen(function (waitFor) { DomReady.onReady(waitFor()); }).nThen(function (waitFor) { to = setTimeout(function () { console.error('TIMEOUT loading iframe on the safe domain'); cb(false); }, 5000); SFCommonO.initIframe(waitFor); }).nThen(function () { // Iframe is loaded clearTimeout(to); cb(true); }); }, _alert("Sandbox domain is not available")); // Test Websocket var evWSError = Util.mkEvent(true); assert(function (cb) { var ws = new WebSocket(NetConfig.getWebsocketURL()); var to = setTimeout(function () { console.error('Websocket TIMEOUT'); evWSError.fire(); cb('TIMEOUT (5 seconds)'); }, 5000); ws.onopen = function () { clearTimeout(to); cb(true); }; ws.onerror = function (err) { clearTimeout(to); console.error('Websocket error', err); evWSError.fire(); cb('WebSocket error: check your console'); }; }, _alert("Websocket is not available")); // Test login block assert(function (cb) { var bytes = new Uint8Array(Login.requiredBytes); var opt = Login.allocateBytes(bytes); var blockUrl = Login.Block.getBlockUrl(opt.blockKeys); var blockRequest = Login.Block.serialize("{}", opt.blockKeys); var removeRequest = Login.Block.remove(opt.blockKeys); console.log('Test block URL:', blockUrl); var userHash = '/2/drive/edit/000000000000000000000000'; var secret = Hash.getSecrets('drive', userHash); opt.keys = secret.keys; opt.channelHex = secret.channel; var RT, rpc, exists; nThen(function (waitFor) { Util.fetch(blockUrl, waitFor(function (err) { if (err) { return; } // No block found exists = true; })); }).nThen(function (waitFor) { // If WebSockets aren't working, don't wait forever here evWSError.reg(function () { waitFor.abort(); cb("No WebSocket (test number 6)"); }); // Create proxy Login.loadUserObject(opt, waitFor(function (err, rt) { if (err) { waitFor.abort(); console.error("Can't create new channel. This may also be a websocket issue."); return void cb(false); } RT = rt; var proxy = rt.proxy; proxy.edPublic = opt.edPublic; proxy.edPrivate = opt.edPrivate; proxy.curvePublic = opt.curvePublic; proxy.curvePrivate = opt.curvePrivate; rt.realtime.onSettle(waitFor()); })); }).nThen(function (waitFor) { // Init RPC Pinpad.create(RT.network, RT.proxy, waitFor(function (e, _rpc) { if (e) { waitFor.abort(); console.error("Can't initialize RPC", e); // INVALID_KEYS return void cb(false); } rpc = _rpc; })); }).nThen(function (waitFor) { // Write block if (exists) { return; } rpc.writeLoginBlock(blockRequest, waitFor(function (e) { if (e) { waitFor.abort(); console.error("Can't write login block", e); return void cb(false); } })); }).nThen(function (waitFor) { // Read block Util.fetch(blockUrl, waitFor(function (e) { if (e) { waitFor.abort(); console.error("Can't read login block", e); return void cb(false); } })); }).nThen(function (waitFor) { // Remove block rpc.removeLoginBlock(removeRequest, waitFor(function (e) { if (e) { waitFor.abort(); console.error("Can't remove login block", e); console.error(blockRequest); return void cb(false); } })); }).nThen(function (waitFor) { rpc.removeOwnedChannel(secret.channel, waitFor(function (e) { if (e) { waitFor.abort(); console.error("Can't remove channel", e); return void cb(false); } })); }).nThen(function () { cb(true); }); }, _alert("Login block is not working (write/read/remove)")); assert(function (cb) { var url = '/common/onlyoffice/v4/web-apps/apps/spreadsheeteditor/main/index.html'; var expect = { 'cross-origin-resource-policy': 'cross-origin', 'cross-origin-embedder-policy': 'require-corp', }; $.ajax(url, { success: function (data, textStatus, xhr) { cb(!Object.keys(expect).some(function (k) { var response = xhr.getResponseHeader(k); console.log(k, response); return response !== expect[k]; })); }, }); }, _alert("Missing HTTP headers required for XLSX export")); var row = function (cells) { return h('tr', cells.map(function (cell) { return h('td', cell); })); }; var failureReport = function (obj) { return h('div.error', [ h('h5', obj.message), h('table', [ row(["Failed test number", obj.test + 1]), row(["Returned value", obj.output]), ]), ]); }; var completed = 0; var $progress = $('#cp-progress'); assert.run(function (state) { var errors = state.errors; var failed = errors.length; Messages.assert_numberOfTestsPassed = "{0} / {1} tests passed."; var statusClass = failed? 'failure': 'success'; var summary = h('div.summary.' + statusClass, [ h('p', Messages._getKey('assert_numberOfTestsPassed', [ state.passed, state.total ])), h('p', "Details found below"), ]); var report = h('div.report', [ summary, h('div.failures', errors.map(failureReport)), ]); $progress.remove(); $('body').prepend(report); }, function (i, total) { console.log('test '+ i +' completed'); completed++; Messages.assert_numberOfTestsCompleted = "{0} / {1} tests completed."; $progress.html('').append(h('div.report.pending.summary', [ h('p', [ h('i.fa.fa-spinner.fa-pulse'), h('span', Messages._getKey('assert_numberOfTestsCompleted', [completed, total])) ]) ])); }); });