add option to sync database after quick-unlocking the database. closes https://github.com/PhilippC/keepass2android/issues/188

This commit is contained in:
Philipp Crocoll
2021-11-17 11:30:43 +01:00
parent 7014f5d9f1
commit 294e6f5edf
11 changed files with 160 additions and 95 deletions

View File

@@ -119,7 +119,7 @@ namespace keepass2android
/// </summary> /// </summary>
IFileStorage GetFileStorage(IOConnectionInfo iocInfo, bool allowCache); IFileStorage GetFileStorage(IOConnectionInfo iocInfo, bool allowCache);
void TriggerReload(Context context); void TriggerReload(Context context, Action<bool> actionOnResult /*if not null, called when the user selected yes (true) or no (false)*/);
bool CheckForDuplicateUuids { get; } bool CheckForDuplicateUuids { get; }

View File

@@ -51,7 +51,7 @@ namespace keepass2android
if (!MemUtil.ArraysEqual(_app.CurrentDb.KpDatabase.HashOfFileOnDisk, hashingRemoteStream.Hash)) if (!MemUtil.ArraysEqual(_app.CurrentDb.KpDatabase.HashOfFileOnDisk, hashingRemoteStream.Hash))
{ {
_app.TriggerReload(_context); _app.TriggerReload(_context, null);
Finish(true); Finish(true);
} }
else else

View File

@@ -85,8 +85,7 @@ namespace keepass2android
{ {
//only the remote file was modified -> reload database. //only the remote file was modified -> reload database.
//note: it's best to lock the database and do a complete reload here (also better for UI consistency in case something goes wrong etc.) //note: it's best to lock the database and do a complete reload here (also better for UI consistency in case something goes wrong etc.)
_app.TriggerReload(_context); _app.TriggerReload(_context, (bool result) => Finish(result));
Finish(true);
} }
} }
else else

View File

@@ -28,7 +28,6 @@ using Android.Widget;
using KeePassLib; using KeePassLib;
using Android.Preferences; using Android.Preferences;
using KeePassLib.Interfaces; using KeePassLib.Interfaces;
using KeePassLib.Serialization;
using KeePassLib.Utility; using KeePassLib.Utility;
using keepass2android.Io; using keepass2android.Io;
using keepass2android.database.edit; using keepass2android.database.edit;
@@ -42,7 +41,6 @@ using Object = Java.Lang.Object;
namespace keepass2android namespace keepass2android
{ {
public abstract class GroupBaseActivity : LockCloseActivity public abstract class GroupBaseActivity : LockCloseActivity
{ {
public const String KeyEntry = "entry"; public const String KeyEntry = "entry";
@@ -1062,7 +1060,7 @@ namespace keepass2android
return true; return true;
case Resource.Id.menu_sync: case Resource.Id.menu_sync:
Synchronize(); new SyncUtil(this).SynchronizeDatabase(() => { });
return true; return true;
case Resource.Id.menu_work_offline: case Resource.Id.menu_work_offline:
@@ -1073,7 +1071,7 @@ namespace keepass2android
case Resource.Id.menu_work_online: case Resource.Id.menu_work_online:
App.Kp2a.OfflineMode = App.Kp2a.OfflineModePreference = false; App.Kp2a.OfflineMode = App.Kp2a.OfflineModePreference = false;
UpdateOfflineModeMenu(); UpdateOfflineModeMenu();
Synchronize(); new SyncUtil(this).SynchronizeDatabase(() => { });
return true; return true;
case Resource.Id.menu_open_other_db: case Resource.Id.menu_open_other_db:
AppTask.SetActivityResult(this, KeePass.ExitLoadAnotherDb); AppTask.SetActivityResult(this, KeePass.ExitLoadAnotherDb);
@@ -1096,77 +1094,7 @@ namespace keepass2android
return base.OnOptionsItemSelected(item); return base.OnOptionsItemSelected(item);
} }
public class SyncOtpAuxFile : RunnableOnFinish
{
private readonly IOConnectionInfo _ioc;
public SyncOtpAuxFile(Activity activity, IOConnectionInfo ioc)
: base(activity,null)
{
_ioc = ioc;
}
public override void Run()
{
StatusLogger.UpdateMessage(UiStringKey.SynchronizingOtpAuxFile);
try
{
//simply open the file. The file storage does a complete sync.
using (App.Kp2a.GetOtpAuxFileStorage(_ioc).OpenFileForRead(_ioc))
{
}
Finish(true);
}
catch (Exception e)
{
Finish(false, e.Message);
}
}
}
private void Synchronize()
{
var filestorage = App.Kp2a.GetFileStorage(App.Kp2a.CurrentDb.Ioc);
RunnableOnFinish task;
OnFinish onFinish = new ActionOnFinish(this, (success, message, activity) =>
{
if (!String.IsNullOrEmpty(message))
Toast.MakeText(activity, message, ToastLength.Long).Show();
// Tell the adapter to refresh it's list
BaseAdapter adapter = (BaseAdapter)((GroupBaseActivity)activity)?.ListAdapter;
adapter?.NotifyDataSetChanged();
if (App.Kp2a.CurrentDb.OtpAuxFileIoc != null)
{
var task2 = new SyncOtpAuxFile(this, App.Kp2a.CurrentDb.OtpAuxFileIoc);
new ProgressTask(App.Kp2a, activity, task2).Run(true);
}
});
if (filestorage is CachingFileStorage)
{
task = new SynchronizeCachedDatabase(this, App.Kp2a, onFinish);
}
else
{
task = new CheckDatabaseForChanges(this, App.Kp2a, onFinish);
}
var progressTask = new ProgressTask(App.Kp2a, this, task);
progressTask.Run();
}
public override void OnBackPressed() public override void OnBackPressed()
{ {

View File

@@ -212,10 +212,8 @@ namespace keepass2android
pwd.Text = ExpectedPasswordPart; pwd.Text = ExpectedPasswordPart;
btn.PostDelayed(() => btn.PostDelayed(() =>
{ {
UnlockAndSyncAndClose();
App.Kp2a.UnlockDatabase();
Finish();
}, 500); }, 500);
@@ -327,20 +325,36 @@ namespace keepass2android
{ {
var expectedPasswordPart = ExpectedPasswordPart; var expectedPasswordPart = ExpectedPasswordPart;
if (pwd.Text == expectedPasswordPart) if (pwd.Text == expectedPasswordPart)
{ {
Kp2aLog.Log("QuickUnlock successful!"); UnlockAndSyncAndClose();
App.Kp2a.UnlockDatabase(); }
}
else else
{ {
Kp2aLog.Log("QuickUnlock not successful!"); Kp2aLog.Log("QuickUnlock not successful!");
App.Kp2a.Lock(false); App.Kp2a.Lock(false);
Toast.MakeText(this, GetString(Resource.String.QuickUnlock_fail), ToastLength.Long).Show(); Toast.MakeText(this, GetString(Resource.String.QuickUnlock_fail), ToastLength.Long).Show();
Finish();
} }
Finish();
} }
private string ExpectedPasswordPart private void UnlockAndSyncAndClose()
{
App.Kp2a.UnlockDatabase();
if (PreferenceManager.GetDefaultSharedPreferences(this)
.GetBoolean(GetString(Resource.String.SyncAfterQuickUnlock_key), false))
{
new SyncUtil(this).SynchronizeDatabase(Finish);
}
else
Finish();
}
private string ExpectedPasswordPart
{ {
get get
{ {

View File

@@ -205,6 +205,8 @@
<string name="PreloadDatabaseEnabled_key">PreloadDatabaseEnabled</string> <string name="PreloadDatabaseEnabled_key">PreloadDatabaseEnabled</string>
<bool name="PreloadDatabaseEnabled_default">true</bool> <bool name="PreloadDatabaseEnabled_default">true</bool>
<string name="SyncAfterQuickUnlock_key">SyncAfterQuickUnlock_key</string>
<string name="ClearPasswordOnLeave_key">ClearPasswordOnLeave</string> <string name="ClearPasswordOnLeave_key">ClearPasswordOnLeave</string>
</resources> </resources>

View File

@@ -473,6 +473,9 @@
<string name="PreloadDatabaseEnabled_title">Pre-load database file</string> <string name="PreloadDatabaseEnabled_title">Pre-load database file</string>
<string name="PreloadDatabaseEnabled_summary">Start background loading or downloading of the database file during password entry.</string> <string name="PreloadDatabaseEnabled_summary">Start background loading or downloading of the database file during password entry.</string>
<string name="SyncAfterQuickUnlock_title">Sync after QuickUnlock</string>
<string name="SyncAfterQuickUnlock_summary">Synchronize database with remote file after unlocking with QuickUnlock.</string>
<string name="AskOverwriteBinary">Do you want to overwrite the existing binary with the same name?</string> <string name="AskOverwriteBinary">Do you want to overwrite the existing binary with the same name?</string>
<string name="AskOverwriteBinary_title">Overwrite existing binary?</string> <string name="AskOverwriteBinary_title">Overwrite existing binary?</string>
<string name="AskOverwriteBinary_yes">Overwrite</string> <string name="AskOverwriteBinary_yes">Overwrite</string>

View File

@@ -567,7 +567,15 @@
android:defaultValue="@bool/PreloadDatabaseEnabled_default" android:defaultValue="@bool/PreloadDatabaseEnabled_default"
android:title="@string/PreloadDatabaseEnabled_title" android:title="@string/PreloadDatabaseEnabled_title"
android:key="@string/PreloadDatabaseEnabled_key" /> android:key="@string/PreloadDatabaseEnabled_key" />
<CheckBoxPreference <CheckBoxPreference
android:enabled="true"
android:persistent="true"
android:summary="@string/SyncAfterQuickUnlock_summary"
android:defaultValue="false"
android:title="@string/SyncAfterQuickUnlock_title"
android:key="@string/SyncAfterQuickUnlock_key" />
<CheckBoxPreference
android:key="@string/TanExpiresOnUse_key" android:key="@string/TanExpiresOnUse_key"
android:title="@string/TanExpiresOnUse_title" android:title="@string/TanExpiresOnUse_title"
android:summary="@string/TanExpiresOnUse_summary" android:summary="@string/TanExpiresOnUse_summary"

View File

@@ -0,0 +1,99 @@
using System;
using Android.App;
using Android.Widget;
using keepass2android.Io;
using KeePassLib.Serialization;
namespace keepass2android
{
public class SyncUtil
{
private Activity _activity;
public SyncUtil(Activity activity)
{
_activity = activity;
}
public class SyncOtpAuxFile : RunnableOnFinish
{
private readonly IOConnectionInfo _ioc;
public SyncOtpAuxFile(Activity activity, IOConnectionInfo ioc)
: base(activity, null)
{
_ioc = ioc;
}
public override void Run()
{
StatusLogger.UpdateMessage(UiStringKey.SynchronizingOtpAuxFile);
try
{
//simply open the file. The file storage does a complete sync.
using (App.Kp2a.GetOtpAuxFileStorage(_ioc).OpenFileForRead(_ioc))
{
}
Finish(true);
}
catch (Exception e)
{
Finish(false, e.Message);
}
}
}
public void SynchronizeDatabase(Action runAfterSuccess)
{
var filestorage = App.Kp2a.GetFileStorage(App.Kp2a.CurrentDb.Ioc);
RunnableOnFinish task;
OnFinish onFinish = new ActionOnFinish(_activity, (success, message, activity) =>
{
if (!String.IsNullOrEmpty(message))
Toast.MakeText(activity, message, ToastLength.Long).Show();
// Tell the adapter to refresh it's list
BaseAdapter adapter = (activity as GroupBaseActivity)?.ListAdapter;
adapter?.NotifyDataSetChanged();
if (App.Kp2a.CurrentDb?.OtpAuxFileIoc != null)
{
var task2 = new SyncOtpAuxFile(_activity, App.Kp2a.CurrentDb.OtpAuxFileIoc);
task2.OnFinishToRun = new ActionOnFinish(_activity, (b, s, activeActivity) =>
{
runAfterSuccess();
});
new ProgressTask(App.Kp2a, activity, task2).Run(true);
}
else
{
runAfterSuccess();
}
});
if (filestorage is CachingFileStorage)
{
task = new SynchronizeCachedDatabase(_activity, App.Kp2a, onFinish);
}
else
{
task = new CheckDatabaseForChanges(_activity, App.Kp2a, onFinish);
}
var progressTask = new ProgressTask(App.Kp2a, _activity, task);
progressTask.Run();
}
}
}

View File

@@ -460,14 +460,14 @@ namespace keepass2android
} }
else else
{ {
AskForReload(activity); AskForReload(activity, null);
} }
} }
} }
private void AskForReload(Activity activity) private void AskForReload(Activity activity, Action<bool> actionOnResult)
{ {
AlertDialog.Builder builder = new AlertDialog.Builder(activity); AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.SetTitle(activity.GetString(Resource.String.AskReloadFile_title)); builder.SetTitle(activity.GetString(Resource.String.AskReloadFile_title));
@@ -480,16 +480,27 @@ namespace keepass2android
CurrentDb.ReloadRequested = true; CurrentDb.ReloadRequested = true;
activity.SetResult(KeePass.ExitReloadDb); activity.SetResult(KeePass.ExitReloadDb);
activity.Finish(); activity.Finish();
if (actionOnResult != null)
actionOnResult(true);
}); });
builder.SetNegativeButton(activity.GetString(Android.Resource.String.No), (dlgSender, dlgEvt) => builder.SetNegativeButton(activity.GetString(Android.Resource.String.No), (dlgSender, dlgEvt) =>
{ {
if (actionOnResult != null)
actionOnResult(false);
}); });
Dialog dialog = builder.Create(); Dialog dialog = builder.Create();
dialog.SetOnDismissListener(new Util.DismissListener(() =>
{
if (actionOnResult != null)
actionOnResult(false);
}));
dialog.Show(); dialog.Show();
} }
@@ -733,12 +744,12 @@ namespace keepass2android
} }
} }
public void TriggerReload(Context ctx) public void TriggerReload(Context ctx, Action<bool> actionOnResult)
{ {
Handler handler = new Handler(Looper.MainLooper); Handler handler = new Handler(Looper.MainLooper);
handler.Post(() => handler.Post(() =>
{ {
AskForReload((Activity) ctx); AskForReload((Activity) ctx, actionOnResult);
}); });
} }

View File

@@ -207,6 +207,7 @@
<Compile Include="settings\ExportKeyfileActivity.cs" /> <Compile Include="settings\ExportKeyfileActivity.cs" />
<Compile Include="settings\IconSetPreference.cs" /> <Compile Include="settings\IconSetPreference.cs" />
<Compile Include="SwitchImeActivity.cs" /> <Compile Include="SwitchImeActivity.cs" />
<Compile Include="SyncUtil.cs" />
<Compile Include="timeout\TimeoutHelper.cs" /> <Compile Include="timeout\TimeoutHelper.cs" />
<Compile Include="GroupActivity.cs" /> <Compile Include="GroupActivity.cs" />
<Compile Include="GroupBaseActivity.cs" /> <Compile Include="GroupBaseActivity.cs" />