Better template engine encapsulation

This commit is contained in:
J-Jamet
2021-06-07 14:54:03 +02:00
parent 42c8f0c345
commit a70fca493d
10 changed files with 97 additions and 72 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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