This commit is contained in:
J-Jamet
2019-05-03 17:15:53 +02:00
parent e460a4fe4f
commit eabd2d3e4c
60 changed files with 1706 additions and 1411 deletions

View File

@@ -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<PwGroupInterface> groups = pm.getGroups();
List<GroupVersioned> 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;
}

View File

@@ -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);
}

View File

@@ -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());

View File

@@ -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);

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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<BasicViewHolder> {
private static final String TAG = NodeAdapter.class.getName();
private SortedList<PwNodeInterface> nodeSortedList;
private SortedList<NodeVersioned> nodeSortedList;
private Context context;
private LayoutInflater inflater;
@@ -85,17 +76,17 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
this.readOnly = false;
this.isASearchResult = false;
this.nodeSortedList = new SortedList<>(PwNodeInterface.class, new SortedListAdapterCallback<PwNodeInterface>(this) {
@Override public int compare(PwNodeInterface item1, PwNodeInterface item2) {
this.nodeSortedList = new SortedList<>(NodeVersioned.class, new SortedListAdapterCallback<NodeVersioned>(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<BasicViewHolder> {
/**
* 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<BasicViewHolder> {
* 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<BasicViewHolder> {
* 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<BasicViewHolder> {
* @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<BasicViewHolder> {
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<BasicViewHolder> {
@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<BasicViewHolder> {
// 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<BasicViewHolder> {
* 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<BasicViewHolder> {
*/
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<BasicViewHolder> {
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 {

View File

@@ -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()

View File

@@ -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)) {

View File

@@ -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<PwEntryInterface>() {
private void build(GroupVersioned rootGroup) {
/*
rootGroup.doForEachChild(new EntryHandler<EntryVersioned>() {
@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);
*/
}
}

View File

@@ -25,6 +25,6 @@ package com.kunzisoft.keepass.database;
* @author bpellin
*
*/
public abstract class GroupHandler<T> {
public abstract class NodeHandler<T> {
public abstract boolean operate(T group);
}

View File

@@ -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<PwNodeInterface> getNodeComparator(boolean ascending, boolean groupsBefore) {
public Comparator<NodeVersioned> 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<PwNodeInterface> {
private static abstract class NodeComparator implements Comparator<NodeVersioned> {
boolean ascending;
boolean groupsBefore;
@@ -56,19 +56,19 @@ public enum SortNodeEnum {
this.groupsBefore = groupsBefore;
}
int compareWith(Comparator<PwGroupInterface> comparatorGroup,
Comparator<PwEntryInterface> comparatorEntry,
PwNodeInterface object1,
PwNodeInterface object2,
int compareWith(Comparator<GroupVersioned> comparatorGroup,
Comparator<EntryVersioned> 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<PwGroupInterface> {
public static class GroupNameComparator extends AscendingComparator<GroupVersioned> {
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<PwGroupInterface> {
public static class GroupCreationComparator extends AscendingComparator<GroupVersioned> {
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<PwGroupInterface> {
public static class GroupLastModificationComparator extends AscendingComparator<GroupVersioned> {
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<PwGroupInterface> {
public static class GroupLastAccessComparator extends AscendingComparator<GroupVersioned> {
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<PwEntryInterface> {
public static class EntryNameComparator extends AscendingComparator<EntryVersioned> {
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<PwEntryInterface> {
public static class EntryCreationComparator extends AscendingComparator<EntryVersioned> {
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<PwEntryInterface> {
public static class EntryLastModificationComparator extends AscendingComparator<EntryVersioned> {
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<PwEntryInterface> {
public static class EntryLastAccessComparator extends AscendingComparator<EntryVersioned> {
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;

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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 {

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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<PwEntryV extends PwEntryInterface> extends MatrixCursor {
public abstract class EntryCursor<PwEntryV extends PwEntry> extends MatrixCursor {
protected long entryId;
public static final String _ID = BaseColumns._ID;

View File

@@ -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<PwEntryInterface>() {
public void deleteGroup(GroupVersioned group) {
group.doForEachChildAndForIt(
new NodeHandler<EntryVersioned>() {
@Override
public boolean operate(PwEntryInterface entry) {
public boolean operate(EntryVersioned entry) {
deleteEntry(entry);
return true;
}
},
new GroupHandler<PwGroupInterface>() {
new NodeHandler<GroupVersioned>() {
@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);
}
}
}

View File

@@ -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<GroupVersioned> {
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<UUID>?
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<EntryVersioned> {
override fun createFromParcel(parcel: Parcel): EntryVersioned {
return EntryVersioned(parcel)
}
override fun newArray(size: Int): Array<EntryVersioned?> {
return arrayOfNulls(size)
}
val PMS_TAN_ENTRY = "<TAN>"
/**
* {@inheritDoc}
* Get the display title from an entry, <br></br>
* [.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
}
}
}
}

View File

@@ -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<GroupVersioned, EntryVersioned> {
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<GroupVersioned> {
override fun createFromParcel(parcel: Parcel): GroupVersioned {
return GroupVersioned(parcel)
}
override fun newArray(size: Int): Array<GroupVersioned?> {
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<GroupVersioned> {
return ArrayList() // TODO if needed
}
override fun getChildEntries(): MutableList<EntryVersioned> {
val children = ArrayList<EntryVersioned>()
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<NodeVersioned>? {
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<Int>?
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<UUID>?
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
}
}

View File

@@ -0,0 +1,12 @@
package com.kunzisoft.keepass.database.element
interface NodeVersioned: PwNodeInterface<GroupVersioned>
/**
* Type of available Nodes
*/
enum class Type {
GROUP, ENTRY
}

View File

@@ -37,7 +37,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.UUID;
public abstract class PwDatabase {
public abstract class PwDatabase<Group extends PwGroup, Entry extends PwEntry> {
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<PwNodeId, PwGroupInterface> groupIndexes = new LinkedHashMap<>();
protected LinkedHashMap<PwNodeId, PwEntryInterface> entryIndexes = new LinkedHashMap<>();
protected LinkedHashMap<PwNodeId, Group> groupIndexes = new LinkedHashMap<>();
protected LinkedHashMap<PwNodeId, Entry> 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<PwGroupInterface> getGroupIndexes() {
public Collection<Group> getGroupIndexes() {
return groupIndexes.values();
}
public void setGroupIndexes(List<PwGroupInterface> groupList) {
public void setGroupIndexes(List<Group> 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<PwEntryInterface> getEntryIndexes() {
public boolean isEntryIdUsed(PwNodeId id) {
return entryIndexes.containsKey(id);
}
public Collection<Entry> 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;
}
}

View File

@@ -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 <nao@phoneid.org>
* @author Bill Zwicky <wrzwicky@pobox.com>
* @author Dominik Reichl <dominik.reichl@t-online.de>
*/
public class PwDatabaseV3 extends PwDatabase {
public class PwDatabaseV3 extends PwDatabase<PwGroupV3, PwEntryV3> {
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<PwGroupInterface> getRootGroups() {
List<PwGroupInterface> kids = new ArrayList<>();
for (Map.Entry<PwNodeId, PwGroupInterface> grp : groupIndexes.entrySet()) {
if (grp.getValue().getLevel() == 0)
kids.add(grp.getValue());
public List<PwGroupV3> getRootGroups() {
List<PwGroupV3> kids = new ArrayList<>();
for (Map.Entry<PwNodeId, PwGroupV3> 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;
}

View File

@@ -43,13 +43,15 @@ import java.security.NoSuchAlgorithmException;
import java.util.*;
public class PwDatabaseV4 extends PwDatabase {
public class PwDatabaseV4 extends PwDatabase<PwGroupV4, PwEntryV4> {
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<PwEntryInterface>() {
@Override
public boolean operate(PwEntryInterface entry) {
addEntryIndex(entry);
return true;
}
},
new GroupHandler<PwGroupInterface>() {
@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<PwEntryV4>() {
@Override
public boolean operate(PwEntryV4 entry) {
addEntryIndex(entry);
return true;
}
},
new NodeHandler<PwGroupV4>() {
@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;
}

View File

@@ -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<PwGroupInterface> {
private class GroupHasCustomData extends NodeHandler<PwGroupV4> {
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<PwEntryInterface> {
private class EntryHasCustomData extends NodeHandler<PwEntryV4> {
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;
}

View File

@@ -0,0 +1,17 @@
package com.kunzisoft.keepass.database.element
import android.os.Parcel
import java.util.*
abstract class PwEntry
<
ParentGroup: PwGroupInterface<ParentGroup, Entry>,
Entry: PwEntryInterface<ParentGroup>
>
: PwNode<UUID, ParentGroup, Entry>, PwEntryInterface<ParentGroup> {
constructor() : super()
constructor(parcel: Parcel) : super(parcel)
}

View File

@@ -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 = "<TAN>";
static boolean isTan(PwEntryInterface entry) {
return entry.getTitle().equals(PMS_TAN_ENTRY)
&& (entry.getUsername().length() > 0);
}
/**
* {@inheritDoc}
* Get the display title from an entry, <br />
* {@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());
}
}

View File

@@ -0,0 +1,14 @@
package com.kunzisoft.keepass.database.element
interface PwEntryInterface<ParentGroup> : PwNodeInterface<ParentGroup> {
var username: String
var password: String
var url: String
var notes: String
fun touchLocation()
}

View File

@@ -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 <dominik.reichl@t-online.de>
* @author Jeremy Jamet <jeremy.jamet@kunzisoft.com>
*/
public class PwEntryV3 extends PwNode<UUID> implements PwEntryInterface {
public class PwEntryV3 extends PwEntry<PwGroupV3, PwEntryV3> {
/** 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<UUID> 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<UUID> 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<UUID> 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<UUID> 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<UUID> 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() {}
}

View File

@@ -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<UUID> implements ITimeLogger, PwEntryInterface {
public class PwEntryV4 extends PwEntry<PwGroupV4, PwEntryV4> 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<UUID> 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<UUID> 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<UUID> 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<UUID> implements ITimeLogger, PwEntryInte
fields.putProtectedString(label, value);
}
@Override
public void removeAllCustomFields() {
fields.removeAllCustomFields();
}
@@ -458,7 +455,7 @@ public class PwEntryV4 extends PwNode<UUID> 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<UUID> 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;
}

View File

@@ -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<Id> extends PwNode<Id> implements PwGroupInterface {
private String title = "";
transient private List<PwGroupInterface> childGroups = new ArrayList<>();
transient private List<PwEntryInterface> 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<PwGroupInterface> getChildGroups() {
return childGroups;
}
@Override
public List<PwEntryInterface> 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<PwNodeInterface> getChildrenWithoutMetastream() {
List<PwNodeInterface> children = new ArrayList<>(childGroups);
for(PwEntryInterface child : childEntries) {
if (!child.isMetaStream())
children.add(child);
}
return children;
}
@Override
public String toString() {
return getTitle();
}
}

View File

@@ -0,0 +1,67 @@
package com.kunzisoft.keepass.database.element
import android.os.Parcel
import java.util.*
abstract class PwGroup
<
Id,
Group: PwGroupInterface<Group, Entry>,
Entry: PwEntryInterface<Group>
>
: PwNode<Id, Group, Entry>, PwGroupInterface<Group, Entry> {
private var titleGroup = ""
@Transient
private val childGroups = ArrayList<Group>()
@Transient
private val childEntries = ArrayList<Entry>()
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<Id, Group, Entry>) {
super.updateWith(source)
titleGroup = source.titleGroup
}
override var title: String
get() = titleGroup
set(value) { titleGroup = value }
override fun getChildGroups(): MutableList<Group> {
return childGroups
}
override fun getChildEntries(): MutableList<Entry> {
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
}
}

View File

@@ -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<PwGroupInterface> getChildGroups();
List<PwEntryInterface> 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<PwNodeInterface> getChildrenWithoutMetastream();
boolean allowAddEntryIfIsRoot();
PwGroupInterface duplicate();
static void doForEachChildAndForRoot(@NonNull PwGroupInterface root,
EntryHandler<PwEntryInterface> entryHandler,
GroupHandler<PwGroupInterface> groupHandler) {
doForEachChild(root, entryHandler, groupHandler);
groupHandler.operate(root);
}
static boolean doForEachChild(@NonNull PwGroupInterface root,
EntryHandler<PwEntryInterface> entryHandler,
GroupHandler<PwGroupInterface> 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;
}
}

View File

@@ -0,0 +1,38 @@
package com.kunzisoft.keepass.database.element
import com.kunzisoft.keepass.database.NodeHandler
interface PwGroupInterface<Group: PwGroupInterface<Group, Entry>, Entry> : PwNodeInterface<Group> {
fun getChildGroups(): MutableList<Group>
fun getChildEntries(): MutableList<Entry>
fun addChildGroup(group: Group)
fun addChildEntry(entry: Entry)
fun removeChildGroup(group: Group)
fun removeChildEntry(entry: Entry)
fun allowAddEntryIfIsRoot(): Boolean
fun doForEachChildAndForIt(entryHandler: NodeHandler<Entry>,
groupHandler: NodeHandler<Group>) {
doForEachChild(entryHandler, groupHandler)
groupHandler.operate(this as Group)
}
fun doForEachChild(entryHandler: NodeHandler<Entry>,
groupHandler: NodeHandler<Group>?): 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
}
}

View File

@@ -22,7 +22,7 @@ package com.kunzisoft.keepass.database.element;
import android.os.Parcel;
public class PwGroupV3 extends PwGroup<Integer> {
public class PwGroupV3 extends PwGroup<Integer, PwGroupV3, PwEntryV3> {
private int level = 0; // short
/** Used by KeePass internally, don't use */
@@ -43,6 +43,11 @@ public class PwGroupV3 extends PwGroup<Integer> {
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<Integer> {
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;
}

View File

@@ -26,7 +26,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class PwGroupV4 extends PwGroup<UUID> implements ITimeLogger {
public class PwGroupV4 extends PwGroup<UUID, PwGroupV4, PwEntryV4> implements ITimeLogger {
public static final boolean DEFAULT_SEARCHING_ENABLED = true;
@@ -68,6 +68,11 @@ public class PwGroupV4 extends PwGroup<UUID> 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<UUID> 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<UUID> 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<UUID> 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<UUID> 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;
}

View File

@@ -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<IdType> implements PwNodeInterface, Parcelable, Cloneable {
public abstract class PwNode
<
IdType,
Parent extends PwGroupInterface<Parent, Entry>,
Entry extends PwEntryInterface<Parent>
>
implements PwNodeInterface<Parent>, Parcelable {
private PwNodeId<IdType> 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<IdType> 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<IdType> implements PwNodeInterface, Parcelable, Clo
return 0;
}
protected void updateWith(PwNode source) {
protected void updateWith(PwNode<IdType, Parent, Entry> source) {
this.nodeId = source.nodeId;
this.parent = source.parent;
this.icon = source.icon;
@@ -114,13 +107,11 @@ public abstract class PwNode<IdType> implements PwNodeInterface, Parcelable, Clo
return getNodeId().getId();
}
@Override
public PwNodeId<IdType> getNodeId() {
return nodeId;
}
@Override
public void setNodeId(PwNodeId id) {
public void setNodeId(PwNodeId<IdType> id) {
this.nodeId = id;
}
@@ -136,18 +127,13 @@ public abstract class PwNode<IdType> 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<IdType> 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<IdType> implements PwNodeInterface, Parcelable, Clo
setLastModificationTime(now);
}
PwGroupInterface parent = getParent();
Parent parent = getParent();
if (touchParents && parent != null) {
parent.touch(modified, true);
}

View File

@@ -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
}
}

View File

@@ -0,0 +1,32 @@
package com.kunzisoft.keepass.database.element
import android.os.Parcelable
import com.kunzisoft.keepass.database.SmallTimeInterface
interface PwNodeInterface<ParentGroup> : 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
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*
*/
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<String> {
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.");
}
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.database;
package com.kunzisoft.keepass.database.iterator
import com.kunzisoft.keepass.database.element.EntryVersioned
abstract class EntrySearchStringIterator : Iterator<String> {
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<T extends PwEntryInterface> {
public abstract boolean operate(T entry);
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*
*/
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<Entry<String, ProtectedString>> 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<String, ProtectedString> 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;
}
}
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*
*/
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<Entry<String, ProtectedString>>? = 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
}
}
}

View File

@@ -226,51 +226,11 @@ public class ImporterV3 extends Importer<PwDatabaseV3> {
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

View File

@@ -173,7 +173,7 @@ public class ImporterV4 extends Importer<PwDatabaseV4> {
ReadXmlStreamed(isXml);
mDatabase.populateNodeIndex();
mDatabase.populateNodesIndexes();
return mDatabase;
}
@@ -291,13 +291,12 @@ public class ImporterV4 extends Importer<PwDatabaseV4> {
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 {

View File

@@ -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<PwDbHeaderV3> {
@@ -215,8 +202,8 @@ public class PwDbV3Output extends PwDbOutput<PwDbHeaderV3> {
}
// 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<PwDbHeaderV3> {
}
// 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<PwDbHeaderV3> {
}
private void sortGroupsForOutput() {
List<PwGroupInterface> groupList = new ArrayList<>();
List<PwGroupV3> 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<PwGroupInterface> groupList) {
private void sortGroup(PwGroupV3 group, List<PwGroupV3> groupList) {
// Add current tree
groupList.add(group);
// Recurse over children
for (PwGroupInterface childGroup : group.getChildGroups()) {
for (PwGroupV3 childGroup : group.getChildGroups()) {
sortGroup(childGroup, groupList);
}
}

View File

@@ -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<PwDbHeaderV4> {
private static final String TAG = PwDbV4Output.class.getName();
@@ -155,18 +132,16 @@ public class PwDbV4Output extends PwDbOutput<PwDbHeaderV4> {
writeMeta();
PwGroupV4 root = (PwGroupV4) mPM.getRootGroup();
PwGroupV4 root = mPM.getRootGroup();
xml.startTag(null, PwDatabaseV4XML.ElemRoot);
startGroup(root);
Stack<PwGroupV4> groupStack = new Stack<>();
groupStack.push(root);
if (!PwGroupInterface.doForEachChild(root,
new EntryHandler<PwEntryInterface>() {
if (!root.doForEachChild(
new NodeHandler<PwEntryV4>() {
@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<PwDbHeaderV4> {
return true;
}
},
new GroupHandler<PwGroupInterface>() {
new NodeHandler<PwGroupV4>() {
@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<PwDbHeaderV4> {
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());

View File

@@ -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);

View File

@@ -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<PwEntryInterface> {
public class EntrySearchHandlerV4 extends NodeHandler<PwEntryV4> {
private List<PwEntryInterface> listStorage;
private List<PwEntryV4> listStorage;
protected SearchParametersV4 sp;
protected Date now;
public EntrySearchHandlerV4(SearchParametersV4 sp, List<PwEntryInterface> listStorage) {
public EntrySearchHandlerV4(SearchParametersV4 sp, List<PwEntryV4> 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<PwEntryInterface> {
}
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<PwEntryInterface> {
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<PwEntryInterface> {
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) {

View File

@@ -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 <http://www.gnu.org/licenses/>.
*
*/
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<PwEntryInterface>() {
@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<PwGroupInterface>() {
@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<String> 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;
}
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*
*/
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<EntryVersioned>() {
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<GroupVersioned>() {
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
}
}

View File

@@ -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());

View File

@@ -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<String, String> refsCache = new HashMap<>();
public SprContextV4(PwDatabaseV4 db, PwEntryV4 entry) {

View File

@@ -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<PwEntryInterface> list = new ArrayList<>();
List<PwEntryV4> 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<PwEntryInterface> listStorage) {
private void searchEntries(PwGroupV4 root, SearchParametersV4 sp, List<PwEntryV4> listStorage) {
if (sp == null) { return; }
if (listStorage == null) { return; }
List<String> 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<PwEntryInterface> pg = root.getChildEntries();
List<PwEntryV4> pg = root.getChildEntries();
for (int i = 0; i < terms.size(); i ++) {
List<PwEntryInterface> pgNew = new ArrayList<>();
List<PwEntryV4> 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<PwEntryInterface> complement = new ArrayList<>();
List<PwEntryV4> complement = new ArrayList<>();
if (negate) {
for (PwEntryInterface entry: pg) {
for (PwEntryV4 entry: pg) {
if (!pgNew.contains(entry)) {
complement.add(entry);
}