fix: send group update promote message and display them

pull/3052/head
Audric Ackermann 7 months ago
parent 6c945a173d
commit f4d0e369c9
No known key found for this signature in database

@ -1,10 +1,12 @@
import styled from 'styled-components';
import { GroupPubkeyType, PubkeyType } from 'libsession_util_nodejs';
import { useNicknameOrProfileNameOrShortenedPubkey } from '../hooks/useParamSelector';
import { promoteUsersInGroup } from '../interactions/conversationInteractions';
import { PubKey } from '../session/types';
import { UserUtils } from '../session/utils';
import { GroupInvite } from '../session/utils/job_runners/jobs/GroupInviteJob';
import { GroupPromote } from '../session/utils/job_runners/jobs/GroupPromoteJob';
import { hasClosedGroupV2QAButtons } from '../shared/env_vars';
import {
useMemberInviteFailed,
useMemberInviteSending,
@ -13,6 +15,7 @@ import {
useMemberPromotionFailed,
useMemberPromotionSent,
} from '../state/selectors/groups';
import { Avatar, AvatarSize, CrownIcon } from './avatar/Avatar';
import { Flex } from './basic/Flex';
import {
SessionButton,
@ -20,10 +23,7 @@ import {
SessionButtonShape,
SessionButtonType,
} from './basic/SessionButton';
import { useNicknameOrProfileNameOrShortenedPubkey } from '../hooks/useParamSelector';
import { Avatar, AvatarSize, CrownIcon } from './avatar/Avatar';
import { SessionRadio } from './basic/SessionRadio';
import { hasClosedGroupV2QAButtons } from '../shared/env_vars';
const AvatarContainer = styled.div`
position: relative;
@ -252,7 +252,10 @@ const ResendPromoteButton = ({
buttonColor={SessionButtonColor.Danger}
text="PrOmOtE"
onClick={() => {
void GroupPromote.addJob({ groupPk, member: pubkey });
void promoteUsersInGroup({
groupPk,
toPromote: [pubkey],
});
}}
/>
);

@ -187,7 +187,7 @@ const InviteContactsDialogInner = (props: Props) => {
<SpacerLG />
{/* TODO: localize those strings once out releasing those buttons for real */}
{/* TODO: localize those strings once out releasing those buttons for real Remove after QA */}
{isGroupV2 && isDevProd() && (
<>
<span style={{ display: 'flex', alignItems: 'center' }}>

@ -194,7 +194,7 @@ export const OverlayClosedGroupV2 = () => {
/>
</div>
<SessionSpinner loading={isCreatingGroup} />
{/* TODO: localize those strings once out releasing those buttons for real */}
{/* TODO: localize those strings once out releasing those buttons for real Remove after QA */}
{isDevProd() && (
<>
<span style={{ display: 'flex', alignItems: 'center' }}>

@ -32,7 +32,7 @@ import {
showBanUserByConvoId,
showInviteContactByConvoId,
showLeaveGroupByConvoId,
showLeavePrivateConversationbyConvoId,
showLeavePrivateConversationByConvoId,
showRemoveModeratorsByConvoId,
showUnbanUserByConvoId,
showUpdateGroupNameByConvoId,
@ -58,7 +58,10 @@ import { useSelectedConversationKey } from '../../state/selectors/selectedConver
import type { LocalizerToken } from '../../types/localizer';
import { SessionButtonColor } from '../basic/SessionButton';
import { ItemWithDataTestId } from './items/MenuItemWithDataTestId';
import { ConversationInteractionStatus, ConversationInteractionType } from '../../interactions/types';
import {
ConversationInteractionStatus,
ConversationInteractionType,
} from '../../interactions/types';
/** Menu items standardized */
@ -420,7 +423,7 @@ export const DeletePrivateConversationMenuItem = () => {
return (
<ItemWithDataTestId
onClick={() => {
showLeavePrivateConversationbyConvoId(convoId);
showLeavePrivateConversationByConvoId(convoId);
}}
>
{isMe ? window.i18n('noteToSelfHide') : window.i18n('conversationsDelete')}

@ -1,4 +1,5 @@
import { isNil } from 'lodash';
import { isEmpty, isNil, uniq } from 'lodash';
import { PubkeyType, WithGroupPubkey } from 'libsession_util_nodejs';
import {
ConversationNotificationSettingType,
READ_MESSAGE_STATE,
@ -53,6 +54,11 @@ import { BlockedNumberController } from '../util';
import { LocalizerComponentProps, LocalizerToken } from '../types/localizer';
import { sendInviteResponseToGroup } from '../session/sending/group/GroupInviteResponse';
import { NetworkTime } from '../util/NetworkTime';
import { ClosedGroup } from '../session';
import { GroupUpdateMessageFactory } from '../session/messages/message_factory/group/groupUpdateMessageFactory';
import { GroupPromote } from '../session/utils/job_runners/jobs/GroupPromoteJob';
import { MessageSender } from '../session/sending';
import { StoreGroupRequestFactory } from '../session/apis/snode_api/factories/StoreGroupRequestFactory';
export async function copyPublicKeyByConvoId(convoId: string) {
if (OpenGroupUtils.isOpenGroupV2(convoId)) {
@ -114,7 +120,7 @@ export const handleAcceptConversationRequest = async ({ convoId }: { convoId: st
if (PubKey.is03Pubkey(convoId)) {
const found = await UserGroupsWrapperActions.getGroup(convoId);
if (!found) {
window.log.warn('cannot approve a non existing group in usergroup');
window.log.warn('cannot approve a non existing group in user group');
return null;
}
// this updates the wrapper and refresh the redux slice
@ -307,7 +313,7 @@ export async function showUpdateGroupMembersByConvoId(conversationId: string) {
window.inboxStore?.dispatch(updateGroupMembersModal({ conversationId }));
}
export function showLeavePrivateConversationbyConvoId(conversationId: string) {
export function showLeavePrivateConversationByConvoId(conversationId: string) {
const conversation = ConvoHub.use().get(conversationId);
const isMe = conversation.isMe();
@ -334,7 +340,7 @@ export function showLeavePrivateConversationbyConvoId(conversationId: string) {
});
await clearConversationInteractionState({ conversationId });
} catch (err) {
window.log.warn(`showLeavePrivateConversationbyConvoId error: ${err}`);
window.log.warn(`showLeavePrivateConversationByConvoId error: ${err}`);
await saveConversationInteractionErrorAsMessage({
conversationId,
interactionType: isMe
@ -954,3 +960,73 @@ async function saveConversationInteractionErrorAsMessage({
conversation.updateLastMessage();
}
export async function promoteUsersInGroup({
groupPk,
toPromote,
}: { toPromote: Array<PubkeyType> } & WithGroupPubkey) {
if (!toPromote.length) {
window.log.debug('promoteUsersInGroup: no users to promote');
return;
}
const convo = ConvoHub.use().get(groupPk);
if (!convo) {
window.log.debug('promoteUsersInGroup: group convo not found');
return;
}
const groupInWrapper = await UserGroupsWrapperActions.getGroup(groupPk);
if (!groupInWrapper || !groupInWrapper.secretKey || isEmpty(groupInWrapper.secretKey)) {
window.log.debug('promoteUsersInGroup: groupInWrapper not found or no secretkey');
return;
}
// push one group change message were initial members are added to the group
const membersHex = uniq(toPromote);
const sentAt = NetworkTime.now();
const us = UserUtils.getOurPubKeyStrFromCache();
const msgModel = await ClosedGroup.addUpdateMessage({
diff: { type: 'promoted', promoted: membersHex },
expireUpdate: null,
sender: us,
sentAt,
convo,
markAlreadySent: false, // the store below will mark the message as sent with dbMsgIdentifier
});
const groupMemberChange = await GroupUpdateMessageFactory.getPromotedControlMessage({
adminSecretKey: groupInWrapper.secretKey,
convo,
groupPk,
promoted: membersHex,
createAtNetworkTimestamp: sentAt,
dbMsgIdentifier: msgModel.id,
});
if (!groupMemberChange) {
window.log.warn('promoteUsersInGroup: failed to build group change');
throw new Error('promoteUsersInGroup: failed to build group change');
}
const storeRequests = await StoreGroupRequestFactory.makeGroupMessageSubRequest(
[groupMemberChange],
groupInWrapper
);
const result = await MessageSender.sendEncryptedDataToSnode({
destination: groupPk,
method: 'batch',
sortedSubRequests: storeRequests,
});
if (result?.[0].code !== 200) {
window.log.warn('promoteUsersInGroup: failed to store change');
throw new Error('promoteUsersInGroup: failed to store change');
}
for (let index = 0; index < membersHex.length; index++) {
const member = membersHex[index];
// eslint-disable-next-line no-await-in-loop
await GroupPromote.addJob({ groupPk, member });
}
}

@ -320,9 +320,9 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
// TODO: clean up this typing
return window.i18n.stripped(...([token, args] as GetMessageArgs<LocalizerToken>));
}
if (groupUpdate.promoted) {
if (groupUpdate.promoted?.length) {
// @ts-expect-error -- TODO: Fix by using new i18n builder
const { token, args } = getPromotedGroupUpdateChangeStr(groupUpdate.kicked, groupName);
const { token, args } = getPromotedGroupUpdateChangeStr(groupUpdate.promoted, groupName);
// TODO: clean up this typing
return window.i18n.stripped(...([token, args] as GetMessageArgs<LocalizerToken>));
}
@ -1455,6 +1455,12 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
? [groupUpdate.kicked]
: undefined;
forcedArrayUpdate.promoted = Array.isArray(groupUpdate.promoted)
? groupUpdate.promoted
: groupUpdate.promoted
? [groupUpdate.promoted]
: undefined;
forcedArrayUpdate.left = Array.isArray(groupUpdate.left)
? groupUpdate.left
: groupUpdate.left

@ -17,15 +17,10 @@ import {
} from './namespaces';
import { GroupDetailsNeededForSignature, SnodeGroupSignature } from './signature/groupSignature';
import { SnodeSignature } from './signature/snodeSignatures';
import {
ShortenOrExtend,
WithMessagesHashes,
WithSecretKey,
WithSignature,
WithTimestamp,
} from './types';
import { ShortenOrExtend, WithMessagesHashes } from './types';
import { TTL_DEFAULT } from '../../constants';
import { NetworkTime } from '../../../util/NetworkTime';
import { WithSecretKey, WithSignature, WithTimestamp } from '../../types/with';
type WithMaxSize = { max_size?: number };
export type WithShortenOrExtend = { shortenOrExtend: 'shorten' | 'extend' | '' };

@ -11,14 +11,9 @@ import { PubKey } from '../../../types';
import { StringUtils, UserUtils } from '../../../utils';
import { fromHexToArray, fromUInt8ArrayToBase64 } from '../../../utils/String';
import { PreConditionFailed } from '../../../utils/errors';
import {
SignedHashesParams,
WithMessagesHashes,
WithShortenOrExtend,
WithSignature,
WithTimestamp,
} from '../types';
import { SignedHashesParams, WithMessagesHashes, WithShortenOrExtend } from '../types';
import { NetworkTime } from '../../../../util/NetworkTime';
import { WithSignature, WithTimestamp } from '../../../types/with';
export type SnodeSignatureResult = WithSignature &
WithTimestamp & {

@ -2,6 +2,7 @@ import { GroupPubkeyType, PubkeyType } from 'libsession_util_nodejs';
import { SnodeNamespaces } from './namespaces';
import { SubaccountRevokeSubRequest, SubaccountUnrevokeSubRequest } from './SnodeRequestTypes';
import { WithSignature, WithTimestamp } from '../../types/with';
export type RetrieveMessageItem = {
hash: string;
@ -10,10 +11,9 @@ export type RetrieveMessageItem = {
storedAt: number; // **not** the envelope timestamp, but when the message was effectively stored on the snode
};
export type RetrieveMessageItemWithNamespace = RetrieveMessageItem & {
namespace: SnodeNamespaces; // the namespace from which this message was fetched
}
};
export type RetrieveMessagesResultsContent = {
hf?: Array<number>;
@ -31,9 +31,6 @@ export type WithMessagesHashes = { messagesHashes: Array<string> };
export type RetrieveMessagesResultsBatched = Array<RetrieveRequestResult>;
export type WithTimestamp = { timestamp: number };
export type WithSignature = { signature: string };
export type WithSecretKey = { secretKey: Uint8Array };
export type ShortenOrExtend = 'extend' | 'shorten' | '';
export type WithShortenOrExtend = { shortenOrExtend: ShortenOrExtend };

@ -0,0 +1,155 @@
import { Uint8ArrayLen64, WithGroupPubkey } from 'libsession_util_nodejs';
import { getSodiumRenderer } from '../../../crypto';
import { DisappearingMessages } from '../../../disappearing_messages';
import { GroupUpdateMemberChangeMessage } from '../../outgoing/controlMessage/group_v2/to_group/GroupUpdateMemberChangeMessage';
import { ConversationModel } from '../../../../models/conversation';
import {
WithAddWithHistoryMembers,
WithAddWithoutHistoryMembers,
WithFromMemberLeftMessage,
WithPromotedMembers,
WithRemoveMembers,
} from '../../../types/with';
/**
* Return the control messages to be pushed to the group's swarm.
* Those are not going to change the state, they are just here as a "notification".
* i.e. "Alice was removed from the group"
*/
async function getRemovedControlMessage({
convo,
groupPk,
removed,
adminSecretKey,
createAtNetworkTimestamp,
fromMemberLeftMessage,
dbMsgIdentifier,
}: WithFromMemberLeftMessage &
WithRemoveMembers &
WithGroupPubkey & {
convo: ConversationModel;
adminSecretKey: Uint8ArrayLen64;
createAtNetworkTimestamp: number;
dbMsgIdentifier: string;
}) {
const sodium = await getSodiumRenderer();
if (fromMemberLeftMessage || !removed.length) {
return null;
}
return new GroupUpdateMemberChangeMessage({
identifier: dbMsgIdentifier,
removed,
groupPk,
typeOfChange: 'removed',
createAtNetworkTimestamp,
secretKey: adminSecretKey,
sodium,
...DisappearingMessages.getExpireDetailsForOutgoingMessage(convo, createAtNetworkTimestamp),
});
}
async function getWithoutHistoryControlMessage({
convo,
withoutHistory,
groupPk,
adminSecretKey,
createAtNetworkTimestamp,
dbMsgIdentifier,
}: WithAddWithoutHistoryMembers &
WithGroupPubkey & {
dbMsgIdentifier: string;
convo: ConversationModel;
adminSecretKey: Uint8ArrayLen64;
createAtNetworkTimestamp: number;
}) {
const sodium = await getSodiumRenderer();
if (!withoutHistory.length) {
return null;
}
return new GroupUpdateMemberChangeMessage({
identifier: dbMsgIdentifier,
added: withoutHistory,
groupPk,
typeOfChange: 'added',
createAtNetworkTimestamp,
secretKey: adminSecretKey,
sodium,
...DisappearingMessages.getExpireDetailsForOutgoingMessage(convo, createAtNetworkTimestamp),
});
}
async function getWithHistoryControlMessage({
convo,
withHistory,
groupPk,
adminSecretKey,
createAtNetworkTimestamp,
dbMsgIdentifier,
}: WithAddWithHistoryMembers &
WithGroupPubkey & {
dbMsgIdentifier: string;
convo: ConversationModel;
adminSecretKey: Uint8ArrayLen64;
createAtNetworkTimestamp: number;
}) {
const sodium = await getSodiumRenderer();
if (!withHistory.length) {
return null;
}
return new GroupUpdateMemberChangeMessage({
identifier: dbMsgIdentifier,
added: withHistory,
groupPk,
typeOfChange: 'addedWithHistory',
createAtNetworkTimestamp,
secretKey: adminSecretKey,
sodium,
...DisappearingMessages.getExpireDetailsForOutgoingMessage(convo, createAtNetworkTimestamp),
});
}
async function getPromotedControlMessage({
convo,
promoted,
groupPk,
adminSecretKey,
createAtNetworkTimestamp,
dbMsgIdentifier,
}: WithPromotedMembers &
WithGroupPubkey & {
dbMsgIdentifier: string;
convo: ConversationModel;
adminSecretKey: Uint8ArrayLen64;
createAtNetworkTimestamp: number;
}) {
const sodium = await getSodiumRenderer();
if (!promoted.length) {
return null;
}
return new GroupUpdateMemberChangeMessage({
identifier: dbMsgIdentifier,
promoted,
groupPk,
typeOfChange: 'promoted',
createAtNetworkTimestamp,
secretKey: adminSecretKey,
sodium,
...DisappearingMessages.getExpireDetailsForOutgoingMessage(convo, createAtNetworkTimestamp),
});
}
export const GroupUpdateMessageFactory = {
getRemovedControlMessage,
getWithoutHistoryControlMessage,
getWithHistoryControlMessage,
getPromotedControlMessage,
};

@ -1 +1,13 @@
import { PubkeyType } from 'libsession_util_nodejs';
export type WithMessageHash = { messageHash: string };
export type WithTimestamp = { timestamp: number };
export type WithSignature = { signature: string };
export type WithSecretKey = { secretKey: Uint8Array };
export type WithFromMemberLeftMessage = { fromMemberLeftMessage: boolean }; // there are some changes we want to skip when doing changes triggered from a memberLeft message.
export type WithAddWithoutHistoryMembers = { withoutHistory: Array<PubkeyType> };
export type WithAddWithHistoryMembers = { withHistory: Array<PubkeyType> };
export type WithRemoveMembers = { removed: Array<PubkeyType> };
export type WithPromotedMembers = { promoted: Array<PubkeyType> };

@ -1,5 +1,5 @@
/* eslint-disable no-await-in-loop */
import { PubkeyType, WithGroupPubkey } from 'libsession_util_nodejs';
import { WithGroupPubkey } from 'libsession_util_nodejs';
import { compact, isEmpty, isNumber } from 'lodash';
import { v4 } from 'uuid';
import { StringUtils } from '../..';
@ -17,7 +17,6 @@ import {
} from '../../../apis/snode_api/SnodeRequestTypes';
import { StoreGroupRequestFactory } from '../../../apis/snode_api/factories/StoreGroupRequestFactory';
import { RevokeChanges, SnodeAPIRevoke } from '../../../apis/snode_api/revokeSubaccount';
import { WithSecretKey } from '../../../apis/snode_api/types';
import { concatUInt8Array, getSodiumRenderer } from '../../../crypto';
import { GroupUpdateDeleteMemberContentMessage } from '../../../messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateDeleteMemberContentMessage';
import { MessageSender } from '../../../sending';
@ -31,10 +30,12 @@ import {
} from '../PersistedJob';
import { GroupSync } from './GroupSyncJob';
import { NetworkTime } from '../../../../util/NetworkTime';
export type WithAddWithoutHistoryMembers = { withoutHistory: Array<PubkeyType> };
export type WithAddWithHistoryMembers = { withHistory: Array<PubkeyType> };
export type WithRemoveMembers = { removed: Array<PubkeyType> };
import {
WithAddWithHistoryMembers,
WithAddWithoutHistoryMembers,
WithRemoveMembers,
WithSecretKey,
} from '../../../types/with';
const defaultMsBetweenRetries = 10000;
const defaultMaxAttempts = 1;

@ -20,7 +20,7 @@ import {
import { MessageQueue } from '../../../sending';
const defaultMsBetweenRetries = 10000;
const defaultMaxAttemps = 1;
const defaultMaxAttempts = 1;
type JobExtraArgs = {
groupPk: GroupPubkeyType;
@ -75,7 +75,7 @@ class GroupPromoteJob extends PersistedJob<GroupPromotePersistedData> {
member,
groupPk,
delayBetweenRetries: defaultMsBetweenRetries,
maxAttempts: isNumber(maxAttempts) ? maxAttempts : defaultMaxAttemps,
maxAttempts: isNumber(maxAttempts) ? maxAttempts : defaultMaxAttempts,
nextAttemptTimestamp: nextAttemptTimestamp || Date.now() + defaultMsBetweenRetries,
currentRetry: isNumber(currentRetry) ? currentRetry : 0,
});

@ -120,7 +120,7 @@ async function pushChangesToGroupSwarmIfNeeded({
if (window.sessionFeatureFlags.debug.debugLibsessionDumps) {
const dumps = await MetaGroupWrapperActions.metaMakeDump(groupPk);
window.log.info(
`pushChangesToGroupSwarmIfNeeded: current metadump: ${ed25519Str(groupPk)}:`,
`pushChangesToGroupSwarmIfNeeded: current meta dump: ${ed25519Str(groupPk)}:`,
to_hex(dumps)
);
}
@ -166,10 +166,10 @@ async function pushChangesToGroupSwarmIfNeeded({
});
const expectedReplyLength =
(supplementalKeysSubRequest ? 1 : 0) + // we are sending all the supplemental keys as a single subrequest
pendingConfigRequests.length + // each of those are sent as a subrequest
extraStoreRequests.length + // each of those are sent as a subrequest
extraRequestWithExpectedResults.length; // each of those are sent as a subrequest, but they don't all return something...
(supplementalKeysSubRequest ? 1 : 0) + // we are sending all the supplemental keys as a single sub request
pendingConfigRequests.length + // each of those are sent as a sub request
extraStoreRequests.length + // each of those are sent as a sub request
extraRequestWithExpectedResults.length; // each of those are sent as a sub request, but they don't all return something...
// we do a sequence call here. If we do not have the right expected number of results, consider it a failure
if (!isArray(result) || result.length !== expectedReplyLength) {
@ -184,6 +184,7 @@ async function pushChangesToGroupSwarmIfNeeded({
const changes = LibSessionUtil.batchResultsToGroupSuccessfulChange(result, {
allOldHashes,
messages: pendingConfigData,
});
if (isEmpty(changes)) {

@ -284,7 +284,6 @@ function batchResultsToGroupSuccessfulChange(
* As it is a sequence, the delete might have failed but the new config message might still be posted.
* So we need to check which request failed, and if it is the delete by hashes, we need to add the hash of the posted message to the list of hashes
*/
if (!result?.length) {
return successfulChanges;
}

@ -5,14 +5,13 @@ import {
GroupMemberGet,
GroupPubkeyType,
PubkeyType,
Uint8ArrayLen64,
UserGroupsGet,
WithGroupPubkey,
WithPubkey,
} from 'libsession_util_nodejs';
import { intersection, isEmpty, uniq } from 'lodash';
import { from_hex } from 'libsodium-wrappers-sumo';
import { ConfigDumpData } from '../../data/configDump/configDump';
import { ConversationModel } from '../../models/conversation';
import { HexString } from '../../node/hexStrings';
import { SignalService } from '../../protobuf';
import { getSwarmPollingInstance } from '../../session/apis/snode_api';
@ -27,12 +26,7 @@ import { PubKey } from '../../session/types';
import { UserUtils } from '../../session/utils';
import { PreConditionFailed } from '../../session/utils/errors';
import { GroupInvite } from '../../session/utils/job_runners/jobs/GroupInviteJob';
import {
GroupPendingRemovals,
WithAddWithHistoryMembers,
WithAddWithoutHistoryMembers,
WithRemoveMembers,
} from '../../session/utils/job_runners/jobs/GroupPendingRemovalsJob';
import { GroupPendingRemovals } from '../../session/utils/job_runners/jobs/GroupPendingRemovalsJob';
import { GroupSync } from '../../session/utils/job_runners/jobs/GroupSyncJob';
import { UserSync } from '../../session/utils/job_runners/jobs/UserSyncJob';
import { RunJobResult } from '../../session/utils/job_runners/PersistedJob';
@ -53,9 +47,14 @@ import { openConversationWithMessages } from './conversations';
import { resetLeftOverlayMode } from './section';
import { ConversationTypeEnum } from '../../models/types';
import { NetworkTime } from '../../util/NetworkTime';
import { from_hex } from 'libsodium-wrappers-sumo';
import { GroupUpdateMessageFactory } from '../../session/messages/message_factory/group/groupUpdateMessageFactory';
import {
WithAddWithHistoryMembers,
WithAddWithoutHistoryMembers,
WithFromMemberLeftMessage,
WithRemoveMembers,
} from '../../session/types/with';
type WithFromMemberLeftMessage = { fromMemberLeftMessage: boolean }; // there are some changes we want to skip when doing changes triggered from a memberLeft message.
export type GroupState = {
infos: Record<GroupPubkeyType, GroupInfoGet>;
members: Record<GroupPubkeyType, Array<GroupMemberGet>>;
@ -206,7 +205,7 @@ const initNewGroupInWrapper = createAsyncThunk(
convo,
markAlreadySent: false, // the store below will mark the message as sent with dbMsgIdentifier
});
groupMemberChange = await getWithoutHistoryControlMessage({
groupMemberChange = await GroupUpdateMessageFactory.getWithoutHistoryControlMessage({
adminSecretKey: groupSecretKey,
convo,
groupPk,
@ -343,7 +342,7 @@ const handleUserGroupUpdate = createAsyncThunk(
/**
* Called only when the app just loaded the SessionInbox (i.e. user logged in and fully loaded).
* This function populates the slice with any meta-dumps we have in the DB, if they also are part of what is the usergroup wrapper tracking.
* This function populates the slice with any meta-dumps we have in the DB, if they also are part of what is the user group wrapper tracking.
*
*/
const loadMetaDumpsFromDB = createAsyncThunk(
@ -562,109 +561,6 @@ async function handleWithoutHistoryMembers({
}
}
/**
* Return the control messages to be pushed to the group's swarm.
* Those are not going to change the state, they are just here as a "notification".
* i.e. "Alice was removed from the group"
*/
async function getRemovedControlMessage({
convo,
groupPk,
removed,
adminSecretKey,
createAtNetworkTimestamp,
fromMemberLeftMessage,
dbMsgIdentifier,
}: WithFromMemberLeftMessage &
WithRemoveMembers &
WithGroupPubkey & {
convo: ConversationModel;
adminSecretKey: Uint8ArrayLen64;
createAtNetworkTimestamp: number;
dbMsgIdentifier: string;
}) {
const sodium = await getSodiumRenderer();
if (fromMemberLeftMessage || !removed.length) {
return null;
}
return new GroupUpdateMemberChangeMessage({
identifier: dbMsgIdentifier,
removed,
groupPk,
typeOfChange: 'removed',
createAtNetworkTimestamp,
secretKey: adminSecretKey,
sodium,
...DisappearingMessages.getExpireDetailsForOutgoingMessage(convo, createAtNetworkTimestamp),
});
}
async function getWithoutHistoryControlMessage({
convo,
withoutHistory,
groupPk,
adminSecretKey,
createAtNetworkTimestamp,
dbMsgIdentifier,
}: WithAddWithoutHistoryMembers &
WithGroupPubkey & {
dbMsgIdentifier: string;
convo: ConversationModel;
adminSecretKey: Uint8ArrayLen64;
createAtNetworkTimestamp: number;
}) {
const sodium = await getSodiumRenderer();
if (!withoutHistory.length) {
return null;
}
return new GroupUpdateMemberChangeMessage({
identifier: dbMsgIdentifier,
added: withoutHistory,
groupPk,
typeOfChange: 'added',
createAtNetworkTimestamp,
secretKey: adminSecretKey,
sodium,
...DisappearingMessages.getExpireDetailsForOutgoingMessage(convo, createAtNetworkTimestamp),
});
}
async function getWithHistoryControlMessage({
convo,
withHistory,
groupPk,
adminSecretKey,
createAtNetworkTimestamp,
dbMsgIdentifier,
}: WithAddWithHistoryMembers &
WithGroupPubkey & {
dbMsgIdentifier: string;
convo: ConversationModel;
adminSecretKey: Uint8ArrayLen64;
createAtNetworkTimestamp: number;
}) {
const sodium = await getSodiumRenderer();
if (!withHistory.length) {
return null;
}
return new GroupUpdateMemberChangeMessage({
identifier: dbMsgIdentifier,
added: withHistory,
groupPk,
typeOfChange: 'addedWithHistory',
createAtNetworkTimestamp,
secretKey: adminSecretKey,
sodium,
...DisappearingMessages.getExpireDetailsForOutgoingMessage(convo, createAtNetworkTimestamp),
});
}
async function handleMemberAddedFromUI({
addMembersWithHistory,
addMembersWithoutHistory,
@ -728,7 +624,7 @@ async function handleMemberAddedFromUI({
diff: { type: 'add', added: withHistory, withHistory: true },
...shared,
});
const groupChange = await getWithHistoryControlMessage({
const groupChange = await GroupUpdateMessageFactory.getWithHistoryControlMessage({
adminSecretKey: group.secretKey,
convo,
groupPk,
@ -745,7 +641,7 @@ async function handleMemberAddedFromUI({
diff: { type: 'add', added: withoutHistory, withHistory: false },
...shared,
});
const groupChange = await getWithoutHistoryControlMessage({
const groupChange = await GroupUpdateMessageFactory.getWithoutHistoryControlMessage({
adminSecretKey: group.secretKey,
convo,
groupPk,
@ -866,7 +762,7 @@ async function handleMemberRemovedFromUI({
},
markAlreadySent: false, // the store below will mark the message as sent using dbMsgIdentifier
});
removedControlMessage = await getRemovedControlMessage({
removedControlMessage = await GroupUpdateMessageFactory.getRemovedControlMessage({
adminSecretKey: group.secretKey,
convo,
groupPk,

@ -7,11 +7,11 @@ import { getSodiumNode } from '../../../../node/sodiumNode';
import { SnodeNamespaces } from '../../../../session/apis/snode_api/namespaces';
import { SnodeGroupSignature } from '../../../../session/apis/snode_api/signature/groupSignature';
import { SnodeSignature } from '../../../../session/apis/snode_api/signature/snodeSignatures';
import { WithSignature } from '../../../../session/apis/snode_api/types';
import { concatUInt8Array } from '../../../../session/crypto';
import { UserUtils } from '../../../../session/utils';
import { fromBase64ToArray, fromHexToArray } from '../../../../session/utils/String';
import { NetworkTime } from '../../../../util/NetworkTime';
import { WithSignature } from '../../../../session/types/with';
use(chaiAsPromised);

Loading…
Cancel
Save