feat: added strings for groupv2 control message and components for them
parent
c9b2d69a73
commit
dbe94f2293
@ -0,0 +1,31 @@
|
||||
import { GroupPubkeyType } from 'libsession_util_nodejs';
|
||||
import { SignalService } from '../../../../../protobuf';
|
||||
import { DataMessage } from '../../DataMessage';
|
||||
import { MessageParams } from '../../Message';
|
||||
|
||||
export interface GroupUpdateMessageParams extends MessageParams {
|
||||
groupPk: GroupPubkeyType;
|
||||
}
|
||||
|
||||
export abstract class GroupUpdateMessage extends DataMessage {
|
||||
public readonly groupPk: GroupUpdateMessageParams['groupPk'];
|
||||
|
||||
constructor(params: GroupUpdateMessageParams) {
|
||||
super(params);
|
||||
|
||||
this.groupPk = params.groupPk;
|
||||
if (!this.groupPk || this.groupPk.length === 0) {
|
||||
throw new Error('groupPk must be set');
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract updateProto(): SignalService.GroupUpdateMessage;
|
||||
|
||||
public dataProto(): SignalService.DataMessage {
|
||||
const groupUpdateMessage = this.updateProto();
|
||||
return new SignalService.DataMessage({ groupUpdateMessage });
|
||||
}
|
||||
|
||||
public abstract isFor1o1Swarm(): boolean;
|
||||
public abstract isForGroupSwarm(): boolean;
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
import { PubkeyType } from 'libsession_util_nodejs';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { SignalService } from '../../../../../../protobuf';
|
||||
import { GroupUpdateMessage, GroupUpdateMessageParams } from '../GroupUpdateMessage';
|
||||
|
||||
type Params = GroupUpdateMessageParams & {
|
||||
memberSessionIds: Array<PubkeyType>;
|
||||
adminSignature: Uint8Array; // this is a signature of `"DELETE_CONTENT" || timestamp || sessionId[0] || ... || sessionId[N]`
|
||||
};
|
||||
|
||||
/**
|
||||
* GroupUpdateDeleteMemberContentMessage is sent as a message to group's swarm.
|
||||
*/
|
||||
export class GroupUpdateDeleteMemberContentMessage extends GroupUpdateMessage {
|
||||
public readonly memberSessionIds: Params['memberSessionIds'];
|
||||
public readonly adminSignature: Params['adminSignature'];
|
||||
|
||||
constructor(params: Params) {
|
||||
super(params);
|
||||
|
||||
this.adminSignature = params.adminSignature;
|
||||
this.memberSessionIds = params.memberSessionIds;
|
||||
if (isEmpty(this.memberSessionIds)) {
|
||||
throw new Error('GroupUpdateDeleteMemberContentMessage needs members in list');
|
||||
}
|
||||
}
|
||||
|
||||
protected updateProto(): SignalService.GroupUpdateMessage {
|
||||
const deleteMemberContent = new SignalService.GroupUpdateDeleteMemberContentMessage({
|
||||
adminSignature: this.adminSignature,
|
||||
memberSessionIds: this.memberSessionIds,
|
||||
});
|
||||
|
||||
return new SignalService.GroupUpdateMessage({
|
||||
deleteMemberContent,
|
||||
});
|
||||
}
|
||||
|
||||
public isForGroupSwarm(): boolean {
|
||||
return true;
|
||||
}
|
||||
public isFor1o1Swarm(): boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
import { isEmpty, isFinite } from 'lodash';
|
||||
import { SignalService } from '../../../../../../protobuf';
|
||||
import { GroupUpdateMessage, GroupUpdateMessageParams } from '../GroupUpdateMessage';
|
||||
|
||||
type NameChangeParams = GroupUpdateMessageParams & {
|
||||
typeOfChange: SignalService.GroupUpdateInfoChangeMessage.Type.NAME;
|
||||
updatedName: string;
|
||||
};
|
||||
|
||||
type AvatarChangeParams = GroupUpdateMessageParams & {
|
||||
typeOfChange: SignalService.GroupUpdateInfoChangeMessage.Type.AVATAR;
|
||||
};
|
||||
|
||||
type DisappearingMessageChangeParams = GroupUpdateMessageParams & {
|
||||
typeOfChange: SignalService.GroupUpdateInfoChangeMessage.Type.DISAPPEARING_MESSAGES;
|
||||
updatedExpirationSeconds: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* GroupUpdateInfoChangeMessage is sent as a message to group's swarm.
|
||||
*/
|
||||
export class GroupUpdateInfoChangeMessage extends GroupUpdateMessage {
|
||||
public readonly typeOfChange: SignalService.GroupUpdateInfoChangeMessage.Type;
|
||||
public readonly updatedName: string = '';
|
||||
public readonly updatedExpirationSeconds: number = 0;
|
||||
|
||||
constructor(params: NameChangeParams | AvatarChangeParams | DisappearingMessageChangeParams) {
|
||||
super(params);
|
||||
const types = SignalService.GroupUpdateInfoChangeMessage.Type;
|
||||
|
||||
this.typeOfChange = params.typeOfChange;
|
||||
|
||||
switch (params.typeOfChange) {
|
||||
case types.NAME: {
|
||||
if (isEmpty(params.updatedName)) {
|
||||
throw new Error('A group needs a name');
|
||||
}
|
||||
this.updatedName = params.updatedName;
|
||||
break;
|
||||
}
|
||||
case types.AVATAR:
|
||||
// nothing to do for avatar
|
||||
break;
|
||||
case types.DISAPPEARING_MESSAGES: {
|
||||
if (!isFinite(params.updatedExpirationSeconds) || params.updatedExpirationSeconds < 0) {
|
||||
throw new Error('Invalid disappearing message timer. Must be finite and >=0');
|
||||
}
|
||||
this.updatedExpirationSeconds = params.updatedExpirationSeconds;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected updateProto(): SignalService.GroupUpdateMessage {
|
||||
const infoChangeMessage = new SignalService.GroupUpdateInfoChangeMessage({
|
||||
type: this.typeOfChange,
|
||||
});
|
||||
|
||||
if (this.typeOfChange === SignalService.GroupUpdateInfoChangeMessage.Type.NAME) {
|
||||
infoChangeMessage.updatedName = this.updatedName;
|
||||
}
|
||||
if (
|
||||
this.typeOfChange === SignalService.GroupUpdateInfoChangeMessage.Type.DISAPPEARING_MESSAGES
|
||||
) {
|
||||
infoChangeMessage.updatedExpiration = this.updatedExpirationSeconds;
|
||||
}
|
||||
|
||||
return new SignalService.GroupUpdateMessage({
|
||||
infoChangeMessage,
|
||||
});
|
||||
}
|
||||
|
||||
public isForGroupSwarm(): boolean {
|
||||
return true;
|
||||
}
|
||||
public isFor1o1Swarm(): boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
import { SignalService } from '../../../../../../protobuf';
|
||||
import { getOurProfile } from '../../../../../utils/User';
|
||||
import { GroupUpdateMessage, GroupUpdateMessageParams } from '../GroupUpdateMessage';
|
||||
|
||||
type Params = GroupUpdateMessageParams & {
|
||||
isApproved: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* GroupUpdateInviteResponseMessage is sent to the group's swarm.
|
||||
* Our pubkey, as the leaving member is part of the encryption of libsession for the new groups
|
||||
*
|
||||
*/
|
||||
export class GroupUpdateInviteResponseMessage extends GroupUpdateMessage {
|
||||
public readonly isApproved: Params['isApproved'];
|
||||
constructor(params: Params) {
|
||||
super(params);
|
||||
this.isApproved = params.isApproved;
|
||||
}
|
||||
|
||||
protected updateProto(): SignalService.GroupUpdateMessage {
|
||||
const ourProfile = getOurProfile();
|
||||
|
||||
const inviteResponse = new SignalService.GroupUpdateInviteResponseMessage({
|
||||
isApproved: true,
|
||||
profileKey: ourProfile?.profileKey,
|
||||
profile: ourProfile
|
||||
? {
|
||||
displayName: ourProfile.displayName,
|
||||
profilePicture: ourProfile.avatarPointer,
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
|
||||
return new SignalService.GroupUpdateMessage({
|
||||
inviteResponse,
|
||||
});
|
||||
}
|
||||
|
||||
public isForGroupSwarm(): boolean {
|
||||
return true;
|
||||
}
|
||||
public isFor1o1Swarm(): boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
import { PubkeyType } from 'libsession_util_nodejs';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { SignalService } from '../../../../../../protobuf';
|
||||
import { assertUnreachable } from '../../../../../../types/sqlSharedTypes';
|
||||
import { GroupUpdateMessage, GroupUpdateMessageParams } from '../GroupUpdateMessage';
|
||||
|
||||
type MembersAddedMessageParams = GroupUpdateMessageParams & {
|
||||
typeOfChange: SignalService.GroupUpdateMemberChangeMessage.Type.ADDED;
|
||||
added: Array<PubkeyType>;
|
||||
};
|
||||
|
||||
type MembersRemovedMessageParams = GroupUpdateMessageParams & {
|
||||
typeOfChange: SignalService.GroupUpdateMemberChangeMessage.Type.REMOVED;
|
||||
removed: Array<PubkeyType>;
|
||||
};
|
||||
|
||||
type MembersPromotedMessageParams = GroupUpdateMessageParams & {
|
||||
typeOfChange: SignalService.GroupUpdateMemberChangeMessage.Type.PROMOTED;
|
||||
promoted: Array<PubkeyType>;
|
||||
};
|
||||
|
||||
/**
|
||||
* GroupUpdateInfoChangeMessage is sent to the group's swarm.
|
||||
*/
|
||||
export class GroupUpdateMemberChangeMessage extends GroupUpdateMessage {
|
||||
public readonly typeOfChange: SignalService.GroupUpdateMemberChangeMessage.Type;
|
||||
public readonly memberSessionIds: Array<PubkeyType> = []; // added, removed, promoted based on the type.
|
||||
|
||||
constructor(
|
||||
params: MembersAddedMessageParams | MembersRemovedMessageParams | MembersPromotedMessageParams
|
||||
) {
|
||||
super(params);
|
||||
const { Type } = SignalService.GroupUpdateMemberChangeMessage;
|
||||
const { typeOfChange } = params;
|
||||
|
||||
this.typeOfChange = typeOfChange;
|
||||
|
||||
switch (typeOfChange) {
|
||||
case Type.ADDED: {
|
||||
if (isEmpty(params.added)) {
|
||||
throw new Error('added members list cannot be empty');
|
||||
}
|
||||
this.memberSessionIds = params.added;
|
||||
break;
|
||||
}
|
||||
case Type.REMOVED: {
|
||||
if (isEmpty(params.removed)) {
|
||||
throw new Error('removed members list cannot be empty');
|
||||
}
|
||||
this.memberSessionIds = params.removed;
|
||||
break;
|
||||
}
|
||||
case Type.PROMOTED: {
|
||||
if (isEmpty(params.promoted)) {
|
||||
throw new Error('promoted members list cannot be empty');
|
||||
}
|
||||
this.memberSessionIds = params.promoted;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assertUnreachable(typeOfChange, 'unhandled switch case');
|
||||
}
|
||||
}
|
||||
|
||||
protected updateProto(): SignalService.GroupUpdateMessage {
|
||||
const memberChangeMessage = new SignalService.GroupUpdateMemberChangeMessage({
|
||||
type: this.typeOfChange,
|
||||
memberSessionIds: this.memberSessionIds,
|
||||
});
|
||||
|
||||
return new SignalService.GroupUpdateMessage({
|
||||
memberChangeMessage,
|
||||
});
|
||||
}
|
||||
|
||||
public isForGroupSwarm(): boolean {
|
||||
return true;
|
||||
}
|
||||
public isFor1o1Swarm(): boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
import { SignalService } from '../../../../../../protobuf';
|
||||
import { GroupUpdateMessage } from '../GroupUpdateMessage';
|
||||
|
||||
/**
|
||||
* GroupUpdateMemberLeftMessage is sent to the group's swarm.
|
||||
* Our pubkey, as the leaving member is part of the encryption of libsession for the new groups
|
||||
*
|
||||
*/
|
||||
export class GroupUpdateMemberLeftMessage extends GroupUpdateMessage {
|
||||
protected updateProto(): SignalService.GroupUpdateMessage {
|
||||
const memberLeftMessage = new SignalService.GroupUpdateMemberLeftMessage({});
|
||||
|
||||
return new SignalService.GroupUpdateMessage({
|
||||
memberLeftMessage,
|
||||
});
|
||||
}
|
||||
|
||||
public isForGroupSwarm(): boolean {
|
||||
return true;
|
||||
}
|
||||
public isFor1o1Swarm(): boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
import { SignalService } from '../../../../../../protobuf';
|
||||
import { GroupUpdateMessage, GroupUpdateMessageParams } from '../GroupUpdateMessage';
|
||||
|
||||
interface Params extends GroupUpdateMessageParams {
|
||||
adminSignature: Uint8Array; // this is a signature of `"DELETE" || sessionId || timestamp `
|
||||
}
|
||||
|
||||
/**
|
||||
* GroupUpdateDeleteMessage is sent as a 1o1 message to the recipient, not through the group's swarm.
|
||||
*/
|
||||
export class GroupUpdateDeleteMessage extends GroupUpdateMessage {
|
||||
public readonly adminSignature: Params['adminSignature'];
|
||||
|
||||
constructor(params: Params) {
|
||||
super(params);
|
||||
|
||||
this.adminSignature = params.adminSignature;
|
||||
}
|
||||
|
||||
protected updateProto(): SignalService.GroupUpdateMessage {
|
||||
const deleteMessage = new SignalService.GroupUpdateDeleteMessage({
|
||||
groupSessionId: this.groupPk,
|
||||
adminSignature: this.adminSignature,
|
||||
});
|
||||
return new SignalService.GroupUpdateMessage({ deleteMessage });
|
||||
}
|
||||
|
||||
public isForGroupSwarm(): boolean {
|
||||
return false;
|
||||
}
|
||||
public isFor1o1Swarm(): boolean {
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
import { SignalService } from '../../../../../../protobuf';
|
||||
import { UserUtils } from '../../../../../utils';
|
||||
import { GroupUpdateMessage, GroupUpdateMessageParams } from '../GroupUpdateMessage';
|
||||
|
||||
interface Params extends GroupUpdateMessageParams {
|
||||
groupName: string;
|
||||
adminSignature: Uint8Array; // this is a signature of `"INVITE" || inviteeSessionId || timestamp`
|
||||
memberAuthData: Uint8Array;
|
||||
}
|
||||
|
||||
/**
|
||||
* GroupUpdateInviteMessage is sent as a 1o1 message to the recipient, not through the group's swarm.
|
||||
*/
|
||||
export class GroupUpdateInviteMessage extends GroupUpdateMessage {
|
||||
public readonly groupName: Params['groupName'];
|
||||
public readonly adminSignature: Params['adminSignature'];
|
||||
public readonly memberAuthData: Params['memberAuthData'];
|
||||
|
||||
constructor(params: Params) {
|
||||
super({
|
||||
timestamp: params.timestamp,
|
||||
identifier: params.identifier,
|
||||
groupPk: params.groupPk,
|
||||
});
|
||||
|
||||
this.groupName = params.groupName;
|
||||
this.adminSignature = params.adminSignature;
|
||||
this.memberAuthData = params.memberAuthData;
|
||||
}
|
||||
|
||||
protected updateProto(): SignalService.GroupUpdateMessage {
|
||||
const ourProfile = UserUtils.getOurProfile();
|
||||
const inviteMessage = new SignalService.GroupUpdateInviteMessage({
|
||||
groupSessionId: this.groupPk,
|
||||
name: this.groupName,
|
||||
adminSignature: this.adminSignature,
|
||||
memberAuthData: this.memberAuthData,
|
||||
profile: ourProfile
|
||||
? { displayName: ourProfile.displayName, profilePicture: ourProfile.avatarPointer }
|
||||
: undefined,
|
||||
profileKey: ourProfile?.profileKey,
|
||||
});
|
||||
return new SignalService.GroupUpdateMessage({ inviteMessage });
|
||||
}
|
||||
|
||||
public isForGroupSwarm(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
public isFor1o1Swarm(): boolean {
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
import { GroupPubkeyType } from 'libsession_util_nodejs';
|
||||
import { SignalService } from '../../../../../../protobuf';
|
||||
import { GroupUpdateMessage, GroupUpdateMessageParams } from '../GroupUpdateMessage';
|
||||
|
||||
interface Params extends GroupUpdateMessageParams {
|
||||
groupPk: GroupPubkeyType;
|
||||
groupIdentitySeed: Uint8Array;
|
||||
}
|
||||
|
||||
/**
|
||||
* GroupUpdateDeleteMessage is sent as a 1o1 message to the recipient, not through the group's swarm.
|
||||
*/
|
||||
export class GroupUpdatePromoteMessage extends GroupUpdateMessage {
|
||||
public readonly groupIdentitySeed: Params['groupIdentitySeed'];
|
||||
|
||||
constructor(params: Params) {
|
||||
super(params);
|
||||
|
||||
this.groupIdentitySeed = params.groupIdentitySeed;
|
||||
if (!this.groupIdentitySeed || this.groupIdentitySeed.length !== 32) {
|
||||
throw new Error('groupIdentitySeed must be set');
|
||||
}
|
||||
}
|
||||
|
||||
protected updateProto(): SignalService.GroupUpdateMessage {
|
||||
const promoteMessage = new SignalService.GroupUpdatePromoteMessage({
|
||||
groupIdentitySeed: this.groupIdentitySeed,
|
||||
});
|
||||
|
||||
return new SignalService.GroupUpdateMessage({ promoteMessage });
|
||||
}
|
||||
|
||||
public isForGroupSwarm(): boolean {
|
||||
return false;
|
||||
}
|
||||
public isFor1o1Swarm(): boolean {
|
||||
return true;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue