diff --git a/_locales/en/messages.json b/_locales/en/messages.json
index e7d08665c..745dea777 100644
--- a/_locales/en/messages.json
+++ b/_locales/en/messages.json
@@ -572,7 +572,7 @@
"messageRequestAcceptedOursNoName": "You have accepted the message request",
"declineRequestMessage": "Are you sure you want to decline this message request?",
"deleteGroupRequest": "Are you sure you want to delete this group invite?",
- "deleteGroupRequestAndBlock": "Are you sure you want to block $name$? Blocked users cannot send you message requests, group invites or call you.",
+ "deleteGroupRequestAndBlock": "Are you sure you want to block $name$?
Blocked users cannot send you message requests, group invites or call you.",
"respondingToRequestWarning": "Sending a message to this user will automatically accept their message request and reveal your Session ID.",
"respondingToGroupRequestWarning": "Sending a message to this group will automatically accept the group invite.",
"userInvitedYouToGroup": "$name$ invited you to join $groupName$.",
@@ -584,7 +584,7 @@
"mustBeApproved": "This conversation must be accepted to use this feature",
"youHaveANewFriendRequest": "You have a new friend request",
"clearAllConfirmationTitle": "Clear All Message Requests",
- "clearAllConfirmationBody": "Are you sure you want to clear all message and group requests?",
+ "clearAllConfirmationBody": "Are you sure you want to clear all message requests and group invites?",
"thereAreNoMessagesIn": "There are no messages in $name$.",
"noMessagesInBlindedDisabledMsgRequests": "$name$ has message requests from Community conversations turned off, so you cannot send them a message.",
"noMessagesInNoteToSelf": "You have no messages in $name$.",
diff --git a/ts/components/leftpane/overlay/OverlayMessageRequest.tsx b/ts/components/leftpane/overlay/OverlayMessageRequest.tsx
index 77e2cd33d..dd810027f 100644
--- a/ts/components/leftpane/overlay/OverlayMessageRequest.tsx
+++ b/ts/components/leftpane/overlay/OverlayMessageRequest.tsx
@@ -59,7 +59,7 @@ export const OverlayMessageRequest = () => {
*/
function handleClearAllRequestsClick() {
const { i18n } = window;
- const title = i18n('clearAllConfirmationTitle');
+ const title = i18n('clearAll');
const message = i18n('clearAllConfirmationBody');
const onClose = dispatch(updateConfirmModal(null));
@@ -68,6 +68,9 @@ export const OverlayMessageRequest = () => {
title,
message,
onClose,
+ okTheme: SessionButtonColor.Danger,
+ closeTheme: SessionButtonColor.Primary,
+ okText: window.i18n('clear'),
onClickOk: async () => {
window?.log?.info('Blocking all message requests');
if (!hasRequests) {
diff --git a/ts/interactions/conversationInteractions.ts b/ts/interactions/conversationInteractions.ts
index 4f52b41b2..8dd2d0fde 100644
--- a/ts/interactions/conversationInteractions.ts
+++ b/ts/interactions/conversationInteractions.ts
@@ -197,6 +197,9 @@ export async function declineConversationWithoutConfirm({
window?.log?.info('No conversation to decline.');
return;
}
+ window.log.debug(
+ `declineConversationWithoutConfirm of ${ed25519Str(conversationId)}, alsoBlock:${alsoBlock}, conversationIdOrigin:${conversationIdOrigin ? ed25519Str(conversationIdOrigin) : ''}`
+ );
// Note: do not set the active_at undefined as this would make that conversation not synced with the libsession wrapper
await conversationToDecline.setIsApproved(false, false);
@@ -288,7 +291,10 @@ export const declineConversationWithConfirm = ({
updateConfirmModal({
okText: window.i18n(okKey),
cancelText: window.i18n('cancel'),
+ title: window.i18n(okKey),
message,
+ okTheme: SessionButtonColor.Danger,
+ closeTheme: SessionButtonColor.Primary,
onClickOk: async () => {
await declineConversationWithoutConfirm({
conversationId,
diff --git a/ts/session/apis/snode_api/SnodeRequestTypes.ts b/ts/session/apis/snode_api/SnodeRequestTypes.ts
index 155a5ae7b..edf978261 100644
--- a/ts/session/apis/snode_api/SnodeRequestTypes.ts
+++ b/ts/session/apis/snode_api/SnodeRequestTypes.ts
@@ -973,24 +973,35 @@ export class StoreUserMessageSubRequest extends SnodeAPISubRequest {
public readonly dbMessageIdentifier: string | null;
public readonly createdAtNetworkTimestamp: number;
+ public readonly plainTextBuffer: Uint8Array | null;
+
constructor(
args: WithCreatedAtNetworkTimestamp & {
ttlMs: number;
encryptedData: Uint8Array;
destination: PubkeyType;
dbMessageIdentifier: string | null;
+ /**
+ * When we send a message to a 1o1 recipient, we then need to send the same message to our own swarm as a synced message.
+ * To forward that message, we need the original message data, which is the plainTextBuffer field here.
+ */
+ plainTextBuffer: Uint8Array | null;
}
) {
super();
this.ttlMs = args.ttlMs;
this.destination = args.destination;
this.encryptedData = args.encryptedData;
+ this.plainTextBuffer = args.plainTextBuffer;
this.dbMessageIdentifier = args.dbMessageIdentifier;
this.createdAtNetworkTimestamp = args.createdAtNetworkTimestamp;
if (isEmpty(this.encryptedData)) {
throw new Error('this.encryptedData cannot be empty');
}
+ if (this.plainTextBuffer && !this.plainTextBuffer.length) {
+ throw new Error('this.plainTextBuffer can be either null or non-empty');
+ }
}
public async buildAndSignParameters(): Promise<{
diff --git a/ts/session/sending/MessageSender.ts b/ts/session/sending/MessageSender.ts
index b924c1f2d..8a6daa964 100644
--- a/ts/session/sending/MessageSender.ts
+++ b/ts/session/sending/MessageSender.ts
@@ -97,15 +97,29 @@ type PubkeyToRequestType = T extends Pub
type StoreRequestsPerPubkey = Array>;
+type EncryptedMessageDetails = Pick<
+ EncryptAndWrapMessageResults,
+ | 'namespace'
+ | 'encryptedAndWrappedData'
+ | 'identifier'
+ | 'ttl'
+ | 'networkTimestamp'
+ | 'plainTextBuffer'
+>;
+
async function messageToRequest05({
destination,
- encryptedAndWrapped: { namespace, encryptedAndWrappedData, identifier, ttl, networkTimestamp },
+ encryptedAndWrapped: {
+ namespace,
+ encryptedAndWrappedData,
+ identifier,
+ ttl,
+ networkTimestamp,
+ plainTextBuffer,
+ },
}: {
destination: PubkeyType;
- encryptedAndWrapped: Pick<
- EncryptAndWrapMessageResults,
- 'namespace' | 'encryptedAndWrappedData' | 'identifier' | 'ttl' | 'networkTimestamp'
- >;
+ encryptedAndWrapped: EncryptedMessageDetails;
}): Promise {
const shared05Arguments = {
encryptedData: encryptedAndWrappedData,
@@ -114,6 +128,7 @@ async function messageToRequest05({
destination,
namespace,
createdAtNetworkTimestamp: networkTimestamp,
+ plainTextBuffer,
};
if (namespace === SnodeNamespaces.Default || namespace === SnodeNamespaces.LegacyClosedGroup) {
return new StoreUserMessageSubRequest(shared05Arguments);
@@ -175,10 +190,7 @@ async function messageToRequest({
encryptedAndWrapped,
}: {
destination: T;
- encryptedAndWrapped: Pick<
- EncryptAndWrapMessageResults,
- 'namespace' | 'encryptedAndWrappedData' | 'identifier' | 'ttl' | 'networkTimestamp'
- >;
+ encryptedAndWrapped: EncryptedMessageDetails;
}): Promise> {
if (PubKey.is03Pubkey(destination)) {
const req = await messageToRequest03({ destination, encryptedAndWrapped });
@@ -200,12 +212,7 @@ async function messagesToRequests({
encryptedAndWrappedArr,
}: {
destination: T;
- encryptedAndWrappedArr: Array<
- Pick<
- EncryptAndWrapMessageResults,
- 'namespace' | 'encryptedAndWrappedData' | 'identifier' | 'ttl' | 'networkTimestamp'
- >
- >;
+ encryptedAndWrappedArr: Array;
}): Promise>> {
const subRequests: Array> = [];
for (let index = 0; index < encryptedAndWrappedArr.length; index++) {
@@ -260,6 +267,7 @@ async function sendSingleMessage({
// before we return from the await below.
// and the isDuplicate messages relies on sent_at timestamp to be valid.
const found = await Data.getMessageById(encryptedAndWrapped.identifier);
+
// make sure to not update the sent timestamp if this a currently syncing message
if (found && !found.get('sentSync')) {
found.set({ sent_at: encryptedAndWrapped.networkTimestamp });
@@ -497,10 +505,10 @@ type SharedEncryptAndWrap = {
ttl: number;
identifier: string;
isSyncMessage: boolean;
+ plainTextBuffer: Uint8Array;
};
type EncryptAndWrapMessage = {
- plainTextBuffer: Uint8Array;
destination: string;
namespace: number;
networkTimestamp: number;
@@ -549,6 +557,7 @@ async function encryptForGroupV2(
ttl,
identifier,
isSyncMessage: syncMessage,
+ plainTextBuffer,
};
}
@@ -594,6 +603,7 @@ async function encryptMessageAndWrap(
ttl,
identifier,
isSyncMessage: syncMessage,
+ plainTextBuffer,
};
}
@@ -847,7 +857,6 @@ async function handleBatchResultWithSubRequests({
window.log.error('handleBatchResultWithSubRequests: invalid batch result ');
return;
}
- const us = UserUtils.getOurPubKeyStrFromCache();
const seenHashes: Array = [];
for (let index = 0; index < subRequests.length; index++) {
@@ -878,11 +887,7 @@ async function handleBatchResultWithSubRequests({
// We need to store the hash of our synced message when for a 1o1. (as this is the one stored on our swarm)
// For groups, we can just store that hash directly as the group's swarm is hosting all of the group messages
-
- if (
- subRequest.dbMessageIdentifier &&
- (subRequest.destination === us || isDestinationClosedGroup)
- ) {
+ if (subRequest.dbMessageIdentifier) {
// eslint-disable-next-line no-await-in-loop
await MessageSentHandler.handleSwarmMessageSentSuccess(
{
@@ -891,7 +896,10 @@ async function handleBatchResultWithSubRequests({
? SignalService.Envelope.Type.CLOSED_GROUP_MESSAGE
: SignalService.Envelope.Type.SESSION_MESSAGE,
identifier: subRequest.dbMessageIdentifier,
- plainTextBuffer: null,
+ plainTextBuffer:
+ subRequest instanceof StoreUserMessageSubRequest
+ ? subRequest.plainTextBuffer
+ : null,
},
subRequest.createdAtNetworkTimestamp,
storedHash
diff --git a/ts/session/sending/MessageSentHandler.ts b/ts/session/sending/MessageSentHandler.ts
index d129989a0..7a3280439 100644
--- a/ts/session/sending/MessageSentHandler.ts
+++ b/ts/session/sending/MessageSentHandler.ts
@@ -99,7 +99,8 @@ async function handleSwarmMessageSentSuccess(
// A message is synced if we triggered a sync message (sentSync)
// and the current message was sent to our device (so a sync message)
- const shouldMarkMessageAsSynced = isOurDevice && fetchedMessage.get('sentSync');
+ const shouldMarkMessageAsSynced =
+ isOurDevice && fetchedMessage.get('sentSync') && isClosedGroupMessage;
// Handle the sync logic here
if (shouldTriggerSyncMessage && sentMessage && sentMessage.plainTextBuffer) {
diff --git a/ts/session/utils/String.ts b/ts/session/utils/String.ts
index 68713e5e5..68576fde6 100644
--- a/ts/session/utils/String.ts
+++ b/ts/session/utils/String.ts
@@ -72,4 +72,5 @@ export const sanitizeSessionUsername = (inputName: string) => {
return validChars;
};
-export const ed25519Str = (ed25519Key: string) => `(...${ed25519Key.substr(58)})`;
+export const ed25519Str = (ed25519Key: string) =>
+ `(...${ed25519Key.length > 58 ? ed25519Key.substr(58) : ed25519Key})`;
diff --git a/ts/types/LocalizerKeys.ts b/ts/types/LocalizerKeys.ts
index 369aa218e..57da8ff1e 100644
--- a/ts/types/LocalizerKeys.ts
+++ b/ts/types/LocalizerKeys.ts
@@ -71,7 +71,6 @@ export type LocalizerKeys =
| 'clear'
| 'clearAll'
| 'clearAllConfirmationBody'
- | 'clearAllConfirmationTitle'
| 'clearAllData'
| 'clearAllReactions'
| 'clearDataSettingsTitle'