diff --git a/js/background.js b/js/background.js index b1a02af86bb9..65c5ef8bcdee 100644 --- a/js/background.js +++ b/js/background.js @@ -338,6 +338,7 @@ db, clearStores: Whisper.Database.clearStores, handleDOMException: Whisper.Database.handleDOMException, + arrayBufferToString: textsecure.MessageReceiver.arrayBufferToString, countCallback: count => { window.log.info(`Migration: ${count} messages complete`); showMigrationStatus(count); diff --git a/js/modules/migrate_to_sql.js b/js/modules/migrate_to_sql.js index 36c8cb015da1..fff080d786c9 100644 --- a/js/modules/migrate_to_sql.js +++ b/js/modules/migrate_to_sql.js @@ -1,6 +1,6 @@ /* global window, IDBKeyRange */ -const { includes, isFunction, isString, last } = require('lodash'); +const { includes, isFunction, isString, last, forEach } = require('lodash'); const { saveMessages, _removeMessages, @@ -25,6 +25,7 @@ async function migrateToSQL({ clearStores, handleDOMException, countCallback, + arrayBufferToString, }) { if (!db) { throw new Error('Need db for IndexedDB connection!'); @@ -32,6 +33,9 @@ async function migrateToSQL({ if (!isFunction(clearStores)) { throw new Error('Need clearStores function!'); } + if (!isFunction(arrayBufferToString)) { + throw new Error('Need arrayBufferToString function!'); + } if (!isFunction(handleDOMException)) { throw new Error('Need handleDOMException function!'); } @@ -78,7 +82,21 @@ async function migrateToSQL({ // eslint-disable-next-line no-await-in-loop const status = await migrateStoreToSQLite({ db, - save: saveUnprocesseds, + save: async array => { + 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. + if (item.envelope) { + // eslint-disable-next-line no-param-reassign + item.envelope = arrayBufferToString(item.envelope); + } + if (item.decrypted) { + // eslint-disable-next-line no-param-reassign + item.decrypted = arrayBufferToString(item.decrypted); + } + }); + await saveUnprocesseds(array); + }, remove: removeUnprocessed, storeName: 'unprocessed', handleDOMException, diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js index a68f794e363a..871b69e2e578 100644 --- a/libtextsecure/message_receiver.js +++ b/libtextsecure/message_receiver.js @@ -31,6 +31,11 @@ function MessageReceiver(username, password, signalingKey, options = {}) { } } +MessageReceiver.stringToArrayBuffer = string => + dcodeIO.ByteBuffer.wrap(string, 'binary').toArrayBuffer(); +MessageReceiver.arrayBufferToString = arrayBuffer => + dcodeIO.ByteBuffer.wrap(arrayBuffer).toString('binary'); + MessageReceiver.prototype = new textsecure.EventTarget(); MessageReceiver.prototype.extend({ constructor: MessageReceiver, @@ -269,10 +274,10 @@ MessageReceiver.prototype.extend({ try { let envelopePlaintext = item.envelope; - // Up until 0.42.6 we stored envelope and decrypted as strings in IndexedDB, - // so we need to be ready for them. if (typeof envelopePlaintext === 'string') { - envelopePlaintext = this.stringToArrayBuffer(envelopePlaintext); + envelopePlaintext = MessageReceiver.stringToArrayBuffer( + envelopePlaintext + ); } const envelope = textsecure.protobuf.Envelope.decode(envelopePlaintext); @@ -280,7 +285,9 @@ MessageReceiver.prototype.extend({ if (decrypted) { let payloadPlaintext = decrypted; if (typeof payloadPlaintext === 'string') { - payloadPlaintext = this.stringToArrayBuffer(payloadPlaintext); + payloadPlaintext = MessageReceiver.stringToArrayBuffer( + payloadPlaintext + ); } this.queueDecryptedEnvelope(envelope, payloadPlaintext); } else { @@ -312,13 +319,6 @@ MessageReceiver.prototype.extend({ envelope.sourceDevice } ${envelope.timestamp.toNumber()}`; }, - stringToArrayBuffer(string) { - // eslint-disable-next-line new-cap - return dcodeIO.ByteBuffer.wrap(string, 'binary').toArrayBuffer(); - }, - arrayBufferToString(arrayBuffer) { - return dcodeIO.ByteBuffer.wrap(arrayBuffer).toString('binary'); - }, getAllFromCache() { window.log.info('getAllFromCache'); return textsecure.storage.unprocessed.getAll().then(items => { @@ -356,7 +356,7 @@ MessageReceiver.prototype.extend({ const id = this.getEnvelopeId(envelope); const data = { id, - envelope: this.arrayBufferToString(plaintext), + envelope: MessageReceiver.arrayBufferToString(plaintext), timestamp: Date.now(), attempts: 1, }; @@ -365,7 +365,7 @@ MessageReceiver.prototype.extend({ updateCache(envelope, plaintext) { const id = this.getEnvelopeId(envelope); const data = { - decrypted: this.arrayBufferToString(plaintext), + decrypted: MessageReceiver.arrayBufferToString(plaintext), }; return textsecure.storage.unprocessed.update(id, data); },