diff --git a/www/assert/main.js b/www/assert/main.js index 3eb9e5892..38e70e2fa 100644 --- a/www/assert/main.js +++ b/www/assert/main.js @@ -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=" && diff --git a/www/code/inner.js b/www/code/inner.js index 5f2cf3df1..9c467ffa8 100644 --- a/www/code/inner.js +++ b/www/code/inner.js @@ -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 = ''; editor.replaceSelection(mt); diff --git a/www/common/common-messenger.js b/www/common/common-messenger.js index 476e60b52..d8975420a 100644 --- a/www/common/common-messenger.js +++ b/www/common/common-messenger.js @@ -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) { diff --git a/www/common/common-metadata.js b/www/common/common-metadata.js deleted file mode 100644 index 99115fac6..000000000 --- a/www/common/common-metadata.js +++ /dev/null @@ -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; -}); - - diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 235cf693a..e926ebb59 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -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 = $('').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 = $('', {'class':'cp-limit-container'}); var todo; - var updateUsage = Cryptpad.notAgainForAnother(function () { + var updateUsage = Util.notAgainForAnother(function () { common.getPinUsage(todo); }, LIMIT_REFRESH_RATE); diff --git a/www/common/common-util.js b/www/common/common-util.js index 5b2b6e84e..421dd9c1e 100644 --- a/www/common/common-util.js +++ b/www/common/common-util.js @@ -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; diff --git a/www/common/cryptget.js b/www/common/cryptget.js index cde78d298..f900eafb2 100644 --- a/www/common/cryptget.js +++ b/www/common/cryptget.js @@ -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 { diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index e68d92b88..faf6577e5 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -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 = $('', {'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 = $('', {'class': 'cryptpad-limit-bar'}).appendTo($container); - var quota = usage/limit; - var $usage = $('', {'class': 'usage'}).css('width', quota*100+'%'); - - var makeDonateButton = function () { - $('', { - 'class': 'upgrade btn btn-success', - href: common.donateURL, - rel: "noreferrer noopener", - target: "_blank", - }).text(Messages.supportCryptpad).appendTo($container); - }; - - var makeUpgradeButton = function () { - $('', { - '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 = $('', {'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 ''; - }; - 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 '' + - ''; - } - 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); diff --git a/www/common/diffMarked.js b/www/common/diffMarked.js index abd5248ec..252ffe2c5 100644 --- a/www/common/diffMarked.js +++ b/www/common/diffMarked.js @@ -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 = ''; if (mediaMap[src]) { diff --git a/www/common/fileObject.js b/www/common/fileObject.js deleted file mode 100644 index f8988956b..000000000 --- a/www/common/fileObject.js +++ /dev/null @@ -1,1179 +0,0 @@ -define([ - 'jquery', -], function ($) { - var module = {}; - - var Messages = {}; - - var ROOT = module.ROOT = "root"; - var UNSORTED = module.UNSORTED = "unsorted"; - var TRASH = module.TRASH = "trash"; - var TEMPLATE = module.TEMPLATE = "template"; - - module.init = function (files, config) { - var Cryptpad = config.Cryptpad; - Messages = Cryptpad.Messages; - - var FILES_DATA = Cryptpad.storageKey; - var NEW_FOLDER_NAME = Messages.fm_newFolder; - var NEW_FILE_NAME = Messages.fm_newFile; - - //var DEBUG = config.DEBUG || false; - var logging = function () { - console.log.apply(console, arguments); - }; - var log = config.log || logging; - var logError = config.logError || logging; - var debug = config.debug || logging; - var workgroup = config.workgroup; - - var exp = {}; - - var error = exp.error = function() { - exp.fixFiles(); - console.error.apply(console, arguments); - }; - - exp.getStructure = function () { - var a = {}; - a[ROOT] = {}; - a[UNSORTED] = []; - a[TRASH] = {}; - a[FILES_DATA] = []; - a[TEMPLATE] = []; - return a; - }; - - var pushFileData = exp.pushData = function (data) { - Cryptpad.pinPads([Cryptpad.hrefToHexChannelId(data.href)], function (e, hash) { - console.log(hash); - }); - files[FILES_DATA].push(data); - }; - var spliceFileData = exp.removeData = function (idx) { - var data = files[FILES_DATA][idx]; - if (typeof data === "object") { - Cryptpad.unpinPads([Cryptpad.hrefToHexChannelId(data.href)], function (e, hash) { - console.log(hash); - }); - } - files[FILES_DATA].splice(idx, 1); - }; - - - var comparePath = exp.comparePath = function (a, b) { - if (!a || !b || !$.isArray(a) || !$.isArray(b)) { return false; } - if (a.length !== b.length) { return false; } - var result = true; - var i = a.length - 1; - while (result && i >= 0) { - result = a[i] === b[i]; - i--; - } - return result; - }; - - var isPathInRoot = exp.isPathInRoot = function (path) { - return path[0] && path[0] === ROOT; - }; - var isPathInUnsorted = exp.isPathInUnsorted = function (path) { - return path[0] && path[0] === UNSORTED; - }; - var isPathInTemplate = exp.isPathInTemplate = function (path) { - return path[0] && path[0] === TEMPLATE; - }; - var isPathInHrefArray = exp.isPathInHrefArray = function (path) { - return isPathInUnsorted(path) || isPathInTemplate(path); - }; - var isPathInTrash = exp.isPathInTrash = function (path) { - return path[0] && path[0] === TRASH; - }; - var isInTrashRoot = exp.isInTrashRoot = function (path) { - return path[0] === TRASH && path.length === 4; - }; - - exp.isPathInFilesData = function (path) { - return path[0] && path[0] === FILES_DATA; - }; - - var isFile = exp.isFile = function (element) { - return typeof(element) === "string"; - }; - - exp.isReadOnlyFile = function (element) { - if (!isFile(element)) { return false; } - var parsed = Cryptpad.parsePadUrl(element); - if (!parsed) { return false; } - var hash = parsed.hash; - var pHash = Cryptpad.parseHash(hash); - if (pHash && !pHash.mode) { return; } - return pHash && pHash.mode === 'view'; - }; - - var isFolder = exp.isFolder = function (element) { - return typeof(element) !== "string"; - }; - - exp.isFolderEmpty = function (element) { - if (typeof(element) !== "object") { return false; } - return Object.keys(element).length === 0; - }; - - exp.hasSubfolder = function (element, trashRoot) { - if (typeof(element) !== "object") { return false; } - var subfolder = 0; - var addSubfolder = function (el) { - subfolder += isFolder(el.element) ? 1 : 0; - }; - for (var f in element) { - if (trashRoot) { - if ($.isArray(element[f])) { - element[f].forEach(addSubfolder); - } - } else { - subfolder += isFolder(element[f]) ? 1 : 0; - } - } - return subfolder; - }; - - exp.hasFile = function (element, trashRoot) { - if (typeof(element) !== "object") { return false; } - var file = 0; - var addFile = function (el) { - file += isFile(el.element) ? 1 : 0; - }; - for (var f in element) { - if (trashRoot) { - if ($.isArray(element[f])) { - element[f].forEach(addFile); - } - } else { - file += isFile(element[f]) ? 1 : 0; - } - } - return file; - }; - - var isSubpath = exp.isSubpath = function (path, parentPath) { - var pathA = parentPath.slice(); - var pathB = path.slice(0, pathA.length); - return comparePath(pathA, pathB); - }; - - var getAvailableName = function (parentEl, name) { - if (typeof(parentEl[name]) === "undefined") { return name; } - var newName = name; - var i = 1; - while (typeof(parentEl[newName]) !== "undefined") { - newName = name + "_" + i; - i++; - } - return newName; - }; - - var compareFiles = function (fileA, fileB) { - // Compare string, might change in the future - return fileA === fileB; - }; - - var isFileInTree = function (file, root) { - if (isFile(root)) { - return compareFiles(file, root); - } - var inTree = false; - for (var e in root) { - inTree = isFileInTree(file, root[e]); - if (inTree) { break; } - } - return inTree; - }; - -/* var isFileInTrash = function (file) { - var inTrash = false; - var root = files[TRASH]; - var filter = function (trashEl) { - inTrash = isFileInTree(file, trashEl.element); - return inTrash; - }; - for (var e in root) { - if (!$.isArray(root[e])) { - error("Trash contains a non-array element"); - return; - } - root[e].some(filter); - if (inTrash) { break; } - } - return inTrash; - };*/ - - var getUnsortedFiles = exp.getUnsortedFiles = function () { - if (!files[UNSORTED]) { - files[UNSORTED] = []; - } - return files[UNSORTED].slice(); - }; - - var getTemplateFiles = exp.getTemplateFiles = function () { - if (!files[TEMPLATE]) { - files[TEMPLATE] = []; - } - return files[TEMPLATE].slice(); - }; - - var getFilesRecursively = function (root, arr) { - for (var e in root) { - if (isFile(root[e])) { - if(arr.indexOf(root[e]) === -1) { arr.push(root[e]); } - } else { - getFilesRecursively(root[e], arr); - } - } - }; - - var getRootFiles = function () { - var ret = []; - getFilesRecursively(files[ROOT], ret); - return ret; - }; - - var getTrashFiles = exp.getTrashFiles = function () { - var root = files[TRASH]; - var ret = []; - var addFiles = function (el) { - if (isFile(el.element)) { - if(ret.indexOf(el.element) === -1) { ret.push(el.element); } - } else { - getFilesRecursively(el.element, ret); - } - }; - for (var e in root) { - if (!$.isArray(root[e])) { - error("Trash contains a non-array element"); - return; - } - root[e].forEach(addFiles); - } - return ret; - }; - - exp.getFilesDataFiles = function () { - var ret = []; - files[FILES_DATA].forEach(function (el) { - if (el.href && ret.indexOf(el.href) === -1) { - ret.push(el.href); - } - }); - return ret; - }; - - var _findFileInRoot = function (path, href) { - if (path[0] !== ROOT && path[0] !== TRASH) { return []; } - var paths = []; - var root = exp.findElement(files, path); - var addPaths = function (p) { - if (paths.indexOf(p) === -1) { - paths.push(p); - } - }; - - if (isFile(root)) { - if (compareFiles(href, root)) { - if (paths.indexOf(path) === -1) { - paths.push(path); - } - } - return paths; - } - for (var e in root) { - var nPath = path.slice(); - nPath.push(e); - _findFileInRoot(nPath, href).forEach(addPaths); - } - - return paths; - }; - var _findFileInHrefArray = function (rootName, href) { - var unsorted = files[rootName].slice(); - var ret = []; - var i = -1; - while ((i = unsorted.indexOf(href, i+1)) !== -1){ - ret.push([rootName, i]); - } - return ret; - }; - var _findFileInTrash = function (path, href) { - var root = exp.findElement(files, path); - var paths = []; - var addPaths = function (p) { - if (paths.indexOf(p) === -1) { - paths.push(p); - } - }; - if (path.length === 1 && typeof(root) === 'object') { - Object.keys(root).forEach(function (key) { - var arr = root[key]; - if (!Array.isArray(arr)) { return; } - var nPath = path.slice(); - nPath.push(key); - _findFileInTrash(nPath, href).forEach(addPaths); - }); - } - if (path.length === 2) { - if (!Array.isArray(root)) { return []; } - root.forEach(function (el, i) { - var nPath = path.slice(); - nPath.push(i); - nPath.push('element'); - if (isFile(el.element)) { - if (compareFiles(href, el.element)) { - addPaths(nPath); - } - return; - } - _findFileInTrash(nPath, href).forEach(addPaths); - }); - } - if (path.length >= 4) { - _findFileInRoot(path, href).forEach(addPaths); - } - return paths; - }; - var findFile = exp.findFile = function (href) { - var rootpaths = _findFileInRoot([ROOT], href); - var unsortedpaths = _findFileInHrefArray(UNSORTED, href); - var templatepaths = _findFileInHrefArray(TEMPLATE, href); - var trashpaths = _findFileInTrash([TRASH], href); - return rootpaths.concat(unsortedpaths, templatepaths, trashpaths); - }; - - exp.search = function (value) { - if (typeof(value) !== "string") { return []; } - var res = []; - // Search in ROOT - var findIn = function (root) { - Object.keys(root).forEach(function (k) { - if (isFile(root[k])) { - if (k.toLowerCase().indexOf(value.toLowerCase()) !== -1) { - res.push(root[k]); - } - return; - } - findIn(root[k]); - }); - }; - findIn(files[ROOT]); - // Search in TRASH - var trash = files[TRASH]; - Object.keys(trash).forEach(function (k) { - if (k.toLowerCase().indexOf(value.toLowerCase()) !== -1) { - trash[k].forEach(function (el) { - if (isFile(el.element)) { - res.push(el.element); - } - }); - } - trash[k].forEach(function (el) { - if (isFolder(el.element)) { - findIn(el.element); - } - }); - }); - - // Search title - var allFilesList = files[FILES_DATA].slice(); - allFilesList.forEach(function (t) { - if (t.title && t.title.toLowerCase().indexOf(value.toLowerCase()) !== -1) { - res.push(t.href); - } - }); - - // Search Href - var href = Cryptpad.getRelativeHref(value); - if (href) { - res.push(href); - } - - res = Cryptpad.deduplicateString(res); - - var ret = []; - res.forEach(function (l) { - //var paths = findFile(l); - ret.push({ - paths: findFile(l), - data: exp.getFileData(l) - }); - }); - return ret; - }; - - // Remove the selected 'href' from the tree located at 'path', and push its locations to the 'paths' array - var removeFileFromRoot = function (path, href) { - var paths = []; - var root = exp.findElement(files, path); - - var rememberUnknownPath = function (p) { - if (paths.indexOf(p) === -1) { - paths.push(p); - } - }; - - if (isFile(root)) { return; } - for (var e in root) { - if (isFile(root[e])) { - if (compareFiles(href, root[e])) { - root[e] = undefined; - delete root[e]; - if (paths.indexOf(path) === -1) { - paths.push(path); - } - } - } else { - var nPath = path.slice(); - nPath.push(e); - removeFileFromRoot(nPath, href).forEach(rememberUnknownPath); - } - } - return paths; - }; - - var removePadAttribute = function (f) { - Object.keys(files).forEach(function (key) { - var hash = f.indexOf('#') !== -1 ? f.slice(f.indexOf('#') + 1) : null; - if (hash && key.indexOf(hash) === 0) { - debug("Deleting pad attribute in the realtime object"); - files[key] = undefined; - delete files[key]; - } - }); - }; - - var checkDeletedFiles = function () { - // Nothing in FILES_DATA for workgroups - if (workgroup) { return; } - - var rootFiles = getRootFiles(); - var unsortedFiles = getUnsortedFiles(); - var templateFiles = getTemplateFiles(); - var trashFiles = getTrashFiles(); - var toRemove = []; - files[FILES_DATA].forEach(function (arr) { - var f = arr.href; - if (rootFiles.indexOf(f) === -1 - && unsortedFiles.indexOf(f) === -1 - && trashFiles.indexOf(f) === -1 - && templateFiles.indexOf(f) === -1) { - toRemove.push(arr); - } - }); - toRemove.forEach(function (f) { - var idx = files[FILES_DATA].indexOf(f); - if (idx !== -1) { - debug("Removing", f, "from filesData"); - spliceFileData(idx); - removePadAttribute(f.href); - } - }); - }; - - var deleteFromObject = exp.deletePathPermanently = function (path) { - var parentPath = path.slice(); - var key = parentPath.pop(); - var parentEl = exp.findElement(files, parentPath); - if (isInTrashRoot(path)) { - files[TRASH][path[1]].splice(path[2], 1); - } else if (isPathInHrefArray(path)) { - parentEl.splice(key, 1); - } else { - parentEl[key] = undefined; - delete parentEl[key]; - } - checkDeletedFiles(); - }; - - // Permanently delete multiple files at once using a list of paths - // NOTE: We have to be careful when removing elements from arrays (trash root, unsorted or template) - var deleteHrefs = function (hrefs) { - hrefs.forEach(function (obj) { - var idx = files[obj.root].indexOf(obj.href); - files[obj.root].splice(idx, 1); - }); - }; - var deleteMultipleTrashRoot = function (roots) { - roots.forEach(function (obj) { - var idx = files[TRASH][obj.name].indexOf(obj.el); - files[TRASH][obj.name].splice(idx, 1); - }); - }; - exp.deletePathsPermanently = function (paths) { - var hrefPaths = paths.filter(isPathInHrefArray); - var rootPaths = paths.filter(isPathInRoot); - var trashPaths = paths.filter(isPathInTrash); - - var hrefs = []; - hrefPaths.forEach(function (path) { - var href = exp.findElement(files, path); - hrefs.push({ - root: path[0], - href: href - }); - }); - deleteHrefs(hrefs); - - rootPaths.forEach(function (path) { - var parentPath = path.slice(); - var key = parentPath.pop(); - var parentEl = exp.findElement(files, parentPath); - parentEl[key] = undefined; - delete parentEl[key]; - }); - - var trashRoot = []; - trashPaths.forEach(function (path) { - var parentPath = path.slice(); - var key = parentPath.pop(); - var parentEl = exp.findElement(files, parentPath); - // Trash root: we have array here, we can't just splice with the path otherwise we might break the path - // of another element in the loop - if (path.length === 4) { - trashRoot.push({ - name: path[1], - el: parentEl - }); - return; - } - // Trash but not root: it's just a tree so remove the key - parentEl[key] = undefined; - delete parentEl[key]; - }); - deleteMultipleTrashRoot(trashRoot); - - checkDeletedFiles(); - }; - - // Find an element in a object following a path, resursively - // NOTE: it is always used with an absolute path and root === files in our code - var findElement = exp.findElement = function (root, pathInput) { - if (!pathInput) { - error("Invalid path:\n", pathInput, "\nin root\n", root); - return; - } - if (pathInput.length === 0) { return root; } - var path = pathInput.slice(); - var key = path.shift(); - if (typeof root[key] === "undefined") { - debug("Unable to find the key '" + key + "' in the root object provided:", root); - return; - } - return findElement(root[key], path); - }; - - // Get the object {element: element, path: [path]} from a trash root path - var getTrashElementData = exp.getTrashElementData = function (trashPath) { - if (!isInTrashRoot) { - debug("Called getTrashElementData on a element not in trash root: ", trashPath); - return; - } - var parentPath = trashPath.slice(); - parentPath.pop(); - return findElement(files, parentPath); - }; - - // Get data from AllFiles (Cryptpad_RECENTPADS) - var getFileData = exp.getFileData = function (file) { - if (!file) { return; } - var res; - files[FILES_DATA].some(function(arr) { - var href = arr.href; - if (href === file) { - res = arr; - return true; - } - return false; - }); - return res; - }; - - // Data from filesData - var getTitle = exp.getTitle = function (href) { - if (workgroup) { debug("No titles in workgroups"); return; } - var data = getFileData(href); - if (!href || !data) { - error("getTitle called with a non-existing href: ", href); - return; - } - return data.title; - }; - - var pushToTrash = function (name, element, path) { - var trash = findElement(files, [TRASH]); - - if (typeof(trash[name]) === "undefined") { - trash[name] = []; - } - var trashArray = trash[name]; - var trashElement = { - element: element, - path: path - }; - trashArray.push(trashElement); - }; - - // Move to trash - var removeElement = exp.removeElement = function (path, cb, keepOld) { - if (!path || path.length < 2 || path[0] === TRASH) { - debug("Calling removeElement from a wrong path: ", path); - return; - } - var element = findElement(files, path); - var key = path[path.length - 1]; - var name = isPathInHrefArray(path) ? getTitle(element) : key; - var parentPath = path.slice(); - parentPath.pop(); - pushToTrash(name, element, parentPath); - if (!keepOld) { deleteFromObject(path); } - if (cb) { cb(); } - }; - - var moveElement = exp.moveElement = function (elementPath, newParentPath, cb, keepOld) { - if (comparePath(elementPath, newParentPath)) { return; } // Nothing to do... - if (isPathInTrash(newParentPath)) { - removeElement(elementPath, cb, keepOld); - return; - } - var element = findElement(files, elementPath); - - var newParent = findElement(files, newParentPath); - - // Never move a folder in one of its children - if (isFolder(element) && isSubpath(newParentPath, elementPath)) { - log(Messages.fo_moveFolderToChildError); - return; - } - - if (isPathInHrefArray(newParentPath)) { - if (isFolder(element)) { - log(Messages.fo_moveUnsortedError); - return; - } else { - if (elementPath[0] === newParentPath[0]) { return; } - var fileRoot = newParentPath[0]; - if (files[fileRoot].indexOf(element) === -1) { - files[fileRoot].push(element); - } - if (!keepOld) { deleteFromObject(elementPath); } - if(cb) { cb(); } - return; - } - } - - var name; - - if (isPathInHrefArray(elementPath)) { - name = getTitle(element); - } else if (isInTrashRoot(elementPath)) { - // Element from the trash root: elementPath = [TRASH, "{dirName}", 0, 'element'] - name = elementPath[1]; - } else { - name = elementPath[elementPath.length-1]; - } - var newName = !isPathInRoot(elementPath) ? getAvailableName(newParent, name) : name; - - if (typeof(newParent[newName]) !== "undefined") { - log(Messages.fo_unavailableName); - return; - } - newParent[newName] = element; - if (!keepOld) { deleteFromObject(elementPath); } - if(cb) { cb(); } - }; - - // "Unsorted" is an array of href: we can't move several of them using "moveElement" in a - // loop because moveElement removes the href from the array and it changes the path for all - // the other elements. We have to move them all and then remove them from unsorted - var moveHrefArrayElements = exp.moveHrefArrayElements = function (paths, newParentPath, cb) { - if (!paths || paths.length === 0) { return; } - //if (isPathInHrefArray(newParentPath)) { return; } - var elements = {}; - // Get the elements - paths.forEach(function (p) { - // Here we move only files from array categories (unsorted, template...) - if (!isPathInHrefArray(p)) { return; } - // And we check that we don't want to move to the same location - if (p[0] === newParentPath[0]) { return; } - var el = findElement(files, p); - if (el) { elements[el] = p; } - }); - // Copy the elements to their new location - Object.keys(elements).forEach(function (el) { - moveElement(elements[el], newParentPath, null, true); - }); - // Remove the elements from their old location - Object.keys(elements).forEach(function (el) { - var fileRoot = elements[el][0]; - var idx = files[fileRoot].indexOf(el); - if (idx !== -1) { - files[fileRoot].splice(idx, 1); - } - }); - if (cb) { cb(); } - }; - - exp.moveElements = function (paths, newParentPath, cb) { - var unsortedPaths = paths.filter(isPathInHrefArray); - moveHrefArrayElements(unsortedPaths, newParentPath); - // Copy the elements to their new location - paths.forEach(function (p) { - if (isPathInHrefArray(p)) { return; } - moveElement(p, newParentPath, null); - }); - if(cb) { cb(); } - }; - - // Import elements in the file manager - exp.importElements = function (elements, path, cb) { - if (!elements || elements.length === 0) { return; } - var newParent = findElement(files, path); - if (!newParent) { debug("Trying to import elements into a non-existing folder"); return; } - elements.forEach(function (e) { - var el = e.el; - var key = e.name; - if (!key) { key = "???"; } // Should not happen... - newParent[key] = el; - }); - if(cb) { cb(); } - }; - - exp.createNewFolder = function (folderPath, name, cb) { - var parentEl = findElement(files, folderPath); - var folderName = getAvailableName(parentEl, name || NEW_FOLDER_NAME); - parentEl[folderName] = {}; - var newPath = folderPath.slice(); - newPath.push(folderName); - cb({ - newPath: newPath - }); - }; - - var pushNewFileData = function (href, title) { - pushFileData({ - href: href, - title: title, - atime: +new Date(), - ctime: +new Date() - }); - }; - exp.createNewFile = function (filePath, name, type, cb) { - var parentEl = findElement(files, filePath); - var fileName = getAvailableName(parentEl, name || NEW_FILE_NAME); - var href = '/' + type + '/#' + Cryptpad.createRandomHash(); - parentEl[fileName] = href; - - pushNewFileData(href, fileName); - - var newPath = filePath.slice(); - newPath.push(fileName); - cb({ - newPath: newPath - }); - }; - - // Remove an element from the trash root - var removeFromTrashArray = function (element, name) { - var array = files[TRASH][name]; - if (!array || !$.isArray(array)) { return; } - // Remove the element from the trash array - var index = array.indexOf(element); - if (index > -1) { - array.splice(index, 1); - } - // Remove the array if empty to have a cleaner object in chainpad - if (array.length === 0) { - files[TRASH][name] = undefined; - delete files[TRASH][name]; - } - }; - - // Restore an element (copy it elsewhere and remove from the trash root) - exp.restoreTrash = function (path, cb) { - if (!path || path.length !== 4 || path[0] !== TRASH) { - debug("restoreTrash was called from an element not in the trash root: ", path); - return; - } - var element = findElement(files, path); - var parentEl = getTrashElementData(path); - var newPath = parentEl.path; - if (isPathInHrefArray(newPath)) { - var fileRoot = newPath[0]; - if (files[fileRoot].indexOf(element) === -1) { - files[fileRoot].push(element); - } - removeFromTrashArray(parentEl, path[1]); - cb(); - return; - } - // Find the new parent element - var newParentEl = findElement(files, newPath); - while (newPath.length > 1 && !newParentEl) { - newPath.pop(); - newParentEl = findElement(files, newPath); - } - if (!newParentEl) { - log(Messages.fo_unableToRestore); - } - var name = getAvailableName(newParentEl, path[1]); - // Move the element - newParentEl[name] = element; - removeFromTrashArray(parentEl, path[1]); - cb(); - }; - - // Delete permanently (remove from the trash root and from filesData) - var removeFromTrash = exp.removeFromTrash = function (path, cb, nocheck) { - if (!path || path.length < 4 || path[0] !== TRASH) { return; } - // Remove the last element from the path to get the parent path and the element name - var parentPath = path.slice(); - var name; - //var element = findElement(files, path); - if (path.length === 4) { // Trash root - name = path[1]; - parentPath.pop(); - var parentElement = findElement(files, parentPath); - removeFromTrashArray(parentElement, name); - } else { - name = parentPath.pop(); - var parentEl = findElement(files, parentPath); - if (typeof(parentEl[name]) === "undefined") { - logError("Unable to locate the element to remove from trash: ", path); - return; - } - parentEl[name] = undefined; - delete parentEl[name]; - } - if (!nocheck) { - checkDeletedFiles(); - } - if(cb) { cb(); } - }; - - exp.emptyTrash = function (cb) { - files[TRASH] = {}; - checkDeletedFiles(); - if(cb) { cb(); } - }; - - exp.deleteFileData = function (href, cb) { - if (workgroup) { return; } - - var toRemove = []; - files[FILES_DATA].forEach(function (arr) { - var f = arr.href; - if (f === href) { - toRemove.push(arr); - } - }); - toRemove.forEach(function (f) { - var idx = files[FILES_DATA].indexOf(f); - if (idx !== -1) { - debug("Removing", f, "from filesData"); - spliceFileData(idx); - // Remove the "padAttributes" stored in the realtime object for that pad - removePadAttribute(f.href); - } - }); - - if(cb) { cb(); } - }; - - exp.renameElement = function (path, newName, cb) { - if (path.length <= 1) { - logError('Renaming `root` is forbidden'); - return; - } - if (!newName || newName.trim() === "") { return; } - // Copy the element path and remove the last value to have the parent path and the old name - var element = findElement(files, path); - var parentPath = path.slice(); - var oldName = parentPath.pop(); - if (oldName === newName) { - return; - } - var parentEl = findElement(files, parentPath); - if (typeof(parentEl[newName]) !== "undefined") { - log(Messages.fo_existingNameError); - return; - } - parentEl[newName] = element; - parentEl[oldName] = undefined; - delete parentEl[oldName]; - cb(); - }; - - - exp.forgetPad = function (href) { - if (workgroup) { return; } - if (!href || !isFile(href)) { return; } - var path; - var rootFiles = getRootFiles().slice(); - if (rootFiles.indexOf(href) !== -1) { - var paths = removeFileFromRoot([ROOT], href); - path = paths[0]; - } - var unsortedIdx = getUnsortedFiles().indexOf(href); - if (unsortedIdx !== -1) { - files[UNSORTED].splice(unsortedIdx, 1); - path = [UNSORTED]; - } - var templateIdx = getTemplateFiles().indexOf(href); - if (templateIdx !== -1) { - files[TEMPLATE].splice(templateIdx, 1); - path = [TEMPLATE]; - } - if (!path) { return; } - var key = getTitle(href); - pushToTrash(key, href, path); - }; - - var addPad = exp.addPad = function (href, path, name) { - if (workgroup) { return; } - if (!href) { return; } - var unsortedFiles = getUnsortedFiles(); - var rootFiles = getRootFiles(); - var trashFiles = getTrashFiles(); - var templateFiles = getTemplateFiles(); - var newPath, parentEl; - if (path) { - newPath = decodeURIComponent(path).split(','); - } - if (path && isPathInHrefArray(newPath)) { - parentEl = findElement(files, newPath); - parentEl.push(href); - return; - } - if (path && isPathInRoot(newPath) && name) { - parentEl = findElement(files, newPath); - if (parentEl) { - var newName = getAvailableName(parentEl, name); - parentEl[newName] = href; - return; - } - } - if (unsortedFiles.indexOf(href) === -1 && rootFiles.indexOf(href) === -1 && templateFiles.indexOf(href) === -1 && trashFiles.indexOf(href) === -1) { - files[UNSORTED].push(href); - } - }; - - var replaceFile = function (path, o, n) { - var root = exp.findElement(files, path); - - if (isFile(root)) { return; } - for (var e in root) { - if (isFile(root[e])) { - if (compareFiles(o, root[e])) { - root[e] = n; - } - } else { - var nPath = path.slice(); - nPath.push(e); - replaceFile(nPath, o, n); - } - } - }; - - // Replace a href by a stronger one everywhere in the drive (except FILES_DATA) - exp.replaceHref = function (o, n) { - if (!isFile(o) || !isFile(n)) { return; } - var paths = findFile(o); - - // Remove all the occurences in the trash - // Replace all the occurences not in the trash - // If all the occurences are in the trash or no occurence, add the pad to unsorted - var allInTrash = true; - paths.forEach(function (p) { - if (p[0] === TRASH) { - removeFromTrash(p, null, true); // 3rd parameter means skip "checkDeletedFiles" - return; - } else { - allInTrash = false; - var parentPath = p.slice(); - var key = parentPath.pop(); - var parentEl = findElement(files, parentPath); - parentEl[key] = n; - } - }); - if (allInTrash) { - addPad(n); - } - }; - - // addTemplate is called when we want to add a new pad, never visited, to the templates list - // first, we must add it to FILES_DATA, so the input has to be an fileDAta object - exp.addTemplate = function (fileData) { - if (workgroup) { return; } - if (typeof fileData !== "object" || !fileData.href || !fileData.title) { - console.error("filedata object expected to add a new template"); - return; - } - - var href = fileData.href; - var test = files[FILES_DATA].some(function (o) { - return o.href === href; - }); - if (!test) { - pushFileData(fileData); - } - if (files[TEMPLATE].indexOf(href) === -1) { - files[TEMPLATE].push(href); - } - }; - - exp.listTemplates = function () { - if (workgroup) { return; } - var templateFiles = getTemplateFiles(); - var res = []; - templateFiles.forEach(function (f) { - var data = getFileData(f); - res.push(JSON.parse(JSON.stringify(data))); - }); - return res; - }; - - var uniq = function (a) { - var seen = {}; - return a.filter(function(item) { - return seen.hasOwnProperty(item) ? false : (seen[item] = true); - }); - }; - - exp.fixFiles = function () { - // Explore the tree and check that everything is correct: - // * 'root', 'trash', 'unsorted' and 'filesData' exist and are objects - // * ROOT: Folders are objects, files are href - // * TRASH: Trash root contains only arrays, each element of the array is an object {element:.., path:..} - // * FILES_DATA: - Data (title, cdate, adte) are stored in filesData. filesData contains only href keys linking to object with title, cdate, adate. - // - Dates (adate, cdate) can be parsed/formatted - // - All files in filesData should be either in 'root', 'trash' or 'unsorted'. If that's not the case, copy the fily to 'unsorted' - // * UNSORTED: Contains only files (href), and does not contains files that are in ROOT - debug("Cleaning file system..."); - - var before = JSON.stringify(files); - - var fixRoot = function (elem) { - if (typeof(files[ROOT]) !== "object") { debug("ROOT was not an object"); files[ROOT] = {}; } - var element = elem || files[ROOT]; - for (var el in element) { - if (!isFile(element[el]) && !isFolder(element[el])) { - debug("An element in ROOT was not a folder nor a file. ", element[el]); - element[el] = undefined; - delete element[el]; - } else if (isFolder(element[el])) { - fixRoot(element[el]); - } - } - }; - var fixTrashRoot = function () { - if (typeof(files[TRASH]) !== "object") { debug("TRASH was not an object"); files[TRASH] = {}; } - var tr = files[TRASH]; - var toClean; - var addToClean = function (obj, idx) { - if (typeof(obj) !== "object") { toClean.push(idx); return; } - if (!isFile(obj.element) && !isFolder(obj.element)) { toClean.push(idx); return; } - if (!$.isArray(obj.path)) { toClean.push(idx); return; } - }; - for (var el in tr) { - if (!$.isArray(tr[el])) { - debug("An element in TRASH root is not an array. ", tr[el]); - tr[el] = undefined; - delete tr[el]; - } else { - toClean = []; - tr[el].forEach(addToClean); - for (var i = toClean.length-1; i>=0; i--) { - tr[el].splice(toClean[i], 1); - } - } - } - }; - var fixUnsorted = function () { - if (!$.isArray(files[UNSORTED])) { debug("UNSORTED was not an array"); files[UNSORTED] = []; } - files[UNSORTED] = uniq(files[UNSORTED]); - var us = files[UNSORTED]; - var rootFiles = getRootFiles().slice(); - var templateFiles = getTemplateFiles(); - var toClean = []; - us.forEach(function (el, idx) { - if (!isFile(el) || rootFiles.indexOf(el) !== -1 || templateFiles.indexOf(el) !== -1) { - toClean.push(idx); - } - }); - toClean.forEach(function (idx) { - us.splice(idx, 1); - }); - }; - var fixTemplate = function () { - if (!$.isArray(files[TEMPLATE])) { debug("TEMPLATE was not an array"); files[TEMPLATE] = []; } - files[TEMPLATE] = uniq(files[TEMPLATE]); - var us = files[TEMPLATE]; - var rootFiles = getRootFiles().slice(); - var unsortedFiles = getUnsortedFiles(); - var toClean = []; - us.forEach(function (el, idx) { - if (!isFile(el) || rootFiles.indexOf(el) !== -1 || unsortedFiles.indexOf(el) !== -1) { - toClean.push(idx); - } - }); - toClean.forEach(function (idx) { - us.splice(idx, 1); - }); - }; - var fixFilesData = function () { - if (!$.isArray(files[FILES_DATA])) { debug("FILES_DATA was not an array"); files[FILES_DATA] = []; } - var fd = files[FILES_DATA]; - var rootFiles = getRootFiles(); - var unsortedFiles = getUnsortedFiles(); - var templateFiles = getTemplateFiles(); - var trashFiles = getTrashFiles(); - var toClean = []; - fd.forEach(function (el) { - if (!el || typeof(el) !== "object") { - debug("An element in filesData was not an object.", el); - toClean.push(el); - return; - } - if (rootFiles.indexOf(el.href) === -1 - && unsortedFiles.indexOf(el.href) === -1 - && templateFiles.indexOf(el.href) === -1 - && trashFiles.indexOf(el.href) === -1) { - debug("An element in filesData was not in ROOT, UNSORTED or TRASH.", el); - files[UNSORTED].push(el.href); - return; - } - }); - toClean.forEach(function (el) { - var idx = fd.indexOf(el); - if (idx !== -1) { - spliceFileData(idx); - } - }); - }; - - fixRoot(); - fixTrashRoot(); - if (!workgroup) { - fixUnsorted(); - fixTemplate(); - fixFilesData(); - } - - if (JSON.stringify(files) !== before) { - debug("Your file system was corrupted. It has been cleaned so that the pads you visit can be stored safely"); - return; - } - debug("File system was clean"); - }; - - return exp; - }; - - return module; -}); diff --git a/www/common/fsStore.js b/www/common/fsStore.js index df56e849a..6440bc949 100644 --- a/www/common/fsStore.js +++ b/www/common/fsStore.js @@ -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 diff --git a/www/common/login.js b/www/common/login.js index c130445f0..4254ce4be 100644 --- a/www/common/login.js +++ b/www/common/login.js @@ -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('/'); diff --git a/www/common/mergeDrive.js b/www/common/mergeDrive.js index 1a5fb5f29..d9e9b3987 100644 --- a/www/common/mergeDrive.js +++ b/www/common/mergeDrive.js @@ -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) { diff --git a/www/common/outer/upload.js b/www/common/outer/upload.js index a5f89aa38..4e42d94da 100644 --- a/www/common/outer/upload.js +++ b/www/common/outer/upload.js @@ -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; diff --git a/www/common/sframe-app-framework.js b/www/common/sframe-app-framework.js index 3b68cf0ce..c25f11fee 100644 --- a/www/common/sframe-app-framework.js +++ b/www/common/sframe-app-framework.js @@ -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) { diff --git a/www/common/sframe-common-file.js b/www/common/sframe-common-file.js index 7033edff7..4ebe35723 100644 --- a/www/common/sframe-common-file.js +++ b/www/common/sframe-common-file.js @@ -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; }; diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index e5e344053..e2f9ce53d 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -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)); } }); }); diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index 2d39d8ef4..d638df897 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -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 ''; }; 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 '' + ''; } 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); } diff --git a/www/common/sframe-messenger-outer.js b/www/common/sframe-messenger-outer.js deleted file mode 100644 index 476e60b52..000000000 --- a/www/common/sframe-messenger-outer.js +++ /dev/null @@ -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; -}); diff --git a/www/common/toolbar3.js b/www/common/toolbar3.js index fb3bd72e2..e488d6382 100644 --- a/www/common/toolbar3.js +++ b/www/common/toolbar3.js @@ -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 = $('
'); @@ -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($('', {'class': 'cp-toolbar-title-readonly'}) .text('('+Messages.readonly+')')); + return $titleContainer; } - if (config.readOnly === 1 || typeof(Cryptpad) === "undefined") { return $titleContainer; } var $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; }; diff --git a/www/common/userObject.js b/www/common/userObject.js index 6d3da74c0..47bc42876 100644 --- a/www/common/userObject.js +++ b/www/common/userObject.js @@ -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; } diff --git a/www/drive/inner.js b/www/drive/inner.js index 9c756cb18..862a647ae 100644 --- a/www/drive/inner.js +++ b/www/drive/inner.js @@ -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 = $(''); var $icon = $('
', {'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]); $('
').appendTo($d); diff --git a/www/drive/main.js b/www/drive/main.js index 5a46b8f6b..3b78bea72 100644 --- a/www/drive/main.js +++ b/www/drive/main.js @@ -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({ diff --git a/www/file/inner.js b/www/file/inner.js index ecd449df2..09a302b0a 100644 --- a/www/file/inner.js +++ b/www/file/inner.js @@ -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); }); }); diff --git a/www/filepicker/inner.js b/www/filepicker/inner.js index e83578668..ccf332d87 100644 --- a/www/filepicker/inner.js +++ b/www/filepicker/inner.js @@ -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, diff --git a/www/invite/main.js b/www/invite/main.js index 7acaa5589..7e10abca5 100644 --- a/www/invite/main.js +++ b/www/invite/main.js @@ -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 $('
', { @@ -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) { diff --git a/www/oldsettings/index.html b/www/oldsettings/index.html deleted file mode 100644 index 31d4c99f8..000000000 --- a/www/oldsettings/index.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - CryptPad: Zero Knowledge, Collaborative Real Time Editing - - - - - - - - diff --git a/www/oldsettings/main.js b/www/oldsettings/main.js deleted file mode 100644 index 57b61268d..000000000 --- a/www/oldsettings/main.js +++ /dev/null @@ -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 = $('
', {'class': 'infoBlock'}); - - var $account = $('
', {'class': 'element'}).appendTo($div); - var accountName = obj.login_name || localStorage[Cryptpad.userNameKey]; - var $label = $('', {'class': 'label'}).text(Messages.user_accountName); - var $name = $('').text(accountName || ''); - if (!accountName) { - $label.text(''); - $name.text(Messages.settings_anonymous); - } - $account.append($label).append($name); - - var publicKey = obj.edPublic; - if (publicKey) { - var $key = $('
', {'class': 'element'}).appendTo($div); - var userHref = Cryptpad.getUserHrefFromKeys(accountName, publicKey); - var $pubLabel = $('', {'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 = $('
', {'class': 'displayName element'}); - $('