Merge branch 'staging' into 5.3-storage

This commit is contained in:
ansuz 2023-03-02 10:53:05 +05:30
commit 6bb336034b
24 changed files with 148 additions and 104 deletions

View File

@ -52,6 +52,12 @@ body > .non-realtime:first-child + * {
margin-top: 0;
}
@media (max-width: 600px) {
body {
padding-bottom: 100px;
}
}
.cke_editable
{
font-size: 16px;

View File

@ -14,11 +14,6 @@ define([
return;
}
/*
Msg.install_header = "CryptPad Install"; // XXX
Msg.install_notes = "<ul class=\"cp-notes-list\"><li>Create your first admin account using this form.</li>" +
"<li>Please note your password carefully. <span class=\"red\">If you lose it there is no way we can recover your data.</span></li></ul>"; // XXX
*/
Msg.install_token = "Install token";
document.title = Msg.install_header;

View File

@ -329,8 +329,6 @@ commands.ADD_INSTALL_TOKEN = function (Env, args) {
var token = args[0];
// XXX check length, etc. ?
Env.installToken = token;
return true;

View File

@ -229,7 +229,7 @@ appIndexesToBuild.forEach(function (app) {
write(built, `./www/${app}/index.html`);
// XXX preloading version for inner.html
// TODO preloading version for inner.html
});
var instance;

View File

@ -22,7 +22,6 @@ nThen(function (w) {
console.log('Existing token');
token = Env.installToken;
}
// XXX IF ADMINS ABORT?
}));
}).nThen(function (w) {
if (Env.installToken) { return; }

View File

@ -1397,8 +1397,8 @@ ICS ==> create a new event with the same UID and a RECURRENCE-ID field (with a v
if (updatedOn) { delete APP.recurrenceRule._next; }
APP.wasRecurrent = Boolean(APP.recurrenceRule);
// XXX TEST
/*
// Test data:
APP.recurrenceRule = {
freq: 'yearly',
interval: 2,

View File

@ -146,6 +146,9 @@
flex: 1;
max-width: 100%;
resize: none;
.CodeMirror-sizer > div {
padding-bottom: 100px;
}
}
#cp-app-code-preview {
display: none !important;

View File

@ -332,6 +332,12 @@ define([
: Messages.error;
return void UI.warn(text);
}
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);
});
}));
}
}).nThen(function (waitFor) {
@ -867,7 +873,7 @@ define([
// In the properties, we should have the edit href if we know it.
// We should know it because the pad is stored, but it's better to check...
//if (!data.noEditPassword && !opts.noEditPassword && owned && data.href) {
if (!data.noEditPassword && !opts.noEditPassword && owned && data.href && parsed.type !== "form") { // XXX password change in forms block responses (validation & decryption)
if (!data.noEditPassword && !opts.noEditPassword && owned && data.href && parsed.type !== "form") { // TODO password change in forms block responses (validation & decryption)
var isOO = parsed.type === 'sheet';
var isFile = parsed.hashData.type === 'file';
var isSharedFolder = parsed.type === 'drive';

View File

@ -2134,9 +2134,7 @@ Uncaught TypeError: Cannot read property 'calculatedType' of null
var exportXLSXFile = function() {
var text = getContent();
var suggestion = Title.suggestTitle(Title.defaultTitle);
var ext = ['.xlsx', '.ods', '.bin',
//'.csv', // XXX 4.11.0
'.pdf'];
var ext = ['.xlsx', '.ods', '.bin', '.pdf'];
var type = common.getMetadataMgr().getPrivateData().ooType;
var warning = '';
if (type==="presentation") {

View File

@ -1694,7 +1694,7 @@ define([
var ed = Util.find(store, ['proxy', 'teams', teamId, 'keys', 'drive', 'edPublic']);
var edPrivate = Util.find(store, ['proxy', 'teams', teamId, 'keys', 'drive', 'edPrivate']);
if (allowed.indexOf(ed) === -1) { return false; }
if (!edPrivate) { return false; } // XXX: Only editors can authenticate...
if (!edPrivate) { return false; } // FIXME: Only editors can authenticate...
// This team is allowed: use its rpc
var t = teamModule.getTeam(teamId);
_store = t;
@ -1952,11 +1952,15 @@ define([
// contactPadOwner is used to send "REQUEST_ACCESS" messages
// and to notify form owners when sending a response
Store.contactPadOwner = function (clientId, data, cb) {
var owner = data.owner;
var owners = data.owners;
// If send is true, send the request to the owner.
if (owner) {
if (data.send) {
if (!Array.isArray(owners) || !owners.length) { return cb({state: false}); }
if (!data.send) { return void cb({state: true}); }
nThen(function (waitFor) {
owners.forEach(function (owner) {
var sendTo = function (query, msg, user, _cb) {
if (store.mailbox && !data.anon) {
return store.mailbox.sendTo(query, msg, user, _cb);
@ -1969,14 +1973,11 @@ define([
}, {
channel: owner.notifications,
curvePublic: owner.curvePublic
}, function () {
}, waitFor());
});
}).nThen(function () {
cb({state: true});
});
return;
}
return void cb({state: true});
}
cb({state: false});
};
Store.givePadAccess = function (clientId, data, cb) {
var edPublic = store.proxy.edPublic;

View File

@ -8,9 +8,10 @@ define([
'/customize/messages.js',
'/bower_components/nthen/index.js',
'chainpad-listmap',
'/lib/datepicker/flatpickr.js',
'/bower_components/chainpad-crypto/crypto.js',
'/bower_components/chainpad/chainpad.dist.js',
], function (Util, Hash, Constants, Realtime, Cache, Rec, Messages, nThen, Listmap, Crypto, ChainPad) {
], function (Util, Hash, Constants, Realtime, Cache, Rec, Messages, nThen, Listmap, FP, Crypto, ChainPad) {
var Calendar = {};
var getStore = function (ctx, id) {
@ -131,9 +132,9 @@ define([
var last = ctx.store.data.lastVisit;
if (ev.isAllDay) {
if (ev.startDay) { ev.start = +new Date(ev.startDay); }
if (ev.startDay) { ev.start = +FP.parseDate(ev.startDay); }
if (ev.endDay) {
var endDate = new Date(ev.endDay);
var endDate = FP.parseDate(ev.endDay);
endDate.setHours(23);
endDate.setMinutes(59);
endDate.setSeconds(59);
@ -223,7 +224,7 @@ define([
};
var addReminders = function (ctx, id, ev) {
var calendar = ctx.calendars[id];
if (!ev) { return; } // XXX deleted event remote: delete reminders
if (!ev) { return; }
if (!calendar || !calendar.reminders) { return; }
if (calendar.stores.length === 1 && calendar.stores[0] === 0) { return; }
@ -1063,7 +1064,6 @@ define([
Calendar.init = function (cfg, waitFor, emit) {
var calendar = {};
var store = cfg.store;
//if (!store.loggedIn || !store.proxy.edPublic) { return; } // XXX logged in only? we should al least allow read-only for URL calendars
var ctx = {
loggedIn: store.loggedIn && store.proxy.edPublic,
store: store,

View File

@ -470,7 +470,6 @@ var factory = function (Util, Hash, CPNetflux, Sortify, nThen, Crypto, Feedback)
delete clone.previewChannel;
members[curve] = clone;
// XXX
var remaining = members[author].remaining || 1;
if (remaining === -1) { return true; } // Infinite uses, keep the link
if (remaining > 1) { // Remove 1 use

View File

@ -856,7 +856,7 @@ define([
}
}
if (!Hash.isValidChannel(el.channel)) {
// XXX delete channel? replace with parsed.channel?
// FIXME delete channel? replace with parsed.channel?
console.error('Remove invalid channel', el.channel, el);
// toClean.push(id);
}

View File

@ -249,7 +249,7 @@ define([
var obj = Util.clone(proxy.metadata || {});
for (var k in Env.user.proxy[UserObject.SHARED_FOLDERS][id] || {}) {
if (typeof(Env.user.proxy[UserObject.SHARED_FOLDERS][id][k]) === "undefined") { // XXX "deleted folder" for restricted shared folders when viewer in a team
if (typeof(Env.user.proxy[UserObject.SHARED_FOLDERS][id][k]) === "undefined") { // TODO "deleted folder" for restricted shared folders when viewer in a team
continue;
}
var data = Util.clone(Env.user.proxy[UserObject.SHARED_FOLDERS][id][k]);

View File

@ -140,10 +140,15 @@ define([
return text.trim();
};
var isMobile = /Android|iPhone/i.test(navigator.userAgent);
module.mkIndentSettings = function (editor, metadataMgr) {
var setIndentation = function (units, useTabs, fontSize, spellcheck, brackets) {
if (typeof(units) !== 'number') { return; }
var doc = editor.getDoc();
if (isMobile && fontSize < 16) {
fontSize = 16;
}
editor.setOption('indentUnit', units);
editor.setOption('tabSize', units);
editor.setOption('indentWithTabs', useTabs);

View File

@ -943,6 +943,50 @@ define([
}, href);
});
sframeChan.on('Q_ACCEPT_OWNERSHIP', function (data, cb) {
var parsed = Utils.Hash.parsePadUrl(data.href);
if (parsed.type === 'drive') {
// Shared folder
var secret = Utils.Hash.getSecrets(parsed.type, parsed.hash, data.password);
Cryptpad.addSharedFolder(null, secret, cb);
} else {
var _data = {
password: data.password,
href: data.href,
channel: data.channel,
title: data.title,
owners: data.metadata ? data.metadata.owners : data.owners,
expire: data.metadata ? data.metadata.expire : data.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);
}
});
// Add or remove our mailbox from the list if we're an owner
sframeChan.on('Q_UPDATE_MAILBOX', function (data, cb) {
var metadata = data.metadata;
@ -1024,7 +1068,7 @@ define([
}
var send = data.send;
var metadata = data.metadata;
var owner, owners;
var owners = [];
var _secret = secret;
if (metadata && metadata.roHref) {
var _parsed = Utils.Hash.parsePadUrl(metadata.roHref);
@ -1037,24 +1081,24 @@ define([
nThen(function (waitFor) {
// Try to get the owner's mailbox from the pad metadata first.
var todo = function (obj) {
owners = obj.owners;
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) {
var decrypt = function (mailbox) {
try {
var dataStr = crypto.decrypt(mailbox, true, true);
var data = JSON.parse(dataStr);
if (!data.notifications || !data.curvePublic) { return; }
owner = data;
return data;
} catch (e) { console.error(e); }
};
if (typeof (obj.mailbox) === "string") {
owners = [decrypt(obj.mailbox)];
return;
}
if (!obj.mailbox || !obj.owners || !obj.owners.length) { return; }
owners = obj.owners.map(function (edPublic) {
var mailbox = obj.mailbox[edPublic];
if (typeof(mailbox) !== "string") { return; }
return decrypt(mailbox);
}).filter(Boolean);
};
// If we already have metadata, use it, otherwise, try to get it
@ -1069,7 +1113,7 @@ define([
}));
}).nThen(function () {
// If we are just checking (send === false) and there is a mailbox field, cb state true
if (!send) { return void cb({state: Boolean(owner)}); }
if (!send) { return void cb({state: Boolean(owners.length)}); }
Cryptpad.padRpc.contactOwner({
send: send,
@ -1077,7 +1121,6 @@ define([
query: data.query,
msgData: data.msgData,
channel: _secret.channel,
owner: owner,
owners: owners
}, cb);
});
@ -1238,50 +1281,6 @@ define([
});
});
sframeChan.on('Q_ACCEPT_OWNERSHIP', function (data, cb) {
var parsed = Utils.Hash.parsePadUrl(data.href);
if (parsed.type === 'drive') {
// Shared folder
var secret = Utils.Hash.getSecrets(parsed.type, parsed.hash, data.password);
Cryptpad.addSharedFolder(null, secret, cb);
} else {
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) {
var key = obj.key;
var channel = obj.channel;

View File

@ -1,7 +1,6 @@
define([], function () {
if (window.__CRYPTPAD_TEST_OBJ_) { return window.__CRYPTPAD_TEST_OBJ_; }
/*
// XXX localhost secureiframe fix
var out = function () {};
out.options = {};
out.testing = false;

View File

@ -294,6 +294,7 @@ define([
Messages.convertPage = "Convert"; // XXX 4.11.0
Messages.convert_hint = "Pick the file you want to convert. The list of output format will be visible afterwards."; // XXX 4.11.0
Messages.convert_unsupported = "UNSUPPORTED FILE TYPE :("; // XXX
var createToolbar = function () {
var displayed = ['useradmin', 'newpad', 'limit', 'pageTitle', 'notifications'];
@ -328,7 +329,6 @@ define([
type: 'file'
});
APP.$rightside.append([hint, picker]);
Messages.convert_unsupported = "UNSUPPORTED FILE TYPE :("; // XXX
$(picker).on('change', function () {
APP.$rightside.find('button, div.notice').remove();

View File

@ -4005,7 +4005,7 @@ define([
$container.empty().append(_content);
// XXX Delete key form_updateMsg
// XXX Delete translation key form_updateMsg
if (editable) {
var responseMsg = h('div.cp-form-response-msg-container');
var $responseMsg = $(responseMsg).appendTo($container);

View File

@ -314,7 +314,7 @@ define([
if (obj && obj.error) { err = obj.error; return; }
var messages = obj.messages;
if (!messages.length) {
// XXX TODO delete from drive.forms
// TODO delete from drive.forms?
return;
}
if (obj.lastKnownHash !== answer.hash) { return; }

View File

@ -79,7 +79,7 @@ define([
Env.metadataMgr.updateMetadata(md);
};
var sendReplyNotification = function(Env, uid) {
var sendReplyNotification = function(Env, uid, mentionedCurve) {
if (!Env.comments || !Env.comments.data || !Env.comments.authors) { return; }
if (!Env.common.isLoggedIn()) { return; }
var thread = Env.comments.data[uid];
@ -88,8 +88,6 @@ define([
var privateData = Env.metadataMgr.getPrivateData();
var others = {};
// XXX mentioned users should be excluded from the list of notified recipients to avoid notifying them twice
// Get all the other registered users with a mailbox
thread.m.forEach(function(obj) {
var u = obj.u;
@ -97,6 +95,9 @@ define([
var author = Env.comments.authors[u];
if (!author || others[u] || !author.notifications || !author.curvePublic) { return; }
if (author.curvePublic === userData.curvePublic) { return; } // don't send to yourself
if (Object.keys(mentionedCurve || {}).includes(author.curvePublic)) {
return; // Don't send to mentioned users
}
others[u] = {
curvePublic: author.curvePublic,
comment: obj.m,
@ -203,7 +204,7 @@ define([
});
// Push the content
cb(content);
cb(content, notify);
});
$(cancel).click(function(e) {
e.stopPropagation();
@ -525,7 +526,7 @@ define([
$(reply).click(function(e) {
e.stopPropagation();
$actions.hide();
var form = getCommentForm(Env, key, function(val) {
var form = getCommentForm(Env, key, function(val, mentioned) {
// Show the "reply" and "resolve" buttons again
$(form).closest('.cp-comment-container')
.find('.cp-comment-actions').css('display', '');
@ -551,7 +552,7 @@ define([
});
// Notify other users
sendReplyNotification(Env, key);
sendReplyNotification(Env, key, mentioned);
// Send to chainpad
updateMetadata(Env);

View File

@ -903,6 +903,10 @@ define([
$toc.addClass('hidden');
localHide = true;
if (store) { store.put(key, '1'); }
if (APP.tocScroll) {
APP.tocScroll();
}
});
$(showBtn).click(function () {
$toc.removeClass('hidden');
@ -922,6 +926,23 @@ define([
e.stopPropagation();
if (!obj.el || UIElements.isVisible(obj.el, $contentContainer)) { return; }
obj.el.scrollIntoView();
var $iframe = $('iframe').contents();
var onScroll = function () {
APP.tocScrollOff();
};
APP.tocScrollOff = function () {
delete APP.tocScroll;
delete APP.tocScrollOff;
$iframe.off('scroll', onScroll);
};
APP.tocScroll = function () {
obj.el.scrollIntoView();
APP.tocScrollOff();
};
//$(window).on('scroll', onScroll);
setTimeout(function () {
$iframe.on('scroll', onScroll);
});
});
a.innerHTML = title;
content.push(h('p.cp-pad-toc-'+level, a));
@ -1003,6 +1024,8 @@ define([
if (scrollMax) {
$iframe.scrollTop($iframe.innerHeight());
}
if (APP.tocScrollOff) { APP.tocScrollOff(); }
});
framework.setTextContentGetter(function() {
@ -1017,6 +1040,8 @@ define([
return str;
});
framework.setContentGetter(function() {
if (APP.tocScrollOff) { APP.tocScrollOff(); }
$inner.find('span[data-cke-display-name="media-tag"]:empty').each(function(i, el) {
$(el).remove();
});

View File

@ -28,7 +28,7 @@ define([
};
window.rc = requireConfig;
window.apiconf = ApiConfig;
// XXX extra sandboxing features are temporarily disabled as I suspect this is the cause of a regression in Safari
// FIXME extra sandboxing features are temporarily disabled as I suspect this is the cause of a regression in Safari
$('#sbox-secure-iframe')/*.attr('sandbox', 'allow-scripts allow-popups allow-modals')*/.attr('src',
ApiConfig.httpSafeOrigin + '/secureiframe/inner.html?' + requireConfig.urlArgs +
'#' + encodeURIComponent(JSON.stringify(req)));

View File

@ -147,6 +147,16 @@
}
}
@media (max-width: @browser_media-medium-screen) {
#cp-app-slide-editor {
#cp-app-slide-editor-container {
.CodeMirror-sizer > div {
padding-bottom: 100px;
}
}
}
}
/* Slide position (print mode) */
@ratio:0.9;
@media print {