diff --git a/lib/components/qr-auth-handler.react.js b/lib/components/qr-auth-handler.react.js --- a/lib/components/qr-auth-handler.react.js +++ b/lib/components/qr-auth-handler.react.js @@ -5,6 +5,7 @@ import { IdentityClientContext } from '../shared/identity-client-context.js'; import { useTunnelbroker } from '../tunnelbroker/tunnelbroker-context.js'; +import type { BackupKeys } from '../types/backup-types.js'; import { tunnelbrokerMessageTypes, type TunnelbrokerMessage, @@ -30,6 +31,7 @@ encryptionKey: string, message: QRCodeAuthMessage, ) => Promise, + performBackupRestore?: (backupKeys: BackupKeys) => Promise, }; function QRAuthHandler(props: QRAuthHandlerProps): React.Node { @@ -39,6 +41,7 @@ processMessage, composeMessage, performSecondaryDeviceRegistration, + performBackupRestore, } = props; const [primaryDeviceID, setPrimaryDeviceID] = React.useState(); const { @@ -100,9 +103,16 @@ const qrCodeAuthMessage = await processMessage(aesKey, innerMessage); if ( - qrCodeAuthMessage?.type === - qrCodeAuthMessageTypes.BACKUP_DATA_KEY_MESSAGE + qrCodeAuthMessage && + qrCodeAuthMessage.type === + qrCodeAuthMessageTypes.BACKUP_DATA_KEY_MESSAGE ) { + const { backupID, backupDataKey, backupLogDataKey } = qrCodeAuthMessage; + void performBackupRestore?.({ + backupID, + backupDataKey, + backupLogDataKey, + }); return; } @@ -125,6 +135,7 @@ identityClient, aesKey, performSecondaryDeviceRegistration, + performBackupRestore, processMessage, ], ); diff --git a/lib/types/backup-types.js b/lib/types/backup-types.js new file mode 100644 --- /dev/null +++ b/lib/types/backup-types.js @@ -0,0 +1,17 @@ +// @flow + +import type { TInterface } from 'tcomb'; +import t from 'tcomb'; + +import { tShape } from '../utils/validation-utils.js'; + +export type BackupKeys = { + +backupID: string, + +backupDataKey: string, + +backupLogDataKey: string, +}; +export const backupKeysValidator: TInterface = tShape({ + backupID: t.String, + backupDataKey: t.String, + backupLogDataKey: 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 @@ -73,4 +73,4 @@ return { uploadBackupProtocol, restoreBackupProtocol }; } -export { useClientBackup }; +export { getBackupSecret, useClientBackup }; diff --git a/native/profile/secondary-device-qr-code-scanner.react.js b/native/profile/secondary-device-qr-code-scanner.react.js --- a/native/profile/secondary-device-qr-code-scanner.react.js +++ b/native/profile/secondary-device-qr-code-scanner.react.js @@ -9,6 +9,10 @@ import { parseDataFromDeepLink } from 'lib/facts/links.js'; import { IdentityClientContext } from 'lib/shared/identity-client-context.js'; import { useTunnelbroker } from 'lib/tunnelbroker/tunnelbroker-context.js'; +import { + backupKeysValidator, + type BackupKeys, +} from 'lib/types/backup-types.js'; import type { RawDeviceList } from 'lib/types/identity-service-types.js'; import { tunnelbrokerMessageTypes, @@ -19,8 +23,11 @@ type PeerToPeerMessage, } from 'lib/types/tunnelbroker/peer-to-peer-message-types.js'; import { qrCodeAuthMessageTypes } from 'lib/types/tunnelbroker/qr-code-auth-message-types.js'; +import { assertWithValidator } from 'lib/utils/validation-utils.js'; import type { ProfileNavigationProp } from './profile.react.js'; +import { getBackupSecret } from '../backup/use-client-backup.js'; +import { commCoreModule } from '../native-modules.js'; import type { NavigationRoute } from '../navigation/route-names.js'; import { composeTunnelbrokerQRAuthMessage, @@ -146,13 +153,19 @@ void broadcastDeviceListUpdate(); + const backupSecret = await getBackupSecret(); + const backupKeysResponse = + await commCoreModule.retrieveBackupKeys(backupSecret); + const backupKeys = assertWithValidator( + JSON.parse(backupKeysResponse), + backupKeysValidator, + ); + const backupKeyMessage = await composeTunnelbrokerQRAuthMessage( encryptionKey, { type: qrCodeAuthMessageTypes.BACKUP_DATA_KEY_MESSAGE, - backupID: 'stub', - backupDataKey: 'stub', - backupLogDataKey: 'stub', + ...backupKeys, }, ); await tunnelbrokerContext.sendMessage({ diff --git a/native/qr-code/qr-code-screen.react.js b/native/qr-code/qr-code-screen.react.js --- a/native/qr-code/qr-code-screen.react.js +++ b/native/qr-code/qr-code-screen.react.js @@ -10,6 +10,7 @@ import { uintArrayToHexString } from 'lib/media/data-utils.js'; import { IdentityClientContext } from 'lib/shared/identity-client-context.js'; import { useTunnelbroker } from 'lib/tunnelbroker/tunnelbroker-context.js'; +import type { BackupKeys } from 'lib/types/backup-types.js'; import type { NonceChallenge, SignedMessage, @@ -32,6 +33,15 @@ +route: NavigationRoute<'QRCodeScreen'>, }; +function performBackupRestore(backupKeys: BackupKeys): Promise { + const { backupID, backupDataKey, backupLogDataKey } = backupKeys; + return commCoreModule.restoreBackupData( + backupID, + backupDataKey, + backupLogDataKey, + ); +} + // eslint-disable-next-line no-unused-vars function QRCodeScreen(props: QRCodeScreenProps): React.Node { const [qrCodeValue, setQrCodeValue] = React.useState(); @@ -99,6 +109,7 @@ performSecondaryDeviceRegistration={performRegistration} composeMessage={composeTunnelbrokerQRAuthMessage} processMessage={parseTunnelbrokerQRAuthMessage} + performBackupRestore={performBackupRestore} /> Log in to Comm