Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F32285121
D11234.1765269960.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
32 KB
Referenced Files
None
Subscribers
None
D11234.1765269960.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D11234: Implement notifications sessions storage on top of MMKV. Migrate existing notifs account to SQLite
Attached
Detach File
Event Timeline
Log In to Comment