You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
session-desktop/ts/receiver/mediumGroups.ts

207 lines
5.5 KiB
TypeScript

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';
import _ from 'lodash';
async function handleSenderKeyRequest(
envelope: EnvelopePlus,
groupUpdate: any
) {
const { SenderKeyAPI, StringView, textsecure, log } = window;
const senderIdentity = envelope.source;
const ourIdentity = await textsecure.storage.user.getNumber();
const { groupId } = groupUpdate;
log.debug('[sender key] sender key request from:', senderIdentity);
// We reuse the same message type for sender keys
const { chainKey, keyIdx } = await SenderKeyAPI.getSenderKeys(
groupId,
ourIdentity
);
const chainKeyHex = StringView.arrayBufferToHex(chainKey);
const responseParams = {
timestamp: Date.now(),
groupId,
chainKey: chainKeyHex,
keyIdx,
};
const keysResponseMessage = new MediumGroupResponseKeysMessage(
responseParams
);
const senderPubKey = new PubKey(senderIdentity);
await getMessageQueue().send(senderPubKey, keysResponseMessage);
await removeFromCache(envelope);
}
async function handleSenderKey(envelope: EnvelopePlus, groupUpdate: any) {
const { SenderKeyAPI, log } = window;
const { groupId, senderKey } = groupUpdate;
const senderIdentity = envelope.source;
log.debug('[sender key] got a new sender key from:', senderIdentity);
await SenderKeyAPI.saveSenderKeys(
groupId,
senderIdentity,
senderKey.chainKey,
senderKey.keyIdx
);
await removeFromCache(envelope);
}
async function handleNewGroup(envelope: EnvelopePlus, groupUpdate: any) {
const { SenderKeyAPI, StringView, Whisper, log, textsecure } = window;
const senderIdentity = envelope.source;
const ourIdentity = await textsecure.storage.user.getNumber();
const {
groupId,
members: membersBinary,
groupSecretKey,
groupName,
senderKey,
admins,
} = groupUpdate;
const maybeConvo = await window.ConversationController.get(groupId);
const groupExists = !!maybeConvo;
const members = membersBinary.map((pk: any) =>
StringView.arrayBufferToHex(pk.toArrayBuffer())
);
const convo = groupExists
? maybeConvo
: await window.ConversationController.getOrCreateAndWait(groupId, 'group');
{
// Add group update message
const now = Date.now();
const message = convo.messageCollection.add({
conversationId: convo.id,
type: 'incoming',
sent_at: now,
received_at: now,
group_update: {
name: groupName,
members,
},
});
const messageId = await window.Signal.Data.saveMessage(message.attributes, {
Message: Whisper.Message,
});
message.set({ id: messageId });
}
if (groupExists) {
// ***** Updating the group *****
log.info('Received a group update for medium group:', groupId);
// Check that the sender is admin (make sure it words with multidevice)
const isAdmin = convo.get('groupAdmins').includes(senderIdentity);
if (!isAdmin) {
log.warn('Rejected attempt to update a group by non-admin');
await removeFromCache(envelope);
return;
}
convo.set('name', groupName);
convo.set('members', members);
// TODO: check that we are still in the group (when we enable deleting members)
convo.saveChangesToDB();
// Update other fields. Add a corresponding "update" message to the conversation
} else {
// ***** Creating a new group *****
log.info('Received a new medium group:', groupId);
// TODO: Check that we are even a part of this group?
convo.set('is_medium_group', true);
convo.set('active_at', Date.now());
convo.set('name', groupName);
convo.set('groupAdmins', admins);
const secretKeyHex = StringView.arrayBufferToHex(
groupSecretKey.toArrayBuffer()
);
await window.Signal.Data.createOrUpdateIdentityKey({
id: groupId,
secretKey: secretKeyHex,
});
// Save sender's key
await SenderKeyAPI.saveSenderKeys(
groupId,
envelope.source,
senderKey.chainKey,
senderKey.keyIdx
);
const ownSenderKeyHex = await SenderKeyAPI.createSenderKeyForGroup(
groupId,
ourIdentity
);
{
// Send own key to every member
const otherMembers = _.without(members, ourIdentity);
// We reuse the same message type for sender keys
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();
});
}
window.SwarmPolling.addGroupId(groupId);
}
await removeFromCache(envelope);
}
export async function handleMediumGroupUpdate(
envelope: EnvelopePlus,
groupUpdate: any
) {
const { type } = groupUpdate;
const { Type } = SignalService.MediumGroupUpdate;
if (type === Type.SENDER_KEY_REQUEST) {
await handleSenderKeyRequest(envelope, groupUpdate);
} else if (type === Type.SENDER_KEY) {
await handleSenderKey(envelope, groupUpdate);
} else if (type === Type.NEW_GROUP) {
await handleNewGroup(envelope, groupUpdate);
}
}