diff --git a/lib/metadata.js b/lib/metadata.js index fb8628410..63ab31819 100644 --- a/lib/metadata.js +++ b/lib/metadata.js @@ -55,6 +55,13 @@ commands.RM_OWNERS = function (meta, args) { args.forEach(function (owner) { var index = meta.owners.indexOf(owner); if (index < 0) { return; } + if (meta.mailbox) { + if (typeof(meta.mailbox) === "string") { + delete meta.mailbox; + } else { + delete meta.mailbox[owner]; + } + } meta.owners.splice(index, 1); changed = true; }); @@ -131,6 +138,40 @@ commands.RESET_OWNERS = function (meta, args) { return true; }; +// ["ADD_MAILBOX", {"7eEqelGso3EBr5jHlei6av4r9w2B9XZiGGwA1EgZ-5I=": mailbox, ...}, 1561623439989] +commands.ADD_MAILBOX = function (meta, args) { + // expect a new array, even if it's empty + if (!args || typeof(args) !== "object") { + throw new Error('METADATA_INVALID_MAILBOX'); + } + // assume there are owners to start + if (!Array.isArray(meta.owners)) { + throw new Error("METADATA_NONSENSE_OWNERS"); + } + + var changed = false; + + // For each mailbox we try to add, check if the associated edPublic is an owner + // If they are, add or replace the mailbox + Object.keys(args).forEach(function (edPublic) { + if (meta.owners.indexOf(edPublic) === -1) { return; } + + if (typeof(meta.mailbox) === "string") { + var str = meta.mailbox; + meta.mailbox = {}; + meta.mailbox[meta.owners[0]] = str; + } + + // Make sure mailbox is defined + if (!meta.mailbox) { meta.mailbox = {}; } + + meta.mailbox[edPublic] = args[edPublic]; + changed = true; + }); + + return changed; +}; + commands.UPDATE_EXPIRATION = function () { throw new Error("E_NOT_IMPLEMENTED"); }; diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 3683f567a..293931a60 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -98,8 +98,8 @@ define([ var user = common.getMetadataMgr().getUserData(); var edPublic = priv.edPublic; var channel = data.channel; - var owners = data.owners; - var pending_owners = data.pending_owners; + var owners = data.owners || []; + var pending_owners = data.pending_owners || []; var redrawAll = function () {}; @@ -316,22 +316,21 @@ define([ return $div2; }; - var pending = false; - redrawAll = function () { - if (pending) { return; } - pending = true; - common.getPadMetadata({ - channel: data.channel - }, function (obj) { - pending = false; + redrawAll = function (md) { + var todo = function (obj) { if (obj && obj.error) { return; } - owners = obj.owners; - pending_owners = obj.pending_owners; + owners = obj.owners || []; + pending_owners = obj.pending_owners || []; $div1.empty(); $div2.empty(); $div1.append(drawRemove(false)).append(drawRemove(true)); $div2.append(drawAdd()); - }); + }; + + if (md) { return void todo(md); } + common.getPadMetadata({ + channel: data.channel + }, todo); }; $div1.append(drawRemove(false)).append(drawRemove(true)); @@ -341,9 +340,9 @@ define([ if (!$div1.length) { return void handler.stop(); } - owners = md.owners; - pending_owners = md.pending_owners; - redrawAll(); + owners = md.owners || []; + pending_owners = md.pending_owners || []; + redrawAll(md); }); // Create modal @@ -3394,6 +3393,8 @@ define([ data.metadata = res; // Add the pad to your drive + // This command will also add your mailbox to the metadata log + // The callback is called when the pad is stored, independantly of the metadata command sframeChan.query('Q_ACCEPT_OWNERSHIP', data, function (err, res) { if (err || (res && res.error)) { return void console.error(err | res.error); diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index ba6a7d481..3c13e0e8e 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -489,6 +489,28 @@ define([ Cryptpad.setPadTitle(_data, function (err) { cb({error: err}); }); + + // Also add your mailbox to the metadata object + var padParsed = Utils.Hash.parsePadUrl(data.href); + var padSecret = Utils.Hash.getSecrets(padParsed.type, padParsed.hash, data.password); + var padCrypto = Utils.Crypto.createEncryptor(padSecret.keys); + try { + var value = {}; + value[edPublic] = padCrypto.encrypt(JSON.stringify({ + notifications: notifications, + curvePublic: curvePublic + })); + var msg = { + channel: data.channel, + command: 'ADD_MAILBOX', + value: value + }; + Cryptpad.setPadMetadata(msg, function (res) { + if (res.error) { console.error(res.error); } + }); + } catch (err) { + return void console.error(err); + } }); sframeChan.on('Q_IMPORT_MEDIATAG', function (obj, cb) { @@ -1001,9 +1023,17 @@ define([ }, waitFor(function (obj) { obj = obj || {}; if (obj.error) { return; } - if (obj.mailbox) { + var mailbox; + // Get the first available mailbox (the field can be an string or an object) + // TODO maybe we should send the request to all the owners? + if (typeof (obj.mailbox) === "string") { + mailbox = obj.mailbox; + } else if (obj.mailbox && obj.owners && obj.owners.length) { + mailbox = obj.mailbox[obj.owners[0]]; + } + if (mailbox) { try { - var dataStr = crypto.decrypt(obj.mailbox, true, true); + var dataStr = crypto.decrypt(mailbox, true, true); var data = JSON.parse(dataStr); if (!data.notifications || !data.curvePublic) { return; } owner = data; @@ -1156,7 +1186,8 @@ define([ }; if (data.owned) { rtConfig.metadata.owners = [edPublic]; - rtConfig.metadata.mailbox = Utils.crypto.encrypt(JSON.stringify({ + rtConfig.metadata.mailbox = {}; + rtConfig.metadata.mailbox[edPublic] = Utils.crypto.encrypt(JSON.stringify({ notifications: notifications, curvePublic: curvePublic }));