Fix read-only shared folders with password change
This commit is contained in:
parent
0583ed3c8b
commit
f9723a6183
@ -6,6 +6,7 @@ define([
|
|||||||
'/common/common-messaging.js',
|
'/common/common-messaging.js',
|
||||||
'/common/common-constants.js',
|
'/common/common-constants.js',
|
||||||
'/common/common-feedback.js',
|
'/common/common-feedback.js',
|
||||||
|
'/common/userObject.js',
|
||||||
'/common/outer/local-store.js',
|
'/common/outer/local-store.js',
|
||||||
'/common/outer/worker-channel.js',
|
'/common/outer/worker-channel.js',
|
||||||
'/common/outer/login-block.js',
|
'/common/outer/login-block.js',
|
||||||
@ -13,7 +14,7 @@ define([
|
|||||||
'/customize/application_config.js',
|
'/customize/application_config.js',
|
||||||
'/bower_components/nthen/index.js',
|
'/bower_components/nthen/index.js',
|
||||||
], function (Config, Messages, Util, Hash,
|
], function (Config, Messages, Util, Hash,
|
||||||
Messaging, Constants, Feedback, LocalStore, Channel, Block,
|
Messaging, Constants, Feedback, UserObject, LocalStore, Channel, Block,
|
||||||
AppConfig, Nthen) {
|
AppConfig, Nthen) {
|
||||||
|
|
||||||
/* This file exposes functionality which is specific to Cryptpad, but not to
|
/* This file exposes functionality which is specific to Cryptpad, but not to
|
||||||
@ -158,7 +159,7 @@ define([
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
common.addSharedFolder = function (teamId, secret, cb) {
|
common.addSharedFolder = function (teamId, secret, cb) {
|
||||||
var href = secret.keys && secret.keys.editKeyStr ? '/drive/#' + Hash.getEditHashFromKeys(secret) : undefined;
|
var href = (secret.keys && secret.keys.editKeyStr) ? '/drive/#' + Hash.getEditHashFromKeys(secret) : undefined;
|
||||||
postMessage("ADD_SHARED_FOLDER", {
|
postMessage("ADD_SHARED_FOLDER", {
|
||||||
teamId: teamId,
|
teamId: teamId,
|
||||||
path: ['root'],
|
path: ['root'],
|
||||||
@ -878,6 +879,8 @@ define([
|
|||||||
initialState: isSharedFolder ? '{}' : undefined
|
initialState: isSharedFolder ? '{}' : undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var cryptgetVal;
|
||||||
|
|
||||||
Nthen(function (waitFor) {
|
Nthen(function (waitFor) {
|
||||||
if (parsed.hashData && parsed.hashData.password) {
|
if (parsed.hashData && parsed.hashData.password) {
|
||||||
common.getPadAttribute('password', waitFor(function (err, password) {
|
common.getPadAttribute('password', waitFor(function (err, password) {
|
||||||
@ -946,13 +949,22 @@ define([
|
|||||||
waitFor.abort();
|
waitFor.abort();
|
||||||
return void cb({ error: err });
|
return void cb({ error: err });
|
||||||
}
|
}
|
||||||
Crypt.put(newHash, val, waitFor(function (err) {
|
cryptgetVal = val;
|
||||||
|
if (isSharedFolder) {
|
||||||
|
var parsed = JSON.parse(val || '{}');
|
||||||
|
var oldKey = parsed.version === 2 && oldSecret.keys.secondaryKey;
|
||||||
|
var newKey = newSecret.keys.secondaryKey;
|
||||||
|
UserObject.reencrypt(oldKey, newKey, parsed);
|
||||||
|
cryptgetVal = JSON.stringify(parsed);
|
||||||
|
}
|
||||||
|
}), optsGet);
|
||||||
|
}).nThen(function (waitFor) {
|
||||||
|
Crypt.put(newHash, cryptgetVal, waitFor(function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
waitFor.abort();
|
waitFor.abort();
|
||||||
return void cb({ error: err });
|
return void cb({ error: err });
|
||||||
}
|
}
|
||||||
}), optsPut);
|
}), optsPut);
|
||||||
}), optsGet);
|
|
||||||
}).nThen(function (waitFor) {
|
}).nThen(function (waitFor) {
|
||||||
if (isSharedFolder) {
|
if (isSharedFolder) {
|
||||||
postMessage("UPDATE_SHARED_FOLDER_PASSWORD", {
|
postMessage("UPDATE_SHARED_FOLDER_PASSWORD", {
|
||||||
@ -1514,7 +1526,6 @@ define([
|
|||||||
noWorker = localStorage.CryptPad_noWorkers === '1';
|
noWorker = localStorage.CryptPad_noWorkers === '1';
|
||||||
console.error('WebWorker/SharedWorker state forced to ' + !noWorker);
|
console.error('WebWorker/SharedWorker state forced to ' + !noWorker);
|
||||||
}
|
}
|
||||||
noWorker = true;
|
|
||||||
Nthen(function (waitFor2) {
|
Nthen(function (waitFor2) {
|
||||||
if (Worker) {
|
if (Worker) {
|
||||||
var w = waitFor2();
|
var w = waitFor2();
|
||||||
|
|||||||
@ -116,6 +116,7 @@ define([
|
|||||||
sf.teams.push({
|
sf.teams.push({
|
||||||
cb: cb,
|
cb: cb,
|
||||||
store: store,
|
store: store,
|
||||||
|
secondaryKey: secondaryKey,
|
||||||
id: id
|
id: id
|
||||||
});
|
});
|
||||||
if (handler) { handler(id, sf.rt); }
|
if (handler) { handler(id, sf.rt); }
|
||||||
@ -126,16 +127,17 @@ define([
|
|||||||
teams: [{
|
teams: [{
|
||||||
cb: cb,
|
cb: cb,
|
||||||
store: store,
|
store: store,
|
||||||
|
secondaryKey: secondaryKey,
|
||||||
id: id
|
id: id
|
||||||
}],
|
}],
|
||||||
readOnly: Boolean(secondaryKey)
|
readOnly: !Boolean(secondaryKey)
|
||||||
};
|
};
|
||||||
|
|
||||||
var owners = data.owners;
|
var owners = data.owners;
|
||||||
var listmapConfig = {
|
var listmapConfig = {
|
||||||
data: {},
|
data: {},
|
||||||
channel: secret.channel,
|
channel: secret.channel,
|
||||||
readOnly: Boolean(secondaryKey),
|
readOnly: !Boolean(secondaryKey),
|
||||||
crypto: Crypto.createEncryptor(secret.keys),
|
crypto: Crypto.createEncryptor(secret.keys),
|
||||||
userName: 'sharedFolder',
|
userName: 'sharedFolder',
|
||||||
logLevel: 1,
|
logLevel: 1,
|
||||||
@ -158,7 +160,7 @@ define([
|
|||||||
}
|
}
|
||||||
sf.teams.forEach(function (obj) {
|
sf.teams.forEach(function (obj) {
|
||||||
var leave = function () { SF.leave(secret.channel, teamId); };
|
var leave = function () { SF.leave(secret.channel, teamId); };
|
||||||
var uo = obj.store.manager.addProxy(obj.id, rt, leave, secondaryKey);
|
var uo = obj.store.manager.addProxy(obj.id, rt, leave, obj.secondaryKey);
|
||||||
SF.checkMigration(secondaryKey, rt.proxy, uo, function () {
|
SF.checkMigration(secondaryKey, rt.proxy, uo, function () {
|
||||||
obj.cb(sf.rt, info.metadata);
|
obj.cb(sf.rt, info.metadata);
|
||||||
});
|
});
|
||||||
@ -171,10 +173,8 @@ define([
|
|||||||
if (info.error === "EDELETED" ) {
|
if (info.error === "EDELETED" ) {
|
||||||
try {
|
try {
|
||||||
// Deprecate the shared folder from each team
|
// Deprecate the shared folder from each team
|
||||||
// XXX We can't deprecate a read-only proxy: the read-only seed will change...
|
// We can only hide it
|
||||||
// We can only remove it
|
|
||||||
sf.teams.forEach(function (obj) {
|
sf.teams.forEach(function (obj) {
|
||||||
console.log(obj.store.id, obj.store, obj.id);
|
|
||||||
obj.store.manager.deprecateProxy(obj.id, secret.channel);
|
obj.store.manager.deprecateProxy(obj.id, secret.channel);
|
||||||
});
|
});
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
@ -187,6 +187,7 @@ define([
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
SF.upgrade = function (channel, secret) {
|
SF.upgrade = function (channel, secret) {
|
||||||
var sf = allSharedFolders[channel];
|
var sf = allSharedFolders[channel];
|
||||||
if (!sf || !sf.readOnly) { return; }
|
if (!sf || !sf.readOnly) { return; }
|
||||||
@ -235,17 +236,21 @@ define([
|
|||||||
}
|
}
|
||||||
var nt = nThen;
|
var nt = nThen;
|
||||||
sf.teams.forEach(function (obj) {
|
sf.teams.forEach(function (obj) {
|
||||||
// XXX if we're a viewer in this team, we can't update the keys
|
|
||||||
nt = nt(function (waitFor) {
|
nt = nt(function (waitFor) {
|
||||||
var s = obj.store;
|
var s = obj.store;
|
||||||
var sfId = obj.id;
|
var sfId = obj.id;
|
||||||
|
// We can't update the password of a shared folder in a read-only team
|
||||||
|
if (s.manager.user.userObject.readOnly) {
|
||||||
|
// Just deprecate the folder so that inner can stop displaying a folder no longer available
|
||||||
|
if (s.manager.folders[sfId]) {
|
||||||
|
s.manager.folders[sfId].proxy = { deprecated: true };
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
var shared = Util.find(s.proxy, ['drive', UserObject.SHARED_FOLDERS]) || {};
|
var shared = Util.find(s.proxy, ['drive', UserObject.SHARED_FOLDERS]) || {};
|
||||||
if (!sfId || !shared[sfId]) { return; }
|
if (!sfId || !shared[sfId]) { return; }
|
||||||
var sf = JSON.parse(JSON.stringify(shared[sfId]));
|
var sf = JSON.parse(JSON.stringify(shared[sfId]));
|
||||||
sf.password = password;
|
sf.password = password;
|
||||||
sf.channel = secret.channel;
|
|
||||||
sf.href = '/drive/#'+Hash.getEditHashFromKeys(secret); // XXX encrypt
|
|
||||||
sf.roHref = '/drive/#'+Hash.getViewHashFromKeys(secret);
|
|
||||||
SF.load({
|
SF.load({
|
||||||
network: network,
|
network: network,
|
||||||
store: s,
|
store: s,
|
||||||
@ -256,7 +261,9 @@ define([
|
|||||||
s.rpc.pin([secret.channel], waitFor());
|
s.rpc.pin([secret.channel], waitFor());
|
||||||
}).nThen;
|
}).nThen;
|
||||||
});
|
});
|
||||||
nt(cb);
|
nt(function () {
|
||||||
|
cb();
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/* loadSharedFolders
|
/* loadSharedFolders
|
||||||
|
|||||||
@ -71,19 +71,21 @@ define([
|
|||||||
cb(null, clone(data[attr]));
|
cb(null, clone(data[attr]));
|
||||||
};
|
};
|
||||||
|
|
||||||
exp.pushData = function (data, cb) {
|
exp.pushData = function (_data, cb) {
|
||||||
if (typeof cb !== "function") { cb = function () {}; }
|
if (typeof cb !== "function") { cb = function () {}; }
|
||||||
if (readOnly) { return void cb('EFORBIDDEN'); }
|
if (readOnly) { return void cb('EFORBIDDEN'); }
|
||||||
var id = Util.createRandomInteger();
|
var id = Util.createRandomInteger();
|
||||||
|
var data = clone(_data);
|
||||||
// If we were given an edit link, encrypt its value if needed
|
// If we were given an edit link, encrypt its value if needed
|
||||||
if (data.href) { data.href = exp.cryptor.encrypt(data.href); }
|
if (data.href) { data.href = exp.cryptor.encrypt(data.href); }
|
||||||
files[FILES_DATA][id] = data;
|
files[FILES_DATA][id] = data;
|
||||||
cb(null, id);
|
cb(null, id);
|
||||||
};
|
};
|
||||||
|
|
||||||
exp.pushSharedFolder = function (data, cb) {
|
exp.pushSharedFolder = function (_data, cb) {
|
||||||
if (typeof cb !== "function") { cb = function () {}; }
|
if (typeof cb !== "function") { cb = function () {}; }
|
||||||
if (readOnly) { return void cb('EFORBIDDEN'); }
|
if (readOnly) { return void cb('EFORBIDDEN'); }
|
||||||
|
var data = clone(_data);
|
||||||
|
|
||||||
// Check if we already have this shared folder in our drive
|
// Check if we already have this shared folder in our drive
|
||||||
var exists;
|
var exists;
|
||||||
@ -476,6 +478,9 @@ define([
|
|||||||
files.migrateRo = 1;
|
files.migrateRo = 1;
|
||||||
var next = function () {
|
var next = function () {
|
||||||
var copy = JSON.parse(JSON.stringify(files));
|
var copy = JSON.parse(JSON.stringify(files));
|
||||||
|
exp.reencrypt(null, config.editKey, copy);
|
||||||
|
// XXX test migration again
|
||||||
|
/*
|
||||||
Object.keys(copy[FILES_DATA]).forEach(function (id) {
|
Object.keys(copy[FILES_DATA]).forEach(function (id) {
|
||||||
var data = copy[FILES_DATA][id] || {};
|
var data = copy[FILES_DATA][id] || {};
|
||||||
// If this pad has a visible href, encrypt it
|
// If this pad has a visible href, encrypt it
|
||||||
@ -490,7 +495,7 @@ define([
|
|||||||
if (data.href && data.roHref && !data.fileType && data.href.indexOf('#') !== -1) {
|
if (data.href && data.roHref && !data.fileType && data.href.indexOf('#') !== -1) {
|
||||||
data.href = exp.cryptor.encrypt(data.href);
|
data.href = exp.cryptor.encrypt(data.href);
|
||||||
}
|
}
|
||||||
});
|
});*/
|
||||||
copy.version = 2;
|
copy.version = 2;
|
||||||
delete copy.migrateRo;
|
delete copy.migrateRo;
|
||||||
|
|
||||||
|
|||||||
@ -52,6 +52,13 @@ define([
|
|||||||
|
|
||||||
// Password may have changed
|
// Password may have changed
|
||||||
var deprecateProxy = function (Env, id, channel) {
|
var deprecateProxy = function (Env, id, channel) {
|
||||||
|
if (Env.user.userObject.readOnly) {
|
||||||
|
// In a read-only team, we can't deprecate a shared folder
|
||||||
|
if (Env.folders[id]) {
|
||||||
|
Env.folders[id].proxy = { deprecated: true };
|
||||||
|
}
|
||||||
|
return void Env.Store.refreshDriveUI();
|
||||||
|
}
|
||||||
Env.unpinPads([channel], function () {});
|
Env.unpinPads([channel], function () {});
|
||||||
Env.user.userObject.deprecateSharedFolder(id);
|
Env.user.userObject.deprecateSharedFolder(id);
|
||||||
if (Env.Store && Env.Store.refreshDriveUI) {
|
if (Env.Store && Env.Store.refreshDriveUI) {
|
||||||
@ -554,7 +561,8 @@ define([
|
|||||||
var secret = Hash.getSecrets(parsed.type, parsed.hash, newPassword);
|
var secret = Hash.getSecrets(parsed.type, parsed.hash, newPassword);
|
||||||
data.password = newPassword;
|
data.password = newPassword;
|
||||||
data.channel = secret.channel;
|
data.channel = secret.channel;
|
||||||
data.href = '/drive/#'+Hash.getEditHashFromKeys(secret); // XXX encrypt
|
var _href = '/drive/#'+Hash.getEditHashFromKeys(secret);
|
||||||
|
data.href = Env.user.userObject.cryptor.encrypt(_href);
|
||||||
data.roHref = '/drive/#'+Hash.getViewHashFromKeys(secret);
|
data.roHref = '/drive/#'+Hash.getViewHashFromKeys(secret);
|
||||||
_addSharedFolder(Env, {
|
_addSharedFolder(Env, {
|
||||||
path: ['root'],
|
path: ['root'],
|
||||||
|
|||||||
@ -15,6 +15,8 @@ define([
|
|||||||
var TEMPLATE = module.TEMPLATE = "template";
|
var TEMPLATE = module.TEMPLATE = "template";
|
||||||
var SHARED_FOLDERS = module.SHARED_FOLDERS = "sharedFolders";
|
var SHARED_FOLDERS = module.SHARED_FOLDERS = "sharedFolders";
|
||||||
var SHARED_FOLDERS_TEMP = module.SHARED_FOLDERS_TEMP = "sharedFoldersTemp"; // Maybe deleted or new password
|
var SHARED_FOLDERS_TEMP = module.SHARED_FOLDERS_TEMP = "sharedFoldersTemp"; // Maybe deleted or new password
|
||||||
|
var FILES_DATA = module.FILES_DATA = Constants.storageKey;
|
||||||
|
var OLD_FILES_DATA = module.OLD_FILES_DATA = Constants.oldStorageKey;
|
||||||
|
|
||||||
// Create untitled documents when no name is given
|
// Create untitled documents when no name is given
|
||||||
var getLocaleDate = function () {
|
var getLocaleDate = function () {
|
||||||
@ -66,6 +68,37 @@ define([
|
|||||||
return pad.roHref;
|
return pad.roHref;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.reencrypt = function (oldKey, newKey, obj) {
|
||||||
|
obj = obj || {};
|
||||||
|
var oldCryptor = createCryptor(oldKey);
|
||||||
|
var newCryptor = createCryptor(newKey);
|
||||||
|
Object.keys(obj[FILES_DATA]).forEach(function (id) {
|
||||||
|
var data = obj[FILES_DATA][id] || {};
|
||||||
|
// If this pad has a visible href, encrypt it
|
||||||
|
// "&& data.roHref" is here to make sure this is not a "file"
|
||||||
|
if (data.href && data.roHref && !data.fileType) {
|
||||||
|
var _href = oldCryptor.decrypt(data.href);
|
||||||
|
data.href = newCryptor.encrypt(_href);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Object.keys(obj[SHARED_FOLDERS] || {}).forEach(function (id) {
|
||||||
|
var data = obj[SHARED_FOLDERS][id] || {};
|
||||||
|
// If this folder has a visible href, encrypt it
|
||||||
|
if (data.href) {
|
||||||
|
var _href = oldCryptor.decrypt(data.href);
|
||||||
|
data.href = newCryptor.encrypt(_href);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Object.keys(obj[SHARED_FOLDERS_TEMP] || {}).forEach(function (id) {
|
||||||
|
var data = obj[SHARED_FOLDERS_TEMP][id] || {};
|
||||||
|
// If this folder has a visible href, encrypt it
|
||||||
|
if (data.href) {
|
||||||
|
var _href = oldCryptor.decrypt(data.href);
|
||||||
|
data.href = newCryptor.encrypt(_href);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
module.init = function (files, config) {
|
module.init = function (files, config) {
|
||||||
var exp = {};
|
var exp = {};
|
||||||
|
|
||||||
@ -74,18 +107,19 @@ define([
|
|||||||
exp.setReadOnly = function (state, key) {
|
exp.setReadOnly = function (state, key) {
|
||||||
config.editKey = key;
|
config.editKey = key;
|
||||||
createCryptor(key);
|
createCryptor(key);
|
||||||
|
exp.readOnly = state;
|
||||||
if (exp._setReadOnly) {
|
if (exp._setReadOnly) {
|
||||||
// Change outer
|
// Change outer
|
||||||
exp._setReadOnly(state);
|
exp._setReadOnly(state);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
exp.readOnly = config.readOnly;
|
||||||
|
exp.reencrypt = module.reencrypt;
|
||||||
|
|
||||||
exp.getDefaultName = module.getDefaultName;
|
exp.getDefaultName = module.getDefaultName;
|
||||||
|
|
||||||
var sframeChan = config.sframeChan;
|
var sframeChan = config.sframeChan;
|
||||||
|
|
||||||
var FILES_DATA = module.FILES_DATA = exp.FILES_DATA = Constants.storageKey;
|
|
||||||
var OLD_FILES_DATA = module.OLD_FILES_DATA = exp.OLD_FILES_DATA = Constants.oldStorageKey;
|
|
||||||
var NEW_FOLDER_NAME = Messages.fm_newFolder || 'New folder';
|
var NEW_FOLDER_NAME = Messages.fm_newFolder || 'New folder';
|
||||||
var NEW_FILE_NAME = Messages.fm_newFile || 'New file';
|
var NEW_FILE_NAME = Messages.fm_newFile || 'New file';
|
||||||
|
|
||||||
@ -95,6 +129,8 @@ define([
|
|||||||
exp.TEMPLATE = TEMPLATE;
|
exp.TEMPLATE = TEMPLATE;
|
||||||
exp.SHARED_FOLDERS = SHARED_FOLDERS;
|
exp.SHARED_FOLDERS = SHARED_FOLDERS;
|
||||||
exp.SHARED_FOLDERS_TEMP = SHARED_FOLDERS_TEMP;
|
exp.SHARED_FOLDERS_TEMP = SHARED_FOLDERS_TEMP;
|
||||||
|
exp.FILES_DATA = FILES_DATA;
|
||||||
|
exp.OLD_FILES_DATA = OLD_FILES_DATA;
|
||||||
|
|
||||||
var sharedFolder = exp.sharedFolder = config.sharedFolder;
|
var sharedFolder = exp.sharedFolder = config.sharedFolder;
|
||||||
exp.id = config.id;
|
exp.id = config.id;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user