diff --git a/js/views/create_group_dialog_view.js b/js/views/create_group_dialog_view.js index 8e7a841e2..df542b021 100644 --- a/js/views/create_group_dialog_view.js +++ b/js/views/create_group_dialog_view.js @@ -62,12 +62,14 @@ return this; }, onSubmit(groupName, avatar) { - window.MediumGroups.initiateGroupUpdate( - this.groupId, - groupName, - this.members, - avatar - ); + if(groupName !== this.groupName || avatar !== this.avatarPath) { + window.MediumGroups.initiateGroupUpdate( + this.groupId, + groupName, + this.members, + avatar + ); + } }, close() { this.remove(); diff --git a/ts/receiver/contentMessage.ts b/ts/receiver/contentMessage.ts index c5f9463b5..eb3fed81b 100644 --- a/ts/receiver/contentMessage.ts +++ b/ts/receiver/contentMessage.ts @@ -4,13 +4,12 @@ import { getEnvelopeId } from './common'; import { removeFromCache, updateCache } from './cache'; import { SignalService } from '../protobuf'; -import { toNumber } from 'lodash'; +import * as Lodash from 'lodash'; import * as libsession from '../session'; import { handleSessionRequestMessage } from './sessionHandling'; import { handlePairingAuthorisationMessage } from './multidevice'; import { MediumGroupRequestKeysMessage, - ReceiptMessage, } from '../session/messages/outgoing'; import { MultiDeviceProtocol, SessionProtocol } from '../session/protocols'; import { PubKey } from '../session/types'; @@ -20,6 +19,7 @@ import { onError } from './errors'; import ByteBuffer from 'bytebuffer'; import { BlockedNumberController } from '../util/blockedNumberController'; import { decryptWithSenderKey } from '../session/medium_group/ratchet'; +import { StringUtils } from '../session/utils'; export async function handleContentMessage(envelope: EnvelopePlus) { const plaintext = await decrypt(envelope, envelope.content); @@ -188,12 +188,6 @@ async function decryptUnidentifiedSender( envelope.type = SignalService.Envelope.Type.FALLBACK_MESSAGE; } - const blocked = await isBlocked(sender.getName()); - if (blocked) { - window.log.info('Dropping blocked message after sealed sender decryption'); - return null; - } - // Here we take this sender information and attach it back to the envelope // to make the rest of the app work properly. @@ -336,6 +330,50 @@ async function decrypt( } } +function shouldDropBlockedUserMessage(content: SignalService.Content): boolean { + // Even if the user is blocked, we should allow the message if: + // - it is a group message AND + // - the group exists already on the db (to not join a closed group created by a blocked user) AND + // - the group is not blocked AND + // - the message is only control (no body/attachments/quote/groupInvitation/contact/preview) + + if (!content?.dataMessage?.group?.id) { + return true; + } + const groupId = StringUtils.decode(content.dataMessage.group.id, 'utf8'); + + const groupConvo = window.ConversationController.get(groupId); + if (!groupConvo) { + return true; + } + + if (groupConvo.isBlocked()) { + return true; + } + + // first check that dataMessage is the only field set in the Content + let msgWithoutDataMessage = Lodash.pickBy( + content, + (_, key) => key !== 'dataMessage' && key !== 'toJSON' + ); + msgWithoutDataMessage = Lodash.pickBy(msgWithoutDataMessage, Lodash.identity); + + const isMessageDataMessageOnly = Lodash.isEmpty(msgWithoutDataMessage); + if (!isMessageDataMessageOnly) { + return true; + } + const data = content.dataMessage; + const isControlDataMessageOnly = + !data.body && + !data.contact?.length && + !data.preview?.length && + !data.attachments?.length && + !data.groupInvitation && + !data.quote; + + return !isControlDataMessageOnly; +} + export async function innerHandleContentMessage( envelope: EnvelopePlus, plaintext: ArrayBuffer @@ -344,6 +382,17 @@ export async function innerHandleContentMessage( const content = SignalService.Content.decode(new Uint8Array(plaintext)); + const blocked = await isBlocked(envelope.source); + if (blocked) { + // We want to allow a blocked user message if that's a control message for a known group and the group is not blocked + if (shouldDropBlockedUserMessage(content)) { + window.log.info('Dropping blocked user message'); + return; + } else { + window.log.info('Allowing group-control message only from blocked user'); + } + } + const { FALLBACK_MESSAGE } = SignalService.Envelope.Type; await ConversationController.getOrCreateAndWait(envelope.source, 'private'); @@ -451,14 +500,14 @@ async function handleReceiptMessage( const results = []; if (type === SignalService.ReceiptMessage.Type.DELIVERY) { for (const ts of timestamp) { - const promise = onDeliveryReceipt(envelope.source, toNumber(ts)); + const promise = onDeliveryReceipt(envelope.source, Lodash.toNumber(ts)); results.push(promise); } } else if (type === SignalService.ReceiptMessage.Type.READ) { for (const ts of timestamp) { const promise = onReadReceipt( - toNumber(envelope.timestamp), - toNumber(ts), + Lodash.toNumber(envelope.timestamp), + Lodash.toNumber(ts), envelope.source ); results.push(promise); @@ -494,8 +543,8 @@ async function handleTypingMessage( await removeFromCache(envelope); if (envelope.timestamp && timestamp) { - const envelopeTimestamp = toNumber(envelope.timestamp); - const typingTimestamp = toNumber(timestamp); + const envelopeTimestamp = Lodash.toNumber(envelope.timestamp); + const typingTimestamp = Lodash.toNumber(timestamp); if (typingTimestamp !== envelopeTimestamp) { window.log.warn(