fix: leave group v2 as only admin mark it as deleted and pushes to swarm

before removing the wrapper data
pull/2963/head
Audric Ackermann 1 year ago
parent 95cd0e86f1
commit 0a4e3041de

@ -342,7 +342,7 @@
"leaveAndRemoveForEveryone": "Leave Group and Remove for Everyone",
"leaveGroupConfirmation": "Are you sure you want to leave <b>$name$</b>?",
"leaveGroupConfirmationAdmin": "As you are the admin of this group, if you leave it it will be removed for every current members. Are you sure you want to leave this group?",
"leaveGroupConrirmationOnlyAdminLegacy": "Because you are the creator of this group it will be deleted for everyone. This cannot be undone.",
"leaveGroupConfirmationOnlyAdminLegacy": "Because you are the creator of this group it will be deleted for everyone. This cannot be undone.",
"leaveGroupConfirmationOnlyAdmin": "You are the only admin in <b>$name$</b>",
"leaveGroupConfirmationOnlyAdminWarning": "Group settings and members cannot be changed without an admin",
"leaveGroupFailed": "Failed to leave Group!",

@ -397,9 +397,9 @@ export async function showLeaveGroupByConvoId(conversationId: string, name: stri
const isClosedGroup = conversation.isClosedGroup() || false;
const isPublic = conversation.isPublic() || false;
const admins = conversation.get('groupAdmins') || [];
const admins = conversation.getGroupAdmins();
const isAdmin = admins.includes(UserUtils.getOurPubKeyStrFromCache());
const showOnlyGroupAdminWarning = isClosedGroup && isAdmin && admins.length === 1;
const showOnlyGroupAdminWarning = isClosedGroup && isAdmin;
const lastMessageInteractionType = conversation.get('lastMessageInteractionType');
const lastMessageInteractionStatus = conversation.get('lastMessageInteractionStatus');
@ -432,7 +432,9 @@ export async function showLeaveGroupByConvoId(conversationId: string, name: stri
window?.inboxStore?.dispatch(
updateConfirmModal({
title: window.i18n('leaveGroup'),
message: window.i18n('leaveGroupConrirmationOnlyAdminLegacy', name ? [name] : ['']),
message: window.i18n('leaveGroupConfirmationOnlyAdminLegacy', [
name || window.i18n('unknown'),
]),
onClickOk,
okText: window.i18n('leave'),
okTheme: SessionButtonColor.Danger,
@ -440,7 +442,7 @@ export async function showLeaveGroupByConvoId(conversationId: string, name: stri
conversationId,
})
);
// TODO Only to be used after the closed group rebuild
// TODO AUDRIC this is chunk3 stuff: Only to be used after the closed group rebuild chunk3
// const onClickOkLastAdmin = () => {
// /* TODO */
// };

@ -1401,7 +1401,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
if (!pubKey) {
throw new Error('isAdmin() pubKey is falsy');
}
const groupAdmins = getLibGroupAdminsOutsideRedux(this.id) || this.getGroupAdmins();
const groupAdmins = this.getGroupAdmins();
return Array.isArray(groupAdmins) && groupAdmins.includes(pubKey);
}
@ -1956,7 +1956,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
}
public getGroupAdmins(): Array<string> {
const groupAdmins = this.get('groupAdmins');
const groupAdmins = getLibGroupAdminsOutsideRedux(this.id) || this.get('groupAdmins');
return groupAdmins && groupAdmins.length > 0 ? groupAdmins : [];
}

@ -224,15 +224,14 @@ class ConvoController {
await leaveClosedGroup(groupId, fromSyncMessage);
window.log.info(`deleteClosedGroup: ${groupId}, sendLeaveMessage?:${sendLeaveMessage}`);
}
// if we were kicked or sent our left message, we have nothing to do more with that group.
// Just delete everything related to it, not trying to add update message or send a left message.
await this.removeGroupOrCommunityFromDBAndRedux(groupId);
if (PubKey.is03Pubkey(groupId)) {
await remove03GroupFromWrappers(groupId);
} else {
await removeLegacyGroupFromWrappers(groupId);
}
// if we were kicked or sent our left message, we have nothing to do more with that group.
// Just delete everything related to it, not trying to add update message or send a left message.
await this.removeGroupOrCommunityFromDBAndRedux(groupId);
if (!fromSyncMessage) {
await UserSync.queueNewJobIfNeeded();
@ -456,6 +455,7 @@ class ConvoController {
/**
* You most likely don't want to call this function directly, but instead use the deleteLegacyGroup() from the ConversationController as it will take care of more cleaningup.
* This throws if a leaveMessage needs to be sent, but fails to be sent.
*
* Note: `fromSyncMessage` is used to know if we need to send a leave group message to the group first.
* So if the user made the action on this device, fromSyncMessage should be false, but if it happened from a linked device polled update, set this to true.
@ -512,20 +512,17 @@ async function leaveClosedGroup(groupPk: PubkeyType | GroupPubkeyType, fromSyncM
// We might not be able to send our leaving messages (no encryption keypair, we were already removed, no network, etc).
// If that happens, we should just remove everything from our current user.
try {
const wasSent = await getMessageQueue().sendToGroupV2NonDurably({
message: ourLeavingMessage,
});
if (!wasSent) {
throw new Error(
`Even with the retries, leaving message for group ${ed25519Str(
groupPk
)} failed to be sent... Still deleting everything`
);
}
} catch (e) {
window.log.warn('leaving groupv2 error:', e.message);
const wasSent = await getMessageQueue().sendToGroupV2NonDurably({
message: ourLeavingMessage,
});
if (!wasSent) {
throw new Error(
`Even with the retries, leaving message for group ${ed25519Str(
groupPk
)} failed to be sent...`
);
}
// the rest of the cleaning of that conversation is done in the `deleteClosedGroup()`
return;
@ -579,12 +576,7 @@ async function removeLegacyGroupFromWrappers(groupId: string) {
}
async function remove03GroupFromWrappers(groupPk: GroupPubkeyType) {
getSwarmPollingInstance().removePubkey(groupPk, 'remove03GroupFromWrappers');
await UserGroupsWrapperActions.eraseGroup(groupPk);
await SessionUtilConvoInfoVolatile.removeGroupFromWrapper(groupPk);
window?.inboxStore?.dispatch(groupInfoActions.destroyGroupDetails({ groupPk }));
window.log.info(`removed 03 from metagroup wrapper ${ed25519Str(groupPk)}`);
}
async function removeCommunityFromWrappers(conversationId: string) {

@ -30,6 +30,7 @@ import { ClosedGroup } from '../../session/group/closed-group';
import { GroupUpdateInfoChangeMessage } from '../../session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateInfoChangeMessage';
import { GroupUpdateMemberChangeMessage } from '../../session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateMemberChangeMessage';
import { GroupUpdateDeleteMessage } from '../../session/messages/outgoing/controlMessage/group_v2/to_user/GroupUpdateDeleteMessage';
import { ed25519Str } from '../../session/onions/onionPath';
import { PubKey } from '../../session/types';
import { UserUtils } from '../../session/utils';
import { PreConditionFailed } from '../../session/utils/errors';
@ -38,6 +39,7 @@ 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';
import { LibSessionUtil } from '../../session/utils/libsession/libsession_utils';
import { SessionUtilConvoInfoVolatile } from '../../session/utils/libsession/libsession_utils_convo_info_volatile';
import { getUserED25519KeyPairBytes } from '../../session/utils/User';
import { stringify, toFixedUint8ArrayOfLength } from '../../types/sqlSharedTypes';
import {
@ -382,14 +384,36 @@ const refreshGroupDetailsFromWrapper = createAsyncThunk(
const destroyGroupDetails = createAsyncThunk(
'group/destroyGroupDetails',
async ({ groupPk }: { groupPk: GroupPubkeyType }) => {
try {
await UserGroupsWrapperActions.eraseGroup(groupPk);
await ConfigDumpData.deleteDumpFor(groupPk);
debugger;
const us = UserUtils.getOurPubKeyStrFromCache();
const weAreAdmin = await checkWeAreAdmin(groupPk);
const allMembers = await MetaGroupWrapperActions.memberGetAll(groupPk);
const otherAdminsCount = allMembers
.filter(m => m.admin || m.promoted)
.filter(m => m.pubkeyHex !== us).length;
// we are the last admin promoted
if (weAreAdmin && otherAdminsCount === 0) {
// this marks the group info as deleted. We need to push those details
await MetaGroupWrapperActions.infoDestroy(groupPk);
getSwarmPollingInstance().removePubkey(groupPk, 'destroyGroupDetails');
} catch (e) {
window.log.warn(`destroyGroupDetails for ${groupPk} failed with ${e.message}`);
const lastPushResult = await GroupSync.pushChangesToGroupSwarmIfNeeded({
groupPk,
revokeSubRequest: null,
unrevokeSubRequest: null,
supplementKeys: [],
});
if (lastPushResult !== RunJobResult.Success) {
throw new Error(`Failed to destroyGroupDetails for pk ${ed25519Str(groupPk)}`);
}
}
// this deletes the secretKey if we had it. If we need it for something, it has to be done before this call.
await UserGroupsWrapperActions.eraseGroup(groupPk);
await SessionUtilConvoInfoVolatile.removeGroupFromWrapper(groupPk);
await ConfigDumpData.deleteDumpFor(groupPk);
getSwarmPollingInstance().removePubkey(groupPk, 'destroyGroupDetails');
return { groupPk };
}
);
@ -1073,11 +1097,13 @@ const handleMemberLeftMessage = createAsyncThunk(
);
}
await handleMemberRemovedFromUI({
groupPk,
removeMembers: [memberLeft],
fromMemberLeftMessage: true,
});
if (await checkWeAreAdmin(groupPk)) {
await handleMemberRemovedFromUI({
groupPk,
removeMembers: [memberLeft],
fromMemberLeftMessage: true,
});
}
return {
groupPk,
@ -1303,7 +1329,7 @@ const metaGroupSlice = createSlice({
});
builder.addCase(destroyGroupDetails.fulfilled, (state, action) => {
const { groupPk } = action.payload;
// FIXME destroyGroupDetails marks the info as destroyed, but does not really remove the wrapper currently
window.log.info(`removed 03 from metagroup wrapper ${ed25519Str(groupPk)}`);
deleteGroupPkEntriesFromState(state, groupPk);
});
builder.addCase(destroyGroupDetails.rejected, (_state, action) => {

@ -291,7 +291,7 @@ export type LocalizerKeys =
| 'leaveGroupConfirmationAdmin'
| 'leaveGroupConfirmationOnlyAdmin'
| 'leaveGroupConfirmationOnlyAdminWarning'
| 'leaveGroupConrirmationOnlyAdminLegacy'
| 'leaveGroupConfirmationOnlyAdminLegacy'
| 'leaveGroupFailed'
| 'leaveGroupFailedPleaseTryAgain'
| 'leaving'

Loading…
Cancel
Save