From 7222d34dc0da29a6ffc59a2e3da044c644e6b6fc Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 5 Sep 2019 13:56:47 +0200 Subject: [PATCH] Refactor async-store to make it work with teams --- www/auth/main.js | 2 +- www/common/cryptpad-common.js | 17 ++-- www/common/outer/async-store.js | 129 +++++++++++++++++++------------ www/common/outer/sharedfolder.js | 18 +++-- www/common/outer/team.js | 16 +++- www/common/proxy-manager.js | 2 +- www/drive/main.js | 6 +- www/settings/main.js | 6 +- www/team/main.js | 14 +++- 9 files changed, 138 insertions(+), 72 deletions(-) diff --git a/www/auth/main.js b/www/auth/main.js index c8a5e9ff9..7930e96e0 100644 --- a/www/auth/main.js +++ b/www/auth/main.js @@ -77,7 +77,7 @@ define([ nThen(function (waitFor) { Cryptpad.ready(waitFor()); }).nThen(function (waitFor) { - Cryptpad.getUserObject(waitFor(function (obj) { + Cryptpad.getUserObject(null, waitFor(function (obj) { proxy = obj; })); }).nThen(function () { diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index f8c3f1545..6e2530d62 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -91,13 +91,16 @@ define([ }); }; // Settings and drive and auth - common.getUserObject = function (cb) { - postMessage("GET", [], function (obj) { + common.getUserObject = function (teamId, cb) { + postMessage("GET", { + teamId: teamId, + key: [] + }, function (obj) { cb(obj); }); }; - common.getSharedFolder = function (id, cb) { - postMessage("GET_SHARED_FOLDER", id, function (obj) { + common.getSharedFolder = function (data, cb) { + postMessage("GET_SHARED_FOLDER", data, function (obj) { cb(obj); }); }; @@ -137,6 +140,7 @@ define([ return; } postMessage("SET", { + teamId: data.teamId, key:['drive'], value: data.drive }, function (obj) { @@ -163,7 +167,7 @@ define([ common.drive.onRemove = Util.mkEvent(); // Profile common.getProfileEditUrl = function (cb) { - postMessage("GET", ['profile', 'edit'], function (obj) { + postMessage("GET", { key: ['profile', 'edit'] }, function (obj) { cb(obj); }); }; @@ -184,7 +188,7 @@ define([ }; // Todo common.getTodoHash = function (cb) { - postMessage("GET", ['todo'], function (obj) { + postMessage("GET", { key: ['todo'] }, function (obj) { cb(obj); }); }; @@ -1038,6 +1042,7 @@ define([ if (!oldIsOwned) { console.error('deprecating old drive.'); postMessage("SET", { + teamId: data.teamId, key: [Constants.deprecatedKey], value: true }, waitFor(function (obj) { diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 1904ba9cd..7ab65449a 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -43,70 +43,88 @@ define([ modules: {} }; - var getProxy = function (teamId) { - if (!teamId) { return store.proxy; } + var getStore = function (teamId) { + if (!teamId) { return store; } try { var teams = store.modules['team']; var team = teams.getTeam(teamId); - if (team) { return; } - return team.proxy; + if (!team) { + console.error('Team not found', teamId); + return; + } + return team; } catch (e) { console.error(e); + console.error('Team not found', teamId); return; } }; + var getProxy = function (teamId) { + var s = getStore(teamId); + if (!s) { return; } + return s.proxy; + }; var getManager = function (teamId) { - if (!teamId) { return store.manager; } - try { - var teams = store.modules['team']; - var team = teams.getTeam(teamId); - if (team) { return; } - return team.manager; - } catch (e) { - console.error(e); - return; - } + var s = getStore(teamId); + if (!s) { return; } + return s.manager; }; - var onSync = function (cb) { + // XXX search for all calls + var onSync = function (teamId, cb) { + var s = getStore(teamId); + if (!s) { return void cb({ error: 'ENOTFOUND' }); } nThen(function (waitFor) { - Realtime.whenRealtimeSyncs(store.realtime, waitFor()); - if (store.sharedFolders) { - for (var k in store.sharedFolders) { - Realtime.whenRealtimeSyncs(store.sharedFolders[k].realtime, waitFor()); + Realtime.whenRealtimeSyncs(s.realtime, waitFor()); + if (s.sharedFolders) { + for (var k in s.sharedFolders) { + Realtime.whenRealtimeSyncs(s.sharedFolders[k].realtime, waitFor()); } } }).nThen(function () { cb(); }); }; - Store.get = function (clientId, key, cb) { - cb(Util.find(store.proxy, key)); + // OKTEAM + Store.get = function (clientId, data, cb) { + var s = getStore(data.teamId); + if (!s) { return void cb({ error: 'ENOTFOUND' }); } + cb(Util.find(s.proxy, data.key)); }; Store.set = function (clientId, data, cb) { + var s = getStore(data.teamId); + if (!s) { return void cb({ error: 'ENOTFOUND' }); } var path = data.key.slice(); var key = path.pop(); - var obj = Util.find(store.proxy, path); + var obj = Util.find(s.proxy, path); if (!obj || typeof(obj) !== "object") { return void cb({error: 'INVALID_PATH'}); } if (typeof data.value === "undefined") { delete obj[key]; } else { obj[key] = data.value; } + if (!data.teamId) { broadcast([clientId], "UPDATE_METADATA"); - if (Array.isArray(path) && path[0] === 'profile' && store.messenger) { - Messaging.updateMyData(store); + if (Array.isArray(path) && path[0] === 'profile' && store.messenger) { + Messaging.updateMyData(store); + } } - onSync(cb); + onSync(data.teamId, cb); }; - Store.getSharedFolder = function (clientId, id, cb) { - if (store.manager.folders[id]) { - return void cb(store.manager.folders[id].proxy); + Store.getSharedFolder = function (clientId, data, cb) { + var s = getStore(data.teamId); + var id = data.id; + if (!s || !s.manager) { return void cb({ error: 'ENOTFOUND' }); } + if (s.manager.folders[id]) { + // If it is loaded, return the shared folder proxy + return void cb(s.manager.folders[id].proxy); } else { - var shared = Util.find(store.proxy, ['drive', UserObject.SHARED_FOLDERS]) || {}; + // Otherwise, check if we know this shared folder + var shared = Util.find(s.proxy, ['drive', UserObject.SHARED_FOLDERS]) || {}; if (shared[id]) { - return void Store.loadSharedFolder(id, shared[id], function () { - cb(store.manager.folders[id].proxy); + // If we know the shared folder, load it and return the proxy + return void Store.loadSharedFolder(data.teamId, id, shared[id], function () { + cb(s.manager.folders[id].proxy); }); } } @@ -115,30 +133,34 @@ define([ Store.restoreSharedFolder = function (clientId, data, cb) { if (!data.sfId || !data.drive) { return void cb({error:'EINVAL'}); } - if (store.sharedFolders[data.sfId]) { + var s = getStore(data.teamId); + if (s.sharedFolders[data.sfId]) { Object.keys(data.drive).forEach(function (k) { - store.sharedFolders[data.sfId].proxy[k] = data.drive[k]; + s.sharedFolders[data.sfId].proxy[k] = data.drive[k]; }); - Object.keys(store.sharedFolders[data.sfId].proxy).forEach(function (k) { + Object.keys(s.sharedFolders[data.sfId].proxy).forEach(function (k) { if (data.drive[k]) { return; } - delete store.sharedFolders[data.sfId].proxy[k]; + delete s.sharedFolders[data.sfId].proxy[k]; }); } - onSync(cb); + onSync(data.teamId, cb); }; + // XXX Teams Store.hasSigningKeys = function () { if (!store.proxy) { return; } return typeof(store.proxy.edPrivate) === 'string' && typeof(store.proxy.edPublic) === 'string'; }; + // XXX Teams Store.hasCurveKeys = function () { if (!store.proxy) { return; } return typeof(store.proxy.curvePrivate) === 'string' && typeof(store.proxy.curvePublic) === 'string'; }; + // XXX TODO Implement same behavior in team.js var getUserChannelList = function () { // start with your userHash... var userHash = storeHash; @@ -181,10 +203,12 @@ define([ return list; }; + // XXX TODO Implement same behavior in team.js var getExpirableChannelList = function () { return store.manager.getChannelsList('expirable'); }; + // XXX TODO Implement same behavior in team.js var getCanonicalChannelList = function (expirable) { var list = expirable ? getExpirableChannelList() : getUserChannelList(); return Util.deduplicateString(list).sort(); @@ -194,6 +218,7 @@ define([ /////////////////////// RPC ////////////////////////////////////// ////////////////////////////////////////////////////////////////// + // XXX Teams pin in teams Store.pinPads = function (clientId, data, cb) { if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); } if (typeof(cb) !== 'function') { @@ -206,6 +231,7 @@ define([ }); }; + // XXX Teams ... Store.unpinPads = function (clientId, data, cb) { if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); } @@ -1529,24 +1555,29 @@ define([ }; // SHARED FOLDERS - var handleSharedFolder = function (id, rt) { - store.sharedFolders[id] = rt; - if (store.driveEvents) { - registerProxyEvents(rt.proxy, id); - } + var addSharedFolderHandler = function () { + store.sharedFolders = {}; + store.handleSharedFolder = function (id, rt) { + store.sharedFolders[id] = rt; + if (store.driveEvents) { + registerProxyEvents(rt.proxy, id); + } + }; }; - var loadSharedFolder = Store.loadSharedFolder = function (id, data, cb) { + Store.loadSharedFolder = function (teamId, id, data, cb) { + var s = getStore(teamId); + if (!s) { return void cb({ error: 'ENOTFOUND' }); } var rt = SF.load({ network: store.network, - manager: store.manager + store: s }, id, data, cb); - handleSharedFolder(id, rt); return rt; }; + var loadSharedFolder = function (id, data, cb) { + Store.loadSharedFolder(null, id, data, cb); + }; Store.loadSharedFolderAnon = function (clientId, data, cb) { - loadSharedFolder(data.id, data.data, function () { - cb(); - }); + Store.loadSharedFolder(null, data.id, data.data, cb); }; Store.addSharedFolder = function (clientId, data, cb) { store.manager.addSharedFolder(data, function (id) { @@ -1827,6 +1858,8 @@ define([ } }); var userObject = store.userObject = manager.user.userObject; + addSharedFolderHandler(); + nThen(function (waitFor) { postMessage(clientId, 'LOADING_DRIVE', { state: 2 @@ -1848,7 +1881,7 @@ define([ state: 3 }); userObject.fixFiles(); - SF.loadSharedFolders(store.proxy, userObject, handleSharedFolder, waitFor); + SF.loadSharedFolders(Store, store.network, store, userObject, waitFor); loadMessenger(); loadCursor(); loadOnlyOffice(); diff --git a/www/common/outer/sharedfolder.js b/www/common/outer/sharedfolder.js index 8f1f9ab49..a628cc74e 100644 --- a/www/common/outer/sharedfolder.js +++ b/www/common/outer/sharedfolder.js @@ -18,7 +18,9 @@ define([ */ SF.load = function (config, id, data, cb) { var network = config.network; - var manager = config.manager; + var store = config.store; + var manager = store.manager; + var handler = store.handleSharedFolder; var parsed = Hash.parsePadUrl(data.href); var secret = Hash.getSecrets('drive', parsed.hash, data.password); @@ -43,18 +45,18 @@ define([ manager.addProxy(id, rt.proxy, info.leave); cb(rt, info.metadata); }); + if (handler) { handler(id, rt); } return rt; }; /* loadSharedFolders load all shared folder stored in a given drive - - proxy: user or team main proxy + - store: user or team main store - userObject: userObject associated to the main drive - handler: a function (sfid, rt) called for each shared folder loaded */ - SF.loadSharedFolders = function (proxy, userObject, handler, waitFor) { - store.sharedFolders = {}; - var shared = Util.find(proxy, ['drive', UserObject.SHARED_FOLDERS]) || {}; + SF.loadSharedFolders = function (Store, network, store, userObject, waitFor) { + var shared = Util.find(store.proxy, ['drive', UserObject.SHARED_FOLDERS]) || {}; // Check if any of our shared folder is expired or deleted by its owner. // If we don't check now, Listmap will create an empty proxy if it no longer exists on // the server. @@ -81,8 +83,10 @@ define([ }).nThen(function (waitFor) { Object.keys(shared).forEach(function (id) { var sf = shared[id]; - var rt = loadSharedFolder(id, sf, waitFor()); - handler(id, rt); + var rt = SF.load({ + network: network, + store: store + }, id, sf, waitFor()); }); }).nThen(waitFor()); }; diff --git a/www/common/outer/team.js b/www/common/outer/team.js index bc49f8a3e..fa04ed30b 100644 --- a/www/common/outer/team.js +++ b/www/common/outer/team.js @@ -19,6 +19,15 @@ define([ cb(); }; + var handleSharedFolder = function (ctx, id, sfId, rt) { + var t = ctx.teams[id]; + if (!t) { return; } + t.sharedFolders[sfId] = rt; + // XXX register events + // rt.proxy.on('change',... emit change event + // TODO: pin or unpin document added to a shared folder from someone who is not a member of the team + }; + var onready = function (ctx, team, id, cb) { // XXX // load manager @@ -49,8 +58,13 @@ define([ ctx.teams[id] = { proxy: lm.proxy, listmap: lm, - clients: [] + clients: [], + manager: undefined, // XXX + realtime: lm.realtime, + handleSharedFolder: function (sfId, rt) { handleSharedFolder(ctx, id, sfId, rt); }, + sharedFolders: {} // equivalent of store.sharedFolders in async-store }; + onReady(ctx, team, id, function () { // TODO }); diff --git a/www/common/proxy-manager.js b/www/common/proxy-manager.js index 474fb09a1..e15517f52 100644 --- a/www/common/proxy-manager.js +++ b/www/common/proxy-manager.js @@ -937,7 +937,7 @@ define([ // Manager addProxy: callWithEnv(addProxy), removeProxy: callWithEnv(removeProxy), - addSharedFolder: callWithEnv(addSharedFolder); + addSharedFolder: callWithEnv(_addSharedFolder), // Drive command: callWithEnv(onCommand), getPadAttribute: callWithEnv(getPadAttribute), diff --git a/www/drive/main.js b/www/drive/main.js index 907be7451..38e111883 100644 --- a/www/drive/main.js +++ b/www/drive/main.js @@ -71,12 +71,14 @@ define([ }); sframeChan.on('Q_DRIVE_GETOBJECT', function (data, cb) { if (data && data.sharedFolder) { - Cryptpad.getSharedFolder(data.sharedFolder, function (obj) { + Cryptpad.getSharedFolder({ + id: data.sharedFolder + }, function (obj) { cb(obj); }); return; } - Cryptpad.getUserObject(function (obj) { + Cryptpad.getUserObject(null, function (obj) { cb(obj); }); }); diff --git a/www/settings/main.js b/www/settings/main.js index ef7d4ab9b..bbc0f87d3 100644 --- a/www/settings/main.js +++ b/www/settings/main.js @@ -43,7 +43,7 @@ define([ }); }); sframeChan.on('Q_SETTINGS_DRIVE_GET', function (d, cb) { - Cryptpad.getUserObject(function (obj) { + Cryptpad.getUserObject(null, function (obj) { if (obj.error) { return void cb(obj); } if (d === "full") { // We want shared folders too @@ -54,7 +54,9 @@ define([ if (!obj.drive || !obj.drive.sharedFolders) { return void cb(result); } Utils.nThen(function (waitFor) { Object.keys(obj.drive.sharedFolders).forEach(function (id) { - Cryptpad.getSharedFolder(id, waitFor(function (obj) { + Cryptpad.getSharedFolder({ + id: id + }, waitFor(function (obj) { result.sf[id] = obj; })); }); diff --git a/www/team/main.js b/www/team/main.js index cc84660a3..42e561812 100644 --- a/www/team/main.js +++ b/www/team/main.js @@ -36,6 +36,7 @@ define([ }; window.addEventListener('message', onMsg); }).nThen(function (/*waitFor*/) { + var teamId; // XXX var afterSecrets = function (Cryptpad, Utils, secret, cb) { var hash = window.location.hash.slice(1); if (hash && Utils.LocalStore.isLoggedIn()) { @@ -66,17 +67,22 @@ define([ sframeChan.on('Q_DRIVE_USEROBJECT', function (data, cb) { Cryptpad.userObjectCommand(data, cb); }); - sframeChan.on('Q_DRIVE_RESTORE', function (data, cb) { + // XXX no drive restore in teams? you could restore old keys... + /*sframeChan.on('Q_DRIVE_RESTORE', function (data, cb) { + data.teamId = teamId; Cryptpad.restoreDrive(data, cb); - }); + });*/ sframeChan.on('Q_DRIVE_GETOBJECT', function (data, cb) { if (data && data.sharedFolder) { - Cryptpad.getSharedFolder(data.sharedFolder, function (obj) { + Cryptpad.getSharedFolder({ + teamId: teamId, + id: data.sharedFolder + }, function (obj) { cb(obj); }); return; } - Cryptpad.getUserObject(function (obj) { + Cryptpad.getUserObject(teamId, function (obj) { cb(obj); }); });