mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Fix #327 save to previous database version when conditions are required
This commit is contained in:
@@ -296,6 +296,8 @@ abstract class PwDatabase<Group : PwGroup<*, Group, Entry>, Entry : PwEntry<Grou
|
||||
|
||||
abstract fun rootCanContainsEntry(): Boolean
|
||||
|
||||
abstract fun containsCustomData(): Boolean
|
||||
|
||||
fun addGroupTo(newGroup: Group, parent: Group?) {
|
||||
// Add tree to parent tree
|
||||
parent?.addChildGroup(newGroup)
|
||||
|
||||
@@ -154,6 +154,10 @@ class PwDatabaseV3 : PwDatabase<PwGroupV3, PwEntryV3>() {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun containsCustomData(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun isBackup(group: PwGroupV3): Boolean {
|
||||
var currentGroup: PwGroupV3? = group
|
||||
while (currentGroup != null) {
|
||||
|
||||
@@ -196,6 +196,10 @@ class PwDatabaseV4 : PwDatabase<PwGroupV4, PwEntryV4> {
|
||||
this.customData[label] = value
|
||||
}
|
||||
|
||||
override fun containsCustomData(): Boolean {
|
||||
return getCustomData().isNotEmpty()
|
||||
}
|
||||
|
||||
@Throws(InvalidKeyFileException::class, IOException::class)
|
||||
public override fun getMasterKey(key: String?, keyInputStream: InputStream?): ByteArray {
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import com.kunzisoft.keepass.database.element.security.ProtectedString
|
||||
import com.kunzisoft.keepass.utils.MemoryUtil
|
||||
import java.util.*
|
||||
|
||||
class PwEntryV4 : PwEntry<PwGroupV4, PwEntryV4>, NodeV4Interface {
|
||||
class PwEntryV4 : PwEntry<PwGroupV4, PwEntryV4>, PwNodeV4Interface {
|
||||
|
||||
// To decode each field not parcelable
|
||||
@Transient
|
||||
@@ -275,12 +275,12 @@ class PwEntryV4 : PwEntry<PwGroupV4, PwEntryV4>, NodeV4Interface {
|
||||
return history.size
|
||||
}
|
||||
|
||||
fun putCustomData(key: String, value: String) {
|
||||
override fun putCustomData(key: String, value: String) {
|
||||
customData[key] = value
|
||||
}
|
||||
|
||||
fun containsCustomData(): Boolean {
|
||||
return customData.size > 0
|
||||
override fun containsCustomData(): Boolean {
|
||||
return customData.isNotEmpty()
|
||||
}
|
||||
|
||||
fun addEntryToHistory(entry: PwEntryV4) {
|
||||
|
||||
@@ -25,7 +25,7 @@ import android.os.Parcelable
|
||||
import java.util.HashMap
|
||||
import java.util.UUID
|
||||
|
||||
class PwGroupV4 : PwGroup<UUID, PwGroupV4, PwEntryV4>, NodeV4Interface {
|
||||
class PwGroupV4 : PwGroup<UUID, PwGroupV4, PwEntryV4>, PwNodeV4Interface {
|
||||
|
||||
// TODO Encapsulate
|
||||
override var icon: PwIcon
|
||||
@@ -123,12 +123,12 @@ class PwGroupV4 : PwGroup<UUID, PwGroupV4, PwEntryV4>, NodeV4Interface {
|
||||
locationChanged = PwDate()
|
||||
}
|
||||
|
||||
fun putCustomData(key: String, value: String) {
|
||||
override fun putCustomData(key: String, value: String) {
|
||||
customData[key] = value
|
||||
}
|
||||
|
||||
fun containsCustomData(): Boolean {
|
||||
return customData.size > 0
|
||||
override fun containsCustomData(): Boolean {
|
||||
return customData.isNotEmpty()
|
||||
}
|
||||
|
||||
override fun allowAddEntryIfIsRoot(): Boolean {
|
||||
|
||||
@@ -19,10 +19,14 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.database.element
|
||||
|
||||
interface NodeV4Interface : NodeTimeInterface {
|
||||
interface PwNodeV4Interface : NodeTimeInterface {
|
||||
|
||||
var usageCount: Long
|
||||
|
||||
var locationChanged: PwDate
|
||||
|
||||
fun putCustomData(key: String, value: String)
|
||||
|
||||
fun containsCustomData(): Boolean
|
||||
|
||||
}
|
||||
@@ -23,7 +23,11 @@ import com.kunzisoft.keepass.crypto.CrsAlgorithm
|
||||
import com.kunzisoft.keepass.crypto.keyDerivation.AesKdf
|
||||
import com.kunzisoft.keepass.crypto.keyDerivation.KdfFactory
|
||||
import com.kunzisoft.keepass.crypto.keyDerivation.KdfParameters
|
||||
import com.kunzisoft.keepass.database.NodeHandler
|
||||
import com.kunzisoft.keepass.database.element.PwNodeV4Interface
|
||||
import com.kunzisoft.keepass.database.element.PwDatabaseV4
|
||||
import com.kunzisoft.keepass.database.element.PwEntryV4
|
||||
import com.kunzisoft.keepass.database.element.PwGroupV4
|
||||
import com.kunzisoft.keepass.database.exception.InvalidDBVersionException
|
||||
import com.kunzisoft.keepass.stream.CopyInputStream
|
||||
import com.kunzisoft.keepass.stream.HmacBlockStream
|
||||
@@ -88,18 +92,42 @@ class PwDbHeaderV4(private val databaseV4: PwDatabaseV4) : PwDbHeader() {
|
||||
this.masterSeed = ByteArray(32)
|
||||
}
|
||||
|
||||
private inner class NodeHasCustomData<T:PwNodeV4Interface> : NodeHandler<T>() {
|
||||
|
||||
internal var containsCustomData = false
|
||||
|
||||
override fun operate(node: T): Boolean {
|
||||
if (node.containsCustomData()) {
|
||||
containsCustomData = true
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMinKdbxVersion(databaseV4: PwDatabaseV4): Long {
|
||||
// https://keepass.info/help/kb/kdbx_4.html
|
||||
|
||||
// Return v4 if AES is not use
|
||||
if (databaseV4.kdfParameters != null
|
||||
&& databaseV4.kdfParameters!!.uuid != AesKdf.CIPHER_UUID) {
|
||||
return FILE_VERSION_32_4
|
||||
}
|
||||
|
||||
if (databaseV4.rootGroup == null) {
|
||||
return FILE_VERSION_32_3
|
||||
}
|
||||
|
||||
// Return v4 if AES is not use
|
||||
if (databaseV4.kdfParameters != null && databaseV4.kdfParameters!!.uuid != AesKdf.CIPHER_UUID) {
|
||||
return FILE_VERSION_32_4
|
||||
val entryHandler = NodeHasCustomData<PwEntryV4>()
|
||||
val groupHandler = NodeHasCustomData<PwGroupV4>()
|
||||
databaseV4.rootGroup?.doForEachChildAndForIt(entryHandler, groupHandler)
|
||||
return if (databaseV4.containsCustomData()
|
||||
|| entryHandler.containsCustomData
|
||||
|| groupHandler.containsCustomData) {
|
||||
FILE_VERSION_32_4
|
||||
} else {
|
||||
FILE_VERSION_32_3
|
||||
}
|
||||
|
||||
// Return V4 by default
|
||||
return FILE_VERSION_32_4
|
||||
}
|
||||
|
||||
/** Assumes the input stream is at the beginning of the .kdbx file
|
||||
|
||||
@@ -577,11 +577,11 @@ class ImporterV4(private val streamDir: File) : Importer<PwDatabaseV4>() {
|
||||
}
|
||||
|
||||
KdbContext.GroupTimes, KdbContext.EntryTimes -> {
|
||||
val tl: NodeV4Interface?
|
||||
val tl: PwNodeV4Interface? =
|
||||
if (ctx == KdbContext.GroupTimes) {
|
||||
tl = ctxGroup
|
||||
ctxGroup
|
||||
} else {
|
||||
tl = ctxEntry
|
||||
ctxEntry
|
||||
}
|
||||
|
||||
when {
|
||||
|
||||
@@ -653,7 +653,7 @@ class PwDbV4Output(private val mDatabaseV4: PwDatabaseV4, outputStream: OutputSt
|
||||
}
|
||||
|
||||
@Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class)
|
||||
private fun writeList(name: String?, it: NodeV4Interface) {
|
||||
private fun writeList(name: String?, it: PwNodeV4Interface) {
|
||||
assert(name != null)
|
||||
|
||||
xml.startTag(null, name)
|
||||
|
||||
Reference in New Issue
Block a user