diff --git a/lib/backup/restored-migrations.js b/lib/backup/restored-migrations.js --- a/lib/backup/restored-migrations.js +++ b/lib/backup/restored-migrations.js @@ -5,7 +5,7 @@ import { databaseIdentifier } from '../types/database-identifier-types.js'; import { syncedMetadataNames } from '../types/synced-metadata-types.js'; import { getConfig } from '../utils/config.js'; -import { getMessageForException } from '../utils/errors.js'; +import { BackupIsNewerError, getMessageForException } from '../utils/errors.js'; async function getRestoredStoreVersion(): Promise { const { sqliteAPI } = getConfig(); @@ -19,7 +19,7 @@ return parseInt(storeVersion, 10); } -async function runRestoredBackupMigrations() { +async function runRestoredBackupMigrations(restoredDatabaseVersion: number) { const currentStoreVersion = getConfig().platformDetails.stateVersion; if (!currentStoreVersion) { throw new Error('currentStoreVersion is missing'); @@ -33,7 +33,11 @@ if (restoredStoreVersion > currentStoreVersion) { console.log('backup-restore: current app is older than backup'); - throw new Error('backup_is_newer'); + throw new BackupIsNewerError( + 'backup_is_newer', + restoredDatabaseVersion, + restoredStoreVersion, + ); } console.log( diff --git a/lib/backup/use-user-data-restore.js b/lib/backup/use-user-data-restore.js --- a/lib/backup/use-user-data-restore.js +++ b/lib/backup/use-user-data-restore.js @@ -21,6 +21,7 @@ import { syncedMetadataNames } from '../types/synced-metadata-types.js'; import type { QRAuthBackupData } from '../types/tunnelbroker/qr-code-auth-message-types.js'; import { getConfig } from '../utils/config.js'; +import { BackupIsNewerError } from '../utils/errors.js'; import { useDispatchActionPromise } from '../utils/redux-promise-utils.js'; import { useSelector, useDispatch } from '../utils/redux-utils.js'; @@ -139,8 +140,11 @@ if (startStepIndex <= 1) { const migrateBackupSchemaPromise = (async () => { storeAndDatabaseVersions = await getStoreAndDatabaseVersions(addLog); - const { mainDatabaseVersion, restoredDatabaseVersion } = - storeAndDatabaseVersions; + const { + mainDatabaseVersion, + restoredDatabaseVersion, + restoredStoreVersion, + } = storeAndDatabaseVersions; if (mainDatabaseVersion === restoredDatabaseVersion) { addLog( @@ -166,7 +170,11 @@ ` aborting.`, new Set([logTypes.BACKUP, logTypes.ERROR]), ); - throw new Error('backup_is_newer'); + throw new BackupIsNewerError( + 'backup_is_newer', + restoredDatabaseVersion, + restoredStoreVersion, + ); } })(); void dispatchActionPromise( @@ -187,8 +195,11 @@ storeAndDatabaseVersions = await getStoreAndDatabaseVersions(addLog); } - const { mainStoreVersion, restoredStoreVersion } = - storeAndDatabaseVersions; + const { + mainStoreVersion, + restoredStoreVersion, + restoredDatabaseVersion, + } = storeAndDatabaseVersions; if (mainStoreVersion === restoredStoreVersion) { addLog( 'User Data Restore', @@ -203,7 +214,7 @@ `restored store version (${restoredStoreVersion}), migrating data`, new Set([logTypes.BACKUP]), ); - await runRestoredBackupMigrations(); + await runRestoredBackupMigrations(restoredDatabaseVersion); } else if (mainStoreVersion < restoredStoreVersion) { addLog( 'User Data Restore', @@ -211,7 +222,11 @@ `restored store version (${restoredStoreVersion}), aborting`, new Set([logTypes.BACKUP, logTypes.ERROR]), ); - throw new Error('backup_is_newer'); + throw new BackupIsNewerError( + 'backup_is_newer', + restoredDatabaseVersion, + restoredStoreVersion, + ); } })(); void dispatchActionPromise( diff --git a/lib/utils/errors.js b/lib/utils/errors.js --- a/lib/utils/errors.js +++ b/lib/utils/errors.js @@ -62,6 +62,21 @@ } } +class BackupIsNewerError extends ExtendableError { + backupDBVersion: number; + backupStoreVersion: number; + + constructor( + error: string, + backupDBVersion: number, + backupStoreVersion: number, + ) { + super(error); + this.backupDBVersion = backupDBVersion; + this.backupStoreVersion = backupStoreVersion; + } +} + function getMessageForException(e: mixed): ?string { if (typeof e === 'string') { return e; @@ -84,4 +99,5 @@ SocketOffline, SocketTimeout, SendMessageError, + BackupIsNewerError, }; diff --git a/native/account/restore.js b/native/account/restore.js --- a/native/account/restore.js +++ b/native/account/restore.js @@ -23,7 +23,10 @@ import { getConfig } from 'lib/utils/config.js'; import { getContentSigningKey } from 'lib/utils/crypto-utils.js'; import { composeRawDeviceList } from 'lib/utils/device-list-utils.js'; -import { getMessageForException } from 'lib/utils/errors.js'; +import { + BackupIsNewerError, + getMessageForException, +} from 'lib/utils/errors.js'; import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js'; import { useSelector } from 'lib/utils/redux-utils.js'; import { fullBackupSupport } from 'lib/utils/services-utils.js'; @@ -224,7 +227,7 @@ messageForException ?? 'unknown error', new Set([logTypes.ERROR, logTypes.BACKUP]), ); - if (messageForException === 'backup_is_newer') { + if (error instanceof BackupIsNewerError) { Alert.alert( backupIsNewerThanAppAlertDetails.title, backupIsNewerThanAppAlertDetails.message, diff --git a/native/utils/qr-code-utils.js b/native/utils/qr-code-utils.js --- a/native/utils/qr-code-utils.js +++ b/native/utils/qr-code-utils.js @@ -9,7 +9,10 @@ qrCodeAuthMessagePayloadValidator, type QRCodeAuthMessagePayload, } from 'lib/types/tunnelbroker/qr-code-auth-message-types.js'; -import { getMessageForException } from 'lib/utils/errors.js'; +import { + BackupIsNewerError, + getMessageForException, +} from 'lib/utils/errors.js'; import * as AES from './aes-crypto-module.js'; import { @@ -76,7 +79,7 @@ networkErrorAlertDetails.title, networkErrorAlertDetails.message, ); - } else if (messageForException === 'backup_is_newer') { + } else if (error instanceof BackupIsNewerError) { Alert.alert( backupIsNewerThanAppAlertDetails.title, backupIsNewerThanAppAlertDetails.message, diff --git a/web/utils/qr-code-utils.js b/web/utils/qr-code-utils.js --- a/web/utils/qr-code-utils.js +++ b/web/utils/qr-code-utils.js @@ -18,7 +18,10 @@ convertBytesToObj, convertObjToBytes, } from 'lib/utils/conversion-utils.js'; -import { getMessageForException } from 'lib/utils/errors.js'; +import { + BackupIsNewerError, + getMessageForException, +} from 'lib/utils/errors.js'; import { base64DecodeBuffer, base64EncodeBuffer } from './base64-utils.js'; import { getBackupIsNewerThanAppError } from './version-utils.js'; @@ -75,7 +78,7 @@ connection. , ); - } else if (messageForException === 'backup_is_newer') { + } else if (error instanceof BackupIsNewerError) { const message = getBackupIsNewerThanAppError(); pushModal({message}); } else {