Merge branch 'bar' into staging

pull/1/head
yflory 5 years ago
commit bd90df9d1e

@ -13,7 +13,8 @@ define([], function () {
right: 0px; right: 0px;
background: linear-gradient(to right, #326599 0%, #326599 50%, #4591c4 50%, #4591c4 100%); background: linear-gradient(to right, #326599 0%, #326599 50%, #4591c4 50%, #4591c4 100%);
color: #fafafa; color: #fafafa;
font-size: 1.5em; font-size: 1.3em;
line-height: 120%;
opacity: 1; opacity: 1;
display: flex; display: flex;
flex-flow: column; flex-flow: column;
@ -77,13 +78,11 @@ define([], function () {
background: #FFF; background: #FFF;
padding: 20px; padding: 20px;
width: 100%; width: 100%;
color: #000; color: #3F4141;
text-align: center; text-align: left;
display: none; display: none;
} }
#cp-loading-password-prompt {
font-size: 18px;
}
#cp-loading-password-prompt .cp-password-error { #cp-loading-password-prompt .cp-password-error {
color: white; color: white;
background: #9e0000; background: #9e0000;
@ -94,24 +93,49 @@ define([], function () {
text-align: left; text-align: left;
margin-bottom: 15px; margin-bottom: 15px;
} }
p.cp-password-info{
text-align: left;
}
#cp-loading-password-prompt .cp-password-form { #cp-loading-password-prompt .cp-password-form {
display: flex; display: flex;
justify-content: space-around;
flex-wrap: wrap; flex-wrap: wrap;
} }
#cp-loading-password-prompt .cp-password-form button, #cp-loading-password-prompt .cp-password-form button{
#cp-loading-password-prompt .cp-password-form .cp-password-input {
background-color: #4591c4; background-color: #4591c4;
color: white; color: white;
border: 1px solid #4591c4; border: 1px solid #4591c4;
} }
.cp-password-input{
font-size:16px;
border: 1px solid #4591c4;
background-color: white;
border-radius 0;
}
.cp-password-form button{
padding: 8px 12px;
font-weight: bold;
text-transform: uppercase;
}
#cp-loading-password-prompt .cp-password-form{
width: 100%;
}
#cp-loading-password-prompt .cp-password-form .cp-password-container { #cp-loading-password-prompt .cp-password-form .cp-password-container {
flex-shrink: 1; flex-shrink: 1;
min-width: 0; min-width: 0;
} }
#cp-loading-password-prompt .cp-password-form .cp-password-container .cp-password-reveal{
color: #4591c4;
padding: 0px 24px;
}
#cp-loading-password-prompt .cp-password-form input { #cp-loading-password-prompt .cp-password-form input {
flex: 1; flex: 1;
padding: 0 5px; padding: 12px;
min-width: 0; min-width: 0;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
@ -119,7 +143,7 @@ define([], function () {
background-color: #326599; background-color: #326599;
} }
#cp-loading-password-prompt ::placeholder { #cp-loading-password-prompt ::placeholder {
color: #d9d9d9; color: #999999;
opacity: 1; opacity: 1;
} }
#cp-loading-password-prompt :-ms-input-placeholder { #cp-loading-password-prompt :-ms-input-placeholder {
@ -154,7 +178,7 @@ define([], function () {
background: #222; background: #222;
color: #fafafa; color: #fafafa;
text-align: center; text-align: center;
font-size: 1.5em; font-size: 1.3em;
opacity: 0.7; opacity: 0.7;
font-family: 'Open Sans', 'Helvetica Neue', sans-serif; font-family: 'Open Sans', 'Helvetica Neue', sans-serif;
padding: 15px; padding: 15px;
@ -201,6 +225,19 @@ define([], function () {
animation-timing-function: cubic-bezier(.6,0.15,0.4,0.85); animation-timing-function: cubic-bezier(.6,0.15,0.4,0.85);
} }
button.primary{
border: 1px solid #4591c4;
padding: 8px 12px;
text-transform: uppercase;
background-color: #4591c4;
color: white;
font-weight: bold;
}
button.primary:hover{
background-color: rgb(52, 118, 162);
}
*/}).toString().slice(14, -3); */}).toString().slice(14, -3);
var urlArgs = window.location.href.replace(/^.*\?([^\?]*)$/, function (all, x) { return x; }); var urlArgs = window.location.href.replace(/^.*\?([^\?]*)$/, function (all, x) { return x; });
var elem = document.createElement('div'); var elem = document.createElement('div');

@ -14,6 +14,9 @@
.radio-group { .radio-group {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
&:not(:last-child){
margin-bottom: 8px;
}
.cp-radio { .cp-radio {
margin-right: 30px; margin-right: 30px;
} }

@ -97,6 +97,12 @@
.ckeditor_fix(); .ckeditor_fix();
.cp-burn-after-reading {
text-align: center;
font-size: @colortheme_app-font-size !important;
margin: 0 !important;
}
.cp-markdown-toolbar { .cp-markdown-toolbar {
height: @toolbar_line-height; height: @toolbar_line-height;
background-color: @toolbar-bg-color-l20; background-color: @toolbar-bg-color-l20;

@ -254,6 +254,40 @@ define([
!secret.hashData.present); !secret.hashData.present);
}, "test support for trailing slashes in version 1 hash failed to parse"); }, "test support for trailing slashes in version 1 hash failed to parse");
// test support for ownerKey
assert(function (cb) {
var secret = Hash.parsePadUrl('/pad/#/1/edit/3Ujt4F2Sjnjbis6CoYWpoQ/usn4+9CqVja8Q7RZOGTfRgqI/present/uPmJDtDJ9okhdIyQ-8zphYlpaAonJDOC6MAcYY6iBwWBQr+XmrQ9uGY9WkApJTfEfAu5QcqaDCw1Ul+JXKcYkA/embed');
return cb(secret.hashData.version === 1 &&
secret.hashData.mode === "edit" &&
secret.hashData.channel === "3Ujt4F2Sjnjbis6CoYWpoQ" &&
secret.hashData.key === "usn4+9CqVja8Q7RZOGTfRgqI" &&
secret.hashData.ownerKey === "uPmJDtDJ9okhdIyQ-8zphYlpaAonJDOC6MAcYY6iBwWBQr+XmrQ9uGY9WkApJTfEfAu5QcqaDCw1Ul+JXKcYkA" &&
secret.hashData.embed &&
secret.hashData.present);
}, "test support for owner key in version 1 hash failed to parse");
assert(function (cb) {
var parsed = Hash.parsePadUrl('/pad/#/2/pad/edit/oRE0oLCtEXusRDyin7GyLGcS/p/uPmJDtDJ9okhdIyQ-8zphYlpaAonJDOC6MAcYY6iBwWBQr+XmrQ9uGY9WkApJTfEfAu5QcqaDCw1Ul+JXKcYkA/embed');
var secret = Hash.getSecrets('pad', parsed.hash);
return cb(parsed.hashData.version === 2 &&
parsed.hashData.mode === "edit" &&
parsed.hashData.type === "pad" &&
parsed.hashData.key === "oRE0oLCtEXusRDyin7GyLGcS" &&
secret.channel === "d8d51b4aea863f3f050f47f8ad261753" &&
window.nacl.util.encodeBase64(secret.keys.cryptKey) === "0Ts1M6VVEozErV2Nx/LTv6Im5SCD7io2LlhasyyBPQo=" &&
secret.keys.validateKey === "f5A1FM9Gp55tnOcM75RyHD1oxBG9ZPh9WDA7qe2Fvps=" &&
parsed.hashData.ownerKey === "uPmJDtDJ9okhdIyQ-8zphYlpaAonJDOC6MAcYY6iBwWBQr+XmrQ9uGY9WkApJTfEfAu5QcqaDCw1Ul+JXKcYkA" &&
parsed.hashData.embed &&
parsed.hashData.password);
}, "test support for owner key in version 2 hash failed to parse");
assert(function (cb) {
var secret = Hash.parsePadUrl('/file/#/1/TRplGM-WsVkXR+LkJ0tD3D45A1YFZ-Cy/eO4RJwh8yHEEDhl1aHfuwQ2IzosPBZx-HDaWc1lW+hY=/uPmJDtDJ9okhdIyQ-8zphYlpaAonJDOC6MAcYY6iBwWBQr+XmrQ9uGY9WkApJTfEfAu5QcqaDCw1Ul+JXKcYkA/');
return cb(secret.hashData.version === 1 &&
secret.hashData.channel === "TRplGM/WsVkXR+LkJ0tD3D45A1YFZ/Cy" &&
secret.hashData.key === "eO4RJwh8yHEEDhl1aHfuwQ2IzosPBZx/HDaWc1lW+hY=" &&
secret.hashData.ownerKey === "uPmJDtDJ9okhdIyQ-8zphYlpaAonJDOC6MAcYY6iBwWBQr+XmrQ9uGY9WkApJTfEfAu5QcqaDCw1Ul+JXKcYkA" &&
!secret.hashData.present);
}, "test support for owner key in version 1 file hash failed to parse");
assert(function (cb) { assert(function (cb) {
var secret = Hash.parsePadUrl('/invite/#/2/invite/edit/oRE0oLCtEXusRDyin7GyLGcS/p/'); var secret = Hash.parsePadUrl('/invite/#/2/invite/edit/oRE0oLCtEXusRDyin7GyLGcS/p/');
var hd = secret.hashData; var hd = secret.hashData;

@ -98,6 +98,7 @@ define([
}; };
var mkHelpMenu = function (framework) { var mkHelpMenu = function (framework) {
var $codeMirrorContainer = $('#cp-app-code-container'); var $codeMirrorContainer = $('#cp-app-code-container');
$codeMirrorContainer.prepend(framework._.sfCommon.getBurnAfterReadingWarning());
var helpMenu = framework._.sfCommon.createHelpMenu(['text', 'code']); var helpMenu = framework._.sfCommon.createHelpMenu(['text', 'code']);
$codeMirrorContainer.prepend(helpMenu.menu); $codeMirrorContainer.prepend(helpMenu.menu);

@ -15,6 +15,20 @@ var factory = function (Util, Crypto, Nacl) {
.decodeUTF8(JSON.stringify(list)))); .decodeUTF8(JSON.stringify(list))));
}; };
// XXX move this code?
Hash.generateSignPair = function () {
var ed = Nacl.sign.keyPair();
var makeSafe = function (key) {
return Crypto.b64RemoveSlashes(key).replace(/=+$/g, '');
};
return {
validateKey: Hash.encodeBase64(ed.publicKey),
signKey: Hash.encodeBase64(ed.secretKey),
safeValidateKey: makeSafe(Hash.encodeBase64(ed.publicKey)),
safeSignKey: makeSafe(Hash.encodeBase64(ed.secretKey)),
};
};
var getEditHashFromKeys = Hash.getEditHashFromKeys = function (secret) { var getEditHashFromKeys = Hash.getEditHashFromKeys = function (secret) {
var version = secret.version; var version = secret.version;
var data = secret.keys; var data = secret.keys;
@ -134,6 +148,17 @@ Version 1
/code/#/1/edit/3Ujt4F2Sjnjbis6CoYWpoQ/usn4+9CqVja8Q7RZOGTfRgqI /code/#/1/edit/3Ujt4F2Sjnjbis6CoYWpoQ/usn4+9CqVja8Q7RZOGTfRgqI
*/ */
var getOwnerKey = function (hashArr) {
var k;
// Check if we have a ownerKey for this pad
hashArr.some(function (data) {
if (data.length === 86) { // XXX 88 characters - 2 trailing "="...
k = data;
return true;
}
});
return k;
};
var parseTypeHash = Hash.parseTypeHash = function (type, hash) { var parseTypeHash = Hash.parseTypeHash = function (type, hash) {
if (!hash) { return; } if (!hash) { return; }
var options; var options;
@ -158,9 +183,12 @@ Version 1
options = hashArr.slice(5); options = hashArr.slice(5);
parsed.present = options.indexOf('present') !== -1; parsed.present = options.indexOf('present') !== -1;
parsed.embed = options.indexOf('embed') !== -1; parsed.embed = options.indexOf('embed') !== -1;
parsed.ownerKey = getOwnerKey(options);
parsed.getHash = function (opts) { parsed.getHash = function (opts) {
var hash = hashArr.slice(0, 5).join('/') + '/'; var hash = hashArr.slice(0, 5).join('/') + '/';
var owner = typeof(opts.ownerKey) !== "undefined" ? opts.ownerKey : parsed.ownerKey;
if (owner) { hash += owner + '/'; }
if (opts.embed) { hash += 'embed/'; } if (opts.embed) { hash += 'embed/'; }
if (opts.present) { hash += 'present/'; } if (opts.present) { hash += 'present/'; }
return hash; return hash;
@ -177,9 +205,12 @@ Version 1
parsed.password = options.indexOf('p') !== -1; parsed.password = options.indexOf('p') !== -1;
parsed.present = options.indexOf('present') !== -1; parsed.present = options.indexOf('present') !== -1;
parsed.embed = options.indexOf('embed') !== -1; parsed.embed = options.indexOf('embed') !== -1;
parsed.ownerKey = getOwnerKey(options);
parsed.getHash = function (opts) { parsed.getHash = function (opts) {
var hash = hashArr.slice(0, 5).join('/') + '/'; var hash = hashArr.slice(0, 5).join('/') + '/';
var owner = typeof(opts.ownerKey) !== "undefined" ? opts.ownerKey : parsed.ownerKey;
if (owner) { hash += owner + '/'; }
if (parsed.password) { hash += 'p/'; } if (parsed.password) { hash += 'p/'; }
if (opts.embed) { hash += 'embed/'; } if (opts.embed) { hash += 'embed/'; }
if (opts.present) { hash += 'present/'; } if (opts.present) { hash += 'present/'; }
@ -196,6 +227,8 @@ Version 1
parsed.version = 1; parsed.version = 1;
parsed.channel = hashArr[2].replace(/-/g, '/'); parsed.channel = hashArr[2].replace(/-/g, '/');
parsed.key = hashArr[3].replace(/-/g, '/'); parsed.key = hashArr[3].replace(/-/g, '/');
options = hashArr.slice(4);
parsed.ownerKey = getOwnerKey(options);
return parsed; return parsed;
} }
if (hashArr[1] && hashArr[1] === '2') { // Version 2 if (hashArr[1] && hashArr[1] === '2') { // Version 2
@ -207,9 +240,12 @@ Version 1
parsed.password = options.indexOf('p') !== -1; parsed.password = options.indexOf('p') !== -1;
parsed.present = options.indexOf('present') !== -1; parsed.present = options.indexOf('present') !== -1;
parsed.embed = options.indexOf('embed') !== -1; parsed.embed = options.indexOf('embed') !== -1;
parsed.ownerKey = getOwnerKey(options);
parsed.getHash = function (opts) { parsed.getHash = function (opts) {
var hash = hashArr.slice(0, 4).join('/') + '/'; var hash = hashArr.slice(0, 4).join('/') + '/';
var owner = typeof(opts.ownerKey) !== "undefined" ? opts.ownerKey : parsed.ownerKey;
if (owner) { hash += owner + '/'; }
if (parsed.password) { hash += 'p/'; } if (parsed.password) { hash += 'p/'; }
if (opts.embed) { hash += 'embed/'; } if (opts.embed) { hash += 'embed/'; }
if (opts.present) { hash += 'present/'; } if (opts.present) { hash += 'present/'; }

@ -209,10 +209,16 @@ define([
$(title).prepend(' ').prepend(icon); $(title).prepend(' ').prepend(icon);
} }
$(title).click(function () { $(title).click(function () {
var old = tabs[active];
if (old.onHide) { old.onHide(); }
titles.forEach(function (t) { $(t).removeClass('alertify-tabs-active'); }); titles.forEach(function (t) { $(t).removeClass('alertify-tabs-active'); });
contents.forEach(function (c) { $(c).removeClass('alertify-tabs-content-active'); }); contents.forEach(function (c) { $(c).removeClass('alertify-tabs-content-active'); });
if (tab.onShow) {
tab.onShow();
}
$(title).addClass('alertify-tabs-active'); $(title).addClass('alertify-tabs-active');
$(content).addClass('alertify-tabs-content-active'); $(content).addClass('alertify-tabs-content-active');
active = i;
}); });
titles.push(title); titles.push(title);
contents.push(content); contents.push(content);

@ -917,7 +917,25 @@ define([
className: 'primary cp-share-with-friends', className: 'primary cp-share-with-friends',
name: Messages.share_withFriends, name: Messages.share_withFriends,
onClick: function () { onClick: function () {
var href = Hash.getRelativeHref(linkGetter()); var href;
NThen(function (waitFor) {
var w = waitFor();
// linkGetter can be async if this is a burn after reading URL
var res = linkGetter({}, function (url) {
if (!url) {
waitFor.abort();
return;
}
console.warn('BAR');
href = url;
setTimeout(w);
});
if (res && /^http/.test(res)) {
href = Hash.getRelativeHref(res);
setTimeout(w);
return;
}
}).nThen(function () {
var $friends = $div.find('.cp-usergrid-user.cp-selected'); var $friends = $div.find('.cp-usergrid-user.cp-selected');
$friends.each(function (i, el) { $friends.each(function (i, el) {
var curve = $(el).attr('data-curve'); var curve = $(el).attr('data-curve');
@ -971,6 +989,7 @@ define([
if (onShare) { if (onShare) {
onShare.fire(); onShare.fire();
} }
});
}, },
keys: [13] keys: [13]
}; };
@ -1049,6 +1068,29 @@ define([
} }
}; };
var makeBurnAfterReadingUrl = function (common, href, channel, cb) {
var keyPair = Hash.generateSignPair();
var parsed = Hash.parsePadUrl(href);
console.error(href, parsed);
var newHref = parsed.getUrl({
ownerKey: keyPair.safeSignKey
});
var sframeChan = common.getSframeChannel();
NThen(function (waitFor) {
sframeChan.query('Q_SET_PAD_METADATA', {
channel: channel,
command: 'ADD_OWNERS',
value: [keyPair.validateKey]
}, waitFor(function (err) {
if (err) {
waitFor.abort();
UI.warn(Messages.error);
}
}));
}).nThen(function () {
cb(newHref);
});
};
UIElements.createShareModal = function (config) { UIElements.createShareModal = function (config) {
var origin = config.origin; var origin = config.origin;
var pathname = config.pathname; var pathname = config.pathname;
@ -1078,6 +1120,7 @@ define([
var parsed = Hash.parsePadUrl(pathname); var parsed = Hash.parsePadUrl(pathname);
var canPresent = ['code', 'slide'].indexOf(parsed.type) !== -1; var canPresent = ['code', 'slide'].indexOf(parsed.type) !== -1;
var burnAfterReading;
var rights = h('div.msg.cp-inline-radio-group', [ var rights = h('div.msg.cp-inline-radio-group', [
h('label', Messages.share_linkAccess), h('label', Messages.share_linkAccess),
h('div.radio-group',[ h('div.radio-group',[
@ -1086,9 +1129,33 @@ define([
canPresent ? UI.createRadio('accessRights', 'cp-share-present', canPresent ? UI.createRadio('accessRights', 'cp-share-present',
Messages.share_linkPresent, false, { mark: {tabindex:1} }) : undefined, Messages.share_linkPresent, false, { mark: {tabindex:1} }) : undefined,
UI.createRadio('accessRights', 'cp-share-editable-true', UI.createRadio('accessRights', 'cp-share-editable-true',
Messages.share_linkEdit, false, { mark: {tabindex:1} })]) Messages.share_linkEdit, false, { mark: {tabindex:1} })]),
burnAfterReading = hashes.viewHash ? UI.createRadio('accessRights', 'cp-share-bar', Messages.burnAfterReading_linkBurnAfterReading ||
'View once and self-destruct', false, { mark: {tabindex:1}, label: {style: "display: none;"} }) : undefined // XXX temp KEY
]); ]);
// Burn after reading
// Check if we are an owner of this pad. If we are, we can show the burn after reading option.
// When BAR is selected, display a red message indicating the consequence and add
// the options to generate the BAR url
var barAlert = h('div.alert.alert-danger.cp-alertify-bar-selected', {
style: 'display: none;'
}, Messages.burnAfterReading_warningLink || " You have set this pad to self-destruct. Once a recipient opens this pad, it will be permanently deleted from the server."); // XXX temp KEY
var channel = Hash.getSecrets('pad', hash, config.password).channel;
common.getPadMetadata({
channel: channel
}, function (obj) {
if (!obj || obj.error) { return; }
var priv = common.getMetadataMgr().getPrivateData();
// Not an owner: don't display the burn after reading option
if (!Array.isArray(obj.owners) || obj.owners.indexOf(priv.edPublic) === -1) {
$(burnAfterReading).remove();
return;
}
// When the burn after reading option is selected, transform the modal buttons
$(burnAfterReading).show();
});
var $rights = $(rights); var $rights = $(rights);
var saveValue = function () { var saveValue = function () {
@ -1100,13 +1167,25 @@ define([
}); });
}; };
var getLinkValue = function (initValue) { var burnAfterReadingUrl;
var getLinkValue = function (initValue, cb) {
var val = initValue || {}; var val = initValue || {};
var edit = val.edit !== undefined ? val.edit : Util.isChecked($rights.find('#cp-share-editable-true')); var edit = val.edit !== undefined ? val.edit : Util.isChecked($rights.find('#cp-share-editable-true'));
var embed = val.embed; var embed = val.embed;
var present = val.present !== undefined ? val.present : Util.isChecked($rights.find('#cp-share-present')); var present = val.present !== undefined ? val.present : Util.isChecked($rights.find('#cp-share-present'));
var burnAfterReading = Util.isChecked($rights.find('#cp-share-bar'));
if (burnAfterReading && !burnAfterReadingUrl) {
if (cb) { // Called from the contacts tab, "share" button
var barHref = origin + pathname + '#' + (hashes.viewHash || hashes.editHash);
return makeBurnAfterReadingUrl(common, barHref, channel, function (url) {
cb(url);
});
}
return Messages.burnAfterReading_generateLink || 'Click on the button below to generate a link'; // XXX temp KEY
}
var hash = (!hashes.viewHash || (edit && hashes.editHash)) ? hashes.editHash : hashes.viewHash; var hash = (!hashes.viewHash || (edit && hashes.editHash)) ? hashes.editHash : hashes.viewHash;
var href = origin + pathname + '#' + hash; var href = burnAfterReading ? burnAfterReadingUrl : (origin + pathname + '#' + hash);
var parsed = Hash.parsePadUrl(href); var parsed = Hash.parsePadUrl(href);
return origin + parsed.getUrl({embed: embed, present: present}); return origin + parsed.getUrl({embed: embed, present: present});
}; };
@ -1161,7 +1240,7 @@ define([
}); });
linkContent.push($(barAlert).clone()[0]); // Burn after reading
var link = h('div.cp-share-modal', linkContent); var link = h('div.cp-share-modal', linkContent);
var $link = $(link); var $link = $(link);
@ -1169,7 +1248,7 @@ define([
var linkButtons = [ var linkButtons = [
makeCancelButton(), makeCancelButton(),
!config.sharedFolder && { !config.sharedFolder && {
className: 'secondary', className: 'secondary cp-nobar',
name: Messages.share_linkOpen, name: Messages.share_linkOpen,
onClick: function () { onClick: function () {
saveValue(); saveValue();
@ -1180,9 +1259,8 @@ define([
return true; return true;
}, },
keys: [[13, 'ctrl']] keys: [[13, 'ctrl']]
}, }, {
{ className: 'primary cp-nobar',
className: 'primary',
name: Messages.share_linkCopy, name: Messages.share_linkCopy,
onClick: function () { onClick: function () {
saveValue(); saveValue();
@ -1193,26 +1271,26 @@ define([
if (success) { UI.log(Messages.shareSuccess); } if (success) { UI.log(Messages.shareSuccess); }
}, },
keys: [13] keys: [13]
}, {
className: 'primary cp-bar',
name: 'GENERATE LINK',
onClick: function () {
var barHref = origin + pathname + '#' + (hashes.viewHash || hashes.editHash);
makeBurnAfterReadingUrl(common, barHref, channel, function (url) {
burnAfterReadingUrl = url;
$rights.find('input[type="radio"]').trigger('change');
});
return true;
},
keys: []
} }
]; ];
// update values for link preview when radio btns change
$link.find('#cp-share-link-preview').val(getLinkValue());
$rights.find('input[type="radio"]').on('change', function () {
$link.find('#cp-share-link-preview').val(getLinkValue({
embed: Util.isChecked($link.find('#cp-share-embed'))
}));
});
$link.find('input[type="checkbox"]').on('change', function () {
$link.find('#cp-share-link-preview').val(getLinkValue({
embed: Util.isChecked($link.find('#cp-share-embed'))
}));
});
var frameLink = UI.dialog.customModal(link, { var frameLink = UI.dialog.customModal(link, {
buttons: linkButtons, buttons: linkButtons,
onClose: config.onClose, onClose: config.onClose,
}); });
$(frameLink).find('.cp-bar').hide();
// Share with contacts tab // Share with contacts tab
@ -1240,10 +1318,17 @@ define([
])); ]));
} }
$(contactsContent).append($(barAlert).clone()); // Burn after reading
var contactButtons = friendsObject.buttons; var contactButtons = friendsObject.buttons;
contactButtons.unshift(makeCancelButton()); contactButtons.unshift(makeCancelButton());
var onShowContacts = function () {
if (!hasFriends) {
$rights.hide();
}
};
var frameContacts = UI.dialog.customModal(contactsContent, { var frameContacts = UI.dialog.customModal(contactsContent, {
buttons: contactButtons, buttons: contactButtons,
onClose: config.onClose, onClose: config.onClose,
@ -1282,26 +1367,60 @@ define([
keys: [13] keys: [13]
}]; }];
var onShowEmbed = function () {
$rights.find('#cp-share-bar').closest('label').hide();
$rights.find('input[type="radio"]:enabled').first().prop('checked', 'checked');
$rights.find('input[type="radio"]').trigger('change');
};
var embed = h('div.cp-share-modal', embedContent); var embed = h('div.cp-share-modal', embedContent);
var $embed = $(embed); var $embed = $(embed);
// update values for link preview when radio btns change var frameEmbed = UI.dialog.customModal(embed, {
buttons: embedButtons,
onClose: config.onClose,
});
// update values for link and embed preview when radio btns change
$embed.find('#cp-embed-link-preview').val(getEmbedValue()); $embed.find('#cp-embed-link-preview').val(getEmbedValue());
$link.find('#cp-share-link-preview').val(getLinkValue());
$rights.find('input[type="radio"]').on('change', function () { $rights.find('input[type="radio"]').on('change', function () {
$link.find('#cp-share-link-preview').val(getLinkValue({
embed: Util.isChecked($link.find('#cp-share-embed'))
}));
// Hide or show the burn after reading alert
if (Util.isChecked($rights.find('#cp-share-bar')) && !burnAfterReadingUrl) {
$('.cp-alertify-bar-selected').show();
// Show burn after reading button
$('.alertify').find('.cp-bar').show();
$('.alertify').find('.cp-nobar').hide();
return;
}
$embed.find('#cp-embed-link-preview').val(getEmbedValue()); $embed.find('#cp-embed-link-preview').val(getEmbedValue());
// Hide burn after reading button
$('.alertify').find('.cp-nobar').show();
$('.alertify').find('.cp-bar').hide();
$('.cp-alertify-bar-selected').hide();
}); });
$link.find('input[type="checkbox"]').on('change', function () {
var frameEmbed = UI.dialog.customModal(embed, { $link.find('#cp-share-link-preview').val(getLinkValue({
buttons: embedButtons, embed: Util.isChecked($link.find('#cp-share-embed'))
onClose: config.onClose, }));
}); });
// Create modal // Create modal
var resetTab = function () {
$rights.show();
$rights.find('label.cp-radio').show();
};
var tabs = [{ var tabs = [{
title: Messages.share_contactCategory, title: Messages.share_contactCategory,
icon: "fa fa-address-book", icon: "fa fa-address-book",
content: frameContacts, content: frameContacts,
active: hasFriends active: hasFriends,
onShow: onShowContacts,
onHide: resetTab
}, { }, {
title: Messages.share_linkCategory, title: Messages.share_linkCategory,
icon: "fa fa-link", icon: "fa fa-link",
@ -1310,7 +1429,9 @@ define([
}, { }, {
title: Messages.share_embedCategory, title: Messages.share_embedCategory,
icon: "fa fa-code", icon: "fa fa-code",
content: frameEmbed content: frameEmbed,
onShow: onShowEmbed,
onHide: resetTab
}]; }];
if (typeof(AppConfig.customizeShareOptions) === 'function') { if (typeof(AppConfig.customizeShareOptions) === 'function') {
AppConfig.customizeShareOptions(hashes, tabs, { AppConfig.customizeShareOptions(hashes, tabs, {
@ -3866,6 +3987,7 @@ define([
UIElements.onServerError = function (common, err, toolbar, cb) { UIElements.onServerError = function (common, err, toolbar, cb) {
if (["EDELETED", "EEXPIRED"].indexOf(err.type) === -1) { return; } if (["EDELETED", "EEXPIRED"].indexOf(err.type) === -1) { return; }
var priv = common.getMetadataMgr().getPrivateData();
var msg = err.type; var msg = err.type;
if (err.type === 'EEXPIRED') { if (err.type === 'EEXPIRED') {
msg = Messages.expiredError; msg = Messages.expiredError;
@ -3873,11 +3995,14 @@ define([
msg += Messages.errorCopy; msg += Messages.errorCopy;
} }
} else if (err.type === 'EDELETED') { } else if (err.type === 'EDELETED') {
if (priv.burnAfterReading) { return void cb(); }
msg = Messages.deletedError; msg = Messages.deletedError;
if (err.loaded) { if (err.loaded) {
msg += Messages.errorCopy; msg += Messages.errorCopy;
} }
} }
var sframeChan = common.getSframeChannel();
sframeChan.event('EV_SHARE_OPEN', {hidden: true});
if (toolbar && typeof toolbar.deleted === "function") { toolbar.deleted(); } if (toolbar && typeof toolbar.deleted === "function") { toolbar.deleted(); }
UI.errorLoadingScreen(msg, true, true); UI.errorLoadingScreen(msg, true, true);
(cb || function () {})(); (cb || function () {})();
@ -3922,6 +4047,26 @@ define([
$password.find('.cp-password-input').focus(); $password.find('.cp-password-input').focus();
}; };
UIElements.displayBurnAfterReadingPage = function (common, cb) {
var info = h('p.cp-password-info', Messages.burnAfterReading_warning || 'This document will self-destruct as soon as you open it. It will be removed form the server, once you close this window you will not be able to access it again. If you are not ready to proceed you can close this window and come back later. '); // XXX temp KEY
var button = h('button.primary', Messages.burnAfterReading_proceed || 'view and delete'); // XXX temp KEY
$(button).on('click', function () {
cb();
});
var block = h('div#cp-loading-burn-after-reading', [
info,
button
]);
UI.errorLoadingScreen(block);
};
UIElements.getBurnAfterReadingWarning = function (common) {
var priv = common.getMetadataMgr().getPrivateData();
if (!priv.burnAfterReading) { return; }
return h('div.alert.alert-danger.cp-burn-after-reading', Messages.burnAfterReading_warningDeleted || 'This pad has been deleted from the server, once you close this window you will not be able to access it again.'); // XXX temp KEY
};
var crowdfundingState = false; var crowdfundingState = false;
UIElements.displayCrowdfunding = function (common) { UIElements.displayCrowdfunding = function (common) {
if (crowdfundingState) { return; } if (crowdfundingState) { return; }
@ -3979,6 +4124,9 @@ define([
if (data && data.stored) { return; } // We won't display the popup for dropped files if (data && data.stored) { return; } // We won't display the popup for dropped files
var priv = common.getMetadataMgr().getPrivateData(); var priv = common.getMetadataMgr().getPrivateData();
// This pad will be deleted automatically, it shouldn't be stored
if (priv.burnAfterReading) { return; }
var typeMsg = priv.pathname.indexOf('/file/') !== -1 ? Messages.autostore_file : var typeMsg = priv.pathname.indexOf('/file/') !== -1 ? Messages.autostore_file :
priv.pathname.indexOf('/drive/') !== -1 ? Messages.autostore_sf : priv.pathname.indexOf('/drive/') !== -1 ? Messages.autostore_sf :
Messages.autostore_pad; Messages.autostore_pad;

@ -847,6 +847,10 @@ define([
postMessage('GET_PAD_METADATA', data, cb); postMessage('GET_PAD_METADATA', data, cb);
}; };
common.burnPad = function (data) {
postMessage('BURN_PAD', data);
};
common.changePadPassword = function (Crypt, Crypto, data, cb) { common.changePadPassword = function (Crypt, Crypto, data, cb) {
var href = data.href; var href = data.href;
var newPassword = data.password; var newPassword = data.password;

@ -926,6 +926,7 @@ define([
$rightside.append($forget); $rightside.append($forget);
var helpMenu = common.createHelpMenu(['beta', 'oo']); var helpMenu = common.createHelpMenu(['beta', 'oo']);
$('#cp-app-oo-editor').prepend(common.getBurnAfterReadingWarning());
$('#cp-app-oo-editor').prepend(helpMenu.menu); $('#cp-app-oo-editor').prepend(helpMenu.menu);
toolbar.$drawer.append(helpMenu.button); toolbar.$drawer.append(helpMenu.button);

@ -9,6 +9,7 @@ define([
'/common/common-feedback.js', '/common/common-feedback.js',
'/common/common-realtime.js', '/common/common-realtime.js',
'/common/common-messaging.js', '/common/common-messaging.js',
'/common/pinpad.js',
'/common/outer/sharedfolder.js', '/common/outer/sharedfolder.js',
'/common/outer/cursor.js', '/common/outer/cursor.js',
'/common/outer/onlyoffice.js', '/common/outer/onlyoffice.js',
@ -26,7 +27,7 @@ define([
'/bower_components/nthen/index.js', '/bower_components/nthen/index.js',
'/bower_components/saferphore/index.js', '/bower_components/saferphore/index.js',
], function (Sortify, UserObject, ProxyManager, Migrate, Hash, Util, Constants, Feedback, ], function (Sortify, UserObject, ProxyManager, Migrate, Hash, Util, Constants, Feedback,
Realtime, Messaging, Realtime, Messaging, Pinpad,
SF, Cursor, OnlyOffice, Mailbox, Profile, Team, Messenger, SF, Cursor, OnlyOffice, Mailbox, Profile, Team, Messenger,
NetConfig, AppConfig, NetConfig, AppConfig,
Crypto, ChainPad, CpNetflux, Listmap, nThen, Saferphore) { Crypto, ChainPad, CpNetflux, Listmap, nThen, Saferphore) {
@ -409,7 +410,6 @@ define([
var initRpc = function (clientId, data, cb) { var initRpc = function (clientId, data, cb) {
if (!store.loggedIn) { return cb(); } if (!store.loggedIn) { return cb(); }
if (store.rpc) { return void cb(account); } if (store.rpc) { return void cb(account); }
require(['/common/pinpad.js'], function (Pinpad) {
Pinpad.create(store.network, store.proxy, function (e, call) { Pinpad.create(store.network, store.proxy, function (e, call) {
if (e) { return void cb({error: e}); } if (e) { return void cb({error: e}); }
@ -423,7 +423,6 @@ define([
cb(obj); cb(obj);
}); });
}); });
});
}; };
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
@ -1653,6 +1652,73 @@ define([
cb(); cb();
}; };
// Delete a pad received with a burn after reading URL
var notifyOwnerPadRemoved = function (data, obj) {
var channel = data.channel;
var href = data.href;
var parsed = Hash.parsePadUrl(href);
var secret = Hash.getSecrets(parsed.type, parsed.hash, data.password);
if (obj && obj.error) { return; }
if (!obj.mailbox) { return; }
// Decrypt the mailbox
var crypto = Crypto.createEncryptor(secret.keys);
var m = [];
try {
if (typeof (obj.mailbox) === "string") {
m.push(crypto.decrypt(obj.mailbox, true, true));
} else {
Object.keys(obj.mailbox).forEach(function (k) {
m.push(crypto.decrypt(obj.mailbox[k], true, true));
});
}
} catch (e) {
console.error(e);
}
// Tell all the owners that the pad was deleted from the server
var curvePublic = store.proxy.curvePublic;
var myData = Messaging.createData(store.proxy, false);
m.forEach(function (obj) {
var mb = JSON.parse(obj);
if (mb.curvePublic === curvePublic) { return; }
store.mailbox.sendTo('OWNED_PAD_REMOVED', {
channel: channel,
user: myData
}, {
channel: mb.notifications,
curvePublic: mb.curvePublic
}, function () {});
});
};
Store.burnPad = function (clientId, data) {
var channel = data.channel;
var ownerKey = Crypto.b64AddSlashes(data.ownerKey || '');
if (!channel || !ownerKey) { return void console.error("Can't delete BAR pad"); }
try {
var signKey = Hash.decodeBase64(ownerKey);
var pair = Crypto.Nacl.sign.keyPair.fromSecretKey(signKey);
Pinpad.create(store.network, {
edPublic: Hash.encodeBase64(pair.publicKey),
edPrivate: Hash.encodeBase64(pair.secretKey)
}, function (e, rpc) {
if (e) { return void console.error(e); }
Store.getPadMetadata(null, {
channel: channel
}, function (md) {
rpc.removeOwnedChannel(channel, function (err) {
if (err) { return void console.error(err); }
// Notify owners that the pad was removed
notifyOwnerPadRemoved(data, md);
});
});
});
} catch (e) {
console.error(e);
}
};
// Fetch the latest version of the metadata on the server and return it. // Fetch the latest version of the metadata on the server and return it.
// If the pad is stored in our drive, update the local values of "owners" and "expire" // If the pad is stored in our drive, update the local values of "owners" and "expire"
Store.getPadMetadata = function (clientId, data, cb) { Store.getPadMetadata = function (clientId, data, cb) {
@ -2109,6 +2175,11 @@ define([
updateMetadata: function () { updateMetadata: function () {
broadcast([], "UPDATE_METADATA"); broadcast([], "UPDATE_METADATA");
}, },
updateDrive: function () {
sendDriveEvent('DRIVE_CHANGE', {
path: ['drive', 'filesData']
});
},
pinPads: function (data, cb) { Store.pinPads(null, data, cb); }, pinPads: function (data, cb) { Store.pinPads(null, data, cb); },
}, waitFor, function (ev, data, clients, _cb) { }, waitFor, function (ev, data, clients, _cb) {
var cb = Util.once(_cb || function () {}); var cb = Util.once(_cb || function () {});

@ -17,6 +17,7 @@ var factory = function (Util, Cred, Nacl) {
}; };
}; };
// XXX move this function?
Invite.generateSignPair = function () { Invite.generateSignPair = function () {
var ed = Nacl.sign.keyPair(); var ed = Nacl.sign.keyPair();
return { return {

@ -482,6 +482,31 @@ define([
cb(true); cb(true);
}; };
handlers['OWNED_PAD_REMOVED'] = 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;
var res = ctx.store.manager.findChannel(channel);
res.forEach(function (obj) {
var paths = ctx.store.manager.findFile(obj.id);
ctx.store.manager.delete({
paths: paths
}, function () {
ctx.updateDrive();
});
});
cb(true);
};
return { return {

@ -422,6 +422,7 @@ proxy.mailboxes = {
store: store, store: store,
pinPads: cfg.pinPads, pinPads: cfg.pinPads,
updateMetadata: cfg.updateMetadata, updateMetadata: cfg.updateMetadata,
updateDrive: cfg.updateDrive,
emit: emit, emit: emit,
clients: [], clients: [],
boxes: {}, boxes: {},

@ -80,6 +80,7 @@ define([
IS_NEW_CHANNEL: Store.isNewChannel, IS_NEW_CHANNEL: Store.isNewChannel,
REQUEST_PAD_ACCESS: Store.requestPadAccess, REQUEST_PAD_ACCESS: Store.requestPadAccess,
GIVE_PAD_ACCESS: Store.givePadAccess, GIVE_PAD_ACCESS: Store.givePadAccess,
BURN_PAD: Store.burnPad,
GET_PAD_METADATA: Store.getPadMetadata, GET_PAD_METADATA: Store.getPadMetadata,
SET_PAD_METADATA: Store.setPadMetadata, SET_PAD_METADATA: Store.setPadMetadata,
CHANGE_PAD_PASSWORD_PIN: Store.changePadPasswordPin, CHANGE_PAD_PASSWORD_PIN: Store.changePadPasswordPin,

@ -119,6 +119,7 @@ define([
// If it's not a shared folder, check the pads // If it's not a shared folder, check the pads
if (!data) { data = Env.user.userObject.getFileData(id, editable); } if (!data) { data = Env.user.userObject.getFileData(id, editable); }
ret.push({ ret.push({
id: id,
data: data, data: data,
userObject: Env.user.userObject userObject: Env.user.userObject
}); });
@ -126,6 +127,7 @@ define([
Object.keys(Env.folders).forEach(function (fId) { Object.keys(Env.folders).forEach(function (fId) {
Env.folders[fId].userObject.findChannels([channel]).forEach(function (id) { Env.folders[fId].userObject.findChannels([channel]).forEach(function (id) {
ret.push({ ret.push({
id: id,
fId: fId, fId: fId,
data: Env.folders[fId].userObject.getFileData(id, editable), data: Env.folders[fId].userObject.getFileData(id, editable),
userObject: Env.folders[fId].userObject userObject: Env.folders[fId].userObject
@ -1095,9 +1097,11 @@ define([
// Store // Store
getChannelsList: callWithEnv(getChannelsList), getChannelsList: callWithEnv(getChannelsList),
addPad: callWithEnv(addPad), addPad: callWithEnv(addPad),
delete: callWithEnv(_delete),
// Tools // Tools
findChannel: callWithEnv(findChannel), findChannel: callWithEnv(findChannel),
findHref: callWithEnv(findHref), findHref: callWithEnv(findHref),
findFile: callWithEnv(findFile),
getEditHash: callWithEnv(getEditHash), getEditHash: callWithEnv(getEditHash),
user: Env.user, user: Env.user,
folders: Env.folders folders: Env.folders

@ -81,8 +81,8 @@ define([
}); });
localStorage.CRYPTPAD_URLARGS = ApiConfig.requireConf.urlArgs; localStorage.CRYPTPAD_URLARGS = ApiConfig.requireConf.urlArgs;
} }
var cache = {}; var cache = window.cpCache = {};
var localStore = {}; var localStore = window.localStore = {};
Object.keys(localStorage).forEach(function (k) { Object.keys(localStorage).forEach(function (k) {
if (k.indexOf('CRYPTPAD_CACHE|') === 0) { if (k.indexOf('CRYPTPAD_CACHE|') === 0) {
cache[k.slice(('CRYPTPAD_CACHE|').length)] = localStorage[k]; cache[k.slice(('CRYPTPAD_CACHE|').length)] = localStorage[k];
@ -323,6 +323,7 @@ define([
} }
Utils.crypto = Utils.Crypto.createEncryptor(Utils.secret.keys); Utils.crypto = Utils.Crypto.createEncryptor(Utils.secret.keys);
var parsed = Utils.Hash.parsePadUrl(window.location.href); var parsed = Utils.Hash.parsePadUrl(window.location.href);
var burnAfterReading = parsed && parsed.hashData && parsed.hashData.ownerKey;
if (!parsed.type) { throw new Error(); } if (!parsed.type) { throw new Error(); }
var defaultTitle = Utils.UserObject.getDefaultName(parsed); var defaultTitle = Utils.UserObject.getDefaultName(parsed);
var edPublic, curvePublic, notifications, isTemplate; var edPublic, curvePublic, notifications, isTemplate;
@ -376,6 +377,7 @@ define([
fromFileData: Cryptpad.fromFileData ? { fromFileData: Cryptpad.fromFileData ? {
title: Cryptpad.fromFileData.title title: Cryptpad.fromFileData.title
} : undefined, } : undefined,
burnAfterReading: burnAfterReading,
storeInTeam: Cryptpad.initialTeam || (Cryptpad.initialPath ? -1 : undefined) storeInTeam: Cryptpad.initialTeam || (Cryptpad.initialPath ? -1 : undefined)
}; };
if (window.CryptPad_newSharedFolder) { if (window.CryptPad_newSharedFolder) {
@ -507,6 +509,17 @@ define([
} }
}); });
sframeChan.on('Q_GET_PAD_METADATA', function (data, cb) {
if (!data || !data.channel) {
data = {
channel: secret.channel
};
}
Cryptpad.getPadMetadata(data, cb);
});
sframeChan.on('Q_SET_PAD_METADATA', function (data, cb) {
Cryptpad.setPadMetadata(data, cb);
});
}; };
addCommonRpc(sframeChan); addCommonRpc(sframeChan);
@ -1170,18 +1183,6 @@ define([
}); });
}); });
sframeChan.on('Q_GET_PAD_METADATA', function (data, cb) {
if (!data || !data.channel) {
data = {
channel: secret.channel
};
}
Cryptpad.getPadMetadata(data, cb);
});
sframeChan.on('Q_SET_PAD_METADATA', function (data, cb) {
Cryptpad.setPadMetadata(data, cb);
});
if (cfg.messaging) { if (cfg.messaging) {
Notifier.getPermission(); Notifier.getPermission();
@ -1236,6 +1237,16 @@ define([
window.location.hash = hash; window.location.hash = hash;
}; };
if (burnAfterReading) {
Cryptpad.padRpc.onReadyEvent.reg(function () {
Cryptpad.burnPad({
password: password,
href: window.location.href,
channel: secret.channel,
ownerKey: burnAfterReading
});
});
}
var cpNfCfg = { var cpNfCfg = {
sframeChan: sframeChan, sframeChan: sframeChan,
channel: secret.channel, channel: secret.channel,
@ -1359,12 +1370,17 @@ define([
}); });
}); });
sframeChan.on('EV_BURN_AFTER_READING', function () {
startRealtime();
});
sframeChan.ready(); sframeChan.ready();
Utils.Feedback.reportAppUsage(); Utils.Feedback.reportAppUsage();
if (!realtime && !Test.testing) { return; } if (!realtime && !Test.testing) { return; }
if (isNewFile && cfg.useCreationScreen && !Test.testing) { return; } if (isNewFile && cfg.useCreationScreen && !Test.testing) { return; }
if (burnAfterReading) { return; }
//if (isNewFile && Utils.LocalStore.isLoggedIn() //if (isNewFile && Utils.LocalStore.isLoggedIn()
// && AppConfig.displayCreationScreen && cfg.useCreationScreen) { return; } // && AppConfig.displayCreationScreen && cfg.useCreationScreen) { return; }

@ -96,6 +96,7 @@ define([
funcs.createMarkdownToolbar = callWithCommon(UIElements.createMarkdownToolbar); funcs.createMarkdownToolbar = callWithCommon(UIElements.createMarkdownToolbar);
funcs.createHelpMenu = callWithCommon(UIElements.createHelpMenu); funcs.createHelpMenu = callWithCommon(UIElements.createHelpMenu);
funcs.getPadCreationScreen = callWithCommon(UIElements.getPadCreationScreen); funcs.getPadCreationScreen = callWithCommon(UIElements.getPadCreationScreen);
funcs.getBurnAfterReadingWarning = callWithCommon(UIElements.getBurnAfterReadingWarning);
funcs.createNewPadModal = callWithCommon(UIElements.createNewPadModal); funcs.createNewPadModal = callWithCommon(UIElements.createNewPadModal);
funcs.onServerError = callWithCommon(UIElements.onServerError); funcs.onServerError = callWithCommon(UIElements.onServerError);
funcs.importMediaTagMenu = callWithCommon(UIElements.importMediaTagMenu); funcs.importMediaTagMenu = callWithCommon(UIElements.importMediaTagMenu);
@ -300,6 +301,13 @@ define([
} }
// If we display the pad creation screen, it will handle deleted pads directly // If we display the pad creation screen, it will handle deleted pads directly
funcs.getPadCreationScreen(c, config, waitFor()); funcs.getPadCreationScreen(c, config, waitFor());
return;
}
if (priv.burnAfterReading) {
UIElements.displayBurnAfterReadingPage(funcs, waitFor(function () {
UI.addLoadingScreen();
ctx.sframeChan.event('EV_BURN_AFTER_READING');
}));
} }
}; };
funcs.createPad = function (cfg, cb) { funcs.createPad = function (cfg, cb) {

@ -58,7 +58,7 @@ define([
// Remove the listener once we've received the READY message // Remove the listener once we've received the READY message
window.removeEventListener('message', whenReady); window.removeEventListener('message', whenReady);
// Answer with the requested data // Answer with the requested data
postMsg(JSON.stringify({ txid: data.txid, language: Cryptpad.getLanguage() })); postMsg(JSON.stringify({ txid: data.txid, language: Cryptpad.getLanguage(), localStore: window.localStore, cache: window.cpCache }));
// Then start the channel // Then start the channel
window.addEventListener('message', function (msg) { window.addEventListener('message', function (msg) {

@ -350,6 +350,8 @@ define([
var mkHelpMenu = function (framework) { var mkHelpMenu = function (framework) {
var $toolbarContainer = $('#cp-app-kanban-container'); var $toolbarContainer = $('#cp-app-kanban-container');
$toolbarContainer.prepend(framework._.sfCommon.getBurnAfterReadingWarning());
var helpMenu = framework._.sfCommon.createHelpMenu(['kanban']); var helpMenu = framework._.sfCommon.createHelpMenu(['kanban']);
$toolbarContainer.prepend(helpMenu.menu); $toolbarContainer.prepend(helpMenu.menu);

@ -190,6 +190,7 @@ define([
var mkHelpMenu = function (framework) { var mkHelpMenu = function (framework) {
var $toolbarContainer = $('.cke_toolbox_main'); var $toolbarContainer = $('.cke_toolbox_main');
$toolbarContainer.before(framework._.sfCommon.getBurnAfterReadingWarning());
var helpMenu = framework._.sfCommon.createHelpMenu(['text', 'pad']); var helpMenu = framework._.sfCommon.createHelpMenu(['text', 'pad']);
$toolbarContainer.before(helpMenu.menu); $toolbarContainer.before(helpMenu.menu);

@ -1187,6 +1187,7 @@ define([
$drawer.append($export); $drawer.append($export);
var helpMenu = common.createHelpMenu(['poll']); var helpMenu = common.createHelpMenu(['poll']);
$('#cp-app-poll-form').prepend(common.getBurnAfterReadingWarning());
$('#cp-app-poll-form').prepend(helpMenu.menu); $('#cp-app-poll-form').prepend(helpMenu.menu);
$drawer.append(helpMenu.button); $drawer.append(helpMenu.button);

@ -60,7 +60,7 @@ define([
// Remove the listener once we've received the READY message // Remove the listener once we've received the READY message
window.removeEventListener('message', whenReady); window.removeEventListener('message', whenReady);
// Answer with the requested data // Answer with the requested data
postMsg(JSON.stringify({ txid: data.txid, language: Cryptpad.getLanguage() })); postMsg(JSON.stringify({ txid: data.txid, language: Cryptpad.getLanguage(), localStore: window.localStore, cache: window.cpCache }));
// Then start the channel // Then start the channel
window.addEventListener('message', function (msg) { window.addEventListener('message', function (msg) {
@ -105,6 +105,21 @@ define([
config.addCommonRpc(sframeChan); config.addCommonRpc(sframeChan);
sframeChan.on('EV_CACHE_PUT', function (x) {
Object.keys(x).forEach(function (k) {
localStorage['CRYPTPAD_CACHE|' + k] = x[k];
});
});
sframeChan.on('EV_LOCALSTORE_PUT', function (x) {
Object.keys(x).forEach(function (k) {
if (typeof(x[k]) === "undefined") {
delete localStorage['CRYPTPAD_STORE|' + k];
return;
}
localStorage['CRYPTPAD_STORE|' + k] = x[k];
});
});
sframeChan.on('Q_GET_FILES_LIST', function (types, cb) { sframeChan.on('Q_GET_FILES_LIST', function (types, cb) {
Cryptpad.getSecureFilesList(types, function (err, data) { Cryptpad.getSecureFilesList(types, function (err, data) {
cb({ cb({

@ -410,6 +410,7 @@ define([
var mkHelpMenu = function (framework) { var mkHelpMenu = function (framework) {
var $codeMirrorContainer = $('#cp-app-slide-editor-container'); var $codeMirrorContainer = $('#cp-app-slide-editor-container');
$codeMirrorContainer.prepend(framework._.sfCommon.getBurnAfterReadingWarning());
var helpMenu = framework._.sfCommon.createHelpMenu(['text', 'slide']); var helpMenu = framework._.sfCommon.createHelpMenu(['text', 'slide']);
$codeMirrorContainer.prepend(helpMenu.menu); $codeMirrorContainer.prepend(helpMenu.menu);

@ -270,6 +270,7 @@ define([
var mkHelpMenu = function (framework) { var mkHelpMenu = function (framework) {
var $appContainer = $('#cp-app-whiteboard-container'); var $appContainer = $('#cp-app-whiteboard-container');
$appContainer.prepend(framework._.sfCommon.getBurnAfterReadingWarning());
var helpMenu = framework._.sfCommon.createHelpMenu(['whiteboard']); var helpMenu = framework._.sfCommon.createHelpMenu(['whiteboard']);
$appContainer.prepend(helpMenu.menu); $appContainer.prepend(helpMenu.menu);
framework._.toolbar.$drawer.append(helpMenu.button); framework._.toolbar.$drawer.append(helpMenu.button);

Loading…
Cancel
Save