|
|
|
require.config({ paths: { 'json.sortify': '/bower_components/json.sortify/dist/JSON.sortify' } });
|
|
|
|
define([
|
|
|
|
'/common/cryptpad-common.js',
|
|
|
|
'/common/cryptget.js',
|
|
|
|
'/common/userObject.js',
|
|
|
|
'json.sortify'
|
|
|
|
], function (Cryptpad, Crypt, FO, Sortify) {
|
|
|
|
var exp = {};
|
|
|
|
|
|
|
|
var getType = function (el) {
|
|
|
|
if (el === null) { return "null"; }
|
|
|
|
return Array.isArray(el) ? "array" : typeof(el);
|
|
|
|
};
|
|
|
|
|
|
|
|
var findAvailableKey = function (obj, key) {
|
|
|
|
if (typeof (obj[key]) === "undefined") { return key; }
|
|
|
|
var i = 1;
|
|
|
|
var nkey = key;
|
|
|
|
while (typeof (obj[nkey]) !== "undefined") {
|
|
|
|
nkey = key + '_' + i;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
return nkey;
|
|
|
|
};
|
|
|
|
|
|
|
|
var copy = function (el) {
|
|
|
|
if (typeof (el) !== "object") { return el; }
|
|
|
|
return JSON.parse(JSON.stringify(el));
|
|
|
|
};
|
|
|
|
|
|
|
|
var deduplicate = function (array) {
|
|
|
|
var a = array.slice();
|
|
|
|
for(var i=0; i<a.length; i++) {
|
|
|
|
for(var j=i+1; j<a.length; j++) {
|
|
|
|
if(a[i] === a[j] || (
|
|
|
|
typeof(a[i]) === "object" && Sortify(a[i]) === Sortify(a[j]))) {
|
|
|
|
a.splice(j--, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return a;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Merge obj2 into obj1
|
|
|
|
// If keepOld is true, obj1 values are kept in case of conflicti
|
|
|
|
// Not used ATM
|
|
|
|
var merge = function (obj1, obj2, keepOld) {
|
|
|
|
if (typeof (obj1) !== "object" || typeof (obj2) !== "object") { return; }
|
|
|
|
Object.keys(obj2).forEach(function (k) {
|
|
|
|
var v = obj2[k];
|
|
|
|
// If one of them is not an object or if we have a map and a array, don't override, create a new key
|
|
|
|
if (!obj1[k] || typeof(obj1[k]) !== "object" || typeof(obj2[k]) !== "object" ||
|
|
|
|
(getType(obj1[k]) !== getType(obj2[k]))) {
|
|
|
|
// We don't want to override the values in the object (username, preferences)
|
|
|
|
// These values should be the ones stored in the first object
|
|
|
|
if (keepOld) { return; }
|
|
|
|
if (obj1[k] === obj2[k]) { return; }
|
|
|
|
var nkey = findAvailableKey(obj1, k);
|
|
|
|
obj1[nkey] = copy(obj2[k]);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Else, they're both maps or both arrays
|
|
|
|
if (getType(obj1[k]) === "array" && getType(obj2[k]) === "array") {
|
|
|
|
var c = obj1[k].concat(obj2[k]);
|
|
|
|
obj1[k] = deduplicate(c);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
merge(obj1[k], obj2[k], keepOld);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
var createFromPath = function (proxy, oldFo, path, href) {
|
|
|
|
var root = proxy.drive;
|
|
|
|
|
|
|
|
var error = function (msg) {
|
|
|
|
console.error(msg || "Unable to find that path", path);
|
|
|
|
};
|
|
|
|
|
|
|
|
if (oldFo.isInTrashRoot(path)) {
|
|
|
|
href = oldFo.find(path.slice(0,3));
|
|
|
|
path.pop();
|
|
|
|
}
|
|
|
|
|
|
|
|
var p, next, nextRoot;
|
|
|
|
path.forEach(function (p, i) {
|
|
|
|
if (!root) { return; }
|
|
|
|
if (typeof(p) === "string") {
|
|
|
|
if (getType(root) !== "object") { root = undefined; error(); return; }
|
|
|
|
if (i === path.length - 1) {
|
|
|
|
root[findAvailableKey(root, p)] = href;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
next = getType(path[i+1]);
|
|
|
|
nextRoot = getType(root[p]);
|
|
|
|
if (nextRoot !== "undefined") {
|
|
|
|
if (next === "string" && nextRoot === "object" || next === "number" && nextRoot === "array") {
|
|
|
|
root = root[p];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
p = findAvailableKey(root, p);
|
|
|
|
}
|
|
|
|
if (next === "number") {
|
|
|
|
root[p] = [];
|
|
|
|
root = root[p];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
root[p] = {};
|
|
|
|
root = root[p];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Path contains a non-string element: it's an array index
|
|
|
|
if (typeof(p) !== "number") { root = undefined; error(); return; }
|
|
|
|
if (getType(root) !== "array") { root = undefined; error(); return; }
|
|
|
|
if (i === path.length - 1) {
|
|
|
|
if (root.indexOf(href) === -1) { root.push(href); }
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
next = getType(path[i+1]);
|
|
|
|
if (next === "number") {
|
|
|
|
error('2 consecutives arrays in the user object');
|
|
|
|
root = undefined;
|
|
|
|
//root.push([]);
|
|
|
|
//root = root[root.length - 1];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
root.push({});
|
|
|
|
root = root[root.length - 1];
|
|
|
|
return;
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
var mergeAnonDrive = exp.anonDriveIntoUser = function (proxy, cb) {
|
|
|
|
// Make sure we have an FS_hash and we don't use it, otherwise just stop the migration and cb
|
|
|
|
if (!localStorage.FS_hash || !Cryptpad.isLoggedIn()) {
|
|
|
|
if (typeof(cb) === "function") { cb(); }
|
|
|
|
}
|
|
|
|
// Get the content of FS_hash and then merge the objects, remove the migration key and cb
|
|
|
|
var todo = function (err, doc) {
|
|
|
|
if (err) { console.error("Cannot migrate recent pads", err); return; }
|
|
|
|
var parsed;
|
|
|
|
if (!doc) {
|
|
|
|
if (typeof(cb) === "function") { cb(); }
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
try { parsed = JSON.parse(doc); } catch (e) {
|
|
|
|
if (typeof(cb) === "function") { cb(); }
|
|
|
|
console.error("Cannot parsed recent pads", e);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (parsed) {
|
|
|
|
//merge(proxy, parsed, true);
|
|
|
|
var oldFo = FO.init(parsed.drive, {
|
|
|
|
Cryptpad: Cryptpad
|
|
|
|
});
|
|
|
|
oldFo.fixFiles();
|
|
|
|
var newData = Cryptpad.getStore().getProxy();
|
|
|
|
var newFo = newData.fo;
|
|
|
|
var newRecentPads = proxy.drive[Cryptpad.storageKey];
|
|
|
|
var newFiles = newFo.getFiles([newFo.FILES_DATA]);
|
|
|
|
var oldFiles = oldFo.getFiles([newFo.FILES_DATA]);
|
|
|
|
oldFiles.forEach(function (href) {
|
|
|
|
// Do not migrate a pad if we already have it, it would create a duplicate in the drive
|
|
|
|
if (newFiles.indexOf(href) !== -1) { return; }
|
|
|
|
// If we have a stronger version, do not add the current href
|
|
|
|
if (Cryptpad.findStronger(href, newRecentPads)) { console.log(href); 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;
|
|
|
|
}
|
|
|
|
// Here it means we have a new href, so we should add it to the drive at its old location
|
|
|
|
var paths = oldFo.findFile(href);
|
|
|
|
if (paths.length === 0) { return; }
|
|
|
|
createFromPath(proxy, oldFo, paths[0], href);
|
|
|
|
// Also, push the file data in our array
|
|
|
|
var data = oldFo.getFileData(href);
|
|
|
|
if (data) {
|
|
|
|
newRecentPads.push(data);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (typeof(cb) === "function") { cb(); }
|
|
|
|
};
|
|
|
|
Crypt.get(localStorage.FS_hash, todo);
|
|
|
|
};
|
|
|
|
|
|
|
|
return exp;
|
|
|
|
});
|