temp
This commit is contained in:
parent
c9c19b8395
commit
6047a8640e
@ -551,9 +551,10 @@ define([
|
|||||||
$d.append(password);
|
$d.append(password);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data.noEditPassword && owned && parsed.type !== "sheet") { // FIXME SHEET fix password change for sheets
|
if (!data.noEditPassword && owned) { // FIXME SHEET fix password change for sheets
|
||||||
var sframeChan = common.getSframeChannel();
|
var sframeChan = common.getSframeChannel();
|
||||||
|
|
||||||
|
var isOO = parsed.type === 'sheet';
|
||||||
var isFile = parsed.hashData.type === 'file';
|
var isFile = parsed.hashData.type === 'file';
|
||||||
var isSharedFolder = parsed.type === 'drive';
|
var isSharedFolder = parsed.type === 'drive';
|
||||||
|
|
||||||
@ -586,7 +587,8 @@ define([
|
|||||||
UI.confirm(changePwConfirm, function (yes) {
|
UI.confirm(changePwConfirm, function (yes) {
|
||||||
if (!yes) { pLocked = false; return; }
|
if (!yes) { pLocked = false; return; }
|
||||||
$(passwordOk).html('').append(h('span.fa.fa-spinner.fa-spin', {style: 'margin-left: 0'}));
|
$(passwordOk).html('').append(h('span.fa.fa-spinner.fa-spin', {style: 'margin-left: 0'}));
|
||||||
var q = isFile ? 'Q_BLOB_PASSWORD_CHANGE' : 'Q_PAD_PASSWORD_CHANGE';
|
var q = isFile ? 'Q_BLOB_PASSWORD_CHANGE' :
|
||||||
|
(isOO ? 'Q_OO_PASSWORD_CHANGE' : 'Q_PAD_PASSWORD_CHANGE');
|
||||||
|
|
||||||
// If this is a file password change, register to the upload events:
|
// If this is a file password change, register to the upload events:
|
||||||
// * if there is a pending upload, ask if we shoudl interrupt
|
// * if there is a pending upload, ask if we shoudl interrupt
|
||||||
|
|||||||
@ -1155,6 +1155,233 @@ define([
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
common.changeOOPassword = function (data, cb) {
|
||||||
|
var href = data.href;
|
||||||
|
var newPassword = data.password;
|
||||||
|
var teamId = data.teamId;
|
||||||
|
if (!href) { return void cb({ error: 'EINVAL_HREF' }); }
|
||||||
|
var parsed = Hash.parsePadUrl(href);
|
||||||
|
if (!parsed.hash) { return void cb({ error: 'EINVAL_HREF' }); }
|
||||||
|
if (parsed.type !== 'sheet') { return void cb({ error: 'EINVAL_TYPE' }); }
|
||||||
|
|
||||||
|
var warning = false;
|
||||||
|
var newHash, newRoHref;
|
||||||
|
var oldChannel;
|
||||||
|
var oldSecret;
|
||||||
|
var oldMetadata;
|
||||||
|
var oldRtChannel;
|
||||||
|
var privateData;
|
||||||
|
var padData;
|
||||||
|
|
||||||
|
var newSecret;
|
||||||
|
if (parsed.hashData.version >= 2) {
|
||||||
|
newSecret = Hash.getSecrets(parsed.type, parsed.hash, newPassword);
|
||||||
|
if (!(newSecret.keys && newSecret.keys.editKeyStr)) {
|
||||||
|
return void cb({error: 'EAUTH'});
|
||||||
|
}
|
||||||
|
newHash = Hash.getEditHashFromKeys(newSecret);
|
||||||
|
}
|
||||||
|
var newHref = '/' + parsed.type + '/#' + newHash;
|
||||||
|
var newRtChannel = Hash.createChannelId();
|
||||||
|
|
||||||
|
var Crypt, Crypto;
|
||||||
|
var cryptgetVal;
|
||||||
|
var lastCp;
|
||||||
|
var optsPut = {
|
||||||
|
password: newPassword,
|
||||||
|
metadata: {
|
||||||
|
validateKey: newSecret.keys.validateKey
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Nthen(function (waitFor) {
|
||||||
|
common.getPadAttribute('', waitFor(function (err, _data) {
|
||||||
|
padData = _data;
|
||||||
|
}), href);
|
||||||
|
}).nThen(function (waitFor) {
|
||||||
|
oldSecret = Hash.getSecrets(parsed.type, parsed.hash, padData.password);
|
||||||
|
|
||||||
|
require([
|
||||||
|
'/common/cryptget.js',
|
||||||
|
'/bower_components/chainpad-crypto/crypto.js',
|
||||||
|
], waitFor(function (_Crypt, _Crypto) {
|
||||||
|
Crypt = _Crypt;
|
||||||
|
Crypto = _Crypto;
|
||||||
|
}));
|
||||||
|
|
||||||
|
common.getPadMetadata({channel: oldSecret.channel}, waitFor(function (metadata) {
|
||||||
|
oldMetadata = metadata;
|
||||||
|
}));
|
||||||
|
common.getMetadata(waitFor(function (err, data) {
|
||||||
|
if (err) {
|
||||||
|
waitFor.abort();
|
||||||
|
return void cb({ error: err });
|
||||||
|
}
|
||||||
|
privateData = data.priv;
|
||||||
|
}));
|
||||||
|
}).nThen(function (waitFor) {
|
||||||
|
// Check if we're allowed to change the password
|
||||||
|
var owners = oldMetadata.owners;
|
||||||
|
optsPut.metadata.owners = owners;
|
||||||
|
var edPublic = teamId ? (privateData.teams[teamId] || {}).edPublic : privateData.edPublic;
|
||||||
|
var isOwner = Array.isArray(owners) && edPublic && owners.indexOf(edPublic) !== -1;
|
||||||
|
if (!isOwner) {
|
||||||
|
// We're not an owner, we shouldn't be able to change the password!
|
||||||
|
waitFor.abort();
|
||||||
|
return void cb({ error: 'EPERM' });
|
||||||
|
}
|
||||||
|
|
||||||
|
var mailbox = oldMetadata.mailbox;
|
||||||
|
if (mailbox) {
|
||||||
|
// Create the encryptors to be able to decrypt and re-encrypt the mailboxes
|
||||||
|
var oldCrypto = Crypto.createEncryptor(oldSecret.keys);
|
||||||
|
var newCrypto = Crypto.createEncryptor(newSecret.keys);
|
||||||
|
|
||||||
|
var m;
|
||||||
|
if (typeof(mailbox) === "string") {
|
||||||
|
try {
|
||||||
|
m = newCrypto.encrypt(oldCrypto.decrypt(mailbox, true, true));
|
||||||
|
} catch (e) {}
|
||||||
|
} else if (mailbox && typeof(mailbox) === "object") {
|
||||||
|
m = {};
|
||||||
|
Object.keys(mailbox).forEach(function (ed) {
|
||||||
|
try {
|
||||||
|
m[ed] = newCrypto.encrypt(oldCrypto.decrypt(mailbox[ed], true, true));
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
optsPut.metadata.mailbox = m;
|
||||||
|
}
|
||||||
|
|
||||||
|
var expire = oldMetadata.expire;
|
||||||
|
if (expire) {
|
||||||
|
optsPut.metadata.expire = (expire - (+new Date())) / 1000; // Lifetime in seconds
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get last cp (cryptget)
|
||||||
|
Crypt.get(parsed.hash, waitFor(function (err, val) {
|
||||||
|
if (err) {
|
||||||
|
waitFor.abort();
|
||||||
|
return void cb({ error: err });
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
cryptgetVal = JSON.parse(val);
|
||||||
|
if (!cryptgetVal.content) {
|
||||||
|
waitFor.abort();
|
||||||
|
return void cb({ error: 'INVALID_CONTENT' });
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
waitFor.abort();
|
||||||
|
return void cb({ error: 'CANT_PARSE' });
|
||||||
|
}
|
||||||
|
}), {
|
||||||
|
password: padData.password
|
||||||
|
});
|
||||||
|
}).nThen(function (waitFor) {
|
||||||
|
// Re-encrypt rtchannel
|
||||||
|
oldRtChannel = Util.find(cryptgetVal, ['content', 'channel']);
|
||||||
|
var newCrypto = Crypto.createEncryptor(newSecret.keys);
|
||||||
|
var oldCrypto = Crypto.createEncryptor(oldSecret.keys);
|
||||||
|
var cps = Util.find(cryptgetVal, ['content', 'hashes']);
|
||||||
|
var lastCp = cps.length ? cps[cps.length - 1] : {};
|
||||||
|
common.getHistory({
|
||||||
|
channel: oldRtChannel,
|
||||||
|
lastKnownHash: lastCp.hash
|
||||||
|
}, waitFor(function (obj) {
|
||||||
|
if (obj && obj.error) {
|
||||||
|
waitFor.abort();
|
||||||
|
return void cb(obj);
|
||||||
|
}
|
||||||
|
var msgs = obj;
|
||||||
|
newHistory = msgs.map(function (str) {
|
||||||
|
try {
|
||||||
|
var d = oldCrypto.decrypt(msg, true, true);
|
||||||
|
return newCrypto.encrypt(d);
|
||||||
|
} catch (e) {
|
||||||
|
waitFor.abort();
|
||||||
|
return void cb({error: e});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Update last knwon hash in cryptgetVal
|
||||||
|
if (lastCp) { lastCp.hash = msgs[0].slice(0, 64); }
|
||||||
|
common.onlyoffice.execCommand({
|
||||||
|
cmd: 'REENCRYPT',
|
||||||
|
data: {
|
||||||
|
channel: newRtChannel,
|
||||||
|
msgs: newHistory,
|
||||||
|
metadata: optsPut.metadata
|
||||||
|
}
|
||||||
|
}, waitFor(function (obj) {
|
||||||
|
if (obj && obj.error) {
|
||||||
|
waitFor.abort();
|
||||||
|
return void cb(obj);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}));
|
||||||
|
}).nThen(function (waitFor) {
|
||||||
|
// The new rt channel is ready
|
||||||
|
// The blob uses its own encryption and doesn't need to be reencrypted
|
||||||
|
cryptgetVal.content.channel = newRtChannel;
|
||||||
|
Crypt.put(newHash, cryptgetVal, waitFor(function (err) {
|
||||||
|
if (err) {
|
||||||
|
waitFor.abort();
|
||||||
|
return void cb({ error: err });
|
||||||
|
}
|
||||||
|
}), optsPut);
|
||||||
|
}).nThen(function (waitFor) {
|
||||||
|
pad.leavePad({
|
||||||
|
channel: oldSecret.channel
|
||||||
|
}, waitFor());
|
||||||
|
pad.onDisconnectEvent.fire(true);
|
||||||
|
}).nThen(function (waitFor) {
|
||||||
|
// Set the new password to our pad data
|
||||||
|
common.setPadAttribute('password', newPassword, waitFor(function (err) {
|
||||||
|
if (err) { warning = true; }
|
||||||
|
}), href);
|
||||||
|
common.setPadAttribute('channel', newSecret.channel, waitFor(function (err) {
|
||||||
|
if (err) { warning = true; }
|
||||||
|
}), href);
|
||||||
|
common.setPadAttribute('rtChannel', newRtChannel, waitFor(function (err) {
|
||||||
|
if (err) { warning = true; }
|
||||||
|
}), href);
|
||||||
|
var viewHash = Hash.getViewHashFromKeys(newSecret);
|
||||||
|
newRoHref = '/' + parsed.type + '/#' + viewHash;
|
||||||
|
common.setPadAttribute('roHref', newRoHref, waitFor(function (err) {
|
||||||
|
if (err) { warning = true; }
|
||||||
|
}), href);
|
||||||
|
|
||||||
|
if (parsed.hashData.password && newPassword) { return; } // same hash
|
||||||
|
common.setPadAttribute('href', newHref, waitFor(function (err) {
|
||||||
|
if (err) { warning = true; }
|
||||||
|
}), href);
|
||||||
|
}).nThen(function (waitFor) {
|
||||||
|
// delete the old pad
|
||||||
|
common.removeOwnedChannel({
|
||||||
|
channel: oldSecret.channel,
|
||||||
|
teamId: teamId
|
||||||
|
}, waitFor(function (obj) {
|
||||||
|
if (obj && obj.error) {
|
||||||
|
waitFor.abort();
|
||||||
|
return void cb(obj);
|
||||||
|
}
|
||||||
|
common.removeOwnedChannel({
|
||||||
|
channel: oldRtChannel,
|
||||||
|
teamId: teamId
|
||||||
|
}, waitFor());
|
||||||
|
}));
|
||||||
|
}).nThen(function () {
|
||||||
|
cb({
|
||||||
|
warning: warning,
|
||||||
|
hash: newHash,
|
||||||
|
href: newHref,
|
||||||
|
roHref: newRoHref
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
common.changeUserPassword = function (Crypt, edPublic, data, cb) {
|
common.changeUserPassword = function (Crypt, edPublic, data, cb) {
|
||||||
if (!edPublic) {
|
if (!edPublic) {
|
||||||
return void cb({
|
return void cb({
|
||||||
@ -1350,6 +1577,9 @@ define([
|
|||||||
common.getFullHistory = function (data, cb) {
|
common.getFullHistory = function (data, cb) {
|
||||||
postMessage("GET_FULL_HISTORY", data, cb, {timeout: 180000});
|
postMessage("GET_FULL_HISTORY", data, cb, {timeout: 180000});
|
||||||
};
|
};
|
||||||
|
common.getHistory = function (data, cb) {
|
||||||
|
postMessage("GET_HISTORY", data, cb, {timeout: 180000});
|
||||||
|
};
|
||||||
common.getHistoryRange = function (data, cb) {
|
common.getHistoryRange = function (data, cb) {
|
||||||
postMessage("GET_HISTORY_RANGE", data, cb);
|
postMessage("GET_HISTORY_RANGE", data, cb);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1692,7 +1692,7 @@ define([
|
|||||||
// GET_FULL_HISTORY from sframe-common-outer
|
// GET_FULL_HISTORY from sframe-common-outer
|
||||||
Store.getFullHistory = function (clientId, data, cb) {
|
Store.getFullHistory = function (clientId, data, cb) {
|
||||||
var network = store.network;
|
var network = store.network;
|
||||||
var hkn = network.historyKeeper;
|
var hk = network.historyKeeper;
|
||||||
//var crypto = Crypto.createEncryptor(data.keys);
|
//var crypto = Crypto.createEncryptor(data.keys);
|
||||||
// Get the history messages and send them to the iframe
|
// Get the history messages and send them to the iframe
|
||||||
var parse = function (msg) {
|
var parse = function (msg) {
|
||||||
@ -1709,6 +1709,7 @@ define([
|
|||||||
var parsed = parse(msg);
|
var parsed = parse(msg);
|
||||||
if (parsed[0] === 'FULL_HISTORY_END') {
|
if (parsed[0] === 'FULL_HISTORY_END') {
|
||||||
cb(msgs);
|
cb(msgs);
|
||||||
|
network.off('message', onMsg);
|
||||||
completed = true;
|
completed = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1725,12 +1726,68 @@ define([
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
network.on('message', onMsg);
|
network.on('message', onMsg);
|
||||||
network.sendto(hkn, JSON.stringify(['GET_FULL_HISTORY', data.channel, data.validateKey]));
|
network.sendto(hk, JSON.stringify(['GET_FULL_HISTORY', data.channel, data.validateKey]));
|
||||||
|
};
|
||||||
|
|
||||||
|
Store.getHistory = function (clientId, data, cb) {
|
||||||
|
var network = store.network;
|
||||||
|
var hk = network.historyKeeper;
|
||||||
|
|
||||||
|
var parse = function (msg) {
|
||||||
|
try {
|
||||||
|
return JSON.parse(msg);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var msgs = [];
|
||||||
|
var completed = false;
|
||||||
|
var onMsg = function (msg, sender) {
|
||||||
|
if (completed) { return; }
|
||||||
|
if (sender !== hk) { return; }
|
||||||
|
var parsed = parse(msg);
|
||||||
|
|
||||||
|
// Ignore the metadata message
|
||||||
|
if (parsed.validateKey && parsed.channel) { return; }
|
||||||
|
if (parsed.error && parsed.channel) {
|
||||||
|
if (parsed.channel === data.channel) {
|
||||||
|
network.off('message', onMsg);
|
||||||
|
completed = true;
|
||||||
|
cb({error: parsed.error});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// End of history: cb
|
||||||
|
if (parsed.state === 1 && parsed.channel) {
|
||||||
|
if (parsed.channel !== data.channel) { return; }
|
||||||
|
cb(msgs);
|
||||||
|
network.off('message', onMsg);
|
||||||
|
completed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = parsed[4];
|
||||||
|
// Keep only the history for our channel
|
||||||
|
if (parsed[3] !== data.channel) { return; }
|
||||||
|
if (msg) {
|
||||||
|
msg = msg.replace(/cp\|(([A-Za-z0-9+\/=]+)\|)?/, '');
|
||||||
|
msgs.push(msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
network.on('message', onMsg);
|
||||||
|
|
||||||
|
var cfg = {
|
||||||
|
lastKnownHash: data.lastKnownHash
|
||||||
|
};
|
||||||
|
var msg = ['GET_HISTORY', data.channel, cfg];
|
||||||
|
network.sendto(hk, JSON.stringify(msg));
|
||||||
};
|
};
|
||||||
|
|
||||||
Store.getHistoryRange = function (clientId, data, cb) {
|
Store.getHistoryRange = function (clientId, data, cb) {
|
||||||
var network = store.network;
|
var network = store.network;
|
||||||
var hkn = network.historyKeeper;
|
var hk = network.historyKeeper;
|
||||||
var parse = function (msg) {
|
var parse = function (msg) {
|
||||||
try {
|
try {
|
||||||
return JSON.parse(msg);
|
return JSON.parse(msg);
|
||||||
@ -1778,7 +1835,7 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
network.on('message', onMsg);
|
network.on('message', onMsg);
|
||||||
network.sendto(hkn, JSON.stringify(['GET_HISTORY_RANGE', data.channel, {
|
network.sendto(hk, JSON.stringify(['GET_HISTORY_RANGE', data.channel, {
|
||||||
from: data.lastKnownHash,
|
from: data.lastKnownHash,
|
||||||
cpCount: 2,
|
cpCount: 2,
|
||||||
txid: txid
|
txid: txid
|
||||||
|
|||||||
@ -200,6 +200,40 @@ define([
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var reencrypt = function (ctx, data, cId, cb) {
|
||||||
|
var channel = data.channel;
|
||||||
|
var network = ctx.store.network;
|
||||||
|
|
||||||
|
var onOpen = function (wc) {
|
||||||
|
var hk = network.historyKeeper;
|
||||||
|
var cfg = {
|
||||||
|
metadata: data.metadata
|
||||||
|
};
|
||||||
|
var msg = ['GET_HISTORY', wc.id, cfg];
|
||||||
|
network.sendto(hk, JSON.stringify(msg));
|
||||||
|
data.msgs.forEach(function (msg) {
|
||||||
|
wc.bcast(msg);
|
||||||
|
});
|
||||||
|
wc.leave();
|
||||||
|
cb();
|
||||||
|
};
|
||||||
|
|
||||||
|
ctx.store.anon_rpc.send("IS_NEW_CHANNEL", channel, function (e, response) {
|
||||||
|
if (e) { return void cb({error: e}); }
|
||||||
|
if (response && response.length && typeof(response[0]) === 'boolean') {
|
||||||
|
var isNew = response[0];
|
||||||
|
} else {
|
||||||
|
cb({error: 'INVALID_RESPONSE'});
|
||||||
|
}
|
||||||
|
if (!isNew) { return void cb({error: 'EEXISTS'}); }
|
||||||
|
|
||||||
|
// Channel is new: we can push our reencrypted history
|
||||||
|
network.join(channel).then(onOpen, function (err) {
|
||||||
|
return void cb({error: err});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
var leaveChannel = function (ctx, padChan) {
|
var leaveChannel = function (ctx, padChan) {
|
||||||
// Leave channel and prevent reconnect when we leave a pad
|
// Leave channel and prevent reconnect when we leave a pad
|
||||||
Object.keys(ctx.channels).some(function (ooChan) {
|
Object.keys(ctx.channels).some(function (ooChan) {
|
||||||
@ -267,6 +301,9 @@ define([
|
|||||||
if (cmd === 'OPEN_CHANNEL') {
|
if (cmd === 'OPEN_CHANNEL') {
|
||||||
return void openChannel(ctx, data, clientId, cb);
|
return void openChannel(ctx, data, clientId, cb);
|
||||||
}
|
}
|
||||||
|
if (cmd === 'REENCRYPT') {
|
||||||
|
return void reencrypt(ctx, data, clientId, cb);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return oo;
|
return oo;
|
||||||
|
|||||||
@ -73,6 +73,7 @@ define([
|
|||||||
JOIN_PAD: Store.joinPad,
|
JOIN_PAD: Store.joinPad,
|
||||||
LEAVE_PAD: Store.leavePad,
|
LEAVE_PAD: Store.leavePad,
|
||||||
GET_FULL_HISTORY: Store.getFullHistory,
|
GET_FULL_HISTORY: Store.getFullHistory,
|
||||||
|
GET_HISTORY: Store.getHistory,
|
||||||
GET_HISTORY_RANGE: Store.getHistoryRange,
|
GET_HISTORY_RANGE: Store.getHistoryRange,
|
||||||
IS_NEW_CHANNEL: Store.isNewChannel,
|
IS_NEW_CHANNEL: Store.isNewChannel,
|
||||||
REQUEST_PAD_ACCESS: Store.requestPadAccess,
|
REQUEST_PAD_ACCESS: Store.requestPadAccess,
|
||||||
|
|||||||
@ -1007,6 +1007,11 @@ define([
|
|||||||
}, cb);
|
}, cb);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
sframeChan.on('Q_OO_PASSWORD_CHANGE', function (data, cb) {
|
||||||
|
data.href = data.href || window.location.href;
|
||||||
|
Cryptpad.changeOOPassword(data, cb);
|
||||||
|
});
|
||||||
|
|
||||||
sframeChan.on('Q_PAD_PASSWORD_CHANGE', function (data, cb) {
|
sframeChan.on('Q_PAD_PASSWORD_CHANGE', function (data, cb) {
|
||||||
data.href = data.href || window.location.href;
|
data.href = data.href || window.location.href;
|
||||||
Cryptpad.changePadPassword(Cryptget, Crypto, data, cb);
|
Cryptpad.changePadPassword(Cryptget, Crypto, data, cb);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user