Merge pull request #1926 from ether/fix/no-connect-to-corrupt-pad

Fix a whole range of bugs related to corrupted changesets
This commit is contained in:
Marcel Klehr 2013-10-10 11:07:37 -07:00
commit 22e9e5fdcd
2 changed files with 23 additions and 19 deletions

View file

@ -594,7 +594,7 @@ function handleUserChanges(data, cb)
// defined in the accompanying attribute pool. // defined in the accompanying attribute pool.
Changeset.eachAttribNumber(changeset, function(n) { Changeset.eachAttribNumber(changeset, function(n) {
if (! wireApool.getAttrib(n)) { if (! wireApool.getAttrib(n)) {
throw "Attribute pool is missing attribute "+n+" for changeset "+changeset; throw new Error("Attribute pool is missing attribute "+n+" for changeset "+changeset);
} }
}); });
@ -608,23 +608,22 @@ function handleUserChanges(data, cb)
if(!attr) return if(!attr) return
attr = wireApool.getAttrib(attr) attr = wireApool.getAttrib(attr)
if(!attr) return if(!attr) return
if('author' == attr[0] && attr[1] != thisSession.author) throw "Trying to submit changes as another author" if('author' == attr[0] && attr[1] != thisSession.author) throw new Error("Trying to submit changes as another author in changeset "+changeset);
}) })
} }
//ex. adoptChangesetAttribs
//Afaik, it copies the new attributes from the changeset, to the global Attribute Pool
changeset = Changeset.moveOpsToNewPool(changeset, wireApool, pad.pool);
} }
catch(e) catch(e)
{ {
// There is an error in this changeset, so just refuse it // There is an error in this changeset, so just refuse it
console.warn("Can't apply USER_CHANGES "+changeset+", because: "+e);
client.json.send({disconnect:"badChangeset"}); client.json.send({disconnect:"badChangeset"});
return callback(); return callback(new Error("Can't apply USER_CHANGES, because "+e.message));
} }
//ex. adoptChangesetAttribs
//Afaik, it copies the new attributes from the changeset, to the global Attribute Pool
changeset = Changeset.moveOpsToNewPool(changeset, wireApool, pad.pool);
//ex. applyUserChanges //ex. applyUserChanges
apool = pad.pool; apool = pad.pool;
r = baseRev; r = baseRev;
@ -651,9 +650,8 @@ function handleUserChanges(data, cb)
{ {
changeset = Changeset.follow(c, changeset, false, apool); changeset = Changeset.follow(c, changeset, false, apool);
}catch(e){ }catch(e){
console.warn("Can't apply USER_CHANGES "+changeset+", possibly because of mismatched follow error");
client.json.send({disconnect:"badChangeset"}); client.json.send({disconnect:"badChangeset"});
return callback(); return callback(new Error("Can't apply USER_CHANGES, because "+e.message));
} }
if ((r - baseRev) % 200 == 0) { // don't let the stack get too deep if ((r - baseRev) % 200 == 0) { // don't let the stack get too deep
@ -674,9 +672,8 @@ function handleUserChanges(data, cb)
if (Changeset.oldLen(changeset) != prevText.length) if (Changeset.oldLen(changeset) != prevText.length)
{ {
console.warn("Can't apply USER_CHANGES "+changeset+" with oldLen " + Changeset.oldLen(changeset) + " to document of length " + prevText.length);
client.json.send({disconnect:"badChangeset"}); client.json.send({disconnect:"badChangeset"});
return callback(); return callback(new Error("Can't apply USER_CHANGES "+changeset+" with oldLen " + Changeset.oldLen(changeset) + " to document of length " + prevText.length));
} }
pad.appendRevision(changeset, thisSession.author); pad.appendRevision(changeset, thisSession.author);
@ -700,7 +697,7 @@ function handleUserChanges(data, cb)
], function(err) ], function(err)
{ {
cb(); cb();
ERR(err); if(err) console.warn(err.stack || err)
}); });
} }
@ -1006,11 +1003,17 @@ function handleClientReady(client, message)
//This is a normal first connect //This is a normal first connect
else else
{ {
//prepare all values for the wire //prepare all values for the wire, there'S a chance that this throws, if the pad is corrupted
var atext = Changeset.cloneAText(pad.atext); try {
var attribsForWire = Changeset.prepareForWire(atext.attribs, pad.pool); var atext = Changeset.cloneAText(pad.atext);
var apool = attribsForWire.pool.toJsonable(); var attribsForWire = Changeset.prepareForWire(atext.attribs, pad.pool);
atext.attribs = attribsForWire.translated; var apool = attribsForWire.pool.toJsonable();
atext.attribs = attribsForWire.translated;
}catch(e) {
console.error(e.stack || e)
client.json.send({disconnect:"padCorrupted"});// pull the breaks
return callback();
}
// Warning: never ever send padIds.padId to the client. If the // Warning: never ever send padIds.padId to the client. If the
// client is read only you would open a security hole 1 swedish // client is read only you would open a security hole 1 swedish

View file

@ -1504,6 +1504,7 @@ exports.moveOpsToNewPool = function (cs, oldPool, newPool) {
return upToDollar.replace(/\*([0-9a-z]+)/g, function (_, a) { return upToDollar.replace(/\*([0-9a-z]+)/g, function (_, a) {
var oldNum = exports.parseNum(a); var oldNum = exports.parseNum(a);
var pair = oldPool.getAttrib(oldNum); var pair = oldPool.getAttrib(oldNum);
if(!pair) exports.error('Can\'t copy unknown attrib (reference attrib string to non-existant pool entry). Inconsistent attrib state!');
var newNum = newPool.putAttrib(pair); var newNum = newPool.putAttrib(pair);
return '*' + exports.numToString(newNum); return '*' + exports.numToString(newNum);
}) + fromDollar; }) + fromDollar;