mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Better template engine encapsulation
This commit is contained in:
@@ -91,6 +91,7 @@ class EntryEditActivity : LockingActivity(),
|
||||
private var mParent: Group? = null
|
||||
private var mIsNew: Boolean = false
|
||||
private var mIsTemplate: Boolean = false
|
||||
private var mEntryTemplate: Template? = null
|
||||
|
||||
// Views
|
||||
private var coordinatorLayout: CoordinatorLayout? = null
|
||||
@@ -187,12 +188,6 @@ class EntryEditActivity : LockingActivity(),
|
||||
tempEntryInfo?.username = mDatabase?.defaultUsername ?: ""
|
||||
}
|
||||
|
||||
// Build template selector
|
||||
val templates = mDatabase?.getTemplates(mIsTemplate)
|
||||
val entryTemplate: Template? = mEntry?.let {
|
||||
mDatabase?.getTemplate(it)
|
||||
} ?: if (templates?.isNotEmpty() == true) Template.STANDARD else null
|
||||
|
||||
// Retrieve data from registration
|
||||
val registerInfo = EntrySelectionHelper.retrieveRegisterInfoFromIntent(intent)
|
||||
val searchInfo: SearchInfo? = registerInfo?.searchInfo
|
||||
@@ -209,7 +204,7 @@ class EntryEditActivity : LockingActivity(),
|
||||
// Build fragment to manage entry modification
|
||||
entryEditFragment = supportFragmentManager.findFragmentByTag(ENTRY_EDIT_FRAGMENT_TAG) as? EntryEditFragment?
|
||||
if (entryEditFragment == null) {
|
||||
entryEditFragment = EntryEditFragment.getInstance(tempEntryInfo, entryTemplate)
|
||||
entryEditFragment = EntryEditFragment.getInstance(tempEntryInfo, mEntryTemplate)
|
||||
}
|
||||
entryEditFragment?.apply {
|
||||
drawFactory = mDatabase?.iconDrawableFactory
|
||||
@@ -251,9 +246,11 @@ class EntryEditActivity : LockingActivity(),
|
||||
// Change template dynamically
|
||||
templateSelectorSpinner = findViewById(R.id.entry_edit_template_selector)
|
||||
templateSelectorSpinner?.apply {
|
||||
// Build template selector
|
||||
val templates = mDatabase?.getTemplates(mIsTemplate)
|
||||
if (templates != null && templates.isNotEmpty()) {
|
||||
adapter = TemplatesSelectorAdapter(this@EntryEditActivity, mDatabase, templates)
|
||||
setSelection(templates.indexOf(entryTemplate))
|
||||
setSelection(templates.indexOf(mEntryTemplate))
|
||||
onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||
val newTemplate = templates[position]
|
||||
@@ -341,13 +338,17 @@ class EntryEditActivity : LockingActivity(),
|
||||
}
|
||||
|
||||
private fun checkIfTemplate() {
|
||||
mIsTemplate = mDatabase?.templatesGroup?.let {
|
||||
mDatabase?.templatesGroup == mParent
|
||||
} ?: false
|
||||
if (mIsTemplate) {
|
||||
mEntry?.let {
|
||||
mEntry = mDatabase?.decodeTemplateEntry(it)
|
||||
}
|
||||
// Define is current entry is a template (in direct template group)
|
||||
mIsTemplate = mDatabase?.entryIsTemplate(mEntry) ?: false
|
||||
|
||||
val templates = mDatabase?.getTemplates(mIsTemplate)
|
||||
mEntryTemplate = mEntry?.let {
|
||||
mDatabase?.getTemplate(it)
|
||||
} ?: if (templates?.isNotEmpty() == true) Template.STANDARD else null
|
||||
|
||||
// Decode the entry
|
||||
mEntry?.let {
|
||||
mEntry = mDatabase?.decodeEntryWithTemplateConfiguration(it)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -601,9 +602,8 @@ class EntryEditActivity : LockingActivity(),
|
||||
newEntry.setEntryInfo(mDatabase, newEntryInfo)
|
||||
|
||||
// Encode entry properties for template
|
||||
if (mIsTemplate) {
|
||||
newEntry = mDatabase?.encodeTemplateEntry(newEntry) ?: newEntry
|
||||
}
|
||||
val template = entryEditFragment?.getTemplate() ?: Template.STANDARD // TODO Move
|
||||
newEntry = mDatabase?.encodeEntryWithTemplateConfiguration(newEntry, template) ?: newEntry
|
||||
|
||||
// Delete temp attachment if not used
|
||||
mTempAttachments.forEach { tempAttachmentState ->
|
||||
|
||||
@@ -56,8 +56,6 @@ import com.kunzisoft.keepass.otp.OtpEntryFields
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.view.*
|
||||
import org.joda.time.DateTime
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class EntryEditFragment: DatabaseFragment() {
|
||||
|
||||
@@ -234,11 +232,6 @@ class EntryEditFragment: DatabaseFragment() {
|
||||
}
|
||||
|
||||
val customFieldsNotConsumed = ArrayList(mEntryInfo.customFields)
|
||||
// Ignore Template field
|
||||
customFieldsNotConsumed.indexOfFirst { it.name == TemplateEngine.TEMPLATE_ENTRY_UUID }.let {
|
||||
if (it != -1)
|
||||
customFieldsNotConsumed.removeAt(it)
|
||||
}
|
||||
|
||||
mTemplate.sections.forEach { templateSection ->
|
||||
|
||||
@@ -445,14 +438,6 @@ class EntryEditFragment: DatabaseFragment() {
|
||||
|
||||
mEntryInfo.customFields = mCustomFieldIds.map {
|
||||
getCustomField(it.label)
|
||||
}.toMutableList().also { customFields ->
|
||||
// Add template field
|
||||
if (mTemplate != Template.STANDARD
|
||||
&& mTemplate != Template.CREATION) {
|
||||
TemplateField.getTemplateUUIDField(mTemplate)?.let { templateField ->
|
||||
customFields.add(templateField)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mEntryInfo.otpModel = OtpEntryFields.parseFields { key ->
|
||||
|
||||
@@ -250,9 +250,7 @@ class EntryFragment: DatabaseFragment() {
|
||||
entryInfo?.customFields?.forEach { field ->
|
||||
val label = field.name
|
||||
// OTP field is already managed in dedicated view
|
||||
// Template UUID must not be shown
|
||||
if (label != OtpEntryFields.OTP_TOKEN_FIELD
|
||||
&& label != TemplateEngine.TEMPLATE_ENTRY_UUID) {
|
||||
if (label != OtpEntryFields.OTP_TOKEN_FIELD) {
|
||||
val value = field.protectedValue
|
||||
val allowCopyProtectedField = !value.isProtected || allowCopyPasswordAndProtectedFields
|
||||
if (allowCopyProtectedField) {
|
||||
|
||||
@@ -154,18 +154,25 @@ class Database {
|
||||
return null
|
||||
}
|
||||
|
||||
fun decodeTemplateEntry(entry: Entry): Entry {
|
||||
fun entryIsTemplate(entry: Entry?): Boolean {
|
||||
// Define is current entry is a template (in direct template group)
|
||||
if (entry == null || templatesGroup == null)
|
||||
return false
|
||||
return templatesGroup == entry.parent
|
||||
}
|
||||
|
||||
fun decodeEntryWithTemplateConfiguration(entry: Entry): Entry {
|
||||
entry.entryKDBX?.let {
|
||||
mDatabaseKDBX?.decodeTemplateEntry(it)?.let { decode ->
|
||||
mDatabaseKDBX?.decodeEntryWithTemplateConfiguration(it, entryIsTemplate(entry))?.let { decode ->
|
||||
return Entry(decode)
|
||||
}
|
||||
}
|
||||
return entry
|
||||
}
|
||||
|
||||
fun encodeTemplateEntry(entry: Entry): Entry {
|
||||
fun encodeEntryWithTemplateConfiguration(entry: Entry, template: Template): Entry {
|
||||
entry.entryKDBX?.let {
|
||||
mDatabaseKDBX?.encodeTemplateEntry(it)?.let { encode ->
|
||||
mDatabaseKDBX?.encodeEntryWithTemplateConfiguration(it, entryIsTemplate(entry), template)?.let { encode ->
|
||||
return Entry(encode)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,12 +369,20 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
|
||||
return mTemplateEngine.getTemplate(entry)
|
||||
}
|
||||
|
||||
fun decodeTemplateEntry(entryKDBX: EntryKDBX): EntryKDBX {
|
||||
return mTemplateEngine.decodeTemplateEntry(entryKDBX)
|
||||
fun decodeEntryWithTemplateConfiguration(entryKDBX: EntryKDBX, entryIsTemplate: Boolean): EntryKDBX {
|
||||
return if (entryIsTemplate) {
|
||||
mTemplateEngine.decodeTemplateEntry(entryKDBX)
|
||||
} else {
|
||||
mTemplateEngine.removeMetaTemplateRecognitionFromEntry(entryKDBX)
|
||||
}
|
||||
}
|
||||
|
||||
fun encodeTemplateEntry(entryKDBX: EntryKDBX): EntryKDBX {
|
||||
return mTemplateEngine.encodeTemplateEntry(entryKDBX)
|
||||
fun encodeEntryWithTemplateConfiguration(entryKDBX: EntryKDBX, entryIsTemplate: Boolean, template: Template): EntryKDBX {
|
||||
return if (entryIsTemplate) {
|
||||
mTemplateEngine.encodeTemplateEntry(entryKDBX)
|
||||
} else {
|
||||
mTemplateEngine.addMetaTemplateRecognitionToEntry(template, entryKDBX)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -297,8 +297,8 @@ class EntryKDBX : EntryVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
|
||||
fields[label] = value
|
||||
}
|
||||
|
||||
fun removeField(field: Field) {
|
||||
fields.remove(field.name)
|
||||
fun removeField(name: String) {
|
||||
fields.remove(name)
|
||||
}
|
||||
|
||||
fun removeAllFields() {
|
||||
|
||||
@@ -25,7 +25,6 @@ import com.kunzisoft.keepass.database.element.database.DatabaseVersioned
|
||||
import com.kunzisoft.keepass.database.element.icon.IconImage
|
||||
import com.kunzisoft.keepass.database.element.icon.IconImageStandard
|
||||
import com.kunzisoft.keepass.database.element.icon.IconImageStandard.Companion.BUILD_ID
|
||||
import com.kunzisoft.keepass.database.element.template.TemplateEngine.Companion.TEMPLATE_LABEL_VERSION
|
||||
import com.kunzisoft.keepass.database.element.template.TemplateField.LABEL_EXPIRATION
|
||||
import com.kunzisoft.keepass.database.element.template.TemplateField.LABEL_NOTES
|
||||
import com.kunzisoft.keepass.database.element.template.TemplateField.LABEL_PASSWORD
|
||||
@@ -141,8 +140,7 @@ class Template : Parcelable {
|
||||
get() {
|
||||
val sections = ArrayList<TemplateSection>()
|
||||
val mainSection = TemplateSection(ArrayList<TemplateAttribute>().apply {
|
||||
add(TemplateAttribute(TEMPLATE_LABEL_VERSION, TemplateAttributeType.INLINE))
|
||||
// Dynamic part after this
|
||||
// Dynamic part
|
||||
})
|
||||
sections.add(mainSection)
|
||||
return Template(UUID(0, 1),
|
||||
|
||||
@@ -192,12 +192,15 @@ class TemplateEngine(private val mDatabase: DatabaseKDBX) {
|
||||
val entryCopy = EntryKDBX().apply {
|
||||
updateWith(templateEntry)
|
||||
}
|
||||
templateEntry.doForEachDecodedCustomField { field, ->
|
||||
// Remove template version
|
||||
entryCopy.removeField(TEMPLATE_LABEL_VERSION)
|
||||
// Dynamic attributes
|
||||
templateEntry.doForEachDecodedCustomField { field ->
|
||||
conditionCustomFields(attributes, field, {
|
||||
if (field.name.startsWith(TEMPLATE_ATTRIBUTE_TYPE_PREFIX)) {
|
||||
it.attribute.defaultValue = field.protectedValue.stringValue
|
||||
}
|
||||
entryCopy.removeField(field)
|
||||
entryCopy.removeField(field.name)
|
||||
}, { })
|
||||
}
|
||||
|
||||
@@ -219,6 +222,9 @@ class TemplateEngine(private val mDatabase: DatabaseKDBX) {
|
||||
val entryCopy = EntryKDBX().apply {
|
||||
updateWith(templateEntry)
|
||||
}
|
||||
// Add template version
|
||||
entryCopy.putField(TEMPLATE_LABEL_VERSION, ProtectedString(false, "1"))
|
||||
// Dynamic attributes
|
||||
var index = 0
|
||||
templateEntry.doForEachDecodedCustomField { field ->
|
||||
val label = field.name.removePrefix(PREFIX_DECODED_TEMPLATE).removeSuffix(SUFFIX_DECODED_TEMPLATE)
|
||||
@@ -228,7 +234,7 @@ class TemplateEngine(private val mDatabase: DatabaseKDBX) {
|
||||
// Keep template version as is
|
||||
}
|
||||
else -> {
|
||||
entryCopy.removeField(field)
|
||||
entryCopy.removeField(field.name)
|
||||
entryCopy.putField(TEMPLATE_ATTRIBUTE_POSITION_PREFIX+'_'+label,
|
||||
ProtectedString(false, index.toString()))
|
||||
entryCopy.putField(TEMPLATE_ATTRIBUTE_TITLE_PREFIX+'_'+label,
|
||||
@@ -248,13 +254,45 @@ class TemplateEngine(private val mDatabase: DatabaseKDBX) {
|
||||
return entryCopy
|
||||
}
|
||||
|
||||
private fun getTemplateUUIDField(template: Template): Field? {
|
||||
UuidUtil.toHexString(template.uuid)?.let { uuidString ->
|
||||
return Field(TEMPLATE_ENTRY_UUID,
|
||||
ProtectedString(false, uuidString))
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun removeMetaTemplateRecognitionFromEntry(entry: EntryKDBX): EntryKDBX {
|
||||
val entryCopy = EntryKDBX().apply {
|
||||
updateWith(entry)
|
||||
}
|
||||
entryCopy.removeField(TEMPLATE_ENTRY_UUID)
|
||||
return entryCopy
|
||||
}
|
||||
|
||||
fun addMetaTemplateRecognitionToEntry(template: Template, entry: EntryKDBX): EntryKDBX {
|
||||
val entryCopy = EntryKDBX().apply {
|
||||
updateWith(entry)
|
||||
}
|
||||
// Add template field
|
||||
if (template != Template.STANDARD
|
||||
&& template != Template.CREATION) {
|
||||
getTemplateUUIDField(template)?.let { templateField ->
|
||||
entryCopy.putField(templateField)
|
||||
}
|
||||
} else {
|
||||
entryCopy.removeField(TEMPLATE_ENTRY_UUID)
|
||||
}
|
||||
return entryCopy
|
||||
}
|
||||
|
||||
companion object {
|
||||
private data class TemplateAttributePosition(var position: Int, var attribute: TemplateAttribute)
|
||||
|
||||
private val TAG = TemplateEngine::class.java.name
|
||||
|
||||
const val PREFIX_DECODED_TEMPLATE = "["
|
||||
const val SUFFIX_DECODED_TEMPLATE = "]"
|
||||
private const val PREFIX_DECODED_TEMPLATE = "["
|
||||
private const val SUFFIX_DECODED_TEMPLATE = "]"
|
||||
|
||||
// Custom template ref
|
||||
private const val TEMPLATE_ATTRIBUTE_TITLE = "@title"
|
||||
@@ -265,8 +303,8 @@ class TemplateEngine(private val mDatabase: DatabaseKDBX) {
|
||||
private const val TEMPLATE_ATTRIBUTE_EXPIRES = "@expires"
|
||||
private const val TEMPLATE_ATTRIBUTE_NOTES = "@notes"
|
||||
|
||||
const val TEMPLATE_LABEL_VERSION = "_etm_template"
|
||||
const val TEMPLATE_ENTRY_UUID = "_etm_template_uuid"
|
||||
private const val TEMPLATE_LABEL_VERSION = "_etm_template"
|
||||
private const val TEMPLATE_ENTRY_UUID = "_etm_template_uuid"
|
||||
private const val TEMPLATE_ATTRIBUTE_POSITION_PREFIX = "_etm_position"
|
||||
private const val TEMPLATE_ATTRIBUTE_TITLE_PREFIX = "_etm_title"
|
||||
private const val TEMPLATE_ATTRIBUTE_TYPE_PREFIX = "_etm_type"
|
||||
@@ -284,6 +322,11 @@ class TemplateEngine(private val mDatabase: DatabaseKDBX) {
|
||||
return resources.getString(R.string.templates)
|
||||
}
|
||||
|
||||
fun isTemplateNameAttribute(name: String): Boolean {
|
||||
return name.startsWith(PREFIX_DECODED_TEMPLATE)
|
||||
&& name.endsWith(SUFFIX_DECODED_TEMPLATE)
|
||||
}
|
||||
|
||||
fun decodeTemplateAttribute(name: String): String {
|
||||
return when {
|
||||
TEMPLATE_LABEL_VERSION.equals(name, true) -> TemplateField.LABEL_VERSION
|
||||
|
||||
@@ -2,11 +2,6 @@ package com.kunzisoft.keepass.database.element.template
|
||||
|
||||
import android.content.Context
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.database.element.security.ProtectedString
|
||||
import com.kunzisoft.keepass.database.element.Field
|
||||
import com.kunzisoft.keepass.database.element.template.TemplateEngine.Companion.PREFIX_DECODED_TEMPLATE
|
||||
import com.kunzisoft.keepass.database.element.template.TemplateEngine.Companion.SUFFIX_DECODED_TEMPLATE
|
||||
import com.kunzisoft.keepass.utils.UuidUtil
|
||||
|
||||
object TemplateField {
|
||||
|
||||
@@ -47,8 +42,7 @@ object TemplateField {
|
||||
|
||||
fun getLocalizedName(context: Context?, name: String): String {
|
||||
if (context == null
|
||||
|| name.startsWith(PREFIX_DECODED_TEMPLATE)
|
||||
&& name.endsWith(SUFFIX_DECODED_TEMPLATE))
|
||||
|| TemplateEngine.isTemplateNameAttribute(name))
|
||||
return name
|
||||
|
||||
return when {
|
||||
@@ -79,12 +73,4 @@ object TemplateField {
|
||||
else -> name
|
||||
}
|
||||
}
|
||||
|
||||
fun getTemplateUUIDField(template: Template): Field? {
|
||||
UuidUtil.toHexString(template.uuid)?.let { uuidString ->
|
||||
return Field(TemplateEngine.TEMPLATE_ENTRY_UUID,
|
||||
ProtectedString(false, uuidString))
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ class EntryViewModel: ViewModel() {
|
||||
entry?.touch(modified = false, touchParents = false)
|
||||
// To simplify template field visibility
|
||||
entry?.let {
|
||||
// TODO entry = mDatabase.decodeTemplateEntry(it)
|
||||
entry = mDatabase.decodeEntryWithTemplateConfiguration(it)
|
||||
}
|
||||
_entry.value = EntryHistory(entry, entryLastVersion, historyPosition)
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user