mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Refactor
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.kunzisoft.keepass.database.element
|
||||
|
||||
interface NodeVersioned: PwNodeInterface<GroupVersioned>
|
||||
|
||||
/**
|
||||
* Type of available Nodes
|
||||
*/
|
||||
enum class Type {
|
||||
GROUP, ENTRY
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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() {}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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.");
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user