From 5933a34a186492ca5aa33a78ffb643ddb17291f8 Mon Sep 17 00:00:00 2001 From: Scott Nonnenberg Date: Sat, 21 Jul 2018 12:00:08 -0700 Subject: [PATCH] Use window.log in browser context, turn on console eslint rule --- .eslintrc.js | 2 +- Gruntfile.js | 2 +- app/.eslintrc.js | 6 + {js/modules => app}/global_errors.js | 2 +- js/background.js | 107 +++++++------ js/conversation_controller.js | 10 +- js/database.js | 10 +- js/delivery_receipts.js | 4 +- js/expire.js | 5 +- js/expiring_messages.js | 7 +- js/logging.js | 53 +++---- js/models/blockedNumbers.js | 4 +- js/models/conversations.js | 47 +++--- js/models/messages.js | 29 ++-- js/modules/backup.js | 81 +++++----- js/modules/debug.js | 5 +- js/modules/i18n.js | 3 +- js/modules/idle_detector.js | 4 +- js/modules/messages_data_migrator.js | 9 +- js/modules/migrations/18/index.js | 6 +- ...rations_0_database_with_attachment_data.js | 49 +++--- ...ions_1_database_without_attachment_data.js | 4 +- js/modules/migrations/run_migrations.js | 13 +- js/modules/signal.js | 12 +- js/modules/types/attachment.js | 47 +++--- .../attachment/migrate_data_to_file_system.js | 4 +- js/modules/types/contact.js | 4 +- js/modules/types/message.js | 124 +++++++++------ js/modules/types/visual_attachment.js | 35 +++-- js/modules/web_api.js | 15 +- js/notifications.js | 8 +- js/read_receipts.js | 6 +- js/read_syncs.js | 78 +++++----- js/reliable_trigger.js | 2 +- js/rotate_signed_prekey_listener.js | 10 +- js/signal_protocol_store.js | 36 ++--- js/spell_check.js | 15 +- js/storage.js | 5 +- js/views/app_view.js | 2 +- js/views/clear_data_view.js | 10 +- js/views/conversation_list_view.js | 6 +- js/views/conversation_view.js | 23 ++- js/views/debug_log_view.js | 2 +- js/views/file_input_view.js | 18 ++- js/views/import_view.js | 4 +- js/views/inbox_view.js | 2 +- js/views/install_view.js | 21 +-- js/views/key_verification_view.js | 10 +- js/views/recorder_view.js | 8 +- js/views/settings_view.js | 12 +- js/views/standalone_registration_view.js | 2 +- libtextsecure/account_manager.js | 45 +++--- libtextsecure/contacts_parser.js | 7 +- libtextsecure/key_worker.js | 2 +- libtextsecure/message_receiver.js | 83 ++++++----- libtextsecure/outgoing_message.js | 4 +- libtextsecure/protobufs.js | 4 +- libtextsecure/sendmessage.js | 8 +- libtextsecure/sync_request.js | 6 +- libtextsecure/task_with_timeout.js | 4 +- libtextsecure/test/message_receiver_test.js | 1 - libtextsecure/websocket-resources.js | 6 +- main.js | 4 +- preload.js | 13 +- prepare_beta_build.js | 2 + prepare_import_build.js | 2 + test/_test.js | 1 + test/modules/types/attachment_test.js | 16 +- test/modules/types/contact_test.js | 39 ++++- test/modules/types/message_test.js | 141 +++++++++++++----- .../media-gallery/MediaGridItem.tsx | 4 + 71 files changed, 816 insertions(+), 559 deletions(-) create mode 100644 app/.eslintrc.js rename {js/modules => app}/global_errors.js (86%) diff --git a/.eslintrc.js b/.eslintrc.js index a53086c51a..9bc431d915 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -34,7 +34,7 @@ module.exports = { 'no-underscore-dangle': 'off', // though we have a logger, we still remap console to log to disk - 'no-console': 'off', + 'no-console': 'error', // consistently place operators at end of line except ternaries 'operator-linebreak': 'error', diff --git a/Gruntfile.js b/Gruntfile.js index 8abd86961e..355d4add77 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -8,7 +8,7 @@ const asar = require('asar'); const fs = require('fs'); const assert = require('assert'); -/* eslint-disable more/no-then */ +/* eslint-disable more/no-then, no-console */ module.exports = grunt => { const bower = grunt.file.readJSON('bower.json'); diff --git a/app/.eslintrc.js b/app/.eslintrc.js new file mode 100644 index 0000000000..db69294e54 --- /dev/null +++ b/app/.eslintrc.js @@ -0,0 +1,6 @@ +module.exports = { + rules: { + // On the node.js side, we're still using console.log + 'no-console': 'off', + }, +}; diff --git a/js/modules/global_errors.js b/app/global_errors.js similarity index 86% rename from js/modules/global_errors.js rename to app/global_errors.js index d7b2279b71..2c00e3c392 100644 --- a/js/modules/global_errors.js +++ b/app/global_errors.js @@ -1,6 +1,6 @@ const addUnhandledErrorHandler = require('electron-unhandled'); -const Errors = require('./types/errors'); +const Errors = require('../js/modules/types/errors'); // addHandler :: Unit -> Unit exports.addHandler = () => { diff --git a/js/background.js b/js/background.js index fff647bf2b..4920760dbb 100644 --- a/js/background.js +++ b/js/background.js @@ -26,10 +26,11 @@ // Implicitly used in `indexeddb-backbonejs-adapter`: // https://github.com/signalapp/Signal-Desktop/blob/4033a9f8137e62ed286170ed5d4941982b1d3a64/components/indexeddb-backbonejs-adapter/backbone-indexeddb.js#L569 - window.onInvalidStateError = e => console.log(e); + window.onInvalidStateError = error => + window.log.error(error && error.stack ? error.stack : error); - console.log('background page reloaded'); - console.log('environment:', window.getEnvironment()); + window.log.info('background page reloaded'); + window.log.info('environment:', window.getEnvironment()); let initialLoadComplete = false; window.owsDesktopApp = {}; @@ -58,7 +59,7 @@ accountManager = new textsecure.AccountManager(USERNAME, PASSWORD); accountManager.addEventListener('registration', () => { Whisper.Registration.markDone(); - console.log('dispatching registration event'); + window.log.info('dispatching registration event'); Whisper.events.trigger('registration_done'); }); } @@ -66,19 +67,22 @@ }; const cancelInitializationMessage = Views.Initialization.setMessage(); - console.log('Start IndexedDB migrations'); + window.log.info('Start IndexedDB migrations'); - console.log('Run migrations on database with attachment data'); - await Migrations0DatabaseWithAttachmentData.run({ Backbone }); + window.log.info('Run migrations on database with attachment data'); + await Migrations0DatabaseWithAttachmentData.run({ + Backbone, + logger: window.log, + }); - console.log('Storage fetch'); + window.log.info('Storage fetch'); storage.fetch(); const idleDetector = new IdleDetector(); let isMigrationWithIndexComplete = false; let isMigrationWithoutIndexComplete = false; idleDetector.on('idle', async () => { - console.log('Idle processing started'); + window.log.info('Idle processing started'); const NUM_MESSAGES_PER_BATCH = 1; if (!isMigrationWithIndexComplete) { @@ -88,7 +92,7 @@ numMessagesPerBatch: NUM_MESSAGES_PER_BATCH, upgradeMessageSchema, }); - console.log('Upgrade message schema (with index):', batchWithIndex); + window.log.info('Upgrade message schema (with index):', batchWithIndex); isMigrationWithIndexComplete = batchWithIndex.done; } @@ -102,14 +106,17 @@ upgradeMessageSchema, } ); - console.log('Upgrade message schema (without index):', batchWithoutIndex); + window.log.info( + 'Upgrade message schema (without index):', + batchWithoutIndex + ); isMigrationWithoutIndexComplete = batchWithoutIndex.done; } const areAllMigrationsComplete = isMigrationWithIndexComplete && isMigrationWithoutIndexComplete; if (areAllMigrationsComplete) { - console.log('All migrations are complete. Stopping idle detector.'); + window.log.info('All migrations are complete. Stopping idle detector.'); idleDetector.stop(); } }); @@ -254,22 +261,22 @@ if (newVersion) { if ( lastVersion && - window.isBeforeVersion(lastVersion, 'v1.15.0-beta.4') + window.isBeforeVersion(lastVersion, 'v1.15.0-beta.5') ) { await window.Signal.Logs.deleteAll(); window.restart(); } - console.log( + window.log.info( `New version detected: ${currentVersion}; previous: ${lastVersion}` ); } window.dispatchEvent(new Event('storage_ready')); - console.log('listening for registration events'); + window.log.info('listening for registration events'); Whisper.events.on('registration_done', () => { - console.log('handling registration event'); + window.log.info('handling registration event'); Whisper.RotateSignedPreKeyListener.init(Whisper.events, newVersion); connect(true); }); @@ -284,7 +291,7 @@ Whisper.ExpiringMessagesListener.init(Whisper.events); if (Whisper.Import.isIncomplete()) { - console.log('Import was interrupted, showing import error screen'); + window.log.info('Import was interrupted, showing import error screen'); appView.openImporter(); } else if (Whisper.Registration.everDone()) { Whisper.RotateSignedPreKeyListener.init(Whisper.events, newVersion); @@ -346,7 +353,7 @@ let disconnectTimer = null; function onOffline() { - console.log('offline'); + window.log.info('offline'); window.removeEventListener('offline', onOffline); window.addEventListener('online', onOnline); @@ -358,13 +365,13 @@ } function onOnline() { - console.log('online'); + window.log.info('online'); window.removeEventListener('online', onOnline); window.addEventListener('offline', onOffline); if (disconnectTimer && isSocketOnline()) { - console.log('Already online. Had a blip in online/offline status.'); + window.log.warn('Already online. Had a blip in online/offline status.'); clearTimeout(disconnectTimer); disconnectTimer = null; return; @@ -385,7 +392,7 @@ } function disconnect() { - console.log('disconnect'); + window.log.info('disconnect'); // Clear timer, since we're only called when the timer is expired disconnectTimer = null; @@ -397,14 +404,14 @@ let connectCount = 0; async function connect(firstRun) { - console.log('connect'); + window.log.info('connect'); // Bootstrap our online/offline detection, only the first time we connect if (connectCount === 0 && navigator.onLine) { window.addEventListener('offline', onOffline); } if (connectCount === 0 && !navigator.onLine) { - console.log( + window.log.warn( 'Starting up offline; will connect when we have network access' ); window.addEventListener('online', onOnline); @@ -480,7 +487,7 @@ sendRequestConfigurationSyncMessage, storage, }); - console.log('Sync read receipt configuration status:', status); + window.log.info('Sync read receipt configuration status:', status); if (firstRun === true && deviceId !== '1') { const hasThemeSetting = Boolean(storage.get('theme-setting')); @@ -494,19 +501,24 @@ ); Whisper.events.trigger('contactsync:begin'); syncRequest.addEventListener('success', () => { - console.log('sync successful'); + window.log.info('sync successful'); storage.put('synced_at', Date.now()); Whisper.events.trigger('contactsync'); }); syncRequest.addEventListener('timeout', () => { - console.log('sync timed out'); + window.log.error('sync timed out'); Whisper.events.trigger('contactsync'); }); if (Whisper.Import.isComplete()) { - textsecure.messaging.sendRequestConfigurationSyncMessage().catch(e => { - console.log(e); - }); + textsecure.messaging + .sendRequestConfigurationSyncMessage() + .catch(error => { + window.log.error( + 'Import complete, but failed to send sync message', + error && error.stack ? error.stack : error + ); + }); } } @@ -571,7 +583,7 @@ if (id === textsecure.storage.user.getNumber()) { // special case for syncing details about ourselves if (details.profileKey) { - console.log('Got sync message with our own profile key'); + window.log.info('Got sync message with our own profile key'); storage.put('profileKey', details.profileKey); } } @@ -581,7 +593,7 @@ }); const validationError = c.validateNumber(); if (validationError) { - console.log( + window.log.error( 'Invalid contact received:', Errors.toLogFormat(validationError) ); @@ -651,7 +663,7 @@ ev.confirm(); } catch (error) { - console.log('onContactReceived error:', Errors.toLogFormat(error)); + window.log.error('onContactReceived error:', Errors.toLogFormat(error)); } } @@ -686,7 +698,7 @@ const { expireTimer } = details; const isValidExpireTimer = typeof expireTimer === 'number'; if (!isValidExpireTimer) { - console.log( + window.log.error( 'Ignore invalid expire timer.', 'Expected numeric `expireTimer`, got:', expireTimer @@ -741,7 +753,7 @@ const message = createMessage(data); const isDuplicate = await isMessageDuplicate(message); if (isDuplicate) { - console.log('Received duplicate message', message.idForLogging()); + window.log.warn('Received duplicate message', message.idForLogging()); return event.confirm(); } @@ -835,7 +847,7 @@ return resolve(false); }); }).catch(error => { - console.log('isMessageDuplicate error:', Errors.toLogFormat(error)); + window.log.error('isMessageDuplicate error:', Errors.toLogFormat(error)); return false; }); } @@ -856,7 +868,7 @@ async function onError(ev) { const { error } = ev; - console.log('background onError:', Errors.toLogFormat(error)); + window.log.error('background onError:', Errors.toLogFormat(error)); if ( error && @@ -865,7 +877,7 @@ ) { Whisper.events.trigger('unauthorized'); - console.log( + window.log.warn( 'Client is no longer authorized; deleting local configuration' ); Whisper.Registration.remove(); @@ -877,9 +889,9 @@ // the conversation list, instead of showing just the QR code screen. Whisper.Registration.markEverDone(); textsecure.storage.put('number_id', previousNumberId); - console.log('Successfully cleared local configuration'); + window.log.info('Successfully cleared local configuration'); } catch (eraseError) { - console.log( + window.log.error( 'Something went wrong clearing local configuration', eraseError && eraseError.stack ? eraseError.stack : eraseError ); @@ -891,7 +903,7 @@ if (error && error.name === 'HTTPError' && error.code === -1) { // Failed to connect to server if (navigator.onLine) { - console.log('retrying in 1 minute'); + window.log.info('retrying in 1 minute'); setTimeout(connect, 60000); Whisper.events.trigger('reconnectTimer'); @@ -945,7 +957,7 @@ const readAt = ev.timestamp; const { timestamp } = ev.read; const { reader } = ev.read; - console.log('read receipt', reader, timestamp); + window.log.info('read receipt', reader, timestamp); if (!storage.get('read-receipt-setting')) { return ev.confirm(); @@ -967,7 +979,7 @@ const readAt = ev.timestamp; const { timestamp } = ev.read; const { sender } = ev.read; - console.log('read sync', sender, timestamp); + window.log.info('read sync', sender, timestamp); const receipt = Whisper.ReadSyncs.add({ sender, @@ -991,7 +1003,10 @@ }); const error = c.validateNumber(); if (error) { - console.log('Invalid verified sync received:', Errors.toLogFormat(error)); + window.log.error( + 'Invalid verified sync received:', + Errors.toLogFormat(error) + ); return; } @@ -1006,10 +1021,10 @@ state = 'UNVERIFIED'; break; default: - console.log(`Got unexpected verified state: ${ev.verified.state}`); + window.log.error(`Got unexpected verified state: ${ev.verified.state}`); } - console.log( + window.log.info( 'got verified sync for', number, state, @@ -1041,7 +1056,7 @@ function onDeliveryReceipt(ev) { const { deliveryReceipt } = ev; - console.log( + window.log.info( 'delivery receipt from', `${deliveryReceipt.source}.${deliveryReceipt.sourceDevice}`, deliveryReceipt.timestamp diff --git a/js/conversation_controller.js b/js/conversation_controller.js index b7c776fd03..75a53f7b34 100644 --- a/js/conversation_controller.js +++ b/js/conversation_controller.js @@ -135,7 +135,7 @@ conversation.initialPromise = new Promise((resolve, reject) => { if (!conversation.isValid()) { const validationError = conversation.validationError || {}; - console.log( + window.log.error( 'Contact is not valid. Not saving, but adding to collection:', conversation.idForLogging(), validationError.stack @@ -146,7 +146,7 @@ const deferred = conversation.save(); if (!deferred) { - console.log('Conversation save failed! ', id, type); + window.log.error('Conversation save failed! ', id, type); return reject(new Error('getOrCreate: Conversation save failed')); } @@ -184,17 +184,17 @@ conversations.reset([]); }, load() { - console.log('ConversationController: starting initial fetch'); + window.log.info('ConversationController: starting initial fetch'); this._initialPromise = new Promise((resolve, reject) => { conversations.fetch().then( () => { - console.log('ConversationController: done with initial fetch'); + window.log.info('ConversationController: done with initial fetch'); this._initialFetchComplete = true; resolve(); }, error => { - console.log( + window.log.error( 'ConversationController: initial fetch failed', error && error.stack ? error.stack : error ); diff --git a/js/database.js b/js/database.js index 2348217008..f057de2bcd 100644 --- a/js/database.js +++ b/js/database.js @@ -15,7 +15,7 @@ window.Whisper.Database.nolog = true; Whisper.Database.handleDOMException = (prefix, error, reject) => { - console.log( + window.log.error( `${prefix}:`, error && error.name, error && error.message, @@ -27,12 +27,12 @@ function clearStores(db, names) { return new Promise((resolve, reject) => { const storeNames = names || db.objectStoreNames; - console.log('Clearing these indexeddb stores:', storeNames); + window.log.info('Clearing these indexeddb stores:', storeNames); const transaction = db.transaction(storeNames, 'readwrite'); let finished = false; const finish = via => { - console.log('clearing all stores done via', via); + window.log.info('clearing all stores done via', via); if (finished) { resolve(); } @@ -57,10 +57,10 @@ request.onsuccess = () => { count += 1; - console.log('Done clearing store', storeName); + window.log.info('Done clearing store', storeName); if (count >= storeNames.length) { - console.log('Done clearing indexeddb stores'); + window.log.info('Done clearing indexeddb stores'); finish('clears complete'); } }; diff --git a/js/delivery_receipts.js b/js/delivery_receipts.js index 8f61ac49d0..e28b489b17 100644 --- a/js/delivery_receipts.js +++ b/js/delivery_receipts.js @@ -81,7 +81,7 @@ // TODO: consider keeping a list of numbers we've // successfully delivered to? } - console.log( + window.log.info( 'No message for delivery receipt', receipt.get('source'), receipt.get('timestamp') @@ -90,7 +90,7 @@ return null; }) .catch(error => { - console.log( + window.log.error( 'DeliveryReceipts.onReceipt error:', error && error.stack ? error.stack : error ); diff --git a/js/expire.js b/js/expire.js index db083c5726..9caff73c19 100644 --- a/js/expire.js +++ b/js/expire.js @@ -6,7 +6,10 @@ try { BUILD_EXPIRATION = parseInt(window.getExpiration(), 10); if (BUILD_EXPIRATION) { - console.log('Build expires: ', new Date(BUILD_EXPIRATION).toISOString()); + window.log.info( + 'Build expires: ', + new Date(BUILD_EXPIRATION).toISOString() + ); } } catch (e) { // nothing diff --git a/js/expiring_messages.js b/js/expiring_messages.js index 81a413e149..d8b80e6db9 100644 --- a/js/expiring_messages.js +++ b/js/expiring_messages.js @@ -15,7 +15,7 @@ // Load messages that have expired and destroy them const expired = new Whisper.MessageCollection(); expired.on('add', async message => { - console.log('Message expired', { + window.log.info('Message expired', { sentAt: message.get('sent_at'), }); const conversation = message.getConversation(); @@ -41,7 +41,10 @@ const expiring = new Whisper.MessageCollection(); expiring.once('add', next => { const expiresAt = next.get('expires_at'); - console.log('next message expires', new Date(expiresAt).toISOString()); + window.log.info( + 'next message expires', + new Date(expiresAt).toISOString() + ); let wait = expiresAt - Date.now(); diff --git a/js/logging.js b/js/logging.js index 07a5b7f612..4d749178bc 100644 --- a/js/logging.js +++ b/js/logging.js @@ -1,9 +1,9 @@ /* eslint-env node */ /* eslint strict: ['error', 'never'] */ +/* eslint-disable no-console */ const electron = require('electron'); -const bunyan = require('bunyan'); const _ = require('lodash'); const debuglogs = require('./modules/debuglogs'); @@ -29,11 +29,8 @@ function now() { return date.toJSON(); } -function log(...args) { - const consoleArgs = ['INFO ', now()].concat(args); - console._log(...consoleArgs); - - // To avoid [Object object] in our log since console.log handles non-strings smoothly +// To avoid [Object object] in our log since console.log handles non-strings smoothly +function cleanArgsForIPC(args) { const str = args.map(item => { if (typeof item !== 'string') { try { @@ -46,8 +43,11 @@ function log(...args) { return item; }); - const logText = Privacy.redactAll(str.join(' ')); - ipc.send('log-info', logText); + return str.join(' '); +} + +function log(...args) { + logAtLevel('info', 'INFO ', ...args); } if (window.console) { @@ -98,37 +98,22 @@ const publish = debuglogs.upload; // A modern logging interface for the browser -// We create our own stream because we don't want to output JSON to the devtools console. -// Anyway, the default process.stdout stream goes to the command-line, not the devtools. -const logger = bunyan.createLogger({ - name: 'log', - streams: [ - { - level: 'debug', - stream: { - write(entry) { - console._log(formatLine(JSON.parse(entry))); - }, - }, - }, - ], -}); - // The Bunyan API: https://github.com/trentm/node-bunyan#log-method-api -function logAtLevel(level, ...args) { - const ipcArgs = [`log-${level}`].concat(args); - ipc.send(...ipcArgs); +function logAtLevel(level, prefix, ...args) { + console._log(prefix, now(), ...args); - logger[level](...args); + const str = cleanArgsForIPC(args); + const logText = Privacy.redactAll(str); + ipc.send(`log-${level}`, logText); } window.log = { - fatal: _.partial(logAtLevel, 'fatal'), - error: _.partial(logAtLevel, 'error'), - warn: _.partial(logAtLevel, 'warn'), - info: _.partial(logAtLevel, 'info'), - debug: _.partial(logAtLevel, 'debug'), - trace: _.partial(logAtLevel, 'trace'), + fatal: _.partial(logAtLevel, 'fatal', 'FATAL'), + error: _.partial(logAtLevel, 'error', 'ERROR'), + warn: _.partial(logAtLevel, 'warn', 'WARN '), + info: _.partial(logAtLevel, 'info', 'INFO '), + debug: _.partial(logAtLevel, 'debug', 'DEBUG'), + trace: _.partial(logAtLevel, 'trace', 'TRACE'), fetch, publish, }; diff --git a/js/models/blockedNumbers.js b/js/models/blockedNumbers.js index ab2e37dde4..54b5ebc20e 100644 --- a/js/models/blockedNumbers.js +++ b/js/models/blockedNumbers.js @@ -15,7 +15,7 @@ return; } - console.log('adding', number, 'to blocked list'); + window.log.info('adding', number, 'to blocked list'); storage.put('blocked', numbers.concat(number)); }; storage.removeBlockedNumber = number => { @@ -24,7 +24,7 @@ return; } - console.log('removing', number, 'from blocked list'); + window.log.info('removing', number, 'from blocked list'); storage.put('blocked', _.without(numbers, number)); }; })(); diff --git a/js/models/conversations.js b/js/models/conversations.js index 90a60d468a..90a05b4138 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -156,7 +156,7 @@ async onExpiredCollection(message) { const removeMessage = () => { - console.log('Remove expired message from collection', { + window.log.info('Remove expired message from collection', { sentAt: message.get('sent_at'), }); this.messageCollection.remove(message.id); @@ -347,7 +347,7 @@ return lookup; }) .catch(error => { - console.log( + window.log.error( 'getIdentityKeys error for conversation', this.idForLogging(), error && error.stack ? error.stack : error @@ -361,7 +361,7 @@ lookup[contact.id] = key; }, error => { - console.log( + window.log.error( 'getIdentityKeys error for group member', contact.idForLogging(), error && error.stack ? error.stack : error @@ -375,7 +375,7 @@ replay(error, message) { const replayable = new textsecure.ReplayableError(error); return replayable.replay(message.attributes).catch(e => { - console.log('replay error:', e && e.stack ? e.stack : e); + window.log.error('replay error:', e && e.stack ? e.stack : e); }); }, decryptOldIncomingKeyErrors() { @@ -383,7 +383,10 @@ if (this.get('decryptedOldIncomingKeyErrors')) { return Promise.resolve(); } - console.log('decryptOldIncomingKeyErrors start for', this.idForLogging()); + window.log.info( + 'decryptOldIncomingKeyErrors start for', + this.idForLogging() + ); const messages = this.messageCollection.filter(message => { const errors = message.get('errors'); @@ -399,7 +402,7 @@ }); const markComplete = () => { - console.log( + window.log.info( 'decryptOldIncomingKeyErrors complete for', this.idForLogging() ); @@ -412,7 +415,7 @@ return markComplete(); } - console.log( + window.log.info( 'decryptOldIncomingKeyErrors found', messages.length, 'messages to process' @@ -449,7 +452,7 @@ ) ) .catch(error => { - console.log( + window.log.error( 'decryptOldIncomingKeyErrors error:', error && error.stack ? error.stack : error ); @@ -583,7 +586,7 @@ }, addKeyChange(id) { - console.log( + window.log.info( 'adding key change advisory for', this.idForLogging(), id, @@ -606,7 +609,7 @@ _.defaults(options, { local: true }); if (this.isMe()) { - console.log( + window.log.info( 'refusing to add verified change advisory for our own number' ); return; @@ -614,7 +617,7 @@ const lastMessage = this.get('timestamp') || Date.now(); - console.log( + window.log.info( 'adding verified change advisory for', this.idForLogging(), id, @@ -823,7 +826,7 @@ this.queueJob(async () => { const now = Date.now(); - console.log( + window.log.info( 'Sending message to conversation', this.idForLogging(), 'with timestamp', @@ -933,7 +936,7 @@ return Promise.resolve(); } - console.log("Update conversation 'expireTimer'", { + window.log.info("Update conversation 'expireTimer'", { id: this.idForLogging(), expireTimer, source, @@ -1085,7 +1088,7 @@ if (this.messageCollection.get(m.id)) { m = this.messageCollection.get(m.id); } else { - console.log( + window.log.warn( 'Marked a message as read in the database, but ' + 'it was not in messageCollection.' ); @@ -1117,7 +1120,7 @@ read = read.filter(item => !item.hasErrors); if (read.length && options.sendReadReceipts) { - console.log('Sending', read.length, 'read receipts'); + window.log.info('Sending', read.length, 'read receipts'); promises.push(textsecure.messaging.syncReadMessages(read)); if (storage.get('read-receipt-setting')) { @@ -1173,7 +1176,7 @@ // save identity will close all sessions except for .1, so we // must close that one manually. const address = new libsignal.SignalProtocolAddress(id, 1); - console.log('closing session for', address.toString()); + window.log.info('closing session for', address.toString()); const sessionCipher = new libsignal.SessionCipher( textsecure.storage.protocol, address @@ -1197,7 +1200,7 @@ e => { if (e.name === 'ProfileDecryptError') { // probably the profile key has changed. - console.log( + window.log.error( 'decryptProfile error:', id, profile, @@ -1209,7 +1212,7 @@ }); }) .catch(error => { - console.log( + window.log.error( 'getProfile error:', error && error.stack ? error.stack : error ); @@ -1365,7 +1368,7 @@ await wrapDeferred(message.save()); } } catch (error) { - console.log( + window.log.error( 'Problem upgrading message quoted message from database', Errors.toLogFormat(error) ); @@ -1532,7 +1535,7 @@ throw new Error('This conversation has no id!'); } if (this.inProgressFetch) { - console.log('Attempting to start a parallel fetchMessages() call'); + window.log.warn('Attempting to start a parallel fetchMessages() call'); return; } @@ -1550,7 +1553,7 @@ // one-time hit. We do this so we have guarantees about message structure. await this.upgradeMessages(this.messageCollection); } catch (error) { - console.log( + window.log.error( 'fetchMessages: failed to upgrade messages', Errors.toLogFormat(error) ); @@ -1758,7 +1761,7 @@ const messageId = message.id; const isExpiringMessage = Message.hasExpiration(messageJSON); - console.log('Add notification', { + window.log.info('Add notification', { conversationId: this.idForLogging(), isExpiringMessage, messageSentAt, diff --git a/js/models/messages.js b/js/models/messages.js index 8de994dadf..190a48a340 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -59,7 +59,12 @@ storeName: 'messages', initialize(attributes) { if (_.isObject(attributes)) { - this.set(TypedMessage.initializeSchemaVersion(attributes)); + this.set( + TypedMessage.initializeSchemaVersion({ + message: attributes, + logger: window.log, + }) + ); } this.OUR_NUMBER = textsecure.storage.user.getNumber(); @@ -86,7 +91,7 @@ const required = ['conversationId', 'received_at', 'sent_at']; const missing = _.filter(required, attr => !attributes[attr]); if (missing.length) { - console.log(`Message missing attributes: ${missing}`); + window.log.warn(`Message missing attributes: ${missing}`); } }, isEndSession() { @@ -860,7 +865,7 @@ errors = [errors]; } errors.forEach(e => { - console.log( + window.log.error( 'Message.saveErrors:', e && e.reason ? e.reason : null, e && e.stack ? e.stack : e @@ -972,7 +977,7 @@ groupUpdate.joined = difference; } if (conversation.get('left')) { - console.log('re-added to a left group'); + window.log.warn('re-added to a left group'); attributes.left = false; } } else if (dataMessage.group.type === GROUP_TYPES.QUIT) { @@ -1038,7 +1043,7 @@ const shouldLogExpireTimerChange = message.isExpirationTimerUpdate() || expireTimer; if (shouldLogExpireTimerChange) { - console.log("Update conversation 'expireTimer'", { + window.log.info("Update conversation 'expireTimer'", { id: conversation.idForLogging(), expireTimer, source: 'handleDataMessage', @@ -1142,7 +1147,7 @@ const handleError = error => { const errorForLog = error && error.stack ? error.stack : error; - console.log( + window.log.error( 'handleDataMessage', message.idForLogging(), 'error:', @@ -1167,7 +1172,7 @@ () => { try { if (previousUnread !== message.get('unread')) { - console.log( + window.log.warn( 'Caught race condition on new message read state! ' + 'Manually starting timers.' ); @@ -1192,7 +1197,7 @@ }, () => { try { - console.log( + window.log.warn( 'handleDataMessage: Message', message.idForLogging(), 'was deleted' @@ -1257,7 +1262,7 @@ } Whisper.ExpiringMessagesListener.update(); - console.log('Set message expiration', { + window.log.info('Set message expiration', { expiresAt, sentAt: this.get('sent_at'), }); @@ -1364,7 +1369,9 @@ return Promise.resolve(); } - console.log('fetchConversation: doing another fetch to get all unread'); + window.log.info( + 'fetchConversation: doing another fetch to get all unread' + ); return this.fetchConversation(conversationId, limit, unreadCount); }); }, @@ -1374,7 +1381,7 @@ }, fetchExpired() { - console.log('Load expired messages'); + window.log.info('Load expired messages'); this.fetch({ conditions: { expires_at: { $lte: Date.now() } }, addIndividually: true, diff --git a/js/modules/backup.js b/js/modules/backup.js index 76a6a409df..2037d3d3c6 100644 --- a/js/modules/backup.js +++ b/js/modules/backup.js @@ -134,7 +134,7 @@ function exportContactsAndGroups(db, fileWriter) { if (storeNames.length === 0) { throw new Error('No stores to export'); } - console.log('Exporting from these stores:', storeNames.join(', ')); + window.log.info('Exporting from these stores:', storeNames.join(', ')); const stream = createOutputStream(fileWriter); @@ -153,7 +153,7 @@ function exportContactsAndGroups(db, fileWriter) { ); }; transaction.oncomplete = () => { - console.log('transaction complete'); + window.log.info('transaction complete'); }; const store = transaction.objectStore(storeName); @@ -168,7 +168,7 @@ function exportContactsAndGroups(db, fileWriter) { }; request.onsuccess = async event => { if (count === 0) { - console.log('cursor opened'); + window.log.info('cursor opened'); stream.write(`"${storeName}": [`); } @@ -188,17 +188,17 @@ function exportContactsAndGroups(db, fileWriter) { } else { // no more stream.write(']'); - console.log('Exported', count, 'items from store', storeName); + window.log.info('Exported', count, 'items from store', storeName); exportedStoreNames.push(storeName); if (exportedStoreNames.length < storeNames.length) { stream.write(','); } else { - console.log('Exported all stores'); + window.log.info('Exported all stores'); stream.write('}'); await stream.close(); - console.log('Finished writing all stores to disk'); + window.log.info('Finished writing all stores to disk'); resolve(); } } @@ -215,11 +215,11 @@ async function importNonMessages(db, parent, options) { function eliminateClientConfigInBackup(data, targetPath) { const cleaned = _.pick(data, 'conversations', 'groups'); - console.log('Writing configuration-free backup file back to disk'); + window.log.info('Writing configuration-free backup file back to disk'); try { fs.writeFileSync(targetPath, JSON.stringify(cleaned)); } catch (error) { - console.log('Error writing cleaned-up backup to disk: ', error.stack); + window.log.error('Error writing cleaned-up backup to disk: ', error.stack); } } @@ -250,7 +250,9 @@ function importFromJsonString(db, jsonString, targetPath, options) { delete importObject.sessions; delete importObject.unprocessed; - console.log('This is a light import; contacts, groups and messages only'); + window.log.info( + 'This is a light import; contacts, groups and messages only' + ); } // We mutate the on-disk backup to prevent the user from importing client @@ -259,11 +261,11 @@ function importFromJsonString(db, jsonString, targetPath, options) { eliminateClientConfigInBackup(importObject, targetPath); const storeNames = _.keys(importObject); - console.log('Importing to these stores:', storeNames.join(', ')); + window.log.info('Importing to these stores:', storeNames.join(', ')); let finished = false; const finish = via => { - console.log('non-messages import done via', via); + window.log.info('non-messages import done via', via); if (finished) { resolve(result); } @@ -281,7 +283,7 @@ function importFromJsonString(db, jsonString, targetPath, options) { transaction.oncomplete = finish.bind(null, 'transaction complete'); _.each(storeNames, storeName => { - console.log('Importing items for store', storeName); + window.log.info('Importing items for store', storeName); if (!importObject[storeName].length) { delete importObject[storeName]; @@ -294,7 +296,7 @@ function importFromJsonString(db, jsonString, targetPath, options) { const finishStore = () => { // added all objects for this store delete importObject[storeName]; - console.log( + window.log.info( 'Done importing to store', storeName, 'Total count:', @@ -304,7 +306,7 @@ function importFromJsonString(db, jsonString, targetPath, options) { ); if (_.keys(importObject).length === 0) { // added all object stores - console.log('DB import complete'); + window.log.info('DB import complete'); finish('puts scheduled'); } }; @@ -455,7 +457,7 @@ async function readAttachment(dir, attachment, name, options) { const targetPath = path.join(dir, sanitizedName); if (!fs.existsSync(targetPath)) { - console.log(`Warning: attachment ${sanitizedName} not found`); + window.log.warn(`Warning: attachment ${sanitizedName} not found`); return; } @@ -518,7 +520,7 @@ async function writeThumbnails(rawQuotedAttachments, options) { ) ); } catch (error) { - console.log( + window.log.error( 'writeThumbnails: error exporting conversation', name, ':', @@ -560,7 +562,7 @@ async function writeAttachments(rawAttachments, options) { try { await Promise.all(promises); } catch (error) { - console.log( + window.log.error( 'writeAttachments: error exporting conversation', name, ':', @@ -571,7 +573,6 @@ async function writeAttachments(rawAttachments, options) { } async function writeAvatar(avatar, options) { - console.log('writeAvatar', { avatar, options }); const { dir, message, index, key, newKey } = options; const name = _getAnonymousAttachmentFileName(message, index); const filename = `${name}-contact-avatar`; @@ -618,7 +619,7 @@ async function writeContactAvatars(contact, options) { ) ); } catch (error) { - console.log( + window.log.error( 'writeContactAvatars: error exporting conversation', name, ':', @@ -633,10 +634,10 @@ async function writeEncryptedAttachment(target, data, options = {}) { if (fs.existsSync(target)) { if (newKey) { - console.log(`Deleting attachment ${filename}; key has changed`); + window.log.info(`Deleting attachment ${filename}; key has changed`); fs.unlinkSync(target); } else { - console.log(`Skipping attachment ${filename}; already exists`); + window.log.info(`Skipping attachment ${filename}; already exists`); return; } } @@ -669,7 +670,7 @@ async function exportConversation(db, conversation, options) { throw new Error('Need a key to encrypt with!'); } - console.log('exporting conversation', name); + window.log.info('exporting conversation', name); const writer = await createFileAndWriter(dir, 'messages.json'); return new Promise(async (resolve, reject) => { @@ -792,7 +793,7 @@ async function exportConversation(db, conversation, options) { try { await Promise.all([stream.write(']}'), promiseChain, stream.close()]); } catch (error) { - console.log( + window.log.error( 'exportConversation: error exporting conversation', name, ':', @@ -802,7 +803,7 @@ async function exportConversation(db, conversation, options) { return; } - console.log('done exporting conversation', name); + window.log.info('done exporting conversation', name); resolve(); } }; @@ -888,12 +889,12 @@ function exportConversations(db, options) { }); }; - console.log('scheduling export for conversation', name); + window.log.info('scheduling export for conversation', name); // eslint-disable-next-line more/no-then promiseChain = promiseChain.then(process); cursor.continue(); } else { - console.log('Done scheduling conversation exports'); + window.log.info('Done scheduling conversation exports'); try { await promiseChain; } catch (error) { @@ -979,7 +980,7 @@ async function loadAttachments(dir, getName, options) { }) ); - console.log('loadAttachments', { message }); + window.log.info('loadAttachments', { message }); } function saveMessage(db, message) { @@ -1000,7 +1001,7 @@ async function saveAllMessages(db, rawMessages) { return new Promise((resolve, reject) => { let finished = false; const finish = via => { - console.log('messages done saving via', via); + window.log.info('messages done saving via', via); if (finished) { resolve(); } @@ -1026,7 +1027,7 @@ async function saveAllMessages(db, rawMessages) { request.onsuccess = () => { count += 1; if (count === messages.length) { - console.log( + window.log.info( 'Saved', messages.length, 'messages for conversation', @@ -1066,7 +1067,9 @@ async function importConversation(db, dir, options) { try { contents = await readFileAsText(dir, 'messages.json'); } catch (error) { - console.log(`Warning: could not access messages.json in directory: ${dir}`); + window.log.error( + `Warning: could not access messages.json in directory: ${dir}` + ); } let promiseChain = Promise.resolve(); @@ -1120,7 +1123,7 @@ async function importConversation(db, dir, options) { await saveAllMessages(db, messages); await promiseChain; - console.log( + window.log.info( 'Finished importing conversation', conversationId, 'Total:', @@ -1208,7 +1211,7 @@ function assembleLookup(db, storeName, keyFunction) { lookup[keyFunction(cursor.value)] = true; cursor.continue(); } else { - console.log(`Done creating ${storeName} lookup`); + window.log.info(`Done creating ${storeName} lookup`); resolve(lookup); } }; @@ -1236,7 +1239,7 @@ function createZip(zipDir, targetDir) { }); archive.on('warning', error => { - console.log(`Archive generation warning: ${error.stack}`); + window.log.warn(`Archive generation warning: ${error.stack}`); }); archive.on('error', reject); @@ -1286,7 +1289,7 @@ function createTempDir() { } function deleteAll(pattern) { - console.log(`Deleting ${pattern}`); + window.log.info(`Deleting ${pattern}`); return pify(rimraf)(pattern); } @@ -1320,10 +1323,10 @@ async function exportToDirectory(directory, options) { const zip = await createZip(encryptionDir, stagingDir); await encryptFile(zip, path.join(directory, 'messages.zip'), options); - console.log('done backing up!'); + window.log.info('done backing up!'); return directory; } catch (error) { - console.log( + window.log.error( 'The backup went wrong!', error && error.stack ? error.stack : error ); @@ -1392,7 +1395,7 @@ async function importFromDirectory(directory, options) { const result = await importNonMessages(db, stagingDir, options); await importConversations(db, stagingDir, Object.assign({}, options)); - console.log('Done importing from backup!'); + window.log.info('Done importing from backup!'); return result; } finally { if (stagingDir) { @@ -1407,10 +1410,10 @@ async function importFromDirectory(directory, options) { const result = await importNonMessages(db, directory, options); await importConversations(db, directory, options); - console.log('Done importing!'); + window.log.info('Done importing!'); return result; } catch (error) { - console.log( + window.log.error( 'The import went wrong!', error && error.stack ? error.stack : error ); diff --git a/js/modules/debug.js b/js/modules/debug.js index 4a1f7035c4..b5b302ff0a 100644 --- a/js/modules/debug.js +++ b/js/modules/debug.js @@ -1,4 +1,5 @@ /* eslint-env node */ +/* global log */ const fs = require('fs-extra'); const path = require('path'); @@ -56,7 +57,7 @@ exports.createConversation = async ({ await Promise.all( range(0, numMessages).map(async index => { await sleep(index * 100); - console.log(`Create message ${index + 1}`); + log.info(`Create message ${index + 1}`); const messageAttributes = await createRandomMessage({ conversationId }); const message = new WhisperMessage(messageAttributes); return deferredToPromise(message.save()); @@ -107,7 +108,7 @@ const createRandomMessage = async ({ conversationId } = {}) => { }; const message = _createMessage({ commonProperties, conversationId, type }); - return Message.initializeSchemaVersion(message); + return Message.initializeSchemaVersion({ message, logger: log }); }; const _createMessage = ({ commonProperties, conversationId, type } = {}) => { diff --git a/js/modules/i18n.js b/js/modules/i18n.js index f10ecda051..a394090af7 100644 --- a/js/modules/i18n.js +++ b/js/modules/i18n.js @@ -1,4 +1,5 @@ /* eslint-env node */ +/* global log */ exports.setup = (locale, messages) => { if (!locale) { @@ -11,7 +12,7 @@ exports.setup = (locale, messages) => { function getMessage(key, substitutions) { const entry = messages[key]; if (!entry) { - console.error( + log.error( `i18n: Attempted to get translation for nonexistent key '${key}'` ); return ''; diff --git a/js/modules/idle_detector.js b/js/modules/idle_detector.js index 49899048fe..9553b7f6ba 100644 --- a/js/modules/idle_detector.js +++ b/js/modules/idle_detector.js @@ -13,7 +13,7 @@ class IdleDetector extends EventEmitter { } start() { - console.log('Start idle detector'); + window.log.info('Start idle detector'); this._scheduleNextCallback(); } @@ -22,7 +22,7 @@ class IdleDetector extends EventEmitter { return; } - console.log('Stop idle detector'); + window.log.info('Stop idle detector'); this._clearScheduledCallbacks(); } diff --git a/js/modules/messages_data_migrator.js b/js/modules/messages_data_migrator.js index 849227f9d7..b5e0c4c41c 100644 --- a/js/modules/messages_data_migrator.js +++ b/js/modules/messages_data_migrator.js @@ -82,6 +82,7 @@ exports.dangerouslyProcessAllWithoutIndex = async ({ minDatabaseVersion, numMessagesPerBatch, upgradeMessageSchema, + logger, } = {}) => { if (!isString(databaseName)) { throw new TypeError("'databaseName' must be a string"); @@ -102,7 +103,7 @@ exports.dangerouslyProcessAllWithoutIndex = async ({ const connection = await database.open(databaseName); const databaseVersion = connection.version; const isValidDatabaseVersion = databaseVersion >= minDatabaseVersion; - console.log('Database status', { + logger.info('Database status', { databaseVersion, isValidDatabaseVersion, minDatabaseVersion, @@ -133,7 +134,7 @@ exports.dangerouslyProcessAllWithoutIndex = async ({ break; } numCumulativeMessagesProcessed += status.numMessagesProcessed; - console.log( + logger.info( 'Upgrade message schema:', Object.assign({}, status, { numTotalMessages, @@ -142,11 +143,11 @@ exports.dangerouslyProcessAllWithoutIndex = async ({ ); } - console.log('Close database connection'); + logger.info('Close database connection'); connection.close(); const totalDuration = Date.now() - migrationStartTime; - console.log('Attachment migration complete:', { + logger.info('Attachment migration complete:', { totalDuration, totalMessagesProcessed: numCumulativeMessagesProcessed, }); diff --git a/js/modules/migrations/18/index.js b/js/modules/migrations/18/index.js index 4db6633d37..ef0650a80d 100644 --- a/js/modules/migrations/18/index.js +++ b/js/modules/migrations/18/index.js @@ -1,7 +1,7 @@ -exports.run = transaction => { +exports.run = ({ transaction, logger }) => { const messagesStore = transaction.objectStore('messages'); - console.log("Create message attachment metadata index: 'hasAttachments'"); + logger.info("Create message attachment metadata index: 'hasAttachments'"); messagesStore.createIndex( 'hasAttachments', ['conversationId', 'hasAttachments', 'received_at'], @@ -9,7 +9,7 @@ exports.run = transaction => { ); ['hasVisualMediaAttachments', 'hasFileAttachments'].forEach(name => { - console.log(`Create message attachment metadata index: '${name}'`); + logger.info(`Create message attachment metadata index: '${name}'`); messagesStore.createIndex(name, ['conversationId', 'received_at', name], { unique: false, }); diff --git a/js/modules/migrations/migrations_0_database_with_attachment_data.js b/js/modules/migrations/migrations_0_database_with_attachment_data.js index 71b935fef6..324d5de584 100644 --- a/js/modules/migrations/migrations_0_database_with_attachment_data.js +++ b/js/modules/migrations/migrations_0_database_with_attachment_data.js @@ -1,3 +1,5 @@ +/* global window */ + const { isString, last } = require('lodash'); const { runMigrations } = require('./run_migrations'); @@ -12,8 +14,8 @@ const migrations = [ { version: '12.0', migrate(transaction, next) { - console.log('Migration 12'); - console.log('creating object stores'); + window.log.info('Migration 12'); + window.log.info('creating object stores'); const messages = transaction.db.createObjectStore('messages'); messages.createIndex('conversation', ['conversationId', 'received_at'], { unique: false, @@ -46,7 +48,7 @@ const migrations = [ transaction.db.createObjectStore('signedPreKeys'); transaction.db.createObjectStore('items'); - console.log('creating debug log'); + window.log.info('creating debug log'); transaction.db.createObjectStore('debug'); next(); @@ -55,8 +57,8 @@ const migrations = [ { version: '13.0', migrate(transaction, next) { - console.log('Migration 13'); - console.log('Adding fields to identity keys'); + window.log.info('Migration 13'); + window.log.info('Adding fields to identity keys'); const identityKeys = transaction.objectStore('identityKeys'); const request = identityKeys.openCursor(); const promises = []; @@ -72,9 +74,9 @@ const migrations = [ new Promise((resolve, reject) => { const putRequest = identityKeys.put(attributes, attributes.id); putRequest.onsuccess = resolve; - putRequest.onerror = e => { - console.log(e); - reject(e); + putRequest.onerror = error => { + window.log.error(error && error.stack ? error.stack : error); + reject(error); }; }) ); @@ -88,15 +90,15 @@ const migrations = [ } }; request.onerror = event => { - console.log(event); + window.log.error(event); }; }, }, { version: '14.0', migrate(transaction, next) { - console.log('Migration 14'); - console.log('Adding unprocessed message store'); + window.log.info('Migration 14'); + window.log.info('Adding unprocessed message store'); const unprocessed = transaction.db.createObjectStore('unprocessed'); unprocessed.createIndex('received', 'timestamp', { unique: false }); next(); @@ -105,8 +107,8 @@ const migrations = [ { version: '15.0', migrate(transaction, next) { - console.log('Migration 15'); - console.log('Adding messages index for de-duplication'); + window.log.info('Migration 15'); + window.log.info('Adding messages index for de-duplication'); const messages = transaction.objectStore('messages'); messages.createIndex('unique', ['source', 'sourceDevice', 'sent_at'], { unique: true, @@ -117,8 +119,8 @@ const migrations = [ { version: '16.0', migrate(transaction, next) { - console.log('Migration 16'); - console.log('Dropping log table, since we now log to disk'); + window.log.info('Migration 16'); + window.log.info('Dropping log table, since we now log to disk'); transaction.db.deleteObjectStore('debug'); next(); }, @@ -126,19 +128,21 @@ const migrations = [ { version: 17, async migrate(transaction, next) { - console.log('Migration 17'); + window.log.info('Migration 17'); const start = Date.now(); const messagesStore = transaction.objectStore('messages'); - console.log('Create index from attachment schema version to attachment'); + window.log.info( + 'Create index from attachment schema version to attachment' + ); messagesStore.createIndex('schemaVersion', 'schemaVersion', { unique: false, }); const duration = Date.now() - start; - console.log( + window.log.info( 'Complete migration to database version 17', `Duration: ${duration}ms` ); @@ -148,13 +152,13 @@ const migrations = [ { version: 18, migrate(transaction, next) { - console.log('Migration 18'); + window.log.info('Migration 18'); const start = Date.now(); - Migration18.run(transaction); + Migration18.run({ transaction, logger: window.log }); const duration = Date.now() - start; - console.log( + window.log.info( 'Complete migration to database version 18', `Duration: ${duration}ms` ); @@ -169,9 +173,10 @@ const database = { migrations, }; -exports.run = ({ Backbone, databaseName } = {}) => +exports.run = ({ Backbone, databaseName, logger } = {}) => runMigrations({ Backbone, + logger, database: Object.assign( {}, database, diff --git a/js/modules/migrations/migrations_1_database_without_attachment_data.js b/js/modules/migrations/migrations_1_database_without_attachment_data.js index df746f7c8e..9bfc5a7e00 100644 --- a/js/modules/migrations/migrations_1_database_without_attachment_data.js +++ b/js/modules/migrations/migrations_1_database_without_attachment_data.js @@ -16,7 +16,7 @@ const migrations = [ // }, ]; -exports.run = async ({ Backbone, database } = {}) => { +exports.run = async ({ Backbone, database, logger } = {}) => { const { canRun } = await exports.getStatus({ database }); if (!canRun) { throw new Error( @@ -24,7 +24,7 @@ exports.run = async ({ Backbone, database } = {}) => { ); } - await runMigrations({ Backbone, database }); + await runMigrations({ Backbone, database, logger }); }; exports.getStatus = async ({ database } = {}) => { diff --git a/js/modules/migrations/run_migrations.js b/js/modules/migrations/run_migrations.js index 8e34f00015..1a60be2491 100644 --- a/js/modules/migrations/run_migrations.js +++ b/js/modules/migrations/run_migrations.js @@ -8,13 +8,13 @@ const { deferredToPromise } = require('../deferred_to_promise'); const closeDatabaseConnection = ({ Backbone } = {}) => deferredToPromise(Backbone.sync('closeall')); -exports.runMigrations = async ({ Backbone, database } = {}) => { +exports.runMigrations = async ({ Backbone, database, logger } = {}) => { if ( !isObject(Backbone) || !isObject(Backbone.Collection) || !isFunction(Backbone.Collection.extend) ) { - throw new TypeError("'Backbone' is required"); + throw new TypeError('runMigrations: Backbone is required'); } if ( @@ -22,7 +22,10 @@ exports.runMigrations = async ({ Backbone, database } = {}) => { !isString(database.id) || !Array.isArray(database.migrations) ) { - throw new TypeError("'database' is required"); + throw new TypeError('runMigrations: database is required'); + } + if (!isObject(logger)) { + throw new TypeError('runMigrations: logger is required'); } const { @@ -33,7 +36,7 @@ exports.runMigrations = async ({ Backbone, database } = {}) => { const databaseVersion = await db.getVersion(database.id); const isAlreadyUpgraded = databaseVersion >= lastMigrationVersion; - console.log('Database status', { + logger.info('Database status', { firstMigrationVersion, lastMigrationVersion, databaseVersion, @@ -50,7 +53,7 @@ exports.runMigrations = async ({ Backbone, database } = {}) => { }))(); await deferredToPromise(migrationCollection.fetch({ limit: 1 })); - console.log('Close database connection'); + logger.info('Close database connection'); await closeDatabaseConnection({ Backbone }); }; diff --git a/js/modules/signal.js b/js/modules/signal.js index 3ebabc498e..4db7680bca 100644 --- a/js/modules/signal.js +++ b/js/modules/signal.js @@ -86,6 +86,7 @@ function initializeMigrations({ Attachments, Type, VisualType, + logger, }) { if (!Attachments) { return null; @@ -131,15 +132,17 @@ function initializeMigrations({ getImageDimensions, makeImageThumbnail, makeVideoScreenshot, + logger, }), - writeMessageAttachments: MessageType.createAttachmentDataWriter( - createWriterForExisting(attachmentsPath) - ), + writeMessageAttachments: MessageType.createAttachmentDataWriter({ + writeExistingAttachmentData: createWriterForExisting(attachmentsPath), + logger, + }), }; } exports.setup = (options = {}) => { - const { Attachments, userDataPath, getRegionCode } = options; + const { Attachments, userDataPath, getRegionCode, logger } = options; const Migrations = initializeMigrations({ userDataPath, @@ -147,6 +150,7 @@ exports.setup = (options = {}) => { Attachments, Type: AttachmentType, VisualType: VisualAttachment, + logger, }); const Components = { diff --git a/js/modules/types/attachment.js b/js/modules/types/attachment.js index 5b0ed5f924..36cda90b6a 100644 --- a/js/modules/types/attachment.js +++ b/js/modules/types/attachment.js @@ -108,9 +108,9 @@ exports._replaceUnicodeOrderOverridesSync = attachment => { exports.replaceUnicodeOrderOverrides = async attachment => exports._replaceUnicodeOrderOverridesSync(attachment); -exports.removeSchemaVersion = attachment => { +exports.removeSchemaVersion = ({ attachment, logger }) => { if (!exports.isValid(attachment)) { - console.log( + logger.error( 'Attachment.removeSchemaVersion: Invalid input attachment:', attachment ); @@ -197,6 +197,7 @@ exports.captureDimensionsAndScreenshot = async ( getImageDimensions, makeImageThumbnail, makeVideoScreenshot, + logger, } ) => { const { contentType } = attachment; @@ -212,13 +213,17 @@ exports.captureDimensionsAndScreenshot = async ( if (GoogleChrome.isImageTypeSupported(contentType)) { try { - const { width, height } = await getImageDimensions(absolutePath); + const { width, height } = await getImageDimensions({ + objectUrl: absolutePath, + logger, + }); const thumbnailBuffer = await blobToArrayBuffer( - await makeImageThumbnail( - THUMBNAIL_SIZE, - absolutePath, - THUMBNAIL_CONTENT_TYPE - ) + await makeImageThumbnail({ + size: THUMBNAIL_SIZE, + objectUrl: absolutePath, + contentType: THUMBNAIL_CONTENT_TYPE, + logger, + }) ); const thumbnailPath = await writeNewAttachmentData(thumbnailBuffer); @@ -234,7 +239,7 @@ exports.captureDimensionsAndScreenshot = async ( }, }; } catch (error) { - console.log( + logger.error( 'captureDimensionsAndScreenshot:', 'error processing image; skipping screenshot generation', toLogFormat(error) @@ -246,21 +251,29 @@ exports.captureDimensionsAndScreenshot = async ( let screenshotObjectUrl; try { const screenshotBuffer = await blobToArrayBuffer( - await makeVideoScreenshot(absolutePath, THUMBNAIL_CONTENT_TYPE) + await makeVideoScreenshot({ + objectUrl: absolutePath, + contentType: THUMBNAIL_CONTENT_TYPE, + logger, + }) ); screenshotObjectUrl = makeObjectUrl( screenshotBuffer, THUMBNAIL_CONTENT_TYPE ); - const { width, height } = await getImageDimensions(screenshotObjectUrl); + const { width, height } = await getImageDimensions({ + objectUrl: screenshotObjectUrl, + logger, + }); const screenshotPath = await writeNewAttachmentData(screenshotBuffer); const thumbnailBuffer = await blobToArrayBuffer( - await makeImageThumbnail( - THUMBNAIL_SIZE, - screenshotObjectUrl, - THUMBNAIL_CONTENT_TYPE - ) + await makeImageThumbnail({ + size: THUMBNAIL_SIZE, + objectUrl: screenshotObjectUrl, + contentType: THUMBNAIL_CONTENT_TYPE, + logger, + }) ); const thumbnailPath = await writeNewAttachmentData(thumbnailBuffer); @@ -283,7 +296,7 @@ exports.captureDimensionsAndScreenshot = async ( height, }; } catch (error) { - console.log( + logger.error( 'captureDimensionsAndScreenshot: error processing video; skipping screenshot generation', toLogFormat(error) ); diff --git a/js/modules/types/attachment/migrate_data_to_file_system.js b/js/modules/types/attachment/migrate_data_to_file_system.js index e6b75d8628..8358858726 100644 --- a/js/modules/types/attachment/migrate_data_to_file_system.js +++ b/js/modules/types/attachment/migrate_data_to_file_system.js @@ -9,7 +9,7 @@ const { isArrayBuffer, isFunction, isUndefined, omit } = require('lodash'); // Promise Attachment exports.migrateDataToFileSystem = async ( attachment, - { writeNewAttachmentData } = {} + { writeNewAttachmentData, logger } = {} ) => { if (!isFunction(writeNewAttachmentData)) { throw new TypeError("'writeNewAttachmentData' must be a function"); @@ -19,7 +19,7 @@ exports.migrateDataToFileSystem = async ( const hasData = !isUndefined(data); const shouldSkipSchemaUpgrade = !hasData; if (shouldSkipSchemaUpgrade) { - console.log('WARNING: `attachment.data` is `undefined`'); + logger.warn('WARNING: `attachment.data` is `undefined`'); return attachment; } diff --git a/js/modules/types/contact.js b/js/modules/types/contact.js index 2f0724bc24..56baa425d0 100644 --- a/js/modules/types/contact.js +++ b/js/modules/types/contact.js @@ -13,7 +13,7 @@ exports.parseAndWriteAvatar = upgradeAttachment => async ( contact, context = {} ) => { - const { message, regionCode } = context; + const { message, regionCode, logger } = context; const { avatar } = contact; // This is to ensure that an omit() call doesn't pull in prototype props/methods @@ -35,7 +35,7 @@ exports.parseAndWriteAvatar = upgradeAttachment => async ( messageId: idForLogging(message), }); if (error) { - console.log( + logger.error( 'Contact.parseAndWriteAvatar: contact was malformed.', toLogFormat(error) ); diff --git a/js/modules/types/message.js b/js/modules/types/message.js index 4a554b2212..7af7c4b53c 100644 --- a/js/modules/types/message.js +++ b/js/modules/types/message.js @@ -1,4 +1,4 @@ -const { isFunction, isString, omit } = require('lodash'); +const { isFunction, isObject, isString, omit } = require('lodash'); const Contact = require('./contact'); const Attachment = require('./attachment'); @@ -55,7 +55,7 @@ exports.PRIVATE = PRIVATE; exports.isValid = () => true; // Schema -exports.initializeSchemaVersion = message => { +exports.initializeSchemaVersion = ({ message, logger }) => { const isInitialized = SchemaVersion.isValid(message.schemaVersion) && message.schemaVersion >= 1; if (isInitialized) { @@ -82,7 +82,9 @@ exports.initializeSchemaVersion = message => { : INITIAL_SCHEMA_VERSION; const messageWithInitialSchema = Object.assign({}, message, { schemaVersion: inheritedSchemaVersion, - attachments: message.attachments.map(Attachment.removeSchemaVersion), + attachments: message.attachments.map(attachment => + Attachment.removeSchemaVersion({ attachment, logger }) + ), }); return messageWithInitialSchema; @@ -92,17 +94,24 @@ exports.initializeSchemaVersion = message => { // type UpgradeStep = (Message, Context) -> Promise Message // SchemaVersion -> UpgradeStep -> UpgradeStep -exports._withSchemaVersion = (schemaVersion, upgrade) => { +exports._withSchemaVersion = ({ schemaVersion, upgrade }) => { if (!SchemaVersion.isValid(schemaVersion)) { - throw new TypeError("'schemaVersion' is invalid"); + throw new TypeError('_withSchemaVersion: schemaVersion is invalid'); } if (!isFunction(upgrade)) { - throw new TypeError("'upgrade' must be a function"); + throw new TypeError('_withSchemaVersion: upgrade must be a function'); } return async (message, context) => { + if (!context || !isObject(context.logger)) { + throw new TypeError( + '_withSchemaVersion: context must have logger object' + ); + } + const { logger } = context; + if (!exports.isValid(message)) { - console.log( + logger.error( 'Message._withSchemaVersion: Invalid input message:', message ); @@ -117,7 +126,7 @@ exports._withSchemaVersion = (schemaVersion, upgrade) => { const expectedVersion = schemaVersion - 1; const hasExpectedVersion = message.schemaVersion === expectedVersion; if (!hasExpectedVersion) { - console.log( + logger.warn( 'WARNING: Message._withSchemaVersion: Unexpected version:', `Expected message to have version ${expectedVersion},`, `but got ${message.schemaVersion}.`, @@ -130,7 +139,7 @@ exports._withSchemaVersion = (schemaVersion, upgrade) => { try { upgradedMessage = await upgrade(message, context); } catch (error) { - console.log( + logger.error( `Message._withSchemaVersion: error updating message ${message.id}:`, Errors.toLogFormat(error) ); @@ -138,7 +147,7 @@ exports._withSchemaVersion = (schemaVersion, upgrade) => { } if (!exports.isValid(upgradedMessage)) { - console.log( + logger.error( 'Message._withSchemaVersion: Invalid upgraded message:', upgradedMessage ); @@ -186,6 +195,10 @@ exports._mapQuotedAttachments = upgradeAttachment => async ( if (!message.quote) { return message; } + if (!context || !isObject(context.logger)) { + throw new Error('_mapQuotedAttachments: context must have logger object'); + } + const { logger } = context; const upgradeWithContext = async attachment => { const { thumbnail } = attachment; @@ -194,7 +207,7 @@ exports._mapQuotedAttachments = upgradeAttachment => async ( } if (!thumbnail.data) { - console.log('Quoted attachment did not have thumbnail data; removing it'); + logger.warn('Quoted attachment did not have thumbnail data; removing it'); return omit(attachment, ['thumbnail']); } @@ -216,39 +229,46 @@ exports._mapQuotedAttachments = upgradeAttachment => async ( }); }; -const toVersion0 = async message => exports.initializeSchemaVersion(message); -const toVersion1 = exports._withSchemaVersion( - 1, - exports._mapAttachments(Attachment.autoOrientJPEG) -); -const toVersion2 = exports._withSchemaVersion( - 2, - exports._mapAttachments(Attachment.replaceUnicodeOrderOverrides) -); -const toVersion3 = exports._withSchemaVersion( - 3, - exports._mapAttachments(Attachment.migrateDataToFileSystem) -); -const toVersion4 = exports._withSchemaVersion( - 4, - exports._mapQuotedAttachments(Attachment.migrateDataToFileSystem) -); -const toVersion5 = exports._withSchemaVersion(5, initializeAttachmentMetadata); -const toVersion6 = exports._withSchemaVersion( - 6, - exports._mapContact( +const toVersion0 = async (message, context) => + exports.initializeSchemaVersion({ message, logger: context.logger }); +const toVersion1 = exports._withSchemaVersion({ + schemaVersion: 1, + upgrade: exports._mapAttachments(Attachment.autoOrientJPEG), +}); +const toVersion2 = exports._withSchemaVersion({ + schemaVersion: 2, + upgrade: exports._mapAttachments(Attachment.replaceUnicodeOrderOverrides), +}); +const toVersion3 = exports._withSchemaVersion({ + schemaVersion: 3, + upgrade: exports._mapAttachments(Attachment.migrateDataToFileSystem), +}); +const toVersion4 = exports._withSchemaVersion({ + schemaVersion: 4, + upgrade: exports._mapQuotedAttachments(Attachment.migrateDataToFileSystem), +}); +const toVersion5 = exports._withSchemaVersion({ + schemaVersion: 5, + upgrade: initializeAttachmentMetadata, +}); +const toVersion6 = exports._withSchemaVersion({ + schemaVersion: 6, + upgrade: exports._mapContact( Contact.parseAndWriteAvatar(Attachment.migrateDataToFileSystem) - ) -); + ), +}); // IMPORTANT: We’ve updated our definition of `initializeAttachmentMetadata`, so // we need to run it again on existing items that have previously been incorrectly // classified: -const toVersion7 = exports._withSchemaVersion(7, initializeAttachmentMetadata); +const toVersion7 = exports._withSchemaVersion({ + schemaVersion: 7, + upgrade: initializeAttachmentMetadata, +}); -const toVersion8 = exports._withSchemaVersion( - 8, - exports._mapAttachments(Attachment.captureDimensionsAndScreenshot) -); +const toVersion8 = exports._withSchemaVersion({ + schemaVersion: 8, + upgrade: exports._mapAttachments(Attachment.captureDimensionsAndScreenshot), +}); const VERSIONS = [ toVersion0, @@ -275,6 +295,7 @@ exports.upgradeSchema = async ( getImageDimensions, makeImageThumbnail, makeVideoScreenshot, + logger, } = {} ) => { if (!isFunction(writeNewAttachmentData)) { @@ -301,6 +322,9 @@ exports.upgradeSchema = async ( if (!isFunction(makeVideoScreenshot)) { throw new TypeError('context.makeVideoScreenshot is required'); } + if (!isObject(logger)) { + throw new TypeError('context.logger is required'); + } let message = rawMessage; // eslint-disable-next-line no-restricted-syntax @@ -317,6 +341,7 @@ exports.upgradeSchema = async ( getImageDimensions, makeImageThumbnail, makeVideoScreenshot, + logger, }); } @@ -339,9 +364,17 @@ exports.createAttachmentLoader = loadAttachmentData => { // createAttachmentDataWriter :: (RelativePath -> IO Unit) // Message -> // IO (Promise Message) -exports.createAttachmentDataWriter = writeExistingAttachmentData => { +exports.createAttachmentDataWriter = ({ + writeExistingAttachmentData, + logger, +}) => { if (!isFunction(writeExistingAttachmentData)) { - throw new TypeError("'writeExistingAttachmentData' must be a function"); + throw new TypeError( + 'createAttachmentDataWriter: writeExistingAttachmentData must be a function' + ); + } + if (!isObject(logger)) { + throw new TypeError('createAttachmentDataWriter: logger must be an object'); } return async rawMessage => { @@ -349,7 +382,10 @@ exports.createAttachmentDataWriter = writeExistingAttachmentData => { throw new TypeError("'rawMessage' is not valid"); } - const message = exports.initializeSchemaVersion(rawMessage); + const message = exports.initializeSchemaVersion({ + message: rawMessage, + logger, + }); const { attachments, quote, contact } = message; const hasFilesToWrite = @@ -387,7 +423,7 @@ exports.createAttachmentDataWriter = writeExistingAttachmentData => { // we want to be bulletproof to thumbnails without data if (!data || !path) { - console.log( + logger.warn( 'Thumbnail had neither data nor path.', 'id:', message.id, @@ -418,7 +454,7 @@ exports.createAttachmentDataWriter = writeExistingAttachmentData => { const messageWithoutAttachmentData = Object.assign( {}, - await writeThumbnails(message), + await writeThumbnails(message, { logger }), { contact: await Promise.all((contact || []).map(writeContactAvatar)), attachments: await Promise.all( diff --git a/js/modules/types/visual_attachment.js b/js/modules/types/visual_attachment.js index f715b18ce0..3246e6d5ae 100644 --- a/js/modules/types/visual_attachment.js +++ b/js/modules/types/visual_attachment.js @@ -10,7 +10,7 @@ const { exports.blobToArrayBuffer = blobToArrayBuffer; -exports.getImageDimensions = objectUrl => +exports.getImageDimensions = ({ objectUrl, logger }) => new Promise((resolve, reject) => { const image = document.createElement('img'); @@ -21,14 +21,19 @@ exports.getImageDimensions = objectUrl => }); }); image.addEventListener('error', error => { - console.log('getImageDimensions error', toLogFormat(error)); + logger.error('getImageDimensions error', toLogFormat(error)); reject(error); }); image.src = objectUrl; }); -exports.makeImageThumbnail = (size, objectUrl, contentType = 'image/png') => +exports.makeImageThumbnail = ({ + size, + objectUrl, + contentType = 'image/png', + logger, +}) => new Promise((resolve, reject) => { const image = document.createElement('img'); @@ -61,14 +66,18 @@ exports.makeImageThumbnail = (size, objectUrl, contentType = 'image/png') => }); image.addEventListener('error', error => { - console.log('makeImageThumbnail error', toLogFormat(error)); + logger.error('makeImageThumbnail error', toLogFormat(error)); reject(error); }); image.src = objectUrl; }); -exports.makeVideoScreenshot = (objectUrl, contentType = 'image/png') => +exports.makeVideoScreenshot = ({ + objectUrl, + contentType = 'image/png', + logger, +}) => new Promise((resolve, reject) => { const video = document.createElement('video'); @@ -89,25 +98,33 @@ exports.makeVideoScreenshot = (objectUrl, contentType = 'image/png') => video.addEventListener('canplay', capture); video.addEventListener('error', error => { - console.log('makeVideoThumbnail error', toLogFormat(error)); + logger.error('makeVideoThumbnail error', toLogFormat(error)); reject(error); }); video.src = objectUrl; }); -exports.makeVideoThumbnail = async (size, videoObjectUrl) => { +exports.makeVideoThumbnail = async ({ size, videoObjectUrl, logger }) => { let screenshotObjectUrl; try { const type = 'image/png'; - const blob = await exports.makeVideoScreenshot(videoObjectUrl, type); + const blob = await exports.makeVideoScreenshot({ + objectUrl: videoObjectUrl, + contentType: type, + logger, + }); const data = await blobToArrayBuffer(blob); screenshotObjectUrl = arrayBufferToObjectURL({ data, type, }); - return exports.makeImageThumbnail(size, screenshotObjectUrl); + return exports.makeImageThumbnail({ + size, + objectUrl: screenshotObjectUrl, + logger, + }); } finally { exports.revokeObjectUrl(screenshotObjectUrl); } diff --git a/js/modules/web_api.js b/js/modules/web_api.js index 791fd74224..00c0c8f7ca 100644 --- a/js/modules/web_api.js +++ b/js/modules/web_api.js @@ -6,6 +6,7 @@ const is = require('@sindresorhus/is'); /* global Buffer: false */ /* global setTimeout: false */ +/* global log: false */ /* eslint-disable more/no-then, no-bitwise, no-nested-ternary */ @@ -159,7 +160,7 @@ function _createSocket(url, { certificateAuthority, proxyUrl }) { function _promiseAjax(providedUrl, options) { return new Promise((resolve, reject) => { const url = providedUrl || `${options.host}/${options.path}`; - console.log(options.type, url); + log.info(options.type, url); const timeout = typeof options.timeout !== 'undefined' ? options.timeout : 10000; @@ -220,7 +221,7 @@ function _promiseAjax(providedUrl, options) { if (options.responseType === 'json') { if (options.validateResponse) { if (!_validateResponse(result, options.validateResponse)) { - console.log(options.type, url, response.status, 'Error'); + log.error(options.type, url, response.status, 'Error'); reject( HTTPError( 'promiseAjax: invalid response', @@ -233,10 +234,10 @@ function _promiseAjax(providedUrl, options) { } } if (response.status >= 0 && response.status < 400) { - console.log(options.type, url, response.status, 'Success'); + log.info(options.type, url, response.status, 'Success'); resolve(result, response.status); } else { - console.log(options.type, url, response.status, 'Error'); + log.error(options.type, url, response.status, 'Error'); reject( HTTPError( 'promiseAjax: error response', @@ -249,7 +250,7 @@ function _promiseAjax(providedUrl, options) { }); }) .catch(e => { - console.log(options.type, url, 0, 'Error'); + log.error(options.type, url, 0, 'Error'); const stack = `${e.stack}\nInitial stack:\n${options.stack}`; reject(HTTPError('promiseAjax catch', 0, e.toString(), stack)); }); @@ -650,7 +651,7 @@ function initialize({ url, cdnUrl, certificateAuthority, proxyUrl }) { } function getMessageSocket() { - console.log('opening message socket', url); + log.info('opening message socket', url); const fixedScheme = url .replace('https://', 'wss://') .replace('http://', 'ws://'); @@ -664,7 +665,7 @@ function initialize({ url, cdnUrl, certificateAuthority, proxyUrl }) { } function getProvisioningSocket() { - console.log('opening provisioning socket', url); + log.info('opening provisioning socket', url); const fixedScheme = url .replace('https://', 'wss://') .replace('http://', 'ws://'); diff --git a/js/notifications.js b/js/notifications.js index b367c57b30..1fb70b76a0 100644 --- a/js/notifications.js +++ b/js/notifications.js @@ -67,7 +67,7 @@ userSetting, }); - console.log( + window.log.info( 'Update notifications:', Object.assign({}, status, { isNotificationGroupingSupported, @@ -128,7 +128,7 @@ iconUrl = last.iconUrl; break; default: - console.log( + window.log.error( `Error: Unknown user notification setting: '${userSetting}'` ); break; @@ -161,11 +161,11 @@ return storage.get('notification-setting') || SettingNames.MESSAGE; }, onRemove() { - console.log('Remove notification'); + window.log.info('Remove notification'); this.update(); }, clear() { - console.log('Remove all notifications'); + window.log.info('Remove all notifications'); this.reset([]); this.update(); }, diff --git a/js/read_receipts.js b/js/read_receipts.js index e211a6dc4f..8b9c370cde 100644 --- a/js/read_receipts.js +++ b/js/read_receipts.js @@ -24,7 +24,7 @@ _.contains(ids, receipt.get('reader')) ); if (receipts.length) { - console.log('Found early read receipts for message'); + window.log.info('Found early read receipts for message'); this.remove(receipts); } return receipts; @@ -75,7 +75,7 @@ }, reject); }); } - console.log( + window.log.info( 'No message for read receipt', receipt.get('reader'), receipt.get('timestamp') @@ -84,7 +84,7 @@ return null; }) .catch(error => { - console.log( + window.log.error( 'ReadReceipts.onReceipt error:', error && error.stack ? error.stack : error ); diff --git a/js/read_syncs.js b/js/read_syncs.js index 4f8054c2e1..729aa51ea4 100644 --- a/js/read_syncs.js +++ b/js/read_syncs.js @@ -14,7 +14,7 @@ timestamp: message.get('sent_at'), }); if (receipt) { - console.log('Found early read sync for message'); + window.log.info('Found early read sync for message'); this.remove(receipt); return receipt; } @@ -23,41 +23,49 @@ }, onReceipt(receipt) { const messages = new Whisper.MessageCollection(); - return messages.fetchSentAt(receipt.get('timestamp')).then(() => { - const message = messages.find( - item => - item.isIncoming() && - item.isUnread() && - item.get('source') === receipt.get('sender') - ); - const notificationForMessage = message - ? Whisper.Notifications.findWhere({ messageId: message.id }) - : null; - const removedNotification = Whisper.Notifications.remove( - notificationForMessage - ); - const receiptSender = receipt.get('sender'); - const receiptTimestamp = receipt.get('timestamp'); - const wasMessageFound = Boolean(message); - const wasNotificationFound = Boolean(notificationForMessage); - const wasNotificationRemoved = Boolean(removedNotification); - console.log('Receive read sync:', { - receiptSender, - receiptTimestamp, - wasMessageFound, - wasNotificationFound, - wasNotificationRemoved, + return messages + .fetchSentAt(receipt.get('timestamp')) + .then(() => { + const message = messages.find( + item => + item.isIncoming() && + item.isUnread() && + item.get('source') === receipt.get('sender') + ); + const notificationForMessage = message + ? Whisper.Notifications.findWhere({ messageId: message.id }) + : null; + const removedNotification = Whisper.Notifications.remove( + notificationForMessage + ); + const receiptSender = receipt.get('sender'); + const receiptTimestamp = receipt.get('timestamp'); + const wasMessageFound = Boolean(message); + const wasNotificationFound = Boolean(notificationForMessage); + const wasNotificationRemoved = Boolean(removedNotification); + window.log.info('Receive read sync:', { + receiptSender, + receiptTimestamp, + wasMessageFound, + wasNotificationFound, + wasNotificationRemoved, + }); + return message + ? message.markRead(receipt.get('read_at')).then(() => { + // This notification may result in messages older than this one being + // marked read. We want those messages to have the same expire timer + // start time as this one, so we pass the read_at value through. + this.notifyConversation(message, receipt.get('read_at')); + this.remove(receipt); + }) + : Promise.resolve(); + }) + .catch(error => { + window.log.error( + 'ReadSyncs.onReceipt error:', + error && error.stack ? error.stack : error + ); }); - return message - ? message.markRead(receipt.get('read_at')).then(() => { - // This notification may result in messages older than this one being - // marked read. We want those messages to have the same expire timer - // start time as this one, so we pass the read_at value through. - this.notifyConversation(message, receipt.get('read_at')); - this.remove(receipt); - }) - : Promise.resolve(); - }); }, notifyConversation(message, readAt) { const conversation = ConversationController.get({ diff --git a/js/reliable_trigger.js b/js/reliable_trigger.js index ccdb5fc25b..3942eea9d5 100644 --- a/js/reliable_trigger.js +++ b/js/reliable_trigger.js @@ -63,7 +63,7 @@ a2 = args[1], a3 = args[2]; const logError = function(error) { - console.log( + window.log.error( 'Model caught error triggering', name, 'event:', diff --git a/js/rotate_signed_prekey_listener.js b/js/rotate_signed_prekey_listener.js index 7004189b05..98617ecda6 100644 --- a/js/rotate_signed_prekey_listener.js +++ b/js/rotate_signed_prekey_listener.js @@ -16,11 +16,11 @@ } function run() { - console.log('Rotating signed prekey...'); + window.log.info('Rotating signed prekey...'); getAccountManager() .rotateSignedPreKey() .catch(() => { - console.log( + window.log.error( 'rotateSignedPrekey() failed. Trying again in five seconds' ); setTimeout(runWhenOnline, 5000); @@ -33,7 +33,7 @@ if (navigator.onLine) { run(); } else { - console.log( + window.log.info( 'We are offline; keys will be rotated when we are next online' ); const listener = () => { @@ -49,7 +49,7 @@ const time = storage.get('nextSignedKeyRotationTime', now); if (scheduledTime !== time || !timeout) { - console.log( + window.log.info( 'Next signed key rotation scheduled for', new Date(time).toISOString() ); @@ -69,7 +69,7 @@ Whisper.RotateSignedPreKeyListener = { init(events, newVersion) { if (initComplete) { - console.log('Rotate signed prekey listener: Already initialized'); + window.log.warn('Rotate signed prekey listener: Already initialized'); return; } initComplete = true; diff --git a/js/signal_protocol_store.js b/js/signal_protocol_store.js index d062a76649..2a1cb4bc6f 100644 --- a/js/signal_protocol_store.js +++ b/js/signal_protocol_store.js @@ -212,14 +212,14 @@ return new Promise(resolve => { prekey.fetch().then( () => { - console.log('Successfully fetched prekey:', keyId); + window.log.info('Successfully fetched prekey:', keyId); resolve({ pubKey: prekey.get('publicKey'), privKey: prekey.get('privateKey'), }); }, () => { - console.log('Failed to fetch prekey:', keyId); + window.log.error('Failed to fetch prekey:', keyId); resolve(); } ); @@ -249,7 +249,7 @@ } return deferred.then(resolve, error => { - console.log( + window.log.error( 'removePreKey error:', error && error.stack ? error.stack : error ); @@ -271,7 +271,7 @@ prekey .fetch() .then(() => { - console.log( + window.log.info( 'Successfully fetched signed prekey:', prekey.get('id') ); @@ -284,7 +284,7 @@ }); }) .fail(() => { - console.log('Failed to fetch signed prekey:', keyId); + window.log.error('Failed to fetch signed prekey:', keyId); resolve(); }); }); @@ -373,7 +373,7 @@ number, }) .fail(e => { - console.log('Failed to save session', encodedNumber, e); + window.log.error('Failed to save session', encodedNumber, e); }) .always(() => { resolve(); @@ -393,7 +393,7 @@ }); }, removeSession(encodedNumber) { - console.log('deleting session for ', encodedNumber); + window.log.info('deleting session for ', encodedNumber); return new Promise(resolve => { const session = new Session({ id: encodedNumber }); session @@ -436,7 +436,7 @@ address.getName(), deviceId ); - console.log('closing session for', sibling.toString()); + window.log.info('closing session for', sibling.toString()); const sessionCipher = new libsignal.SessionCipher( textsecure.storage.protocol, sibling @@ -454,7 +454,7 @@ number, deviceId ); - console.log('closing session for', address.toString()); + window.log.info('closing session for', address.toString()); const sessionCipher = new libsignal.SessionCipher( textsecure.storage.protocol, address @@ -500,19 +500,19 @@ const existing = identityRecord.get('publicKey'); if (!existing) { - console.log('isTrustedForSending: Nothing here, returning true...'); + window.log.info('isTrustedForSending: Nothing here, returning true...'); return true; } if (!equalArrayBuffers(existing, publicKey)) { - console.log("isTrustedForSending: Identity keys don't match..."); + window.log.info("isTrustedForSending: Identity keys don't match..."); return false; } if (identityRecord.get('verified') === VerifiedStatus.UNVERIFIED) { - console.log('Needs unverified approval!'); + window.log.error('Needs unverified approval!'); return false; } if (this.isNonBlockingApprovalRequired(identityRecord)) { - console.log('isTrustedForSending: Needs non-blocking approval!'); + window.log.error('isTrustedForSending: Needs non-blocking approval!'); return false; } @@ -549,7 +549,7 @@ const oldpublicKey = identityRecord.get('publicKey'); if (!oldpublicKey) { // Lookup failed, or the current key was removed, so save this one. - console.log('Saving new identity...'); + window.log.info('Saving new identity...'); identityRecord .save({ publicKey, @@ -562,7 +562,7 @@ resolve(false); }, reject); } else if (!equalArrayBuffers(oldpublicKey, publicKey)) { - console.log('Replacing existing identity...'); + window.log.info('Replacing existing identity...'); const previousStatus = identityRecord.get('verified'); let verifiedStatus; if ( @@ -588,7 +588,7 @@ }, reject); }, reject); } else if (this.isNonBlockingApprovalRequired(identityRecord)) { - console.log('Setting approval status...'); + window.log.info('Setting approval status...'); identityRecord .save({ nonblockingApproval, @@ -680,7 +680,7 @@ reject(identityRecord.validationError); } } else { - console.log('No identity record for specified publicKey'); + window.log.info('No identity record for specified publicKey'); resolve(); } }, @@ -821,7 +821,7 @@ }) .always(() => { if (!isPresent && verifiedStatus === VerifiedStatus.DEFAULT) { - console.log('No existing record for default status'); + window.log.info('No existing record for default status'); return resolve(); } diff --git a/js/spell_check.js b/js/spell_check.js index e36e823281..96ea34e000 100644 --- a/js/spell_check.js +++ b/js/spell_check.js @@ -41,7 +41,7 @@ function setupLinux(locale) { // to other dictionaries const location = process.env.HUNSPELL_DICTIONARIES || '/usr/share/hunspell'; - console.log( + window.log.info( 'Detected Linux. Setting up spell check with locale', locale, 'and dictionary location', @@ -49,7 +49,9 @@ function setupLinux(locale) { ); spellchecker.setDictionary(locale, location); } else { - console.log('Detected Linux. Using default en_US spell check dictionary'); + window.log.info( + 'Detected Linux. Using default en_US spell check dictionary' + ); } } @@ -57,7 +59,7 @@ function setupWin7AndEarlier(locale) { if (process.env.HUNSPELL_DICTIONARIES || locale !== 'en_US') { const location = process.env.HUNSPELL_DICTIONARIES; - console.log( + window.log.info( 'Detected Windows 7 or below. Setting up spell-check with locale', locale, 'and dictionary location', @@ -65,7 +67,7 @@ function setupWin7AndEarlier(locale) { ); spellchecker.setDictionary(locale, location); } else { - console.log( + window.log.info( 'Detected Windows 7 or below. Using default en_US spell check dictionary' ); } @@ -87,7 +89,10 @@ if (process.platform === 'linux') { setupWin7AndEarlier(locale); } else { // OSX and Windows 8+ have OS-level spellcheck APIs - console.log('Using OS-level spell check API with locale', process.env.LANG); + window.log.info( + 'Using OS-level spell check API with locale', + process.env.LANG + ); } const simpleChecker = { diff --git a/js/storage.js b/js/storage.js index 86aeea73e1..227360dee2 100644 --- a/js/storage.js +++ b/js/storage.js @@ -31,7 +31,10 @@ throw new Error('Tried to store undefined'); } if (!ready) { - console.log('Called storage.put before storage is ready. key:', key); + window.log.warn( + 'Called storage.put before storage is ready. key:', + key + ); } const item = items.add({ id: key, value }, { merge: true }); return new Promise((resolve, reject) => { diff --git a/js/views/app_view.js b/js/views/app_view.js index 8e215bf1f7..65dc701c33 100644 --- a/js/views/app_view.js +++ b/js/views/app_view.js @@ -129,7 +129,7 @@ // this.initialLoadComplete. An example of this: on a phone-pairing setup. _.defaults(options, { initialLoadComplete: this.initialLoadComplete }); - console.log('open inbox'); + window.log.info('open inbox'); this.closeInstaller(); if (!this.inboxView) { diff --git a/js/views/clear_data_view.js b/js/views/clear_data_view.js index 5159969208..ec132c9e52 100644 --- a/js/views/clear_data_view.js +++ b/js/views/clear_data_view.js @@ -29,15 +29,17 @@ this.remove(); }, async onDeleteAllData() { - console.log('Deleting everything!'); + window.log.info('Deleting everything!'); this.step = CLEAR_DATA_STEPS.DELETING; this.render(); try { await Database.close(); - console.log('All database connections closed. Starting delete.'); + window.log.info('All database connections closed. Starting delete.'); } catch (error) { - console.log('Something went wrong closing all database connections.'); + window.log.error( + 'Something went wrong closing all database connections.' + ); } this.clearAllData(); @@ -46,7 +48,7 @@ try { await Promise.all([Logs.deleteAll(), Database.drop()]); } catch (error) { - console.log( + window.log.error( 'Something went wrong deleting all data:', error && error.stack ? error.stack : error ); diff --git a/js/views/conversation_list_view.js b/js/views/conversation_list_view.js index 6db1c209dd..cbf3554a5a 100644 --- a/js/views/conversation_list_view.js +++ b/js/views/conversation_list_view.js @@ -13,14 +13,14 @@ const $el = this.$(`.${conversation.cid}`); if (!$el || !$el.length) { - console.log( + window.log.warn( 'updateLocation: did not find element for conversation', conversation.idForLogging() ); return; } if ($el.length > 1) { - console.log( + window.log.warn( 'updateLocation: found more than one element for conversation', conversation.idForLogging() ); @@ -33,7 +33,7 @@ const elIndex = $allConversations.index($el); if (elIndex < 0) { - console.log( + window.log.warn( 'updateLocation: did not find index for conversation', conversation.idForLogging() ); diff --git a/js/views/conversation_view.js b/js/views/conversation_view.js index 6134433200..3bb571a73d 100644 --- a/js/views/conversation_view.js +++ b/js/views/conversation_view.js @@ -259,7 +259,7 @@ }, unload(reason) { - console.log( + window.log.info( 'unloading conversation', this.model.idForLogging(), 'due to:', @@ -329,7 +329,7 @@ return; } - console.log( + window.log.info( 'trimming conversation', this.model.idForLogging(), 'of', @@ -482,7 +482,7 @@ const view = this.loadingScreen; if (view) { const openDelta = Date.now() - this.openStart; - console.log( + window.log.info( 'Conversation', this.model.idForLogging(), 'took', @@ -507,7 +507,7 @@ this.model.updateVerified().then(() => { this.onVerifiedChange(); this.statusFetch = null; - console.log('done with status fetch'); + window.log.info('done with status fetch'); }) ); @@ -786,10 +786,10 @@ }, fetchMessages() { - console.log('fetchMessages'); + window.log.info('fetchMessages'); this.$('.bar-container').show(); if (this.inProgressFetch) { - console.log('Multiple fetchMessage calls!'); + window.log.warn('Multiple fetchMessage calls!'); } // Avoiding await, since we want to capture the promise and make it available via @@ -806,7 +806,7 @@ this.inProgressFetch = null; }) .catch(error => { - console.log( + window.log.error( 'fetchMessages error:', error && error.stack ? error.stack : error ); @@ -1195,7 +1195,7 @@ this.showSendConfirmationDialog(e, contacts); } catch (error) { this.focusMessageFieldAndClearDisabled(); - console.log( + window.log.error( 'checkUnverifiedSendMessage error:', error && error.stack ? error.stack : error ); @@ -1221,7 +1221,7 @@ this.showSendConfirmationDialog(e, contacts); } catch (error) { this.focusMessageFieldAndClearDisabled(); - console.log( + window.log.error( 'checkUntrustedSendMessage error:', error && error.stack ? error.stack : error ); @@ -1290,7 +1290,6 @@ if (message) { const quote = await this.model.makeQuote(this.quotedMessage); - console.log('DEBUG', { quote }); this.quote = quote; this.focusMessageFieldAndClearDisabled(); @@ -1371,7 +1370,7 @@ const attachments = await this.fileInput.getFiles(); const sendDelta = Date.now() - this.sendStart; - console.log('Send pre-checks took', sendDelta, 'milliseconds'); + window.log.info('Send pre-checks took', sendDelta, 'milliseconds'); this.model.sendMessage(message, attachments, this.quote); @@ -1381,7 +1380,7 @@ this.forceUpdateMessageFieldSize(e); this.fileInput.deleteFiles(); } catch (error) { - console.log( + window.log.error( 'Error pulling attached files before send', error && error.stack ? error.stack : error ); diff --git a/js/views/debug_log_view.js b/js/views/debug_log_view.js index 303307b765..9f0ffaa2c1 100644 --- a/js/views/debug_log_view.js +++ b/js/views/debug_log_view.js @@ -67,7 +67,7 @@ .focus() .select(); } catch (error) { - console.log( + window.log.error( 'DebugLogView error:', error && error.stack ? error.stack : error ); diff --git a/js/views/file_input_view.js b/js/views/file_input_view.js index 47c70e93cf..1c38738485 100644 --- a/js/views/file_input_view.js +++ b/js/views/file_input_view.js @@ -161,10 +161,11 @@ // we use the variable on this here to ensure cleanup if we're interrupted this.previewObjectUrl = URL.createObjectURL(file); const type = 'image/png'; - const thumbnail = await VisualAttachment.makeVideoScreenshot( - this.previewObjectUrl, - type - ); + const thumbnail = await VisualAttachment.makeVideoScreenshot({ + objectUrl: this.previewObjectUrl, + contentType: type, + logger: window.log, + }); URL.revokeObjectURL(this.previewObjectUrl); const data = await VisualAttachment.blobToArrayBuffer(thumbnail); @@ -197,7 +198,7 @@ this.addThumb('images/file.svg'); } } catch (e) { - console.log( + window.log.error( `Was unable to generate thumbnail for file type ${contentType}`, e && e.stack ? e.stack : e ); @@ -297,10 +298,11 @@ const objectUrl = URL.createObjectURL(file); - const arrayBuffer = await VisualAttachment.makeImageThumbnail( + const arrayBuffer = await VisualAttachment.makeImageThumbnail({ size, - objectUrl - ); + objectUrl, + logger: window.log, + }); URL.revokeObjectURL(objectUrl); return this.readFile(arrayBuffer); diff --git a/js/views/import_view.js b/js/views/import_view.js index 0e6cb5a1a1..459b6be2d4 100644 --- a/js/views/import_view.js +++ b/js/views/import_view.js @@ -112,7 +112,7 @@ }, error => { if (error.name !== 'ChooseError') { - console.log( + window.log.error( 'Error choosing directory:', error && error.stack ? error.stack : error ); @@ -158,7 +158,7 @@ return this.finishLightImport(directory); }) .catch(error => { - console.log( + window.log.error( 'Error importing:', error && error.stack ? error.stack : error ); diff --git a/js/views/inbox_view.js b/js/views/inbox_view.js index 1a6fcfb134..6064c23abd 100644 --- a/js/views/inbox_view.js +++ b/js/views/inbox_view.js @@ -193,7 +193,7 @@ this.onEmpty(); break; default: - console.log( + window.log.error( 'Whisper.InboxView::startConnectionListener:', 'Unknown web socket status:', status diff --git a/js/views/install_view.js b/js/views/install_view.js index 00e3287ebd..b45257f40c 100644 --- a/js/views/install_view.js +++ b/js/views/install_view.js @@ -104,19 +104,22 @@ ) .catch(this.handleDisconnect.bind(this)); }, - handleDisconnect(e) { - console.log('provisioning failed', e.stack); + handleDisconnect(error) { + window.log.error( + 'provisioning failed', + error && error.stack ? error.stack : error + ); - this.error = e; + this.error = error; this.render(); - if (e.message === 'websocket closed') { + if (error.message === 'websocket closed') { this.trigger('disconnected'); } else if ( - e.name !== 'HTTPError' || - (e.code !== CONNECTION_ERROR && e.code !== TOO_MANY_DEVICES) + error.name !== 'HTTPError' || + (error.code !== CONNECTION_ERROR && error.code !== TOO_MANY_DEVICES) ) { - throw e; + throw error; } }, reconnect() { @@ -134,7 +137,7 @@ }, setProvisioningUrl(url) { if ($('#qr').length === 0) { - console.log('Did not find #qr element in the DOM!'); + window.log.error('Did not find #qr element in the DOM!'); return; } @@ -186,7 +189,7 @@ } return tsp.removeAllData().then(finish, error => { - console.log( + window.log.error( 'confirmNumber: error clearing database', error && error.stack ? error.stack : error ); diff --git a/js/views/key_verification_view.js b/js/views/key_verification_view.js index d4ada6563a..64a7e87fc6 100644 --- a/js/views/key_verification_view.js +++ b/js/views/key_verification_view.js @@ -81,7 +81,10 @@ if (result.name === 'OutgoingIdentityKeyError') { this.onSafetyNumberChanged(); } else { - console.log('failed to toggle verified:', result.stack); + window.log.error( + 'failed to toggle verified:', + result && result.stack ? result.stack : result + ); } } else { const keyError = _.some( @@ -92,7 +95,10 @@ this.onSafetyNumberChanged(); } else { _.forEach(result.errors, error => { - console.log('failed to toggle verified:', error.stack); + window.log.error( + 'failed to toggle verified:', + error && error.stack ? error.stack : error + ); }); } } diff --git a/js/views/recorder_view.js b/js/views/recorder_view.js index 4770f8af86..2a99d986f0 100644 --- a/js/views/recorder_view.js +++ b/js/views/recorder_view.js @@ -51,7 +51,7 @@ if (this.context) { this.context.close().then(() => { - console.log('audio context closed'); + window.log.info('audio context closed'); }); } this.context = null; @@ -97,10 +97,12 @@ this.close(); if (error && error.name === 'PermissionDeniedError') { - console.log('RecorderView.onError: Microphone access is not allowed!'); + window.log.warn( + 'RecorderView.onError: Microphone access is not allowed!' + ); window.showPermissionsPopup(); } else { - console.log( + window.log.error( 'RecorderView.onError:', error && error.stack ? error.stack : error ); diff --git a/js/views/settings_view.js b/js/views/settings_view.js index a9e7c0f3cf..9d21013358 100644 --- a/js/views/settings_view.js +++ b/js/views/settings_view.js @@ -23,7 +23,7 @@ change(e) { const value = e.target.checked; this.setFn(value); - console.log(this.name, 'changed to', value); + window.log.info(this.name, 'changed to', value); }, populate() { this.$('input').prop('checked', !!this.value); @@ -42,7 +42,7 @@ change(e) { this.value = e.target.checked; this.setFn(this.value); - console.log('media-permissions changed to', this.value); + window.log.info('media-permissions changed to', this.value); }, populate() { this.$('input').prop('checked', Boolean(this.value)); @@ -62,7 +62,7 @@ change(e) { const value = this.$(e.target).val(); this.setFn(value); - console.log(this.name, 'changed to', value); + window.log.info(this.name, 'changed to', value); }, populate() { this.$(`#${this.name}-${this.value}`).attr('checked', 'checked'); @@ -177,12 +177,12 @@ onsuccess() { window.setLastSyncTime(Date.now()); this.lastSyncTime = Date.now(); - console.log('sync successful'); + window.log.info('sync successful'); this.enable(); this.render(); }, ontimeout() { - console.log('sync timed out'); + window.log.error('sync timed out'); this.$('.synced_at').hide(); this.$('.sync_failed').show(); this.enable(); @@ -190,7 +190,7 @@ async sync() { this.$('.sync_failed').hide(); if (window.initialData.isPrimary) { - console.log('Tried to sync from device 1'); + window.log.warn('Tried to sync from device 1'); return; } diff --git a/js/views/standalone_registration_view.js b/js/views/standalone_registration_view.js index fac597e1b5..8756758f51 100644 --- a/js/views/standalone_registration_view.js +++ b/js/views/standalone_registration_view.js @@ -46,7 +46,7 @@ .catch(this.log.bind(this)); }, log(s) { - console.log(s); + window.log.info(s); this.$('#status').text(s); }, validateCode() { diff --git a/libtextsecure/account_manager.js b/libtextsecure/account_manager.js index f740c739f4..16f4244c46 100644 --- a/libtextsecure/account_manager.js +++ b/libtextsecure/account_manager.js @@ -78,14 +78,14 @@ return provisioningCipher.getPublicKey().then(function(pubKey) { return new Promise(function(resolve, reject) { var socket = getSocket(); - socket.onclose = function(e) { - console.log('provisioning socket closed', e.code); + socket.onclose = function(event) { + window.log.info('provisioning socket closed. Code:', event.code); if (!gotProvisionEnvelope) { reject(new Error('websocket closed')); } }; socket.onopen = function(e) { - console.log('provisioning socket open'); + window.log.info('provisioning socket open'); }; var wsr = new WebSocketResource(socket, { keepalive: { path: '/v1/keepalive/provisioning' }, @@ -150,7 +150,7 @@ }) ); } else { - console.log('Unknown websocket message', request.path); + window.log.error('Unknown websocket message', request.path); } }, }); @@ -164,7 +164,7 @@ return this.queueTask( function() { return this.server.getMyKeys().then(function(preKeyCount) { - console.log('prekey count ' + preKeyCount); + window.log.info('prekey count ' + preKeyCount); if (preKeyCount < 10) { return generateKeys().then(registerKeys); } @@ -196,7 +196,7 @@ ); }, function(error) { - console.log( + window.log.error( 'Failed to get identity key. Canceling key rotation.' ); } @@ -205,7 +205,7 @@ if (!res) { return; } - console.log('Saving new signed prekey', res.keyId); + window.log.info('Saving new signed prekey', res.keyId); return Promise.all([ textsecure.storage.put('signedKeyId', signedKeyId + 1), store.storeSignedPreKey(res.keyId, res.keyPair), @@ -217,7 +217,7 @@ ]) .then(function() { var confirmed = true; - console.log('Confirming new signed prekey', res.keyId); + window.log.info('Confirming new signed prekey', res.keyId); return Promise.all([ textsecure.storage.remove('signedKeyRotationRejected'), store.storeSignedPreKey(res.keyId, res.keyPair, confirmed), @@ -228,7 +228,7 @@ }); }) .catch(function(e) { - console.log( + window.log.error( 'rotateSignedPrekey error:', e && e.stack ? e.stack : e ); @@ -242,7 +242,10 @@ var rejections = 1 + textsecure.storage.get('signedKeyRotationRejected', 0); textsecure.storage.put('signedKeyRotationRejected', rejections); - console.log('Signed key rotation rejected count:', rejections); + window.log.error( + 'Signed key rotation rejected count:', + rejections + ); } else { throw e; } @@ -274,9 +277,9 @@ var recent = allKeys[0] ? allKeys[0].keyId : 'none'; var recentConfirmed = confirmed[0] ? confirmed[0].keyId : 'none'; - console.log('Most recent signed key: ' + recent); - console.log('Most recent confirmed signed key: ' + recentConfirmed); - console.log( + window.log.info('Most recent signed key: ' + recent); + window.log.info('Most recent confirmed signed key: ' + recentConfirmed); + window.log.info( 'Total signed key count:', allKeys.length, '-', @@ -294,7 +297,7 @@ var created_at = key.created_at || 0; var age = Date.now() - created_at; if (age > ARCHIVE_AGE) { - console.log( + window.log.info( 'Removing confirmed signed prekey:', key.keyId, 'with timestamp:', @@ -317,7 +320,7 @@ var created_at = key.created_at || 0; var age = Date.now() - created_at; if (age > ARCHIVE_AGE) { - console.log( + window.log.info( 'Removing unconfirmed signed prekey:', key.keyId, 'with timestamp:', @@ -355,17 +358,17 @@ ) .then(function(response) { if (previousNumber && previousNumber !== number) { - console.log( + window.log.warn( 'New number is different from old number; deleting all previous data' ); return textsecure.storage.protocol.removeAllData().then( function() { - console.log('Successfully deleted previous data'); + window.log.info('Successfully deleted previous data'); return response; }, function(error) { - console.log( + window.log.error( 'Something went wrong deleting data from previous number', error && error.stack ? error.stack : error ); @@ -432,7 +435,7 @@ clearSessionsAndPreKeys: function() { var store = textsecure.storage.protocol; - console.log('clearing all sessions, prekeys, and signed prekeys'); + window.log.info('clearing all sessions, prekeys, and signed prekeys'); return Promise.all([ store.clearPreKeyStore(), store.clearSignedPreKeysStore(), @@ -445,7 +448,7 @@ var key = keys.signedPreKey; var confirmed = true; - console.log('confirmKeys: confirming key', key.keyId); + window.log.info('confirmKeys: confirming key', key.keyId); return store.storeSignedPreKey(key.keyId, key.keyPair, confirmed); }, generateKeys: function(count, progressCallback) { @@ -513,7 +516,7 @@ ); }, registrationDone: function() { - console.log('registration done'); + window.log.info('registration done'); this.dispatchEvent(new Event('registration')); }, }); diff --git a/libtextsecure/contacts_parser.js b/libtextsecure/contacts_parser.js index 27e8c25b93..fac0d228b6 100644 --- a/libtextsecure/contacts_parser.js +++ b/libtextsecure/contacts_parser.js @@ -35,8 +35,11 @@ ProtoParser.prototype = { } return proto; - } catch (e) { - console.log(e); + } catch (error) { + window.log.error( + 'ProtoParser.next error:', + error && error.stack ? error.stack : error + ); } }, }; diff --git a/libtextsecure/key_worker.js b/libtextsecure/key_worker.js index 8a249fd8eb..d8cccd6f89 100644 --- a/libtextsecure/key_worker.js +++ b/libtextsecure/key_worker.js @@ -21,7 +21,7 @@ localStorage.removeItem(e.data.key); break; case 'done': - console.log(e.data.keys); + console.error(e.data.keys); } }; */ diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js index f56ca963d6..830c9ce8d1 100644 --- a/libtextsecure/message_receiver.js +++ b/libtextsecure/message_receiver.js @@ -86,7 +86,7 @@ MessageReceiver.prototype.extend({ } }, close() { - console.log('MessageReceiver.close()'); + window.log.info('MessageReceiver.close()'); this.calledClose = true; // Our WebSocketResource instance will close the socket and emit a 'close' event @@ -98,16 +98,16 @@ MessageReceiver.prototype.extend({ return this.drain(); }, onopen() { - console.log('websocket open'); + window.log.info('websocket open'); }, onerror() { - console.log('websocket error'); + window.log.error('websocket error'); }, dispatchAndWait(event) { return Promise.all(this.dispatchEvent(event)); }, onclose(ev) { - console.log( + window.log.info( 'websocket closed', ev.code, ev.reason || '', @@ -143,7 +143,7 @@ MessageReceiver.prototype.extend({ // TODO: handle different types of requests. if (request.path !== '/api/v1/message') { - console.log('got request', request.verb, request.path); + window.log.info('got request', request.verb, request.path); request.respond(200, 'OK'); if (request.verb === 'PUT' && request.path === '/api/v1/queue/empty') { @@ -170,7 +170,7 @@ MessageReceiver.prototype.extend({ this.queueEnvelope(envelope); }, error => { - console.log( + window.log.error( 'handleRequest error trying to add message to cache:', error && error.stack ? error.stack : error ); @@ -179,7 +179,7 @@ MessageReceiver.prototype.extend({ }) .catch(e => { request.respond(500, 'Bad encrypted websocket message'); - console.log( + window.log.error( 'Error handling incoming message:', e && e.stack ? e.stack : e ); @@ -215,7 +215,7 @@ MessageReceiver.prototype.extend({ this.incoming = []; const dispatchEmpty = () => { - console.log("MessageReceiver: emitting 'empty' event"); + window.log.info("MessageReceiver: emitting 'empty' event"); const ev = new Event('empty'); return this.dispatchAndWait(ev); }; @@ -238,7 +238,7 @@ MessageReceiver.prototype.extend({ const queueDispatch = () => this.addToQueue(() => { - console.log('drained'); + window.log.info('drained'); }); // This promise will resolve when there are no more messages to be processed. @@ -282,7 +282,7 @@ MessageReceiver.prototype.extend({ this.queueEnvelope(envelope); } } catch (error) { - console.log('queueCached error handling item', item.id); + window.log.error('queueCached error handling item', item.id); } }, getEnvelopeId(envelope) { @@ -295,15 +295,22 @@ MessageReceiver.prototype.extend({ return new dcodeIO.ByteBuffer.wrap(string, 'binary').toArrayBuffer(); }, getAllFromCache() { - console.log('getAllFromCache'); + window.log.info('getAllFromCache'); return textsecure.storage.unprocessed.getAll().then(items => { - console.log('getAllFromCache loaded', items.length, 'saved envelopes'); + window.log.info( + 'getAllFromCache loaded', + items.length, + 'saved envelopes' + ); return Promise.all( _.map(items, item => { const attempts = 1 + (item.attempts || 0); if (attempts >= 5) { - console.log('getAllFromCache final attempt for envelope', item.id); + window.log.warn( + 'getAllFromCache final attempt for envelope', + item.id + ); return textsecure.storage.unprocessed.remove(item.id); } return textsecure.storage.unprocessed.update(item.id, { attempts }); @@ -311,7 +318,7 @@ MessageReceiver.prototype.extend({ ).then( () => items, error => { - console.log( + window.log.error( 'getAllFromCache error updating items after load:', error && error.stack ? error.stack : error ); @@ -343,7 +350,7 @@ MessageReceiver.prototype.extend({ }, queueDecryptedEnvelope(envelope, plaintext) { const id = this.getEnvelopeId(envelope); - console.log('queueing decrypted envelope', id); + window.log.info('queueing decrypted envelope', id); const task = this.handleDecryptedEnvelope.bind(this, envelope, plaintext); const taskWithTimeout = textsecure.createTaskWithTimeout( @@ -353,7 +360,7 @@ MessageReceiver.prototype.extend({ const promise = this.addToQueue(taskWithTimeout); return promise.catch(error => { - console.log( + window.log.error( 'queueDecryptedEnvelope error handling envelope', id, ':', @@ -363,7 +370,7 @@ MessageReceiver.prototype.extend({ }, queueEnvelope(envelope) { const id = this.getEnvelopeId(envelope); - console.log('queueing envelope', id); + window.log.info('queueing envelope', id); const task = this.handleEnvelope.bind(this, envelope); const taskWithTimeout = textsecure.createTaskWithTimeout( @@ -373,7 +380,7 @@ MessageReceiver.prototype.extend({ const promise = this.addToQueue(taskWithTimeout); return promise.catch(error => { - console.log( + window.log.error( 'queueEnvelope error handling envelope', id, ':', @@ -470,13 +477,13 @@ MessageReceiver.prototype.extend({ switch (envelope.type) { case textsecure.protobuf.Envelope.Type.CIPHERTEXT: - console.log('message from', this.getEnvelopeId(envelope)); + window.log.info('message from', this.getEnvelopeId(envelope)); promise = sessionCipher .decryptWhisperMessage(ciphertext) .then(this.unpad); break; case textsecure.protobuf.Envelope.Type.PREKEY_BUNDLE: - console.log('prekey message from', this.getEnvelopeId(envelope)); + window.log.info('prekey message from', this.getEnvelopeId(envelope)); promise = this.decryptPreKeyWhisperMessage( ciphertext, sessionCipher, @@ -492,7 +499,7 @@ MessageReceiver.prototype.extend({ this.updateCache(envelope, plaintext).then( () => plaintext, error => { - console.log( + window.log.error( 'decrypt failed to save decrypted message contents to cache:', error && error.stack ? error.stack : error ); @@ -571,7 +578,7 @@ MessageReceiver.prototype.extend({ ); }, handleDataMessage(envelope, msg) { - console.log('data message from', this.getEnvelopeId(envelope)); + window.log.info('data message from', this.getEnvelopeId(envelope)); let p = Promise.resolve(); // eslint-disable-next-line no-bitwise if (msg.flags & textsecure.protobuf.DataMessage.Flags.END_SESSION) { @@ -623,7 +630,7 @@ MessageReceiver.prototype.extend({ throw new Error('Unsupported content message'); }, handleCallMessage(envelope) { - console.log('call message from', this.getEnvelopeId(envelope)); + window.log.info('call message from', this.getEnvelopeId(envelope)); this.removeFromCache(envelope); }, handleReceiptMessage(envelope, receiptMessage) { @@ -658,7 +665,7 @@ MessageReceiver.prototype.extend({ return Promise.all(results); }, handleNullMessage(envelope) { - console.log('null message from', this.getEnvelopeId(envelope)); + window.log.info('null message from', this.getEnvelopeId(envelope)); this.removeFromCache(envelope); }, handleSyncMessage(envelope, syncMessage) { @@ -675,7 +682,7 @@ MessageReceiver.prototype.extend({ ? `group(${sentMessage.message.group.id.toBinary()})` : sentMessage.destination; - console.log( + window.log.info( 'sent message to', to, sentMessage.timestamp.toNumber(), @@ -696,10 +703,10 @@ MessageReceiver.prototype.extend({ } else if (syncMessage.blocked) { return this.handleBlocked(envelope, syncMessage.blocked); } else if (syncMessage.request) { - console.log('Got SyncMessage Request'); + window.log.info('Got SyncMessage Request'); return this.removeFromCache(envelope); } else if (syncMessage.read && syncMessage.read.length) { - console.log('read messages from', this.getEnvelopeId(envelope)); + window.log.info('read messages from', this.getEnvelopeId(envelope)); return this.handleRead(envelope, syncMessage.read); } else if (syncMessage.verified) { return this.handleVerified(envelope, syncMessage.verified); @@ -741,7 +748,7 @@ MessageReceiver.prototype.extend({ return Promise.all(results); }, handleContacts(envelope, contacts) { - console.log('contact sync'); + window.log.info('contact sync'); const attachmentPointer = contacts.blob; return this.handleAttachment(attachmentPointer).then(() => { const results = []; @@ -764,7 +771,7 @@ MessageReceiver.prototype.extend({ }); }, handleGroups(envelope, groups) { - console.log('group sync'); + window.log.info('group sync'); const attachmentPointer = groups.blob; return this.handleAttachment(attachmentPointer).then(() => { const groupBuffer = new GroupBuffer(attachmentPointer.data); @@ -802,7 +809,7 @@ MessageReceiver.prototype.extend({ return this.dispatchAndWait(ev); }) .catch(e => { - console.log('error processing group', e); + window.log.error('error processing group', e); }); groupDetails = groupBuffer.next(); promises.push(promise); @@ -816,7 +823,7 @@ MessageReceiver.prototype.extend({ }); }, handleBlocked(envelope, blocked) { - console.log('Setting these numbers as blocked:', blocked.numbers); + window.log.info('Setting these numbers as blocked:', blocked.numbers); textsecure.storage.put('blocked', blocked.numbers); }, isBlocked(number) { @@ -900,7 +907,7 @@ MessageReceiver.prototype.extend({ address, options ); - console.log('retrying prekey whisper message'); + window.log.info('retrying prekey whisper message'); return this.decryptPreKeyWhisperMessage( ciphertext, sessionCipher, @@ -946,7 +953,7 @@ MessageReceiver.prototype.extend({ }); }, async handleEndSession(number) { - console.log('got end session'); + window.log.info('got end session'); const deviceIds = await textsecure.storage.protocol.getDeviceIds(number); return Promise.all( @@ -957,7 +964,7 @@ MessageReceiver.prototype.extend({ address ); - console.log('deleting sessions for', address.toString()); + window.log.info('deleting sessions for', address.toString()); return sessionCipher.deleteAllSessionsForDevice(); }) ); @@ -1016,7 +1023,7 @@ MessageReceiver.prototype.extend({ textsecure.protobuf.GroupContext.Type.UPDATE ) { decrypted.group.members = [source]; - console.log('Got message for unknown group'); + window.log.warn('Got message for unknown group'); } return textsecure.storage.groups.createNewGroup( decrypted.group.members, @@ -1027,7 +1034,7 @@ MessageReceiver.prototype.extend({ if (fromIndex < 0) { // TODO: This could be indication of a race... - console.log( + window.log.warn( 'Sender was not a member of the group they were sending from' ); } @@ -1082,7 +1089,7 @@ MessageReceiver.prototype.extend({ // this message entirely, like we do for full attachments. promises.push( this.handleAttachment(avatar.avatar).catch(error => { - console.log( + window.log.error( 'Problem loading avatar for contact', error && error.stack ? error.stack : error ); @@ -1108,7 +1115,7 @@ MessageReceiver.prototype.extend({ // this message entirely, like we do for full attachments. promises.push( this.handleAttachment(thumbnail).catch(error => { - console.log( + window.log.error( 'Problem loading thumbnail for quote', error && error.stack ? error.stack : error ); diff --git a/libtextsecure/outgoing_message.js b/libtextsecure/outgoing_message.js index 3bb949c1b7..d82134790c 100644 --- a/libtextsecure/outgoing_message.js +++ b/libtextsecure/outgoing_message.js @@ -85,7 +85,7 @@ OutgoingMessage.prototype = { address ); if (device.registrationId === 0) { - console.log('device registrationId 0!'); + window.log.info('device registrationId 0!'); } return builder.processPreKey(device).catch( function(error) { @@ -267,7 +267,7 @@ OutgoingMessage.prototype = { } else if (error.message === 'Identity key changed') { error.timestamp = this.timestamp; error.originalMessage = this.message.toArrayBuffer(); - console.log( + window.log.error( 'Got "key changed" error from encrypt - no identityKey for application layer', number, deviceIds diff --git a/libtextsecure/protobufs.js b/libtextsecure/protobufs.js index 4ef228edc5..3dbfb48efa 100644 --- a/libtextsecure/protobufs.js +++ b/libtextsecure/protobufs.js @@ -15,7 +15,7 @@ window.PROTO_ROOT + ') ' + (error && error.stack ? error.stack : error); - console.log(text); + window.log.error(text); throw error; } var protos = result.build('signalservice'); @@ -26,7 +26,7 @@ ' (root: ' + window.PROTO_ROOT + ')'; - console.log(text); + window.log.error(text); throw new Error(text); } for (var protoName in protos) { diff --git a/libtextsecure/sendmessage.js b/libtextsecure/sendmessage.js index 5cdcfe7246..a98838006d 100644 --- a/libtextsecure/sendmessage.js +++ b/libtextsecure/sendmessage.js @@ -663,14 +663,14 @@ MessageSender.prototype = { }, resetSession: function(number, timestamp) { - console.log('resetting secure session'); + window.log.info('resetting secure session'); var proto = new textsecure.protobuf.DataMessage(); proto.body = 'TERMINATE'; proto.flags = textsecure.protobuf.DataMessage.Flags.END_SESSION; var logError = function(prefix) { return function(error) { - console.log(prefix, error && error.stack ? error.stack : error); + window.log.error(prefix, error && error.stack ? error.stack : error); throw error; }; }; @@ -684,7 +684,7 @@ MessageSender.prototype = { number, deviceId ); - console.log('deleting sessions for', address.toString()); + window.log.info('deleting sessions for', address.toString()); var sessionCipher = new libsignal.SessionCipher( textsecure.storage.protocol, address @@ -699,7 +699,7 @@ MessageSender.prototype = { .catch(logError('resetSession/deleteAllSessions1 error:')) .then( function() { - console.log( + window.log.info( 'finished closing local sessions, now sending to contact' ); return this.sendIndividualProto(number, proto, timestamp).catch( diff --git a/libtextsecure/sync_request.js b/libtextsecure/sync_request.js index 5e5bacabf5..290e0fff15 100644 --- a/libtextsecure/sync_request.js +++ b/libtextsecure/sync_request.js @@ -19,15 +19,15 @@ this.ongroup = this.onGroupSyncComplete.bind(this); receiver.addEventListener('groupsync', this.ongroup); - console.log('SyncRequest created. Sending contact sync message...'); + window.log.info('SyncRequest created. Sending contact sync message...'); sender .sendRequestContactSyncMessage() .then(function() { - console.log('SyncRequest now sending group sync messsage...'); + window.log.info('SyncRequest now sending group sync messsage...'); return sender.sendRequestGroupSyncMessage(); }) .catch(function(error) { - console.log( + window.log.error( 'SyncRequest error:', error && error.stack ? error.stack : error ); diff --git a/libtextsecure/task_with_timeout.js b/libtextsecure/task_with_timeout.js index 20672375ed..d966ab4c99 100644 --- a/libtextsecure/task_with_timeout.js +++ b/libtextsecure/task_with_timeout.js @@ -17,7 +17,7 @@ ' task did not complete in time. Calling stack: ' + errorForStack.stack; - console.log(message); + window.log.error(message); return reject(new Error(message)); } }.bind(this), @@ -31,7 +31,7 @@ clearTimeout(localTimer); } } catch (error) { - console.log( + window.log.error( id || '', 'task ran into problem canceling timer. Calling stack:', errorForStack.stack diff --git a/libtextsecure/test/message_receiver_test.js b/libtextsecure/test/message_receiver_test.js index bf5577e381..2da31fa5be 100644 --- a/libtextsecure/test/message_receiver_test.js +++ b/libtextsecure/test/message_receiver_test.js @@ -62,7 +62,6 @@ describe('MessageReceiver', function() { mac, ]); websocketmessage.request.body = message.toArrayBuffer(); - console.log(new Uint8Array(message.toArrayBuffer())); done(); }); }); diff --git a/libtextsecure/websocket-resources.js b/libtextsecure/websocket-resources.js index bff8942f7f..1e736491e2 100644 --- a/libtextsecure/websocket-resources.js +++ b/libtextsecure/websocket-resources.js @@ -168,7 +168,7 @@ return; } - console.log('WebSocketResource.close()'); + window.log.info('WebSocketResource.close()'); if (!code) { code = 3000; } @@ -189,7 +189,7 @@ } this.closed = true; - console.log('Dispatching our own socket close event'); + window.log.warn('Dispatching our own socket close event'); var ev = new Event('close'); ev.code = code; ev.reason = reason; @@ -241,7 +241,7 @@ } else { this.reset(); } - console.log('Sending a keepalive message'); + window.log.info('Sending a keepalive message'); this.wsr.sendRequest({ verb: 'GET', path: this.path, diff --git a/main.js b/main.js index a4b72be4ec..684a814fe2 100644 --- a/main.js +++ b/main.js @@ -1,3 +1,5 @@ +/* eslint-disable no-console */ + const path = require('path'); const url = require('url'); const os = require('os'); @@ -24,7 +26,7 @@ const packageJson = require('./package.json'); const Attachments = require('./app/attachments'); const autoUpdate = require('./app/auto_update'); const createTrayIcon = require('./app/tray_icon'); -const GlobalErrors = require('./js/modules/global_errors'); +const GlobalErrors = require('./app/global_errors'); const logging = require('./app/logging'); const windowState = require('./app/window_state'); const { createTemplate } = require('./app/menu'); diff --git a/preload.js b/preload.js index 7f9d5f8a5f..4cd3d53a33 100644 --- a/preload.js +++ b/preload.js @@ -1,8 +1,6 @@ /* global Whisper: false */ /* global window: false */ -console.log('preload'); - const electron = require('electron'); const semver = require('semver'); @@ -34,7 +32,7 @@ window.isBeforeVersion = (toCheck, baseVersion) => { try { return semver.lt(toCheck, baseVersion); } catch (error) { - console.log( + window.log.error( `isBeforeVersion error: toCheck: ${toCheck}, baseVersion: ${baseVersion}`, error && error.stack ? error.stack : error ); @@ -55,11 +53,11 @@ window.open = () => null; window.eval = global.eval = () => null; window.drawAttention = () => { - console.log('draw attention'); + window.log.info('draw attention'); ipc.send('draw-attention'); }; window.showWindow = () => { - console.log('show window'); + window.log.info('show window'); ipc.send('show-window'); }; @@ -70,7 +68,7 @@ window.setMenuBarVisibility = visibility => ipc.send('set-menu-bar-visibility', visibility); window.restart = () => { - console.log('restart'); + window.log.info('restart'); ipc.send('restart'); }; @@ -188,7 +186,7 @@ window.removeSetupMenuItems = () => ipc.send('remove-setup-menu-items'); require('./js/logging'); if (config.proxyUrl) { - console.log('using proxy url', config.proxyUrl); + window.log.info('Using provided proxy url'); } window.nodeSetImmediate = setImmediate; @@ -241,6 +239,7 @@ window.Signal = Signal.setup({ Attachments, userDataPath: app.getPath('userData'), getRegionCode: () => window.storage.get('regionCode'), + logger: window.log, }); // Pulling these in separately since they access filesystem, electron diff --git a/prepare_beta_build.js b/prepare_beta_build.js index 693bdfcec5..01cfb8ba07 100644 --- a/prepare_beta_build.js +++ b/prepare_beta_build.js @@ -1,3 +1,5 @@ +/* eslint-disable no-console */ + const fs = require('fs'); const _ = require('lodash'); diff --git a/prepare_import_build.js b/prepare_import_build.js index 408f9977a5..e74a168eda 100644 --- a/prepare_import_build.js +++ b/prepare_import_build.js @@ -1,3 +1,5 @@ +/* eslint-disable no-console */ + const fs = require('fs'); const _ = require('lodash'); diff --git a/test/_test.js b/test/_test.js index f68b303a87..e03fadb2ae 100644 --- a/test/_test.js +++ b/test/_test.js @@ -72,6 +72,7 @@ async function clearDatabase() { await Signal.Migrations.Migrations0DatabaseWithAttachmentData.run({ Backbone, databaseName: Whisper.Database.id, + logger: window.log, }); const convos = new Whisper.ConversationCollection(); diff --git a/test/modules/types/attachment_test.js b/test/modules/types/attachment_test.js index 7cc131a65b..b8af004d44 100644 --- a/test/modules/types/attachment_test.js +++ b/test/modules/types/attachment_test.js @@ -100,7 +100,12 @@ describe('Attachment', () => { size: 1111, }; - const actual = Attachment.removeSchemaVersion(input); + const actual = Attachment.removeSchemaVersion({ + attachment: input, + logger: { + error: () => null, + }, + }); assert.deepEqual(actual, expected); }); }); @@ -129,6 +134,9 @@ describe('Attachment', () => { const actual = await Attachment.migrateDataToFileSystem(input, { writeNewAttachmentData, + logger: { + warn: () => null, + }, }); assert.deepEqual(actual, expected); }); @@ -150,6 +158,9 @@ describe('Attachment', () => { const actual = await Attachment.migrateDataToFileSystem(input, { writeNewAttachmentData, + logger: { + warn: () => null, + }, }); assert.deepEqual(actual, expected); }); @@ -167,6 +178,9 @@ describe('Attachment', () => { try { await Attachment.migrateDataToFileSystem(input, { writeNewAttachmentData, + logger: { + warn: () => null, + }, }); } catch (error) { assert.strictEqual( diff --git a/test/modules/types/contact_test.js b/test/modules/types/contact_test.js index 2a8627839d..e9732be10f 100644 --- a/test/modules/types/contact_test.js +++ b/test/modules/types/contact_test.js @@ -8,6 +8,9 @@ const { describe('Contact', () => { const NUMBER = '+12025550099'; + const logger = { + error: () => null, + }; describe('parseAndWriteAvatar', () => { it('handles message with no avatar in contact', async () => { @@ -32,7 +35,10 @@ describe('Contact', () => { }, ], }; - const result = await upgradeVersion(message.contact[0], { message }); + const result = await upgradeVersion(message.contact[0], { + message, + logger, + }); assert.deepEqual(result, message.contact[0]); }); @@ -72,6 +78,7 @@ describe('Contact', () => { const result = await upgradeVersion(message.contact[0], { message, regionCode: 'US', + logger, }); assert.deepEqual(result, expected); }); @@ -112,7 +119,10 @@ describe('Contact', () => { }, ], }; - const result = await upgradeVersion(message.contact[0], { message }); + const result = await upgradeVersion(message.contact[0], { + message, + logger, + }); assert.deepEqual(result, expected); }); @@ -190,7 +200,10 @@ describe('Contact', () => { }, }; - const result = await upgradeVersion(message.contact[0], { message }); + const result = await upgradeVersion(message.contact[0], { + message, + logger, + }); assert.deepEqual(result, expected); }); @@ -231,7 +244,10 @@ describe('Contact', () => { }, ], }; - const result = await upgradeVersion(message.contact[0], { message }); + const result = await upgradeVersion(message.contact[0], { + message, + logger, + }); assert.deepEqual(result, expected); }); @@ -272,7 +288,10 @@ describe('Contact', () => { }, ], }; - const result = await upgradeVersion(message.contact[0], { message }); + const result = await upgradeVersion(message.contact[0], { + message, + logger, + }); assert.deepEqual(result, expected); }); @@ -310,7 +329,10 @@ describe('Contact', () => { displayName: 'Someone Somewhere', }, }; - const result = await upgradeVersion(message.contact[0], { message }); + const result = await upgradeVersion(message.contact[0], { + message, + logger, + }); assert.deepEqual(result, expected); }); @@ -333,7 +355,10 @@ describe('Contact', () => { }, ], }; - const result = await upgradeVersion(message.contact[0], { message }); + const result = await upgradeVersion(message.contact[0], { + message, + logger, + }); assert.deepEqual(result, message.contact[0]); }); }); diff --git a/test/modules/types/message_test.js b/test/modules/types/message_test.js index b555f34c38..40f258570e 100644 --- a/test/modules/types/message_test.js +++ b/test/modules/types/message_test.js @@ -8,6 +8,11 @@ const { } = require('../../../js/modules/string_to_array_buffer'); describe('Message', () => { + const logger = { + warn: () => null, + error: () => null, + }; + describe('createAttachmentDataWriter', () => { it('should ignore messages that didn’t go through attachment migration', async () => { const input = { @@ -20,9 +25,10 @@ describe('Message', () => { }; const writeExistingAttachmentData = () => {}; - const actual = await Message.createAttachmentDataWriter( - writeExistingAttachmentData - )(input); + const actual = await Message.createAttachmentDataWriter({ + writeExistingAttachmentData, + logger, + })(input); assert.deepEqual(actual, expected); }); @@ -39,9 +45,10 @@ describe('Message', () => { }; const writeExistingAttachmentData = () => {}; - const actual = await Message.createAttachmentDataWriter( - writeExistingAttachmentData - )(input); + const actual = await Message.createAttachmentDataWriter({ + writeExistingAttachmentData, + logger, + })(input); assert.deepEqual(actual, expected); }); @@ -75,9 +82,10 @@ describe('Message', () => { ); }; - const actual = await Message.createAttachmentDataWriter( - writeExistingAttachmentData - )(input); + const actual = await Message.createAttachmentDataWriter({ + writeExistingAttachmentData, + logger, + })(input); assert.deepEqual(actual, expected); }); @@ -121,9 +129,10 @@ describe('Message', () => { ); }; - const actual = await Message.createAttachmentDataWriter( - writeExistingAttachmentData - )(input); + const actual = await Message.createAttachmentDataWriter({ + writeExistingAttachmentData, + logger, + })(input); assert.deepEqual(actual, expected); }); @@ -170,9 +179,10 @@ describe('Message', () => { ); }; - const actual = await Message.createAttachmentDataWriter( - writeExistingAttachmentData - )(input); + const actual = await Message.createAttachmentDataWriter({ + writeExistingAttachmentData, + logger, + })(input); assert.deepEqual(actual, expected); }); }); @@ -188,7 +198,10 @@ describe('Message', () => { schemaVersion: 2, }; - const actual = Message.initializeSchemaVersion(input); + const actual = Message.initializeSchemaVersion({ + message: input, + logger, + }); assert.deepEqual(actual, expected); }); @@ -204,7 +217,10 @@ describe('Message', () => { schemaVersion: 0, }; - const actual = Message.initializeSchemaVersion(input); + const actual = Message.initializeSchemaVersion({ + message: input, + logger, + }); assert.deepEqual(actual, expected); }); }); @@ -232,7 +248,10 @@ describe('Message', () => { schemaVersion: 7, }; - const actual = Message.initializeSchemaVersion(input); + const actual = Message.initializeSchemaVersion({ + message: input, + logger, + }); assert.deepEqual(actual, expected); }); }); @@ -284,6 +303,10 @@ describe('Message', () => { getImageDimensions: () => ({ height: 10, width: 15 }), makeImageThumbnail: () => new Blob(), makeVideoScreenshot: () => new Blob(), + logger: { + warn: () => null, + error: () => null, + }, }; const actual = await Message.upgradeSchema(input, context); assert.deepEqual(actual, expected); @@ -323,12 +346,25 @@ describe('Message', () => { const v3 = async message => Object.assign({}, message, { hasUpgradedToVersion3: true }); - const toVersion1 = Message._withSchemaVersion(1, v1); - const toVersion2 = Message._withSchemaVersion(2, v2); - const toVersion3 = Message._withSchemaVersion(3, v3); + const toVersion1 = Message._withSchemaVersion({ + schemaVersion: 1, + upgrade: v1, + }); + const toVersion2 = Message._withSchemaVersion({ + schemaVersion: 2, + upgrade: v2, + }); + const toVersion3 = Message._withSchemaVersion({ + schemaVersion: 3, + upgrade: v3, + }); + const context = { logger }; const upgradeSchema = async message => - toVersion3(await toVersion2(await toVersion1(message))); + toVersion3( + await toVersion2(await toVersion1(message, context), context), + context + ); const actual = await upgradeSchema(input); assert.deepEqual(actual, expected); @@ -367,13 +403,26 @@ describe('Message', () => { const v3 = async attachment => Object.assign({}, attachment, { hasUpgradedToVersion3: true }); - const toVersion1 = Message._withSchemaVersion(1, v1); - const toVersion2 = Message._withSchemaVersion(2, v2); - const toVersion3 = Message._withSchemaVersion(3, v3); + const toVersion1 = Message._withSchemaVersion({ + schemaVersion: 1, + upgrade: v1, + }); + const toVersion2 = Message._withSchemaVersion({ + schemaVersion: 2, + upgrade: v2, + }); + const toVersion3 = Message._withSchemaVersion({ + schemaVersion: 3, + upgrade: v3, + }); + const context = { logger }; // NOTE: We upgrade to 3 before 2, i.e. the pipeline should abort: const upgradeSchema = async attachment => - toVersion2(await toVersion3(await toVersion1(attachment))); + toVersion2( + await toVersion3(await toVersion1(attachment, context), context), + context + ); const actual = await upgradeSchema(input); assert.deepEqual(actual, expected); @@ -385,22 +434,26 @@ describe('Message', () => { it('should require a version number', () => { const toVersionX = () => {}; assert.throws( - () => Message._withSchemaVersion(toVersionX, 2), - "'schemaVersion' is invalid" + () => + Message._withSchemaVersion({ schemaVersion: toVersionX, upgrade: 2 }), + '_withSchemaVersion: schemaVersion is invalid' ); }); it('should require an upgrade function', () => { assert.throws( - () => Message._withSchemaVersion(2, 3), - "'upgrade' must be a function" + () => Message._withSchemaVersion({ schemaVersion: 2, upgrade: 3 }), + '_withSchemaVersion: upgrade must be a function' ); }); it('should skip upgrading if message has already been upgraded', async () => { const upgrade = async message => Object.assign({}, message, { foo: true }); - const upgradeWithVersion = Message._withSchemaVersion(3, upgrade); + const upgradeWithVersion = Message._withSchemaVersion({ + schemaVersion: 3, + upgrade, + }); const input = { id: 'guid-guid-guid-guid', @@ -410,7 +463,7 @@ describe('Message', () => { id: 'guid-guid-guid-guid', schemaVersion: 4, }; - const actual = await upgradeWithVersion(input); + const actual = await upgradeWithVersion(input, { logger }); assert.deepEqual(actual, expected); }); @@ -418,7 +471,10 @@ describe('Message', () => { const upgrade = async () => { throw new Error('boom!'); }; - const upgradeWithVersion = Message._withSchemaVersion(3, upgrade); + const upgradeWithVersion = Message._withSchemaVersion({ + schemaVersion: 3, + upgrade, + }); const input = { id: 'guid-guid-guid-guid', @@ -428,13 +484,16 @@ describe('Message', () => { id: 'guid-guid-guid-guid', schemaVersion: 0, }; - const actual = await upgradeWithVersion(input); + const actual = await upgradeWithVersion(input, { logger }); assert.deepEqual(actual, expected); }); it('should return original message if upgrade function returns null', async () => { const upgrade = async () => null; - const upgradeWithVersion = Message._withSchemaVersion(3, upgrade); + const upgradeWithVersion = Message._withSchemaVersion({ + schemaVersion: 3, + upgrade, + }); const input = { id: 'guid-guid-guid-guid', @@ -444,7 +503,7 @@ describe('Message', () => { id: 'guid-guid-guid-guid', schemaVersion: 0, }; - const actual = await upgradeWithVersion(input); + const actual = await upgradeWithVersion(input, { logger }); assert.deepEqual(actual, expected); }); }); @@ -482,7 +541,7 @@ describe('Message', () => { attachments: [], }, }; - const result = await upgradeVersion(message); + const result = await upgradeVersion(message, { logger }); assert.deepEqual(result, expected); }); @@ -499,7 +558,7 @@ describe('Message', () => { attachments: [], }, }; - const result = await upgradeVersion(message); + const result = await upgradeVersion(message, { logger }); assert.deepEqual(result, message); }); @@ -516,7 +575,7 @@ describe('Message', () => { attachments: [], }, }; - const result = await upgradeVersion(message); + const result = await upgradeVersion(message, { logger }); assert.deepEqual(result, message); }); @@ -553,7 +612,7 @@ describe('Message', () => { ], }, }; - const result = await upgradeVersion(message); + const result = await upgradeVersion(message, { logger }); assert.deepEqual(result, expected); }); @@ -589,7 +648,7 @@ describe('Message', () => { ], }, }; - const result = await upgradeVersion(message); + const result = await upgradeVersion(message, { logger }); assert.deepEqual(result, expected); }); }); diff --git a/ts/components/conversation/media-gallery/MediaGridItem.tsx b/ts/components/conversation/media-gallery/MediaGridItem.tsx index d1b72f2b1f..0051f0c2c9 100644 --- a/ts/components/conversation/media-gallery/MediaGridItem.tsx +++ b/ts/components/conversation/media-gallery/MediaGridItem.tsx @@ -32,6 +32,10 @@ export class MediaGridItem extends React.Component { } public onImageError() { + // tslint:disable-next-line no-console + console.log( + 'MediaGridItem: Image failed to load; failing over to placeholder' + ); this.setState({ imageBroken: true, });