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

pull/1/head
ClemDee 5 years ago
commit 0485497a58

@ -162,7 +162,7 @@ define([
} }
var parsed = Hash.parsePadUrl(data.href || data.roHref); var parsed = Hash.parsePadUrl(data.href || data.roHref);
if (!data.noEditPassword && owned && parsed.hashData.type === 'pad') { if (!data.noEditPassword && owned && parsed.hashData.type === 'pad' && parsed.type !== "sheet") { // FIXME SHEET fix password change for sheets
var sframeChan = common.getSframeChannel(); var sframeChan = common.getSframeChannel();
var changePwTitle = Messages.properties_changePassword; var changePwTitle = Messages.properties_changePassword;
var changePwConfirm = Messages.properties_confirmChange; var changePwConfirm = Messages.properties_confirmChange;
@ -412,6 +412,7 @@ define([
if (!friend.notifications || !friend.curvePublic) { return; } if (!friend.notifications || !friend.curvePublic) { return; }
common.mailbox.sendTo("SHARE_PAD", { common.mailbox.sendTo("SHARE_PAD", {
href: href, href: href,
password: config.password,
name: myName, name: myName,
title: title title: title
}, { }, {

@ -57,7 +57,12 @@ define([
.html(Messages._getKey(key, [msg.content.name || Messages.anonymous, msg.content.title])); .html(Messages._getKey(key, [msg.content.name || Messages.anonymous, msg.content.title]));
$(el).find('.cp-notification-content').addClass("cp-clickable") $(el).find('.cp-notification-content').addClass("cp-clickable")
.click(function () { .click(function () {
common.openURL(msg.content.href); var todo = function () { common.openURL(msg.content.href); };
if (!msg.content.password) { return void todo(); }
common.getSframeChannel().query('Q_SESSIONSTORAGE_PUT', {
key: 'newPadPassword',
value: msg.content.password
}, todo);
}); });
$(el).find('.cp-notification-dismiss').css('display', 'flex'); $(el).find('.cp-notification-dismiss').css('display', 'flex');
}; };

@ -102,9 +102,12 @@ define([
Cryptpad.onlyoffice.onEvent.reg(function (obj) { Cryptpad.onlyoffice.onEvent.reg(function (obj) {
if (obj.ev === 'MESSAGE' && !/^cp\|/.test(obj.data)) { if (obj.ev === 'MESSAGE' && !/^cp\|/.test(obj.data)) {
try { try {
var validateKey = obj.data.validateKey || true;
var skipCheck = validateKey === true;
var msg = obj.data.msg;
obj.data = { obj.data = {
msg: JSON.parse(Utils.crypto.decrypt(obj.data, Utils.secret.keys.validateKey)), msg: JSON.parse(Utils.crypto.decrypt(msg, validateKey, skipCheck)),
hash: obj.data.slice(0,64) hash: msg.slice(0,64)
}; };
} catch (e) { } catch (e) {
console.error(e); console.error(e);

@ -1,6 +1,7 @@
define([ define([
'/common/common-messaging.js', '/common/common-messaging.js',
], function (Messaging) { '/common/common-hash.js',
], function (Messaging, Hash) {
var getRandomTimeout = function (ctx) { var getRandomTimeout = function (ctx) {
var lag = ctx.store.realtime.getLag().lag || 0; var lag = ctx.store.realtime.getLag().lag || 0;
@ -156,6 +157,50 @@ define([
cb(true); cb(true);
}; };
// Hide duplicates when receiving a SHARE_PAD notification:
// Keep only one notification per channel: the stronger and more recent one
var channels = {};
handlers['SHARE_PAD'] = function (ctx, box, data, cb) {
var msg = data.msg;
var hash = data.hash;
var content = msg.content;
// content.name, content.title, content.href, content.password
var channel = Hash.hrefToHexChannelId(content.href, content.password);
var parsed = Hash.parsePadUrl(content.href);
var mode = parsed.hashData && parsed.hashData.mode || 'n/a';
var old = channels[channel];
var toRemove;
if (old) {
// New hash is weaker, ignore
if (old.mode === 'edit' && mode === 'view') {
return void cb(true);
}
// New hash is not weaker, clear the old one
toRemove = old.data;
}
// Update the data
channels[channel] = {
mode: mode,
data: {
type: box.type,
hash: hash
}
};
cb(false, toRemove);
};
removeHandlers['SHARE_PAD'] = function (ctx, box, data, hash) {
var content = data.content;
var channel = Hash.hrefToHexChannelId(content.href, content.password);
var old = channels[channel];
if (old && old.data && old.data.hash === hash) {
delete channels[channel];
}
};
return { return {
add: function (ctx, box, data, cb) { add: function (ctx, box, data, cb) {
/** /**

@ -157,6 +157,7 @@ proxy.mailboxes = {
var openChannel = function (ctx, type, m, onReady) { var openChannel = function (ctx, type, m, onReady) {
var box = ctx.boxes[type] = { var box = ctx.boxes[type] = {
type: type,
queue: [], // Store the messages to send when the channel is ready queue: [], // Store the messages to send when the channel is ready
history: [], // All the hashes loaded from the server in corretc order history: [], // All the hashes loaded from the server in corretc order
content: {}, // Content of the messages that should be displayed content: {}, // Content of the messages that should be displayed
@ -228,8 +229,8 @@ proxy.mailboxes = {
msg: msg, msg: msg,
hash: hash hash: hash
}; };
Handlers.add(ctx, box, message, function (toDismiss) { Handlers.add(ctx, box, message, function (dismissed, toDismiss) {
if (toDismiss) { if (dismissed) { // This message should be removed
dismiss(ctx, { dismiss(ctx, {
type: type, type: type,
hash: hash hash: hash
@ -238,6 +239,11 @@ proxy.mailboxes = {
}); });
return; return;
} }
if (toDismiss) { // List of other messages to remove
dismiss(ctx, toDismiss, '', function () {
console.log('Notification handled automatically');
});
}
box.content[hash] = msg; box.content[hash] = msg;
showMessage(ctx, type, message); showMessage(ctx, type, message);
}); });

@ -26,7 +26,10 @@ define([
if (!c.id) { c.id = chan.wc.myID + '-' + client; } if (!c.id) { c.id = chan.wc.myID + '-' + client; }
chan.history.forEach(function (msg) { chan.history.forEach(function (msg) {
ctx.emit('MESSAGE', msg, [client]); ctx.emit('MESSAGE', {
msg: msg,
validateKey: chan.validateKey
}, [client]);
}); });
// ==> And push the new tab to the list // ==> And push the new tab to the list
@ -37,7 +40,8 @@ define([
var onOpen = function (wc) { var onOpen = function (wc) {
ctx.channels[channel] = ctx.channels[channel] || { ctx.channels[channel] = ctx.channels[channel] || {
history: [] history: [],
validateKey: obj.validateKey
}; };
chan = ctx.channels[channel]; chan = ctx.channels[channel];
@ -61,7 +65,10 @@ define([
}); });
wc.on('message', function (msg) { wc.on('message', function (msg) {
chan.history.push(msg); chan.history.push(msg);
ctx.emit('MESSAGE', msg, chan.clients); ctx.emit('MESSAGE', {
msg: msg,
validateKey: chan.validateKey
}, chan.clients);
}); });
chan.wc = wc; chan.wc = wc;
@ -101,6 +108,7 @@ define([
}; };
network.on('message', function (msg, sender) { network.on('message', function (msg, sender) {
if (!ctx.channels[channel]) { return; }
var hk = network.historyKeeper; var hk = network.historyKeeper;
if (sender !== hk) { return; } if (sender !== hk) { return; }
@ -115,7 +123,12 @@ define([
// Keep only metadata messages for the current channel // Keep only metadata messages for the current channel
if (parsed.channel && parsed.channel !== channel) { return; } if (parsed.channel && parsed.channel !== channel) { return; }
// Ignore the metadata message // Ignore the metadata message
if (parsed.validateKey && parsed.channel) { return; } if (parsed.validateKey && parsed.channel) {
if (!chan.validateKey) {
chan.validateKey = parsed.validateKey;
}
return;
}
// End of history: emit READY // End of history: emit READY
if (parsed.state && parsed.state === 1 && parsed.channel) { if (parsed.state && parsed.state === 1 && parsed.channel) {
ctx.emit('READY', '', chan.clients); ctx.emit('READY', '', chan.clients);
@ -132,7 +145,9 @@ define([
if (hash === chan.lastKnownHash || hash === chan.lastCpHash) { return; } if (hash === chan.lastKnownHash || hash === chan.lastCpHash) { return; }
chan.lastKnownHash = hash; chan.lastKnownHash = hash;
ctx.emit('MESSAGE', msg, chan.clients); ctx.emit('MESSAGE', {
msg: msg,
}, chan.clients);
chan.history.push(msg); chan.history.push(msg);
}); });
@ -176,7 +191,9 @@ define([
return void chan.sendMsg(data.isCp, cb); return void chan.sendMsg(data.isCp, cb);
} }
chan.sendMsg(data.msg, cb); chan.sendMsg(data.msg, cb);
ctx.emit('MESSAGE', data.msg, chan.clients.filter(function (cl) { ctx.emit('MESSAGE', {
msg: data.msg
}, chan.clients.filter(function (cl) {
return cl !== clientId; return cl !== clientId;
})); }));
}; };

@ -625,6 +625,11 @@ define([
var root = exp.find([ROOT]); var root = exp.find([ROOT]);
var toClean = []; var toClean = [];
for (var id in fd) { for (var id in fd) {
if (String(id) !== String(Number(id))) {
debug("Invalid file ID in filesData.", id);
toClean.push(id);
continue;
}
id = Number(id); id = Number(id);
var el = fd[id]; var el = fd[id];

@ -342,7 +342,7 @@ define([
}); });
// Remove the elements from the old location (without unpinning) // Remove the elements from the old location (without unpinning)
Env.user.userObject.delete(resolved.main, waitFor()); Env.user.userObject.delete(resolved.main, waitFor()); // FIXME waitFor() is called synchronously
} }
} }
} }
@ -369,7 +369,7 @@ define([
if (copy) { return; } if (copy) { return; }
// Remove the elements from the old location (without unpinning) // Remove the elements from the old location (without unpinning)
uoFrom.delete(paths, waitFor()); uoFrom.delete(paths, waitFor()); // FIXME waitFor() is called synchronously
} }
}); });
} }
@ -707,6 +707,7 @@ define([
if (type === 'expirable') { if (type === 'expirable') {
return function (fileId) { return function (fileId) {
var data = userObject.getFileData(fileId); var data = userObject.getFileData(fileId);
if (!data) { return; }
// Don't push duplicates // Don't push duplicates
if (result.indexOf(data.channel) !== -1) { return; } if (result.indexOf(data.channel) !== -1) { return; }
// Return pads owned by someone else or expired by time // Return pads owned by someone else or expired by time
@ -718,6 +719,7 @@ define([
if (type === 'owned') { if (type === 'owned') {
return function (fileId) { return function (fileId) {
var data = userObject.getFileData(fileId); var data = userObject.getFileData(fileId);
if (!data) { return; }
// Don't push duplicates // Don't push duplicates
if (result.indexOf(data.channel) !== -1) { return; } if (result.indexOf(data.channel) !== -1) { return; }
// Return owned pads // Return owned pads
@ -729,6 +731,7 @@ define([
if (type === "pin") { if (type === "pin") {
return function (fileId) { return function (fileId) {
var data = userObject.getFileData(fileId); var data = userObject.getFileData(fileId);
if (!data) { return; }
// Don't pin pads owned by someone else // Don't pin pads owned by someone else
if (_ownedByOther(Env, data.owners)) { return; } if (_ownedByOther(Env, data.owners)) { return; }
// Don't push duplicates // Don't push duplicates

@ -223,6 +223,11 @@ define([
sframeChan.event("EV_PAD_PASSWORD"); sframeChan.event("EV_PAD_PASSWORD");
}; };
if (!val && sessionStorage.newPadPassword) {
val = sessionStorage.newPadPassword;
delete sessionStorage.newPadPassword;
}
if (val) { if (val) {
password = val; password = val;
Cryptpad.getFileSize(window.location.href, password, waitFor(function (e, size) { Cryptpad.getFileSize(window.location.href, password, waitFor(function (e, size) {

@ -832,11 +832,17 @@ MessengerUI, Messages) {
return $spin; return $spin;
}; };
var createLimit = function (toolbar) { var createLimit = function (toolbar, config) {
var $limitIcon = $('<span>', {'class': 'fa fa-exclamation-triangle'}); var $limitIcon = $('<span>', {'class': 'fa fa-exclamation-triangle'});
var $limit = toolbar.$userAdmin.find('.'+LIMIT_CLS).attr({ var $limit = toolbar.$userAdmin.find('.'+LIMIT_CLS).attr({
'title': Messages.pinLimitReached 'title': Messages.pinLimitReached
}).append($limitIcon).hide(); }).append($limitIcon).hide();
var priv = config.metadataMgr.getPrivateData();
var origin = priv.origin;
var l = document.createElement("a");
l.href = origin;
var todo = function (e, overLimit) { var todo = function (e, overLimit) {
if (e) { return void console.error("Unable to get the pinned usage", e); } if (e) { return void console.error("Unable to get the pinned usage", e); }
if (overLimit) { if (overLimit) {
@ -845,7 +851,7 @@ MessengerUI, Messages) {
key = 'pinLimitReachedAlertNoAccounts'; key = 'pinLimitReachedAlertNoAccounts';
} }
$limit.show().click(function () { $limit.show().click(function () {
UI.alert(Messages._getKey(key, [encodeURIComponent(window.location.hostname)]), null, true); UI.alert(Messages._getKey(key, [encodeURIComponent(l.hostname)]), null, true);
}); });
} }
}; };

@ -565,7 +565,7 @@
"download_step1": "Laden...", "download_step1": "Laden...",
"download_step2": "Entschlüsselung...", "download_step2": "Entschlüsselung...",
"todo_title": "CryptTodo", "todo_title": "CryptTodo",
"todo_newTodoNamePlaceholder": "Beschreibe deine Aufgabe...", "todo_newTodoNamePlaceholder": "Beschreibe deine Aufgabe",
"todo_newTodoNameTitle": "Diese Aufgabe zu deiner ToDo-Liste hinzufügen", "todo_newTodoNameTitle": "Diese Aufgabe zu deiner ToDo-Liste hinzufügen",
"todo_markAsCompleteTitle": "Diese Aufgabe als erledigt markieren", "todo_markAsCompleteTitle": "Diese Aufgabe als erledigt markieren",
"todo_markAsIncompleteTitle": "Diese Aufgabe als nicht erledigt markieren", "todo_markAsIncompleteTitle": "Diese Aufgabe als nicht erledigt markieren",
@ -830,7 +830,7 @@
"generic": { "generic": {
"more": "Erfahre mehr über die Nutzung von CryptPad, indem du unsere <a href=\"/faq.html\" target=\"_blank\">FAQ</a> liest", "more": "Erfahre mehr über die Nutzung von CryptPad, indem du unsere <a href=\"/faq.html\" target=\"_blank\">FAQ</a> liest",
"share": "Benutze das Teilen-Menü (<span class=\"fa fa-share-alt\"></span>), um Links zu generieren, die Mitarbeiter zum Lesen oder Bearbeiten einladen", "share": "Benutze das Teilen-Menü (<span class=\"fa fa-share-alt\"></span>), um Links zu generieren, die Mitarbeiter zum Lesen oder Bearbeiten einladen",
"save": "Alle Änderungen werden automatisch synchronisiert. Du misst sie also nicht speichern" "save": "Alle Änderungen werden automatisch synchronisiert. Du musst sie also nicht selbst speichern"
}, },
"text": { "text": {
"formatting": "Du kannst die Werkzeugleiste anzeigen oder verbergen, indem du auf <span class=\"fa fa-caret-down\"></span> oder <span class=\"fa fa-caret-up\"></span> klickst", "formatting": "Du kannst die Werkzeugleiste anzeigen oder verbergen, indem du auf <span class=\"fa fa-caret-down\"></span> oder <span class=\"fa fa-caret-up\"></span> klickst",

@ -1075,5 +1075,33 @@
"share_withFriends": "Share", "share_withFriends": "Share",
"notifications_dismiss": "Dismiss", "notifications_dismiss": "Dismiss",
"fm_info_sharedFolderHistory": "This is only the history of your shared folder: <b>{0}</b><br/>Your CryptDrive will stay in read-only mode while you navigate.", "fm_info_sharedFolderHistory": "This is only the history of your shared folder: <b>{0}</b><br/>Your CryptDrive will stay in read-only mode while you navigate.",
"share_description": "Choose what you'd like to share and either get the link or send it directly to your CryptPad friends." "share_description": "Choose what you'd like to share and either get the link or send it directly to your CryptPad friends.",
"supportPage": "Support",
"admin_cat_support": "Support",
"admin_supportInitHelp": "Your server is not yet configured to have a support mailbox. If you want a support mailbox to receive messages from your users, you should ask your server administrator to run the script located in \"./scripts/generate-admin-keys.js\", then store the public key in the \"config.js\" file and send you the private key.",
"admin_supportInitPrivate": "Your CryptPad instance is configured to use a support mailbox but your account doesn't have the correct private key to access it. Please use the following form to add or update the private key to your account.",
"admin_supportAddKey": "Add private key",
"admin_supportAddError": "Invalid private key",
"admin_supportInitTitle": "Support mailbox initialization",
"admin_supportInitHint": "You can configure a support mailbox in order to give users of your CryptPad instance a way to contact you securely if they have an issue with their account.",
"admin_supportListTitle": "Support mailbox",
"admin_supportListHint": "Here is the list of tickets sent by the users to the support mailbox. All the administrators can see the messages and the answers. A closed ticket cannot be reopened. You can only remove (hide) closed tickets, and the removed tickets are still visible by the other administrators.",
"support_disabledTitle": "Support is not enabled",
"support_disabledHint": "This CryptPad instance is not yet configured to use a support form.",
"support_cat_new": "New ticket",
"support_formTitle": "Ticket title",
"support_formHint": "This form can be used to create a new support ticket. Using this form, you can contact the administrators to solve issues or ask any question in a secure way. Please don't create a new ticket if you already have an open ticket about the same issue, but use reply button to provide more information.",
"support_formButton": "Send",
"support_formTitleError": "Error: title is empty",
"support_formContentError": "Error: content is empty",
"support_formMessage": "Type your message...",
"support_cat_tickets": "Existing tickets",
"support_listTitle": "Support tickets",
"support_listHint": "Here is the list of tickets sent to the administrators and their answers. A closed ticket cannot be re-opened, you have to make a new one. You can hide tickets that have been closed but they will still be visible by the administrators.",
"support_answer": "Reply",
"support_close": "Close the ticket",
"support_remove": "Remove the ticket",
"support_showData": "Show/hide user data",
"support_from": "<b>From:</b> {0}",
"support_closed": "This ticket has been closed"
} }

@ -311,12 +311,12 @@ define([
_getFiles[FILES_DATA] = function () { _getFiles[FILES_DATA] = function () {
var ret = []; var ret = [];
if (!files[FILES_DATA]) { return ret; } if (!files[FILES_DATA]) { return ret; }
return Object.keys(files[FILES_DATA]).map(Number); return Object.keys(files[FILES_DATA]).map(Number).filter(Boolean);
}; };
_getFiles[SHARED_FOLDERS] = function () { _getFiles[SHARED_FOLDERS] = function () {
var ret = []; var ret = [];
if (!files[SHARED_FOLDERS]) { return ret; } if (!files[SHARED_FOLDERS]) { return ret; }
return Object.keys(files[SHARED_FOLDERS]).map(Number); return Object.keys(files[SHARED_FOLDERS]).map(Number).filter(Boolean);
}; };
var getFiles = exp.getFiles = function (categories) { var getFiles = exp.getFiles = function (categories) {
var ret = []; var ret = [];

@ -2173,6 +2173,7 @@ define([
pathname: "/drive/", pathname: "/drive/",
friends: friends, friends: friends,
title: data.title, title: data.title,
password: data.password,
common: common, common: common,
hashes: { hashes: {
editHash: parsed.hash editHash: parsed.hash
@ -3510,6 +3511,7 @@ define([
friends: friends, friends: friends,
title: data.title, title: data.title,
common: common, common: common,
password: data.password,
hashes: { hashes: {
editHash: parsed.hash editHash: parsed.hash
} }
@ -3523,6 +3525,7 @@ define([
origin: APP.origin, origin: APP.origin,
pathname: "/" + padType + "/", pathname: "/" + padType + "/",
friends: friends, friends: friends,
password: data.password,
hashes: { hashes: {
editHash: parsed.hash, editHash: parsed.hash,
viewHash: roParsed.hash, viewHash: roParsed.hash,

@ -42,6 +42,7 @@ define([
var modal = f({ var modal = f({
origin: origin, origin: origin,
pathname: pathname, pathname: pathname,
password: priv.password,
hashes: hashes, hashes: hashes,
common: common, common: common,
title: data.title, title: data.title,

Loading…
Cancel
Save