From 29fca5c1f0a0c661076a6860e20c0f21253474db Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Mon, 30 Nov 2020 11:56:39 +0100 Subject: [PATCH] allow to export imported keyfiles, closes https://github.com/PhilippC/keepass2android/issues/599 --- .../app/src/main/AndroidManifest.xml | 2 +- .../Resources/values/strings.xml | 8 +- .../Resources/xml/preferences.xml | 14 ++- .../settings/DatabaseSettingsActivity.cs | 40 +++++-- .../settings/ExportKeyfileActivity.cs | 113 ++++++++++++++++++ 5 files changed, 159 insertions(+), 18 deletions(-) create mode 100644 src/keepass2android/settings/ExportKeyfileActivity.cs diff --git a/src/java/JavaFileStorage/app/src/main/AndroidManifest.xml b/src/java/JavaFileStorage/app/src/main/AndroidManifest.xml index 048d89e2..d3e90d8a 100644 --- a/src/java/JavaFileStorage/app/src/main/AndroidManifest.xml +++ b/src/java/JavaFileStorage/app/src/main/AndroidManifest.xml @@ -6,7 +6,7 @@ android:versionName="1.0"> diff --git a/src/keepass2android/Resources/values/strings.xml b/src/keepass2android/Resources/values/strings.xml index ee03fa6f..68c54d79 100644 --- a/src/keepass2android/Resources/values/strings.xml +++ b/src/keepass2android/Resources/values/strings.xml @@ -56,6 +56,7 @@ Biometric unlock Import database to internal folder Import key file to internal folder + Export key file from internal folder Keyboard switching Only available for local files. File is stored in internal directory. @@ -248,8 +249,10 @@ Saving database… Exporting database… Database exported successfully! - - Space + Key file exported successfully! + + + Space Search Show password Sort by... @@ -784,6 +787,7 @@ + Updated Jsch to version 0.1.55 No longer storing package names of Android apps in the URL field Improve locking behavior - no longer displaying biometric prompt immediately after unlocking Update OkHttp to support HTTP/2 diff --git a/src/keepass2android/Resources/xml/preferences.xml b/src/keepass2android/Resources/xml/preferences.xml index d37b08ca..7fd360c4 100644 --- a/src/keepass2android/Resources/xml/preferences.xml +++ b/src/keepass2android/Resources/xml/preferences.xml @@ -128,10 +128,16 @@ android:key="import_keyfile_prefs" android:title="@string/import_keyfile_prefs" /> - - - - + + + + + + + { ExportKeyfileFromInternalFolder(); }; + importKeyfile.Summary = GetString(Resource.String.FileIsInInternalDirectory); } else { - importDb.Enabled = true; - importDb.PreferenceClick += (sender, args) => { MoveKeyfileToInternalFolder(); }; + exportKeyfile.Enabled = false; + importKeyfile.Enabled = true; + importKeyfile.PreferenceClick += (sender, args) => { MoveKeyfileToInternalFolder(); }; } } else { - importDb.Enabled = false; + exportKeyfile.Enabled = false; + importKeyfile.Enabled = false; } } + + + private void ExportKeyfileFromInternalFolder() + { + StartActivity(new Intent(Activity.ApplicationContext, typeof(ExportKeyfileActivity))); + + } + private void MoveKeyfileToInternalFolder() { Func copyAndReturnPostExecute = () => diff --git a/src/keepass2android/settings/ExportKeyfileActivity.cs b/src/keepass2android/settings/ExportKeyfileActivity.cs new file mode 100644 index 00000000..e185d588 --- /dev/null +++ b/src/keepass2android/settings/ExportKeyfileActivity.cs @@ -0,0 +1,113 @@ +using System; +using Android.App; +using Android.Content; +using Android.Widget; +using keepass2android.Io; +using KeePassLib.Keys; +using KeePassLib.Serialization; + +namespace keepass2android +{ + [Activity] + public class ExportKeyfileActivity : LockCloseActivity + { + + public class ExportKeyfile : RunnableOnFinish + { + private readonly IKp2aApp _app; + private IOConnectionInfo _targetIoc; + + public ExportKeyfile(Activity activity, IKp2aApp app, OnFinish onFinish, IOConnectionInfo targetIoc) : base( + activity, onFinish) + { + _app = app; + _targetIoc = targetIoc; + } + + public override void Run() + { + StatusLogger.UpdateMessage(UiStringKey.exporting_database); + + try + { + var fileStorage = _app.GetFileStorage(_targetIoc); + if (fileStorage is IOfflineSwitchable) + { + ((IOfflineSwitchable) fileStorage).IsOffline = false; + } + + CompositeKey masterKey = App.Kp2a.CurrentDb.KpDatabase.MasterKey; + var sourceIoc = ((KcpKeyFile) masterKey.GetUserKey(typeof(KcpKeyFile))).Ioc; + + IoUtil.Copy(_targetIoc, sourceIoc, App.Kp2a); + + if (fileStorage is IOfflineSwitchable) + { + ((IOfflineSwitchable) fileStorage).IsOffline = App.Kp2a.OfflineMode; + } + + Finish(true); + + + } + catch (Exception ex) + { + Finish(false, ex.Message); + } + + + } + } + + + public class ExportKeyfileProcessManager : FileSaveProcessManager + { + public ExportKeyfileProcessManager(int requestCode, Activity activity) : base(requestCode, activity) + { + + } + + protected override void SaveFile(IOConnectionInfo ioc) + { + var exportKeyfile = new ExportKeyfile(_activity, App.Kp2a, new ActionOnFinish(_activity, + (success, message, activity) => + { + if (!success) + Toast.MakeText(activity, message, ToastLength.Long).Show(); + else + Toast.MakeText(activity, _activity.GetString(Resource.String.export_keyfile_successful), + ToastLength.Long).Show(); + activity.Finish(); + } + ), ioc); + ProgressTask pt = new ProgressTask(App.Kp2a, _activity, exportKeyfile); + pt.Run(); + + } + } + + private ExportKeyfileProcessManager _exportKeyfileProcessManager; + + + protected override void OnCreate(Android.OS.Bundle savedInstanceState) + { + base.OnCreate(savedInstanceState); + _exportKeyfileProcessManager = new ExportKeyfileProcessManager(0, this); + _exportKeyfileProcessManager.StartProcess(); + + } + + protected override void OnActivityResult(int requestCode, Result resultCode, Intent data) + { + base.OnActivityResult(requestCode, resultCode, data); + + if (_exportKeyfileProcessManager?.OnActivityResult(requestCode, resultCode, data) == true) + return; + + Finish(); + + } + + + } +} \ No newline at end of file