diff --git a/native/backup/restore-siwe-backup.react.js b/native/backup/restore-siwe-backup.react.js
index f4e10d58f..294f3d35c 100644
--- a/native/backup/restore-siwe-backup.react.js
+++ b/native/backup/restore-siwe-backup.react.js
@@ -1,83 +1,83 @@
// @flow
import * as React from 'react';
import { Alert } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { type SIWEResult } from 'lib/types/siwe-types.js';
import { getMessageForException } from 'lib/utils/errors.js';
import { SignSIWEBackupMessageForRestore } from '../account/registration/siwe-backup-message-creation.react.js';
import { commCoreModule } from '../native-modules.js';
import { type RootNavigationProp } from '../navigation/root-navigator.react.js';
import { type NavigationRoute } from '../navigation/route-names.js';
import { persistConfig } from '../redux/persist.js';
import { useStyles } from '../themes/colors.js';
export type RestoreSIWEBackupParams = {
+backupID: string,
+siweNonce: string,
+siweStatement: string,
+siweIssuedAt: string,
};
type Props = {
+navigation: RootNavigationProp<'RestoreSIWEBackup'>,
+route: NavigationRoute<'RestoreSIWEBackup'>,
};
function RestoreSIWEBackup(props: Props): React.Node {
const styles = useStyles(unboundStyles);
const { goBack } = props.navigation;
const { route } = props;
const {
params: { backupID, siweStatement, siweIssuedAt, siweNonce },
} = route;
const onSuccessfulWalletSignature = React.useCallback(
(result: SIWEResult) => {
void (async () => {
const { signature } = result;
let message = 'success';
try {
- await commCoreModule.restoreSIWEBackup(
+ await commCoreModule.restoreBackup(
signature,
- backupID,
persistConfig.version.toString(),
+ backupID,
);
} catch (e) {
message = `Backup restore error: ${String(
getMessageForException(e),
)}`;
console.error(message);
}
Alert.alert('Restore protocol result', message);
goBack();
})();
},
[goBack, backupID],
);
return (
);
}
const safeAreaEdges = ['top'];
const unboundStyles = {
container: {
flex: 1,
backgroundColor: 'panelBackground',
justifyContent: 'space-between',
},
};
export default RestoreSIWEBackup;
diff --git a/native/backup/use-client-backup.js b/native/backup/use-client-backup.js
index ec11b398b..c66bbd52f 100644
--- a/native/backup/use-client-backup.js
+++ b/native/backup/use-client-backup.js
@@ -1,141 +1,88 @@
// @flow
import * as React from 'react';
import { isLoggedIn } from 'lib/selectors/user-selectors.js';
import { accountHasPassword } from 'lib/shared/account-utils.js';
import {
latestBackupInfoResponseValidator,
- siweBackupDataValidator,
type LatestBackupInfo,
- type SIWEBackupData,
} 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 ClientBackup = {
+uploadBackupProtocol: () => Promise,
- +restorePasswordUserBackupProtocol: () => Promise,
- +retrieveLatestSIWEBackupData: () => Promise,
+retrieveLatestBackupInfo: () => Promise,
};
async function getBackupSecret(): Promise {
const nativeCredentials = await fetchNativeKeychainCredentials();
if (!nativeCredentials) {
throw new Error('Native credentials are missing');
}
return nativeCredentials.password;
}
async function getSIWEBackupSecrets(): Promise {
const siweBackupSecrets = await commCoreModule.getSIWEBackupSecrets();
if (!siweBackupSecrets) {
throw new Error('SIWE backup message and its signature are missing');
}
return siweBackupSecrets;
}
function useClientBackup(): ClientBackup {
const currentUserID = useSelector(
state => state.currentUserInfo && state.currentUserInfo.id,
);
const currentUserInfo = useSelector(state => state.currentUserInfo);
const loggedIn = useSelector(isLoggedIn);
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...');
if (accountHasPassword(currentUserInfo)) {
const backupSecret = await getBackupSecret();
await commCoreModule.createNewBackup(backupSecret);
} else {
const { message, signature } = await getSIWEBackupSecrets();
await commCoreModule.createNewSIWEBackup(signature, message);
}
console.info('Backup uploaded.');
}, [currentUserID, loggedIn, currentUserInfo]);
- const retrieveLatestSIWEBackupData = React.useCallback(async () => {
- if (!loggedIn || !currentUserID) {
- throw new Error('Attempt to restore backup for not logged in user.');
- }
-
- if (accountHasPassword(currentUserInfo)) {
- throw new Error(
- 'Attempt to retrieve siwe backup data for password user.',
- );
- }
-
- const serializedBackupData =
- await commCoreModule.retrieveLatestSIWEBackupData();
-
- return assertWithValidator(
- JSON.parse(serializedBackupData),
- siweBackupDataValidator,
- );
- }, [currentUserID, currentUserInfo, loggedIn]);
-
const retrieveLatestBackupInfo = React.useCallback(async () => {
if (!loggedIn || !currentUserID || !currentUserInfo?.username) {
throw new Error('Attempt to restore backup for not logged in user.');
}
const userIdentitifer = currentUserInfo?.username;
const response =
await commCoreModule.retrieveLatestBackupInfo(userIdentitifer);
return assertWithValidator(
JSON.parse(response),
latestBackupInfoResponseValidator,
);
}, [currentUserID, currentUserInfo, loggedIn]);
- const restorePasswordUserBackupProtocol = React.useCallback(async () => {
- if (!accountHasPassword(currentUserInfo)) {
- throw new Error(
- 'Attempt to restore from password for non-password user.',
- );
- }
-
- const [latestBackupInfo, backupSecret] = await Promise.all([
- retrieveLatestBackupInfo(),
- getBackupSecret(),
- ]);
-
- console.info('Start restoring backup...');
- await commCoreModule.restoreBackup(
- backupSecret,
- persistConfig.version.toString(),
- latestBackupInfo.backupID,
- );
- console.info('Backup restored.');
- }, [currentUserInfo, retrieveLatestBackupInfo]);
-
return React.useMemo(
() => ({
uploadBackupProtocol,
- restorePasswordUserBackupProtocol,
- retrieveLatestSIWEBackupData,
retrieveLatestBackupInfo,
}),
- [
- restorePasswordUserBackupProtocol,
- retrieveLatestBackupInfo,
- retrieveLatestSIWEBackupData,
- uploadBackupProtocol,
- ],
+ [retrieveLatestBackupInfo, uploadBackupProtocol],
);
}
export { getBackupSecret, useClientBackup };
diff --git a/native/profile/backup-menu.react.js b/native/profile/backup-menu.react.js
index 54dbc4a30..df0025c33 100644
--- a/native/profile/backup-menu.react.js
+++ b/native/profile/backup-menu.react.js
@@ -1,221 +1,234 @@
// @flow
import { useNavigation } from '@react-navigation/native';
import * as React from 'react';
import { Switch, Text, View } from 'react-native';
import { ScrollView } from 'react-native-gesture-handler';
import { accountHasPassword } from 'lib/shared/account-utils.js';
import { getMessageForException } from 'lib/utils/errors.js';
import { useDispatch } from 'lib/utils/redux-utils.js';
import type { ProfileNavigationProp } from './profile.react.js';
-import { useClientBackup } from '../backup/use-client-backup.js';
+import {
+ getBackupSecret,
+ useClientBackup,
+} from '../backup/use-client-backup.js';
import Button from '../components/button.react.js';
+import { commCoreModule } from '../native-modules.js';
import type { NavigationRoute } from '../navigation/route-names.js';
import { RestoreSIWEBackupRouteName } from '../navigation/route-names.js';
import { setLocalSettingsActionType } from '../redux/action-types.js';
+import { persistConfig } from '../redux/persist.js';
import { useSelector } from '../redux/redux-utils.js';
import { useColors, useStyles } from '../themes/colors.js';
import Alert from '../utils/alert.js';
type Props = {
+navigation: ProfileNavigationProp<'BackupMenu'>,
+route: NavigationRoute<'BackupMenu'>,
};
// eslint-disable-next-line no-unused-vars
function BackupMenu(props: Props): React.Node {
const styles = useStyles(unboundStyles);
const dispatch = useDispatch();
const colors = useColors();
const currentUserInfo = useSelector(state => state.currentUserInfo);
const navigation = useNavigation();
const isBackupEnabled = useSelector(
state => state.localSettings.isBackupEnabled,
);
- const {
- uploadBackupProtocol,
- restorePasswordUserBackupProtocol,
- retrieveLatestSIWEBackupData,
- retrieveLatestBackupInfo,
- } = useClientBackup();
+ const { uploadBackupProtocol, retrieveLatestBackupInfo } = 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 testRestoreForPasswordUser = React.useCallback(async () => {
let message = 'success';
try {
- await restorePasswordUserBackupProtocol();
+ const [latestBackupInfo, backupSecret] = await Promise.all([
+ retrieveLatestBackupInfo(),
+ getBackupSecret(),
+ ]);
+ await commCoreModule.restoreBackup(
+ backupSecret,
+ persistConfig.version.toString(),
+ latestBackupInfo.backupID,
+ );
+ console.info('Backup restored.');
} catch (e) {
message = `Backup restore error: ${String(getMessageForException(e))}`;
console.error(message);
}
Alert.alert('Restore protocol result', message);
- }, [restorePasswordUserBackupProtocol]);
+ }, [retrieveLatestBackupInfo]);
const testLatestBackupInfo = React.useCallback(async () => {
let message;
try {
const backupInfo = await retrieveLatestBackupInfo();
const { backupID, userID } = backupInfo;
message =
`Success!\n` +
`Backup ID: ${backupID},\n` +
`userID: ${userID},\n` +
`userID check: ${currentUserInfo?.id === userID ? 'true' : 'false'}`;
} catch (e) {
message = `Latest backup info error: ${String(
getMessageForException(e),
)}`;
console.error(message);
}
Alert.alert('Latest backup info result', message);
}, [currentUserInfo?.id, retrieveLatestBackupInfo]);
const testRestoreForSIWEUser = React.useCallback(async () => {
let message = 'success';
try {
- const siweBackupData = await retrieveLatestSIWEBackupData();
+ const backupInfo = await retrieveLatestBackupInfo();
+ const { siweBackupData, backupID } = backupInfo;
+
+ if (!siweBackupData) {
+ throw new Error('Missing SIWE message for Wallet user backup');
+ }
const {
- backupID,
siweBackupMsgNonce,
siweBackupMsgIssuedAt,
siweBackupMsgStatement,
} = siweBackupData;
navigation.navigate<'RestoreSIWEBackup'>({
name: RestoreSIWEBackupRouteName,
params: {
backupID,
siweNonce: siweBackupMsgNonce,
siweStatement: siweBackupMsgStatement,
siweIssuedAt: siweBackupMsgIssuedAt,
},
});
} catch (e) {
message = `Backup restore error: ${String(getMessageForException(e))}`;
console.error(message);
}
- }, [navigation, retrieveLatestSIWEBackupData]);
+ }, [navigation, retrieveLatestBackupInfo]);
const onBackupToggled = React.useCallback(
(value: boolean) => {
dispatch({
type: setLocalSettingsActionType,
payload: { isBackupEnabled: value },
});
},
[dispatch],
);
const onPressRestoreButton = accountHasPassword(currentUserInfo)
? testRestoreForPasswordUser
: testRestoreForSIWEUser;
return (
SETTINGS
Toggle automatic backup
ACTIONS
);
}
const unboundStyles = {
scrollViewContentContainer: {
paddingTop: 24,
},
scrollView: {
backgroundColor: 'panelBackground',
},
section: {
backgroundColor: 'panelForeground',
borderBottomWidth: 1,
borderColor: 'panelForegroundBorder',
borderTopWidth: 1,
marginBottom: 24,
marginVertical: 2,
},
header: {
color: 'panelBackgroundLabel',
fontSize: 12,
fontWeight: '400',
paddingBottom: 3,
paddingHorizontal: 24,
},
submenuButton: {
flexDirection: 'row',
paddingHorizontal: 24,
paddingVertical: 10,
alignItems: 'center',
},
submenuText: {
color: 'panelForegroundLabel',
flex: 1,
fontSize: 16,
},
row: {
flexDirection: 'row',
justifyContent: 'space-between',
paddingHorizontal: 24,
paddingVertical: 14,
},
};
export default BackupMenu;