fix expirationTimer updates closed group desktop to ios

pull/1424/head
Audric Ackermann 5 years ago
parent 58be168227
commit f1d84177a0

@ -392,7 +392,7 @@ function shouldDropBlockedUserMessage(content: SignalService.Content): boolean {
if (!content?.dataMessage?.group?.id) { if (!content?.dataMessage?.group?.id) {
return true; return true;
} }
const groupId = StringUtils.decode(content.dataMessage.group.id, 'utf8'); const groupId = toHex(content.dataMessage.group.id);
const groupConvo = ConversationController.getInstance().get(groupId); const groupConvo = ConversationController.getInstance().get(groupId);
if (!groupConvo) { if (!groupConvo) {

@ -1,4 +1,3 @@
import { ContentMessage } from '../ContentMessage';
import { SignalService } from '../../../../../protobuf'; import { SignalService } from '../../../../../protobuf';
import { MessageParams } from '../../Message'; import { MessageParams } from '../../Message';
import { StringUtils } from '../../../../utils'; import { StringUtils } from '../../../../utils';

@ -1,7 +1,5 @@
import { Constants } from '../../../../..'; import { Constants } from '../../../../..';
import { SignalService } from '../../../../../../protobuf'; import { SignalService } from '../../../../../../protobuf';
import { PubKey } from '../../../../../types';
import { fromHexToArray } from '../../../../../utils/String';
import { import {
ClosedGroupV2Message, ClosedGroupV2Message,
ClosedGroupV2MessageParams, ClosedGroupV2MessageParams,

@ -26,6 +26,13 @@ export abstract class ClosedGroupV2Message extends DataMessage {
} }
} }
public static areAdminsMembers(
admins: Array<string>,
members: Array<string>
) {
return admins.every(a => members.includes(a));
}
public ttl(): number { public ttl(): number {
return TTL_DEFAULT.REGULAR_MESSAGE; return TTL_DEFAULT.REGULAR_MESSAGE;
} }

@ -38,6 +38,10 @@ export class ClosedGroupV2NewMessage extends ClosedGroupV2Message {
if (!params.members || params.members.length === 0) { if (!params.members || params.members.length === 0) {
throw new Error('Members must be set'); throw new Error('Members must be set');
} }
// Assert that every admins is a member
if (!ClosedGroupV2Message.areAdminsMembers(params.admins, params.members)) {
throw new Error('Admins must all be members of the group');
}
if (!params.name || params.name.length === 0) { if (!params.name || params.name.length === 0) {
throw new Error('Name must cannot be empty'); throw new Error('Name must cannot be empty');
} }

@ -98,46 +98,19 @@ export class MessageQueue implements MessageQueueInterface {
} }
let groupId: PubKey | undefined; let groupId: PubKey | undefined;
if (message instanceof TypingMessage) {
groupId = message.groupId;
} else if (message instanceof ExpirationTimerUpdateMessage) {
groupId = message.groupId;
} else if (message instanceof ClosedGroupV2Message) {
groupId = message.groupId;
}
if (!groupId) {
throw new Error('Invalid group message passed in sendToGroup.');
}
// if this is a medium group message. We just need to send to the group pubkey
if ( if (
message instanceof ClosedGroupV2ChatMessage || message instanceof TypingMessage ||
message instanceof ExpirationTimerUpdateMessage ||
message instanceof ClosedGroupV2Message message instanceof ClosedGroupV2Message
) { ) {
return this.send(PubKey.cast(groupId), message, sentCb); groupId = message.groupId;
}
// Get devices in group
let recipients = await GroupUtils.getGroupMembers(groupId);
// Don't send to our own device as they'll likely be synced across.
const ourKey = await UserUtil.getCurrentDevicePubKey();
if (!ourKey) {
throw new Error('Cannot get current user public key');
} }
const ourPrimary = await MultiDeviceProtocol.getPrimaryDevice(ourKey);
recipients = recipients.filter(member => !ourPrimary.isEqual(member));
if (recipients.length === 0) { if (!groupId) {
return; throw new Error('Invalid group message passed in sendToGroup.');
} }
// if groupId is set here, it means it's for a medium group. So send it as it
// Send to all devices of members return this.send(PubKey.cast(groupId), message, sentCb);
await Promise.all(
recipients.map(async recipient =>
this.sendUsingMultiDevice(recipient, message)
)
);
} }
public async sendSyncMessage( public async sendSyncMessage(

@ -1,9 +1,34 @@
import { RawMessage } from '../types/RawMessage'; import { RawMessage } from '../types/RawMessage';
import { ContentMessage } from '../messages/outgoing'; import {
ContentMessage,
ExpirationTimerUpdateMessage,
TypingMessage,
} from '../messages/outgoing';
import { EncryptionType, PubKey } from '../types'; import { EncryptionType, PubKey } from '../types';
import { ClosedGroupV2Message } from '../messages/outgoing/content/data/groupv2/ClosedGroupV2Message'; import { ClosedGroupV2Message } from '../messages/outgoing/content/data/groupv2/ClosedGroupV2Message';
import { ClosedGroupV2NewMessage } from '../messages/outgoing/content/data/groupv2/ClosedGroupV2NewMessage'; import { ClosedGroupV2NewMessage } from '../messages/outgoing/content/data/groupv2/ClosedGroupV2NewMessage';
export function getEncryptionTypeFromMessageType(
message: ContentMessage
): EncryptionType {
// ClosedGroupV2NewMessage is sent using established channels, so using fallback
if (message instanceof ClosedGroupV2NewMessage) {
return EncryptionType.Fallback;
}
// 1. any ClosedGroupV2Message which is not a ClosedGroupV2NewMessage must be encoded with ClosedGroup
// 2. if TypingMessage or ExpirationTimer and groupId is set => must be encoded with ClosedGroup too
if (
message instanceof ClosedGroupV2Message ||
(message instanceof ExpirationTimerUpdateMessage && message.groupId) ||
(message instanceof TypingMessage && message.groupId)
) {
return EncryptionType.ClosedGroup;
} else {
return EncryptionType.Fallback;
}
}
export async function toRawMessage( export async function toRawMessage(
device: PubKey, device: PubKey,
message: ContentMessage message: ContentMessage
@ -13,17 +38,8 @@ export async function toRawMessage(
window?.log?.debug('toRawMessage proto:', message.contentProto()); window?.log?.debug('toRawMessage proto:', message.contentProto());
const plainTextBuffer = message.plainTextBuffer(); const plainTextBuffer = message.plainTextBuffer();
let encryption: EncryptionType; const encryption = getEncryptionTypeFromMessageType(message);
// ClosedGroupV2NewMessage is sent using established channels, so using fallback
if (
message instanceof ClosedGroupV2Message &&
!(message instanceof ClosedGroupV2NewMessage)
) {
encryption = EncryptionType.ClosedGroup;
} else {
encryption = EncryptionType.Fallback;
}
// tslint:disable-next-line: no-unnecessary-local-variable // tslint:disable-next-line: no-unnecessary-local-variable
const rawMessage: RawMessage = { const rawMessage: RawMessage = {
identifier: message.identifier, identifier: message.identifier,

@ -5,6 +5,12 @@ import { MessageUtils } from '../../../../session/utils';
import { EncryptionType, PubKey } from '../../../../session/types'; import { EncryptionType, PubKey } from '../../../../session/types';
import { SessionProtocol } from '../../../../session/protocols'; import { SessionProtocol } from '../../../../session/protocols';
import { ClosedGroupV2ChatMessage } from '../../../../session/messages/outgoing/content/data/groupv2/ClosedGroupV2ChatMessage'; import { ClosedGroupV2ChatMessage } from '../../../../session/messages/outgoing/content/data/groupv2/ClosedGroupV2ChatMessage';
import {
ClosedGroupV2EncryptionPairMessage,
ClosedGroupV2NewMessage,
ClosedGroupV2UpdateMessage,
} from '../../../../session/messages/outgoing';
import { SignalService } from '../../../../protobuf';
// tslint:disable-next-line: no-require-imports no-var-requires // tslint:disable-next-line: no-require-imports no-var-requires
const chaiAsPromised = require('chai-as-promised'); const chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised); chai.use(chaiAsPromised);
@ -115,5 +121,80 @@ describe('Message Utils', () => {
expect(rawMessage.encryption).to.equal(EncryptionType.Fallback); expect(rawMessage.encryption).to.equal(EncryptionType.Fallback);
}); });
it('passing ClosedGroupV2NewMessage returns Fallback', async () => {
const device = TestUtils.generateFakePubKey();
const member = TestUtils.generateFakePubKey().key;
const msg = new ClosedGroupV2NewMessage({
timestamp: Date.now(),
name: 'df',
members: [member],
admins: [member],
groupId: TestUtils.generateFakePubKey().key,
keypair: TestUtils.generateFakeECKeyPair(),
expireTimer: 0,
});
const rawMessage = await MessageUtils.toRawMessage(device, msg);
expect(rawMessage.encryption).to.equal(EncryptionType.Fallback);
});
it('passing ClosedGroupV2UpdateMessage returns ClosedGroup', async () => {
const device = TestUtils.generateFakePubKey();
const msg = new ClosedGroupV2UpdateMessage({
timestamp: Date.now(),
name: 'df',
members: [TestUtils.generateFakePubKey().key],
groupId: TestUtils.generateFakePubKey().key,
expireTimer: 0,
});
const rawMessage = await MessageUtils.toRawMessage(device, msg);
expect(rawMessage.encryption).to.equal(EncryptionType.ClosedGroup);
});
it('passing ClosedGroupV2EncryptionPairMessage returns ClosedGroup', async () => {
const device = TestUtils.generateFakePubKey();
const fakeWrappers = new Array<
SignalService.ClosedGroupUpdateV2.KeyPairWrapper
>();
fakeWrappers.push(
new SignalService.ClosedGroupUpdateV2.KeyPairWrapper({
publicKey: new Uint8Array(8),
encryptedKeyPair: new Uint8Array(8),
})
);
const msg = new ClosedGroupV2EncryptionPairMessage({
timestamp: Date.now(),
groupId: TestUtils.generateFakePubKey().key,
encryptedKeyPairs: fakeWrappers,
expireTimer: 0,
});
const rawMessage = await MessageUtils.toRawMessage(device, msg);
expect(rawMessage.encryption).to.equal(EncryptionType.ClosedGroup);
});
it('passing ClosedGroupV2EncryptionPairMessage returns ClosedGroup', async () => {
const device = TestUtils.generateFakePubKey();
const fakeWrappers = new Array<
SignalService.ClosedGroupUpdateV2.KeyPairWrapper
>();
fakeWrappers.push(
new SignalService.ClosedGroupUpdateV2.KeyPairWrapper({
publicKey: new Uint8Array(8),
encryptedKeyPair: new Uint8Array(8),
})
);
const msg = new ClosedGroupV2EncryptionPairMessage({
timestamp: Date.now(),
groupId: TestUtils.generateFakePubKey().key,
encryptedKeyPairs: fakeWrappers,
expireTimer: 0,
});
const rawMessage = await MessageUtils.toRawMessage(device, msg);
expect(rawMessage.encryption).to.equal(EncryptionType.ClosedGroup);
});
}); });
}); });

@ -1,5 +1,7 @@
import * as crypto from 'crypto'; import * as crypto from 'crypto';
import { ECKeyPair } from '../../../receiver/closedGroupsV2';
import { PubKey } from '../../../session/types'; import { PubKey } from '../../../session/types';
import { fromHexToArray } from '../../../session/utils/String';
export function generateFakePubKey(): PubKey { export function generateFakePubKey(): PubKey {
// Generates a mock pubkey for testing // Generates a mock pubkey for testing
@ -10,6 +12,12 @@ export function generateFakePubKey(): PubKey {
return new PubKey(pubkeyString); return new PubKey(pubkeyString);
} }
export function generateFakeECKeyPair(): ECKeyPair {
const pubkey = generateFakePubKey().toArray();
const privKey = new Uint8Array(crypto.randomBytes(64));
return new ECKeyPair(pubkey, privKey);
}
export function generateFakePubKeys(amount: number): Array<PubKey> { export function generateFakePubKeys(amount: number): Array<PubKey> {
const numPubKeys = amount > 0 ? Math.floor(amount) : 0; const numPubKeys = amount > 0 ? Math.floor(amount) : 0;

Loading…
Cancel
Save