Page MenuHomePhabricator

D10859.diff
No OneTemporary

D10859.diff

diff --git a/native/backup/use-client-backup.js b/native/backup/use-client-backup.js
--- a/native/backup/use-client-backup.js
+++ b/native/backup/use-client-backup.js
@@ -16,7 +16,7 @@
};
type ClientBackup = {
- +uploadBackupProtocol: (userData: UserData) => Promise<void>,
+ +uploadBackupProtocol: () => Promise<void>,
+restoreBackupProtocol: (
expectedUserData: UserData,
) => Promise<{ +dataIntegritySuccess: boolean }>,
@@ -37,30 +37,24 @@
);
const loggedIn = useSelector(isLoggedIn);
- const uploadBackupProtocol = React.useCallback(
- async (userData: UserData) => {
- if (!loggedIn || !currentUserID) {
- throw new Error('Attempt to upload backup for not logged in user.');
- }
- console.info('Start uploading backup...');
+ const uploadBackupProtocol = React.useCallback(async () => {
+ if (!loggedIn || !currentUserID) {
+ throw new Error('Attempt to upload backup for not logged in user.');
+ }
+ console.info('Start uploading backup...');
- const ed25519 = await getContentSigningKey();
- await commCoreModule.setCommServicesAuthMetadata(
- currentUserID,
- ed25519,
- accessToken ? accessToken : '',
- );
+ const ed25519 = await getContentSigningKey();
+ await commCoreModule.setCommServicesAuthMetadata(
+ currentUserID,
+ ed25519,
+ accessToken ? accessToken : '',
+ );
- const backupSecret = await getBackupSecret();
- await commCoreModule.createNewBackup(
- backupSecret,
- JSON.stringify(userData),
- );
+ const backupSecret = await getBackupSecret();
+ await commCoreModule.createNewBackup(backupSecret);
- console.info('Backup uploaded.');
- },
- [accessToken, currentUserID, loggedIn],
- );
+ console.info('Backup uploaded.');
+ }, [accessToken, currentUserID, loggedIn]);
const restoreBackupProtocol = React.useCallback(
async (expectedUserData: UserData) => {
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
@@ -23,6 +23,7 @@
std::string SQLiteQueryExecutor::encryptionKey;
std::once_flag SQLiteQueryExecutor::initialized;
int SQLiteQueryExecutor::sqlcipherEncryptionKeySize = 64;
+// Should match constant defined in `native_rust_library/src/constants.rs`
std::string SQLiteQueryExecutor::secureStoreEncryptionKeyID =
"comm.encryptionKey";
int SQLiteQueryExecutor::backupLogsEncryptionKeySize = 32;
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
@@ -135,10 +135,8 @@
virtual jsi::Value clearCommServicesAccessToken(jsi::Runtime &rt) override;
virtual void startBackupHandler(jsi::Runtime &rt) override;
virtual void stopBackupHandler(jsi::Runtime &rt) override;
- virtual jsi::Value createNewBackup(
- jsi::Runtime &rt,
- jsi::String backupSecret,
- jsi::String userData) override;
+ virtual jsi::Value
+ createNewBackup(jsi::Runtime &rt, jsi::String backupSecret) override;
virtual jsi::Value
restoreBackup(jsi::Runtime &rt, jsi::String backupSecret) override;
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
@@ -1426,12 +1426,9 @@
}
}
-jsi::Value CommCoreModule::createNewBackup(
- jsi::Runtime &rt,
- jsi::String backupSecret,
- jsi::String userData) {
+jsi::Value
+CommCoreModule::createNewBackup(jsi::Runtime &rt, jsi::String backupSecret) {
std::string backupSecretStr = backupSecret.utf8(rt);
- std::string userDataStr = userData.utf8(rt);
return createPromiseAsJSIValue(
rt, [=](jsi::Runtime &innerRt, std::shared_ptr<Promise> promise) {
this->cryptoThread->scheduleTask([=, &innerRt]() {
@@ -1466,7 +1463,6 @@
rust::string(backupSecretStr),
rust::string(pickleKey),
rust::string(pickledAccount),
- rust::string(userDataStr),
currentID);
} else {
this->jsInvoker_->invokeAsync(
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
@@ -155,7 +155,7 @@
return jsi::Value::undefined();
}
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_createNewBackup(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
- return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->createNewBackup(rt, args[0].asString(rt), args[1].asString(rt));
+ return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->createNewBackup(rt, args[0].asString(rt));
}
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_restoreBackup(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->restoreBackup(rt, args[0].asString(rt));
@@ -208,7 +208,7 @@
methodMap_["clearCommServicesAccessToken"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_clearCommServicesAccessToken};
methodMap_["startBackupHandler"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_startBackupHandler};
methodMap_["stopBackupHandler"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_stopBackupHandler};
- methodMap_["createNewBackup"] = MethodMetadata {2, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_createNewBackup};
+ methodMap_["createNewBackup"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_createNewBackup};
methodMap_["restoreBackup"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_restoreBackup};
}
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
@@ -65,7 +65,7 @@
virtual jsi::Value clearCommServicesAccessToken(jsi::Runtime &rt) = 0;
virtual void startBackupHandler(jsi::Runtime &rt) = 0;
virtual void stopBackupHandler(jsi::Runtime &rt) = 0;
- virtual jsi::Value createNewBackup(jsi::Runtime &rt, jsi::String backupSecret, jsi::String userData) = 0;
+ virtual jsi::Value createNewBackup(jsi::Runtime &rt, jsi::String backupSecret) = 0;
virtual jsi::Value restoreBackup(jsi::Runtime &rt, jsi::String backupSecret) = 0;
};
@@ -448,13 +448,13 @@
return bridging::callFromJs<void>(
rt, &T::stopBackupHandler, jsInvoker_, instance_);
}
- jsi::Value createNewBackup(jsi::Runtime &rt, jsi::String backupSecret, jsi::String userData) override {
+ jsi::Value createNewBackup(jsi::Runtime &rt, jsi::String backupSecret) override {
static_assert(
- bridging::getParameterCount(&T::createNewBackup) == 3,
- "Expected createNewBackup(...) to have 3 parameters");
+ bridging::getParameterCount(&T::createNewBackup) == 2,
+ "Expected createNewBackup(...) to have 2 parameters");
return bridging::callFromJs<jsi::Value>(
- rt, &T::createNewBackup, jsInvoker_, instance_, std::move(backupSecret), std::move(userData));
+ rt, &T::createNewBackup, jsInvoker_, instance_, std::move(backupSecret));
}
jsi::Value restoreBackup(jsi::Runtime &rt, jsi::String backupSecret) override {
static_assert(
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
@@ -4,14 +4,16 @@
use crate::argon2_tools::{compute_backup_key, compute_backup_key_str};
use crate::constants::{aes, secure_store};
-use crate::ffi::secure_store_get;
+use crate::ffi::{
+ create_main_compaction, get_backup_user_keys_file_path, secure_store_get,
+};
+use crate::future_manager;
+use crate::handle_string_result_as_callback;
use crate::BACKUP_SOCKET_ADDR;
use crate::RUNTIME;
-use crate::{handle_string_result_as_callback, handle_void_result_as_callback};
use backup_client::{
- BackupClient, BackupData, BackupDescriptor, DownloadLogsRequest,
- LatestBackupIDResponse, LogUploadConfirmation, LogWSResponse, RequestedData,
- SinkExt, StreamExt, UploadLogRequest, UserIdentity,
+ BackupClient, BackupDescriptor, DownloadLogsRequest, LatestBackupIDResponse,
+ LogWSResponse, RequestedData, SinkExt, StreamExt, UserIdentity,
};
use serde::{Deserialize, Serialize};
use serde_json::json;
@@ -22,24 +24,41 @@
pub use upload_handler::ffi::*;
- pub fn create_backup_sync(
+ pub fn create_backup(
backup_id: String,
backup_secret: String,
pickle_key: String,
pickled_account: String,
- user_data: String,
promise_id: u32,
) {
+ compaction_upload_promises::insert(backup_id.clone(), promise_id);
+
RUNTIME.spawn(async move {
- let result = create_backup(
- backup_id,
+ let result = create_userkeys_compaction(
+ backup_id.clone(),
backup_secret,
pickle_key,
pickled_account,
- user_data,
)
- .await;
- handle_void_result_as_callback(result, promise_id);
+ .await
+ .map_err(|err| err.to_string());
+
+ if let Err(err) = result {
+ compaction_upload_promises::resolve(&backup_id, Err(err));
+ return;
+ }
+
+ let (future_id, future) = future_manager::new_future::<()>().await;
+ create_main_compaction(&backup_id, future_id);
+ if let Err(err) = future.await {
+ compaction_upload_promises::resolve(&backup_id, Err(err));
+ tokio::spawn(upload_handler::compaction::cleanup_files(backup_id));
+ return;
+ }
+
+ trigger_backup_file_upload();
+
+ // The promise will be resolved when the backup is uploaded
});
}
@@ -51,21 +70,17 @@
}
}
-pub async fn create_backup(
+pub async fn create_userkeys_compaction(
backup_id: String,
backup_secret: String,
pickle_key: String,
pickled_account: String,
- user_data: String,
) -> Result<(), Box<dyn Error>> {
let mut backup_key =
compute_backup_key(backup_secret.as_bytes(), backup_id.as_bytes())?;
- let mut user_data = user_data.into_bytes();
-
- let mut backup_data_key = [0; aes::KEY_SIZE];
- crate::ffi::generate_key(&mut backup_data_key)?;
- let encrypted_user_data = encrypt(&mut backup_data_key, &mut user_data)?;
+ let backup_data_key =
+ secure_store_get(secure_store::SECURE_STORE_ENCRYPTION_KEY_ID)?;
let user_keys = UserKeys {
backup_data_key,
@@ -74,46 +89,8 @@
};
let encrypted_user_keys = user_keys.encrypt(&mut backup_key)?;
- let backup_client = BackupClient::new(BACKUP_SOCKET_ADDR)?;
-
- let user_identity = get_user_identity_from_secure_store()?;
-
- let backup_data = BackupData {
- backup_id: backup_id.clone(),
- user_data: encrypted_user_data,
- user_keys: encrypted_user_keys,
- attachments: Vec::new(),
- };
-
- backup_client
- .upload_backup(&user_identity, backup_data)
- .await?;
-
- let (tx, rx) = backup_client.upload_logs(&user_identity).await?;
-
- tokio::pin!(tx);
- tokio::pin!(rx);
-
- let log_data = UploadLogRequest {
- backup_id: backup_id.clone(),
- log_id: 1,
- content: (1..100).collect(),
- attachments: None,
- };
- tx.send(log_data.clone()).await?;
- match rx.next().await {
- Some(Ok(LogUploadConfirmation {
- backup_id: response_backup_id,
- log_id: 1,
- }))
- if backup_id == response_backup_id =>
- {
- // Correctly uploaded
- }
- response => {
- return Err(Box::new(InvalidWSLogResponse(format!("{response:?}"))))
- }
- };
+ let user_keys_file = get_backup_user_keys_file_path(&backup_id)?;
+ tokio::fs::write(user_keys_file, encrypted_user_keys).await?;
Ok(())
}
@@ -142,7 +119,7 @@
.download_backup_data(&latest_backup_descriptor, RequestedData::UserKeys)
.await?;
- let mut user_keys =
+ let user_keys =
UserKeys::from_encrypted(&mut encrypted_user_keys, &mut backup_key)?;
let backup_data_descriptor = BackupDescriptor::BackupID {
@@ -154,8 +131,10 @@
.download_backup_data(&backup_data_descriptor, RequestedData::UserData)
.await?;
- let user_data =
- decrypt(&mut user_keys.backup_data_key, &mut encrypted_user_data)?;
+ let user_data = decrypt(
+ &mut user_keys.backup_data_key.as_bytes().to_vec(),
+ &mut encrypted_user_data,
+ )?;
let user_data: serde_json::Value = serde_json::from_slice(&user_data)?;
@@ -210,7 +189,7 @@
#[derive(Debug, Serialize, Deserialize)]
struct UserKeys {
- backup_data_key: [u8; 32],
+ backup_data_key: String,
pickle_key: String,
pickled_account: String,
}
diff --git a/native/native_rust_library/src/constants.rs b/native/native_rust_library/src/constants.rs
--- a/native/native_rust_library/src/constants.rs
+++ b/native/native_rust_library/src/constants.rs
@@ -1,16 +1,19 @@
use std::time::Duration;
+#[allow(unused)]
pub mod aes {
pub const KEY_SIZE: usize = 32; // bytes
pub const IV_LENGTH: usize = 12; // bytes - unique Initialization Vector (nonce)
pub const TAG_LENGTH: usize = 16; // bytes - GCM auth tag
}
-/// Should match constants defined in `CommSecureStore.h`
pub mod secure_store {
+ /// Should match constants defined in `CommSecureStore.h`
pub const COMM_SERVICES_ACCESS_TOKEN: &str = "accessToken";
pub const USER_ID: &str = "userID";
pub const DEVICE_ID: &str = "deviceID";
+ /// Should match constant defined in `SQLiteQueryExecutor.h`
+ pub const SECURE_STORE_ENCRYPTION_KEY_ID: &str = "comm.encryptionKey";
}
pub const BACKUP_SERVICE_CONNECTION_RETRY_DELAY: Duration =
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
@@ -310,12 +310,11 @@
fn trigger_backup_file_upload();
#[cxx_name = "createBackup"]
- fn create_backup_sync(
+ fn create_backup(
backup_id: String,
backup_secret: String,
pickle_key: String,
pickled_account: String,
- user_data: String,
promise_id: u32,
);
@@ -341,18 +340,15 @@
unsafe extern "C++" {
include!("RustBackupExecutor.h");
- #[allow(unused)]
#[cxx_name = "getBackupDirectoryPath"]
fn get_backup_directory_path() -> Result<String>;
- #[allow(unused)]
#[cxx_name = "getBackupFilePath"]
fn get_backup_file_path(
backup_id: &str,
is_attachments: bool,
) -> Result<String>;
- #[allow(unused)]
#[cxx_name = "getBackupLogFilePath"]
fn get_backup_log_file_path(
backup_id: &str,
@@ -360,7 +356,6 @@
is_attachments: bool,
) -> Result<String>;
- #[allow(unused)]
#[cxx_name = "getBackupUserKeysFilePath"]
fn get_backup_user_keys_file_path(backup_id: &str) -> Result<String>;
diff --git a/native/profile/backup-menu.react.js b/native/profile/backup-menu.react.js
--- a/native/profile/backup-menu.react.js
+++ b/native/profile/backup-menu.react.js
@@ -31,7 +31,18 @@
state => state.localSettings.isBackupEnabled,
);
- const { restoreBackupProtocol } = useClientBackup();
+ const { uploadBackupProtocol, restoreBackupProtocol } = useClientBackup();
+
+ const uploadBackup = React.useCallback(async () => {
+ let message = 'Success';
+ try {
+ await uploadBackupProtocol();
+ } catch (e) {
+ message = `Backup upload error: ${String(getMessageForException(e))}`;
+ console.error(message);
+ }
+ Alert.alert('Upload protocol result', message);
+ }, [uploadBackupProtocol]);
const testRestore = React.useCallback(async () => {
let message;
@@ -71,6 +82,17 @@
</View>
<Text style={styles.header}>ACTIONS</Text>
+ <View style={styles.section}>
+ <Button
+ onPress={uploadBackup}
+ style={styles.row}
+ iosFormat="highlight"
+ iosHighlightUnderlayColor={colors.panelIosHighlightUnderlay}
+ iosActiveOpacity={0.85}
+ >
+ <Text style={styles.submenuText}>Test backup upload protocol</Text>
+ </Button>
+ </View>
<View style={styles.section}>
<Button
onPress={testRestore}
diff --git a/native/schema/CommCoreModuleSchema.js b/native/schema/CommCoreModuleSchema.js
--- a/native/schema/CommCoreModuleSchema.js
+++ b/native/schema/CommCoreModuleSchema.js
@@ -123,7 +123,7 @@
+clearCommServicesAccessToken: () => Promise<void>;
+startBackupHandler: () => void;
+stopBackupHandler: () => void;
- +createNewBackup: (backupSecret: string, userData: string) => Promise<void>;
+ +createNewBackup: (backupSecret: string) => Promise<void>;
+restoreBackup: (backupSecret: string) => Promise<string>;
}

File Metadata

Mime Type
text/plain
Expires
Sun, Dec 1, 8:52 AM (19 h, 45 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2604465
Default Alt Text
D10859.diff (16 KB)

Event Timeline