From b9f5a0f52bd0261bb10a6920b0c60a16d6e91877 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 31 May 2018 18:22:16 +0200 Subject: [PATCH] Move async store in a webworker! --- www/common/common-messaging.js | 18 ++-- www/common/cryptpad-common.js | 137 +++++++++++++++++++++++++++--- www/common/outer/async-store.js | 8 +- www/common/outer/store-rpc.js | 76 ++++++++++++++++- www/common/sframe-common-outer.js | 3 + 5 files changed, 215 insertions(+), 27 deletions(-) diff --git a/www/common/common-messaging.js b/www/common/common-messaging.js index b5a12da0b..1c75927fc 100644 --- a/www/common/common-messaging.js +++ b/www/common/common-messaging.js @@ -89,7 +89,7 @@ define([ }; /* Used to accept friend requests within apps other than /contacts/ */ - Msg.addDirectMessageHandler = function (cfg) { + Msg.addDirectMessageHandler = function (cfg, href) { var network = cfg.network; var proxy = cfg.proxy; if (!network) { return void console.error('Network not ready'); } @@ -97,13 +97,12 @@ define([ var msg; if (sender === network.historyKeeper) { return; } try { - var parsed = Hash.parsePadUrl(window.location.href); + var parsed = Hash.parsePadUrl(href); + var secret = Hash.getSecrets(parsed.type, parsed.hash); if (!parsed.hashData) { return; } - var chan = Hash.hrefToHexChannelId(window.location.href); + var chan = secret.channel; // Decrypt - var keyStr = parsed.hashData.key; - var cryptor = Crypto.createEditCryptor(keyStr); - var key = cryptor.cryptKey; + var key = secret.keys ? secret.keys.cryptKey : Hash.decodeBase64(secret.key); var decryptMsg; try { decryptMsg = Crypto.decrypt(message, key); @@ -197,15 +196,14 @@ define([ var network = cfg.network; var netfluxId = data.netfluxId; var parsed = Hash.parsePadUrl(data.href); + var secret = Hash.getSecrets(parsed.type, parsed.hash); if (!parsed.hashData) { return; } // Message - var chan = Hash.hrefToHexChannelId(data.href); + var chan = secret.channel; var myData = createData(cfg.proxy); var msg = ["FRIEND_REQ", chan, myData]; // Encryption - var keyStr = parsed.hashData.key; - var cryptor = Crypto.createEditCryptor(keyStr); - var key = cryptor.cryptKey; + var key = secret.keys ? secret.keys.cryptKey : Hash.decodeBase64(secret.key); var msgStr = Crypto.encrypt(JSON.stringify(msg), key); // Send encrypted message if (pendingRequests.indexOf(netfluxId) === -1) { diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index f91f050e8..77707860c 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -7,12 +7,13 @@ define([ '/common/common-constants.js', '/common/common-feedback.js', '/common/outer/local-store.js', - '/common/outer/store-rpc.js', + //'/common/outer/store-rpc.js', + '/common/outer/worker-channel.js', '/customize/application_config.js', '/bower_components/nthen/index.js', ], function (Config, Messages, Util, Hash, - Messaging, Constants, Feedback, LocalStore, AStore, + Messaging, Constants, Feedback, LocalStore, /*AStore, */Channel, AppConfig, Nthen) { @@ -22,10 +23,11 @@ define([ Additionally, there is some basic functionality for import/export. */ - var postMessage = function (cmd, data, cb) { - setTimeout(function () { + var postMessage = function (/*cmd, data, cb*/) { + /*setTimeout(function () { AStore.query(cmd, data, cb); - }); + });*/ + console.error('NOT_READY'); }; var tryParsing = function (x) { try { return JSON.parse(x); } @@ -510,6 +512,11 @@ define([ var messaging = common.messaging = {}; messaging.onFriendRequest = Util.mkEvent(); messaging.onFriendComplete = Util.mkEvent(); + messaging.addHandlers = function (href) { + postMessage("ADD_DIRECT_MESSAGE_HANDLERS", { + href: href + }); + }; // Messenger var messenger = common.messenger = {}; @@ -641,14 +648,58 @@ define([ window.location.href = '/login/'; }; - common.startAccountDeletion = function (cb) { + common.startAccountDeletion = function (data, cb) { // Logout other tabs LocalStore.logout(null, true); cb(); }; + var queries = { + REQUEST_LOGIN: requestLogin, + UPDATE_METADATA: common.changeMetadata, + UPDATE_TOKEN: function (data) { + var localToken = tryParsing(localStorage.getItem(Constants.tokenKey)); + if (localToken !== data.token) { requestLogin(); } + }, + // Messaging + Q_FRIEND_REQUEST: common.messaging.onFriendRequest.fire, + EV_FIREND_COMPLETE: common.messaging.onFriendComplete.fire, + // Network + NETWORK_DISCONNECT: common.onNetworkDisconnect.fire, + NETWORK_RECONNECT: common.onNetworkReconnect.fire, + // Messenger + CONTACTS_MESSAGE: common.messenger.onMessageEvent.fire, + CONTACTS_JOIN: common.messenger.onJoinEvent.fire, + CONTACTS_LEAVE: common.messenger.onLeaveEvent.fire, + CONTACTS_UPDATE: common.messenger.onUpdateEvent.fire, + CONTACTS_FRIEND: common.messenger.onFriendEvent.fire, + CONTACTS_UNFRIEND: common.messenger.onUnfriendEvent.fire, + // Pad + PAD_READY: common.padRpc.onReadyEvent.fire, + PAD_MESSAGE: common.padRpc.onMessageEvent.fire, + PAD_JOIN: common.padRpc.onJoinEvent.fire, + PAD_LEAVE: common.padRpc.onLeaveEvent.fire, + PAD_DISCONNECT: common.padRpc.onDisconnectEvent.fire, + PAD_ERROR: common.padRpc.onErrorEvent.fire, + // Drive + DRIVE_LOG: common.drive.onLog.fire, + DRIVE_CHANGE: common.drive.onChange.fire, + DRIVE_REMOVE: common.drive.onRemove.fire, + // Account deletion + DELETE_ACCOUNT: common.startAccountDeletion, + // Loading + LOADING_DRIVE: common.loading.onDriveEvent.fire + }; + + /* var onMessage = function (cmd, data, cb) { cb = cb || function () {}; + if (queries[cmd]) { + return void queries[cmd](data, cb); + } else { + console.error("Unhandled command " + cmd); + } + /* switch (cmd) { case 'REQUEST_LOGIN': { requestLogin(); @@ -735,7 +786,7 @@ define([ common.loading.onDriveEvent.fire(data); break; } } - }; + };*/ common.ready = (function () { var env = {}; @@ -792,7 +843,8 @@ define([ } }).nThen(function (waitFor) { var cfg = { - query: onMessage, // TODO temporary, will be replaced by a webworker channel + init: true, + //query: onMessage, // TODO temporary, will be replaced by a webworker channel userHash: LocalStore.getUserHash(), anonHash: LocalStore.getFSHash(), localToken: tryParsing(localStorage.getItem(Constants.tokenKey)), @@ -804,7 +856,7 @@ define([ cfg.initialPath = sessionStorage[Constants.newPadPathKey]; delete sessionStorage[Constants.newPadPathKey]; } - AStore.query("CONNECT", cfg, waitFor(function (data) { + /*AStore.query("CONNECT", cfg, waitFor(function (data) { if (data.error) { throw new Error(data.error); } if (data.state === 'ALREADY_INIT') { data = data.returned; @@ -812,11 +864,11 @@ define([ if (data.anonHash && !cfg.userHash) { LocalStore.setFSHash(data.anonHash); } - /*if (cfg.userHash && sessionStorage) { + / *if (cfg.userHash && sessionStorage) { // copy User_hash into sessionStorage because cross-domain iframes // on safari replaces localStorage with sessionStorage or something sessionStorage.setItem(Constants.userHashKey, cfg.userHash); - }*/ + }* / if (cfg.userHash) { var localToken = tryParsing(localStorage.getItem(Constants.tokenKey)); @@ -828,7 +880,68 @@ define([ initFeedback(data.feedback); initialized = true; - })); + }));*/ + + var msgEv = Util.mkEvent(); + var worker = new Worker('/common/outer/webworker.js'); + worker.onmessage = function (ev) { + msgEv.fire(ev); + }; + var postMsg = function (data) { + worker.postMessage(data); + }; + Channel.create(msgEv, postMsg, waitFor(function (chan) { + console.log('outer ready'); + Object.keys(queries).forEach(function (q) { + chan.on(q, function (data, cb) { + try { + queries[q](data, cb); + } catch (e) { + console.error("Error in outer when executing query " + q); + console.error(e); + console.log(data); + } + }); + }); + + postMessage = function (cmd, data, cb) { + /*setTimeout(function () { + AStore.query(cmd, data, cb); + });*/ + chan.query(cmd, data, function (err, data) { + if (err) { return void cb ({error: err}); } + cb(data); + }); + }; + + postMessage('CONNECT', cfg, waitFor(function (data) { + if (data.error) { throw new Error(data.error); } + if (data.state === 'ALREADY_INIT') { + data = data.returned; + } + + if (data.anonHash && !cfg.userHash) { LocalStore.setFSHash(data.anonHash); } + + /*if (cfg.userHash && sessionStorage) { + // copy User_hash into sessionStorage because cross-domain iframes + // on safari replaces localStorage with sessionStorage or something + sessionStorage.setItem(Constants.userHashKey, cfg.userHash); + }*/ + + if (cfg.userHash) { + var localToken = tryParsing(localStorage.getItem(Constants.tokenKey)); + if (localToken === null) { + // if that number hasn't been set to localStorage, do so. + localStorage.setItem(Constants.tokenKey, data[Constants.tokenKey]); + } + } + + initFeedback(data.feedback); + initialized = true; + })); + + }), false); + }).nThen(function (waitFor) { // Load the new pad when the hash has changed var oldHref = document.location.href; diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 680712f17..664ad56af 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -828,6 +828,10 @@ define([ var messagingCfg = getMessagingCfg(); Messaging.inviteFromUserlist(messagingCfg, data, cb); }; + Store.addDirectMessageHandlers = function (data) { + var messagingCfg = getMessagingCfg(); + Messaging.addDirectMessageHandler(messagingCfg, data.href); + }; // Messenger @@ -976,7 +980,6 @@ define([ channel.sendMessage(data, cb); }; - // TODO // GET_FULL_HISTORY from sframe-common-outer Store.getFullHistory = function (data, cb) { var network = store.network; @@ -1233,9 +1236,6 @@ define([ callback(ret); - var messagingCfg = getMessagingCfg(); - Messaging.addDirectMessageHandler(messagingCfg); - // Send events whenever there is a change or a removal in the drive if (data.driveEvents) { store.proxy.on('change', [], function (o, n, p) { diff --git a/www/common/outer/store-rpc.js b/www/common/outer/store-rpc.js index b134435b2..94a6eee85 100644 --- a/www/common/outer/store-rpc.js +++ b/www/common/outer/store-rpc.js @@ -3,7 +3,81 @@ define([ ], function (Store) { var Rpc = {}; + var queries = Rpc.queries = { + // Ready + CONNECT: Store.init, + DISCONNECT: Store.disconnect, + CREATE_README: Store.createReadme, + MIGRATE_ANON_DRIVE: Store.migrateAnonDrive, + // RPC + INIT_RPC: Store.initRpc, + UPDATE_PIN_LIMIT: Store.updatePinLimit, + GET_PIN_LIMIT: Store.getPinLimit, + CLEAR_OWNED_CHANNEL: Store.clearOwnedChannel, + REMOVE_OWNED_CHANNEL: Store.removeOwnedChannel, + UPLOAD_CHUNK: Store.uploadChunk, + UPLOAD_COMPLETE: Store.uploadComplete, + UPLOAD_STATUS: Store.uploadStatus, + UPLOAD_CANCEL: Store.uploadCancel, + PIN_PADS: Store.pinPads, + UNPIN_PADS: Store.unpinPads, + GET_DELETED_PADS: Store.getDeletedPads, + GET_PINNED_USAGE: Store.getPinnedUsage, + // ANON RPC + INIT_ANON_RPC: Store.initAnonRpc, + ANON_RPC_MESSAGE: Store.anonRpcMsg, + GET_FILE_SIZE: Store.getFileSize, + GET_MULTIPLE_FILE_SIZE: Store.getMultipleFileSize, + // Store + GET: Store.get, + SET: Store.set, + ADD_PAD: Store.addPad, + SET_PAD_TITLE: Store.setPadTitle, + MOVE_TO_TRASH: Store.moveToTrash, + RESET_DRIVE: Store.resetDrive, + GET_METADATA: Store.getMetadata, + SET_DISPLAY_NAME: Store.setDisplayName, + SET_PAD_ATTRIBUTE: Store.setPadAttribute, + GET_PAD_ATTRIBUTE: Store.getPadAttribute, + SET_ATTRIBUTE: Store.setAttribute, + GET_ATTRIBUTE: Store.getAttribute, + LIST_ALL_TAGS: Store.listAllTags, + GET_TEMPLATES: Store.getTemplates, + GET_SECURE_FILES_LIST: Store.getSecureFilesList, + GET_PAD_DATA: Store.getPadData, + GET_STRONGER_HASH: Store.getStrongerHash, + INCREMENT_TEMPLATE_USE: Store.incrementTemplateUse, + // Messaging + INVITE_FROM_USERLIST: Store.inviteFromUserlist, + ADD_DIRECT_MESSAGE_HANDLERS: Store.addDirectMessageHandlers, + // Messenger + CONTACTS_GET_FRIEND_LIST: Store.messenger.getFriendList, + CONTACTS_GET_MY_INFO: Store.messenger.getMyInfo, + CONTACTS_GET_FRIEND_INFO: Store.messenger.getFriendInfo, + CONTACTS_REMOVE_FRIEND: Store.messenger.removeFriend, + CONTACTS_OPEN_FRIEND_CHANNEL: Store.messenger.openFriendChannel, + CONTACTS_GET_FRIEND_STATUS: Store.messenger.getFriendStatus, + CONTACTS_GET_MORE_HISTORY: Store.messenger.getMoreHistory, + CONTACTS_SEND_MESSAGE: Store.messenger.sendMessage, + CONTACTS_SET_CHANNEL_HEAD: Store.messenger.setChannelHead, + // Pad + SEND_PAD_MSG: Store.sendPadMsg, + JOIN_PAD: Store.joinPad, + GET_FULL_HISTORY: Store.getFullHistory, + IS_NEW_CHANNEL: Store.isNewChannel, + // Drive + DRIVE_USEROBJECT: Store.userObjectCommand, + // Settings, + DELETE_ACCOUNT: Store.deleteAccount, + }; + Rpc.query = function (cmd, data, cb) { + if (queries[cmd]) { + queries[cmd](data, cb); + } else { + console.error('UNHANDLED_STORE_RPC'); + } + /* switch (cmd) { // READY case 'CONNECT': { @@ -184,7 +258,7 @@ define([ break; } - } + }*/ }; diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index c78bf53f9..60bc142a8 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -699,6 +699,9 @@ define([ readOnly: readOnly, crypto: Crypto.createEncryptor(secret.keys), onConnect: function () { + var href = parsed.getUrl(); + // Add friends requests handlers when we have the final href + Cryptpad.messaging.addHandlers(href); if (window.location.hash && window.location.hash !== '#') { window.location = parsed.getUrl({ present: parsed.hashData.present,