Page MenuHomePhabricator

D12668.id43129.diff
No OneTemporary

D12668.id43129.diff

diff --git a/native/cpp/CommonCpp/NativeModules/CommCoreModule.h b/native/cpp/CommonCpp/NativeModules/CommCoreModule.h
--- a/native/cpp/CommonCpp/NativeModules/CommCoreModule.h
+++ b/native/cpp/CommonCpp/NativeModules/CommCoreModule.h
@@ -133,6 +133,13 @@
jsi::String deviceID,
double sessionVersion,
bool overwrite) override;
+ virtual jsi::Value initializeNotificationsOutboundSession(
+ jsi::Runtime &rt,
+ jsi::String identityKeys,
+ jsi::String prekey,
+ jsi::String prekeySignature,
+ std::optional<jsi::String> oneTimeKey,
+ jsi::String deviceID) override;
virtual jsi::Value
encrypt(jsi::Runtime &rt, jsi::String message, jsi::String deviceID) override;
virtual jsi::Value encryptAndPersist(
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
@@ -851,6 +851,19 @@
return jsiOneTimeKeysResult;
}
+jsi::Object parseEncryptedData(
+ jsi::Runtime &rt,
+ const crypto::EncryptedData &encryptedData) {
+ auto encryptedDataJSI = jsi::Object(rt);
+ auto message =
+ std::string{encryptedData.message.begin(), encryptedData.message.end()};
+ auto messageJSI = jsi::String::createFromUtf8(rt, message);
+ encryptedDataJSI.setProperty(rt, "message", messageJSI);
+ encryptedDataJSI.setProperty(
+ rt, "messageType", static_cast<int>(encryptedData.messageType));
+ return encryptedDataJSI;
+}
+
jsi::Value
CommCoreModule::getOneTimeKeys(jsi::Runtime &rt, double oneTimeKeysAmount) {
return createPromiseAsJSIValue(
@@ -1148,6 +1161,8 @@
NotificationsCryptoModule::persistNotificationsSession(
keyserverIDCpp, keyserverNotificationsSession);
+ // Session is removed from the account since it is persisted
+ // at different location that the account after serialization
this->notifsCryptoModule->removeSessionByDeviceId(keyserverIDCpp);
this->persistCryptoModules(false, true);
} catch (const std::exception &e) {
@@ -1373,17 +1388,8 @@
promise->reject(error);
return;
}
- auto initialEncryptedDataJSI = jsi::Object(innerRt);
- auto message = std::string{
- initialEncryptedData.message.begin(),
- initialEncryptedData.message.end()};
- auto messageJSI = jsi::String::createFromUtf8(innerRt, message);
- initialEncryptedDataJSI.setProperty(innerRt, "message", messageJSI);
- initialEncryptedDataJSI.setProperty(
- innerRt,
- "messageType",
- static_cast<int>(initialEncryptedData.messageType));
-
+ auto initialEncryptedDataJSI =
+ parseEncryptedData(innerRt, initialEncryptedData);
auto outboundSessionCreationResultJSI = jsi::Object(innerRt);
outboundSessionCreationResultJSI.setProperty(
innerRt, "encryptedData", initialEncryptedDataJSI);
@@ -1447,6 +1453,73 @@
});
}
+jsi::Value CommCoreModule::initializeNotificationsOutboundSession(
+ jsi::Runtime &rt,
+ jsi::String identityKeys,
+ jsi::String prekey,
+ jsi::String prekeySignature,
+ std::optional<jsi::String> oneTimeKey,
+ jsi::String deviceID) {
+ auto identityKeysCpp{identityKeys.utf8(rt)};
+ auto prekeyCpp{prekey.utf8(rt)};
+ auto prekeySignatureCpp{prekeySignature.utf8(rt)};
+ auto deviceIDCpp{deviceID.utf8(rt)};
+
+ std::optional<std::string> oneTimeKeyCpp;
+ if (oneTimeKey) {
+ oneTimeKeyCpp = oneTimeKey->utf8(rt);
+ }
+
+ return createPromiseAsJSIValue(
+ rt, [=](jsi::Runtime &innerRt, std::shared_ptr<Promise> promise) {
+ taskType job = [=, &innerRt]() {
+ std::string error;
+ crypto::EncryptedData result;
+ try {
+ std::optional<crypto::OlmBuffer> oneTimeKeyBuffer;
+ if (oneTimeKeyCpp) {
+ oneTimeKeyBuffer = crypto::OlmBuffer(
+ oneTimeKeyCpp->begin(), oneTimeKeyCpp->end());
+ }
+ this->notifsCryptoModule->initializeOutboundForSendingSession(
+ deviceIDCpp,
+ std::vector<uint8_t>(
+ identityKeysCpp.begin(), identityKeysCpp.end()),
+ std::vector<uint8_t>(prekeyCpp.begin(), prekeyCpp.end()),
+ std::vector<uint8_t>(
+ prekeySignatureCpp.begin(), prekeySignatureCpp.end()),
+ oneTimeKeyBuffer);
+
+ result = this->notifsCryptoModule->encrypt(
+ deviceIDCpp,
+ NotificationsCryptoModule::initialEncryptedMessageContent);
+
+ std::shared_ptr<crypto::Session> peerNotificationsSession =
+ this->notifsCryptoModule->getSessionByDeviceId(deviceIDCpp);
+
+ NotificationsCryptoModule::persistDeviceNotificationsSession(
+ deviceIDCpp, peerNotificationsSession);
+
+ // Session is removed from the account since it is persisted
+ // at different location that the account after serialization
+ this->notifsCryptoModule->removeSessionByDeviceId(deviceIDCpp);
+ this->persistCryptoModules(false, true);
+ } catch (const std::exception &e) {
+ error = e.what();
+ }
+ this->jsInvoker_->invokeAsync([=, &innerRt]() {
+ if (error.size()) {
+ promise->reject(error);
+ return;
+ }
+ auto initialEncryptedDataJSI = parseEncryptedData(innerRt, result);
+ promise->resolve(std::move(initialEncryptedDataJSI));
+ });
+ };
+ this->cryptoThread->scheduleTask(job);
+ });
+}
+
jsi::Value CommCoreModule::encrypt(
jsi::Runtime &rt,
jsi::String message,
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
@@ -23,17 +23,22 @@
static std::string
getKeyserverNotificationsSessionKey(const std::string &keyserverID);
+ static std::string
+ getDeviceNotificationsSessionKey(const std::string &deviceID);
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,
+ bool isKeyserverSession,
+ const std::string &senderID,
const std::string &picklingKey,
std::shared_ptr<crypto::Session> session);
static std::optional<std::pair<std::unique_ptr<crypto::Session>, std::string>>
- fetchNotificationsSession(const std::string &keyserverID);
+ fetchNotificationsSession(
+ bool isKeyserverSession,
+ const std::string &senderID);
public:
const static std::string initialEncryptedMessageContent;
@@ -43,7 +48,12 @@
static void persistNotificationsSession(
const std::string &keyserverID,
std::shared_ptr<crypto::Session> keyserverNotificationsSession);
+ static void persistDeviceNotificationsSession(
+ const std::string &deviceID,
+ std::shared_ptr<crypto::Session> peerNotificationsSession);
static bool isNotificationsSessionInitialized(const std::string &keyserverID);
+ static bool
+ isDeviceNotificationsSessionInitialized(const std::string &deviceID);
class BaseStatefulDecryptResult {
BaseStatefulDecryptResult(
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
@@ -151,6 +151,11 @@
return "KEYSERVER." + keyserverID + ".NOTIFS_SESSION";
}
+std::string NotificationsCryptoModule::getDeviceNotificationsSessionKey(
+ const std::string &deviceID) {
+ return "DEVICE." + deviceID + ".NOTIFS_SESSION";
+}
+
std::string NotificationsCryptoModule::serializeNotificationsSession(
std::shared_ptr<crypto::Session> session,
std::string picklingKey) {
@@ -194,45 +199,65 @@
}
void NotificationsCryptoModule::persistNotificationsSessionInternal(
- const std::string &keyserverID,
+ bool isKeyserverSession,
+ const std::string &senderID,
const std::string &picklingKey,
std::shared_ptr<crypto::Session> session) {
std::string serializedSession =
NotificationsCryptoModule::serializeNotificationsSession(
session, picklingKey);
- std::string keyserverNotificationsSessionKey =
- NotificationsCryptoModule::getKeyserverNotificationsSessionKey(
- keyserverID);
+
+ std::string notificationsSessionKey;
+ std::string persistenceErrorMessage;
+
+ if (isKeyserverSession) {
+ notificationsSessionKey =
+ NotificationsCryptoModule::getKeyserverNotificationsSessionKey(
+ senderID);
+ persistenceErrorMessage =
+ "Failed to persist to MMKV notifications session for keyserver: " +
+ senderID;
+ } else {
+ notificationsSessionKey =
+ NotificationsCryptoModule::getDeviceNotificationsSessionKey(senderID);
+ persistenceErrorMessage =
+ "Failed to persist to MMKV notifications session for device: " +
+ senderID;
+ }
bool sessionStored =
- CommMMKV::setString(keyserverNotificationsSessionKey, serializedSession);
+ CommMMKV::setString(notificationsSessionKey, serializedSession);
if (!sessionStored) {
- throw std::runtime_error(
- "Failed to persist to MMKV notifications session for keyserver: " +
- keyserverID);
+ throw std::runtime_error(persistenceErrorMessage);
}
}
std::optional<std::pair<std::unique_ptr<crypto::Session>, std::string>>
NotificationsCryptoModule::fetchNotificationsSession(
- const std::string &keyserverID) {
- std::string keyserverNotificationsSessionKey =
- NotificationsCryptoModule::getKeyserverNotificationsSessionKey(
- keyserverID);
+ bool isKeyserverSession,
+ const std::string &senderID) {
+ std::string notificationsSessionKey;
+ if (isKeyserverSession) {
+ notificationsSessionKey =
+ NotificationsCryptoModule::getKeyserverNotificationsSessionKey(
+ senderID);
+ } else {
+ notificationsSessionKey =
+ NotificationsCryptoModule::getDeviceNotificationsSessionKey(senderID);
+ }
std::optional<std::string> serializedSession;
try {
- serializedSession = CommMMKV::getString(keyserverNotificationsSessionKey);
+ serializedSession = CommMMKV::getString(notificationsSessionKey);
} catch (const CommMMKV::InitFromNSEForbiddenError &e) {
serializedSession = std::nullopt;
}
- if (!serializedSession.has_value() &&
- keyserverID !=
- ashoatKeyserverIDUsedOnlyForMigrationFromLegacyNotifStorage) {
+ if (!serializedSession.has_value() && isKeyserverSession &&
+ senderID != ashoatKeyserverIDUsedOnlyForMigrationFromLegacyNotifStorage) {
throw std::runtime_error(
- "Missing notifications session for keyserver: " + keyserverID);
+ "Missing notifications session for keyserver: " + senderID);
} else if (!serializedSession.has_value()) {
return std::nullopt;
}
@@ -246,16 +271,31 @@
std::shared_ptr<crypto::Session> keyserverNotificationsSession) {
std::string picklingKey = crypto::Tools::generateRandomString(64);
NotificationsCryptoModule::persistNotificationsSessionInternal(
- keyserverID, picklingKey, keyserverNotificationsSession);
+ true, keyserverID, picklingKey, keyserverNotificationsSession);
+}
+
+void NotificationsCryptoModule::persistDeviceNotificationsSession(
+ const std::string &deviceID,
+ std::shared_ptr<crypto::Session> peerNotificationsSession) {
+ std::string picklingKey = crypto::Tools::generateRandomString(64);
+ NotificationsCryptoModule::persistNotificationsSessionInternal(
+ false, deviceID, picklingKey, peerNotificationsSession);
}
bool NotificationsCryptoModule::isNotificationsSessionInitialized(
const std::string &keyserverID) {
std::string keyserverNotificationsSessionKey =
- "KEYSERVER." + keyserverID + ".NOTIFS_SESSION";
+ getKeyserverNotificationsSessionKey(keyserverID);
return CommMMKV::getString(keyserverNotificationsSessionKey).has_value();
}
+bool NotificationsCryptoModule::isDeviceNotificationsSessionInitialized(
+ const std::string &deviceID) {
+ std::string peerNotificationsSessionKey =
+ getDeviceNotificationsSessionKey(deviceID);
+ return CommMMKV::getString(peerNotificationsSessionKey).has_value();
+}
+
NotificationsCryptoModule::BaseStatefulDecryptResult::BaseStatefulDecryptResult(
std::string picklingKey,
std::string decryptedData)
@@ -280,7 +320,10 @@
void NotificationsCryptoModule::StatefulDecryptResult::flushState() {
NotificationsCryptoModule::persistNotificationsSessionInternal(
- this->keyserverID, this->picklingKey, std::move(this->sessionState));
+ true,
+ this->keyserverID,
+ this->picklingKey,
+ std::move(this->sessionState));
}
NotificationsCryptoModule::LegacyStatefulDecryptResult::
@@ -349,7 +392,7 @@
const size_t messageType) {
auto sessionWithPicklingKey =
- NotificationsCryptoModule::fetchNotificationsSession(keyserverID);
+ NotificationsCryptoModule::fetchNotificationsSession(true, keyserverID);
if (!sessionWithPicklingKey.has_value()) {
auto statefulDecryptResult =
NotificationsCryptoModule::prepareLegacyDecryptedState(
@@ -366,7 +409,7 @@
std::string decryptedData = session->decrypt(encryptedData);
NotificationsCryptoModule::persistNotificationsSessionInternal(
- keyserverID, picklingKey, std::move(session));
+ true, keyserverID, picklingKey, std::move(session));
return decryptedData;
}
@@ -377,7 +420,7 @@
const size_t messageType) {
auto sessionWithPicklingKey =
- NotificationsCryptoModule::fetchNotificationsSession(keyserverID);
+ NotificationsCryptoModule::fetchNotificationsSession(true, keyserverID);
if (!sessionWithPicklingKey.has_value()) {
return NotificationsCryptoModule::prepareLegacyDecryptedState(
data, messageType);
diff --git a/native/cpp/CommonCpp/_generated/commJSI-generated.cpp b/native/cpp/CommonCpp/_generated/commJSI-generated.cpp
--- a/native/cpp/CommonCpp/_generated/commJSI-generated.cpp
+++ b/native/cpp/CommonCpp/_generated/commJSI-generated.cpp
@@ -84,6 +84,9 @@
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_initializeContentInboundSession(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->initializeContentInboundSession(rt, args[0].asString(rt), args[1].asObject(rt), args[2].asString(rt), args[3].asNumber(), args[4].asBool());
}
+static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_initializeNotificationsOutboundSession(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
+ return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->initializeNotificationsOutboundSession(rt, args[0].asString(rt), args[1].asString(rt), args[2].asString(rt), args[3].isNull() || args[3].isUndefined() ? std::nullopt : std::make_optional(args[3].asString(rt)), args[4].asString(rt));
+}
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_encrypt(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->encrypt(rt, args[0].asString(rt), args[1].asString(rt));
}
@@ -243,6 +246,7 @@
methodMap_["getKeyserverDataFromNotifStorage"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getKeyserverDataFromNotifStorage};
methodMap_["initializeContentOutboundSession"] = MethodMetadata {5, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_initializeContentOutboundSession};
methodMap_["initializeContentInboundSession"] = MethodMetadata {5, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_initializeContentInboundSession};
+ methodMap_["initializeNotificationsOutboundSession"] = MethodMetadata {5, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_initializeNotificationsOutboundSession};
methodMap_["encrypt"] = MethodMetadata {2, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_encrypt};
methodMap_["encryptAndPersist"] = MethodMetadata {3, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_encryptAndPersist};
methodMap_["decrypt"] = MethodMetadata {2, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_decrypt};
diff --git a/native/cpp/CommonCpp/_generated/commJSI.h b/native/cpp/CommonCpp/_generated/commJSI.h
--- a/native/cpp/CommonCpp/_generated/commJSI.h
+++ b/native/cpp/CommonCpp/_generated/commJSI.h
@@ -43,6 +43,7 @@
virtual jsi::Value getKeyserverDataFromNotifStorage(jsi::Runtime &rt, jsi::Array keyserverIDs) = 0;
virtual jsi::Value initializeContentOutboundSession(jsi::Runtime &rt, jsi::String identityKeys, jsi::String prekey, jsi::String prekeySignature, std::optional<jsi::String> oneTimeKey, jsi::String deviceID) = 0;
virtual jsi::Value initializeContentInboundSession(jsi::Runtime &rt, jsi::String identityKeys, jsi::Object encryptedContent, jsi::String deviceID, double sessionVersion, bool overwrite) = 0;
+ virtual jsi::Value initializeNotificationsOutboundSession(jsi::Runtime &rt, jsi::String identityKeys, jsi::String prekey, jsi::String prekeySignature, std::optional<jsi::String> oneTimeKey, jsi::String deviceID) = 0;
virtual jsi::Value encrypt(jsi::Runtime &rt, jsi::String message, jsi::String deviceID) = 0;
virtual jsi::Value encryptAndPersist(jsi::Runtime &rt, jsi::String message, jsi::String deviceID, jsi::String messageID) = 0;
virtual jsi::Value decrypt(jsi::Runtime &rt, jsi::Object encryptedData, jsi::String deviceID) = 0;
@@ -291,6 +292,14 @@
return bridging::callFromJs<jsi::Value>(
rt, &T::initializeContentInboundSession, jsInvoker_, instance_, std::move(identityKeys), std::move(encryptedContent), std::move(deviceID), std::move(sessionVersion), std::move(overwrite));
}
+ jsi::Value initializeNotificationsOutboundSession(jsi::Runtime &rt, jsi::String identityKeys, jsi::String prekey, jsi::String prekeySignature, std::optional<jsi::String> oneTimeKey, jsi::String deviceID) override {
+ static_assert(
+ bridging::getParameterCount(&T::initializeNotificationsOutboundSession) == 6,
+ "Expected initializeNotificationsOutboundSession(...) to have 6 parameters");
+
+ return bridging::callFromJs<jsi::Value>(
+ rt, &T::initializeNotificationsOutboundSession, jsInvoker_, instance_, std::move(identityKeys), std::move(prekey), std::move(prekeySignature), std::move(oneTimeKey), std::move(deviceID));
+ }
jsi::Value encrypt(jsi::Runtime &rt, jsi::String message, jsi::String deviceID) override {
static_assert(
bridging::getParameterCount(&T::encrypt) == 3,
diff --git a/native/schema/CommCoreModuleSchema.js b/native/schema/CommCoreModuleSchema.js
--- a/native/schema/CommCoreModuleSchema.js
+++ b/native/schema/CommCoreModuleSchema.js
@@ -91,6 +91,13 @@
sessionVersion: number,
overwrite: boolean,
) => Promise<string>;
+ +initializeNotificationsOutboundSession: (
+ identityKeys: string,
+ prekey: string,
+ prekeySignature: string,
+ oneTimeKey: ?string,
+ deviceID: string,
+ ) => Promise<EncryptedData>;
+encrypt: (message: string, deviceID: string) => Promise<EncryptedData>;
+encryptAndPersist: (
message: string,

File Metadata

Mime Type
text/plain
Expires
Tue, Nov 26, 5:00 AM (20 h, 18 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2580515
Default Alt Text
D12668.id43129.diff (19 KB)

Event Timeline