diff --git a/app/sql.js b/app/sql.js index 7923c481c..168b8a447 100644 --- a/app/sql.js +++ b/app/sql.js @@ -1716,7 +1716,7 @@ async function getMessageCount() { return row['count(*)']; } -async function saveMessage(data, { forceSave } = {}) { +async function saveMessage(data) { const { body, conversationId, @@ -1742,6 +1742,14 @@ async function saveMessage(data, { forceSave } = {}) { expirationStartTimestamp, } = data; + if (!id) { + throw new Error('id is required'); + } + + if (!conversationId) { + throw new Error('conversationId is required'); + } + const payload = { $id: id, $json: objectToJSON(data), @@ -1766,46 +1774,10 @@ async function saveMessage(data, { forceSave } = {}) { $unread: unread, }; - if (id && !forceSave) { - await db.run( - `UPDATE messages SET - json = $json, - serverId = $serverId, - serverTimestamp = $serverTimestamp, - body = $body, - conversationId = $conversationId, - expirationStartTimestamp = $expirationStartTimestamp, - expires_at = $expires_at, - expireTimer = $expireTimer, - hasAttachments = $hasAttachments, - hasFileAttachments = $hasFileAttachments, - hasVisualMediaAttachments = $hasVisualMediaAttachments, - id = $id, - received_at = $received_at, - schemaVersion = $schemaVersion, - sent = $sent, - sent_at = $sent_at, - source = $source, - sourceDevice = $sourceDevice, - type = $type, - unread = $unread - WHERE id = $id;`, - payload - ); - - return id; - } - - const toCreate = { - ...data, - id: id || uuidv4(), - }; - await db.run( - `INSERT INTO messages ( + `INSERT OR REPLACE INTO ${MESSAGES_TABLE} ( id, json, - serverId, serverTimestamp, body, @@ -1827,7 +1799,6 @@ async function saveMessage(data, { forceSave } = {}) { ) values ( $id, $json, - $serverId, $serverTimestamp, $body, @@ -1849,12 +1820,11 @@ async function saveMessage(data, { forceSave } = {}) { );`, { ...payload, - $id: toCreate.id, - $json: objectToJSON(toCreate), + $json: objectToJSON(data), } ); - return toCreate.id; + return id; } async function saveSeenMessageHashes(arrayOfHashes) { @@ -1926,13 +1896,13 @@ async function cleanSeenMessages() { }); } -async function saveMessages(arrayOfMessages, { forceSave } = {}) { +async function saveMessages(arrayOfMessages) { let promise; db.serialize(() => { promise = Promise.all([ db.run('BEGIN TRANSACTION;'), - ...map(arrayOfMessages, message => saveMessage(message, { forceSave })), + ...map(arrayOfMessages, message => saveMessage(message)), db.run('COMMIT TRANSACTION;'), ]); }); @@ -2175,7 +2145,7 @@ async function getNextExpiringMessage() { async function saveUnprocessed(data, { forceSave } = {}) { const { id, timestamp, version, attempts, envelope, senderIdentity } = data; if (!id) { - throw new Error('saveUnprocessed: id was falsey'); + throw new Error(`saveUnprocessed: id was falsey: ${id}`); } if (forceSave) { diff --git a/preload.js b/preload.js index 2abc6c887..d2842f020 100644 --- a/preload.js +++ b/preload.js @@ -386,7 +386,6 @@ window.autoOrientImage = autoOrientImage; window.loadImage = require('blueimp-load-image'); window.dataURLToBlobSync = require('blueimp-canvas-to-blob'); window.filesize = require('filesize'); -window.getGuid = require('uuid/v4'); window.profileImages = require('./app/profile_images'); window.React = require('react'); diff --git a/test/backup_test.js b/test/backup_test.js index 38f1bc2e7..8d15a14cc 100644 --- a/test/backup_test.js +++ b/test/backup_test.js @@ -489,7 +489,6 @@ describe('Backup', () => { const message = await upgradeMessageSchema(messageWithAttachments); await window.Signal.Data.saveMessage(message, { Message: window.models.Message.MessageModel, - forceSave: true, }); const conversation = { diff --git a/ts/data/data.ts b/ts/data/data.ts index 73804a6a3..a1330bd8e 100644 --- a/ts/data/data.ts +++ b/ts/data/data.ts @@ -65,8 +65,6 @@ export type ServerToken = { }; const channelsToMake = { - _cleanData, - shutdown, close, removeDB, @@ -205,7 +203,7 @@ export function init() { // When IPC arguments are prepared for the cross-process send, they are JSON.stringified. // We can't send ArrayBuffers or BigNumbers (what we get from proto library for dates). -export async function _cleanData(data: any): Promise { +function _cleanData(data: any): any { const keys = Object.keys(data); for (let index = 0, max = keys.length; index < max; index += 1) { const key = keys[index]; @@ -691,13 +689,8 @@ export async function updateLastHash(data: any): Promise { await channels.updateLastHash(_cleanData(data)); } -export async function saveMessage( - data: MessageModel, - options?: { forceSave: boolean } -): Promise { - const id = await channels.saveMessage(_cleanData(data), { - forceSave: options?.forceSave, - }); +export async function saveMessage(data: MessageModel): Promise { + const id = await channels.saveMessage(_cleanData(data)); window.Whisper.ExpiringMessagesListener.update(); return id; } @@ -797,7 +790,6 @@ export async function getMessagesByConversation( receivedAt, type, }); - return new MessageCollection(messages); } diff --git a/ts/models/conversation.ts b/ts/models/conversation.ts index 36c06bcb0..1d6d4e323 100644 --- a/ts/models/conversation.ts +++ b/ts/models/conversation.ts @@ -936,7 +936,6 @@ export class ConversationModel extends Backbone.Model { destination: this.id, recipients: isOutgoing ? this.getRecipients() : undefined, }; - const message = await this.addSingleMessage(messageAttributes); // tell the UI this conversation was updated diff --git a/ts/models/message.ts b/ts/models/message.ts index bca525922..dc5461c5b 100644 --- a/ts/models/message.ts +++ b/ts/models/message.ts @@ -44,6 +44,7 @@ export class MessageModel extends Backbone.Model { // this.on('expired', this.onExpired); void this.setToExpire(); autoBind(this); + this.markRead = this.markRead.bind(this); // Keep props ready const generateProps = (triggerEvent = true) => { @@ -207,14 +208,16 @@ export class MessageModel extends Backbone.Model { return window.i18n('mediaMessage'); } if (this.isExpirationTimerUpdate()) { - const { expireTimer } = this.get('expirationTimerUpdate'); - if (!expireTimer) { + const expireTimerUpdate = this.get('expirationTimerUpdate'); + if (!expireTimerUpdate || !expireTimerUpdate.expireTimer) { return window.i18n('disappearingMessagesDisabled'); } return window.i18n( 'timerSetTo', - window.Whisper.ExpirationTimerOptions.getAbbreviated(expireTimer || 0) + window.Whisper.ExpirationTimerOptions.getAbbreviated( + expireTimerUpdate.expireTimer || 0 + ) ); } const contacts = this.get('contact'); @@ -1234,11 +1237,11 @@ export class MessageModel extends Backbone.Model { await this.commit(); } - public async commit(forceSave = false) { - // TODO investigate the meaning of the forceSave - const id = await saveMessage(this.attributes, { - forceSave, - }); + public async commit() { + if (!this.attributes.id) { + throw new Error('A message always needs an id'); + } + const id = await saveMessage(this.attributes); this.trigger('change'); return id; } diff --git a/ts/models/messageType.ts b/ts/models/messageType.ts index a54230c60..e19e937dd 100644 --- a/ts/models/messageType.ts +++ b/ts/models/messageType.ts @@ -1,5 +1,6 @@ import { DefaultTheme } from 'styled-components'; import _ from 'underscore'; +import uuidv4 from 'uuid'; import { QuotedAttachmentType } from '../components/conversation/Quote'; import { AttachmentType } from '../types/Attachment'; import { Contact } from '../types/Contact'; @@ -43,7 +44,12 @@ export interface MessageAttributes { hasFileAttachments: boolean; hasVisualMediaAttachments: boolean; schemaVersion: number; - expirationTimerUpdate?: any; + expirationTimerUpdate?: { + expireTimer: number; + source: string; + fromSync?: boolean; + fromGroupUpdate?: boolean; + }; unread: boolean; group?: any; timestamp?: number; @@ -91,7 +97,12 @@ export interface MessageAttributesOptionals { hasFileAttachments?: boolean; hasVisualMediaAttachments?: boolean; schemaVersion?: number; - expirationTimerUpdate?: any; + expirationTimerUpdate?: { + expireTimer: number; + source: string; + fromSync?: boolean; + fromGroupUpdate?: boolean; + }; unread?: boolean; group?: any; timestamp?: number; @@ -120,6 +131,7 @@ export const fillMessageAttributesWithDefaults = ( //FIXME audric to do put the default return _.defaults(optAttributes, { expireTimer: 0, // disabled + id: uuidv4(), }); }; diff --git a/ts/receiver/cache.ts b/ts/receiver/cache.ts index 6c94fe805..9c63c619d 100644 --- a/ts/receiver/cache.ts +++ b/ts/receiver/cache.ts @@ -37,13 +37,10 @@ export async function addToCache( if (envelope.senderIdentity) { data.senderIdentity = envelope.senderIdentity; } - return saveUnprocessed(data, { forceSave: true }); } async function fetchAllFromCache(): Promise> { - const { textsecure } = window; - const count = await getUnprocessedCount(); if (count > 1500) { @@ -63,7 +60,6 @@ export async function getAllFromCache() { const items = await fetchAllFromCache(); window.log.info('getAllFromCache loaded', items.length, 'saved envelopes'); - const { textsecure } = window; return Promise.all( _.map(items, async (item: any) => { @@ -104,7 +100,6 @@ export async function getAllFromCacheForSource(source: string) { itemsFromSource.length, 'saved envelopes' ); - const { textsecure } = window; return Promise.all( _.map(items, async (item: any) => { diff --git a/ts/receiver/receiver.ts b/ts/receiver/receiver.ts index 982ca0f60..65e553c48 100644 --- a/ts/receiver/receiver.ts +++ b/ts/receiver/receiver.ts @@ -2,6 +2,7 @@ import { EnvelopePlus } from './types'; export { downloadAttachment } from './attachments'; +import uuidv4 from 'uuid'; import { addToCache, @@ -27,6 +28,7 @@ import { getEnvelopeId } from './common'; import { StringUtils, UserUtils } from '../session/utils'; import { SignalService } from '../protobuf'; import { ConversationController } from '../session/conversations'; +import { removeUnprocessed } from '../data/data'; // TODO: check if some of these exports no longer needed @@ -131,7 +133,7 @@ async function handleRequestDetail( envelope.senderIdentity = senderIdentity; } - envelope.id = envelope.serverGuid || window.getGuid(); + envelope.id = envelope.serverGuid || uuidv4(); envelope.serverTimestamp = envelope.serverTimestamp ? envelope.serverTimestamp.toNumber() : null; diff --git a/ts/session/messages/outgoing/content/data/ChatMessage.ts b/ts/session/messages/outgoing/content/data/ChatMessage.ts index 6e4677bf1..619272ce7 100644 --- a/ts/session/messages/outgoing/content/data/ChatMessage.ts +++ b/ts/session/messages/outgoing/content/data/ChatMessage.ts @@ -92,7 +92,10 @@ export class ChatMessage extends DataMessage { profileKey: dataMessage.profileKey, }; - if ((dataMessage as any)?.$type?.name !== 'DataMessage' && !(dataMessage instanceof DataMessage)) { + if ( + (dataMessage as any)?.$type?.name !== 'DataMessage' && + !(dataMessage instanceof DataMessage) + ) { throw new Error( 'Tried to build a sync message from something else than a DataMessage' ); diff --git a/ts/window.d.ts b/ts/window.d.ts index 673de4fde..5cd849f31 100644 --- a/ts/window.d.ts +++ b/ts/window.d.ts @@ -90,7 +90,6 @@ declare global { versionInfo: any; getStoragePubKey: (key: string) => string; getConversations: () => ConversationCollection; - getGuid: any; SwarmPolling: SwarmPolling; SnodePool: { getSnodesFor: (string) => any;