fix: send msg to group unapproved accepts and then sends message

pull/2963/head
Audric Ackermann 1 year ago
parent 5867c5af7f
commit b9da60af3b

@ -2,14 +2,9 @@ import React from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import { useIsIncomingRequest } from '../../hooks/useParamSelector'; import { useIsIncomingRequest } from '../../hooks/useParamSelector';
import { import {
approveConvoAndSendResponse,
declineConversationWithConfirm, declineConversationWithConfirm,
handleAcceptConversationRequest,
} from '../../interactions/conversationInteractions'; } from '../../interactions/conversationInteractions';
import { GroupV2Receiver } from '../../receiver/groupv2/handleGroupV2Message';
import { getSwarmPollingInstance } from '../../session/apis/snode_api/swarmPolling';
import { ConvoHub } from '../../session/conversations';
import { PubKey } from '../../session/types';
import { sleepFor } from '../../session/utils/Promise';
import { import {
useSelectedConversationIdOrigin, useSelectedConversationIdOrigin,
useSelectedConversationKey, useSelectedConversationKey,
@ -17,7 +12,6 @@ import {
useSelectedIsPrivateFriend, useSelectedIsPrivateFriend,
} from '../../state/selectors/selectedConversation'; } from '../../state/selectors/selectedConversation';
import { useLibGroupInvitePending } from '../../state/selectors/userGroups'; import { useLibGroupInvitePending } from '../../state/selectors/userGroups';
import { UserGroupsWrapperActions } from '../../webworker/workers/browser/libsession_worker_interface';
import { SessionButton, SessionButtonColor } from '../basic/SessionButton'; import { SessionButton, SessionButtonColor } from '../basic/SessionButton';
import { InvitedToGroupControlMessage, MessageRequestExplanation } from './SubtleNotification'; import { InvitedToGroupControlMessage, MessageRequestExplanation } from './SubtleNotification';
@ -77,34 +71,6 @@ const handleDeclineAndBlockConversationRequest = (
}); });
}; };
const handleAcceptConversationRequest = async (convoId: string) => {
const convo = ConvoHub.use().get(convoId);
if (!convo) {
return;
}
await convo.setDidApproveMe(true, false);
await convo.setIsApproved(true, false);
await convo.commit();
if (convo.isPrivate()) {
await convo.addOutgoingApprovalMessage(Date.now());
await approveConvoAndSendResponse(convoId);
} else if (PubKey.is03Pubkey(convoId)) {
const found = await UserGroupsWrapperActions.getGroup(convoId);
if (!found) {
window.log.warn('cannot approve a non existing group in usergroup');
return;
}
// this updates the wrapper and refresh the redux slice
await UserGroupsWrapperActions.setGroup({ ...found, invitePending: false });
getSwarmPollingInstance().addGroupId(convoId, async () => {
// we need to do a first poll to fetch the keys etc before we can send our invite response
// this is pretty hacky, but also an admin seeing a message from that user in the group will mark it as not pending anymore
await sleepFor(2000);
await GroupV2Receiver.sendInviteResponseToGroup({ groupPk: convoId });
});
}
};
export const ConversationMessageRequestButtons = () => { export const ConversationMessageRequestButtons = () => {
const selectedConvoId = useSelectedConversationKey(); const selectedConvoId = useSelectedConversationKey();
const isIncomingRequest = useIsIncomingRequest(selectedConvoId); const isIncomingRequest = useIsIncomingRequest(selectedConvoId);
@ -131,7 +97,7 @@ export const ConversationMessageRequestButtons = () => {
<ConversationBannerRow> <ConversationBannerRow>
<SessionButton <SessionButton
onClick={async () => { onClick={async () => {
await handleAcceptConversationRequest(selectedConvoId); await handleAcceptConversationRequest({ convoId: selectedConvoId, sendResponse: true });
}} }}
text={window.i18n('accept')} text={window.i18n('accept')}
dataTestId="accept-message-request" dataTestId="accept-message-request"

@ -4,9 +4,10 @@ import { Item, Menu } from 'react-contexify';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { useIsPinned, useIsPrivate, useIsPrivateAndFriend } from '../../hooks/useParamSelector'; import { useIsPinned, useIsPrivate, useIsPrivateAndFriend } from '../../hooks/useParamSelector';
import { ConvoHub } from '../../session/conversations'; import { ConvoHub } from '../../session/conversations';
import { isSearching } from '../../state/selectors/search';
import { getIsMessageSection } from '../../state/selectors/section'; import { getIsMessageSection } from '../../state/selectors/section';
import { useConvoIdFromContext } from '../leftpane/conversation-list-item/ConvoIdContext';
import { SessionContextMenuContainer } from '../SessionContextMenuContainer'; import { SessionContextMenuContainer } from '../SessionContextMenuContainer';
import { useConvoIdFromContext } from '../leftpane/conversation-list-item/ConvoIdContext';
import { import {
AcceptMsgRequestMenuItem, AcceptMsgRequestMenuItem,
BanMenuItem, BanMenuItem,
@ -17,16 +18,15 @@ import {
DeclineAndBlockMsgRequestMenuItem, DeclineAndBlockMsgRequestMenuItem,
DeclineMsgRequestMenuItem, DeclineMsgRequestMenuItem,
DeleteMessagesMenuItem, DeleteMessagesMenuItem,
DeletePrivateConversationMenuItem,
InviteContactMenuItem, InviteContactMenuItem,
LeaveGroupOrCommunityMenuItem, LeaveGroupOrCommunityMenuItem,
MarkAllReadMenuItem, MarkAllReadMenuItem,
MarkConversationUnreadMenuItem, MarkConversationUnreadMenuItem,
NotificationForConvoMenuItem,
ShowUserDetailsMenuItem, ShowUserDetailsMenuItem,
UnbanMenuItem, UnbanMenuItem,
DeletePrivateConversationMenuItem,
NotificationForConvoMenuItem,
} from './Menu'; } from './Menu';
import { isSearching } from '../../state/selectors/search';
export type PropsContextConversationItem = { export type PropsContextConversationItem = {
triggerId: string; triggerId: string;

@ -23,12 +23,12 @@ import {
import { import {
ConversationInteractionStatus, ConversationInteractionStatus,
ConversationInteractionType, ConversationInteractionType,
approveConvoAndSendResponse,
blockConvoById, blockConvoById,
clearNickNameByConvoId, clearNickNameByConvoId,
copyPublicKeyByConvoId, copyPublicKeyByConvoId,
declineConversationWithConfirm, declineConversationWithConfirm,
deleteAllMessagesByConvoIdWithConfirmation, deleteAllMessagesByConvoIdWithConfirmation,
handleAcceptConversationRequest,
markAllReadByConvoId, markAllReadByConvoId,
setNotificationForConvoId, setNotificationForConvoId,
showAddModeratorsByConvoId, showAddModeratorsByConvoId,
@ -441,17 +441,17 @@ export const DeletePrivateConversationMenuItem = () => {
export const AcceptMsgRequestMenuItem = () => { export const AcceptMsgRequestMenuItem = () => {
const convoId = useConvoIdFromContext(); const convoId = useConvoIdFromContext();
const isRequest = useIsIncomingRequest(convoId); const isRequest = useIsIncomingRequest(convoId);
const convo = ConvoHub.use().get(convoId);
const isPrivate = useIsPrivate(convoId); const isPrivate = useIsPrivate(convoId);
if (isRequest && isPrivate) { if (isRequest && (isPrivate || PubKey.is03Pubkey(convoId))) {
return ( return (
<Item <Item
// eslint-disable-next-line @typescript-eslint/no-misused-promises // eslint-disable-next-line @typescript-eslint/no-misused-promises
onClick={async () => { onClick={async () => {
await convo.setDidApproveMe(true); await handleAcceptConversationRequest({
await convo.addOutgoingApprovalMessage(Date.now()); convoId,
await approveConvoAndSendResponse(convoId); sendResponse: true,
});
}} }}
> >
{window.i18n('accept')} {window.i18n('accept')}

@ -10,15 +10,19 @@ import { SessionButtonColor } from '../components/basic/SessionButton';
import { getCallMediaPermissionsSettings } from '../components/settings/SessionSettings'; import { getCallMediaPermissionsSettings } from '../components/settings/SessionSettings';
import { Data } from '../data/data'; import { Data } from '../data/data';
import { SettingsKey } from '../data/settings-key'; import { SettingsKey } from '../data/settings-key';
import { GroupV2Receiver } from '../receiver/groupv2/handleGroupV2Message';
import { uploadFileToFsWithOnionV4 } from '../session/apis/file_server_api/FileServerApi'; import { uploadFileToFsWithOnionV4 } from '../session/apis/file_server_api/FileServerApi';
import { OpenGroupUtils } from '../session/apis/open_group_api/utils'; import { OpenGroupUtils } from '../session/apis/open_group_api/utils';
import { getSwarmPollingInstance } from '../session/apis/snode_api';
import { GetNetworkTime } from '../session/apis/snode_api/getNetworkTime'; import { GetNetworkTime } from '../session/apis/snode_api/getNetworkTime';
import { ConvoHub } from '../session/conversations'; import { ConvoHub } from '../session/conversations';
import { getSodiumRenderer } from '../session/crypto'; import { getSodiumRenderer } from '../session/crypto';
import { getDecryptedMediaUrl } from '../session/crypto/DecryptedAttachmentsManager'; import { getDecryptedMediaUrl } from '../session/crypto/DecryptedAttachmentsManager';
import { DisappearingMessageConversationModeType } from '../session/disappearing_messages/types'; import { DisappearingMessageConversationModeType } from '../session/disappearing_messages/types';
import { ed25519Str } from '../session/onions/onionPath';
import { PubKey } from '../session/types'; import { PubKey } from '../session/types';
import { perfEnd, perfStart } from '../session/utils/Performance'; import { perfEnd, perfStart } from '../session/utils/Performance';
import { sleepFor } from '../session/utils/Promise';
import { fromHexToArray, toHex } from '../session/utils/String'; import { fromHexToArray, toHex } from '../session/utils/String';
import { UserSync } from '../session/utils/job_runners/jobs/UserSyncJob'; import { UserSync } from '../session/utils/job_runners/jobs/UserSyncJob';
import { SessionUtilContact } from '../session/utils/libsession/libsession_utils_contacts'; import { SessionUtilContact } from '../session/utils/libsession/libsession_utils_contacts';
@ -109,21 +113,53 @@ export async function unblockConvoById(conversationId: string) {
await conversation.commit(); await conversation.commit();
} }
/** export const handleAcceptConversationRequest = async ({
* marks the conversation's approval fields, sends messageRequestResponse convoId,
*/ sendResponse,
export const approveConvoAndSendResponse = async (conversationId: string) => { }: {
const convoToApprove = ConvoHub.use().get(conversationId); convoId: string;
sendResponse: boolean;
if (!convoToApprove) { }) => {
window?.log?.info('Conversation is already approved.'); const convo = ConvoHub.use().get(convoId);
return; if (!convo) {
return null;
} }
await convo.setDidApproveMe(true, false);
await convo.setIsApproved(true, false);
await convo.commit();
await convoToApprove.setIsApproved(true, false); if (convo.isPrivate()) {
await convo.addOutgoingApprovalMessage(Date.now());
await convoToApprove.commit(); if (sendResponse) {
await convoToApprove.sendMessageRequestResponse(); await convo.sendMessageRequestResponse();
}
return null;
}
if (PubKey.is03Pubkey(convoId)) {
const found = await UserGroupsWrapperActions.getGroup(convoId);
if (!found) {
window.log.warn('cannot approve a non existing group in usergroup');
return null;
}
// this updates the wrapper and refresh the redux slice
await UserGroupsWrapperActions.setGroup({ ...found, invitePending: false });
const acceptedPromise = new Promise(resolve => {
getSwarmPollingInstance().addGroupId(convoId, async () => {
// we need to do a first poll to fetch the keys etc before we can send our invite response
// this is pretty hacky, but also an admin seeing a message from that user in the group will mark it as not pending anymore
await sleepFor(2000);
if (sendResponse) {
await GroupV2Receiver.sendInviteResponseToGroup({ groupPk: convoId });
}
window.log.info(
`handleAcceptConversationRequest: first poll for group ${ed25519Str(convoId)} happened, we should have encryption keys now`
);
return resolve(true);
});
});
await acceptedPromise;
}
return null;
}; };
export async function declineConversationWithoutConfirm({ export async function declineConversationWithoutConfirm({

@ -127,6 +127,7 @@ import {
getSubscriberCountOutsideRedux, getSubscriberCountOutsideRedux,
} from '../state/selectors/sogsRoomInfo'; // decide it it makes sense to move this to a redux slice? } from '../state/selectors/sogsRoomInfo'; // decide it it makes sense to move this to a redux slice?
import { handleAcceptConversationRequest } from '../interactions/conversationInteractions';
import { DisappearingMessages } from '../session/disappearing_messages'; import { DisappearingMessages } from '../session/disappearing_messages';
import { DisappearingMessageConversationModeType } from '../session/disappearing_messages/types'; import { DisappearingMessageConversationModeType } from '../session/disappearing_messages/types';
import { GroupUpdateInfoChangeMessage } from '../session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateInfoChangeMessage'; import { GroupUpdateInfoChangeMessage } from '../session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateInfoChangeMessage';
@ -2034,7 +2035,8 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
lokiProfile: UserUtils.getOurProfile(), lokiProfile: UserUtils.getOurProfile(),
}; };
const shouldApprove = !this.isApproved() && this.isPrivate(); const shouldApprove = !this.isApproved() && (this.isPrivate() || this.isClosedGroupV2());
const incomingMessageCount = await Data.getMessageCountByType( const incomingMessageCount = await Data.getMessageCountByType(
this.id, this.id,
MessageDirection.incoming MessageDirection.incoming
@ -2048,6 +2050,10 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
} }
if (shouldApprove) { if (shouldApprove) {
await handleAcceptConversationRequest({
convoId: this.id,
sendResponse: !message,
});
await this.setIsApproved(true); await this.setIsApproved(true);
if (hasIncomingMessages) { if (hasIncomingMessages) {
// have to manually add approval for local client here as DB conditional approval check in config msg handling will prevent this from running // have to manually add approval for local client here as DB conditional approval check in config msg handling will prevent this from running

@ -24,7 +24,7 @@ import { PubKey } from '../../types';
import { getMessageQueue } from '../..'; import { getMessageQueue } from '../..';
import { getCallMediaPermissionsSettings } from '../../../components/settings/SessionSettings'; import { getCallMediaPermissionsSettings } from '../../../components/settings/SessionSettings';
import { Data } from '../../../data/data'; import { Data } from '../../../data/data';
import { approveConvoAndSendResponse } from '../../../interactions/conversationInteractions'; import { handleAcceptConversationRequest } from '../../../interactions/conversationInteractions';
import { READ_MESSAGE_STATE } from '../../../models/conversationAttributes'; import { READ_MESSAGE_STATE } from '../../../models/conversationAttributes';
import { PnServer } from '../../apis/push_notification_api'; import { PnServer } from '../../apis/push_notification_api';
import { GetNetworkTime } from '../../apis/snode_api/getNetworkTime'; import { GetNetworkTime } from '../../apis/snode_api/getNetworkTime';
@ -533,7 +533,7 @@ export async function USER_callRecipient(recipient: string) {
weAreCallerOnCurrentCall = true; weAreCallerOnCurrentCall = true;
// initiating a call is analogous to sending a message request // initiating a call is analogous to sending a message request
await approveConvoAndSendResponse(recipient); await handleAcceptConversationRequest({ convoId: recipient, sendResponse: false });
// Note: we do the sending of the preoffer manually as the sendTo1o1NonDurably rely on having a message saved to the db for MessageSentSuccess // Note: we do the sending of the preoffer manually as the sendTo1o1NonDurably rely on having a message saved to the db for MessageSentSuccess
// which is not the case for a pre offer message (the message only exists in memory) // which is not the case for a pre offer message (the message only exists in memory)
@ -932,8 +932,10 @@ export async function USER_acceptIncomingCallRequest(fromSender: string) {
await buildAnswerAndSendIt(fromSender, msgIdentifier); await buildAnswerAndSendIt(fromSender, msgIdentifier);
// consider the conversation completely approved // consider the conversation completely approved
await callerConvo.setDidApproveMe(true); await handleAcceptConversationRequest({
await approveConvoAndSendResponse(fromSender); convoId: fromSender,
sendResponse: true,
});
} }
export async function rejectCallAlreadyAnotherCall(fromSender: string, forcedUUID: string) { export async function rejectCallAlreadyAnotherCall(fromSender: string, forcedUUID: string) {

Loading…
Cancel
Save