diff --git a/js/models/conversations.js b/js/models/conversations.js index 8744c2fa8..8b2362ff5 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -1813,26 +1813,32 @@ if (groupUpdate.is_medium_group) { // Constructing a "create group" message - const proto = new textsecure.protobuf.DataMessage(); - - const mgUpdate = new textsecure.protobuf.MediumGroupUpdate(); - const { id, name, secretKey, senderKey, members } = groupUpdate; + const { chainKey, keyIdx } = senderKey; - mgUpdate.type = textsecure.protobuf.MediumGroupUpdate.Type.NEW_GROUP; - mgUpdate.groupId = id; - mgUpdate.groupSecretKey = secretKey; - mgUpdate.senderKey = new textsecure.protobuf.SenderKey(senderKey); - mgUpdate.members = members.map(pkHex => - StringView.hexToArrayBuffer(pkHex) - ); - mgUpdate.groupName = name; - mgUpdate.admins = this.get('groupAdmins'); - proto.mediumGroupUpdate = mgUpdate; + const createParams = { + timestamp: Date.now(), + groupId: id, + groupSecretKey: secretKey, + members: members.map(pkHex => StringView.hexToArrayBuffer(pkHex)), + groupName: name, + admins: this.get('groupAdmins'), + chainKey, + keyIdx, + }; - message.send( - this.wrapSend(textsecure.messaging.updateMediumGroup(members, proto)) + const mediumGroupCreateMessage = new libsession.Messages.Outgoing.MediumGroupCreateMessage( + createParams ); + message.trigger('pending'); + + members.forEach(member => { + const memberPubKey = new libsession.Types.PubKey(member); + libsession + .getMessageQueue() + .sendUsingMultiDevice(memberPubKey, mediumGroupCreateMessage); + }); + return; } diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js index 7c0b48aba..e23e917d4 100644 --- a/libtextsecure/message_receiver.js +++ b/libtextsecure/message_receiver.js @@ -850,8 +850,15 @@ MessageReceiver.prototype.extend({ groupId ); - textsecure.messaging.requestSenderKeys(senderIdentity, groupId); - + const params = { + timestamp: Date.now(), + groupId, + }; + const requestKeysMessage = new libsession.Messages.Outgoing.MediumGroupRequestKeysMessage( + params + ); + const senderPubKey = new libsession.Types.PubKey(senderIdentity); + libsession.getMessageQueue().send(senderPubKey, requestKeysMessage); return; } diff --git a/libtextsecure/sendmessage.js b/libtextsecure/sendmessage.js index 656941eb9..bbedbc947 100644 --- a/libtextsecure/sendmessage.js +++ b/libtextsecure/sendmessage.js @@ -631,26 +631,16 @@ MessageSender.prototype = { } }, - async updateMediumGroup(members, groupUpdateProto) { - // Automatically request session if not found (updates use pairwise sessions) - const autoSession = true; - - await this.sendGroupProto(members, groupUpdateProto, Date.now(), { - isPublic: false, - autoSession, - }); - - return true; - }, - requestSenderKeys(sender, groupId) { - const proto = new textsecure.protobuf.DataMessage(); - const update = new textsecure.protobuf.MediumGroupUpdate(); - update.type = textsecure.protobuf.MediumGroupUpdate.Type.SENDER_KEY_REQUEST; - update.groupId = groupId; - proto.mediumGroupUpdate = update; - - textsecure.messaging.updateMediumGroup([sender], proto); + const params = { + timestamp: Date.now(), + groupId, + }; + const requestKeysMessage = new libsession.Messages.Outgoing.MediumGroupRequestKeysMessage( + params + ); + const senderPubKey = new libsession.Types.PubKey(sender); + libsession.getMessageQueue().send(senderPubKey, requestKeysMessage); }, makeProxiedRequest(url, options) { return this.server.makeProxiedRequest(url, options); @@ -669,7 +659,6 @@ textsecure.MessageSender = function MessageSenderWrapper(username, password) { this.sendOpenGroupsSyncMessage = sender.sendOpenGroupsSyncMessage.bind( sender ); - this.updateMediumGroup = sender.updateMediumGroup.bind(sender); this.requestSenderKeys = sender.requestSenderKeys.bind(sender); this.uploadAvatar = sender.uploadAvatar.bind(sender); this.syncReadMessages = sender.syncReadMessages.bind(sender); diff --git a/ts/receiver/mediumGroups.ts b/ts/receiver/mediumGroups.ts index b47ea51da..be2010a56 100644 --- a/ts/receiver/mediumGroups.ts +++ b/ts/receiver/mediumGroups.ts @@ -1,6 +1,9 @@ import { SignalService } from '../protobuf'; import { removeFromCache } from './cache'; import { EnvelopePlus } from './types'; +import { MediumGroupResponseKeysMessage } from '../session/messages/outgoing'; +import { getMessageQueue } from '../session'; +import { PubKey } from '../session/types'; async function handleSenderKeyRequest( envelope: EnvelopePlus, @@ -14,26 +17,26 @@ async function handleSenderKeyRequest( log.debug('[sender key] sender key request from:', senderIdentity); - const proto = new SignalService.DataMessage(); - // We reuse the same message type for sender keys - const update = new SignalService.MediumGroupUpdate(); - const { chainKey, keyIdx } = await SenderKeyAPI.getSenderKeys( groupId, ourIdentity ); - update.type = SignalService.MediumGroupUpdate.Type.SENDER_KEY; - update.groupId = groupId; - update.senderKey = new SignalService.SenderKey({ - chainKey: StringView.arrayBufferToHex(chainKey), + const chainKeyHex = StringView.arrayBufferToHex(chainKey); + const responseParams = { + timestamp: Date.now(), + groupId, + chainKey: chainKeyHex, keyIdx, - }); + }; - proto.mediumGroupUpdate = update; + const keysResponseMessage = new MediumGroupResponseKeysMessage( + responseParams + ); - textsecure.messaging.updateMediumGroup([senderIdentity], proto); + const senderPubKey = new PubKey(senderIdentity); + await getMessageQueue().send(senderPubKey, keysResponseMessage); removeFromCache(envelope); } @@ -157,7 +160,7 @@ async function handleNewGroup(envelope: EnvelopePlus, groupUpdate: any) { senderKey.keyIdx ); - const ownSenderKey = await SenderKeyAPI.createSenderKeyForGroup( + const ownSenderKeyHex = await SenderKeyAPI.createSenderKeyForGroup( groupId, ourIdentity ); @@ -166,20 +169,24 @@ async function handleNewGroup(envelope: EnvelopePlus, groupUpdate: any) { // Send own key to every member const otherMembers = _.without(members, ourIdentity); - const proto = new SignalService.DataMessage(); - // We reuse the same message type for sender keys - const update = new SignalService.MediumGroupUpdate(); - update.type = SignalService.MediumGroupUpdate.Type.SENDER_KEY; - update.groupId = groupId; - update.senderKey = new SignalService.SenderKey({ - chainKey: ownSenderKey, + const responseParams = { + timestamp: Date.now(), + groupId, + chainKey: ownSenderKeyHex, keyIdx: 0, + }; + + const keysResponseMessage = new MediumGroupResponseKeysMessage( + responseParams + ); + // send our senderKey to every other member + otherMembers.forEach((member: string) => { + const memberPubKey = new PubKey(member); + getMessageQueue() + .sendUsingMultiDevice(memberPubKey, keysResponseMessage) + .ignore(); }); - - proto.mediumGroupUpdate = update; - - textsecure.messaging.updateMediumGroup(otherMembers, proto); } // TODO: !!!! This will need to be re-enabled after message polling refactor !!!!! diff --git a/ts/session/messages/outgoing/content/data/index.ts b/ts/session/messages/outgoing/content/data/index.ts index a8022724b..c76911036 100644 --- a/ts/session/messages/outgoing/content/data/index.ts +++ b/ts/session/messages/outgoing/content/data/index.ts @@ -3,4 +3,5 @@ export * from './DeviceUnlinkMessage'; export * from './GroupInvitationMessage'; export * from './ChatMessage'; export * from './group'; +export * from './mediumgroup'; export * from './ExpirationTimerUpdateMessage'; diff --git a/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupCreateMessage.ts b/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupCreateMessage.ts new file mode 100644 index 000000000..aed1cc1c3 --- /dev/null +++ b/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupCreateMessage.ts @@ -0,0 +1,49 @@ +import { SignalService } from '../../../../../../protobuf'; +import { + MediumGroupResponseKeysMessage, + MediumGroupResponseKeysParams, +} from './MediumGroupResponseKeysMessage'; + +interface MediumGroupCreateParams extends MediumGroupResponseKeysParams { + groupSecretKey: Uint8Array; + members: Array; + admins: Array; + groupName: string; +} + +export abstract class MediumGroupCreateMessage extends MediumGroupResponseKeysMessage { + public readonly groupSecretKey: Uint8Array; + public readonly members: Array; + public readonly admins: Array; + public readonly groupName: string; + + constructor({ + timestamp, + identifier, + chainKey, + keyIdx, + groupId, + groupSecretKey, + members, + admins, + groupName, + }: MediumGroupCreateParams) { + super({ timestamp, identifier, groupId, chainKey, keyIdx }); + this.groupSecretKey = groupSecretKey; + this.members = members; + this.admins = admins; + this.groupName = groupName; + } + + protected mediumGroupContext(): SignalService.MediumGroupUpdate { + const mediumGroupContext = super.mediumGroupContext(); + + mediumGroupContext.type = SignalService.MediumGroupUpdate.Type.NEW_GROUP; + mediumGroupContext.groupSecretKey = this.groupSecretKey; + mediumGroupContext.members = this.members; + mediumGroupContext.admins = this.admins; + mediumGroupContext.groupName = this.groupName; + + return mediumGroupContext; + } +} diff --git a/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupMessage.ts b/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupMessage.ts new file mode 100644 index 000000000..6f5f7514b --- /dev/null +++ b/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupMessage.ts @@ -0,0 +1,36 @@ +import { DataMessage } from '../DataMessage'; +import { SignalService } from '../../../../../../protobuf'; +import { MessageParams } from '../../../Message'; +import { PubKey } from '../../../../../types'; +import { StringUtils } from '../../../../../utils'; + +export interface MediumGroupMessageParams extends MessageParams { + groupId: string | PubKey; +} + +export abstract class MediumGroupMessage extends DataMessage { + public readonly groupId: PubKey; + + constructor(params: MediumGroupMessageParams) { + super({ + timestamp: params.timestamp, + identifier: params.identifier, + }); + this.groupId = PubKey.cast(params.groupId); + } + + public ttl(): number { + return this.getDefaultTTL(); + } + + protected mediumGroupContext(): SignalService.MediumGroupUpdate { + return new SignalService.MediumGroupUpdate({ groupId: this.groupId.key }); + } + + protected dataProto(): SignalService.DataMessage { + const dataMessage = new SignalService.DataMessage(); + dataMessage.mediumGroupUpdate = this.mediumGroupContext(); + + return dataMessage; + } +} diff --git a/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupRequestKeysMessage.ts b/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupRequestKeysMessage.ts new file mode 100644 index 000000000..5cc6499cc --- /dev/null +++ b/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupRequestKeysMessage.ts @@ -0,0 +1,13 @@ +import { SignalService } from '../../../../../../protobuf'; +import { MediumGroupMessage } from '.'; + +export class MediumGroupRequestKeysMessage extends MediumGroupMessage { + protected mediumGroupContext(): SignalService.MediumGroupUpdate { + const mediumGroupContext = super.mediumGroupContext(); + + mediumGroupContext.type = + SignalService.MediumGroupUpdate.Type.SENDER_KEY_REQUEST; + + return mediumGroupContext; + } +} diff --git a/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupResponseKeysMessage.ts b/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupResponseKeysMessage.ts new file mode 100644 index 000000000..3dbd8d66c --- /dev/null +++ b/ts/session/messages/outgoing/content/data/mediumgroup/MediumGroupResponseKeysMessage.ts @@ -0,0 +1,37 @@ +import { SignalService } from '../../../../../../protobuf'; +import { MediumGroupMessage, MediumGroupMessageParams } from '.'; + +export interface MediumGroupResponseKeysParams + extends MediumGroupMessageParams { + chainKey: string; + keyIdx: number; +} + +export class MediumGroupResponseKeysMessage extends MediumGroupMessage { + public readonly chainKey: string; + public readonly keyIdx: number; + + constructor({ + timestamp, + identifier, + groupId, + chainKey, + keyIdx, + }: MediumGroupResponseKeysParams) { + super({ timestamp, identifier, groupId }); + this.chainKey = chainKey; + this.keyIdx = keyIdx; + } + + protected mediumGroupContext(): SignalService.MediumGroupUpdate { + const mediumGroupContext = super.mediumGroupContext(); + + mediumGroupContext.type = SignalService.MediumGroupUpdate.Type.SENDER_KEY; + mediumGroupContext.senderKey = new SignalService.SenderKey({ + chainKey: this.chainKey, + keyIdx: this.keyIdx, + }); + + return mediumGroupContext; + } +} diff --git a/ts/session/messages/outgoing/content/data/mediumgroup/index.ts b/ts/session/messages/outgoing/content/data/mediumgroup/index.ts new file mode 100644 index 000000000..f6b317532 --- /dev/null +++ b/ts/session/messages/outgoing/content/data/mediumgroup/index.ts @@ -0,0 +1,4 @@ +export * from './MediumGroupMessage'; +export * from './MediumGroupRequestKeysMessage'; +export * from './MediumGroupResponseKeysMessage'; +export * from './MediumGroupCreateMessage';