disable sending of explicit group updates for now - only receiving is ON

pull/1468/head
Audric Ackermann 4 years ago
parent 2462e12a04
commit ab8aa0d982
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -440,12 +440,12 @@ if (process.env.USE_STUBBED_NETWORK) {
window.lokiFeatureFlags = {
multiDeviceUnpairing: true,
privateGroupChats: true,
useOnionRequests: true,
useOnionRequestsV2: true,
useFileOnionRequests: true,
useFileOnionRequestsV2: true, // more compact encoding of files in response
onionRequestHops: 3,
useExplicitGroupUpdatesSending: false,
};
// eslint-disable-next-line no-extend-native,func-names
@ -476,10 +476,10 @@ if (
if (config.environment.includes('test-integration')) {
window.lokiFeatureFlags = {
multiDeviceUnpairing: true,
privateGroupChats: true,
useOnionRequests: false,
useFileOnionRequests: false,
useOnionRequestsV2: false,
useExplicitGroupUpdatesSending: false,
};
/* eslint-disable global-require, import/no-extraneous-dependencies */
window.sinon = require('sinon');

@ -25,6 +25,7 @@ import {
ClosedGroupAddedMembersMessage,
ClosedGroupNameChangeMessage,
ClosedGroupRemovedMembersMessage,
ClosedGroupUpdateMessage,
} from '../messages/outgoing/content/data/group';
export interface GroupInfo {
@ -77,6 +78,8 @@ export async function syncMediumGroups(groups: Array<ConversationModel>) {
// await Promise.all(groups.map(syncMediumGroup));
}
// tslint:disable: max-func-body-length
// tslint:disable: cyclomatic-complexity
export async function initiateGroupUpdate(
groupId: string,
groupName: string,
@ -119,6 +122,111 @@ export async function initiateGroupUpdate(
expireTimer: convo.get('expireTimer'),
};
if (!window.lokiFeatureFlags.useExplicitGroupUpdatesSending) {
// we still don't send any explicit group updates for now - only the receiving side is enabled
const dbMessageAdded = await addUpdateMessage(convo, diff, 'outgoing');
window.getMessageController().register(dbMessageAdded.id, dbMessageAdded);
// Check preconditions
const hexEncryptionKeyPair = await Data.getLatestClosedGroupEncryptionKeyPair(
groupId
);
if (!hexEncryptionKeyPair) {
throw new Error("Couldn't get key pair for closed group");
}
const encryptionKeyPair = ECKeyPair.fromHexKeyPair(hexEncryptionKeyPair);
const removedMembers = diff.leavingMembers || [];
const newMembers = diff.joiningMembers || []; // joining members
const wasAnyUserRemoved = removedMembers.length > 0;
const ourPrimary = await UserUtils.getOurNumber();
const isUserLeaving = removedMembers.includes(ourPrimary.key);
const isCurrentUserAdmin = convo
.get('groupAdmins')
?.includes(ourPrimary.key);
const expireTimerToShare = groupDetails.expireTimer || 0;
const admins = convo.get('groupAdmins') || [];
if (removedMembers.includes(admins[0]) && newMembers.length !== 0) {
throw new Error(
"Can't remove admin from closed group without removing everyone."
); // Error.invalidClosedGroupUpdate
}
if (isUserLeaving && newMembers.length !== 0) {
if (removedMembers.length !== 1 || newMembers.length !== 0) {
throw new Error(
"Can't remove self and add or remove others simultaneously."
);
}
}
// Send the update to the group
const mainClosedGroupUpdate = new ClosedGroupUpdateMessage({
timestamp: Date.now(),
groupId,
name: groupName,
members,
identifier: dbMessageAdded.id || uuid(),
expireTimer: expireTimerToShare,
});
if (isUserLeaving) {
window.log.info(
`We are leaving the group ${groupId}. Sending our leaving message.`
);
// sent the message to the group and once done, remove everything related to this group
window.SwarmPolling.removePubkey(groupId);
await getMessageQueue().sendToGroup(mainClosedGroupUpdate, async () => {
window.log.info(
`Leaving message sent ${groupId}. Removing everything related to this group.`
);
await Data.removeAllClosedGroupEncryptionKeyPairs(groupId);
});
} else {
// Send the group update, and only once sent, generate and distribute a new encryption key pair if needed
await getMessageQueue().sendToGroup(mainClosedGroupUpdate, async () => {
if (wasAnyUserRemoved && isCurrentUserAdmin) {
// we send the new encryption key only to members already here before the update
const membersNotNew = members.filter(m => !newMembers.includes(m));
window.log.info(
`Sending group update: A user was removed from ${groupId} and we are the admin. Generating and sending a new EncryptionKeyPair`
);
await generateAndSendNewEncryptionKeyPair(groupId, membersNotNew);
}
});
if (newMembers.length) {
// Send closed group update messages to any new members individually
const newClosedGroupUpdate = new ClosedGroupNewMessage({
timestamp: Date.now(),
name: groupName,
groupId,
admins,
members,
keypair: encryptionKeyPair,
identifier: dbMessageAdded.id || uuid(),
expireTimer: expireTimerToShare,
});
const promises = newMembers.map(async m => {
await ConversationController.getInstance().getOrCreateAndWait(
m,
'private'
);
const memberPubKey = PubKey.cast(m);
await getMessageQueue().sendToPubKey(
memberPubKey,
newClosedGroupUpdate
);
});
await Promise.all(promises);
}
}
return;
}
if (diff.newName?.length) {
const nameOnlyDiff: GroupDiff = { newName: diff.newName };
const dbMessageName = await addUpdateMessage(
@ -344,12 +452,26 @@ export async function leaveClosedGroup(groupId: string) {
window.getMessageController().register(dbMessage.id, dbMessage);
const existingExpireTimer = convo.get('expireTimer') || 0;
// Send the update to the group
const ourLeavingMessage = new ClosedGroupMemberLeftMessage({
timestamp: Date.now(),
groupId,
identifier: dbMessage.id,
expireTimer: existingExpireTimer,
});
let ourLeavingMessage;
if (window.lokiFeatureFlags.useExplicitGroupUpdatesSending) {
ourLeavingMessage = new ClosedGroupMemberLeftMessage({
timestamp: Date.now(),
groupId,
identifier: dbMessage.id,
expireTimer: existingExpireTimer,
});
} else {
const ourPubkey = await UserUtils.getOurNumber();
ourLeavingMessage = new ClosedGroupUpdateMessage({
timestamp: Date.now(),
groupId,
identifier: dbMessage.id,
expireTimer: existingExpireTimer,
name: convo.get('name'),
members: convo.get('members').filter(m => m !== ourPubkey.key),
});
}
window.log.info(
`We are leaving the group ${groupId}. Sending our leaving message.`

@ -0,0 +1,51 @@
import { SignalService } from '../../../../../../protobuf';
import {
ClosedGroupMessage,
ClosedGroupMessageParams,
} from './ClosedGroupMessage';
import { fromHexToArray } from '../../../../../utils/String';
export interface ClosedGroupUpdateMessageParams
extends ClosedGroupMessageParams {
name: string;
members: Array<string>;
expireTimer: number;
}
export class ClosedGroupUpdateMessage extends ClosedGroupMessage {
private readonly name: string;
private readonly members: Array<string>;
constructor(params: ClosedGroupUpdateMessageParams) {
super({
timestamp: params.timestamp,
identifier: params.identifier,
groupId: params.groupId,
expireTimer: params.expireTimer,
});
this.name = params.name;
this.members = params.members;
// members can be empty. It means noone is in the group anymore and it happens when an admin leaves the group
if (!params.members) {
throw new Error('Members must be set');
}
if (!params.name || params.name.length === 0) {
throw new Error('Name must cannot be empty');
}
}
public dataProto(): SignalService.DataMessage {
const dataMessage = new SignalService.DataMessage();
dataMessage.closedGroupControlMessage = new SignalService.DataMessage.ClosedGroupControlMessage();
dataMessage.closedGroupControlMessage.type =
SignalService.DataMessage.ClosedGroupControlMessage.Type.UPDATE;
dataMessage.closedGroupControlMessage.name = this.name;
dataMessage.closedGroupControlMessage.members = this.members.map(
fromHexToArray
);
return dataMessage;
}
}

@ -4,3 +4,4 @@ export * from './ClosedGroupNewMessage';
export * from './ClosedGroupAddedMembersMessage';
export * from './ClosedGroupNameChangeMessage';
export * from './ClosedGroupRemovedMembersMessage';
export * from './ClosedGroupUpdateMessage';

2
ts/window.d.ts vendored

@ -59,11 +59,11 @@ declare global {
log: any;
lokiFeatureFlags: {
multiDeviceUnpairing: boolean;
privateGroupChats: boolean;
useOnionRequests: boolean;
useOnionRequestsV2: boolean;
useFileOnionRequests: boolean;
useFileOnionRequestsV2: boolean;
useExplicitGroupUpdatesSending: boolean;
onionRequestHops: number;
};
lokiFileServerAPI: LokiFileServerInstance;

Loading…
Cancel
Save