cryptpad/www/common/outer/sharedfolder.js

202 lines
7.2 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

define([
'/common/common-hash.js',
'/common/common-util.js',
'/common/userObject.js',
'/bower_components/nthen/index.js',
'/bower_components/chainpad-crypto/crypto.js',
'/bower_components/chainpad-listmap/chainpad-listmap.js',
'/bower_components/chainpad/chainpad.dist.js',
], function (Hash, Util, UserObject,
nThen, Crypto, Listmap, ChainPad) {
var SF = {};
/* load
create and load a proxy using listmap for a given shared folder
- config: network and "manager" (either the user one or a team manager)
- id: shared folder id
*/
var allSharedFolders = {};
SF.load = function (config, id, data, cb) {
var network = config.network;
var store = config.store;
var isNew = config.isNew;
var isNewChannel = config.isNewChannel;
var teamId = store.id;
var handler = store.handleSharedFolder;
var parsed = Hash.parsePadUrl(data.href);
var secret = Hash.getSecrets('drive', parsed.hash, data.password);
// If we try to load en existing shared folder (isNew === false) but this folder
// doesn't exist in the database, abort and cb
nThen(function (waitFor) {
isNewChannel(null, { channel: secret.channel }, waitFor(function (obj) {
if (obj.isNew && !isNew) {
store.manager.deprecateProxy(id, secret.channel);
waitFor.abort();
return void cb(null);
}
}));
}).nThen(function () {
var sf = allSharedFolders[secret.channel];
if (sf && sf.ready && sf.rt) {
// The shared folder is already loaded, return its data
setTimeout(function () {
var leave = function () { SF.leave(secret.channel, teamId); };
store.manager.addProxy(id, sf.rt.proxy, leave);
cb(sf.rt, sf.metadata);
});
sf.teams.push(store);
if (handler) { handler(id, sf.rt); }
return sf.rt;
}
if (sf && sf.queue && sf.rt) {
// The shared folder is loading, add our callbacks to the queue
sf.queue.push({
cb: cb,
store: store,
id: id
});
sf.teams.push(store);
if (handler) { handler(id, sf.rt); }
return sf.rt;
}
sf = allSharedFolders[secret.channel] = {
queue: [{
cb: cb,
store: store,
id: id
}],
teams: [store]
};
var owners = data.owners;
var listmapConfig = {
data: {},
channel: secret.channel,
readOnly: false,
crypto: Crypto.createEncryptor(secret.keys),
userName: 'sharedFolder',
logLevel: 1,
ChainPad: ChainPad,
classic: true,
network: network,
metadata: {
validateKey: secret.keys.validateKey || undefined,
owners: owners
}
};
var rt = sf.rt = Listmap.create(listmapConfig);
rt.proxy.on('ready', function (info) {
if (!sf.queue) {
return;
}
sf.queue.forEach(function (obj) {
var leave = function () { SF.leave(secret.channel, teamId); };
obj.store.manager.addProxy(obj.id, rt.proxy, leave);
obj.cb(rt, info.metadata);
});
sf.metadata = info.metadata;
sf.ready = true;
delete sf.queue;
});
rt.proxy.on('error', function (info) {
if (info && info.error) {
if (info.error === "EDELETED" ) {
try {
// Deprecate the shared folder from each team
sf.teams.forEach(function (store) {
store.manager.deprecateProxy(id, secret.channel);
});
} catch (e) {}
delete allSharedFolders[secret.channel];
}
}
});
if (handler) { handler(id, rt); }
});
};
SF.leave = function (channel, teamId) {
var sf = allSharedFolders[channel];
if (!sf) { return; }
var clients = sf.teams;
if (!Array.isArray(clients)) { return; }
var idx;
clients.some(function (store, i) {
if (store.id === teamId) {
idx = i;
return true;
}
});
if (typeof (idx) === "undefined") { return; }
// Remove the selected team
clients.splice(idx, 1);
//If all the teams have closed this shared folder, stop it
if (clients.length) { return; }
if (sf.rt && sf.rt.stop) {
sf.rt.stop();
}
};
SF.updatePassword = function (Store, data, network, cb) {
var oldChannel = data.oldChannel;
var href = data.href;
var password = data.password;
var parsed = Hash.parsePadUrl(href);
var secret = Hash.getSecrets(parsed.type, parsed.hash, password);
var sf = allSharedFolders[oldChannel];
if (!sf) { return void cb({ error: 'ENOTFOUND' }); }
if (sf.rt && sf.rt.stop) {
sf.rt.stop();
}
var nt = nThen;
sf.teams.forEach(function (s) {
nt = nt(function (waitFor) {
var sfId = s.manager.user.userObject.getSFIdFromHref(href);
var shared = Util.find(s.proxy, ['drive', UserObject.SHARED_FOLDERS]) || {};
if (!sfId || !shared[sfId]) { return; }
var sf = JSON.parse(JSON.stringify(shared[sfId]));
sf.password = password;
SF.load({
network: network,
store: s,
isNewChannel: Store.isNewChannel
}, sfId, sf, waitFor());
if (!s.rpc) { return; }
s.rpc.unpin([oldChannel], waitFor());
s.rpc.pin([secret.channel], waitFor());
}).nThen;
});
nt(cb);
};
/* loadSharedFolders
load all shared folder stored in a given drive
- store: user or team main store
- userObject: userObject associated to the main drive
- handler: a function (sfid, rt) called for each shared folder loaded
*/
SF.loadSharedFolders = function (Store, network, store, userObject, waitFor) {
var shared = Util.find(store.proxy, ['drive', UserObject.SHARED_FOLDERS]) || {};
nThen(function (waitFor) {
Object.keys(shared).forEach(function (id) {
var sf = shared[id];
SF.load({
network: network,
store: store,
isNewChannel: Store.isNewChannel
}, id, sf, waitFor());
});
}).nThen(waitFor());
};
return SF;
});