Merge branch 'staging' of github.com:xwiki-labs/cryptpad into teams-server-features

pull/1/head
ansuz 5 years ago
commit 70161dbd73

@ -462,6 +462,10 @@
} }
} }
margin-bottom: 15px; margin-bottom: 15px;
&:empty {
margin: 0;
display: none;
}
} }
.cp-share-friend { .cp-share-friend {
width: 70px; width: 70px;
@ -493,6 +497,11 @@
visibility: hidden; visibility: hidden;
} }
} }
.cp-ownership {
& > label {
font-weight: bold;
}
}
} }
} }

@ -28,10 +28,14 @@ commands.ADD_OWNERS = function (meta, args) {
throw new Error("METADATA_NONSENSE_OWNERS"); throw new Error("METADATA_NONSENSE_OWNERS");
} }
var changed = false;
args.forEach(function (owner) { args.forEach(function (owner) {
if (meta.owners.indexOf(owner) >= 0) { return; } if (meta.owners.indexOf(owner) >= 0) { return; }
meta.owners.push(owner); meta.owners.push(owner);
changed = true;
}); });
return changed;
}; };
// ["RM_OWNERS", ["CrufexqXcY-z+eKJlEbNELVy5Sb7E-EAAEFI8GnEtZ0="], 1561623439989] // ["RM_OWNERS", ["CrufexqXcY-z+eKJlEbNELVy5Sb7E-EAAEFI8GnEtZ0="], 1561623439989]
@ -45,13 +49,24 @@ commands.RM_OWNERS = function (meta, args) {
throw new Error("METADATA_NONSENSE_OWNERS"); throw new Error("METADATA_NONSENSE_OWNERS");
} }
var changed = false;
// remove owners one by one // remove owners one by one
// we assume there are no duplicates // we assume there are no duplicates
args.forEach(function (owner) { args.forEach(function (owner) {
var index = meta.owners.indexOf(owner); var index = meta.owners.indexOf(owner);
if (index < 0) { return; } 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); meta.owners.splice(index, 1);
changed = true;
}); });
return changed;
}; };
// ["ADD_PENDING_OWNERS", ["7eEqelGso3EBr5jHlei6av4r9w2B9XZiGGwA1EgZ-5I="], 1561623438989] // ["ADD_PENDING_OWNERS", ["7eEqelGso3EBr5jHlei6av4r9w2B9XZiGGwA1EgZ-5I="], 1561623438989]
@ -67,16 +82,20 @@ commands.ADD_PENDING_OWNERS = function (meta, args) {
throw new Error("METADATA_NONSENSE_PENDING_OWNERS"); throw new Error("METADATA_NONSENSE_PENDING_OWNERS");
} }
var changed = false;
// Add pending_owners array if it doesn't exist // Add pending_owners array if it doesn't exist
if (!meta.pending_owners) { if (!meta.pending_owners) {
meta.pending_owners = deduplicate(args); meta.pending_owners = deduplicate(args);
return; return true;
} }
// or fill it // or fill it
args.forEach(function (owner) { args.forEach(function (owner) {
if (meta.pending_owners.indexOf(owner) >= 0) { return; } if (meta.pending_owners.indexOf(owner) >= 0) { return; }
meta.pending_owners.push(owner); meta.pending_owners.push(owner);
changed = true;
}); });
return changed;
}; };
// ["RM_PENDING_OWNERS", ["CrufexqXcY-z+eKJlEbNELVy5Sb7E-EAAEFI8GnEtZ0="], 1561623439989] // ["RM_PENDING_OWNERS", ["CrufexqXcY-z+eKJlEbNELVy5Sb7E-EAAEFI8GnEtZ0="], 1561623439989]
@ -90,13 +109,17 @@ commands.RM_PENDING_OWNERS = function (meta, args) {
throw new Error("METADATA_NONSENSE_PENDING_OWNERS"); throw new Error("METADATA_NONSENSE_PENDING_OWNERS");
} }
var changed = false;
// remove owners one by one // remove owners one by one
// we assume there are no duplicates // we assume there are no duplicates
args.forEach(function (owner) { args.forEach(function (owner) {
var index = meta.pending_owners.indexOf(owner); var index = meta.pending_owners.indexOf(owner);
if (index < 0) { return; } if (index < 0) { return; }
meta.pending_owners.splice(index, 1); meta.pending_owners.splice(index, 1);
changed = true;
}); });
return changed;
}; };
// ["RESET_OWNERS", ["7eEqelGso3EBr5jHlei6av4r9w2B9XZiGGwA1EgZ-5I="], 1561623439989] // ["RESET_OWNERS", ["7eEqelGso3EBr5jHlei6av4r9w2B9XZiGGwA1EgZ-5I="], 1561623439989]
@ -112,6 +135,41 @@ commands.RESET_OWNERS = function (meta, args) {
// overwrite the existing owners with the new one // overwrite the existing owners with the new one
meta.owners = deduplicate(args); meta.owners = deduplicate(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 () { commands.UPDATE_EXPIRATION = function () {
@ -127,7 +185,7 @@ var handleCommand = Meta.handleCommand = function (meta, line) {
throw new Error("METADATA_UNSUPPORTED_COMMAND"); throw new Error("METADATA_UNSUPPORTED_COMMAND");
} }
commands[command](meta, args); return commands[command](meta, args);
}; };
Meta.commands = Object.keys(commands); Meta.commands = Object.keys(commands);

@ -340,6 +340,7 @@ var getMetadata = function (Env, channel, cb) {
value: value value: value
} }
*/ */
// XXX global saferphore may cause issues here, a queue "per channel" is probably better
var metadataSem = Saferphore.create(1); var metadataSem = Saferphore.create(1);
var setMetadata = function (Env, data, unsafeKey, cb) { var setMetadata = function (Env, data, unsafeKey, cb) {
var channel = data.channel; var channel = data.channel;
@ -382,13 +383,20 @@ var setMetadata = function (Env, data, unsafeKey, cb) {
// Add the new metadata line // Add the new metadata line
var line = [command, data.value, +new Date()]; var line = [command, data.value, +new Date()];
var changed = false;
try { try {
Meta.handleCommand(metadata, line); changed = Meta.handleCommand(metadata, line);
} catch (e) { } catch (e) {
g(); g();
return void cb(e); return void cb(e);
} }
// if your command is valid but it didn't result in any change to the metadata,
// call back now and don't write any "useless" line to the log
if (!changed) {
g();
return void cb(void 0, metadata);
}
Env.msgStore.writeMetadata(channel, JSON.stringify(line), function (e) { Env.msgStore.writeMetadata(channel, JSON.stringify(line), function (e) {
g(); g();
if (e) { if (e) {

@ -83,6 +83,9 @@ define([
store.messenger.updateMyData(); store.messenger.updateMyData();
} }
var myData = createData(store.proxy); var myData = createData(store.proxy);
if (store.proxy.friends) {
store.proxy.friends.me = myData;
}
var todo = function (friend) { var todo = function (friend) {
if (!friend || !friend.notifications) { return; } if (!friend || !friend.notifications) { return; }
myData.channel = friend.channel; myData.channel = friend.channel;

@ -230,6 +230,11 @@ define([
}); });
}; };
messenger.onFriendUpdate = function (curve) {
var friend = getFriend(proxy, curve);
checkFriendData(curve, friend, friend.channel);
};
// Id message allows us to map a netfluxId with a public curve key // Id message allows us to map a netfluxId with a public curve key
var onIdMessage = function (msg, sender) { var onIdMessage = function (msg, sender) {
var channel, parsed0; var channel, parsed0;
@ -374,12 +379,14 @@ define([
|| mySyncData.profile !== myData.profile || mySyncData.profile !== myData.profile
|| mySyncData.avatar !== myData.avatar) { || mySyncData.avatar !== myData.avatar) {
delete myData.channel; delete myData.channel;
Object.keys(channels).forEach(function (chan) { Object.keys(friends).forEach(function (curve) {
var channel = channels[chan]; var friend = friends[curve];
var chan = friend.channel;
if (friend.notifications) { return; }
if (!chan) { return; }
if (!channel) { var channel = channels[chan];
return void console.error('NO_SUCH_CHANNEL'); if (!channel) { return; }
}
if (channel.readOnly) { return; } if (channel.readOnly) { return; }
var msg = [Types.update, myData.curvePublic, +new Date(), myData]; var msg = [Types.update, myData.curvePublic, +new Date(), myData];
@ -397,7 +404,6 @@ define([
info: myData, info: myData,
types: ['displayName', 'profile', 'avatar'], types: ['displayName', 'profile', 'avatar'],
}); });
friends.me = myData;
} }
}; };

@ -71,56 +71,22 @@ define([
var getPropertiesData = function (common, cb) { var getPropertiesData = function (common, cb) {
var data = {}; var data = {};
NThen(function (waitFor) { NThen(function (waitFor) {
common.getPadAttribute('password', waitFor(function (err, val) {
data.password = val;
}));
}).nThen(function (waitFor) {
var base = common.getMetadataMgr().getPrivateData().origin; var base = common.getMetadataMgr().getPrivateData().origin;
// XXX getFileData? common.getPadAttribute('', waitFor(function (err, val) {
// XXX getPadMetadata if (err || !val) {
common.getPadAttribute('href', waitFor(function (err, val) { waitFor.abort();
if (!val) { return; } return void cb(err || 'EEMPTY');
data.href = base + val; }
})); Util.extend(data, val);
common.getPadAttribute('roHref', waitFor(function (err, val) { if (data.href) { data.href = base + data.href; }
if (!val) { return; } if (data.roHref) { data.roHref = base + data.roHref; }
data.roHref = base + val;
}));
common.getPadAttribute('channel', waitFor(function (err, val) {
data.channel = val;
}));
common.getPadAttribute('rtChannel', waitFor(function (err, val) {
data.rtChannel = val;
}));
common.getPadAttribute('lastVersion', waitFor(function (err, val) {
data.lastVersion = val;
}));
common.getPadAttribute('atime', waitFor(function (err, val) {
data.atime = val;
}));
common.getPadAttribute('ctime', waitFor(function (err, val) {
data.ctime = val;
}));
common.getPadAttribute('title', waitFor(function (err, val) {
data.title = val;
}));
common.getPadAttribute('tags', waitFor(function (err, val) {
data.tags = val;
})); }));
common.getPadMetadata(null, waitFor(function (obj) { common.getPadMetadata(null, waitFor(function (obj) {
console.log(obj);
if (obj && obj.error) { return; } if (obj && obj.error) { return; }
data.owners = obj.owners; data.owners = obj.owners;
data.expire = obj.expire; data.expire = obj.expire;
data.pending_owners = obj.pending_owners; data.pending_owners = obj.pending_owners;
})); }));
/*
common.getPadAttribute('owners', waitFor(function (err, val) {
data.owners = val;
}));
common.getPadAttribute('expire', waitFor(function (err, val) {
data.expire = val;
}));*/
}).nThen(function () { }).nThen(function () {
cb(void 0, data); cb(void 0, data);
}); });
@ -132,20 +98,20 @@ define([
var user = common.getMetadataMgr().getUserData(); var user = common.getMetadataMgr().getUserData();
var edPublic = priv.edPublic; var edPublic = priv.edPublic;
var channel = data.channel; var channel = data.channel;
var owners = data.owners; var owners = data.owners || [];
var pending_owners = data.pending_owners; var pending_owners = data.pending_owners || [];
var redrawAll = function () {}; var redrawAll = function () {};
var div1 = h('div.cp-share-friends.cp-share-column'); var div1 = h('div.cp-share-friends.cp-share-column.cp-ownership');
var div2 = h('div.cp-share-friends.cp-share-column'); var div2 = h('div.cp-share-friends.cp-share-column.cp-ownership');
var $div1 = $(div1); var $div1 = $(div1);
var $div2 = $(div2); var $div2 = $(div2);
// Remove owner column // Remove owner column
var drawRemove = function (pending) { var drawRemove = function (pending) {
var _owners = {}; var _owners = {};
var o = pending ? pending_owners : owners; var o = (pending ? pending_owners : owners) || [];
o.forEach(function (ed) { o.forEach(function (ed) {
var f; var f;
Object.keys(friends).some(function (c) { Object.keys(friends).some(function (c) {
@ -154,20 +120,25 @@ define([
return true; return true;
} }
}); });
if (ed === edPublic) {
f = f || user;
if (f.name) {
f.displayName = f.name;
}
}
_owners[ed] = f || { _owners[ed] = f || {
displayName: 'Unknown user: '+ ed, // XXX displayName: Messages._getKey('owner_unknownUser', [ed]),
notifications: true, notifications: true,
edPublic: ed, edPublic: ed,
}; };
}); });
var msg = pending ? 'Remove a pending owner:' var msg = pending ? Messages.owner_removePendingText
: 'Remove an existing owner:'; // XXX : Messages.owner_removeText;
var removeCol = UIElements.getFriendsList(msg, { var removeCol = UIElements.getFriendsList(msg, {
common: common, common: common,
friends: _owners, friends: _owners,
noFilter: true noFilter: true
}, function () { }, function () {
console.log(arguments);
}); });
var $div = $(removeCol.div); var $div = $(removeCol.div);
var others1 = removeCol.others; var others1 = removeCol.others;
@ -184,12 +155,13 @@ define([
}); });
// When clicking on the remove button, we check the selected users. // When clicking on the remove button, we check the selected users.
// If you try to remove yourself, we'll display an additional warning message // If you try to remove yourself, we'll display an additional warning message
var btnMsg = pending ? 'Remove pending owners' : 'Remove owners'; // XXX var btnMsg = pending ? Messages.owner_removePendingButton : Messages.owner_removeButton;
var removeButton = h('button.no-margin', btnMsg); var removeButton = h('button.no-margin', btnMsg);
$(removeButton).click(function () { $(removeButton).click(function () {
// Check selection // Check selection
var $sel = $div.find('.cp-share-friend.cp-selected'); var $sel = $div.find('.cp-share-friend.cp-selected');
var sel = $sel.toArray(); var sel = $sel.toArray();
if (!sel.length) { return; }
var me = false; var me = false;
var toRemove = sel.map(function (el) { var toRemove = sel.map(function (el) {
var ed = $(el).attr('data-ed'); var ed = $(el).attr('data-ed');
@ -197,25 +169,54 @@ define([
if (ed === edPublic) { me = true; } if (ed === edPublic) { me = true; }
return ed; return ed;
}).filter(function (x) { return x; }); }).filter(function (x) { return x; });
NThen(function (waitFor) {
var msg = me ? Messages.owner_removeMeConfirm : Messages.owner_removeConfirm;
UI.confirm(msg, waitFor(function (yes) {
if (!yes) {
waitFor.abort();
return;
}
}));
}).nThen(function (waitFor) {
// Send the command // Send the command
var send = function () {
sframeChan.query('Q_SET_PAD_METADATA', { sframeChan.query('Q_SET_PAD_METADATA', {
channel: channel, channel: channel,
command: pending ? 'RM_PENDING_OWNERS' : 'RM_OWNERS', command: pending ? 'RM_PENDING_OWNERS' : 'RM_OWNERS',
value: toRemove value: toRemove
}, function (err, res) { }, waitFor(function (err, res) {
err = err || (res && res.error); err = err || (res && res.error);
if (err) { return void UI.warn('ERROR' + err); } // XXX if (err) {
waitFor.abort();
redrawAll(); redrawAll();
UI.log('DONE'); // XXX var text = err === "INSUFFICIENT_PERMISSIONS" ? Messages.fm_forbidden
: Messages.error;
return void UI.warn(text);
}
UI.log(Messages.saved);
}));
}).nThen(function (waitFor) {
sel.forEach(function (el) {
var friend = friends[$(el).attr('data-curve')];
if (!friend) { return; }
common.mailbox.sendTo("RM_OWNER", {
channel: channel,
title: data.title,
pending: pending,
user: {
displayName: user.name,
avatar: user.avatar,
profile: user.profile,
notifications: user.notifications,
curvePublic: user.curvePublic,
edPublic: priv.edPublic
}
}, {
channel: friend.notifications,
curvePublic: friend.curvePublic
}, waitFor());
}); });
}; }).nThen(function () {
var msg = me ? redrawAll();
"Are you sure? You're going to give up on your rights, this can't be undone!" :
"Are you sure?"; // XXX
UI.confirm(msg, function (yes) {
if (!yes) { return; }
send();
}); });
}); });
$div.append(h('p', removeButton)); $div.append(h('p', removeButton));
@ -226,16 +227,16 @@ define([
var drawAdd = function () { var drawAdd = function () {
var _friends = JSON.parse(JSON.stringify(friends)); var _friends = JSON.parse(JSON.stringify(friends));
Object.keys(_friends).forEach(function (curve) { Object.keys(_friends).forEach(function (curve) {
if (owners.indexOf(_friends[curve].edPublic) !== -1) { if (owners.indexOf(_friends[curve].edPublic) !== -1 ||
pending_owners.indexOf(_friends[curve].edPublic) !== -1) {
delete _friends[curve]; delete _friends[curve];
} }
}); });
var addCol = UIElements.getFriendsList('Ask a friend to be an owner.', { var addCol = UIElements.getFriendsList(Messages.owner_addText, {
common: common, common: common,
friends: _friends friends: _friends
}, function () { }, function () {
// XXX onSelect... //console.log(arguments);
console.log(arguments);
}); });
$div2 = $(addCol.div); $div2 = $(addCol.div);
var others2 = addCol.others; var others2 = addCol.others;
@ -249,20 +250,20 @@ define([
order = order ? 'order:'+order : ''; order = order ? 'order:'+order : '';
$(this).removeClass('cp-selected').attr('style', order); $(this).removeClass('cp-selected').attr('style', order);
} }
// XXX onSelect...
}); });
// When clicking on the add button, we get the selected users. // When clicking on the add button, we get the selected users.
var addButton = h('button.no-margin', 'Add owners'); // XXX var addButton = h('button.no-margin', Messages.owner_addButton);
$(addButton).click(function () { $(addButton).click(function () {
// Check selection // Check selection
var $sel = $div2.find('.cp-share-friend.cp-selected'); var $sel = $div2.find('.cp-share-friend.cp-selected');
var sel = $sel.toArray(); var sel = $sel.toArray();
if (!sel.length) { return; }
var toAdd = sel.map(function (el) { var toAdd = sel.map(function (el) {
return friends[$(el).attr('data-curve')].edPublic; return friends[$(el).attr('data-curve')].edPublic;
}).filter(function (x) { return x; }); }).filter(function (x) { return x; });
NThen(function (waitFor) { NThen(function (waitFor) {
var msg = "Are you sure?"; // XXX var msg = Messages.owner_addConfirm;
UI.confirm(msg, waitFor(function (yes) { UI.confirm(msg, waitFor(function (yes) {
if (!yes) { if (!yes) {
waitFor.abort(); waitFor.abort();
@ -270,23 +271,22 @@ define([
} }
})); }));
}).nThen(function (waitFor) { }).nThen(function (waitFor) {
console.log('koko');
// Send the command // Send the command
sframeChan.query('Q_SET_PAD_METADATA', { sframeChan.query('Q_SET_PAD_METADATA', {
channel: channel, channel: channel,
command: 'ADD_PENDING_OWNERS', command: 'ADD_PENDING_OWNERS',
value: toAdd value: toAdd
}, waitFor(function (err, res) { }, waitFor(function (err, res) {
console.error(arguments);
err = err || (res && res.error); err = err || (res && res.error);
if (err) { if (err) {
waitFor.abort(); waitFor.abort();
return void UI.warn('ERROR' + err); redrawAll();
} // XXX var text = err === "INSUFFICIENT_PERMISSIONS" ? Messages.fm_forbidden
: Messages.error;
return void UI.warn(text);
}
})); }));
}).nThen(function (waitFor) { }).nThen(function (waitFor) {
console.log('okok');
// TODO send notifications
sel.forEach(function (el) { sel.forEach(function (el) {
var friend = friends[$(el).attr('data-curve')]; var friend = friends[$(el).attr('data-curve')];
if (!friend) { return; } if (!friend) { return; }
@ -310,28 +310,42 @@ define([
}); });
}).nThen(function () { }).nThen(function () {
redrawAll(); redrawAll();
UI.log('DONE'); // XXX UI.log(Messages.saved);
}); });
}); });
$div2.append(h('p', addButton)); $div2.append(h('p', addButton));
return $div2; return $div2;
}; };
redrawAll = function () { redrawAll = function (md) {
var todo = function (obj) {
if (obj && obj.error) { return; }
owners = obj.owners || [];
pending_owners = obj.pending_owners || [];
$div1.empty(); $div1.empty();
$div2.empty(); $div2.empty();
common.getPadMetadata(null, function (obj) {
if (obj && obj.error) { return; }
owners = obj.owners;
pending_owners = obj.pending_owners;
$div1.append(drawRemove(false)).append(drawRemove(true)); $div1.append(drawRemove(false)).append(drawRemove(true));
$div2.append(drawAdd()); $div2.append(drawAdd());
}); };
if (md) { return void todo(md); }
common.getPadMetadata({
channel: data.channel
}, todo);
}; };
$div1.append(drawRemove(false)).append(drawRemove(true)); $div1.append(drawRemove(false)).append(drawRemove(true));
$div2.append(drawAdd()); $div2.append(drawAdd());
var handler = sframeChan.on('EV_RT_METADATA', function (md) {
if (!$div1.length) {
return void handler.stop();
}
owners = md.owners || [];
pending_owners = md.pending_owners || [];
redrawAll(md);
});
// Create modal // Create modal
var link = h('div.cp-share-columns', [ var link = h('div.cp-share-columns', [
div1, div1,
@ -341,16 +355,18 @@ define([
]); ]);
var linkButtons = [{ var linkButtons = [{
className: 'cancel', className: 'cancel',
name: 'CLOSE', // XXX existing key? name: Messages.filePicker_close,
onClick: function () {}, onClick: function () {},
keys: [27] keys: [27]
}]; }];
return UI.dialog.customModal(link, {buttons: linkButtons}); return UI.dialog.customModal(link, {buttons: linkButtons});
}; };
var getRightsProperties = function (common, data, cb) { var getRightsProperties = function (common, data, cb) {
var $d = $('<div>'); var $div = $('<div>');
if (!data) { return void cb(void 0, $d); } if (!data) { return void cb(void 0, $div); }
var draw = function () {
var $d = $('<div>');
$('<label>', {'for': 'cp-app-prop-owners'}).text(Messages.creation_owners) $('<label>', {'for': 'cp-app-prop-owners'}).text(Messages.creation_owners)
.appendTo($d); .appendTo($d);
var owners = Messages.creation_noOwner; var owners = Messages.creation_noOwner;
@ -388,7 +404,7 @@ define([
id: 'cp-app-prop-owners', id: 'cp-app-prop-owners',
})); }));
if (owned) { if (owned) {
var manageOwners = h('button.no-margin', 'Manage owners'); // XXX var manageOwners = h('button.no-margin', Messages.owner_openModalButton);
$(manageOwners).click(function () { $(manageOwners).click(function () {
var modal = createOwnerModal(common, data); var modal = createOwnerModal(common, data);
UI.openCustomModal(modal, { UI.openCustomModal(modal, {
@ -479,8 +495,25 @@ define([
$d.append(changePass); $d.append(changePass);
} }
} }
return $d;
};
cb(void 0, $d); var sframeChan = common.getSframeChannel();
var handler = sframeChan.on('EV_RT_METADATA', function (md) {
if (!$div.length) {
handler.stop();
return;
}
md = JSON.parse(JSON.stringify(md));
data.owners = md.owners;
data.expire = md.expire;
data.pending_owners = md.pending_owners;
$div.empty();
$div.append(draw());
});
$div.append(draw());
cb(void 0, $div);
}; };
var getPadProperties = function (common, data, cb) { var getPadProperties = function (common, data, cb) {
var $d = $('<div>'); var $d = $('<div>');
@ -567,6 +600,8 @@ define([
} else { } else {
cb(void 0, $d); cb(void 0, $d);
} }
}; };
UIElements.getProperties = function (common, data, cb) { UIElements.getProperties = function (common, data, cb) {
var c1; var c1;
@ -3068,6 +3103,7 @@ define([
}; };
var storePopupState = false; var storePopupState = false;
var autoStoreModal = {};
UIElements.displayStorePadPopup = function (common, data) { UIElements.displayStorePadPopup = function (common, data) {
if (storePopupState) { return; } if (storePopupState) { return; }
storePopupState = true; storePopupState = true;
@ -3087,6 +3123,8 @@ define([
var initialHide = data && data.autoStore && data.autoStore === -1; var initialHide = data && data.autoStore && data.autoStore === -1;
var modal = UI.cornerPopup(text, actions, footer, {hidden: initialHide}); var modal = UI.cornerPopup(text, actions, footer, {hidden: initialHide});
autoStoreModal[priv.channel] = modal;
$(modal.popup).find('.cp-corner-footer a').click(function (e) { $(modal.popup).find('.cp-corner-footer a').click(function (e) {
e.preventDefault(); e.preventDefault();
common.openURL('/settings/'); common.openURL('/settings/');
@ -3094,6 +3132,7 @@ define([
$(hide).click(function () { $(hide).click(function () {
UIElements.displayCrowdfunding(common); UIElements.displayCrowdfunding(common);
delete autoStoreModal[priv.channel];
modal.delete(); modal.delete();
}); });
var waitingForStoringCb = false; var waitingForStoringCb = false;
@ -3109,6 +3148,7 @@ define([
} }
return void UI.warn(Messages.autostore_error); return void UI.warn(Messages.autostore_error);
} }
delete autoStoreModal[priv.channel];
modal.delete(); modal.delete();
UIElements.displayCrowdfunding(common); UIElements.displayCrowdfunding(common);
UI.log(Messages.autostore_saved); UI.log(Messages.autostore_saved);
@ -3286,7 +3326,6 @@ define([
var name = Util.fixHTML(msg.content.user.displayName) || Messages.anonymous; var name = Util.fixHTML(msg.content.user.displayName) || Messages.anonymous;
var title = Util.fixHTML(msg.content.title); var title = Util.fixHTML(msg.content.title);
Messages.owner_add = '{0} wants you to be an owner of the pad <b>{1}</b>. Do you accept?'; //XXX
var text = Messages._getKey('owner_add', [name, title]); var text = Messages._getKey('owner_add', [name, title]);
var link = h('a', { var link = h('a', {
@ -3343,13 +3382,32 @@ define([
}, function (err, res) { }, function (err, res) {
err = err || (res && res.error); err = err || (res && res.error);
if (err) { if (err) {
return void UI.warn('ERROR ' + err); var text = err === "INSUFFICIENT_PERMISSIONS" ? Messages.fm_forbidden
} // XXX : Messages.error;
UI.log('DONE'); // XXX return void UI.warn(text);
}
UI.log(Messages.saved);
// Send notification to the sender // Send notification to the sender
answer(true); answer(true);
var data = JSON.parse(JSON.stringify(msg.content));
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);
}
UI.log(Messages.saved);
if (autoStoreModal[data.channel]) {
autoStoreModal[data.channel].delete();
delete autoStoreModal[data.channel];
}
});
// Remove yourself from the pending owners // Remove yourself from the pending owners
sframeChan.query('Q_SET_PAD_METADATA', { sframeChan.query('Q_SET_PAD_METADATA', {
channel: msg.content.channel, channel: msg.content.channel,

@ -757,6 +757,7 @@ define([
pad.onDisconnectEvent = Util.mkEvent(); pad.onDisconnectEvent = Util.mkEvent();
pad.onConnectEvent = Util.mkEvent(); pad.onConnectEvent = Util.mkEvent();
pad.onErrorEvent = Util.mkEvent(); pad.onErrorEvent = Util.mkEvent();
pad.onMetadataEvent = Util.mkEvent();
pad.getPadMetadata = function (data, cb) { pad.getPadMetadata = function (data, cb) {
postMessage('GET_PAD_METADATA', data, cb); postMessage('GET_PAD_METADATA', data, cb);
@ -1208,6 +1209,7 @@ define([
PAD_DISCONNECT: common.padRpc.onDisconnectEvent.fire, PAD_DISCONNECT: common.padRpc.onDisconnectEvent.fire,
PAD_CONNECT: common.padRpc.onConnectEvent.fire, PAD_CONNECT: common.padRpc.onConnectEvent.fire,
PAD_ERROR: common.padRpc.onErrorEvent.fire, PAD_ERROR: common.padRpc.onErrorEvent.fire,
PAD_METADATA: common.padRpc.onMetadataEvent.fire,
// Drive // Drive
DRIVE_LOG: common.drive.onLog.fire, DRIVE_LOG: common.drive.onLog.fire,
DRIVE_CHANGE: common.drive.onChange.fire, DRIVE_CHANGE: common.drive.onChange.fire,

@ -218,7 +218,6 @@ define([
// Display the notification // Display the notification
var name = Util.fixHTML(msg.content.user.displayName) || Messages.anonymous; var name = Util.fixHTML(msg.content.user.displayName) || Messages.anonymous;
var title = Util.fixHTML(msg.content.title); var title = Util.fixHTML(msg.content.title);
Messages.owner_request = '{0} wants you to be an owner of <b>{1}</b>'; // XXX
content.getFormatText = function () { content.getFormatText = function () {
return Messages._getKey('owner_request', [name, title]); return Messages._getKey('owner_request', [name, title]);
}; };
@ -241,8 +240,6 @@ define([
// Display the notification // Display the notification
var name = Util.fixHTML(msg.content.user.displayName) || Messages.anonymous; var name = Util.fixHTML(msg.content.user.displayName) || Messages.anonymous;
var title = Util.fixHTML(msg.content.title); var title = Util.fixHTML(msg.content.title);
Messages.owner_request_accepted = '{0} has accepted your offer to be an owner of <b>{1}</b>'; // XXX
Messages.owner_request_declined = '{0} has declined your offer to be an owner of <b>{1}</b>'; // XXX
var key = 'owner_request_' + (msg.content.answer ? 'accepted' : 'declined'); var key = 'owner_request_' + (msg.content.answer ? 'accepted' : 'declined');
content.getFormatText = function () { content.getFormatText = function () {
return Messages._getKey(key, [name, title]); return Messages._getKey(key, [name, title]);
@ -252,6 +249,22 @@ define([
} }
}; };
handlers['RM_OWNER'] = function (common, data) {
var content = data.content;
var msg = content.msg;
// Display the notification
var name = Util.fixHTML(msg.content.user.displayName) || Messages.anonymous;
var title = Util.fixHTML(msg.content.title);
var key = 'owner_removed' + (msg.content.pending ? 'Pending' : '');
content.getFormatText = function () {
return Messages._getKey(key, [name, title]);
};
if (!content.archived) {
content.dismissHandler = defaultDismiss(common, data);
}
};
// NOTE: don't forget to fixHTML everything returned by "getFormatText" // NOTE: don't forget to fixHTML everything returned by "getFormatText"
return { return {

@ -1205,7 +1205,6 @@ define([
} }
}, },
onMetadataUpdate: function (metadata) { onMetadataUpdate: function (metadata) {
console.log('onMetadataUpdate', metadata);
channel.data = metadata || {}; channel.data = metadata || {};
var allData = store.manager.findChannel(data.channel); var allData = store.manager.findChannel(data.channel);
allData.forEach(function (obj) { allData.forEach(function (obj) {
@ -1214,7 +1213,7 @@ define([
obj.data.expire = +metadata.expire; obj.data.expire = +metadata.expire;
} }
}); });
//channel.bcast("PAD_METADATA", metadata); channel.bcast("PAD_METADATA", metadata);
}, },
crypto: { crypto: {
// The encryption and decryption is done in the outer window. // The encryption and decryption is done in the outer window.
@ -1374,7 +1373,6 @@ define([
}; };
Store.getPadMetadata = function (clientId, data, cb) { Store.getPadMetadata = function (clientId, data, cb) {
console.log(data);
if (!data.channel) { return void cb({ error: 'ENOTFOUND'}); } if (!data.channel) { return void cb({ error: 'ENOTFOUND'}); }
var channel = channels[data.channel]; var channel = channels[data.channel];
if (!channel) { return void cb({ error: 'ENOTFOUND' }); } if (!channel) { return void cb({ error: 'ENOTFOUND' }); }
@ -1397,7 +1395,6 @@ define([
cb(channel.data || {}); cb(channel.data || {});
}; };
Store.setPadMetadata = function (clientId, data, cb) { Store.setPadMetadata = function (clientId, data, cb) {
console.log(data);
if (!data.channel) { return void cb({ error: 'ENOTFOUND'}); } if (!data.channel) { return void cb({ error: 'ENOTFOUND'}); }
if (!data.command) { return void cb({ error: 'EINVAL' }); } if (!data.command) { return void cb({ error: 'EINVAL' }); }
store.rpc.setMetadata(data, function (err, res) { store.rpc.setMetadata(data, function (err, res) {

@ -153,6 +153,9 @@ define([
Object.keys(msg.content).forEach(function (key) { Object.keys(msg.content).forEach(function (key) {
friend[key] = msg.content[key]; friend[key] = msg.content[key];
}); });
if (ctx.store.messenger) {
ctx.store.messenger.onFriendUpdate(curve, friend);
}
ctx.updateMetadata(); ctx.updateMetadata();
cb(true); cb(true);
}; };
@ -264,7 +267,6 @@ define([
handlers['ADD_OWNER'] = function (ctx, box, data, cb) { handlers['ADD_OWNER'] = function (ctx, box, data, cb) {
var msg = data.msg; var msg = data.msg;
var content = msg.content; var content = msg.content;
console.log(msg);
if (msg.author !== content.user.curvePublic) { return void cb(true); } if (msg.author !== content.user.curvePublic) { return void cb(true); }
if (!content.href || !content.title || !content.channel) { if (!content.href || !content.title || !content.channel) {
@ -275,7 +277,10 @@ console.log(msg);
var channel = content.channel; var channel = content.channel;
if (addOwners[channel]) { return void cb(true); } if (addOwners[channel]) { return void cb(true); }
addOwners[channel] = true; addOwners[channel] = {
type: box.type,
hash: data.hash
};
cb(false); cb(false);
}; };
@ -286,6 +291,24 @@ console.log(msg);
} }
}; };
handlers['RM_OWNER'] = function (ctx, box, data, cb) {
var msg = data.msg;
var content = msg.content;
if (msg.author !== content.user.curvePublic) { return void cb(true); }
if (!content.channel) {
console.log('Remove invalid notification');
return void cb(true);
}
var channel = content.channel;
if (addOwners[channel] && content.pending) {
return void cb(false, addOwners[channel]);
}
cb(false);
};
return { return {
add: function (ctx, box, data, cb) { add: function (ctx, box, data, cb) {
/** /**

@ -495,8 +495,8 @@ define([
_addSharedFolder(Env, { _addSharedFolder(Env, {
path: parentPath, path: parentPath,
name: folderName, name: folderName,
owned: data.owned, // XXX FIXME hardcoded preference owned: data.owned,
password: data.password || '', // XXX FIXME hardcoded preference password: data.password || '',
}, waitFor(function (id) { }, waitFor(function (id) {
// _addSharedFolder can be an id or an error // _addSharedFolder can be an id or an error
if (typeof(id) === 'object' && id && id.error) { if (typeof(id) === 'object' && id && id.error) {
@ -741,29 +741,17 @@ define([
return void cb(null, Env.user.proxy[UserObject.SHARED_FOLDERS][sfId][data.attr]); return void cb(null, Env.user.proxy[UserObject.SHARED_FOLDERS][sfId][data.attr]);
} }
var datas = findHref(Env, data.href); var datas = findHref(Env, data.href);
var nt = nThen;
var res = {}; var res = {};
datas.forEach(function (d) { datas.forEach(function (d) {
nt = nt(function (waitFor) { var atime = d.data.atime;
var atime, value;
var w = waitFor(); var value = data.attr ? d.data[data.attr] : JSON.parse(JSON.stringify(d.data));
nThen(function (waitFor2) {
d.userObject.getPadAttribute(data.href, 'atime', waitFor2(function (err, v) {
atime = v;
}));
d.userObject.getPadAttribute(data.href, data.attr, waitFor2(function (err, v) {
value = v;
}));
}).nThen(function () {
if (!res.value || res.atime < atime) { if (!res.value || res.atime < atime) {
res.atime = atime; res.atime = atime;
res.value = value; res.value = value;
} }
w();
});
}).nThen;
}); });
nt(function () { cb(null, res.value); }); cb(null, res.value);
}; };
var getTagsList = function (Env) { var getTagsList = function (Env) {

@ -118,6 +118,10 @@ define([], function () {
onOpen(data); onOpen(data);
}); });
padRpc.onMetadataEvent.reg(function (data) {
sframeChan.event('EV_RT_METADATA', data);
});
padRpc.onErrorEvent.reg(function (err) { padRpc.onErrorEvent.reg(function (err) {
sframeChan.event('EV_RT_ERROR', err); sframeChan.event('EV_RT_ERROR', err);
}); });

@ -476,6 +476,43 @@ define([
}); });
}); });
sframeChan.on('Q_ACCEPT_OWNERSHIP', function (data, cb) {
var _data = {
password: data.password,
href: data.href,
channel: data.channel,
title: data.title,
owners: data.metadata.owners,
expire: data.metadata.expire,
forceSave: true
};
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) { sframeChan.on('Q_IMPORT_MEDIATAG', function (obj, cb) {
var key = obj.key; var key = obj.key;
var channel = obj.channel; var channel = obj.channel;
@ -986,9 +1023,17 @@ define([
}, waitFor(function (obj) { }, waitFor(function (obj) {
obj = obj || {}; obj = obj || {};
if (obj.error) { return; } 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 { try {
var dataStr = crypto.decrypt(obj.mailbox, true, true); var dataStr = crypto.decrypt(mailbox, true, true);
var data = JSON.parse(dataStr); var data = JSON.parse(dataStr);
if (!data.notifications || !data.curvePublic) { return; } if (!data.notifications || !data.curvePublic) { return; }
owner = data; owner = data;
@ -1010,7 +1055,6 @@ define([
channel: secret.channel channel: secret.channel
}; };
} }
console.log(data);
Cryptpad.getPadMetadata(data, cb); Cryptpad.getPadMetadata(data, cb);
}); });
sframeChan.on('Q_SET_PAD_METADATA', function (data, cb) { sframeChan.on('Q_SET_PAD_METADATA', function (data, cb) {
@ -1142,7 +1186,8 @@ define([
}; };
if (data.owned) { if (data.owned) {
rtConfig.metadata.owners = [edPublic]; 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, notifications: notifications,
curvePublic: curvePublic curvePublic: curvePublic
})); }));

@ -1139,5 +1139,26 @@
"features_noData": "Aucune donnée personnelle requise", "features_noData": "Aucune donnée personnelle requise",
"features_pricing": "Entre {0} et {2}€ par mois", "features_pricing": "Entre {0} et {2}€ par mois",
"features_emailRequired": "Adresse email requise", "features_emailRequired": "Adresse email requise",
"register_emailWarning0": "Il semble que vous ayez entré votre adresse email à la place du nom d'utilisateur.",
"register_emailWarning1": "Vous pouvez continuer, mais ces données ne sont pas nécessaires et ne seront pas envoyées à notre serveur.",
"register_emailWarning2": "Vous ne pourrez pas réinitialiser votre mot de passe en utilisant votre adresse email comme sur beaucoup d'autres services",
"register_emailWarning3": "Si vous souhaitez tout de même utiliser votre adresse email comme nom d'utilisateur, appuyez sur OK",
"owner_removeText": "Supprimer un propriétaire existant",
"owner_removePendingText": "Annuler une offre en attente",
"owner_addText": "Proposer à un ami d'être co-propriétaire de ce document",
"owner_unknownUser": "Utilisateur inconnu",
"owner_removeButton": "Supprimer les propriétaires sélectionnés",
"owner_removePendingButton": "Annuler les offres sélectionnées",
"owner_addButton": "Proposer la co-propriété",
"owner_removeConfirm": "Êtes-vous sûr de vouloir suppprimer les droits de propriétaire pour les utilisateurs sélectionnés ? Ils seront notifiés de cette action.",
"owner_removeMeConfirm": "Vous êtes sur le point de renoncer à vos droits de propriétaire. Vous ne serez pas en mesure d'annuler cette action. Continuer ?",
"owner_addConfirm": "Les co-propriétaires seront en mesure de changer le contenu du document et pourront supprimer vos droits de propriétaire. Continuer ?",
"owner_openModalButton": "Gérer les propriétaires",
"owner_add": "{0} souhaite que vous soyez propriétaire du pad <b>{1}</b>. Acceptez-vous ?",
"owner_request": "{0} souhaite que vous soyez propriétaire de <b>{1}</b>",
"owner_request_accepted": "{0} a accepté votre offre de devenir propriétaire de <b>{1}</b>",
"owner_request_declined": "{0} a refusé votre offre de devenir propriétaire de <b>{1}</b>",
"owner_removed": "{0} a supprimé vos droits de propriétaire de <b>{1}</b>",
"owner_removedPending": "{0} a annulé l'offre de co-propriété reçue pour <b>{1}</b>",
"padNotPinnedVariable": "Ce pad va expirer après {4} jours d'inactivité, {0}connectez-vous{1} ou {2}enregistrez-vous{3} pour le préserver." "padNotPinnedVariable": "Ce pad va expirer après {4} jours d'inactivité, {0}connectez-vous{1} ou {2}enregistrez-vous{3} pour le préserver."
} }

@ -3720,7 +3720,6 @@ define([
sframeChan.query('Q_GET_PAD_METADATA', { sframeChan.query('Q_GET_PAD_METADATA', {
channel: data.channel channel: data.channel
}, function (err, val) { }, function (err, val) {
console.log(arguments);
if (!err && !(val && val.error)) { if (!err && !(val && val.error)) {
data.owners = val.owners; data.owners = val.owners;
data.expire = val.expire; data.expire = val.expire;

Loading…
Cancel
Save