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

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

@ -3,7 +3,9 @@ define([
'/bower_components/chainpad-crypto/crypto.js',
'/common/curve.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';
var Msg = {
inputs: [],
@ -149,7 +151,7 @@ define([
return;
}
var txid = common.uid();
var txid = Util.uid();
initRangeRequest(txid, curvePublic, hash, cb);
var msg = [ 'GET_HISTORY_RANGE', chan.id, {
from: hash,
@ -245,7 +247,7 @@ define([
if (!proxy.friends) { return; }
var friends = proxy.friends;
delete friends[curvePublic];
common.whenRealtimeSyncs(realtime, cb);
Realtime.whenRealtimeSyncs(realtime, cb);
};
var pushMsg = function (channel, cryptMsg) {
@ -352,7 +354,7 @@ define([
return cb();
};
var onDirectMessage = function (common, msg, sender) {
var onDirectMessage = function (msg, sender) {
if (sender !== Msg.hk) { return void onIdMessage(msg, sender); }
var parsed = JSON.parse(msg);
@ -443,7 +445,7 @@ define([
// listen for messages...
network.on('message', function(msg, sender) {
onDirectMessage(common, msg, sender);
onDirectMessage(msg, sender);
});
messenger.removeFriend = function (curvePublic, cb) {
@ -476,7 +478,7 @@ define([
channel.wc.bcast(cryptMsg).then(function () {
delete friends[curvePublic];
delete channels[curvePublic];
common.whenRealtimeSyncs(realtime, function () {
Realtime.whenRealtimeSyncs(realtime, function () {
cb();
});
}, 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',
'/common/cryptpad-common.js',
'/common/common-util.js',
'/common/common-hash.js',
'/common/common-language.js',
'/common/common-interface.js',
'/common/media-tag.js',
'css!/common/tippy.css',
], function ($, Config, Cryptpad, Util, Language, UI, MediaTag) {
], function ($, Config, Cryptpad, Util, Hash, Language, UI, MediaTag) {
var UIElements = {};
var Messages = Cryptpad.Messages;
/**
* Requirements from cryptpad-common.js
* getFileSize
* - hrefToHexChannelId
* displayAvatar
* - getFirstEmojiOrCharacter
* - parsePadUrl
* - getSecrets
* - base64ToHex
* - getBlobPathFromHex
* - bytesToMegabytes
*/
UIElements.updateTags = function (common, href) {
var sframeChan = common.getSframeChannel();
sframeChan.query('Q_TAGS_GET', href || null, function (err, res) {
@ -308,19 +296,19 @@ define([
if (cb) { cb(); }
};
if (!href) { return void displayDefault(); }
var parsed = Cryptpad.parsePadUrl(href);
var secret = Cryptpad.getSecrets('file', parsed.hash);
var parsed = Hash.parsePadUrl(href);
var secret = Hash.getSecrets('file', parsed.hash);
if (secret.keys && secret.channel) {
var cryptKey = secret.keys && secret.keys.fileKeyStr;
var hexFileName = Cryptpad.base64ToHex(secret.channel);
var src = Cryptpad.getBlobPathFromHex(hexFileName);
var hexFileName = Util.base64ToHex(secret.channel);
var src = Hash.getBlobPathFromHex(hexFileName);
Common.getFileSize(href, function (e, data) {
if (e) {
displayDefault();
return void console.error(e);
}
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);
$img.attr('src', src);
$img.attr('data-crypto-key', 'cryptpad:' + cryptKey);
@ -356,7 +344,7 @@ define([
// so we can just use those and only check for errors
var $container = $('<span>', {'class':'cp-limit-container'});
var todo;
var updateUsage = Cryptpad.notAgainForAnother(function () {
var updateUsage = Util.notAgainForAnother(function () {
common.getPinUsage(todo);
}, LIMIT_REFRESH_RATE);

@ -89,22 +89,6 @@ define([], function () {
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
*/
@ -186,13 +170,6 @@ define([], function () {
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 */
Util.once = function (f) {
var called;

@ -3,8 +3,11 @@ define([
'/bower_components/chainpad-crypto/crypto.js',
'/bower_components/chainpad-netflux/chainpad-netflux.js',
'/common/cryptpad-common.js',
'/common/common-util.js',
'/common/common-hash.js',
'/common/common-realtime.js',
'/bower_components/textpatcher/TextPatcher.js'
], function ($, Crypto, Realtime, Cryptpad, TextPatcher) {
], function ($, Crypto, CPNetflux, Cryptpad, Util, Hash, Realtime, TextPatcher) {
//var Messages = Cryptpad.Messages;
//var noop = function () {};
var finish = function (S, err, doc) {
@ -12,9 +15,9 @@ define([
S.cb(err, doc);
S.done = true;
var disconnect = Cryptpad.find(S, ['network', 'disconnect']);
var disconnect = Util.find(S, ['network', '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') {
S.realtime.realtime.sync();
abort();
@ -23,7 +26,7 @@ define([
var makeConfig = function (hash) {
// 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
var config = {
websocketURL: Cryptpad.getWebsocketURL(),
@ -58,7 +61,7 @@ define([
};
overwrite(config, opt);
Session.realtime = Realtime.start(config);
Session.realtime = CPNetflux.start(config);
};
var put = function (hash, doc, cb, opt) {
@ -80,7 +83,7 @@ define([
cb(new Error("Timeout"));
}, 5000);
Cryptpad.whenRealtimeSyncs(realtime, function () {
Realtime.whenRealtimeSyncs(realtime, function () {
window.clearTimeout(to);
realtime.abort();
finish(Session, void 0);
@ -88,7 +91,7 @@ define([
};
overwrite(config, opt);
Session.session = Realtime.start(config);
Session.session = CPNetflux.start(config);
};
return {

@ -58,44 +58,44 @@ define([
var anon_rpc;
// import common utilities for export
common.find = Util.find;
common.hexToBase64 = Util.hexToBase64;
common.base64ToHex = Util.base64ToHex;
var deduplicateString = common.deduplicateString = Util.deduplicateString;
common.uint8ArrayToHex = Util.uint8ArrayToHex;
common.replaceHash = Util.replaceHash;
common.getHash = Util.getHash;
common.fixFileName = Util.fixFileName;
common.bytesToMegabytes = Util.bytesToMegabytes;
common.bytesToKilobytes = Util.bytesToKilobytes;
common.fetch = Util.fetch;
common.throttle = Util.throttle;
common.createRandomInteger = Util.createRandomInteger;
common.getAppType = Util.getAppType;
common.notAgainForAnother = Util.notAgainForAnother;
common.uid = Util.uid;
common.slice = Util.slice;
//common.find = Util.find;
//common.hexToBase64 = Util.hexToBase64;
//common.base64ToHex = Util.base64ToHex;
//var deduplicateString = common.deduplicateString = Util.deduplicateString;
//common.uint8ArrayToHex = Util.uint8ArrayToHex;
//common.replaceHash = Util.replaceHash;
//common.getHash = Util.getHash;
//common.fixFileName = Util.fixFileName;
//common.bytesToMegabytes = Util.bytesToMegabytes;
//common.bytesToKilobytes = Util.bytesToKilobytes;
//common.fetch = Util.fetch;
//common.throttle = Util.throttle;
//common.createRandomInteger = Util.createRandomInteger;
//common.getAppType = Util.getAppType;
//common.notAgainForAnother = Util.notAgainForAnother;
//common.uid = Util.uid;
//common.slice = Util.slice;
// import hash utilities for export
var createRandomHash = common.createRandomHash = Hash.createRandomHash;
common.parseTypeHash = Hash.parseTypeHash;
var parsePadUrl = common.parsePadUrl = Hash.parsePadUrl;
common.isNotStrongestStored = Hash.isNotStrongestStored;
var hrefToHexChannelId = common.hrefToHexChannelId = Hash.hrefToHexChannelId;
var getRelativeHref = common.getRelativeHref = Hash.getRelativeHref;
common.getBlobPathFromHex = Hash.getBlobPathFromHex;
common.getEditHashFromKeys = Hash.getEditHashFromKeys;
common.getViewHashFromKeys = Hash.getViewHashFromKeys;
common.getFileHashFromKeys = Hash.getFileHashFromKeys;
common.getUserHrefFromKeys = Hash.getUserHrefFromKeys;
common.getSecrets = Hash.getSecrets;
common.getHashes = Hash.getHashes;
common.createChannelId = Hash.createChannelId;
common.findWeaker = Hash.findWeaker;
common.findStronger = Hash.findStronger;
common.serializeHash = Hash.serializeHash;
common.createInviteUrl = Hash.createInviteUrl;
//var createRandomHash = common.createRandomHash = Hash.createRandomHash;
//common.parseTypeHash = Hash.parseTypeHash;
//var parsePadUrl = common.parsePadUrl = Hash.parsePadUrl;
//common.isNotStrongestStored = Hash.isNotStrongestStored;
//var hrefToHexChannelId = common.hrefToHexChannelId = Hash.hrefToHexChannelId;
//var getRelativeHref = common.getRelativeHref = Hash.getRelativeHref;
//common.getBlobPathFromHex = Hash.getBlobPathFromHex;
//common.getEditHashFromKeys = Hash.getEditHashFromKeys;
//common.getViewHashFromKeys = Hash.getViewHashFromKeys;
//common.getFileHashFromKeys = Hash.getFileHashFromKeys;
//common.getUserHrefFromKeys = Hash.getUserHrefFromKeys;
//common.getSecrets = Hash.getSecrets;
//common.getHashes = Hash.getHashes;
//common.createChannelId = Hash.createChannelId;
//common.findWeaker = Hash.findWeaker;
//common.findStronger = Hash.findStronger;
//common.serializeHash = Hash.serializeHash;
//common.createInviteUrl = Hash.createInviteUrl;
// Messaging
common.addDirectMessageHandler = Messaging.addDirectMessageHandler;
@ -107,10 +107,10 @@ define([
common.getLatestMessages = Messaging.getLatestMessages;
// Realtime
// REFACTOR: common is not needed anymore so we should just pull common-reealtime directly
var whenRealtimeSyncs = common.whenRealtimeSyncs = function (realtime, cb) {
Realtime.whenRealtimeSyncs(common, realtime, cb);
};
common.beginDetectingInfiniteSpinner = function (realtime) {
Realtime.beginDetectingInfiniteSpinner(common, realtime);
};
@ -137,12 +137,16 @@ define([
}
return;
};
// REFACTOR pull language directly
common.getLanguage = function () {
return Messages._languageUsed;
};
common.setLanguage = function (l, cb) {
Language.setLanguage(l, null, cb);
};
// REAFCTOR store.getProfile should be store.get(['profile'])
common.getProfileUrl = function () {
if (store && store.getProfile()) {
return store.getProfile().view;
@ -166,13 +170,14 @@ define([
return localStorage[common.userNameKey];
};
// REFACTOR: move to util?
var randomToken = function () {
return Math.random().toString(16).replace(/0./, '');
};
common.isFeedbackAllowed = function () {
try {
var entry = common.find(getProxy(), [
var entry = Util.find(getProxy(), [
'settings',
'general',
'allowUserFeedback'
@ -246,7 +251,7 @@ define([
common.login = function (hash, name, cb) {
if (!hash) { throw new Error('expected a user hash'); }
if (!name) { throw new Error('expected a user name'); }
hash = common.serializeHash(hash);
hash = Hash.serializeHash(hash);
localStorage.setItem(userHashKey, hash);
localStorage.setItem(userNameKey, name);
if (cb) { cb(); }
@ -283,7 +288,7 @@ define([
// 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
if (!localStorage[fileHashKey]) {
localStorage[fileHashKey] = common.createRandomHash();
localStorage[fileHashKey] = Hash.createRandomHash();
}
eraseTempSessionValues();
@ -308,7 +313,7 @@ define([
}
if (hash) {
var sHash = common.serializeHash(hash);
var sHash = Hash.serializeHash(hash);
if (sHash !== hash) { localStorage[userHashKey] = sHash; }
}
@ -357,9 +362,9 @@ define([
var checkObjectData = function (pad, cb) {
if (!pad.ctime) { pad.ctime = pad.atime; }
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 (typeof(cb) === 'function') {
cb(parsed);
@ -369,28 +374,6 @@ define([
}
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
var checkRecentPads = common.checkRecentPads = function (pads) {
Object.keys(pads).forEach(function (id, i) {
@ -410,7 +393,7 @@ define([
};
// Create untitled documents when no name is given
var getLocaleDate = common.getLocaleDate = function () {
var getLocaleDate = function () {
if (window.Intl && window.Intl.DateTimeFormat) {
var options = {weekday: "short", year: "numeric", month: "long", day: "numeric"};
return new window.Intl.DateTimeFormat(undefined, options).format(new Date());
@ -433,18 +416,13 @@ define([
href: href,
atime: 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
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);
};
common.setDisplayName = function (value, cb) {
@ -464,7 +442,7 @@ define([
// STORAGE
common.getPadAttribute = function (attr, cb) {
var href = getRelativeHref(window.location.href);
var href = Hash.getRelativeHref(window.location.href);
getStore().getPadAttribute(href, attr, cb);
};
common.getAttribute = function (attr, cb) {
@ -492,7 +470,7 @@ define([
href = href || (window.location.pathname + window.location.hash);
var id = store.getIdFromHref(href);
if (!id) { return void cb('NO_ID'); }
var entry = common.find(getProxy(), [
var entry = Util.find(getProxy(), [
'drive',
'filesData',
id
@ -558,7 +536,7 @@ define([
common.listAllTags = function (cb) {
var all = [];
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'); }
Object.keys(files).forEach(function (k) {
@ -583,7 +561,7 @@ define([
if (!type) { return allTemplates; }
var templates = allTemplates.filter(function (f) {
var parsed = parsePadUrl(f.href);
var parsed = Hash.parsePadUrl(f.href);
return parsed.type === type;
});
return templates;
@ -596,7 +574,7 @@ define([
};
common.isTemplate = function (href) {
var rhref = getRelativeHref(href);
var rhref = Hash.getRelativeHref(href);
var templates = listTemplates();
return templates.some(function (t) {
return t.href === rhref;
@ -605,11 +583,11 @@ define([
// Secure iframes
common.useTemplate = function (href, Crypt, cb) {
var parsed = parsePadUrl(href);
var parsed = Hash.parsePadUrl(href);
if(!parsed) { throw new Error("Cannot get template hash"); }
Crypt.get(parsed.hash, function (err, val) {
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);
});
};
@ -649,7 +627,7 @@ define([
// STORAGE
common.forgetPad = function (href, cb) {
if (typeof(getStore().forgetPad) === "function") {
getStore().forgetPad(common.getRelativeHref(href), cb);
getStore().forgetPad(Hash.getRelativeHref(href), cb);
return;
}
cb ("store.forgetPad is not a function");
@ -657,10 +635,10 @@ define([
common.setPadTitle = function (name, padHref, cb) {
var href = typeof padHref === "string" ? padHref : window.location.href;
var parsed = parsePadUrl(href);
var parsed = Hash.parsePadUrl(href);
if (!parsed.hash) { return; }
href = parsed.getUrl({present: parsed.present});
//href = getRelativeHref(href);
//href = Hash.getRelativeHref(href);
// 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
getRecentPads(function (err, recent) {
@ -673,7 +651,7 @@ define([
var contains;
Object.keys(recent).forEach(function (id) {
var pad = recent[id];
var p = parsePadUrl(pad.href);
var p = Hash.parsePadUrl(pad.href);
if (p.type !== parsed.type) { return pad; }
@ -759,7 +737,7 @@ define([
if (title === null) { return; }
if (title.trim() === "") {
var parsed = parsePadUrl(href || window.location.href);
var parsed = Hash.parsePadUrl(href || window.location.href);
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
common.getSecureFilesList = function (query, cb) {
var store = common.getStore();
@ -813,7 +775,7 @@ define([
};
fo.getFiles(where).forEach(function (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)
&& hashes.indexOf(parsed.hash) === -1) {
if (isFiltered(parsed.type, data)) { return; }
@ -833,21 +795,21 @@ define([
var userHash = localStorage && localStorage.User_hash;
if (!userHash) { return null; }
var userParsedHash = common.parseTypeHash('drive', userHash);
var userParsedHash = Hash.parseTypeHash('drive', userHash);
var userChannel = userParsedHash && userParsedHash.channel;
if (!userChannel) { return null; }
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; });
// Get the avatar
var profile = store.getProfile();
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); }
var avatarChan = profile.avatar ? hrefToHexChannelId(profile.avatar) : null;
var avatarChan = profile.avatar ? Hash.hrefToHexChannelId(profile.avatar) : null;
if (avatarChan) { list.push(avatarChan); }
}
@ -856,14 +818,14 @@ define([
list = list.concat(fList);
}
list.push(common.base64ToHex(userChannel));
list.push(Util.base64ToHex(userChannel));
list.sort();
return list;
};
var getCanonicalChannelList = common.getCanonicalChannelList = function () {
return deduplicateString(getUserChannelList()).sort();
return Util.deduplicateString(getUserChannelList()).sort();
};
var pinsReady = common.pinsReady = function () {
@ -1042,100 +1004,6 @@ define([
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
// TODO REFACTOR only used in sframe-common-outer
common.moveToTrash = function (cb, href) {
@ -1159,11 +1027,12 @@ define([
}
});
};
// TODO REFACTOR only used in sframe-common-outer
common.saveAsTemplate = function (Cryptput, data, cb) {
var p = parsePadUrl(window.location.href);
var p = Hash.parsePadUrl(window.location.href);
if (!p.type) { return; }
var hash = createRandomHash();
var hash = Hash.createRandomHash();
var href = '/' + p.type + '/#' + hash;
Cryptput(hash, data.toSave, function (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) {
var decrypted = e.originalEvent;
if (decrypted.callback) {
@ -1218,7 +1070,7 @@ define([
size = decrypted.blob.size;
}
var sizeMb = common.bytesToMegabytes(size);
var sizeMb = Util.bytesToMegabytes(size);
var $btn = $(root).find('button');
$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) {
if (!window.location.hash) {
var hashes = common.getHashes(secret.channel, secret);
var hashes = Hash.getHashes(secret.channel, secret);
return void cb(null, hashes);
}
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 === '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) {
// 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
var stronger = recent && common.findStronger(null, recent);
var stronger = recent && Hash.findStronger(null, recent);
if (stronger) {
var parsed2 = parsePadUrl(stronger);
var parsed2 = Hash.parsePadUrl(stronger);
hashes.editHash = parsed2.hash;
}
@ -1357,8 +1203,8 @@ define([
var oldHref = document.location.href;
window.onhashchange = function () {
var newHref = document.location.href;
var parsedOld = parsePadUrl(oldHref).hashData;
var parsedNew = parsePadUrl(newHref).hashData;
var parsedOld = Hash.parsePadUrl(oldHref).hashData;
var parsedNew = Hash.parsePadUrl(newHref).hashData;
if (parsedOld && parsedNew && (
parsedOld.type !== parsedNew.type
|| parsedOld.channel !== parsedNew.channel
@ -1438,7 +1284,7 @@ define([
if (sessionStorage.createReadme) {
var w = waitFor();
require(['/common/cryptget.js'], function (Crypt) {
var hash = common.createRandomHash();
var hash = Hash.createRandomHash();
Crypt.put(hash, Messages.driveReadme, function (e) {
if (e) {
console.error("Error while creating the default pad:", e);

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

File diff suppressed because it is too large Load Diff

@ -5,8 +5,9 @@ define([
'/bower_components/textpatcher/TextPatcher.amd.js',
'/common/userObject.js',
'/common/common-interface.js',
'/common/common-hash.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
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) {
// even anonymous users should have a persistent, unique-ish id
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...
@ -285,11 +286,11 @@ define([
if (!Cryptpad || initialized) { return; }
initialized = true;
var hash = Cryptpad.getUserHash() || localStorage.FS_hash || Cryptpad.createRandomHash();
var hash = Cryptpad.getUserHash() || localStorage.FS_hash || Hash.createRandomHash();
if (!hash) {
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 = {
data: {},
websocketURL: Cryptpad.getWebsocketURL(),
@ -332,7 +333,7 @@ define([
rt.proxy.on('create', function (info) {
exp.info = info;
if (!Cryptpad.getUserHash()) {
localStorage.FS_hash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys);
localStorage.FS_hash = Hash.getEditHashFromKeys(info.channel, secret.keys);
}
}).on('ready', function () {
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-crypto/crypto.js',
'/common/cryptpad-common.js',
'/common/common-util.js',
'/common/credential.js',
'/bower_components/tweetnacl/nacl-fast.min.js',
'/bower_components/scrypt-async/scrypt-async.min.js', // better load speed
], function ($, Listmap, Crypto, Cryptpad, Cred) {
], function ($, Listmap, Crypto, Cryptpad, Util, Cred) {
var Exports = {
Cred: Cred,
};
@ -43,12 +44,12 @@ define([
keys.editKeyStr = keys.editKeyStr.replace(/\//g, '-');
// 32 bytes of hex
var channelHex = opt.channelHex = Cryptpad.uint8ArrayToHex(channelSeed);
var channelHex = opt.channelHex = Util.uint8ArrayToHex(channelSeed);
// should never happen
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('/');

@ -2,7 +2,8 @@ define([
'/common/cryptpad-common.js',
'/common/cryptget.js',
'/common/userObject.js',
], function (Cryptpad, Crypt, FO) {
'/common/common-hash.js',
], function (Cryptpad, Crypt, FO, Hash) {
var exp = {};
var getType = function (el) {
@ -41,7 +42,7 @@ define([
if (typeof(p) === "string") {
if (getType(root) !== "object") { root = undefined; error(); return; }
if (i === path.length - 1) {
root[Cryptpad.createChannelId()] = id;
root[Hash.createChannelId()] = id;
return;
}
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
if (newHrefs.indexOf(href) !== -1) { return; }
// 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
// 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) {
// Update RECENTPADS
newRecentPads.some(function (pad) {

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

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

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

@ -19,6 +19,7 @@ define([
var FilePicker;
var Messenger;
var Notifier;
var Utils = {};
nThen(function (waitFor) {
// Load #2, the loading screen is up so grab whatever you need...
@ -31,8 +32,11 @@ define([
'/filepicker/main.js',
'/common/common-messenger.js',
'/common/common-notifier.js',
'/common/common-hash.js',
'/common/common-util.js',
'/common/common-realtime.js',
], waitFor(function (_CpNfOuter, _Cryptpad, _Crypto, _Cryptget, SFrameChannel,
_FilePicker, _Messenger, _Notifier) {
_FilePicker, _Messenger, _Notifier, _Hash, _Util, _Realtime) {
CpNfOuter = _CpNfOuter;
Cryptpad = _Cryptpad;
Crypto = _Crypto;
@ -40,6 +44,9 @@ define([
FilePicker = _FilePicker;
Messenger = _Messenger;
Notifier = _Notifier;
Utils.Hash = _Hash;
Utils.Util = _Util;
Utils.Realtime = _Realtime;
if (localStorage.CRYPTPAD_URLARGS !== ApiConfig.requireConf.urlArgs) {
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) {
// 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; }));
}).nThen(function () {
var readOnly = secret.keys && !secret.keys.editKeyStr;
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(); }
var defaultTitle = Cryptpad.getDefaultName(parsed);
var proxy = Cryptpad.getProxy();
@ -335,11 +342,11 @@ define([
// Present mode URL
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);
});
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({
embed: parsed.hashData.embed,
present: data
@ -463,7 +470,7 @@ define([
});
if (cfg.addRpc) {
cfg.addRpc(sframeChan, Cryptpad);
cfg.addRpc(sframeChan, Cryptpad, Utils);
}
if (cfg.messaging) {
@ -580,6 +587,18 @@ define([
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({
sframeChan: sframeChan,
channel: secret.channel,
@ -596,7 +615,7 @@ define([
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',
'/customize/application_config.js',
'/common/cryptpad-common.js',
'/common/common-realtime.js',
'/common/common-util.js',
'/common/common-hash.js',
'/common/common-thumbnail.js',
'/common/common-interface.js',
'/bower_components/localforage/dist/localforage.min.js'
@ -31,9 +31,9 @@ define([
CodeMirror,
MetadataMgr,
AppConfig,
Cryptpad,
CommonRealtime,
Util,
Hash,
Thumb,
UI,
localForage
@ -57,7 +57,6 @@ define([
};
funcs.getMetadataMgr = function () { return ctx.metadataMgr; };
funcs.getCryptpadCommon = function () { return Cryptpad; };
funcs.getSframeChannel = function () { return ctx.sframeChan; };
funcs.getAppConfig = function () { return AppConfig; };
@ -104,21 +103,21 @@ define([
return '<script src="' + origin + '/common/media-tag-nacl.min.js"></script>';
};
funcs.getMediatagFromHref = function (href) {
var parsed = Cryptpad.parsePadUrl(href);
var secret = Cryptpad.getSecrets('file', parsed.hash);
var parsed = Hash.parsePadUrl(href);
var secret = Hash.getSecrets('file', parsed.hash);
var data = ctx.metadataMgr.getPrivateData();
if (secret.keys && secret.channel) {
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 src = origin + Cryptpad.getBlobPathFromHex(hexFileName);
var src = origin + Hash.getBlobPathFromHex(hexFileName);
return '<media-tag src="' + src + '" data-crypto-key="cryptpad:' + cryptKey + '">' +
'</media-tag>';
}
return;
};
funcs.getFileSize = function (href, cb) {
var channelId = Cryptpad.hrefToHexChannelId(href);
var channelId = Hash.hrefToHexChannelId(href);
funcs.sendAnonRpcMsg("GET_FILE_SIZE", channelId, function (data) {
if (!data) { return void cb("No response"); }
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',
'/api/config',
'/common/common-ui-elements.js',
'/common/common-interface.js'
], function ($, Config, ApiConfig, UIElements, UI) {
var Messages = {};
var Cryptpad;
'/common/common-interface.js',
'/common/common-hash.js',
'/customize/messages.js',
'/common/clipboard.js',
], function ($, Config, ApiConfig, UIElements, UI, Hash, Messages, Clipboard) {
var Common;
var Bar = {
@ -439,7 +440,7 @@ define([
if (!err) { UI.log(Messages.shareSuccess); }
});*/
var url = origin + pathname + '#' + hashes.editHash;
var success = Cryptpad.Clipboard.copy(url);
var success = Clipboard.copy(url);
if (success) { UI.log(Messages.shareSuccess); }
});
}
@ -449,12 +450,12 @@ define([
if (!err) { UI.log(Messages.shareSuccess); }
});*/
var url = origin + pathname + '#' + hashes.viewHash;
var success = Cryptpad.Clipboard.copy(url);
var success = Clipboard.copy(url);
if (success) { UI.log(Messages.shareSuccess); }
});
$shareBlock.find('a.cp-toolbar-share-view-embed').click(function () {
var url = origin + pathname + '#' + hashes.viewHash;
var parsed = Cryptpad.parsePadUrl(url);
var parsed = Hash.parsePadUrl(url);
url = origin + parsed.getUrl({embed: true, present: true});
// Alertify content
var $content = $('<div>');
@ -474,7 +475,7 @@ define([
$('#'+iframeId).click(function () {
this.select();
});
//var success = Cryptpad.Clipboard.copy(url);
//var success = Clipboard.copy(url);
//if (success) { UI.log(Messages.shareSuccess); }
});
}
@ -520,7 +521,7 @@ define([
// Add handlers
$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); }
});
$shareBlock.find('a.cp-toolbar-share-file-embed').click(function () {
@ -570,8 +571,8 @@ define([
if (config.readOnly === 1) {
$titleContainer.append($('<span>', {'class': 'cp-toolbar-title-readonly'})
.text('('+Messages.readonly+')'));
return $titleContainer;
}
if (config.readOnly === 1 || typeof(Cryptpad) === "undefined") { return $titleContainer; }
var $input = $('<input>', {
type: 'text',
placeholder: placeholder
@ -842,7 +843,6 @@ define([
console.error(err);
return;
}
//Cryptpad.changeDisplayName(newName, true); Already done?
});
});
});
@ -894,90 +894,88 @@ define([
if (!config.metadataMgr) { return; }
var metadataMgr = config.metadataMgr;
var userNetfluxId = metadataMgr.getNetfluxId();
if (typeof Cryptpad !== "undefined") {
var notify = function(type, name, oldname) {
// type : 1 (+1 user), 0 (rename existing user), -1 (-1 user)
if (typeof name === "undefined") { return; }
name = name || Messages.anonymous;
if (Config.disableUserlistNotifications) { return; }
switch(type) {
case 1:
UI.log(Messages._getKey("notifyJoined", [name]));
break;
case 0:
oldname = (!oldname) ? Messages.anonymous : oldname;
UI.log(Messages._getKey("notifyRenamed", [oldname, name]));
break;
case -1:
UI.log(Messages._getKey("notifyLeft", [name]));
break;
default:
console.log("Invalid type of notification");
break;
}
};
var notify = function(type, name, oldname) {
// type : 1 (+1 user), 0 (rename existing user), -1 (-1 user)
if (typeof name === "undefined") { return; }
name = name || Messages.anonymous;
if (Config.disableUserlistNotifications) { return; }
switch(type) {
case 1:
UI.log(Messages._getKey("notifyJoined", [name]));
break;
case 0:
oldname = (!oldname) ? Messages.anonymous : oldname;
UI.log(Messages._getKey("notifyRenamed", [oldname, name]));
break;
case -1:
UI.log(Messages._getKey("notifyLeft", [name]));
break;
default:
console.log("Invalid type of notification");
break;
}
};
var userPresent = function (id, user, data) {
if (!(user && user.uid)) {
console.log('no uid');
return 0;
}
if (!data) {
console.log('no data');
return 0;
}
var userPresent = function (id, user, data) {
if (!(user && user.uid)) {
console.log('no uid');
return 0;
}
if (!data) {
console.log('no data');
return 0;
}
var count = 0;
Object.keys(data).forEach(function (k) {
if (data[k] && data[k].uid === user.uid) { count++; }
});
return count;
};
var count = 0;
Object.keys(data).forEach(function (k) {
if (data[k] && data[k].uid === user.uid) { count++; }
});
return count;
};
var joined = false;
metadataMgr.onChange(function () {
var newdata = metadataMgr.getMetadata().users;
var netfluxIds = Object.keys(newdata);
// Notify for disconnected users
if (typeof oldUserData !== "undefined") {
for (var u in oldUserData) {
// if a user's uid is still present after having left, don't notify
if (netfluxIds.indexOf(u) === -1) {
var temp = JSON.parse(JSON.stringify(oldUserData[u]));
delete oldUserData[u];
if (temp && newdata[userNetfluxId] && temp.uid === newdata[userNetfluxId].uid) { return; }
if (userPresent(u, temp, newdata || oldUserData) < 1) {
notify(-1, temp.name);
}
var joined = false;
metadataMgr.onChange(function () {
var newdata = metadataMgr.getMetadata().users;
var netfluxIds = Object.keys(newdata);
// Notify for disconnected users
if (typeof oldUserData !== "undefined") {
for (var u in oldUserData) {
// if a user's uid is still present after having left, don't notify
if (netfluxIds.indexOf(u) === -1) {
var temp = JSON.parse(JSON.stringify(oldUserData[u]));
delete oldUserData[u];
if (temp && newdata[userNetfluxId] && temp.uid === newdata[userNetfluxId].uid) { return; }
if (userPresent(u, temp, newdata || oldUserData) < 1) {
notify(-1, temp.name);
}
}
}
// Update the "oldUserData" object and notify for new users and names changed
if (typeof newdata === "undefined") { return; }
if (typeof oldUserData === "undefined") {
oldUserData = JSON.parse(JSON.stringify(newdata));
return;
}
if (config.readOnly === 0 && !oldUserData[userNetfluxId]) {
oldUserData = JSON.parse(JSON.stringify(newdata));
return;
}
for (var k in newdata) {
if (joined && k !== userNetfluxId && netfluxIds.indexOf(k) !== -1) {
if (typeof oldUserData[k] === "undefined") {
// if the same uid is already present in the userdata, don't notify
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);
}
// Update the "oldUserData" object and notify for new users and names changed
if (typeof newdata === "undefined") { return; }
if (typeof oldUserData === "undefined") {
oldUserData = JSON.parse(JSON.stringify(newdata));
return;
}
if (config.readOnly === 0 && !oldUserData[userNetfluxId]) {
oldUserData = JSON.parse(JSON.stringify(newdata));
return;
}
for (var k in newdata) {
if (joined && k !== userNetfluxId && netfluxIds.indexOf(k) !== -1) {
if (typeof oldUserData[k] === "undefined") {
// if the same uid is already present in the userdata, don't notify
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);
}
}
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) {
var config = cfg || {};
Cryptpad = config.common;
Common = config.sfCommon;
Messages = Cryptpad.Messages;
config.readOnly = (typeof config.readOnly !== "undefined") ? (config.readOnly ? 1 : 0) : -1;
config.displayed = config.displayed || [];
@ -1042,7 +1038,7 @@ define([
initClickEvents(toolbar, config);
initNotifications(toolbar, config);
var failed = toolbar.failed = function () {
toolbar.failed = function () {
toolbar.connected = false;
if (toolbar.spinner) {
@ -1083,11 +1079,12 @@ define([
};
// On log out, remove permanently the realtime elements of the toolbar
Cryptpad.onLogout(function () {
// TODO
/*Common.onLogout(function () {
failed();
if (toolbar.useradmin) { toolbar.useradmin.hide(); }
if (toolbar.userlist) { toolbar.userlist.hide(); }
});
});*/
return toolbar;
};

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

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

@ -38,9 +38,9 @@ define([
};
window.addEventListener('message', onMsg);
}).nThen(function (/*waitFor*/) {
var getSecrets = function (Cryptpad) {
var getSecrets = function (Cryptpad, Utils) {
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) {
SFCommonO.start({

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

@ -8,6 +8,8 @@ define([
'/common/sframe-common.js',
'/common/common-interface.js',
'/common/common-ui-elements.js',
'/common/common-util.js',
'/common/common-hash.js',
'json.sortify',
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
@ -23,6 +25,8 @@ define([
SFCommon,
UI,
UIElements,
Util,
Hash,
Sortify)
{
var Messages = Cryptpad.Messages;
@ -45,10 +49,10 @@ define([
sframeChan.event('EV_FILE_PICKER_CLOSE');
};
var onFilePicked = function (data) {
var parsed = Cryptpad.parsePadUrl(data.url);
var parsed = Hash.parsePadUrl(data.url);
hideFileDialog();
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;
sframeChan.event("EV_FILE_PICKED", {
type: parsed.type,

@ -2,10 +2,11 @@ define([
'jquery',
'/common/cryptpad-common.js',
'/common/common-interface.js',
//'/common/common-hash.js',
//'/bower_components/chainpad-listmap/chainpad-listmap.js',
//'/common/curve.js',
'less!/invite/main.less',
], function ($, Cryptpad, UI /*, Listmap, Curve*/) {
], function ($, Cryptpad, UI/*, Hash , Listmap, Curve*/) {
var Messages = Cryptpad.Messages;
var comingSoon = function () {
return $('<div>', {
@ -34,7 +35,7 @@ define([
var andThen = function () {
var hash = window.location.hash.slice(1);
var info = Cryptpad.parseTypeHash('invite', hash);
var info = Hash.parseTypeHash('invite', hash);
console.log(info);
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,
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;
@ -119,7 +119,7 @@ define([
var csv = getCSV();
var suggestion = Title.suggestTitle(Title.defaultTitle);
UI.prompt(Messages.exportPrompt,
Cryptpad.fixFileName(suggestion) + '.csv', function (filename) {
Util.fixFileName(suggestion) + '.csv', function (filename) {
if (!(typeof(filename) === 'string' && filename)) { return; }
var blob = new Blob([csv], {type: "application/csv;charset=utf-8"});
saveAs(blob, filename);

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

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

@ -4,7 +4,7 @@ define([
'/api/config',
'jquery',
'/common/requireconfig.js',
'/common/sframe-common-outer.js'
'/common/sframe-common-outer.js',
], function (nThen, ApiConfig, $, RequireConfig, SFCommonO) {
var requireConfig = RequireConfig();
@ -36,20 +36,21 @@ define([
};
window.addEventListener('message', onMsg);
}).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
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
var obj = Cryptpad.getProxy();
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)
if (!Cryptpad.isLoggedIn()) { return; }
var hash = Cryptpad.createRandomHash();
var secret = Cryptpad.getSecrets('profile', hash);
var hash = Hash.createRandomHash();
var secret = Hash.getSecrets('profile', hash);
Cryptpad.pinPads([secret.channel], function (e) {
if (e) {
if (e === 'E_OVER_LIMIT') {
@ -59,26 +60,26 @@ define([
//return void UI.log(Messages._getKey('profile_error', [e])) // TODO
}
obj.profile = {};
obj.profile.edit = Cryptpad.getEditHashFromKeys(secret.channel, secret.keys);
obj.profile.view = Cryptpad.getViewHashFromKeys(secret.channel, secret.keys);
obj.profile.edit = Utils.Hash.getEditHashFromKeys(secret.channel, secret.keys);
obj.profile.view = Utils.Hash.getViewHashFromKeys(secret.channel, secret.keys);
});
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
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) {
if (e) { return void cb(e); }
Cryptpad.getProxy().profile.avatar = data;
Cryptpad.whenRealtimeSyncs(Cryptpad.getRealtime(), function () {
Utils.Realtime.whenRealtimeSyncs(Cryptpad.getRealtime(), function () {
cb();
});
});
});
// Removing the avatar from the profile: unpin it
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) {
delete Cryptpad.getProxy().profile.avatar;
cb(e);

@ -5,9 +5,10 @@ define([
'/common/test.js',
'/common/credential.js', // preloaded for login.js
'/common/common-interface.js',
'/common/common-util.js',
'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;
$(function () {
@ -215,7 +216,7 @@ define([
}, 150);
});
var clickRegister = Cryptpad.notAgainForAnother(function () {
var clickRegister = Util.notAgainForAnother(function () {
$register.click();
}, 500);

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

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

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

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

Loading…
Cancel
Save