Remove GroupContext proto
Co-authored-by: Scott Nonnenberg <scott@signal.org>
This commit is contained in:
parent
9bfbee464b
commit
68ae25f5cd
16 changed files with 74 additions and 713 deletions
|
@ -47,7 +47,7 @@ import { parseIntOrThrow } from '../util/parseIntOrThrow';
|
|||
import { clearTimeoutIfNecessary } from '../util/clearTimeoutIfNecessary';
|
||||
import { Zone } from '../util/Zone';
|
||||
import { DurationInSeconds } from '../util/durations';
|
||||
import { deriveMasterKeyFromGroupV1, bytesToUuid } from '../Crypto';
|
||||
import { bytesToUuid } from '../Crypto';
|
||||
import type { DownloadedAttachmentType } from '../types/Attachment';
|
||||
import { Address } from '../types/Address';
|
||||
import { QualifiedAddress } from '../types/QualifiedAddress';
|
||||
|
@ -127,7 +127,6 @@ import { inspectUnknownFieldTags } from '../util/inspectProtobufs';
|
|||
import { incrementMessageCounter } from '../util/incrementMessageCounter';
|
||||
import { filterAndClean } from '../types/BodyRange';
|
||||
|
||||
const GROUPV1_ID_LENGTH = 16;
|
||||
const GROUPV2_ID_LENGTH = 32;
|
||||
const RETRY_TIMEOUT = 2 * 60 * 1000;
|
||||
|
||||
|
@ -2007,19 +2006,8 @@ export default class MessageReceiver
|
|||
const message = this.processDecrypted(envelope, msg);
|
||||
const groupId = this.getProcessedGroupId(message);
|
||||
const isBlocked = groupId ? this.isGroupBlocked(groupId) : false;
|
||||
const { source, sourceUuid } = envelope;
|
||||
const ourE164 = this.storage.user.getNumber();
|
||||
const ourUuid = this.storage.user.getCheckedUuid().toString();
|
||||
const isMe =
|
||||
(source && ourE164 && source === ourE164) ||
|
||||
(sourceUuid && ourUuid && sourceUuid === ourUuid);
|
||||
const isLeavingGroup = Boolean(
|
||||
!message.groupV2 &&
|
||||
message.group &&
|
||||
message.group.type === Proto.GroupContext.Type.QUIT
|
||||
);
|
||||
|
||||
if (groupId && isBlocked && !(isMe && isLeavingGroup)) {
|
||||
if (groupId && isBlocked) {
|
||||
log.warn(
|
||||
`Message ${getEnvelopeId(envelope)} ignored; destined for blocked group`
|
||||
);
|
||||
|
@ -2282,19 +2270,8 @@ export default class MessageReceiver
|
|||
const message = this.processDecrypted(envelope, msg.dataMessage);
|
||||
const groupId = this.getProcessedGroupId(message);
|
||||
const isBlocked = groupId ? this.isGroupBlocked(groupId) : false;
|
||||
const { source, sourceUuid } = envelope;
|
||||
const ourE164 = this.storage.user.getNumber();
|
||||
const ourUuid = this.storage.user.getCheckedUuid().toString();
|
||||
const isMe =
|
||||
(source && ourE164 && source === ourE164) ||
|
||||
(sourceUuid && ourUuid && sourceUuid === ourUuid);
|
||||
const isLeavingGroup = Boolean(
|
||||
!message.groupV2 &&
|
||||
message.group &&
|
||||
message.group.type === Proto.GroupContext.Type.QUIT
|
||||
);
|
||||
|
||||
if (groupId && isBlocked && !(isMe && isLeavingGroup)) {
|
||||
if (groupId && isBlocked) {
|
||||
log.warn(
|
||||
`Message ${getEnvelopeId(envelope)} ignored; destined for blocked group`
|
||||
);
|
||||
|
@ -2354,8 +2331,6 @@ export default class MessageReceiver
|
|||
return undefined;
|
||||
}
|
||||
|
||||
this.checkGroupV1Data(msg);
|
||||
|
||||
if (msg.flags && msg.flags & Proto.DataMessage.Flags.END_SESSION) {
|
||||
p = this.handleEndSession(envelope, new UUID(destination));
|
||||
}
|
||||
|
@ -2393,8 +2368,6 @@ export default class MessageReceiver
|
|||
msg.flags & Proto.DataMessage.Flags.EXPIRATION_TIMER_UPDATE
|
||||
) {
|
||||
type = 'expirationTimerUpdate';
|
||||
} else if (msg.group) {
|
||||
type = 'legacyGroupChange';
|
||||
}
|
||||
// Note: other data messages without any of these attributes will fall into the
|
||||
// 'message' bucket - like stickers, gift badges, etc.
|
||||
|
@ -2404,19 +2377,8 @@ export default class MessageReceiver
|
|||
const message = this.processDecrypted(envelope, msg);
|
||||
const groupId = this.getProcessedGroupId(message);
|
||||
const isBlocked = groupId ? this.isGroupBlocked(groupId) : false;
|
||||
const { source, sourceUuid } = envelope;
|
||||
const ourE164 = this.storage.user.getNumber();
|
||||
const ourUuid = this.storage.user.getCheckedUuid().toString();
|
||||
const isMe =
|
||||
(source && ourE164 && source === ourE164) ||
|
||||
(sourceUuid && ourUuid && sourceUuid === ourUuid);
|
||||
const isLeavingGroup = Boolean(
|
||||
!message.groupV2 &&
|
||||
message.group &&
|
||||
message.group.type === Proto.GroupContext.Type.QUIT
|
||||
);
|
||||
|
||||
if (groupId && isBlocked && !(isMe && isLeavingGroup)) {
|
||||
if (groupId && isBlocked) {
|
||||
log.warn(
|
||||
`Message ${getEnvelopeId(envelope)} ignored; destined for blocked group`
|
||||
);
|
||||
|
@ -2780,17 +2742,11 @@ export default class MessageReceiver
|
|||
|
||||
const { groupId, timestamp, action } = typingMessage;
|
||||
|
||||
let groupIdString: string | undefined;
|
||||
let groupV2IdString: string | undefined;
|
||||
if (groupId && groupId.byteLength > 0) {
|
||||
if (groupId.byteLength === GROUPV1_ID_LENGTH) {
|
||||
groupIdString = Bytes.toBinary(groupId);
|
||||
groupV2IdString = this.deriveGroupV2FromV1(groupId);
|
||||
} else if (groupId.byteLength === GROUPV2_ID_LENGTH) {
|
||||
groupV2IdString = Bytes.toBase64(groupId);
|
||||
} else {
|
||||
log.error('handleTypingMessage: Received invalid groupId value');
|
||||
}
|
||||
if (groupId && groupId.byteLength === GROUPV2_ID_LENGTH) {
|
||||
groupV2IdString = Bytes.toBase64(groupId);
|
||||
} else {
|
||||
log.error('handleTypingMessage: Received invalid groupId value');
|
||||
}
|
||||
|
||||
this.dispatchEvent(
|
||||
|
@ -2799,13 +2755,11 @@ export default class MessageReceiver
|
|||
senderUuid: envelope.sourceUuid,
|
||||
senderDevice: envelope.sourceDevice,
|
||||
typing: {
|
||||
groupV2Id: groupV2IdString,
|
||||
typingMessage,
|
||||
timestamp: timestamp?.toNumber() ?? Date.now(),
|
||||
started: action === Proto.TypingMessage.Action.STARTED,
|
||||
stopped: action === Proto.TypingMessage.Action.STOPPED,
|
||||
|
||||
groupId: groupIdString,
|
||||
groupV2Id: groupV2IdString,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
@ -2823,22 +2777,7 @@ export default class MessageReceiver
|
|||
message: Proto.IDataMessage,
|
||||
envelope: ProcessedEnvelope
|
||||
): boolean {
|
||||
const { group, groupV2 } = message;
|
||||
|
||||
if (group) {
|
||||
const { id } = group;
|
||||
strictAssert(id, 'Group data has no id');
|
||||
const isInvalid = id.byteLength !== GROUPV1_ID_LENGTH;
|
||||
|
||||
if (isInvalid) {
|
||||
log.info(
|
||||
'isInvalidGroupData: invalid GroupV1 message from',
|
||||
getEnvelopeId(envelope)
|
||||
);
|
||||
}
|
||||
|
||||
return isInvalid;
|
||||
}
|
||||
const { groupV2 } = message;
|
||||
|
||||
if (groupV2) {
|
||||
const { masterKey } = groupV2;
|
||||
|
@ -2857,46 +2796,12 @@ export default class MessageReceiver
|
|||
return false;
|
||||
}
|
||||
|
||||
private deriveGroupV2FromV1(groupId: Uint8Array): string {
|
||||
if (groupId.byteLength !== GROUPV1_ID_LENGTH) {
|
||||
throw new Error(
|
||||
`deriveGroupV2FromV1: had id with wrong byteLength: ${groupId.byteLength}`
|
||||
);
|
||||
}
|
||||
const masterKey = deriveMasterKeyFromGroupV1(groupId);
|
||||
const data = deriveGroupFields(masterKey);
|
||||
|
||||
return Bytes.toBase64(data.id);
|
||||
}
|
||||
|
||||
private checkGroupV1Data(message: Readonly<Proto.IDataMessage>): void {
|
||||
const { group } = message;
|
||||
|
||||
if (!group) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!group.id) {
|
||||
throw new Error('deriveGroupV1Data: had falsey id');
|
||||
}
|
||||
|
||||
const { id } = group;
|
||||
if (id.byteLength !== GROUPV1_ID_LENGTH) {
|
||||
throw new Error(
|
||||
`deriveGroupV1Data: had id with wrong byteLength: ${id.byteLength}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private getProcessedGroupId(
|
||||
message: ProcessedDataMessage
|
||||
): string | undefined {
|
||||
if (message.groupV2) {
|
||||
return message.groupV2.id;
|
||||
}
|
||||
if (message.group && message.group.id) {
|
||||
return message.group.id;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
@ -2906,9 +2811,6 @@ export default class MessageReceiver
|
|||
const { id } = deriveGroupFields(message.groupV2.masterKey);
|
||||
return Bytes.toBase64(id);
|
||||
}
|
||||
if (message.group && message.group.id) {
|
||||
return Bytes.toBinary(message.group.id);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
@ -2917,10 +2819,6 @@ export default class MessageReceiver
|
|||
if (sentMessage.message && sentMessage.message.groupV2) {
|
||||
return `groupv2(${this.getGroupId(sentMessage.message)})`;
|
||||
}
|
||||
if (sentMessage.message && sentMessage.message.group) {
|
||||
strictAssert(sentMessage.message.group.id, 'group without id');
|
||||
return `group(${this.getGroupId(sentMessage.message)})`;
|
||||
}
|
||||
return sentMessage.destination || sentMessage.destinationUuid;
|
||||
}
|
||||
|
||||
|
@ -2998,8 +2896,6 @@ export default class MessageReceiver
|
|||
return;
|
||||
}
|
||||
|
||||
this.checkGroupV1Data(sentMessage.message);
|
||||
|
||||
strictAssert(sentMessage.timestamp, 'sent message without timestamp');
|
||||
|
||||
log.info(
|
||||
|
@ -3192,19 +3088,13 @@ export default class MessageReceiver
|
|||
|
||||
const { groupId } = sync;
|
||||
|
||||
let groupIdString: string | undefined;
|
||||
let groupV2IdString: string | undefined;
|
||||
if (groupId && groupId.byteLength > 0) {
|
||||
if (groupId.byteLength === GROUPV1_ID_LENGTH) {
|
||||
groupIdString = Bytes.toBinary(groupId);
|
||||
groupV2IdString = this.deriveGroupV2FromV1(groupId);
|
||||
} else if (groupId.byteLength === GROUPV2_ID_LENGTH) {
|
||||
groupV2IdString = Bytes.toBase64(groupId);
|
||||
} else {
|
||||
this.removeFromCache(envelope);
|
||||
log.error('Received message request with invalid groupId');
|
||||
return undefined;
|
||||
}
|
||||
if (groupId && groupId.byteLength === GROUPV2_ID_LENGTH) {
|
||||
groupV2IdString = Bytes.toBase64(groupId);
|
||||
} else {
|
||||
this.removeFromCache(envelope);
|
||||
log.error('Received message request with invalid groupId');
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const ev = new MessageRequestResponseEvent(
|
||||
|
@ -3217,7 +3107,6 @@ export default class MessageReceiver
|
|||
)
|
||||
: undefined,
|
||||
messageRequestResponseType: sync.type,
|
||||
groupId: groupIdString,
|
||||
groupV2Id: groupV2IdString,
|
||||
},
|
||||
this.removeFromCache.bind(this, envelope)
|
||||
|
@ -3583,14 +3472,10 @@ export default class MessageReceiver
|
|||
|
||||
if (blocked.groupIds) {
|
||||
const previous = this.storage.get('blocked-groups', []);
|
||||
const groupV1Ids: Array<string> = [];
|
||||
const groupIds: Array<string> = [];
|
||||
|
||||
blocked.groupIds.forEach(groupId => {
|
||||
if (groupId.byteLength === GROUPV1_ID_LENGTH) {
|
||||
groupV1Ids.push(Bytes.toBinary(groupId));
|
||||
groupIds.push(this.deriveGroupV2FromV1(groupId));
|
||||
} else if (groupId.byteLength === GROUPV2_ID_LENGTH) {
|
||||
if (groupId.byteLength === GROUPV2_ID_LENGTH) {
|
||||
groupIds.push(Bytes.toBase64(groupId));
|
||||
} else {
|
||||
log.error('handleBlocked: Received invalid groupId value');
|
||||
|
@ -3598,18 +3483,15 @@ export default class MessageReceiver
|
|||
});
|
||||
log.info(
|
||||
'handleBlocked: Blocking these groups - v2:',
|
||||
groupIds.map(groupId => `groupv2(${groupId})`),
|
||||
'v1:',
|
||||
groupV1Ids.map(groupId => `group(${groupId})`)
|
||||
groupIds.map(groupId => `groupv2(${groupId})`)
|
||||
);
|
||||
|
||||
const ids = [...groupIds, ...groupV1Ids];
|
||||
await this.storage.put('blocked-groups', ids);
|
||||
await this.storage.put('blocked-groups', groupIds);
|
||||
|
||||
if (!areArraysMatchingSets(previous, ids)) {
|
||||
if (!areArraysMatchingSets(previous, groupIds)) {
|
||||
changed = true;
|
||||
allIdentifiers.push(...previous);
|
||||
allIdentifiers.push(...ids);
|
||||
allIdentifiers.push(...groupIds);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -103,10 +103,6 @@ export type GroupV2InfoType = {
|
|||
revision: number;
|
||||
members: ReadonlyArray<string>;
|
||||
};
|
||||
export type GroupV1InfoType = {
|
||||
id: string;
|
||||
members: ReadonlyArray<string>;
|
||||
};
|
||||
|
||||
type GroupCallUpdateType = {
|
||||
eraId: string;
|
||||
|
@ -207,7 +203,6 @@ export type GroupSendOptionsType = {
|
|||
expireTimer?: DurationInSeconds;
|
||||
flags?: number;
|
||||
groupCallUpdate?: GroupCallUpdateType;
|
||||
groupV1?: GroupV1InfoType;
|
||||
groupV2?: GroupV2InfoType;
|
||||
messageText?: string;
|
||||
preview?: ReadonlyArray<LinkPreviewType>;
|
||||
|
@ -381,10 +376,6 @@ class Message {
|
|||
proto.groupV2.masterKey = this.groupV2.masterKey;
|
||||
proto.groupV2.revision = this.groupV2.revision;
|
||||
proto.groupV2.groupChange = this.groupV2.groupChange || null;
|
||||
} else if (this.group) {
|
||||
proto.group = new Proto.GroupContext();
|
||||
proto.group.id = Bytes.fromString(this.group.id);
|
||||
proto.group.type = this.group.type;
|
||||
}
|
||||
if (this.sticker) {
|
||||
proto.sticker = new Proto.DataMessage.Sticker();
|
||||
|
@ -1106,7 +1097,6 @@ export default class MessageSender {
|
|||
expireTimer,
|
||||
flags,
|
||||
groupCallUpdate,
|
||||
groupV1,
|
||||
groupV2,
|
||||
messageText,
|
||||
preview,
|
||||
|
@ -1118,16 +1108,16 @@ export default class MessageSender {
|
|||
timestamp,
|
||||
} = options;
|
||||
|
||||
if (!groupV1 && !groupV2) {
|
||||
if (!groupV2) {
|
||||
throw new Error(
|
||||
'getAttrsFromGroupOptions: Neither group1 nor groupv2 information provided!'
|
||||
'getAttrsFromGroupOptions: No groupv2 information provided!'
|
||||
);
|
||||
}
|
||||
|
||||
const myE164 = window.textsecure.storage.user.getNumber();
|
||||
const myUuid = window.textsecure.storage.user.getUuid()?.toString();
|
||||
|
||||
const groupMembers = groupV2?.members || groupV1?.members || [];
|
||||
const groupMembers = groupV2?.members || [];
|
||||
|
||||
// We should always have a UUID but have this check just in case we don't.
|
||||
let isNotMe: (recipient: string) => boolean;
|
||||
|
@ -1158,12 +1148,6 @@ export default class MessageSender {
|
|||
flags,
|
||||
groupCallUpdate,
|
||||
groupV2,
|
||||
group: groupV1
|
||||
? {
|
||||
id: groupV1.id,
|
||||
type: Proto.GroupContext.Type.DELIVER,
|
||||
}
|
||||
: undefined,
|
||||
preview,
|
||||
profileKey,
|
||||
quote,
|
||||
|
@ -2424,50 +2408,6 @@ export default class MessageSender {
|
|||
});
|
||||
}
|
||||
|
||||
// GroupV1-only functions; not to be used in the future
|
||||
|
||||
async leaveGroup(
|
||||
groupId: string,
|
||||
groupIdentifiers: Array<string>,
|
||||
options?: SendOptionsType
|
||||
): Promise<CallbackResultType> {
|
||||
const timestamp = Date.now();
|
||||
const proto = new Proto.Content({
|
||||
dataMessage: {
|
||||
group: {
|
||||
id: Bytes.fromString(groupId),
|
||||
type: Proto.GroupContext.Type.QUIT,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
|
||||
|
||||
const contentHint = ContentHint.RESENDABLE;
|
||||
const sendLogCallback =
|
||||
groupIdentifiers.length > 1
|
||||
? this.makeSendLogCallback({
|
||||
contentHint,
|
||||
proto: Buffer.from(Proto.Content.encode(proto).finish()),
|
||||
sendType: 'legacyGroupChange',
|
||||
timestamp,
|
||||
urgent: false,
|
||||
hasPniSignatureMessage: false,
|
||||
})
|
||||
: undefined;
|
||||
|
||||
return this.sendGroupProto({
|
||||
contentHint,
|
||||
groupId: undefined, // only for GV2 ids
|
||||
options,
|
||||
proto,
|
||||
recipients: groupIdentifiers,
|
||||
sendLogCallback,
|
||||
timestamp,
|
||||
urgent: false,
|
||||
});
|
||||
}
|
||||
|
||||
// Simple pass-throughs
|
||||
|
||||
// Note: instead of updating these functions, or adding new ones, remove these and go
|
||||
|
|
12
ts/textsecure/Types.d.ts
vendored
12
ts/textsecure/Types.d.ts
vendored
|
@ -118,17 +118,6 @@ export type ProcessedAttachment = {
|
|||
textAttachment?: Omit<TextAttachmentType, 'preview'>;
|
||||
};
|
||||
|
||||
export type ProcessedGroupContext = {
|
||||
id: string;
|
||||
type: Proto.GroupContext.Type;
|
||||
name?: string;
|
||||
membersE164: ReadonlyArray<string>;
|
||||
avatar?: ProcessedAttachment;
|
||||
|
||||
// Computed fields
|
||||
derivedGroupV2Id: string;
|
||||
};
|
||||
|
||||
export type ProcessedGroupV2Context = {
|
||||
masterKey: string;
|
||||
revision?: number;
|
||||
|
@ -208,7 +197,6 @@ export type ProcessedGiftBadge = {
|
|||
export type ProcessedDataMessage = {
|
||||
body?: string;
|
||||
attachments: ReadonlyArray<ProcessedAttachment>;
|
||||
group?: ProcessedGroupContext;
|
||||
groupV2?: ProcessedGroupV2Context;
|
||||
flags: number;
|
||||
expireTimer: DurationInSeconds;
|
||||
|
|
|
@ -10,12 +10,10 @@ import { dropNull, shallowDropNull } from '../util/dropNull';
|
|||
import { SignalService as Proto } from '../protobuf';
|
||||
import { deriveGroupFields } from '../groups';
|
||||
import * as Bytes from '../Bytes';
|
||||
import { deriveMasterKeyFromGroupV1 } from '../Crypto';
|
||||
|
||||
import type {
|
||||
ProcessedAttachment,
|
||||
ProcessedDataMessage,
|
||||
ProcessedGroupContext,
|
||||
ProcessedGroupV2Context,
|
||||
ProcessedQuote,
|
||||
ProcessedContact,
|
||||
|
@ -25,7 +23,6 @@ import type {
|
|||
ProcessedDelete,
|
||||
ProcessedGiftBadge,
|
||||
} from './Types.d';
|
||||
import { WarnOnlyError } from './Errors';
|
||||
import { GiftBadgeStates } from '../components/conversation/Message';
|
||||
import { APPLICATION_OCTET_STREAM, stringToMIMEType } from '../types/MIME';
|
||||
import { SECOND, DurationInSeconds } from '../util/durations';
|
||||
|
@ -71,39 +68,6 @@ export function processAttachment(
|
|||
};
|
||||
}
|
||||
|
||||
function processGroupContext(
|
||||
group?: Proto.IGroupContext | null
|
||||
): ProcessedGroupContext | undefined {
|
||||
if (!group) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
strictAssert(group.id, 'group context without id');
|
||||
strictAssert(group.type != null, 'group context without type');
|
||||
|
||||
const masterKey = deriveMasterKeyFromGroupV1(group.id);
|
||||
const data = deriveGroupFields(masterKey);
|
||||
|
||||
const derivedGroupV2Id = Bytes.toBase64(data.id);
|
||||
|
||||
const result: ProcessedGroupContext = {
|
||||
id: Bytes.toBinary(group.id),
|
||||
type: group.type,
|
||||
name: dropNull(group.name),
|
||||
membersE164: group.membersE164 ?? [],
|
||||
avatar: processAttachment(group.avatar),
|
||||
derivedGroupV2Id,
|
||||
};
|
||||
|
||||
if (result.type === Proto.GroupContext.Type.DELIVER) {
|
||||
result.name = undefined;
|
||||
result.membersE164 = [];
|
||||
result.avatar = undefined;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function processGroupV2Context(
|
||||
groupV2?: Proto.IGroupContextV2 | null
|
||||
): ProcessedGroupV2Context | undefined {
|
||||
|
@ -331,7 +295,6 @@ export function processDataMessage(
|
|||
attachments: (message.attachments ?? []).map(
|
||||
(attachment: Proto.IAttachmentPointer) => processAttachment(attachment)
|
||||
),
|
||||
group: processGroupContext(message.group),
|
||||
groupV2: processGroupV2Context(message.groupV2),
|
||||
flags: message.flags ?? 0,
|
||||
expireTimer: DurationInSeconds.fromSeconds(message.expireTimer ?? 0),
|
||||
|
@ -375,7 +338,6 @@ export function processDataMessage(
|
|||
if (isEndSession) {
|
||||
result.body = undefined;
|
||||
result.attachments = [];
|
||||
result.group = undefined;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -389,27 +351,6 @@ export function processDataMessage(
|
|||
throw new Error(`Unknown flags in message: ${result.flags}`);
|
||||
}
|
||||
|
||||
if (result.group) {
|
||||
switch (result.group.type) {
|
||||
case Proto.GroupContext.Type.UPDATE:
|
||||
result.body = undefined;
|
||||
result.attachments = [];
|
||||
break;
|
||||
case Proto.GroupContext.Type.QUIT:
|
||||
result.body = undefined;
|
||||
result.attachments = [];
|
||||
break;
|
||||
case Proto.GroupContext.Type.DELIVER:
|
||||
// Cleaned up in `processGroupContext`
|
||||
break;
|
||||
default: {
|
||||
throw new WarnOnlyError(
|
||||
`Unknown group message type: ${result.group.type}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const attachmentCount = result.attachments.length;
|
||||
if (attachmentCount > ATTACHMENT_MAX) {
|
||||
throw new Error(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue