mirror of
https://github.com/oxen-io/session-desktop.git
synced 2023-12-14 02:12:57 +01:00
fix expirationTimer updates closed group desktop to ios
This commit is contained in:
parent
58be168227
commit
f1d84177a0
9 changed files with 135 additions and 49 deletions
|
@ -392,7 +392,7 @@ function shouldDropBlockedUserMessage(content: SignalService.Content): boolean {
|
|||
if (!content?.dataMessage?.group?.id) {
|
||||
return true;
|
||||
}
|
||||
const groupId = StringUtils.decode(content.dataMessage.group.id, 'utf8');
|
||||
const groupId = toHex(content.dataMessage.group.id);
|
||||
|
||||
const groupConvo = ConversationController.getInstance().get(groupId);
|
||||
if (!groupConvo) {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { ContentMessage } from '../ContentMessage';
|
||||
import { SignalService } from '../../../../../protobuf';
|
||||
import { MessageParams } from '../../Message';
|
||||
import { StringUtils } from '../../../../utils';
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import { Constants } from '../../../../..';
|
||||
import { SignalService } from '../../../../../../protobuf';
|
||||
import { PubKey } from '../../../../../types';
|
||||
import { fromHexToArray } from '../../../../../utils/String';
|
||||
import {
|
||||
ClosedGroupV2Message,
|
||||
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 {
|
||||
return TTL_DEFAULT.REGULAR_MESSAGE;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,10 @@ export class ClosedGroupV2NewMessage extends ClosedGroupV2Message {
|
|||
if (!params.members || params.members.length === 0) {
|
||||
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) {
|
||||
throw new Error('Name must cannot be empty');
|
||||
}
|
||||
|
|
|
@ -98,46 +98,19 @@ export class MessageQueue implements MessageQueueInterface {
|
|||
}
|
||||
|
||||
let groupId: PubKey | undefined;
|
||||
if (message instanceof TypingMessage) {
|
||||
groupId = message.groupId;
|
||||
} else if (message instanceof ExpirationTimerUpdateMessage) {
|
||||
groupId = message.groupId;
|
||||
} else if (message instanceof ClosedGroupV2Message) {
|
||||
if (
|
||||
message instanceof TypingMessage ||
|
||||
message instanceof ExpirationTimerUpdateMessage ||
|
||||
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 (
|
||||
message instanceof ClosedGroupV2ChatMessage ||
|
||||
message instanceof ClosedGroupV2Message
|
||||
) {
|
||||
return this.send(PubKey.cast(groupId), message, sentCb);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Send to all devices of members
|
||||
await Promise.all(
|
||||
recipients.map(async recipient =>
|
||||
this.sendUsingMultiDevice(recipient, message)
|
||||
)
|
||||
);
|
||||
// if groupId is set here, it means it's for a medium group. So send it as it
|
||||
return this.send(PubKey.cast(groupId), message, sentCb);
|
||||
}
|
||||
|
||||
public async sendSyncMessage(
|
||||
|
|
|
@ -1,9 +1,34 @@
|
|||
import { RawMessage } from '../types/RawMessage';
|
||||
import { ContentMessage } from '../messages/outgoing';
|
||||
import {
|
||||
ContentMessage,
|
||||
ExpirationTimerUpdateMessage,
|
||||
TypingMessage,
|
||||
} from '../messages/outgoing';
|
||||
import { EncryptionType, PubKey } from '../types';
|
||||
import { ClosedGroupV2Message } from '../messages/outgoing/content/data/groupv2/ClosedGroupV2Message';
|
||||
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(
|
||||
device: PubKey,
|
||||
message: ContentMessage
|
||||
|
@ -13,17 +38,8 @@ export async function toRawMessage(
|
|||
window?.log?.debug('toRawMessage proto:', message.contentProto());
|
||||
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
|
||||
const rawMessage: RawMessage = {
|
||||
identifier: message.identifier,
|
||||
|
|
|
@ -5,6 +5,12 @@ import { MessageUtils } from '../../../../session/utils';
|
|||
import { EncryptionType, PubKey } from '../../../../session/types';
|
||||
import { SessionProtocol } from '../../../../session/protocols';
|
||||
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
|
||||
const chaiAsPromised = require('chai-as-promised');
|
||||
chai.use(chaiAsPromised);
|
||||
|
@ -115,5 +121,80 @@ describe('Message Utils', () => {
|
|||
|
||||
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 { ECKeyPair } from '../../../receiver/closedGroupsV2';
|
||||
import { PubKey } from '../../../session/types';
|
||||
import { fromHexToArray } from '../../../session/utils/String';
|
||||
|
||||
export function generateFakePubKey(): PubKey {
|
||||
// Generates a mock pubkey for testing
|
||||
|
@ -10,6 +12,12 @@ export function generateFakePubKey(): PubKey {
|
|||
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> {
|
||||
const numPubKeys = amount > 0 ? Math.floor(amount) : 0;
|
||||
|
||||
|
|
Loading…
Reference in a new issue