diff --git a/app/src/androidTest/java/com/kunzisoft/keepass/tests/database/DeleteEntry.java b/app/src/androidTest/java/com/kunzisoft/keepass/tests/database/DeleteEntry.java index 227c5ca94..15a46383c 100644 --- a/app/src/androidTest/java/com/kunzisoft/keepass/tests/database/DeleteEntry.java +++ b/app/src/androidTest/java/com/kunzisoft/keepass/tests/database/DeleteEntry.java @@ -19,19 +19,11 @@ */ package com.kunzisoft.keepass.tests.database; -import android.content.Context; import android.test.AndroidTestCase; - -import com.kunzisoft.keepass.database.action.node.DeleteGroupRunnable; -import com.kunzisoft.keepass.database.element.Database; +import com.kunzisoft.keepass.database.element.GroupVersioned; import com.kunzisoft.keepass.database.element.PwDatabase; import com.kunzisoft.keepass.database.element.PwDatabaseV3; -import com.kunzisoft.keepass.database.element.PwEntryInterface; import com.kunzisoft.keepass.database.element.PwEntryV3; -import com.kunzisoft.keepass.database.element.PwGroupInterface; -import com.kunzisoft.keepass.database.search.SearchDbHelper; - -import java.util.List; public class DeleteEntry extends AndroidTestCase { private static final String GROUP1_NAME = "Group1"; @@ -57,7 +49,7 @@ public class DeleteEntry extends AndroidTestCase { } PwDatabaseV3 pm = (PwDatabaseV3) db.getPwDatabase(); - PwGroupInterface group1 = getGroup(pm, GROUP1_NAME); + GroupVersioned group1 = getGroup(pm, GROUP1_NAME); assertNotNull("Could not find group1", group1); // Delete the group @@ -73,8 +65,8 @@ public class DeleteEntry extends AndroidTestCase { // Verify the entries were removed from the search index SearchDbHelper dbHelp = new SearchDbHelper(ctx); - PwGroupInterface results1 = dbHelp.search(db.getPwDatabase(), ENTRY1_NAME, 100); - PwGroupInterface results2 = dbHelp.search(db.getPwDatabase(), ENTRY2_NAME, 100); + GroupVersioned results1 = dbHelp.search(db.getPwDatabase(), ENTRY1_NAME, 100); + GroupVersioned results2 = dbHelp.search(db.getPwDatabase(), ENTRY2_NAME, 100); assertEquals("Entry1 was not removed from the search results", 0, results1.numbersOfChildEntries()); assertEquals("Entry2 was not removed from the search results", 0, results2.numbersOfChildEntries()); @@ -101,11 +93,11 @@ public class DeleteEntry extends AndroidTestCase { } - private PwGroupInterface getGroup(PwDatabase pm, String name) { + private GroupVersioned getGroup(PwDatabase pm, String name) { /* - List groups = pm.getGroups(); + List groups = pm.getGroups(); for ( int i = 0; i < groups.size(); i++ ) { - PwGroupInterface group = groups.get(i); + GroupVersioned group = groups.get(i); if ( group.getTitle().equals(name) ) { return group; } diff --git a/app/src/androidTest/java/com/kunzisoft/keepass/tests/search/SearchTest.java b/app/src/androidTest/java/com/kunzisoft/keepass/tests/search/SearchTest.java index 6163c3fff..55dccb177 100644 --- a/app/src/androidTest/java/com/kunzisoft/keepass/tests/search/SearchTest.java +++ b/app/src/androidTest/java/com/kunzisoft/keepass/tests/search/SearchTest.java @@ -24,10 +24,8 @@ import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; import android.test.AndroidTestCase; - import com.kunzisoft.keepass.database.element.Database; -import com.kunzisoft.keepass.database.element.PwGroupInterface; -import com.kunzisoft.keepass.tests.database.TestData; +import com.kunzisoft.keepass.database.element.GroupVersioned; public class SearchTest extends AndroidTestCase { @@ -37,25 +35,25 @@ public class SearchTest extends AndroidTestCase { protected void setUp() throws Exception { super.setUp(); - mDb = TestData.GetDb1(getContext(), true); + //mDb = TestData.GetDb1(getContext(), true); } public void testSearch() { - PwGroupInterface results = mDb.search("Amazon"); + GroupVersioned results = mDb.search("Amazon"); //assertTrue("Search result not found.", results.numbersOfChildEntries() > 0); } public void testBackupIncluded() { updateOmitSetting(false); - PwGroupInterface results = mDb.search("BackupOnly"); + GroupVersioned results = mDb.search("BackupOnly"); //assertTrue("Search result not found.", results.numbersOfChildEntries() > 0); } public void testBackupExcluded() { updateOmitSetting(true); - PwGroupInterface results = mDb.search("BackupOnly"); + GroupVersioned results = mDb.search("BackupOnly"); //assertFalse("Search result found, but should not have been.", results.numbersOfChildEntries() > 0); } diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.java b/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.java index 1dc39b442..5b9070006 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.java +++ b/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.java @@ -37,7 +37,6 @@ import android.view.MenuItem; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; - import com.getkeepsafe.taptargetview.TapTarget; import com.getkeepsafe.taptargetview.TapTargetView; import com.kunzisoft.keepass.R; @@ -45,7 +44,7 @@ import com.kunzisoft.keepass.activities.lock.LockingHideActivity; import com.kunzisoft.keepass.app.App; import com.kunzisoft.keepass.database.ExtraFields; import com.kunzisoft.keepass.database.element.Database; -import com.kunzisoft.keepass.database.element.PwEntryInterface; +import com.kunzisoft.keepass.database.element.EntryVersioned; import com.kunzisoft.keepass.database.element.PwNodeId; import com.kunzisoft.keepass.database.security.ProtectedString; import com.kunzisoft.keepass.notifications.NotificationCopyingService; @@ -75,7 +74,7 @@ public class EntryActivity extends LockingHideActivity { private EntryContentsView entryContentsView; private Toolbar toolbar; - protected PwEntryInterface mEntry; + protected EntryVersioned mEntry; private boolean mShowPassword; private ClipboardHelper clipboardHelper; @@ -83,7 +82,7 @@ public class EntryActivity extends LockingHideActivity { private int iconColor; - public static void launch(Activity activity, PwEntryInterface pw, boolean readOnly) { + public static void launch(Activity activity, EntryVersioned pw, boolean readOnly) { if (TimeoutHelper.INSTANCE.checkTimeAndLockIfTimeout(activity)) { Intent intent = new Intent(activity, EntryActivity.class); intent.putExtra(KEY_ENTRY, pw.getNodeId()); @@ -318,7 +317,7 @@ public class EntryActivity extends LockingHideActivity { database.getDrawFactory().assignDatabaseIconTo(this, titleIconView, mEntry.getIcon(), iconColor); // Assign title text - titleView.setText(PwEntryInterface.getVisualTitle(mEntry)); + titleView.setText(mEntry.getVisualTitle()); // Assign basic fields entryContentsView.assignUserName(mEntry.getUsername()); diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.java b/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.java index 47303e9f6..58fbf3d60 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.java +++ b/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.java @@ -46,13 +46,7 @@ import com.kunzisoft.keepass.database.action.node.ActionNodeValues; import com.kunzisoft.keepass.database.action.node.AddEntryRunnable; import com.kunzisoft.keepass.database.action.node.AfterActionNodeFinishRunnable; import com.kunzisoft.keepass.database.action.node.UpdateEntryRunnable; -import com.kunzisoft.keepass.database.element.Database; -import com.kunzisoft.keepass.database.element.PwDate; -import com.kunzisoft.keepass.database.element.PwEntryInterface; -import com.kunzisoft.keepass.database.element.PwGroupInterface; -import com.kunzisoft.keepass.database.element.PwIcon; -import com.kunzisoft.keepass.database.element.PwIconStandard; -import com.kunzisoft.keepass.database.element.PwNodeId; +import com.kunzisoft.keepass.database.element.*; import com.kunzisoft.keepass.database.security.ProtectedString; import com.kunzisoft.keepass.dialogs.GeneratePasswordDialogFragment; import com.kunzisoft.keepass.dialogs.IconPickerDialogFragment; @@ -85,9 +79,9 @@ public class EntryEditActivity extends LockingHideActivity private Database database; - protected PwEntryInterface mEntry; - protected PwGroupInterface mParent; - protected PwEntryInterface mCallbackNewEntry; + protected EntryVersioned mEntry; + protected GroupVersioned mParent; + protected EntryVersioned mCallbackNewEntry; protected boolean mIsNew; protected PwIconStandard mSelectedIconStandard; @@ -112,7 +106,7 @@ public class EntryEditActivity extends LockingHideActivity * @param activity from activity * @param pwEntry Entry to update */ - public static void launch(Activity activity, PwEntryInterface pwEntry) { + public static void launch(Activity activity, EntryVersioned pwEntry) { if (TimeoutHelper.INSTANCE.checkTimeAndLockIfTimeout(activity)) { Intent intent = new Intent(activity, EntryEditActivity.class); intent.putExtra(KEY_ENTRY, pwEntry.getNodeId()); @@ -126,7 +120,7 @@ public class EntryEditActivity extends LockingHideActivity * @param activity from activity * @param pwGroup Group who will contains new entry */ - public static void launch(Activity activity, PwGroupInterface pwGroup) { + public static void launch(Activity activity, GroupVersioned pwGroup) { if (TimeoutHelper.INSTANCE.checkTimeAndLockIfTimeout(activity)) { Intent intent = new Intent(activity, EntryEditActivity.class); intent.putExtra(KEY_PARENT, pwGroup.getNodeId()); @@ -415,10 +409,10 @@ public class EntryEditActivity extends LockingHideActivity return errorValidation.isValidate; } - protected PwEntryInterface populateNewEntry() { + protected EntryVersioned populateNewEntry() { Database database = App.getDB(); - PwEntryInterface newEntry = mEntry.duplicate(); + EntryVersioned newEntry = new EntryVersioned(mEntry); database.startManageEntry(newEntry); database.createBackupOf(newEntry); diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/GroupActivity.java b/app/src/main/java/com/kunzisoft/keepass/activities/GroupActivity.java index 8249b4d5f..fba39248e 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/GroupActivity.java +++ b/app/src/main/java/com/kunzisoft/keepass/activities/GroupActivity.java @@ -71,12 +71,7 @@ import com.kunzisoft.keepass.database.action.node.DeleteGroupRunnable; import com.kunzisoft.keepass.database.action.node.MoveEntryRunnable; import com.kunzisoft.keepass.database.action.node.MoveGroupRunnable; import com.kunzisoft.keepass.database.action.node.UpdateGroupRunnable; -import com.kunzisoft.keepass.database.element.Database; -import com.kunzisoft.keepass.database.element.PwEntryInterface; -import com.kunzisoft.keepass.database.element.PwGroupInterface; -import com.kunzisoft.keepass.database.element.PwIcon; -import com.kunzisoft.keepass.database.element.PwNodeId; -import com.kunzisoft.keepass.database.element.PwNodeInterface; +import com.kunzisoft.keepass.database.element.*; import com.kunzisoft.keepass.dialogs.AssignMasterKeyDialogFragment; import com.kunzisoft.keepass.dialogs.GroupEditDialogFragment; import com.kunzisoft.keepass.dialogs.IconPickerDialogFragment; @@ -129,17 +124,17 @@ public class GroupActivity extends LockingActivity private ListNodesFragment listNodesFragment; private boolean currentGroupIsASearch; - private PwGroupInterface rootGroup; - private PwGroupInterface mCurrentGroup; - private PwGroupInterface oldGroupToUpdate; - private PwNodeInterface nodeToCopy; - private PwNodeInterface nodeToMove; + private GroupVersioned rootGroup; + private GroupVersioned mCurrentGroup; + private GroupVersioned oldGroupToUpdate; + private NodeVersioned nodeToCopy; + private NodeVersioned nodeToMove; private SearchEntryCursorAdapter searchSuggestionAdapter; private int iconColor; - private static void buildAndLaunchIntent(Activity activity, PwGroupInterface group, boolean readOnly, + private static void buildAndLaunchIntent(Activity activity, GroupVersioned group, boolean readOnly, IntentBuildLauncher intentBuildLauncher) { if (TimeoutHelper.INSTANCE.checkTimeAndLockIfTimeout(activity)) { Intent intent = new Intent(activity, GroupActivity.class); @@ -165,7 +160,7 @@ public class GroupActivity extends LockingActivity launch(activity, null, readOnly); } - public static void launch(Activity activity, PwGroupInterface group, boolean readOnly) { + public static void launch(Activity activity, GroupVersioned group, boolean readOnly) { TimeoutHelper.INSTANCE.recordTime(activity); buildAndLaunchIntent(activity, group, readOnly, (intent) -> activity.startActivityForResult(intent, 0)); @@ -316,7 +311,7 @@ public class GroupActivity extends LockingActivity } } - private void openSearchGroup(PwGroupInterface group) { + private void openSearchGroup(GroupVersioned group) { // Delete the previous search fragment Fragment searchFragment = getSupportFragmentManager().findFragmentByTag(SEARCH_FRAGMENT_TAG); if (searchFragment != null) { @@ -328,11 +323,11 @@ public class GroupActivity extends LockingActivity openGroup(group, true); } - private void openChildGroup(PwGroupInterface group) { + private void openChildGroup(GroupVersioned group) { openGroup(group, false); } - private void openGroup(PwGroupInterface group, boolean isASearch) { + private void openGroup(GroupVersioned group, boolean isASearch) { // Check TimeoutHelper TimeoutHelper.INSTANCE.checkTimeAndLockIfTimeoutOrResetTimeout(this, () -> { // Open a group in a new fragment @@ -375,7 +370,7 @@ public class GroupActivity extends LockingActivity super.onSaveInstanceState(outState); } - protected @Nullable PwGroupInterface retrieveCurrentGroup(Intent intent, @Nullable Bundle savedInstanceState) { + protected @Nullable GroupVersioned retrieveCurrentGroup(Intent intent, @Nullable Bundle savedInstanceState) { // If it's a search if ( Intent.ACTION_SEARCH.equals(intent.getAction()) ) { @@ -395,7 +390,7 @@ public class GroupActivity extends LockingActivity setReadOnly(database.isReadOnly() || getReadOnly()); // Force read only if the database is like that Log.w(TAG, "Creating tree view"); - PwGroupInterface currentGroup; + GroupVersioned currentGroup; if (pwGroupId == null) { currentGroup = rootGroup; } else { @@ -486,18 +481,18 @@ public class GroupActivity extends LockingActivity } @Override - public void onNodeClick(PwNodeInterface node) { + public void onNodeClick(NodeVersioned node) { switch (node.getType()) { case GROUP: try { - openChildGroup((PwGroupInterface) node); + openChildGroup((GroupVersioned) node); } catch (ClassCastException e) { Log.e(TAG, "Node can't be cast in Group"); } break; case ENTRY: try { - PwEntryInterface entry = ((PwEntryInterface) node); + EntryVersioned entry = ((EntryVersioned) node); EntrySelectionHelper.INSTANCE.doEntrySelectionAction(getIntent(), () -> { EntryActivity.launch(GroupActivity.this, entry, getReadOnly()); @@ -531,7 +526,7 @@ public class GroupActivity extends LockingActivity } } - private Entry getEntry(PwEntryInterface entry) { + private Entry getEntry(EntryVersioned entry) { Entry entryModel = new Entry(); entryModel.setTitle(entry.getTitle()); entryModel.setUsername(entry.getUsername()); @@ -547,29 +542,29 @@ public class GroupActivity extends LockingActivity } @Override - public boolean onOpenMenuClick(PwNodeInterface node) { + public boolean onOpenMenuClick(NodeVersioned node) { onNodeClick(node); return true; } @Override - public boolean onEditMenuClick(PwNodeInterface node) { + public boolean onEditMenuClick(NodeVersioned node) { switch (node.getType()) { case GROUP: - oldGroupToUpdate = (PwGroupInterface) node; + oldGroupToUpdate = (GroupVersioned) node; GroupEditDialogFragment.build(oldGroupToUpdate) .show(getSupportFragmentManager(), GroupEditDialogFragment.TAG_CREATE_GROUP); break; case ENTRY: - EntryEditActivity.launch(GroupActivity.this, (PwEntryInterface) node); + EntryEditActivity.launch(GroupActivity.this, (EntryVersioned) node); break; } return true; } @Override - public boolean onCopyMenuClick(PwNodeInterface node) { + public boolean onCopyMenuClick(NodeVersioned node) { toolbarPasteExpandableLayout.expand(); nodeToCopy = node; @@ -590,7 +585,7 @@ public class GroupActivity extends LockingActivity Log.e(TAG, "Copy not allowed for group"); break; case ENTRY: - copyEntry((PwEntryInterface) nodeToCopy, mCurrentGroup); + copyEntry((EntryVersioned) nodeToCopy, mCurrentGroup); break; } nodeToCopy = null; @@ -600,7 +595,7 @@ public class GroupActivity extends LockingActivity } } - private void copyEntry(PwEntryInterface entryToCopy, PwGroupInterface newParent) { + private void copyEntry(EntryVersioned entryToCopy, GroupVersioned newParent) { new Thread(new CopyEntryRunnable(this, App.getDB(), entryToCopy, @@ -611,7 +606,7 @@ public class GroupActivity extends LockingActivity } @Override - public boolean onMoveMenuClick(PwNodeInterface node) { + public boolean onMoveMenuClick(NodeVersioned node) { toolbarPasteExpandableLayout.expand(); nodeToMove = node; @@ -629,10 +624,10 @@ public class GroupActivity extends LockingActivity case R.id.menu_paste: switch (nodeToMove.getType()) { case GROUP: - moveGroup((PwGroupInterface) nodeToMove, mCurrentGroup); + moveGroup((GroupVersioned) nodeToMove, mCurrentGroup); break; case ENTRY: - moveEntry((PwEntryInterface) nodeToMove, mCurrentGroup); + moveEntry((EntryVersioned) nodeToMove, mCurrentGroup); break; } nodeToMove = null; @@ -642,7 +637,7 @@ public class GroupActivity extends LockingActivity } } - private void moveGroup(PwGroupInterface groupToMove, PwGroupInterface newParent) { + private void moveGroup(GroupVersioned groupToMove, GroupVersioned newParent) { new Thread(new MoveGroupRunnable( this, App.getDB(), @@ -653,7 +648,7 @@ public class GroupActivity extends LockingActivity ).start(); } - private void moveEntry(PwEntryInterface entryToMove, PwGroupInterface newParent) { + private void moveEntry(EntryVersioned entryToMove, GroupVersioned newParent) { new Thread(new MoveEntryRunnable( this, App.getDB(), @@ -665,19 +660,19 @@ public class GroupActivity extends LockingActivity } @Override - public boolean onDeleteMenuClick(PwNodeInterface node) { + public boolean onDeleteMenuClick(NodeVersioned node) { switch (node.getType()) { case GROUP: - deleteGroup((PwGroupInterface) node); + deleteGroup((GroupVersioned) node); break; case ENTRY: - deleteEntry((PwEntryInterface) node); + deleteEntry((EntryVersioned) node); break; } return true; } - private void deleteGroup(PwGroupInterface group) { + private void deleteGroup(GroupVersioned group) { //TODO Verify trash recycle bin new Thread(new DeleteGroupRunnable( this, @@ -688,7 +683,7 @@ public class GroupActivity extends LockingActivity ).start(); } - private void deleteEntry(PwEntryInterface entry) { + private void deleteEntry(EntryVersioned entry) { new Thread(new DeleteEntryRunnable( this, App.getDB(), @@ -978,7 +973,7 @@ public class GroupActivity extends LockingActivity case CREATION: // If group creation // Build the group - PwGroupInterface newGroup = database.createGroup(); + GroupVersioned newGroup = database.createGroup(); newGroup.setTitle(name); newGroup.setIcon(icon); // Not really needed here because added in runnable but safe @@ -997,7 +992,7 @@ public class GroupActivity extends LockingActivity case UPDATE: // If update add new elements if (oldGroupToUpdate != null) { - PwGroupInterface updateGroup = oldGroupToUpdate.duplicate(); + GroupVersioned updateGroup = new GroupVersioned(oldGroupToUpdate); updateGroup.setTitle(name); // TODO custom icon updateGroup.setIcon(icon); @@ -1056,11 +1051,11 @@ public class GroupActivity extends LockingActivity listNodesFragment.removeNode(actionNodeValues.getOldNode()); if (actionNodeValues.getOldNode() != null) { - PwGroupInterface parent = actionNodeValues.getOldNode().getParent(); + GroupVersioned parent = actionNodeValues.getOldNode().getParent(); Database database = App.getDB(); if (database.isRecycleBinAvailable() && database.isRecycleBinEnabled()) { - PwGroupInterface recycleBin = database.getRecycleBin(); + GroupVersioned recycleBin = database.getRecycleBin(); // Add trash if it doesn't exists if (parent.equals(recycleBin) && mCurrentGroup != null diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/ListNodesFragment.java b/app/src/main/java/com/kunzisoft/keepass/activities/ListNodesFragment.java index 100365e95..9d82dcc76 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/ListNodesFragment.java +++ b/app/src/main/java/com/kunzisoft/keepass/activities/ListNodesFragment.java @@ -20,8 +20,8 @@ import android.view.ViewGroup; import com.kunzisoft.keepass.R; import com.kunzisoft.keepass.adapters.NodeAdapter; import com.kunzisoft.keepass.database.SortNodeEnum; -import com.kunzisoft.keepass.database.element.PwGroupInterface; -import com.kunzisoft.keepass.database.element.PwNodeInterface; +import com.kunzisoft.keepass.database.element.GroupVersioned; +import com.kunzisoft.keepass.database.element.NodeVersioned; import com.kunzisoft.keepass.dialogs.SortDialogFragment; import com.kunzisoft.keepass.settings.PreferencesUtil; import com.kunzisoft.keepass.stylish.StylishFragment; @@ -39,7 +39,7 @@ public class ListNodesFragment extends StylishFragment implements private OnScrollListener onScrollListener; private RecyclerView listView; - private PwGroupInterface currentGroup; + private GroupVersioned currentGroup; private NodeAdapter mAdapter; private View notFoundView; @@ -50,7 +50,7 @@ public class ListNodesFragment extends StylishFragment implements private boolean readOnly; - public static ListNodesFragment newInstance(PwGroupInterface group, boolean readOnly, boolean isASearch) { + public static ListNodesFragment newInstance(GroupVersioned group, boolean readOnly, boolean isASearch) { Bundle bundle = new Bundle(); if (group != null) { bundle.putParcelable(GROUP_KEY, group); @@ -245,7 +245,7 @@ public class ListNodesFragment extends StylishFragment implements case EntryEditActivity.ADD_OR_UPDATE_ENTRY_REQUEST_CODE: if (resultCode == EntryEditActivity.ADD_ENTRY_RESULT_CODE || resultCode == EntryEditActivity.UPDATE_ENTRY_RESULT_CODE) { - PwNodeInterface newNode = data.getParcelableExtra(EntryEditActivity.ADD_OR_UPDATE_ENTRY_KEY); + NodeVersioned newNode = data.getParcelableExtra(EntryEditActivity.ADD_OR_UPDATE_ENTRY_KEY); if (newNode != null) { if (resultCode == EntryEditActivity.ADD_ENTRY_RESULT_CODE) mAdapter.addNode(newNode); @@ -265,19 +265,19 @@ public class ListNodesFragment extends StylishFragment implements return mAdapter == null || mAdapter.getItemCount() <= 0; } - public void addNode(PwNodeInterface newNode) { + public void addNode(NodeVersioned newNode) { mAdapter.addNode(newNode); } - public void updateNode(PwNodeInterface oldNode, PwNodeInterface newNode) { + public void updateNode(NodeVersioned oldNode, NodeVersioned newNode) { mAdapter.updateNode(oldNode, newNode); } - public void removeNode(PwNodeInterface pwNode) { + public void removeNode(NodeVersioned pwNode) { mAdapter.removeNode(pwNode); } - public PwGroupInterface getMainGroup() { + public GroupVersioned getMainGroup() { return currentGroup; } diff --git a/app/src/main/java/com/kunzisoft/keepass/adapters/NodeAdapter.java b/app/src/main/java/com/kunzisoft/keepass/adapters/NodeAdapter.java index 304189db7..3dcdd0a43 100644 --- a/app/src/main/java/com/kunzisoft/keepass/adapters/NodeAdapter.java +++ b/app/src/main/java/com/kunzisoft/keepass/adapters/NodeAdapter.java @@ -27,28 +27,19 @@ import android.support.v7.util.SortedList; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.util.SortedListAdapterCallback; import android.util.Log; -import android.view.ContextMenu; -import android.view.LayoutInflater; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; +import android.view.*; import android.widget.Toast; - import com.kunzisoft.keepass.R; import com.kunzisoft.keepass.app.App; import com.kunzisoft.keepass.database.SortNodeEnum; -import com.kunzisoft.keepass.database.element.Database; -import com.kunzisoft.keepass.database.element.PwEntryInterface; -import com.kunzisoft.keepass.database.element.PwGroupInterface; -import com.kunzisoft.keepass.database.element.PwNodeInterface; +import com.kunzisoft.keepass.database.element.*; import com.kunzisoft.keepass.settings.PreferencesUtil; import com.kunzisoft.keepass.utils.Util; public class NodeAdapter extends RecyclerView.Adapter { private static final String TAG = NodeAdapter.class.getName(); - private SortedList nodeSortedList; + private SortedList nodeSortedList; private Context context; private LayoutInflater inflater; @@ -85,17 +76,17 @@ public class NodeAdapter extends RecyclerView.Adapter { this.readOnly = false; this.isASearchResult = false; - this.nodeSortedList = new SortedList<>(PwNodeInterface.class, new SortedListAdapterCallback(this) { - @Override public int compare(PwNodeInterface item1, PwNodeInterface item2) { + this.nodeSortedList = new SortedList<>(NodeVersioned.class, new SortedListAdapterCallback(this) { + @Override public int compare(NodeVersioned item1, NodeVersioned item2) { return listSort.getNodeComparator(ascendingSort, groupsBeforeSort).compare(item1, item2); } - @Override public boolean areContentsTheSame(PwNodeInterface oldItem, PwNodeInterface newItem) { + @Override public boolean areContentsTheSame(NodeVersioned oldItem, NodeVersioned newItem) { return oldItem.getTitle().equals(newItem.getTitle()) && oldItem.getIcon().equals(newItem.getIcon()); } - @Override public boolean areItemsTheSame(PwNodeInterface item1, PwNodeInterface item2) { + @Override public boolean areItemsTheSame(NodeVersioned item1, NodeVersioned item2) { return item1.equals(item2); } }); @@ -143,12 +134,12 @@ public class NodeAdapter extends RecyclerView.Adapter { /** * Rebuild the list by clear and build children from the group */ - public void rebuildList(PwGroupInterface group) { + public void rebuildList(GroupVersioned group) { this.nodeSortedList.clear(); assignPreferences(); // TODO verify sort try { - this.nodeSortedList.addAll(group.getChildrenWithoutMetastream()); + this.nodeSortedList.addAll(group.getChildEntriesWithoutMetaStream()); } catch (Exception e) { Log.e(TAG, "Can't add node elements to the list", e); Toast.makeText(context, "Can't add node elements to the list : " + e.getMessage(), Toast.LENGTH_LONG).show(); @@ -167,7 +158,7 @@ public class NodeAdapter extends RecyclerView.Adapter { * Add a node to the list * @param node Node to add */ - public void addNode(PwNodeInterface node) { + public void addNode(NodeVersioned node) { nodeSortedList.add(node); } @@ -175,7 +166,7 @@ public class NodeAdapter extends RecyclerView.Adapter { * Remove a node in the list * @param node Node to delete */ - public void removeNode(PwNodeInterface node) { + public void removeNode(NodeVersioned node) { nodeSortedList.remove(node); } @@ -184,7 +175,7 @@ public class NodeAdapter extends RecyclerView.Adapter { * @param oldNode Node before the update * @param newNode Node after the update */ - public void updateNode(PwNodeInterface oldNode, PwNodeInterface newNode) { + public void updateNode(NodeVersioned oldNode, NodeVersioned newNode) { nodeSortedList.beginBatchedUpdates(); nodeSortedList.remove(oldNode); nodeSortedList.add(newNode); @@ -210,7 +201,7 @@ public class NodeAdapter extends RecyclerView.Adapter { public BasicViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { BasicViewHolder basicViewHolder; View view; - if (viewType == PwNodeInterface.Type.GROUP.ordinal()) { + if (viewType == Type.GROUP.ordinal()) { view = inflater.inflate(R.layout.list_nodes_group, parent, false); basicViewHolder = new GroupViewHolder(view); } else { @@ -222,7 +213,7 @@ public class NodeAdapter extends RecyclerView.Adapter { @Override public void onBindViewHolder(@NonNull BasicViewHolder holder, int position) { - PwNodeInterface subNode = nodeSortedList.get(position); + NodeVersioned subNode = nodeSortedList.get(position); // Assign image int iconColor = Color.BLACK; switch (subNode.getType()) { @@ -248,12 +239,12 @@ public class NodeAdapter extends RecyclerView.Adapter { // Add username holder.subText.setText(""); holder.subText.setVisibility(View.GONE); - if (subNode.getType().equals(PwNodeInterface.Type.ENTRY)) { - PwEntryInterface entry = (PwEntryInterface) subNode; + if (subNode.getType().equals(Type.ENTRY)) { + EntryVersioned entry = (EntryVersioned) subNode; database.startManageEntry(entry); - holder.text.setText(PwEntryInterface.getVisualTitle(entry)); + holder.text.setText(entry.getVisualTitle()); String username = entry.getUsername(); if (showUsernames && !username.isEmpty()) { @@ -295,27 +286,27 @@ public class NodeAdapter extends RecyclerView.Adapter { * Callback listener to redefine to do an action when a node is click */ public interface NodeClickCallback { - void onNodeClick(PwNodeInterface node); + void onNodeClick(NodeVersioned node); } /** * Menu listener to redefine to do an action in menu */ public interface NodeMenuListener { - boolean onOpenMenuClick(PwNodeInterface node); - boolean onEditMenuClick(PwNodeInterface node); - boolean onCopyMenuClick(PwNodeInterface node); - boolean onMoveMenuClick(PwNodeInterface node); - boolean onDeleteMenuClick(PwNodeInterface node); + boolean onOpenMenuClick(NodeVersioned node); + boolean onEditMenuClick(NodeVersioned node); + boolean onCopyMenuClick(NodeVersioned node); + boolean onMoveMenuClick(NodeVersioned node); + boolean onDeleteMenuClick(NodeVersioned node); } /** * Utility class for node listener */ private class OnNodeClickListener implements View.OnClickListener { - private PwNodeInterface node; + private NodeVersioned node; - OnNodeClickListener(PwNodeInterface node) { + OnNodeClickListener(NodeVersioned node) { this.node = node; } @@ -331,11 +322,11 @@ public class NodeAdapter extends RecyclerView.Adapter { */ private class ContextMenuBuilder implements View.OnCreateContextMenuListener { - private PwNodeInterface node; + private NodeVersioned node; private NodeMenuListener menuListener; private boolean readOnly; - ContextMenuBuilder(PwNodeInterface node, NodeMenuListener menuListener, boolean readOnly) { + ContextMenuBuilder(NodeVersioned node, NodeMenuListener menuListener, boolean readOnly) { this.menuListener = menuListener; this.node = node; this.readOnly = readOnly; @@ -363,7 +354,7 @@ public class NodeAdapter extends RecyclerView.Adapter { if (readOnly || isASearchResult || node.equals(database.getRecycleBin()) - || node.getType().equals(PwNodeInterface.Type.GROUP)) { + || node.getType().equals(Type.GROUP)) { // TODO COPY For Group contextMenu.removeItem(R.id.menu_copy); } else { diff --git a/app/src/main/java/com/kunzisoft/keepass/adapters/SearchEntryCursorAdapter.java b/app/src/main/java/com/kunzisoft/keepass/adapters/SearchEntryCursorAdapter.java index ca81259e3..7e11dd460 100644 --- a/app/src/main/java/com/kunzisoft/keepass/adapters/SearchEntryCursorAdapter.java +++ b/app/src/main/java/com/kunzisoft/keepass/adapters/SearchEntryCursorAdapter.java @@ -33,7 +33,7 @@ import android.widget.TextView; import com.kunzisoft.keepass.R; import com.kunzisoft.keepass.database.cursor.EntryCursor; import com.kunzisoft.keepass.database.element.Database; -import com.kunzisoft.keepass.database.element.PwEntryInterface; +import com.kunzisoft.keepass.database.element.EntryVersioned; import com.kunzisoft.keepass.database.element.PwIcon; import com.kunzisoft.keepass.database.element.PwIconFactory; import com.kunzisoft.keepass.settings.PreferencesUtil; @@ -104,7 +104,7 @@ public class SearchEntryCursorAdapter extends CursorAdapter { database.getDrawFactory().assignDatabaseIconTo(context, viewHolder.imageViewIcon, icon, iconColor); // Assign title - String showTitle = PwEntryInterface.getVisualTitle(false, title, username, url, uuid.toString()); + String showTitle = EntryVersioned.CREATOR.getVisualTitle(false, title, username, url, uuid.toString()); viewHolder.textViewTitle.setText(showTitle); if (displayUsername && !username.isEmpty()) { viewHolder.textViewSubTitle.setText(String.format("(%s)", username)); @@ -124,8 +124,8 @@ public class SearchEntryCursorAdapter extends CursorAdapter { return database.searchEntry(constraint.toString()); } - public PwEntryInterface getEntryFromPosition(int position) { - PwEntryInterface pwEntry = null; + public EntryVersioned getEntryFromPosition(int position) { + EntryVersioned pwEntry = null; Cursor cursor = this.getCursor(); if (cursor.moveToFirst() diff --git a/app/src/main/java/com/kunzisoft/keepass/autofill/AutofillHelper.kt b/app/src/main/java/com/kunzisoft/keepass/autofill/AutofillHelper.kt index 26c610e88..7eaf623d4 100644 --- a/app/src/main/java/com/kunzisoft/keepass/autofill/AutofillHelper.kt +++ b/app/src/main/java/com/kunzisoft/keepass/autofill/AutofillHelper.kt @@ -33,7 +33,7 @@ import android.view.autofill.AutofillValue import android.widget.RemoteViews import com.kunzisoft.keepass.R import com.kunzisoft.keepass.activities.EntrySelectionHelper -import com.kunzisoft.keepass.database.element.PwEntryInterface +import com.kunzisoft.keepass.database.element.EntryVersioned import java.util.* @@ -42,7 +42,7 @@ object AutofillHelper { private const val AUTOFILL_RESPONSE_REQUEST_CODE = 8165 - private const val ASSIST_STRUCTURE = android.view.autofill.AutofillManager.EXTRA_ASSIST_STRUCTURE + private const val ASSIST_STRUCTURE = AutofillManager.EXTRA_ASSIST_STRUCTURE fun retrieveAssistStructure(intent: Intent?): AssistStructure? { intent?.let { @@ -51,7 +51,7 @@ object AutofillHelper { return null } - private fun makeEntryTitle(entry: PwEntryInterface): String { + private fun makeEntryTitle(entry: EntryVersioned): String { if (!entry.title.isEmpty() && !entry.username.isEmpty()) return String.format("%s (%s)", entry.title, entry.username) if (!entry.title.isEmpty()) @@ -62,24 +62,21 @@ object AutofillHelper { // TODO No title } - private fun buildDataset(context: Context, entry: PwEntryInterface, + private fun buildDataset(context: Context, + entry: EntryVersioned, struct: StructureParser.Result): Dataset? { val title = makeEntryTitle(entry) val views = newRemoteViews(context.packageName, title) val builder = Dataset.Builder(views) builder.setId(entry.nodeId.toString()) - if (entry.password != null) { - val value = AutofillValue.forText(entry.password) - struct.password.forEach { id -> builder.setValue(id, value) } - } - if (entry.username != null) { - val value = AutofillValue.forText(entry.username) - val ids = ArrayList(struct.username) - if (entry.username.contains("@") || struct.username.isEmpty()) - ids.addAll(struct.email) - ids.forEach { id -> builder.setValue(id, value) } - } + struct.password.forEach { id -> builder.setValue(id, AutofillValue.forText(entry.password)) } + + val ids = ArrayList(struct.username) + if (entry.username.contains("@") || struct.username.isEmpty()) + ids.addAll(struct.email) + ids.forEach { id -> builder.setValue(id, AutofillValue.forText(entry.username)) } + return try { builder.build() } catch (e: IllegalArgumentException) { @@ -91,7 +88,7 @@ object AutofillHelper { /** * Method to hit when right key is selected */ - fun buildResponseWhenEntrySelected(activity: Activity, entry: PwEntryInterface) { + fun buildResponseWhenEntrySelected(activity: Activity, entry: EntryVersioned) { val mReplyIntent: Intent activity.intent?.let { intent -> if (intent.extras.containsKey(ASSIST_STRUCTURE)) { diff --git a/app/src/main/java/com/kunzisoft/keepass/database/BinaryPool.java b/app/src/main/java/com/kunzisoft/keepass/database/BinaryPool.java index edc1864f0..14e5f8df9 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/BinaryPool.java +++ b/app/src/main/java/com/kunzisoft/keepass/database/BinaryPool.java @@ -19,9 +19,7 @@ */ package com.kunzisoft.keepass.database; -import com.kunzisoft.keepass.database.element.PwEntryInterface; -import com.kunzisoft.keepass.database.element.PwEntryV4; -import com.kunzisoft.keepass.database.element.PwGroupInterface; +import com.kunzisoft.keepass.database.element.GroupVersioned; import com.kunzisoft.keepass.database.element.PwGroupV4; import com.kunzisoft.keepass.database.security.ProtectedBinary; @@ -38,7 +36,7 @@ public class BinaryPool { } public BinaryPool(PwGroupV4 rootGroup) { - build(rootGroup); + // TODO ? build(rootGroup); } public ProtectedBinary get(int key) { @@ -92,12 +90,13 @@ public class BinaryPool { return -1; } - - private void build(PwGroupV4 rootGroup) { - PwGroupInterface.doForEachChild(rootGroup, new EntryHandler() { + + private void build(GroupVersioned rootGroup) { + /* + rootGroup.doForEachChild(new EntryHandler() { @Override - public boolean operate(PwEntryInterface entryInterface) { - PwEntryV4 entry = (PwEntryV4) entryInterface; + public boolean operate(EntryVersioned entryInterface) { + PwEntryV4 entry = entryInterface.getPwEntryV4(); for (PwEntryV4 histEntry : entry.getHistory()) { add(histEntry.getBinaries()); @@ -106,5 +105,6 @@ public class BinaryPool { return true; } }, null); + */ } } diff --git a/app/src/main/java/com/kunzisoft/keepass/database/GroupHandler.java b/app/src/main/java/com/kunzisoft/keepass/database/NodeHandler.java similarity index 95% rename from app/src/main/java/com/kunzisoft/keepass/database/GroupHandler.java rename to app/src/main/java/com/kunzisoft/keepass/database/NodeHandler.java index 8e83b4f1c..55aed8d20 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/GroupHandler.java +++ b/app/src/main/java/com/kunzisoft/keepass/database/NodeHandler.java @@ -25,6 +25,6 @@ package com.kunzisoft.keepass.database; * @author bpellin * */ -public abstract class GroupHandler { +public abstract class NodeHandler { public abstract boolean operate(T group); } \ No newline at end of file diff --git a/app/src/main/java/com/kunzisoft/keepass/database/SortNodeEnum.java b/app/src/main/java/com/kunzisoft/keepass/database/SortNodeEnum.java index b59df0f16..d9d616bf0 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/SortNodeEnum.java +++ b/app/src/main/java/com/kunzisoft/keepass/database/SortNodeEnum.java @@ -20,16 +20,16 @@ package com.kunzisoft.keepass.database; -import com.kunzisoft.keepass.database.element.PwEntryInterface; -import com.kunzisoft.keepass.database.element.PwGroupInterface; -import com.kunzisoft.keepass.database.element.PwNodeInterface; +import com.kunzisoft.keepass.database.element.EntryVersioned; +import com.kunzisoft.keepass.database.element.GroupVersioned; +import com.kunzisoft.keepass.database.element.NodeVersioned; import java.util.Comparator; public enum SortNodeEnum { DB, TITLE, USERNAME, CREATION_TIME, LAST_MODIFY_TIME, LAST_ACCESS_TIME; - public Comparator getNodeComparator(boolean ascending, boolean groupsBefore) { + public Comparator getNodeComparator(boolean ascending, boolean groupsBefore) { switch (this) { case DB: return new NodeCreationComparator(ascending, groupsBefore); // TODO Sort @@ -47,7 +47,7 @@ public enum SortNodeEnum { } } - private static abstract class NodeComparator implements Comparator { + private static abstract class NodeComparator implements Comparator { boolean ascending; boolean groupsBefore; @@ -56,19 +56,19 @@ public enum SortNodeEnum { this.groupsBefore = groupsBefore; } - int compareWith(Comparator comparatorGroup, - Comparator comparatorEntry, - PwNodeInterface object1, - PwNodeInterface object2, + int compareWith(Comparator comparatorGroup, + Comparator comparatorEntry, + NodeVersioned object1, + NodeVersioned object2, int resultOfNodeMethodCompare) { if (object1.equals(object2)) return 0; - if (object1 instanceof PwGroupInterface) { - if (object2 instanceof PwGroupInterface) { + if (object1 instanceof GroupVersioned) { + if (object2 instanceof GroupVersioned) { return comparatorGroup - .compare((PwGroupInterface) object1, (PwGroupInterface) object2); - } else if (object2 instanceof PwEntryInterface) { + .compare((GroupVersioned) object1, (GroupVersioned) object2); + } else if (object2 instanceof EntryVersioned) { if(groupsBefore) return -1; else @@ -76,11 +76,11 @@ public enum SortNodeEnum { } else { return -1; } - } else if (object1 instanceof PwEntryInterface) { - if(object2 instanceof PwEntryInterface) { + } else if (object1 instanceof EntryVersioned) { + if(object2 instanceof EntryVersioned) { return comparatorEntry - .compare((PwEntryInterface) object1, (PwEntryInterface) object2); - } else if (object2 instanceof PwGroupInterface) { + .compare((EntryVersioned) object1, (EntryVersioned) object2); + } else if (object2 instanceof GroupVersioned) { if(groupsBefore) return 1; else @@ -106,7 +106,7 @@ public enum SortNodeEnum { super(ascending, groupsBefore); } - public int compare(PwNodeInterface object1, PwNodeInterface object2) { + public int compare(NodeVersioned object1, NodeVersioned object2) { return compareWith( new GroupNameComparator(ascending), @@ -129,7 +129,7 @@ public enum SortNodeEnum { } @Override - public int compare(PwNodeInterface object1, PwNodeInterface object2) { + public int compare(NodeVersioned object1, NodeVersioned object2) { return compareWith( new GroupCreationComparator(ascending), @@ -151,7 +151,7 @@ public enum SortNodeEnum { } @Override - public int compare(PwNodeInterface object1, PwNodeInterface object2) { + public int compare(NodeVersioned object1, NodeVersioned object2) { return compareWith( new GroupLastModificationComparator(ascending), @@ -173,7 +173,7 @@ public enum SortNodeEnum { } @Override - public int compare(PwNodeInterface object1, PwNodeInterface object2) { + public int compare(NodeVersioned object1, NodeVersioned object2) { return compareWith( new GroupLastAccessComparator(ascending), @@ -205,13 +205,13 @@ public enum SortNodeEnum { /** * Group comparator by name */ - public static class GroupNameComparator extends AscendingComparator { + public static class GroupNameComparator extends AscendingComparator { GroupNameComparator(boolean ascending) { super(ascending); } - public int compare(PwGroupInterface object1, PwGroupInterface object2) { + public int compare(GroupVersioned object1, GroupVersioned object2) { if (object1.equals(object2)) return 0; @@ -228,13 +228,13 @@ public enum SortNodeEnum { /** * Group comparator by name */ - public static class GroupCreationComparator extends AscendingComparator { + public static class GroupCreationComparator extends AscendingComparator { GroupCreationComparator(boolean ascending) { super(ascending); } - public int compare(PwGroupInterface object1, PwGroupInterface object2) { + public int compare(GroupVersioned object1, GroupVersioned object2) { if (object1.equals(object2)) return 0; @@ -252,13 +252,13 @@ public enum SortNodeEnum { /** * Group comparator by last modification */ - public static class GroupLastModificationComparator extends AscendingComparator { + public static class GroupLastModificationComparator extends AscendingComparator { GroupLastModificationComparator(boolean ascending) { super(ascending); } - public int compare(PwGroupInterface object1, PwGroupInterface object2) { + public int compare(GroupVersioned object1, GroupVersioned object2) { if (object1.equals(object2)) return 0; @@ -276,13 +276,13 @@ public enum SortNodeEnum { /** * Group comparator by last access */ - public static class GroupLastAccessComparator extends AscendingComparator { + public static class GroupLastAccessComparator extends AscendingComparator { GroupLastAccessComparator(boolean ascending) { super(ascending); } - public int compare(PwGroupInterface object1, PwGroupInterface object2) { + public int compare(GroupVersioned object1, GroupVersioned object2) { if (object1.equals(object2)) return 0; @@ -300,13 +300,13 @@ public enum SortNodeEnum { /** * Comparator of Entry by Name */ - public static class EntryNameComparator extends AscendingComparator { + public static class EntryNameComparator extends AscendingComparator { EntryNameComparator(boolean ascending) { super(ascending); } - public int compare(PwEntryInterface object1, PwEntryInterface object2) { + public int compare(EntryVersioned object1, EntryVersioned object2) { if (object1.equals(object2)) return 0; @@ -323,13 +323,13 @@ public enum SortNodeEnum { /** * Comparator of Entry by Creation */ - public static class EntryCreationComparator extends AscendingComparator { + public static class EntryCreationComparator extends AscendingComparator { EntryCreationComparator(boolean ascending) { super(ascending); } - public int compare(PwEntryInterface object1, PwEntryInterface object2) { + public int compare(EntryVersioned object1, EntryVersioned object2) { if (object1.equals(object2)) return 0; @@ -347,13 +347,13 @@ public enum SortNodeEnum { /** * Comparator of Entry by Last Modification */ - public static class EntryLastModificationComparator extends AscendingComparator { + public static class EntryLastModificationComparator extends AscendingComparator { EntryLastModificationComparator(boolean ascending) { super(ascending); } - public int compare(PwEntryInterface object1, PwEntryInterface object2) { + public int compare(EntryVersioned object1, EntryVersioned object2) { if (object1.equals(object2)) return 0; @@ -371,13 +371,13 @@ public enum SortNodeEnum { /** * Comparator of Entry by Last Access */ - public static class EntryLastAccessComparator extends AscendingComparator { + public static class EntryLastAccessComparator extends AscendingComparator { EntryLastAccessComparator(boolean ascending) { super(ascending); } - public int compare(PwEntryInterface object1, PwEntryInterface object2) { + public int compare(EntryVersioned object1, EntryVersioned object2) { if (object1.equals(object2)) return 0; diff --git a/app/src/main/java/com/kunzisoft/keepass/database/action/node/AddEntryRunnable.kt b/app/src/main/java/com/kunzisoft/keepass/database/action/node/AddEntryRunnable.kt index e770e13d6..8a245e027 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/action/node/AddEntryRunnable.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/action/node/AddEntryRunnable.kt @@ -21,14 +21,14 @@ package com.kunzisoft.keepass.database.action.node import android.support.v4.app.FragmentActivity import com.kunzisoft.keepass.database.element.Database -import com.kunzisoft.keepass.database.element.PwEntryInterface -import com.kunzisoft.keepass.database.element.PwGroupInterface +import com.kunzisoft.keepass.database.element.EntryVersioned +import com.kunzisoft.keepass.database.element.GroupVersioned class AddEntryRunnable constructor( context: FragmentActivity, database: Database, - private val mNewEntry: PwEntryInterface, - private val mParent: PwGroupInterface, + private val mNewEntry: EntryVersioned, + private val mParent: GroupVersioned, finishRunnable: AfterActionNodeFinishRunnable?, save: Boolean) : ActionNodeDatabaseRunnable(context, database, finishRunnable, save) { diff --git a/app/src/main/java/com/kunzisoft/keepass/database/action/node/AddGroupRunnable.kt b/app/src/main/java/com/kunzisoft/keepass/database/action/node/AddGroupRunnable.kt index 5daf7eb05..9a4c15fe6 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/action/node/AddGroupRunnable.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/action/node/AddGroupRunnable.kt @@ -21,13 +21,13 @@ package com.kunzisoft.keepass.database.action.node import android.support.v4.app.FragmentActivity import com.kunzisoft.keepass.database.element.Database -import com.kunzisoft.keepass.database.element.PwGroupInterface +import com.kunzisoft.keepass.database.element.GroupVersioned class AddGroupRunnable constructor( context: FragmentActivity, database: Database, - private val mNewGroup: PwGroupInterface, - private val mParent: PwGroupInterface, + private val mNewGroup: GroupVersioned, + private val mParent: GroupVersioned, afterAddNodeRunnable: AfterActionNodeFinishRunnable?, save: Boolean) : ActionNodeDatabaseRunnable(context, database, afterAddNodeRunnable, save) { diff --git a/app/src/main/java/com/kunzisoft/keepass/database/action/node/AfterActionNodeFinishRunnable.kt b/app/src/main/java/com/kunzisoft/keepass/database/action/node/AfterActionNodeFinishRunnable.kt index 1ff76ece1..18eb29dee 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/action/node/AfterActionNodeFinishRunnable.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/action/node/AfterActionNodeFinishRunnable.kt @@ -19,7 +19,7 @@ */ package com.kunzisoft.keepass.database.action.node -import com.kunzisoft.keepass.database.element.PwNodeInterface +import com.kunzisoft.keepass.database.element.NodeVersioned /** * Callback method who return the node(s) modified after an action @@ -29,7 +29,7 @@ import com.kunzisoft.keepass.database.element.PwNodeInterface * - Move : @param oldNode NULL, @param NodeToMove * - Update : @param oldNode NodeToUpdate, @param NodeUpdated */ -data class ActionNodeValues(val success: Boolean, val message: String?, val oldNode: PwNodeInterface?, val newNode: PwNodeInterface?) +data class ActionNodeValues(val success: Boolean, val message: String?, val oldNode: NodeVersioned?, val newNode: NodeVersioned?) abstract class AfterActionNodeFinishRunnable { abstract fun onActionNodeFinish(actionNodeValues: ActionNodeValues) diff --git a/app/src/main/java/com/kunzisoft/keepass/database/action/node/CopyEntryRunnable.kt b/app/src/main/java/com/kunzisoft/keepass/database/action/node/CopyEntryRunnable.kt index c04c79a8a..07c98413b 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/action/node/CopyEntryRunnable.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/action/node/CopyEntryRunnable.kt @@ -22,19 +22,19 @@ package com.kunzisoft.keepass.database.action.node import android.support.v4.app.FragmentActivity import android.util.Log import com.kunzisoft.keepass.database.element.Database -import com.kunzisoft.keepass.database.element.PwEntryInterface -import com.kunzisoft.keepass.database.element.PwGroupInterface +import com.kunzisoft.keepass.database.element.EntryVersioned +import com.kunzisoft.keepass.database.element.GroupVersioned class CopyEntryRunnable constructor( context: FragmentActivity, database: Database, - private val mEntryToCopy: PwEntryInterface, - private val mNewParent: PwGroupInterface, + private val mEntryToCopy: EntryVersioned, + private val mNewParent: GroupVersioned, afterAddNodeRunnable: AfterActionNodeFinishRunnable?, save: Boolean) : ActionNodeDatabaseRunnable(context, database, afterAddNodeRunnable, save) { - private var mEntryCopied: PwEntryInterface? = null + private var mEntryCopied: EntryVersioned? = null override fun nodeAction() { // Update entry with new values diff --git a/app/src/main/java/com/kunzisoft/keepass/database/action/node/DeleteEntryRunnable.kt b/app/src/main/java/com/kunzisoft/keepass/database/action/node/DeleteEntryRunnable.kt index 0a8b4c2b4..93c58eafb 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/action/node/DeleteEntryRunnable.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/action/node/DeleteEntryRunnable.kt @@ -21,18 +21,18 @@ package com.kunzisoft.keepass.database.action.node import android.support.v4.app.FragmentActivity import com.kunzisoft.keepass.database.element.Database -import com.kunzisoft.keepass.database.element.PwEntryInterface -import com.kunzisoft.keepass.database.element.PwGroupInterface +import com.kunzisoft.keepass.database.element.EntryVersioned +import com.kunzisoft.keepass.database.element.GroupVersioned class DeleteEntryRunnable constructor( context: FragmentActivity, database: Database, - private val mEntryToDelete: PwEntryInterface, + private val mEntryToDelete: EntryVersioned, finishRunnable: AfterActionNodeFinishRunnable?, save: Boolean) : ActionNodeDatabaseRunnable(context, database, finishRunnable, save) { - private var mParent: PwGroupInterface? = null + private var mParent: GroupVersioned? = null private var mRecycle: Boolean = false diff --git a/app/src/main/java/com/kunzisoft/keepass/database/action/node/DeleteGroupRunnable.java b/app/src/main/java/com/kunzisoft/keepass/database/action/node/DeleteGroupRunnable.java index 251dc5245..e1b9e4aab 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/action/node/DeleteGroupRunnable.java +++ b/app/src/main/java/com/kunzisoft/keepass/database/action/node/DeleteGroupRunnable.java @@ -22,7 +22,7 @@ package com.kunzisoft.keepass.database.action.node; import android.support.v4.app.FragmentActivity; import com.kunzisoft.keepass.database.element.Database; -import com.kunzisoft.keepass.database.element.PwGroupInterface; +import com.kunzisoft.keepass.database.element.GroupVersioned; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -30,13 +30,13 @@ import org.jetbrains.annotations.Nullable; // TODO Kotlinized public class DeleteGroupRunnable extends ActionNodeDatabaseRunnable { - private PwGroupInterface mGroupToDelete; - private PwGroupInterface mParent; + private GroupVersioned mGroupToDelete; + private GroupVersioned mParent; private boolean mRecycle; public DeleteGroupRunnable(FragmentActivity context, Database database, - PwGroupInterface group, + GroupVersioned group, AfterActionNodeFinishRunnable finish, boolean save) { super(context, database, finish, save); @@ -67,7 +67,7 @@ public class DeleteGroupRunnable extends ActionNodeDatabaseRunnable { } else { // Let's not bother recovering from a failure to save a deleted tree. It is too much work. - // TODO TEST pm.undoDeleteGroup(mGroup, mParent); + // TODO TEST pm.undoDeleteGroupFrom(mGroup, mParent); } } return new ActionNodeValues(isSuccess, message, mGroupToDelete, null); diff --git a/app/src/main/java/com/kunzisoft/keepass/database/action/node/MoveEntryRunnable.kt b/app/src/main/java/com/kunzisoft/keepass/database/action/node/MoveEntryRunnable.kt index f76732a7b..64ddcad1a 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/action/node/MoveEntryRunnable.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/action/node/MoveEntryRunnable.kt @@ -22,19 +22,19 @@ package com.kunzisoft.keepass.database.action.node import android.support.v4.app.FragmentActivity import android.util.Log import com.kunzisoft.keepass.database.element.Database -import com.kunzisoft.keepass.database.element.PwEntryInterface -import com.kunzisoft.keepass.database.element.PwGroupInterface +import com.kunzisoft.keepass.database.element.EntryVersioned +import com.kunzisoft.keepass.database.element.GroupVersioned class MoveEntryRunnable constructor( context: FragmentActivity, database: Database, - private val mEntryToMove: PwEntryInterface?, - private val mNewParent: PwGroupInterface, + private val mEntryToMove: EntryVersioned?, + private val mNewParent: GroupVersioned, afterAddNodeRunnable: AfterActionNodeFinishRunnable?, save: Boolean) : ActionNodeDatabaseRunnable(context, database, afterAddNodeRunnable, save) { - private var mOldParent: PwGroupInterface? = null + private var mOldParent: GroupVersioned? = null override fun nodeAction() { // Move entry in new parent diff --git a/app/src/main/java/com/kunzisoft/keepass/database/action/node/MoveGroupRunnable.kt b/app/src/main/java/com/kunzisoft/keepass/database/action/node/MoveGroupRunnable.kt index f5f0aa5b7..ac1cf96b2 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/action/node/MoveGroupRunnable.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/action/node/MoveGroupRunnable.kt @@ -23,18 +23,18 @@ import android.support.v4.app.FragmentActivity import android.util.Log import com.kunzisoft.keepass.R import com.kunzisoft.keepass.database.element.Database -import com.kunzisoft.keepass.database.element.PwGroupInterface +import com.kunzisoft.keepass.database.element.GroupVersioned class MoveGroupRunnable constructor( context: FragmentActivity, database: Database, - private val mGroupToMove: PwGroupInterface?, - private val mNewParent: PwGroupInterface, + private val mGroupToMove: GroupVersioned?, + private val mNewParent: GroupVersioned, afterAddNodeRunnable: AfterActionNodeFinishRunnable?, save: Boolean) : ActionNodeDatabaseRunnable(context, database, afterAddNodeRunnable, save) { - private var mOldParent: PwGroupInterface? = null + private var mOldParent: GroupVersioned? = null override fun nodeAction() { mGroupToMove?.let { diff --git a/app/src/main/java/com/kunzisoft/keepass/database/action/node/UpdateEntryRunnable.kt b/app/src/main/java/com/kunzisoft/keepass/database/action/node/UpdateEntryRunnable.kt index 399e185d8..944b1bbff 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/action/node/UpdateEntryRunnable.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/action/node/UpdateEntryRunnable.kt @@ -21,30 +21,30 @@ package com.kunzisoft.keepass.database.action.node import android.support.v4.app.FragmentActivity import com.kunzisoft.keepass.database.element.Database -import com.kunzisoft.keepass.database.element.PwEntryInterface +import com.kunzisoft.keepass.database.element.EntryVersioned class UpdateEntryRunnable constructor( context: FragmentActivity, database: Database, - private val mOldEntry: PwEntryInterface, - private val mNewEntry: PwEntryInterface, + private val mOldEntry: EntryVersioned, + private val mNewEntry: EntryVersioned, finishRunnable: AfterActionNodeFinishRunnable?, save: Boolean) : ActionNodeDatabaseRunnable(context, database, finishRunnable, save) { // Keep backup of original values in case save fails - private val mBackupEntry: PwEntryInterface = mOldEntry.duplicate() + private val mBackupEntry: EntryVersioned = EntryVersioned(mOldEntry) override fun nodeAction() { // Update entry with new values mOldEntry.touch(true, true) - database.updateEntry(mOldEntry, mNewEntry) + mOldEntry.updateWith(mNewEntry) } override fun nodeFinish(isSuccess: Boolean, message: String?): ActionNodeValues { if (!isSuccess) { // If we fail to save, back out changes to global structure - database.updateEntry(mOldEntry, mBackupEntry) + mOldEntry.updateWith(mBackupEntry) } return ActionNodeValues(isSuccess, message, mOldEntry, mNewEntry) } diff --git a/app/src/main/java/com/kunzisoft/keepass/database/action/node/UpdateGroupRunnable.kt b/app/src/main/java/com/kunzisoft/keepass/database/action/node/UpdateGroupRunnable.kt index 4d97a6846..9059b1df4 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/action/node/UpdateGroupRunnable.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/action/node/UpdateGroupRunnable.kt @@ -21,30 +21,30 @@ package com.kunzisoft.keepass.database.action.node import android.support.v4.app.FragmentActivity import com.kunzisoft.keepass.database.element.Database -import com.kunzisoft.keepass.database.element.PwGroupInterface +import com.kunzisoft.keepass.database.element.GroupVersioned class UpdateGroupRunnable constructor( context: FragmentActivity, database: Database, - private val mOldGroup: PwGroupInterface, - private val mNewGroup: PwGroupInterface, + private val mOldGroup: GroupVersioned, + private val mNewGroup: GroupVersioned, finishRunnable: AfterActionNodeFinishRunnable?, save: Boolean) : ActionNodeDatabaseRunnable(context, database, finishRunnable, save) { // Keep backup of original values in case save fails - private val mBackupGroup: PwGroupInterface = mOldGroup.duplicate() + private val mBackupGroup: GroupVersioned = GroupVersioned(mOldGroup) override fun nodeAction() { // Update group with new values mOldGroup.touch(true, true) - database.updateGroup(mOldGroup, mNewGroup) + mOldGroup.updateWith(mNewGroup) } override fun nodeFinish(isSuccess: Boolean, message: String?): ActionNodeValues { if (!isSuccess) { // If we fail to save, back out changes to global structure - database.updateGroup(mOldGroup, mBackupGroup) + mOldGroup.updateWith(mBackupGroup) } return ActionNodeValues(isSuccess, message, mOldGroup, mNewGroup) } diff --git a/app/src/main/java/com/kunzisoft/keepass/database/cursor/EntryCursor.java b/app/src/main/java/com/kunzisoft/keepass/database/cursor/EntryCursor.java index ce613685a..ddc70d1d4 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/cursor/EntryCursor.java +++ b/app/src/main/java/com/kunzisoft/keepass/database/cursor/EntryCursor.java @@ -3,14 +3,11 @@ package com.kunzisoft.keepass.database.cursor; import android.database.MatrixCursor; import android.provider.BaseColumns; -import com.kunzisoft.keepass.database.element.PwEntryInterface; -import com.kunzisoft.keepass.database.element.PwIconFactory; -import com.kunzisoft.keepass.database.element.PwIconStandard; -import com.kunzisoft.keepass.database.element.PwNodeIdUUID; +import com.kunzisoft.keepass.database.element.*; import java.util.UUID; -public abstract class EntryCursor extends MatrixCursor { +public abstract class EntryCursor extends MatrixCursor { protected long entryId; public static final String _ID = BaseColumns._ID; diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/Database.java b/app/src/main/java/com/kunzisoft/keepass/database/element/Database.java index 085463a81..0511866b8 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/element/Database.java +++ b/app/src/main/java/com/kunzisoft/keepass/database/element/Database.java @@ -27,8 +27,7 @@ import android.util.Log; import android.webkit.URLUtil; import com.kunzisoft.keepass.crypto.keyDerivation.KdfEngine; import com.kunzisoft.keepass.crypto.keyDerivation.KdfFactory; -import com.kunzisoft.keepass.database.EntryHandler; -import com.kunzisoft.keepass.database.GroupHandler; +import com.kunzisoft.keepass.database.NodeHandler; import com.kunzisoft.keepass.database.cursor.EntryCursorV3; import com.kunzisoft.keepass.database.cursor.EntryCursorV4; import com.kunzisoft.keepass.database.exception.*; @@ -55,7 +54,8 @@ public class Database { private PwDatabase pwDatabase = null; private PwVersion version = null; - // To keep a reference for specific methods provided by V4 + // To keep a reference for specific methods provided by version + private PwDatabaseV3 pwDatabaseV3 = null; private PwDatabaseV4 pwDatabaseV4 = null; private Uri mUri = null; @@ -84,12 +84,14 @@ public class Database { } private void setDatabaseV3(PwDatabaseV3 pwDatabaseV3) { + this.pwDatabaseV3 = pwDatabaseV3; this.pwDatabaseV4 = null; this.pwDatabase = pwDatabaseV3; this.version = pwDatabase.getVersion(); } private void setDatabaseV4(PwDatabaseV4 pwDatabaseV4) { + this.pwDatabaseV3 = null; this.pwDatabaseV4 = pwDatabaseV4; this.pwDatabase = pwDatabaseV4; this.version = pwDatabase.getVersion(); @@ -179,9 +181,9 @@ public class Database { int sig1 = LEDataInputStream.readInt(bufferedInputStream); int sig2 = LEDataInputStream.readInt(bufferedInputStream); + bufferedInputStream.reset(); // Return to the start // Header of database V3 if ( PwDbHeaderV3.matchesHeader(sig1, sig2) ) { - bufferedInputStream.reset(); // Return to the start setDatabaseV3(new ImporterV3().openDatabase(bufferedInputStream, password, keyFileInputStream, @@ -190,7 +192,6 @@ public class Database { // Header of database V4 else if ( PwDbHeaderV4.matchesHeader(sig1, sig2) ) { - bufferedInputStream.reset(); // Return to the start setDatabaseV4(new ImporterV4(ctx.getFilesDir()).openDatabase(bufferedInputStream, password, keyFileInputStream, @@ -214,14 +215,24 @@ public class Database { } } - public PwGroupInterface search(String str) { + public Boolean isGroupSearchable(GroupVersioned group, Boolean isOmitBackup) { + switch (version) { + case V3: + return pwDatabaseV3.isGroupSearchable(group.getPwGroupV3(), isOmitBackup); + case V4: + return pwDatabaseV4.isGroupSearchable(group.getPwGroupV4(), isOmitBackup); + } + return false; + } + + public GroupVersioned search(String str) { return search(str, Integer.MAX_VALUE); } - public PwGroupInterface search(String str, int max) { + public GroupVersioned search(String str, int max) { if (searchHelper == null) return null; - return searchHelper.search(pwDatabase, str, max); + return searchHelper.search(this, str, max); } public Cursor searchEntry(String query) { @@ -229,11 +240,11 @@ public class Database { case V3: EntryCursorV3 cursorV3 = new EntryCursorV3(); if (!query.isEmpty()) { - PwGroupInterface searchResult = search(query, 6); + GroupVersioned searchResult = search(query, 6); if (searchResult != null) { - for (PwEntryInterface entry: searchResult.getChildEntries()) { + for (EntryVersioned entry: searchResult.getChildEntries()) { if (!entry.isMetaStream()) { // TODO metastream - cursorV3.addEntry((PwEntryV3) entry); + cursorV3.addEntry(entry.getPwEntryV3()); } } } @@ -242,11 +253,11 @@ public class Database { case V4: EntryCursorV4 cursorv4 = new EntryCursorV4(); if (!query.isEmpty()) { - PwGroupInterface searchResult = search(query, 6); + GroupVersioned searchResult = search(query, 6); if (searchResult != null) { - for (PwEntryInterface entry: searchResult.getChildEntries()) { + for (EntryVersioned entry: searchResult.getChildEntries()) { if (!entry.isMetaStream()) { // TODO metastream - cursorv4.addEntry((PwEntryV4) entry); + cursorv4.addEntry(entry.getPwEntryV4()); } } } @@ -256,25 +267,25 @@ public class Database { return null; } - public PwEntryInterface getEntryFrom(Cursor cursor) { + public EntryVersioned getEntryFrom(Cursor cursor) { PwIconFactory iconFactory = pwDatabase.getIconFactory(); - PwEntryInterface pwEntry = createEntry(); + EntryVersioned entry = createEntry(); try { switch (version) { case V3: - ((EntryCursorV3) cursor).populateEntry((PwEntryV3) pwEntry, iconFactory); + ((EntryCursorV3) cursor).populateEntry(entry.getPwEntryV3(), iconFactory); break; case V4: // TODO invert field reference manager - startManageEntry(pwEntry); - ((EntryCursorV4) cursor).populateEntry((PwEntryV4) pwEntry, iconFactory); - stopManageEntry(pwEntry); + startManageEntry(entry); + ((EntryCursorV4) cursor).populateEntry(entry.getPwEntryV4(), iconFactory); + stopManageEntry(entry); break; } } catch (Exception e) { Log.e(TAG, "This version of PwGroup can't be populated", e); } - return pwEntry; + return entry; } public void saveData(Context ctx) throws IOException, PwDbOutputException { @@ -567,107 +578,113 @@ public class Database { pwDatabase.retrieveMasterKey(key, keyInputStream); } - public PwGroupInterface getRootGroup() { - return pwDatabase.getRootGroup(); + public GroupVersioned getRootGroup() { + switch (version) { + case V3: + return new GroupVersioned(pwDatabaseV3.getRootGroup()); + case V4: + return new GroupVersioned(pwDatabaseV4.getRootGroup()); + } + return null; } - public PwEntryInterface createEntry() { + public EntryVersioned createEntry() { + EntryVersioned newEntry = null; try { switch (version) { case V3: - return new PwEntryV3(); + newEntry = new EntryVersioned(new PwEntryV3()); + newEntry.setNodeId(pwDatabaseV3.newEntryId()); + case V4: - return new PwEntryV4(); + newEntry = new EntryVersioned(new PwEntryV4()); + newEntry.setNodeId(pwDatabaseV4.newEntryId()); } } catch (Exception e) { Log.e(TAG, "This version of PwEntry can't be created", e); } - return null; + return newEntry; } - public PwGroupInterface createGroup() { - PwGroupInterface newPwGroup = null; + public GroupVersioned createGroup() { + GroupVersioned newPwGroup = null; try { switch (version) { case V3: - newPwGroup = new PwGroupV3(); + newPwGroup = new GroupVersioned(new PwGroupV3()); + newPwGroup.setNodeId(pwDatabaseV3.newGroupId()); + case V4: - newPwGroup = new PwGroupV4(); + newPwGroup = new GroupVersioned(new PwGroupV4()); + newPwGroup.setNodeId(pwDatabaseV4.newGroupId()); } - newPwGroup.setNodeId(pwDatabase.newGroupId()); } catch (Exception e) { Log.e(TAG, "This version of PwGroup can't be created", e); } return newPwGroup; } - public PwEntryInterface getEntryById(PwNodeId id) { - return pwDatabase.getEntryById(id); + public EntryVersioned getEntryById(PwNodeId id) { + PwEntryV3 entryV3 = pwDatabaseV3.getEntryById(id); + if (entryV3 != null) + return new EntryVersioned(entryV3); + + PwEntryV4 entryV4 = pwDatabaseV4.getEntryById(id); + if (entryV4 != null) + return new EntryVersioned(entryV4); + + return null; } - public PwGroupInterface getGroupById(PwNodeId id) { - return pwDatabase.getGroupById(id); + public GroupVersioned getGroupById(PwNodeId id) { + if (pwDatabaseV3 != null) { + PwGroupV3 groupV3 = pwDatabaseV3.getGroupById(id); + if (groupV3 != null) + return new GroupVersioned(groupV3); + } + + if (pwDatabaseV4 != null) { + PwGroupV4 groupV4 = pwDatabaseV4.getGroupById(id); + if (groupV4 != null) + return new GroupVersioned(groupV4); + } + + return null; } - public void addEntryTo(PwEntryInterface entry, PwGroupInterface parent) { - try { - pwDatabase.addEntryTo(entry, parent); - } catch (Exception e) { - Log.e(TAG, "This version of PwEntry can't be added from this version of PwGroup", e); + public void addEntryTo(EntryVersioned entry, GroupVersioned parent) { + switch (version) { + case V3: + pwDatabaseV3.addEntryTo(entry.getPwEntryV3(), parent.getPwGroupV3()); + case V4: + pwDatabaseV4.addEntryTo(entry.getPwEntryV4(), parent.getPwGroupV4()); } } - public void removeEntryFrom(PwEntryInterface entry, PwGroupInterface parent) { - try { - pwDatabase.removeEntryFrom(entry, parent); - } catch (Exception e) { - Log.e(TAG, "This version of PwEntry can't be removed from this version of PwGroup", e); + public void removeEntryFrom(EntryVersioned entry, GroupVersioned parent) { + switch (version) { + case V3: + pwDatabaseV3.removeEntryFrom(entry.getPwEntryV3(), parent.getPwGroupV3()); + case V4: + pwDatabaseV4.removeEntryFrom(entry.getPwEntryV4(), parent.getPwGroupV4()); } } - public void addGroupTo(PwGroupInterface group, PwGroupInterface parent) { - try { - pwDatabase.addGroupTo(group, parent); - } catch (Exception e) { - Log.e(TAG, "This version of PwGroup can't be added in this version of PwGroup", e); + public void addGroupTo(GroupVersioned group, GroupVersioned parent) { + switch (version) { + case V3: + pwDatabaseV3.addGroupTo(group.getPwGroupV3(), parent.getPwGroupV3()); + case V4: + pwDatabaseV4.addGroupTo(group.getPwGroupV4(), parent.getPwGroupV4()); } } - public void removeGroupFrom(PwGroupInterface group, PwGroupInterface parent) { - try { - pwDatabase.removeGroupFrom(group, parent); - } catch (Exception e) { - Log.e(TAG, "This version of PwGroup can't be removed from this version of PwGroup", e); - } - } - - public void updateEntry(PwEntryInterface oldEntry, PwEntryInterface newEntry) { - try { - switch (version) { - case V3: - ((PwEntryV3) oldEntry).updateWith((PwEntryV3) newEntry); - break; - case V4: - ((PwEntryV4) oldEntry).updateWith((PwEntryV4) newEntry); - break; - } - } catch (Exception e) { - Log.e(TAG, "This version of PwEntry can't be updated", e); - } - } - - public void updateGroup(PwGroupInterface oldGroup, PwGroupInterface newGroup) { - try { - switch (version) { - case V3: - ((PwGroupV3) oldGroup).updateWith((PwGroupV3) newGroup); - break; - case V4: - ((PwGroupV4) oldGroup).updateWith((PwGroupV4) newGroup); - break; - } - } catch (Exception e) { - Log.e(TAG, "This version of PwEntry can't be updated", e); + public void removeGroupFrom(GroupVersioned group, GroupVersioned parent) { + switch (version) { + case V3: + pwDatabaseV3.removeGroupFrom(group.getPwGroupV3(), parent.getPwGroupV3()); + case V4: + pwDatabaseV4.removeGroupFrom(group.getPwGroupV4(), parent.getPwGroupV4()); } } @@ -676,15 +693,15 @@ public class Database { * @param entryToCopy * @param newParent */ - public @Nullable PwEntryInterface copyEntry(PwEntryInterface entryToCopy, PwGroupInterface newParent) { + public @Nullable EntryVersioned copyEntry(EntryVersioned entryToCopy, GroupVersioned newParent) { try { - PwEntryInterface entryCopied = null; + EntryVersioned entryCopied = null; switch (version) { case V3: - entryCopied = entryToCopy.duplicate(); + entryCopied = new EntryVersioned(entryToCopy); break; case V4: - entryCopied = entryToCopy.duplicate(); + entryCopied = new EntryVersioned(entryToCopy); break; } entryCopied.setNodeId(new PwNodeIdUUID()); @@ -697,45 +714,55 @@ public class Database { return null; } - public void moveEntry(PwEntryInterface entryToMove, PwGroupInterface newParent) { + public void moveEntry(EntryVersioned entryToMove, GroupVersioned newParent) { removeEntryFrom(entryToMove, entryToMove.getParent()); addEntryTo(entryToMove, newParent); } - public void moveGroup(PwGroupInterface groupToMove, PwGroupInterface newParent) { + public void moveGroup(GroupVersioned groupToMove, GroupVersioned newParent) { removeGroupFrom(groupToMove, groupToMove.getParent()); addGroupTo(groupToMove, newParent); } - public void deleteEntry(PwEntryInterface entry) { + public void deleteEntry(EntryVersioned entry) { removeEntryFrom(entry, entry.getParent()); } - public void deleteGroup(PwGroupInterface group) { - PwGroupInterface.doForEachChildAndForRoot(group, - new EntryHandler() { + public void deleteGroup(GroupVersioned group) { + group.doForEachChildAndForIt( + new NodeHandler() { @Override - public boolean operate(PwEntryInterface entry) { + public boolean operate(EntryVersioned entry) { deleteEntry(entry); return true; } }, - new GroupHandler() { + new NodeHandler() { @Override - public boolean operate(PwGroupInterface group) { - PwGroupInterface parent = group.getParent(); + public boolean operate(GroupVersioned group) { + GroupVersioned parent = group.getParent(); removeGroupFrom(group, parent); return true; } }); } - public void undoDeleteEntry(PwEntryInterface entry, PwGroupInterface parent) { - pwDatabase.undoDeleteEntryFrom(entry, parent); + public void undoDeleteEntry(EntryVersioned entry, GroupVersioned parent) { + switch (version) { + case V3: + pwDatabaseV3.undoDeleteEntryFrom(entry.getPwEntryV3(), parent.getPwGroupV3()); + case V4: + pwDatabaseV4.undoDeleteEntryFrom(entry.getPwEntryV4(), parent.getPwGroupV4()); + } } - public void undoDeleteGroup(PwGroupInterface group, PwGroupInterface parent) { - pwDatabase.undoDeleteGroup(group, parent); + public void undoDeleteGroup(GroupVersioned group, GroupVersioned parent) { + switch (version) { + case V3: + pwDatabaseV3.undoDeleteGroupFrom(group.getPwGroupV3(), parent.getPwGroupV3()); + case V4: + pwDatabaseV4.undoDeleteGroupFrom(group.getPwGroupV4(), parent.getPwGroupV4()); + } } /** @@ -743,122 +770,76 @@ public class Database { * @return true if RecycleBin available */ public boolean isRecycleBinAvailable() { - if (pwDatabaseV4 != null) { - switch (version) { - case V4: - return true; - } - } - return false; + return pwDatabaseV4 != null; } public boolean isRecycleBinEnabled() { if (pwDatabaseV4 != null) { - switch (version) { - case V4: - return pwDatabaseV4.isRecycleBinEnabled(); - } + return pwDatabaseV4.isRecycleBinEnabled(); } return false; } - public PwGroupInterface getRecycleBin() { + public GroupVersioned getRecycleBin() { if (pwDatabaseV4 != null) { - switch (version) { - case V4: - return pwDatabaseV4.getRecycleBin(); - } + return new GroupVersioned(pwDatabaseV4.getRecycleBin()); } return null; } - public boolean canRecycle(PwEntryInterface entry) { + public boolean canRecycle(EntryVersioned entry) { if (pwDatabaseV4 != null) { - switch (version) { - case V4: - return pwDatabaseV4.canRecycle(entry); - } + return pwDatabaseV4.canRecycle(entry.getPwEntryV4()); } return false; } - public boolean canRecycle(PwGroupInterface group) { + public boolean canRecycle(GroupVersioned group) { if (pwDatabaseV4 != null) { - switch (version) { - case V4: - return pwDatabaseV4.canRecycle(group); - } + return pwDatabaseV4.canRecycle(group.getPwGroupV4()); } return false; } - public void recycle(PwEntryInterface entry) { + public void recycle(EntryVersioned entry) { if (pwDatabaseV4 != null) { - switch (version) { - case V4: - pwDatabaseV4.recycle(entry); - break; - } + pwDatabaseV4.recycle(entry.getPwEntryV4()); } } - public void recycle(PwGroupInterface group) { + public void recycle(GroupVersioned group) { if (pwDatabaseV4 != null) { - switch (version) { - case V4: - pwDatabaseV4.recycle(group); - break; - } + pwDatabaseV4.recycle(group.getPwGroupV4()); } } - public void undoRecycle(PwEntryInterface entry, PwGroupInterface parent) { + public void undoRecycle(EntryVersioned entry, GroupVersioned parent) { if (pwDatabaseV4 != null) { - switch (version) { - case V4: - pwDatabaseV4.undoRecycle(entry, parent); - break; - } + pwDatabaseV4.undoRecycle(entry.getPwEntryV4(), parent.getPwGroupV4()); } } - public void undoRecycle(PwGroupInterface group, PwGroupInterface parent) { + public void undoRecycle(GroupVersioned group, GroupVersioned parent) { if (pwDatabaseV4 != null) { - switch (version) { - case V4: - pwDatabaseV4.undoRecycle(group, parent); - break; - } + pwDatabaseV4.undoRecycle(group.getPwGroupV4(), parent.getPwGroupV4()); } } - public void startManageEntry(PwEntryInterface entry) { + public void startManageEntry(EntryVersioned entry) { if (pwDatabaseV4 != null) { - switch (version) { - case V4: - ((PwEntryV4) entry).startToManageFieldReferences(pwDatabaseV4); - break; - } + entry.startToManageFieldReferences(pwDatabaseV4); } } - public void stopManageEntry(PwEntryInterface entry) { + public void stopManageEntry(EntryVersioned entry) { if (pwDatabaseV4 != null) { - switch (version) { - case V4: - ((PwEntryV4) entry).stopToManageFieldReferences(); - break; - } + entry.stopToManageFieldReferences(); } } - public void createBackupOf(PwEntryInterface entry) { + public void createBackupOf(EntryVersioned entry) { if (pwDatabaseV4 != null) { - switch (version) { - case V4: - ((PwEntryV4) entry).createBackup(pwDatabaseV4); - break; - } + entry.createBackup(pwDatabaseV4); } } } diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/EntryVersioned.kt b/app/src/main/java/com/kunzisoft/keepass/database/element/EntryVersioned.kt new file mode 100644 index 000000000..eb7fc77c9 --- /dev/null +++ b/app/src/main/java/com/kunzisoft/keepass/database/element/EntryVersioned.kt @@ -0,0 +1,341 @@ +package com.kunzisoft.keepass.database.element + +import android.os.Parcel +import android.os.Parcelable +import com.kunzisoft.keepass.database.ExtraFields +import com.kunzisoft.keepass.database.security.ProtectedString +import java.util.* + +class EntryVersioned : NodeVersioned, PwEntryInterface { + + var pwEntryV3: PwEntryV3? = null + private set + var pwEntryV4: PwEntryV4? = null + private set + + fun updateWith(entry: EntryVersioned) { + this.pwEntryV3?.updateWith(entry.pwEntryV3) + this.pwEntryV4?.updateWith(entry.pwEntryV4) + } + + constructor() + + /** + * Use this constructor to copy an Entry + */ + constructor(entry: EntryVersioned) { + if (entry.pwEntryV3 != null) { + if (this.pwEntryV3 != null) + this.pwEntryV3 = PwEntryV3() + } + if (entry.pwEntryV4 != null) { + if (this.pwEntryV4 != null) + this.pwEntryV4 = PwEntryV4() + } + updateWith(entry) + } + + constructor(entry: PwEntryV3) { + this.pwEntryV4 = null + if (this.pwEntryV3 != null) + this.pwEntryV3 = PwEntryV3() + this.pwEntryV3?.updateWith(entry) + } + + constructor(entry: PwEntryV4) { + this.pwEntryV3 = null + if (this.pwEntryV4 != null) + this.pwEntryV4 = PwEntryV4() + this.pwEntryV4?.updateWith(entry) + } + + constructor(parcel: Parcel) { + pwEntryV3 = parcel.readParcelable(PwEntryV3::class.java.classLoader) + pwEntryV4 = parcel.readParcelable(PwEntryV4::class.java.classLoader) + } + + override fun describeContents(): Int { + return 0 + } + + override fun writeToParcel(dest: Parcel, flags: Int) { + dest.writeParcelable(pwEntryV3, flags) + dest.writeParcelable(pwEntryV4, flags) + } + + var nodeId: PwNodeId? + get() = pwEntryV4?.nodeId ?: pwEntryV3?.nodeId + set(value) { + pwEntryV3?.nodeId = value + pwEntryV4?.nodeId = value + } + + override var title: String + get() = pwEntryV3?.title ?: pwEntryV4?.title ?: "" + set(value) { + pwEntryV3?.title = value + pwEntryV4?.title = value + } + + override var icon: PwIcon + get() = pwEntryV3?.icon ?: pwEntryV4?.icon ?: PwIconStandard() + set(value) { + pwEntryV3?.icon = value + pwEntryV4?.icon = value + } + + override val type: Type + get() = Type.ENTRY + + override var parent: GroupVersioned? + get() { + pwEntryV3?.parent?.let { + return GroupVersioned(it) + } + pwEntryV4?.parent?.let { + return GroupVersioned(it) + } + return null + } + set(value) { + pwEntryV3?.parent = value?.pwGroupV3 + pwEntryV4?.parent = value?.pwGroupV4 + } + + override fun containsParent(): Boolean { + return pwEntryV3?.containsParent() ?: pwEntryV4?.containsParent() ?: false + } + + override fun touch(modified: Boolean, touchParents: Boolean) { + pwEntryV3?.touch(modified, touchParents) + pwEntryV4?.touch(modified, touchParents) + } + + override fun isContainedIn(container: GroupVersioned): Boolean { + return pwEntryV3?.isContainedIn(container.pwGroupV3) ?: pwEntryV4?.isContainedIn(container.pwGroupV4) ?: false + } + + override val isSearchingEnabled: Boolean + get() = pwEntryV3?.isSearchingEnabled ?: pwEntryV4?.isSearchingEnabled ?: false + + override fun getLastModificationTime(): PwDate? { + return pwEntryV3?.lastModificationTime ?: pwEntryV4?.lastModificationTime + } + + override fun setLastModificationTime(date: PwDate) { + pwEntryV3?.lastModificationTime = date + pwEntryV4?.lastModificationTime = date + } + + override fun getCreationTime(): PwDate? { + return pwEntryV3?.creationTime ?: pwEntryV4?.creationTime + } + + override fun setCreationTime(date: PwDate) { + pwEntryV3?.creationTime = date + pwEntryV4?.creationTime = date + } + + override fun getLastAccessTime(): PwDate? { + return pwEntryV3?.lastAccessTime ?: pwEntryV4?.lastAccessTime + } + + override fun setLastAccessTime(date: PwDate) { + pwEntryV3?.lastAccessTime = date + pwEntryV4?.lastAccessTime = date + } + + override fun getExpiryTime(): PwDate? { + return pwEntryV3?.expiryTime ?: pwEntryV4?.expiryTime + } + + override fun setExpiryTime(date: PwDate) { + pwEntryV3?.expiryTime = date + pwEntryV4?.expiryTime = date + } + + override fun isExpires(): Boolean { + return pwEntryV3?.isExpires ?: pwEntryV4?.isExpires ?: false + } + + override fun setExpires(exp: Boolean) { + pwEntryV3?.isExpires = exp + pwEntryV4?.isExpires = exp + } + + override var username: String + get() = pwEntryV3?.username ?: pwEntryV4?.username ?: "" + set(value) { + pwEntryV3?.username = value + pwEntryV4?.username = value + } + + override var password: String + get() = pwEntryV3?.password ?: pwEntryV4?.password ?: "" + set(value) { + pwEntryV3?.password = value + pwEntryV4?.password = value + } + + override var url: String + get() = pwEntryV3?.url ?: pwEntryV4?.url ?: "" + set(value) { + pwEntryV3?.url = value + pwEntryV4?.url = value + } + + override var notes: String + get() = pwEntryV3?.notes ?: pwEntryV4?.notes ?: "" + set(value) { + pwEntryV3?.notes = value + pwEntryV4?.notes = value + } + + override fun touchLocation() { + pwEntryV3?.touchLocation() + pwEntryV4?.touchLocation() + } + + fun isTan(): Boolean { + return title == PMS_TAN_ENTRY && username.isNotEmpty() + } + + fun getVisualTitle(): String { + return getVisualTitle(isTan(), + title, + username, + url, + nodeId.toString()) + } + + /* + ------------ + V3 Methods + ------------ + */ + + /** + * If it's a node with only meta information like Meta-info SYSTEM Database Color + * @return false by default, true if it's a meta stream + */ + val isMetaStream: Boolean + get() = pwEntryV3?.isMetaStream ?: false + + /* + ------------ + V4 Methods + ------------ + */ + + /** + * Retrieve extra fields to show, key is the label, value is the value of field + * @return Map of label/value + */ + val fields: ExtraFields + get() = pwEntryV4?.fields ?: ExtraFields() + + /** + * To redefine if version of entry allow extra field, + * @return true if entry allows extra field + */ + fun allowExtraFields(): Boolean { + return pwEntryV4?.allowExtraFields() ?: false + } + + /** + * If entry contains extra fields + * @return true if there is extra fields + */ + fun containsCustomFields(): Boolean { + return pwEntryV4?.containsCustomFields() ?: false + } + + /** + * If entry contains extra fields that are protected + * @return true if there is extra fields protected + */ + fun containsCustomFieldsProtected(): Boolean { + return pwEntryV4?.containsCustomFieldsProtected() ?: false + } + + /** + * If entry contains extra fields that are not protected + * @return true if there is extra fields not protected + */ + fun containsCustomFieldsNotProtected(): Boolean { + return pwEntryV4?.containsCustomFieldsNotProtected() ?: false + } + + /** + * Add an extra field to the list (standard or custom) + * @param label Label of field, must be unique + * @param value Value of field + */ + fun addExtraField(label: String, value: ProtectedString) { + pwEntryV4?.addExtraField(label, value) + } + + /** + * Delete all custom fields + */ + fun removeAllCustomFields() { + pwEntryV4?.removeAllCustomFields() + } + + fun startToManageFieldReferences(db: PwDatabaseV4) { + pwEntryV4?.startToManageFieldReferences(db) + } + + fun stopToManageFieldReferences() { + pwEntryV4?.stopToManageFieldReferences() + } + + fun createBackup(db: PwDatabaseV4?) { + pwEntryV4?.createBackup(db) + } + + fun containsCustomData(): Boolean { + return pwEntryV4?.containsCustomData() ?: false + } + + /* + ------------ + Class methods + ------------ + */ + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): EntryVersioned { + return EntryVersioned(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + + val PMS_TAN_ENTRY = "" + + /** + * {@inheritDoc} + * Get the display title from an entry,

+ * [.startManageEntry] and [.stopManageEntry] must be called + * before and after [.getVisualTitle] + */ + fun getVisualTitle(isTan: Boolean, title: String, userName: String, url: String, id: String): String { + return if (isTan) { + "$PMS_TAN_ENTRY $userName" + } else { + if (title.isEmpty()) + if (userName.isEmpty()) + if (url.isEmpty()) + id + else + url + else + userName + else + title + } + } + } +} diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/GroupVersioned.kt b/app/src/main/java/com/kunzisoft/keepass/database/element/GroupVersioned.kt new file mode 100644 index 000000000..a4e7a3194 --- /dev/null +++ b/app/src/main/java/com/kunzisoft/keepass/database/element/GroupVersioned.kt @@ -0,0 +1,299 @@ +package com.kunzisoft.keepass.database.element + +import android.os.Parcel +import android.os.Parcelable +import java.util.* +import kotlin.collections.ArrayList + +class GroupVersioned : NodeVersioned, PwGroupInterface { + + var pwGroupV3: PwGroupV3? = null + private set + var pwGroupV4: PwGroupV4? = null + private set + + fun updateWith(group: GroupVersioned) { + this.pwGroupV3?.updateWith(group.pwGroupV3) + this.pwGroupV4?.updateWith(group.pwGroupV4) + } + + /** + * Use this constructor to copy a Group + */ + constructor(group: GroupVersioned) { + if (group.pwGroupV3 != null) { + if (this.pwGroupV3 == null) + this.pwGroupV3 = PwGroupV3() + } + if (group.pwGroupV4 == null) { + if (this.pwGroupV4 != null) + this.pwGroupV4 = PwGroupV4() + } + updateWith(group) + } + + constructor(group: PwGroupV3) { + this.pwGroupV4 = null + if (this.pwGroupV3 == null) + this.pwGroupV3 = PwGroupV3() + this.pwGroupV3?.updateWith(group) + } + + constructor(group: PwGroupV4) { + this.pwGroupV3 = null + if (this.pwGroupV4 == null) + this.pwGroupV4 = PwGroupV4() + this.pwGroupV4?.updateWith(group) + } + + constructor(parcel: Parcel) { + pwGroupV3 = parcel.readParcelable(PwGroupV3::class.java.classLoader) + pwGroupV4 = parcel.readParcelable(PwGroupV4::class.java.classLoader) + } + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): GroupVersioned { + return GroupVersioned(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } + + override fun describeContents(): Int { + return 0 + } + + override fun writeToParcel(dest: Parcel, flags: Int) { + dest.writeParcelable(pwGroupV3, flags) + dest.writeParcelable(pwGroupV4, flags) + } + + val nodeId: PwNodeId<*>? + get() = pwGroupV4?.nodeId ?: pwGroupV3?.nodeId + + override var title: String + get() = pwGroupV3?.title ?: pwGroupV4?.title ?: "" + set(value) { + pwGroupV3?.title = value + pwGroupV4?.title = value + } + + override var icon: PwIcon + get() = pwGroupV3?.icon ?: pwGroupV4?.icon ?: PwIconStandard() + set(value) { + pwGroupV3?.icon = value + pwGroupV4?.icon = value + } + + override val type: Type + get() = Type.GROUP + + override var parent: GroupVersioned? + get() { + pwGroupV3?.parent?.let { + return GroupVersioned(it) + } + pwGroupV4?.parent?.let { + return GroupVersioned(it) + } + return null + } + set(value) { + pwGroupV3?.parent = value?.pwGroupV3 + pwGroupV4?.parent = value?.pwGroupV4 + } + + override fun containsParent(): Boolean { + return pwGroupV3?.containsParent() ?: pwGroupV4?.containsParent() ?: false + } + + override fun touch(modified: Boolean, touchParents: Boolean) { + pwGroupV3?.touch(modified, touchParents) + pwGroupV4?.touch(modified, touchParents) + } + + override fun isContainedIn(container: GroupVersioned): Boolean { + return pwGroupV3?.isContainedIn(container.pwGroupV3) ?: pwGroupV4?.isContainedIn(container.pwGroupV4) ?: false + } + + override val isSearchingEnabled: Boolean? + get() = pwGroupV3?.isSearchingEnabled ?: pwGroupV4?.isSearchingEnabled ?: false + + override fun getLastModificationTime(): PwDate? { + return pwGroupV3?.lastModificationTime ?: pwGroupV4?.lastModificationTime + } + + override fun setLastModificationTime(date: PwDate) { + pwGroupV3?.lastModificationTime = date + pwGroupV4?.lastModificationTime = date + } + + override fun getCreationTime(): PwDate? { + return pwGroupV3?.creationTime ?: pwGroupV4?.creationTime + } + + override fun setCreationTime(date: PwDate) { + pwGroupV3?.creationTime = date + pwGroupV4?.creationTime = date + } + + override fun getLastAccessTime(): PwDate? { + return pwGroupV3?.lastAccessTime ?: pwGroupV4?.lastAccessTime + } + + override fun setLastAccessTime(date: PwDate) { + pwGroupV3?.lastAccessTime = date + pwGroupV4?.lastAccessTime = date + } + + override fun getExpiryTime(): PwDate? { + return pwGroupV3?.expiryTime ?: pwGroupV4?.expiryTime + } + + override fun setExpiryTime(date: PwDate) { + pwGroupV3?.expiryTime = date + pwGroupV4?.expiryTime = date + } + + override fun isExpires(): Boolean { + return pwGroupV3?.isExpires ?: pwGroupV4?.isExpires ?: false + } + + override fun setExpires(exp: Boolean) { + pwGroupV3?.isExpires = exp + pwGroupV4?.isExpires = exp + } + + override fun getChildGroups(): MutableList { + return ArrayList() // TODO if needed + } + + override fun getChildEntries(): MutableList { + val children = ArrayList() + + pwGroupV3?.getChildEntries()?.forEach { + children.add(EntryVersioned(it)) + } + + pwGroupV4?.getChildEntries()?.forEach { + children.add(EntryVersioned(it)) + } + + return children + } + + /** + * Filter MetaStream entries and return children + * @return List of direct children (one level below) as PwNode + */ + fun getChildEntriesWithoutMetaStream(): List? { + pwGroupV3?.let { + return getChildEntries().filter { !it.isMetaStream } + } + + pwGroupV4?.let { + // No MetasStream in V4 + return getChildEntries() + } + + return null + } + + override fun addChildGroup(group: GroupVersioned) { + group.pwGroupV3?.let { + pwGroupV3?.addChildGroup(it) + } + group.pwGroupV4?.let { + pwGroupV4?.addChildGroup(it) + } + } + + override fun addChildEntry(entry: EntryVersioned) { + entry.pwEntryV3?.let { + pwGroupV3?.addChildEntry(it) + } + entry.pwEntryV4?.let { + pwGroupV4?.addChildEntry(it) + } + } + + override fun removeChildGroup(group: GroupVersioned) { + group.pwGroupV3?.let { + pwGroupV3?.removeChildGroup(it) + } + group.pwGroupV4?.let { + pwGroupV4?.removeChildGroup(it) + } + } + + override fun removeChildEntry(entry: EntryVersioned) { + entry.pwEntryV3?.let { + pwGroupV3?.removeChildEntry(it) + } + entry.pwEntryV4?.let { + pwGroupV4?.removeChildEntry(it) + } + } + + override fun allowAddEntryIfIsRoot(): Boolean { + return pwGroupV3?.allowAddEntryIfIsRoot() ?: pwGroupV4?.allowAddEntryIfIsRoot() ?: false + } + + /* + ------------ + V3 Methods + ------------ + */ + + var nodeIdV3: PwNodeId? + get() = pwGroupV3?.nodeId + set(value) { pwGroupV3?.nodeId = value } + + fun setNodeId(id: PwNodeIdInt) { + pwGroupV3?.nodeId = id + } + + fun getLevel(): Int { + return pwGroupV3?.level ?: -1 + } + + fun setLevel(level: Int) { + pwGroupV3?.level = level + } + + /* + ------------ + V4 Methods + ------------ + */ + + var nodeIdV4: PwNodeId? + get() = pwGroupV4?.nodeId + set(value) { pwGroupV4?.nodeId = value } + + fun setNodeId(id: PwNodeIdUUID) { + pwGroupV4?.nodeId = id + } + + fun setIconStandard(icon: PwIconStandard) { + pwGroupV4?.setIconStandard(icon) + } + + fun setEnableAutoType(enableAutoType: Boolean?) { + pwGroupV4?.enableAutoType = enableAutoType + } + + fun setEnableSearching(enableSearching: Boolean?) { + pwGroupV4?.enableSearching = enableSearching + } + + fun setExpanded(expanded: Boolean) { + pwGroupV4?.isExpanded = expanded + } + + fun containsCustomData(): Boolean { + return pwGroupV4?.containsCustomData() ?: false + } +} diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/NodeVersioned.kt b/app/src/main/java/com/kunzisoft/keepass/database/element/NodeVersioned.kt new file mode 100644 index 000000000..c0de233e9 --- /dev/null +++ b/app/src/main/java/com/kunzisoft/keepass/database/element/NodeVersioned.kt @@ -0,0 +1,12 @@ +package com.kunzisoft.keepass.database.element + +interface NodeVersioned: PwNodeInterface + +/** + * Type of available Nodes + */ +enum class Type { + GROUP, ENTRY +} + + diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/PwDatabase.java b/app/src/main/java/com/kunzisoft/keepass/database/element/PwDatabase.java index 3912fd8d4..b236523b0 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/element/PwDatabase.java +++ b/app/src/main/java/com/kunzisoft/keepass/database/element/PwDatabase.java @@ -37,7 +37,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.UUID; -public abstract class PwDatabase { +public abstract class PwDatabase { public static final UUID UUID_ZERO = new UUID(0,0); @@ -49,9 +49,8 @@ public abstract class PwDatabase { protected PwIconFactory iconFactory = new PwIconFactory(); - protected PwGroupInterface rootGroup; - protected LinkedHashMap groupIndexes = new LinkedHashMap<>(); - protected LinkedHashMap entryIndexes = new LinkedHashMap<>(); + protected LinkedHashMap groupIndexes = new LinkedHashMap<>(); + protected LinkedHashMap entryIndexes = new LinkedHashMap<>(); public abstract PwVersion getVersion(); @@ -230,17 +229,15 @@ public abstract class PwDatabase { * ------------------------------------- */ + public abstract void populateNodesIndexes(); + public abstract PwNodeId newGroupId(); - public abstract PwGroupInterface createGroup(); + public abstract PwNodeId newEntryId(); - public PwGroupInterface getRootGroup() { - return rootGroup; - } + public abstract Group createGroup(); - public void setRootGroup(PwGroupInterface rootGroup) { - this.rootGroup = rootGroup; - } + public abstract Group getRootGroup(); /* * ------------------------------------- @@ -259,26 +256,26 @@ public abstract class PwDatabase { return groupIndexes.containsKey(id); } - public Collection getGroupIndexes() { + public Collection getGroupIndexes() { return groupIndexes.values(); } - public void setGroupIndexes(List groupList) { + public void setGroupIndexes(List groupList) { this.groupIndexes.clear(); - for (PwGroupInterface currentGroup : groupList) { + for (Group currentGroup : groupList) { this.groupIndexes.put(currentGroup.getNodeId(), currentGroup); } } - public PwGroupInterface getGroupById(PwNodeId id) { + public Group getGroupById(PwNodeId id) { return this.groupIndexes.get(id); } - public void addGroupIndex(PwGroupInterface group) { + public void addGroupIndex(Group group) { this.groupIndexes.put(group.getNodeId(), group); } - public void removeGroupIndex(PwGroupInterface group) { + public void removeGroupIndex(Group group) { this.groupIndexes.remove(group.getNodeId()); } @@ -286,19 +283,23 @@ public abstract class PwDatabase { return groupIndexes.size(); } - public Collection getEntryIndexes() { + public boolean isEntryIdUsed(PwNodeId id) { + return entryIndexes.containsKey(id); + } + + public Collection getEntryIndexes() { return entryIndexes.values(); } - public PwEntryInterface getEntryById(PwNodeId id) { + public Entry getEntryById(PwNodeId id) { return this.entryIndexes.get(id); } - public void addEntryIndex(PwEntryInterface entry) { + public void addEntryIndex(Entry entry) { this.entryIndexes.put(entry.getNodeId(), entry); } - public void removeEntryIndex(PwEntryInterface entry) { + public void removeEntryIndex(Entry entry) { this.entryIndexes.remove(entry.getNodeId()); } @@ -312,7 +313,7 @@ public abstract class PwDatabase { * ------------------------------------- */ - protected void addGroupTo(PwGroupInterface newGroup, @Nullable PwGroupInterface parent) { + protected void addGroupTo(Group newGroup, @Nullable Group parent) { // Add tree to parent tree if (parent != null) parent.addChildGroup(newGroup); @@ -320,7 +321,7 @@ public abstract class PwDatabase { addGroupIndex(newGroup); } - protected void removeGroupFrom(PwGroupInterface groupToRemove, PwGroupInterface parent) { + protected void removeGroupFrom(Group groupToRemove, Group parent) { // Remove tree from parent tree if (parent != null) { parent.removeChildGroup(groupToRemove); @@ -328,7 +329,7 @@ public abstract class PwDatabase { removeGroupIndex(groupToRemove); } - protected void addEntryTo(PwEntryInterface newEntry, @Nullable PwGroupInterface parent) { + protected void addEntryTo(Entry newEntry, @Nullable Group parent) { // Add entry to parent if (parent != null) parent.addChildEntry(newEntry); @@ -336,7 +337,7 @@ public abstract class PwDatabase { addEntryIndex(newEntry); } - protected void removeEntryFrom(PwEntryInterface entryToRemove, PwGroupInterface parent) { + protected void removeEntryFrom(Entry entryToRemove, Group parent) { // Remove entry for parent if (parent != null) { parent.removeChildEntry(entryToRemove); @@ -345,17 +346,17 @@ public abstract class PwDatabase { } // TODO Delete group - public void undoDeleteGroup(PwGroupInterface group, PwGroupInterface origParent) { + public void undoDeleteGroupFrom(Group group, Group origParent) { addGroupTo(group, origParent); } - public void undoDeleteEntryFrom(PwEntryInterface entry, PwGroupInterface origParent) { + public void undoDeleteEntryFrom(Entry entry, Group origParent) { addEntryTo(entry, origParent); } - public abstract boolean isBackup(PwGroupInterface group); + public abstract boolean isBackup(Group group); - public boolean isGroupSearchable(PwGroupInterface group, boolean omitBackup) { + public boolean isGroupSearchable(Group group, boolean omitBackup) { return group != null; } } diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/PwDatabaseV3.java b/app/src/main/java/com/kunzisoft/keepass/database/element/PwDatabaseV3.java index 7f7fae7ad..07bcaa97e 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/element/PwDatabaseV3.java +++ b/app/src/main/java/com/kunzisoft/keepass/database/element/PwDatabaseV3.java @@ -29,22 +29,21 @@ import java.io.InputStream; import java.security.DigestOutputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Random; +import java.util.*; /** * @author Naomaru Itoi * @author Bill Zwicky * @author Dominik Reichl */ -public class PwDatabaseV3 extends PwDatabase { +public class PwDatabaseV3 extends PwDatabase { private static final int DEFAULT_ENCRYPTION_ROUNDS = 300; private int numKeyEncRounds; + protected PwGroupV3 rootGroup; + public PwDatabaseV3() { algorithm = PwEncryptionAlgorithm.AES_Rijndael; numKeyEncRounds = DEFAULT_ENCRYPTION_ROUNDS; @@ -62,15 +61,60 @@ public class PwDatabaseV3 extends PwDatabase { return list; } - public List getRootGroups() { - List kids = new ArrayList<>(); - for (Map.Entry grp : groupIndexes.entrySet()) { - if (grp.getValue().getLevel() == 0) - kids.add(grp.getValue()); + public List getRootGroups() { + List kids = new ArrayList<>(); + for (Map.Entry group : groupIndexes.entrySet()) { + if (group.getValue().getLevel() == 0) + kids.add(group.getValue()); } return kids; } + private void assignGroupsChildren(PwGroupV3 parent) { + int levelToCheck = parent.getLevel() + 1; + boolean startFromParentPosition = false; + for (PwGroupV3 groupToCheck: getGroupIndexes()) { + if (getRootGroup().getNodeId().equals(parent.getNodeId()) + || groupToCheck.getNodeId().equals(parent.getNodeId())) { + startFromParentPosition = true; + } + if (startFromParentPosition) { + if (groupToCheck.getLevel() < levelToCheck) + break; + else if (groupToCheck.getLevel() == levelToCheck) + parent.addChildGroup(groupToCheck); + } + } + } + + private void assignEntriesChildren(PwGroupV3 parent) { + for (PwEntryV3 entry : getEntryIndexes()) { + if (entry.getParent().getNodeId().equals(parent.getNodeId())) + parent.addChildEntry(entry); + } + } + + private void constructTreeFromIndex(PwGroupV3 currentGroup) { + + assignGroupsChildren(currentGroup); + assignEntriesChildren(currentGroup); + + // set parent in child entries (normally useless but to be sure or to update parent metadata) + for (PwEntryV3 childEntry : currentGroup.getChildEntries()) { + childEntry.setParent(currentGroup); + } + // recursively construct child groups + for (PwGroupV3 childGroup : currentGroup.getChildGroups()) { + childGroup.setParent(currentGroup); + constructTreeFromIndex(childGroup); + } + } + + @Override + public void populateNodesIndexes() { + constructTreeFromIndex(getRootGroup()); + } + /** * Generates an unused random tree id * @@ -86,6 +130,21 @@ public class PwDatabaseV3 extends PwDatabase { return newId; } + /** + * Generates an unused random tree id + * + * @return new tree id + */ + @Override + public PwNodeIdUUID newEntryId() { + PwNodeIdUUID newId; + do { + newId = new PwNodeIdUUID(UUID.randomUUID()); + } while (isEntryIdUsed(newId)); + + return newId; + } + @Override public byte[] getMasterKey(String key, InputStream keyInputStream) throws InvalidKeyFileException, IOException { @@ -158,7 +217,16 @@ public class PwDatabaseV3 extends PwDatabase { public PwGroupV3 createGroup() { return new PwGroupV3(); } - + + public void setRootGroup(PwGroupV3 rootGroup) { + this.rootGroup = rootGroup; + } + + @Override + public PwGroupV3 getRootGroup() { + return rootGroup; + } + // TODO: This could still be refactored cleaner public void copyEncrypted(byte[] buf, int offset, int size) { // No-op @@ -170,7 +238,7 @@ public class PwDatabaseV3 extends PwDatabase { } @Override - public boolean isBackup(PwGroupInterface group) { + public boolean isBackup(PwGroupV3 group) { while (group != null) { if (group.getLevel() == 0 && group.getTitle().equalsIgnoreCase("Backup")) { return true; @@ -181,7 +249,7 @@ public class PwDatabaseV3 extends PwDatabase { } @Override - public boolean isGroupSearchable(PwGroupInterface group, boolean omitBackup) { + public boolean isGroupSearchable(PwGroupV3 group, boolean omitBackup) { if (!super.isGroupSearchable(group, omitBackup)) { return false; } diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/PwDatabaseV4.java b/app/src/main/java/com/kunzisoft/keepass/database/element/PwDatabaseV4.java index c4933f595..fdf31e880 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/element/PwDatabaseV4.java +++ b/app/src/main/java/com/kunzisoft/keepass/database/element/PwDatabaseV4.java @@ -43,13 +43,15 @@ import java.security.NoSuchAlgorithmException; import java.util.*; -public class PwDatabaseV4 extends PwDatabase { +public class PwDatabaseV4 extends PwDatabase { private static final String TAG = PwDatabaseV4.class.getName(); private static final int DEFAULT_HISTORY_MAX_ITEMS = 10; // -1 unlimited private static final long DEFAULT_HISTORY_MAX_SIZE = 6 * 1024 * 1024; // -1 unlimited private static final String RECYCLEBIN_NAME = "RecycleBin"; + private PwGroupV4 rootGroup; + private byte[] hmacKey; private UUID dataCipher = AesEngine.CIPHER_UUID; private CipherEngine dataEngine = new AesEngine(); @@ -93,24 +95,6 @@ public class PwDatabaseV4 extends PwDatabase { public PwDatabaseV4() {} - public void populateNodeIndex() { - PwGroupInterface.doForEachChildAndForRoot(getRootGroup(), - new EntryHandler() { - @Override - public boolean operate(PwEntryInterface entry) { - addEntryIndex(entry); - return true; - } - }, - new GroupHandler() { - @Override - public boolean operate(PwGroupInterface group) { - addGroupIndex(group); - return true; - } - }); - } - @Override public PwVersion getVersion() { return PwVersion.V4; @@ -486,6 +470,25 @@ public class PwDatabaseV4 extends PwDatabase { return null; } + @Override + public void populateNodesIndexes() { + getRootGroup().doForEachChildAndForIt( + new NodeHandler() { + @Override + public boolean operate(PwEntryV4 entry) { + addEntryIndex(entry); + return true; + } + }, + new NodeHandler() { + @Override + public boolean operate(PwGroupV4 group) { + addGroupIndex(group); + return true; + } + }); + } + @Override public PwNodeIdUUID newGroupId() { PwNodeIdUUID newId; @@ -496,13 +499,32 @@ public class PwDatabaseV4 extends PwDatabase { return newId; } + @Override + public PwNodeIdUUID newEntryId() { + PwNodeIdUUID newId; + do { + newId = new PwNodeIdUUID(UUID.randomUUID()); + } while (isEntryIdUsed(newId)); + + return newId; + } + @Override public PwGroupV4 createGroup() { return new PwGroupV4(); } - @Override - public boolean isBackup(PwGroupInterface group) { + public void setRootGroup(PwGroupV4 rootGroup) { + this.rootGroup = rootGroup; + } + + @Override + public PwGroupV4 getRootGroup() { + return rootGroup; + } + + @Override + public boolean isBackup(PwGroupV4 group) { if (!recycleBinEnabled) { return false; } @@ -564,11 +586,11 @@ public class PwDatabaseV4 extends PwDatabase { * @param group Group to remove * @return true if group can be recycle, false elsewhere */ - public boolean canRecycle(PwGroupInterface group) { + public boolean canRecycle(PwGroupV4 group) { if (!recycleBinEnabled) { return false; } - PwGroupInterface recycle = getRecycleBin(); + PwGroupV4 recycle = getRecycleBin(); return (recycle == null) || (!group.isContainedIn(recycle)); } @@ -577,50 +599,44 @@ public class PwDatabaseV4 extends PwDatabase { * @param entry Entry to remove * @return true if entry can be recycle, false elsewhere */ - public boolean canRecycle(PwEntryInterface entry) { + public boolean canRecycle(PwEntryV4 entry) { if (!recycleBinEnabled) { return false; } - PwGroupInterface parent = entry.getParent(); + PwGroupV4 parent = entry.getParent(); return (parent != null) && canRecycle(parent); } - public void recycle(PwGroupInterface group) { + public void recycle(PwGroupV4 group) { ensureRecycleBin(); - PwGroupInterface parent = group.getParent(); - removeGroupFrom(group, parent); + removeGroupFrom(group, group.getParent()); - PwGroupInterface recycleBin = getRecycleBin(); - addGroupTo(group, recycleBin); + addGroupTo(group, getRecycleBin()); // TODO ? group.touchLocation(); } - public void recycle(PwEntryInterface entry) { + public void recycle(PwEntryV4 entry) { ensureRecycleBin(); - PwGroupInterface parent = entry.getParent(); - removeEntryFrom(entry, parent); + removeEntryFrom(entry, entry.getParent()); - PwGroupInterface recycleBin = getRecycleBin(); - addEntryTo(entry, recycleBin); + addEntryTo(entry, getRecycleBin()); entry.touchLocation(); } - public void undoRecycle(PwGroupInterface group, PwGroupInterface origParent) { + public void undoRecycle(PwGroupV4 group, PwGroupV4 origParent) { - PwGroupInterface recycleBin = getRecycleBin(); - removeGroupFrom(group, recycleBin); + removeGroupFrom(group, getRecycleBin()); addGroupTo(group, origParent); } - public void undoRecycle(PwEntryInterface entry, PwGroupInterface origParent) { + public void undoRecycle(PwEntryV4 entry, PwGroupV4 origParent) { - PwGroupInterface recycleBin = getRecycleBin(); - removeEntryFrom(entry, recycleBin); + removeEntryFrom(entry, getRecycleBin()); addEntryTo(entry, origParent); } @@ -634,18 +650,18 @@ public class PwDatabaseV4 extends PwDatabase { } @Override - protected void removeEntryFrom(PwEntryInterface entryToRemove, PwGroupInterface parent) { + protected void removeEntryFrom(PwEntryV4 entryToRemove, PwGroupV4 parent) { super.removeEntryFrom(entryToRemove, parent); deletedObjects.add(new PwDeletedObject((UUID) entryToRemove.getNodeId().getId())); } @Override - public void undoDeleteEntryFrom(PwEntryInterface entry, PwGroupInterface origParent) { + public void undoDeleteEntryFrom(PwEntryV4 entry, PwGroupV4 origParent) { super.undoDeleteEntryFrom(entry, origParent); deletedObjects.remove(new PwDeletedObject((UUID) entry.getNodeId().getId())); } - public PwGroupInterface getRecycleBin() { // TODO delete recycle bin preference + public PwGroupV4 getRecycleBin() { // TODO delete recycle bin preference if (recycleBinUUID == null) { return null; } @@ -675,7 +691,7 @@ public class PwDatabaseV4 extends PwDatabase { } @Override - public boolean isGroupSearchable(PwGroupInterface group, boolean omitBackup) { + public boolean isGroupSearchable(PwGroupV4 group, boolean omitBackup) { if (!super.isGroupSearchable(group, omitBackup)) { return false; } diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/PwDbHeaderV4.java b/app/src/main/java/com/kunzisoft/keepass/database/element/PwDbHeaderV4.java index 065fb8912..f11765814 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/element/PwDbHeaderV4.java +++ b/app/src/main/java/com/kunzisoft/keepass/database/element/PwDbHeaderV4.java @@ -23,8 +23,7 @@ import com.kunzisoft.keepass.crypto.keyDerivation.AesKdf; import com.kunzisoft.keepass.crypto.keyDerivation.KdfFactory; import com.kunzisoft.keepass.crypto.keyDerivation.KdfParameters; import com.kunzisoft.keepass.database.CrsAlgorithm; -import com.kunzisoft.keepass.database.EntryHandler; -import com.kunzisoft.keepass.database.GroupHandler; +import com.kunzisoft.keepass.database.NodeHandler; import com.kunzisoft.keepass.database.PwCompressionAlgorithm; import com.kunzisoft.keepass.database.exception.InvalidDBVersionException; import com.kunzisoft.keepass.stream.CopyInputStream; @@ -32,6 +31,8 @@ import com.kunzisoft.keepass.stream.HmacBlockStream; import com.kunzisoft.keepass.stream.LEDataInputStream; import com.kunzisoft.keepass.utils.Types; +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -40,9 +41,6 @@ import java.security.InvalidKeyException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; - public class PwDbHeaderV4 extends PwDbHeader { public static final int DBSIG_PRE2 = 0xB54BFB66; public static final int DBSIG_2 = 0xB54BFB67; @@ -109,12 +107,12 @@ public class PwDbHeaderV4 extends PwDbHeader { this.version = version; } - private class GroupHasCustomData extends GroupHandler { + private class GroupHasCustomData extends NodeHandler { boolean hasCustomData = false; @Override - public boolean operate(PwGroupInterface group) { + public boolean operate(PwGroupV4 group) { if (group == null) { return true; } @@ -127,12 +125,12 @@ public class PwDbHeaderV4 extends PwDbHeader { } } - private class EntryHasCustomData extends EntryHandler { + private class EntryHasCustomData extends NodeHandler { boolean hasCustomData = false; @Override - public boolean operate(PwEntryInterface entry) { + public boolean operate(PwEntryV4 entry) { if (entry == null) { return true; } @@ -164,7 +162,7 @@ public class PwDbHeaderV4 extends PwDbHeader { if (databaseV4.getRootGroup() == null ) { return PwDbHeaderV4.FILE_VERSION_32_3; } - PwGroupInterface.doForEachChildAndForRoot(databaseV4.getRootGroup(), entryHandler, groupHandler); + databaseV4.getRootGroup().doForEachChildAndForIt(entryHandler, groupHandler); if (groupHandler.hasCustomData || entryHandler.hasCustomData) { return PwDbHeaderV4.FILE_VERSION_32_4; } diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/PwEntry.kt b/app/src/main/java/com/kunzisoft/keepass/database/element/PwEntry.kt new file mode 100644 index 000000000..1b27ce15d --- /dev/null +++ b/app/src/main/java/com/kunzisoft/keepass/database/element/PwEntry.kt @@ -0,0 +1,17 @@ +package com.kunzisoft.keepass.database.element + +import android.os.Parcel +import java.util.* + +abstract class PwEntry + < + ParentGroup: PwGroupInterface, + Entry: PwEntryInterface + > + : PwNode, PwEntryInterface { + + constructor() : super() + + constructor(parcel: Parcel) : super(parcel) + +} \ No newline at end of file diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/PwEntryInterface.java b/app/src/main/java/com/kunzisoft/keepass/database/element/PwEntryInterface.java deleted file mode 100644 index f0896c663..000000000 --- a/app/src/main/java/com/kunzisoft/keepass/database/element/PwEntryInterface.java +++ /dev/null @@ -1,113 +0,0 @@ -package com.kunzisoft.keepass.database.element; - -import com.kunzisoft.keepass.database.ExtraFields; -import com.kunzisoft.keepass.database.SmallTimeInterface; -import com.kunzisoft.keepass.database.security.ProtectedString; - -public interface PwEntryInterface extends PwNodeInterface, SmallTimeInterface { - - String getTitle(); - void setTitle(String title); - - String getUsername(); - void setUsername(String user); - - String getPassword(); - void setPassword(String pass); - - String getUrl(); - void setUrl(String url); - - String getNotes(); - void setNotes(String notes); - - - /** - * To redefine if version of entry allow extra field, - * @return true if entry allows extra field - */ - boolean allowExtraFields(); - - /** - * Retrieve extra fields to show, key is the label, value is the value of field - * @return Map of label/value - */ - ExtraFields getFields(); - - /** - * If entry contains extra fields - * @return true if there is extra fields - */ - boolean containsCustomFields(); - /** - * If entry contains extra fields that are protected - * @return true if there is extra fields protected - */ - boolean containsCustomFieldsProtected(); - - /** - * If entry contains extra fields that are not protected - * @return true if there is extra fields not protected - */ - boolean containsCustomFieldsNotProtected(); - - /** - * Add an extra field to the list (standard or custom) - * @param label Label of field, must be unique - * @param value Value of field - */ - void addExtraField(String label, ProtectedString value); - - /** - * Delete all custom fields - */ - void removeAllCustomFields(); - - /** - * If it's a node with only meta information like Meta-info SYSTEM Database Color - * @return false by default, true if it's a meta stream - */ - boolean isMetaStream(); - - void touchLocation(); - - PwEntryInterface duplicate(); - - String PMS_TAN_ENTRY = ""; - - static boolean isTan(PwEntryInterface entry) { - return entry.getTitle().equals(PMS_TAN_ENTRY) - && (entry.getUsername().length() > 0); - } - - /** - * {@inheritDoc} - * Get the display title from an entry,
- * {@link #startManageEntry()} and {@link #stopManageEntry()} must be called - * before and after {@link #getVisualTitle(PwEntryInterface entry)} - */ - static String getVisualTitle(boolean isTan, String title, String userName, String url, String id) { - if ( isTan ) { - return PMS_TAN_ENTRY + " " + userName; - } else { - if (title.isEmpty()) - if (userName.isEmpty()) - if (url.isEmpty()) - return id; - else - return url; - else - return userName; - else - return title; - } - } - - static String getVisualTitle(PwEntryInterface entry) { - return getVisualTitle(PwEntryInterface.isTan(entry), - entry.getTitle(), - entry.getUsername(), - entry.getUrl(), - entry.getNodeId().toString()); - } -} diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/PwEntryInterface.kt b/app/src/main/java/com/kunzisoft/keepass/database/element/PwEntryInterface.kt new file mode 100644 index 000000000..ea6c72a4b --- /dev/null +++ b/app/src/main/java/com/kunzisoft/keepass/database/element/PwEntryInterface.kt @@ -0,0 +1,14 @@ +package com.kunzisoft.keepass.database.element + +interface PwEntryInterface : PwNodeInterface { + + var username: String + + var password: String + + var url: String + + var notes: String + + fun touchLocation() +} diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/PwEntryV3.java b/app/src/main/java/com/kunzisoft/keepass/database/element/PwEntryV3.java index f2ca42a16..f5b3c0195 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/element/PwEntryV3.java +++ b/app/src/main/java/com/kunzisoft/keepass/database/element/PwEntryV3.java @@ -44,10 +44,8 @@ package com.kunzisoft.keepass.database.element; import android.os.Parcel; -import com.kunzisoft.keepass.database.ExtraFields; -import com.kunzisoft.keepass.database.security.ProtectedString; - import java.io.UnsupportedEncodingException; +import java.util.Arrays; import java.util.UUID; @@ -72,7 +70,7 @@ import java.util.UUID; * @author Dominik Reichl * @author Jeremy Jamet */ -public class PwEntryV3 extends PwNode implements PwEntryInterface { +public class PwEntryV3 extends PwEntry { /** Size of byte buffer needed to hold this struct. */ private static final String PMS_ID_BINDESC = "bin-stream"; @@ -109,6 +107,11 @@ public class PwEntryV3 extends PwNode implements PwEntryInterface { parcel.readByteArray(binaryData); } + @Override + protected PwGroupV3 readParentParcelable(Parcel parcel) { + return parcel.readParcelable(PwGroupV3.class.getClassLoader()); + } + @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); @@ -179,11 +182,6 @@ public class PwEntryV3 extends PwNode implements PwEntryInterface { return newEntry; } - @Override - public PwEntryInterface duplicate() { - return clone(); - } - @Override public Type getType() { return Type.ENTRY; @@ -192,7 +190,7 @@ public class PwEntryV3 extends PwNode implements PwEntryInterface { public void setNewParent(int groupId) { PwGroupV3 pwGroupV3 = new PwGroupV3(); pwGroupV3.setNodeId(new PwNodeIdInt(groupId)); - this.parent = pwGroupV3; + setParent(pwGroupV3); } @Override @@ -300,9 +298,8 @@ public class PwEntryV3 extends PwNode implements PwEntryInterface { } // Determine if this is a MetaStream entry - @Override public boolean isMetaStream() { - if (binaryData == new byte[0]) return false; + if (Arrays.equals(binaryData, new byte[0])) return false; if (additional.isEmpty()) return false; if (!binaryDesc.equals(PMS_ID_BINDESC)) return false; if (title.isEmpty()) return false; @@ -311,50 +308,14 @@ public class PwEntryV3 extends PwNode implements PwEntryInterface { if (!username.equals(PMS_ID_USER)) return false; if (url.isEmpty()) return false; if (!url.equals(PMS_ID_URL)) return false; - return icon.isMetaStreamIcon(); + return getIcon().isMetaStreamIcon(); } @Override - public boolean isSearchingEnabled() { + public Boolean isSearchingEnabled() { return false; } - @Override - public boolean containsCustomData() { - return false; - } - @Override public void touchLocation() {} - - @Override - public boolean allowExtraFields() { - return false; - } - - @Override - public ExtraFields getFields() { - return new ExtraFields(); // TODO Nullable - } - - @Override - public boolean containsCustomFields() { - return getFields().containsCustomFields(); - } - - @Override - public boolean containsCustomFieldsProtected() { - return getFields().containsCustomFieldsProtected(); - } - - @Override - public boolean containsCustomFieldsNotProtected() { - return getFields().containsCustomFieldsNotProtected(); - } - - @Override - public void addExtraField(String label, ProtectedString value) {} - - @Override - public void removeAllCustomFields() {} } diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/PwEntryV4.java b/app/src/main/java/com/kunzisoft/keepass/database/element/PwEntryV4.java index 067d0e8ca..4f90fd83e 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/element/PwEntryV4.java +++ b/app/src/main/java/com/kunzisoft/keepass/database/element/PwEntryV4.java @@ -21,6 +21,7 @@ package com.kunzisoft.keepass.database.element; import android.os.Parcel; +import android.support.annotation.NonNull; import com.kunzisoft.keepass.database.AutoType; import com.kunzisoft.keepass.database.ExtraFields; import com.kunzisoft.keepass.database.ITimeLogger; @@ -36,7 +37,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.UUID; -public class PwEntryV4 extends PwNode implements ITimeLogger, PwEntryInterface { +public class PwEntryV4 extends PwEntry implements ITimeLogger { public static final String STR_TITLE = "Title"; public static final String STR_USERNAME = "UserName"; @@ -90,6 +91,11 @@ public class PwEntryV4 extends PwNode implements ITimeLogger, PwEntryInte tags = parcel.readString(); } + @Override + protected PwGroupV4 readParentParcelable(Parcel parcel) { + return parcel.readParcelable(PwGroupV4.class.getClassLoader()); + } + @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); @@ -167,11 +173,6 @@ public class PwEntryV4 extends PwNode implements ITimeLogger, PwEntryInte return newEntry; } - @Override - public PwEntryInterface duplicate() { - return clone(); - } - @Override public Type getType() { return Type.ENTRY; @@ -306,34 +307,31 @@ public class PwEntryV4 extends PwNode implements ITimeLogger, PwEntryInte } public PwIcon getIconStandard() { - return icon; + return getIcon(); } public void setIconStandard(PwIconStandard icon) { - this.icon = icon; + super.setIcon(icon); this.customIcon = PwIconCustom.ZERO; } - @Override public boolean allowExtraFields() { return true; } + @NonNull public ExtraFields getFields() { return fields; } - @Override public boolean containsCustomFields() { return getFields().containsCustomFields(); } - @Override public boolean containsCustomFieldsProtected() { return getFields().containsCustomFieldsProtected(); } - @Override public boolean containsCustomFieldsNotProtected() { return getFields().containsCustomFieldsNotProtected(); } @@ -342,7 +340,6 @@ public class PwEntryV4 extends PwNode implements ITimeLogger, PwEntryInte fields.putProtectedString(label, value); } - @Override public void removeAllCustomFields() { fields.removeAllCustomFields(); } @@ -458,7 +455,7 @@ public class PwEntryV4 extends PwNode implements ITimeLogger, PwEntryInte } public void createBackup(PwDatabaseV4 db) { - PwEntryV4 copy = clone(); + PwEntryV4 copy = new PwEntryV4(); // Clone copy.history = new ArrayList<>(); history.add(copy); @@ -526,9 +523,9 @@ public class PwEntryV4 extends PwNode implements ITimeLogger, PwEntryInte parentGroupLastMod = new PwDate(); } - public boolean isSearchingEnabled() { - if (parent != null) { - return parent.isSearchingEnabled(); + public Boolean isSearchingEnabled() { + if (getParent() != null) { + return getParent().isSearchingEnabled(); } return PwGroupV4.DEFAULT_SEARCHING_ENABLED; } diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/PwGroup.java b/app/src/main/java/com/kunzisoft/keepass/database/element/PwGroup.java deleted file mode 100644 index 715447eeb..000000000 --- a/app/src/main/java/com/kunzisoft/keepass/database/element/PwGroup.java +++ /dev/null @@ -1,98 +0,0 @@ -package com.kunzisoft.keepass.database.element; - -import android.os.Parcel; - -import java.util.ArrayList; -import java.util.List; - -public abstract class PwGroup extends PwNode implements PwGroupInterface { - - private String title = ""; - transient private List childGroups = new ArrayList<>(); - transient private List childEntries = new ArrayList<>(); - - public PwGroup() { - super(); - } - - public PwGroup(Parcel in) { - super(in); - title = in.readString(); - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeString(title); - } - - protected void updateWith(PwGroup source) { - super.updateWith(source); - title = source.title; - } - - @Override - public String getTitle() { - return title; - } - - @Override - public void setTitle(String name) { - this.title = name; - } - - @Override - public List getChildGroups() { - return childGroups; - } - - @Override - public List getChildEntries() { - return childEntries; - } - - @Override - public void addChildGroup(PwGroupInterface group) { - this.childGroups.add(group); - } - - @Override - public void addChildEntry(PwEntryInterface entry) { - this.childEntries.add(entry); - } - - @Override - public void removeChildGroup(PwGroupInterface group) { - this.childGroups.remove(group); - } - - @Override - public void removeChildEntry(PwEntryInterface entry) { - this.childEntries.remove(entry); - } - - @Override - public int getLevel() { - return -1; - } - - @Override - public void setLevel(int level) { - // Do nothing here - } - - @Override - public List getChildrenWithoutMetastream() { - List children = new ArrayList<>(childGroups); - for(PwEntryInterface child : childEntries) { - if (!child.isMetaStream()) - children.add(child); - } - return children; - } - - @Override - public String toString() { - return getTitle(); - } -} diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/PwGroup.kt b/app/src/main/java/com/kunzisoft/keepass/database/element/PwGroup.kt new file mode 100644 index 000000000..2a0ccf13e --- /dev/null +++ b/app/src/main/java/com/kunzisoft/keepass/database/element/PwGroup.kt @@ -0,0 +1,67 @@ +package com.kunzisoft.keepass.database.element + +import android.os.Parcel +import java.util.* + +abstract class PwGroup + < + Id, + Group: PwGroupInterface, + Entry: PwEntryInterface + > + : PwNode, PwGroupInterface { + + private var titleGroup = "" + @Transient + private val childGroups = ArrayList() + @Transient + private val childEntries = ArrayList() + + constructor() : super() + + constructor(parcel: Parcel) : super(parcel) { + titleGroup = parcel.readString() + } + + override fun writeToParcel(dest: Parcel, flags: Int) { + super.writeToParcel(dest, flags) + dest.writeString(titleGroup) + } + + protected fun updateWith(source: PwGroup) { + super.updateWith(source) + titleGroup = source.titleGroup + } + + override var title: String + get() = titleGroup + set(value) { titleGroup = value } + + override fun getChildGroups(): MutableList { + return childGroups + } + + override fun getChildEntries(): MutableList { + return childEntries + } + + override fun addChildGroup(group: Group) { + this.childGroups.add(group) + } + + override fun addChildEntry(entry: Entry) { + this.childEntries.add(entry) + } + + override fun removeChildGroup(group: Group) { + this.childGroups.remove(group) + } + + override fun removeChildEntry(entry: Entry) { + this.childEntries.remove(entry) + } + + override fun toString(): String { + return titleGroup + } +} diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/PwGroupInterface.java b/app/src/main/java/com/kunzisoft/keepass/database/element/PwGroupInterface.java deleted file mode 100644 index add78a1df..000000000 --- a/app/src/main/java/com/kunzisoft/keepass/database/element/PwGroupInterface.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.kunzisoft.keepass.database.element; - -import android.support.annotation.NonNull; - -import com.kunzisoft.keepass.database.EntryHandler; -import com.kunzisoft.keepass.database.GroupHandler; - -import java.util.List; - -public interface PwGroupInterface extends PwNodeInterface { - - int getLevel(); - - void setLevel(int level); - - List getChildGroups(); - - List getChildEntries(); - - void addChildGroup(PwGroupInterface group); - - void addChildEntry(PwEntryInterface entry); - - void removeChildGroup(PwGroupInterface group); - - void removeChildEntry(PwEntryInterface entry); - - /** - * Filter MetaStream entries and return children - * @return List of direct children (one level below) as PwNode - */ - List getChildrenWithoutMetastream(); - - boolean allowAddEntryIfIsRoot(); - - PwGroupInterface duplicate(); - - static void doForEachChildAndForRoot(@NonNull PwGroupInterface root, - EntryHandler entryHandler, - GroupHandler groupHandler) { - doForEachChild(root, entryHandler, groupHandler); - groupHandler.operate(root); - } - - static boolean doForEachChild(@NonNull PwGroupInterface root, - EntryHandler entryHandler, - GroupHandler groupHandler) { - for (PwEntryInterface entry : root.getChildEntries()) { - if (!entryHandler.operate(entry)) return false; - } - for (PwGroupInterface group : root.getChildGroups()) { - if ((groupHandler != null) && !groupHandler.operate(group)) return false; - doForEachChild(group, entryHandler, groupHandler); - } - return true; - } -} diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/PwGroupInterface.kt b/app/src/main/java/com/kunzisoft/keepass/database/element/PwGroupInterface.kt new file mode 100644 index 000000000..f5cd9d562 --- /dev/null +++ b/app/src/main/java/com/kunzisoft/keepass/database/element/PwGroupInterface.kt @@ -0,0 +1,38 @@ +package com.kunzisoft.keepass.database.element + +import com.kunzisoft.keepass.database.NodeHandler + +interface PwGroupInterface, Entry> : PwNodeInterface { + + fun getChildGroups(): MutableList + + fun getChildEntries(): MutableList + + fun addChildGroup(group: Group) + + fun addChildEntry(entry: Entry) + + fun removeChildGroup(group: Group) + + fun removeChildEntry(entry: Entry) + + fun allowAddEntryIfIsRoot(): Boolean + + fun doForEachChildAndForIt(entryHandler: NodeHandler, + groupHandler: NodeHandler) { + doForEachChild(entryHandler, groupHandler) + groupHandler.operate(this as Group) + } + + fun doForEachChild(entryHandler: NodeHandler, + groupHandler: NodeHandler?): Boolean { + for (entry in this.getChildEntries()) { + if (!entryHandler.operate(entry)) return false + } + for (group in this.getChildGroups()) { + if (groupHandler != null && !groupHandler.operate(group)) return false + group.doForEachChild(entryHandler, groupHandler) + } + return true + } +} diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/PwGroupV3.java b/app/src/main/java/com/kunzisoft/keepass/database/element/PwGroupV3.java index 76a29f3d7..46d5d1a1d 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/element/PwGroupV3.java +++ b/app/src/main/java/com/kunzisoft/keepass/database/element/PwGroupV3.java @@ -22,7 +22,7 @@ package com.kunzisoft.keepass.database.element; import android.os.Parcel; -public class PwGroupV3 extends PwGroup { +public class PwGroupV3 extends PwGroup { private int level = 0; // short /** Used by KeePass internally, don't use */ @@ -43,6 +43,11 @@ public class PwGroupV3 extends PwGroup { flags = in.readInt(); } + @Override + protected PwGroupV3 readParentParcelable(Parcel parcel) { + return parcel.readParcelable(PwGroupV3.class.getClassLoader()); + } + @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); @@ -78,41 +83,31 @@ public class PwGroupV3 extends PwGroup { return (PwGroupV3) super.clone(); } - @Override - public PwGroupInterface duplicate() { - return clone(); - } - @Override public Type getType() { return Type.GROUP; } - public void setParent(PwGroupInterface parent) { + public void setParent(PwGroupV3 parent) { super.setParent(parent); - level = parent.getLevel() + 1; + try { + level = parent.getLevel() + 1; + } catch (ClassCastException ignored) {} } @Override - public boolean isSearchingEnabled() { + public Boolean isSearchingEnabled() { return false; } - @Override - public boolean containsCustomData() { - return false; - } - public void setGroupId(int groupId) { this.setNodeId(new PwNodeIdInt(groupId)); } - @Override public int getLevel() { return level; } - @Override public void setLevel(int level) { this.level = level; } diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/PwGroupV4.java b/app/src/main/java/com/kunzisoft/keepass/database/element/PwGroupV4.java index 0e3a05c16..14b87d057 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/element/PwGroupV4.java +++ b/app/src/main/java/com/kunzisoft/keepass/database/element/PwGroupV4.java @@ -26,7 +26,7 @@ import java.util.HashMap; import java.util.Map; import java.util.UUID; -public class PwGroupV4 extends PwGroup implements ITimeLogger { +public class PwGroupV4 extends PwGroup implements ITimeLogger { public static final boolean DEFAULT_SEARCHING_ENABLED = true; @@ -68,6 +68,11 @@ public class PwGroupV4 extends PwGroup implements ITimeLogger { lastTopVisibleEntry = (UUID) in.readSerializable(); } + @Override + protected PwGroupV4 readParentParcelable(Parcel parcel) { + return parcel.readParcelable(PwGroupV4.class.getClassLoader()); + } + @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); @@ -138,18 +143,13 @@ public class PwGroupV4 extends PwGroup implements ITimeLogger { return newGroup; } - @Override - public PwGroupInterface duplicate() { - return clone(); - } - @Override public Type getType() { return Type.GROUP; } @Override - public void setParent(PwGroupInterface parent) { + public void setParent(PwGroupV4 parent) { super.setParent(parent); locationChangeDate = new PwDate(); } @@ -186,7 +186,7 @@ public class PwGroupV4 extends PwGroup implements ITimeLogger { @Override public PwIcon getIcon() { - if (customIcon == null || customIcon.getUUID().equals(PwDatabase.UUID_ZERO)) { + if (customIcon == null || customIcon.isUnknown()) { // TODO Encapsulate with PwEntryV4 return super.getIcon(); } else { return customIcon; @@ -202,11 +202,11 @@ public class PwGroupV4 extends PwGroup implements ITimeLogger { } public PwIcon getIconStandard() { - return icon; + return getIcon(); } public void setIconStandard(PwIconStandard icon) { // TODO Encapsulate with PwEntryV4 - this.icon = icon; + super.setIcon(icon); this.customIcon = PwIconCustom.ZERO; } @@ -266,16 +266,17 @@ public class PwGroupV4 extends PwGroup implements ITimeLogger { this.lastTopVisibleEntry = lastTopVisibleEntry; } - public boolean isSearchingEnabled() { - PwGroupV4 group = this; + public Boolean isSearchingEnabled() { + + GroupVersioned group = new GroupVersioned(this); while (group != null) { - Boolean search = group.enableSearching; + Boolean search = group.isSearchingEnabled(); if (search != null) { return search; } - group = (PwGroupV4) group.parent; + group = group.getParent(); } - + // If we get to the root tree and its null, default to true return true; } diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/PwNode.java b/app/src/main/java/com/kunzisoft/keepass/database/element/PwNode.java index d3172c22a..03483e307 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/element/PwNode.java +++ b/app/src/main/java/com/kunzisoft/keepass/database/element/PwNode.java @@ -22,19 +22,22 @@ package com.kunzisoft.keepass.database.element; import android.os.Parcel; import android.os.Parcelable; - -import com.kunzisoft.keepass.app.App; - import org.joda.time.LocalDate; /** * Abstract class who manage Groups and Entries */ -public abstract class PwNode implements PwNodeInterface, Parcelable, Cloneable { +public abstract class PwNode + < + IdType, + Parent extends PwGroupInterface, + Entry extends PwEntryInterface + > + implements PwNodeInterface, Parcelable { private PwNodeId nodeId = initNodeId(); - protected PwGroupInterface parent = null; - protected PwIcon icon = new PwIconStandard(); + private Parent parent = null; + private PwIcon icon = new PwIconStandard(); protected PwDate creation = new PwDate(); private PwDate lastMod = new PwDate(); private PwDate lastAccess = new PwDate(); @@ -44,32 +47,22 @@ public abstract class PwNode implements PwNodeInterface, Parcelable, Clo protected PwNode() {} - protected PwNode(Parcel in) { - nodeId = in.readParcelable(PwNodeId.class.getClassLoader()); - // TODO better technique ? - try { - PwNodeId pwGroupId = in.readParcelable(PwNodeId.class.getClassLoader()); - parent = App.getDB().getGroupById(pwGroupId); - } catch (Exception e) { - e.printStackTrace(); - } - - icon = in.readParcelable(PwIconStandard.class.getClassLoader()); - creation = in.readParcelable(PwDate.class.getClassLoader()); - lastMod = in.readParcelable(PwDate.class.getClassLoader()); - lastAccess = in.readParcelable(PwDate.class.getClassLoader()); - expireDate = in.readParcelable(PwDate.class.getClassLoader()); + protected PwNode(Parcel parcel) { + nodeId = parcel.readParcelable(PwNodeId.class.getClassLoader()); + parent = readParentParcelable(parcel); + icon = parcel.readParcelable(PwIconStandard.class.getClassLoader()); + creation = parcel.readParcelable(PwDate.class.getClassLoader()); + lastMod = parcel.readParcelable(PwDate.class.getClassLoader()); + lastAccess = parcel.readParcelable(PwDate.class.getClassLoader()); + expireDate = parcel.readParcelable(PwDate.class.getClassLoader()); } + protected abstract Parent readParentParcelable(Parcel parcel); + @Override public void writeToParcel(Parcel dest, int flags) { dest.writeParcelable(nodeId, flags); - - PwNodeId parentId = null; - if (parent != null) - parentId = parent.getNodeId(); - dest.writeParcelable(parentId, flags); - + dest.writeParcelable(parent, flags); dest.writeParcelable(icon, flags); dest.writeParcelable(creation, flags); dest.writeParcelable(lastMod, flags); @@ -82,7 +75,7 @@ public abstract class PwNode implements PwNodeInterface, Parcelable, Clo return 0; } - protected void updateWith(PwNode source) { + protected void updateWith(PwNode source) { this.nodeId = source.nodeId; this.parent = source.parent; this.icon = source.icon; @@ -114,13 +107,11 @@ public abstract class PwNode implements PwNodeInterface, Parcelable, Clo return getNodeId().getId(); } - @Override public PwNodeId getNodeId() { return nodeId; } - @Override - public void setNodeId(PwNodeId id) { + public void setNodeId(PwNodeId id) { this.nodeId = id; } @@ -136,18 +127,13 @@ public abstract class PwNode implements PwNodeInterface, Parcelable, Clo this.icon = icon; } - /** - * Retrieve the parent node - * @return PwGroup parent as group - */ - public PwGroupInterface getParent() { + @Override + public Parent getParent() { return parent; } - /** - * Assign a parent to this node - */ - public void setParent(PwGroupInterface parent) { + @Override + public void setParent(Parent parent) { this.parent = parent; } @@ -202,8 +188,8 @@ public abstract class PwNode implements PwNodeInterface, Parcelable, Clo } @Override - public boolean isContainedIn(PwGroupInterface container) { - PwGroupInterface cur = this.getParent(); + public boolean isContainedIn(Parent container) { + Parent cur = this.getParent(); while (cur != null) { if (cur.equals(container)) { return true; @@ -222,7 +208,7 @@ public abstract class PwNode implements PwNodeInterface, Parcelable, Clo setLastModificationTime(now); } - PwGroupInterface parent = getParent(); + Parent parent = getParent(); if (touchParents && parent != null) { parent.touch(modified, true); } diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/PwNodeInterface.java b/app/src/main/java/com/kunzisoft/keepass/database/element/PwNodeInterface.java deleted file mode 100644 index 51b07977b..000000000 --- a/app/src/main/java/com/kunzisoft/keepass/database/element/PwNodeInterface.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.kunzisoft.keepass.database.element; - -import android.os.Parcelable; - -import com.kunzisoft.keepass.database.SmallTimeInterface; - -public interface PwNodeInterface extends SmallTimeInterface, Parcelable { - - PwNodeId getNodeId(); - - void setNodeId(PwNodeId id); - - String getTitle(); - - void setTitle(String title); - - /** - * @return Visual icon - */ - PwIcon getIcon(); - - void setIcon(PwIcon icon); - - /** - * @return Type of Node - */ - PwNodeInterface.Type getType(); - - /** - * Retrieve the parent node - * @return PwGroup parent as group - */ - PwGroupInterface getParent(); - - /** - * Assign a parent to this node - */ - void setParent(PwGroupInterface prt); - - boolean containsParent(); - - void touch(boolean modified, boolean touchParents); - - boolean isContainedIn(PwGroupInterface container); - - boolean isSearchingEnabled(); - - boolean containsCustomData(); - - /** - * Type of available Nodes - */ - enum Type { - GROUP, ENTRY - } -} diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/PwNodeInterface.kt b/app/src/main/java/com/kunzisoft/keepass/database/element/PwNodeInterface.kt new file mode 100644 index 000000000..aade02266 --- /dev/null +++ b/app/src/main/java/com/kunzisoft/keepass/database/element/PwNodeInterface.kt @@ -0,0 +1,32 @@ +package com.kunzisoft.keepass.database.element + +import android.os.Parcelable +import com.kunzisoft.keepass.database.SmallTimeInterface + +interface PwNodeInterface : SmallTimeInterface, Parcelable { + + var title: String + + /** + * @return Visual icon + */ + var icon: PwIcon + + /** + * @return Type of Node + */ + val type: Type + + /** + * Retrieve the parent node + */ + var parent: ParentGroup? + + val isSearchingEnabled: Boolean? + + fun containsParent(): Boolean + + fun touch(modified: Boolean, touchParents: Boolean) + + fun isContainedIn(container: ParentGroup): Boolean +} \ No newline at end of file diff --git a/app/src/main/java/com/kunzisoft/keepass/database/iterator/EntrySearchStringIterator.java b/app/src/main/java/com/kunzisoft/keepass/database/iterator/EntrySearchStringIterator.java deleted file mode 100644 index 4911b9f7a..000000000 --- a/app/src/main/java/com/kunzisoft/keepass/database/iterator/EntrySearchStringIterator.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft. - * - * This file is part of KeePass DX. - * - * KeePass DX is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * KeePass DX is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with KeePass DX. If not, see . - * - */ -package com.kunzisoft.keepass.database.iterator; - -import com.kunzisoft.keepass.database.element.PwEntryInterface; -import com.kunzisoft.keepass.database.element.PwEntryV3; -import com.kunzisoft.keepass.database.element.PwEntryV4; -import com.kunzisoft.keepass.database.search.SearchParameters; -import com.kunzisoft.keepass.database.search.SearchParametersV4; - -import java.util.Iterator; - -public abstract class EntrySearchStringIterator implements Iterator { - - public static EntrySearchStringIterator getInstance(PwEntryInterface e) { - if (e instanceof PwEntryV3) { - return new EntrySearchStringIteratorV3((PwEntryV3) e); - } else if (e instanceof PwEntryV4) { - return new EntrySearchStringIteratorV4((PwEntryV4) e); - } else { - throw new RuntimeException("This should not be possible"); - } - } - - public static EntrySearchStringIterator getInstance(PwEntryInterface e, SearchParameters sp) { - if (e instanceof PwEntryV3) { - return new EntrySearchStringIteratorV3((PwEntryV3) e, sp); - } else if (e instanceof PwEntryV4) { - return new EntrySearchStringIteratorV4((PwEntryV4) e, (SearchParametersV4) sp); - } else { - throw new RuntimeException("This should not be possible"); - } - } - - @Override - public abstract boolean hasNext(); - - @Override - public abstract String next(); - - @Override - public void remove() { - throw new UnsupportedOperationException("This iterator cannot be used to remove strings."); - - } - - -} diff --git a/app/src/main/java/com/kunzisoft/keepass/database/EntryHandler.java b/app/src/main/java/com/kunzisoft/keepass/database/iterator/EntrySearchStringIterator.kt similarity index 52% rename from app/src/main/java/com/kunzisoft/keepass/database/EntryHandler.java rename to app/src/main/java/com/kunzisoft/keepass/database/iterator/EntrySearchStringIterator.kt index ddd3f5906..c32979c5b 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/EntryHandler.java +++ b/app/src/main/java/com/kunzisoft/keepass/database/iterator/EntrySearchStringIterator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft. + * Copyright 2019 Jeremy Jamet / Kunzisoft. * * This file is part of KeePass DX. * @@ -17,16 +17,25 @@ * along with KeePass DX. If not, see . * */ -package com.kunzisoft.keepass.database; +package com.kunzisoft.keepass.database.iterator + +import com.kunzisoft.keepass.database.element.EntryVersioned + +abstract class EntrySearchStringIterator : Iterator { + + companion object { + + fun getInstance(entry: EntryVersioned): EntrySearchStringIterator { + if (entry.pwEntryV3 != null) { + return EntrySearchStringIteratorV3(entry.pwEntryV3) + } + if (entry.pwEntryV4 != null) { + return EntrySearchStringIteratorV4(entry.pwEntryV4!!) + } + + throw RuntimeException("This should not be possible") + } + } -import com.kunzisoft.keepass.database.element.PwEntryInterface; -/** "Delegate" class for operating on each entry when traversing all of - * them - * @author bpellin - * - */ -public abstract class EntryHandler { - public abstract boolean operate(T entry); } - diff --git a/app/src/main/java/com/kunzisoft/keepass/database/iterator/EntrySearchStringIteratorV4.java b/app/src/main/java/com/kunzisoft/keepass/database/iterator/EntrySearchStringIteratorV4.java deleted file mode 100644 index 795a752ae..000000000 --- a/app/src/main/java/com/kunzisoft/keepass/database/iterator/EntrySearchStringIteratorV4.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft. - * - * This file is part of KeePass DX. - * - * KeePass DX is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * KeePass DX is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with KeePass DX. If not, see . - * - */ -package com.kunzisoft.keepass.database.iterator; - -import com.kunzisoft.keepass.database.element.PwEntryV4; -import com.kunzisoft.keepass.database.search.SearchParametersV4; -import com.kunzisoft.keepass.database.security.ProtectedString; - -import java.util.Iterator; -import java.util.Map.Entry; -import java.util.NoSuchElementException; - -public class EntrySearchStringIteratorV4 extends EntrySearchStringIterator { - - private String current; - private Iterator> setIterator; - private SearchParametersV4 sp; - - public EntrySearchStringIteratorV4(PwEntryV4 entry) { - this.sp = SearchParametersV4.DEFAULT; - setIterator = entry.getFields().getListOfAllFields().entrySet().iterator(); - advance(); - } - - public EntrySearchStringIteratorV4(PwEntryV4 entry, SearchParametersV4 sp) { - this.sp = sp; - setIterator = entry.getFields().getListOfAllFields().entrySet().iterator(); - advance(); - } - - @Override - public boolean hasNext() { - return current != null; - } - - @Override - public String next() { - if (current == null) { - throw new NoSuchElementException("Past the end of the list."); - } - - String next = current; - advance(); - return next; - } - - private void advance() { - while (setIterator.hasNext()) { - Entry entry = setIterator.next(); - - String key = entry.getKey(); - - if (searchInField(key)) { - current = entry.getValue().toString(); - return; - } - - } - - current = null; - } - - private boolean searchInField(String key) { - switch (key) { - case PwEntryV4.STR_TITLE: - return sp.searchInTitles; - case PwEntryV4.STR_USERNAME: - return sp.searchInUserNames; - case PwEntryV4.STR_PASSWORD: - return sp.searchInPasswords; - case PwEntryV4.STR_URL: - return sp.searchInUrls; - case PwEntryV4.STR_NOTES: - return sp.searchInNotes; - default: - return sp.searchInOther; - } - } - -} diff --git a/app/src/main/java/com/kunzisoft/keepass/database/iterator/EntrySearchStringIteratorV4.kt b/app/src/main/java/com/kunzisoft/keepass/database/iterator/EntrySearchStringIteratorV4.kt new file mode 100644 index 000000000..06c3fc341 --- /dev/null +++ b/app/src/main/java/com/kunzisoft/keepass/database/iterator/EntrySearchStringIteratorV4.kt @@ -0,0 +1,87 @@ +/* + * Copyright 2019 Jeremy Jamet / Kunzisoft. + * + * This file is part of KeePass DX. + * + * KeePass DX is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * KeePass DX is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with KeePass DX. If not, see . + * + */ +package com.kunzisoft.keepass.database.iterator + +import com.kunzisoft.keepass.database.element.PwEntryV4 +import com.kunzisoft.keepass.database.search.SearchParametersV4 +import com.kunzisoft.keepass.database.security.ProtectedString +import java.util.* +import kotlin.collections.Map.Entry + +class EntrySearchStringIteratorV4 : EntrySearchStringIterator { + + private var current: String? = null + private var setIterator: Iterator>? = null + private var sp: SearchParametersV4? = null + + constructor(entry: PwEntryV4) { + this.sp = SearchParametersV4.DEFAULT + setIterator = entry.fields.listOfAllFields.entries.iterator() + advance() + } + + constructor(entry: PwEntryV4, sp: SearchParametersV4) { + this.sp = sp + setIterator = entry.fields.listOfAllFields.entries.iterator() + advance() + } + + override fun hasNext(): Boolean { + return current != null + } + + override fun next(): String { + if (current == null) { + throw NoSuchElementException("Past the end of the list.") + } + + val next = current + advance() + return next!! + } + + private fun advance() { + while (setIterator!!.hasNext()) { + val entry = setIterator!!.next() + + val key = entry.key + + if (searchInField(key)) { + current = entry.value.toString() + return + } + + } + + current = null + } + + private fun searchInField(key: String): Boolean { + when (key) { + PwEntryV4.STR_TITLE -> return sp!!.searchInTitles + PwEntryV4.STR_USERNAME -> return sp!!.searchInUserNames + PwEntryV4.STR_PASSWORD -> return sp!!.searchInPasswords + PwEntryV4.STR_URL -> return sp!!.searchInUrls + PwEntryV4.STR_NOTES -> return sp!!.searchInNotes + else -> return sp!!.searchInOther + } + } + +} diff --git a/app/src/main/java/com/kunzisoft/keepass/database/load/ImporterV3.java b/app/src/main/java/com/kunzisoft/keepass/database/load/ImporterV3.java index e7e04bb59..e8072b2b1 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/load/ImporterV3.java +++ b/app/src/main/java/com/kunzisoft/keepass/database/load/ImporterV3.java @@ -226,51 +226,11 @@ public class ImporterV3 extends Importer { pos += 2 + 4 + fieldSize; } - constructTreeFromIndex(databaseToOpen.getRootGroup()); + databaseToOpen.populateNodesIndexes(); return databaseToOpen; } - private void constructTreeFromIndex(PwGroupInterface currentGroup) { - - assignGroupsChildren(currentGroup); - assignEntriesChildren(currentGroup); - - // set parent in child entries (normally useless but to be sure or to update parent metadata) - for (PwEntryInterface childEntry : currentGroup.getChildEntries()) { - childEntry.setParent(currentGroup); - } - // recursively construct child groups - for (PwGroupInterface childGroup : currentGroup.getChildGroups()) { - childGroup.setParent(currentGroup); - constructTreeFromIndex(childGroup); - } - } - - private void assignGroupsChildren(PwGroupInterface parent) { - int levelToCheck = parent.getLevel() + 1; - boolean startFromParentPosition = false; - for (PwGroupInterface groupToCheck: databaseToOpen.getGroupIndexes()) { - if (databaseToOpen.getRootGroup().getNodeId().equals(parent.getNodeId()) - || groupToCheck.getNodeId().equals(parent.getNodeId())) { - startFromParentPosition = true; - } - if (startFromParentPosition) { - if (groupToCheck.getLevel() < levelToCheck) - break; - else if (groupToCheck.getLevel() == levelToCheck) - parent.addChildGroup(groupToCheck); - } - } - } - - private void assignEntriesChildren(PwGroupInterface parent) { - for (PwEntryInterface entry : databaseToOpen.getEntryIndexes()) { - if (entry.getParent().getNodeId().equals(parent.getNodeId())) - parent.addChildEntry(entry); - } - } - /** * Parse and save one record from binary file. * @param buf diff --git a/app/src/main/java/com/kunzisoft/keepass/database/load/ImporterV4.java b/app/src/main/java/com/kunzisoft/keepass/database/load/ImporterV4.java index c80724dd3..6c1baebe7 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/load/ImporterV4.java +++ b/app/src/main/java/com/kunzisoft/keepass/database/load/ImporterV4.java @@ -173,7 +173,7 @@ public class ImporterV4 extends Importer { ReadXmlStreamed(isXml); - mDatabase.populateNodeIndex(); + mDatabase.populateNodesIndexes(); return mDatabase; } @@ -291,13 +291,12 @@ public class ImporterV4 extends Importer { private String entryCustomDataValue = null; private void ReadXmlStreamed(InputStream readerStream) throws IOException, InvalidDBException { - - try { - ReadDocumentStreamed(CreatePullParser(readerStream)); - } catch (XmlPullParserException e) { - e.printStackTrace(); - throw new IOException(e.getLocalizedMessage()); - } + try { + ReadDocumentStreamed(CreatePullParser(readerStream)); + } catch (XmlPullParserException e) { + e.printStackTrace(); + throw new IOException(e.getLocalizedMessage()); + } } private static XmlPullParser CreatePullParser(InputStream readerStream) throws XmlPullParserException { diff --git a/app/src/main/java/com/kunzisoft/keepass/database/save/PwDbV3Output.java b/app/src/main/java/com/kunzisoft/keepass/database/save/PwDbV3Output.java index 4b72e00ac..208494065 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/save/PwDbV3Output.java +++ b/app/src/main/java/com/kunzisoft/keepass/database/save/PwDbV3Output.java @@ -20,35 +20,22 @@ package com.kunzisoft.keepass.database.save; import com.kunzisoft.keepass.crypto.CipherFactory; -import com.kunzisoft.keepass.database.element.PwDatabaseV3; -import com.kunzisoft.keepass.database.element.PwDbHeader; -import com.kunzisoft.keepass.database.element.PwDbHeaderV3; -import com.kunzisoft.keepass.database.element.PwEncryptionAlgorithm; -import com.kunzisoft.keepass.database.element.PwEntryInterface; -import com.kunzisoft.keepass.database.element.PwEntryV3; -import com.kunzisoft.keepass.database.element.PwGroupInterface; -import com.kunzisoft.keepass.database.element.PwGroupV3; +import com.kunzisoft.keepass.database.element.*; import com.kunzisoft.keepass.database.exception.PwDbOutputException; import com.kunzisoft.keepass.stream.LEDataOutputStream; import com.kunzisoft.keepass.stream.NullOutputStream; -import java.io.BufferedOutputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.security.DigestOutputStream; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.List; - import javax.crypto.Cipher; import javax.crypto.CipherOutputStream; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.security.*; +import java.util.ArrayList; +import java.util.List; public class PwDbV3Output extends PwDbOutput { @@ -215,8 +202,8 @@ public class PwDbV3Output extends PwDbOutput { } // Groups - for (PwGroupInterface group: mDatabaseV3.getGroupIndexes()) { - PwGroupOutputV3 pgo = new PwGroupOutputV3((PwGroupV3) group, os); + for (PwGroupV3 group: mDatabaseV3.getGroupIndexes()) { + PwGroupOutputV3 pgo = new PwGroupOutputV3(group, os); try { pgo.output(); } catch (IOException e) { @@ -225,8 +212,8 @@ public class PwDbV3Output extends PwDbOutput { } // Entries - for (PwEntryInterface entry : mDatabaseV3.getEntryIndexes()) { - PwEntryOutputV3 peo = new PwEntryOutputV3((PwEntryV3) (entry), os); + for (PwEntryV3 entry : mDatabaseV3.getEntryIndexes()) { + PwEntryOutputV3 peo = new PwEntryOutputV3(entry, os); try { peo.output(); } catch (IOException e) { @@ -236,20 +223,20 @@ public class PwDbV3Output extends PwDbOutput { } private void sortGroupsForOutput() { - List groupList = new ArrayList<>(); + List groupList = new ArrayList<>(); // Rebuild list according to coalation sorting order removing any orphaned groups - for (PwGroupInterface rootGroup : mDatabaseV3.getRootGroups()) { + for (PwGroupV3 rootGroup : mDatabaseV3.getRootGroups()) { sortGroup(rootGroup, groupList); } mDatabaseV3.setGroupIndexes(groupList); } - private void sortGroup(PwGroupInterface group, List groupList) { + private void sortGroup(PwGroupV3 group, List groupList) { // Add current tree groupList.add(group); // Recurse over children - for (PwGroupInterface childGroup : group.getChildGroups()) { + for (PwGroupV3 childGroup : group.getChildGroups()) { sortGroup(childGroup, groupList); } } diff --git a/app/src/main/java/com/kunzisoft/keepass/database/save/PwDbV4Output.java b/app/src/main/java/com/kunzisoft/keepass/database/save/PwDbV4Output.java index a59ef3a00..dcec07d1d 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/save/PwDbV4Output.java +++ b/app/src/main/java/com/kunzisoft/keepass/database/save/PwDbV4Output.java @@ -21,29 +21,14 @@ package com.kunzisoft.keepass.database.save; import android.util.Log; import android.util.Xml; - +import biz.source_code.base64Coder.Base64Coder; import com.kunzisoft.keepass.crypto.CipherFactory; import com.kunzisoft.keepass.crypto.PwStreamCipherFactory; import com.kunzisoft.keepass.crypto.engine.CipherEngine; import com.kunzisoft.keepass.crypto.keyDerivation.KdfEngine; import com.kunzisoft.keepass.crypto.keyDerivation.KdfFactory; -import com.kunzisoft.keepass.database.AutoType; -import com.kunzisoft.keepass.database.CrsAlgorithm; -import com.kunzisoft.keepass.database.EntryHandler; -import com.kunzisoft.keepass.database.GroupHandler; -import com.kunzisoft.keepass.database.ITimeLogger; -import com.kunzisoft.keepass.database.MemoryProtectionConfig; -import com.kunzisoft.keepass.database.PwCompressionAlgorithm; -import com.kunzisoft.keepass.database.element.PwDatabaseV4; -import com.kunzisoft.keepass.database.element.PwDatabaseV4XML; -import com.kunzisoft.keepass.database.element.PwDbHeaderV4; -import com.kunzisoft.keepass.database.element.PwDefsV4; -import com.kunzisoft.keepass.database.element.PwDeletedObject; -import com.kunzisoft.keepass.database.element.PwEntryInterface; -import com.kunzisoft.keepass.database.element.PwEntryV4; -import com.kunzisoft.keepass.database.element.PwGroupInterface; -import com.kunzisoft.keepass.database.element.PwGroupV4; -import com.kunzisoft.keepass.database.element.PwIconCustom; +import com.kunzisoft.keepass.database.*; +import com.kunzisoft.keepass.database.element.*; import com.kunzisoft.keepass.database.exception.PwDbOutputException; import com.kunzisoft.keepass.database.exception.UnknownKDF; import com.kunzisoft.keepass.database.security.ProtectedBinary; @@ -55,28 +40,20 @@ import com.kunzisoft.keepass.utils.DateUtil; import com.kunzisoft.keepass.utils.EmptyUtils; import com.kunzisoft.keepass.utils.MemUtil; import com.kunzisoft.keepass.utils.Types; - import org.joda.time.DateTime; import org.spongycastle.crypto.StreamCipher; import org.xmlpull.v1.XmlSerializer; +import javax.crypto.Cipher; +import javax.crypto.CipherOutputStream; import java.io.IOException; import java.io.OutputStream; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; -import java.util.Date; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import java.util.Stack; -import java.util.UUID; import java.util.zip.GZIPOutputStream; -import javax.crypto.Cipher; -import javax.crypto.CipherOutputStream; - -import biz.source_code.base64Coder.Base64Coder; - public class PwDbV4Output extends PwDbOutput { private static final String TAG = PwDbV4Output.class.getName(); @@ -155,18 +132,16 @@ public class PwDbV4Output extends PwDbOutput { writeMeta(); - PwGroupV4 root = (PwGroupV4) mPM.getRootGroup(); + PwGroupV4 root = mPM.getRootGroup(); xml.startTag(null, PwDatabaseV4XML.ElemRoot); startGroup(root); Stack groupStack = new Stack<>(); groupStack.push(root); - if (!PwGroupInterface.doForEachChild(root, - new EntryHandler() { + if (!root.doForEachChild( + new NodeHandler() { @Override - public boolean operate(PwEntryInterface entryInterface) { - PwEntryV4 entry = (PwEntryV4) entryInterface; - + public boolean operate(PwEntryV4 entry) { try { writeEntry(entry, false); } catch (IOException ex) { @@ -176,11 +151,9 @@ public class PwDbV4Output extends PwDbOutput { return true; } }, - new GroupHandler() { + new NodeHandler() { @Override - public boolean operate(PwGroupInterface groupInterface) { - PwGroupV4 group = (PwGroupV4) groupInterface; - + public boolean operate(PwGroupV4 group) { while (true) { try { if (group.getParent() == groupStack.peek()) { @@ -338,7 +311,7 @@ public class PwDbV4Output extends PwDbOutput { private void startGroup(PwGroupV4 group) throws IllegalArgumentException, IllegalStateException, IOException { xml.startTag(null, PwDatabaseV4XML.ElemGroup); - writeObject(PwDatabaseV4XML.ElemUuid, group.getNodeId().getId()); + writeObject(PwDatabaseV4XML.ElemUuid, group.getId()); writeObject(PwDatabaseV4XML.ElemName, group.getTitle()); writeObject(PwDatabaseV4XML.ElemNotes, group.getNotes()); writeObject(PwDatabaseV4XML.ElemIcon, group.getIconStandard().getIconId()); diff --git a/app/src/main/java/com/kunzisoft/keepass/database/save/PwEntryOutputV3.java b/app/src/main/java/com/kunzisoft/keepass/database/save/PwEntryOutputV3.java index 972f1bb01..137ab94fa 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/save/PwEntryOutputV3.java +++ b/app/src/main/java/com/kunzisoft/keepass/database/save/PwEntryOutputV3.java @@ -20,7 +20,6 @@ package com.kunzisoft.keepass.database.save; import com.kunzisoft.keepass.database.element.PwEntryV3; -import com.kunzisoft.keepass.database.element.PwGroupV3; import com.kunzisoft.keepass.stream.LEDataOutputStream; import com.kunzisoft.keepass.utils.Types; @@ -80,7 +79,7 @@ public class PwEntryOutputV3 { // Group ID mOS.write(GROUPID_FIELD_TYPE); mOS.write(LONG_FOUR); - mOS.write(LEDataOutputStream.writeIntBuf(((PwGroupV3) mPE.getParent()).getNodeId().getId())); + mOS.write(LEDataOutputStream.writeIntBuf(mPE.getParent().getNodeId().getId())); // Image ID mOS.write(IMAGEID_FIELD_TYPE); diff --git a/app/src/main/java/com/kunzisoft/keepass/database/search/EntrySearchHandlerV4.java b/app/src/main/java/com/kunzisoft/keepass/database/search/EntrySearchHandlerV4.java index 9e3668d39..ec1270a50 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/search/EntrySearchHandlerV4.java +++ b/app/src/main/java/com/kunzisoft/keepass/database/search/EntrySearchHandlerV4.java @@ -19,11 +19,11 @@ */ package com.kunzisoft.keepass.database.search; -import com.kunzisoft.keepass.database.EntryHandler; -import com.kunzisoft.keepass.database.element.PwEntryInterface; +import com.kunzisoft.keepass.database.NodeHandler; import com.kunzisoft.keepass.database.element.PwEntryV4; -import com.kunzisoft.keepass.database.element.PwGroupInterface; +import com.kunzisoft.keepass.database.element.PwGroupV4; import com.kunzisoft.keepass.database.iterator.EntrySearchStringIterator; +import com.kunzisoft.keepass.database.iterator.EntrySearchStringIteratorV4; import com.kunzisoft.keepass.utils.StrUtil; import com.kunzisoft.keepass.utils.UuidUtil; @@ -31,20 +31,20 @@ import java.util.Date; import java.util.List; import java.util.Locale; -public class EntrySearchHandlerV4 extends EntryHandler { +public class EntrySearchHandlerV4 extends NodeHandler { - private List listStorage; + private List listStorage; protected SearchParametersV4 sp; protected Date now; - public EntrySearchHandlerV4(SearchParametersV4 sp, List listStorage) { + public EntrySearchHandlerV4(SearchParametersV4 sp, List listStorage) { this.listStorage = listStorage; this.sp = sp; this.now = new Date(); } @Override - public boolean operate(PwEntryInterface entry) { + public boolean operate(PwEntryV4 entry) { if (sp.respectEntrySearchingDisabled && !entry.isSearchingEnabled()) { return true; } @@ -64,7 +64,7 @@ public class EntrySearchHandlerV4 extends EntryHandler { } if (sp.searchInGroupNames) { - PwGroupInterface parent = entry.getParent(); + PwGroupV4 parent = entry.getParent(); if (parent != null) { String groupName = parent.getTitle(); if (groupName != null) { @@ -88,8 +88,7 @@ public class EntrySearchHandlerV4 extends EntryHandler { return true; } - private boolean searchID(PwEntryInterface e) { - PwEntryV4 entry = (PwEntryV4) e; + private boolean searchID(PwEntryV4 entry) { if (sp.searchInUUIDs) { String hex = UuidUtil.toHexString(entry.getNodeId().getId()); return StrUtil.indexOfIgnoreCase(hex, sp.searchString, Locale.ENGLISH) >= 0; @@ -98,8 +97,8 @@ public class EntrySearchHandlerV4 extends EntryHandler { return false; } - private boolean searchStrings(PwEntryInterface entry, String term) { - EntrySearchStringIterator iter = EntrySearchStringIterator.getInstance(entry, sp); + private boolean searchStrings(PwEntryV4 entry, String term) { + EntrySearchStringIterator iter = new EntrySearchStringIteratorV4(entry, sp); while (iter.hasNext()) { String str = iter.next(); if (str != null && str.length() > 0) { diff --git a/app/src/main/java/com/kunzisoft/keepass/database/search/SearchDbHelper.java b/app/src/main/java/com/kunzisoft/keepass/database/search/SearchDbHelper.java deleted file mode 100644 index 49bf7605d..000000000 --- a/app/src/main/java/com/kunzisoft/keepass/database/search/SearchDbHelper.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft. - * - * This file is part of KeePass DX. - * - * KeePass DX is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * KeePass DX is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with KeePass DX. If not, see . - * - */ -package com.kunzisoft.keepass.database.search; - -import android.content.Context; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; -import com.kunzisoft.keepass.R; -import com.kunzisoft.keepass.database.EntryHandler; -import com.kunzisoft.keepass.database.GroupHandler; -import com.kunzisoft.keepass.database.element.PwDatabase; -import com.kunzisoft.keepass.database.element.PwEntryInterface; -import com.kunzisoft.keepass.database.element.PwGroupInterface; -import com.kunzisoft.keepass.database.iterator.EntrySearchStringIterator; - -import java.util.Iterator; -import java.util.Locale; - -public class SearchDbHelper { - - private final Context mContext; - private int incrementEntry = 0; - - public SearchDbHelper(Context context) { - this.mContext = context; - } - - private boolean omitBackup() { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext); - return prefs.getBoolean(mContext.getString(R.string.omitbackup_key), mContext.getResources().getBoolean(R.bool.omitbackup_default)); - } - - public PwGroupInterface search(PwDatabase pm, String qStr, int max) { - - PwGroupInterface searchGroup = pm.createGroup(); - searchGroup.setTitle("\"" + qStr + "\""); - - // Search all entries - Locale loc = Locale.getDefault(); - String finalQStr = qStr.toLowerCase(loc); - boolean isOmitBackup = omitBackup(); - - - incrementEntry = 0; - PwGroupInterface.doForEachChild(pm.getRootGroup(), - new EntryHandler() { - @Override - public boolean operate(PwEntryInterface entry) { - if (entryContainsString(entry, finalQStr, loc)) { - searchGroup.addChildEntry(entry); - incrementEntry++; - } - // Stop searching when we have max entries - return incrementEntry <= max; - } - }, - new GroupHandler() { - @Override - public boolean operate(PwGroupInterface group) { - if (pm.isGroupSearchable(group, isOmitBackup)) { - return true; - } - return incrementEntry <= max; - } - }); - - return searchGroup; - } - - private boolean entryContainsString(PwEntryInterface entry, String qStr, Locale loc) { - // Search all strings in the entry - Iterator iterator = EntrySearchStringIterator.getInstance(entry); - while (iterator.hasNext()) { - String str = iterator.next(); - if (str != null && str.length() != 0) { - String lower = str.toLowerCase(loc); - if (lower.contains(qStr)) { - return true; - } - } - } - return false; - } -} diff --git a/app/src/main/java/com/kunzisoft/keepass/database/search/SearchDbHelper.kt b/app/src/main/java/com/kunzisoft/keepass/database/search/SearchDbHelper.kt new file mode 100644 index 000000000..70c0d594e --- /dev/null +++ b/app/src/main/java/com/kunzisoft/keepass/database/search/SearchDbHelper.kt @@ -0,0 +1,88 @@ +/* + * Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft. + * + * This file is part of KeePass DX. + * + * KeePass DX is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * KeePass DX is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with KeePass DX. If not, see . + * + */ +package com.kunzisoft.keepass.database.search + +import android.content.Context +import android.preference.PreferenceManager +import com.kunzisoft.keepass.R +import com.kunzisoft.keepass.database.NodeHandler +import com.kunzisoft.keepass.database.element.Database +import com.kunzisoft.keepass.database.element.EntryVersioned +import com.kunzisoft.keepass.database.element.GroupVersioned +import com.kunzisoft.keepass.database.iterator.EntrySearchStringIterator +import java.util.* + +class SearchDbHelper(private val mContext: Context) { + private var incrementEntry = 0 + + private fun omitBackup(): Boolean { + val prefs = PreferenceManager.getDefaultSharedPreferences(mContext) + return prefs.getBoolean(mContext.getString(R.string.omitbackup_key), mContext.resources.getBoolean(R.bool.omitbackup_default)) + } + + fun search(pm: Database, qStr: String, max: Int): GroupVersioned { + + val searchGroup = pm.createGroup() + searchGroup!!.title = "\"" + qStr + "\"" + + // Search all entries + val loc = Locale.getDefault() + val finalQStr = qStr.toLowerCase(loc) + val isOmitBackup = omitBackup() + + + incrementEntry = 0 + pm.rootGroup.doForEachChild( + object : NodeHandler() { + override fun operate(entry: EntryVersioned): Boolean { + if (entryContainsString(entry, finalQStr, loc)) { + searchGroup.addChildEntry(entry) + incrementEntry++ + } + // Stop searching when we have max entries + return incrementEntry <= max + } + }, + object : NodeHandler() { + override fun operate(group: GroupVersioned): Boolean { + return if (pm.isGroupSearchable(group, isOmitBackup)!!) { + true + } else incrementEntry <= max + } + }) + + return searchGroup + } + + private fun entryContainsString(entry: EntryVersioned, qStr: String, loc: Locale): Boolean { + // Search all strings in the entry + val iterator = EntrySearchStringIterator.getInstance(entry) + while (iterator.hasNext()) { + val str = iterator.next() + if (str.isNotEmpty()) { + val lower = str.toLowerCase(loc) + if (lower.contains(qStr)) { + return true + } + } + } + return false + } +} diff --git a/app/src/main/java/com/kunzisoft/keepass/dialogs/GroupEditDialogFragment.java b/app/src/main/java/com/kunzisoft/keepass/dialogs/GroupEditDialogFragment.java index 236098279..354e36f56 100644 --- a/app/src/main/java/com/kunzisoft/keepass/dialogs/GroupEditDialogFragment.java +++ b/app/src/main/java/com/kunzisoft/keepass/dialogs/GroupEditDialogFragment.java @@ -36,7 +36,7 @@ import android.widget.Toast; import com.kunzisoft.keepass.R; import com.kunzisoft.keepass.app.App; import com.kunzisoft.keepass.database.element.Database; -import com.kunzisoft.keepass.database.element.PwGroupInterface; +import com.kunzisoft.keepass.database.element.GroupVersioned; import com.kunzisoft.keepass.database.element.PwIcon; import static com.kunzisoft.keepass.dialogs.GroupEditDialogFragment.EditGroupDialogAction.CREATION; @@ -79,7 +79,7 @@ public class GroupEditDialogFragment extends DialogFragment return fragment; } - public static GroupEditDialogFragment build(PwGroupInterface group) { + public static GroupEditDialogFragment build(GroupVersioned group) { Bundle bundle = new Bundle(); bundle.putString(KEY_NAME, group.getTitle()); bundle.putParcelable(KEY_ICON, group.getIcon()); diff --git a/app/src/main/java/com/kunzisoft/keepass/utils/SprContextV4.java b/app/src/main/java/com/kunzisoft/keepass/utils/SprContextV4.java index fad1e0541..b5450adca 100644 --- a/app/src/main/java/com/kunzisoft/keepass/utils/SprContextV4.java +++ b/app/src/main/java/com/kunzisoft/keepass/utils/SprContextV4.java @@ -20,7 +20,6 @@ package com.kunzisoft.keepass.utils; import com.kunzisoft.keepass.database.element.PwDatabaseV4; -import com.kunzisoft.keepass.database.element.PwEntryInterface; import com.kunzisoft.keepass.database.element.PwEntryV4; import java.util.HashMap; @@ -29,7 +28,7 @@ import java.util.Map; public class SprContextV4 implements Cloneable { public PwDatabaseV4 db; - public PwEntryInterface entry; + public PwEntryV4 entry; public Map refsCache = new HashMap<>(); public SprContextV4(PwDatabaseV4 db, PwEntryV4 entry) { diff --git a/app/src/main/java/com/kunzisoft/keepass/utils/SprEngineV4.java b/app/src/main/java/com/kunzisoft/keepass/utils/SprEngineV4.java index 78bef9cc3..a40c2ac38 100644 --- a/app/src/main/java/com/kunzisoft/keepass/utils/SprEngineV4.java +++ b/app/src/main/java/com/kunzisoft/keepass/utils/SprEngineV4.java @@ -19,19 +19,14 @@ */ package com.kunzisoft.keepass.utils; +import com.kunzisoft.keepass.database.element.PwEntryV4; +import com.kunzisoft.keepass.database.element.PwGroupV4; import com.kunzisoft.keepass.database.element.PwDatabase; import com.kunzisoft.keepass.database.element.PwDatabaseV4; -import com.kunzisoft.keepass.database.element.PwEntryInterface; -import com.kunzisoft.keepass.database.element.PwEntryV4; -import com.kunzisoft.keepass.database.element.PwGroupInterface; import com.kunzisoft.keepass.database.search.EntrySearchHandlerV4; import com.kunzisoft.keepass.database.search.SearchParametersV4; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Locale; +import java.util.*; import java.util.Map.Entry; public class SprEngineV4 { @@ -40,17 +35,17 @@ public class SprEngineV4 { private static final String STR_REF_END = "}"; public class TargetResult { - public PwEntryInterface entry; + public PwEntryV4 entry; public char wanted; - public TargetResult(PwEntryInterface entry, char wanted) { + public TargetResult(PwEntryV4 entry, char wanted) { this.entry = entry; this.wanted = wanted; } } - public String compile(String text, PwEntryInterface entry, PwDatabase database) { - SprContextV4 ctx = new SprContextV4((PwDatabaseV4)database, (PwEntryV4)entry); + public String compile(String text, PwEntryV4 entry, PwDatabase database) { + SprContextV4 ctx = new SprContextV4((PwDatabaseV4)database, entry); return compileInternal(text, ctx, 0); } @@ -80,7 +75,7 @@ public class SprEngineV4 { TargetResult result = findRefTarget(fullRef, ctx); if (result != null) { - PwEntryInterface found = result.entry; + PwEntryV4 found = result.entry; char wanted = result.wanted; if (found != null) { @@ -158,7 +153,7 @@ public class SprEngineV4 { else if (scan == 'O') { sp.searchInOther = true; } else { return null; } - List list = new ArrayList<>(); + List list = new ArrayList<>(); // TODO type parameter searchEntries(ctx.db.getRootGroup(), sp, list); @@ -187,13 +182,13 @@ public class SprEngineV4 { return text; } - private void searchEntries(PwGroupInterface root, SearchParametersV4 sp, List listStorage) { + private void searchEntries(PwGroupV4 root, SearchParametersV4 sp, List listStorage) { if (sp == null) { return; } if (listStorage == null) { return; } List terms = StrUtil.splitSearchTerms(sp.searchString); if (terms.size() <= 1 || sp.regularExpression) { - PwGroupInterface.doForEachChild(root, new EntrySearchHandlerV4(sp, listStorage), null); + root.doForEachChild(new EntrySearchHandlerV4(sp, listStorage), null); return; } @@ -202,9 +197,9 @@ public class SprEngineV4 { Collections.sort(terms, stringLengthComparator); String fullSearch = sp.searchString; - List pg = root.getChildEntries(); + List pg = root.getChildEntries(); for (int i = 0; i < terms.size(); i ++) { - List pgNew = new ArrayList<>(); + List pgNew = new ArrayList<>(); sp.searchString = terms.get(i); @@ -214,14 +209,14 @@ public class SprEngineV4 { negate = sp.searchString.length() > 0; } - if (!PwGroupInterface.doForEachChild(root, new EntrySearchHandlerV4(sp, pgNew), null)) { + if (!root.doForEachChild(new EntrySearchHandlerV4(sp, pgNew), null)) { pg = null; break; } - List complement = new ArrayList<>(); + List complement = new ArrayList<>(); if (negate) { - for (PwEntryInterface entry: pg) { + for (PwEntryV4 entry: pg) { if (!pgNew.contains(entry)) { complement.add(entry); }