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 @@ -48,6 +48,10 @@ void persistCryptoModules(bool persistContentModule, bool persistNotifsModule); + jsi::Value createNewBackupInternal( + jsi::Runtime &rt, + std::string backupSecret, + std::string backupMessage); virtual jsi::Value getDraft(jsi::Runtime &rt, jsi::String key) override; virtual jsi::Value @@ -169,6 +173,10 @@ virtual void stopBackupHandler(jsi::Runtime &rt) override; virtual jsi::Value createNewBackup(jsi::Runtime &rt, jsi::String backupSecret) override; + virtual jsi::Value createNewSIWEBackup( + jsi::Runtime &rt, + jsi::String backupSecret, + jsi::String siweBackupMsg) override; virtual jsi::Value restoreBackup(jsi::Runtime &rt, jsi::String backupSecret) override; virtual jsi::Value restoreBackupData( 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 @@ -1918,9 +1918,10 @@ } } -jsi::Value -CommCoreModule::createNewBackup(jsi::Runtime &rt, jsi::String backupSecret) { - std::string backupSecretStr = backupSecret.utf8(rt); +jsi::Value CommCoreModule::createNewBackupInternal( + jsi::Runtime &rt, + std::string backupSecret, + std::string backupMessage) { return createPromiseAsJSIValue( rt, [=](jsi::Runtime &innerRt, std::shared_ptr promise) { this->cryptoThread->scheduleTask([=, &innerRt]() { @@ -1952,9 +1953,10 @@ {promise, this->jsInvoker_, innerRt}); ::createBackup( rust::string(backupID), - rust::string(backupSecretStr), + rust::string(backupSecret), rust::string(pickleKey), rust::string(pickledAccount), + rust::string(backupMessage), currentID); } else { this->jsInvoker_->invokeAsync( @@ -1964,6 +1966,21 @@ }); } +jsi::Value +CommCoreModule::createNewBackup(jsi::Runtime &rt, jsi::String backupSecret) { + std::string backupSecretStr = backupSecret.utf8(rt); + return createNewBackupInternal(rt, backupSecretStr, ""); +} + +jsi::Value CommCoreModule::createNewSIWEBackup( + jsi::Runtime &rt, + jsi::String backupSecret, + jsi::String siweBackupMsg) { + std::string backupSecretStr = backupSecret.utf8(rt); + std::string siweBackupMsgStr = siweBackupMsg.utf8(rt); + return createNewBackupInternal(rt, backupSecretStr, siweBackupMsgStr); +} + jsi::Value CommCoreModule::restoreBackup(jsi::Runtime &rt, jsi::String backupSecret) { std::string backupSecretStr = backupSecret.utf8(rt); 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 @@ -157,6 +157,9 @@ static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_createNewBackup(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->createNewBackup(rt, args[0].asString(rt)); } +static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_createNewSIWEBackup(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->createNewSIWEBackup(rt, args[0].asString(rt), args[1].asString(rt)); +} static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_restoreBackup(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->restoreBackup(rt, args[0].asString(rt)); } @@ -227,6 +230,7 @@ methodMap_["startBackupHandler"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_startBackupHandler}; methodMap_["stopBackupHandler"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_stopBackupHandler}; methodMap_["createNewBackup"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_createNewBackup}; + methodMap_["createNewSIWEBackup"] = MethodMetadata {2, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_createNewSIWEBackup}; methodMap_["restoreBackup"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_restoreBackup}; methodMap_["restoreBackupData"] = MethodMetadata {3, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_restoreBackupData}; methodMap_["retrieveBackupKeys"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_retrieveBackupKeys}; 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 @@ -66,6 +66,7 @@ virtual void startBackupHandler(jsi::Runtime &rt) = 0; virtual void stopBackupHandler(jsi::Runtime &rt) = 0; virtual jsi::Value createNewBackup(jsi::Runtime &rt, jsi::String backupSecret) = 0; + virtual jsi::Value createNewSIWEBackup(jsi::Runtime &rt, jsi::String backupSecret, jsi::String siweBackupMsg) = 0; virtual jsi::Value restoreBackup(jsi::Runtime &rt, jsi::String backupSecret) = 0; virtual jsi::Value restoreBackupData(jsi::Runtime &rt, jsi::String backupID, jsi::String backupDataKey, jsi::String backupLogDataKey) = 0; virtual jsi::Value retrieveBackupKeys(jsi::Runtime &rt, jsi::String backupSecret) = 0; @@ -462,6 +463,14 @@ return bridging::callFromJs( rt, &T::createNewBackup, jsInvoker_, instance_, std::move(backupSecret)); } + jsi::Value createNewSIWEBackup(jsi::Runtime &rt, jsi::String backupSecret, jsi::String siweBackupMsg) override { + static_assert( + bridging::getParameterCount(&T::createNewSIWEBackup) == 3, + "Expected createNewSIWEBackup(...) to have 3 parameters"); + + return bridging::callFromJs( + rt, &T::createNewSIWEBackup, jsInvoker_, instance_, std::move(backupSecret), std::move(siweBackupMsg)); + } jsi::Value restoreBackup(jsi::Runtime &rt, jsi::String backupSecret) override { static_assert( bridging::getParameterCount(&T::restoreBackup) == 2, diff --git a/native/native_rust_library/src/backup.rs b/native/native_rust_library/src/backup.rs --- a/native/native_rust_library/src/backup.rs +++ b/native/native_rust_library/src/backup.rs @@ -6,9 +6,9 @@ use crate::constants::{aes, secure_store}; use crate::ffi::{ create_main_compaction, get_backup_directory_path, - get_backup_user_keys_file_path, restore_from_backup_log, - restore_from_main_compaction, secure_store_get, string_callback, - void_callback, + get_backup_user_keys_file_path, get_siwe_backup_message_path, + restore_from_backup_log, restore_from_main_compaction, secure_store_get, + string_callback, void_callback, }; use crate::utils::future_manager; use crate::utils::jsi_callbacks::handle_string_result_as_callback; @@ -32,6 +32,7 @@ backup_secret: String, pickle_key: String, pickled_account: String, + siwe_backup_msg: String, promise_id: u32, ) { compaction_upload_promises::insert(backup_id.clone(), promise_id); @@ -51,6 +52,15 @@ return; } + if !siwe_backup_msg.is_empty() { + if let Err(err) = + create_siwe_backup_msg_compaction(&backup_id, siwe_backup_msg).await + { + compaction_upload_promises::resolve(&backup_id, Err(err.to_string())); + return; + } + } + let (future_id, future) = future_manager::new_future::<()>().await; create_main_compaction(&backup_id, future_id); if let Err(err) = future.await { @@ -200,6 +210,16 @@ Ok(()) } +pub async fn create_siwe_backup_msg_compaction( + backup_id: &String, + siwe_backup_msg: String, +) -> Result<(), Box> { + let siwe_backup_msg_file = get_siwe_backup_message_path(&backup_id)?; + tokio::fs::write(siwe_backup_msg_file, siwe_backup_msg).await?; + + Ok(()) +} + async fn download_backup( backup_secret: String, ) -> Result> { diff --git a/native/native_rust_library/src/backup/upload_handler.rs b/native/native_rust_library/src/backup/upload_handler.rs --- a/native/native_rust_library/src/backup/upload_handler.rs +++ b/native/native_rust_library/src/backup/upload_handler.rs @@ -4,7 +4,7 @@ use crate::constants::BACKUP_SERVICE_CONNECTION_RETRY_DELAY; use crate::ffi::{ get_backup_directory_path, get_backup_file_path, get_backup_log_file_path, - get_backup_user_keys_file_path, + get_backup_user_keys_file_path, get_siwe_backup_message_path, }; use crate::BACKUP_SOCKET_ADDR; use crate::RUNTIME; @@ -103,6 +103,7 @@ | BackupHandlerError::LockError => break, BackupHandlerError::IoError(_) | BackupHandlerError::CxxException(_) => continue, + BackupHandlerError::FromUtf8Error(_) => break, } } @@ -207,11 +208,22 @@ Err(err) => return Err(err.into()), }; + let siwe_backup_msg_path = get_siwe_backup_message_path(&backup_id)?; + let siwe_backup_msg = match tokio::fs::read(&siwe_backup_msg_path).await { + Ok(data) => match String::from_utf8(data) { + Ok(valid_string) => Some(valid_string), + Err(err) => return Err(err.into()), + }, + Err(err) if err.kind() == ErrorKind::NotFound => None, + Err(err) => return Err(err.into()), + }; + let backup_data = BackupData { backup_id: backup_id.clone(), user_data, user_keys, attachments, + siwe_backup_msg, }; backup_client @@ -235,6 +247,12 @@ Ok(()) => Result::<_, Box>::Ok(()), Err(err) if err.kind() == ErrorKind::NotFound => Ok(()), Err(err) => Err(err.into()), + }?; + let siwe_backup_msg_path = get_siwe_backup_message_path(&backup_id)?; + match tokio::fs::remove_file(&siwe_backup_msg_path).await { + Ok(()) => Result::<_, Box>::Ok(()), + Err(err) if err.kind() == ErrorKind::NotFound => Ok(()), + Err(err) => Err(err.into()), } }; @@ -309,6 +327,7 @@ IoError(std::io::Error), CxxException(cxx::Exception), LockError, + FromUtf8Error(std::string::FromUtf8Error), } impl From> for BackupHandlerError { diff --git a/native/native_rust_library/src/lib.rs b/native/native_rust_library/src/lib.rs --- a/native/native_rust_library/src/lib.rs +++ b/native/native_rust_library/src/lib.rs @@ -355,6 +355,7 @@ backup_secret: String, pickle_key: String, pickled_account: String, + siwe_backup_msg: String, promise_id: u32, ); diff --git a/native/schema/CommCoreModuleSchema.js b/native/schema/CommCoreModuleSchema.js --- a/native/schema/CommCoreModuleSchema.js +++ b/native/schema/CommCoreModuleSchema.js @@ -119,6 +119,10 @@ +startBackupHandler: () => void; +stopBackupHandler: () => void; +createNewBackup: (backupSecret: string) => Promise; + +createNewSIWEBackup: ( + backupSecret: string, + siweBackupMsg: string, + ) => Promise; +restoreBackup: (backupSecret: string) => Promise; +restoreBackupData: ( backupID: string, diff --git a/services/commtest/tests/backup_integration_test.rs b/services/commtest/tests/backup_integration_test.rs --- a/services/commtest/tests/backup_integration_test.rs +++ b/services/commtest/tests/backup_integration_test.rs @@ -160,6 +160,7 @@ Some(b'A'), ), attachments: vec![], + siwe_backup_msg: None, }, generate_log_data("b1", b'a'), ), @@ -175,6 +176,7 @@ Some(b'B'), ), attachments: vec![], + siwe_backup_msg: None, }, generate_log_data("b2", b'b'), ), diff --git a/services/commtest/tests/backup_performance_test.rs b/services/commtest/tests/backup_performance_test.rs --- a/services/commtest/tests/backup_performance_test.rs +++ b/services/commtest/tests/backup_performance_test.rs @@ -35,6 +35,7 @@ Some(i as u8), ), attachments: vec![], + siwe_backup_msg: None, }); } diff --git a/shared/backup_client/src/lib.rs b/shared/backup_client/src/lib.rs --- a/shared/backup_client/src/lib.rs +++ b/shared/backup_client/src/lib.rs @@ -53,10 +53,11 @@ user_keys, user_data, attachments, + siwe_backup_msg, } = backup_data; let client = reqwest::Client::new(); - let form = Form::new() + let mut form = Form::new() .text("backup_id", backup_id) .text( "user_keys_hash", @@ -70,6 +71,10 @@ .part("user_data", Part::stream(Body::from(user_data))) .text("attachments", attachments.join("\n")); + if let Some(siwe_backup_msg_value) = siwe_backup_msg { + form = form.text("siwe_backup_msg", siwe_backup_msg_value); + } + let response = client .post(self.url.join("backups")?) .bearer_auth(user_identity.as_authorization_token()?) @@ -309,6 +314,7 @@ pub user_keys: Vec, pub user_data: Vec, pub attachments: Vec, + pub siwe_backup_msg: Option, } #[derive(Debug, Clone, Serialize, Deserialize)]