can now view entry history and remove/restore previous versions. closes #298

This commit is contained in:
Philipp Crocoll
2022-02-05 15:53:08 +01:00
parent 35f74f5ea4
commit ed234c898e
10 changed files with 5238 additions and 3505 deletions

1
.gitignore vendored
View File

@@ -172,3 +172,4 @@ src/java/Keepass2AndroidPluginSDK2/build/generated/mockable-Google-Inc.-Google-A
/src/java/KP2AKdbLibrary/app/.cxx
/src/ActionViewFilterTest
/docs/gdrive-verification
/src/MegaTest

File diff suppressed because it is too large Load Diff

View File

@@ -93,6 +93,7 @@ namespace keepass2android
{
public const String KeyEntry = "entry";
public const String KeyRefreshPos = "refresh_pos";
public const String KeyEntryHistoryIndex = "entry_history_index";
public const String KeyActivateKeyboard = "activate_keyboard";
public const String KeyGroupFullPath = "groupfullpath_key";
@@ -101,13 +102,14 @@ namespace keepass2android
public static void Launch(Activity act, PwEntry pw, int pos, AppTask appTask, ActivityFlags? flags = null)
public static void Launch(Activity act, PwEntry pw, int pos, AppTask appTask, ActivityFlags? flags = null, int historyIndex=-1)
{
Intent i = new Intent(act, typeof(EntryActivity));
var db = App.Kp2a.FindDatabaseForElement(pw);
i.PutExtra(KeyEntry, new ElementAndDatabaseId(db, pw).FullId);
i.PutExtra(KeyRefreshPos, pos);
i.PutExtra(KeyEntryHistoryIndex, historyIndex);
if (App.Kp2a.CurrentDb != db)
{
@@ -135,7 +137,10 @@ namespace keepass2android
_activityDesign = new ActivityDesign(this);
}
//this is the entry we display. Note that it might be an element from a History list in case _historyIndex >= 0
public PwEntry Entry;
//if _historyIndex >=0, _historyParentEntry stores the PwEntry which contains the history entry "Entry"
private PwEntry _historyParentEntry;
private PasswordFont _passwordFont = new PasswordFont();
@@ -183,7 +188,7 @@ namespace keepass2android
protected void SetupEditButtons() {
View edit = FindViewById(Resource.Id.entry_edit);
if (App.Kp2a.CurrentDb.CanWrite)
if (App.Kp2a.CurrentDb.CanWrite && _historyIndex < 0)
{
edit.Visibility = ViewStates.Visible;
edit.Click += (sender, e) =>
@@ -421,16 +426,41 @@ namespace keepass2android
ElementAndDatabaseId dbAndElementId = new ElementAndDatabaseId(i.GetStringExtra(KeyEntry));
PwUuid uuid = new PwUuid(MemUtil.HexStringToByteArray(dbAndElementId.ElementIdString));
_pos = i.GetIntExtra(KeyRefreshPos, -1);
_historyIndex = i.GetIntExtra(KeyEntryHistoryIndex, -1);
AppTask = AppTask.GetTaskInOnCreate(savedInstanceState, Intent);
Entry = db.EntriesById[uuid];
// Refresh Menu contents in case onCreateMenuOptions was called before Entry was set
if (_historyIndex >= 0 && _historyIndex < Entry.History.UCount)
{
_historyParentEntry = Entry;
Entry = Entry.History.Skip(_historyIndex).First();
FindViewById<Button>(Resource.Id.btn_restore_history).Click += (sender, args) =>
{
RestoreFromHistory();
SaveHistoryChangeAndFinish();
};
FindViewById<Button>(Resource.Id.btn_remove_history).Click += (sender, args) =>
{
RemoveFromHistory();
SaveHistoryChangeAndFinish();
};
}
else
{
// Update last access time.
Entry.Touch(false);
FindViewById<Button>(Resource.Id.btn_restore_history).Visibility = ViewStates.Gone;
FindViewById<Button>(Resource.Id.btn_remove_history).Visibility = ViewStates.Gone;
}
// Refresh Menu contents in case onCreateMenuOptions was called before Entry was set
ActivityCompat.InvalidateOptionsMenu(this);
// Update last access time.
Entry.Touch(false);
if (PwDefs.IsTanEntry(Entry)
&& prefs.GetBoolean(GetString(Resource.String.TanExpiresOnUse_key), Resources.GetBoolean(Resource.Boolean.TanExpiresOnUse_default))
@@ -462,7 +492,39 @@ namespace keepass2android
AppTask.CompleteOnCreateEntryActivity(this);
}
private void NotifyPluginsOnOpen()
private void RemoveFromHistory()
{
_historyParentEntry.History.RemoveAt((uint)_historyIndex);
_historyParentEntry.Touch(true, false);
}
private void RestoreFromHistory()
{
var db = App.Kp2a.FindDatabaseForElement(_historyParentEntry);
_historyParentEntry.RestoreFromBackup((uint)_historyIndex, db.KpDatabase);
_historyParentEntry.Touch(true, false);
}
private void SaveHistoryChangeAndFinish()
{
PwGroup parent = _historyParentEntry.ParentGroup;
if (parent != null)
{
// Mark parent group dirty (title might have changed etc.)
App.Kp2a.DirtyGroups.Add(parent);
}
var saveTask = new SaveDb(this, App.Kp2a, App.Kp2a.FindDatabaseForElement(Entry), new ActionOnFinish(this, (success, message, activity) =>
{
activity.SetResult(KeePass.ExitRefresh);
activity.Finish();
}));
ProgressTask pt = new ProgressTask(App.Kp2a, this, saveTask);
pt.Run();
}
private void NotifyPluginsOnOpen()
{
Intent i = new Intent(Strings.ActionOpenEntry);
i.PutExtra(Strings.ExtraSender, PackageName);
@@ -854,12 +916,41 @@ namespace keepass2android
PopulateBinaries();
PopulatePreviousVersions();
SetPasswordStyle();
}
private void PopulatePreviousVersions()
{
ViewGroup historyGroup = (ViewGroup)FindViewById(Resource.Id.previous_versions);
int index = 0;
foreach (var previousVersion in Entry.History)
{
protected override void OnDestroy()
Button btn = new Button(this);
btn.Text = getDateTime(previousVersion.LastModificationTime);
//copy variable from outer scope for capturing it below.
var index1 = index;
btn.Click += (sender, args) =>
{
EntryActivity.Launch(this, this.Entry, this._pos, this.AppTask, null, index1);
};
historyGroup.AddView(btn);
index++;
}
FindViewById(Resource.Id.entry_history_container).Visibility = Entry.History.Any() ? ViewStates.Visible : ViewStates.Gone;
}
protected override void OnDestroy()
{
NotifyPluginsOnClose();
if (_pluginActionReceiver != null)
@@ -1083,6 +1174,7 @@ namespace keepass2android
private ExportBinaryProcessManager _exportBinaryProcessManager;
private bool _showPasswordDefault;
private bool _showTotpDefault;
private int _historyIndex;
protected override void OnSaveInstanceState(Bundle outState)
{

View File

@@ -797,7 +797,7 @@ namespace keepass2android
}
}
public void Reload() {
//this reload ìs necessary to overcome a strange problem with the extra string fields which get lost
//somehow after re-creating the activity. Maybe a Mono for Android bug?

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/entry_table"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
@@ -348,32 +349,7 @@
style="@style/EntryItem" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/entryfield_container_modified"
style="@style/EntryEditSingleLine_container">
<ImageView
style="@style/EntryEditSingleLine_ImageView"
android:src="@drawable/ic_entry_modified" />
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="vertical">
<!-- Modified -->
<TextView
android:id="@+id/entry_modified_label"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/entry_modified"
style="@style/EntryFieldHeader" />
<TextView
android:id="@+id/entry_modified"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
style="@style/EntryItem" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/entryfield_container_expires"
style="@style/EntryEditSingleLine_container">
@@ -400,4 +376,77 @@
style="@style/EntryItem" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/entryfield_container_modified"
style="@style/EntryEditSingleLine_container">
<ImageView
style="@style/EntryEditSingleLine_ImageView"
android:src="@drawable/ic_entry_modified" />
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="vertical">
<!-- Modified -->
<TextView
android:id="@+id/entry_modified_label"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/entry_modified"
style="@style/EntryFieldHeader" />
<TextView
android:id="@+id/entry_modified"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
style="@style/EntryItem" />
<Button android:id="@+id/btn_restore_history"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/ic_entry_history"
android:text="@string/restore_history"
/>
<Button android:id="@+id/btn_remove_history"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:drawableLeft="@android:drawable/ic_menu_delete"
android:text="@string/remove_history"
/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/entry_history_container"
style="@style/EntryEditSingleLine_container">
<ImageView
style="@style/EntryEditSingleLine_ImageView"
android:src="@drawable/ic_entry_history" />
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="vertical">
<!-- previous versions-->
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/entry_history"
style="@style/EntryFieldHeader" />
<LinearLayout
android:id="@+id/previous_versions"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@@ -136,6 +136,7 @@
<string name="entry_user_name">User Name</string>
<string name="entry_extra_strings">Extra string fields</string>
<string name="entry_binaries">File attachments</string>
<string name="entry_history">Previous versions</string>
<string name="error_can_not_handle_uri">Keepass2Android cannot handle this URI.</string>
<string name="error_could_not_create_group">Error creating group.</string>
<string name="error_could_not_create_parent">Could not create parent directory.</string>
@@ -828,8 +829,9 @@
<string name="child_db_Enabled_title">Open automatically</string>
<string name="database_file_heading">Database file</string>
<string name="if_device_text">Enable for %1$s</string>
<string name="restore_history">Restore this version</string>
<string name="remove_history">Remove this version</string>
<string name="DbUnlockedChannel_name">Database unlocked</string>
<string name="DbUnlockedChannel_desc">Notification about the database being unlocked</string>

View File

@@ -1138,7 +1138,8 @@ namespace keepass2android
{
foreach (var db in OpenDatabases)
{
if (db.Elements.Contains(element))
//we compare UUIDs and not by reference. this is more robust and works with history items as well
if (db.Elements.Any(e => e.Uuid?.Equals(element.Uuid) == true))
return db;
}
return null;

View File

@@ -399,6 +399,7 @@
<AndroidResource Include="Resources\drawable-mdpi\ic_arrow_back_white_24dp.png" />
<AndroidResource Include="Resources\drawable-mdpi\ic_cross.png" />
<AndroidResource Include="Resources\drawable-mdpi\ic_entry_attachments.png" />
<AndroidResource Include="Resources\drawable-mdpi\ic_entry_history.png" />
<AndroidResource Include="Resources\drawable-mdpi\ic_entry_comments.png" />
<AndroidResource Include="Resources\drawable-mdpi\ic_entry_created.png" />
<AndroidResource Include="Resources\drawable-mdpi\ic_entry_expires.png" />
@@ -987,6 +988,9 @@
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\ic_entry_attachments.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\ic_entry_history.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\ic_entry_comments.png" />
</ItemGroup>