Page MenuHomePhabricator

D13028.diff
No OneTemporary

D13028.diff

diff --git a/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h b/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h
--- a/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h
+++ b/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h
@@ -166,6 +166,8 @@
virtual void markOutboundP2PMessageAsSent(
std::string messageID,
std::string deviceID) const = 0;
+ virtual std::vector<std::string>
+ resetOutboundP2PMessagesForDevice(std::string deviceID) const = 0;
virtual void addInboundP2PMessage(InboundP2PMessage message) const = 0;
virtual std::vector<InboundP2PMessage> getAllInboundP2PMessage() const = 0;
virtual void
diff --git a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h
--- a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h
+++ b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h
@@ -180,6 +180,8 @@
std::string ciphertext) const override;
void markOutboundP2PMessageAsSent(std::string messageID, std::string deviceID)
const override;
+ std::vector<std::string>
+ resetOutboundP2PMessagesForDevice(std::string deviceID) const override;
void addInboundP2PMessage(InboundP2PMessage message) const override;
std::vector<InboundP2PMessage> getAllInboundP2PMessage() const override;
void
diff --git a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp
--- a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp
+++ b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp
@@ -9,6 +9,7 @@
#include "entities/KeyserverInfo.h"
#include "entities/LocalMessageInfo.h"
#include "entities/Metadata.h"
+#include "entities/SQLiteDataConverters.h"
#include "entities/SyncedMetadataEntry.h"
#include "entities/UserInfo.h"
#include <fstream>
@@ -2543,6 +2544,83 @@
sqlite3_step(preparedSQL);
}
+std::vector<std::string> SQLiteQueryExecutor::resetOutboundP2PMessagesForDevice(
+ std::string deviceID) const {
+ // Query all messages that need to be resent - all message that supports
+ // auto retry or already sent messages.
+ std::string queryMessageIDsToResend =
+ "SELECT message_id "
+ "FROM outbound_p2p_messages "
+ "WHERE device_id = ? AND ( "
+ " supports_auto_retry = 1 "
+ " OR (supports_auto_retry = 0 AND status = 'sent') "
+ ");";
+
+ SQLiteStatementWrapper preparedQueryMessageIDsSQL(
+ SQLiteQueryExecutor::getConnection(),
+ queryMessageIDsToResend,
+ "Failed to get all messages to reset");
+
+ bindStringToSQL(deviceID.c_str(), preparedQueryMessageIDsSQL, 1);
+ std::vector<std::string> messageIDs;
+ for (int stepResult = sqlite3_step(preparedQueryMessageIDsSQL);
+ stepResult == SQLITE_ROW;
+ stepResult = sqlite3_step(preparedQueryMessageIDsSQL)) {
+ messageIDs.push_back(getStringFromSQLRow(preparedQueryMessageIDsSQL, 0));
+ }
+
+ // Setting ciphertext to an empty string to make sure this message will be
+ // encrypted again with a new session, update the status, and set
+ // supports_auto_retry to true.
+ // Updating supports_auto_retry to true because those are already sent
+ // messages (from the UI perspective), but the recipient failed to decrypt
+ // so needs to be automatically resent.
+ std::stringstream resetMessagesSQLStream;
+ resetMessagesSQLStream
+ << "UPDATE outbound_p2p_messages "
+ << "SET supports_auto_retry = 1, status = 'persisted', ciphertext = '' "
+ << "WHERE message_id IN " << getSQLStatementArray(messageIDs.size())
+ << ";";
+
+ SQLiteStatementWrapper preparedUpdateSQL(
+ SQLiteQueryExecutor::getConnection(),
+ resetMessagesSQLStream.str(),
+ "Failed to reset messages.");
+
+ for (int i = 0; i < messageIDs.size(); i++) {
+ int bindResult = bindStringToSQL(messageIDs[i], preparedUpdateSQL, i + 1);
+ if (bindResult != SQLITE_OK) {
+ std::stringstream error_message;
+ error_message << "Failed to bind key to SQL statement. Details: "
+ << sqlite3_errstr(bindResult) << std::endl;
+ sqlite3_finalize(preparedUpdateSQL);
+ throw std::runtime_error(error_message.str());
+ }
+ }
+ sqlite3_step(preparedUpdateSQL);
+
+ // This handles the case of messages that are encrypted (with a malformed
+ // session) but not yet queued on Tunnelbroker. In this case, this message
+ // is not considered to be sent (from the UI perspective),
+ // and supports_auto_retry is not updated.
+ std::string updateCiphertextQuery =
+ "UPDATE outbound_p2p_messages "
+ "SET ciphertext = '', status = 'persisted'"
+ "WHERE device_id = ? "
+ " AND supports_auto_retry = 0 "
+ " AND status = 'encrypted';";
+
+ SQLiteStatementWrapper preparedUpdateCiphertextSQL(
+ SQLiteQueryExecutor::getConnection(),
+ updateCiphertextQuery,
+ "Failed to set ciphertext");
+
+ bindStringToSQL(deviceID.c_str(), preparedUpdateCiphertextSQL, 1);
+ sqlite3_step(preparedUpdateCiphertextSQL);
+
+ return messageIDs;
+}
+
void SQLiteQueryExecutor::addInboundP2PMessage(
InboundP2PMessage message) const {
static std::string addMessage =
diff --git a/web/cpp/SQLiteQueryExecutorBindings.cpp b/web/cpp/SQLiteQueryExecutorBindings.cpp
--- a/web/cpp/SQLiteQueryExecutorBindings.cpp
+++ b/web/cpp/SQLiteQueryExecutorBindings.cpp
@@ -307,6 +307,9 @@
.function(
"markOutboundP2PMessageAsSent",
&SQLiteQueryExecutor::markOutboundP2PMessageAsSent)
+ .function(
+ "resetOutboundP2PMessagesForDevice",
+ &SQLiteQueryExecutor::resetOutboundP2PMessagesForDevice)
.function(
"addInboundP2PMessage", &SQLiteQueryExecutor::addInboundP2PMessage)
.function(
diff --git a/web/shared-worker/_generated/comm_query_executor.wasm b/web/shared-worker/_generated/comm_query_executor.wasm
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001
diff --git a/web/shared-worker/queries/outbound-p2p-message-queries.test.js b/web/shared-worker/queries/outbound-p2p-message-queries.test.js
--- a/web/shared-worker/queries/outbound-p2p-message-queries.test.js
+++ b/web/shared-worker/queries/outbound-p2p-message-queries.test.js
@@ -1,6 +1,9 @@
// @flow
-import type { OutboundP2PMessage } from 'lib/types/sqlite-types.js';
+import {
+ type OutboundP2PMessage,
+ outboundP2PMessageStatuses,
+} from 'lib/types/sqlite-types.js';
import { getDatabaseModule } from '../db-module.js';
import type { EmscriptenModule } from '../types/module.js';
@@ -175,4 +178,81 @@
it(`should return undefined when a message with ID doesn't exist`, () => {
expect(queryExecutor?.getOutboundP2PMessagesByID(['id-5'])).toEqual([]);
});
+
+ it('should reset messages', () => {
+ const deviceID = 'deviceID';
+ const MSG_TO_RESET_1: OutboundP2PMessage = {
+ messageID: 'reset-1',
+ deviceID,
+ userID: 'user-1',
+ timestamp: '1',
+ plaintext: 'decrypted-1',
+ ciphertext: 'encrypted-1',
+ status: 'encrypted',
+ supportsAutoRetry: true,
+ };
+
+ const MSG_TO_RESET_2: OutboundP2PMessage = {
+ messageID: 'reset-2',
+ deviceID,
+ userID: 'user-1',
+ timestamp: '1',
+ plaintext: 'decrypted-1',
+ ciphertext: 'encrypted-1',
+ status: 'sent',
+ supportsAutoRetry: false,
+ };
+
+ const MSG_NOT_RESET: OutboundP2PMessage = {
+ messageID: 'reset-3',
+ deviceID,
+ userID: 'user-1',
+ timestamp: '3',
+ plaintext: 'decrypted-1',
+ ciphertext: 'encrypted-1',
+ status: 'encrypted',
+ supportsAutoRetry: false,
+ };
+
+ queryExecutor?.addOutboundP2PMessages([
+ MSG_TO_RESET_1,
+ MSG_TO_RESET_2,
+ MSG_NOT_RESET,
+ ]);
+
+ const messageIDs =
+ queryExecutor?.resetOutboundP2PMessagesForDevice(deviceID);
+
+ expect(messageIDs).toEqual([
+ MSG_TO_RESET_1.messageID,
+ MSG_TO_RESET_2.messageID,
+ ]);
+
+ const messagesAfterReset = [
+ {
+ ...MSG_TO_RESET_1,
+ status: outboundP2PMessageStatuses.persisted,
+ ciphertext: '',
+ supportsAutoRetry: true,
+ },
+ {
+ ...MSG_TO_RESET_2,
+ status: outboundP2PMessageStatuses.persisted,
+ ciphertext: '',
+ supportsAutoRetry: true,
+ },
+ ];
+ expect(queryExecutor?.getOutboundP2PMessagesByID(messageIDs ?? [])).toEqual(
+ messagesAfterReset,
+ );
+ expect(
+ queryExecutor?.getOutboundP2PMessagesByID([MSG_NOT_RESET.messageID]),
+ ).toEqual([
+ {
+ ...MSG_NOT_RESET,
+ ciphertext: '',
+ status: outboundP2PMessageStatuses.persisted,
+ },
+ ]);
+ });
});
diff --git a/web/shared-worker/types/sqlite-query-executor.js b/web/shared-worker/types/sqlite-query-executor.js
--- a/web/shared-worker/types/sqlite-query-executor.js
+++ b/web/shared-worker/types/sqlite-query-executor.js
@@ -190,6 +190,7 @@
ciphertext: string,
): void;
markOutboundP2PMessageAsSent(messageID: string, deviceID: string): void;
+ resetOutboundP2PMessagesForDevice(deviceID: string): $ReadOnlyArray<string>;
addInboundP2PMessage(message: InboundP2PMessage): void;
getAllInboundP2PMessage(): $ReadOnlyArray<InboundP2PMessage>;

File Metadata

Mime Type
text/plain
Expires
Sat, Nov 30, 3:09 PM (17 h, 28 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2601405
Default Alt Text
D13028.diff (9 KB)

Event Timeline