Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3373756
D12036.id40623.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
14 KB
Referenced Files
None
Subscribers
None
D12036.id40623.diff
View Options
diff --git a/native/account/registration/siwe-backup-message-creation.react.js b/native/account/registration/siwe-backup-message-creation.react.js
--- a/native/account/registration/siwe-backup-message-creation.react.js
+++ b/native/account/registration/siwe-backup-message-creation.react.js
@@ -42,9 +42,9 @@
function CreateSIWEBackupMessageBase(
props: CreateSIWEBackupMessageBaseProps,
): React.Node {
+ const styles = useStyles(unboundStyles);
const { onSuccessfulWalletSignature, onExistingWalletSignature, onSkip } =
props;
- const styles = useStyles(unboundStyles);
const {
panelState,
@@ -215,6 +215,84 @@
);
}
+type SignSIWEBackupMessageForRestoreBaseProps = {
+ +siweNonce: string,
+ +siweIssuedAt: string,
+ +siweStatement: string,
+ +onSuccessfulWalletSignature: (result: SIWEResult) => void,
+ +onSkip: () => void,
+};
+
+function SignSIWEBackupMessageForRestore(
+ props: SignSIWEBackupMessageForRestoreBaseProps,
+): React.Node {
+ const styles = useStyles(unboundStyles);
+ const {
+ panelState,
+ openPanel,
+ onPanelClosed,
+ onPanelClosing,
+ siwePanelSetLoading,
+ } = useSIWEPanelState();
+
+ const {
+ siweIssuedAt,
+ siweNonce,
+ siweStatement,
+ onSuccessfulWalletSignature,
+ onSkip,
+ } = props;
+ const siweSignatureRequestData = React.useMemo(
+ () => ({
+ messageType: SIWEMessageTypes.MSG_BACKUP_RESTORE,
+ siweNonce,
+ siweStatement,
+ siweIssuedAt,
+ }),
+ [siweStatement, siweIssuedAt, siweNonce],
+ );
+
+ let siwePanel;
+ if (panelState !== 'closed') {
+ siwePanel = (
+ <SIWEPanel
+ onClosing={onPanelClosing}
+ onClosed={onPanelClosed}
+ closing={panelState === 'closing'}
+ onSuccessfulWalletSignature={onSuccessfulWalletSignature}
+ siweSignatureRequestData={siweSignatureRequestData}
+ setLoading={siwePanelSetLoading}
+ />
+ );
+ }
+
+ return (
+ <>
+ <RegistrationContainer>
+ <RegistrationContentContainer style={styles.scrollViewContentContainer}>
+ <Text style={styles.header}>Decrypting your Comm backup</Text>
+ <Text style={styles.body}>
+ To make sure we can’t see your data, Comm encrypts your backup using
+ a signature from your wallet.
+ </Text>
+ <View style={styles.siweBackupIconContainer}>
+ <Icon name="backup" size={200} style={styles.siweBackupIcon} />
+ </View>
+ </RegistrationContentContainer>
+ <RegistrationButtonContainer>
+ <RegistrationButton
+ onPress={openPanel}
+ label="Decrypt with Ethereum signature"
+ variant="enabled"
+ />
+ <RegistrationButton onPress={onSkip} label="Skip" variant="outline" />
+ </RegistrationButtonContainer>
+ </RegistrationContainer>
+ {siwePanel}
+ </>
+ );
+}
+
const unboundStyles = {
scrollViewContentContainer: {
flexGrow: 1,
@@ -241,4 +319,8 @@
},
};
-export { CreateSIWEBackupMessageBase, CreateSIWEBackupMessage };
+export {
+ CreateSIWEBackupMessageBase,
+ CreateSIWEBackupMessage,
+ SignSIWEBackupMessageForRestore,
+};
diff --git a/native/backup/restore-siwe-backup.react.js b/native/backup/restore-siwe-backup.react.js
new file mode 100644
--- /dev/null
+++ b/native/backup/restore-siwe-backup.react.js
@@ -0,0 +1,78 @@
+// @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 { 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(signature, backupID);
+ } catch (e) {
+ message = `Backup restore error: ${String(
+ getMessageForException(e),
+ )}`;
+ console.error(message);
+ }
+ Alert.alert('Restore protocol result', message);
+ goBack();
+ })();
+ },
+ [goBack, backupID],
+ );
+
+ return (
+ <SafeAreaView edges={safeAreaEdges} style={styles.container}>
+ <SignSIWEBackupMessageForRestore
+ siweNonce={siweNonce}
+ siweStatement={siweStatement}
+ siweIssuedAt={siweIssuedAt}
+ onSkip={goBack}
+ onSuccessfulWalletSignature={onSuccessfulWalletSignature}
+ />
+ </SafeAreaView>
+ );
+}
+
+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
--- a/native/backup/use-client-backup.js
+++ b/native/backup/use-client-backup.js
@@ -11,9 +11,18 @@
import { commCoreModule } from '../native-modules.js';
import { useSelector } from '../redux/redux-utils.js';
+type SIWEBackupData = {
+ +backupID: string,
+ +siweBackupMsg: string,
+ +siweBackupMsgNonce: string,
+ +siweBackupMsgStatement: string,
+ +siweBackupMsgIssuedAt: string,
+};
+
type ClientBackup = {
+uploadBackupProtocol: () => Promise<void>,
- +restoreBackupProtocol: () => Promise<void>,
+ +restorePasswordUserBackupProtocol: () => Promise<void>,
+ +retrieveLatestSIWEBackupData: () => Promise<SIWEBackupData>,
};
async function getBackupSecret(): Promise<string> {
@@ -78,21 +87,60 @@
currentUserInfo,
]);
- const restoreBackupProtocol = React.useCallback(async () => {
+ const restorePasswordUserBackupProtocol = React.useCallback(async () => {
if (!loggedIn || !currentUserID) {
throw new Error('Attempt to restore backup for not logged in user.');
}
- console.info('Start restoring backup...');
+ if (!accountHasPassword(currentUserInfo)) {
+ throw new Error(
+ 'Attempt to restore from password for non-password user.',
+ );
+ }
+ console.info('Start restoring backup...');
await setMockCommServicesAuthMetadata();
+
const backupSecret = await getBackupSecret();
await commCoreModule.restoreBackup(backupSecret);
console.info('Backup restored.');
- }, [currentUserID, loggedIn, setMockCommServicesAuthMetadata]);
+ return;
+ }, [
+ currentUserID,
+ loggedIn,
+ setMockCommServicesAuthMetadata,
+ 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.',
+ );
+ }
+
+ await setMockCommServicesAuthMetadata();
+ const serializedBackupData =
+ await commCoreModule.retrieveLatestSIWEBackupData();
+ const siweBackupData: SIWEBackupData = JSON.parse(serializedBackupData);
+ return siweBackupData;
+ }, [
+ currentUserID,
+ currentUserInfo,
+ loggedIn,
+ setMockCommServicesAuthMetadata,
+ ]);
- return { uploadBackupProtocol, restoreBackupProtocol };
+ return {
+ uploadBackupProtocol,
+ restorePasswordUserBackupProtocol,
+ retrieveLatestSIWEBackupData,
+ };
}
export { getBackupSecret, useClientBackup };
diff --git a/native/navigation/root-navigator.react.js b/native/navigation/root-navigator.react.js
--- a/native/navigation/root-navigator.react.js
+++ b/native/navigation/root-navigator.react.js
@@ -55,11 +55,13 @@
ConnectFarcasterBottomSheetRouteName,
TagFarcasterChannelNavigatorRouteName,
CreateMissingSIWEBackupMessageRouteName,
+ RestoreSIWEBackupRouteName,
} from './route-names.js';
import LoggedOutModal from '../account/logged-out-modal.react.js';
import CreateMissingSIWEBackupMessage from '../account/registration/missing-registration-data/missing-siwe-backup-message.react.js';
import RegistrationNavigator from '../account/registration/registration-navigator.react.js';
import TermsAndPrivacyModal from '../account/terms-and-privacy-modal.react.js';
+import RestoreSIWEBackup from '../backup/restore-siwe-backup.react.js';
import ThreadPickerModal from '../calendar/thread-picker-modal.react.js';
import ImagePasteModal from '../chat/image-paste-modal.react.js';
import MessageReactionsModal from '../chat/message-reactions-modal.react.js';
@@ -303,6 +305,10 @@
name={CreateMissingSIWEBackupMessageRouteName}
component={CreateMissingSIWEBackupMessage}
/>
+ <Root.Screen
+ name={RestoreSIWEBackupRouteName}
+ component={RestoreSIWEBackup}
+ />
</Root.Navigator>
);
}
diff --git a/native/navigation/route-names.js b/native/navigation/route-names.js
--- a/native/navigation/route-names.js
+++ b/native/navigation/route-names.js
@@ -15,6 +15,7 @@
import type { CreateSIWEBackupMessageParams } from '../account/registration/siwe-backup-message-creation.react.js';
import type { UsernameSelectionParams } from '../account/registration/username-selection.react.js';
import type { TermsAndPrivacyModalParams } from '../account/terms-and-privacy-modal.react.js';
+import type { RestoreSIWEBackupParams } from '../backup/restore-siwe-backup.react.js';
import type { ThreadPickerModalParams } from '../calendar/thread-picker-modal.react.js';
import type { ComposeSubchannelParams } from '../chat/compose-subchannel.react.js';
import type { FullScreenThreadMediaGalleryParams } from '../chat/fullscreen-thread-media-gallery.react.js';
@@ -127,6 +128,7 @@
export const CreateSIWEBackupMessageRouteName = 'CreateSIWEBackupMessage';
export const CreateMissingSIWEBackupMessageRouteName =
'CreateMissingSIWEBackupMessage';
+export const RestoreSIWEBackupRouteName = 'RestoreSIWEBackup';
export const ExistingEthereumAccountRouteName = 'ExistingEthereumAccount';
export const ConnectFarcasterRouteName = 'ConnectFarcaster';
export const UsernameSelectionRouteName = 'UsernameSelection';
@@ -187,6 +189,7 @@
+ConnectFarcasterBottomSheet: void,
+TagFarcasterChannelNavigator: void,
+CreateMissingSIWEBackupMessage: void,
+ +RestoreSIWEBackup: RestoreSIWEBackupParams,
};
export type MessageTooltipRouteNames =
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
@@ -1,9 +1,11 @@
// @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';
@@ -11,6 +13,7 @@
import { useClientBackup } from '../backup/use-client-backup.js';
import Button from '../components/button.react.js';
import type { NavigationRoute } from '../navigation/route-names.js';
+import { RestoreSIWEBackupRouteName } from '../navigation/route-names.js';
import { setLocalSettingsActionType } from '../redux/action-types.js';
import { useSelector } from '../redux/redux-utils.js';
import { useColors, useStyles } from '../themes/colors.js';
@@ -25,12 +28,18 @@
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, restoreBackupProtocol } = useClientBackup();
+ const {
+ uploadBackupProtocol,
+ restorePasswordUserBackupProtocol,
+ retrieveLatestSIWEBackupData,
+ } = useClientBackup();
const uploadBackup = React.useCallback(async () => {
let message = 'Success';
@@ -43,16 +52,43 @@
Alert.alert('Upload protocol result', message);
}, [uploadBackupProtocol]);
- const testRestore = React.useCallback(async () => {
+ const testRestoreForPasswordUser = React.useCallback(async () => {
let message = 'success';
try {
- await restoreBackupProtocol();
+ await restorePasswordUserBackupProtocol();
} catch (e) {
message = `Backup restore error: ${String(getMessageForException(e))}`;
console.error(message);
}
Alert.alert('Restore protocol result', message);
- }, [restoreBackupProtocol]);
+ }, [restorePasswordUserBackupProtocol]);
+
+ const testRestoreForSIWEUser = React.useCallback(async () => {
+ let message = 'success';
+ try {
+ const siweBackupData = await retrieveLatestSIWEBackupData();
+
+ 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]);
const onBackupToggled = React.useCallback(
(value: boolean) => {
@@ -64,6 +100,10 @@
[dispatch],
);
+ const onPressRestoreButton = accountHasPassword(currentUserInfo)
+ ? testRestoreForPasswordUser
+ : testRestoreForSIWEUser;
+
return (
<ScrollView
contentContainerStyle={styles.scrollViewContentContainer}
@@ -91,7 +131,7 @@
</View>
<View style={styles.section}>
<Button
- onPress={testRestore}
+ onPress={onPressRestoreButton}
style={styles.row}
iosFormat="highlight"
iosHighlightUnderlayColor={colors.panelIosHighlightUnderlay}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Nov 27, 11:40 AM (22 h, 5 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2590027
Default Alt Text
D12036.id40623.diff (14 KB)
Attached To
Mode
D12036: Enable backup restoration for SIWE users via testing buttons
Attached
Detach File
Event Timeline
Log In to Comment