From bb0365622b9c776974098b33308b1ef24e47d051 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 9 Sep 2019 14:13:27 +0200 Subject: [PATCH] re-encrypt the mailbox field when changing a pad password --- www/common/cryptpad-common.js | 66 +++++++++++++++++++++++-------- www/common/outer/mailbox.js | 7 +++- www/common/sframe-common-outer.js | 4 +- 3 files changed, 58 insertions(+), 19 deletions(-) diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 0c4ccb3a3..7941163ab 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -779,7 +779,7 @@ define([ }); }; - common.changePadPassword = function (Crypt, href, newPassword, edPublic, cb) { + common.changePadPassword = function (Crypt, Crypto, href, newPassword, edPublic, cb) { if (!href) { return void cb({ error: 'EINVAL_HREF' }); } var parsed = Hash.parsePadUrl(href); if (!parsed.hash) { return void cb({ error: 'EINVAL_HREF' }); } @@ -787,6 +787,8 @@ define([ var warning = false; var newHash, newRoHref; var oldChannel; + var oldSecret; + var oldMetadata; var newSecret; if (parsed.hashData.version >= 2) { @@ -803,27 +805,61 @@ define([ var optsGet = {}; var optsPut = { - password: newPassword + password: newPassword, + metadata: {} }; + + Nthen(function (waitFor) { if (parsed.hashData && parsed.hashData.password) { common.getPadAttribute('password', waitFor(function (err, password) { optsGet.password = password; }), href); } - common.getPadAttribute('owners', waitFor(function (err, owners) { - if (!Array.isArray(owners) || owners.indexOf(edPublic) === -1) { - // We're not an owner, we shouldn't be able to change the password! - waitFor.abort(); - return void cb({ error: 'EPERM' }); + }).nThen(function (waitFor) { + oldSecret = Hash.getSecrets(parsed.type, parsed.hash, optsGet.password); + oldChannel = oldSecret.channel; + common.getPadMetadata({channel: oldChannel}, waitFor(function (metadata) { + oldMetadata = metadata; + })); + }).nThen(function (waitFor) { + // Get owners, mailbox and expiration time + + var owners = oldMetadata.owners; + if (!Array.isArray(owners) || owners.indexOf(edPublic) === -1) { + // We're not an owner, we shouldn't be able to change the password! + waitFor.abort(); + return void cb({ error: 'EPERM' }); + } + optsPut.metadata.owners = owners; + + var mailbox = oldMetadata.mailbox; + if (mailbox) { + // Create the encryptors to be able to decrypt and re-encrypt the mailboxes + var oldCrypto = Crypto.createEncryptor(oldSecret.keys); + var newCrypto = Crypto.createEncryptor(newSecret.keys); + + var m; + if (typeof(mailbox) === "string") { + try { + m = newCrypto.encrypt(oldCrypto.decrypt(mailbox, true, true)); + } catch (e) {} + } else if (mailbox && typeof(mailbox) == "object") { + m = {}; + Object.keys(mailbox).forEach(function (ed) { + console.log(mailbox[ed]); + try { + m[ed] = newCrypto.encrypt(oldCrypto.decrypt(mailbox[ed], true, true)); + } catch (e) { + console.error(e); + } + }); } - optsPut.owners = owners; - }), href); - // XXX get the mailbox fields, decrypt all the mailboxes, reencrypt them, and put them in the metadata - // XXX also use optsPut.metadata (and fix it in cryptget) instead of optsPut.owners - common.getPadAttribute('expire', waitFor(function (err, expire) { - optsPut.expire = (expire - (+new Date())) / 1000; // Lifetime in seconds - }), href); + optsPut.metadata.mailbox = m; + } + + var expire = oldMetadata.expire; + optsPut.metadata.expire = (expire - (+new Date())) / 1000; // Lifetime in seconds }).nThen(function (waitFor) { Crypt.get(parsed.hash, waitFor(function (err, val) { if (err) { @@ -838,8 +874,6 @@ define([ }), optsPut); }), optsGet); }).nThen(function (waitFor) { - var secret = Hash.getSecrets(parsed.type, parsed.hash, optsGet.password); - oldChannel = secret.channel; pad.leavePad({ channel: oldChannel }, waitFor()); diff --git a/www/common/outer/mailbox.js b/www/common/outer/mailbox.js index 30c03c1b9..ac88b616e 100644 --- a/www/common/outer/mailbox.js +++ b/www/common/outer/mailbox.js @@ -77,7 +77,12 @@ proxy.mailboxes = { }; // Send a message to someone else - var sendTo = Mailbox.sendTo = function (ctx, type, msg, user, cb) { + var sendTo = Mailbox.sendTo = function (ctx, type, msg, user, _cb) { + var cb = _cb || function (obj) { + if (obj && obj.error) { + console.error(obj.error); + } + }; if (!Crypto.Mailbox) { return void cb({error: "chainpad-crypto is outdated and doesn't support mailboxes."}); } diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 71282114b..a8bc62bd0 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -911,7 +911,7 @@ define([ sframeChan.on('Q_PAD_PASSWORD_CHANGE', function (data, cb) { var href = data.href || window.location.href; - Cryptpad.changePadPassword(Cryptget, href, data.password, edPublic, cb); + Cryptpad.changePadPassword(Cryptget, Crypto, href, data.password, edPublic, cb); }); sframeChan.on('Q_CHANGE_USER_PASSWORD', function (data, cb) { @@ -1020,7 +1020,7 @@ define([ // Try to get the owner's mailbox from the pad metadata first. // If it's is an older owned pad, check if the owner is a friend // or an acquaintance (from async-store directly in requestAccess) - Cryptpad.pad.getPadMetadata({ + Cryptpad.padRpc.getPadMetadata({ channel: secret.channel }, waitFor(function (obj) { obj = obj || {};