Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3388611
D13028.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
9 KB
Referenced Files
None
Subscribers
None
D13028.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D13028: [SQLite] implement resetting Outbound P2P messages
Attached
Detach File
Event Timeline
Log In to Comment