From 34148e67ec4d487e839314f4628a7609db0cbce9 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Mon, 26 Apr 2021 16:15:27 +1000 Subject: [PATCH] add return of url after v2 attachment upload --- js/background.js | 2 +- js/expire.js | 3 +- js/modules/attachment_downloads.js | 4 +- preload.js | 5 +- ts/opengroup/opengroupV2/OpenGroupAPIV2.ts | 21 ++- .../opengroupV2/OpenGroupServerPoller.ts | 24 ++-- ts/opengroup/utils/OpenGroupUtils.ts | 9 ++ ts/receiver/attachments.ts | 120 ++++++++++++++++-- ts/receiver/contentMessage.ts | 2 +- ts/receiver/dataMessage.ts | 52 +++++--- ts/receiver/queuedJob.ts | 15 ++- ts/receiver/receiver.ts | 107 ++++++++++++---- ts/session/sending/MessageSender.ts | 2 +- ts/session/sending/MessageSentHandler.ts | 2 +- ts/session/snode_api/swarmPolling.ts | 7 +- ts/session/utils/AttachmentsV2.ts | 6 +- 16 files changed, 300 insertions(+), 81 deletions(-) diff --git a/js/background.js b/js/background.js index d74d9a588..a69aae56a 100644 --- a/js/background.js +++ b/js/background.js @@ -464,7 +464,7 @@ profileKey ); - const avatarPointer = await libsession.Utils.AttachmentUtils.uploadAvatar({ + const avatarPointer = await libsession.Utils.AttachmentUtils.uploadAvatarV1({ ...dataResized, data: encryptedData, size: encryptedData.byteLength, diff --git a/js/expire.js b/js/expire.js index 9944d37ea..d66b85682 100644 --- a/js/expire.js +++ b/js/expire.js @@ -66,7 +66,8 @@ }; // don't wait for this to finish - checkForUpgrades(); + // FIXME audric + // checkForUpgrades(); window.extension = window.extension || {}; diff --git a/js/modules/attachment_downloads.js b/js/modules/attachment_downloads.js index 590f16c77..a39c16daf 100644 --- a/js/modules/attachment_downloads.js +++ b/js/modules/attachment_downloads.js @@ -131,7 +131,7 @@ async function _maybeStartJob() { } async function _runJob(job) { - const { id, messageId, attachment, type, index, attempts } = job || {}; + const { id, messageId, attachment, type, index, attempts, isOpenGroupV2 } = job || {}; let message; try { @@ -155,7 +155,7 @@ async function _runJob(job) { try { downloaded = await NewReceiver.downloadAttachment(attachment); } catch (error) { - // Attachments on the server expire after 30 days, then start returning 404 + // Attachments on the server expire after 60 days, then start returning 404 if (error && error.code === 404) { logger.warn( `_runJob: Got 404 from server, marking attachment ${ diff --git a/preload.js b/preload.js index 24bc3b658..837b97d5a 100644 --- a/preload.js +++ b/preload.js @@ -53,7 +53,10 @@ window.isBehindProxy = () => Boolean(config.proxyUrl); window.getStoragePubKey = key => key.substring(0, key.length - 2); // window.isDev() ? key.substring(0, key.length - 2) : key; -window.getDefaultFileServer = () => config.defaultFileServer; + +// FIXME audric +// config.defaultFileServer +window.getDefaultFileServer = () => 'https://file-dev.getsession.org'; window.initialisedAPI = false; window.lokiFeatureFlags = { diff --git a/ts/opengroup/opengroupV2/OpenGroupAPIV2.ts b/ts/opengroup/opengroupV2/OpenGroupAPIV2.ts index 69b10fa94..b5d89d456 100644 --- a/ts/opengroup/opengroupV2/OpenGroupAPIV2.ts +++ b/ts/opengroup/opengroupV2/OpenGroupAPIV2.ts @@ -10,7 +10,11 @@ import { toHex, } from '../../session/utils/String'; import { getIdentityKeyPair, getOurPubKeyStrFromCache } from '../../session/utils/User'; -import { getOpenGroupV2ConversationId } from '../utils/OpenGroupUtils'; +import { + getCompleteEndpointUrl, + getCompleteUrlFromRoom, + getOpenGroupV2ConversationId, +} from '../utils/OpenGroupUtils'; import { buildUrl, cachedModerators, @@ -557,19 +561,21 @@ export const downloadPreviewOpenGroupV2 = async ( export const uploadFileOpenGroupV2 = async ( fileContent: Uint8Array, roomInfos: OpenGroupRequestCommonType -): Promise => { +): Promise<{ fileId: number; fileUrl: string } | null> => { if (!fileContent || !fileContent.length) { return null; } const queryParams = { file: fromArrayBufferToBase64(fileContent), }; + + const filesEndpoint = 'files'; const request: OpenGroupV2Request = { method: 'POST', room: roomInfos.roomId, server: roomInfos.serverUrl, isAuthRequired: true, - endpoint: 'files', + endpoint: filesEndpoint, queryParams, }; @@ -581,5 +587,12 @@ export const uploadFileOpenGroupV2 = async ( // we should probably change the logic of sendOnionRequest to not have all those levels const fileId = (result as any)?.result?.result as number | undefined; - return fileId || null; + if (!fileId) { + return null; + } + const fileUrl = getCompleteEndpointUrl(roomInfos, `${filesEndpoint}/${fileId}`); + return { + fileId: fileId, + fileUrl, + }; }; diff --git a/ts/opengroup/opengroupV2/OpenGroupServerPoller.ts b/ts/opengroup/opengroupV2/OpenGroupServerPoller.ts index 95df97a4e..b36374cfc 100644 --- a/ts/opengroup/opengroupV2/OpenGroupServerPoller.ts +++ b/ts/opengroup/opengroupV2/OpenGroupServerPoller.ts @@ -6,13 +6,10 @@ import { compactFetchEverything, ParsedRoomCompactPollResults } from './OpenGrou import _ from 'lodash'; import { ConversationModel } from '../../models/conversation'; import { getMessageIdsFromServerIds, removeMessage } from '../../data/data'; -import { - getV2OpenGroupRoom, - getV2OpenGroupRoomByRoomId, - saveV2OpenGroupRoom, -} from '../../data/opengroups'; +import { getV2OpenGroupRoom, saveV2OpenGroupRoom } from '../../data/opengroups'; import { OpenGroupMessageV2 } from './OpenGroupMessageV2'; import { handleOpenGroupV2Message } from '../../receiver/receiver'; + const pollForEverythingInterval = 4 * 1000; /** @@ -207,20 +204,29 @@ const handleNewMessages = async ( const incomingMessageIds = _.compact(newMessages.map(n => n.serverId)); const maxNewMessageId = Math.max(...incomingMessageIds); // TODO filter out duplicates ? + const roomInfos = await getV2OpenGroupRoom(conversationId); + if (!roomInfos || !roomInfos.serverUrl || !roomInfos.roomId) { + throw new Error(`No room for convo ${conversationId}`); + } + + const roomDetails: OpenGroupRequestCommonType = _.pick(roomInfos, 'serverUrl', 'roomId'); // tslint:disable-next-line: prefer-for-of for (let index = 0; index < newMessages.length; index++) { const newMessage = newMessages[index]; - await handleOpenGroupV2Message(newMessage); + try { + await handleOpenGroupV2Message(newMessage, roomDetails); + } catch (e) { + window.log.warn('handleOpenGroupV2Message', e); + } } - const roomInfos = await getV2OpenGroupRoom(conversationId); if (roomInfos && roomInfos.lastMessageFetchedServerID !== maxNewMessageId) { roomInfos.lastMessageFetchedServerID = maxNewMessageId; await saveV2OpenGroupRoom(roomInfos); } } catch (e) { - // window.log.warn('handleNewMessages failed:', e); + window.log.warn('handleNewMessages failed:', e); } }; @@ -240,7 +246,7 @@ const handleCompactPollResults = async ( } if (res.messages.length) { - // new deletions + // new messages await handleNewMessages(res.messages, convoId, convo); } diff --git a/ts/opengroup/utils/OpenGroupUtils.ts b/ts/opengroup/utils/OpenGroupUtils.ts index 3881bb741..4c8f42420 100644 --- a/ts/opengroup/utils/OpenGroupUtils.ts +++ b/ts/opengroup/utils/OpenGroupUtils.ts @@ -58,6 +58,15 @@ export function getCompleteUrlFromRoom(roomInfos: OpenGroupV2Room) { return `${roomInfos.serverUrl}/${roomInfos.roomId}?${publicKeyParam}${roomInfos.serverPublicKey}`; } +/** + * This function returns a base url to this room + * This is basically used for building url after posting an attachment + */ +export function getCompleteEndpointUrl(roomInfos: OpenGroupRequestCommonType, endpoint: string) { + // serverUrl has the port and protocol already + return `${roomInfos.serverUrl}/${roomInfos.roomId}/${endpoint}`; +} + /** * Tries to establish a connection with the specified open group url. * diff --git a/ts/receiver/attachments.ts b/ts/receiver/attachments.ts index 9e5677bcc..8a97f95d3 100644 --- a/ts/receiver/attachments.ts +++ b/ts/receiver/attachments.ts @@ -4,6 +4,7 @@ import { MessageModel } from '../models/message'; import { saveMessage } from '../../ts/data/data'; import { fromBase64ToArrayBuffer } from '../session/utils/String'; import { AttachmentUtils } from '../session/utils'; +import { ConversationModel } from '../models/conversation'; export async function downloadAttachment(attachment: any) { const serverUrl = new URL(attachment.url).origin; @@ -82,16 +83,96 @@ export async function downloadAttachment(attachment: any) { }; } +export async function downloadAttachmentOpenGrouPV2(attachment: any) { + const serverUrl = new URL(attachment.url).origin; + + // The fileserver adds the `-static` part for some reason + const defaultFileserver = _.includes( + ['https://file-static.lokinet.org', 'https://file.getsession.org'], + serverUrl + ); + + let res: ArrayBuffer | null = null; + + // TODO: we need attachments to remember which API should be used to retrieve them + if (!defaultFileserver) { + const serverAPI = await window.lokiPublicChatAPI.findOrCreateServer(serverUrl); + + if (serverAPI) { + res = await serverAPI.downloadAttachment(attachment.url); + } + } + + // Fallback to using the default fileserver + if (defaultFileserver || !res || res.byteLength === 0) { + res = await window.lokiFileServerAPI.downloadAttachment(attachment.url); + } + + if (res.byteLength === 0) { + window.log.error('Failed to download attachment. Length is 0'); + throw new Error(`Failed to download attachment. Length is 0 for ${attachment.url}`); + } + + // FIXME "178" test to remove once this is fixed server side. + if (!window.lokiFeatureFlags.useFileOnionRequestsV2) { + if (res.byteLength === 178) { + window.log.error( + 'Data of 178 length corresponds of a 404 returned as 200 by file.getsession.org.' + ); + throw new Error(`downloadAttachment: invalid response for ${attachment.url}`); + } + } else { + // if useFileOnionRequestsV2 is true, we expect an ArrayBuffer not empty + } + + // The attachment id is actually just the absolute url of the attachment + let data = res; + if (!attachment.isRaw) { + const { key, digest, size } = attachment; + + if (!key || !digest) { + throw new Error('Attachment is not raw but we do not have a key to decode it'); + } + + data = await window.textsecure.crypto.decryptAttachment( + data, + fromBase64ToArrayBuffer(key), + fromBase64ToArrayBuffer(digest) + ); + + if (!size || size !== data.byteLength) { + // we might have padding, check that all the remaining bytes are padding bytes + // otherwise we have an error. + if (AttachmentUtils.isLeftOfBufferPaddingOnly(data, size)) { + // we can safely remove the padding + data = data.slice(0, size); + } else { + throw new Error( + `downloadAttachment: Size ${size} did not match downloaded attachment size ${data.byteLength}` + ); + } + } + } + + return { + ..._.omit(attachment, 'digest', 'key'), + data, + }; +} + async function processNormalAttachments( message: MessageModel, - normalAttachments: Array + normalAttachments: Array, + convo: ConversationModel ): Promise { + const isOpenGroupV2 = convo.isOpenGroupV2(); const attachments = await Promise.all( normalAttachments.map((attachment: any, index: any) => { return window.Signal.AttachmentDownloads.addJob(attachment, { messageId: message.id, type: 'attachment', index, + isOpenGroupV2, }); }) ); @@ -101,8 +182,9 @@ async function processNormalAttachments( return attachments.length; } -async function processPreviews(message: MessageModel): Promise { +async function processPreviews(message: MessageModel, convo: ConversationModel): Promise { let addedCount = 0; + const isOpenGroupV2 = convo.isOpenGroupV2(); const preview = await Promise.all( (message.get('preview') || []).map(async (item: any, index: any) => { @@ -115,6 +197,7 @@ async function processPreviews(message: MessageModel): Promise { messageId: message.id, type: 'preview', index, + isOpenGroupV2, }); return { ...item, image }; @@ -126,8 +209,9 @@ async function processPreviews(message: MessageModel): Promise { return addedCount; } -async function processAvatars(message: MessageModel): Promise { +async function processAvatars(message: MessageModel, convo: ConversationModel): Promise { let addedCount = 0; + const isOpenGroupV2 = convo.isOpenGroupV2(); const contacts = message.get('contact') || []; @@ -143,6 +227,7 @@ async function processAvatars(message: MessageModel): Promise { messaeId: message.id, type: 'contact', index, + isOpenGroupV2, }); return { @@ -160,7 +245,10 @@ async function processAvatars(message: MessageModel): Promise { return addedCount; } -async function processQuoteAttachments(message: MessageModel): Promise { +async function processQuoteAttachments( + message: MessageModel, + convo: ConversationModel +): Promise { let addedCount = 0; const quote = message.get('quote'); @@ -168,6 +256,7 @@ async function processQuoteAttachments(message: MessageModel): Promise { if (!quote || !quote.attachments || !quote.attachments.length) { return 0; } + const isOpenGroupV2 = convo.isOpenGroupV2(); quote.attachments = await Promise.all( quote.attachments.map(async (item: any, index: any) => { @@ -183,6 +272,7 @@ async function processQuoteAttachments(message: MessageModel): Promise { messageId: message.id, type: 'quote', index, + isOpenGroupV2, }); return { ...item, thumbnail }; @@ -194,12 +284,16 @@ async function processQuoteAttachments(message: MessageModel): Promise { return addedCount; } -async function processGroupAvatar(message: MessageModel): Promise { +async function processGroupAvatar( + message: MessageModel, + convo: ConversationModel +): Promise { let group = message.get('group'); if (!group || !group.avatar) { return false; } + const isOpenGroupV2 = convo.isOpenGroupV2(); group = { ...group, @@ -207,6 +301,7 @@ async function processGroupAvatar(message: MessageModel): Promise { messageId: message.id, type: 'group-avatar', index: 0, + isOpenGroupV2, }), }; @@ -215,18 +310,21 @@ async function processGroupAvatar(message: MessageModel): Promise { return true; } -export async function queueAttachmentDownloads(message: MessageModel): Promise { +export async function queueAttachmentDownloads( + message: MessageModel, + conversation: ConversationModel +): Promise { let count = 0; - count += await processNormalAttachments(message, message.get('attachments') || []); + count += await processNormalAttachments(message, message.get('attachments') || [], conversation); - count += await processPreviews(message); + count += await processPreviews(message, conversation); - count += await processAvatars(message); + count += await processAvatars(message, conversation); - count += await processQuoteAttachments(message); + count += await processQuoteAttachments(message, conversation); - if (await processGroupAvatar(message)) { + if (await processGroupAvatar(message, conversation)) { count += 1; } diff --git a/ts/receiver/contentMessage.ts b/ts/receiver/contentMessage.ts index db4fa6e2a..5a5ad294d 100644 --- a/ts/receiver/contentMessage.ts +++ b/ts/receiver/contentMessage.ts @@ -191,7 +191,7 @@ export async function decryptWithSessionProtocol( return plaintext; } -function unpad(paddedData: ArrayBuffer): ArrayBuffer { +export function unpad(paddedData: ArrayBuffer): ArrayBuffer { const paddedPlaintext = new Uint8Array(paddedData); for (let i = paddedPlaintext.length - 1; i >= 0; i -= 1) { diff --git a/ts/receiver/dataMessage.ts b/ts/receiver/dataMessage.ts index 34d882393..0f2b7b8ff 100644 --- a/ts/receiver/dataMessage.ts +++ b/ts/receiver/dataMessage.ts @@ -322,17 +322,31 @@ export async function handleDataMessage( await handleMessageEvent(ev); } -interface MessageId { - source: any; - sourceDevice: any; - timestamp: any; - message: any; -} +type MessageDuplicateSearchType = { + body: string; + id: string; + timestamp: number; + serverId?: number; +}; + +export type MessageId = { + source: string; + serverId: number; + sourceDevice: number; + timestamp: number; + message: MessageDuplicateSearchType; +}; const PUBLICCHAT_MIN_TIME_BETWEEN_DUPLICATE_MESSAGES = 10 * 1000; // 10s -async function isMessageDuplicate({ source, sourceDevice, timestamp, message }: MessageId) { +export async function isMessageDuplicate({ + source, + sourceDevice, + timestamp, + message, + serverId, +}: MessageId) { const { Errors } = window.Signal.Types; - + // serverId is only used for opengroupv2 try { const result = await getMessageBySender({ source, @@ -344,19 +358,27 @@ async function isMessageDuplicate({ source, sourceDevice, timestamp, message }: return false; } const filteredResult = [result].filter((m: any) => m.attributes.body === message.body); - const isSimilar = filteredResult.some((m: any) => isDuplicate(m, message, source)); - return isSimilar; + if (serverId) { + return filteredResult.some(m => isDuplicate(m, { ...message, serverId }, source)); + } + return filteredResult.some(m => isDuplicate(m, message, source)); } catch (error) { window.log.error('isMessageDuplicate error:', Errors.toLogFormat(error)); return false; } } -export const isDuplicate = (m: any, testedMessage: any, source: string) => { +export const isDuplicate = ( + m: MessageModel, + testedMessage: MessageDuplicateSearchType, + source: string +) => { // The username in this case is the users pubKey const sameUsername = m.attributes.source === source; + // testedMessage.id is needed as long as we support opengroupv1 const sameServerId = - m.attributes.serverId !== undefined && testedMessage.id === m.attributes.serverId; + m.attributes.serverId !== undefined && + (testedMessage.serverId || testedMessage.id) === m.attributes.serverId; const sameText = m.attributes.body === testedMessage.body; // Don't filter out messages that are too far apart from each other const timestampsSimilar = @@ -395,12 +417,12 @@ async function handleProfileUpdate( } } -interface MessageCreationData { +export interface MessageCreationData { timestamp: number; isPublic: boolean; receivedAt: number; sourceDevice: number; // always 1 isn't it? - source: boolean; + source: string; serverId: number; message: any; serverTimestamp: any; @@ -491,7 +513,7 @@ function createSentMessage(data: MessageCreationData): MessageModel { return new MessageModel(messageData); } -function createMessage(data: MessageCreationData, isIncoming: boolean): MessageModel { +export function createMessage(data: MessageCreationData, isIncoming: boolean): MessageModel { if (isIncoming) { return initIncomingMessage(data); } else { diff --git a/ts/receiver/queuedJob.ts b/ts/receiver/queuedJob.ts index b7ce205d1..9a698baf9 100644 --- a/ts/receiver/queuedJob.ts +++ b/ts/receiver/queuedJob.ts @@ -11,6 +11,7 @@ import { MessageCollection, MessageModel } from '../models/message'; import { MessageController } from '../session/messages'; import { getMessageById, getMessagesBySentAt } from '../../ts/data/data'; import { actions as conversationActions } from '../state/ducks/conversations'; +import { updateProfile } from './dataMessage'; async function handleGroups( conversation: ConversationModel, @@ -84,7 +85,7 @@ function contentTypeSupported(type: any): boolean { async function copyFromQuotedMessage( msg: MessageModel, - quote: Quote, + quote?: Quote, attemptCount: number = 1 ): Promise { const { upgradeMessageSchema } = window.Signal.Migrations; @@ -365,6 +366,16 @@ async function handleRegularMessage( source, ConversationType.PRIVATE ); + // Check if we need to update any profile names + // the only profile we don't update with what is coming here is ours, + // as our profile is shared accross our devices with a ConfigurationMessage + if (type === 'incoming' && dataMessage.profile) { + await updateProfile( + sendingDeviceConversation, + dataMessage.profile, + dataMessage.profile?.profileKey + ); + } if (dataMessage.profileKey) { await processProfileKey( @@ -454,7 +465,7 @@ export async function handleMessageJob( // call it after we have an id for this message, because the jobs refer back // to their source message. - await queueAttachmentDownloads(message); + await queueAttachmentDownloads(message, conversation); const unreadCount = await conversation.getUnreadCount(); conversation.set({ unreadCount }); diff --git a/ts/receiver/receiver.ts b/ts/receiver/receiver.ts index f688ec184..6d2d139bb 100644 --- a/ts/receiver/receiver.ts +++ b/ts/receiver/receiver.ts @@ -9,12 +9,18 @@ import { processMessage } from '../session/snode_api/swarmPolling'; import { onError } from './errors'; // innerHandleContentMessage is only needed because of code duplication in handleDecryptedEnvelope... -import { handleContentMessage, innerHandleContentMessage } from './contentMessage'; -import _ from 'lodash'; +import { handleContentMessage, innerHandleContentMessage, unpad } from './contentMessage'; +import _, { noop } from 'lodash'; export { processMessage }; -import { handleMessageEvent, updateProfile } from './dataMessage'; +import { + createMessage, + handleMessageEvent, + isMessageDuplicate, + MessageCreationData, + updateProfile, +} from './dataMessage'; import { getEnvelopeId } from './common'; import { StringUtils, UserUtils } from '../session/utils'; @@ -22,8 +28,14 @@ import { SignalService } from '../protobuf'; import { ConversationController } from '../session/conversations'; import { removeUnprocessed } from '../data/data'; import { ConversationType } from '../models/conversation'; -import { OpenGroup } from '../opengroup/opengroupV1/OpenGroup'; -import { openGroupPrefixRegex } from '../opengroup/utils/OpenGroupUtils'; +import { + getOpenGroupV2ConversationId, + openGroupPrefixRegex, +} from '../opengroup/utils/OpenGroupUtils'; +import { OpenGroupMessageV2 } from '../opengroup/opengroupV2/OpenGroupMessageV2'; +import { OpenGroupRequestCommonType } from '../opengroup/opengroupV2/ApiUtil'; +import { handleMessageJob } from './queuedJob'; +import { fromBase64ToArray } from '../session/utils/String'; // TODO: check if some of these exports no longer needed @@ -292,34 +304,75 @@ export async function handlePublicMessage(messageData: any) { await handleMessageEvent(ev); // open groups } -export async function handleOpenGroupV2Message(messageData: any) { - const { source } = messageData; - const { group, profile, profileKey } = messageData.message; +export async function handleOpenGroupV2Message( + message: OpenGroupMessageV2, + roomInfos: OpenGroupRequestCommonType +) { + const { base64EncodedData, sentTimestamp, sender, serverId } = message; + const { serverUrl, roomId } = roomInfos; + if (!base64EncodedData || !sentTimestamp || !sender || !serverId) { + window.log.warn('Invalid data passed to handleMessageEvent.', message); + return; + } - const isMe = UserUtils.isUsFromCache(source); + const dataUint = new Uint8Array(unpad(fromBase64ToArray(base64EncodedData))); - if (!isMe && profile) { - const conversation = await ConversationController.getInstance().getOrCreateAndWait( - source, - ConversationType.PRIVATE - ); - await updateProfile(conversation, profile, profileKey); + const decoded = SignalService.Content.decode(dataUint); + + const conversationId = getOpenGroupV2ConversationId(serverUrl, roomId); + if (!conversationId) { + window.log.error('We cannot handle a message without a conversationId'); + return; + } + const dataMessage = decoded?.dataMessage; + if (!dataMessage) { + window.log.error('Invalid decoded opengroup message: no dataMessage'); + return; } - const isPublicVisibleMessage = group && group.id && !!group.id.match(openGroupPrefixRegex); + if (!ConversationController.getInstance().get(conversationId)) { + window.log.error('Received a message for an unknown convo. Skipping'); + return; + } + const isMe = UserUtils.isUsFromCache(sender); + const messageCreationData: MessageCreationData = { + isPublic: true, + sourceDevice: 1, + serverId, + serverTimestamp: sentTimestamp, + receivedAt: Date.now(), + destination: conversationId, + timestamp: sentTimestamp, + unidentifiedStatus: undefined, + expirationStartTimestamp: undefined, + source: sender, + message: dataMessage, + }; - if (!isPublicVisibleMessage) { - throw new Error('handlePublicMessage Should only be called with public message groups'); + if (await isMessageDuplicate(messageCreationData)) { + window.log.info('Received duplicate message. Dropping it.'); + return; } - const ev = { - // Public chat messages from ourselves should be outgoing - type: isMe ? 'sent' : 'message', - data: messageData, - confirm: () => { - /* do nothing */ - }, - }; + // this line just create an empty message with some basic stuff set. + // the whole decoding of data is happening in handleMessageJob() + const msg = createMessage(messageCreationData, !isMe); - await handleMessageEvent(ev); // open groups + // if the message is `sent` (from secondary device) we have to set the sender manually... (at least for now) + // source = source || msg.get('source'); + + const ourNumber = UserUtils.getOurPubKeyStrFromCache(); + const conversation = await ConversationController.getInstance().getOrCreateAndWait( + conversationId, + ConversationType.GROUP + ); + + if (!conversation) { + window.log.warn('Skipping handleJob for unknown convo: ', conversationId); + return; + } + + conversation.queueJob(async () => { + await handleMessageJob(msg, conversation, decoded?.dataMessage, ourNumber, noop, sender); + }); } diff --git a/ts/session/sending/MessageSender.ts b/ts/session/sending/MessageSender.ts index ede87ce60..b43809d71 100644 --- a/ts/session/sending/MessageSender.ts +++ b/ts/session/sending/MessageSender.ts @@ -156,7 +156,7 @@ export async function sendToOpenGroupV2( // the signature is added in the postMessage()) }); - // postMessage throws + // Warning: postMessage throws const sentMessage = await postMessage(v2Message, roomInfos); return sentMessage; } diff --git a/ts/session/sending/MessageSentHandler.ts b/ts/session/sending/MessageSentHandler.ts index 2e4f9b15a..83f36ba8e 100644 --- a/ts/session/sending/MessageSentHandler.ts +++ b/ts/session/sending/MessageSentHandler.ts @@ -28,7 +28,7 @@ export class MessageSentHandler { serverId, isPublic: true, sent: true, - sent_at: sentMessage.timestamp, + sent_at: serverTimestamp, sync: true, synced: true, sentSync: true, diff --git a/ts/session/snode_api/swarmPolling.ts b/ts/session/snode_api/swarmPolling.ts index 8a798a4b6..3cec40be4 100644 --- a/ts/session/snode_api/swarmPolling.ts +++ b/ts/session/snode_api/swarmPolling.ts @@ -53,7 +53,8 @@ export class SwarmPolling { public start(): void { this.loadGroupIds(); - void this.pollForAllKeys(); + //FIXME audric + // void this.pollForAllKeys(); } public addGroupId(pubkey: PubKey) { @@ -105,9 +106,11 @@ export class SwarmPolling { nodesToPoll = _.concat(nodesToPoll, newNodes); } + // FXIME audric const results = await Promise.all( nodesToPoll.map(async (n: Snode) => { - return this.pollNodeForKey(n, pubkey); + return []; + // return this.pollNodeForKey(n, pubkey); }) ); diff --git a/ts/session/utils/AttachmentsV2.ts b/ts/session/utils/AttachmentsV2.ts index aee0d6984..4486705d9 100644 --- a/ts/session/utils/AttachmentsV2.ts +++ b/ts/session/utils/AttachmentsV2.ts @@ -62,10 +62,10 @@ export async function uploadV2(params: UploadParamsV2): Promise