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 rootCanContainsEntry(): Boolean
|
||||||
|
|
||||||
|
abstract fun containsCustomData(): Boolean
|
||||||
|
|
||||||
fun addGroupTo(newGroup: Group, parent: Group?) {
|
fun addGroupTo(newGroup: Group, parent: Group?) {
|
||||||
// Add tree to parent tree
|
// Add tree to parent tree
|
||||||
parent?.addChildGroup(newGroup)
|
parent?.addChildGroup(newGroup)
|
||||||
|
|||||||
@@ -154,6 +154,10 @@ class PwDatabaseV3 : PwDatabase<PwGroupV3, PwEntryV3>() {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun containsCustomData(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
override fun isBackup(group: PwGroupV3): Boolean {
|
override fun isBackup(group: PwGroupV3): Boolean {
|
||||||
var currentGroup: PwGroupV3? = group
|
var currentGroup: PwGroupV3? = group
|
||||||
while (currentGroup != null) {
|
while (currentGroup != null) {
|
||||||
|
|||||||
@@ -196,6 +196,10 @@ class PwDatabaseV4 : PwDatabase<PwGroupV4, PwEntryV4> {
|
|||||||
this.customData[label] = value
|
this.customData[label] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun containsCustomData(): Boolean {
|
||||||
|
return getCustomData().isNotEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
@Throws(InvalidKeyFileException::class, IOException::class)
|
@Throws(InvalidKeyFileException::class, IOException::class)
|
||||||
public override fun getMasterKey(key: String?, keyInputStream: InputStream?): ByteArray {
|
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 com.kunzisoft.keepass.utils.MemoryUtil
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class PwEntryV4 : PwEntry<PwGroupV4, PwEntryV4>, NodeV4Interface {
|
class PwEntryV4 : PwEntry<PwGroupV4, PwEntryV4>, PwNodeV4Interface {
|
||||||
|
|
||||||
// To decode each field not parcelable
|
// To decode each field not parcelable
|
||||||
@Transient
|
@Transient
|
||||||
@@ -275,12 +275,12 @@ class PwEntryV4 : PwEntry<PwGroupV4, PwEntryV4>, NodeV4Interface {
|
|||||||
return history.size
|
return history.size
|
||||||
}
|
}
|
||||||
|
|
||||||
fun putCustomData(key: String, value: String) {
|
override fun putCustomData(key: String, value: String) {
|
||||||
customData[key] = value
|
customData[key] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun containsCustomData(): Boolean {
|
override fun containsCustomData(): Boolean {
|
||||||
return customData.size > 0
|
return customData.isNotEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addEntryToHistory(entry: PwEntryV4) {
|
fun addEntryToHistory(entry: PwEntryV4) {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import android.os.Parcelable
|
|||||||
import java.util.HashMap
|
import java.util.HashMap
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
class PwGroupV4 : PwGroup<UUID, PwGroupV4, PwEntryV4>, NodeV4Interface {
|
class PwGroupV4 : PwGroup<UUID, PwGroupV4, PwEntryV4>, PwNodeV4Interface {
|
||||||
|
|
||||||
// TODO Encapsulate
|
// TODO Encapsulate
|
||||||
override var icon: PwIcon
|
override var icon: PwIcon
|
||||||
@@ -123,12 +123,12 @@ class PwGroupV4 : PwGroup<UUID, PwGroupV4, PwEntryV4>, NodeV4Interface {
|
|||||||
locationChanged = PwDate()
|
locationChanged = PwDate()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun putCustomData(key: String, value: String) {
|
override fun putCustomData(key: String, value: String) {
|
||||||
customData[key] = value
|
customData[key] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun containsCustomData(): Boolean {
|
override fun containsCustomData(): Boolean {
|
||||||
return customData.size > 0
|
return customData.isNotEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun allowAddEntryIfIsRoot(): Boolean {
|
override fun allowAddEntryIfIsRoot(): Boolean {
|
||||||
|
|||||||
@@ -19,10 +19,14 @@
|
|||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.database.element
|
package com.kunzisoft.keepass.database.element
|
||||||
|
|
||||||
interface NodeV4Interface : NodeTimeInterface {
|
interface PwNodeV4Interface : NodeTimeInterface {
|
||||||
|
|
||||||
var usageCount: Long
|
var usageCount: Long
|
||||||
|
|
||||||
var locationChanged: PwDate
|
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.AesKdf
|
||||||
import com.kunzisoft.keepass.crypto.keyDerivation.KdfFactory
|
import com.kunzisoft.keepass.crypto.keyDerivation.KdfFactory
|
||||||
import com.kunzisoft.keepass.crypto.keyDerivation.KdfParameters
|
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.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.database.exception.InvalidDBVersionException
|
||||||
import com.kunzisoft.keepass.stream.CopyInputStream
|
import com.kunzisoft.keepass.stream.CopyInputStream
|
||||||
import com.kunzisoft.keepass.stream.HmacBlockStream
|
import com.kunzisoft.keepass.stream.HmacBlockStream
|
||||||
@@ -88,18 +92,42 @@ class PwDbHeaderV4(private val databaseV4: PwDatabaseV4) : PwDbHeader() {
|
|||||||
this.masterSeed = ByteArray(32)
|
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 {
|
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) {
|
if (databaseV4.rootGroup == null) {
|
||||||
return FILE_VERSION_32_3
|
return FILE_VERSION_32_3
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return v4 if AES is not use
|
val entryHandler = NodeHasCustomData<PwEntryV4>()
|
||||||
if (databaseV4.kdfParameters != null && databaseV4.kdfParameters!!.uuid != AesKdf.CIPHER_UUID) {
|
val groupHandler = NodeHasCustomData<PwGroupV4>()
|
||||||
return FILE_VERSION_32_4
|
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
|
/** Assumes the input stream is at the beginning of the .kdbx file
|
||||||
|
|||||||
@@ -577,12 +577,12 @@ class ImporterV4(private val streamDir: File) : Importer<PwDatabaseV4>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
KdbContext.GroupTimes, KdbContext.EntryTimes -> {
|
KdbContext.GroupTimes, KdbContext.EntryTimes -> {
|
||||||
val tl: NodeV4Interface?
|
val tl: PwNodeV4Interface? =
|
||||||
if (ctx == KdbContext.GroupTimes) {
|
if (ctx == KdbContext.GroupTimes) {
|
||||||
tl = ctxGroup
|
ctxGroup
|
||||||
} else {
|
} else {
|
||||||
tl = ctxEntry
|
ctxEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
when {
|
when {
|
||||||
name.equals(PwDatabaseV4XML.ElemLastModTime, ignoreCase = true) -> tl?.lastModificationTime = readPwTime(xpp)
|
name.equals(PwDatabaseV4XML.ElemLastModTime, ignoreCase = true) -> tl?.lastModificationTime = readPwTime(xpp)
|
||||||
|
|||||||
@@ -653,7 +653,7 @@ class PwDbV4Output(private val mDatabaseV4: PwDatabaseV4, outputStream: OutputSt
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class)
|
@Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class)
|
||||||
private fun writeList(name: String?, it: NodeV4Interface) {
|
private fun writeList(name: String?, it: PwNodeV4Interface) {
|
||||||
assert(name != null)
|
assert(name != null)
|
||||||
|
|
||||||
xml.startTag(null, name)
|
xml.startTag(null, name)
|
||||||
|
|||||||
Reference in New Issue
Block a user