Merge branch 'staging' into newCk
This commit is contained in:
commit
5a248db267
59 files changed
+1651
-671
No files matched your search
@@ -20,5 +20,25 @@ define([], function () {
|
||||
};
|
||||
}
|
||||
|
||||
var failStore = function () {
|
||||
console.error(new Error('wut'));
|
||||
require(['jquery'], function ($) {
|
||||
$.ajax({
|
||||
type: 'HEAD',
|
||||
url: '/common/feedback.html?NO_LOCALSTORAGE=' + (+new Date()),
|
||||
});
|
||||
});
|
||||
window.alert("CryptPad needs localStorage to work, try a different browser");
|
||||
};
|
||||
|
||||
try {
|
||||
var test_key = 'localStorage_test';
|
||||
var testval = Math.random().toString();
|
||||
localStorage.setItem(test_key, testval);
|
||||
if (localStorage.getItem(test_key) !== testval) {
|
||||
failStore();
|
||||
}
|
||||
} catch (e) { console.error(e); failStore(); }
|
||||
|
||||
require([document.querySelector('script[data-bootload]').getAttribute('data-bootload')]);
|
||||
});
|
||||
@@ -0,0 +1,294 @@
|
||||
define([
|
||||
'jquery',
|
||||
'/file/file-crypto.js',
|
||||
'/bower_components/tweetnacl/nacl-fast.min.js',
|
||||
], function ($, FileCrypto) {
|
||||
var Nacl = window.nacl;
|
||||
var module = {};
|
||||
|
||||
module.create = function (common, config) {
|
||||
var File = {};
|
||||
|
||||
var Messages = common.Messages;
|
||||
|
||||
var queue = File.queue = {
|
||||
queue: [],
|
||||
inProgress: false
|
||||
};
|
||||
|
||||
var uid = function () {
|
||||
return 'file-' + String(Math.random()).substring(2);
|
||||
};
|
||||
|
||||
var $table = File.$table = $('<table>', { id: 'uploadStatus' });
|
||||
var $thead = $('<tr>').appendTo($table);
|
||||
$('<td>').text(Messages.upload_name).appendTo($thead);
|
||||
$('<td>').text(Messages.upload_size).appendTo($thead);
|
||||
$('<td>').text(Messages.upload_progress).appendTo($thead);
|
||||
$('<td>').text(Messages.cancel).appendTo($thead);
|
||||
|
||||
var createTableContainer = function ($body) {
|
||||
File.$container = $('<div>', { id: 'uploadStatusContainer' }).append($table).appendTo($body);
|
||||
return File.$container;
|
||||
};
|
||||
|
||||
var getData = function (file, href) {
|
||||
var data = {};
|
||||
|
||||
data.name = file.metadata.name;
|
||||
data.url = href;
|
||||
if (file.metadata.type.slice(0,6) === 'image/') {
|
||||
data.mediatag = true;
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
var upload = function (file) {
|
||||
var blob = file.blob;
|
||||
var metadata = file.metadata;
|
||||
var id = file.id;
|
||||
if (queue.inProgress) { return; }
|
||||
queue.inProgress = true;
|
||||
|
||||
var $row = $table.find('tr[id="'+id+'"]');
|
||||
|
||||
$row.find('.upCancel').html('-');
|
||||
var $pv = $row.find('.progressValue');
|
||||
var $pb = $row.find('.progressContainer');
|
||||
var $link = $row.find('.upLink');
|
||||
|
||||
var updateProgress = function (progressValue) {
|
||||
$pv.text(Math.round(progressValue*100)/100 + '%');
|
||||
$pb.css({
|
||||
width: (progressValue/100)*188+'px'
|
||||
});
|
||||
};
|
||||
|
||||
var u8 = new Uint8Array(blob);
|
||||
|
||||
var key = Nacl.randomBytes(32);
|
||||
var next = FileCrypto.encrypt(u8, metadata, key);
|
||||
|
||||
var estimate = FileCrypto.computeEncryptedSize(blob.byteLength, metadata);
|
||||
|
||||
var sendChunk = function (box, cb) {
|
||||
var enc = Nacl.util.encodeBase64(box);
|
||||
common.rpc.send.unauthenticated('UPLOAD', enc, function (e, msg) {
|
||||
console.log(box);
|
||||
cb(e, msg);
|
||||
});
|
||||
};
|
||||
|
||||
var actual = 0;
|
||||
var again = function (err, box) {
|
||||
if (err) { throw new Error(err); }
|
||||
if (box) {
|
||||
actual += box.length;
|
||||
var progressValue = (actual / estimate * 100);
|
||||
updateProgress(progressValue);
|
||||
|
||||
return void sendChunk(box, function (e) {
|
||||
if (e) { return console.error(e); }
|
||||
next(again);
|
||||
});
|
||||
}
|
||||
|
||||
if (actual !== estimate) {
|
||||
console.error('Estimated size does not match actual size');
|
||||
}
|
||||
|
||||
// if not box then done
|
||||
common.uploadComplete(function (e, id) {
|
||||
if (e) { return void console.error(e); }
|
||||
var uri = ['', 'blob', id.slice(0,2), id].join('/');
|
||||
console.log("encrypted blob is now available as %s", uri);
|
||||
|
||||
var b64Key = Nacl.util.encodeBase64(key);
|
||||
|
||||
var hash = common.getFileHashFromKeys(id, b64Key);
|
||||
var href = '/file/#' + hash;
|
||||
$link.attr('href', href)
|
||||
.click(function (e) {
|
||||
e.preventDefault();
|
||||
window.open($link.attr('href'), '_blank');
|
||||
});
|
||||
|
||||
// TODO add button to table which copies link to clipboard?
|
||||
//APP.toolbar.addElement(['fileshare'], {});
|
||||
|
||||
var title = metadata.name;
|
||||
|
||||
common.renamePad(title || "", href, function (err) {
|
||||
if (err) { return void console.error(err); } // TODO
|
||||
console.log(title);
|
||||
common.log(Messages._getKey('upload_success', [title]));
|
||||
common.prepareFeedback('upload')();
|
||||
|
||||
if (config.onUploaded) {
|
||||
var data = getData(file, href);
|
||||
config.onUploaded(file.dropEvent, data);
|
||||
}
|
||||
|
||||
queue.inProgress = false;
|
||||
queue.next();
|
||||
});
|
||||
//Title.updateTitle(title || "", href);
|
||||
//APP.toolbar.title.show();
|
||||
});
|
||||
};
|
||||
|
||||
common.uploadStatus(estimate, function (e, pending) {
|
||||
if (e) {
|
||||
queue.inProgress = false;
|
||||
queue.next();
|
||||
if (e === 'TOO_LARGE') {
|
||||
// TODO update table to say too big?
|
||||
return void common.alert(Messages.upload_tooLarge);
|
||||
}
|
||||
if (e === 'NOT_ENOUGH_SPACE') {
|
||||
// TODO update table to say not enough space?
|
||||
return void common.alert(Messages.upload_notEnoughSpace);
|
||||
}
|
||||
console.error(e);
|
||||
return void common.alert(Messages.upload_serverError);
|
||||
}
|
||||
|
||||
if (pending) {
|
||||
// TODO keep this message in case of pending files in another window?
|
||||
return void common.confirm(Messages.upload_uploadPending, function (yes) {
|
||||
if (!yes) { return; }
|
||||
common.uploadCancel(function (e, res) {
|
||||
if (e) {
|
||||
return void console.error(e);
|
||||
}
|
||||
console.log(res);
|
||||
next(again);
|
||||
});
|
||||
});
|
||||
}
|
||||
next(again);
|
||||
});
|
||||
};
|
||||
|
||||
var prettySize = function (bytes) {
|
||||
var kB = common.bytesToKilobytes(bytes);
|
||||
if (kB < 1024) { return kB + Messages.KB; }
|
||||
var mB = common.bytesToMegabytes(bytes);
|
||||
return mB + Messages.MB;
|
||||
};
|
||||
|
||||
queue.next = function () {
|
||||
if (queue.queue.length === 0) {
|
||||
queue.to = window.setTimeout(function () {
|
||||
if (config.keepTable) { return; }
|
||||
File.$container.fadeOut();
|
||||
}, 3000);
|
||||
return;
|
||||
}
|
||||
if (queue.inProgress) { return; }
|
||||
File.$container.show();
|
||||
var file = queue.queue.shift();
|
||||
upload(file);
|
||||
};
|
||||
queue.push = function (obj) {
|
||||
var id = uid();
|
||||
obj.id = id;
|
||||
queue.queue.push(obj);
|
||||
|
||||
$table.show();
|
||||
var estimate = FileCrypto.computeEncryptedSize(obj.blob.byteLength, obj.metadata);
|
||||
|
||||
var $progressBar = $('<div>', {'class':'progressContainer'});
|
||||
var $progressValue = $('<span>', {'class':'progressValue'}).text(Messages.upload_pending);
|
||||
|
||||
var $tr = $('<tr>', {id: id}).appendTo($table);
|
||||
|
||||
var $cancel = $('<span>', {'class': 'cancel fa fa-times'}).click(function () {
|
||||
queue.queue = queue.queue.filter(function (el) { return el.id !== id; });
|
||||
$cancel.remove();
|
||||
$tr.find('.upCancel').text('-');
|
||||
$tr.find('.progressValue').text(Messages.upload_cancelled);
|
||||
});
|
||||
|
||||
var $link = $('<a>', {
|
||||
'class': 'upLink',
|
||||
'rel': 'noopener noreferrer'
|
||||
}).text(obj.metadata.name);
|
||||
|
||||
$('<td>').append($link).appendTo($tr);
|
||||
$('<td>').text(prettySize(estimate)).appendTo($tr);
|
||||
$('<td>', {'class': 'upProgress'}).append($progressBar).append($progressValue).appendTo($tr);
|
||||
$('<td>', {'class': 'upCancel'}).append($cancel).appendTo($tr);
|
||||
|
||||
queue.next();
|
||||
};
|
||||
|
||||
var handleFile = File.handleFile = function (file, e) {
|
||||
var reader = new FileReader();
|
||||
reader.onloadend = function () {
|
||||
queue.push({
|
||||
blob: this.result,
|
||||
metadata: {
|
||||
name: file.name,
|
||||
type: file.type,
|
||||
},
|
||||
dropEvent: e
|
||||
});
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
};
|
||||
|
||||
var onFileDrop = File.onFileDrop = function (file, e) {
|
||||
Array.prototype.slice.call(file).forEach(function (d) {
|
||||
handleFile(d, e);
|
||||
});
|
||||
};
|
||||
|
||||
var createAreaHandlers = File.createDropArea = function ($area, $hoverArea) {
|
||||
var counter = 0;
|
||||
if (!$hoverArea) { $hoverArea = $area; }
|
||||
$hoverArea
|
||||
.on('dragenter', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
counter++;
|
||||
$hoverArea.addClass('hovering');
|
||||
})
|
||||
.on('dragleave', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
counter--;
|
||||
if (counter <= 0) {
|
||||
$hoverArea.removeClass('hovering');
|
||||
}
|
||||
});
|
||||
|
||||
$area
|
||||
.on('drag dragstart dragend dragover drop dragenter dragleave', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
})
|
||||
.on('drop', function (e) {
|
||||
e.stopPropagation();
|
||||
var dropped = e.originalEvent.dataTransfer.files;
|
||||
counter = 0;
|
||||
$hoverArea.removeClass('hovering');
|
||||
onFileDrop(dropped, e);
|
||||
});
|
||||
};
|
||||
|
||||
var createUploader = function ($area, $hover, $body) {
|
||||
if (!config.noHandlers) {
|
||||
createAreaHandlers($area, null);
|
||||
}
|
||||
createTableContainer($body);
|
||||
};
|
||||
|
||||
createUploader(config.dropArea, config.hoverArea, config.body);
|
||||
|
||||
return File;
|
||||
};
|
||||
|
||||
return module;
|
||||
});
|
||||
@@ -37,6 +37,17 @@ define([
|
||||
|
||||
var parsed = config.href ? common.parsePadUrl(config.href) : {};
|
||||
var secret = common.getSecrets(parsed.type, parsed.hash);
|
||||
|
||||
History.readOnly = 1;
|
||||
if (!secret.keys) {
|
||||
secret.keys = secret.key;
|
||||
History.readOnly = 2;
|
||||
}
|
||||
else if (!secret.keys.validateKey) {
|
||||
secret.keys.validateKey = true;
|
||||
History.readOnly = 0;
|
||||
}
|
||||
|
||||
var crypto = Crypto.createEncryptor(secret.keys);
|
||||
|
||||
var to = window.setTimeout(function () {
|
||||
@@ -185,6 +196,7 @@ define([
|
||||
'class':'revertHistory buttonSuccess',
|
||||
title: Messages.history_restoreTitle
|
||||
}).text(Messages.history_restore).appendTo($nav);
|
||||
if (!History.readOnly) { $rev.hide(); }
|
||||
|
||||
onUpdate = function () {
|
||||
$cur.attr('max', states.length);
|
||||
|
||||
@@ -14,6 +14,7 @@ define(function () {
|
||||
var getHeadingText = cfg.getHeadingText || function () { return; };
|
||||
var updateLocalTitle = function (newTitle) {
|
||||
exp.title = newTitle;
|
||||
onLocal();
|
||||
if (typeof cfg.updateLocalTitle === "function") {
|
||||
cfg.updateLocalTitle(newTitle);
|
||||
} else {
|
||||
@@ -43,11 +44,12 @@ define(function () {
|
||||
onLocal();
|
||||
};
|
||||
|
||||
exp.updateTitle = function (newTitle) {
|
||||
// update title: href is optional; if not specified, we use window.location.href
|
||||
exp.updateTitle = function (newTitle, href) {
|
||||
if (newTitle === exp.title) { return; }
|
||||
// Change the title now, and set it back to the old value if there is an error
|
||||
var oldTitle = exp.title;
|
||||
Cryptpad.renamePad(newTitle, function (err, data) {
|
||||
Cryptpad.renamePad(newTitle, href, function (err, data) {
|
||||
if (err) {
|
||||
console.log("Couldn't set pad title");
|
||||
console.error(err);
|
||||
|
||||
@@ -68,7 +68,11 @@ define([], function () {
|
||||
Util.replaceHash = function (hash) {
|
||||
if (window.history && window.history.replaceState) {
|
||||
if (!/^#/.test(hash)) { hash = '#' + hash; }
|
||||
return void window.history.replaceState({}, window.document.title, hash);
|
||||
void window.history.replaceState({}, window.document.title, hash);
|
||||
if (typeof(window.onhashchange) === 'function') {
|
||||
window.onhashchange();
|
||||
}
|
||||
return;
|
||||
}
|
||||
window.location.hash = hash;
|
||||
};
|
||||
|
||||
+100
-28
@@ -11,11 +11,13 @@ define([
|
||||
'/common/common-title.js',
|
||||
'/common/common-metadata.js',
|
||||
'/common/common-codemirror.js',
|
||||
'/common/common-file.js',
|
||||
|
||||
'/common/clipboard.js',
|
||||
'/common/pinpad.js',
|
||||
'/customize/application_config.js'
|
||||
], function ($, Config, Messages, Store, Util, Hash, UI, History, UserList, Title, Metadata, CodeMirror, Clipboard, Pinpad, AppConfig) {
|
||||
], function ($, Config, Messages, Store, Util, Hash, UI, History, UserList, Title, Metadata,
|
||||
CodeMirror, Files, Clipboard, Pinpad, AppConfig) {
|
||||
|
||||
/* This file exposes functionality which is specific to Cryptpad, but not to
|
||||
any particular pad type. This includes functions for committing metadata
|
||||
@@ -114,6 +116,9 @@ define([
|
||||
// CodeMirror
|
||||
common.createCodemirror = CodeMirror.create;
|
||||
|
||||
// Files
|
||||
common.createFileManager = function (config) { return Files.create(common, config); };
|
||||
|
||||
// History
|
||||
common.getHistory = function (config) { return History.create(common, config); };
|
||||
|
||||
@@ -126,6 +131,11 @@ define([
|
||||
return store.getProxy().proxy;
|
||||
}
|
||||
};
|
||||
common.getFO = function () {
|
||||
if (store && store.getProxy()) {
|
||||
return store.getProxy().fo;
|
||||
}
|
||||
};
|
||||
var getNetwork = common.getNetwork = function () {
|
||||
if (store) {
|
||||
if (store.getProxy() && store.getProxy().info) {
|
||||
@@ -144,7 +154,6 @@ define([
|
||||
}
|
||||
|
||||
var href = '/common/feedback.html?' + action + '=' + (+new Date());
|
||||
console.log('[feedback] %s', href);
|
||||
$.ajax({
|
||||
type: "HEAD",
|
||||
url: href,
|
||||
@@ -300,7 +309,7 @@ define([
|
||||
cb(parsed);
|
||||
}
|
||||
if (!pad.title) {
|
||||
pad.title = common.getDefaultname(parsed);
|
||||
pad.title = common.getDefaultName(parsed);
|
||||
}
|
||||
return parsed.hashData;
|
||||
};
|
||||
@@ -520,8 +529,8 @@ define([
|
||||
cb ("store.forgetPad is not a function");
|
||||
};
|
||||
|
||||
common.setPadTitle = function (name, cb) {
|
||||
var href = window.location.href;
|
||||
common.setPadTitle = function (name, padHref, cb) {
|
||||
var href = padHref || window.location.href;
|
||||
var parsed = parsePadUrl(href);
|
||||
if (!parsed.hash) { return; }
|
||||
href = getRelativeHref(href);
|
||||
@@ -581,19 +590,6 @@ define([
|
||||
return pad;
|
||||
});
|
||||
|
||||
if (!contains && href) {
|
||||
var data = makePad(href, name);
|
||||
getStore().pushData(data, function (e, id) {
|
||||
if (e) {
|
||||
if (e === 'E_OVER_LIMIT') {
|
||||
common.alert(Messages.pinLimitNotPinned, null, true);
|
||||
return;
|
||||
}
|
||||
else { throw new Error("Cannot push this pad to CryptDrive", e); }
|
||||
}
|
||||
getStore().addPad(id, common.initialPath);
|
||||
});
|
||||
}
|
||||
if (updateWeaker.length > 0) {
|
||||
updateWeaker.forEach(function (obj) {
|
||||
// If we have a stronger url, and if all the occurences of the weaker were
|
||||
@@ -601,6 +597,20 @@ define([
|
||||
getStore().restoreHref(obj.n);
|
||||
});
|
||||
}
|
||||
if (!contains && href) {
|
||||
var data = makePad(href, name);
|
||||
getStore().pushData(data, function (e, id) {
|
||||
if (e) {
|
||||
if (e === 'E_OVER_LIMIT') {
|
||||
common.alert(Messages.pinLimitNotPinned, null, true);
|
||||
}
|
||||
return void cb(e);
|
||||
}
|
||||
getStore().addPad(id, common.initialPath);
|
||||
cb(err, recent);
|
||||
});
|
||||
return;
|
||||
}
|
||||
cb(err, recent);
|
||||
});
|
||||
};
|
||||
@@ -621,24 +631,41 @@ define([
|
||||
/*
|
||||
* Buttons
|
||||
*/
|
||||
common.renamePad = function (title, callback) {
|
||||
common.renamePad = function (title, href, callback) {
|
||||
if (title === null) { return; }
|
||||
|
||||
if (title.trim() === "") {
|
||||
var parsed = parsePadUrl(window.location.href);
|
||||
var parsed = parsePadUrl(href || window.location.href);
|
||||
title = getDefaultName(parsed);
|
||||
}
|
||||
|
||||
common.setPadTitle(title, function (err) {
|
||||
common.setPadTitle(title, href, function (err) {
|
||||
if (err) {
|
||||
console.log("unable to set pad title");
|
||||
console.log(err);
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
callback(null, title);
|
||||
});
|
||||
};
|
||||
|
||||
common.getUserFilesList = function () {
|
||||
var store = common.getStore();
|
||||
var proxy = store.getProxy();
|
||||
var fo = proxy.fo;
|
||||
var hashes = [];
|
||||
var list = fo.getFiles().filter(function (id) {
|
||||
var href = fo.getFileData(id).href;
|
||||
var parsed = parsePadUrl(href);
|
||||
if ((parsed.type === 'file' || parsed.type === 'media')
|
||||
&& hashes.indexOf(parsed.hash) === -1) {
|
||||
hashes.push(parsed.hash);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return list;
|
||||
};
|
||||
|
||||
var getUserChannelList = common.getUserChannelList = function () {
|
||||
var store = common.getStore();
|
||||
var proxy = store.getProxy();
|
||||
@@ -879,6 +906,21 @@ define([
|
||||
common.getPinnedUsage(todo);
|
||||
};
|
||||
|
||||
var getAppSuffix = function () {
|
||||
var parts = window.location.pathname.split('/')
|
||||
.filter(function (x) { return x; });
|
||||
|
||||
if (!parts[0]) { return ''; }
|
||||
return '_' + parts[0].toUpperCase();
|
||||
};
|
||||
|
||||
var prepareFeedback = common.prepareFeedback = function (key) {
|
||||
if (typeof(key) !== 'string') { return $.noop; }
|
||||
return function () {
|
||||
feedback(key.toUpperCase() + getAppSuffix());
|
||||
};
|
||||
};
|
||||
|
||||
common.createButton = function (type, rightside, data, callback) {
|
||||
var button;
|
||||
var size = "17px";
|
||||
@@ -887,6 +929,8 @@ define([
|
||||
button = $('<button>', {
|
||||
title: Messages.exportButtonTitle,
|
||||
}).append($('<span>', {'class':'fa fa-download', style: 'font:'+size+' FontAwesome'}));
|
||||
|
||||
button.click(prepareFeedback(type));
|
||||
if (callback) {
|
||||
button.click(callback);
|
||||
}
|
||||
@@ -896,18 +940,40 @@ define([
|
||||
title: Messages.importButtonTitle,
|
||||
}).append($('<span>', {'class':'fa fa-upload', style: 'font:'+size+' FontAwesome'}));
|
||||
if (callback) {
|
||||
button.click(UI.importContent('text/plain', function (content, file) {
|
||||
button
|
||||
.click(prepareFeedback(type))
|
||||
.click(UI.importContent('text/plain', function (content, file) {
|
||||
callback(content, file);
|
||||
}));
|
||||
}
|
||||
break;
|
||||
case 'upload':
|
||||
button = $('<button>', {
|
||||
'class': 'btn btn-primary new',
|
||||
title: Messages.uploadButtonTitle,
|
||||
}).append($('<span>', {'class':'fa fa-upload'})).append(' '+Messages.uploadButton);
|
||||
if (!data.FM) { return; }
|
||||
var $input = $('<input>', {
|
||||
'type': 'file',
|
||||
'style': 'display: none;'
|
||||
}).on('change', function (e) {
|
||||
var file = e.target.files[0];
|
||||
var ev = {
|
||||
target: data.target
|
||||
};
|
||||
data.FM.handleFile(file, ev);
|
||||
if (callback) { callback(); }
|
||||
});
|
||||
button.click(function () { $input.click(); });
|
||||
break;
|
||||
case 'template':
|
||||
if (!AppConfig.enableTemplates) { return; }
|
||||
button = $('<button>', {
|
||||
title: Messages.saveTemplateButton,
|
||||
}).append($('<span>', {'class':'fa fa-bookmark', style: 'font:'+size+' FontAwesome'}));
|
||||
if (data.rt && data.Crypt) {
|
||||
button.click(function () {
|
||||
button
|
||||
.click(function () {
|
||||
var title = data.getTitle() || document.title;
|
||||
var todo = function (val) {
|
||||
if (typeof(val) !== "string") { return; }
|
||||
@@ -965,7 +1031,9 @@ define([
|
||||
}
|
||||
});
|
||||
if (callback) {
|
||||
button.click(function() {
|
||||
button
|
||||
.click(prepareFeedback(type))
|
||||
.click(function() {
|
||||
var href = window.location.href;
|
||||
var msg = isLoggedIn() ? Messages.forgetPrompt : Messages.fm_removePermanentlyDialog;
|
||||
common.confirm(msg, function (yes) {
|
||||
@@ -1021,7 +1089,9 @@ define([
|
||||
style: 'font:'+size+' FontAwesome'
|
||||
});
|
||||
if (data.histConfig) {
|
||||
button.click(function () {
|
||||
button
|
||||
.click(prepareFeedback(type))
|
||||
.click(function () {
|
||||
common.getHistory(data.histConfig);
|
||||
});
|
||||
}
|
||||
@@ -1030,7 +1100,8 @@ define([
|
||||
button = $('<button>', {
|
||||
'class': "fa fa-question",
|
||||
style: 'font:'+size+' FontAwesome'
|
||||
});
|
||||
})
|
||||
.click(prepareFeedback(type));
|
||||
}
|
||||
if (rightside) {
|
||||
button.addClass('rightside-button');
|
||||
@@ -1378,8 +1449,8 @@ define([
|
||||
initialized = true;
|
||||
|
||||
updateLocalVersion();
|
||||
|
||||
f(void 0, env);
|
||||
if (typeof(window.onhashchange) === 'function') { window.onhashchange(); }
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1422,6 +1493,7 @@ define([
|
||||
|| parsedOld.channel !== parsedNew.channel
|
||||
|| parsedOld.mode !== parsedNew.mode
|
||||
|| parsedOld.key !== parsedNew.key)) {
|
||||
if (!parsedOld.channel) { oldHref = newHref; return; }
|
||||
document.location.reload();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
define([
|
||||
'jquery',
|
||||
'/bower_components/marked/marked.min.js',
|
||||
'/bower_components/diff-dom/diffDOM.js'
|
||||
],function ($, Marked) {
|
||||
'/common/cryptpad-common.js',
|
||||
'/common/media-tag.js',
|
||||
'/bower_components/diff-dom/diffDOM.js',
|
||||
'/bower_components/tweetnacl/nacl-fast.min.js',
|
||||
],function ($, Marked, Cryptpad, MediaTag) {
|
||||
var DiffMd = {};
|
||||
|
||||
var DiffDOM = window.diffDOM;
|
||||
@@ -33,6 +36,20 @@ define([
|
||||
var cls = (isCheckedTaskItem || isUncheckedTaskItem) ? ' class="todo-list-item"' : '';
|
||||
return '<li'+ cls + '>' + text + '</li>\n';
|
||||
};
|
||||
renderer.image = function (href, title, text) {
|
||||
if (href.slice(0,6) === '/file/') {
|
||||
var parsed = Cryptpad.parsePadUrl(href);
|
||||
var hexFileName = Cryptpad.base64ToHex(parsed.hashData.channel);
|
||||
var mt = '<media-tag src="/blob/' + hexFileName.slice(0,2) + '/' + hexFileName + '" data-crypto-key="cryptpad:' + parsed.hashData.key + '"></media-tag>';
|
||||
return mt;
|
||||
}
|
||||
var out = '<img src="' + href + '" alt="' + text + '"';
|
||||
if (title) {
|
||||
out += ' title="' + title + '"';
|
||||
}
|
||||
out += this.options.xhtml ? '/>' : '>';
|
||||
return out;
|
||||
};
|
||||
|
||||
var forbiddenTags = [
|
||||
'SCRIPT',
|
||||
@@ -43,6 +60,10 @@ define([
|
||||
'AUDIO',
|
||||
];
|
||||
var unsafeTag = function (info) {
|
||||
if (info.node && $(info.node).parents('media-tag').length) {
|
||||
// Do not remove elements inside a media-tag
|
||||
return true;
|
||||
}
|
||||
if (['addAttribute', 'modifyAttribute'].indexOf(info.diff.action) !== -1) {
|
||||
if (/^on/.test(info.diff.name)) {
|
||||
console.log("Rejecting forbidden element attribute with name", info.diff.name);
|
||||
@@ -61,6 +82,7 @@ define([
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var slice = function (coll) {
|
||||
return Array.prototype.slice.call(coll);
|
||||
};
|
||||
@@ -85,7 +107,7 @@ define([
|
||||
var DD = new DiffDOM({
|
||||
preDiffApply: function (info) {
|
||||
if (unsafeTag(info)) { return true; }
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
var makeDiff = function (A, B, id) {
|
||||
@@ -119,9 +141,18 @@ define([
|
||||
throw new Error(patch);
|
||||
} else {
|
||||
DD.apply($content[0], patch);
|
||||
var $mts = $content.find('media-tag:not(:has(*))');
|
||||
$mts.each(function (i, el) {
|
||||
MediaTag(el);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$(window.document).on('decryption', function (e) {
|
||||
var decrypted = e.originalEvent;
|
||||
if (decrypted.callback) { decrypted.callback(); }
|
||||
});
|
||||
|
||||
return DiffMd;
|
||||
});
|
||||
|
||||
@@ -1 +1 @@
|
||||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.MediaTag=t():e.MediaTag=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var n={};return t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=86)}([function(e,t,n){"use strict";var r={IMAGE:"image",AUDIO:"audio",VIDEO:"video",PDF:"pdf",DASH:"dash",DOWNLOAD:"download",CRYPTO:"crypto",CLEAR_KEY:"clear-key",MEDIA_OBJECT:"media-object"};e.exports=r},function(e,t,n){"use strict";var r={MATCHER:"matcher",RENDERER:"renderer",FILTER:"filter",SANITIZER:"sanitizer"};e.exports=r},function(e,t,n){"use strict";function r(e){if(e instanceof Array){var t=[];return e.forEach(function(e){e.mediaObject?t.push(e.mediaObject):t.push(r.start(e))}),t}var n=e;return r.start(n)}var o=n(25),i=n(24),u=n(44),a=n(45),c=n(23),s=n(22);r.createMediaObject=function(e){var t=new s(e),n=c.parse(t);return t.setProperties(n),t},r.start=function(e){var t=r.createMediaObject(e);return r.processingEngine.start(t)},r.pluginStore=r.pluginStore||new u,r.uriStore=r.uriStore||new a("../plugins"),r.processingEngine=r.processingEngine||new o(r.pluginStore),r.matchingEngine=r.matchingEngine||new i(r.pluginStore,r.uriStore),r.loadingEngine=null,e.exports=r},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function i(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var u=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}(),a=n(1),c=n(5),s=n(6),f=function(e){function t(e,n){r(this,t);var i=o(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,a.MATCHER,c.ANY));return i.targetType=n,i}return i(t,e),u(t,[{key:"getTargetType",value:function(){return this.targetType}}]),t}(s);e.exports=f},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function i(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var u=n(1),a=n(5),c=n(6),s=function(e){function t(e){return r(this,t),o(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,u.RENDERER,a.ONCE))}return i(t,e),t}(c);e.exports=s},function(e,t,n){"use strict";var r={EVERY:"every",ANY:"any",ONCE:"once"};e.exports=r},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}(),i=function(){function e(t,n,o){r(this,e),this.identifier=t,this.type=n,this.occurrence=o}return o(e,[{key:"getIdentifier",value:function(){if(this.identifier)return this.identifier;throw new Error("Plugin has not identifier")}},{key:"getType",value:function(){if(this.type)return this.type;throw new Error("Plugin has no type")}},{key:"start",value:function(e){return this.process(e)}}]),e}();e.exports=i},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function i(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Line truncated
|
||||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.MediaTag=t():e.MediaTag=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var n={};return t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=86)}([function(e,t,n){"use strict";var r={IMAGE:"image",AUDIO:"audio",VIDEO:"video",PDF:"pdf",DASH:"dash",DOWNLOAD:"download",CRYPTO:"crypto",CLEAR_KEY:"clear-key",MEDIA_OBJECT:"media-object"};e.exports=r},function(e,t,n){"use strict";var r={MATCHER:"matcher",RENDERER:"renderer",FILTER:"filter",SANITIZER:"sanitizer"};e.exports=r},function(e,t,n){"use strict";function r(e){if(e instanceof Array){var t=[];return e.forEach(function(e){e.mediaObject?t.push(e.mediaObject):t.push(r.start(e))}),t}var n=e;return r.start(n)}var o=n(25),i=n(24),u=n(44),a=n(45),c=n(23),s=n(22);r.createMediaObject=function(e){var t=new s(e),n=c.parse(t);return t.setProperties(n),t},r.start=function(e){var t=r.createMediaObject(e);return r.processingEngine.start(t)},r.pluginStore=r.pluginStore||new u,r.uriStore=r.uriStore||new a("../plugins"),r.processingEngine=r.processingEngine||new o(r.pluginStore),r.matchingEngine=r.matchingEngine||new i(r.pluginStore,r.uriStore),r.loadingEngine=null,e.exports=r},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function i(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var u=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}(),a=n(1),c=n(5),s=n(6),f=function(e){function t(e,n){r(this,t);var i=o(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,a.MATCHER,c.ANY));return i.targetType=n,i}return i(t,e),u(t,[{key:"getTargetType",value:function(){return this.targetType}}]),t}(s);e.exports=f},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function i(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var u=n(1),a=n(5),c=n(6),s=function(e){function t(e){return r(this,t),o(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,u.RENDERER,a.ONCE))}return i(t,e),t}(c);e.exports=s},function(e,t,n){"use strict";var r={EVERY:"every",ANY:"any",ONCE:"once"};e.exports=r},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}(),i=function(){function e(t,n,o){r(this,e),this.identifier=t,this.type=n,this.occurrence=o}return o(e,[{key:"getIdentifier",value:function(){if(this.identifier)return this.identifier;throw new Error("Plugin has not identifier")}},{key:"getType",value:function(){if(this.type)return this.type;throw new Error("Plugin has no type")}},{key:"start",value:function(e){return this.process(e)}}]),e}();e.exports=i},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function i(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Line truncated
|
||||
@@ -105,7 +105,7 @@ define([
|
||||
var oldFo = FO.init(parsed.drive, {
|
||||
Cryptpad: Cryptpad
|
||||
});
|
||||
var todo = function () {
|
||||
var onMigrated = function () {
|
||||
oldFo.fixFiles();
|
||||
var newData = Cryptpad.getStore().getProxy();
|
||||
var newFo = newData.fo;
|
||||
@@ -151,8 +151,10 @@ define([
|
||||
proxy.FS_hashes = [];
|
||||
}
|
||||
proxy.FS_hashes.push(localStorage.FS_hash);
|
||||
if (typeof(cb) === "function") { cb(); }
|
||||
};
|
||||
oldFo.migrate(todo);
|
||||
oldFo.migrate(onMigrated);
|
||||
return;
|
||||
}
|
||||
if (typeof(cb) === "function") { cb(); }
|
||||
};
|
||||
|
||||
+2
-1
@@ -63,6 +63,7 @@ types of messages:
|
||||
// RPC responses are arrays. this message isn't meant for us.
|
||||
return;
|
||||
}
|
||||
if (/FULL_HISTORY/.test(parsed[0])) { return; }
|
||||
|
||||
var response = parsed.slice(2);
|
||||
|
||||
@@ -98,7 +99,7 @@ types of messages:
|
||||
delete ctx.pending[txid];
|
||||
return;
|
||||
}
|
||||
console.error("received message for txid[%s] with no callback", txid);
|
||||
console.error("received message [%s] for txid[%s] with no callback", msg, txid);
|
||||
};
|
||||
|
||||
var create = function (network, edPrivateKey, edPublicKey, cb) {
|
||||
|
||||
@@ -96,6 +96,10 @@ define([
|
||||
} else {
|
||||
styleToolbar($container);
|
||||
}
|
||||
$container.on('drop dragover', function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
});
|
||||
return $toolbar;
|
||||
};
|
||||
|
||||
|
||||
@@ -520,7 +520,7 @@ define([
|
||||
|
||||
// ADD
|
||||
var add = exp.add = function (id, path) {
|
||||
if (!Cryptpad.isLoggedIn()) { return; }
|
||||
if (!Cryptpad.isLoggedIn() && !config.testMode) { return; }
|
||||
var data = files[FILES_DATA][id];
|
||||
if (!data || typeof(data) !== "object") { return; }
|
||||
var newPath = path, parentEl;
|
||||
@@ -559,7 +559,7 @@ define([
|
||||
exp.forget = function (href) {
|
||||
var id = getIdFromHref(href);
|
||||
if (!id) { return; }
|
||||
if (!Cryptpad.isLoggedIn()) {
|
||||
if (!Cryptpad.isLoggedIn() && !config.testMode) {
|
||||
// delete permanently
|
||||
exp.removePadAttribute(href);
|
||||
spliceFileData(id);
|
||||
@@ -588,7 +588,7 @@ define([
|
||||
};
|
||||
var checkDeletedFiles = function () {
|
||||
// Nothing in OLD_FILES_DATA for workgroups
|
||||
if (workgroup || !Cryptpad.isLoggedIn()) { return; }
|
||||
if (workgroup || (!Cryptpad.isLoggedIn() && !config.testMode)) { return; }
|
||||
|
||||
var filesList = getFiles([ROOT, 'hrefArray', TRASH]);
|
||||
var fData = files[FILES_DATA];
|
||||
@@ -617,7 +617,7 @@ define([
|
||||
var trashPaths = paths.filter(function(x) { return isPathIn(x, [TRASH]); });
|
||||
var allFilesPaths = paths.filter(function(x) { return isPathIn(x, [FILES_DATA]); });
|
||||
|
||||
if (!Cryptpad.isLoggedIn()) {
|
||||
if (!Cryptpad.isLoggedIn() && !config.testMode) {
|
||||
allFilesPaths.forEach(function (path) {
|
||||
var el = find(path);
|
||||
if (!el) { return; }
|
||||
@@ -967,7 +967,7 @@ define([
|
||||
toClean.push(id);
|
||||
continue;
|
||||
}
|
||||
if (Cryptpad.isLoggedIn() && rootFiles.indexOf(id) === -1) {
|
||||
if ((Cryptpad.isLoggedIn() || config.testMode) && rootFiles.indexOf(id) === -1) {
|
||||
debug("An element in filesData was not in ROOT, TEMPLATE or TRASH.", id, el);
|
||||
var newName = Cryptpad.createChannelId();
|
||||
root[newName] = id;
|
||||
|
||||
Reference in new issue
Block a user