mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Kotlinized PwNode PwEntry PwGroup
This commit is contained in:
@@ -45,7 +45,7 @@ public class PwEntryTestV4 extends TestCase {
|
||||
entry.getAutoType().obfuscationOptions = 123412432109L;
|
||||
entry.getAutoType().put("key", "value");
|
||||
|
||||
entry.setBackgroupColor("blue");
|
||||
entry.setBackgroundColor("blue");
|
||||
entry.putProtectedBinary("key1", new ProtectedBinary(false, new byte[] {0,1}));
|
||||
entry.setIconCustom(new PwIconCustom(UUID.randomUUID(), new byte[0]));
|
||||
entry.setForegroundColor("red");
|
||||
|
||||
@@ -21,6 +21,7 @@ package com.kunzisoft.keepass.database;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.kunzisoft.keepass.database.security.ProtectedString;
|
||||
import com.kunzisoft.keepass.utils.MemUtil;
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ public class EntryCursorV3 extends EntryCursor<PwEntryV3> {
|
||||
|
||||
public void addEntry(PwEntryV3 entry) {
|
||||
addRow(new Object[] {entryId,
|
||||
entry.getNodeId().getId().getMostSignificantBits(),
|
||||
entry.getNodeId().getId().getLeastSignificantBits(),
|
||||
entry.getId().getMostSignificantBits(),
|
||||
entry.getId().getLeastSignificantBits(),
|
||||
entry.getTitle(),
|
||||
entry.getIcon().getIconId(),
|
||||
PwDatabase.UUID_ZERO.getMostSignificantBits(),
|
||||
|
||||
@@ -17,8 +17,8 @@ public class EntryCursorV4 extends EntryCursor<PwEntryV4> {
|
||||
|
||||
public void addEntry(PwEntryV4 entry) {
|
||||
addRow(new Object[] {entryId,
|
||||
entry.getNodeId().getId().getMostSignificantBits(),
|
||||
entry.getNodeId().getId().getLeastSignificantBits(),
|
||||
entry.getId().getMostSignificantBits(),
|
||||
entry.getId().getLeastSignificantBits(),
|
||||
entry.getTitle(),
|
||||
entry.getIcon().getIconId(),
|
||||
entry.getIconCustom().getUuid().getMostSignificantBits(),
|
||||
|
||||
@@ -64,9 +64,9 @@ class Database {
|
||||
|
||||
var loaded = false
|
||||
|
||||
val iconFactory: PwIconFactory?
|
||||
val iconFactory: PwIconFactory
|
||||
get() {
|
||||
return pwDatabaseV3?.getIconFactory() ?: pwDatabaseV4?.getIconFactory()
|
||||
return pwDatabaseV3?.getIconFactory() ?: pwDatabaseV4?.getIconFactory() ?: PwIconFactory()
|
||||
}
|
||||
|
||||
val name: String
|
||||
@@ -189,7 +189,7 @@ class Database {
|
||||
val databaseV4 = PwDatabaseV4()
|
||||
val groupV4 = databaseV4.createGroup()
|
||||
groupV4.title = dbNameFromPath(databasePath)
|
||||
groupV4.setIconStandard(databaseV4.getIconFactory().folderIcon)
|
||||
groupV4.icon = databaseV4.getIconFactory().folderIcon
|
||||
databaseV4.rootGroup = groupV4
|
||||
setDatabaseV4(databaseV4)
|
||||
}
|
||||
@@ -499,7 +499,14 @@ class Database {
|
||||
}
|
||||
|
||||
fun createEntry(): EntryVersioned? {
|
||||
pwDatabaseV3 ?: pwDatabaseV4?.let { database ->
|
||||
pwDatabaseV3?.let { database ->
|
||||
return EntryVersioned(database.createEntry()).apply {
|
||||
database.newEntryId()?.let {
|
||||
nodeId = it
|
||||
}
|
||||
}
|
||||
}
|
||||
pwDatabaseV4?.let { database ->
|
||||
return EntryVersioned(database.createEntry()).apply {
|
||||
database.newEntryId()?.let {
|
||||
nodeId = it
|
||||
@@ -511,7 +518,14 @@ class Database {
|
||||
}
|
||||
|
||||
fun createGroup(): GroupVersioned? {
|
||||
pwDatabaseV3 ?: pwDatabaseV4?.let { database ->
|
||||
pwDatabaseV3?.let { database ->
|
||||
return GroupVersioned(database.createGroup()).apply {
|
||||
database.newGroupId()?.let {
|
||||
setNodeId(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
pwDatabaseV4?.let { database ->
|
||||
return GroupVersioned(database.createGroup()).apply {
|
||||
database.newGroupId()?.let {
|
||||
setNodeId(it)
|
||||
@@ -545,21 +559,25 @@ class Database {
|
||||
fun addEntryTo(entry: EntryVersioned, parent: GroupVersioned) {
|
||||
pwDatabaseV3?.addEntryTo(entry.pwEntryV3, parent.pwGroupV3)
|
||||
pwDatabaseV4?.addEntryTo(entry.pwEntryV4, parent.pwGroupV4)
|
||||
entry.afterAssignNewParent()
|
||||
}
|
||||
|
||||
fun removeEntryFrom(entry: EntryVersioned, parent: GroupVersioned) {
|
||||
pwDatabaseV3?.removeEntryFrom(entry.pwEntryV3, parent.pwGroupV3)
|
||||
pwDatabaseV4?.removeEntryFrom(entry.pwEntryV4, parent.pwGroupV4)
|
||||
entry.afterAssignNewParent()
|
||||
}
|
||||
|
||||
fun addGroupTo(group: GroupVersioned, parent: GroupVersioned) {
|
||||
pwDatabaseV3?.addGroupTo(group.pwGroupV3, parent.pwGroupV3)
|
||||
pwDatabaseV4?.addGroupTo(group.pwGroupV4, parent.pwGroupV4)
|
||||
group.afterAssignNewParent()
|
||||
}
|
||||
|
||||
fun removeGroupFrom(group: GroupVersioned, parent: GroupVersioned) {
|
||||
pwDatabaseV3?.removeGroupFrom(group.pwGroupV3, parent.pwGroupV3)
|
||||
pwDatabaseV4?.removeGroupFrom(group.pwGroupV4, parent.pwGroupV4)
|
||||
group.afterAssignNewParent()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,8 +15,12 @@ class EntryVersioned : NodeVersioned, PwEntryInterface<GroupVersioned> {
|
||||
private set
|
||||
|
||||
fun updateWith(entry: EntryVersioned) {
|
||||
this.pwEntryV3?.updateWith(entry.pwEntryV3)
|
||||
this.pwEntryV4?.updateWith(entry.pwEntryV4)
|
||||
entry.pwEntryV3?.let {
|
||||
this.pwEntryV3?.updateWith(it)
|
||||
}
|
||||
entry.pwEntryV4?.let {
|
||||
this.pwEntryV4?.updateWith(it)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,7 +75,16 @@ class EntryVersioned : NodeVersioned, PwEntryInterface<GroupVersioned> {
|
||||
}
|
||||
|
||||
override var icon: PwIcon
|
||||
get() = pwEntryV3?.icon ?: pwEntryV4?.icon ?: PwIconStandard()
|
||||
get() {
|
||||
var iconGet: PwIcon? = pwEntryV3?.icon
|
||||
if (iconGet == null)
|
||||
iconGet = pwEntryV4?.iconCustom
|
||||
if (iconGet == null || iconGet.isUnknown)
|
||||
iconGet = pwEntryV4?.icon
|
||||
if (iconGet == null)
|
||||
PwIconStandard()
|
||||
return iconGet!!
|
||||
}
|
||||
set(value) {
|
||||
pwEntryV3?.icon = value
|
||||
pwEntryV4?.icon = value
|
||||
@@ -99,13 +112,24 @@ class EntryVersioned : NodeVersioned, PwEntryInterface<GroupVersioned> {
|
||||
return pwEntryV3?.containsParent() ?: pwEntryV4?.containsParent() ?: false
|
||||
}
|
||||
|
||||
override fun afterAssignNewParent() {
|
||||
pwEntryV4?.afterChangeParent()
|
||||
}
|
||||
|
||||
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
|
||||
var contained: Boolean? = false
|
||||
container.pwGroupV3?.let {
|
||||
contained = pwEntryV3?.isContainedIn(it)
|
||||
}
|
||||
container.pwGroupV4?.let {
|
||||
contained = pwEntryV4?.isContainedIn(it)
|
||||
}
|
||||
return contained ?: false
|
||||
}
|
||||
|
||||
override val isSearchingEnabled: Boolean
|
||||
@@ -174,11 +198,6 @@ class EntryVersioned : NodeVersioned, PwEntryInterface<GroupVersioned> {
|
||||
pwEntryV4?.notes = value
|
||||
}
|
||||
|
||||
override fun touchLocation() {
|
||||
pwEntryV3?.touchLocation()
|
||||
pwEntryV4?.touchLocation()
|
||||
}
|
||||
|
||||
private fun isTan(): Boolean {
|
||||
return title == PMS_TAN_ENTRY && username.isNotEmpty()
|
||||
}
|
||||
@@ -210,6 +229,12 @@ class EntryVersioned : NodeVersioned, PwEntryInterface<GroupVersioned> {
|
||||
------------
|
||||
*/
|
||||
|
||||
var iconCustom: PwIconCustom
|
||||
get() = pwEntryV4?.iconCustom ?: PwIconCustom.ZERO
|
||||
set(value) {
|
||||
pwEntryV4?.iconCustom = value
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve extra fields to show, key is the label, value is the value of field
|
||||
* @return Map of label/value
|
||||
@@ -308,7 +333,7 @@ class EntryVersioned : NodeVersioned, PwEntryInterface<GroupVersioned> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
|
||||
val PMS_TAN_ENTRY = "<TAN>"
|
||||
const val PMS_TAN_ENTRY = "<TAN>"
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
|
||||
@@ -13,8 +13,12 @@ class GroupVersioned : NodeVersioned, PwGroupInterface<GroupVersioned, EntryVers
|
||||
private set
|
||||
|
||||
fun updateWith(group: GroupVersioned) {
|
||||
this.pwGroupV3?.updateWith(group.pwGroupV3)
|
||||
this.pwGroupV4?.updateWith(group.pwGroupV4)
|
||||
group.pwGroupV3?.let {
|
||||
this.pwGroupV3?.updateWith(it)
|
||||
}
|
||||
group.pwGroupV4?.let {
|
||||
this.pwGroupV4?.updateWith(it)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,13 +109,25 @@ class GroupVersioned : NodeVersioned, PwGroupInterface<GroupVersioned, EntryVers
|
||||
return pwGroupV3?.containsParent() ?: pwGroupV4?.containsParent() ?: false
|
||||
}
|
||||
|
||||
override fun afterAssignNewParent() {
|
||||
pwGroupV3?.afterAssignNewParent()
|
||||
pwGroupV4?.afterAssignNewParent()
|
||||
}
|
||||
|
||||
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
|
||||
var contained: Boolean? = null
|
||||
container.pwGroupV3?.let {
|
||||
contained = pwGroupV3?.isContainedIn(it)
|
||||
}
|
||||
container.pwGroupV4?.let {
|
||||
contained = pwGroupV4?.isContainedIn(it)
|
||||
}
|
||||
return contained ?: false
|
||||
}
|
||||
|
||||
override val isSearchingEnabled: Boolean
|
||||
@@ -268,10 +284,6 @@ class GroupVersioned : NodeVersioned, PwGroupInterface<GroupVersioned, EntryVers
|
||||
pwGroupV4?.nodeId = id
|
||||
}
|
||||
|
||||
fun setIconStandard(icon: PwIconStandard) {
|
||||
pwGroupV4?.setIconStandard(icon)
|
||||
}
|
||||
|
||||
fun setEnableAutoType(enableAutoType: Boolean?) {
|
||||
pwGroupV4?.enableAutoType = enableAutoType
|
||||
}
|
||||
|
||||
@@ -529,13 +529,13 @@ public class PwDatabaseV4 extends PwDatabase<PwGroupV4, PwEntryV4> {
|
||||
|
||||
PwGroupV4 recycleBin = createGroup();
|
||||
recycleBin.setTitle(RECYCLEBIN_NAME);
|
||||
recycleBin.setIconStandard(iconFactory.getTrashIcon());
|
||||
recycleBin.setIcon(iconFactory.getTrashIcon());
|
||||
recycleBin.setEnableAutoType(false);
|
||||
recycleBin.setEnableSearching(false);
|
||||
recycleBin.setExpanded(false);
|
||||
addGroupTo(recycleBin, rootGroup);
|
||||
|
||||
recycleBinUUID = recycleBin.getNodeId().getId();
|
||||
recycleBinUUID = recycleBin.getId();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -601,7 +601,7 @@ public class PwDatabaseV4 extends PwDatabase<PwGroupV4, PwEntryV4> {
|
||||
|
||||
addGroupTo(group, getRecycleBin());
|
||||
|
||||
// TODO ? group.touchLocation();
|
||||
// TODO ? group.afterChangeParent();
|
||||
}
|
||||
|
||||
public void recycle(PwEntryV4 entry) {
|
||||
@@ -611,7 +611,7 @@ public class PwDatabaseV4 extends PwDatabase<PwGroupV4, PwEntryV4> {
|
||||
|
||||
addEntryTo(entry, getRecycleBin());
|
||||
|
||||
entry.touchLocation();
|
||||
entry.afterChangeParent();
|
||||
}
|
||||
|
||||
public void undoRecycle(PwGroupV4 group, PwGroupV4 origParent) {
|
||||
@@ -639,13 +639,13 @@ public class PwDatabaseV4 extends PwDatabase<PwGroupV4, PwEntryV4> {
|
||||
@Override
|
||||
public void removeEntryFrom(PwEntryV4 entryToRemove, PwGroupV4 parent) {
|
||||
super.removeEntryFrom(entryToRemove, parent);
|
||||
deletedObjects.add(new PwDeletedObject(entryToRemove.getNodeId().getId()));
|
||||
deletedObjects.add(new PwDeletedObject(entryToRemove.getId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undoDeleteEntryFrom(PwEntryV4 entry, PwGroupV4 origParent) {
|
||||
super.undoDeleteEntryFrom(entry, origParent);
|
||||
deletedObjects.remove(new PwDeletedObject(entry.getNodeId().getId()));
|
||||
deletedObjects.remove(new PwDeletedObject(entry.getId()));
|
||||
}
|
||||
|
||||
public PwGroupV4 getRecycleBin() { // TODO delete recycle bin preference
|
||||
|
||||
@@ -9,6 +9,4 @@ interface PwEntryInterface<ParentGroup> : PwNodeInterface<ParentGroup> {
|
||||
var url: String
|
||||
|
||||
var notes: String
|
||||
|
||||
fun touchLocation()
|
||||
}
|
||||
|
||||
@@ -1,299 +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/>.
|
||||
*
|
||||
|
||||
This file was derived from
|
||||
|
||||
Copyright 2007 Naomaru Itoi <nao@phoneid.org>
|
||||
|
||||
This file was derived from
|
||||
|
||||
Java clone of KeePass - A KeePass file viewer for Java
|
||||
Copyright 2006 Bill Zwicky <billzwicky@users.sourceforge.net>
|
||||
|
||||
This program 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; version 2
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package com.kunzisoft.keepass.database.element;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
|
||||
|
||||
/**
|
||||
* Structure containing information about one entry.
|
||||
*
|
||||
* <PRE>
|
||||
* One entry: [FIELDTYPE(FT)][FIELDSIZE(FS)][FIELDDATA(FD)]
|
||||
* [FT+FS+(FD)][FT+FS+(FD)][FT+FS+(FD)][FT+FS+(FD)][FT+FS+(FD)]...
|
||||
*
|
||||
* [ 2 bytes] FIELDTYPE
|
||||
* [ 4 bytes] FIELDSIZE, size of FIELDDATA in bytes
|
||||
* [ n bytes] FIELDDATA, n = FIELDSIZE
|
||||
*
|
||||
* Notes:
|
||||
* - Strings are stored in UTF-8 encoded form and are null-terminated.
|
||||
* - FIELDTYPE can be one of the FT_ constants.
|
||||
* </PRE>
|
||||
*
|
||||
* @author Naomaru Itoi <nao@phoneid.org>
|
||||
* @author Bill Zwicky <wrzwicky@pobox.com>
|
||||
* @author Dominik Reichl <dominik.reichl@t-online.de>
|
||||
* @author Jeremy Jamet <jeremy.jamet@kunzisoft.com>
|
||||
*/
|
||||
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";
|
||||
private static final String PMS_ID_TITLE = "Meta-Info";
|
||||
private static final String PMS_ID_USER = "SYSTEM";
|
||||
private static final String PMS_ID_URL = "$";
|
||||
|
||||
private String title = "";
|
||||
private String username = "";
|
||||
private byte[] password = new byte[0];
|
||||
private String url = "";
|
||||
private String additional = "";
|
||||
/** A string describing what is in pBinaryData */
|
||||
private String binaryDesc = "";
|
||||
private byte[] binaryData = new byte[0];
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected PwNodeId<UUID> initNodeId() {
|
||||
return new PwNodeIdUUID();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected PwNodeId<UUID> copyNodeId(@NonNull PwNodeId<UUID> nodeId) {
|
||||
return new PwNodeIdUUID(nodeId.getId());
|
||||
}
|
||||
|
||||
public PwEntryV3() {
|
||||
super();
|
||||
}
|
||||
|
||||
public PwEntryV3(Parcel parcel) {
|
||||
super(parcel);
|
||||
title = parcel.readString();
|
||||
username = parcel.readString();
|
||||
parcel.readByteArray(password);
|
||||
url = parcel.readString();
|
||||
additional = parcel.readString();
|
||||
binaryDesc = parcel.readString();
|
||||
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);
|
||||
dest.writeString(title);
|
||||
dest.writeString(username);
|
||||
dest.writeByteArray(password);
|
||||
dest.writeString(url);
|
||||
dest.writeString(additional);
|
||||
dest.writeString(binaryDesc);
|
||||
dest.writeByteArray(binaryData);
|
||||
}
|
||||
|
||||
public static final Creator<PwEntryV3> CREATOR = new Creator<PwEntryV3>() {
|
||||
@Override
|
||||
public PwEntryV3 createFromParcel(Parcel in) {
|
||||
return new PwEntryV3(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PwEntryV3[] newArray(int size) {
|
||||
return new PwEntryV3[size];
|
||||
}
|
||||
};
|
||||
|
||||
public void updateWith(PwEntryV3 source) {
|
||||
super.updateWith(source);
|
||||
title = source.title;
|
||||
username = source.username;
|
||||
|
||||
if (source.password != null) {
|
||||
int passLen = source.password.length;
|
||||
password = new byte[passLen];
|
||||
System.arraycopy(source.password, 0, password, 0, passLen);
|
||||
}
|
||||
|
||||
url = source.url;
|
||||
additional = source.additional;
|
||||
binaryDesc = source.binaryDesc;
|
||||
|
||||
if ( source.binaryData != null ) {
|
||||
int descLen = source.binaryData.length;
|
||||
binaryData = new byte[descLen];
|
||||
System.arraycopy(source.binaryData, 0, binaryData, 0, descLen);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return Type.ENTRY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUsername(String user) {
|
||||
username = user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNotes() {
|
||||
return additional;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNotes(String notes) {
|
||||
additional = notes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the actual password byte array.
|
||||
*/
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return new String(password);
|
||||
}
|
||||
|
||||
public byte[] getPasswordBytes() {
|
||||
return password;
|
||||
}
|
||||
|
||||
/**
|
||||
* fill byte array
|
||||
*/
|
||||
private static void fill(byte[] array, byte value) {
|
||||
for (int i=0; i<array.length; i++)
|
||||
array[i] = value;
|
||||
}
|
||||
|
||||
/** Securely erase old password before copying new. */
|
||||
public void setPassword( byte[] buf, int offset, int len ) {
|
||||
fill(password, (byte)0);
|
||||
password = new byte[len];
|
||||
System.arraycopy( buf, offset, password, 0, len );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPassword(String pass) {
|
||||
byte[] password;
|
||||
try {
|
||||
password = pass.getBytes("UTF-8");
|
||||
setPassword(password, 0, password.length);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
password = pass.getBytes();
|
||||
setPassword(password, 0, password.length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the actual binaryData byte array.
|
||||
*/
|
||||
public byte[] getBinaryData() {
|
||||
return binaryData;
|
||||
}
|
||||
|
||||
/** Securely erase old data before copying new. */
|
||||
public void setBinaryData( byte[] buf, int offset, int len ) {
|
||||
if( binaryData != null ) {
|
||||
fill( binaryData, (byte)0 );
|
||||
binaryData = null;
|
||||
}
|
||||
binaryData = new byte[len];
|
||||
System.arraycopy( buf, offset, binaryData, 0, len );
|
||||
}
|
||||
|
||||
public String getBinaryDesc() {
|
||||
return binaryDesc;
|
||||
}
|
||||
|
||||
public void setBinaryDesc(String binaryDesc) {
|
||||
this.binaryDesc = binaryDesc;
|
||||
}
|
||||
|
||||
// Determine if this is a MetaStream entry
|
||||
public boolean isMetaStream() {
|
||||
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;
|
||||
if (!title.equals(PMS_ID_TITLE)) return false;
|
||||
if (username.isEmpty()) return false;
|
||||
if (!username.equals(PMS_ID_USER)) return false;
|
||||
if (url.isEmpty()) return false;
|
||||
if (!url.equals(PMS_ID_URL)) return false;
|
||||
return getIcon().isMetaStreamIcon();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSearchingEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void touchLocation() {}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* 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.element
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
|
||||
import java.io.UnsupportedEncodingException
|
||||
import java.util.Arrays
|
||||
import java.util.UUID
|
||||
|
||||
|
||||
/**
|
||||
* Structure containing information about one entry.
|
||||
*
|
||||
* <PRE>
|
||||
* One entry: [FIELDTYPE(FT)][FIELDSIZE(FS)][FIELDDATA(FD)]
|
||||
* [FT+FS+(FD)][FT+FS+(FD)][FT+FS+(FD)][FT+FS+(FD)][FT+FS+(FD)]...
|
||||
*
|
||||
* [ 2 bytes] FIELDTYPE
|
||||
* [ 4 bytes] FIELDSIZE, size of FIELDDATA in bytes
|
||||
* [ n bytes] FIELDDATA, n = FIELDSIZE
|
||||
*
|
||||
* Notes:
|
||||
* - Strings are stored in UTF-8 encoded form and are null-terminated.
|
||||
* - FIELDTYPE can be one of the FT_ constants.
|
||||
</PRE> *
|
||||
*
|
||||
* @author Naomaru Itoi <nao></nao>@phoneid.org>
|
||||
* @author Bill Zwicky <wrzwicky></wrzwicky>@pobox.com>
|
||||
* @author Dominik Reichl <dominik.reichl></dominik.reichl>@t-online.de>
|
||||
* @author Jeremy Jamet <jeremy.jamet></jeremy.jamet>@kunzisoft.com>
|
||||
*/
|
||||
class PwEntryV3 : PwEntry<PwGroupV3, PwEntryV3> {
|
||||
|
||||
/** A string describing what is in pBinaryData */
|
||||
var binaryDesc = ""
|
||||
/**
|
||||
* @return the actual binaryData byte array.
|
||||
*/
|
||||
var binaryData: ByteArray = ByteArray(0)
|
||||
private set
|
||||
|
||||
// Determine if this is a MetaStream entry
|
||||
val isMetaStream: Boolean
|
||||
get() {
|
||||
if (Arrays.equals(binaryData, ByteArray(0))) return false
|
||||
if (notes.isEmpty()) return false
|
||||
if (binaryDesc != PMS_ID_BINDESC) return false
|
||||
if (title.isEmpty()) return false
|
||||
if (title != PMS_ID_TITLE) return false
|
||||
if (username.isEmpty()) return false
|
||||
if (username != PMS_ID_USER) return false
|
||||
if (url.isEmpty()) return false
|
||||
return if (url != PMS_ID_URL) false else icon.isMetaStreamIcon
|
||||
}
|
||||
|
||||
override fun initNodeId(): PwNodeId<UUID> {
|
||||
return PwNodeIdUUID()
|
||||
}
|
||||
|
||||
override fun copyNodeId(nodeId: PwNodeId<UUID>): PwNodeId<UUID> {
|
||||
return PwNodeIdUUID(nodeId.id)
|
||||
}
|
||||
|
||||
constructor() : super()
|
||||
|
||||
constructor(parcel: Parcel) : super(parcel) {
|
||||
title = parcel.readString()
|
||||
username = parcel.readString()
|
||||
parcel.readByteArray(passwordBytes)
|
||||
url = parcel.readString()
|
||||
notes = parcel.readString()
|
||||
binaryDesc = parcel.readString()
|
||||
parcel.readByteArray(binaryData)
|
||||
}
|
||||
|
||||
override fun readParentParcelable(parcel: Parcel): PwGroupV3 {
|
||||
return parcel.readParcelable(PwGroupV3::class.java.classLoader)
|
||||
}
|
||||
|
||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||
super.writeToParcel(dest, flags)
|
||||
dest.writeString(title)
|
||||
dest.writeString(username)
|
||||
dest.writeByteArray(passwordBytes)
|
||||
dest.writeString(url)
|
||||
dest.writeString(notes)
|
||||
dest.writeString(binaryDesc)
|
||||
dest.writeByteArray(binaryData)
|
||||
}
|
||||
|
||||
fun updateWith(source: PwEntryV3) {
|
||||
super.updateWith(source)
|
||||
title = source.title
|
||||
username = source.username
|
||||
|
||||
val passLen = source.passwordBytes.size
|
||||
passwordBytes = ByteArray(passLen)
|
||||
System.arraycopy(source.passwordBytes, 0, passwordBytes, 0, passLen)
|
||||
|
||||
url = source.url
|
||||
notes = source.notes
|
||||
binaryDesc = source.binaryDesc
|
||||
|
||||
val descLen = source.binaryData.size
|
||||
binaryData = ByteArray(descLen)
|
||||
System.arraycopy(source.binaryData, 0, binaryData, 0, descLen)
|
||||
}
|
||||
|
||||
override var username = ""
|
||||
|
||||
var passwordBytes: ByteArray = ByteArray(0)
|
||||
private set
|
||||
|
||||
/** Securely erase old password before copying new. */
|
||||
fun setPassword(buf: ByteArray, offset: Int, len: Int) {
|
||||
fill(passwordBytes, 0.toByte())
|
||||
passwordBytes = ByteArray(len)
|
||||
System.arraycopy(buf, offset, passwordBytes, 0, len)
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the actual password byte array.
|
||||
*/
|
||||
override var password: String
|
||||
get() = String(passwordBytes)
|
||||
set(pass) {
|
||||
var password: ByteArray
|
||||
try {
|
||||
password = pass.toByteArray(charset("UTF-8"))
|
||||
setPassword(password, 0, password.size)
|
||||
} catch (e: UnsupportedEncodingException) {
|
||||
password = pass.toByteArray()
|
||||
setPassword(password, 0, password.size)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override var url = ""
|
||||
|
||||
override var notes = ""
|
||||
|
||||
override var title = ""
|
||||
|
||||
override val type: Type
|
||||
get() = Type.ENTRY
|
||||
|
||||
override val isSearchingEnabled: Boolean
|
||||
get() = false
|
||||
|
||||
|
||||
fun setBinaryData(buf: ByteArray, offset: Int, len: Int) {
|
||||
/** Securely erase old data before copying new. */
|
||||
fill(binaryData, 0.toByte())
|
||||
binaryData = ByteArray(len)
|
||||
System.arraycopy(buf, offset, binaryData, 0, len)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
/** Size of byte buffer needed to hold this struct. */
|
||||
private const val PMS_ID_BINDESC = "bin-stream"
|
||||
private const val PMS_ID_TITLE = "Meta-Info"
|
||||
private const val PMS_ID_USER = "SYSTEM"
|
||||
private const val PMS_ID_URL = "$"
|
||||
|
||||
@JvmField
|
||||
val CREATOR: Parcelable.Creator<PwEntryV3> = object : Parcelable.Creator<PwEntryV3> {
|
||||
override fun createFromParcel(`in`: Parcel): PwEntryV3 {
|
||||
return PwEntryV3(`in`)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<PwEntryV3?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fill byte array
|
||||
*/
|
||||
private fun fill(array: ByteArray, value: Byte) {
|
||||
for (i in array.indices)
|
||||
array[i] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,503 +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.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.security.ProtectedBinary;
|
||||
import com.kunzisoft.keepass.database.security.ProtectedString;
|
||||
import com.kunzisoft.keepass.utils.MemUtil;
|
||||
import com.kunzisoft.keepass.utils.SprEngineV4;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PwEntryV4 extends PwEntry<PwGroupV4, PwEntryV4> implements NodeV4Interface {
|
||||
|
||||
public static final String STR_TITLE = "Title";
|
||||
public static final String STR_USERNAME = "UserName";
|
||||
public static final String STR_PASSWORD = "Password";
|
||||
public static final String STR_URL = "URL";
|
||||
public static final String STR_NOTES = "Notes";
|
||||
|
||||
// To decode each field not parcelable
|
||||
private transient PwDatabaseV4 mDatabase = null;
|
||||
private transient boolean mDecodeRef = false;
|
||||
|
||||
private PwIconCustom customIcon = PwIconCustom.Companion.getZERO();
|
||||
private long usageCount = 0;
|
||||
private PwDate parentGroupLastMod = new PwDate();
|
||||
private Map<String, String> customData = new HashMap<>();
|
||||
private ExtraFields fields = new ExtraFields();
|
||||
private HashMap<String, ProtectedBinary> binaries = new HashMap<>();
|
||||
private String foregroundColor = "";
|
||||
private String backgroupColor = "";
|
||||
private String overrideURL = "";
|
||||
private AutoType autoType = new AutoType();
|
||||
private ArrayList<PwEntryV4> history = new ArrayList<>();
|
||||
private String url = "";
|
||||
private String additional = "";
|
||||
private String tags = "";
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected PwNodeId<UUID> initNodeId() {
|
||||
return new PwNodeIdUUID();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected PwNodeId<UUID> copyNodeId(@NonNull PwNodeId<UUID> nodeId) {
|
||||
return new PwNodeIdUUID(nodeId.getId());
|
||||
}
|
||||
|
||||
public PwEntryV4() {
|
||||
super();
|
||||
}
|
||||
|
||||
public PwEntryV4(Parcel parcel) {
|
||||
super(parcel);
|
||||
customIcon = parcel.readParcelable(PwIconCustom.class.getClassLoader());
|
||||
usageCount = parcel.readLong();
|
||||
parentGroupLastMod = parcel.readParcelable(PwDate.class.getClassLoader());
|
||||
customData = MemUtil.readStringParcelableMap(parcel);
|
||||
fields = parcel.readParcelable(ExtraFields.class.getClassLoader());
|
||||
// TODO binaries = MemUtil.readStringParcelableMap(parcel, ProtectedBinary.class);
|
||||
foregroundColor = parcel.readString();
|
||||
backgroupColor = parcel.readString();
|
||||
overrideURL = parcel.readString();
|
||||
autoType = parcel.readParcelable(AutoType.class.getClassLoader());
|
||||
history = parcel.readArrayList(PwEntryV4.class.getClassLoader()); // TODO verify
|
||||
url = parcel.readString();
|
||||
additional = parcel.readString();
|
||||
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);
|
||||
dest.writeParcelable(customIcon, flags);
|
||||
dest.writeLong(usageCount);
|
||||
dest.writeParcelable(parentGroupLastMod, flags);
|
||||
MemUtil.writeStringParcelableMap(dest, customData);
|
||||
dest.writeParcelable(fields, flags);
|
||||
// TODO MemUtil.writeStringParcelableMap(dest, flags, binaries);
|
||||
dest.writeString(foregroundColor);
|
||||
dest.writeString(backgroupColor);
|
||||
dest.writeString(overrideURL);
|
||||
dest.writeParcelable(autoType, flags);
|
||||
dest.writeList(history);
|
||||
dest.writeString(url);
|
||||
dest.writeString(additional);
|
||||
dest.writeString(tags);
|
||||
}
|
||||
|
||||
public static final Creator<PwEntryV4> CREATOR = new Creator<PwEntryV4>() {
|
||||
@Override
|
||||
public PwEntryV4 createFromParcel(Parcel in) {
|
||||
return new PwEntryV4(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PwEntryV4[] newArray(int size) {
|
||||
return new PwEntryV4[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Update with deep copy of each entry element
|
||||
* @param source
|
||||
*/
|
||||
public void updateWith(PwEntryV4 source) {
|
||||
super.updateWith(source);
|
||||
customIcon = new PwIconCustom(source.customIcon);
|
||||
usageCount = source.usageCount;
|
||||
parentGroupLastMod = new PwDate(source.parentGroupLastMod);
|
||||
// Add all custom elements in map
|
||||
customData.clear();
|
||||
for (Map.Entry<String, String> entry : source.customData.entrySet()) {
|
||||
customData.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
fields = new ExtraFields(source.fields);
|
||||
for (Map.Entry<String, ProtectedBinary> entry: source.binaries.entrySet()) {
|
||||
binaries.put(entry.getKey(), new ProtectedBinary(entry.getValue()));
|
||||
}
|
||||
foregroundColor = source.foregroundColor;
|
||||
backgroupColor = source.backgroupColor;
|
||||
overrideURL = source.overrideURL;
|
||||
autoType = new AutoType(source.autoType);
|
||||
history.clear();
|
||||
history.addAll(source.history);
|
||||
url = source.url;
|
||||
additional = source.additional;
|
||||
tags = source.tags;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Type getType() {
|
||||
return Type.ENTRY;
|
||||
}
|
||||
|
||||
public void startToManageFieldReferences(PwDatabaseV4 db) {
|
||||
this.mDatabase = db;
|
||||
this.mDecodeRef = true;
|
||||
}
|
||||
|
||||
public void stopToManageFieldReferences() {
|
||||
this.mDatabase = null;
|
||||
this.mDecodeRef = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a reference key woth the SprEngineV4
|
||||
* @param decodeRef
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
private String decodeRefKey(boolean decodeRef, String key) {
|
||||
String text = getProtectedStringValue(key);
|
||||
if (decodeRef) {
|
||||
if (mDatabase == null)
|
||||
return text;
|
||||
return new SprEngineV4().compile(text, this, mDatabase);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return decodeRefKey(mDecodeRef, STR_USERNAME);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return decodeRefKey(mDecodeRef, STR_TITLE);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return decodeRefKey(mDecodeRef, STR_PASSWORD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(@NonNull String title) {
|
||||
boolean protect = (mDatabase != null) && mDatabase.getMemoryProtection().protectTitle;
|
||||
setProtectedString(STR_TITLE, title, protect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUsername(@NonNull String user) {
|
||||
boolean protect = (mDatabase != null) && mDatabase.getMemoryProtection().protectUserName;
|
||||
setProtectedString(STR_USERNAME, user, protect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPassword(@NonNull String pass) {
|
||||
boolean protect = (mDatabase != null) && mDatabase.getMemoryProtection().protectPassword;
|
||||
setProtectedString(STR_PASSWORD, pass, protect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUrl(@NonNull String url) {
|
||||
boolean protect = (mDatabase != null) && mDatabase.getMemoryProtection().protectUrl;
|
||||
setProtectedString(STR_URL, url, protect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNotes(@NonNull String notes) {
|
||||
boolean protect = (mDatabase != null) && mDatabase.getMemoryProtection().protectNotes;
|
||||
setProtectedString(STR_NOTES, notes, protect);
|
||||
}
|
||||
|
||||
public String getProtectedStringValue(String key) {
|
||||
return fields.getProtectedStringValue(key);
|
||||
}
|
||||
|
||||
public void setProtectedString(String key, String value, boolean protect) {
|
||||
fields.putProtectedString(key, value, protect);
|
||||
}
|
||||
|
||||
public PwDate getLocationChanged() {
|
||||
return parentGroupLastMod;
|
||||
}
|
||||
|
||||
public long getUsageCount() {
|
||||
return usageCount;
|
||||
}
|
||||
|
||||
public void setLocationChanged(PwDate date) {
|
||||
parentGroupLastMod = date;
|
||||
}
|
||||
|
||||
public void setUsageCount(long count) {
|
||||
usageCount = count;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getNotes() {
|
||||
return decodeRefKey(mDecodeRef, STR_NOTES);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getUrl() {
|
||||
return decodeRefKey(mDecodeRef, STR_URL);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public PwIcon getIcon() {
|
||||
if (customIcon == null || customIcon.isUnknown()) {
|
||||
return super.getIcon();
|
||||
} else {
|
||||
return customIcon;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIcon(@NonNull PwIcon icon) {
|
||||
if (icon instanceof PwIconStandard)
|
||||
setIconStandard((PwIconStandard) icon);
|
||||
if (icon instanceof PwIconCustom)
|
||||
setIconCustom((PwIconCustom) icon);
|
||||
}
|
||||
|
||||
public PwIconCustom getIconCustom() {
|
||||
return customIcon;
|
||||
}
|
||||
|
||||
public void setIconCustom(PwIconCustom icon) {
|
||||
this.customIcon = icon;
|
||||
}
|
||||
|
||||
public PwIcon getIconStandard() {
|
||||
return getIcon();
|
||||
}
|
||||
|
||||
public void setIconStandard(PwIconStandard icon) {
|
||||
super.setIcon(icon);
|
||||
this.customIcon = PwIconCustom.Companion.getZERO();
|
||||
}
|
||||
|
||||
public boolean allowExtraFields() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public ExtraFields getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public boolean containsCustomFields() {
|
||||
return getFields().containsCustomFields();
|
||||
}
|
||||
|
||||
public boolean containsCustomFieldsProtected() {
|
||||
return getFields().containsCustomFieldsProtected();
|
||||
}
|
||||
|
||||
public boolean containsCustomFieldsNotProtected() {
|
||||
return getFields().containsCustomFieldsNotProtected();
|
||||
}
|
||||
|
||||
public void addExtraField(String label, ProtectedString value) {
|
||||
fields.putProtectedString(label, value);
|
||||
}
|
||||
|
||||
public void removeAllCustomFields() {
|
||||
fields.removeAllCustomFields();
|
||||
}
|
||||
|
||||
public HashMap<String, ProtectedBinary> getBinaries() {
|
||||
return binaries;
|
||||
}
|
||||
|
||||
public void putProtectedBinary(String key, ProtectedBinary value) {
|
||||
binaries.put(key, value);
|
||||
}
|
||||
|
||||
public String getForegroundColor() {
|
||||
return foregroundColor;
|
||||
}
|
||||
|
||||
public void setForegroundColor(String color) {
|
||||
this.foregroundColor = color;
|
||||
}
|
||||
|
||||
public String getBackgroupColor() {
|
||||
return backgroupColor;
|
||||
}
|
||||
|
||||
public void setBackgroupColor(String color) {
|
||||
this.backgroupColor = color;
|
||||
}
|
||||
|
||||
public String getOverrideURL() {
|
||||
return overrideURL;
|
||||
}
|
||||
|
||||
public void setOverrideURL(String overrideURL) {
|
||||
this.overrideURL = overrideURL;
|
||||
}
|
||||
|
||||
public AutoType getAutoType() {
|
||||
return autoType;
|
||||
}
|
||||
|
||||
public void setAutoType(AutoType autoType) {
|
||||
this.autoType = autoType;
|
||||
}
|
||||
|
||||
public ArrayList<PwEntryV4> getHistory() {
|
||||
return history;
|
||||
}
|
||||
|
||||
public void setHistory(ArrayList<PwEntryV4> history) {
|
||||
this.history = history;
|
||||
}
|
||||
|
||||
public void addToHistory(PwEntryV4 entry) {
|
||||
history.add(entry);
|
||||
}
|
||||
|
||||
public int sizeOfHistory() {
|
||||
return history.size();
|
||||
}
|
||||
|
||||
public String getAdditional() {
|
||||
return additional;
|
||||
}
|
||||
|
||||
public void setAdditional(String additional) {
|
||||
this.additional = additional;
|
||||
}
|
||||
|
||||
public String getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
public void setTags(String tags) {
|
||||
this.tags = tags;
|
||||
}
|
||||
|
||||
public void putCustomData(String key, String value) {
|
||||
customData.put(key, value);
|
||||
}
|
||||
|
||||
public boolean containsCustomData() {
|
||||
return customData.size() > 0;
|
||||
}
|
||||
|
||||
private static final long FIXED_LENGTH_SIZE = 128; // Approximate fixed length size
|
||||
public long getSize() {
|
||||
long size = FIXED_LENGTH_SIZE;
|
||||
|
||||
for (Entry<String, ProtectedString> pair : fields.getListOfAllFields().entrySet()) {
|
||||
size += pair.getKey().length();
|
||||
size += pair.getValue().length();
|
||||
}
|
||||
|
||||
for (Entry<String, ProtectedBinary> pair : binaries.entrySet()) {
|
||||
size += pair.getKey().length();
|
||||
size += pair.getValue().length();
|
||||
}
|
||||
|
||||
size += autoType.defaultSequence.length();
|
||||
for (Entry<String, String> pair : autoType.entrySet()) {
|
||||
size += pair.getKey().length();
|
||||
size += pair.getValue().length();
|
||||
}
|
||||
|
||||
for (PwEntryV4 entry : history) {
|
||||
size += entry.getSize();
|
||||
}
|
||||
|
||||
size += overrideURL.length();
|
||||
size += tags.length();
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
public void addEntryToHistory(PwEntryV4 entry) {
|
||||
history.add(entry);
|
||||
}
|
||||
|
||||
public void removeOldestEntryFromHistory() {
|
||||
Date min = null;
|
||||
int index = -1;
|
||||
|
||||
for (int i = 0; i < history.size(); i++) {
|
||||
PwEntryV4 entry = history.get(i);
|
||||
Date lastMod = entry.getLastModificationTime().getDate();
|
||||
if ((min == null) || lastMod.before(min)) {
|
||||
index = i;
|
||||
min = lastMod;
|
||||
}
|
||||
}
|
||||
|
||||
if (index != -1) {
|
||||
history.remove(index);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void touch(boolean modified, boolean touchParents) {
|
||||
super.touch(modified, touchParents);
|
||||
++usageCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void touchLocation() {
|
||||
parentGroupLastMod = new PwDate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSearchingEnabled() {
|
||||
if (getParent() != null) {
|
||||
return getParent().isSearchingEnabled();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public boolean isMetaStream() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
* 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.element
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import com.kunzisoft.keepass.database.AutoType
|
||||
import com.kunzisoft.keepass.database.ExtraFields
|
||||
import com.kunzisoft.keepass.database.security.ProtectedBinary
|
||||
import com.kunzisoft.keepass.database.security.ProtectedString
|
||||
import com.kunzisoft.keepass.utils.MemUtil
|
||||
import com.kunzisoft.keepass.utils.SprEngineV4
|
||||
import java.util.*
|
||||
|
||||
class PwEntryV4 : PwEntry<PwGroupV4, PwEntryV4>, NodeV4Interface {
|
||||
|
||||
// To decode each field not parcelable
|
||||
@Transient
|
||||
private var mDatabase: PwDatabaseV4? = null
|
||||
@Transient
|
||||
private var mDecodeRef = false
|
||||
|
||||
var iconCustom = PwIconCustom.ZERO
|
||||
private var customData = HashMap<String, String>()
|
||||
var fields = ExtraFields()
|
||||
private set
|
||||
val binaries = HashMap<String, ProtectedBinary>()
|
||||
var foregroundColor = ""
|
||||
var backgroundColor = ""
|
||||
var overrideURL = ""
|
||||
var autoType = AutoType()
|
||||
var history = ArrayList<PwEntryV4>()
|
||||
var additional = ""
|
||||
var tags = ""
|
||||
|
||||
val size: Long
|
||||
get() {
|
||||
var size = FIXED_LENGTH_SIZE
|
||||
|
||||
for ((key, value) in fields.listOfAllFields) {
|
||||
size += key.length.toLong()
|
||||
size += value.length().toLong()
|
||||
}
|
||||
|
||||
for ((key, value) in binaries) {
|
||||
size += key.length.toLong()
|
||||
size += value.length()
|
||||
}
|
||||
|
||||
size += autoType.defaultSequence.length.toLong()
|
||||
for ((key, value) in autoType.entrySet()) {
|
||||
size += key.length.toLong()
|
||||
size += value.length.toLong()
|
||||
}
|
||||
|
||||
for (entry in history) {
|
||||
size += entry.size
|
||||
}
|
||||
|
||||
size += overrideURL.length.toLong()
|
||||
size += tags.length.toLong()
|
||||
|
||||
return size
|
||||
}
|
||||
|
||||
constructor() : super()
|
||||
|
||||
constructor(parcel: Parcel) : super(parcel) {
|
||||
iconCustom = parcel.readParcelable(PwIconCustom::class.java.classLoader)
|
||||
usageCount = parcel.readLong()
|
||||
locationChanged = parcel.readParcelable(PwDate::class.java.classLoader)
|
||||
customData = MemUtil.readStringParcelableMap(parcel)
|
||||
fields = parcel.readParcelable(ExtraFields::class.java.classLoader)
|
||||
// TODO binaries = MemUtil.readStringParcelableMap(parcel, ProtectedBinary.class);
|
||||
foregroundColor = parcel.readString()
|
||||
backgroundColor = parcel.readString()
|
||||
overrideURL = parcel.readString()
|
||||
autoType = parcel.readParcelable(AutoType::class.java.classLoader)
|
||||
parcel.readTypedList(history, CREATOR)
|
||||
url = parcel.readString()
|
||||
additional = parcel.readString()
|
||||
tags = parcel.readString()
|
||||
}
|
||||
|
||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||
super.writeToParcel(dest, flags)
|
||||
dest.writeParcelable(iconCustom, flags)
|
||||
dest.writeLong(usageCount)
|
||||
dest.writeParcelable(locationChanged, flags)
|
||||
MemUtil.writeStringParcelableMap(dest, customData)
|
||||
dest.writeParcelable(fields, flags)
|
||||
// TODO MemUtil.writeStringParcelableMap(dest, flags, binaries);
|
||||
dest.writeString(foregroundColor)
|
||||
dest.writeString(backgroundColor)
|
||||
dest.writeString(overrideURL)
|
||||
dest.writeParcelable(autoType, flags)
|
||||
dest.writeTypedList(history)
|
||||
dest.writeString(url)
|
||||
dest.writeString(additional)
|
||||
dest.writeString(tags)
|
||||
}
|
||||
|
||||
/**
|
||||
* Update with deep copy of each entry element
|
||||
* @param source
|
||||
*/
|
||||
fun updateWith(source: PwEntryV4) {
|
||||
super.updateWith(source)
|
||||
iconCustom = PwIconCustom(source.iconCustom)
|
||||
usageCount = source.usageCount
|
||||
locationChanged = PwDate(source.locationChanged)
|
||||
// Add all custom elements in map
|
||||
customData.clear()
|
||||
for ((key, value) in source.customData) {
|
||||
customData[key] = value
|
||||
}
|
||||
fields = ExtraFields(source.fields)
|
||||
for ((key, value) in source.binaries) {
|
||||
binaries[key] = ProtectedBinary(value)
|
||||
}
|
||||
foregroundColor = source.foregroundColor
|
||||
backgroundColor = source.backgroundColor
|
||||
overrideURL = source.overrideURL
|
||||
autoType = AutoType(source.autoType)
|
||||
history.clear()
|
||||
history.addAll(source.history)
|
||||
url = source.url
|
||||
additional = source.additional
|
||||
tags = source.tags
|
||||
}
|
||||
|
||||
fun startToManageFieldReferences(db: PwDatabaseV4) {
|
||||
this.mDatabase = db
|
||||
this.mDecodeRef = true
|
||||
}
|
||||
|
||||
fun stopToManageFieldReferences() {
|
||||
this.mDatabase = null
|
||||
this.mDecodeRef = false
|
||||
}
|
||||
|
||||
override fun initNodeId(): PwNodeId<UUID> {
|
||||
return PwNodeIdUUID()
|
||||
}
|
||||
|
||||
override fun copyNodeId(nodeId: PwNodeId<UUID>): PwNodeId<UUID> {
|
||||
return PwNodeIdUUID(nodeId.id)
|
||||
}
|
||||
|
||||
override fun readParentParcelable(parcel: Parcel): PwGroupV4 {
|
||||
return parcel.readParcelable(PwGroupV4::class.java.classLoader)
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a reference key woth the SprEngineV4
|
||||
* @param decodeRef
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
private fun decodeRefKey(decodeRef: Boolean, key: String): String {
|
||||
val text = fields.getProtectedStringValue(key)
|
||||
return if (decodeRef) {
|
||||
if (mDatabase == null) text else SprEngineV4().compile(text, this, mDatabase)
|
||||
} else text
|
||||
}
|
||||
|
||||
override var title: String
|
||||
get() = decodeRefKey(mDecodeRef, STR_TITLE)
|
||||
set(value) {
|
||||
val protect = mDatabase != null && mDatabase!!.memoryProtection.protectTitle
|
||||
fields.putProtectedString(STR_TITLE, value, protect)
|
||||
}
|
||||
|
||||
override val type: Type
|
||||
get() = Type.ENTRY
|
||||
|
||||
override val isSearchingEnabled: Boolean
|
||||
get() = parent?.isSearchingEnabled ?: true
|
||||
|
||||
override var username: String
|
||||
get() = decodeRefKey(mDecodeRef, STR_USERNAME)
|
||||
set(value) {
|
||||
val protect = mDatabase != null && mDatabase!!.memoryProtection.protectUserName
|
||||
fields.putProtectedString(STR_USERNAME, value, protect)
|
||||
}
|
||||
|
||||
override var password: String
|
||||
get() = decodeRefKey(mDecodeRef, STR_PASSWORD)
|
||||
set(value) {
|
||||
val protect = mDatabase != null && mDatabase!!.memoryProtection.protectPassword
|
||||
fields.putProtectedString(STR_PASSWORD, value, protect)
|
||||
}
|
||||
|
||||
override var url
|
||||
get() = decodeRefKey(mDecodeRef, STR_URL)
|
||||
set(value) {
|
||||
val protect = mDatabase != null && mDatabase!!.memoryProtection.protectUrl
|
||||
fields.putProtectedString(STR_URL, value, protect)
|
||||
}
|
||||
|
||||
override var notes: String
|
||||
get() = decodeRefKey(mDecodeRef, STR_NOTES)
|
||||
set(value) {
|
||||
val protect = mDatabase != null && mDatabase!!.memoryProtection.protectNotes
|
||||
fields.putProtectedString(STR_NOTES, value, protect)
|
||||
}
|
||||
|
||||
override var usageCount: Long = 0
|
||||
|
||||
override var locationChanged = PwDate()
|
||||
|
||||
fun afterChangeParent() {
|
||||
locationChanged = PwDate()
|
||||
}
|
||||
|
||||
fun allowExtraFields(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
fun containsCustomFields(): Boolean {
|
||||
return fields.containsCustomFields()
|
||||
}
|
||||
|
||||
fun containsCustomFieldsProtected(): Boolean {
|
||||
return fields.containsCustomFieldsProtected()
|
||||
}
|
||||
|
||||
fun containsCustomFieldsNotProtected(): Boolean {
|
||||
return fields.containsCustomFieldsNotProtected()
|
||||
}
|
||||
|
||||
fun addExtraField(label: String, value: ProtectedString) {
|
||||
fields.putProtectedString(label, value)
|
||||
}
|
||||
|
||||
fun removeAllCustomFields() {
|
||||
fields.removeAllCustomFields()
|
||||
}
|
||||
|
||||
fun putProtectedBinary(key: String, value: ProtectedBinary) {
|
||||
binaries[key] = value
|
||||
}
|
||||
|
||||
fun addToHistory(entry: PwEntryV4) {
|
||||
history.add(entry)
|
||||
}
|
||||
|
||||
fun sizeOfHistory(): Int {
|
||||
return history.size
|
||||
}
|
||||
|
||||
fun putCustomData(key: String, value: String) {
|
||||
customData[key] = value
|
||||
}
|
||||
|
||||
fun containsCustomData(): Boolean {
|
||||
return customData.size > 0
|
||||
}
|
||||
|
||||
fun addEntryToHistory(entry: PwEntryV4) {
|
||||
history.add(entry)
|
||||
}
|
||||
|
||||
fun removeOldestEntryFromHistory() {
|
||||
var min: Date? = null
|
||||
var index = -1
|
||||
|
||||
for (i in history.indices) {
|
||||
val entry = history[i]
|
||||
val lastMod = entry.lastModificationTime.date
|
||||
if (min == null || lastMod.before(min)) {
|
||||
index = i
|
||||
min = lastMod
|
||||
}
|
||||
}
|
||||
|
||||
if (index != -1) {
|
||||
history.removeAt(index)
|
||||
}
|
||||
}
|
||||
|
||||
override fun touch(modified: Boolean, touchParents: Boolean) {
|
||||
super.touch(modified, touchParents)
|
||||
++usageCount
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val STR_TITLE = "Title"
|
||||
const val STR_USERNAME = "UserName"
|
||||
const val STR_PASSWORD = "Password"
|
||||
const val STR_URL = "URL"
|
||||
const val STR_NOTES = "Notes"
|
||||
|
||||
@JvmField
|
||||
val CREATOR: Parcelable.Creator<PwEntryV4> = object : Parcelable.Creator<PwEntryV4> {
|
||||
override fun createFromParcel(parcel: Parcel): PwEntryV4 {
|
||||
return PwEntryV4(parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<PwEntryV4?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
|
||||
private const val FIXED_LENGTH_SIZE: Long = 128 // Approximate fixed length size
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
/*
|
||||
* 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.element;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
public class PwGroupV3 extends PwGroup<Integer, PwGroupV3, PwEntryV3> {
|
||||
|
||||
private int level = 0; // short
|
||||
/** Used by KeePass internally, don't use */
|
||||
private int flags;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected PwNodeId<Integer> initNodeId() {
|
||||
return new PwNodeIdInt();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected PwNodeId<Integer> copyNodeId(@NonNull PwNodeId<Integer> nodeId) {
|
||||
return new PwNodeIdInt(nodeId.getId());
|
||||
}
|
||||
|
||||
public PwGroupV3() {
|
||||
super();
|
||||
}
|
||||
|
||||
public PwGroupV3(Parcel in) {
|
||||
super(in);
|
||||
level = in.readInt();
|
||||
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);
|
||||
dest.writeInt(level);
|
||||
dest.writeInt(flags);
|
||||
}
|
||||
|
||||
public static final Creator<PwGroupV3> CREATOR = new Creator<PwGroupV3>() {
|
||||
@Override
|
||||
public PwGroupV3 createFromParcel(Parcel in) {
|
||||
return new PwGroupV3(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PwGroupV3[] newArray(int size) {
|
||||
return new PwGroupV3[size];
|
||||
}
|
||||
};
|
||||
|
||||
protected void updateWith(PwGroupV3 source) {
|
||||
super.updateWith(source);
|
||||
level = source.level;
|
||||
flags = source.flags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return Type.GROUP;
|
||||
}
|
||||
|
||||
public void setParent(PwGroupV3 parent) {
|
||||
super.setParent(parent);
|
||||
try {
|
||||
level = parent.getLevel() + 1;
|
||||
} catch (ClassCastException ignored) {}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSearchingEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setGroupId(int groupId) {
|
||||
this.setNodeId(new PwNodeIdInt(groupId));
|
||||
}
|
||||
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public void setLevel(int level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public int getFlags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
public void setFlags(int flags) {
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowAddEntryIfIsRoot() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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.element
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
|
||||
class PwGroupV3 : PwGroup<Int, PwGroupV3, PwEntryV3> {
|
||||
|
||||
var level = 0 // short
|
||||
/** Used by KeePass internally, don't use */
|
||||
var flags: Int = 0
|
||||
|
||||
constructor() : super()
|
||||
|
||||
constructor(parcel: Parcel) : super(parcel) {
|
||||
level = parcel.readInt()
|
||||
flags = parcel.readInt()
|
||||
}
|
||||
|
||||
override fun readParentParcelable(parcel: Parcel): PwGroupV3 {
|
||||
return parcel.readParcelable(PwGroupV3::class.java.classLoader)
|
||||
}
|
||||
|
||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||
super.writeToParcel(dest, flags)
|
||||
dest.writeInt(level)
|
||||
dest.writeInt(flags)
|
||||
}
|
||||
|
||||
fun updateWith(source: PwGroupV3) {
|
||||
super.updateWith(source)
|
||||
level = source.level
|
||||
flags = source.flags
|
||||
}
|
||||
|
||||
override val type: Type
|
||||
get() = Type.GROUP
|
||||
|
||||
override val isSearchingEnabled: Boolean
|
||||
get() = false
|
||||
|
||||
override fun initNodeId(): PwNodeId<Int> {
|
||||
return PwNodeIdInt()
|
||||
}
|
||||
|
||||
override fun copyNodeId(nodeId: PwNodeId<Int>): PwNodeId<Int> {
|
||||
return PwNodeIdInt(nodeId.id)
|
||||
}
|
||||
|
||||
override fun afterAssignNewParent() {
|
||||
if (parent != null)
|
||||
level = parent!!.level + 1
|
||||
}
|
||||
|
||||
fun setGroupId(groupId: Int) {
|
||||
this.nodeId = PwNodeIdInt(groupId)
|
||||
}
|
||||
|
||||
override fun allowAddEntryIfIsRoot(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmField
|
||||
val CREATOR: Parcelable.Creator<PwGroupV3> = object : Parcelable.Creator<PwGroupV3> {
|
||||
override fun createFromParcel(parcel: Parcel): PwGroupV3 {
|
||||
return PwGroupV3(parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<PwGroupV3?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,267 +0,0 @@
|
||||
/*
|
||||
* 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.element;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PwGroupV4 extends PwGroup<UUID, PwGroupV4, PwEntryV4> implements NodeV4Interface {
|
||||
|
||||
private PwIconCustom customIcon = PwIconCustom.Companion.getZERO();
|
||||
private long usageCount = 0;
|
||||
private PwDate locationChangeDate = new PwDate();
|
||||
private Map<String, String> customData = new HashMap<>();
|
||||
private boolean expires = false;
|
||||
private String notes = "";
|
||||
private boolean isExpanded = true;
|
||||
private String defaultAutoTypeSequence = "";
|
||||
private Boolean enableAutoType = null;
|
||||
private Boolean enableSearching = null;
|
||||
private UUID lastTopVisibleEntry = PwDatabase.UUID_ZERO;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected PwNodeId<UUID> initNodeId() {
|
||||
return new PwNodeIdUUID();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected PwNodeId<UUID> copyNodeId(@NonNull PwNodeId<UUID> nodeId) {
|
||||
return new PwNodeIdUUID(nodeId.getId());
|
||||
}
|
||||
|
||||
public PwGroupV4() {
|
||||
super();
|
||||
}
|
||||
|
||||
public PwGroupV4(Parcel in) {
|
||||
super(in);
|
||||
customIcon = in.readParcelable(PwIconCustom.class.getClassLoader());
|
||||
usageCount = in.readLong();
|
||||
locationChangeDate = in.readParcelable(PwDate.class.getClassLoader());
|
||||
// TODO customData = MemUtil.readStringParcelableMap(in);
|
||||
expires = in.readByte() != 0;
|
||||
notes = in.readString();
|
||||
isExpanded = in.readByte() != 0;
|
||||
defaultAutoTypeSequence = in.readString();
|
||||
byte autoTypeByte = in.readByte();
|
||||
enableAutoType = (autoTypeByte == -1) ? null : autoTypeByte != 0;
|
||||
byte enableSearchingByte = in.readByte();
|
||||
enableSearching = (enableSearchingByte == -1) ? null : enableSearchingByte != 0;
|
||||
lastTopVisibleEntry = (UUID) in.readSerializable();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PwGroupV4 readParentParcelable(Parcel parcel) {
|
||||
return parcel.readParcelable(PwGroupV4.class.getClassLoader());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeParcelable(customIcon, flags);
|
||||
dest.writeLong(usageCount);
|
||||
dest.writeParcelable(locationChangeDate, flags);
|
||||
// TODO MemUtil.writeStringParcelableMap(dest, customData);
|
||||
dest.writeByte((byte) (expires ? 1 : 0));
|
||||
dest.writeString(notes);
|
||||
dest.writeByte((byte) (isExpanded ? 1 : 0));
|
||||
dest.writeString(defaultAutoTypeSequence);
|
||||
dest.writeByte((byte) (enableAutoType == null ? -1 : (enableAutoType ? 1 : 0)));
|
||||
dest.writeByte((byte) (enableAutoType == null ? -1 : (enableAutoType ? 1 : 0)));
|
||||
dest.writeSerializable(lastTopVisibleEntry);
|
||||
}
|
||||
|
||||
public static final Creator<PwGroupV4> CREATOR = new Creator<PwGroupV4>() {
|
||||
@Override
|
||||
public PwGroupV4 createFromParcel(Parcel in) {
|
||||
return new PwGroupV4(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PwGroupV4[] newArray(int size) {
|
||||
return new PwGroupV4[size];
|
||||
}
|
||||
};
|
||||
|
||||
protected void updateWith(PwGroupV4 source) {
|
||||
super.updateWith(source);
|
||||
customIcon = new PwIconCustom(source.customIcon);
|
||||
usageCount = source.usageCount;
|
||||
locationChangeDate = new PwDate(source.locationChangeDate);
|
||||
// Add all custom elements in map
|
||||
customData.clear();
|
||||
for (Map.Entry<String, String> entry : source.customData.entrySet()) {
|
||||
customData.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
expires = source.expires;
|
||||
|
||||
notes = source.notes;
|
||||
isExpanded = source.isExpanded;
|
||||
defaultAutoTypeSequence = source.defaultAutoTypeSequence;
|
||||
enableAutoType = source.enableAutoType;
|
||||
enableSearching = source.enableSearching;
|
||||
lastTopVisibleEntry = source.lastTopVisibleEntry;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Type getType() {
|
||||
return Type.GROUP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParent(PwGroupV4 parent) {
|
||||
super.setParent(parent);
|
||||
locationChangeDate = new PwDate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PwDate getLocationChanged() {
|
||||
return locationChangeDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLocationChanged(PwDate date) {
|
||||
locationChangeDate = date;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUsageCount() {
|
||||
return usageCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUsageCount(long count) {
|
||||
usageCount = count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExpires() {
|
||||
return expires;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExpires(boolean exp) {
|
||||
expires = exp;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public PwIcon getIcon() {
|
||||
if (customIcon == null || customIcon.isUnknown()) { // TODO Encapsulate with PwEntryV4
|
||||
return super.getIcon();
|
||||
} else {
|
||||
return customIcon;
|
||||
}
|
||||
}
|
||||
|
||||
public PwIconCustom getIconCustom() {
|
||||
return customIcon;
|
||||
}
|
||||
|
||||
public void setIconCustom(PwIconCustom icon) {
|
||||
this.customIcon = icon;
|
||||
}
|
||||
|
||||
public PwIcon getIconStandard() {
|
||||
return getIcon();
|
||||
}
|
||||
|
||||
public void setIconStandard(PwIconStandard icon) { // TODO Encapsulate with PwEntryV4
|
||||
super.setIcon(icon);
|
||||
this.customIcon = PwIconCustom.Companion.getZERO();
|
||||
}
|
||||
|
||||
public void putCustomData(String key, String value) {
|
||||
customData.put(key, value);
|
||||
}
|
||||
|
||||
public boolean containsCustomData() {
|
||||
return customData.size() > 0;
|
||||
}
|
||||
|
||||
public String getNotes() {
|
||||
return notes;
|
||||
}
|
||||
|
||||
public void setNotes(String notes) {
|
||||
this.notes = notes;
|
||||
}
|
||||
|
||||
public boolean isExpanded() {
|
||||
return isExpanded;
|
||||
}
|
||||
|
||||
public void setExpanded(boolean expanded) {
|
||||
isExpanded = expanded;
|
||||
}
|
||||
|
||||
public String getDefaultAutoTypeSequence() {
|
||||
return defaultAutoTypeSequence;
|
||||
}
|
||||
|
||||
public void setDefaultAutoTypeSequence(String defaultAutoTypeSequence) {
|
||||
this.defaultAutoTypeSequence = defaultAutoTypeSequence;
|
||||
}
|
||||
|
||||
public Boolean getEnableAutoType() {
|
||||
return enableAutoType;
|
||||
}
|
||||
|
||||
public void setEnableAutoType(Boolean enableAutoType) {
|
||||
this.enableAutoType = enableAutoType;
|
||||
}
|
||||
|
||||
public Boolean getEnableSearching() {
|
||||
return enableSearching;
|
||||
}
|
||||
|
||||
public void setEnableSearching(Boolean enableSearching) {
|
||||
this.enableSearching = enableSearching;
|
||||
}
|
||||
|
||||
public UUID getLastTopVisibleEntry() {
|
||||
return lastTopVisibleEntry;
|
||||
}
|
||||
|
||||
public void setLastTopVisibleEntry(UUID lastTopVisibleEntry) {
|
||||
this.lastTopVisibleEntry = lastTopVisibleEntry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSearchingEnabled() {
|
||||
if (getParent() != null) {
|
||||
return getParent().isSearchingEnabled();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowAddEntryIfIsRoot() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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.element
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
|
||||
import java.util.HashMap
|
||||
import java.util.UUID
|
||||
|
||||
class PwGroupV4 : PwGroup<UUID, PwGroupV4, PwEntryV4>, NodeV4Interface {
|
||||
|
||||
var iconCustom = PwIconCustom.ZERO
|
||||
private val customData = HashMap<String, String>()
|
||||
var notes = ""
|
||||
var isExpanded = true
|
||||
var defaultAutoTypeSequence = ""
|
||||
var enableAutoType: Boolean? = null
|
||||
var enableSearching: Boolean? = null
|
||||
var lastTopVisibleEntry: UUID = PwDatabase.UUID_ZERO
|
||||
|
||||
override val type: Type
|
||||
get() = Type.GROUP
|
||||
|
||||
override val isSearchingEnabled: Boolean
|
||||
get() = parent?.isSearchingEnabled ?: true
|
||||
|
||||
override fun initNodeId(): PwNodeId<UUID> {
|
||||
return PwNodeIdUUID()
|
||||
}
|
||||
|
||||
override fun copyNodeId(nodeId: PwNodeId<UUID>): PwNodeId<UUID> {
|
||||
return PwNodeIdUUID(nodeId.id)
|
||||
}
|
||||
|
||||
constructor() : super()
|
||||
|
||||
constructor(parcel: Parcel) : super(parcel) {
|
||||
iconCustom = parcel.readParcelable(PwIconCustom::class.java.classLoader)
|
||||
usageCount = parcel.readLong()
|
||||
locationChanged = parcel.readParcelable(PwDate::class.java.classLoader)
|
||||
// TODO customData = MemUtil.readStringParcelableMap(in);
|
||||
notes = parcel.readString()
|
||||
isExpanded = parcel.readByte().toInt() != 0
|
||||
defaultAutoTypeSequence = parcel.readString()
|
||||
enableAutoType = parcel.readByte().toInt() != 0
|
||||
enableSearching = parcel.readByte().toInt() != 0
|
||||
lastTopVisibleEntry = parcel.readSerializable() as UUID
|
||||
}
|
||||
|
||||
override fun readParentParcelable(parcel: Parcel): PwGroupV4 {
|
||||
return parcel.readParcelable(PwGroupV4::class.java.classLoader)
|
||||
}
|
||||
|
||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||
super.writeToParcel(dest, flags)
|
||||
dest.writeParcelable(iconCustom, flags)
|
||||
dest.writeLong(usageCount)
|
||||
dest.writeParcelable(locationChanged, flags)
|
||||
// TODO MemUtil.writeStringParcelableMap(dest, customData);
|
||||
dest.writeString(notes)
|
||||
dest.writeByte((if (isExpanded) 1 else 0).toByte())
|
||||
dest.writeString(defaultAutoTypeSequence)
|
||||
dest.writeByte((if (enableAutoType == null) -1 else if (enableAutoType!!) 1 else 0).toByte())
|
||||
dest.writeByte((if (enableSearching == null) -1 else if (enableSearching!!) 1 else 0).toByte())
|
||||
dest.writeSerializable(lastTopVisibleEntry)
|
||||
}
|
||||
|
||||
fun updateWith(source: PwGroupV4) {
|
||||
super.updateWith(source)
|
||||
iconCustom = PwIconCustom(source.iconCustom)
|
||||
usageCount = source.usageCount
|
||||
locationChanged = PwDate(source.locationChanged)
|
||||
// Add all custom elements in map
|
||||
customData.clear()
|
||||
for ((key, value) in source.customData) {
|
||||
customData[key] = value
|
||||
}
|
||||
notes = source.notes
|
||||
isExpanded = source.isExpanded
|
||||
defaultAutoTypeSequence = source.defaultAutoTypeSequence
|
||||
enableAutoType = source.enableAutoType
|
||||
enableSearching = source.enableSearching
|
||||
lastTopVisibleEntry = source.lastTopVisibleEntry
|
||||
}
|
||||
|
||||
override var usageCount: Long = 0
|
||||
|
||||
override var locationChanged = PwDate()
|
||||
|
||||
override fun afterAssignNewParent() {
|
||||
locationChanged = PwDate()
|
||||
}
|
||||
|
||||
fun putCustomData(key: String, value: String) {
|
||||
customData[key] = value
|
||||
}
|
||||
|
||||
fun containsCustomData(): Boolean {
|
||||
return customData.size > 0
|
||||
}
|
||||
|
||||
override fun allowAddEntryIfIsRoot(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmField
|
||||
val CREATOR: Parcelable.Creator<PwGroupV4> = object : Parcelable.Creator<PwGroupV4> {
|
||||
override fun createFromParcel(parcel: Parcel): PwGroupV4 {
|
||||
return PwGroupV4(parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<PwGroupV4?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,11 +23,9 @@ import android.os.Parcelable
|
||||
|
||||
abstract class PwIcon protected constructor() : Parcelable {
|
||||
|
||||
abstract val isMetaStreamIcon: Boolean
|
||||
|
||||
abstract val isUnknown: Boolean
|
||||
|
||||
abstract val iconId: Int
|
||||
abstract val isUnknown: Boolean
|
||||
abstract val isMetaStreamIcon: Boolean
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
|
||||
@@ -30,15 +30,6 @@ class PwIconCustom : PwIcon {
|
||||
@Transient
|
||||
var imageData: ByteArray = ByteArray(0)
|
||||
|
||||
override val isMetaStreamIcon: Boolean
|
||||
get() = false
|
||||
|
||||
override val isUnknown: Boolean
|
||||
get() = this == ZERO
|
||||
|
||||
override val iconId: Int
|
||||
get() = PwIcon.UNKNOWN
|
||||
|
||||
constructor(uuid: UUID, data: ByteArray) : super() {
|
||||
this.uuid = uuid
|
||||
this.imageData = data
|
||||
@@ -82,6 +73,15 @@ class PwIconCustom : PwIcon {
|
||||
return uuid == other.uuid
|
||||
}
|
||||
|
||||
override val iconId: Int
|
||||
get() = UNKNOWN
|
||||
|
||||
override val isUnknown: Boolean
|
||||
get() = this == ZERO
|
||||
|
||||
override val isMetaStreamIcon: Boolean
|
||||
get() = false
|
||||
|
||||
companion object {
|
||||
val ZERO = PwIconCustom(PwDatabase.UUID_ZERO, ByteArray(0))
|
||||
|
||||
|
||||
@@ -23,13 +23,6 @@ import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
|
||||
class PwIconStandard : PwIcon {
|
||||
override val iconId: Int
|
||||
|
||||
override val isUnknown: Boolean
|
||||
get() = iconId == PwIcon.UNKNOWN
|
||||
|
||||
override val isMetaStreamIcon: Boolean
|
||||
get() = iconId == 0
|
||||
|
||||
constructor() {
|
||||
this.iconId = KEY
|
||||
@@ -69,6 +62,14 @@ class PwIconStandard : PwIcon {
|
||||
return iconId == other.iconId
|
||||
}
|
||||
|
||||
override val iconId: Int
|
||||
|
||||
override val isUnknown: Boolean
|
||||
get() = iconId == UNKNOWN
|
||||
|
||||
override val isMetaStreamIcon: Boolean
|
||||
get() = iconId == 0
|
||||
|
||||
companion object {
|
||||
|
||||
const val KEY = 0
|
||||
|
||||
@@ -31,37 +31,29 @@ abstract class PwNode<IdType, Parent : PwGroupInterface<Parent, Entry>, Entry :
|
||||
|
||||
var nodeId: PwNodeId<IdType> = this.initNodeId()
|
||||
|
||||
private var mParent: Parent? = null
|
||||
private var mIcon: PwIcon = PwIconStandard()
|
||||
private var mCreationDate = PwDate()
|
||||
private var mLastModificationDate = PwDate()
|
||||
private var mLastAccessDate = PwDate()
|
||||
private var mExpireDate = PwDate.PW_NEVER_EXPIRE
|
||||
|
||||
protected abstract fun initNodeId(): PwNodeId<IdType>
|
||||
protected abstract fun copyNodeId(nodeId: PwNodeId<IdType>): PwNodeId<IdType>
|
||||
protected abstract fun readParentParcelable(parcel: Parcel): Parent
|
||||
val id: IdType
|
||||
get() = nodeId.id
|
||||
|
||||
protected constructor()
|
||||
|
||||
protected constructor(parcel: Parcel) {
|
||||
this.nodeId = parcel.readParcelable(PwNodeId::class.java.classLoader)
|
||||
this.mParent = this.readParentParcelable(parcel)
|
||||
this.mIcon = parcel.readParcelable(PwIconStandard::class.java.classLoader)
|
||||
this.mCreationDate = parcel.readParcelable(PwDate::class.java.classLoader)
|
||||
this.mLastModificationDate = parcel.readParcelable(PwDate::class.java.classLoader)
|
||||
this.mLastAccessDate = parcel.readParcelable(PwDate::class.java.classLoader)
|
||||
this.mExpireDate = parcel.readParcelable(PwDate::class.java.classLoader)
|
||||
this.parent = this.readParentParcelable(parcel)
|
||||
this.icon = parcel.readParcelable(PwIconStandard::class.java.classLoader)
|
||||
this.creationTime = parcel.readParcelable(PwDate::class.java.classLoader)
|
||||
this.lastModificationTime = parcel.readParcelable(PwDate::class.java.classLoader)
|
||||
this.lastAccessTime = parcel.readParcelable(PwDate::class.java.classLoader)
|
||||
this.expiryTime = parcel.readParcelable(PwDate::class.java.classLoader)
|
||||
}
|
||||
|
||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||
dest.writeParcelable(nodeId, flags)
|
||||
dest.writeParcelable(mParent, flags)
|
||||
dest.writeParcelable(mIcon, flags)
|
||||
dest.writeParcelable(mCreationDate, flags)
|
||||
dest.writeParcelable(mLastModificationDate, flags)
|
||||
dest.writeParcelable(mLastAccessDate, flags)
|
||||
dest.writeParcelable(mExpireDate, flags)
|
||||
dest.writeParcelable(parent, flags)
|
||||
dest.writeParcelable(icon, flags)
|
||||
dest.writeParcelable(creationTime, flags)
|
||||
dest.writeParcelable(lastModificationTime, flags)
|
||||
dest.writeParcelable(lastAccessTime, flags)
|
||||
dest.writeParcelable(expiryTime, flags)
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
@@ -70,47 +62,36 @@ abstract class PwNode<IdType, Parent : PwGroupInterface<Parent, Entry>, Entry :
|
||||
|
||||
protected fun updateWith(source: PwNode<IdType, Parent, Entry>) {
|
||||
this.nodeId = copyNodeId(source.nodeId)
|
||||
this.mParent = source.parent
|
||||
this.mIcon = source.icon
|
||||
this.mCreationDate = PwDate(source.mCreationDate)
|
||||
this.mLastModificationDate = PwDate(source.mLastModificationDate)
|
||||
this.mLastAccessDate = PwDate(source.mLastAccessDate)
|
||||
this.mExpireDate = PwDate(source.mExpireDate)
|
||||
this.parent = source.parent
|
||||
this.icon = source.icon
|
||||
this.creationTime = PwDate(source.creationTime)
|
||||
this.lastModificationTime = PwDate(source.lastModificationTime)
|
||||
this.lastAccessTime = PwDate(source.lastAccessTime)
|
||||
this.expiryTime = PwDate(source.expiryTime)
|
||||
}
|
||||
|
||||
val id: IdType
|
||||
get() = nodeId.id
|
||||
protected abstract fun initNodeId(): PwNodeId<IdType>
|
||||
protected abstract fun copyNodeId(nodeId: PwNodeId<IdType>): PwNodeId<IdType>
|
||||
protected abstract fun readParentParcelable(parcel: Parcel): Parent
|
||||
|
||||
override var parent: Parent?
|
||||
get() = mParent
|
||||
set(value) { mParent = value }
|
||||
final override var parent: Parent? = null
|
||||
|
||||
override var icon: PwIcon
|
||||
get() = mIcon
|
||||
set(value) { mIcon = value }
|
||||
final override var icon: PwIcon = PwIconStandard()
|
||||
|
||||
override var creationTime: PwDate
|
||||
get() = mCreationDate
|
||||
set(value) { mCreationDate = value }
|
||||
final override var creationTime: PwDate = PwDate()
|
||||
|
||||
override var lastModificationTime: PwDate
|
||||
get() = mLastModificationDate
|
||||
set(value) { mLastModificationDate = value }
|
||||
final override var lastModificationTime: PwDate = PwDate()
|
||||
|
||||
override var lastAccessTime: PwDate
|
||||
get() = mLastAccessDate
|
||||
set(value) { mLastAccessDate = value }
|
||||
final override var lastAccessTime: PwDate = PwDate()
|
||||
|
||||
override var expiryTime: PwDate
|
||||
get() = mExpireDate
|
||||
set(value) { mExpireDate = value }
|
||||
final override var expiryTime: PwDate = PwDate.PW_NEVER_EXPIRE
|
||||
|
||||
override var isExpires: Boolean
|
||||
final override var isExpires: Boolean
|
||||
// If expireDate is before NEVER_EXPIRE date less 1 month (to be sure)
|
||||
get() = mExpireDate.date.before(LocalDate.fromDateFields(PwDate.NEVER_EXPIRE).minusMonths(1).toDate())
|
||||
get() = expiryTime.date.before(LocalDate.fromDateFields(PwDate.NEVER_EXPIRE).minusMonths(1).toDate())
|
||||
set(value) {
|
||||
if (!value) {
|
||||
mExpireDate = PwDate.PW_NEVER_EXPIRE
|
||||
expiryTime = PwDate.PW_NEVER_EXPIRE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,6 +102,8 @@ abstract class PwNode<IdType, Parent : PwGroupInterface<Parent, Entry>, Entry :
|
||||
return parent != null
|
||||
}
|
||||
|
||||
override fun afterAssignNewParent() {}
|
||||
|
||||
override fun isContainedIn(container: Parent): Boolean {
|
||||
var cur = this.parent
|
||||
while (cur != null) {
|
||||
|
||||
@@ -25,6 +25,8 @@ interface PwNodeInterface<ParentGroup> : NodeTimeInterface, Parcelable {
|
||||
|
||||
fun containsParent(): Boolean
|
||||
|
||||
fun afterAssignNewParent()
|
||||
|
||||
fun isContainedIn(container: ParentGroup): Boolean
|
||||
|
||||
fun touch(modified: Boolean, touchParents: Boolean)
|
||||
|
||||
@@ -531,7 +531,7 @@ public class ImporterV4 extends Importer<PwDatabaseV4> {
|
||||
} else if ( name.equalsIgnoreCase(PwDatabaseV4XML.ElemNotes) ) {
|
||||
ctxGroup.setNotes(ReadString(xpp));
|
||||
} else if ( name.equalsIgnoreCase(PwDatabaseV4XML.ElemIcon) ) {
|
||||
ctxGroup.setIconStandard(mDatabase.getIconFactory().getIcon((int)ReadUInt(xpp, 0)));
|
||||
ctxGroup.setIcon(mDatabase.getIconFactory().getIcon((int)ReadUInt(xpp, 0)));
|
||||
} else if ( name.equalsIgnoreCase(PwDatabaseV4XML.ElemCustomIconID) ) {
|
||||
ctxGroup.setIconCustom(mDatabase.getIconFactory().getIcon(ReadUuid(xpp)));
|
||||
} else if ( name.equalsIgnoreCase(PwDatabaseV4XML.ElemTimes) ) {
|
||||
@@ -590,13 +590,13 @@ public class ImporterV4 extends Importer<PwDatabaseV4> {
|
||||
ctxEntry.setNodeId(new PwNodeIdUUID(ReadUuid(xpp)));
|
||||
mDatabase.addEntryIndex(ctxEntry);
|
||||
} else if ( name.equalsIgnoreCase(PwDatabaseV4XML.ElemIcon) ) {
|
||||
ctxEntry.setIconStandard(mDatabase.getIconFactory().getIcon((int)ReadUInt(xpp, 0)));
|
||||
ctxEntry.setIcon(mDatabase.getIconFactory().getIcon((int)ReadUInt(xpp, 0)));
|
||||
} else if ( name.equalsIgnoreCase(PwDatabaseV4XML.ElemCustomIconID) ) {
|
||||
ctxEntry.setIconCustom(mDatabase.getIconFactory().getIcon(ReadUuid(xpp)));
|
||||
} else if ( name.equalsIgnoreCase(PwDatabaseV4XML.ElemFgColor) ) {
|
||||
ctxEntry.setForegroundColor(ReadString(xpp));
|
||||
} else if ( name.equalsIgnoreCase(PwDatabaseV4XML.ElemBgColor) ) {
|
||||
ctxEntry.setBackgroupColor(ReadString(xpp));
|
||||
ctxEntry.setBackgroundColor(ReadString(xpp));
|
||||
} else if ( name.equalsIgnoreCase(PwDatabaseV4XML.ElemOverrideUrl) ) {
|
||||
ctxEntry.setOverrideURL(ReadString(xpp));
|
||||
} else if ( name.equalsIgnoreCase(PwDatabaseV4XML.ElemTags) ) {
|
||||
@@ -789,7 +789,7 @@ public class ImporterV4 extends Importer<PwDatabaseV4> {
|
||||
|
||||
return KdbContext.CustomData;
|
||||
} else if ( ctx == KdbContext.Group && name.equalsIgnoreCase(PwDatabaseV4XML.ElemGroup) ) {
|
||||
if ( ctxGroup.getNodeId() == null || ctxGroup.getNodeId().getId().equals(PwDatabase.UUID_ZERO) ) {
|
||||
if ( ctxGroup.getId().equals(PwDatabase.UUID_ZERO) ) {
|
||||
ctxGroup.setNodeId(mDatabase.newGroupId());
|
||||
mDatabase.addGroupIndex(ctxGroup);
|
||||
}
|
||||
@@ -818,7 +818,7 @@ public class ImporterV4 extends Importer<PwDatabaseV4> {
|
||||
return KdbContext.GroupCustomData;
|
||||
|
||||
} else if ( ctx == KdbContext.Entry && name.equalsIgnoreCase(PwDatabaseV4XML.ElemEntry) ) {
|
||||
if ( ctxEntry.getNodeId() == null || ctxEntry.getNodeId().getId().equals(PwDatabase.UUID_ZERO) ) {
|
||||
if ( ctxEntry.getId().equals(PwDatabase.UUID_ZERO) ) {
|
||||
ctxEntry.setNodeId(mDatabase.newEntryId());
|
||||
mDatabase.addEntryIndex(ctxEntry);
|
||||
}
|
||||
@@ -1132,6 +1132,5 @@ public class ImporterV4 extends Importer<PwDatabaseV4> {
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,7 +314,7 @@ public class PwDbV4Output extends PwDbOutput<PwDbHeaderV4> {
|
||||
writeObject(PwDatabaseV4XML.ElemUuid, group.getId());
|
||||
writeObject(PwDatabaseV4XML.ElemName, group.getTitle());
|
||||
writeObject(PwDatabaseV4XML.ElemNotes, group.getNotes());
|
||||
writeObject(PwDatabaseV4XML.ElemIcon, group.getIconStandard().getIconId());
|
||||
writeObject(PwDatabaseV4XML.ElemIcon, group.getIcon().getIconId());
|
||||
|
||||
if (!group.getIconCustom().equals(PwIconCustom.Companion.getZERO())) {
|
||||
writeObject(PwDatabaseV4XML.ElemCustomIconID, group.getIconCustom().getUuid());
|
||||
@@ -338,15 +338,15 @@ public class PwDbV4Output extends PwDbOutput<PwDbHeaderV4> {
|
||||
|
||||
xml.startTag(null, PwDatabaseV4XML.ElemEntry);
|
||||
|
||||
writeObject(PwDatabaseV4XML.ElemUuid, entry.getNodeId().getId());
|
||||
writeObject(PwDatabaseV4XML.ElemIcon, entry.getIconStandard().getIconId());
|
||||
writeObject(PwDatabaseV4XML.ElemUuid, entry.getId());
|
||||
writeObject(PwDatabaseV4XML.ElemIcon, entry.getIcon().getIconId());
|
||||
|
||||
if (!entry.getIconCustom().equals(PwIconCustom.Companion.getZERO())) {
|
||||
writeObject(PwDatabaseV4XML.ElemCustomIconID, entry.getIconCustom().getUuid());
|
||||
}
|
||||
|
||||
writeObject(PwDatabaseV4XML.ElemFgColor, entry.getForegroundColor());
|
||||
writeObject(PwDatabaseV4XML.ElemBgColor, entry.getBackgroupColor());
|
||||
writeObject(PwDatabaseV4XML.ElemBgColor, entry.getBackgroundColor());
|
||||
writeObject(PwDatabaseV4XML.ElemOverrideUrl, entry.getOverrideURL());
|
||||
writeObject(PwDatabaseV4XML.ElemTags, entry.getTags());
|
||||
|
||||
|
||||
@@ -74,12 +74,12 @@ public class PwEntryOutputV3 {
|
||||
// UUID
|
||||
mOS.write(UUID_FIELD_TYPE);
|
||||
mOS.write(UUID_FIELD_SIZE);
|
||||
mOS.write(Types.UUIDtoBytes(mPE.getNodeId().getId()));
|
||||
mOS.write(Types.UUIDtoBytes(mPE.getId()));
|
||||
|
||||
// Group ID
|
||||
mOS.write(GROUPID_FIELD_TYPE);
|
||||
mOS.write(LONG_FOUR);
|
||||
mOS.write(LEDataOutputStream.writeIntBuf(mPE.getParent().getNodeId().getId()));
|
||||
mOS.write(LEDataOutputStream.writeIntBuf(mPE.getParent().getId()));
|
||||
|
||||
// Image ID
|
||||
mOS.write(IMAGEID_FIELD_TYPE);
|
||||
|
||||
@@ -88,7 +88,7 @@ public class EntrySearchHandlerV4 extends NodeHandler<PwEntryV4> {
|
||||
|
||||
private boolean searchID(PwEntryV4 entry) {
|
||||
if (mSearchParametersV4.getSearchInUUIDs()) {
|
||||
String hex = UuidUtil.toHexString(entry.getNodeId().getId());
|
||||
String hex = UuidUtil.toHexString(entry.getId());
|
||||
return StringUtil.INSTANCE.indexOfIgnoreCase(hex, mSearchParametersV4.getSearchString(), Locale.ENGLISH) >= 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user