diff --git a/www/common/fsStore.js b/www/common/fsStore.js index 90dfa9f57..2fa5f87cd 100644 --- a/www/common/fsStore.js +++ b/www/common/fsStore.js @@ -141,76 +141,81 @@ define([ var onReady = function (f, proxy, Cryptpad, exp) { var fo = exp.fo = FO.init(proxy.drive, { - Cryptpad: Cryptpad + Cryptpad: Cryptpad, + rt: exp.realtime }); + var todo = function () { + fo.fixFiles(); - //storeObj = proxy; - store = initStore(fo, proxy, exp); - if (typeof(f) === 'function') { - f(void 0, store); - } + //storeObj = proxy; + store = initStore(fo, proxy, exp); + if (typeof(f) === 'function') { + f(void 0, store); + } - var requestLogin = function () { - // log out so that you don't go into an endless loop... - Cryptpad.logout(); + var requestLogin = function () { + // log out so that you don't go into an endless loop... + Cryptpad.logout(); - // redirect them to log in, and come back when they're done. - sessionStorage.redirectTo = window.location.href; - window.location.href = '/login/'; - }; + // redirect them to log in, and come back when they're done. + sessionStorage.redirectTo = window.location.href; + window.location.href = '/login/'; + }; - var tokenKey = 'loginToken'; - if (Cryptpad.isLoggedIn()) { -/* This isn't truly secure, since anyone who can read the user's object can - set their local loginToken to match that in the object. However, it exposes - a UI that will work most of the time. */ + var tokenKey = 'loginToken'; + if (Cryptpad.isLoggedIn()) { + /* This isn't truly secure, since anyone who can read the user's object can + set their local loginToken to match that in the object. However, it exposes + a UI that will work most of the time. */ - // every user object should have a persistent, random number - if (typeof(proxy.loginToken) !== 'number') { - proxy[tokenKey] = Math.floor(Math.random()*Number.MAX_SAFE_INTEGER); - } + // every user object should have a persistent, random number + if (typeof(proxy.loginToken) !== 'number') { + proxy[tokenKey] = Math.floor(Math.random()*Number.MAX_SAFE_INTEGER); + } - // copy User_hash into sessionStorage because cross-domain iframes - // on safari replaces localStorage with sessionStorage or something - if (sessionStorage) { sessionStorage.setItem('User_hash', localStorage.getItem('User_hash')); } - - var localToken = tryParsing(localStorage.getItem(tokenKey)); - if (localToken === null) { - // if that number hasn't been set to localStorage, do so. - localStorage.setItem(tokenKey, proxy.loginToken); - } else if (localToken !== proxy[tokenKey]) { - // if it has been, and the local number doesn't match that in - // the user object, request that they reauthenticate. - return void requestLogin(); + // copy User_hash into sessionStorage because cross-domain iframes + // on safari replaces localStorage with sessionStorage or something + if (sessionStorage) { sessionStorage.setItem('User_hash', localStorage.getItem('User_hash')); } + + var localToken = tryParsing(localStorage.getItem(tokenKey)); + if (localToken === null) { + // if that number hasn't been set to localStorage, do so. + localStorage.setItem(tokenKey, proxy.loginToken); + } else if (localToken !== proxy[tokenKey]) { + // if it has been, and the local number doesn't match that in + // the user object, request that they reauthenticate. + return void requestLogin(); + } } - } - - if (typeof(proxy.allowUserFeedback) !== 'boolean') { - proxy.allowUserFeedback = true; - } - 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(); - } + if (typeof(proxy.allowUserFeedback) !== 'boolean') { + proxy.allowUserFeedback = true; + } - // if the user is logged in, but does not have signing keys... - if (Cryptpad.isLoggedIn() && !Cryptpad.hasSigningKeys(proxy)) { - return void requestLogin(); - } + 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.on('change', [Cryptpad.displayNameKey], function (o, n) { - if (typeof(n) !== "string") { return; } - Cryptpad.changeDisplayName(n); - }); - proxy.on('change', [tokenKey], function () { - console.log('wut'); - var localToken = tryParsing(localStorage.getItem(tokenKey)); - if (localToken !== proxy[tokenKey]) { + // if the user is logged in, but does not have signing keys... + if (Cryptpad.isLoggedIn() && !Cryptpad.hasSigningKeys(proxy)) { return void requestLogin(); } - }); + + proxy.on('change', [Cryptpad.displayNameKey], function (o, n) { + if (typeof(n) !== "string") { return; } + Cryptpad.changeDisplayName(n); + }); + proxy.on('change', [tokenKey], function () { + console.log('wut'); + var localToken = tryParsing(localStorage.getItem(tokenKey)); + if (localToken !== proxy[tokenKey]) { + return void requestLogin(); + } + }); + }; + fo.migrate(todo); }; var initialized = false; @@ -260,6 +265,7 @@ define([ var rt = window.rt = Listmap.create(listmapConfig); + exp.realtime = rt.realtime; exp.proxy = rt.proxy; rt.proxy.on('create', function (info) { exp.info = info; @@ -291,10 +297,13 @@ define([ return; } }) - .on('change', ['drive'], function () { + .on('change', [], function () { var path = arguments[2]; var value = arguments[1]; - if (path[1] === "migrate" && value === 1) { + console.log('abcd'); + console.log(arguments); + if (path[0] === 'drive' && path[1] === "migrate" && value === 1) { + console.log('PEWPEWPEW'); rt.network.disconnect(); rt.realtime.abort(); Cryptpad.alert("Disconnected while migration"); diff --git a/www/common/mergeDrive.js b/www/common/mergeDrive.js index 05603f56c..50188fd6e 100644 --- a/www/common/mergeDrive.js +++ b/www/common/mergeDrive.js @@ -106,51 +106,54 @@ define([ var oldFo = FO.init(parsed.drive, { Cryptpad: Cryptpad }); - oldFo.fixFiles(); - var newData = Cryptpad.getStore().getProxy(); - var newFo = newData.fo; - var oldRecentPads = parsed.drive[newFo.FILES_DATA]; - var newRecentPads = proxy.drive[newFo.FILES_DATA]; - var newFiles = newFo.getFiles([newFo.FILES_DATA]); - var oldFiles = oldFo.getFiles([newFo.FILES_DATA]); - oldFiles.forEach(function (id) { - var href = oldRecentPads[id].href; - // Do not migrate a pad if we already have it, it would create a duplicate in the drive - if (newFiles.indexOf(id) !== -1) { return; } - // If we have a stronger version, do not add the current href - if (Cryptpad.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); - if (weaker) { - // Update RECENTPADS - newRecentPads.some(function (pad) { - if (pad.href === weaker) { - pad.href = href; - return true; - } + var todo = function () { + oldFo.fixFiles(); + var newData = Cryptpad.getStore().getProxy(); + var newFo = newData.fo; + var oldRecentPads = parsed.drive[newFo.FILES_DATA]; + var newRecentPads = proxy.drive[newFo.FILES_DATA]; + var newFiles = newFo.getFiles([newFo.FILES_DATA]); + var oldFiles = oldFo.getFiles([newFo.FILES_DATA]); + oldFiles.forEach(function (id) { + var href = oldRecentPads[id].href; + // Do not migrate a pad if we already have it, it would create a duplicate in the drive + if (newFiles.indexOf(id) !== -1) { return; } + // If we have a stronger version, do not add the current href + if (Cryptpad.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); + if (weaker) { + // Update RECENTPADS + newRecentPads.some(function (pad) { + if (pad.href === weaker) { + pad.href = href; + return true; + } + return; + }); + // Update the file in the drive + newFo.replace(weaker, href); return; - }); - // Update the file in the drive - newFo.replace(weaker, href); - return; - } - // Here it means we have a new href, so we should add it to the drive at its old location - var paths = oldFo.findFile(id); - if (paths.length === 0) { return; } - // Add the file data in our array and use the id to add the file - var data = oldFo.getFileData(id); - if (data) { - newFo.pushData(data, function (err, id) { - if (err) { return void console.error("Cannot import file:", data, err); } - createFromPath(proxy, oldFo, paths[0], id); - }); + } + // Here it means we have a new href, so we should add it to the drive at its old location + var paths = oldFo.findFile(id); + if (paths.length === 0) { return; } + // Add the file data in our array and use the id to add the file + var data = oldFo.getFileData(id); + if (data) { + newFo.pushData(data, function (err, id) { + if (err) { return void console.error("Cannot import file:", data, err); } + createFromPath(proxy, oldFo, paths[0], id); + }); + } + }); + if (!proxy.FS_hashes || !Array.isArray(proxy.FS_hashes)) { + proxy.FS_hashes = []; } - }); - if (!proxy.FS_hashes || !Array.isArray(proxy.FS_hashes)) { - proxy.FS_hashes = []; - } - proxy.FS_hashes.push(localStorage.FS_hash); + proxy.FS_hashes.push(localStorage.FS_hash); + }; + oldFo.migrate(todo); } if (typeof(cb) === "function") { cb(); } }; diff --git a/www/common/userObject.js b/www/common/userObject.js index 68fe94a04..9b4cbced2 100644 --- a/www/common/userObject.js +++ b/www/common/userObject.js @@ -759,7 +759,101 @@ define([ * INTEGRITY CHECK */ + exp.migrate = function (cb) { + // Make sure unsorted doesn't exist anymore + // Note: Unsorted only works with the old structure where pads are href + // It should be called before the migration code + var fixUnsorted = function () { + if (!files[UNSORTED] || !files[OLD_FILES_DATA]) { return; } + debug("UNSORTED still exists in the object, removing it..."); + var us = files[UNSORTED]; + if (us.length === 0) { + delete files[UNSORTED]; + return; + } + var root = find([ROOT]); + us.forEach(function (el) { + if (typeof el !== "string") { + return; + } + var data = files[OLD_FILES_DATA].filter(function (x) { + return x.href === el; + }); + if (data.length === 0) { + files[OLD_FILES_DATA].push({ + href: el + }); + } + return; + }); + delete files[UNSORTED]; + }; + // mergeDrive... + var migrateToNewFormat = function (todo) { + if (!files[OLD_FILES_DATA]) { + return void todo(); + } + try { + debug("Migrating file system..."); + files.migrate = 1; + if (exp.rt) { exp.rt.sync(); } + window.setTimeout(function () { + var oldData = files[OLD_FILES_DATA].slice(); + if (!files[FILES_DATA]) { + files[FILES_DATA] = {}; + } + var newData = files[FILES_DATA]; + //var oldFiles = oldData.map(function (o) { return o.href; }); + oldData.forEach(function (obj) { + if (!obj || !obj.href) { return; } + var href = obj.href; + var id = Cryptpad.createRandomInteger(); + var paths = findFile(href); + var data = obj; + var key = Cryptpad.createChannelId(); + if (data) { + newData[id] = data; + } else { + newData[id] = {href: href}; + } + paths.forEach(function (p) { + var parentPath = p.slice(); + var okey = parentPath.pop(); // get the parent + var parent = find(parentPath); + if (isInTrashRoot(p)) { + parent.element = id; + newData[id].filename = p[1]; + return; + } + if (isPathIn(p, ['hrefArray'])) { + parent[okey] = id; + return; + } + // else root or trash (not trashroot) + parent[key] = id; + newData[id].filename = okey; + delete parent[okey]; + }); + }); + files[OLD_FILES_DATA] = undefined; + delete files[OLD_FILES_DATA]; + files.migrate = undefined; + delete files.migrate; + console.log('done'); + todo(); + }, 300); + } catch(e) { + console.error(e); + todo(); + } + }; + + fixUnsorted(); + migrateToNewFormat(cb); + }; + exp.fixFiles = function () { + console.error('.'); // 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 @@ -882,87 +976,6 @@ define([ }); }; - // Make sure unsorted doesn't exist anymore - // Note: Unsorted only works with the old structure where pads are href - // It should be called before the migration code - var fixUnsorted = function () { - if (!files[UNSORTED] || !files[OLD_FILES_DATA]) { return; } - debug("UNSORTED still exists in the object, removing it..."); - var us = files[UNSORTED]; - if (us.length === 0) { - delete files[UNSORTED]; - return; - } - var root = find([ROOT]); - us.forEach(function (el) { - if (typeof el !== "string") { - return; - } - var data = files[OLD_FILES_DATA].filter(function (x) { - return x.href === el; - }); - if (data.length === 0) { - files[OLD_FILES_DATA].push({ - href: el - }); - } - return; - }); - delete files[UNSORTED]; - }; - // mergeDrive... - var migrateToNewFormat = function () { - if (!files[OLD_FILES_DATA]) { return; } - try { - files.migrate = 1; - var oldData = files[OLD_FILES_DATA].slice(); - if (!files[FILES_DATA]) { - files[FILES_DATA] = {}; - } - var newData = files[FILES_DATA]; - //var oldFiles = oldData.map(function (o) { return o.href; }); - oldData.forEach(function (obj) { - if (!obj || !obj.href) { return; } - var href = obj.href; - var id = Cryptpad.createRandomInteger(); - var paths = findFile(href); - var data = obj; - var key = Cryptpad.createChannelId(); - if (data) { - newData[id] = data; - } else { - newData[id] = {href: href}; - } - paths.forEach(function (p) { - var parentPath = p.slice(); - var okey = parentPath.pop(); // get the parent - var parent = find(parentPath); - if (isInTrashRoot(p)) { - parent.element = id; - newData[id].filename = p[1]; - return; - } - if (isPathIn(p, ['hrefArray'])) { - parent[okey] = id; - return; - } - // else root or trash (not trashroot) - parent[key] = id; - newData[id].filename = okey; - delete parent[okey]; - }); - }); - files[OLD_FILES_DATA] = undefined; - delete files[OLD_FILES_DATA]; - files.migrate = undefined; - delete files.migrate; - } catch(e) { - console.error(e); - } - }; - - fixUnsorted(); - migrateToNewFormat(); fixRoot(); fixTrashRoot(); if (!workgroup) { diff --git a/www/drive/main.js b/www/drive/main.js index 85fe00d50..16659786b 100644 --- a/www/drive/main.js +++ b/www/drive/main.js @@ -2504,6 +2504,7 @@ define([ module.resetTree(); return false; }).on('change', ['drive', 'migrate'], function () { + console.log('OKOKOK'); var path = arguments[2]; var value = arguments[1]; if (path[1] === "migrate" && value === 1) {