From 6ed74c9807873c5f0d75396abbd9e622ebba8371 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Tue, 24 Oct 2023 11:00:18 +1100 Subject: [PATCH] feat: move profile details of group invite to use the one in dataMsg --- protos/SignalService.proto | 4 --- .../group_v2/GroupUpdateMessage.ts | 7 +--- .../GroupUpdateDeleteMemberContentMessage.ts | 6 ++-- .../to_group/GroupUpdateInfoChangeMessage.ts | 7 ++-- .../GroupUpdateInviteResponseMessage.ts | 10 +++--- .../GroupUpdateMemberChangeMessage.ts | 6 ++-- .../to_group/GroupUpdateMemberLeftMessage.ts | 6 ++-- .../to_user/GroupUpdateDeleteMessage.ts | 5 +-- .../to_user/GroupUpdateInviteMessage.ts | 32 +++++++++++++------ .../to_user/GroupUpdatePromoteMessage.ts | 6 ++-- ts/session/sending/MessageQueue.ts | 7 +++- ts/session/sending/MessageSender.ts | 11 +++++-- ts/session/types/PubKey.ts | 8 ++++- ts/state/ducks/groups.ts | 5 +++ 14 files changed, 71 insertions(+), 49 deletions(-) diff --git a/protos/SignalService.proto b/protos/SignalService.proto index f91beb367..d71ab754c 100644 --- a/protos/SignalService.proto +++ b/protos/SignalService.proto @@ -89,8 +89,6 @@ message GroupUpdateInviteMessage { // @required required string name = 2; required bytes memberAuthData = 3; - optional bytes profileKey = 4; - optional LokiProfile profile = 5; // @required required bytes adminSignature = 6; } @@ -140,8 +138,6 @@ message GroupUpdateMemberLeftMessage { message GroupUpdateInviteResponseMessage { // @required required bool isApproved = 1; // Whether the request was approved - optional bytes profileKey = 2; - optional LokiProfile profile = 3; } diff --git a/ts/session/messages/outgoing/controlMessage/group_v2/GroupUpdateMessage.ts b/ts/session/messages/outgoing/controlMessage/group_v2/GroupUpdateMessage.ts index 012e61daa..c5af608f4 100644 --- a/ts/session/messages/outgoing/controlMessage/group_v2/GroupUpdateMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/group_v2/GroupUpdateMessage.ts @@ -19,12 +19,7 @@ export abstract class GroupUpdateMessage extends DataMessage { } } - protected abstract updateProto(): SignalService.GroupUpdateMessage; - - public dataProto(): SignalService.DataMessage { - const groupUpdateMessage = this.updateProto(); - return new SignalService.DataMessage({ groupUpdateMessage }); - } + public abstract dataProto(): SignalService.DataMessage; public abstract isFor1o1Swarm(): boolean; public abstract isForGroupSwarm(): boolean; diff --git a/ts/session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateDeleteMemberContentMessage.ts b/ts/session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateDeleteMemberContentMessage.ts index d8e2d7559..33a5e5a55 100644 --- a/ts/session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateDeleteMemberContentMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateDeleteMemberContentMessage.ts @@ -25,15 +25,13 @@ export class GroupUpdateDeleteMemberContentMessage extends GroupUpdateMessage { } } - protected updateProto(): SignalService.GroupUpdateMessage { + public dataProto(): SignalService.DataMessage { const deleteMemberContent = new SignalService.GroupUpdateDeleteMemberContentMessage({ adminSignature: this.adminSignature, memberSessionIds: this.memberSessionIds, }); - return new SignalService.GroupUpdateMessage({ - deleteMemberContent, - }); + return new SignalService.DataMessage({ groupUpdateMessage: { deleteMemberContent } }); } public isForGroupSwarm(): boolean { diff --git a/ts/session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateInfoChangeMessage.ts b/ts/session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateInfoChangeMessage.ts index fbfd41325..c8ded9623 100644 --- a/ts/session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateInfoChangeMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateInfoChangeMessage.ts @@ -53,7 +53,7 @@ export class GroupUpdateInfoChangeMessage extends GroupUpdateMessage { } } - protected updateProto(): SignalService.GroupUpdateMessage { + public dataProto(): SignalService.DataMessage { const infoChangeMessage = new SignalService.GroupUpdateInfoChangeMessage({ type: this.typeOfChange, }); @@ -66,10 +66,7 @@ export class GroupUpdateInfoChangeMessage extends GroupUpdateMessage { ) { infoChangeMessage.updatedExpiration = this.updatedExpirationSeconds; } - - return new SignalService.GroupUpdateMessage({ - infoChangeMessage, - }); + return new SignalService.DataMessage({ groupUpdateMessage: { infoChangeMessage } }); } public isForGroupSwarm(): boolean { diff --git a/ts/session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateInviteResponseMessage.ts b/ts/session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateInviteResponseMessage.ts index 3722047a0..428e84bf5 100644 --- a/ts/session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateInviteResponseMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateInviteResponseMessage.ts @@ -18,11 +18,14 @@ export class GroupUpdateInviteResponseMessage extends GroupUpdateMessage { this.isApproved = params.isApproved; } - protected updateProto(): SignalService.GroupUpdateMessage { + public dataProto(): SignalService.DataMessage { const ourProfile = getOurProfile(); const inviteResponse = new SignalService.GroupUpdateInviteResponseMessage({ isApproved: true, + }); + + return new SignalService.DataMessage({ profileKey: ourProfile?.profileKey, profile: ourProfile ? { @@ -30,10 +33,7 @@ export class GroupUpdateInviteResponseMessage extends GroupUpdateMessage { profilePicture: ourProfile.avatarPointer, } : undefined, - }); - - return new SignalService.GroupUpdateMessage({ - inviteResponse, + groupUpdateMessage: { inviteResponse }, }); } diff --git a/ts/session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateMemberChangeMessage.ts b/ts/session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateMemberChangeMessage.ts index 734097d8f..9783f8222 100644 --- a/ts/session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateMemberChangeMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateMemberChangeMessage.ts @@ -62,15 +62,13 @@ export class GroupUpdateMemberChangeMessage extends GroupUpdateMessage { } } - protected updateProto(): SignalService.GroupUpdateMessage { + public dataProto(): SignalService.DataMessage { const memberChangeMessage = new SignalService.GroupUpdateMemberChangeMessage({ type: this.typeOfChange, memberSessionIds: this.memberSessionIds, }); - return new SignalService.GroupUpdateMessage({ - memberChangeMessage, - }); + return new SignalService.DataMessage({ groupUpdateMessage: { memberChangeMessage } }); } public isForGroupSwarm(): boolean { diff --git a/ts/session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateMemberLeftMessage.ts b/ts/session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateMemberLeftMessage.ts index 4266dd3fa..de46bdedd 100644 --- a/ts/session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateMemberLeftMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateMemberLeftMessage.ts @@ -7,12 +7,10 @@ import { GroupUpdateMessage } from '../GroupUpdateMessage'; * */ export class GroupUpdateMemberLeftMessage extends GroupUpdateMessage { - protected updateProto(): SignalService.GroupUpdateMessage { + public dataProto(): SignalService.DataMessage { const memberLeftMessage = new SignalService.GroupUpdateMemberLeftMessage({}); - return new SignalService.GroupUpdateMessage({ - memberLeftMessage, - }); + return new SignalService.DataMessage({ groupUpdateMessage: { memberLeftMessage } }); } public isForGroupSwarm(): boolean { diff --git a/ts/session/messages/outgoing/controlMessage/group_v2/to_user/GroupUpdateDeleteMessage.ts b/ts/session/messages/outgoing/controlMessage/group_v2/to_user/GroupUpdateDeleteMessage.ts index 70ccaf0fe..328b41412 100644 --- a/ts/session/messages/outgoing/controlMessage/group_v2/to_user/GroupUpdateDeleteMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/group_v2/to_user/GroupUpdateDeleteMessage.ts @@ -17,12 +17,13 @@ export class GroupUpdateDeleteMessage extends GroupUpdateMessage { this.adminSignature = params.adminSignature; } - protected updateProto(): SignalService.GroupUpdateMessage { + public dataProto(): SignalService.DataMessage { const deleteMessage = new SignalService.GroupUpdateDeleteMessage({ groupSessionId: this.groupPk, adminSignature: this.adminSignature, }); - return new SignalService.GroupUpdateMessage({ deleteMessage }); + + return new SignalService.DataMessage({ groupUpdateMessage: { deleteMessage } }); } public isForGroupSwarm(): boolean { diff --git a/ts/session/messages/outgoing/controlMessage/group_v2/to_user/GroupUpdateInviteMessage.ts b/ts/session/messages/outgoing/controlMessage/group_v2/to_user/GroupUpdateInviteMessage.ts index 4394aacd9..380203759 100644 --- a/ts/session/messages/outgoing/controlMessage/group_v2/to_user/GroupUpdateInviteMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/group_v2/to_user/GroupUpdateInviteMessage.ts @@ -1,5 +1,6 @@ import { SignalService } from '../../../../../../protobuf'; import { UserUtils } from '../../../../../utils'; +import { Preconditions } from '../../../preconditions'; import { GroupUpdateMessage, GroupUpdateMessageParams } from '../GroupUpdateMessage'; interface Params extends GroupUpdateMessageParams { @@ -16,31 +17,44 @@ export class GroupUpdateInviteMessage extends GroupUpdateMessage { public readonly adminSignature: Params['adminSignature']; public readonly memberAuthData: Params['memberAuthData']; - constructor(params: Params) { + constructor({ adminSignature, groupName, memberAuthData, ...others }: Params) { super({ - timestamp: params.timestamp, - identifier: params.identifier, - groupPk: params.groupPk, + ...others, }); - this.groupName = params.groupName; - this.adminSignature = params.adminSignature; - this.memberAuthData = params.memberAuthData; + this.groupName = groupName; // not sure if getting an invite with an empty group name should make us drop an incoming group invite (and the keys associated to it too) + this.adminSignature = adminSignature; + this.memberAuthData = memberAuthData; + Preconditions.checkUin8tArrayOrThrow( + memberAuthData, + 100, + 'memberAuthData', + 'GroupUpdateInviteMessage' + ); + Preconditions.checkUin8tArrayOrThrow( + adminSignature, + 32, + 'adminSignature', + 'GroupUpdateInviteMessage' + ); } - protected updateProto(): SignalService.GroupUpdateMessage { + public dataProto(): SignalService.DataMessage { const ourProfile = UserUtils.getOurProfile(); const inviteMessage = new SignalService.GroupUpdateInviteMessage({ groupSessionId: this.groupPk, name: this.groupName, adminSignature: this.adminSignature, memberAuthData: this.memberAuthData, + }); + + return new SignalService.DataMessage({ profile: ourProfile ? { displayName: ourProfile.displayName, profilePicture: ourProfile.avatarPointer } : undefined, profileKey: ourProfile?.profileKey, + groupUpdateMessage: { inviteMessage }, }); - return new SignalService.GroupUpdateMessage({ inviteMessage }); } public isForGroupSwarm(): boolean { diff --git a/ts/session/messages/outgoing/controlMessage/group_v2/to_user/GroupUpdatePromoteMessage.ts b/ts/session/messages/outgoing/controlMessage/group_v2/to_user/GroupUpdatePromoteMessage.ts index 1cc325225..b41fec363 100644 --- a/ts/session/messages/outgoing/controlMessage/group_v2/to_user/GroupUpdatePromoteMessage.ts +++ b/ts/session/messages/outgoing/controlMessage/group_v2/to_user/GroupUpdatePromoteMessage.ts @@ -22,12 +22,14 @@ export class GroupUpdatePromoteMessage extends GroupUpdateMessage { } } - protected updateProto(): SignalService.GroupUpdateMessage { + public dataProto(): SignalService.DataMessage { const promoteMessage = new SignalService.GroupUpdatePromoteMessage({ groupIdentitySeed: this.groupIdentitySeed, }); - return new SignalService.GroupUpdateMessage({ promoteMessage }); + return new SignalService.DataMessage({ + groupUpdateMessage: { promoteMessage }, + }); } public isForGroupSwarm(): boolean { diff --git a/ts/session/sending/MessageQueue.ts b/ts/session/sending/MessageQueue.ts index 78452b6a9..7a607132c 100644 --- a/ts/session/sending/MessageQueue.ts +++ b/ts/session/sending/MessageQueue.ts @@ -31,6 +31,7 @@ import { } from '../apis/snode_api/namespaces'; import { CallMessage } from '../messages/outgoing/controlMessage/CallMessage'; import { UnsendMessage } from '../messages/outgoing/controlMessage/UnsendMessage'; +import { GroupUpdateInviteMessage } from '../messages/outgoing/controlMessage/group_v2/to_user/GroupUpdateInviteMessage'; import { OpenGroupVisibleMessage } from '../messages/outgoing/visibleMessage/OpenGroupVisibleMessage'; type ClosedGroupMessageType = @@ -249,7 +250,11 @@ export class MessageQueue { pubkey, }: { pubkey: PubKey; - message: ClosedGroupNewMessage | CallMessage | ClosedGroupMemberLeftMessage; + message: + | ClosedGroupNewMessage + | CallMessage + | ClosedGroupMemberLeftMessage + | GroupUpdateInviteMessage; namespace: SnodeNamespaces; }): Promise { let rawMessage; diff --git a/ts/session/sending/MessageSender.ts b/ts/session/sending/MessageSender.ts index 28e02eba9..8942fe7cd 100644 --- a/ts/session/sending/MessageSender.ts +++ b/ts/session/sending/MessageSender.ts @@ -49,8 +49,15 @@ function overwriteOutgoingTimestampWithNetworkTimestamp(message: { plainTextBuff const { dataMessage, dataExtractionNotification, typingMessage } = contentDecoded; if (dataMessage && dataMessage.timestamp && toNumber(dataMessage.timestamp) > 0) { - // this is a sync message, do not overwrite the message timestamp - if (dataMessage.syncTarget) { + // for a few message types, we cannot override the timestamp when sending it. + // - for a sync message + // - groupv2InviteMessage, groupUpdateDeleteMemberContentMessage, groupUpdateDeleteMessage as the embedded signature depends on the timestamp inside + if ( + dataMessage.syncTarget || + dataMessage.groupUpdateMessage?.inviteMessage || + dataMessage.groupUpdateMessage?.deleteMemberContent || + dataMessage.groupUpdateMessage?.deleteMessage + ) { return { overRiddenTimestampBuffer: plainTextBuffer, networkTimestamp: _.toNumber(dataMessage.timestamp), diff --git a/ts/session/types/PubKey.ts b/ts/session/types/PubKey.ts index ad2c2bb55..4f7dc8554 100644 --- a/ts/session/types/PubKey.ts +++ b/ts/session/types/PubKey.ts @@ -1,4 +1,4 @@ -import { GroupPubkeyType } from 'libsession_util_nodejs'; +import { GroupPubkeyType, PubkeyType } from 'libsession_util_nodejs'; import { fromHexToArray } from '../utils/String'; export enum KeyPrefixType { @@ -235,8 +235,14 @@ export class PubKey { return key.startsWith(KeyPrefixType.blinded15) || key.startsWith(KeyPrefixType.blinded25); } + // TODO we should probably move those to a libsession exported ts file public static isClosedGroupV2(key: string): key is GroupPubkeyType { const regex = new RegExp(`^${KeyPrefixType.groupV2}${PubKey.HEX}{64}$`); return regex.test(key); } + + public static is05Pubkey(key: string): key is PubkeyType { + const regex = new RegExp(`^${KeyPrefixType.standard}${PubKey.HEX}{64}$`); + return regex.test(key); + } } diff --git a/ts/state/ducks/groups.ts b/ts/state/ducks/groups.ts index 5ab0cbb4a..df7a213a5 100644 --- a/ts/state/ducks/groups.ts +++ b/ts/state/ducks/groups.ts @@ -4,6 +4,7 @@ import { GroupInfoGet, GroupMemberGet, GroupPubkeyType, + PubkeyType, UserGroupsGet, } from 'libsession_util_nodejs'; import { isEmpty, uniq } from 'lodash'; @@ -11,7 +12,11 @@ import { ConfigDumpData } from '../../data/configDump/configDump'; import { ConversationTypeEnum } from '../../models/conversationAttributes'; import { HexString } from '../../node/hexStrings'; import { getSwarmPollingInstance } from '../../session/apis/snode_api'; +import { SnodeNamespaces } from '../../session/apis/snode_api/namespaces'; import { ConvoHub } from '../../session/conversations'; +import { getGroupInvitesMessages } from '../../session/crypto/group/groupSignature'; +import { getMessageQueue } from '../../session/sending'; +import { PubKey } from '../../session/types'; import { UserUtils } from '../../session/utils'; import { getUserED25519KeyPairBytes } from '../../session/utils/User'; import { PreConditionFailed } from '../../session/utils/errors';