Group Description: Edit/Receive
This commit is contained in:
parent
e5d365dfc4
commit
9705f464be
29 changed files with 859 additions and 149 deletions
133
ts/groups.ts
133
ts/groups.ts
|
@ -178,6 +178,10 @@ export type GroupV2AdminApprovalRemoveOneChangeType = {
|
|||
conversationId: string;
|
||||
inviter?: string;
|
||||
};
|
||||
export type GroupV2DescriptionChangeType = {
|
||||
type: 'description';
|
||||
removed?: boolean;
|
||||
};
|
||||
|
||||
export type GroupV2ChangeDetailType =
|
||||
| GroupV2AccessAttributesChangeType
|
||||
|
@ -187,9 +191,10 @@ export type GroupV2ChangeDetailType =
|
|||
| GroupV2AdminApprovalAddOneChangeType
|
||||
| GroupV2AdminApprovalRemoveOneChangeType
|
||||
| GroupV2AvatarChangeType
|
||||
| GroupV2DescriptionChangeType
|
||||
| GroupV2GroupLinkAddChangeType
|
||||
| GroupV2GroupLinkResetChangeType
|
||||
| GroupV2GroupLinkRemoveChangeType
|
||||
| GroupV2GroupLinkResetChangeType
|
||||
| GroupV2MemberAddChangeType
|
||||
| GroupV2MemberAddFromAdminApprovalChangeType
|
||||
| GroupV2MemberAddFromInviteChangeType
|
||||
|
@ -251,12 +256,13 @@ type UploadedAvatarType = {
|
|||
|
||||
export const MASTER_KEY_LENGTH = 32;
|
||||
const GROUP_TITLE_MAX_ENCRYPTED_BYTES = 1024;
|
||||
const GROUP_DESC_MAX_ENCRYPTED_BYTES = 8192;
|
||||
export const ID_V1_LENGTH = 16;
|
||||
export const ID_LENGTH = 32;
|
||||
const TEMPORAL_AUTH_REJECTED_CODE = 401;
|
||||
const GROUP_ACCESS_DENIED_CODE = 403;
|
||||
const GROUP_NONEXISTENT_CODE = 404;
|
||||
const SUPPORTED_CHANGE_EPOCH = 1;
|
||||
const SUPPORTED_CHANGE_EPOCH = 2;
|
||||
export const LINK_VERSION_ERROR = 'LINK_VERSION_ERROR';
|
||||
const GROUP_INVITE_LINK_PASSWORD_LENGTH = 16;
|
||||
|
||||
|
@ -415,6 +421,25 @@ function buildGroupTitleBuffer(
|
|||
return result;
|
||||
}
|
||||
|
||||
function buildGroupDescriptionBuffer(
|
||||
clientZkGroupCipher: ClientZkGroupCipher,
|
||||
description: string
|
||||
): ArrayBuffer {
|
||||
const attrsBlob = new window.textsecure.protobuf.GroupAttributeBlob();
|
||||
attrsBlob.descriptionText = description;
|
||||
const attrsBlobPlaintext = attrsBlob.toArrayBuffer();
|
||||
|
||||
const result = encryptGroupBlob(clientZkGroupCipher, attrsBlobPlaintext);
|
||||
|
||||
if (result.byteLength > GROUP_DESC_MAX_ENCRYPTED_BYTES) {
|
||||
throw new Error(
|
||||
'buildGroupDescriptionBuffer: encrypted group title is too long'
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function buildGroupProto(
|
||||
attributes: Pick<
|
||||
ConversationAttributesType,
|
||||
|
@ -716,6 +741,7 @@ export async function buildUpdateAttributesChange(
|
|||
>,
|
||||
attributes: Readonly<{
|
||||
avatar?: undefined | ArrayBuffer;
|
||||
description?: string;
|
||||
title?: string;
|
||||
}>
|
||||
): Promise<undefined | GroupChangeClass.Actions> {
|
||||
|
@ -774,6 +800,17 @@ export async function buildUpdateAttributesChange(
|
|||
);
|
||||
}
|
||||
|
||||
const { description } = attributes;
|
||||
if (typeof description === 'string') {
|
||||
hasChangedSomething = true;
|
||||
|
||||
actions.modifyDescription = new window.textsecure.protobuf.GroupChange.Actions.ModifyDescriptionAction();
|
||||
actions.modifyDescription.descriptionBytes = buildGroupDescriptionBuffer(
|
||||
clientZkGroupCipher,
|
||||
description
|
||||
);
|
||||
}
|
||||
|
||||
if (!hasChangedSomething) {
|
||||
// This shouldn't happen. When these actions are passed to `modifyGroupV2`, a warning
|
||||
// will be logged.
|
||||
|
@ -3612,6 +3649,14 @@ function extractDiffs({
|
|||
});
|
||||
}
|
||||
|
||||
// description
|
||||
if (old.description !== current.description) {
|
||||
details.push({
|
||||
type: 'description',
|
||||
removed: !current.description,
|
||||
});
|
||||
}
|
||||
|
||||
// No disappearing message timer check here - see below
|
||||
|
||||
// membersV2
|
||||
|
@ -4396,6 +4441,19 @@ async function applyGroupChange({
|
|||
}
|
||||
}
|
||||
|
||||
// modifyDescription?: GroupChangeClass.Actions.ModifyDescriptionAction;
|
||||
if (actions.modifyDescription) {
|
||||
const { descriptionBytes } = actions.modifyDescription;
|
||||
if (descriptionBytes && descriptionBytes.content === 'descriptionText') {
|
||||
result.description = descriptionBytes.descriptionText;
|
||||
} else {
|
||||
window.log.warn(
|
||||
`applyGroupChange/${logId}: Clearing group description due to missing data.`
|
||||
);
|
||||
result.description = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
if (ourConversationId) {
|
||||
result.left = !members[ourConversationId];
|
||||
}
|
||||
|
@ -4669,6 +4727,14 @@ async function applyGroupState({
|
|||
result.groupInviteLinkPassword = undefined;
|
||||
}
|
||||
|
||||
// descriptionBytes
|
||||
const { descriptionBytes } = groupState;
|
||||
if (descriptionBytes && descriptionBytes.content === 'descriptionText') {
|
||||
result.description = descriptionBytes.descriptionText;
|
||||
} else {
|
||||
result.description = undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
newAttributes: result,
|
||||
newProfileKeys,
|
||||
|
@ -5219,6 +5285,29 @@ function decryptGroupChange(
|
|||
actions.modifyInviteLinkPassword = undefined;
|
||||
}
|
||||
|
||||
// modifyDescription?: GroupChangeClass.Actions.ModifyDescriptionAction;
|
||||
if (
|
||||
actions.modifyDescription &&
|
||||
!isByteBufferEmpty(actions.modifyDescription.descriptionBytes)
|
||||
) {
|
||||
try {
|
||||
actions.modifyDescription.descriptionBytes = window.textsecure.protobuf.GroupAttributeBlob.decode(
|
||||
decryptGroupBlob(
|
||||
clientZkGroupCipher,
|
||||
actions.modifyDescription.descriptionBytes.toArrayBuffer()
|
||||
)
|
||||
);
|
||||
} catch (error) {
|
||||
window.log.warn(
|
||||
`decryptGroupChange/${logId}: Unable to decrypt modifyDescription.descriptionBytes`,
|
||||
error && error.stack ? error.stack : error
|
||||
);
|
||||
actions.modifyDescription.descriptionBytes = undefined;
|
||||
}
|
||||
} else if (actions.modifyDescription) {
|
||||
actions.modifyDescription.descriptionBytes = undefined;
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
|
@ -5240,6 +5329,26 @@ export function decryptGroupTitle(
|
|||
return undefined;
|
||||
}
|
||||
|
||||
export function decryptGroupDescription(
|
||||
description: ProtoBinaryType,
|
||||
secretParams: string
|
||||
): string | undefined {
|
||||
const clientZkGroupCipher = getClientZkGroupCipher(secretParams);
|
||||
if (isByteBufferEmpty(description)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const blob = window.textsecure.protobuf.GroupAttributeBlob.decode(
|
||||
decryptGroupBlob(clientZkGroupCipher, description.toArrayBuffer())
|
||||
);
|
||||
|
||||
if (blob && blob.content === 'descriptionText') {
|
||||
return blob.descriptionText;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function decryptGroupState(
|
||||
groupState: GroupClass,
|
||||
groupSecretParams: string,
|
||||
|
@ -5349,6 +5458,26 @@ function decryptGroupState(
|
|||
groupState.inviteLinkPassword = undefined;
|
||||
}
|
||||
|
||||
// descriptionBytes
|
||||
if (!isByteBufferEmpty(groupState.descriptionBytes)) {
|
||||
try {
|
||||
groupState.descriptionBytes = window.textsecure.protobuf.GroupAttributeBlob.decode(
|
||||
decryptGroupBlob(
|
||||
clientZkGroupCipher,
|
||||
groupState.descriptionBytes.toArrayBuffer()
|
||||
)
|
||||
);
|
||||
} catch (error) {
|
||||
window.log.warn(
|
||||
`decryptGroupState/${logId}: Unable to decrypt descriptionBytes. Clearing it.`,
|
||||
error && error.stack ? error.stack : error
|
||||
);
|
||||
groupState.descriptionBytes = undefined;
|
||||
}
|
||||
} else {
|
||||
groupState.descriptionBytes = undefined;
|
||||
}
|
||||
|
||||
return groupState;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue