diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 51c04066f..580cae7e9 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -17,6 +17,7 @@ define([ '/common/outer/profile.js', '/common/outer/team.js', '/common/outer/messenger.js', + '/common/outer/history.js', '/common/outer/network-config.js', '/customize/application_config.js', @@ -28,7 +29,7 @@ define([ '/bower_components/saferphore/index.js', ], function (Sortify, UserObject, ProxyManager, Migrate, Hash, Util, Constants, Feedback, Realtime, Messaging, Pinpad, - SF, Cursor, OnlyOffice, Mailbox, Profile, Team, Messenger, + SF, Cursor, OnlyOffice, Mailbox, Profile, Team, Messenger, History, NetConfig, AppConfig, Crypto, ChainPad, CpNetflux, Listmap, nThen, Saferphore) { @@ -39,8 +40,6 @@ define([ var sendDriveEvent = function () {}; var registerProxyEvents = function () {}; - var storeHash, storeChannel; - var store = window.CryptPad_AsyncStore = { modules: {} }; @@ -149,13 +148,7 @@ define([ }; var getUserChannelList = function () { - // start with your userHash... - var userHash = storeHash; - if (!userHash) { return null; } - - // No password for drive - var secret = Hash.getSecrets('drive', userHash); - var userChannel = secret.channel; + var userChannel = store.driveChannel; if (!userChannel) { return null; } // Get the list of pads' channel ID in your drive @@ -304,7 +297,7 @@ define([ teamId = data.teamId; } - if (channel === storeChannel && !force) { + if (channel === store.driveChannel && !force) { return void cb({error: 'User drive removal blocked!'}); } @@ -703,11 +696,9 @@ define([ Store.deleteAccount = function (clientId, data, cb) { var edPublic = store.proxy.edPublic; - // No password for drive - var secret = Hash.getSecrets('drive', storeHash); Store.anonRpcMsg(clientId, { msg: 'GET_METADATA', - data: secret.channel + data: store.driveChannel }, function (data) { var metadata = data[0]; // Owned drive @@ -727,7 +718,7 @@ define([ }).nThen(function (waitFor) { // Delete Drive Store.removeOwnedChannel(clientId, { - channel: secret.channel, + channel: store.driveChannel, force: true }, waitFor()); }).nThen(function () { @@ -743,7 +734,7 @@ define([ var toSign = { intent: 'Please delete my account.' }; - toSign.drive = secret.channel; + toSign.drive = store.driveChannel; toSign.edPublic = edPublic; var signKey = Crypto.Nacl.util.decodeBase64(store.proxy.edPrivate); var proof = Crypto.Nacl.sign.detached(Crypto.Nacl.util.decodeUTF8(Sortify(toSign)), signKey); @@ -2073,6 +2064,7 @@ define([ store.mailbox.removeClient(clientId); } catch (e) { console.error(e); } Object.keys(store.modules).forEach(function (key) { + if (!store.modules[key].removeClient) { return; } try { store.modules[key].removeClient(clientId); } catch (e) { console.error(e); } @@ -2334,6 +2326,7 @@ define([ store.messenger = store.modules['messenger']; loadUniversal(Profile, 'profile', waitFor); loadUniversal(Team, 'team', waitFor); + loadUniversal(History, 'history', waitFor); cleanFriendRequests(); }).nThen(function () { var requestLogin = function () { @@ -2435,13 +2428,12 @@ define([ var connect = function (clientId, data, cb) { var hash = data.userHash || data.anonHash || Hash.createRandomHash('drive'); - storeHash = hash; if (!hash) { return void cb({error: '[Store.init] Unable to find or create a drive hash. Aborting...'}); } // No password for drive var secret = Hash.getSecrets('drive', hash); - storeChannel = secret.channel; + store.driveChannel = secret.channel; var listmapConfig = { data: {}, websocketURL: NetConfig.getWebsocketURL(), diff --git a/www/common/outer/history.js b/www/common/outer/history.js new file mode 100644 index 000000000..59b3d1021 --- /dev/null +++ b/www/common/outer/history.js @@ -0,0 +1,155 @@ +define([ + '/common/common-util.js', + '/common/common-hash.js', + '/common/userObject.js', + '/bower_components/nthen/index.js', +], function (Util, Hash, UserObject, nThen) { + var History = {}; + var commands = {}; + + var getAccountChannels = function (ctx) { + var channels = []; + var edPublic = Util.find(ctx.store, ['proxy', 'edPublic']); + + // Drive + channels.push(ctx.store.driveChannel); + + // Profile + var profile = ctx.store.proxy.profile; + if (profile) { + var profileChan = profile.edit ? Hash.hrefToHexChannelId('/profile/#' + profile.edit, null) : null; + if (profileChan) { channels.push(profileChan); } + } + + // Mailboxes + var mailboxes = ctx.store.proxy.mailboxes; + if (mailboxes) { + var mList = Object.keys(mailboxes).map(function (m) { + return { + lastKnownHash: mailboxes[m].lastKnownHash, + channel: mailboxes[m].channel + }; + }); + Array.prototype.push.apply(channels, mList); + } + + // Shared folders owned by me + var sf = ctx.store.proxy[UserObject.SHARED_FOLDERS]; + if (sf) { + console.log(sf); + var sfChannels = Object.keys(sf).map(function (fId) { + var data = sf[fId]; + if (!data || !data.owners) { return; } + var isOwner = Array.isArray(data.owners) && data.owners.indexOf(edPublic) !== -1; + if (!isOwner) { return; } + return data.channel; + }).filter(Boolean); + console.log(sfChannels); + Array.prototype.push.apply(channels, sfChannels); + } + + return channels; + }; + + commands.GET_HISTORY_SIZE = function (ctx, data, cId, cb) { + if (!ctx.store.loggedIn || !ctx.store.rpc) { return void cb({ error: 'INSUFFICIENT_PERMISSIONS' }); } + var channels = data.channels; + if (!Array.isArray(channels)) { return void cb({ error: 'EINVAL' }); } + + // If account trim history, get the correct channels here + if (data.account) { + channels = getAccountChannels(ctx); + } + + var size = 0; + var warning = false; + nThen(function (waitFor) { + // TODO: check if owner first? + channels.forEach(function (chan) { + size += Math.floor(Math.random()*1000) * 1024; // XXX + /* + var channel = chan; + var lastKnownHash; + if (typeof (chan) === "object" && chan.channel) { + channel = chan.channel; + lastKnownHash = chan.lastKnownHash; + } + ctx.store.rpc.getHistorySize({ + channel: channel, + lastKnownHash: lastKnownHash + }, waitFor(function (err, value) { + if (err) { + warning = true; + return; + } + size += value; + })); + */ // XXX TODO + }); + }).nThen(function () { + cb({ + warning: warning, + size: size + }); + }); + }; + + commands.TRIM_HISTORY = function (ctx, data, cId, cb) { + if (!ctx.store.loggedIn || !ctx.store.rpc) { return void cb({ error: 'INSUFFICIENT_PERMISSIONS' }); } + var channels = data.channels; + if (!Array.isArray(channels)) { return void cb({ error: 'EINVAL' }); } + + // If account trim history, get the correct channels here + if (data.account) { + channels = getAccountChannels(ctx); + } + + var warning = false; + nThen(function (waitFor) { + channels.forEach(function (chan) { + /* + ctx.store.rpc.trimHistory(chan, waitFor(function (err) { + if (err) { + warning = err; + return; + } + })); + */ // XXX TODO + }); + }).nThen(function () { + if (channels.length === 1 && warning) { + return void cb({error: err}); + } + cb({ warning: warning }); + }); + }; + + History.init = function (cfg, waitFor, emit) { + var history = {}; + if (!cfg.store) { return; } + var ctx = { + store: cfg.store, + Store: cfg.Store, + pinPads: cfg.pinPads, + updateMetadata: cfg.updateMetadata, + emit: emit, + }; + + history.execCommand = function (clientId, obj, cb) { + var cmd = obj.cmd; + var data = obj.data; + try { + commands[cmd](ctx, data, clientId, cb); + } catch (e) { + console.error(e); + } + }; + + return history; + }; + + return History; +}); + + +