diff --git a/ts/session/types/ClosedGroup.ts b/ts/session/types/ClosedGroup.ts new file mode 100644 index 000000000..0eddf992b --- /dev/null +++ b/ts/session/types/ClosedGroup.ts @@ -0,0 +1,134 @@ + + +// This is the (Closed | Medium) Group equivalent to the SessionGroup type. + +import { PubKey } from '.'; +import { UserUtil } from '../../util'; + +enum ClosedGroupType { + SMALL, + MEDIUM, +} + +interface ClosedGroupParams { + id: PubKey; + type: ClosedGroupType; + admins: Array; + members: Array; +} + +class ClosedGroup { + public readonly id: PubKey; + public readonly type: ClosedGroupType; + public admins: Array; + public members: Array; + + constructor(params: ClosedGroupParams) { + this.id = params.id; + this.type = params.type; + this.admins = params.admins; + this.members = params.members; + } + + public static async create(name: string, type: ClosedGroupType, members: Array, onSuccess: any): Promise { + const { ConversationController, StringView, libsignal } = window; + + // Manage small group size + // TODO - Eventually we want to default to MediumGroups and abandon regular groups + // once medium groups have been thoroughly tested + if ( + type === ClosedGroupType.SMALL && + members.length === 0 || + members.length >= window.CONSTANTS.SMALL_GROUP_SIZE_LIMIT + ) { + console.warn(`ClosedGroup create: Cannot create a small group with more than ${window.CONSTANTS.SMALL_GROUP_SIZE_LIMIT} members`); + } + + const primaryDevice = UserUtil.getCurrentPrimaryDevicePubKey(); + const allMembers = [primaryDevice, ...members]; + + // Create Group Identity + const identityKeys = await libsignal.KeyHelper.generateIdentityKeyPair(); + + const keypair = await libsignal.KeyHelper.generateIdentityKeyPair(); + const id = StringView.arrayBufferToHex(keypair.pubKey); + + // Medium groups + const senderKey = (type === ClosedGroupType.MEDIUM) + ? await window.SenderKeyAPI.createSenderKeyForGroup(id, primaryDevice) + : undefined; + + const secretKey = (type === ClosedGroupType.MEDIUM) + ? identityKeys.privKey + : undefined; + + const groupSecretKeyHex = StringView.arrayBufferToHex( + identityKeys.privKey + ); + + const ev = { + groupDetails: { + id, + name, + members: allMembers, + recipients: allMembers, + active: true, + expireTimer: 0, + avatar: '', + secretKey, + senderKey, + is_medium_group: type === ClosedGroupType.MEDIUM, + }, + confirm: () => null, + }; + + await window.NewReceiver.onGroupReceived(ev); + } + + public static get(id: PubKey): ClosedGroup | undefined { + // Gets a closed group from its group id + return; + } + + public update(): Promise> { + // + } + + public updateMembers(): Promise> { + // Abstraction on update + + // Update the conversation and this object + } + + public async removeMembers(): Promise> { + // Abstraction on updateMembers + } + + public async addMembers(): Promise> { + // Abstraction on updateMembers + } + + public async setName(): Promise { + // Set or update the name of the group + } + + public leave() { + // Leave group + } + + + // static from(groupId) { + // // Returns a new instance from a groupId if it's valid + // const groupIdAsPubKey = groupId instanceof _1.PubKey + // ? groupId + // : _1.PubKey.from(groupId); + // openGroupParams = { + // groupId: + // }; + // return new SessionGroup(openGroupParams); + // } + + +} + + diff --git a/ts/test/session/sending/MessageSender_test.ts b/ts/test/session/sending/MessageSender_test.ts index 1a6e33ee0..ccc729c29 100644 --- a/ts/test/session/sending/MessageSender_test.ts +++ b/ts/test/session/sending/MessageSender_test.ts @@ -49,6 +49,7 @@ describe('MessageSender', () => { [string, Uint8Array, number, number], Promise >(); + TestUtils.stubWindow('lokiMessageAPI', { sendMessage: lokiMessageAPISendStub, }); diff --git a/ts/util/user.ts b/ts/util/user.ts index cea991b17..bacaefb69 100644 --- a/ts/util/user.ts +++ b/ts/util/user.ts @@ -10,6 +10,15 @@ export async function getCurrentDevicePubKey(): Promise { return item.value.split('.')[0]; } +export async function getCurrentPrimaryDevicePubKey(): Promise { + const item = await getItemById('primaryDevicePubKey'); + if (!item || !item.value) { + return undefined; + } + + return item.value; +} + export async function getIdentityKeyPair(): Promise { const item = await getItemById('identityKey');