Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3396569
D14047.id46081.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
10 KB
Referenced Files
None
Subscribers
None
D14047.id46081.diff
View Options
diff --git a/native/backup/restore-siwe-backup.react.js b/native/backup/restore-siwe-backup.react.js
--- a/native/backup/restore-siwe-backup.react.js
+++ b/native/backup/restore-siwe-backup.react.js
@@ -4,11 +4,10 @@
import { Alert } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
-import { userKeysResponseValidator } from 'lib/types/backup-types.js';
import { type SIWEResult } from 'lib/types/siwe-types.js';
import { getMessageForException } from 'lib/utils/errors.js';
-import { assertWithValidator } from 'lib/utils/validation-utils.js';
+import { useClientBackup } from './use-client-backup.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';
@@ -43,25 +42,23 @@
},
} = route;
+ const { getBackupUserKeys } = useClientBackup();
+
const onSuccessfulWalletSignature = React.useCallback(
(result: SIWEResult) => {
void (async () => {
const { signature } = result;
let message = 'success';
try {
- const userKeysResponse = commCoreModule.getBackupUserKeys(
+ const { backupDataKey, backupLogDataKey } = await getBackupUserKeys(
userIdentifier,
signature,
backupID,
);
- const userKeys = assertWithValidator(
- userKeysResponse,
- userKeysResponseValidator,
- );
await commCoreModule.restoreBackupData(
backupID,
- userKeys.backupDataKey,
- userKeys.backupLogDataKey,
+ backupDataKey,
+ backupLogDataKey,
persistConfig.version.toString(),
);
} catch (e) {
@@ -74,7 +71,7 @@
goBack();
})();
},
- [backupID, goBack, userIdentifier],
+ [backupID, getBackupUserKeys, goBack, userIdentifier],
);
return (
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
@@ -6,6 +6,8 @@
import {
latestBackupInfoResponseValidator,
type LatestBackupInfo,
+ type UserKeys,
+ userKeysResponseValidator,
} from 'lib/types/backup-types.js';
import { assertWithValidator } from 'lib/utils/validation-utils.js';
@@ -20,8 +22,29 @@
+latestBackupInfo: LatestBackupInfo,
+userIdentifier: string,
}>,
+ +getBackupUserKeys: (
+ userIdentifier: string,
+ backupSecret: string,
+ backupID: string,
+ ) => Promise<UserKeys>,
};
+async function getBackupUserKeys(
+ userIdentifier: string,
+ backupSecret: string,
+ backupID: string,
+): Promise<UserKeys> {
+ const userKeysResponse = await commCoreModule.getBackupUserKeys(
+ userIdentifier,
+ backupSecret,
+ backupID,
+ );
+ return assertWithValidator(
+ JSON.parse(userKeysResponse),
+ userKeysResponseValidator,
+ );
+}
+
function useClientBackup(): ClientBackup {
const currentUserID = useSelector(
state => state.currentUserInfo && state.currentUserInfo.id,
@@ -69,8 +92,9 @@
createFullBackup,
createUserKeysBackup,
retrieveLatestBackupInfo,
+ getBackupUserKeys,
}),
- [retrieveLatestBackupInfo, createFullBackup, createUserKeysBackup],
+ [createFullBackup, createUserKeysBackup, retrieveLatestBackupInfo],
);
}
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,15 +1,17 @@
// @flow
import { useNavigation } from '@react-navigation/native';
+import invariant from 'invariant';
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 { userKeysResponseValidator } from 'lib/types/backup-types.js';
+import { IdentityClientContext } from 'lib/shared/identity-client-context.js';
+import { getConfig } from 'lib/utils/config.js';
+import { rawDeviceListFromSignedList } from 'lib/utils/device-list-utils.js';
import { getMessageForException } from 'lib/utils/errors.js';
import { useDispatch } from 'lib/utils/redux-utils.js';
-import { assertWithValidator } from 'lib/utils/validation-utils.js';
import type { ProfileNavigationProp } from './profile.react.js';
import { useClientBackup } from '../backup/use-client-backup.js';
@@ -41,8 +43,16 @@
state => state.localSettings.isBackupEnabled,
);
- const { createFullBackup, retrieveLatestBackupInfo, createUserKeysBackup } =
- useClientBackup();
+ const identityContext = React.useContext(IdentityClientContext);
+ invariant(identityContext, 'Identity context should be set');
+ const { identityClient, getAuthMetadata } = identityContext;
+
+ const {
+ createFullBackup,
+ retrieveLatestBackupInfo,
+ createUserKeysBackup,
+ getBackupUserKeys,
+ } = useClientBackup();
const uploadBackup = React.useCallback(async () => {
let message;
@@ -73,19 +83,15 @@
try {
const [{ latestBackupInfo, userIdentifier }, backupSecret] =
await Promise.all([retrieveLatestBackupInfo(), getBackupSecret()]);
- const userKeysResponse = await commCoreModule.getBackupUserKeys(
+ const { backupDataKey, backupLogDataKey } = await getBackupUserKeys(
userIdentifier,
backupSecret,
latestBackupInfo.backupID,
);
- const userKeys = assertWithValidator(
- JSON.parse(userKeysResponse),
- userKeysResponseValidator,
- );
await commCoreModule.restoreBackupData(
latestBackupInfo.backupID,
- userKeys.backupDataKey,
- userKeys.backupLogDataKey,
+ backupDataKey,
+ backupLogDataKey,
persistConfig.version.toString(),
);
console.info('Backup restored.');
@@ -94,7 +100,7 @@
console.error(message);
}
Alert.alert('Restore protocol result', message);
- }, [getBackupSecret, retrieveLatestBackupInfo]);
+ }, [getBackupSecret, getBackupUserKeys, retrieveLatestBackupInfo]);
const testLatestBackupInfo = React.useCallback(async () => {
let message;
@@ -115,6 +121,102 @@
Alert.alert('Latest backup info result', message);
}, [currentUserInfo?.id, retrieveLatestBackupInfo]);
+ const testSigning = React.useCallback(async () => {
+ // This test only works in the following case:
+ // 1. Logged in on Primary Device using v1
+ // 2. Creating User Keys Backup on Primary
+ // 3. Log Out on Primary Device using v1
+ // 4. Log In on any native device using v1
+ // 5. Perform this test
+ let message;
+ try {
+ const {
+ latestBackupInfo: { userID, backupID },
+ userIdentifier,
+ } = await retrieveLatestBackupInfo();
+
+ if (currentUserInfo?.id !== userID) {
+ throw new Error('Backup returned different userID');
+ }
+
+ // We fetch Device List history to get previous primary `deviceID`
+ const deviceLists =
+ await identityClient.getDeviceListHistoryForUser(userID);
+ if (deviceLists.length < 3) {
+ throw new Error(
+ 'Previous Primary Device issue: device list history too short',
+ );
+ }
+
+ // According to steps listed above, device list history looks like this:
+ // 1. [...], [lastPrimaryDeviceID]
+ // 2. [...], [lastPrimaryDeviceID]
+ // 3. [...], [lastPrimaryDeviceID], []
+ // 4. [...], [lastPrimaryDeviceID], [], [currentPrimaryDeviceID]
+ // 5. [...], [lastPrimaryDeviceID], [], [currentPrimaryDeviceID]
+ // In order to get lastPrimaryDeviceID, we need to get the last
+ // but two item
+ const lastDeviceListWithPrimary = deviceLists[deviceLists.length - 3];
+ const lastRawDeviceListWithPrimary = rawDeviceListFromSignedList(
+ lastDeviceListWithPrimary,
+ );
+ const lastPrimaryDeviceID = lastRawDeviceListWithPrimary.devices[0];
+ if (!lastPrimaryDeviceID) {
+ throw new Error('Previous Primary Device issue: empty device list');
+ }
+
+ const { deviceID } = await getAuthMetadata();
+ if (deviceID === lastPrimaryDeviceID) {
+ throw new Error('Previous Primary Device issue: the same deviceIDs');
+ }
+
+ const backupSecret = await getBackupSecret();
+ const { pickledAccount, pickleKey } = await getBackupUserKeys(
+ userIdentifier,
+ backupSecret,
+ backupID,
+ );
+
+ const emptyDeviceListMessage = '[]';
+
+ // Sign using Olm Account from backup
+ const signature = await commCoreModule.signMessageUsingAccount(
+ emptyDeviceListMessage,
+ pickledAccount,
+ pickleKey,
+ );
+
+ // Verify using previous primary `deviceID`
+ const { olmAPI } = getConfig();
+ const verificationResult = await olmAPI.verifyMessage(
+ emptyDeviceListMessage,
+ signature,
+ lastPrimaryDeviceID,
+ );
+
+ message =
+ `Backup ID: ${backupID},\n` +
+ `userID: ${userID},\n` +
+ `deviceID: ${deviceID ?? ''},\n` +
+ `lastPrimaryDeviceID: ${lastPrimaryDeviceID},\n` +
+ `signature: ${signature},\n` +
+ `verificationResult: ${verificationResult.toString()}\n`;
+ } catch (e) {
+ message = `Latest backup info error: ${String(
+ getMessageForException(e),
+ )}`;
+ console.error(message);
+ }
+ Alert.alert('Signing with previous primary Olm Account result', message);
+ }, [
+ currentUserInfo?.id,
+ getAuthMetadata,
+ getBackupSecret,
+ getBackupUserKeys,
+ identityClient,
+ retrieveLatestBackupInfo,
+ ]);
+
const testRestoreForSIWEUser = React.useCallback(async () => {
let message = 'success';
try {
@@ -222,6 +324,19 @@
</Text>
</Button>
</View>
+ <View style={styles.section}>
+ <Button
+ onPress={testSigning}
+ style={styles.row}
+ iosFormat="highlight"
+ iosHighlightUnderlayColor={colors.panelIosHighlightUnderlay}
+ iosActiveOpacity={0.85}
+ >
+ <Text style={styles.submenuText}>
+ Test signing with previous primary Olm Account
+ </Text>
+ </Button>
+ </View>
</ScrollView>
);
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Dec 2, 1:21 PM (7 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2607688
Default Alt Text
D14047.id46081.diff (10 KB)
Attached To
Mode
D14047: [native] make it possible to test signing using Olm Account from User Keys
Attached
Detach File
Event Timeline
Log In to Comment