Fix session corruption due to database races

Prevent races between encrypt and decrypt calls, and other read/write
operations on the session store by serializing session io ops per
device.

Possible fix for #535

// FREEBIE
pull/749/head
lilia 9 years ago
parent f0539fda52
commit 57d64fe669

@ -35242,16 +35242,39 @@ axolotlInternal.RecipientRecord = function() {
textsecure.storage.axolotl = new AxolotlStore(); textsecure.storage.axolotl = new AxolotlStore();
var axolotlInstance = axolotl.protocol(textsecure.storage.axolotl); var axolotlInstance = axolotl.protocol(textsecure.storage.axolotl);
/*
* jobQueue manages multiple queues indexed by device to serialize
* session io ops on the database.
*/
var jobQueue = {};
function queueJobForNumber(number, runJob) {
var runPrevious = jobQueue[number] || Promise.resolve();
var runCurrent = jobQueue[number] = runPrevious.then(runJob, runJob);
runCurrent.then(function() {
if (jobQueue[number] === runCurrent) {
delete jobQueue[number];
}
});
return runCurrent;
}
window.textsecure = window.textsecure || {}; window.textsecure = window.textsecure || {};
window.textsecure.protocol_wrapper = { window.textsecure.protocol_wrapper = {
decryptWhisperMessage: function(fromAddress, blob) { decryptWhisperMessage: function(fromAddress, blob) {
return queueJobForNumber(fromAddress, function() {
return axolotlInstance.decryptWhisperMessage(fromAddress, getString(blob)); return axolotlInstance.decryptWhisperMessage(fromAddress, getString(blob));
});
}, },
closeOpenSessionForDevice: function(encodedNumber) { closeOpenSessionForDevice: function(encodedNumber) {
return queueJobForNumber(encodedNumber, function() {
return axolotlInstance.closeOpenSessionForDevice(encodedNumber); return axolotlInstance.closeOpenSessionForDevice(encodedNumber);
});
}, },
encryptMessageFor: function(deviceObject, pushMessageContent) { encryptMessageFor: function(deviceObject, pushMessageContent) {
return queueJobForNumber(deviceObject.encodedNumber, function() {
return axolotlInstance.encryptMessageFor(deviceObject, pushMessageContent); return axolotlInstance.encryptMessageFor(deviceObject, pushMessageContent);
});
}, },
startWorker: function() { startWorker: function() {
axolotlInstance.startWorker('/js/libaxolotl-worker.js'); axolotlInstance.startWorker('/js/libaxolotl-worker.js');
@ -35263,10 +35286,14 @@ axolotlInternal.RecipientRecord = function() {
return axolotlInstance.createIdentityKeyRecvSocket(); return axolotlInstance.createIdentityKeyRecvSocket();
}, },
hasOpenSession: function(encodedNumber) { hasOpenSession: function(encodedNumber) {
return queueJobForNumber(encodedNumber, function() {
return axolotlInstance.hasOpenSession(encodedNumber); return axolotlInstance.hasOpenSession(encodedNumber);
});
}, },
getRegistrationId: function(encodedNumber) { getRegistrationId: function(encodedNumber) {
return queueJobForNumber(encodedNumber, function() {
return axolotlInstance.getRegistrationId(encodedNumber); return axolotlInstance.getRegistrationId(encodedNumber);
});
}, },
handlePreKeyWhisperMessage: function(from, blob) { handlePreKeyWhisperMessage: function(from, blob) {
blob.mark(); blob.mark();
@ -35275,6 +35302,7 @@ axolotlInternal.RecipientRecord = function() {
// min version > 3 or max version < 3 // min version > 3 or max version < 3
throw new Error("Incompatible version byte"); throw new Error("Incompatible version byte");
} }
return queueJobForNumber(from, function() {
return axolotlInstance.handlePreKeyWhisperMessage(from, blob).catch(function(e) { return axolotlInstance.handlePreKeyWhisperMessage(from, blob).catch(function(e) {
if (e.message === 'Unknown identity key') { if (e.message === 'Unknown identity key') {
blob.reset(); // restore the version byte. blob.reset(); // restore the version byte.
@ -35285,6 +35313,7 @@ axolotlInternal.RecipientRecord = function() {
} }
throw e; throw e;
}); });
});
} }
}; };
})(); })();

@ -9,16 +9,39 @@
textsecure.storage.axolotl = new AxolotlStore(); textsecure.storage.axolotl = new AxolotlStore();
var axolotlInstance = axolotl.protocol(textsecure.storage.axolotl); var axolotlInstance = axolotl.protocol(textsecure.storage.axolotl);
/*
* jobQueue manages multiple queues indexed by device to serialize
* session io ops on the database.
*/
var jobQueue = {};
function queueJobForNumber(number, runJob) {
var runPrevious = jobQueue[number] || Promise.resolve();
var runCurrent = jobQueue[number] = runPrevious.then(runJob, runJob);
runCurrent.then(function() {
if (jobQueue[number] === runCurrent) {
delete jobQueue[number];
}
});
return runCurrent;
}
window.textsecure = window.textsecure || {}; window.textsecure = window.textsecure || {};
window.textsecure.protocol_wrapper = { window.textsecure.protocol_wrapper = {
decryptWhisperMessage: function(fromAddress, blob) { decryptWhisperMessage: function(fromAddress, blob) {
return queueJobForNumber(fromAddress, function() {
return axolotlInstance.decryptWhisperMessage(fromAddress, getString(blob)); return axolotlInstance.decryptWhisperMessage(fromAddress, getString(blob));
});
}, },
closeOpenSessionForDevice: function(encodedNumber) { closeOpenSessionForDevice: function(encodedNumber) {
return queueJobForNumber(encodedNumber, function() {
return axolotlInstance.closeOpenSessionForDevice(encodedNumber); return axolotlInstance.closeOpenSessionForDevice(encodedNumber);
});
}, },
encryptMessageFor: function(deviceObject, pushMessageContent) { encryptMessageFor: function(deviceObject, pushMessageContent) {
return queueJobForNumber(deviceObject.encodedNumber, function() {
return axolotlInstance.encryptMessageFor(deviceObject, pushMessageContent); return axolotlInstance.encryptMessageFor(deviceObject, pushMessageContent);
});
}, },
startWorker: function() { startWorker: function() {
axolotlInstance.startWorker('/js/libaxolotl-worker.js'); axolotlInstance.startWorker('/js/libaxolotl-worker.js');
@ -30,10 +53,14 @@
return axolotlInstance.createIdentityKeyRecvSocket(); return axolotlInstance.createIdentityKeyRecvSocket();
}, },
hasOpenSession: function(encodedNumber) { hasOpenSession: function(encodedNumber) {
return queueJobForNumber(encodedNumber, function() {
return axolotlInstance.hasOpenSession(encodedNumber); return axolotlInstance.hasOpenSession(encodedNumber);
});
}, },
getRegistrationId: function(encodedNumber) { getRegistrationId: function(encodedNumber) {
return queueJobForNumber(encodedNumber, function() {
return axolotlInstance.getRegistrationId(encodedNumber); return axolotlInstance.getRegistrationId(encodedNumber);
});
}, },
handlePreKeyWhisperMessage: function(from, blob) { handlePreKeyWhisperMessage: function(from, blob) {
blob.mark(); blob.mark();
@ -42,6 +69,7 @@
// min version > 3 or max version < 3 // min version > 3 or max version < 3
throw new Error("Incompatible version byte"); throw new Error("Incompatible version byte");
} }
return queueJobForNumber(from, function() {
return axolotlInstance.handlePreKeyWhisperMessage(from, blob).catch(function(e) { return axolotlInstance.handlePreKeyWhisperMessage(from, blob).catch(function(e) {
if (e.message === 'Unknown identity key') { if (e.message === 'Unknown identity key') {
blob.reset(); // restore the version byte. blob.reset(); // restore the version byte.
@ -52,6 +80,7 @@
} }
throw e; throw e;
}); });
});
} }
}; };
})(); })();

Loading…
Cancel
Save