Remove util and hash from common

pull/1/head
yflory 7 years ago
parent c9e1de042c
commit 30c8c253dd

@ -3,12 +3,12 @@ define([
'/bower_components/hyperjson/hyperjson.js', '/bower_components/hyperjson/hyperjson.js',
'/bower_components/textpatcher/TextPatcher.amd.js', '/bower_components/textpatcher/TextPatcher.amd.js',
'json.sortify', 'json.sortify',
'/common/cryptpad-common.js',
'/drive/tests.js', '/drive/tests.js',
'/common/test.js', '/common/test.js',
'/common/common-hash.js',
'/common/common-thumbnail.js', '/common/common-thumbnail.js',
'/common/flat-dom.js', '/common/flat-dom.js',
], function ($, Hyperjson, TextPatcher, Sortify, Cryptpad, Drive, Test, Thumb, Flat) { ], function ($, Hyperjson, TextPatcher, Sortify, Drive, Test, Hash, Thumb, Flat) {
window.Hyperjson = Hyperjson; window.Hyperjson = Hyperjson;
window.TextPatcher = TextPatcher; window.TextPatcher = TextPatcher;
window.Sortify = Sortify; window.Sortify = Sortify;
@ -158,7 +158,7 @@ define([
// check that old hashes parse correctly // check that old hashes parse correctly
assert(function (cb) { assert(function (cb) {
var secret = Cryptpad.parsePadUrl('/pad/#67b8385b07352be53e40746d2be6ccd7XAYSuJYYqa9NfmInyHci7LNy'); var secret = Hash.parsePadUrl('/pad/#67b8385b07352be53e40746d2be6ccd7XAYSuJYYqa9NfmInyHci7LNy');
return cb(secret.hashData.channel === "67b8385b07352be53e40746d2be6ccd7" && return cb(secret.hashData.channel === "67b8385b07352be53e40746d2be6ccd7" &&
secret.hashData.key === "XAYSuJYYqa9NfmInyHci7LNy" && secret.hashData.key === "XAYSuJYYqa9NfmInyHci7LNy" &&
secret.hashData.version === 0); secret.hashData.version === 0);
@ -166,7 +166,7 @@ define([
// make sure version 1 hashes parse correctly // make sure version 1 hashes parse correctly
assert(function (cb) { assert(function (cb) {
var secret = Cryptpad.parsePadUrl('/pad/#/1/edit/3Ujt4F2Sjnjbis6CoYWpoQ/usn4+9CqVja8Q7RZOGTfRgqI'); var secret = Hash.parsePadUrl('/pad/#/1/edit/3Ujt4F2Sjnjbis6CoYWpoQ/usn4+9CqVja8Q7RZOGTfRgqI');
return cb(secret.hashData.version === 1 && return cb(secret.hashData.version === 1 &&
secret.hashData.mode === "edit" && secret.hashData.mode === "edit" &&
secret.hashData.channel === "3Ujt4F2Sjnjbis6CoYWpoQ" && secret.hashData.channel === "3Ujt4F2Sjnjbis6CoYWpoQ" &&
@ -176,7 +176,7 @@ define([
// test support for present mode in hashes // test support for present mode in hashes
assert(function (cb) { assert(function (cb) {
var secret = Cryptpad.parsePadUrl('/pad/#/1/edit/CmN5+YJkrHFS3NSBg-P7Sg/DNZ2wcG683GscU4fyOyqA87G/present'); var secret = Hash.parsePadUrl('/pad/#/1/edit/CmN5+YJkrHFS3NSBg-P7Sg/DNZ2wcG683GscU4fyOyqA87G/present');
return cb(secret.hashData.version === 1 return cb(secret.hashData.version === 1
&& secret.hashData.mode === "edit" && secret.hashData.mode === "edit"
&& secret.hashData.channel === "CmN5+YJkrHFS3NSBg-P7Sg" && secret.hashData.channel === "CmN5+YJkrHFS3NSBg-P7Sg"
@ -186,7 +186,7 @@ define([
// test support for present mode in hashes // test support for present mode in hashes
assert(function (cb) { assert(function (cb) {
var secret = Cryptpad.parsePadUrl('/pad/#/1/edit//CmN5+YJkrHFS3NSBg-P7Sg/DNZ2wcG683GscU4fyOyqA87G//present'); var secret = Hash.parsePadUrl('/pad/#/1/edit//CmN5+YJkrHFS3NSBg-P7Sg/DNZ2wcG683GscU4fyOyqA87G//present');
return cb(secret.hashData.version === 1 return cb(secret.hashData.version === 1
&& secret.hashData.mode === "edit" && secret.hashData.mode === "edit"
&& secret.hashData.channel === "CmN5+YJkrHFS3NSBg-P7Sg" && secret.hashData.channel === "CmN5+YJkrHFS3NSBg-P7Sg"
@ -196,7 +196,7 @@ define([
// test support for present & embed mode in hashes // test support for present & embed mode in hashes
assert(function (cb) { assert(function (cb) {
var secret = Cryptpad.parsePadUrl('/pad/#/1/edit//CmN5+YJkrHFS3NSBg-P7Sg/DNZ2wcG683GscU4fyOyqA87G/embed/present/'); var secret = Hash.parsePadUrl('/pad/#/1/edit//CmN5+YJkrHFS3NSBg-P7Sg/DNZ2wcG683GscU4fyOyqA87G/embed/present/');
return cb(secret.hashData.version === 1 return cb(secret.hashData.version === 1
&& secret.hashData.mode === "edit" && secret.hashData.mode === "edit"
&& secret.hashData.channel === "CmN5+YJkrHFS3NSBg-P7Sg" && secret.hashData.channel === "CmN5+YJkrHFS3NSBg-P7Sg"
@ -207,7 +207,7 @@ define([
// test support for present & embed mode in hashes // test support for present & embed mode in hashes
assert(function (cb) { assert(function (cb) {
var secret = Cryptpad.parsePadUrl('/pad/#/1/edit//CmN5+YJkrHFS3NSBg-P7Sg/DNZ2wcG683GscU4fyOyqA87G/present/embed'); var secret = Hash.parsePadUrl('/pad/#/1/edit//CmN5+YJkrHFS3NSBg-P7Sg/DNZ2wcG683GscU4fyOyqA87G/present/embed');
return cb(secret.hashData.version === 1 return cb(secret.hashData.version === 1
&& secret.hashData.mode === "edit" && secret.hashData.mode === "edit"
&& secret.hashData.channel === "CmN5+YJkrHFS3NSBg-P7Sg" && secret.hashData.channel === "CmN5+YJkrHFS3NSBg-P7Sg"
@ -218,7 +218,7 @@ define([
// test support for embed mode in hashes // test support for embed mode in hashes
assert(function (cb) { assert(function (cb) {
var secret = Cryptpad.parsePadUrl('/pad/#/1/edit//CmN5+YJkrHFS3NSBg-P7Sg/DNZ2wcG683GscU4fyOyqA87G///embed//'); var secret = Hash.parsePadUrl('/pad/#/1/edit//CmN5+YJkrHFS3NSBg-P7Sg/DNZ2wcG683GscU4fyOyqA87G///embed//');
return cb(secret.hashData.version === 1 return cb(secret.hashData.version === 1
&& secret.hashData.mode === "edit" && secret.hashData.mode === "edit"
&& secret.hashData.channel === "CmN5+YJkrHFS3NSBg-P7Sg" && secret.hashData.channel === "CmN5+YJkrHFS3NSBg-P7Sg"
@ -229,7 +229,7 @@ define([
// test support for trailing slash // test support for trailing slash
assert(function (cb) { assert(function (cb) {
var secret = Cryptpad.parsePadUrl('/pad/#/1/edit/3Ujt4F2Sjnjbis6CoYWpoQ/usn4+9CqVja8Q7RZOGTfRgqI/'); var secret = Hash.parsePadUrl('/pad/#/1/edit/3Ujt4F2Sjnjbis6CoYWpoQ/usn4+9CqVja8Q7RZOGTfRgqI/');
return cb(secret.hashData.version === 1 && return cb(secret.hashData.version === 1 &&
secret.hashData.mode === "edit" && secret.hashData.mode === "edit" &&
secret.hashData.channel === "3Ujt4F2Sjnjbis6CoYWpoQ" && secret.hashData.channel === "3Ujt4F2Sjnjbis6CoYWpoQ" &&
@ -238,7 +238,7 @@ define([
}, "test support for trailing slashes in version 1 hash failed to parse"); }, "test support for trailing slashes in version 1 hash failed to parse");
assert(function (cb) { assert(function (cb) {
var secret = Cryptpad.parsePadUrl('/invite/#/1/ilrOtygzDVoUSRpOOJrUuQ/e8jvf36S3chzkkcaMrLSW7PPrz7VDp85lIFNI26dTmr=/'); var secret = Hash.parsePadUrl('/invite/#/1/ilrOtygzDVoUSRpOOJrUuQ/e8jvf36S3chzkkcaMrLSW7PPrz7VDp85lIFNI26dTmr=/');
var hd = secret.hashData; var hd = secret.hashData;
cb(hd.channel === "ilrOtygzDVoUSRpOOJrUuQ" && cb(hd.channel === "ilrOtygzDVoUSRpOOJrUuQ" &&
hd.pubkey === "e8jvf36S3chzkkcaMrLSW7PPrz7VDp85lIFNI26dTmr=" && hd.pubkey === "e8jvf36S3chzkkcaMrLSW7PPrz7VDp85lIFNI26dTmr=" &&

@ -7,6 +7,7 @@ define([
'/common/sframe-common.js', '/common/sframe-common.js',
'/common/sframe-app-framework.js', '/common/sframe-app-framework.js',
'/common/common-util.js', '/common/common-util.js',
'/common/common-hash.js',
'/common/modes.js', '/common/modes.js',
'cm/lib/codemirror', 'cm/lib/codemirror',
@ -45,6 +46,7 @@ define([
SFCommon, SFCommon,
Framework, Framework,
Util, Util,
Hash,
Modes, Modes,
CMeditor) CMeditor)
{ {
@ -293,8 +295,8 @@ define([
//var cursor = editor.getCursor(); //var cursor = editor.getCursor();
//var cleanName = data.name.replace(/[\[\]]/g, ''); //var cleanName = data.name.replace(/[\[\]]/g, '');
//var text = '!['+cleanName+']('+data.url+')'; //var text = '!['+cleanName+']('+data.url+')';
var parsed = Cryptpad.parsePadUrl(data.url); var parsed = Hash.parsePadUrl(data.url);
var hexFileName = Cryptpad.base64ToHex(parsed.hashData.channel); var hexFileName = Util.base64ToHex(parsed.hashData.channel);
var src = '/blob/' + hexFileName.slice(0,2) + '/' + hexFileName; var src = '/blob/' + hexFileName.slice(0,2) + '/' + hexFileName;
var mt = '<media-tag src="' + src + '" data-crypto-key="cryptpad:' + parsed.hashData.key + '"></media-tag>'; var mt = '<media-tag src="' + src + '" data-crypto-key="cryptpad:' + parsed.hashData.key + '"></media-tag>';
editor.replaceSelection(mt); editor.replaceSelection(mt);

@ -3,7 +3,9 @@ define([
'/bower_components/chainpad-crypto/crypto.js', '/bower_components/chainpad-crypto/crypto.js',
'/common/curve.js', '/common/curve.js',
'/common/common-hash.js', '/common/common-hash.js',
], function ($, Crypto, Curve, Hash) { '/common/common-util.js',
'/common/common-realtime.js',
], function ($, Crypto, Curve, Hash, Util, Realtime) {
'use strict'; 'use strict';
var Msg = { var Msg = {
inputs: [], inputs: [],
@ -149,7 +151,7 @@ define([
return; return;
} }
var txid = common.uid(); var txid = Util.uid();
initRangeRequest(txid, curvePublic, hash, cb); initRangeRequest(txid, curvePublic, hash, cb);
var msg = [ 'GET_HISTORY_RANGE', chan.id, { var msg = [ 'GET_HISTORY_RANGE', chan.id, {
from: hash, from: hash,
@ -245,7 +247,7 @@ define([
if (!proxy.friends) { return; } if (!proxy.friends) { return; }
var friends = proxy.friends; var friends = proxy.friends;
delete friends[curvePublic]; delete friends[curvePublic];
common.whenRealtimeSyncs(realtime, cb); Realtime.whenRealtimeSyncs(realtime, cb);
}; };
var pushMsg = function (channel, cryptMsg) { var pushMsg = function (channel, cryptMsg) {
@ -352,7 +354,7 @@ define([
return cb(); return cb();
}; };
var onDirectMessage = function (common, msg, sender) { var onDirectMessage = function (msg, sender) {
if (sender !== Msg.hk) { return void onIdMessage(msg, sender); } if (sender !== Msg.hk) { return void onIdMessage(msg, sender); }
var parsed = JSON.parse(msg); var parsed = JSON.parse(msg);
@ -443,7 +445,7 @@ define([
// listen for messages... // listen for messages...
network.on('message', function(msg, sender) { network.on('message', function(msg, sender) {
onDirectMessage(common, msg, sender); onDirectMessage(msg, sender);
}); });
messenger.removeFriend = function (curvePublic, cb) { messenger.removeFriend = function (curvePublic, cb) {
@ -476,7 +478,7 @@ define([
channel.wc.bcast(cryptMsg).then(function () { channel.wc.bcast(cryptMsg).then(function () {
delete friends[curvePublic]; delete friends[curvePublic];
delete channels[curvePublic]; delete channels[curvePublic];
common.whenRealtimeSyncs(realtime, function () { Realtime.whenRealtimeSyncs(realtime, function () {
cb(); cb();
}); });
}, function (err) { }, function (err) {

@ -1,59 +0,0 @@
define(function () {
var module = {};
module.create = function (UserList, Title, cfg, Cryptpad) {
var exp = {};
exp.update = function (shjson) {
// Extract the user list (metadata) from the hyperjson
var json = (!shjson || typeof shjson !== "string") ? "" : JSON.parse(shjson);
var titleUpdated = false;
var metadata;
if (Array.isArray(json)) {
metadata = json[3] && json[3].metadata;
} else {
metadata = json.metadata;
}
if (typeof metadata === "object") {
if (Cryptpad) {
if (typeof(metadata.type) === 'undefined') {
// initialize pad type by location.pathname
metadata.type = Cryptpad.getAppType();
}
} else {
console.log("Cryptpad should exist but it does not");
}
if (metadata.users) {
var userData = metadata.users;
// Update the local user data
UserList.addToUserData(userData);
}
if (metadata.defaultTitle) {
Title.updateDefaultTitle(metadata.defaultTitle);
}
if (typeof metadata.title !== "undefined") {
Title.updateTitle(metadata.title || Title.defaultTitle);
titleUpdated = true;
}
if (metadata.slideOptions && cfg.slideOptions) {
cfg.slideOptions(metadata.slideOptions);
}
if (metadata.color && cfg.slideColors) {
cfg.slideColors(metadata.color, metadata.backColor);
}
if (typeof(metadata.palette) !== 'undefined' && cfg.updatePalette) {
cfg.updatePalette(metadata.palette);
}
}
if (!titleUpdated) {
Title.updateTitle(Title.defaultTitle);
}
};
return exp;
};
return module;
});

@ -3,28 +3,16 @@ define([
'/api/config', '/api/config',
'/common/cryptpad-common.js', '/common/cryptpad-common.js',
'/common/common-util.js', '/common/common-util.js',
'/common/common-hash.js',
'/common/common-language.js', '/common/common-language.js',
'/common/common-interface.js', '/common/common-interface.js',
'/common/media-tag.js', '/common/media-tag.js',
'css!/common/tippy.css', 'css!/common/tippy.css',
], function ($, Config, Cryptpad, Util, Language, UI, MediaTag) { ], function ($, Config, Cryptpad, Util, Hash, Language, UI, MediaTag) {
var UIElements = {}; var UIElements = {};
var Messages = Cryptpad.Messages; var Messages = Cryptpad.Messages;
/**
* Requirements from cryptpad-common.js
* getFileSize
* - hrefToHexChannelId
* displayAvatar
* - getFirstEmojiOrCharacter
* - parsePadUrl
* - getSecrets
* - base64ToHex
* - getBlobPathFromHex
* - bytesToMegabytes
*/
UIElements.updateTags = function (common, href) { UIElements.updateTags = function (common, href) {
var sframeChan = common.getSframeChannel(); var sframeChan = common.getSframeChannel();
sframeChan.query('Q_TAGS_GET', href || null, function (err, res) { sframeChan.query('Q_TAGS_GET', href || null, function (err, res) {
@ -308,19 +296,19 @@ define([
if (cb) { cb(); } if (cb) { cb(); }
}; };
if (!href) { return void displayDefault(); } if (!href) { return void displayDefault(); }
var parsed = Cryptpad.parsePadUrl(href); var parsed = Hash.parsePadUrl(href);
var secret = Cryptpad.getSecrets('file', parsed.hash); var secret = Hash.getSecrets('file', parsed.hash);
if (secret.keys && secret.channel) { if (secret.keys && secret.channel) {
var cryptKey = secret.keys && secret.keys.fileKeyStr; var cryptKey = secret.keys && secret.keys.fileKeyStr;
var hexFileName = Cryptpad.base64ToHex(secret.channel); var hexFileName = Util.base64ToHex(secret.channel);
var src = Cryptpad.getBlobPathFromHex(hexFileName); var src = Hash.getBlobPathFromHex(hexFileName);
Common.getFileSize(href, function (e, data) { Common.getFileSize(href, function (e, data) {
if (e) { if (e) {
displayDefault(); displayDefault();
return void console.error(e); return void console.error(e);
} }
if (typeof data !== "number") { return void displayDefault(); } if (typeof data !== "number") { return void displayDefault(); }
if (Cryptpad.bytesToMegabytes(data) > 0.5) { return void displayDefault(); } if (Util.bytesToMegabytes(data) > 0.5) { return void displayDefault(); }
var $img = $('<media-tag>').appendTo($container); var $img = $('<media-tag>').appendTo($container);
$img.attr('src', src); $img.attr('src', src);
$img.attr('data-crypto-key', 'cryptpad:' + cryptKey); $img.attr('data-crypto-key', 'cryptpad:' + cryptKey);
@ -356,7 +344,7 @@ define([
// so we can just use those and only check for errors // so we can just use those and only check for errors
var $container = $('<span>', {'class':'cp-limit-container'}); var $container = $('<span>', {'class':'cp-limit-container'});
var todo; var todo;
var updateUsage = Cryptpad.notAgainForAnother(function () { var updateUsage = Util.notAgainForAnother(function () {
common.getPinUsage(todo); common.getPinUsage(todo);
}, LIMIT_REFRESH_RATE); }, LIMIT_REFRESH_RATE);

@ -89,22 +89,6 @@ define([], function () {
return a; return a;
}; };
Util.getHash = function () {
return window.location.hash.slice(1);
};
Util.replaceHash = function (hash) {
if (window.history && window.history.replaceState) {
if (!/^#/.test(hash)) { hash = '#' + hash; }
void window.history.replaceState({}, window.document.title, hash);
if (typeof(window.onhashchange) === 'function') {
window.onhashchange();
}
return;
}
window.location.hash = hash;
};
/* /*
* Saving files * Saving files
*/ */
@ -186,13 +170,6 @@ define([], function () {
return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER); return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
}; };
Util.getAppType = function () {
var parts = window.location.pathname.split('/')
.filter(function (x) { return x; });
if (!parts[0]) { return ''; }
return parts[0];
};
/* for wrapping async functions such that they can only be called once */ /* for wrapping async functions such that they can only be called once */
Util.once = function (f) { Util.once = function (f) {
var called; var called;

@ -3,8 +3,11 @@ define([
'/bower_components/chainpad-crypto/crypto.js', '/bower_components/chainpad-crypto/crypto.js',
'/bower_components/chainpad-netflux/chainpad-netflux.js', '/bower_components/chainpad-netflux/chainpad-netflux.js',
'/common/cryptpad-common.js', '/common/cryptpad-common.js',
'/common/common-util.js',
'/common/common-hash.js',
'/common/common-realtime.js',
'/bower_components/textpatcher/TextPatcher.js' '/bower_components/textpatcher/TextPatcher.js'
], function ($, Crypto, Realtime, Cryptpad, TextPatcher) { ], function ($, Crypto, CPNetflux, Cryptpad, Util, Hash, Realtime, TextPatcher) {
//var Messages = Cryptpad.Messages; //var Messages = Cryptpad.Messages;
//var noop = function () {}; //var noop = function () {};
var finish = function (S, err, doc) { var finish = function (S, err, doc) {
@ -12,9 +15,9 @@ define([
S.cb(err, doc); S.cb(err, doc);
S.done = true; S.done = true;
var disconnect = Cryptpad.find(S, ['network', 'disconnect']); var disconnect = Util.find(S, ['network', 'disconnect']);
if (typeof(disconnect) === 'function') { disconnect(); } if (typeof(disconnect) === 'function') { disconnect(); }
var abort = Cryptpad.find(S, ['realtime', 'realtime', 'abort']); var abort = Util.find(S, ['realtime', 'realtime', 'abort']);
if (typeof(abort) === 'function') { if (typeof(abort) === 'function') {
S.realtime.realtime.sync(); S.realtime.realtime.sync();
abort(); abort();
@ -23,7 +26,7 @@ define([
var makeConfig = function (hash) { var makeConfig = function (hash) {
// We can't use cryptget with a file or a user so we can use 'pad' as hash type // We can't use cryptget with a file or a user so we can use 'pad' as hash type
var secret = Cryptpad.getSecrets('pad', hash); var secret = Hash.getSecrets('pad', hash);
if (!secret.keys) { secret.keys = secret.key; } // support old hashses if (!secret.keys) { secret.keys = secret.key; } // support old hashses
var config = { var config = {
websocketURL: Cryptpad.getWebsocketURL(), websocketURL: Cryptpad.getWebsocketURL(),
@ -58,7 +61,7 @@ define([
}; };
overwrite(config, opt); overwrite(config, opt);
Session.realtime = Realtime.start(config); Session.realtime = CPNetflux.start(config);
}; };
var put = function (hash, doc, cb, opt) { var put = function (hash, doc, cb, opt) {
@ -80,7 +83,7 @@ define([
cb(new Error("Timeout")); cb(new Error("Timeout"));
}, 5000); }, 5000);
Cryptpad.whenRealtimeSyncs(realtime, function () { Realtime.whenRealtimeSyncs(realtime, function () {
window.clearTimeout(to); window.clearTimeout(to);
realtime.abort(); realtime.abort();
finish(Session, void 0); finish(Session, void 0);
@ -88,7 +91,7 @@ define([
}; };
overwrite(config, opt); overwrite(config, opt);
Session.session = Realtime.start(config); Session.session = CPNetflux.start(config);
}; };
return { return {

@ -58,44 +58,44 @@ define([
var anon_rpc; var anon_rpc;
// import common utilities for export // import common utilities for export
common.find = Util.find; //common.find = Util.find;
common.hexToBase64 = Util.hexToBase64; //common.hexToBase64 = Util.hexToBase64;
common.base64ToHex = Util.base64ToHex; //common.base64ToHex = Util.base64ToHex;
var deduplicateString = common.deduplicateString = Util.deduplicateString; //var deduplicateString = common.deduplicateString = Util.deduplicateString;
common.uint8ArrayToHex = Util.uint8ArrayToHex; //common.uint8ArrayToHex = Util.uint8ArrayToHex;
common.replaceHash = Util.replaceHash; //common.replaceHash = Util.replaceHash;
common.getHash = Util.getHash; //common.getHash = Util.getHash;
common.fixFileName = Util.fixFileName; //common.fixFileName = Util.fixFileName;
common.bytesToMegabytes = Util.bytesToMegabytes; //common.bytesToMegabytes = Util.bytesToMegabytes;
common.bytesToKilobytes = Util.bytesToKilobytes; //common.bytesToKilobytes = Util.bytesToKilobytes;
common.fetch = Util.fetch; //common.fetch = Util.fetch;
common.throttle = Util.throttle; //common.throttle = Util.throttle;
common.createRandomInteger = Util.createRandomInteger; //common.createRandomInteger = Util.createRandomInteger;
common.getAppType = Util.getAppType; //common.getAppType = Util.getAppType;
common.notAgainForAnother = Util.notAgainForAnother; //common.notAgainForAnother = Util.notAgainForAnother;
common.uid = Util.uid; //common.uid = Util.uid;
common.slice = Util.slice; //common.slice = Util.slice;
// import hash utilities for export // import hash utilities for export
var createRandomHash = common.createRandomHash = Hash.createRandomHash; //var createRandomHash = common.createRandomHash = Hash.createRandomHash;
common.parseTypeHash = Hash.parseTypeHash; //common.parseTypeHash = Hash.parseTypeHash;
var parsePadUrl = common.parsePadUrl = Hash.parsePadUrl; //var parsePadUrl = common.parsePadUrl = Hash.parsePadUrl;
common.isNotStrongestStored = Hash.isNotStrongestStored; //common.isNotStrongestStored = Hash.isNotStrongestStored;
var hrefToHexChannelId = common.hrefToHexChannelId = Hash.hrefToHexChannelId; //var hrefToHexChannelId = common.hrefToHexChannelId = Hash.hrefToHexChannelId;
var getRelativeHref = common.getRelativeHref = Hash.getRelativeHref; //var getRelativeHref = common.getRelativeHref = Hash.getRelativeHref;
common.getBlobPathFromHex = Hash.getBlobPathFromHex; //common.getBlobPathFromHex = Hash.getBlobPathFromHex;
common.getEditHashFromKeys = Hash.getEditHashFromKeys; //common.getEditHashFromKeys = Hash.getEditHashFromKeys;
common.getViewHashFromKeys = Hash.getViewHashFromKeys; //common.getViewHashFromKeys = Hash.getViewHashFromKeys;
common.getFileHashFromKeys = Hash.getFileHashFromKeys; //common.getFileHashFromKeys = Hash.getFileHashFromKeys;
common.getUserHrefFromKeys = Hash.getUserHrefFromKeys; //common.getUserHrefFromKeys = Hash.getUserHrefFromKeys;
common.getSecrets = Hash.getSecrets; //common.getSecrets = Hash.getSecrets;
common.getHashes = Hash.getHashes; //common.getHashes = Hash.getHashes;
common.createChannelId = Hash.createChannelId; //common.createChannelId = Hash.createChannelId;
common.findWeaker = Hash.findWeaker; //common.findWeaker = Hash.findWeaker;
common.findStronger = Hash.findStronger; //common.findStronger = Hash.findStronger;
common.serializeHash = Hash.serializeHash; //common.serializeHash = Hash.serializeHash;
common.createInviteUrl = Hash.createInviteUrl; //common.createInviteUrl = Hash.createInviteUrl;
// Messaging // Messaging
common.addDirectMessageHandler = Messaging.addDirectMessageHandler; common.addDirectMessageHandler = Messaging.addDirectMessageHandler;
@ -107,10 +107,10 @@ define([
common.getLatestMessages = Messaging.getLatestMessages; common.getLatestMessages = Messaging.getLatestMessages;
// Realtime // Realtime
// REFACTOR: common is not needed anymore so we should just pull common-reealtime directly
var whenRealtimeSyncs = common.whenRealtimeSyncs = function (realtime, cb) { var whenRealtimeSyncs = common.whenRealtimeSyncs = function (realtime, cb) {
Realtime.whenRealtimeSyncs(common, realtime, cb); Realtime.whenRealtimeSyncs(common, realtime, cb);
}; };
common.beginDetectingInfiniteSpinner = function (realtime) { common.beginDetectingInfiniteSpinner = function (realtime) {
Realtime.beginDetectingInfiniteSpinner(common, realtime); Realtime.beginDetectingInfiniteSpinner(common, realtime);
}; };
@ -137,12 +137,16 @@ define([
} }
return; return;
}; };
// REFACTOR pull language directly
common.getLanguage = function () { common.getLanguage = function () {
return Messages._languageUsed; return Messages._languageUsed;
}; };
common.setLanguage = function (l, cb) { common.setLanguage = function (l, cb) {
Language.setLanguage(l, null, cb); Language.setLanguage(l, null, cb);
}; };
// REAFCTOR store.getProfile should be store.get(['profile'])
common.getProfileUrl = function () { common.getProfileUrl = function () {
if (store && store.getProfile()) { if (store && store.getProfile()) {
return store.getProfile().view; return store.getProfile().view;
@ -166,13 +170,14 @@ define([
return localStorage[common.userNameKey]; return localStorage[common.userNameKey];
}; };
// REFACTOR: move to util?
var randomToken = function () { var randomToken = function () {
return Math.random().toString(16).replace(/0./, ''); return Math.random().toString(16).replace(/0./, '');
}; };
common.isFeedbackAllowed = function () { common.isFeedbackAllowed = function () {
try { try {
var entry = common.find(getProxy(), [ var entry = Util.find(getProxy(), [
'settings', 'settings',
'general', 'general',
'allowUserFeedback' 'allowUserFeedback'
@ -246,7 +251,7 @@ define([
common.login = function (hash, name, cb) { common.login = function (hash, name, cb) {
if (!hash) { throw new Error('expected a user hash'); } if (!hash) { throw new Error('expected a user hash'); }
if (!name) { throw new Error('expected a user name'); } if (!name) { throw new Error('expected a user name'); }
hash = common.serializeHash(hash); hash = Hash.serializeHash(hash);
localStorage.setItem(userHashKey, hash); localStorage.setItem(userHashKey, hash);
localStorage.setItem(userNameKey, name); localStorage.setItem(userNameKey, name);
if (cb) { cb(); } if (cb) { cb(); }
@ -283,7 +288,7 @@ define([
// Make sure we have an FS_hash in localStorage before reloading all the tabs // Make sure we have an FS_hash in localStorage before reloading all the tabs
// so that we don't end up with tabs using different anon hashes // so that we don't end up with tabs using different anon hashes
if (!localStorage[fileHashKey]) { if (!localStorage[fileHashKey]) {
localStorage[fileHashKey] = common.createRandomHash(); localStorage[fileHashKey] = Hash.createRandomHash();
} }
eraseTempSessionValues(); eraseTempSessionValues();
@ -308,7 +313,7 @@ define([
} }
if (hash) { if (hash) {
var sHash = common.serializeHash(hash); var sHash = Hash.serializeHash(hash);
if (sHash !== hash) { localStorage[userHashKey] = sHash; } if (sHash !== hash) { localStorage[userHashKey] = sHash; }
} }
@ -357,9 +362,9 @@ define([
var checkObjectData = function (pad, cb) { var checkObjectData = function (pad, cb) {
if (!pad.ctime) { pad.ctime = pad.atime; } if (!pad.ctime) { pad.ctime = pad.atime; }
if (/^https*:\/\//.test(pad.href)) { if (/^https*:\/\//.test(pad.href)) {
pad.href = common.getRelativeHref(pad.href); pad.href = Hash.getRelativeHref(pad.href);
} }
var parsed = common.parsePadUrl(pad.href); var parsed = Hash.parsePadUrl(pad.href);
if (!parsed || !parsed.hash) { return; } if (!parsed || !parsed.hash) { return; }
if (typeof(cb) === 'function') { if (typeof(cb) === 'function') {
cb(parsed); cb(parsed);
@ -369,28 +374,6 @@ define([
} }
return parsed.hashData; return parsed.hashData;
}; };
// Migrate from legacy store (localStorage)
common.migrateRecentPads = function (pads) {
return pads.map(function (pad) {
var parsedHash;
if (Array.isArray(pad)) { // TODO DEPRECATE_F
return {
href: pad[0],
atime: pad[1],
title: pad[2] || '',
ctime: pad[1],
};
} else if (pad && typeof(pad) === 'object') {
parsedHash = checkObjectData(pad);
if (!parsedHash || !parsedHash.type) { return; }
return pad;
} else {
console.error("[Cryptpad.migrateRecentPads] pad had unexpected value");
console.log(pad);
return;
}
}).filter(function (x) { return x; });
};
// Remove everything from RecentPads that is not an object and check the objects // Remove everything from RecentPads that is not an object and check the objects
var checkRecentPads = common.checkRecentPads = function (pads) { var checkRecentPads = common.checkRecentPads = function (pads) {
Object.keys(pads).forEach(function (id, i) { Object.keys(pads).forEach(function (id, i) {
@ -410,7 +393,7 @@ define([
}; };
// Create untitled documents when no name is given // Create untitled documents when no name is given
var getLocaleDate = common.getLocaleDate = function () { var getLocaleDate = function () {
if (window.Intl && window.Intl.DateTimeFormat) { if (window.Intl && window.Intl.DateTimeFormat) {
var options = {weekday: "short", year: "numeric", month: "long", day: "numeric"}; var options = {weekday: "short", year: "numeric", month: "long", day: "numeric"};
return new window.Intl.DateTimeFormat(undefined, options).format(new Date()); return new window.Intl.DateTimeFormat(undefined, options).format(new Date());
@ -433,18 +416,13 @@ define([
href: href, href: href,
atime: now, atime: now,
ctime: now, ctime: now,
title: title || getDefaultName(parsePadUrl(href)), title: title || getDefaultName(Hash.parsePadUrl(href)),
}; };
}; };
/* Sort pads according to how recently they were accessed */
common.mostRecent = function (a, b) {
return new Date(b.atime).getTime() - new Date(a.atime).getTime();
};
// STORAGE // STORAGE
common.setPadAttribute = function (attr, value, cb, href) { common.setPadAttribute = function (attr, value, cb, href) {
href = getRelativeHref(href || window.location.href); href = Hash.getRelativeHref(href || window.location.href);
getStore().setPadAttribute(href, attr, value, cb); getStore().setPadAttribute(href, attr, value, cb);
}; };
common.setDisplayName = function (value, cb) { common.setDisplayName = function (value, cb) {
@ -464,7 +442,7 @@ define([
// STORAGE // STORAGE
common.getPadAttribute = function (attr, cb) { common.getPadAttribute = function (attr, cb) {
var href = getRelativeHref(window.location.href); var href = Hash.getRelativeHref(window.location.href);
getStore().getPadAttribute(href, attr, cb); getStore().getPadAttribute(href, attr, cb);
}; };
common.getAttribute = function (attr, cb) { common.getAttribute = function (attr, cb) {
@ -492,7 +470,7 @@ define([
href = href || (window.location.pathname + window.location.hash); href = href || (window.location.pathname + window.location.hash);
var id = store.getIdFromHref(href); var id = store.getIdFromHref(href);
if (!id) { return void cb('NO_ID'); } if (!id) { return void cb('NO_ID'); }
var entry = common.find(getProxy(), [ var entry = Util.find(getProxy(), [
'drive', 'drive',
'filesData', 'filesData',
id id
@ -558,7 +536,7 @@ define([
common.listAllTags = function (cb) { common.listAllTags = function (cb) {
var all = []; var all = [];
var proxy = getProxy(); var proxy = getProxy();
var files = common.find(proxy, ['drive', 'filesData']); var files = Util.find(proxy, ['drive', 'filesData']);
if (typeof(files) !== 'object') { return cb('invalid_drive'); } if (typeof(files) !== 'object') { return cb('invalid_drive'); }
Object.keys(files).forEach(function (k) { Object.keys(files).forEach(function (k) {
@ -583,7 +561,7 @@ define([
if (!type) { return allTemplates; } if (!type) { return allTemplates; }
var templates = allTemplates.filter(function (f) { var templates = allTemplates.filter(function (f) {
var parsed = parsePadUrl(f.href); var parsed = Hash.parsePadUrl(f.href);
return parsed.type === type; return parsed.type === type;
}); });
return templates; return templates;
@ -596,7 +574,7 @@ define([
}; };
common.isTemplate = function (href) { common.isTemplate = function (href) {
var rhref = getRelativeHref(href); var rhref = Hash.getRelativeHref(href);
var templates = listTemplates(); var templates = listTemplates();
return templates.some(function (t) { return templates.some(function (t) {
return t.href === rhref; return t.href === rhref;
@ -605,11 +583,11 @@ define([
// Secure iframes // Secure iframes
common.useTemplate = function (href, Crypt, cb) { common.useTemplate = function (href, Crypt, cb) {
var parsed = parsePadUrl(href); var parsed = Hash.parsePadUrl(href);
if(!parsed) { throw new Error("Cannot get template hash"); } if(!parsed) { throw new Error("Cannot get template hash"); }
Crypt.get(parsed.hash, function (err, val) { Crypt.get(parsed.hash, function (err, val) {
if (err) { throw new Error(err); } if (err) { throw new Error(err); }
var p = parsePadUrl(window.location.href); var p = Hash.parsePadUrl(window.location.href);
Crypt.put(p.hash, val, cb); Crypt.put(p.hash, val, cb);
}); });
}; };
@ -649,7 +627,7 @@ define([
// STORAGE // STORAGE
common.forgetPad = function (href, cb) { common.forgetPad = function (href, cb) {
if (typeof(getStore().forgetPad) === "function") { if (typeof(getStore().forgetPad) === "function") {
getStore().forgetPad(common.getRelativeHref(href), cb); getStore().forgetPad(Hash.getRelativeHref(href), cb);
return; return;
} }
cb ("store.forgetPad is not a function"); cb ("store.forgetPad is not a function");
@ -657,10 +635,10 @@ define([
common.setPadTitle = function (name, padHref, cb) { common.setPadTitle = function (name, padHref, cb) {
var href = typeof padHref === "string" ? padHref : window.location.href; var href = typeof padHref === "string" ? padHref : window.location.href;
var parsed = parsePadUrl(href); var parsed = Hash.parsePadUrl(href);
if (!parsed.hash) { return; } if (!parsed.hash) { return; }
href = parsed.getUrl({present: parsed.present}); href = parsed.getUrl({present: parsed.present});
//href = getRelativeHref(href); //href = Hash.getRelativeHref(href);
// getRecentPads return the array from the drive, not a copy // getRecentPads return the array from the drive, not a copy
// We don't have to call "set..." at the end, everything is stored with listmap // We don't have to call "set..." at the end, everything is stored with listmap
getRecentPads(function (err, recent) { getRecentPads(function (err, recent) {
@ -673,7 +651,7 @@ define([
var contains; var contains;
Object.keys(recent).forEach(function (id) { Object.keys(recent).forEach(function (id) {
var pad = recent[id]; var pad = recent[id];
var p = parsePadUrl(pad.href); var p = Hash.parsePadUrl(pad.href);
if (p.type !== parsed.type) { return pad; } if (p.type !== parsed.type) { return pad; }
@ -759,7 +737,7 @@ define([
if (title === null) { return; } if (title === null) { return; }
if (title.trim() === "") { if (title.trim() === "") {
var parsed = parsePadUrl(href || window.location.href); var parsed = Hash.parsePadUrl(href || window.location.href);
title = getDefaultName(parsed); title = getDefaultName(parsed);
} }
@ -773,22 +751,6 @@ define([
}); });
}; };
common.getUserFilesList = function () {
var store = common.getStore();
var proxy = store.getProxy();
var fo = proxy.fo;
var hashes = [];
var list = fo.getFiles([fo.ROOT]).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;
};
// Needed for the secure filepicker app // Needed for the secure filepicker app
common.getSecureFilesList = function (query, cb) { common.getSecureFilesList = function (query, cb) {
var store = common.getStore(); var store = common.getStore();
@ -813,7 +775,7 @@ define([
}; };
fo.getFiles(where).forEach(function (id) { fo.getFiles(where).forEach(function (id) {
var data = fo.getFileData(id); var data = fo.getFileData(id);
var parsed = parsePadUrl(data.href); var parsed = Hash.parsePadUrl(data.href);
if ((!types || types.length === 0 || types.indexOf(parsed.type) !== -1) if ((!types || types.length === 0 || types.indexOf(parsed.type) !== -1)
&& hashes.indexOf(parsed.hash) === -1) { && hashes.indexOf(parsed.hash) === -1) {
if (isFiltered(parsed.type, data)) { return; } if (isFiltered(parsed.type, data)) { return; }
@ -833,21 +795,21 @@ define([
var userHash = localStorage && localStorage.User_hash; var userHash = localStorage && localStorage.User_hash;
if (!userHash) { return null; } if (!userHash) { return null; }
var userParsedHash = common.parseTypeHash('drive', userHash); var userParsedHash = Hash.parseTypeHash('drive', userHash);
var userChannel = userParsedHash && userParsedHash.channel; var userChannel = userParsedHash && userParsedHash.channel;
if (!userChannel) { return null; } if (!userChannel) { return null; }
var list = fo.getFiles([fo.FILES_DATA]).map(function (id) { var list = fo.getFiles([fo.FILES_DATA]).map(function (id) {
return hrefToHexChannelId(fo.getFileData(id).href); return Hash.hrefToHexChannelId(fo.getFileData(id).href);
}) })
.filter(function (x) { return x; }); .filter(function (x) { return x; });
// Get the avatar // Get the avatar
var profile = store.getProfile(); var profile = store.getProfile();
if (profile) { if (profile) {
var profileChan = profile.edit ? hrefToHexChannelId('/profile/#' + profile.edit) : null; var profileChan = profile.edit ? Hash.hrefToHexChannelId('/profile/#' + profile.edit) : null;
if (profileChan) { list.push(profileChan); } if (profileChan) { list.push(profileChan); }
var avatarChan = profile.avatar ? hrefToHexChannelId(profile.avatar) : null; var avatarChan = profile.avatar ? Hash.hrefToHexChannelId(profile.avatar) : null;
if (avatarChan) { list.push(avatarChan); } if (avatarChan) { list.push(avatarChan); }
} }
@ -856,14 +818,14 @@ define([
list = list.concat(fList); list = list.concat(fList);
} }
list.push(common.base64ToHex(userChannel)); list.push(Util.base64ToHex(userChannel));
list.sort(); list.sort();
return list; return list;
}; };
var getCanonicalChannelList = common.getCanonicalChannelList = function () { var getCanonicalChannelList = common.getCanonicalChannelList = function () {
return deduplicateString(getUserChannelList()).sort(); return Util.deduplicateString(getUserChannelList()).sort();
}; };
var pinsReady = common.pinsReady = function () { var pinsReady = common.pinsReady = function () {
@ -1042,100 +1004,6 @@ define([
rpc.uploadCancel(cb); rpc.uploadCancel(cb);
}; };
/* Create a usage bar which keeps track of how much storage space is used
by your CryptDrive. The getPinnedUsage RPC is one of the heavier calls,
so we throttle its usage. Clients will not update more than once per
LIMIT_REFRESH_RATE. It will be update at least once every three such intervals
If changes are made to your drive in the interim, they will trigger an
update.
*/
var LIMIT_REFRESH_RATE = 30000; // milliseconds
common.createUsageBar = function (cb) {
if (!isLoggedIn()) { return cb("NOT_LOGGED_IN"); }
// getPinnedUsage updates common.account.usage, and other values
// so we can just use those and only check for errors
var $container = $('<span>', {'class':'limit-container'});
var todo;
var updateUsage = window.updateUsage = common.notAgainForAnother(function () {
common.getPinnedUsage(todo);
}, LIMIT_REFRESH_RATE);
todo = function (err) {
if (err) { return void console.error(err); }
$container.html('');
var unit = Util.magnitudeOfBytes(common.account.limit);
var usage = unit === 'GB'? Util.bytesToGigabytes(common.account.usage):
Util.bytesToMegabytes(common.account.usage);
var limit = unit === 'GB'? Util.bytesToGigabytes(common.account.limit):
Util.bytesToMegabytes(common.account.limit);
var $limit = $('<span>', {'class': 'cryptpad-limit-bar'}).appendTo($container);
var quota = usage/limit;
var $usage = $('<span>', {'class': 'usage'}).css('width', quota*100+'%');
var makeDonateButton = function () {
$('<a>', {
'class': 'upgrade btn btn-success',
href: common.donateURL,
rel: "noreferrer noopener",
target: "_blank",
}).text(Messages.supportCryptpad).appendTo($container);
};
var makeUpgradeButton = function () {
$('<a>', {
'class': 'upgrade btn btn-success',
href: common.upgradeURL,
rel: "noreferrer noopener",
target: "_blank",
}).text(Messages.upgradeAccount).appendTo($container);
};
if (!Config.removeDonateButton) {
if (!common.isLoggedIn() || !Config.allowSubscriptions) {
// user is not logged in, or subscriptions are disallowed
makeDonateButton();
} else if (!common.account.plan) {
// user is logged in and subscriptions are allowed
// and they don't have one. show upgrades
makeUpgradeButton();
} else {
// they have a plan. show nothing
}
}
var prettyUsage;
var prettyLimit;
if (unit === 'GB') {
prettyUsage = Messages._getKey('formattedGB', [usage]);
prettyLimit = Messages._getKey('formattedGB', [limit]);
} else {
prettyUsage = Messages._getKey('formattedMB', [usage]);
prettyLimit = Messages._getKey('formattedMB', [limit]);
}
if (quota < 0.8) { $usage.addClass('normal'); }
else if (quota < 1) { $usage.addClass('warning'); }
else { $usage.addClass('above'); }
var $text = $('<span>', {'class': 'usageText'});
$text.text(usage + ' / ' + prettyLimit);
$limit.append($usage).append($text);
};
setInterval(function () {
updateUsage();
}, LIMIT_REFRESH_RATE * 3);
updateUsage();
getProxy().on('change', ['drive'], function () {
updateUsage();
});
cb(null, $container);
};
// Forget button // Forget button
// TODO REFACTOR only used in sframe-common-outer // TODO REFACTOR only used in sframe-common-outer
common.moveToTrash = function (cb, href) { common.moveToTrash = function (cb, href) {
@ -1159,11 +1027,12 @@ define([
} }
}); });
}; };
// TODO REFACTOR only used in sframe-common-outer // TODO REFACTOR only used in sframe-common-outer
common.saveAsTemplate = function (Cryptput, data, cb) { common.saveAsTemplate = function (Cryptput, data, cb) {
var p = parsePadUrl(window.location.href); var p = Hash.parsePadUrl(window.location.href);
if (!p.type) { return; } if (!p.type) { return; }
var hash = createRandomHash(); var hash = Hash.createRandomHash();
var href = '/' + p.type + '/#' + hash; var href = '/' + p.type + '/#' + hash;
Cryptput(hash, data.toSave, function (e) { Cryptput(hash, data.toSave, function (e) {
if (e) { throw new Error(e); } if (e) { throw new Error(e); }
@ -1175,23 +1044,6 @@ define([
}; };
common.getMediatagScript = function () {
var origin = window.location.origin;
return '<script src="' + origin + '/common/media-tag-nacl.min.js"></script>';
};
common.getMediatagFromHref = function (href) {
var parsed = common.parsePadUrl(href);
var secret = common.getSecrets('file', parsed.hash);
if (secret.keys && secret.channel) {
var cryptKey = secret.keys && secret.keys.fileKeyStr;
var hexFileName = common.base64ToHex(secret.channel);
var origin = Config.fileHost || window.location.origin;
var src = origin + common.getBlobPathFromHex(hexFileName);
return '<media-tag src="' + src + '" data-crypto-key="cryptpad:' + cryptKey + '">' +
'</media-tag>';
}
return;
};
$(window.document).on('decryption', function (e) { $(window.document).on('decryption', function (e) {
var decrypted = e.originalEvent; var decrypted = e.originalEvent;
if (decrypted.callback) { if (decrypted.callback) {
@ -1218,7 +1070,7 @@ define([
size = decrypted.blob.size; size = decrypted.blob.size;
} }
var sizeMb = common.bytesToMegabytes(size); var sizeMb = Util.bytesToMegabytes(size);
var $btn = $(root).find('button'); var $btn = $(root).find('button');
$btn.addClass('btn btn-success') $btn.addClass('btn btn-success')
@ -1236,23 +1088,17 @@ define([
}); });
} }
}); });
common.avatarAllowedTypes = [
'image/png',
'image/jpeg',
'image/jpg',
'image/gif',
];
common.getShareHashes = function (secret, cb) { common.getShareHashes = function (secret, cb) {
if (!window.location.hash) { if (!window.location.hash) {
var hashes = common.getHashes(secret.channel, secret); var hashes = Hash.getHashes(secret.channel, secret);
return void cb(null, hashes); return void cb(null, hashes);
} }
common.getRecentPads(function (err, recent) { common.getRecentPads(function (err, recent) {
var parsed = parsePadUrl(window.location.href); var parsed = Hash.parsePadUrl(window.location.href);
if (!parsed.type || !parsed.hashData) { return void cb('E_INVALID_HREF'); } if (!parsed.type || !parsed.hashData) { return void cb('E_INVALID_HREF'); }
if (parsed.type === 'file') { secret.channel = Util.base64ToHex(secret.channel); } if (parsed.type === 'file') { secret.channel = Util.base64ToHex(secret.channel); }
var hashes = common.getHashes(secret.channel, secret); var hashes = Hash.getHashes(secret.channel, secret);
if (!hashes.editHash && !hashes.viewHash && parsed.hashData && !parsed.hashData.mode) { if (!hashes.editHash && !hashes.viewHash && parsed.hashData && !parsed.hashData.mode) {
// It means we're using an old hash // It means we're using an old hash
@ -1260,9 +1106,9 @@ define([
} }
// If we have a stronger version in drive, add it and add a redirect button // If we have a stronger version in drive, add it and add a redirect button
var stronger = recent && common.findStronger(null, recent); var stronger = recent && Hash.findStronger(null, recent);
if (stronger) { if (stronger) {
var parsed2 = parsePadUrl(stronger); var parsed2 = Hash.parsePadUrl(stronger);
hashes.editHash = parsed2.hash; hashes.editHash = parsed2.hash;
} }
@ -1357,8 +1203,8 @@ define([
var oldHref = document.location.href; var oldHref = document.location.href;
window.onhashchange = function () { window.onhashchange = function () {
var newHref = document.location.href; var newHref = document.location.href;
var parsedOld = parsePadUrl(oldHref).hashData; var parsedOld = Hash.parsePadUrl(oldHref).hashData;
var parsedNew = parsePadUrl(newHref).hashData; var parsedNew = Hash.parsePadUrl(newHref).hashData;
if (parsedOld && parsedNew && ( if (parsedOld && parsedNew && (
parsedOld.type !== parsedNew.type parsedOld.type !== parsedNew.type
|| parsedOld.channel !== parsedNew.channel || parsedOld.channel !== parsedNew.channel
@ -1438,7 +1284,7 @@ define([
if (sessionStorage.createReadme) { if (sessionStorage.createReadme) {
var w = waitFor(); var w = waitFor();
require(['/common/cryptget.js'], function (Crypt) { require(['/common/cryptget.js'], function (Crypt) {
var hash = common.createRandomHash(); var hash = Hash.createRandomHash();
Crypt.put(hash, Messages.driveReadme, function (e) { Crypt.put(hash, Messages.driveReadme, function (e) {
if (e) { if (e) {
console.error("Error while creating the default pad:", e); console.error("Error while creating the default pad:", e);

@ -1,11 +1,12 @@
define([ define([
'jquery', 'jquery',
'/bower_components/marked/marked.min.js', '/bower_components/marked/marked.min.js',
'/common/cryptpad-common.js', '/common/common-hash.js',
'/common/common-util.js',
'/common/media-tag.js', '/common/media-tag.js',
'/bower_components/diff-dom/diffDOM.js', '/bower_components/diff-dom/diffDOM.js',
'/bower_components/tweetnacl/nacl-fast.min.js', '/bower_components/tweetnacl/nacl-fast.min.js',
],function ($, Marked, Cryptpad, MediaTag) { ],function ($, Marked, Hash, Util, MediaTag) {
var DiffMd = {}; var DiffMd = {};
var DiffDOM = window.diffDOM; var DiffDOM = window.diffDOM;
@ -40,8 +41,8 @@ define([
}; };
renderer.image = function (href, title, text) { renderer.image = function (href, title, text) {
if (href.slice(0,6) === '/file/') { if (href.slice(0,6) === '/file/') {
var parsed = Cryptpad.parsePadUrl(href); var parsed = Hash.parsePadUrl(href);
var hexFileName = Cryptpad.base64ToHex(parsed.hashData.channel); var hexFileName = Util.base64ToHex(parsed.hashData.channel);
var src = '/blob/' + hexFileName.slice(0,2) + '/' + hexFileName; var src = '/blob/' + hexFileName.slice(0,2) + '/' + hexFileName;
var mt = '<media-tag src="' + src + '" data-crypto-key="cryptpad:' + parsed.hashData.key + '">'; var mt = '<media-tag src="' + src + '" data-crypto-key="cryptpad:' + parsed.hashData.key + '">';
if (mediaMap[src]) { if (mediaMap[src]) {

File diff suppressed because it is too large Load Diff

@ -5,8 +5,9 @@ define([
'/bower_components/textpatcher/TextPatcher.amd.js', '/bower_components/textpatcher/TextPatcher.amd.js',
'/common/userObject.js', '/common/userObject.js',
'/common/common-interface.js', '/common/common-interface.js',
'/common/common-hash.js',
'/common/migrate-user-object.js', '/common/migrate-user-object.js',
], function ($, Listmap, Crypto, TextPatcher, FO, UI, Migrate) { ], function ($, Listmap, Crypto, TextPatcher, FO, UI, Hash, Migrate) {
/* /*
This module uses localStorage, which is synchronous, but exposes an This module uses localStorage, which is synchronous, but exposes an
asyncronous API. This is so that we can substitute other storage asyncronous API. This is so that we can substitute other storage
@ -248,7 +249,7 @@ define([
if (typeof(proxy.uid) !== 'string' || proxy.uid.length !== 32) { if (typeof(proxy.uid) !== 'string' || proxy.uid.length !== 32) {
// even anonymous users should have a persistent, unique-ish id // even anonymous users should have a persistent, unique-ish id
console.log('generating a persistent identifier'); console.log('generating a persistent identifier');
proxy.uid = Cryptpad.createChannelId(); proxy.uid = Hash.createChannelId();
} }
// if the user is logged in, but does not have signing keys... // if the user is logged in, but does not have signing keys...
@ -285,11 +286,11 @@ define([
if (!Cryptpad || initialized) { return; } if (!Cryptpad || initialized) { return; }
initialized = true; initialized = true;
var hash = Cryptpad.getUserHash() || localStorage.FS_hash || Cryptpad.createRandomHash(); var hash = Cryptpad.getUserHash() || localStorage.FS_hash || Hash.createRandomHash();
if (!hash) { if (!hash) {
throw new Error('[Store.init] Unable to find or create a drive hash. Aborting...'); throw new Error('[Store.init] Unable to find or create a drive hash. Aborting...');
} }
var secret = Cryptpad.getSecrets('drive', hash); var secret = Hash.getSecrets('drive', hash);
var listmapConfig = { var listmapConfig = {
data: {}, data: {},
websocketURL: Cryptpad.getWebsocketURL(), websocketURL: Cryptpad.getWebsocketURL(),
@ -332,7 +333,7 @@ define([
rt.proxy.on('create', function (info) { rt.proxy.on('create', function (info) {
exp.info = info; exp.info = info;
if (!Cryptpad.getUserHash()) { if (!Cryptpad.getUserHash()) {
localStorage.FS_hash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys); localStorage.FS_hash = Hash.getEditHashFromKeys(info.channel, secret.keys);
} }
}).on('ready', function () { }).on('ready', function () {
if (store) { return; } // the store is already ready, it is a reconnection if (store) { return; } // the store is already ready, it is a reconnection

@ -3,10 +3,11 @@ define([
'/bower_components/chainpad-listmap/chainpad-listmap.js', '/bower_components/chainpad-listmap/chainpad-listmap.js',
'/bower_components/chainpad-crypto/crypto.js', '/bower_components/chainpad-crypto/crypto.js',
'/common/cryptpad-common.js', '/common/cryptpad-common.js',
'/common/common-util.js',
'/common/credential.js', '/common/credential.js',
'/bower_components/tweetnacl/nacl-fast.min.js', '/bower_components/tweetnacl/nacl-fast.min.js',
'/bower_components/scrypt-async/scrypt-async.min.js', // better load speed '/bower_components/scrypt-async/scrypt-async.min.js', // better load speed
], function ($, Listmap, Crypto, Cryptpad, Cred) { ], function ($, Listmap, Crypto, Cryptpad, Util, Cred) {
var Exports = { var Exports = {
Cred: Cred, Cred: Cred,
}; };
@ -43,12 +44,12 @@ define([
keys.editKeyStr = keys.editKeyStr.replace(/\//g, '-'); keys.editKeyStr = keys.editKeyStr.replace(/\//g, '-');
// 32 bytes of hex // 32 bytes of hex
var channelHex = opt.channelHex = Cryptpad.uint8ArrayToHex(channelSeed); var channelHex = opt.channelHex = Util.uint8ArrayToHex(channelSeed);
// should never happen // should never happen
if (channelHex.length !== 32) { throw new Error('invalid channel id'); } if (channelHex.length !== 32) { throw new Error('invalid channel id'); }
opt.channel64 = Cryptpad.hexToBase64(channelHex); opt.channel64 = Util.hexToBase64(channelHex);
opt.userHash = '/1/edit/' + [opt.channel64, opt.keys.editKeyStr].join('/'); opt.userHash = '/1/edit/' + [opt.channel64, opt.keys.editKeyStr].join('/');

@ -2,7 +2,8 @@ define([
'/common/cryptpad-common.js', '/common/cryptpad-common.js',
'/common/cryptget.js', '/common/cryptget.js',
'/common/userObject.js', '/common/userObject.js',
], function (Cryptpad, Crypt, FO) { '/common/common-hash.js',
], function (Cryptpad, Crypt, FO, Hash) {
var exp = {}; var exp = {};
var getType = function (el) { var getType = function (el) {
@ -41,7 +42,7 @@ define([
if (typeof(p) === "string") { if (typeof(p) === "string") {
if (getType(root) !== "object") { root = undefined; error(); return; } if (getType(root) !== "object") { root = undefined; error(); return; }
if (i === path.length - 1) { if (i === path.length - 1) {
root[Cryptpad.createChannelId()] = id; root[Hash.createChannelId()] = id;
return; return;
} }
next = getType(path[i+1]); next = getType(path[i+1]);
@ -120,10 +121,10 @@ define([
// Do not migrate a pad if we already have it, it would create a duplicate in the drive // Do not migrate a pad if we already have it, it would create a duplicate in the drive
if (newHrefs.indexOf(href) !== -1) { return; } if (newHrefs.indexOf(href) !== -1) { return; }
// If we have a stronger version, do not add the current href // If we have a stronger version, do not add the current href
if (Cryptpad.findStronger(href, newRecentPads)) { return; } if (Hash.findStronger(href, newRecentPads)) { return; }
// If we have a weaker version, replace the href by the new one // If we have a weaker version, replace the href by the new one
// NOTE: if that weaker version is in the trash, the strong one will be put in unsorted // NOTE: if that weaker version is in the trash, the strong one will be put in unsorted
var weaker = Cryptpad.findWeaker(href, newRecentPads); var weaker = Hash.findWeaker(href, newRecentPads);
if (weaker) { if (weaker) {
// Update RECENTPADS // Update RECENTPADS
newRecentPads.some(function (pad) { newRecentPads.some(function (pad) {

@ -1,7 +1,8 @@
define([ define([
'/file/file-crypto.js', '/file/file-crypto.js',
'/common/common-hash.js',
'/bower_components/tweetnacl/nacl-fast.min.js', '/bower_components/tweetnacl/nacl-fast.min.js',
], function (FileCrypto) { ], function (FileCrypto, Hash) {
var Nacl = window.nacl; var Nacl = window.nacl;
var module = {}; var module = {};
@ -50,7 +51,7 @@ define([
var b64Key = Nacl.util.encodeBase64(key); var b64Key = Nacl.util.encodeBase64(key);
var hash = common.getFileHashFromKeys(id, b64Key); var hash = Hash.getFileHashFromKeys(id, b64Key);
var href = '/file/#' + hash; var href = '/file/#' + hash;
var title = metadata.name; var title = metadata.name;

@ -300,7 +300,7 @@ define([
var ext = (typeof(extension) === 'function') ? extension() : extension; var ext = (typeof(extension) === 'function') ? extension() : extension;
var suggestion = title.suggestTitle('cryptpad-document'); var suggestion = title.suggestTitle('cryptpad-document');
UI.prompt(Messages.exportPrompt, UI.prompt(Messages.exportPrompt,
Cryptpad.fixFileName(suggestion) + '.' + ext, function (filename) Util.fixFileName(suggestion) + '.' + ext, function (filename)
{ {
if (!(typeof(filename) === 'string' && filename)) { return; } if (!(typeof(filename) === 'string' && filename)) { return; }
if (async) { if (async) {

@ -3,9 +3,11 @@ define([
'/file/file-crypto.js', '/file/file-crypto.js',
'/common/common-thumbnail.js', '/common/common-thumbnail.js',
'/common/common-interface.js', '/common/common-interface.js',
'/common/common-util.js',
'/customize/messages.js',
'/bower_components/tweetnacl/nacl-fast.min.js', '/bower_components/tweetnacl/nacl-fast.min.js',
], function ($, FileCrypto, Thumb, UI) { ], function ($, FileCrypto, Thumb, UI, Util, Messages) {
var Nacl = window.nacl; var Nacl = window.nacl;
var module = {}; var module = {};
@ -33,9 +35,6 @@ define([
module.create = function (common, config) { module.create = function (common, config) {
var File = {}; var File = {};
var Cryptpad = common.getCryptpadCommon();
var Messages = Cryptpad.Messages;
var queue = File.queue = { var queue = File.queue = {
queue: [], queue: [],
@ -168,9 +167,9 @@ define([
}; };
var prettySize = function (bytes) { var prettySize = function (bytes) {
var kB = Cryptpad.bytesToKilobytes(bytes); var kB = Util.bytesToKilobytes(bytes);
if (kB < 1024) { return kB + Messages.KB; } if (kB < 1024) { return kB + Messages.KB; }
var mB = Cryptpad.bytesToMegabytes(bytes); var mB = Util.bytesToMegabytes(bytes);
return mB + Messages.MB; return mB + Messages.MB;
}; };

@ -19,6 +19,7 @@ define([
var FilePicker; var FilePicker;
var Messenger; var Messenger;
var Notifier; var Notifier;
var Utils = {};
nThen(function (waitFor) { nThen(function (waitFor) {
// Load #2, the loading screen is up so grab whatever you need... // Load #2, the loading screen is up so grab whatever you need...
@ -31,8 +32,11 @@ define([
'/filepicker/main.js', '/filepicker/main.js',
'/common/common-messenger.js', '/common/common-messenger.js',
'/common/common-notifier.js', '/common/common-notifier.js',
'/common/common-hash.js',
'/common/common-util.js',
'/common/common-realtime.js',
], waitFor(function (_CpNfOuter, _Cryptpad, _Crypto, _Cryptget, SFrameChannel, ], waitFor(function (_CpNfOuter, _Cryptpad, _Crypto, _Cryptget, SFrameChannel,
_FilePicker, _Messenger, _Notifier) { _FilePicker, _Messenger, _Notifier, _Hash, _Util, _Realtime) {
CpNfOuter = _CpNfOuter; CpNfOuter = _CpNfOuter;
Cryptpad = _Cryptpad; Cryptpad = _Cryptpad;
Crypto = _Crypto; Crypto = _Crypto;
@ -40,6 +44,9 @@ define([
FilePicker = _FilePicker; FilePicker = _FilePicker;
Messenger = _Messenger; Messenger = _Messenger;
Notifier = _Notifier; Notifier = _Notifier;
Utils.Hash = _Hash;
Utils.Util = _Util;
Utils.Realtime = _Realtime;
if (localStorage.CRYPTPAD_URLARGS !== ApiConfig.requireConf.urlArgs) { if (localStorage.CRYPTPAD_URLARGS !== ApiConfig.requireConf.urlArgs) {
console.log("New version, flushing cache"); console.log("New version, flushing cache");
@ -85,16 +92,16 @@ define([
}); });
}); });
secret = cfg.getSecrets ? cfg.getSecrets(Cryptpad) : Cryptpad.getSecrets(); secret = cfg.getSecrets ? cfg.getSecrets(Cryptpad, Utils) : Utils.Hash.getSecrets();
if (!secret.channel) { if (!secret.channel) {
// New pad: create a new random channel id // New pad: create a new random channel id
secret.channel = Cryptpad.createChannelId(); secret.channel = Utils.Hash.createChannelId();
} }
Cryptpad.getShareHashes(secret, waitFor(function (err, h) { hashes = h; })); Cryptpad.getShareHashes(secret, waitFor(function (err, h) { hashes = h; }));
}).nThen(function () { }).nThen(function () {
var readOnly = secret.keys && !secret.keys.editKeyStr; var readOnly = secret.keys && !secret.keys.editKeyStr;
if (!secret.keys) { secret.keys = secret.key; } if (!secret.keys) { secret.keys = secret.key; }
var parsed = Cryptpad.parsePadUrl(window.location.href); var parsed = Utils.Hash.parsePadUrl(window.location.href);
if (!parsed.type) { throw new Error(); } if (!parsed.type) { throw new Error(); }
var defaultTitle = Cryptpad.getDefaultName(parsed); var defaultTitle = Cryptpad.getDefaultName(parsed);
var proxy = Cryptpad.getProxy(); var proxy = Cryptpad.getProxy();
@ -335,11 +342,11 @@ define([
// Present mode URL // Present mode URL
sframeChan.on('Q_PRESENT_URL_GET_VALUE', function (data, cb) { sframeChan.on('Q_PRESENT_URL_GET_VALUE', function (data, cb) {
var parsed = Cryptpad.parsePadUrl(window.location.href); var parsed = Utils.Hash.parsePadUrl(window.location.href);
cb(parsed.hashData && parsed.hashData.present); cb(parsed.hashData && parsed.hashData.present);
}); });
sframeChan.on('EV_PRESENT_URL_SET_VALUE', function (data) { sframeChan.on('EV_PRESENT_URL_SET_VALUE', function (data) {
var parsed = Cryptpad.parsePadUrl(window.location.href); var parsed = Utils.Hash.parsePadUrl(window.location.href);
window.location.href = parsed.getUrl({ window.location.href = parsed.getUrl({
embed: parsed.hashData.embed, embed: parsed.hashData.embed,
present: data present: data
@ -463,7 +470,7 @@ define([
}); });
if (cfg.addRpc) { if (cfg.addRpc) {
cfg.addRpc(sframeChan, Cryptpad); cfg.addRpc(sframeChan, Cryptpad, Utils);
} }
if (cfg.messaging) { if (cfg.messaging) {
@ -580,6 +587,18 @@ define([
if (!realtime) { return; } if (!realtime) { return; }
var replaceHash = function (hash) {
if (window.history && window.history.replaceState) {
if (!/^#/.test(hash)) { hash = '#' + hash; }
void window.history.replaceState({}, window.document.title, hash);
if (typeof(window.onhashchange) === 'function') {
window.onhashchange();
}
return;
}
window.location.hash = hash;
};
CpNfOuter.start({ CpNfOuter.start({
sframeChan: sframeChan, sframeChan: sframeChan,
channel: secret.channel, channel: secret.channel,
@ -596,7 +615,7 @@ define([
return; return;
} }
if (readOnly || cfg.noHash) { return; } if (readOnly || cfg.noHash) { return; }
Cryptpad.replaceHash(Cryptpad.getEditHashFromKeys(wc.id, secret.keys)); replaceHash(Utils.Hash.getEditHashFromKeys(wc.id, secret.keys));
} }
}); });
}); });

@ -12,9 +12,9 @@ define([
'/common/metadata-manager.js', '/common/metadata-manager.js',
'/customize/application_config.js', '/customize/application_config.js',
'/common/cryptpad-common.js',
'/common/common-realtime.js', '/common/common-realtime.js',
'/common/common-util.js', '/common/common-util.js',
'/common/common-hash.js',
'/common/common-thumbnail.js', '/common/common-thumbnail.js',
'/common/common-interface.js', '/common/common-interface.js',
'/bower_components/localforage/dist/localforage.min.js' '/bower_components/localforage/dist/localforage.min.js'
@ -31,9 +31,9 @@ define([
CodeMirror, CodeMirror,
MetadataMgr, MetadataMgr,
AppConfig, AppConfig,
Cryptpad,
CommonRealtime, CommonRealtime,
Util, Util,
Hash,
Thumb, Thumb,
UI, UI,
localForage localForage
@ -57,7 +57,6 @@ define([
}; };
funcs.getMetadataMgr = function () { return ctx.metadataMgr; }; funcs.getMetadataMgr = function () { return ctx.metadataMgr; };
funcs.getCryptpadCommon = function () { return Cryptpad; };
funcs.getSframeChannel = function () { return ctx.sframeChan; }; funcs.getSframeChannel = function () { return ctx.sframeChan; };
funcs.getAppConfig = function () { return AppConfig; }; funcs.getAppConfig = function () { return AppConfig; };
@ -104,21 +103,21 @@ define([
return '<script src="' + origin + '/common/media-tag-nacl.min.js"></script>'; return '<script src="' + origin + '/common/media-tag-nacl.min.js"></script>';
}; };
funcs.getMediatagFromHref = function (href) { funcs.getMediatagFromHref = function (href) {
var parsed = Cryptpad.parsePadUrl(href); var parsed = Hash.parsePadUrl(href);
var secret = Cryptpad.getSecrets('file', parsed.hash); var secret = Hash.getSecrets('file', parsed.hash);
var data = ctx.metadataMgr.getPrivateData(); var data = ctx.metadataMgr.getPrivateData();
if (secret.keys && secret.channel) { if (secret.keys && secret.channel) {
var cryptKey = secret.keys && secret.keys.fileKeyStr; var cryptKey = secret.keys && secret.keys.fileKeyStr;
var hexFileName = Cryptpad.base64ToHex(secret.channel); var hexFileName = Util.base64ToHex(secret.channel);
var origin = data.fileHost || data.origin; var origin = data.fileHost || data.origin;
var src = origin + Cryptpad.getBlobPathFromHex(hexFileName); var src = origin + Hash.getBlobPathFromHex(hexFileName);
return '<media-tag src="' + src + '" data-crypto-key="cryptpad:' + cryptKey + '">' + return '<media-tag src="' + src + '" data-crypto-key="cryptpad:' + cryptKey + '">' +
'</media-tag>'; '</media-tag>';
} }
return; return;
}; };
funcs.getFileSize = function (href, cb) { funcs.getFileSize = function (href, cb) {
var channelId = Cryptpad.hrefToHexChannelId(href); var channelId = Hash.hrefToHexChannelId(href);
funcs.sendAnonRpcMsg("GET_FILE_SIZE", channelId, function (data) { funcs.sendAnonRpcMsg("GET_FILE_SIZE", channelId, function (data) {
if (!data) { return void cb("No response"); } if (!data) { return void cb("No response"); }
if (data.error) { return void cb(data.error); } if (data.error) { return void cb(data.error); }

@ -1,677 +0,0 @@
define([
'jquery',
'/bower_components/chainpad-crypto/crypto.js',
'/common/curve.js',
'/common/common-hash.js',
], function ($, Crypto, Curve, Hash) {
'use strict';
var Msg = {
inputs: [],
};
var Types = {
message: 'MSG',
update: 'UPDATE',
unfriend: 'UNFRIEND',
mapId: 'MAP_ID',
mapIdAck: 'MAP_ID_ACK'
};
var clone = function (o) {
return JSON.parse(JSON.stringify(o));
};
// TODO
// - mute a channel (hide notifications or don't open it?)
var createData = Msg.createData = function (proxy, hash) {
return {
channel: hash || Hash.createChannelId(),
displayName: proxy['cryptpad.username'],
profile: proxy.profile && proxy.profile.view,
edPublic: proxy.edPublic,
curvePublic: proxy.curvePublic,
avatar: proxy.profile && proxy.profile.avatar
};
};
var getFriend = function (proxy, pubkey) {
if (pubkey === proxy.curvePublic) {
var data = createData(proxy);
delete data.channel;
return data;
}
return proxy.friends ? proxy.friends[pubkey] : undefined;
};
var getFriendList = Msg.getFriendList = function (proxy) {
if (!proxy.friends) { proxy.friends = {}; }
return proxy.friends;
};
var eachFriend = function (friends, cb) {
Object.keys(friends).forEach(function (id) {
if (id === 'me') { return; }
cb(friends[id], id, friends);
});
};
Msg.getFriendChannelsList = function (proxy) {
var list = [];
eachFriend(proxy, function (friend) {
list.push(friend.channel);
});
return list;
};
var msgAlreadyKnown = function (channel, sig) {
return channel.messages.some(function (message) {
return message[0] === sig;
});
};
Msg.messenger = function (common) {
var messenger = {
handlers: {
message: [],
join: [],
leave: [],
update: [],
friend: [],
unfriend: [],
},
range_requests: {},
};
var eachHandler = function (type, g) {
messenger.handlers[type].forEach(g);
};
messenger.on = function (type, f) {
var stack = messenger.handlers[type];
if (!Array.isArray(stack)) {
return void console.error('unsupported message type');
}
if (typeof(f) !== 'function') {
return void console.error('expected function');
}
stack.push(f);
};
var channels = messenger.channels = {};
var joining = {};
// declare common variables
var network = common.getNetwork();
var proxy = common.getProxy();
var realtime = common.getRealtime();
Msg.hk = network.historyKeeper;
var friends = getFriendList(proxy);
var getChannel = function (curvePublic) {
var friend = friends[curvePublic];
if (!friend) { return; }
var chanId = friend.channel;
if (!chanId) { return; }
return channels[chanId];
};
var initRangeRequest = function (txid, curvePublic, sig, cb) {
messenger.range_requests[txid] = {
messages: [],
cb: cb,
curvePublic: curvePublic,
sig: sig,
};
};
var getRangeRequest = function (txid) {
return messenger.range_requests[txid];
};
var deleteRangeRequest = function (txid) {
delete messenger.range_requests[txid];
};
messenger.getMoreHistory = function (curvePublic, hash, count, cb) {
if (typeof(cb) !== 'function') { return; }
if (typeof(hash) !== 'string') {
// FIXME hash is not necessarily defined.
// What does this mean?
console.error("not sure what to do here");
return;
}
var chan = getChannel(curvePublic);
if (typeof(chan) === 'undefined') {
console.error("chan is undefined. we're going to have a problem here");
return;
}
var txid = common.uid();
initRangeRequest(txid, curvePublic, hash, cb);
var msg = [ 'GET_HISTORY_RANGE', chan.id, {
from: hash,
count: count,
txid: txid,
}
];
network.sendto(network.historyKeeper, JSON.stringify(msg)).then(function () {
}, function (err) {
throw new Error(err);
});
};
var getCurveForChannel = function (id) {
var channel = channels[id];
if (!channel) { return; }
return channel.curve;
};
messenger.getChannelHead = function (curvePublic, cb) {
var friend = friends[curvePublic];
if (!friend) { return void cb('NO_SUCH_FRIEND'); }
cb(void 0, friend.lastKnownHash);
};
messenger.setChannelHead = function (curvePublic, hash, cb) {
var friend = friends[curvePublic];
if (!friend) { return void cb('NO_SUCH_FRIEND'); }
friend.lastKnownHash = hash;
cb();
};
// Id message allows us to map a netfluxId with a public curve key
var onIdMessage = function (msg, sender) {
var channel;
var isId = Object.keys(channels).some(function (chanId) {
if (channels[chanId].userList.indexOf(sender) !== -1) {
channel = channels[chanId];
return true;
}
});
if (!isId) { return; }
var decryptedMsg = channel.encryptor.decrypt(msg);
if (decryptedMsg === null) {
return void console.error("Failed to decrypt message");
}
if (!decryptedMsg) {
console.error('decrypted message was falsey but not null');
return;
}
var parsed;
try {
parsed = JSON.parse(decryptedMsg);
} catch (e) {
console.error(decryptedMsg);
return;
}
if (parsed[0] !== Types.mapId && parsed[0] !== Types.mapIdAck) { return; }
// check that the responding peer's encrypted netflux id matches
// the sender field. This is to prevent replay attacks.
if (parsed[2] !== sender || !parsed[1]) { return; }
channel.mapId[sender] = parsed[1];
eachHandler('join', function (f) {
f(parsed[1], channel.id);
});
if (parsed[0] !== Types.mapId) { return; } // Don't send your key if it's already an ACK
// Answer with your own key
var rMsg = [Types.mapIdAck, proxy.curvePublic, channel.wc.myID];
var rMsgStr = JSON.stringify(rMsg);
var cryptMsg = channel.encryptor.encrypt(rMsgStr);
network.sendto(sender, cryptMsg);
};
var orderMessages = function (curvePublic, new_messages /*, sig */) {
var channel = getChannel(curvePublic);
var messages = channel.messages;
// TODO improve performance, guarantee correct ordering
new_messages.reverse().forEach(function (msg) {
messages.unshift(msg);
});
};
var removeFromFriendList = function (curvePublic, cb) {
if (!proxy.friends) { return; }
var friends = proxy.friends;
delete friends[curvePublic];
common.whenRealtimeSyncs(realtime, cb);
};
var pushMsg = function (channel, cryptMsg) {
var msg = channel.encryptor.decrypt(cryptMsg);
var sig = cryptMsg.slice(0, 64);
if (msgAlreadyKnown(channel, sig)) { return; }
var parsedMsg = JSON.parse(msg);
var curvePublic;
if (parsedMsg[0] === Types.message) {
// TODO validate messages here
var res = {
type: parsedMsg[0],
sig: sig,
author: parsedMsg[1],
time: parsedMsg[2],
text: parsedMsg[3],
// this makes debugging a whole lot easier
curve: getCurveForChannel(channel.id),
};
channel.messages.push(res);
eachHandler('message', function (f) {
f(res);
});
return true;
}
if (parsedMsg[0] === Types.update) {
if (parsedMsg[1] === proxy.curvePublic) { return; }
curvePublic = parsedMsg[1];
var newdata = parsedMsg[3];
var data = getFriend(proxy, parsedMsg[1]);
var types = [];
Object.keys(newdata).forEach(function (k) {
if (data[k] !== newdata[k]) {
types.push(k);
data[k] = newdata[k];
}
});
eachHandler('update', function (f) {
f(clone(newdata), curvePublic);
});
return;
}
if (parsedMsg[0] === Types.unfriend) {
curvePublic = parsedMsg[1];
delete friends[curvePublic];
removeFromFriendList(parsedMsg[1], function () {
channel.wc.leave(Types.unfriend);
eachHandler('unfriend', function (f) {
f(curvePublic);
});
});
return;
}
};
/* Broadcast a display name, profile, or avatar change to all contacts
*/
// TODO send event...
messenger.updateMyData = function () {
var friends = getFriendList(proxy);
var mySyncData = friends.me;
var myData = createData(proxy);
if (!mySyncData || mySyncData.displayName !== myData.displayName
|| mySyncData.profile !== myData.profile
|| mySyncData.avatar !== myData.avatar) {
delete myData.channel;
Object.keys(channels).forEach(function (chan) {
var channel = channels[chan];
if (!channel) {
return void console.error('NO_SUCH_CHANNEL');
}
var msg = [Types.update, myData.curvePublic, +new Date(), myData];
var msgStr = JSON.stringify(msg);
var cryptMsg = channel.encryptor.encrypt(msgStr);
channel.wc.bcast(cryptMsg).then(function () {
// TODO send event
//channel.refresh();
}, function (err) {
console.error(err);
});
});
eachHandler('update', function (f) {
f(myData, myData.curvePublic);
});
friends.me = myData;
}
};
var onChannelReady = function (chanId) {
var cb = joining[chanId];
if (typeof(cb) !== 'function') {
return void console.error('channel ready without callback');
}
delete joining[chanId];
return cb();
};
var onDirectMessage = function (common, msg, sender) {
if (sender !== Msg.hk) { return void onIdMessage(msg, sender); }
var parsed = JSON.parse(msg);
if (/HISTORY_RANGE/.test(parsed[0])) {
//console.log(parsed);
var txid = parsed[1];
var req = getRangeRequest(txid);
var type = parsed[0];
if (!req) {
return void console.error("received response to unknown request");
}
if (type === 'HISTORY_RANGE') {
req.messages.push(parsed[2]);
} else if (type === 'HISTORY_RANGE_END') {
// process all the messages (decrypt)
var curvePublic = req.curvePublic;
var channel = getChannel(curvePublic);
var decrypted = req.messages.map(function (msg) {
if (msg[2] !== 'MSG') { return; }
try {
return {
d: JSON.parse(channel.encryptor.decrypt(msg[4])),
sig: msg[4].slice(0, 64),
};
} catch (e) {
console.log('failed to decrypt');
return null;
}
}).filter(function (decrypted) {
return decrypted;
}).map(function (O) {
return {
type: O.d[0],
sig: O.sig,
author: O.d[1],
time: O.d[2],
text: O.d[3],
curve: curvePublic,
};
});
orderMessages(curvePublic, decrypted, req.sig);
req.cb(void 0, decrypted);
return deleteRangeRequest(txid);
} else {
console.log(parsed);
}
return;
}
if ((parsed.validateKey || parsed.owners) && parsed.channel) {
return;
}
if (parsed.state && parsed.state === 1 && parsed.channel) {
if (channels[parsed.channel]) {
// parsed.channel is Ready
// channel[parsed.channel].ready();
channels[parsed.channel].ready = true;
onChannelReady(parsed.channel);
var updateTypes = channels[parsed.channel].updateOnReady;
if (updateTypes) {
//channels[parsed.channel].updateUI(updateTypes);
}
}
return;
}
var chan = parsed[3];
if (!chan || !channels[chan]) { return; }
pushMsg(channels[chan], parsed[4]);
};
var onMessage = function (msg, sender, chan) {
if (!channels[chan.id]) { return; }
var isMessage = pushMsg(channels[chan.id], msg);
if (isMessage) {
if (channels[chan.id].wc.myID !== sender) {
// Don't notify for your own messages
//channels[chan.id].notify();
}
//channels[chan.id].refresh();
// TODO emit message event
}
};
// listen for messages...
network.on('message', function(msg, sender) {
onDirectMessage(common, msg, sender);
});
messenger.removeFriend = function (curvePublic, cb) {
if (typeof(cb) !== 'function') { throw new Error('NO_CALLBACK'); }
var data = getFriend(proxy, curvePublic);
if (!data) {
// friend is not valid
console.error('friend is not valid');
return;
}
var channel = channels[data.channel];
if (!channel) {
return void cb("NO_SUCH_CHANNEL");
}
if (!network.webChannels.some(function (wc) {
return wc.id === channel.id;
})) {
console.error('bad channel: ', curvePublic);
}
var msg = [Types.unfriend, proxy.curvePublic, +new Date()];
var msgStr = JSON.stringify(msg);
var cryptMsg = channel.encryptor.encrypt(msgStr);
// TODO emit remove_friend event?
try {
channel.wc.bcast(cryptMsg).then(function () {
delete friends[curvePublic];
delete channels[curvePublic];
common.whenRealtimeSyncs(realtime, function () {
cb();
});
}, function (err) {
console.error(err);
cb(err);
});
} catch (e) {
cb(e);
}
};
var getChannelMessagesSince = function (chan, data, keys) {
console.log('Fetching [%s] messages since [%s]', data.curvePublic, data.lastKnownHash || '');
var cfg = {
validateKey: keys.validateKey,
owners: [proxy.edPublic, data.edPublic],
lastKnownHash: data.lastKnownHash
};
var msg = ['GET_HISTORY', chan.id, cfg];
network.sendto(network.historyKeeper, JSON.stringify(msg))
.then($.noop, function (err) {
throw new Error(err);
});
};
var openFriendChannel = function (data, f) {
var keys = Curve.deriveKeys(data.curvePublic, proxy.curvePrivate);
var encryptor = Curve.createEncryptor(keys);
network.join(data.channel).then(function (chan) {
var channel = channels[data.channel] = {
id: data.channel,
sending: false,
friendEd: f,
keys: keys,
curve: data.curvePublic,
encryptor: encryptor,
messages: [],
wc: chan,
userList: [],
mapId: {},
send: function (payload, cb) {
if (!network.webChannels.some(function (wc) {
if (wc.id === channel.wc.id) { return true; }
})) {
return void cb('NO_SUCH_CHANNEL');
}
var msg = [Types.message, proxy.curvePublic, +new Date(), payload];
var msgStr = JSON.stringify(msg);
var cryptMsg = channel.encryptor.encrypt(msgStr);
channel.wc.bcast(cryptMsg).then(function () {
pushMsg(channel, cryptMsg);
cb();
}, function (err) {
cb(err);
});
}
};
chan.on('message', function (msg, sender) {
onMessage(msg, sender, chan);
});
var onJoining = function (peer) {
if (peer === Msg.hk) { return; }
if (channel.userList.indexOf(peer) !== -1) { return; }
channel.userList.push(peer);
var msg = [Types.mapId, proxy.curvePublic, chan.myID];
var msgStr = JSON.stringify(msg);
var cryptMsg = channel.encryptor.encrypt(msgStr);
network.sendto(peer, cryptMsg);
};
chan.members.forEach(function (peer) {
if (peer === Msg.hk) { return; }
if (channel.userList.indexOf(peer) !== -1) { return; }
channel.userList.push(peer);
});
chan.on('join', onJoining);
chan.on('leave', function (peer) {
var curvePublic = channel.mapId[peer];
var i = channel.userList.indexOf(peer);
while (i !== -1) {
channel.userList.splice(i, 1);
i = channel.userList.indexOf(peer);
}
// update status
if (!curvePublic) { return; }
eachHandler('leave', function (f) {
f(curvePublic, channel.id);
});
});
// FIXME don't subscribe to the channel implicitly
getChannelMessagesSince(chan, data, keys);
}, function (err) {
console.error(err);
});
};
messenger.getFriendList = function (cb) {
var friends = proxy.friends;
if (!friends) { return void cb(void 0, []); }
cb(void 0, Object.keys(proxy.friends).filter(function (k) {
return k !== 'me';
}));
};
messenger.openFriendChannel = function (curvePublic, cb) {
if (typeof(curvePublic) !== 'string') { return void cb('INVALID_ID'); }
if (typeof(cb) !== 'function') { throw new Error('expected callback'); }
var friend = clone(friends[curvePublic]);
if (typeof(friend) !== 'object') {
return void cb('NO_FRIEND_DATA');
}
var channel = friend.channel;
if (!channel) { return void cb('E_NO_CHANNEL'); }
joining[channel] = cb;
openFriendChannel(friend, curvePublic);
};
messenger.sendMessage = function (curvePublic, payload, cb) {
var channel = getChannel(curvePublic);
if (!channel) { return void cb('NO_CHANNEL'); }
if (!network.webChannels.some(function (wc) {
if (wc.id === channel.wc.id) { return true; }
})) {
return void cb('NO_SUCH_CHANNEL');
}
var msg = [Types.message, proxy.curvePublic, +new Date(), payload];
var msgStr = JSON.stringify(msg);
var cryptMsg = channel.encryptor.encrypt(msgStr);
channel.wc.bcast(cryptMsg).then(function () {
pushMsg(channel, cryptMsg);
cb();
}, function (err) {
cb(err);
});
};
messenger.getStatus = function (curvePublic, cb) {
var channel = getChannel(curvePublic);
if (!channel) { return void cb('NO_SUCH_CHANNEL'); }
var online = channel.userList.some(function (nId) {
return channel.mapId[nId] === curvePublic;
});
cb(void 0, online);
};
messenger.getFriendInfo = function (curvePublic, cb) {
setTimeout(function () {
var friend = friends[curvePublic];
if (!friend) { return void cb('NO_SUCH_FRIEND'); }
// this clone will be redundant when ui uses postmessage
cb(void 0, clone(friend));
});
};
messenger.getMyInfo = function (cb) {
cb(void 0, {
curvePublic: proxy.curvePublic,
displayName: common.getDisplayName(),
});
};
// TODO listen for changes to your friend list
// emit 'update' events for clients
//var update = function (curvePublic
proxy.on('change', ['friends'], function (o, n, p) {
var curvePublic;
if (o === undefined) {
// new friend added
curvePublic = p.slice(-1)[0];
eachHandler('friend', function (f) {
f(curvePublic, clone(n));
});
return;
}
console.error(o, n, p);
}).on('remove', ['friends'], function (o, p) {
eachHandler('unfriend', function (f) {
f(p[1]); // TODO
});
});
Object.freeze(messenger);
return messenger;
};
return Msg;
});

@ -3,10 +3,11 @@ define([
'/customize/application_config.js', '/customize/application_config.js',
'/api/config', '/api/config',
'/common/common-ui-elements.js', '/common/common-ui-elements.js',
'/common/common-interface.js' '/common/common-interface.js',
], function ($, Config, ApiConfig, UIElements, UI) { '/common/common-hash.js',
var Messages = {}; '/customize/messages.js',
var Cryptpad; '/common/clipboard.js',
], function ($, Config, ApiConfig, UIElements, UI, Hash, Messages, Clipboard) {
var Common; var Common;
var Bar = { var Bar = {
@ -439,7 +440,7 @@ define([
if (!err) { UI.log(Messages.shareSuccess); } if (!err) { UI.log(Messages.shareSuccess); }
});*/ });*/
var url = origin + pathname + '#' + hashes.editHash; var url = origin + pathname + '#' + hashes.editHash;
var success = Cryptpad.Clipboard.copy(url); var success = Clipboard.copy(url);
if (success) { UI.log(Messages.shareSuccess); } if (success) { UI.log(Messages.shareSuccess); }
}); });
} }
@ -449,12 +450,12 @@ define([
if (!err) { UI.log(Messages.shareSuccess); } if (!err) { UI.log(Messages.shareSuccess); }
});*/ });*/
var url = origin + pathname + '#' + hashes.viewHash; var url = origin + pathname + '#' + hashes.viewHash;
var success = Cryptpad.Clipboard.copy(url); var success = Clipboard.copy(url);
if (success) { UI.log(Messages.shareSuccess); } if (success) { UI.log(Messages.shareSuccess); }
}); });
$shareBlock.find('a.cp-toolbar-share-view-embed').click(function () { $shareBlock.find('a.cp-toolbar-share-view-embed').click(function () {
var url = origin + pathname + '#' + hashes.viewHash; var url = origin + pathname + '#' + hashes.viewHash;
var parsed = Cryptpad.parsePadUrl(url); var parsed = Hash.parsePadUrl(url);
url = origin + parsed.getUrl({embed: true, present: true}); url = origin + parsed.getUrl({embed: true, present: true});
// Alertify content // Alertify content
var $content = $('<div>'); var $content = $('<div>');
@ -474,7 +475,7 @@ define([
$('#'+iframeId).click(function () { $('#'+iframeId).click(function () {
this.select(); this.select();
}); });
//var success = Cryptpad.Clipboard.copy(url); //var success = Clipboard.copy(url);
//if (success) { UI.log(Messages.shareSuccess); } //if (success) { UI.log(Messages.shareSuccess); }
}); });
} }
@ -520,7 +521,7 @@ define([
// Add handlers // Add handlers
$shareBlock.find('a.cp-toolbar-share-file-copy').click(function () { $shareBlock.find('a.cp-toolbar-share-file-copy').click(function () {
var success = Cryptpad.Clipboard.copy(url); var success = Clipboard.copy(url);
if (success) { UI.log(Messages.shareSuccess); } if (success) { UI.log(Messages.shareSuccess); }
}); });
$shareBlock.find('a.cp-toolbar-share-file-embed').click(function () { $shareBlock.find('a.cp-toolbar-share-file-embed').click(function () {
@ -570,8 +571,8 @@ define([
if (config.readOnly === 1) { if (config.readOnly === 1) {
$titleContainer.append($('<span>', {'class': 'cp-toolbar-title-readonly'}) $titleContainer.append($('<span>', {'class': 'cp-toolbar-title-readonly'})
.text('('+Messages.readonly+')')); .text('('+Messages.readonly+')'));
return $titleContainer;
} }
if (config.readOnly === 1 || typeof(Cryptpad) === "undefined") { return $titleContainer; }
var $input = $('<input>', { var $input = $('<input>', {
type: 'text', type: 'text',
placeholder: placeholder placeholder: placeholder
@ -842,7 +843,6 @@ define([
console.error(err); console.error(err);
return; return;
} }
//Cryptpad.changeDisplayName(newName, true); Already done?
}); });
}); });
}); });
@ -894,90 +894,88 @@ define([
if (!config.metadataMgr) { return; } if (!config.metadataMgr) { return; }
var metadataMgr = config.metadataMgr; var metadataMgr = config.metadataMgr;
var userNetfluxId = metadataMgr.getNetfluxId(); var userNetfluxId = metadataMgr.getNetfluxId();
if (typeof Cryptpad !== "undefined") { var notify = function(type, name, oldname) {
var notify = function(type, name, oldname) { // type : 1 (+1 user), 0 (rename existing user), -1 (-1 user)
// type : 1 (+1 user), 0 (rename existing user), -1 (-1 user) if (typeof name === "undefined") { return; }
if (typeof name === "undefined") { return; } name = name || Messages.anonymous;
name = name || Messages.anonymous; if (Config.disableUserlistNotifications) { return; }
if (Config.disableUserlistNotifications) { return; } switch(type) {
switch(type) { case 1:
case 1: UI.log(Messages._getKey("notifyJoined", [name]));
UI.log(Messages._getKey("notifyJoined", [name])); break;
break; case 0:
case 0: oldname = (!oldname) ? Messages.anonymous : oldname;
oldname = (!oldname) ? Messages.anonymous : oldname; UI.log(Messages._getKey("notifyRenamed", [oldname, name]));
UI.log(Messages._getKey("notifyRenamed", [oldname, name])); break;
break; case -1:
case -1: UI.log(Messages._getKey("notifyLeft", [name]));
UI.log(Messages._getKey("notifyLeft", [name])); break;
break; default:
default: console.log("Invalid type of notification");
console.log("Invalid type of notification"); break;
break; }
} };
};
var userPresent = function (id, user, data) { var userPresent = function (id, user, data) {
if (!(user && user.uid)) { if (!(user && user.uid)) {
console.log('no uid'); console.log('no uid');
return 0; return 0;
} }
if (!data) { if (!data) {
console.log('no data'); console.log('no data');
return 0; return 0;
} }
var count = 0; var count = 0;
Object.keys(data).forEach(function (k) { Object.keys(data).forEach(function (k) {
if (data[k] && data[k].uid === user.uid) { count++; } if (data[k] && data[k].uid === user.uid) { count++; }
}); });
return count; return count;
}; };
var joined = false; var joined = false;
metadataMgr.onChange(function () { metadataMgr.onChange(function () {
var newdata = metadataMgr.getMetadata().users; var newdata = metadataMgr.getMetadata().users;
var netfluxIds = Object.keys(newdata); var netfluxIds = Object.keys(newdata);
// Notify for disconnected users // Notify for disconnected users
if (typeof oldUserData !== "undefined") { if (typeof oldUserData !== "undefined") {
for (var u in oldUserData) { for (var u in oldUserData) {
// if a user's uid is still present after having left, don't notify // if a user's uid is still present after having left, don't notify
if (netfluxIds.indexOf(u) === -1) { if (netfluxIds.indexOf(u) === -1) {
var temp = JSON.parse(JSON.stringify(oldUserData[u])); var temp = JSON.parse(JSON.stringify(oldUserData[u]));
delete oldUserData[u]; delete oldUserData[u];
if (temp && newdata[userNetfluxId] && temp.uid === newdata[userNetfluxId].uid) { return; } if (temp && newdata[userNetfluxId] && temp.uid === newdata[userNetfluxId].uid) { return; }
if (userPresent(u, temp, newdata || oldUserData) < 1) { if (userPresent(u, temp, newdata || oldUserData) < 1) {
notify(-1, temp.name); notify(-1, temp.name);
}
} }
} }
} }
// Update the "oldUserData" object and notify for new users and names changed }
if (typeof newdata === "undefined") { return; } // Update the "oldUserData" object and notify for new users and names changed
if (typeof oldUserData === "undefined") { if (typeof newdata === "undefined") { return; }
oldUserData = JSON.parse(JSON.stringify(newdata)); if (typeof oldUserData === "undefined") {
return; oldUserData = JSON.parse(JSON.stringify(newdata));
} return;
if (config.readOnly === 0 && !oldUserData[userNetfluxId]) { }
oldUserData = JSON.parse(JSON.stringify(newdata)); if (config.readOnly === 0 && !oldUserData[userNetfluxId]) {
return; oldUserData = JSON.parse(JSON.stringify(newdata));
} return;
for (var k in newdata) { }
if (joined && k !== userNetfluxId && netfluxIds.indexOf(k) !== -1) { for (var k in newdata) {
if (typeof oldUserData[k] === "undefined") { if (joined && k !== userNetfluxId && netfluxIds.indexOf(k) !== -1) {
// if the same uid is already present in the userdata, don't notify if (typeof oldUserData[k] === "undefined") {
if (!userPresent(k, newdata[k], oldUserData)) { // if the same uid is already present in the userdata, don't notify
notify(1, newdata[k].name); if (!userPresent(k, newdata[k], oldUserData)) {
} notify(1, newdata[k].name);
} else if (oldUserData[k].name !== newdata[k].name) {
notify(0, newdata[k].name, oldUserData[k].name);
} }
} else if (oldUserData[k].name !== newdata[k].name) {
notify(0, newdata[k].name, oldUserData[k].name);
} }
} }
joined = true; }
oldUserData = JSON.parse(JSON.stringify(newdata)); joined = true;
}); oldUserData = JSON.parse(JSON.stringify(newdata));
} });
}; };
@ -986,9 +984,7 @@ define([
Bar.create = function (cfg) { Bar.create = function (cfg) {
var config = cfg || {}; var config = cfg || {};
Cryptpad = config.common;
Common = config.sfCommon; Common = config.sfCommon;
Messages = Cryptpad.Messages;
config.readOnly = (typeof config.readOnly !== "undefined") ? (config.readOnly ? 1 : 0) : -1; config.readOnly = (typeof config.readOnly !== "undefined") ? (config.readOnly ? 1 : 0) : -1;
config.displayed = config.displayed || []; config.displayed = config.displayed || [];
@ -1042,7 +1038,7 @@ define([
initClickEvents(toolbar, config); initClickEvents(toolbar, config);
initNotifications(toolbar, config); initNotifications(toolbar, config);
var failed = toolbar.failed = function () { toolbar.failed = function () {
toolbar.connected = false; toolbar.connected = false;
if (toolbar.spinner) { if (toolbar.spinner) {
@ -1083,11 +1079,12 @@ define([
}; };
// On log out, remove permanently the realtime elements of the toolbar // On log out, remove permanently the realtime elements of the toolbar
Cryptpad.onLogout(function () { // TODO
/*Common.onLogout(function () {
failed(); failed();
if (toolbar.useradmin) { toolbar.useradmin.hide(); } if (toolbar.useradmin) { toolbar.useradmin.hide(); }
if (toolbar.userlist) { toolbar.userlist.hide(); } if (toolbar.userlist) { toolbar.userlist.hide(); }
}); });*/
return toolbar; return toolbar;
}; };

@ -1,7 +1,10 @@
define([ define([
'jquery', 'jquery',
'/customize/application_config.js' '/customize/application_config.js',
], function ($, AppConfig) { '/common/common-util.js',
'/common/common-hash.js',
'/common/common-realtime.js'
], function ($, AppConfig, Util, Hash, Realtime) {
var module = {}; var module = {};
var ROOT = module.ROOT = "root"; var ROOT = module.ROOT = "root";
@ -74,7 +77,7 @@ define([
exp.isReadOnlyFile = function (element) { exp.isReadOnlyFile = function (element) {
if (!isFile(element)) { return false; } if (!isFile(element)) { return false; }
var data = exp.getFileData(element); var data = exp.getFileData(element);
var parsed = Cryptpad.parsePadUrl(data.href); var parsed = Hash.parsePadUrl(data.href);
if (!parsed) { return false; } if (!parsed) { return false; }
var pHash = parsed.hashData; var pHash = parsed.hashData;
if (!pHash || pHash.type !== "pad") { return; } if (!pHash || pHash.type !== "pad") { return; }
@ -243,7 +246,7 @@ define([
getHrefArray().forEach(function (c) { getHrefArray().forEach(function (c) {
ret = ret.concat(_getFiles[c]()); ret = ret.concat(_getFiles[c]());
}); });
return Cryptpad.deduplicateString(ret); return Util.deduplicateString(ret);
}; };
_getFiles[ROOT] = function () { _getFiles[ROOT] = function () {
var ret = []; var ret = [];
@ -294,7 +297,7 @@ define([
ret = ret.concat(_getFiles[c]()); ret = ret.concat(_getFiles[c]());
} }
}); });
return Cryptpad.deduplicateString(ret); return Util.deduplicateString(ret);
}; };
var getIdFromHref = exp.getIdFromHref = function (href) { var getIdFromHref = exp.getIdFromHref = function (href) {
@ -437,13 +440,13 @@ define([
}); });
// Search Href // Search Href
var href = Cryptpad.getRelativeHref(value); var href = Hash.getRelativeHref(value);
if (href) { if (href) {
var id = getIdFromHref(href); var id = getIdFromHref(href);
if (id) { res.push(id); } if (id) { res.push(id); }
} }
res = Cryptpad.deduplicateString(res); res = Util.deduplicateString(res);
var ret = []; var ret = [];
res.forEach(function (l) { res.forEach(function (l) {
@ -486,14 +489,14 @@ define([
// TODO: can only be called from outside atm // TODO: can only be called from outside atm
if (typeof cb !== "function") { cb = function () {}; } if (typeof cb !== "function") { cb = function () {}; }
var todo = function () { var todo = function () {
var id = Cryptpad.createRandomInteger(); var id = Util.createRandomInteger();
files[FILES_DATA][id] = data; files[FILES_DATA][id] = data;
cb(null, id); cb(null, id);
}; };
if (!loggedIn || !AppConfig.enablePinning || config.testMode) { if (!loggedIn || !AppConfig.enablePinning || config.testMode) {
return void todo(); return void todo();
} }
Cryptpad.pinPads([Cryptpad.hrefToHexChannelId(data.href)], function (e) { Cryptpad.pinPads([Hash.hrefToHexChannelId(data.href)], function (e) {
if (e) { return void cb(e); } if (e) { return void cb(e); }
todo(); todo();
}); });
@ -547,7 +550,7 @@ define([
} }
// Move to root // Move to root
var newName = isFile(element) ? var newName = isFile(element) ?
getAvailableName(newParent, Cryptpad.createChannelId()) : getAvailableName(newParent, Hash.createChannelId()) :
isInTrashRoot(elementPath) ? isInTrashRoot(elementPath) ?
elementPath[1] : elementPath.pop(); elementPath[1] : elementPath.pop();
@ -605,7 +608,7 @@ define([
if (path && isPathIn(newPath, [ROOT]) || filesList.indexOf(id) === -1) { if (path && isPathIn(newPath, [ROOT]) || filesList.indexOf(id) === -1) {
parentEl = find(newPath || [ROOT]); parentEl = find(newPath || [ROOT]);
if (parentEl) { if (parentEl) {
var newName = getAvailableName(parentEl, Cryptpad.createChannelId()); var newName = getAvailableName(parentEl, Hash.createChannelId());
parentEl[newName] = id; parentEl[newName] = id;
return; return;
} }
@ -865,10 +868,10 @@ define([
oldData.forEach(function (obj) { oldData.forEach(function (obj) {
if (!obj || !obj.href) { return; } if (!obj || !obj.href) { return; }
var href = obj.href; var href = obj.href;
var id = Cryptpad.createRandomInteger(); var id = Util.createRandomInteger();
var paths = findFile(href); var paths = findFile(href);
var data = obj; var data = obj;
var key = Cryptpad.createChannelId(); var key = Hash.createChannelId();
if (data) { if (data) {
newData[id] = data; newData[id] = data;
} else { } else {
@ -901,7 +904,7 @@ define([
if (exp.rt) { if (exp.rt) {
exp.rt.sync(); exp.rt.sync();
// TODO // TODO
Cryptpad.whenRealtimeSyncs(exp.rt, next); Realtime.whenRealtimeSyncs(exp.rt, next);
} else { } else {
window.setTimeout(next, 1000); window.setTimeout(next, 1000);
} }
@ -943,8 +946,8 @@ define([
} }
if (typeof element[el] === "string") { if (typeof element[el] === "string") {
// We have an old file (href) which is not in filesData: add it // We have an old file (href) which is not in filesData: add it
var id = Cryptpad.createRandomInteger(); var id = Util.createRandomInteger();
var key = Cryptpad.createChannelId(); var key = Hash.createChannelId();
files[FILES_DATA][id] = {href: element[el], filename: el}; files[FILES_DATA][id] = {href: element[el], filename: el};
element[key] = id; element[key] = id;
delete element[el]; delete element[el];
@ -968,7 +971,7 @@ define([
if (!$.isArray(obj.path)) { toClean.push(idx); return; } if (!$.isArray(obj.path)) { toClean.push(idx); return; }
if (typeof obj.element === "string") { if (typeof obj.element === "string") {
// We have an old file (href) which is not in filesData: add it // We have an old file (href) which is not in filesData: add it
var id = Cryptpad.createRandomInteger(); var id = Util.createRandomInteger();
files[FILES_DATA][id] = {href: obj.element, filename: el}; files[FILES_DATA][id] = {href: obj.element, filename: el};
obj.element = id; obj.element = id;
} }
@ -1002,7 +1005,7 @@ define([
}; };
var fixTemplate = function () { var fixTemplate = function () {
if (!Array.isArray(files[TEMPLATE])) { debug("TEMPLATE was not an array"); files[TEMPLATE] = []; } if (!Array.isArray(files[TEMPLATE])) { debug("TEMPLATE was not an array"); files[TEMPLATE] = []; }
files[TEMPLATE] = Cryptpad.deduplicateString(files[TEMPLATE].slice()); files[TEMPLATE] = Util.deduplicateString(files[TEMPLATE].slice());
var us = files[TEMPLATE]; var us = files[TEMPLATE];
var rootFiles = getFiles([ROOT]).slice(); var rootFiles = getFiles([ROOT]).slice();
var toClean = []; var toClean = [];
@ -1012,7 +1015,7 @@ define([
} }
if (typeof el === "string") { if (typeof el === "string") {
// We have an old file (href) which is not in filesData: add it // We have an old file (href) which is not in filesData: add it
var id = Cryptpad.createRandomInteger(); var id = Util.createRandomInteger();
files[FILES_DATA][id] = {href: el}; files[FILES_DATA][id] = {href: el};
us[idx] = id; us[idx] = id;
} }
@ -1050,7 +1053,7 @@ define([
toClean.push(id); toClean.push(id);
continue; continue;
} }
var parsed = Cryptpad.parsePadUrl(el.href); var parsed = Hash.parsePadUrl(el.href);
if (!parsed.hash) { if (!parsed.hash) {
debug("Removing an element in filesData with a invalid href.", el); debug("Removing an element in filesData with a invalid href.", el);
toClean.push(id); toClean.push(id);
@ -1059,7 +1062,7 @@ define([
if ((loggedIn || config.testMode) && rootFiles.indexOf(id) === -1) { if ((loggedIn || config.testMode) && rootFiles.indexOf(id) === -1) {
debug("An element in filesData was not in ROOT, TEMPLATE or TRASH.", id, el); debug("An element in filesData was not in ROOT, TEMPLATE or TRASH.", id, el);
var newName = Cryptpad.createChannelId(); var newName = Hash.createChannelId();
root[newName] = id; root[newName] = id;
continue; continue;
} }

@ -5,6 +5,7 @@ define([
'json.sortify', 'json.sortify',
'/common/cryptpad-common.js', '/common/cryptpad-common.js',
'/common/common-util.js', '/common/common-util.js',
'/common/common-hash.js',
'/common/common-ui-elements.js', '/common/common-ui-elements.js',
'/common/common-interface.js', '/common/common-interface.js',
'/common/cryptget.js', '/common/cryptget.js',
@ -25,6 +26,7 @@ define([
JSONSortify, JSONSortify,
Cryptpad, Cryptpad,
Util, Util,
Hash,
UIElements, UIElements,
UI, UI,
Cryptget, Cryptget,
@ -1148,7 +1150,7 @@ define([
var data = filesOp.getFileData(element); var data = filesOp.getFileData(element);
if (!data) { return void logError("No data for the file", element); } if (!data) { return void logError("No data for the file", element); }
var hrefData = Cryptpad.parsePadUrl(data.href); var hrefData = Hash.parsePadUrl(data.href);
if (hrefData.type) { if (hrefData.type) {
$span.addClass('cp-border-color-'+hrefData.type); $span.addClass('cp-border-color-'+hrefData.type);
} }
@ -1707,7 +1709,7 @@ define([
var data = filesOp.getFileData(id); var data = filesOp.getFileData(id);
if (!data) { return ''; } if (!data) { return ''; }
if (prop === 'type') { if (prop === 'type') {
var hrefData = Cryptpad.parsePadUrl(data.href); var hrefData = Hash.parsePadUrl(data.href);
return hrefData.type; return hrefData.type;
} }
if (prop === 'atime' || prop === 'ctime') { if (prop === 'atime' || prop === 'ctime') {
@ -1742,7 +1744,7 @@ define([
}; };
} }
if (prop === 'type') { if (prop === 'type') {
var hrefData = Cryptpad.parsePadUrl(e.href); var hrefData = Hash.parsePadUrl(e.href);
return hrefData.type; return hrefData.type;
} }
if (prop === 'atime' || prop === 'ctime') { if (prop === 'atime' || prop === 'ctime') {
@ -1957,7 +1959,7 @@ define([
filesList.forEach(function (r) { filesList.forEach(function (r) {
r.paths.forEach(function (path) { r.paths.forEach(function (path) {
var href = r.data.href; var href = r.data.href;
var parsed = Cryptpad.parsePadUrl(href); var parsed = Hash.parsePadUrl(href);
var $table = $('<table>'); var $table = $('<table>');
var $icon = $('<td>', {'rowspan': '3', 'class': 'cp-app-drive-search-icon'}) var $icon = $('<td>', {'rowspan': '3', 'class': 'cp-app-drive-search-icon'})
.append(getFileIcon(href)); .append(getFileIcon(href));
@ -2447,13 +2449,13 @@ define([
if (!filesOp.isFile(id)) { return; } if (!filesOp.isFile(id)) { return; }
var data = filesOp.getFileData(id); var data = filesOp.getFileData(id);
if (!data) { return; } if (!data) { return; }
var parsed = Cryptpad.parsePadUrl(data.href); var parsed = Hash.parsePadUrl(data.href);
if (parsed.hashData.type !== "pad") { return; } if (parsed.hashData.type !== "pad") { return; }
var i = data.href.indexOf('#') + 1; var i = data.href.indexOf('#') + 1;
var base = data.href.slice(0, i); var base = data.href.slice(0, i);
var hrefsecret = Cryptpad.getSecrets(parsed.type, parsed.hash); var hrefsecret = Hash.getSecrets(parsed.type, parsed.hash);
if (!hrefsecret.keys) { return; } if (!hrefsecret.keys) { return; }
var viewHash = Cryptpad.getViewHashFromKeys(hrefsecret.channel, hrefsecret.keys); var viewHash = Hash.getViewHashFromKeys(hrefsecret.channel, hrefsecret.keys);
return base + viewHash; return base + viewHash;
}; };
@ -2486,7 +2488,7 @@ define([
})); }));
} }
var parsed = Cryptpad.parsePadUrl(data.href); var parsed = Hash.parsePadUrl(data.href);
if (parsed.hashData && parsed.hashData.type === 'pad') { if (parsed.hashData && parsed.hashData.type === 'pad') {
var roLink = ro ? base + data.href : base + getReadOnlyUrl(el); var roLink = ro ? base + data.href : base + getReadOnlyUrl(el);
if (roLink) { if (roLink) {
@ -2528,7 +2530,7 @@ define([
return void cb(void 0, $d); return void cb(void 0, $d);
} }
var KB = Cryptpad.bytesToKilobytes(bytes); var KB = Util.bytesToKilobytes(bytes);
var formatted = Messages._getKey('formattedKB', [KB]); var formatted = Messages._getKey('formattedKB', [KB]);
$('<br>').appendTo($d); $('<br>').appendTo($d);

@ -38,9 +38,9 @@ define([
}; };
window.addEventListener('message', onMsg); window.addEventListener('message', onMsg);
}).nThen(function (/*waitFor*/) { }).nThen(function (/*waitFor*/) {
var getSecrets = function (Cryptpad) { var getSecrets = function (Cryptpad, Utils) {
var hash = window.location.hash.slice(1) || Cryptpad.getUserHash() || localStorage.FS_hash; var hash = window.location.hash.slice(1) || Cryptpad.getUserHash() || localStorage.FS_hash;
return Cryptpad.getSecrets('drive', hash); return Utils.Hash.getSecrets('drive', hash);
}; };
Netflux.connect(Cryptpad.getWebsocketURL()).then(function (network) { Netflux.connect(Cryptpad.getWebsocketURL()).then(function (network) {
SFCommonO.start({ SFCommonO.start({

@ -2,12 +2,13 @@ define([
'jquery', 'jquery',
'/bower_components/chainpad-crypto/crypto.js', '/bower_components/chainpad-crypto/crypto.js',
'/common/toolbar3.js', '/common/toolbar3.js',
'/common/cryptpad-common.js',
'/bower_components/nthen/index.js', '/bower_components/nthen/index.js',
'/common/sframe-common.js', '/common/sframe-common.js',
'/common/common-realtime.js', '/common/common-realtime.js',
'/common/common-util.js', '/common/common-util.js',
'/common/common-hash.js',
'/common/common-interface.js', '/common/common-interface.js',
'/customize/messages.js',
'/file/file-crypto.js', '/file/file-crypto.js',
'/common/media-tag.js', '/common/media-tag.js',
@ -22,22 +23,20 @@ define([
$, $,
Crypto, Crypto,
Toolbar, Toolbar,
Cryptpad,
nThen, nThen,
SFCommon, SFCommon,
CommonRealtime, CommonRealtime,
Util, Util,
Hash,
UI, UI,
Messages,
FileCrypto, FileCrypto,
MediaTag) MediaTag)
{ {
var Messages = Cryptpad.Messages;
var saveAs = window.saveAs; var saveAs = window.saveAs;
var Nacl = window.nacl; var Nacl = window.nacl;
var APP = window.APP = { var APP = window.APP = {};
Cryptpad: Cryptpad,
};
var andThen = function (common) { var andThen = function (common) {
var $appContainer = $('#cp-app-file-content'); var $appContainer = $('#cp-app-file-content');
@ -62,9 +61,9 @@ define([
if (!priv.filehash) { if (!priv.filehash) {
uploadMode = true; uploadMode = true;
} else { } else {
secret = Cryptpad.getSecrets('file', priv.filehash); secret = Hash.getSecrets('file', priv.filehash);
if (!secret.keys) { throw new Error("You need a hash"); } if (!secret.keys) { throw new Error("You need a hash"); }
hexFileName = Cryptpad.base64ToHex(secret.channel); hexFileName = Util.base64ToHex(secret.channel);
} }
var Title = common.createTitle({}); var Title = common.createTitle({});
@ -74,7 +73,6 @@ define([
} }
var configTb = { var configTb = {
displayed: displayed, displayed: displayed,
common: Cryptpad,
//hideDisplayName: true, //hideDisplayName: true,
$container: $bar, $container: $bar,
metadataMgr: metadataMgr, metadataMgr: metadataMgr,
@ -88,7 +86,7 @@ define([
toolbar.$rightside.html(''); toolbar.$rightside.html('');
if (!uploadMode) { if (!uploadMode) {
var src = Cryptpad.getBlobPathFromHex(hexFileName); var src = Hash.getBlobPathFromHex(hexFileName);
var cryptKey = secret.keys && secret.keys.fileKeyStr; var cryptKey = secret.keys && secret.keys.fileKeyStr;
var key = Nacl.util.decodeBase64(cryptKey); var key = Nacl.util.decodeBase64(cryptKey);
@ -110,7 +108,7 @@ define([
var $mt = $dlview.find('media-tag'); var $mt = $dlview.find('media-tag');
var cryptKey = secret.keys && secret.keys.fileKeyStr; var cryptKey = secret.keys && secret.keys.fileKeyStr;
var hexFileName = Cryptpad.base64ToHex(secret.channel); var hexFileName = Util.base64ToHex(secret.channel);
$mt.attr('src', '/blob/' + hexFileName.slice(0,2) + '/' + hexFileName); $mt.attr('src', '/blob/' + hexFileName.slice(0,2) + '/' + hexFileName);
$mt.attr('data-crypto-key', 'cryptpad:'+cryptKey); $mt.attr('data-crypto-key', 'cryptpad:'+cryptKey);
@ -232,7 +230,7 @@ define([
if (e) { if (e) {
return void UI.errorLoadingScreen(e); return void UI.errorLoadingScreen(e);
} }
var size = Cryptpad.bytesToMegabytes(data); var size = Util.bytesToMegabytes(data);
return void todoBigFile(size); return void todoBigFile(size);
}); });
}); });

@ -8,6 +8,8 @@ define([
'/common/sframe-common.js', '/common/sframe-common.js',
'/common/common-interface.js', '/common/common-interface.js',
'/common/common-ui-elements.js', '/common/common-ui-elements.js',
'/common/common-util.js',
'/common/common-hash.js',
'json.sortify', 'json.sortify',
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
@ -23,6 +25,8 @@ define([
SFCommon, SFCommon,
UI, UI,
UIElements, UIElements,
Util,
Hash,
Sortify) Sortify)
{ {
var Messages = Cryptpad.Messages; var Messages = Cryptpad.Messages;
@ -45,10 +49,10 @@ define([
sframeChan.event('EV_FILE_PICKER_CLOSE'); sframeChan.event('EV_FILE_PICKER_CLOSE');
}; };
var onFilePicked = function (data) { var onFilePicked = function (data) {
var parsed = Cryptpad.parsePadUrl(data.url); var parsed = Hash.parsePadUrl(data.url);
hideFileDialog(); hideFileDialog();
if (parsed.type === 'file') { if (parsed.type === 'file') {
var hexFileName = Cryptpad.base64ToHex(parsed.hashData.channel); var hexFileName = Util.base64ToHex(parsed.hashData.channel);
var src = '/blob/' + hexFileName.slice(0,2) + '/' + hexFileName; var src = '/blob/' + hexFileName.slice(0,2) + '/' + hexFileName;
sframeChan.event("EV_FILE_PICKED", { sframeChan.event("EV_FILE_PICKED", {
type: parsed.type, type: parsed.type,

@ -2,10 +2,11 @@ define([
'jquery', 'jquery',
'/common/cryptpad-common.js', '/common/cryptpad-common.js',
'/common/common-interface.js', '/common/common-interface.js',
//'/common/common-hash.js',
//'/bower_components/chainpad-listmap/chainpad-listmap.js', //'/bower_components/chainpad-listmap/chainpad-listmap.js',
//'/common/curve.js', //'/common/curve.js',
'less!/invite/main.less', 'less!/invite/main.less',
], function ($, Cryptpad, UI /*, Listmap, Curve*/) { ], function ($, Cryptpad, UI/*, Hash , Listmap, Curve*/) {
var Messages = Cryptpad.Messages; var Messages = Cryptpad.Messages;
var comingSoon = function () { var comingSoon = function () {
return $('<div>', { return $('<div>', {
@ -34,7 +35,7 @@ define([
var andThen = function () { var andThen = function () {
var hash = window.location.hash.slice(1); var hash = window.location.hash.slice(1);
var info = Cryptpad.parseTypeHash('invite', hash); var info = Hash.parseTypeHash('invite', hash);
console.log(info); console.log(info);
if (!info.pubkey) { if (!info.pubkey) {

@ -1,16 +0,0 @@
<!DOCTYPE html>
<html class="cp">
<!-- If this file is not called customize.dist/src/template.html, it is generated -->
<head>
<title data-localization="main_title">CryptPad: Zero Knowledge, Collaborative Real Time Editing</title>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" type="image/png" href="/customize/main-favicon.png" id="favicon"/>
<script async data-bootload="/customize/template.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
</head>
<body class="html">
<noscript>
<p><strong>OOPS</strong> In order to do encryption in your browser, Javascript is really <strong>really</strong> required.</p>
<p><strong>OUPS</strong> Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est <strong>vraiment</strong> nécessaire.</p>
</noscript>
</html>

@ -1,569 +0,0 @@
define([
'jquery',
'/common/cryptpad-common.js',
'/common/cryptget.js',
'/common/mergeDrive.js',
'/common/toolbar2.js',
'/bower_components/file-saver/FileSaver.min.js',
'less!/customize/src/less/cryptpad.less',
'less!/bower_components/components-font-awesome/css/font-awesome.min.css',
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
'less!/customize/src/less/toolbar.less',
'less!/settings/main.less',
], function ($, Cryptpad, Crypt, Merge, Toolbar) {
var saveAs = window.saveAs;
var USERNAME_KEY = 'cryptpad.username';
var APP = window.APP = {
Cryptpad: Cryptpad,
_onRefresh: []
};
var Messages = Cryptpad.Messages;
// Manage changes in the realtime object made from another page
var onRefresh = function (h) {
if (typeof(h) !== "function") { return; }
if (APP._onRefresh.indexOf(h) !== -1) { return; }
APP._onRefresh.push(h);
};
var refresh = APP.refresh = function () {
APP._onRefresh.forEach(function (h) {
h();
});
};
var categories = {
'account': [
'infoBlock',
'displayName',
'languageSelector',
'logoutEverywhere',
'resetTips',
'thumbnails',
'userFeedback'
],
'drive': [
'backupDrive',
'importLocalPads',
'resetDrive'
],
'code': [
'indentUnit',
'indentType'
]
};
var createInfoBlock = function (store) {
var obj = store.proxy;
var $div = $('<div>', {'class': 'infoBlock'});
var $account = $('<div>', {'class': 'element'}).appendTo($div);
var accountName = obj.login_name || localStorage[Cryptpad.userNameKey];
var $label = $('<span>', {'class': 'label'}).text(Messages.user_accountName);
var $name = $('<span>').text(accountName || '');
if (!accountName) {
$label.text('');
$name.text(Messages.settings_anonymous);
}
$account.append($label).append($name);
var publicKey = obj.edPublic;
if (publicKey) {
var $key = $('<div>', {'class': 'element'}).appendTo($div);
var userHref = Cryptpad.getUserHrefFromKeys(accountName, publicKey);
var $pubLabel = $('<span>', {'class': 'label'})
.text(Messages.settings_publicSigningKey);
$key.append($pubLabel).append(Cryptpad.dialog.selectable(userHref));
}
return $div;
};
// Create the block containing the display name field
var createDisplayNameInput = function (store) {
var obj = store.proxy;
var $div = $('<div>', {'class': 'displayName element'});
$('<label>', {'for' : 'displayName'}).text(Messages.user_displayName).appendTo($div);
var $inputBlock = $('<div>', {'class': 'inputBlock'}).appendTo($div);
var $input = $('<input>', {
'type': 'text',
'id': 'displayName',
'placeholder': Messages.anonymous}).appendTo($inputBlock);
var $save = $('<button>', {'class': 'btn btn-primary'}).text(Messages.settings_save).appendTo($inputBlock);
var $ok = $('<span>', {'class': 'fa fa-check', title: Messages.saved}).hide().appendTo($div);
var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'}).hide().appendTo($div);
var displayName = obj[USERNAME_KEY] || '';
$input.val(displayName);
// When the display name is changed (enter or button clicked)
var todo = function () {
displayName = $input.val();
if (displayName === obj[USERNAME_KEY]) { return; }
obj[USERNAME_KEY] = displayName;
Cryptpad.changeDisplayName(displayName);
$spinner.show();
Cryptpad.whenRealtimeSyncs(store.info.realtime, function () {
$spinner.hide();
$ok.show();
});
};
$input.on('keyup', function (e) {
if ($input.val() !== displayName) { $ok.hide(); }
if (e.which === 13) { todo(); }
});
$save.click(todo);
// On remote change
var onChange = function () {
if (obj[USERNAME_KEY] !== $input.val()) {
$input.val(obj[USERNAME_KEY]);
$input.focusout();
}
};
onRefresh(onChange);
return $div;
};
var createIndentUnitSelector = function (obj) {
var proxy = obj.proxy;
proxy.settings = proxy.settings || {};
var $div = $('<div>', {
'class': 'indentUnit element'
});
$('<label>').text(Messages.settings_codeIndentation).appendTo($div);
var $inputBlock = $('<div>', {
'class': 'inputBlock',
}).appendTo($div);
var $input = $('<input>', {
'min': 1,
'max': 8,
type: 'number',
}).on('change', function () {
var val = parseInt($input.val());
if (typeof(val) !== 'number') { return; }
Cryptpad.setAttribute(['codemirror', 'indentUnit'], val);
}).appendTo($inputBlock);
proxy.on('change', [ 'settings', 'codemirror', 'indentUnit', ], function (o, n) {
$input.val(n);
});
Cryptpad.getAttribute(['codemirror', 'indentUnit'], function (e, val) {
if (e) { return void console.error(e); }
if (typeof(val) !== 'number') {
$input.val(2);
} else {
$input.val(val);
}
});
return $div;
};
var createIndentTypeSelector = function (obj) {
var proxy = obj.proxy;
proxy.settings = proxy.settings || {};
var key = 'indentWithTabs';
var $div = $('<div>', {
'class': 'indentType element'
});
$('<label>').text(Messages.settings_codeUseTabs).appendTo($div);
var $inputBlock = $('<div>', {
'class': 'inputBlock',
}).css('flex-flow', 'column')
.appendTo($div);
var $input = $('<input>', {
type: 'checkbox',
}).on('change', function () {
var val = $input.is(':checked');
if (typeof(val) !== 'boolean') { return; }
Cryptpad.setAttribute(['codemirror', key], val);
}).appendTo($inputBlock);
$input[0].checked = !!proxy.settings[key];
proxy.on('change', ['settings', 'codemirror', key], function (o, n) {
$input[0].checked = !!n;
});
Cryptpad.getAttribute(['codemirror', key], function (e, val) {
if (e) { return void console.error(e); }
$input[0].checked = !!val;
});
return $div;
};
var createResetTips = function () {
var $div = $('<div>', {'class': 'resetTips element'});
$('<label>', {'for' : 'resetTips'}).text(Messages.settings_resetTips).appendTo($div);
$('<span>', {'class': 'description'})
.text(Messages.settings_resetTipsButton).appendTo($div);
var $button = $('<button>', {'id': 'resetTips', 'class': 'btn btn-primary'})
.text(Messages.settings_resetTipsAction).appendTo($div);
$button.click(function () {
Object.keys(localStorage).forEach(function (k) {
if(k.slice(0, 9) === "hide-info") {
delete localStorage[k];
}
});
Cryptpad.alert(Messages.settings_resetTipsDone);
});
return $div;
};
var createThumbnails = function (obj) {
var $div = $('<div>', {'class': 'thumbnails element'});
$('<label>').text(Messages.settings_thumbnails).appendTo($div);
// Disable
$('<span>', {'class': 'description'})
.text(Messages.settings_disableThumbnailsDescription).appendTo($div);
var $label = $('<label>', { 'for': 'disableThumbnails', 'class': 'noTitle' })
.text(Messages.settings_disableThumbnailsAction);
var $ok = $('<span>', {'class': 'fa fa-check', title: Messages.saved});
var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'});
var $checkbox = $('<input>', {
'type': 'checkbox',
id: 'disableThumbnails'
}).on('change', function () {
$spinner.show();
$ok.hide();
if (!obj.proxy.settings) { obj.proxy.settings = {}; }
if (!obj.proxy.settings.general) { obj.proxy.settings.general = {}; }
obj.proxy.settings.general.disableThumbnails = $checkbox.is(':checked') || false;
Cryptpad.whenRealtimeSyncs(obj.info.realtime, function () {
$spinner.hide();
$ok.show();
});
});
$checkbox.appendTo($div);
$label.appendTo($div);
$ok.hide().appendTo($div);
$spinner.hide().appendTo($div);
if (obj.proxy.settings && obj.proxy.settings.general
&& obj.proxy.settings.general.disableThumbnails) {
$checkbox[0].checked = true;
}
// Reset
/*$('<span>', {'class': 'description'})
.text(Messages.settings_resetThumbnailsDescription).appendTo($div);
var $button = $('<button>', {'id': 'resetThumbnails', 'class': 'btn btn-primary'})
.text(Messages.settings_resetThumbnailsAction).appendTo($div);
$button.click(function () {
// TODO we need to have access to the sandbox localforage first...
Cryptpad.alert(Messages.settings_resetThumbnailsDone);
});*/
return $div;
};
var createBackupDrive = function (store) {
var obj = store.proxy;
var $div = $('<div>', {'class': 'backupDrive element'});
var exportFile = function () {
var sjson = JSON.stringify(obj);
var name = obj.login_name || obj[USERNAME_KEY] || Messages.anonymous;
var suggestion = name + '-' + new Date().toDateString();
Cryptpad.prompt(Cryptpad.Messages.exportPrompt,
Cryptpad.fixFileName(suggestion) + '.json', function (filename) {
if (!(typeof(filename) === 'string' && filename)) { return; }
var blob = new Blob([sjson], {type: "application/json;charset=utf-8"});
saveAs(blob, filename);
});
};
var importFile = function (content) {
var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'}).appendTo($div);
Crypt.put(Cryptpad.getUserHash() || localStorage[Cryptpad.fileHashKey], content, function (e) {
if (e) { console.error(e); }
$spinner.remove();
});
};
$('<label>', {'for' : 'exportDrive'}).text(Messages.settings_backupCategory).appendTo($div);
$('<span>', {'class': 'description'})
.text(Messages.settings_backupTitle).appendTo($div);
/* add an export button */
var $export = Cryptpad.createButton('export', true, {}, exportFile);
$export.attr('class', 'btn btn-success').text(Messages.settings_backup);
$div.append($export);
/* add an import button */
var $import = Cryptpad.createButton('import', true, {}, importFile);
$import.attr('class', 'btn btn-success').text(Messages.settings_restore);
$div.append($import);
return $div;
};
var createResetDrive = function (obj) {
var $div = $('<div>', {'class': 'resetDrive element'});
$('<label>', {'for' : 'resetDrive'}).text(Messages.settings_resetNewTitle).appendTo($div);
$('<span>', {'class': 'description'})
.text(Messages.settings_reset).appendTo($div);
var $button = $('<button>', {'id': 'resetDrive', 'class': 'btn btn-danger'})
.text(Messages.settings_resetButton).appendTo($div);
$button.click(function () {
Cryptpad.prompt(Messages.settings_resetPrompt, "", function (val) {
if (val !== "I love CryptPad") {
Cryptpad.alert(Messages.settings_resetError);
return;
}
obj.proxy.drive = Cryptpad.getStore().getEmptyObject();
Cryptpad.alert(Messages.settings_resetDone);
}, undefined, true);
});
return $div;
};
var createUserFeedbackToggle = function (obj) {
var $div = $('<div>', { 'class': 'userFeedback element'});
$('<span>', {'class': 'label'}).text(Messages.settings_userFeedbackTitle).appendTo($div);
var $label = $('<label>', { 'for': 'userFeedback', 'class': 'noTitle' })
.text(Messages.settings_userFeedback);
$('<span>', {'class': 'description'})
.append(Messages.settings_userFeedbackHint1)
.append(Messages.settings_userFeedbackHint2).appendTo($div);
var $ok = $('<span>', {'class': 'fa fa-check', title: Messages.saved});
var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'});
var $checkbox = $('<input>', {
'type': 'checkbox',
}).on('change', function () {
$spinner.show();
$ok.hide();
obj.proxy.allowUserFeedback = $checkbox.is(':checked') || false;
Cryptpad.whenRealtimeSyncs(obj.info.realtime, function () {
$spinner.hide();
$ok.show();
});
});
$checkbox.appendTo($div);
$label.appendTo($div);
$ok.hide().appendTo($div);
$spinner.hide().appendTo($div);
if (obj.proxy.allowUserFeedback) {
$checkbox[0].checked = true;
}
return $div;
};
var createUsageButton = function () {
Cryptpad.createUsageBar(function (err, $bar) {
if (err) { return void console.error(err); }
APP.$usage.html('').append($bar);
}, true);
};
var createLogoutEverywhere = function (obj) {
var proxy = obj.proxy;
var $div = $('<div>', { 'class': 'logoutEverywhere element'});
$('<label>', { 'for': 'logoutEverywhere'})
.text(Messages.settings_logoutEverywhereTitle).appendTo($div);
$('<span>', {'class': 'description'})
.text(Messages.settings_logoutEverywhere).appendTo($div);
var $button = $('<button>', { id: 'logoutEverywhere', 'class': 'btn btn-primary' })
.text(Messages.settings_logoutEverywhereButton)
.appendTo($div);
var $ok = $('<span>', {'class': 'fa fa-check', title: Messages.saved}).hide().appendTo($div);
var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'}).hide().appendTo($div);
$button.click(function () {
var realtime = obj.info.realtime;
console.log(realtime);
Cryptpad.confirm(Messages.settings_logoutEverywhereConfirm, function (yes) {
if (!yes) { return; }
$spinner.show();
$ok.hide();
var token = Math.floor(Math.random()*Number.MAX_SAFE_INTEGER);
localStorage.setItem('loginToken', token);
proxy.loginToken = token;
Cryptpad.whenRealtimeSyncs(realtime, function () {
$spinner.hide();
$ok.show();
window.setTimeout(function () {
$ok.fadeOut(1500);
}, 2500);
});
});
});
return $div;
};
var createImportLocalPads = function (obj) {
if (!Cryptpad.isLoggedIn()) { return; }
var $div = $('<div>', {'class': 'importLocalPads element'});
$('<label>', {'for' : 'importLocalPads'}).text(Messages.settings_import).appendTo($div);
$('<span>', {'class': 'description'})
.text(Messages.settings_importTitle).appendTo($div);
var $button = $('<button>', {'id': 'importLocalPads', 'class': 'btn btn-primary'})
.text(Messages.settings_import).appendTo($div);
var $ok = $('<span>', {'class': 'fa fa-check', title: Messages.saved}).hide().appendTo($div);
var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'}).hide().appendTo($div);
$button.click(function () {
Cryptpad.confirm(Messages.settings_importConfirm, function (yes) {
if (!yes) { return; }
$spinner.show();
$ok.hide();
Merge.anonDriveIntoUser(obj, localStorage.FS_hash, function () {
$spinner.hide();
$ok.show();
Cryptpad.alert(Messages.settings_importDone);
});
}, undefined, true);
});
return $div;
};
var createLanguageSelector = function () {
var $div = $('<div>', {'class': 'languageSelector element'});
$('<label>').text(Messages.language).appendTo($div);
var $b = Cryptpad.createLanguageSelector().appendTo($div);
$b.find('button').addClass('btn btn-secondary');
return $div;
};
var hideCategories = function () {
APP.$rightside.find('> div').hide();
};
var showCategories = function (cat) {
hideCategories();
cat.forEach(function (c) {
APP.$rightside.find('.'+c).show();
});
};
var createLeftside = function () {
var $categories = $('<div>', {'class': 'categories'}).appendTo(APP.$leftside);
APP.$usage = $('<div>', {'class': 'usage'}).appendTo(APP.$leftside);
var active = 'account';
Object.keys(categories).forEach(function (key) {
var $category = $('<div>', {'class': 'category'}).appendTo($categories);
if (key === 'account') { $category.append($('<span>', {'class': 'fa fa-user-o'})); }
if (key === 'drive') { $category.append($('<span>', {'class': 'fa fa-hdd-o'})); }
if (key === 'code') { $category.append($('<span>', {'class': 'fa fa-file-code-o' })); }
if (key === active) {
$category.addClass('active');
}
$category.click(function () {
active = key;
$categories.find('.active').removeClass('active');
$category.addClass('active');
showCategories(categories[key]);
});
$category.append(Messages['settings_cat_'+key]);
});
showCategories(categories[active]);
};
var createToolbar = function () {
var displayed = ['useradmin', 'newpad', 'limit', 'upgrade', 'pageTitle'];
var configTb = {
displayed: displayed,
ifrw: window,
common: Cryptpad,
$container: APP.$toolbar,
pageTitle: Messages.settings_title
};
var toolbar = APP.toolbar = Toolbar.create(configTb);
toolbar.$rightside.html(''); // Remove the drawer if we don't use it to hide the toolbar
};
var andThen = function (obj) {
APP.$leftside = $('<div>', {id: 'leftSide'}).appendTo(APP.$container);
var $rightside = APP.$rightside = $('<div>', {id: 'rightSide'}).appendTo(APP.$container);
createToolbar();
//$rightside.append(createTitle());
$rightside.append(createInfoBlock(obj));
$rightside.append(createDisplayNameInput(obj));
$rightside.append(createLanguageSelector());
$rightside.append(createIndentUnitSelector(obj));
$rightside.append(createIndentTypeSelector(obj));
if (Cryptpad.isLoggedIn()) {
$rightside.append(createLogoutEverywhere(obj));
}
$rightside.append(createResetTips());
$rightside.append(createThumbnails(obj));
$rightside.append(createBackupDrive(obj));
$rightside.append(createImportLocalPads(obj));
$rightside.append(createResetDrive(obj));
$rightside.append(createUserFeedbackToggle(obj));
obj.proxy.on('change', [], refresh);
obj.proxy.on('remove', [], refresh);
Cryptpad.onDisplayNameChanged(refresh);
createLeftside();
createUsageButton();
Cryptpad.removeLoadingScreen();
};
$(function () {
$(window).click(function () {
$('.cp-dropdown-content').hide();
});
APP.$container = $('#container');
APP.$toolbar = $('#toolbar');
Cryptpad.ready(function () {
//if (!Cryptpad.getUserHash()) { return redirectToMain(); }
var storeObj = Cryptpad.getStore().getProxy && Cryptpad.getStore().getProxy().proxy
? Cryptpad.getStore().getProxy() : undefined;
andThen(storeObj);
Cryptpad.reportAppUsage();
});
});
window.addEventListener('storage', function (e) {
if (e.key !== Cryptpad.userHashKey) { return; }
var o = e.oldValue;
var n = e.newValue;
window.location.reload();
if (o && !n) { // disconnect
//redirectToMain();
}
});
});

@ -1,54 +0,0 @@
@import '/customize/src/less/variables.less';
@import '/customize/src/less/mixins.less';
@import '/customize/src/less/sidebar-layout.less';
.cp {
#container {
#rightSide {
.userFeedback, .thumbnails {
input[type="checkbox"] {
vertical-align: middle;
margin-right: 5px;
}
}
.languageSelector {
button.btn {
width: @button-width;
background-color: @button-alt-bg;
border-color: #adadad;
color: black;
&:hover {
background-color: darken(@button-alt-bg, 15%);
}
}
}
.inputBlock {
input {
border-top-right-radius: 0.25em;
border-bottom-right-radius: 0.25em;
padding: 5px;
padding-left: 15px;
&[type="number"] {
border-right: 1px solid #adadad;
}
&[type="checkbox"] {
margin-right: 100%;
}
}
}
.infoBlock {
[type="text"] {
width: @button-width;
}
}
.backupDrive {
button {
span.fa {
margin-right: 5px;
}
margin-right: 5px;
}
}
}
}
}

@ -60,7 +60,7 @@ define([
Cryptpad: Cryptpad, Cryptpad: Cryptpad,
mobile: function () { return $('body').width() <= 600; } // Menu and content area are not inline-block anymore for mobiles mobile: function () { return $('body').width() <= 600; } // Menu and content area are not inline-block anymore for mobiles
}; };
var Render = Renderer(Cryptpad, APP); var Render = Renderer(APP);
var debug = $.noop; //console.log; var debug = $.noop; //console.log;
@ -119,7 +119,7 @@ define([
var csv = getCSV(); var csv = getCSV();
var suggestion = Title.suggestTitle(Title.defaultTitle); var suggestion = Title.suggestTitle(Title.defaultTitle);
UI.prompt(Messages.exportPrompt, UI.prompt(Messages.exportPrompt,
Cryptpad.fixFileName(suggestion) + '.csv', function (filename) { Util.fixFileName(suggestion) + '.csv', function (filename) {
if (!(typeof(filename) === 'string' && filename)) { return; } if (!(typeof(filename) === 'string' && filename)) { return; }
var blob = new Blob([csv], {type: "application/csv;charset=utf-8"}); var blob = new Blob([csv], {type: "application/csv;charset=utf-8"});
saveAs(blob, filename); saveAs(blob, filename);

@ -3,8 +3,10 @@ define([
'jquery', 'jquery',
'/bower_components/hyperjson/hyperjson.js', '/bower_components/hyperjson/hyperjson.js',
'/bower_components/textpatcher/TextPatcher.js', '/bower_components/textpatcher/TextPatcher.js',
'/common/common-util.js',
'/customize/messages.js',
'/bower_components/diff-dom/diffDOM.js', '/bower_components/diff-dom/diffDOM.js',
], function ($, Hyperjson, TextPatcher) { ], function ($, Hyperjson, TextPatcher, Util, Messages) {
var DiffDOM = window.diffDOM; var DiffDOM = window.diffDOM;
var Example = { var Example = {
@ -31,7 +33,7 @@ by maintaining indexes in rowsOrder and colsOrder
} }
}; };
var Renderer = function (Cryptpad, APP) { var Renderer = function (APP) {
var Render = { var Render = {
Example: Example Example: Example
@ -64,15 +66,15 @@ var Renderer = function (Cryptpad, APP) {
}; };
var getColumnValue = Render.getColumnValue = function (obj, colId) { var getColumnValue = Render.getColumnValue = function (obj, colId) {
return Cryptpad.find(obj, ['content', 'cols'].concat([colId])); return Util.find(obj, ['content', 'cols'].concat([colId]));
}; };
var getRowValue = Render.getRowValue = function (obj, rowId) { var getRowValue = Render.getRowValue = function (obj, rowId) {
return Cryptpad.find(obj, ['content', 'rows'].concat([rowId])); return Util.find(obj, ['content', 'rows'].concat([rowId]));
}; };
var getCellValue = Render.getCellValue = function (obj, cellId) { var getCellValue = Render.getCellValue = function (obj, cellId) {
var value = Cryptpad.find(obj, ['content', 'cells'].concat([cellId])); var value = Util.find(obj, ['content', 'cells'].concat([cellId]));
if (typeof value === 'boolean') { if (typeof value === 'boolean') {
return (value === true ? 1 : 0); return (value === true ? 1 : 0);
} else { } else {
@ -81,25 +83,25 @@ var Renderer = function (Cryptpad, APP) {
}; };
var setRowValue = Render.setRowValue = function (obj, rowId, value) { var setRowValue = Render.setRowValue = function (obj, rowId, value) {
var parent = Cryptpad.find(obj, ['content', 'rows']); var parent = Util.find(obj, ['content', 'rows']);
if (typeof(parent) === 'object') { return (parent[rowId] = value); } if (typeof(parent) === 'object') { return (parent[rowId] = value); }
return null; return null;
}; };
var setColumnValue = Render.setColumnValue = function (obj, colId, value) { var setColumnValue = Render.setColumnValue = function (obj, colId, value) {
var parent = Cryptpad.find(obj, ['content', 'cols']); var parent = Util.find(obj, ['content', 'cols']);
if (typeof(parent) === 'object') { return (parent[colId] = value); } if (typeof(parent) === 'object') { return (parent[colId] = value); }
return null; return null;
}; };
var setCellValue = Render.setCellValue = function (obj, cellId, value) { var setCellValue = Render.setCellValue = function (obj, cellId, value) {
var parent = Cryptpad.find(obj, ['content', 'cells']); var parent = Util.find(obj, ['content', 'cells']);
if (typeof(parent) === 'object') { return (parent[cellId] = value); } if (typeof(parent) === 'object') { return (parent[cellId] = value); }
return null; return null;
}; };
Render.createColumn = function (obj, cb, id, value) { Render.createColumn = function (obj, cb, id, value) {
var order = Cryptpad.find(obj, ['content', 'colsOrder']); var order = Util.find(obj, ['content', 'colsOrder']);
if (!order) { throw new Error("Uninitialized realtime object!"); } if (!order) { throw new Error("Uninitialized realtime object!"); }
id = id || coluid(); id = id || coluid();
value = value || ""; value = value || "";
@ -109,8 +111,8 @@ var Renderer = function (Cryptpad, APP) {
}; };
Render.removeColumn = function (obj, id, cb) { Render.removeColumn = function (obj, id, cb) {
var order = Cryptpad.find(obj, ['content', 'colsOrder']); var order = Util.find(obj, ['content', 'colsOrder']);
var parent = Cryptpad.find(obj, ['content', 'cols']); var parent = Util.find(obj, ['content', 'cols']);
if (!(order && parent)) { throw new Error("Uninitialized realtime object!"); } if (!(order && parent)) { throw new Error("Uninitialized realtime object!"); }
@ -134,7 +136,7 @@ var Renderer = function (Cryptpad, APP) {
}; };
Render.createRow = function (obj, cb, id, value) { Render.createRow = function (obj, cb, id, value) {
var order = Cryptpad.find(obj, ['content', 'rowsOrder']); var order = Util.find(obj, ['content', 'rowsOrder']);
if (!order) { throw new Error("Uninitialized realtime object!"); } if (!order) { throw new Error("Uninitialized realtime object!"); }
id = id || rowuid(); id = id || rowuid();
value = value || ""; value = value || "";
@ -144,8 +146,8 @@ var Renderer = function (Cryptpad, APP) {
}; };
Render.removeRow = function (obj, id, cb) { Render.removeRow = function (obj, id, cb) {
var order = Cryptpad.find(obj, ['content', 'rowsOrder']); var order = Util.find(obj, ['content', 'rowsOrder']);
var parent = Cryptpad.find(obj, ['content', 'rows']); var parent = Util.find(obj, ['content', 'rows']);
if (!(order && parent)) { throw new Error("Uninitialized realtime object!"); } if (!(order && parent)) { throw new Error("Uninitialized realtime object!"); }
@ -185,15 +187,15 @@ var Renderer = function (Cryptpad, APP) {
}; };
var getRowIds = Render.getRowIds = function (obj) { var getRowIds = Render.getRowIds = function (obj) {
return Cryptpad.find(obj, ['content', 'rowsOrder']); return Util.find(obj, ['content', 'rowsOrder']);
}; };
var getColIds = Render.getColIds = function (obj) { var getColIds = Render.getColIds = function (obj) {
return Cryptpad.find(obj, ['content', 'colsOrder']); return Util.find(obj, ['content', 'colsOrder']);
}; };
var getCells = Render.getCells = function (obj) { var getCells = Render.getCells = function (obj) {
return Cryptpad.find(obj, ['content', 'cells']); return Util.find(obj, ['content', 'cells']);
}; };
/* cellMatrix takes a proxy object, and optionally an alternate ordering /* cellMatrix takes a proxy object, and optionally an alternate ordering
@ -219,13 +221,13 @@ var Renderer = function (Cryptpad, APP) {
'data-rt-id': col, 'data-rt-id': col,
type: 'text', type: 'text',
value: getColumnValue(obj, col) || "", value: getColumnValue(obj, col) || "",
title: getColumnValue(obj, col) || Cryptpad.Messages.anonymous, title: getColumnValue(obj, col) || Messages.anonymous,
placeholder: Cryptpad.Messages.anonymous, placeholder: Messages.anonymous,
disabled: 'disabled' disabled: 'disabled'
}; };
return result; return result;
})).concat([{ })).concat([{
content: Cryptpad.Messages.poll_total content: Messages.poll_total
}]); }]);
} }
if (i === rows.length) { if (i === rows.length) {
@ -239,9 +241,9 @@ var Renderer = function (Cryptpad, APP) {
return [{ return [{
'data-rt-id': row, 'data-rt-id': row,
value: getRowValue(obj, row) || '', value: getRowValue(obj, row) || '',
title: getRowValue(obj, row) || Cryptpad.Messages.poll_optionPlaceholder, title: getRowValue(obj, row) || Messages.poll_optionPlaceholder,
type: 'text', type: 'text',
placeholder: Cryptpad.Messages.poll_optionPlaceholder, placeholder: Messages.poll_optionPlaceholder,
disabled: 'disabled', disabled: 'disabled',
}].concat(cols.map(function (col) { }].concat(cols.map(function (col) {
var id = [col, rows[i-1]].join('_'); var id = [col, rows[i-1]].join('_');
@ -269,7 +271,7 @@ var Renderer = function (Cryptpad, APP) {
var makeRemoveElement = Render.makeRemoveElement = function (id) { var makeRemoveElement = Render.makeRemoveElement = function (id) {
return ['SPAN', { return ['SPAN', {
'data-rt-id': id, 'data-rt-id': id,
'title': Cryptpad.Messages.poll_remove, 'title': Messages.poll_remove,
class: 'cp-app-poll-table-remove', class: 'cp-app-poll-table-remove',
}, ['✖']]; }, ['✖']];
}; };
@ -277,7 +279,7 @@ var Renderer = function (Cryptpad, APP) {
var makeEditElement = Render.makeEditElement = function (id) { var makeEditElement = Render.makeEditElement = function (id) {
return ['SPAN', { return ['SPAN', {
'data-rt-id': id, 'data-rt-id': id,
'title': Cryptpad.Messages.poll_edit, 'title': Messages.poll_edit,
class: 'cp-app-poll-table-edit', class: 'cp-app-poll-table-edit',
}, ['✐']]; }, ['✐']];
}; };
@ -285,7 +287,7 @@ var Renderer = function (Cryptpad, APP) {
var makeLockElement = Render.makeLockElement = function (id) { var makeLockElement = Render.makeLockElement = function (id) {
return ['SPAN', { return ['SPAN', {
'data-rt-id': id, 'data-rt-id': id,
'title': Cryptpad.Messages.poll_locked, 'title': Messages.poll_locked,
class: 'cp-app-poll-table-lock fa fa-lock', class: 'cp-app-poll-table-lock fa fa-lock',
}, []]; }, []];
}; };
@ -293,7 +295,7 @@ var Renderer = function (Cryptpad, APP) {
var makeBookmarkElement = Render.makeBookmarkElement = function (id) { var makeBookmarkElement = Render.makeBookmarkElement = function (id) {
return ['SPAN', { return ['SPAN', {
'data-rt-id': id, 'data-rt-id': id,
'title': Cryptpad.Messages.poll_bookmark_col, 'title': Messages.poll_bookmark_col,
'style': 'visibility: hidden;', 'style': 'visibility: hidden;',
class: 'cp-app-poll-table-bookmark fa fa-thumb-tack', class: 'cp-app-poll-table-bookmark fa fa-thumb-tack',
}, []]; }, []];
@ -383,13 +385,13 @@ var Renderer = function (Cryptpad, APP) {
}; };
var diffIsInput = Render.diffIsInput = function (info) { var diffIsInput = Render.diffIsInput = function (info) {
var nodeName = Cryptpad.find(info, ['node', 'nodeName']); var nodeName = Util.find(info, ['node', 'nodeName']);
if (nodeName !== 'INPUT') { return; } if (nodeName !== 'INPUT') { return; }
return true; return true;
}; };
var getInputType = Render.getInputType = function (info) { var getInputType = Render.getInputType = function (info) {
return Cryptpad.find(info, ['node', 'type']); return Util.find(info, ['node', 'type']);
}; };
var preserveCursor = Render.preserveCursor = function (info) { var preserveCursor = Render.preserveCursor = function (info) {
@ -457,14 +459,14 @@ var Renderer = function (Cryptpad, APP) {
// Enable input for the userid column // Enable input for the userid column
APP.enableColumn(userid, table); APP.enableColumn(userid, table);
$(table).find('input[disabled="disabled"][data-rt-id^="' + userid + '"]') $(table).find('input[disabled="disabled"][data-rt-id^="' + userid + '"]')
.attr('placeholder', Cryptpad.Messages.poll_userPlaceholder); .attr('placeholder', Messages.poll_userPlaceholder);
$(table).find('.cp-app-poll-table-lock[data-rt-id="' + userid + '"]').remove(); $(table).find('.cp-app-poll-table-lock[data-rt-id="' + userid + '"]').remove();
$(table).find('[data-rt-id^="' + userid + '"]').closest('td') $(table).find('[data-rt-id^="' + userid + '"]').closest('td')
.addClass("cp-app-poll-table-own"); .addClass("cp-app-poll-table-own");
$(table).find('.cp-app-poll-table-bookmark[data-rt-id="' + userid + '"]') $(table).find('.cp-app-poll-table-bookmark[data-rt-id="' + userid + '"]')
.css('visibility', '') .css('visibility', '')
.addClass('cp-app-poll-table-bookmark-full') .addClass('cp-app-poll-table-bookmark-full')
.attr('title', Cryptpad.Messages.poll_bookmarked_col); .attr('title', Messages.poll_bookmarked_col);
}; };
var styleUncommittedColumn = function (table) { var styleUncommittedColumn = function (table) {
APP.uncommitted.content.colsOrder.forEach(function(id) { APP.uncommitted.content.colsOrder.forEach(function(id) {

@ -139,7 +139,7 @@ define([
/* jshint ignore:start */ /* jshint ignore:start */
var isFriend = function (proxy, edKey) { var isFriend = function (proxy, edKey) {
var friends = Cryptpad.find(proxy, ['friends']); var friends = Util.find(proxy, ['friends']);
return typeof(edKey) === 'string' && friends && (edKey in friends); return typeof(edKey) === 'string' && friends && (edKey in friends);
}; };
@ -148,7 +148,7 @@ define([
var obj = APP.lm.proxy; var obj = APP.lm.proxy;
var proxy = Cryptpad.getProxy(); var proxy = Cryptpad.getProxy();
var userViewHash = Cryptpad.find(proxy, ['profile', 'view']); var userViewHash = Util.find(proxy, ['profile', 'view']);
var edKey = obj.edKey; var edKey = obj.edKey;
var curveKey = obj.curveKey; var curveKey = obj.curveKey;
@ -257,10 +257,15 @@ define([
createEditableInput($block, LINK_ID, placeholder, getValue, setValue); createEditableInput($block, LINK_ID, placeholder, getValue, setValue);
}; };
var allowedMediaTypes = [
'image/png',
'image/jpeg',
'image/jpg',
'image/gif',
];
var addAvatar = function ($container) { var addAvatar = function ($container) {
var $block = $('<div>', {id: AVATAR_ID}).appendTo($container); var $block = $('<div>', {id: AVATAR_ID}).appendTo($container);
var $span = $('<span>').appendTo($block); var $span = $('<span>').appendTo($block);
var allowedMediaTypes = Cryptpad.avatarAllowedTypes;
var sframeChan = common.getSframeChannel(); var sframeChan = common.getSframeChannel();
var displayAvatar = function () { var displayAvatar = function () {
$span.html(''); $span.html('');
@ -320,7 +325,7 @@ define([
var data = { var data = {
FM: APP.FM, FM: APP.FM,
filter: function (file) { filter: function (file) {
var sizeMB = Cryptpad.bytesToMegabytes(file.size); var sizeMB = Util.bytesToMegabytes(file.size);
var type = file.type; var type = file.type;
return sizeMB <= 0.5 && allowedMediaTypes.indexOf(type) !== -1; return sizeMB <= 0.5 && allowedMediaTypes.indexOf(type) !== -1;
}, },

@ -4,7 +4,7 @@ define([
'/api/config', '/api/config',
'jquery', 'jquery',
'/common/requireconfig.js', '/common/requireconfig.js',
'/common/sframe-common-outer.js' '/common/sframe-common-outer.js',
], function (nThen, ApiConfig, $, RequireConfig, SFCommonO) { ], function (nThen, ApiConfig, $, RequireConfig, SFCommonO) {
var requireConfig = RequireConfig(); var requireConfig = RequireConfig();
@ -36,20 +36,21 @@ define([
}; };
window.addEventListener('message', onMsg); window.addEventListener('message', onMsg);
}).nThen(function (/*waitFor*/) { }).nThen(function (/*waitFor*/) {
var getSecrets = function (Cryptpad) { var getSecrets = function (Cryptpad, Utils) {
var Hash = Utils.Hash;
// 1st case: visiting someone else's profile with hash in the URL // 1st case: visiting someone else's profile with hash in the URL
if (window.location.hash) { if (window.location.hash) {
return Cryptpad.getSecrets('profile', window.location.hash.slice(1)); return Hash.getSecrets('profile', window.location.hash.slice(1));
} }
// 2nd case: visiting our own existing profile // 2nd case: visiting our own existing profile
var obj = Cryptpad.getProxy(); var obj = Cryptpad.getProxy();
if (obj.profile && obj.profile.view && obj.profile.edit) { if (obj.profile && obj.profile.view && obj.profile.edit) {
return Cryptpad.getSecrets('profile', obj.profile.edit); return Hash.getSecrets('profile', obj.profile.edit);
} }
// 3rd case: profile creation (create a new random hash, store it later if needed) // 3rd case: profile creation (create a new random hash, store it later if needed)
if (!Cryptpad.isLoggedIn()) { return; } if (!Cryptpad.isLoggedIn()) { return; }
var hash = Cryptpad.createRandomHash(); var hash = Hash.createRandomHash();
var secret = Cryptpad.getSecrets('profile', hash); var secret = Hash.getSecrets('profile', hash);
Cryptpad.pinPads([secret.channel], function (e) { Cryptpad.pinPads([secret.channel], function (e) {
if (e) { if (e) {
if (e === 'E_OVER_LIMIT') { if (e === 'E_OVER_LIMIT') {
@ -59,26 +60,26 @@ define([
//return void UI.log(Messages._getKey('profile_error', [e])) // TODO //return void UI.log(Messages._getKey('profile_error', [e])) // TODO
} }
obj.profile = {}; obj.profile = {};
obj.profile.edit = Cryptpad.getEditHashFromKeys(secret.channel, secret.keys); obj.profile.edit = Utils.Hash.getEditHashFromKeys(secret.channel, secret.keys);
obj.profile.view = Cryptpad.getViewHashFromKeys(secret.channel, secret.keys); obj.profile.view = Utils.Hash.getViewHashFromKeys(secret.channel, secret.keys);
}); });
return secret; return secret;
}; };
var addRpc = function (sframeChan, Cryptpad) { var addRpc = function (sframeChan, Cryptpad, Utils) {
// Adding a new avatar from the profile: pin it and store it in the object // Adding a new avatar from the profile: pin it and store it in the object
sframeChan.on('Q_PROFILE_AVATAR_ADD', function (data, cb) { sframeChan.on('Q_PROFILE_AVATAR_ADD', function (data, cb) {
var chanId = Cryptpad.hrefToHexChannelId(data); var chanId = Utils.Hash.hrefToHexChannelId(data);
Cryptpad.pinPads([chanId], function (e) { Cryptpad.pinPads([chanId], function (e) {
if (e) { return void cb(e); } if (e) { return void cb(e); }
Cryptpad.getProxy().profile.avatar = data; Cryptpad.getProxy().profile.avatar = data;
Cryptpad.whenRealtimeSyncs(Cryptpad.getRealtime(), function () { Utils.Realtime.whenRealtimeSyncs(Cryptpad.getRealtime(), function () {
cb(); cb();
}); });
}); });
}); });
// Removing the avatar from the profile: unpin it // Removing the avatar from the profile: unpin it
sframeChan.on('Q_PROFILE_AVATAR_REMOVE', function (data, cb) { sframeChan.on('Q_PROFILE_AVATAR_REMOVE', function (data, cb) {
var chanId = Cryptpad.hrefToHexChannelId(data); var chanId = Utils.Hash.hrefToHexChannelId(data);
Cryptpad.unpinPads([chanId], function (e) { Cryptpad.unpinPads([chanId], function (e) {
delete Cryptpad.getProxy().profile.avatar; delete Cryptpad.getProxy().profile.avatar;
cb(e); cb(e);

@ -5,9 +5,10 @@ define([
'/common/test.js', '/common/test.js',
'/common/credential.js', // preloaded for login.js '/common/credential.js', // preloaded for login.js
'/common/common-interface.js', '/common/common-interface.js',
'/common/common-util.js',
'less!/bower_components/components-font-awesome/css/font-awesome.min.css', 'less!/bower_components/components-font-awesome/css/font-awesome.min.css',
], function ($, Login, Cryptpad, Test, Cred, UI) { ], function ($, Login, Cryptpad, Test, Cred, UI, Util) {
var Messages = Cryptpad.Messages; var Messages = Cryptpad.Messages;
$(function () { $(function () {
@ -215,7 +216,7 @@ define([
}, 150); }, 150);
}); });
var clickRegister = Cryptpad.notAgainForAnother(function () { var clickRegister = Util.notAgainForAnother(function () {
$register.click(); $register.click();
}, 500); }, 500);

@ -5,6 +5,9 @@ define([
'/bower_components/nthen/index.js', '/bower_components/nthen/index.js',
'/common/sframe-common.js', '/common/sframe-common.js',
'/common/common-interface.js', '/common/common-interface.js',
'/common/common-util.js',
'/common/common-hash.js',
'/customize/messages.js',
'/bower_components/file-saver/FileSaver.min.js', '/bower_components/file-saver/FileSaver.min.js',
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
@ -16,17 +19,16 @@ define([
Cryptpad, Cryptpad,
nThen, nThen,
SFCommon, SFCommon,
UI UI,
Util,
Hash,
Messages
) )
{ {
var saveAs = window.saveAs; var saveAs = window.saveAs;
var Messages = Cryptpad.Messages;
var APP = window.APP = { var APP = window.APP = {
Cryptpad: Cryptpad, Cryptpad: Cryptpad,
}; };
var onConnectError = function () {
UI.errorLoadingScreen(Messages.websocketError);
};
var common; var common;
var metadataMgr; var metadataMgr;
@ -70,7 +72,7 @@ define([
var publicKey = privateData.edPublic; var publicKey = privateData.edPublic;
if (publicKey) { if (publicKey) {
var $key = $('<div>', {'class': 'cp-sidebarlayout-element'}).appendTo($div); var $key = $('<div>', {'class': 'cp-sidebarlayout-element'}).appendTo($div);
var userHref = Cryptpad.getUserHrefFromKeys(accountName, publicKey); var userHref = Hash.getUserHrefFromKeys(accountName, publicKey);
var $pubLabel = $('<span>', {'class': 'label'}) var $pubLabel = $('<span>', {'class': 'label'})
.text(Messages.settings_publicSigningKey); .text(Messages.settings_publicSigningKey);
$key.append($pubLabel).append(UI.dialog.selectable(userHref)); $key.append($pubLabel).append(UI.dialog.selectable(userHref));
@ -270,8 +272,8 @@ define([
var sjson = JSON.stringify(data); var sjson = JSON.stringify(data);
var name = displayName || accountName || Messages.anonymous; var name = displayName || accountName || Messages.anonymous;
var suggestion = name + '-' + new Date().toDateString(); var suggestion = name + '-' + new Date().toDateString();
UI.prompt(Cryptpad.Messages.exportPrompt, UI.prompt(Messages.exportPrompt,
Cryptpad.fixFileName(suggestion) + '.json', function (filename) { Util.fixFileName(suggestion) + '.json', function (filename) {
if (!(typeof(filename) === 'string' && filename)) { return; } if (!(typeof(filename) === 'string' && filename)) { return; }
var blob = new Blob([sjson], {type: "application/json;charset=utf-8"}); var blob = new Blob([sjson], {type: "application/json;charset=utf-8"});
saveAs(blob, filename); saveAs(blob, filename);
@ -500,12 +502,6 @@ define([
sframeChan = common.getSframeChannel(); sframeChan = common.getSframeChannel();
sframeChan.onReady(waitFor()); sframeChan.onReady(waitFor());
}).nThen(function (/*waitFor*/) { }).nThen(function (/*waitFor*/) {
Cryptpad.onError(function (info) {
if (info && info.type === "store") {
onConnectError();
}
});
metadataMgr = common.getMetadataMgr(); metadataMgr = common.getMetadataMgr();
privateData = metadataMgr.getPrivateData(); privateData = metadataMgr.getPrivateData();

@ -7,6 +7,7 @@ define([
'/slide/slide.js', '/slide/slide.js',
'/common/sframe-app-framework.js', '/common/sframe-app-framework.js',
'/common/common-util.js', '/common/common-util.js',
'/common/common-hash.js',
'/common/common-interface.js', '/common/common-interface.js',
'cm/lib/codemirror', 'cm/lib/codemirror',
@ -49,6 +50,7 @@ define([
Slide, Slide,
Framework, Framework,
Util, Util,
Hash,
UI, UI,
CMeditor) CMeditor)
{ {
@ -438,8 +440,8 @@ define([
//var cursor = editor.getCursor(); //var cursor = editor.getCursor();
//var cleanName = data.name.replace(/[\[\]]/g, ''); //var cleanName = data.name.replace(/[\[\]]/g, '');
//var text = '!['+cleanName+']('+data.url+')'; //var text = '!['+cleanName+']('+data.url+')';
var parsed = Cryptpad.parsePadUrl(data.url); var parsed = Hash.parsePadUrl(data.url);
var hexFileName = Cryptpad.base64ToHex(parsed.hashData.channel); var hexFileName = Util.base64ToHex(parsed.hashData.channel);
var src = '/blob/' + hexFileName.slice(0,2) + '/' + hexFileName; var src = '/blob/' + hexFileName.slice(0,2) + '/' + hexFileName;
var mt = '<media-tag src="' + src + '" data-crypto-key="cryptpad:' + parsed.hashData.key + '"></media-tag>'; var mt = '<media-tag src="' + src + '" data-crypto-key="cryptpad:' + parsed.hashData.key + '"></media-tag>';
editor.replaceSelection(mt); editor.replaceSelection(mt);

@ -7,6 +7,7 @@ define([
'/bower_components/nthen/index.js', '/bower_components/nthen/index.js',
'/common/sframe-common.js', '/common/sframe-common.js',
'/common/common-interface.js', '/common/common-interface.js',
'/common/common-hash.js',
'/todo/todo.js', '/todo/todo.js',
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
@ -20,6 +21,7 @@ define([
Cryptpad, Cryptpad,
nThen, nThen,
SFCommon, SFCommon,
Hash,
UI, UI,
Todo Todo
) )
@ -165,7 +167,7 @@ define([
"mtime": +new Date() "mtime": +new Date()
}; };
var id = Cryptpad.createChannelId(); var id = Hash.createChannelId();
todo.add(id, obj); todo.add(id, obj);
$input.val(""); $input.val("");

@ -36,10 +36,10 @@ define([
}; };
window.addEventListener('message', onMsg); window.addEventListener('message', onMsg);
}).nThen(function (/*waitFor*/) { }).nThen(function (/*waitFor*/) {
var getSecrets = function (Cryptpad) { var getSecrets = function (Cryptpad, Utils) {
var proxy = Cryptpad.getProxy(); var proxy = Cryptpad.getProxy();
var hash = proxy.todo || Cryptpad.createRandomHash(); var hash = proxy.todo || Utils.Hash.createRandomHash();
return Cryptpad.getSecrets('todo', hash); return Utils.Hash.getSecrets('todo', hash);
}; };
SFCommonO.start({ SFCommonO.start({
getSecrets: getSecrets, getSecrets: getSecrets,

Loading…
Cancel
Save