You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			169 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			JavaScript
		
	
			
		
		
	
	
			169 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			JavaScript
		
	
/* global window, Whisper, textsecure */
 | 
						|
 | 
						|
const { isFunction } = require('lodash');
 | 
						|
 | 
						|
const MessageDataMigrator = require('./messages_data_migrator');
 | 
						|
const {
 | 
						|
  run,
 | 
						|
  getLatestVersion,
 | 
						|
  getDatabase,
 | 
						|
} = require('./migrations/migrations');
 | 
						|
 | 
						|
const MESSAGE_MINIMUM_VERSION = 7;
 | 
						|
 | 
						|
module.exports = {
 | 
						|
  doesDatabaseExist,
 | 
						|
  mandatoryMessageUpgrade,
 | 
						|
  MESSAGE_MINIMUM_VERSION,
 | 
						|
  migrateAllToSQLCipher,
 | 
						|
  removeDatabase,
 | 
						|
  runMigrations,
 | 
						|
};
 | 
						|
 | 
						|
async function runMigrations() {
 | 
						|
  window.log.info('Run migrations on database with attachment data');
 | 
						|
  await run({
 | 
						|
    Backbone: window.Backbone,
 | 
						|
    logger: window.log,
 | 
						|
  });
 | 
						|
 | 
						|
  Whisper.Database.migrations[0].version = getLatestVersion();
 | 
						|
}
 | 
						|
 | 
						|
async function mandatoryMessageUpgrade({ upgradeMessageSchema } = {}) {
 | 
						|
  if (!isFunction(upgradeMessageSchema)) {
 | 
						|
    throw new Error(
 | 
						|
      'mandatoryMessageUpgrade: upgradeMessageSchema must be a function!'
 | 
						|
    );
 | 
						|
  }
 | 
						|
 | 
						|
  const NUM_MESSAGES_PER_BATCH = 10;
 | 
						|
  window.log.info(
 | 
						|
    'upgradeMessages: Mandatory message schema upgrade started.',
 | 
						|
    `Target version: ${MESSAGE_MINIMUM_VERSION}`
 | 
						|
  );
 | 
						|
 | 
						|
  let isMigrationWithoutIndexComplete = false;
 | 
						|
  while (!isMigrationWithoutIndexComplete) {
 | 
						|
    const database = getDatabase();
 | 
						|
    // eslint-disable-next-line no-await-in-loop
 | 
						|
    const batchWithoutIndex = await MessageDataMigrator.processNextBatchWithoutIndex(
 | 
						|
      {
 | 
						|
        databaseName: database.name,
 | 
						|
        minDatabaseVersion: database.version,
 | 
						|
        numMessagesPerBatch: NUM_MESSAGES_PER_BATCH,
 | 
						|
        upgradeMessageSchema,
 | 
						|
        maxVersion: MESSAGE_MINIMUM_VERSION,
 | 
						|
        BackboneMessage: Whisper.Message,
 | 
						|
        saveMessage: window.Signal.Data.saveLegacyMessage,
 | 
						|
      }
 | 
						|
    );
 | 
						|
    window.log.info(
 | 
						|
      'upgradeMessages: upgrade without index',
 | 
						|
      batchWithoutIndex
 | 
						|
    );
 | 
						|
    isMigrationWithoutIndexComplete = batchWithoutIndex.done;
 | 
						|
  }
 | 
						|
  window.log.info('upgradeMessages: upgrade without index complete!');
 | 
						|
 | 
						|
  let isMigrationWithIndexComplete = false;
 | 
						|
  while (!isMigrationWithIndexComplete) {
 | 
						|
    // eslint-disable-next-line no-await-in-loop
 | 
						|
    const batchWithIndex = await MessageDataMigrator.processNext({
 | 
						|
      BackboneMessage: Whisper.Message,
 | 
						|
      BackboneMessageCollection: Whisper.MessageCollection,
 | 
						|
      numMessagesPerBatch: NUM_MESSAGES_PER_BATCH,
 | 
						|
      upgradeMessageSchema,
 | 
						|
      getMessagesNeedingUpgrade:
 | 
						|
        window.Signal.Data.getLegacyMessagesNeedingUpgrade,
 | 
						|
      saveMessage: window.Signal.Data.saveLegacyMessage,
 | 
						|
      maxVersion: MESSAGE_MINIMUM_VERSION,
 | 
						|
    });
 | 
						|
    window.log.info('upgradeMessages: upgrade with index', batchWithIndex);
 | 
						|
    isMigrationWithIndexComplete = batchWithIndex.done;
 | 
						|
  }
 | 
						|
  window.log.info('upgradeMessages: upgrade with index complete!');
 | 
						|
 | 
						|
  window.log.info('upgradeMessages: Message schema upgrade complete');
 | 
						|
}
 | 
						|
 | 
						|
async function migrateAllToSQLCipher({ writeNewAttachmentData, Views } = {}) {
 | 
						|
  if (!isFunction(writeNewAttachmentData)) {
 | 
						|
    throw new Error(
 | 
						|
      'migrateAllToSQLCipher: writeNewAttachmentData must be a function'
 | 
						|
    );
 | 
						|
  }
 | 
						|
  if (!Views) {
 | 
						|
    throw new Error('migrateAllToSQLCipher: Views must be provided!');
 | 
						|
  }
 | 
						|
 | 
						|
  let totalMessages;
 | 
						|
  const db = await Whisper.Database.open();
 | 
						|
 | 
						|
  function showMigrationStatus(current) {
 | 
						|
    const status = `${current}/${totalMessages}`;
 | 
						|
    Views.Initialization.setMessage(
 | 
						|
      window.i18n('migratingToSQLCipher', [status])
 | 
						|
    );
 | 
						|
  }
 | 
						|
 | 
						|
  try {
 | 
						|
    totalMessages = await MessageDataMigrator.getNumMessages({
 | 
						|
      connection: db,
 | 
						|
    });
 | 
						|
  } catch (error) {
 | 
						|
    window.log.error(
 | 
						|
      'background.getNumMessages error:',
 | 
						|
      error && error.stack ? error.stack : error
 | 
						|
    );
 | 
						|
    totalMessages = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  if (totalMessages) {
 | 
						|
    window.log.info(`About to migrate ${totalMessages} messages`);
 | 
						|
    showMigrationStatus(0);
 | 
						|
  } else {
 | 
						|
    window.log.info('About to migrate non-messages');
 | 
						|
  }
 | 
						|
 | 
						|
  await window.Signal.migrateToSQL({
 | 
						|
    db,
 | 
						|
    clearStores: Whisper.Database.clearStores,
 | 
						|
    handleDOMException: Whisper.Database.handleDOMException,
 | 
						|
    arrayBufferToString: textsecure.MessageReceiver.arrayBufferToStringBase64,
 | 
						|
    countCallback: count => {
 | 
						|
      window.log.info(`Migration: ${count} messages complete`);
 | 
						|
      showMigrationStatus(count);
 | 
						|
    },
 | 
						|
    writeNewAttachmentData,
 | 
						|
  });
 | 
						|
 | 
						|
  db.close();
 | 
						|
}
 | 
						|
 | 
						|
async function doesDatabaseExist() {
 | 
						|
  return new Promise((resolve, reject) => {
 | 
						|
    const { id } = Whisper.Database;
 | 
						|
    const req = window.indexedDB.open(id);
 | 
						|
 | 
						|
    let existed = true;
 | 
						|
 | 
						|
    req.onerror = reject;
 | 
						|
    req.onsuccess = () => {
 | 
						|
      req.result.close();
 | 
						|
      resolve(existed);
 | 
						|
    };
 | 
						|
    req.onupgradeneeded = () => {
 | 
						|
      if (req.result.version === 1) {
 | 
						|
        existed = false;
 | 
						|
        window.indexedDB.deleteDatabase(id);
 | 
						|
      }
 | 
						|
    };
 | 
						|
  });
 | 
						|
}
 | 
						|
 | 
						|
function removeDatabase() {
 | 
						|
  window.log.info(`Deleting IndexedDB database '${Whisper.Database.id}'`);
 | 
						|
  window.indexedDB.deleteDatabase(Whisper.Database.id);
 | 
						|
}
 |