pull/1/head
yflory 8 years ago
parent f8c69573fd
commit 2a94bdaf05

@ -141,76 +141,81 @@ define([
var onReady = function (f, proxy, Cryptpad, exp) { var onReady = function (f, proxy, Cryptpad, exp) {
var fo = exp.fo = FO.init(proxy.drive, { var fo = exp.fo = FO.init(proxy.drive, {
Cryptpad: Cryptpad Cryptpad: Cryptpad,
rt: exp.realtime
}); });
var todo = function () {
fo.fixFiles();
//storeObj = proxy; //storeObj = proxy;
store = initStore(fo, proxy, exp); store = initStore(fo, proxy, exp);
if (typeof(f) === 'function') { if (typeof(f) === 'function') {
f(void 0, store); f(void 0, store);
} }
var requestLogin = function () { var requestLogin = function () {
// log out so that you don't go into an endless loop... // log out so that you don't go into an endless loop...
Cryptpad.logout(); Cryptpad.logout();
// redirect them to log in, and come back when they're done. // redirect them to log in, and come back when they're done.
sessionStorage.redirectTo = window.location.href; sessionStorage.redirectTo = window.location.href;
window.location.href = '/login/'; window.location.href = '/login/';
}; };
var tokenKey = 'loginToken'; var tokenKey = 'loginToken';
if (Cryptpad.isLoggedIn()) { if (Cryptpad.isLoggedIn()) {
/* This isn't truly secure, since anyone who can read the user's object can /* 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 set their local loginToken to match that in the object. However, it exposes
a UI that will work most of the time. */ a UI that will work most of the time. */
// every user object should have a persistent, random number // every user object should have a persistent, random number
if (typeof(proxy.loginToken) !== 'number') { if (typeof(proxy.loginToken) !== 'number') {
proxy[tokenKey] = Math.floor(Math.random()*Number.MAX_SAFE_INTEGER); proxy[tokenKey] = Math.floor(Math.random()*Number.MAX_SAFE_INTEGER);
} }
// copy User_hash into sessionStorage because cross-domain iframes // copy User_hash into sessionStorage because cross-domain iframes
// on safari replaces localStorage with sessionStorage or something // on safari replaces localStorage with sessionStorage or something
if (sessionStorage) { sessionStorage.setItem('User_hash', localStorage.getItem('User_hash')); } if (sessionStorage) { sessionStorage.setItem('User_hash', localStorage.getItem('User_hash')); }
var localToken = tryParsing(localStorage.getItem(tokenKey)); var localToken = tryParsing(localStorage.getItem(tokenKey));
if (localToken === null) { if (localToken === null) {
// if that number hasn't been set to localStorage, do so. // if that number hasn't been set to localStorage, do so.
localStorage.setItem(tokenKey, proxy.loginToken); localStorage.setItem(tokenKey, proxy.loginToken);
} else if (localToken !== proxy[tokenKey]) { } else if (localToken !== proxy[tokenKey]) {
// if it has been, and the local number doesn't match that in // if it has been, and the local number doesn't match that in
// the user object, request that they reauthenticate. // the user object, request that they reauthenticate.
return void requestLogin(); return void requestLogin();
}
} }
}
if (typeof(proxy.allowUserFeedback) !== 'boolean') {
proxy.allowUserFeedback = true;
}
if (typeof(proxy.uid) !== 'string' || proxy.uid.length !== 32) { if (typeof(proxy.allowUserFeedback) !== 'boolean') {
// even anonymous users should have a persistent, unique-ish id proxy.allowUserFeedback = true;
console.log('generating a persistent identifier'); }
proxy.uid = Cryptpad.createChannelId();
}
// if the user is logged in, but does not have signing keys... if (typeof(proxy.uid) !== 'string' || proxy.uid.length !== 32) {
if (Cryptpad.isLoggedIn() && !Cryptpad.hasSigningKeys(proxy)) { // even anonymous users should have a persistent, unique-ish id
return void requestLogin(); console.log('generating a persistent identifier');
} proxy.uid = Cryptpad.createChannelId();
}
proxy.on('change', [Cryptpad.displayNameKey], function (o, n) { // if the user is logged in, but does not have signing keys...
if (typeof(n) !== "string") { return; } if (Cryptpad.isLoggedIn() && !Cryptpad.hasSigningKeys(proxy)) {
Cryptpad.changeDisplayName(n);
});
proxy.on('change', [tokenKey], function () {
console.log('wut');
var localToken = tryParsing(localStorage.getItem(tokenKey));
if (localToken !== proxy[tokenKey]) {
return void requestLogin(); 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; var initialized = false;
@ -260,6 +265,7 @@ define([
var rt = window.rt = Listmap.create(listmapConfig); var rt = window.rt = Listmap.create(listmapConfig);
exp.realtime = rt.realtime;
exp.proxy = rt.proxy; exp.proxy = rt.proxy;
rt.proxy.on('create', function (info) { rt.proxy.on('create', function (info) {
exp.info = info; exp.info = info;
@ -291,10 +297,13 @@ define([
return; return;
} }
}) })
.on('change', ['drive'], function () { .on('change', [], function () {
var path = arguments[2]; var path = arguments[2];
var value = arguments[1]; 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.network.disconnect();
rt.realtime.abort(); rt.realtime.abort();
Cryptpad.alert("Disconnected while migration"); Cryptpad.alert("Disconnected while migration");

@ -106,51 +106,54 @@ define([
var oldFo = FO.init(parsed.drive, { var oldFo = FO.init(parsed.drive, {
Cryptpad: Cryptpad Cryptpad: Cryptpad
}); });
oldFo.fixFiles(); var todo = function () {
var newData = Cryptpad.getStore().getProxy(); oldFo.fixFiles();
var newFo = newData.fo; var newData = Cryptpad.getStore().getProxy();
var oldRecentPads = parsed.drive[newFo.FILES_DATA]; var newFo = newData.fo;
var newRecentPads = proxy.drive[newFo.FILES_DATA]; var oldRecentPads = parsed.drive[newFo.FILES_DATA];
var newFiles = newFo.getFiles([newFo.FILES_DATA]); var newRecentPads = proxy.drive[newFo.FILES_DATA];
var oldFiles = oldFo.getFiles([newFo.FILES_DATA]); var newFiles = newFo.getFiles([newFo.FILES_DATA]);
oldFiles.forEach(function (id) { var oldFiles = oldFo.getFiles([newFo.FILES_DATA]);
var href = oldRecentPads[id].href; oldFiles.forEach(function (id) {
// Do not migrate a pad if we already have it, it would create a duplicate in the drive var href = oldRecentPads[id].href;
if (newFiles.indexOf(id) !== -1) { return; } // Do not migrate a pad if we already have it, it would create a duplicate in the drive
// If we have a stronger version, do not add the current href if (newFiles.indexOf(id) !== -1) { return; }
if (Cryptpad.findStronger(href, newRecentPads)) { return; } // If we have a stronger version, do not add the current href
// If we have a weaker version, replace the href by the new one if (Cryptpad.findStronger(href, newRecentPads)) { return; }
// NOTE: if that weaker version is in the trash, the strong one will be put in unsorted // If we have a weaker version, replace the href by the new one
var weaker = Cryptpad.findWeaker(href, newRecentPads); // NOTE: if that weaker version is in the trash, the strong one will be put in unsorted
if (weaker) { var weaker = Cryptpad.findWeaker(href, newRecentPads);
// Update RECENTPADS if (weaker) {
newRecentPads.some(function (pad) { // Update RECENTPADS
if (pad.href === weaker) { newRecentPads.some(function (pad) {
pad.href = href; if (pad.href === weaker) {
return true; pad.href = href;
} return true;
}
return;
});
// Update the file in the drive
newFo.replace(weaker, href);
return; return;
}); }
// Update the file in the drive // Here it means we have a new href, so we should add it to the drive at its old location
newFo.replace(weaker, href); var paths = oldFo.findFile(id);
return; if (paths.length === 0) { return; }
} // Add the file data in our array and use the id to add the file
// Here it means we have a new href, so we should add it to the drive at its old location var data = oldFo.getFileData(id);
var paths = oldFo.findFile(id); if (data) {
if (paths.length === 0) { return; } newFo.pushData(data, function (err, id) {
// Add the file data in our array and use the id to add the file if (err) { return void console.error("Cannot import file:", data, err); }
var data = oldFo.getFileData(id); createFromPath(proxy, oldFo, paths[0], 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 = [];
} }
}); proxy.FS_hashes.push(localStorage.FS_hash);
if (!proxy.FS_hashes || !Array.isArray(proxy.FS_hashes)) { };
proxy.FS_hashes = []; oldFo.migrate(todo);
}
proxy.FS_hashes.push(localStorage.FS_hash);
} }
if (typeof(cb) === "function") { cb(); } if (typeof(cb) === "function") { cb(); }
}; };

@ -759,7 +759,101 @@ define([
* INTEGRITY CHECK * 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 () { exp.fixFiles = function () {
console.error('.');
// Explore the tree and check that everything is correct: // Explore the tree and check that everything is correct:
// * 'root', 'trash', 'unsorted' and 'filesData' exist and are objects // * 'root', 'trash', 'unsorted' and 'filesData' exist and are objects
// * ROOT: Folders are objects, files are href // * 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(); fixRoot();
fixTrashRoot(); fixTrashRoot();
if (!workgroup) { if (!workgroup) {

@ -2504,6 +2504,7 @@ define([
module.resetTree(); module.resetTree();
return false; return false;
}).on('change', ['drive', 'migrate'], function () { }).on('change', ['drive', 'migrate'], function () {
console.log('OKOKOK');
var path = arguments[2]; var path = arguments[2];
var value = arguments[1]; var value = arguments[1];
if (path[1] === "migrate" && value === 1) { if (path[1] === "migrate" && value === 1) {

Loading…
Cancel
Save