mirror of
https://github.com/jagandeepbrar/lunasea.git
synced 2026-08-31 04:32:32 +00:00
feat(config): support retrying entering encryption password on failure
This commit is contained in:
@@ -34,6 +34,8 @@
|
||||
"settings.BackupToCloudDescription": "Backup Configuration Data",
|
||||
"settings.BackupToCloudFailure": "Failed to Backup",
|
||||
"settings.BackupToCloudSuccess": "Successfully Backed Up",
|
||||
"settings.BackupToDevice": "Backup to Device",
|
||||
"settings.BackupToDeviceDescription": "Backup Configuration Data",
|
||||
"settings.BannersNotificationModuleSupportHeader": "Supported Modules",
|
||||
"settings.BannersNotificationModuleSupportBody": "Webhook-based notifications are currently only supported in the modules listed below.\n\nAdditional module support will come in the future!",
|
||||
"settings.BasicAuthentication": "Basic Authentication",
|
||||
@@ -197,6 +199,8 @@
|
||||
"settings.RestoreFromCloudFailure": "Failed to Restore",
|
||||
"settings.RestoreFromCloudSuccess": "Successfully Restored",
|
||||
"settings.RestoreFromCloudSuccessMessage": "Your configuration has been restored",
|
||||
"settings.RestoreFromDevice": "Restore from Device",
|
||||
"settings.RestoreFromDeviceDescription": "Restore Configuration Data",
|
||||
"settings.SignedInFailure": "Failed to Sign In",
|
||||
"settings.SignedInSuccess": "Successfully Signed In",
|
||||
"settings.SignedOutFailure": "Failed to Sign Out",
|
||||
@@ -282,6 +286,7 @@
|
||||
"lunasea.Remove": "Remove",
|
||||
"lunasea.Rename": "Rename",
|
||||
"lunasea.Restore": "Restore",
|
||||
"lunasea.Retry": "Retry",
|
||||
"lunasea.ReturnToDashboard": "Return to Dashboard",
|
||||
"lunasea.SearchTextBar": "Search…",
|
||||
"lunasea.Set": "Set",
|
||||
|
||||
@@ -40,7 +40,7 @@ class Desktop implements LunaFileSystem {
|
||||
data: result.files[0].bytes!,
|
||||
);
|
||||
} else {
|
||||
showLunaInfoSnackBar(
|
||||
showLunaErrorSnackBar(
|
||||
title: 'lunasea.InvalidFileTypeSelected'.tr(),
|
||||
message: 'lunasea.PleaseTryAgain'.tr(),
|
||||
);
|
||||
|
||||
@@ -53,7 +53,7 @@ class Mobile implements LunaFileSystem {
|
||||
data: result.files[0].bytes!,
|
||||
);
|
||||
} else {
|
||||
showLunaInfoSnackBar(
|
||||
showLunaErrorSnackBar(
|
||||
title: 'lunasea.InvalidFileTypeSelected'.tr(),
|
||||
message: 'lunasea.PleaseTryAgain'.tr(),
|
||||
);
|
||||
|
||||
@@ -4,12 +4,25 @@ Future<void> showLunaErrorSnackBar({
|
||||
required String title,
|
||||
dynamic error,
|
||||
String? message,
|
||||
bool showButton = false,
|
||||
String buttonText = 'view',
|
||||
Function? buttonOnPressed,
|
||||
}) async =>
|
||||
showLunaSnackBar(
|
||||
title: title,
|
||||
message: message ?? LunaLogger.checkLogsMessage,
|
||||
type: LunaSnackbarType.ERROR,
|
||||
showButton: error != null,
|
||||
buttonOnPressed: () async => LunaDialogs().textPreview(
|
||||
LunaState.navigatorKey.currentContext!, 'Error', error.toString()),
|
||||
showButton: error != null || showButton,
|
||||
buttonText: buttonText,
|
||||
buttonOnPressed: () async {
|
||||
if (error != null) {
|
||||
LunaDialogs().textPreview(
|
||||
LunaState.navigatorKey.currentContext!,
|
||||
'Error',
|
||||
error.toString(),
|
||||
);
|
||||
} else if (buttonOnPressed != null) {
|
||||
buttonOnPressed();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@@ -22,7 +22,7 @@ class LunaEncryption {
|
||||
return _encrypted;
|
||||
} catch (error, stack) {
|
||||
LunaLogger().error(
|
||||
'Failed to decrypted "$data" using the key "$encryptionKey"',
|
||||
'Failed to encrypt "${data.substring(0, 10)}..."',
|
||||
error,
|
||||
stack,
|
||||
);
|
||||
@@ -44,7 +44,7 @@ class LunaEncryption {
|
||||
return _encrypter.decrypt64(data, iv: iv);
|
||||
} catch (error, stack) {
|
||||
LunaLogger().error(
|
||||
'Failed to decrypted "$data" using the key "$decryptionKey"',
|
||||
'Failed to decrypt "${data.substring(0, 10)}..."',
|
||||
error,
|
||||
stack,
|
||||
);
|
||||
|
||||
@@ -35,35 +35,16 @@ class _State extends State<SettingsAccountRestoreConfigurationTile> {
|
||||
if (_loadingState == LunaLoadingState.ACTIVE) return;
|
||||
updateState(LunaLoadingState.ACTIVE);
|
||||
try {
|
||||
List<LunaFirebaseBackupDocument> documents =
|
||||
await LunaFirebaseFirestore().getBackupEntries();
|
||||
Tuple2<bool, LunaFirebaseBackupDocument?> result =
|
||||
await SettingsDialogs().getBackupFromCloud(context, documents);
|
||||
final docs = await LunaFirebaseFirestore().getBackupEntries();
|
||||
final result = await SettingsDialogs().getBackupFromCloud(context, docs);
|
||||
|
||||
if (result.item1) {
|
||||
String? encrypted =
|
||||
await LunaFirebaseStorage().downloadBackup(result.item2!.id);
|
||||
Tuple2<bool, String> key =
|
||||
await SettingsDialogs().decryptBackup(context);
|
||||
if (key.item1) {
|
||||
String decrypted = LunaEncryption().decrypt(key.item2, encrypted!);
|
||||
if (decrypted != LunaEncryption.ENCRYPTION_FAILURE) {
|
||||
await LunaConfiguration().import(context, decrypted).then((_) {
|
||||
updateState(LunaLoadingState.INACTIVE);
|
||||
showLunaSuccessSnackBar(
|
||||
title: 'settings.RestoreFromCloudSuccess'.tr(),
|
||||
message: 'settings.RestoreFromCloudSuccessMessage'.tr(),
|
||||
);
|
||||
});
|
||||
} else {
|
||||
showLunaErrorSnackBar(
|
||||
title: 'settings.RestoreFromCloudFailure'.tr(),
|
||||
message: 'lunasea.IncorrectEncryptionKey'.tr(),
|
||||
);
|
||||
}
|
||||
}
|
||||
String? id = result.item2!.id;
|
||||
String? encrypted = await LunaFirebaseStorage().downloadBackup(id);
|
||||
if (encrypted != null) _decryptBackup(context, encrypted);
|
||||
}
|
||||
} catch (error, stack) {
|
||||
LunaLogger().error('Restore Failed', error, stack);
|
||||
LunaLogger().error('Failed to restore cloud backup', error, stack);
|
||||
showLunaErrorSnackBar(
|
||||
title: 'settings.RestoreFromCloudFailure'.tr(),
|
||||
error: error,
|
||||
@@ -71,4 +52,26 @@ class _State extends State<SettingsAccountRestoreConfigurationTile> {
|
||||
}
|
||||
updateState(LunaLoadingState.INACTIVE);
|
||||
}
|
||||
|
||||
Future<void> _decryptBackup(BuildContext context, String encrypted) async {
|
||||
Tuple2<bool, String> _key = await SettingsDialogs().decryptBackup(context);
|
||||
if (_key.item1) {
|
||||
String decrypted = LunaEncryption().decrypt(_key.item2, encrypted);
|
||||
if (decrypted != LunaEncryption.ENCRYPTION_FAILURE) {
|
||||
await LunaConfiguration().import(context, decrypted);
|
||||
showLunaSuccessSnackBar(
|
||||
title: 'settings.RestoreFromCloudSuccess'.tr(),
|
||||
message: 'settings.RestoreFromCloudSuccessMessage'.tr(),
|
||||
);
|
||||
} else {
|
||||
showLunaErrorSnackBar(
|
||||
title: 'settings.RestoreFromCloudFailure'.tr(),
|
||||
message: 'settings.IncorrectEncryptionKey'.tr(),
|
||||
showButton: true,
|
||||
buttonText: 'lunasea.Retry'.tr(),
|
||||
buttonOnPressed: () async => _decryptBackup(context, encrypted),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@ class SettingsSystemBackupRestoreBackupTile extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LunaBlock(
|
||||
title: 'Backup to Device',
|
||||
body: const [TextSpan(text: 'Backup Configuration Data')],
|
||||
title: 'settings.BackupToDevice'.tr(),
|
||||
body: [TextSpan(text: 'settings.BackupToDeviceDescription'.tr())],
|
||||
trailing: const LunaIconButton(icon: Icons.upload_rounded),
|
||||
onTap: () async => _backup(context),
|
||||
);
|
||||
@@ -31,16 +31,18 @@ class SettingsSystemBackupRestoreBackupTile extends StatelessWidget {
|
||||
'$name.lunasea',
|
||||
utf8.encode(encrypted),
|
||||
);
|
||||
if (result)
|
||||
if (result) {
|
||||
showLunaSuccessSnackBar(
|
||||
title: 'Saved Backup',
|
||||
message: 'Backup has been successfully saved');
|
||||
title: 'settings.BackupToCloudSuccess'.tr(),
|
||||
message: '$name.lunasea',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error, stack) {
|
||||
LunaLogger().error('Backup Failed', error, stack);
|
||||
LunaLogger().error('Failed to create device backup', error, stack);
|
||||
showLunaErrorSnackBar(
|
||||
title: 'Failed to Backup',
|
||||
title: 'settings.BackupToCloudFailure'.tr(),
|
||||
error: error,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@ class SettingsSystemBackupRestoreRestoreTile extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LunaBlock(
|
||||
title: 'Restore from Device',
|
||||
body: const [TextSpan(text: 'Restore Configuration Data')],
|
||||
title: 'settings.RestoreFromDevice'.tr(),
|
||||
body: [TextSpan(text: 'settings.RestoreFromDeviceDescription'.tr())],
|
||||
trailing: const LunaIconButton(icon: Icons.download_rounded),
|
||||
onTap: () async => _restore(context),
|
||||
);
|
||||
@@ -20,35 +20,36 @@ class SettingsSystemBackupRestoreRestoreTile extends StatelessWidget {
|
||||
Future<void> _restore(BuildContext context) async {
|
||||
try {
|
||||
LunaFile? file = await LunaFileSystem().read(context, ['lunasea']);
|
||||
if (file != null) {
|
||||
Tuple2<bool, String> _key =
|
||||
await SettingsDialogs().decryptBackup(context);
|
||||
if (_key.item1) {
|
||||
String _decrypted = LunaEncryption().decrypt(
|
||||
_key.item2,
|
||||
String.fromCharCodes(file.data),
|
||||
);
|
||||
if (_decrypted != LunaEncryption.ENCRYPTION_FAILURE) {
|
||||
LunaConfiguration().import(context, _decrypted).then(
|
||||
(_) => showLunaSuccessSnackBar(
|
||||
title: 'Restored',
|
||||
message: 'Your configuration has been restored',
|
||||
),
|
||||
);
|
||||
} else {
|
||||
showLunaErrorSnackBar(
|
||||
title: 'Failed to Restore',
|
||||
message: 'An incorrect encryption key was supplied',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (file != null) await _decryptBackup(context, file);
|
||||
} catch (error, stack) {
|
||||
LunaLogger().error('Restore Failed', error, stack);
|
||||
LunaLogger().error('Failed to restore device backup', error, stack);
|
||||
showLunaErrorSnackBar(
|
||||
title: 'Failed to Restore',
|
||||
title: 'settings.RestoreFromCloudFailure'.tr(),
|
||||
error: error,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _decryptBackup(BuildContext context, LunaFile file) async {
|
||||
Tuple2<bool, String> _key = await SettingsDialogs().decryptBackup(context);
|
||||
if (_key.item1) {
|
||||
String encrypted = String.fromCharCodes(file.data);
|
||||
String decrypted = LunaEncryption().decrypt(_key.item2, encrypted);
|
||||
if (decrypted != LunaEncryption.ENCRYPTION_FAILURE) {
|
||||
await LunaConfiguration().import(context, decrypted);
|
||||
showLunaSuccessSnackBar(
|
||||
title: 'settings.RestoreFromCloudSuccess'.tr(),
|
||||
message: 'settings.RestoreFromCloudSuccessMessage'.tr(),
|
||||
);
|
||||
} else {
|
||||
showLunaErrorSnackBar(
|
||||
title: 'settings.RestoreFromCloudFailure'.tr(),
|
||||
message: 'settings.IncorrectEncryptionKey'.tr(),
|
||||
showButton: true,
|
||||
buttonText: 'lunasea.Retry'.tr(),
|
||||
buttonOnPressed: () async => _decryptBackup(context, file),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
"lunasea.Remove": "Remove",
|
||||
"lunasea.Rename": "Rename",
|
||||
"lunasea.Restore": "Restore",
|
||||
"lunasea.Retry": "Retry",
|
||||
"lunasea.ReturnToDashboard": "Return to Dashboard",
|
||||
"lunasea.SearchTextBar": "Search…",
|
||||
"lunasea.Set": "Set",
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
"settings.BackupToCloudDescription": "Backup Configuration Data",
|
||||
"settings.BackupToCloudFailure": "Failed to Backup",
|
||||
"settings.BackupToCloudSuccess": "Successfully Backed Up",
|
||||
"settings.BackupToDevice": "Backup to Device",
|
||||
"settings.BackupToDeviceDescription": "Backup Configuration Data",
|
||||
"settings.BannersNotificationModuleSupportHeader": "Supported Modules",
|
||||
"settings.BannersNotificationModuleSupportBody": "Webhook-based notifications are currently only supported in the modules listed below.\n\nAdditional module support will come in the future!",
|
||||
"settings.BasicAuthentication": "Basic Authentication",
|
||||
@@ -197,6 +199,8 @@
|
||||
"settings.RestoreFromCloudFailure": "Failed to Restore",
|
||||
"settings.RestoreFromCloudSuccess": "Successfully Restored",
|
||||
"settings.RestoreFromCloudSuccessMessage": "Your configuration has been restored",
|
||||
"settings.RestoreFromDevice": "Restore from Device",
|
||||
"settings.RestoreFromDeviceDescription": "Restore Configuration Data",
|
||||
"settings.SignedInFailure": "Failed to Sign In",
|
||||
"settings.SignedInSuccess": "Successfully Signed In",
|
||||
"settings.SignedOutFailure": "Failed to Sign Out",
|
||||
|
||||
Reference in New Issue
Block a user