mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Better custom fields implementation, fix references
This commit is contained in:
@@ -212,10 +212,12 @@ class EntryActivity : LockingHideActivity() {
|
||||
entryContentsView?.assignComment(entry.notes)
|
||||
|
||||
// Assign custom fields
|
||||
if (entry.allowExtraFields()) {
|
||||
if (entry.allowCustomFields()) {
|
||||
entryContentsView?.clearExtraFields()
|
||||
|
||||
entry.fields.doActionToAllCustomProtectedField { label, value ->
|
||||
for (element in entry.customFields.entries) {
|
||||
val label = element.key
|
||||
val value = element.value
|
||||
|
||||
val allowCopyProtectedField = !value.isProtected || allowCopyPasswordAndProtectedFields
|
||||
if (allowCopyProtectedField) {
|
||||
|
||||
@@ -152,7 +152,7 @@ class EntryEditActivity : LockingHideActivity(),
|
||||
saveView = findViewById(R.id.entry_edit_save)
|
||||
saveView?.setOnClickListener { saveEntry() }
|
||||
|
||||
entryEditContentsView?.allowCustomField(mNewEntry?.allowExtraFields() == true) { addNewCustomField() }
|
||||
entryEditContentsView?.allowCustomField(mNewEntry?.allowCustomFields() == true) { addNewCustomField() }
|
||||
|
||||
// Verify the education views
|
||||
entryEditActivityEducation = EntryEditActivityEducation(this)
|
||||
@@ -172,8 +172,8 @@ class EntryEditActivity : LockingHideActivity(),
|
||||
url = newEntry.url
|
||||
password = newEntry.password
|
||||
notes = newEntry.notes
|
||||
newEntry.fields.doActionToAllCustomProtectedField { key, value ->
|
||||
addNewCustomField(key, value)
|
||||
for (entry in newEntry.customFields.entries) {
|
||||
addNewCustomField(entry.key, entry.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -307,7 +307,7 @@ class EntryEditActivity : LockingHideActivity(),
|
||||
)
|
||||
if (!generatePasswordEducationPerformed) {
|
||||
// entryNewFieldEducationPerformed
|
||||
mNewEntry != null && mNewEntry!!.allowExtraFields() && !mNewEntry!!.containsCustomFields()
|
||||
mNewEntry != null && mNewEntry!!.allowCustomFields() && mNewEntry!!.customFields.isEmpty()
|
||||
&& addNewFieldView != null && addNewFieldView.visibility == View.VISIBLE
|
||||
&& entryEditActivityEducation.checkAndPerformedEntryNewFieldEducation(
|
||||
addNewFieldView,
|
||||
|
||||
@@ -24,8 +24,8 @@ class EntryCursorV4 : EntryCursor<PwEntryV4>() {
|
||||
entry.notes
|
||||
))
|
||||
|
||||
entry.fields.doActionToAllCustomProtectedField { key, value ->
|
||||
extraFieldCursor.addExtraField(entryId, key, value)
|
||||
for (element in entry.customFields.entries) {
|
||||
extraFieldCursor.addExtraField(entryId, element.key, element.value)
|
||||
}
|
||||
|
||||
entryId++
|
||||
|
||||
@@ -227,42 +227,18 @@ class EntryVersioned : NodeVersioned, PwEntryInterface<GroupVersioned> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve extra fields to show, key is the label, value is the value of field
|
||||
* Retrieve custom fields to show, key is the label, value is the value of field (protected or not)
|
||||
* @return Map of label/value
|
||||
*/
|
||||
val fields: ExtraFields
|
||||
get() = pwEntryV4?.fields ?: ExtraFields()
|
||||
val customFields: HashMap<String, ProtectedString>
|
||||
get() = pwEntryV4?.customFields ?: HashMap()
|
||||
|
||||
/**
|
||||
* To redefine if version of entry allow extra field,
|
||||
* @return true if entry allows extra field
|
||||
* To redefine if version of entry allow custom field,
|
||||
* @return true if entry allows custom 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
|
||||
fun allowCustomFields(): Boolean {
|
||||
return pwEntryV4?.allowCustomFields() ?: false
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -274,13 +250,6 @@ class EntryVersioned : NodeVersioned, PwEntryInterface<GroupVersioned> {
|
||||
pwEntryV4?.addExtraField(label, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all custom fields
|
||||
*/
|
||||
fun removeAllCustomFields() {
|
||||
pwEntryV4?.removeAllCustomFields()
|
||||
}
|
||||
|
||||
fun startToManageFieldReferences(db: PwDatabaseV4) {
|
||||
pwEntryV4?.startToManageFieldReferences(db)
|
||||
}
|
||||
@@ -327,11 +296,9 @@ class EntryVersioned : NodeVersioned, PwEntryInterface<GroupVersioned> {
|
||||
entryInfo.password = password
|
||||
entryInfo.url = url
|
||||
entryInfo.notes = notes
|
||||
if (containsCustomFields()) {
|
||||
fields.doActionToAllCustomProtectedField { key, value ->
|
||||
for (entry in customFields.entries) {
|
||||
entryInfo.customFields.add(
|
||||
Field(key, value))
|
||||
}
|
||||
Field(entry.key, entry.value))
|
||||
}
|
||||
if (!raw)
|
||||
database?.stopManageEntry(this)
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 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.element.security.ProtectedString
|
||||
import com.kunzisoft.keepass.utils.MemUtil
|
||||
|
||||
import java.util.HashMap
|
||||
|
||||
import com.kunzisoft.keepass.database.element.PwEntryV4.Companion.STR_TITLE
|
||||
import com.kunzisoft.keepass.database.element.PwEntryV4.Companion.STR_USERNAME
|
||||
import com.kunzisoft.keepass.database.element.PwEntryV4.Companion.STR_PASSWORD
|
||||
import com.kunzisoft.keepass.database.element.PwEntryV4.Companion.STR_URL
|
||||
import com.kunzisoft.keepass.database.element.PwEntryV4.Companion.STR_NOTES
|
||||
|
||||
class ExtraFields : Parcelable {
|
||||
|
||||
private var fields: MutableMap<String, ProtectedString> = HashMap()
|
||||
|
||||
/**
|
||||
* @return list of standard and customized fields
|
||||
*/
|
||||
val listOfAllFields: Map<String, ProtectedString>
|
||||
get() = fields
|
||||
|
||||
private val customProtectedFields: Map<String, ProtectedString>
|
||||
get() {
|
||||
val protectedFields = HashMap<String, ProtectedString>()
|
||||
if (fields.isNotEmpty()) {
|
||||
for ((key, value) in fields) {
|
||||
if (isNotStandardField(key)) {
|
||||
protectedFields[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
return protectedFields
|
||||
}
|
||||
|
||||
constructor()
|
||||
|
||||
constructor(extraFields: ExtraFields) : this() {
|
||||
for ((key, value) in extraFields.fields) {
|
||||
fields[key] = ProtectedString(value)
|
||||
}
|
||||
}
|
||||
|
||||
constructor(parcel: Parcel) {
|
||||
fields = MemUtil.readStringParcelableMap(parcel, ProtectedString::class.java)
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||
MemUtil.writeStringParcelableMap(dest, flags, fields)
|
||||
}
|
||||
|
||||
fun containsCustomFields(): Boolean {
|
||||
return customProtectedFields.keys.isNotEmpty()
|
||||
}
|
||||
|
||||
fun containsCustomFieldsProtected(): Boolean {
|
||||
for ((_, value) in customProtectedFields) {
|
||||
if (value.isProtected)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun containsCustomFieldsNotProtected(): Boolean {
|
||||
for ((_, value) in customProtectedFields) {
|
||||
if (!value.isProtected)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun getProtectedStringValue(key: String): String {
|
||||
val value = fields[key] ?: return ""
|
||||
return value.toString()
|
||||
}
|
||||
|
||||
fun putProtectedString(key: String, protectedString: ProtectedString) {
|
||||
fields[key] = protectedString
|
||||
}
|
||||
|
||||
fun putProtectedString(key: String, value: String, protect: Boolean) {
|
||||
val ps = ProtectedString(protect, value)
|
||||
fields[key] = ps
|
||||
}
|
||||
|
||||
fun doActionToAllCustomProtectedField(actionProtected: (key: String, value: ProtectedString)-> Unit) {
|
||||
for ((key, value) in customProtectedFields) {
|
||||
actionProtected.invoke(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
interface ActionProtected {
|
||||
fun doAction(key: String, value: ProtectedString)
|
||||
}
|
||||
|
||||
fun removeAllCustomFields() {
|
||||
val iterator = fields.entries.iterator()
|
||||
while (iterator.hasNext()) {
|
||||
val pair = iterator.next()
|
||||
if (isNotStandardField(pair.key)) {
|
||||
iterator.remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmField
|
||||
val CREATOR: Parcelable.Creator<ExtraFields> = object : Parcelable.Creator<ExtraFields> {
|
||||
override fun createFromParcel(parcel: Parcel): ExtraFields {
|
||||
return ExtraFields(parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<ExtraFields?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isNotStandardField(key: String): Boolean {
|
||||
return (key != STR_TITLE && key != STR_USERNAME
|
||||
&& key != STR_PASSWORD && key != STR_URL
|
||||
&& key != STR_NOTES)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,8 +48,7 @@ class PwEntryV4 : PwEntry<PwGroupV4, PwEntryV4>, NodeV4Interface {
|
||||
}
|
||||
var iconCustom = PwIconCustom.UNKNOWN_ICON
|
||||
private var customData = HashMap<String, String>()
|
||||
var fields = ExtraFields()
|
||||
private set
|
||||
var fields = HashMap<String, ProtectedString>()
|
||||
val binaries = HashMap<String, ProtectedBinary>()
|
||||
var foregroundColor = ""
|
||||
var backgroundColor = ""
|
||||
@@ -63,9 +62,9 @@ class PwEntryV4 : PwEntry<PwGroupV4, PwEntryV4>, NodeV4Interface {
|
||||
get() {
|
||||
var size = FIXED_LENGTH_SIZE
|
||||
|
||||
for ((key, value) in fields.listOfAllFields) {
|
||||
size += key.length.toLong()
|
||||
size += value.length().toLong()
|
||||
for (entry in fields.entries) {
|
||||
size += entry.key.length.toLong()
|
||||
size += entry.value.length().toLong()
|
||||
}
|
||||
|
||||
for ((key, value) in binaries) {
|
||||
@@ -96,7 +95,7 @@ class PwEntryV4 : PwEntry<PwGroupV4, PwEntryV4>, NodeV4Interface {
|
||||
usageCount = parcel.readLong()
|
||||
locationChanged = parcel.readParcelable(PwDate::class.java.classLoader)
|
||||
customData = MemUtil.readStringParcelableMap(parcel)
|
||||
fields = parcel.readParcelable(ExtraFields::class.java.classLoader)
|
||||
fields = MemUtil.readStringParcelableMap(parcel, ProtectedString::class.java)
|
||||
// TODO binaries = MemUtil.readStringParcelableMap(parcel, ProtectedBinary.class);
|
||||
foregroundColor = parcel.readString()
|
||||
backgroundColor = parcel.readString()
|
||||
@@ -114,7 +113,7 @@ class PwEntryV4 : PwEntry<PwGroupV4, PwEntryV4>, NodeV4Interface {
|
||||
dest.writeLong(usageCount)
|
||||
dest.writeParcelable(locationChanged, flags)
|
||||
MemUtil.writeStringParcelableMap(dest, customData)
|
||||
dest.writeParcelable(fields, flags)
|
||||
MemUtil.writeStringParcelableMap(dest, flags, fields)
|
||||
// TODO MemUtil.writeStringParcelableMap(dest, flags, binaries);
|
||||
dest.writeString(foregroundColor)
|
||||
dest.writeString(backgroundColor)
|
||||
@@ -137,13 +136,11 @@ class PwEntryV4 : PwEntry<PwGroupV4, PwEntryV4>, NodeV4Interface {
|
||||
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)
|
||||
}
|
||||
customData.putAll(source.customData)
|
||||
fields.clear()
|
||||
fields.putAll(source.fields)
|
||||
binaries.clear()
|
||||
binaries.putAll(source.binaries)
|
||||
foregroundColor = source.foregroundColor
|
||||
backgroundColor = source.backgroundColor
|
||||
overrideURL = source.overrideURL
|
||||
@@ -188,17 +185,18 @@ class PwEntryV4 : PwEntry<PwGroupV4, PwEntryV4>, NodeV4Interface {
|
||||
* @return
|
||||
*/
|
||||
private fun decodeRefKey(decodeRef: Boolean, key: String): String {
|
||||
val text = fields.getProtectedStringValue(key)
|
||||
return fields[key]?.toString()?.let { text ->
|
||||
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)
|
||||
fields[STR_TITLE] = ProtectedString(protect, value)
|
||||
}
|
||||
|
||||
override val type: Type
|
||||
@@ -208,28 +206,28 @@ class PwEntryV4 : PwEntry<PwGroupV4, PwEntryV4>, NodeV4Interface {
|
||||
get() = decodeRefKey(mDecodeRef, STR_USERNAME)
|
||||
set(value) {
|
||||
val protect = mDatabase != null && mDatabase!!.memoryProtection.protectUserName
|
||||
fields.putProtectedString(STR_USERNAME, value, protect)
|
||||
fields[STR_USERNAME] = ProtectedString(protect, value)
|
||||
}
|
||||
|
||||
override var password: String
|
||||
get() = decodeRefKey(mDecodeRef, STR_PASSWORD)
|
||||
set(value) {
|
||||
val protect = mDatabase != null && mDatabase!!.memoryProtection.protectPassword
|
||||
fields.putProtectedString(STR_PASSWORD, value, protect)
|
||||
fields[STR_PASSWORD] = ProtectedString(protect, value)
|
||||
}
|
||||
|
||||
override var url
|
||||
get() = decodeRefKey(mDecodeRef, STR_URL)
|
||||
set(value) {
|
||||
val protect = mDatabase != null && mDatabase!!.memoryProtection.protectUrl
|
||||
fields.putProtectedString(STR_URL, value, protect)
|
||||
fields[STR_URL] = ProtectedString(protect, value)
|
||||
}
|
||||
|
||||
override var notes: String
|
||||
get() = decodeRefKey(mDecodeRef, STR_NOTES)
|
||||
set(value) {
|
||||
val protect = mDatabase != null && mDatabase!!.memoryProtection.protectNotes
|
||||
fields.putProtectedString(STR_NOTES, value, protect)
|
||||
fields[STR_NOTES] = ProtectedString(protect, value)
|
||||
}
|
||||
|
||||
override var usageCount: Long = 0
|
||||
@@ -240,28 +238,33 @@ class PwEntryV4 : PwEntry<PwGroupV4, PwEntryV4>, NodeV4Interface {
|
||||
locationChanged = PwDate()
|
||||
}
|
||||
|
||||
fun allowExtraFields(): Boolean {
|
||||
private fun isStandardField(key: String): Boolean {
|
||||
return (key == STR_TITLE
|
||||
|| key == STR_USERNAME
|
||||
|| key == STR_PASSWORD
|
||||
|| key == STR_URL
|
||||
|| key == STR_NOTES)
|
||||
}
|
||||
|
||||
var customFields = HashMap<String, ProtectedString>()
|
||||
get() {
|
||||
field.clear()
|
||||
for (entry in fields.entries) {
|
||||
val key = entry.key
|
||||
val value = entry.value
|
||||
if (!isStandardField(entry.key)) {
|
||||
field[key] = ProtectedString(value.isProtected, decodeRefKey(mDecodeRef, key))
|
||||
}
|
||||
}
|
||||
return field
|
||||
}
|
||||
|
||||
fun allowCustomFields(): 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()
|
||||
fields[label] = value
|
||||
}
|
||||
|
||||
fun putProtectedBinary(key: String, value: ProtectedBinary) {
|
||||
|
||||
@@ -349,7 +349,7 @@ class PwDbV4Output(private val mDatabaseV4: PwDatabaseV4, outputStream: OutputSt
|
||||
|
||||
writeList(PwDatabaseV4XML.ElemTimes, entry)
|
||||
|
||||
writeList(entry.fields.listOfAllFields, true)
|
||||
writeList(entry.fields, true)
|
||||
writeList(entry.binaries)
|
||||
writeList(PwDatabaseV4XML.ElemAutoType, entry.autoType)
|
||||
|
||||
|
||||
@@ -33,13 +33,13 @@ class EntrySearchStringIteratorV4 : EntrySearchStringIterator {
|
||||
|
||||
constructor(entry: PwEntryV4) {
|
||||
this.mSearchParametersV4 = SearchParametersV4()
|
||||
mSetIterator = entry.fields.listOfAllFields.entries.iterator()
|
||||
mSetIterator = entry.fields.entries.iterator()
|
||||
advance()
|
||||
}
|
||||
|
||||
constructor(entry: PwEntryV4, searchParametersV4: SearchParametersV4) {
|
||||
this.mSearchParametersV4 = searchParametersV4
|
||||
mSetIterator = entry.fields.listOfAllFields.entries.iterator()
|
||||
mSetIterator = entry.fields.entries.iterator()
|
||||
advance()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user