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.
		
		
		
		
		
			
		
			
	
	
		
			246 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			JavaScript
		
	
		
		
			
		
	
	
			246 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			JavaScript
		
	
| 
											7 years ago
										 | /* global window */ | ||
|  | 
 | ||
| 
											8 years ago
										 | const { isString, last } = require('lodash'); | ||
| 
											8 years ago
										 | 
 | ||
| 
											8 years ago
										 | const { runMigrations } = require('./run_migrations'); | ||
| 
											8 years ago
										 | const Migration18 = require('./18'); | ||
| 
											8 years ago
										 | 
 | ||
|  | // IMPORTANT: The migrations below are run on a database that may be very large
 | ||
|  | // due to attachments being directly stored inside the database. Please avoid
 | ||
|  | // any expensive operations, e.g. modifying all messages / attachments, etc., as
 | ||
|  | // it may cause out-of-memory errors for users with long histories:
 | ||
|  | // https://github.com/signalapp/Signal-Desktop/issues/2163
 | ||
| 
											8 years ago
										 | const migrations = [ | ||
| 
											8 years ago
										 |   { | ||
|  |     version: '12.0', | ||
|  |     migrate(transaction, next) { | ||
| 
											7 years ago
										 |       window.log.info('Migration 12'); | ||
|  |       window.log.info('creating object stores'); | ||
| 
											8 years ago
										 |       const messages = transaction.db.createObjectStore('messages'); | ||
|  |       messages.createIndex('conversation', ['conversationId', 'received_at'], { | ||
|  |         unique: false, | ||
|  |       }); | ||
|  |       messages.createIndex('receipt', 'sent_at', { unique: false }); | ||
| 
											8 years ago
										 |       messages.createIndex('unread', ['conversationId', 'unread'], { | ||
|  |         unique: false, | ||
|  |       }); | ||
| 
											8 years ago
										 |       messages.createIndex('expires_at', 'expires_at', { unique: false }); | ||
|  | 
 | ||
|  |       const conversations = transaction.db.createObjectStore('conversations'); | ||
|  |       conversations.createIndex('inbox', 'active_at', { unique: false }); | ||
|  |       conversations.createIndex('group', 'members', { | ||
|  |         unique: false, | ||
|  |         multiEntry: true, | ||
|  |       }); | ||
|  |       conversations.createIndex('type', 'type', { | ||
|  |         unique: false, | ||
|  |       }); | ||
|  |       conversations.createIndex('search', 'tokens', { | ||
|  |         unique: false, | ||
|  |         multiEntry: true, | ||
|  |       }); | ||
|  | 
 | ||
|  |       transaction.db.createObjectStore('groups'); | ||
|  | 
 | ||
|  |       transaction.db.createObjectStore('sessions'); | ||
|  |       transaction.db.createObjectStore('identityKeys'); | ||
| 
											7 years ago
										 |       const preKeys = transaction.db.createObjectStore('preKeys', { | ||
|  |         keyPath: 'id', | ||
|  |       }); | ||
| 
											7 years ago
										 |       preKeys.createIndex('recipient', 'recipient', { unique: true }); | ||
|  | 
 | ||
| 
											8 years ago
										 |       transaction.db.createObjectStore('signedPreKeys'); | ||
|  |       transaction.db.createObjectStore('items'); | ||
| 
											7 years ago
										 | 
 | ||
|  |       const contactPreKeys = transaction.db.createObjectStore( | ||
|  |         'contactPreKeys', | ||
|  |         { keyPath: 'id', autoIncrement: true } | ||
|  |       ); | ||
|  |       contactPreKeys.createIndex('identityKeyString', 'identityKeyString', { | ||
|  |         unique: false, | ||
|  |       }); | ||
| 
											7 years ago
										 |       contactPreKeys.createIndex('keyId', 'keyId', { unique: false }); | ||
| 
											7 years ago
										 | 
 | ||
|  |       const contactSignedPreKeys = transaction.db.createObjectStore( | ||
|  |         'contactSignedPreKeys', | ||
|  |         { keyPath: 'id', autoIncrement: true } | ||
|  |       ); | ||
|  |       contactSignedPreKeys.createIndex( | ||
|  |         'identityKeyString', | ||
|  |         'identityKeyString', | ||
|  |         { unique: false } | ||
|  |       ); | ||
| 
											7 years ago
										 |       contactSignedPreKeys.createIndex('keyId', 'keyId', { unique: false }); | ||
| 
											8 years ago
										 | 
 | ||
| 
											7 years ago
										 |       window.log.info('creating debug log'); | ||
| 
											8 years ago
										 |       transaction.db.createObjectStore('debug'); | ||
|  | 
 | ||
|  |       next(); | ||
|  |     }, | ||
|  |   }, | ||
|  |   { | ||
|  |     version: '13.0', | ||
|  |     migrate(transaction, next) { | ||
| 
											7 years ago
										 |       window.log.info('Migration 13'); | ||
|  |       window.log.info('Adding fields to identity keys'); | ||
| 
											8 years ago
										 |       const identityKeys = transaction.objectStore('identityKeys'); | ||
|  |       const request = identityKeys.openCursor(); | ||
|  |       const promises = []; | ||
| 
											8 years ago
										 |       request.onsuccess = event => { | ||
| 
											8 years ago
										 |         const cursor = event.target.result; | ||
|  |         if (cursor) { | ||
|  |           const attributes = cursor.value; | ||
|  |           attributes.timestamp = 0; | ||
|  |           attributes.firstUse = false; | ||
|  |           attributes.nonblockingApproval = false; | ||
|  |           attributes.verified = 0; | ||
| 
											8 years ago
										 |           promises.push( | ||
|  |             new Promise((resolve, reject) => { | ||
|  |               const putRequest = identityKeys.put(attributes, attributes.id); | ||
|  |               putRequest.onsuccess = resolve; | ||
| 
											7 years ago
										 |               putRequest.onerror = error => { | ||
|  |                 window.log.error(error && error.stack ? error.stack : error); | ||
|  |                 reject(error); | ||
| 
											8 years ago
										 |               }; | ||
|  |             }) | ||
|  |           ); | ||
| 
											8 years ago
										 |           cursor.continue(); | ||
|  |         } else { | ||
|  |           // no more results
 | ||
|  |           // eslint-disable-next-line more/no-then
 | ||
|  |           Promise.all(promises).then(() => { | ||
|  |             next(); | ||
|  |           }); | ||
|  |         } | ||
|  |       }; | ||
| 
											8 years ago
										 |       request.onerror = event => { | ||
| 
											7 years ago
										 |         window.log.error(event); | ||
| 
											8 years ago
										 |       }; | ||
|  |     }, | ||
|  |   }, | ||
|  |   { | ||
|  |     version: '14.0', | ||
|  |     migrate(transaction, next) { | ||
| 
											7 years ago
										 |       window.log.info('Migration 14'); | ||
|  |       window.log.info('Adding unprocessed message store'); | ||
| 
											8 years ago
										 |       const unprocessed = transaction.db.createObjectStore('unprocessed'); | ||
|  |       unprocessed.createIndex('received', 'timestamp', { unique: false }); | ||
|  |       next(); | ||
|  |     }, | ||
|  |   }, | ||
|  |   { | ||
|  |     version: '15.0', | ||
|  |     migrate(transaction, next) { | ||
| 
											7 years ago
										 |       window.log.info('Migration 15'); | ||
|  |       window.log.info('Adding messages index for de-duplication'); | ||
| 
											8 years ago
										 |       const messages = transaction.objectStore('messages'); | ||
|  |       messages.createIndex('unique', ['source', 'sourceDevice', 'sent_at'], { | ||
|  |         unique: true, | ||
|  |       }); | ||
|  |       next(); | ||
|  |     }, | ||
|  |   }, | ||
|  |   { | ||
|  |     version: '16.0', | ||
|  |     migrate(transaction, next) { | ||
| 
											7 years ago
										 |       window.log.info('Migration 16'); | ||
|  |       window.log.info('Dropping log table, since we now log to disk'); | ||
| 
											8 years ago
										 |       transaction.db.deleteObjectStore('debug'); | ||
|  |       next(); | ||
|  |     }, | ||
|  |   }, | ||
|  |   { | ||
|  |     version: 17, | ||
|  |     async migrate(transaction, next) { | ||
| 
											7 years ago
										 |       window.log.info('Migration 17'); | ||
| 
											8 years ago
										 | 
 | ||
|  |       const start = Date.now(); | ||
|  | 
 | ||
|  |       const messagesStore = transaction.objectStore('messages'); | ||
| 
											7 years ago
										 |       window.log.info( | ||
|  |         'Create index from attachment schema version to attachment' | ||
|  |       ); | ||
| 
											8 years ago
										 |       messagesStore.createIndex('schemaVersion', 'schemaVersion', { | ||
|  |         unique: false, | ||
|  |       }); | ||
| 
											8 years ago
										 | 
 | ||
|  |       const duration = Date.now() - start; | ||
|  | 
 | ||
| 
											7 years ago
										 |       window.log.info( | ||
| 
											8 years ago
										 |         'Complete migration to database version 17', | ||
|  |         `Duration: ${duration}ms` | ||
|  |       ); | ||
|  |       next(); | ||
|  |     }, | ||
|  |   }, | ||
|  |   { | ||
|  |     version: 18, | ||
|  |     migrate(transaction, next) { | ||
| 
											7 years ago
										 |       window.log.info('Migration 18'); | ||
| 
											8 years ago
										 | 
 | ||
|  |       const start = Date.now(); | ||
| 
											7 years ago
										 |       Migration18.run({ transaction, logger: window.log }); | ||
| 
											8 years ago
										 |       const duration = Date.now() - start; | ||
|  | 
 | ||
| 
											7 years ago
										 |       window.log.info( | ||
| 
											8 years ago
										 |         'Complete migration to database version 18', | ||
| 
											8 years ago
										 |         `Duration: ${duration}ms` | ||
|  |       ); | ||
|  |       next(); | ||
|  |     }, | ||
|  |   }, | ||
| 
											7 years ago
										 |   { | ||
|  |     version: 19, | ||
|  |     migrate(transaction, next) { | ||
|  |       window.log.info('Migration 19'); | ||
|  | 
 | ||
| 
											7 years ago
										 |       // Empty because we don't want to cause incompatibility with beta users who have
 | ||
|  |       //   already run migration 19 when it was object store removal.
 | ||
|  | 
 | ||
|  |       next(); | ||
|  |     }, | ||
|  |   }, | ||
|  |   { | ||
|  |     version: 20, | ||
|  |     migrate(transaction, next) { | ||
|  |       window.log.info('Migration 20'); | ||
|  | 
 | ||
| 
											7 years ago
										 |       // Empty because we don't want to cause incompatibility with users who have already
 | ||
| 
											7 years ago
										 |       //   run migration 20 when it was object store removal.
 | ||
| 
											7 years ago
										 | 
 | ||
|  |       next(); | ||
|  |     }, | ||
|  |   }, | ||
| 
											8 years ago
										 | ]; | ||
|  | 
 | ||
|  | const database = { | ||
| 
											7 years ago
										 |   id: 'loki-messenger', | ||
| 
											8 years ago
										 |   nolog: true, | ||
| 
											8 years ago
										 |   migrations, | ||
| 
											8 years ago
										 | }; | ||
|  | 
 | ||
| 
											7 years ago
										 | exports.run = ({ Backbone, databaseName, logger } = {}) => | ||
| 
											8 years ago
										 |   runMigrations({ | ||
|  |     Backbone, | ||
| 
											7 years ago
										 |     logger, | ||
| 
											8 years ago
										 |     database: Object.assign( | ||
|  |       {}, | ||
|  |       database, | ||
|  |       isString(databaseName) ? { id: databaseName } : {} | ||
|  |     ), | ||
|  |   }); | ||
| 
											8 years ago
										 | 
 | ||
| 
											8 years ago
										 | exports.getDatabase = () => ({ | ||
|  |   name: database.id, | ||
| 
											8 years ago
										 |   version: exports.getLatestVersion(), | ||
| 
											8 years ago
										 | }); | ||
| 
											8 years ago
										 | 
 | ||
|  | exports.getLatestVersion = () => { | ||
|  |   const lastMigration = last(migrations); | ||
|  |   if (!lastMigration) { | ||
|  |     return null; | ||
|  |   } | ||
|  | 
 | ||
|  |   return lastMigration.version; | ||
|  | }; |