Use base64 strings for incoming message cache instead of binary

This commit is contained in:
Scott Nonnenberg 2018-08-09 17:28:51 -07:00
parent 9eefc0c29b
commit 7983300f4a
7 changed files with 62 additions and 28 deletions

View File

@ -338,7 +338,8 @@
db,
clearStores: Whisper.Database.clearStores,
handleDOMException: Whisper.Database.handleDOMException,
arrayBufferToString: textsecure.MessageReceiver.arrayBufferToString,
arrayBufferToString:
textsecure.MessageReceiver.arrayBufferToStringBase64,
countCallback: count => {
window.log.info(`Migration: ${count} messages complete`);
showMigrationStatus(count);

View File

@ -59,7 +59,6 @@ module.exports = {
getUnprocessedById,
saveUnprocessed,
saveUnprocesseds,
updateUnprocessed,
removeUnprocessed,
removeAllUnprocessed,
@ -374,19 +373,6 @@ async function saveUnprocesseds(arrayOfUnprocessed, { forceSave } = {}) {
});
}
async function updateUnprocessed(id, updates) {
const existing = await channels.getUnprocessedById(id);
if (!existing) {
throw new Error(`Unprocessed id ${id} does not exist in the database!`);
}
const toSave = {
...existing,
...updates,
};
await saveUnprocessed(toSave);
}
async function removeUnprocessed(id) {
await channels.removeUnprocessed(id);
}

View File

@ -86,6 +86,11 @@ async function migrateToSQL({
forEach(array, item => {
// In the new database, we can't store ArrayBuffers, so we turn these two fields
// into strings like MessageReceiver now does before save.
// Need to set it to version two, since we're using Base64 strings now
// eslint-disable-next-line no-param-reassign
item.version = 2;
if (item.envelope) {
// eslint-disable-next-line no-param-reassign
item.envelope = arrayBufferToString(item.envelope);

View File

@ -942,6 +942,9 @@
getAllUnprocessed() {
return window.Signal.Data.getAllUnprocessed();
},
getUnprocessedById(id) {
return window.Signal.Data.getUnprocessedById(id, { Unprocessed });
},
addUnprocessed(data) {
// We need to pass forceSave because the data has an id already, which will cause
// an update instead of an insert.
@ -950,8 +953,8 @@
Unprocessed,
});
},
updateUnprocessed(id, updates) {
return window.Signal.Data.updateUnprocessed(id, updates, { Unprocessed });
saveUnprocessed(data) {
return window.Signal.Data.saveUnprocessed(data, { Unprocessed });
},
removeUnprocessed(id) {
return window.Signal.Data.removeUnprocessed(id, { Unprocessed });

View File

@ -35,6 +35,10 @@ MessageReceiver.stringToArrayBuffer = string =>
dcodeIO.ByteBuffer.wrap(string, 'binary').toArrayBuffer();
MessageReceiver.arrayBufferToString = arrayBuffer =>
dcodeIO.ByteBuffer.wrap(arrayBuffer).toString('binary');
MessageReceiver.stringToArrayBufferBase64 = string =>
dcodeIO.ByteBuffer.wrap(string, 'base64').toArrayBuffer();
MessageReceiver.arrayBufferToStringBase64 = arrayBuffer =>
dcodeIO.ByteBuffer.wrap(arrayBuffer).toString('base64');
MessageReceiver.prototype = new textsecure.EventTarget();
MessageReceiver.prototype.extend({
@ -275,6 +279,12 @@ MessageReceiver.prototype.extend({
try {
let envelopePlaintext = item.envelope;
if (item.version === 2) {
envelopePlaintext = MessageReceiver.stringToArrayBufferBase64(
envelopePlaintext
);
}
if (typeof envelopePlaintext === 'string') {
envelopePlaintext = MessageReceiver.stringToArrayBuffer(
envelopePlaintext
@ -285,6 +295,13 @@ MessageReceiver.prototype.extend({
const { decrypted } = item;
if (decrypted) {
let payloadPlaintext = decrypted;
if (item.version === 2) {
payloadPlaintext = MessageReceiver.stringToArrayBufferBase64(
payloadPlaintext
);
}
if (typeof payloadPlaintext === 'string') {
payloadPlaintext = MessageReceiver.stringToArrayBuffer(
payloadPlaintext
@ -339,7 +356,7 @@ MessageReceiver.prototype.extend({
);
return textsecure.storage.unprocessed.remove(item.id);
}
return textsecure.storage.unprocessed.update(item.id, { attempts });
return textsecure.storage.unprocessed.save({ ...item, attempts });
})
).then(
() => items,
@ -357,18 +374,33 @@ MessageReceiver.prototype.extend({
const id = this.getEnvelopeId(envelope);
const data = {
id,
envelope: MessageReceiver.arrayBufferToString(plaintext),
version: 2,
envelope: MessageReceiver.arrayBufferToStringBase64(plaintext),
timestamp: Date.now(),
attempts: 1,
};
return textsecure.storage.unprocessed.add(data);
},
updateCache(envelope, plaintext) {
async updateCache(envelope, plaintext) {
const id = this.getEnvelopeId(envelope);
const data = {
decrypted: MessageReceiver.arrayBufferToString(plaintext),
};
return textsecure.storage.unprocessed.update(id, data);
const item = await textsecure.storage.unprocessed.get(id);
if (!item) {
window.log.error(
`updateCache: Didn't find item ${id} in cache to update`
);
return null;
}
if (item.get('version') === 2) {
item.set(
'decrypted',
MessageReceiver.arrayBufferToStringBase64(plaintext)
);
} else {
item.set('decrypted', MessageReceiver.arrayBufferToString(plaintext));
}
return textsecure.storage.unprocessed.save(item.attributes);
},
removeFromCache(envelope) {
const id = this.getEnvelopeId(envelope);
@ -1189,3 +1221,7 @@ textsecure.MessageReceiver.stringToArrayBuffer =
MessageReceiver.stringToArrayBuffer;
textsecure.MessageReceiver.arrayBufferToString =
MessageReceiver.arrayBufferToString;
textsecure.MessageReceiver.stringToArrayBufferBase64 =
MessageReceiver.stringToArrayBufferBase64;
textsecure.MessageReceiver.arrayBufferToStringBase64 =
MessageReceiver.arrayBufferToStringBase64;

View File

@ -12,11 +12,14 @@
getAll() {
return textsecure.storage.protocol.getAllUnprocessed();
},
get(id) {
return textsecure.storage.protocol.getUnprocessedById(id);
},
add(data) {
return textsecure.storage.protocol.addUnprocessed(data);
},
update(id, updates) {
return textsecure.storage.protocol.updateUnprocessed(id, updates);
save(data) {
return textsecure.storage.protocol.saveUnprocessed(data);
},
remove(id) {
return textsecure.storage.protocol.removeUnprocessed(id);

View File

@ -1241,12 +1241,12 @@ describe('SignalProtocolStore', function() {
});
});
it('updateUnprocessed successfully updates only part of itme', function() {
it('saveUnprocessed successfully updates item', function() {
var id = 1;
return store
.addUnprocessed({ id: id, name: 'first', timestamp: 1 })
.then(function() {
return store.updateUnprocessed(id, { name: 'updated' });
return store.saveUnprocessed({ id, name: 'updated', timestamp: 1 });
})
.then(function() {
return store.getAllUnprocessed();