Merge branch 'staging' into team

pull/1/head
yflory 5 years ago
commit 798296489a

@ -103,7 +103,7 @@ define([
])*/
])
]),
h('div.cp-version-footer', "CryptPad v3.0.1 (Aurochs' revenge)")
h('div.cp-version-footer', "CryptPad v3.1.0 (Baiji)")
]);
};

@ -1,8 +1,7 @@
module.exports = function (f) {
var called;
module.exports = function (f, g) {
return function () {
if (called) { return; }
called = true;
if (!f) { return; }
f.apply(this, Array.prototype.slice.call(arguments));
f = g;
};
};

@ -1,7 +1,7 @@
{
"name": "cryptpad",
"description": "realtime collaborative visual editor with zero knowlege server",
"version": "3.0.1",
"version": "3.1.0",
"license": "AGPL-3.0+",
"repository": {
"type": "git",

@ -294,37 +294,33 @@ var getUploadSize = function (Env, channel, cb) { // FIXME FILES
});
};
const batchFileSize = BatchRead("GET_FILE_SIZE");
var getFileSize = function (Env, channel, cb) {
if (!isValidId(channel)) { return void cb('INVALID_CHAN'); }
batchFileSize(channel, cb, function (done) {
if (channel.length === 32) {
if (typeof(Env.msgStore.getChannelSize) !== 'function') {
return done('GET_CHANNEL_SIZE_UNSUPPORTED');
}
return void Env.msgStore.getChannelSize(channel, function (e, size /*:number*/) {
if (e) {
if (e.code === 'ENOENT') { return void done(void 0, 0); }
return void done(e.code);
}
done(void 0, size);
});
if (channel.length === 32) {
if (typeof(Env.msgStore.getChannelSize) !== 'function') {
return cb('GET_CHANNEL_SIZE_UNSUPPORTED');
}
// 'channel' refers to a file, so you need another API
getUploadSize(Env, channel, function (e, size) {
if (typeof(size) === 'undefined') { return void done(e); }
done(void 0, size);
return void Env.msgStore.getChannelSize(channel, function (e, size /*:number*/) {
if (e) {
if (e.code === 'ENOENT') { return void cb(void 0, 0); }
return void cb(e.code);
}
cb(void 0, size);
});
}
// 'channel' refers to a file, so you need another API
getUploadSize(Env, channel, function (e, size) {
if (typeof(size) === 'undefined') { return void cb(e); }
cb(void 0, size);
});
};
const batchMetadata = BatchRead("GET_METADATA");
var getMetadata = function (Env, channel, cb) {
if (!isValidId(channel)) { return void cb('INVALID_CHAN'); }
if (channel.length !== 32) { return cb("INVALID_CHAN"); }
if (channel.length !== 32) { return cb("INVALID_CHAN_LENGTH"); }
batchMetadata(channel, cb, function (done) {
var ref = {};

@ -251,8 +251,7 @@ nThen(function (w) {
return void console.error(err);
}
// XXX validate that the write was actually successful by checking its size
// TODO validate that the write was actually successful by checking its size
response = response;
// shutdown doesn't work, so we need to do this instead
}));

@ -76,7 +76,7 @@ var getMetadataAtPath = function (Env, path, cb) {
catch (e) {
console.log("getMetadataAtPath");
console.error(e);
complete('INVALID_METADATA');
complete('INVALID_METADATA', metadata);
}
});
stream.on('end', function () {

@ -158,14 +158,14 @@ define([
var done = function () {
clearTimeout(timeout);
if (btime) {
console.log("Compiling [" + url + "] took " + (+new Date() - btime) + "ms");
console.info("Compiling [" + url + "] took " + (+new Date() - btime) + "ms");
}
cb();
};
stack.push(url);
cacheGet(url, function (css) {
if (css) { return void loadSubmodulesAndInject(css, url, done, stack); }
console.log('CACHE MISS ' + url);
console.debug('CACHE MISS ' + url);
((/\.less([\?\#].*)?$/.test(url)) ? loadLess : loadCSS)(url, function (err, css) {
if (!css) { return void console.error(err); }
var output = fixAllURLs(css, url);

@ -728,6 +728,15 @@ define([
network.on('reconnect', function () {
if (channel && channel.stopped) { return; }
if (!channels[data.channel]) { return; }
if (!joining[data.channel]) {
joining[data.channel] = function () {
console.log("reconnected to %s", data.channel);
};
} else {
console.error("Reconnected to a chat channel (%s) which was not fully connected", data.channel);
}
network.join(data.channel).then(onOpen, function (err) {
console.error(err);
});

@ -406,7 +406,11 @@ define([
$d.append(UI.dialog.selectable(owners, {
id: 'cp-app-prop-owners',
}));
if (owned) {
var parsed;
if (data.href || data.roHref) {
parsed = Hash.parsePadUrl(data.href || data.roHref);
}
if (owned && data.roHref && parsed.type !== 'drive' && parsed.hashData.type === 'pad') {
var manageOwners = h('button.no-margin', Messages.owner_openModalButton);
$(manageOwners).click(function () {
var modal = createOwnerModal(common, data);
@ -445,7 +449,6 @@ define([
$d.append(password);
}
var parsed = Hash.parsePadUrl(data.href || data.roHref);
if (!data.noEditPassword && owned && parsed.hashData.type === 'pad' && parsed.type !== "sheet") { // FIXME SHEET fix password change for sheets
var sframeChan = common.getSframeChannel();
var changePwTitle = Messages.properties_changePassword;
@ -590,7 +593,7 @@ define([
id: 'cp-app-prop-size',
}));
if (data.sharedFolder) {
if (data.sharedFolder && false) {
$('<label>', {'for': 'cp-app-prop-channel'}).text('Channel ID').appendTo($d);
if (AppConfig.pinBugRecovery) { $d.append(h('p', AppConfig.pinBugRecovery)); }
$d.append(UI.dialog.selectable(data.channel, {

@ -222,13 +222,14 @@
return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
};
Util.noop = function () {};
/* for wrapping async functions such that they can only be called once */
Util.once = function (f) {
var called;
Util.once = function (f, g) {
return function () {
if (called) { return; }
called = true;
if (!f) { return; }
f.apply(this, Array.prototype.slice.call(arguments));
f = g;
};
};

@ -1366,7 +1366,7 @@ define([
console.log(parsed);
return;
} else {
console.log(parsed);
//console.log(parsed);
}
Util.fetch(parsed.href, waitFor(function (err, arraybuffer) {
if (err) { return void console.log(err); }

@ -4,9 +4,10 @@ define(['/api/config'], function (ApiConfig) {
var DEFAULT_MAIN = '/customize/main-favicon.png?' + ApiConfig.requireConf.urlArgs;
var DEFAULT_ALT = '/customize/alt-favicon.png?' + ApiConfig.requireConf.urlArgs;
var document = window.document;
var isSupported = Module.isSupported = function () {
return typeof(window.Notification) === 'function';
return typeof(window.Notification) === 'function' && window.isSecureContext;
};
var hasPermission = Module.hasPermission = function () {
@ -22,9 +23,11 @@ define(['/api/config'], function (ApiConfig) {
};
var create = Module.create = function (msg, title, icon) {
if (!icon) {
if (document && !icon) {
var favicon = document.getElementById('favicon');
icon = favicon.getAttribute('data-main-favicon') || DEFAULT_MAIN;
icon = favicon.getAttribute('data-main-favicon') || DEFAULT_ALT;
} else if (!icon) {
icon = DEFAULT_ALT;
}
return new Notification(title,{
@ -52,7 +55,10 @@ define(['/api/config'], function (ApiConfig) {
};
var createFavicon = function () {
console.log("creating favicon");
if (!document) {
return void console.error('document is not available in this context');
}
console.debug("creating favicon");
var fav = document.createElement('link');
var attrs = {
id: 'favicon',
@ -68,9 +74,12 @@ define(['/api/config'], function (ApiConfig) {
document.head.appendChild(fav);
};
if (!document.getElementById('favicon')) { createFavicon(); }
if (document && !document.getElementById('favicon')) { createFavicon(); }
Module.tab = function (frequency, count) {
if (!document) {
return void console.error('document is not available in this context');
}
var key = '_pendingTabNotification';
var favicon = document.getElementById('favicon');

@ -48,6 +48,7 @@ define([
};
var CHECKPOINT_INTERVAL = 50;
var DISPLAY_RESTORE_BUTTON = false;
var debug = function (x) {
if (!window.CP_DEV_MODE) { return; }
@ -237,6 +238,35 @@ define([
}
};
var onUploaded = function (ev, data, err) {
if (err) {
console.error(err);
return void UI.alert(Messages.oo_saveError);
}
var i = Math.floor(ev.index / CHECKPOINT_INTERVAL);
content.hashes[i] = {
file: data.url,
hash: ev.hash,
index: ev.index
};
oldHashes = JSON.parse(JSON.stringify(content.hashes));
content.saveLock = undefined;
APP.onLocal();
APP.realtime.onSettle(function () {
fixSheets();
UI.log(Messages.saved);
if (ev.callback) {
return void ev.callback();
}
});
sframeChan.query('Q_OO_COMMAND', {
cmd: 'UPDATE_HASH',
data: ev.hash
}, function (err, obj) {
if (err || (obj && obj.error)) { console.error(err || obj.error); }
});
};
var fmConfig = {
noHandlers: true,
noStore: true,
@ -244,32 +274,7 @@ define([
onUploaded: function (ev, data) {
if (!data || !data.url) { return; }
sframeChan.query('Q_OO_SAVE', data, function (err) {
if (err) {
console.error(err);
return void UI.alert(Messages.oo_saveError);
}
var i = Math.floor(ev.index / CHECKPOINT_INTERVAL);
content.hashes[i] = {
file: data.url,
hash: ev.hash,
index: ev.index
};
oldHashes = JSON.parse(JSON.stringify(content.hashes));
content.saveLock = undefined;
APP.onLocal();
APP.realtime.onSettle(function () {
fixSheets();
UI.log(Messages.saved);
if (ev.callback) {
return void ev.callback();
}
});
sframeChan.query('Q_OO_COMMAND', {
cmd: 'UPDATE_HASH',
data: ev.hash
}, function (err, obj) {
if (err || (obj && obj.error)) { console.error(err || obj.error); }
});
onUploaded(ev, data, err);
});
}
};
@ -307,6 +312,19 @@ define([
}
}, to);
};
var restoreLastCp = function () {
content.saveLock = myOOId;
APP.onLocal();
APP.realtime.onSettle(function () {
onUploaded({
hash: ooChannel.lastHash,
index: ooChannel.cpIndex
}, {
url: getLastCp().file,
});
});
};
var openRtChannel = function (cb) {
if (rtChannel.ready) { return void cb(); }
@ -880,6 +898,16 @@ define([
});
$save.appendTo($rightside);
}
if (window.CP_DEV_MODE || DISPLAY_RESTORE_BUTTON) {
common.createButton('', true, {
name: 'restore',
icon: 'fa-history',
hiddenReadOnly: true
}).click(function () {
if (initializing) { return void console.error('initializing'); }
restoreLastCp();
}).attr('title', 'Restore last checkpoint').appendTo($rightside);
}
var $export = common.createButton('export', true, {}, exportFile);
$export.appendTo($rightside);

@ -703,8 +703,13 @@ define([
href: href,
channel: channel,
title: data.driveReadmeTitle,
owners: [ store.proxy.edPublic ],
};
Store.addPad(clientId, fileData, cb);
}, {
metadata: {
owners: [ store.proxy.edPublic ],
},
});
});
};
@ -989,11 +994,18 @@ define([
pad.href = href;
});
// If we've just accepted ownership for a pad stored in a shared folder,
// we need to make a copy of this pad in our drive. We're going to check
// the pad is owned by us BUT is not stored in our main drive
var inMyDrive = datas.some(function (obj) {
return !obj.fId;
});
// XXX owned by one of our teams?
var ownedByMe = Array.isArray(owners) && owners.indexOf(store.proxy.edPublic) !== -1;
// Add the pad if it does not exist in our drive
if (!contains) {
if (!contains || (ownedByMe && !inMyDrive)) {
var autoStore = Util.find(store.proxy, ['settings', 'general', 'autostore']);
// XXX owned by one of our teams?
var ownedByMe = Array.isArray(owners) && owners.indexOf(store.proxy.edPublic) !== -1;
if (autoStore !== 1 && !data.forceSave && !data.path && !ownedByMe) {
// send event to inner to display the corner popup
postMessage(clientId, "AUTOSTORE_DISPLAY_POPUP", {
@ -1920,12 +1932,12 @@ define([
broadcast([], "UPDATE_METADATA");
},
pinPads: function (data, cb) { Store.pinPads(null, data, cb); },
}, waitFor, function (ev, data, clients) {
}, waitFor, function (ev, data, clients, cb) {
clients.forEach(function (cId) {
postMessage(cId, 'MAILBOX_EVENT', {
ev: ev,
data: data
});
}, cb);
});
});
};

@ -148,12 +148,15 @@ define([
return void cb({error: err});
});
network.on('reconnect', function () {
var onReconnect = function () {
if (!ctx.channels[channel]) { console.log("cant reconnect", channel); return; }
network.join(channel).then(onOpen, function (err) {
console.error(err);
});
});
};
ctx.channels[channel] = ctx.channels[channel] || {};
ctx.channels[channel].onReconnect = onReconnect;
network.on('reconnect', onReconnect);
};
var updateCursor = function (ctx, data, client, cb) {
@ -173,6 +176,10 @@ define([
var channel = ctx.channels[cursorChan];
if (channel.padChan !== padChan) { return; }
if (channel.wc) { channel.wc.leave(); }
if (channel.onReconnect) {
var network = ctx.store.network;
network.off('reconnect', channel.onReconnect);
}
delete ctx.channels[cursorChan];
return true;
});
@ -190,6 +197,10 @@ define([
chan.clients = chan.clients.filter(filter);
if (chan.clients.length === 0) {
if (chan.wc) { chan.wc.leave(); }
if (chan.onReconnect) {
var network = ctx.store.network;
network.off('reconnect', chan.onReconnect);
}
delete ctx.channels[k];
}
}

@ -2,10 +2,11 @@ define([
'/common/common-util.js',
'/common/common-hash.js',
'/common/common-realtime.js',
'/common/notify.js',
'/common/outer/mailbox-handlers.js',
'/bower_components/chainpad-netflux/chainpad-netflux.js',
'/bower_components/chainpad-crypto/crypto.js',
], function (Util, Hash, Realtime, Handlers, CpNetflux, Crypto) {
], function (Util, Hash, Realtime, Notify, Handlers, CpNetflux, Crypto) {
var Mailbox = {};
var TYPES = [
@ -54,11 +55,11 @@ proxy.mailboxes = {
return (m.viewed || []).indexOf(hash) === -1 && hash !== m.lastKnownHash;
};
var showMessage = function (ctx, type, msg, cId) {
var showMessage = function (ctx, type, msg, cId, cb) {
ctx.emit('MESSAGE', {
type: type,
content: msg
}, cId ? [cId] : ctx.clients);
}, cId ? [cId] : ctx.clients, cb);
};
var hideMessage = function (ctx, type, hash, clients) {
ctx.emit('VIEWED', {
@ -272,7 +273,11 @@ proxy.mailboxes = {
});
}
box.content[hash] = msg;
showMessage(ctx, type, message);
showMessage(ctx, type, message, null, function (obj) {
if (!box.ready) { return; }
if (!obj || !obj.msg) { return; }
Notify.system(undefined, obj.msg);
});
});
} else {
// Message has already been viewed by the user
@ -320,6 +325,7 @@ proxy.mailboxes = {
view(n);
}
});
box.ready = true;
// Continue
onReady();
};

@ -124,10 +124,16 @@ define([
removeFromHistory(data.type, data.hash);
};
var onMessage = function (data) {
var onMessage = function (data, cb) {
// data = { type: 'type', content: {msg: 'msg', hash: 'hash'} }
console.log(data.type, data.content);
console.debug(data.type, data.content);
pushMessage(data);
if (data.content && typeof (data.content.getFormatText) === "function") {
var text = $('<div>').html(data.content.getFormatText()).text();
cb({
msg: text
});
}
if (!history[data.type]) { history[data.type] = []; }
history[data.type].push(data.content);
};
@ -224,7 +230,7 @@ define([
// CHANNEL WITH WORKER
sframeChan.on('EV_MAILBOX_EVENT', function (obj) {
sframeChan.on('EV_MAILBOX_EVENT', function (obj, cb) {
// obj = { ev: 'type', data: obj }
var ev = obj.ev;
var data = obj.data;
@ -232,7 +238,7 @@ define([
return void onHistory(data);
}
if (ev === 'MESSAGE') {
return void onMessage(data);
return void onMessage(data, cb);
}
if (ev === 'VIEWED') {
return void onViewed(data);

@ -414,8 +414,12 @@ define([
});
});
Cryptpad.mailbox.onEvent.reg(function (data) {
sframeChan.event('EV_MAILBOX_EVENT', data);
Cryptpad.mailbox.onEvent.reg(function (data, cb) {
sframeChan.query('EV_MAILBOX_EVENT', data, function (err, obj) {
if (!cb) { return; }
if (err) { return void cb({error: err}); }
cb(obj);
});
});
sframeChan.on('Q_MAILBOX_COMMAND', function (data, cb) {
Cryptpad.mailbox.execCommand(data, cb);

@ -351,13 +351,13 @@
"fm_info_sharedFolder": "Dieser Ordner ist geteilt. Da du aber nicht eingeloggt bist, hast du nur einen schreibgeschützen Zugriff.<br><a href=\"/register/\">Registriere</a> oder <a href=\"/login/\">logge ich ein</a>, damit du diesen Ordner in dein CryptDrive importieren und bearbeiten kannst.",
"fm_info_owned": "Diese Pads sind deine eigenen. Das heißt, dass du sie jederzeit vom Server entfernen kannst. Wenn du das machst, dann sind sie auch für andere Nutzer nicht mehr zugänglich.",
"fm_alert_backupUrl": "Backup-Link für dieses CryptDrive.<br>Es wird <strong>dringend empfohlen</strong>, diesen Link geheim zu halten.<br>Du kannst ihn benutzen, um deine gesamten Dateien abzurufen, wenn dein Browserspeicher gelöscht wurde.<br>Jede Person, die diesen Link hat, kann die Dateien in deinem CryptDrive bearbeiten oder löschen.<br>",
"fm_alert_anonymous": "Hallo, du benutzt CryptPad anonym. Das ist in Ordnung, aber Dokumente können nach einer längerer Inaktivität gelöscht werden. Wir haben fortgeschrittene Funktionen in anonymen CryptDrives deaktiviert, weil wir deutlich machen wollen, dass es kein sicherer Platz zur Ablage von Daten ist. Du kannst <a href=\"https://blog.cryptpad.fr/2017/05/17/You-gotta-log-in/\" target=\"_blank\">nachlesen</a>, weshalb wir das machen und weshalb du dich wirklich <a href=\"/register/\">registrieren</a> oder <a href=\"/login/\">einloggen</a> solltest.",
"fm_alert_anonymous": "Hallo, du benutzt CryptPad anonym. Das ist in Ordnung, aber Dokumente können nach längerer Inaktivität gelöscht werden. Wir haben fortgeschrittene Funktionen in anonymen CryptDrives deaktiviert, weil wir deutlich machen wollen, dass es kein sicherer Platz zur Ablage von Daten ist. Du kannst <a href=\"https://blog.cryptpad.fr/2017/05/17/You-gotta-log-in/\" target=\"_blank\">nachlesen</a>, weshalb wir das machen und weshalb du dich wirklich <a href=\"/register/\">registrieren</a> oder <a href=\"/login/\">einloggen</a> solltest.",
"fm_backup_title": "Backup-Link",
"fm_nameFile": "Wie soll diese Datei heißen?",
"fm_error_cantPin": "Interner Serverfehler. Bitte lade die Seite neu und versuche es erneut.",
"fm_viewListButton": "Listenansicht",
"fm_viewGridButton": "Kachelansicht",
"fm_renamedPad": "Du hast einen benutzerdefinierten Namen für dieses Pad gesetzt. Sein geteilter Titel ist:<br><b>{0}</b>",
"fm_renamedPad": "Du hast einen benutzerdefinierten Namen für dieses Pad gesetzt. Der geteilte Titel ist:<br><b>{0}</b>",
"fm_canBeShared": "Dieser Ordner kann geteilt werden",
"fm_prop_tagsList": "Tags",
"fm_burnThisDriveButton": "Alle Informationen löschen, die CryptPad in deinem Browser speichert",
@ -1131,7 +1131,7 @@
"uploadFolder_modal_filesPassword": "Passwort für Dateien",
"uploadFolder_modal_owner": "Eigene Dateien",
"uploadFolder_modal_forceSave": "Dateien im CryptDrive speichern",
"convertFolderToSF_SFParent": "Dieser Ordner kann an seinem aktuellen Ort nicht einen geteilten Ordner umgewandelt werden. Verschiebe ihn zunächst aus dem übergeordneten geteilten Ordner heraus.",
"convertFolderToSF_SFParent": "Dieser Ordner kann an seinem aktuellen Ort nicht in einen geteilten Ordner umgewandelt werden. Verschiebe ihn zunächst aus dem übergeordneten geteilten Ordner heraus.",
"convertFolderToSF_SFChildren": "Dieser Ordner kann nicht in einen geteilten Ordner umgewandelt werden, weil er bereits geteilte Ordner enthält. Verschiebe diese geteilten Ordner zunächst an einen anderen Ort.",
"convertFolderToSF_confirm": "Dieser Ordner muss in einen geteilten Ordner umgewandelt werden, damit ihn andere sehen können. Fortfahren?",
"pricing": "Preise und Konditionen",
@ -1149,5 +1149,16 @@
"owner_removeConfirm": "Bist du sicher, dass die Eigentümerschaft der ausgewählten Benutzer entfernen möchtest? Sie werden über diese Aktion informiert.",
"owner_removeMeConfirm": "Du bist dabei, deine Rechte als Eigentümer aufzugeben. Diese Aktion kannst du nicht rückgängig machen. Bist du sicher?",
"owner_openModalButton": "Eigentümer verwalten",
"owner_add": "{0} möchte ein Eigentümer des Pads <b>{1}</b> sein. Bist du damit einverstanden?"
"owner_add": "{0} möchte ein Eigentümer des Pads <b>{1}</b> sein. Bist du damit einverstanden?",
"owner_removeText": "Einen Eigentümer entfernen",
"owner_removePendingText": "Eine ausstehende Einladung zurückziehen",
"owner_addText": "Einen Freund zur Mit-Eigentümerschaft einladen",
"owner_removePendingButton": "Ausgewählte Einladungen zurückziehen",
"owner_addButton": "Zur Eigentümerschaft einladen",
"owner_addConfirm": "Mit-Eigentümer können den Inhalt bearbeiten und dich als Eigentümer entfernen. Bist du sicher?",
"owner_request": "{0} möchte dich zum Eigentümer von <b>{1}</b> machen",
"owner_request_accepted": "{0} hat deine Einladung angenommen, ein Eigentümer von <b>{1}</b> zu sein",
"owner_request_declined": "{0} hat deine Einladung abgelehnt, ein Eigentümer von <b>{1}</b> zu sein",
"owner_removed": "{0} hat dich als Eigentümer von <b>{1}</b> entfernt",
"owner_removedPending": "{0} hat die Einladung zur Eigentümerschaft von <b>{1}</b> zurückgezogen"
}

Loading…
Cancel
Save