Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3363354
D12668.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
19 KB
Referenced Files
None
Subscribers
None
D12668.diff
View Options
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
Details
Attached
Mime Type
text/plain
Expires
Tue, Nov 26, 1:54 AM (17 h, 12 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2580515
Default Alt Text
D12668.diff (19 KB)
Attached To
Mode
D12668: Implement peer notifications session creation as outbound on native
Attached
Detach File
Event Timeline
Log In to Comment