Page MenuHomePhorge

D11234.1765269960.diff
No OneTemporary

Size
32 KB
Referenced Files
None
Subscribers
None

D11234.1765269960.diff

diff --git a/native/android/app/src/cpp/NotificationsCryptoModuleJNIHelper.cpp b/native/android/app/src/cpp/NotificationsCryptoModuleJNIHelper.cpp
--- a/native/android/app/src/cpp/NotificationsCryptoModuleJNIHelper.cpp
+++ b/native/android/app/src/cpp/NotificationsCryptoModuleJNIHelper.cpp
@@ -9,11 +9,11 @@
std::string NotificationsCryptoModuleJNIHelper::decrypt(
facebook::jni::alias_ref<NotificationsCryptoModuleJNIHelper> jThis,
+ std::string keyserverID,
std::string data,
- int messageType,
- std::string callingProcessName) {
+ int messageType) {
std::string decryptedData =
- NotificationsCryptoModule::decrypt(data, messageType, callingProcessName);
+ NotificationsCryptoModule::decrypt(keyserverID, data, messageType);
return decryptedData;
}
@@ -25,4 +25,4 @@
makeNativeMethod("decrypt", NotificationsCryptoModuleJNIHelper::decrypt),
});
}
-} // namespace comm
\ No newline at end of file
+} // namespace comm
diff --git a/native/android/app/src/main/java/app/comm/android/fbjni/NotificationsCryptoModule.java b/native/android/app/src/main/java/app/comm/android/fbjni/NotificationsCryptoModule.java
--- a/native/android/app/src/main/java/app/comm/android/fbjni/NotificationsCryptoModule.java
+++ b/native/android/app/src/main/java/app/comm/android/fbjni/NotificationsCryptoModule.java
@@ -3,5 +3,5 @@
public class NotificationsCryptoModule {
public static native int olmEncryptedTypeMessage();
public static native String
- decrypt(String data, int messageType, String callingProcessName);
+ decrypt(String keyserverID, String data, int messageType);
}
diff --git a/native/android/app/src/main/java/app/comm/android/notifications/CommNotificationsHandler.java b/native/android/app/src/main/java/app/comm/android/notifications/CommNotificationsHandler.java
--- a/native/android/app/src/main/java/app/comm/android/notifications/CommNotificationsHandler.java
+++ b/native/android/app/src/main/java/app/comm/android/notifications/CommNotificationsHandler.java
@@ -91,9 +91,19 @@
@Override
public void onMessageReceived(RemoteMessage message) {
+ if (message.getData().get(KEYSERVER_ID_KEY) == null) {
+ displayErrorMessageNotification(
+ "Received notification without keyserver ID.",
+ "Missing keyserver ID.",
+ null);
+ return;
+ }
+
+ String senderKeyserverID = message.getData().get(KEYSERVER_ID_KEY);
+
if (message.getData().get(ENCRYPTED_PAYLOAD_KEY) != null) {
try {
- message = this.decryptRemoteMessage(message);
+ message = this.decryptRemoteMessage(message, senderKeyserverID);
} catch (JSONException e) {
Log.w("COMM", "Malformed notification JSON payload.", e);
return;
@@ -377,14 +387,15 @@
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
}
- private RemoteMessage decryptRemoteMessage(RemoteMessage message)
+ private RemoteMessage
+ decryptRemoteMessage(RemoteMessage message, String senderKeyserverID)
throws JSONException, IllegalStateException {
String encryptedSerializedPayload =
message.getData().get(ENCRYPTED_PAYLOAD_KEY);
String decryptedSerializedPayload = NotificationsCryptoModule.decrypt(
+ senderKeyserverID,
encryptedSerializedPayload,
- NotificationsCryptoModule.olmEncryptedTypeMessage(),
- "CommNotificationsHandler");
+ NotificationsCryptoModule.olmEncryptedTypeMessage());
JSONObject decryptedPayload = new JSONObject(decryptedSerializedPayload);
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
@@ -12,6 +12,8 @@
#include <thread>
#ifndef EMSCRIPTEN
+#include "../CryptoTools/CryptoModule.h"
+#include "../Notifications/BackgroundDataStorage/NotificationsCryptoModule.h"
#include "CommSecureStore.h"
#include "PlatformSpecificTools.h"
#include "StaffUtils.h"
@@ -541,6 +543,41 @@
return create_table(db, query, "integrity_store");
}
+bool migrate_notifs_crypto_account(sqlite3 *db) {
+#ifndef EMSCRIPTEN
+ std::string legacyCryptoAccountDataKey = "cryptoAccountDataKey";
+ folly::Optional<std::string> secretKey =
+ CommSecureStore::get(legacyCryptoAccountDataKey);
+
+ if (!secretKey.hasValue()) {
+ return false;
+ }
+
+ std::unique_ptr<crypto::CryptoModule> legacyNotifsAccount =
+ NotificationsCryptoModule::migrateLegacyNotificationsCryptoModule();
+
+ if (!legacyNotifsAccount) {
+ return true;
+ }
+
+ std::string insert_notifs_account_query =
+ "REPLACE INTO olm_persist_account (id, account_data) "
+ "VALUES (?, ?);";
+
+ crypto::Persist legacyNotifsPersist =
+ legacyNotifsAccount->storeAsB64(secretKey.value());
+ std::string notifsAccountData = std::string(
+ legacyNotifsPersist.account.begin(), legacyNotifsPersist.account.end());
+
+ replaceEntity<OlmPersistAccount>(
+ db, insert_notifs_account_query, {NOTIFS_ACCOUNT_ID, notifsAccountData});
+
+ return true;
+#else
+ return true;
+#endif
+}
+
bool create_schema(sqlite3 *db) {
char *error;
sqlite3_exec(
@@ -895,7 +932,8 @@
{34, {enable_rollback_journal_mode, false}},
{35, {create_communities_table, true}},
{36, {create_messages_to_device_table, true}},
- {37, {create_integrity_table, true}}}};
+ {37, {create_integrity_table, true}},
+ {38, {migrate_notifs_crypto_account, true}}}};
enum class MigrationResult { SUCCESS, FAILURE, NOT_APPLIED };
diff --git a/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp b/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp
--- a/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp
+++ b/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp
@@ -906,21 +906,35 @@
auto prekeyCpp{prekey.utf8(rt)};
auto prekeySignatureCpp{prekeySignature.utf8(rt)};
auto oneTimeKeyCpp{oneTimeKey.utf8(rt)};
+ auto keyserverIDCpp{keyserverID.utf8(rt)};
return createPromiseAsJSIValue(
rt, [=](jsi::Runtime &innerRt, std::shared_ptr<Promise> promise) {
taskType job = [=, &innerRt]() {
std::string error;
crypto::EncryptedData result;
try {
- // Introduced temporarily to make this diff non-breaking change
- NotificationsCryptoModule::initializeNotificationsCryptoAccount(
- "Comm");
- result = NotificationsCryptoModule::initializeNotificationsSession(
- identityKeysCpp,
- prekeyCpp,
- prekeySignatureCpp,
- oneTimeKeyCpp,
- "Comm");
+ this->notifsCryptoModule->initializeOutboundForSendingSession(
+ keyserverIDCpp,
+ std::vector<uint8_t>(
+ identityKeysCpp.begin(), identityKeysCpp.end()),
+ std::vector<uint8_t>(prekeyCpp.begin(), prekeyCpp.end()),
+ std::vector<uint8_t>(
+ prekeySignatureCpp.begin(), prekeySignatureCpp.end()),
+ std::vector<uint8_t>(
+ oneTimeKeyCpp.begin(), oneTimeKeyCpp.end()));
+
+ result = this->notifsCryptoModule->encrypt(
+ keyserverIDCpp,
+ NotificationsCryptoModule::initialEncryptedMessageContent);
+
+ std::shared_ptr<crypto::Session> keyserverNotificationsSession =
+ this->notifsCryptoModule->getSessionByDeviceId(keyserverIDCpp);
+
+ NotificationsCryptoModule::persistNotificationsSession(
+ keyserverIDCpp, keyserverNotificationsSession);
+
+ this->notifsCryptoModule->removeSessionByDeviceId(keyserverIDCpp);
+ this->persistCryptoModules(false, true);
} catch (const std::exception &e) {
error = e.what();
}
diff --git a/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.h b/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.h
--- a/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.h
+++ b/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.h
@@ -7,59 +7,65 @@
namespace comm {
class NotificationsCryptoModule {
- const static std::string secureStoreNotificationsAccountDataKey;
const static std::string notificationsCryptoAccountID;
- const static std::string keyserverHostedNotificationsID;
- const static std::string initialEncryptedMessageContent;
- static std::string getPicklingKey();
- static void serializeAndFlushCryptoModule(
- std::unique_ptr<crypto::CryptoModule> cryptoModule,
- const std::string &path,
- const std::string &picklingKey,
- const std::string &callingProcessName);
+ // Used for migration of legacy notifications sessions
static std::unique_ptr<crypto::CryptoModule> deserializeCryptoModule(
const std::string &path,
const std::string &picklingKey);
- static void callCryptoModule(
- std::function<void(
- const std::unique_ptr<crypto::CryptoModule> &cryptoModule)> caller,
- const std::string &callingProcessName);
+ static std::string
+ getKeyserverNotificationsSessionKey(const std::string &keyserverID);
+ static std::string serializeNotificationsSession(
+ std::shared_ptr<crypto::Session> session,
+ std::string picklingKey);
+ static std::pair<std::unique_ptr<crypto::Session>, std::string>
+ deserializeNotificationsSession(const std::string &serializedSession);
+ static void persistNotificationsSessionInternal(
+ const std::string &keyserverID,
+ const std::string &picklingKey,
+ std::shared_ptr<crypto::Session> session);
+ static std::pair<std::unique_ptr<crypto::Session>, std::string>
+ fetchNotificationsSession(const std::string &keyserverID);
public:
+ const static std::string initialEncryptedMessageContent;
const static int olmEncryptedTypeMessage;
- static void
- initializeNotificationsCryptoAccount(const std::string &callingProcessName);
+
+ static std::unique_ptr<crypto::CryptoModule>
+ migrateLegacyNotificationsCryptoModule();
static void clearSensitiveData();
- static crypto::EncryptedData initializeNotificationsSession(
- const std::string &identityKeys,
- const std::string &prekey,
- const std::string &prekeySignature,
- const std::string &oneTimeKeys,
- const std::string &callingProcessName);
- static bool
- isNotificationsSessionInitialized(const std::string &callingProcessName);
+ static void persistNotificationsSession(
+ const std::string &keyserverID,
+ std::shared_ptr<crypto::Session> keyserverNotificationsSession);
+ static bool isNotificationsSessionInitialized(const std::string &keyserverID);
static std::string decrypt(
+ const std::string &keyserverID,
const std::string &data,
- const size_t messageType,
- const std::string &callingProcessName);
+ const size_t messageType);
class StatefulDecryptResult {
StatefulDecryptResult(
- std::unique_ptr<crypto::CryptoModule> cryptoModule,
+ std::unique_ptr<crypto::Session> session,
+ std::string keyserverID,
+ std::string picklingKey,
std::string decryptedData);
- std::unique_ptr<crypto::CryptoModule> cryptoModuleState;
+ std::unique_ptr<crypto::Session> sessionState;
+ std::string keyserverID;
+ std::string picklingKey;
std::string decryptedData;
friend NotificationsCryptoModule;
public:
std::string getDecryptedData();
+ std::string getKeyserverID();
+ std::string getPicklingKey();
};
- static std::unique_ptr<StatefulDecryptResult>
- statefulDecrypt(const std::string &data, const size_t messageType);
- static void flushState(
- std::unique_ptr<StatefulDecryptResult> statefulDecryptResult,
- const std::string &callingProcessName);
+ static std::unique_ptr<StatefulDecryptResult> statefulDecrypt(
+ const std::string &keyserverID,
+ const std::string &data,
+ const size_t messageType);
+ static void
+ flushState(std::unique_ptr<StatefulDecryptResult> statefulDecryptResult);
};
} // namespace comm
diff --git a/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.cpp b/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.cpp
--- a/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.cpp
+++ b/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.cpp
@@ -1,31 +1,34 @@
#include "NotificationsCryptoModule.h"
#include "../../CryptoTools/Persist.h"
#include "../../CryptoTools/Tools.h"
+#include "../../Tools/CommMMKV.h"
#include "../../Tools/CommSecureStore.h"
+#include "../../Tools/Logger.h"
#include "../../Tools/PlatformSpecificTools.h"
-#include <fcntl.h>
#include <folly/String.h>
#include <folly/dynamic.h>
#include <folly/json.h>
-#include <unistd.h>
#include <fstream>
#include <memory>
#include <sstream>
namespace comm {
-const std::string
- NotificationsCryptoModule::secureStoreNotificationsAccountDataKey =
- "notificationsCryptoAccountDataKey";
const std::string NotificationsCryptoModule::notificationsCryptoAccountID =
"notificationsCryptoAccountDataID";
-const std::string NotificationsCryptoModule::keyserverHostedNotificationsID =
- "keyserverHostedNotificationsID";
const std::string NotificationsCryptoModule::initialEncryptedMessageContent =
"{\"type\": \"init\"}";
const int NotificationsCryptoModule::olmEncryptedTypeMessage = 1;
-const int temporaryFilePathRandomSuffixLength = 32;
+
+// This constant is only used to migrate the existing notifications
+// session with production keyserver from flat file to MMKV. This
+// migration will fire when user updates the app. It will also fire
+// on dev env provided old keyserver set up is used. Developers willing
+// to use new keyserver set up must log out before installing updated
+// app version. Do not introduce new usages of this constant in the code!!!
+const std::string ashoatKeyserverIDUsedOnlyForMigrationFromLegacyNotifStorage =
+ "256";
std::unique_ptr<crypto::CryptoModule>
NotificationsCryptoModule::deserializeCryptoModule(
@@ -74,156 +77,77 @@
crypto::Persist({account, sessions}));
}
-void NotificationsCryptoModule::serializeAndFlushCryptoModule(
- std::unique_ptr<crypto::CryptoModule> cryptoModule,
- const std::string &path,
- const std::string &picklingKey,
- const std::string &callingProcessName) {
- crypto::Persist persist = cryptoModule->storeAsB64(picklingKey);
-
- folly::dynamic sessions = folly::dynamic::object;
- for (auto &sessionKeyValuePair : persist.sessions) {
- std::string targetUserID = sessionKeyValuePair.first;
- crypto::OlmBuffer sessionData = sessionKeyValuePair.second;
- sessions[targetUserID] =
- std::string(sessionData.begin(), sessionData.end());
- }
+std::string NotificationsCryptoModule::getKeyserverNotificationsSessionKey(
+ const std::string &keyserverID) {
+ return "KEYSERVER." + keyserverID + ".NOTIFS_SESSION";
+}
- std::string account =
- std::string(persist.account.begin(), persist.account.end());
- folly::dynamic persistJSON =
- folly::dynamic::object("account", account)("sessions", sessions);
- std::string pickledPersist = folly::toJson(persistJSON);
-
- std::string temporaryFilePathRandomSuffix =
- crypto::Tools::generateRandomHexString(
- temporaryFilePathRandomSuffixLength);
- std::string temporaryPath =
- path + callingProcessName + temporaryFilePathRandomSuffix;
-
- mode_t readWritePermissionsMode = 0666;
- int temporaryFD =
- open(temporaryPath.c_str(), O_CREAT | O_WRONLY, readWritePermissionsMode);
- if (temporaryFD == -1) {
- throw std::runtime_error(
- "Failed to create temporary file. Unable to atomically update "
- "notifications crypto account. Details: " +
- std::string(strerror(errno)));
- }
- ssize_t bytesWritten =
- write(temporaryFD, pickledPersist.c_str(), pickledPersist.length());
- if (bytesWritten == -1 || bytesWritten != pickledPersist.length()) {
- remove(temporaryPath.c_str());
- throw std::runtime_error(
- "Failed to write all data to temporary file. Unable to atomically "
- "update notifications crypto account. Details: " +
- std::string(strerror(errno)));
- }
- if (fsync(temporaryFD) == -1) {
- remove(temporaryPath.c_str());
- throw std::runtime_error(
- "Failed to synchronize temporary file data with hardware storage. "
- "Unable to atomically update notifications crypto account. Details: " +
- std::string(strerror(errno)));
- };
- close(temporaryFD);
- if (rename(temporaryPath.c_str(), path.c_str()) == -1) {
- remove(temporaryPath.c_str());
- throw std::runtime_error(
- "Failed to replace temporary file content with notifications crypto "
- "account. Unable to atomically update notifications crypto account. "
- "Details: " +
- std::string(strerror(errno)));
- }
- remove(temporaryPath.c_str());
+std::string NotificationsCryptoModule::serializeNotificationsSession(
+ std::shared_ptr<crypto::Session> session,
+ std::string picklingKey) {
+ crypto::OlmBuffer pickledSessionBytes = session->storeAsB64(picklingKey);
+ std::string pickledSession =
+ std::string{pickledSessionBytes.begin(), pickledSessionBytes.end()};
+ folly::dynamic serializedSessionJson = folly::dynamic::object(
+ "session", pickledSession)("picklingKey", picklingKey);
+ return folly::toJson(serializedSessionJson);
}
-std::string NotificationsCryptoModule::getPicklingKey() {
- folly::Optional<std::string> picklingKey = CommSecureStore::get(
- NotificationsCryptoModule::secureStoreNotificationsAccountDataKey);
- if (!picklingKey.hasValue()) {
+std::pair<std::unique_ptr<crypto::Session>, std::string>
+NotificationsCryptoModule::deserializeNotificationsSession(
+ const std::string &serializedSession) {
+ folly::dynamic serializedSessionJson;
+ try {
+ serializedSessionJson = folly::parseJson(serializedSession);
+ } catch (const folly::json::parse_error &e) {
throw std::runtime_error(
- "Attempt to retrieve notifications crypto account before it was "
- "correctly initialized.");
+ "Notifications session deserialization failed with reason: " +
+ std::string(e.what()));
}
- return picklingKey.value();
-}
-void NotificationsCryptoModule::callCryptoModule(
- std::function<
- void(const std::unique_ptr<crypto::CryptoModule> &cryptoModule)> caller,
- const std::string &callingProcessName) {
- const std::string picklingKey = NotificationsCryptoModule::getPicklingKey();
- const std::string path =
- PlatformSpecificTools::getNotificationsCryptoAccountPath();
- std::unique_ptr<crypto::CryptoModule> cryptoModule =
- NotificationsCryptoModule::deserializeCryptoModule(path, picklingKey);
- caller(cryptoModule);
- NotificationsCryptoModule::serializeAndFlushCryptoModule(
- std::move(cryptoModule), path, picklingKey, callingProcessName);
+ std::string pickledSession = serializedSessionJson["session"].asString();
+ crypto::OlmBuffer pickledSessionBytes =
+ crypto::OlmBuffer{pickledSession.begin(), pickledSession.end()};
+ std::string picklingKey = serializedSessionJson["picklingKey"].asString();
+ std::unique_ptr<crypto::Session> session =
+ crypto::Session::restoreFromB64(picklingKey, pickledSessionBytes);
+ return {std::move(session), picklingKey};
}
-void NotificationsCryptoModule::initializeNotificationsCryptoAccount(
- const std::string &callingProcessName) {
+std::unique_ptr<crypto::CryptoModule>
+NotificationsCryptoModule::migrateLegacyNotificationsCryptoModule() {
const std::string notificationsCryptoAccountPath =
PlatformSpecificTools::getNotificationsCryptoAccountPath();
std::ifstream notificationCryptoAccountCheck(notificationsCryptoAccountPath);
- if (notificationCryptoAccountCheck.good()) {
- // Implemented in CommmCoreModule semantics regarding public olm account
- // initialization is idempotent. We should follow the same approach when it
- // comes to notifications
+
+ if (!notificationCryptoAccountCheck.good()) {
notificationCryptoAccountCheck.close();
- return;
+ return nullptr;
}
- // There is no reason to check if the key is already present since if we are
- // in this place in the code we are about to create new account
- std::string picklingKey = crypto::Tools::generateRandomString(64);
- CommSecureStore::set(
- NotificationsCryptoModule::secureStoreNotificationsAccountDataKey,
- picklingKey);
-
- std::unique_ptr<crypto::CryptoModule> cryptoModule =
- std::make_unique<crypto::CryptoModule>(
- NotificationsCryptoModule::notificationsCryptoAccountID);
- NotificationsCryptoModule::serializeAndFlushCryptoModule(
- std::move(cryptoModule),
- notificationsCryptoAccountPath,
- picklingKey,
- callingProcessName);
-}
+ notificationCryptoAccountCheck.close();
-crypto::EncryptedData NotificationsCryptoModule::initializeNotificationsSession(
- const std::string &identityKeys,
- const std::string &prekey,
- const std::string &prekeySignature,
- const std::string &oneTimeKey,
- const std::string &callingProcessName) {
- crypto::EncryptedData initialEncryptedMessage;
- auto caller = [&](const std::unique_ptr<crypto::CryptoModule> &cryptoModule) {
- cryptoModule->initializeOutboundForSendingSession(
- NotificationsCryptoModule::keyserverHostedNotificationsID,
- std::vector<uint8_t>(identityKeys.begin(), identityKeys.end()),
- std::vector<uint8_t>(prekey.begin(), prekey.end()),
- std::vector<uint8_t>(prekeySignature.begin(), prekeySignature.end()),
- std::vector<uint8_t>(oneTimeKey.begin(), oneTimeKey.end()));
- initialEncryptedMessage = cryptoModule->encrypt(
- NotificationsCryptoModule::keyserverHostedNotificationsID,
- NotificationsCryptoModule::initialEncryptedMessageContent);
- };
- NotificationsCryptoModule::callCryptoModule(caller, callingProcessName);
- return initialEncryptedMessage;
-}
+ std::string legacySecureStoreNotifsAccountKey =
+ "notificationsCryptoAccountDataKey";
+ folly::Optional<std::string> legacyPicklingKey =
+ CommSecureStore::get(legacySecureStoreNotifsAccountKey);
+ if (!legacyPicklingKey.hasValue()) {
+ throw std::runtime_error(
+ "Attempt to migrate legacy notifications account but pickling key "
+ "missing.");
+ }
-bool NotificationsCryptoModule::isNotificationsSessionInitialized(
- const std::string &callingProcessName) {
- bool sessionInitialized;
- auto caller = [&sessionInitialized](
- const std::unique_ptr<crypto::CryptoModule> &cryptoModule) {
- sessionInitialized = cryptoModule->hasSessionFor(
- NotificationsCryptoModule::keyserverHostedNotificationsID);
- };
- NotificationsCryptoModule::callCryptoModule(caller, callingProcessName);
- return sessionInitialized;
+ std::unique_ptr<crypto::CryptoModule> legacyCryptoModule =
+ NotificationsCryptoModule::deserializeCryptoModule(
+ notificationsCryptoAccountPath, legacyPicklingKey.value());
+
+ std::string legacyNotificationsSessionID = "keyserverHostedNotificationsID";
+ std::shared_ptr<crypto::Session> legacyNotificationsSession =
+ legacyCryptoModule->getSessionByDeviceId(legacyNotificationsSessionID);
+
+ NotificationsCryptoModule::persistNotificationsSession(
+ ashoatKeyserverIDUsedOnlyForMigrationFromLegacyNotifStorage,
+ legacyNotificationsSession);
+ return legacyCryptoModule;
}
void NotificationsCryptoModule::clearSensitiveData() {
@@ -236,26 +160,86 @@
}
}
+void NotificationsCryptoModule::persistNotificationsSessionInternal(
+ const std::string &keyserverID,
+ const std::string &picklingKey,
+ std::shared_ptr<crypto::Session> session) {
+ std::string serializedSession =
+ NotificationsCryptoModule::serializeNotificationsSession(
+ session, picklingKey);
+ std::string keyserverNotificationsSessionKey =
+ NotificationsCryptoModule::getKeyserverNotificationsSessionKey(
+ keyserverID);
+
+ bool sessionStored =
+ CommMMKV::setString(keyserverNotificationsSessionKey, serializedSession);
+
+ if (!sessionStored) {
+ throw std::runtime_error(
+ "Failed to persist to MMKV notifications session for keyserver: " +
+ keyserverID);
+ }
+}
+
+std::pair<std::unique_ptr<crypto::Session>, std::string>
+NotificationsCryptoModule::fetchNotificationsSession(
+ const std::string &keyserverID) {
+ std::string keyserverNotificationsSessionKey =
+ NotificationsCryptoModule::getKeyserverNotificationsSessionKey(
+ keyserverID);
+ std::optional<std::string> serializedSession =
+ CommMMKV::getString(keyserverNotificationsSessionKey);
+
+ if (!serializedSession.has_value()) {
+ throw std::runtime_error(
+ "Missing notifications session for keyserver: " + keyserverID);
+ }
+
+ return NotificationsCryptoModule::deserializeNotificationsSession(
+ serializedSession.value());
+}
+
+void NotificationsCryptoModule::persistNotificationsSession(
+ const std::string &keyserverID,
+ std::shared_ptr<crypto::Session> keyserverNotificationsSession) {
+ std::string picklingKey = crypto::Tools::generateRandomString(64);
+ NotificationsCryptoModule::persistNotificationsSessionInternal(
+ keyserverID, picklingKey, keyserverNotificationsSession);
+}
+
+bool NotificationsCryptoModule::isNotificationsSessionInitialized(
+ const std::string &keyserverID) {
+ std::string keyserverNotificationsSessionKey =
+ "KEYSERVER." + keyserverID + ".NOTIFS_SESSION";
+ return CommMMKV::getString(keyserverNotificationsSessionKey).has_value();
+}
+
std::string NotificationsCryptoModule::decrypt(
+ const std::string &keyserverID,
const std::string &data,
- const size_t messageType,
- const std::string &callingProcessName) {
- std::string decryptedData;
- auto caller = [&](const std::unique_ptr<crypto::CryptoModule> &cryptoModule) {
- crypto::EncryptedData encryptedData{
- std::vector<uint8_t>(data.begin(), data.end()), messageType};
- decryptedData = cryptoModule->decrypt(
- NotificationsCryptoModule::keyserverHostedNotificationsID,
- encryptedData);
- };
- NotificationsCryptoModule::callCryptoModule(caller, callingProcessName);
+ const size_t messageType) {
+ std::unique_ptr<crypto::Session> session;
+ std::string picklingKey;
+ std::tie(session, picklingKey) =
+ NotificationsCryptoModule::fetchNotificationsSession(keyserverID);
+
+ crypto::EncryptedData encryptedData{
+ std::vector<uint8_t>(data.begin(), data.end()), messageType};
+ std::string decryptedData = session->decrypt(encryptedData);
+ NotificationsCryptoModule::persistNotificationsSessionInternal(
+ keyserverID, picklingKey, std::move(session));
return decryptedData;
}
NotificationsCryptoModule::StatefulDecryptResult::StatefulDecryptResult(
- std::unique_ptr<crypto::CryptoModule> cryptoModule,
+ std::unique_ptr<crypto::Session> session,
+ std::string keyserverID,
+ std::string picklingKey,
std::string decryptedData)
- : cryptoModuleState(std::move(cryptoModule)), decryptedData(decryptedData) {
+ : sessionState(std::move(session)),
+ keyserverID(keyserverID),
+ picklingKey(picklingKey),
+ decryptedData(decryptedData) {
}
std::string
@@ -263,37 +247,39 @@
return this->decryptedData;
}
+std::string NotificationsCryptoModule::StatefulDecryptResult::getKeyserverID() {
+ return this->keyserverID;
+}
+
+std::string NotificationsCryptoModule::StatefulDecryptResult::getPicklingKey() {
+ return this->picklingKey;
+}
+
std::unique_ptr<NotificationsCryptoModule::StatefulDecryptResult>
NotificationsCryptoModule::statefulDecrypt(
+ const std::string &keyserverID,
const std::string &data,
const size_t messageType) {
- std::string path = PlatformSpecificTools::getNotificationsCryptoAccountPath();
- std::string picklingKey = NotificationsCryptoModule::getPicklingKey();
+ std::unique_ptr<crypto::Session> session;
+ std::string picklingKey;
+ std::tie(session, picklingKey) =
+ NotificationsCryptoModule::fetchNotificationsSession(keyserverID);
- std::unique_ptr<crypto::CryptoModule> cryptoModule =
- NotificationsCryptoModule::deserializeCryptoModule(path, picklingKey);
crypto::EncryptedData encryptedData{
std::vector<uint8_t>(data.begin(), data.end()), messageType};
- std::string decryptedData = cryptoModule->decrypt(
- NotificationsCryptoModule::keyserverHostedNotificationsID, encryptedData);
- StatefulDecryptResult statefulDecryptResult(
- std::move(cryptoModule), decryptedData);
+ std::string decryptedData = session->decrypt(encryptedData);
+ StatefulDecryptResult statefulDecryptResult(
+ std::move(session), keyserverID, picklingKey, decryptedData);
return std::make_unique<StatefulDecryptResult>(
std::move(statefulDecryptResult));
}
void NotificationsCryptoModule::flushState(
- std::unique_ptr<StatefulDecryptResult> statefulDecryptResult,
- const std::string &callingProcessName) {
-
- std::string path = PlatformSpecificTools::getNotificationsCryptoAccountPath();
- std::string picklingKey = NotificationsCryptoModule::getPicklingKey();
-
- NotificationsCryptoModule::serializeAndFlushCryptoModule(
- std::move(statefulDecryptResult->cryptoModuleState),
- path,
- picklingKey,
- callingProcessName);
+ std::unique_ptr<StatefulDecryptResult> statefulDecryptResult) {
+ NotificationsCryptoModule::persistNotificationsSessionInternal(
+ statefulDecryptResult->getKeyserverID(),
+ statefulDecryptResult->getPicklingKey(),
+ std::move(statefulDecryptResult->sessionState));
}
} // namespace comm
diff --git a/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModuleJNIHelper.h b/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModuleJNIHelper.h
--- a/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModuleJNIHelper.h
+++ b/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModuleJNIHelper.h
@@ -14,10 +14,10 @@
static std::string decrypt(
facebook::jni::alias_ref<NotificationsCryptoModuleJNIHelper> jThis,
+ std::string keyserverID,
std::string data,
- int messageType,
- std::string callingProcessName);
+ int messageType);
static void registerNatives();
};
-} // namespace comm
\ No newline at end of file
+} // namespace comm
diff --git a/native/ios/NotificationService/NotificationService.mm b/native/ios/NotificationService/NotificationService.mm
--- a/native/ios/NotificationService/NotificationService.mm
+++ b/native/ios/NotificationService/NotificationService.mm
@@ -20,7 +20,7 @@
const std::string mmkvKeySeparator = ".";
const std::string mmkvKeyserverPrefix = "KEYSERVER";
const std::string mmkvUnreadCountSuffix = "UNREAD_COUNT";
-const std::string callingProcessName = "NSE";
+
// The context for this constant can be found here:
// https://linear.app/comm/issue/ENG-3074#comment-bd2f5e28
int64_t const notificationRemovalDelay = (int64_t)(0.1 * NSEC_PER_SEC);
@@ -279,7 +279,7 @@
if (decryptionExecuted) {
comm::NotificationsCryptoModule::flushState(
- std::move(statefulDecryptResultPtr), callingProcessName);
+ std::move(statefulDecryptResultPtr));
}
}
@@ -549,8 +549,17 @@
std::string encryptedData =
std::string([content.userInfo[encryptedPayloadKey] UTF8String]);
+ if (!content.userInfo[keyserverIDKey]) {
+ throw std::runtime_error(
+ "Received encrypted notification without keyserverID.");
+ }
+ std::string senderKeyserverID =
+ std::string([content.userInfo[keyserverIDKey] UTF8String]);
+
auto decryptResult = comm::NotificationsCryptoModule::statefulDecrypt(
- encryptedData, comm::NotificationsCryptoModule::olmEncryptedTypeMessage);
+ senderKeyserverID,
+ encryptedData,
+ comm::NotificationsCryptoModule::olmEncryptedTypeMessage);
NSString *decryptedSerializedPayload =
[NSString stringWithUTF8String:decryptResult->getDecryptedData().c_str()];
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

File Metadata

Mime Type
text/plain
Expires
Tue, Dec 9, 8:46 AM (6 h, 39 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5850487
Default Alt Text
D11234.1765269960.diff (32 KB)

Event Timeline