diff --git a/js/models/conversations.js b/js/models/conversations.js index 767726687..17a1692a8 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -1127,7 +1127,7 @@ async sendMessageJob(message) { try { const uploads = await message.uploadData(); - const id = message.id; + const { id } = message; const expireTimer = this.get('expireTimer'); const destination = this.id; @@ -1236,6 +1236,7 @@ throw new TypeError(`Invalid conversation type: '${this.get('type')}'`); } catch (e) { await message.saveErrors(e); + return null; } }, async sendMessage( @@ -1252,100 +1253,102 @@ const expireTimer = this.get('expireTimer'); const recipients = this.getRecipients(); - this.queueJob(async () => { - const now = Date.now(); + const now = Date.now(); - window.log.info( - 'Sending message to conversation', - this.idForLogging(), - 'with timestamp', - now - ); - // be sure an empty quote is marked as undefined rather than being empty - // otherwise upgradeMessageSchema() will return an object with an empty array - // and this.get('quote') will be true, even if there is no quote. - const editedQuote = _.isEmpty(quote) ? undefined : quote; + window.log.info( + 'Sending message to conversation', + this.idForLogging(), + 'with timestamp', + now + ); + // be sure an empty quote is marked as undefined rather than being empty + // otherwise upgradeMessageSchema() will return an object with an empty array + // and this.get('quote') will be true, even if there is no quote. + const editedQuote = _.isEmpty(quote) ? undefined : quote; - const messageWithSchema = await upgradeMessageSchema({ - type: 'outgoing', - body, - conversationId: destination, - quote: editedQuote, - preview, - attachments, - sent_at: now, - received_at: now, - expireTimer, - recipients, - }); + const messageWithSchema = await upgradeMessageSchema({ + type: 'outgoing', + body, + conversationId: destination, + quote: editedQuote, + preview, + attachments, + sent_at: now, + received_at: now, + expireTimer, + recipients, + }); - if (this.isPublic()) { - // Public chats require this data to detect duplicates - messageWithSchema.source = textsecure.storage.user.getNumber(); - messageWithSchema.sourceDevice = 1; - } else { - messageWithSchema.destination = destination; - } + if (this.isPublic()) { + // Public chats require this data to detect duplicates + messageWithSchema.source = textsecure.storage.user.getNumber(); + messageWithSchema.sourceDevice = 1; + } else { + messageWithSchema.destination = destination; + } - const { sessionRestoration = false } = otherOptions; + const { sessionRestoration = false } = otherOptions; - const attributes = { - ...messageWithSchema, - groupInvitation, - sessionRestoration, - id: window.getGuid(), - }; + const attributes = { + ...messageWithSchema, + groupInvitation, + sessionRestoration, + id: window.getGuid(), + }; - const model = this.addSingleMessage(attributes); - const message = MessageController.register(model.id, model); + const model = this.addSingleMessage(attributes); + const message = MessageController.register(model.id, model); - await message.commit(true); + await message.commit(true); - if (this.isPrivate()) { - message.set({ destination }); - } - if (this.isPublic()) { - message.setServerTimestamp(new Date().getTime()); - } + if (this.isPrivate()) { + message.set({ destination }); + } + if (this.isPublic()) { + message.setServerTimestamp(new Date().getTime()); + } - const id = await message.commit(); - message.set({ id }); + const id = await message.commit(); + message.set({ id }); - window.Whisper.events.trigger('messageAdded', { - conversationKey: this.id, - messageModel: message, - }); + window.Whisper.events.trigger('messageAdded', { + conversationKey: this.id, + messageModel: message, + }); - this.set({ - lastMessage: model.getNotificationText(), - lastMessageStatus: 'sending', - active_at: now, - timestamp: now, - isArchived: false, - }); - await this.commit(); + this.set({ + lastMessage: model.getNotificationText(), + lastMessageStatus: 'sending', + active_at: now, + timestamp: now, + isArchived: false, + }); + await this.commit(); - // We're offline! - if (!textsecure.messaging) { - let errors; - if (this.contactCollection.length) { - errors = this.contactCollection.map(contact => { - const error = new Error('Network is not available'); - error.name = 'SendMessageNetworkError'; - error.number = contact.id; - return error; - }); - } else { + // We're offline! + if (!textsecure.messaging) { + let errors; + if (this.contactCollection.length) { + errors = this.contactCollection.map(contact => { const error = new Error('Network is not available'); error.name = 'SendMessageNetworkError'; - error.number = this.id; - errors = [error]; - } - await message.saveErrors(errors); - return null; + error.number = contact.id; + return error; + }); + } else { + const error = new Error('Network is not available'); + error.name = 'SendMessageNetworkError'; + error.number = this.id; + errors = [error]; } - void this.sendMessageJob(message); + await message.saveErrors(errors); + return null; + } + + this.queueJob(async () => { + await this.sendMessageJob(message); }); + return null; }, async updateAvatarOnPublicChat({ url, profileKey }) { diff --git a/js/modules/loki_app_dot_net_api.js b/js/modules/loki_app_dot_net_api.js index 43a0b9d89..ffa2a27cf 100644 --- a/js/modules/loki_app_dot_net_api.js +++ b/js/modules/loki_app_dot_net_api.js @@ -1723,122 +1723,126 @@ class LokiPublicChannelAPI { } const pubKey = adnMessage.user.username; + try { + const messengerData = await this.getMessengerData(adnMessage); + if (messengerData === false) { + return false; + } + // eslint-disable-next-line no-param-reassign + adnMessage.timestamp = messengerData.timestamp; + // eslint-disable-next-line no-param-reassign + adnMessage.body = messengerData.text; + const { + timestamp, + serverTimestamp, + quote, + attachments, + preview, + avatar, + profileKey, + } = messengerData; + if (!timestamp) { + return false; // Invalid message + } - const messengerData = await this.getMessengerData(adnMessage); - if (messengerData === false) { - return false; - } - // eslint-disable-next-line no-param-reassign - adnMessage.timestamp = messengerData.timestamp; - // eslint-disable-next-line no-param-reassign - adnMessage.body = messengerData.text; - const { - timestamp, - serverTimestamp, - quote, - attachments, - preview, - avatar, - profileKey, - } = messengerData; - if (!timestamp) { - return false; // Invalid message - } - - // Duplicate check - const isDuplicate = (message, testedMessage) => - dataMessage.isDuplicate( - message, - testedMessage, - testedMessage.user.username - ); - - // Filter out any messages that we got previously - if (this.lastMessagesCache.some(m => isDuplicate(m, adnMessage))) { - return false; // Duplicate message - } + // Duplicate check + const isDuplicate = (message, testedMessage) => + dataMessage.isDuplicate( + message, + testedMessage, + testedMessage.user.username + ); + + // Filter out any messages that we got previously + if (this.lastMessagesCache.some(m => isDuplicate(m, adnMessage))) { + return false; // Duplicate message + } - // FIXME: maybe move after the de-multidev-decode - // Add the message to the lastMessage cache and keep the last 5 recent messages - this.lastMessagesCache = [ - ...this.lastMessagesCache, - { - attributes: { - source: pubKey, - body: adnMessage.text, - sent_at: timestamp, + // FIXME: maybe move after the de-multidev-decode + // Add the message to the lastMessage cache and keep the last 5 recent messages + this.lastMessagesCache = [ + ...this.lastMessagesCache, + { + attributes: { + source: pubKey, + body: adnMessage.text, + sent_at: timestamp, + }, }, - }, - ].splice(-5); + ].splice(-5); - const from = adnMessage.user.name || 'Anonymous'; // profileName + const from = adnMessage.user.name || 'Anonymous'; // profileName - // if us - if (pubKey === ourNumberProfile || pubKey === ourNumberDevice) { - // update the last name we saw from ourself - lastProfileName = from; - } + // if us + if (pubKey === ourNumberProfile || pubKey === ourNumberDevice) { + // update the last name we saw from ourself + lastProfileName = from; + } - // track sources for multidevice support - // sort it by home server - let homeServer = window.getDefaultFileServer(); - if (adnMessage.user && adnMessage.user.annotations.length) { - const homeNotes = adnMessage.user.annotations.filter( - note => note.type === HOMESERVER_USER_ANNOTATION_TYPE - ); - // FIXME: this annotation should probably be signed and verified... - homeServer = homeNotes.reduce( - (curVal, note) => (note.value ? note.value : curVal), - homeServer - ); - } - if (homeServerPubKeys[homeServer] === undefined) { - homeServerPubKeys[homeServer] = []; - } - if (homeServerPubKeys[homeServer].indexOf(`@${pubKey}`) === -1) { - homeServerPubKeys[homeServer].push(`@${pubKey}`); - } + // track sources for multidevice support + // sort it by home server + let homeServer = window.getDefaultFileServer(); + if (adnMessage.user && adnMessage.user.annotations.length) { + const homeNotes = adnMessage.user.annotations.filter( + note => note.type === HOMESERVER_USER_ANNOTATION_TYPE + ); + // FIXME: this annotation should probably be signed and verified... + homeServer = homeNotes.reduce( + (curVal, note) => (note.value ? note.value : curVal), + homeServer + ); + } + if (homeServerPubKeys[homeServer] === undefined) { + homeServerPubKeys[homeServer] = []; + } + if (homeServerPubKeys[homeServer].indexOf(`@${pubKey}`) === -1) { + homeServerPubKeys[homeServer].push(`@${pubKey}`); + } - // generate signal message object - const messageData = { - serverId: adnMessage.id, - clientVerified: true, - isSessionRequest: false, - source: pubKey, - sourceDevice: 1, - timestamp, // sender timestamp - - serverTimestamp, // server created_at, used to order messages - receivedAt, - isPublic: true, - message: { - body: - adnMessage.text === timestamp.toString() ? '' : adnMessage.text, - attachments, - group: { - id: this.conversationId, - type: textsecure.protobuf.GroupContext.Type.DELIVER, + // generate signal message object + const messageData = { + serverId: adnMessage.id, + clientVerified: true, + isSessionRequest: false, + source: pubKey, + sourceDevice: 1, + timestamp, // sender timestamp + + serverTimestamp, // server created_at, used to order messages + receivedAt, + isPublic: true, + message: { + body: + adnMessage.text === timestamp.toString() ? '' : adnMessage.text, + attachments, + group: { + id: this.conversationId, + type: textsecure.protobuf.GroupContext.Type.DELIVER, + }, + flags: 0, + expireTimer: 0, + profileKey, + timestamp, + received_at: receivedAt, + sent_at: timestamp, // sender timestamp inner + quote, + contact: [], + preview, + profile: { + displayName: from, + avatar, + }, }, - flags: 0, - expireTimer: 0, - profileKey, - timestamp, - received_at: receivedAt, - sent_at: timestamp, // sender timestamp inner - quote, - contact: [], - preview, - profile: { - displayName: from, - avatar, - }, - }, - }; - receivedAt += 1; // Ensure different arrival times - - // now process any user meta data updates - // - update their conversation with a potentially new avatar - return messageData; + }; + receivedAt += 1; // Ensure different arrival times + + // now process any user meta data updates + // - update their conversation with a potentially new avatar + return messageData; + } catch (e) { + window.log.error('pollOnceForMessages: caught error:', e); + return false; + } }) );