diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index a95e1c672..0039323ee 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -357,27 +357,48 @@ define([ if (data.owners && data.owners.length) { if (data.owners.indexOf(edPublic) !== -1) { owned = true; + } else { + Object.keys(priv.teams || {}).some(function (id) { + var team = priv.teams[id] || {}; + if (data.owners.indexOf(team.edPublic) === -1) { return; } + owned = id; + return true; + }); } var names = []; var strangers = 0; data.owners.forEach(function (ed) { // If a friend is an owner, add their name to the list // otherwise, increment the list of strangers + + // Our edPublic? print "Yourself" if (ed === edPublic) { names.push(Messages.yourself); return; } - if (!Object.keys(priv.friends || {}).some(function (c) { + // One of our teams? print the team name + if (Object.keys(priv.teams || {}).some(function (id) { + var team = priv.teams[id] || {}; + if (team.edPublic !== ed) { return; } + names.push('TEAM: '+team.name); // XXX + return true; + })) { + return; + } + // One of our friends? print the friend name + if (Object.keys(priv.friends || {}).some(function (c) { var friend = priv.friends[c] || {}; if (friend.edPublic !== ed || c === 'me') { return; } names.push(friend.displayName); return true; })) { - strangers++; + return; } + // Otherwise it's a stranger + strangers++; }); if (strangers) { - names.push(Messages._getKey('properties_unknownUser', [strangers])); + names.push(Messages._getKey('properties_unknownUser', [strangers])); // XXX unknown owner? } owners = names.join(', '); } @@ -388,6 +409,7 @@ define([ if (data.href || data.roHref) { parsed = Hash.parsePadUrl(data.href || data.roHref); } + // XXX Teams owner: transfer ownership if (owned && data.roHref && parsed.type !== 'drive' && parsed.hashData.type === 'pad') { var manageOwners = h('button.no-margin', Messages.owner_openModalButton); $(manageOwners).click(function () { @@ -455,6 +477,7 @@ define([ UI.confirm(changePwConfirm, function (yes) { if (!yes) { return; } sframeChan.query("Q_PAD_PASSWORD_CHANGE", { + teamId: typeof(owned) !== "boolean" ? owned : undefined, href: data.href || data.roHref, password: newPass }, function (err, data) { diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index a7b554420..0516bf057 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -209,15 +209,23 @@ define([ // RPC - common.pinPads = function (pads, cb) { - postMessage("PIN_PADS", pads, function (obj) { + common.pinPads = function (pads, cb, teamId) { + var data = { + teamId: teamId, + pads: pads + }; + postMessage("PIN_PADS", data, function (obj) { if (obj && obj.error) { return void cb(obj.error); } cb(null, obj.hash); }); }; - common.unpinPads = function (pads, cb) { - postMessage("UNPIN_PADS", pads, function (obj) { + common.unpinPads = function (pads, cb, teamId) { + var data = { + teamId: teamId, + pads: pads + }; + postMessage("UNPIN_PADS", data, function (obj) { if (obj && obj.error) { return void cb(obj.error); } cb(null, obj.hash); }); @@ -831,7 +839,10 @@ define([ }; // XXX Teams: change the password of a pad owned by the team - common.changePadPassword = function (Crypt, Crypto, href, newPassword, edPublic, cb) { + common.changePadPassword = function (Crypt, Crypto, data, cb) { + var href = data.href; + var newPassword = data.password; + var teamId = data.teamId; if (!href) { return void cb({ error: 'EINVAL_HREF' }); } var parsed = Hash.parsePadUrl(href); if (!parsed.hash) { return void cb({ error: 'EINVAL_HREF' }); } @@ -842,6 +853,7 @@ define([ var oldSecret; var oldMetadata; var newSecret; + var privateData; if (parsed.hashData.version >= 2) { newSecret = Hash.getSecrets(parsed.type, parsed.hash, newPassword); @@ -874,16 +886,26 @@ define([ common.getPadMetadata({channel: oldChannel}, waitFor(function (metadata) { oldMetadata = metadata; })); + common.getMetadata(waitFor(function (err, data) { + if (err) { + waitFor.abort(); + return void cb({ error: err }); + } + privateData = data.priv; + })); }).nThen(function (waitFor) { // Get owners, mailbox and expiration time - var owners = oldMetadata.owners; - if (!Array.isArray(owners) || owners.indexOf(edPublic) === -1) { + optsPut.metadata.owners = owners; + + // Check if we're allowed to change the password + var edPublic = teamId ? (privateData.teams[teamId] || {}).edPublic : privateData.edPublic; + var isOwner = Array.isArray(owners) && edPublic && owners.indexOf(edPublic) !== -1; + if (!isOwner) { // 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) { @@ -933,15 +955,15 @@ define([ }).nThen(function (waitFor) { common.removeOwnedChannel({ channel: oldChannel, - teamId: null // TODO + teamId: teamId }, waitFor(function (obj) { if (obj && obj.error) { waitFor.abort(); return void cb(obj); } })); - common.unpinPads([oldChannel], waitFor()); - common.pinPads([newSecret.channel], waitFor()); + common.unpinPads([oldChannel], waitFor(), teamId); + common.pinPads([newSecret.channel], waitFor(), teamId); }).nThen(function (waitFor) { common.setPadAttribute('password', newPassword, waitFor(function (err) { if (err) { warning = true; } diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 6edfa1299..e33c19883 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -203,22 +203,36 @@ define([ /////////////////////// RPC ////////////////////////////////////// ////////////////////////////////////////////////////////////////// + // pinPads needs to support the old format where data is an array of channel IDs + // and the new format where data is an object with "teamId" and "pads" Store.pinPads = function (clientId, data, cb) { - if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); } + if (!data) { return void cb({error: 'EINVAL'}); } + + var s = getStore(data && data.teamId); + if (!s.rpc) { return void cb({error: 'RPC_NOT_READY'}); } + if (typeof(cb) !== 'function') { console.error('expected a callback'); + cb = function () {}; } - store.rpc.pin(data, function (e, hash) { + var pads = data.pads || data; + s.rpc.pin(pads, function (e, hash) { if (e) { return void cb({error: e}); } cb({hash: hash}); }); }; + // unpinPads needs to support the old format where data is an array of channel IDs + // and the new format where data is an object with "teamId" and "pads" Store.unpinPads = function (clientId, data, cb) { - if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); } + if (!data) { return void cb({error: 'EINVAL'}); } + + var s = getStore(data && data.teamId); + if (!s.rpc) { return void cb({error: 'RPC_NOT_READY'}); } - store.rpc.unpin(data, function (e, hash) { + var pads = data.pads || data; + s.rpc.unpin(pads, function (e, hash) { if (e) { return void cb({error: e}); } cb({hash: hash}); }); diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index d3e49559d..cf3f987dc 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -928,8 +928,8 @@ define([ }); sframeChan.on('Q_PAD_PASSWORD_CHANGE', function (data, cb) { - var href = data.href || window.location.href; - Cryptpad.changePadPassword(Cryptget, Crypto, href, data.password, edPublic, cb); + data.href = data.href || window.location.href; + Cryptpad.changePadPassword(Cryptget, Crypto, data, cb); }); sframeChan.on('Q_CHANGE_USER_PASSWORD', function (data, cb) {