diff --git a/lib/types/backup-types.js b/lib/types/backup-types.js --- a/lib/types/backup-types.js +++ b/lib/types/backup-types.js @@ -17,3 +17,19 @@ backupDataKey: t.String, backupLogDataKey: t.String, }); + +// This type should match `SIWEBackupData` in +// `native/native_rust_library/src/backup.rs` +export type SIWEBackupData = { + +backupID: string, + +siweBackupMsgNonce: string, + +siweBackupMsgStatement: string, + +siweBackupMsgIssuedAt: string, +}; +export const siweBackupDataValidator: TInterface = + tShape({ + backupID: t.String, + siweBackupMsgNonce: t.String, + siweBackupMsgStatement: t.String, + siweBackupMsgIssuedAt: t.String, + }); 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 @@ -4,21 +4,18 @@ import { isLoggedIn } from 'lib/selectors/user-selectors.js'; import { accountHasPassword } from 'lib/shared/account-utils.js'; +import { + type SIWEBackupData, + siweBackupDataValidator, +} from 'lib/types/backup-types.js'; import type { SIWEBackupSecrets } from 'lib/types/siwe-types.js'; +import { assertWithValidator } from 'lib/utils/validation-utils.js'; import { fetchNativeKeychainCredentials } from '../account/native-credentials.js'; import { commCoreModule } from '../native-modules.js'; import { persistConfig } from '../redux/persist.js'; import { useSelector } from '../redux/redux-utils.js'; -type SIWEBackupData = { - +backupID: string, - +siweBackupMsg: string, - +siweBackupMsgNonce: string, - +siweBackupMsgStatement: string, - +siweBackupMsgIssuedAt: string, -}; - type ClientBackup = { +uploadBackupProtocol: () => Promise, +restorePasswordUserBackupProtocol: () => Promise, @@ -86,7 +83,6 @@ ); console.info('Backup restored.'); - return; }, [currentUserID, loggedIn, currentUserInfo]); const retrieveLatestSIWEBackupData = React.useCallback(async () => { @@ -102,8 +98,11 @@ const serializedBackupData = await commCoreModule.retrieveLatestSIWEBackupData(); - const siweBackupData: SIWEBackupData = JSON.parse(serializedBackupData); - return siweBackupData; + + return assertWithValidator( + JSON.parse(serializedBackupData), + siweBackupDataValidator, + ); }, [currentUserID, currentUserInfo, loggedIn]); return { 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 @@ -202,6 +202,34 @@ }); } + fn get_siwe_backup_data_from_msg( + backup_id: String, + siwe_backup_msg: String, + ) -> Result { + let siwe_backup_msg_obj: Message = match siwe_backup_msg.parse() { + Ok(siwe_backup_msg_obj) => siwe_backup_msg_obj, + Err(error) => { + return Err(error.to_string()); + } + }; + + let siwe_backup_msg_nonce = siwe_backup_msg_obj.nonce; + let siwe_backup_msg_statement = match siwe_backup_msg_obj.statement { + Some(statement) => statement, + None => { + return Err("Backup message invalid: missing statement".to_string()); + } + }; + + let siwe_backup_msg_issued_at = siwe_backup_msg_obj.issued_at.to_string(); + + Ok(SIWEBackupData { + backup_id, + siwe_backup_msg_nonce, + siwe_backup_msg_statement, + siwe_backup_msg_issued_at, + }) + } pub fn retrieve_latest_siwe_backup_data(promise_id: u32) { RUNTIME.spawn(async move { let result = download_latest_backup_id() @@ -222,47 +250,23 @@ siwe_backup_msg, } = result; - let siwe_backup_msg_string = match siwe_backup_msg { - Some(siwe_backup_msg_value) => siwe_backup_msg_value, - None => { - string_callback( - "Backup message unavailable".to_string(), - promise_id, - "".to_string(), - ); - return; - } - }; - - let siwe_backup_msg_obj: Message = match siwe_backup_msg_string.parse() { - Ok(siwe_backup_msg_obj) => siwe_backup_msg_obj, - Err(error) => { - string_callback(error.to_string(), promise_id, "".to_string()); - return; - } - }; - - let siwe_backup_msg_nonce = siwe_backup_msg_obj.nonce; - let siwe_backup_msg_statement = match siwe_backup_msg_obj.statement { - Some(statement) => statement, - None => { - string_callback( - "Backup message invalid: missing statement".to_string(), - promise_id, - "".to_string(), - ); - return; + let siwe_backup_data = if let Some(siwe_backup_msg_value) = + siwe_backup_msg + { + match get_siwe_backup_data_from_msg(backup_id, siwe_backup_msg_value) { + Ok(data) => data, + Err(err) => { + string_callback(err, promise_id, "".to_string()); + return; + } } - }; - - let siwe_backup_msg_issued_at = siwe_backup_msg_obj.issued_at.to_string(); - - let siwe_backup_data = SIWEBackupData { - backup_id: backup_id, - siwe_backup_msg: siwe_backup_msg_string, - siwe_backup_msg_nonce: siwe_backup_msg_nonce, - siwe_backup_msg_statement: siwe_backup_msg_statement, - siwe_backup_msg_issued_at: siwe_backup_msg_issued_at, + } else { + string_callback( + "Backup message unavailable".to_string(), + promise_id, + "".to_string(), + ); + return; }; let serialize_result = serde_json::to_string(&siwe_backup_data); @@ -456,12 +460,12 @@ backup_log_data_key: String, } +// This struct should match `SIWEBackupData` in `lib/types/backup-types.js` #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] struct SIWEBackupData { #[serde(rename = "backupID")] backup_id: String, - siwe_backup_msg: String, siwe_backup_msg_statement: String, siwe_backup_msg_nonce: String, siwe_backup_msg_issued_at: String,