Add compression setting

This commit is contained in:
J-Jamet
2019-09-24 12:52:07 +02:00
parent 9b891013b8
commit 5abc403171
11 changed files with 173 additions and 27 deletions

View File

@@ -87,6 +87,12 @@ class Database {
pwDatabaseV4?.defaultUserNameChanged = PwDate() pwDatabaseV4?.defaultUserNameChanged = PwDate()
} }
val availableCompressionAlgorithms: List<PwCompressionAlgorithm>
get() = pwDatabaseV4?.availableCompressionAlgorithms ?: ArrayList()
val compressionAlgorithm: PwCompressionAlgorithm?
get() = pwDatabaseV4?.compressionAlgorithm
val availableEncryptionAlgorithms: List<PwEncryptionAlgorithm> val availableEncryptionAlgorithms: List<PwEncryptionAlgorithm>
get() = pwDatabaseV3?.availableEncryptionAlgorithms ?: pwDatabaseV4?.availableEncryptionAlgorithms ?: ArrayList() get() = pwDatabaseV3?.availableEncryptionAlgorithms ?: pwDatabaseV4?.availableEncryptionAlgorithms ?: ArrayList()
@@ -437,6 +443,11 @@ class Database {
pwDatabaseV4?.descriptionChanged = PwDate() pwDatabaseV4?.descriptionChanged = PwDate()
} }
fun assignCompressionAlgorithm(algorithm: PwCompressionAlgorithm) {
pwDatabaseV4?.compressionAlgorithm = algorithm
// TODO Compression
}
fun allowEncryptionAlgorithmModification(): Boolean { fun allowEncryptionAlgorithmModification(): Boolean {
return availableEncryptionAlgorithms.size > 1 return availableEncryptionAlgorithms.size > 1
} }

View File

@@ -17,25 +17,24 @@
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. * along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package com.kunzisoft.keepass.database.file package com.kunzisoft.keepass.database.element
import android.content.res.Resources
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.ObjectNameResource
// Note: We can get away with using int's to store unsigned 32-bit ints // Note: We can get away with using int's to store unsigned 32-bit ints
// since we won't do arithmetic on these values (also unlikely to // since we won't do arithmetic on these values (also unlikely to
// reach negative ids). // reach negative ids).
enum class PwCompressionAlgorithm constructor(val id: Int) { enum class PwCompressionAlgorithm : ObjectNameResource {
None(0), None,
Gzip(1); Gzip;
companion object { override fun getName(resources: Resources): String {
return when (this) {
fun fromId(num: Int): PwCompressionAlgorithm? { None -> resources.getString(R.string.compression_none)
for (e in values()) { Gzip -> resources.getString(R.string.compression_gzip)
if (e.id == num) {
return e
}
}
return null
} }
} }

View File

@@ -29,7 +29,6 @@ import com.kunzisoft.keepass.crypto.engine.CipherEngine
import com.kunzisoft.keepass.crypto.keyDerivation.* import com.kunzisoft.keepass.crypto.keyDerivation.*
import com.kunzisoft.keepass.database.exception.InvalidKeyFileException import com.kunzisoft.keepass.database.exception.InvalidKeyFileException
import com.kunzisoft.keepass.database.exception.UnknownKDF import com.kunzisoft.keepass.database.exception.UnknownKDF
import com.kunzisoft.keepass.database.file.PwCompressionAlgorithm
import com.kunzisoft.keepass.utils.VariantDictionary import com.kunzisoft.keepass.utils.VariantDictionary
import org.w3c.dom.Node import org.w3c.dom.Node
import org.w3c.dom.Text import org.w3c.dom.Text
@@ -136,6 +135,14 @@ class PwDatabaseV4 : PwDatabase<PwGroupV4, PwEntryV4> {
throw unknownKDFException throw unknownKDFException
} }
val availableCompressionAlgorithms: List<PwCompressionAlgorithm>
get() {
val list = ArrayList<PwCompressionAlgorithm>()
list.add(PwCompressionAlgorithm.None)
list.add(PwCompressionAlgorithm.Gzip)
return list
}
override val availableEncryptionAlgorithms: List<PwEncryptionAlgorithm> override val availableEncryptionAlgorithms: List<PwEncryptionAlgorithm>
get() { get() {
val list = ArrayList<PwEncryptionAlgorithm>() val list = ArrayList<PwEncryptionAlgorithm>()

View File

@@ -24,10 +24,7 @@ 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.NodeHandler
import com.kunzisoft.keepass.database.element.PwNodeV4Interface import com.kunzisoft.keepass.database.element.*
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
@@ -263,7 +260,7 @@ class PwDbHeaderV4(private val databaseV4: PwDatabaseV4) : PwDbHeader() {
throw IOException("Unrecognized compression flag.") throw IOException("Unrecognized compression flag.")
} }
PwCompressionAlgorithm.fromId(flag)?.let { compression -> getCompressionFromFlag(flag)?.let { compression ->
databaseV4.compressionAlgorithm = compression databaseV4.compressionAlgorithm = compression
} }
} }
@@ -301,6 +298,21 @@ class PwDbHeaderV4(private val databaseV4: PwDatabaseV4) : PwDbHeader() {
const val FILE_VERSION_32_3: Long = 0x00030001 const val FILE_VERSION_32_3: Long = 0x00030001
const val FILE_VERSION_32_4: Long = 0x00040000 const val FILE_VERSION_32_4: Long = 0x00040000
fun getCompressionFromFlag(flag: Int): PwCompressionAlgorithm? {
return when (flag) {
0 -> PwCompressionAlgorithm.None
1 -> PwCompressionAlgorithm.Gzip
else -> null
}
}
fun getFlagFromCompression(compression: PwCompressionAlgorithm): Int {
return when (compression) {
PwCompressionAlgorithm.Gzip -> 1
else -> 0
}
}
fun matchesHeader(sig1: Int, sig2: Int): Boolean { fun matchesHeader(sig1: Int, sig2: Int): Boolean {
return sig1 == PWM_DBSIG_1 && (sig2 == DBSIG_PRE2 || sig2 == DBSIG_2) return sig1 == PWM_DBSIG_1 && (sig2 == DBSIG_PRE2 || sig2 == DBSIG_2)
} }

View File

@@ -24,7 +24,7 @@ import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.crypto.CipherFactory import com.kunzisoft.keepass.crypto.CipherFactory
import com.kunzisoft.keepass.crypto.StreamCipherFactory import com.kunzisoft.keepass.crypto.StreamCipherFactory
import com.kunzisoft.keepass.crypto.engine.CipherEngine import com.kunzisoft.keepass.crypto.engine.CipherEngine
import com.kunzisoft.keepass.database.file.PwCompressionAlgorithm import com.kunzisoft.keepass.database.element.PwCompressionAlgorithm
import com.kunzisoft.keepass.database.element.* import com.kunzisoft.keepass.database.element.*
import com.kunzisoft.keepass.database.exception.ArcFourException import com.kunzisoft.keepass.database.exception.ArcFourException
import com.kunzisoft.keepass.database.exception.InvalidDBException import com.kunzisoft.keepass.database.exception.InvalidDBException

View File

@@ -86,9 +86,8 @@ constructor(private val db: PwDatabaseV4, private val header: PwDbHeaderV4, os:
los.writeUInt(PwDbHeaderV4.DBSIG_2.toLong()) los.writeUInt(PwDbHeaderV4.DBSIG_2.toLong())
los.writeUInt(header.version) los.writeUInt(header.version)
writeHeaderField(PwDbHeaderV4.PwDbHeaderV4Fields.CipherID, Types.UUIDtoBytes(db.dataCipher)) writeHeaderField(PwDbHeaderV4.PwDbHeaderV4Fields.CipherID, Types.UUIDtoBytes(db.dataCipher))
writeHeaderField(PwDbHeaderV4.PwDbHeaderV4Fields.CompressionFlags, LEDataOutputStream.writeIntBuf(db.compressionAlgorithm.id)) writeHeaderField(PwDbHeaderV4.PwDbHeaderV4Fields.CompressionFlags, LEDataOutputStream.writeIntBuf(PwDbHeaderV4.getFlagFromCompression(db.compressionAlgorithm)))
writeHeaderField(PwDbHeaderV4.PwDbHeaderV4Fields.MasterSeed, header.masterSeed) writeHeaderField(PwDbHeaderV4.PwDbHeaderV4Fields.MasterSeed, header.masterSeed)
if (header.version < PwDbHeaderV4.FILE_VERSION_32_4) { if (header.version < PwDbHeaderV4.FILE_VERSION_32_4) {

View File

@@ -31,7 +31,7 @@ import com.kunzisoft.keepass.database.*
import com.kunzisoft.keepass.database.element.* import com.kunzisoft.keepass.database.element.*
import com.kunzisoft.keepass.database.exception.PwDbOutputException import com.kunzisoft.keepass.database.exception.PwDbOutputException
import com.kunzisoft.keepass.database.exception.UnknownKDF import com.kunzisoft.keepass.database.exception.UnknownKDF
import com.kunzisoft.keepass.database.file.PwCompressionAlgorithm import com.kunzisoft.keepass.database.element.PwCompressionAlgorithm
import com.kunzisoft.keepass.database.file.PwDbHeaderV4 import com.kunzisoft.keepass.database.file.PwDbHeaderV4
import com.kunzisoft.keepass.database.element.security.ProtectedBinary import com.kunzisoft.keepass.database.element.security.ProtectedBinary
import com.kunzisoft.keepass.database.element.security.ProtectedString import com.kunzisoft.keepass.database.element.security.ProtectedString

View File

@@ -44,6 +44,7 @@ import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
import com.kunzisoft.keepass.database.element.Database import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.education.Education import com.kunzisoft.keepass.education.Education
import com.kunzisoft.keepass.biometric.BiometricUnlockDatabaseHelper import com.kunzisoft.keepass.biometric.BiometricUnlockDatabaseHelper
import com.kunzisoft.keepass.database.element.PwCompressionAlgorithm
import com.kunzisoft.keepass.icons.IconPackChooser import com.kunzisoft.keepass.icons.IconPackChooser
import com.kunzisoft.keepass.settings.preference.* import com.kunzisoft.keepass.settings.preference.*
import com.kunzisoft.keepass.settings.preferencedialogfragment.* import com.kunzisoft.keepass.settings.preferencedialogfragment.*
@@ -348,7 +349,7 @@ class NestedSettingsFragment : PreferenceFragmentCompat(), Preference.OnPreferen
dbGeneralPrefCategory?.removePreference(dbNamePref) dbGeneralPrefCategory?.removePreference(dbNamePref)
} }
// Db description // Database description
val dbDescriptionPref: InputTextPreference? = findPreference(getString(R.string.database_description_key)) val dbDescriptionPref: InputTextPreference? = findPreference(getString(R.string.database_description_key))
if (mDatabase.containsDescription()) { if (mDatabase.containsDescription()) {
dbDescriptionPref?.summary = mDatabase.description dbDescriptionPref?.summary = mDatabase.description
@@ -356,6 +357,10 @@ class NestedSettingsFragment : PreferenceFragmentCompat(), Preference.OnPreferen
dbGeneralPrefCategory?.removePreference(dbDescriptionPref) dbGeneralPrefCategory?.removePreference(dbDescriptionPref)
} }
// Database compression
findPreference<Preference>(getString(R.string.database_data_compression_key))
?.summary = (mDatabase.compressionAlgorithm ?: PwCompressionAlgorithm.None).getName(resources)
// Recycle bin // Recycle bin
val recycleBinPref: SwitchPreference? = findPreference(getString(R.string.recycle_bin_key)) val recycleBinPref: SwitchPreference? = findPreference(getString(R.string.recycle_bin_key))
// TODO Recycle // TODO Recycle
@@ -497,6 +502,9 @@ class NestedSettingsFragment : PreferenceFragmentCompat(), Preference.OnPreferen
preference.key == getString(R.string.database_description_key) -> { preference.key == getString(R.string.database_description_key) -> {
dialogFragment = DatabaseDescriptionPreferenceDialogFragmentCompat.newInstance(preference.key) dialogFragment = DatabaseDescriptionPreferenceDialogFragmentCompat.newInstance(preference.key)
} }
preference.key == getString(R.string.database_data_compression_key) -> {
dialogFragment = DatabaseDataCompressionPreferenceDialogFragmentCompat.newInstance(preference.key)
}
preference.key == getString(R.string.max_history_items_key) -> { preference.key == getString(R.string.max_history_items_key) -> {
dialogFragment = MaxHistoryItemsPreferenceDialogFragmentCompat.newInstance(preference.key) dialogFragment = MaxHistoryItemsPreferenceDialogFragmentCompat.newInstance(preference.key)
} }

View File

@@ -0,0 +1,109 @@
/*
* Copyright 2019 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.settings.preferencedialogfragment
import android.os.Bundle
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.PwCompressionAlgorithm
import com.kunzisoft.keepass.settings.preferencedialogfragment.adapter.ListRadioItemAdapter
import com.kunzisoft.keepass.tasks.ActionRunnable
class DatabaseDataCompressionPreferenceDialogFragmentCompat
: DatabaseSavePreferenceDialogFragmentCompat(),
ListRadioItemAdapter.RadioItemSelectedCallback<PwCompressionAlgorithm> {
private var compressionSelected: PwCompressionAlgorithm? = null
override fun onBindDialogView(view: View) {
super.onBindDialogView(view)
setExplanationText(R.string.database_data_compression_summary)
val recyclerView = view.findViewById<RecyclerView>(R.id.pref_dialog_list)
recyclerView.layoutManager = LinearLayoutManager(context)
activity?.let { activity ->
val compressionAdapter = ListRadioItemAdapter<PwCompressionAlgorithm>(activity)
compressionAdapter.setRadioItemSelectedCallback(this)
recyclerView.adapter = compressionAdapter
database?.let { database ->
compressionSelected = database.compressionAlgorithm?.apply {
compressionAdapter.setItems(database.availableCompressionAlgorithms, this)
}
}
}
}
override fun onDialogClosed(positiveResult: Boolean) {
if (positiveResult) {
database?.let { database ->
if (compressionSelected != null) {
val newAlgorithm = compressionSelected
val oldAlgorithm = database.compressionAlgorithm
newAlgorithm?.let {
database.assignCompressionAlgorithm(it)
}
if (oldAlgorithm != null && newAlgorithm != null)
actionInUIThreadAfterSaveDatabase = AfterDescriptionSave(newAlgorithm, oldAlgorithm)
}
}
}
super.onDialogClosed(positiveResult)
}
override fun onItemSelected(item: PwCompressionAlgorithm) {
this.compressionSelected = item
}
private inner class AfterDescriptionSave(private val mNewAlgorithm: PwCompressionAlgorithm,
private val mOldAlgorithm: PwCompressionAlgorithm)
: ActionRunnable() {
override fun onFinishRun(result: Result) {
val algorithmToShow =
if (result.isSuccess) {
mNewAlgorithm
} else {
database?.assignCompressionAlgorithm(mOldAlgorithm)
mOldAlgorithm
}
preference.summary = algorithmToShow.getName(settingsResources)
}
}
companion object {
fun newInstance(key: String): DatabaseDataCompressionPreferenceDialogFragmentCompat {
val fragment = DatabaseDataCompressionPreferenceDialogFragmentCompat()
val bundle = Bundle(1)
bundle.putString(ARG_KEY, key)
fragment.arguments = bundle
return fragment
}
}
}

View File

@@ -291,6 +291,7 @@
<string name="full_file_path_enable_title">File path</string> <string name="full_file_path_enable_title">File path</string>
<string name="full_file_path_enable_summary">View the full file path</string> <string name="full_file_path_enable_summary">View the full file path</string>
<string name="database_data_compression_title">Data compression</string> <string name="database_data_compression_title">Data compression</string>
<string name="database_data_compression_summary">Data compression reduces the size of the database.</string>
<string name="recycle_bin_title">Use recycle bin</string> <string name="recycle_bin_title">Use recycle bin</string>
<string name="recycle_bin_summary">Moves groups and entries to \"Recycle bin\" before deleting</string> <string name="recycle_bin_summary">Moves groups and entries to \"Recycle bin\" before deleting</string>
<string name="max_history_items_title">Max. history items</string> <string name="max_history_items_title">Max. history items</string>
@@ -324,6 +325,8 @@
<string name="application_appearance">App</string> <string name="application_appearance">App</string>
<string name="other">Other</string> <string name="other">Other</string>
<string name="compression">Compression</string> <string name="compression">Compression</string>
<string name="compression_none">None</string>
<string name="compression_gzip">GZip</string>
<string name="recycle_bin">Recycle Bin</string> <string name="recycle_bin">Recycle Bin</string>
<string name="keyboard">Keyboard</string> <string name="keyboard">Keyboard</string>
<string name="magic_keyboard_title">Magikeyboard</string> <string name="magic_keyboard_title">Magikeyboard</string>

View File

@@ -18,8 +18,7 @@
along with KeePass DX. If not, see <http://www.gnu.org/licenses/>. along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
--> -->
<PreferenceScreen <PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android">
xmlns:custom="http://schemas.android.com/apk/res-auto">
<PreferenceCategory <PreferenceCategory
android:key="@string/database_general_key" android:key="@string/database_general_key"
@@ -64,7 +63,6 @@
<com.kunzisoft.keepass.settings.preference.DialogListExplanationPreference <com.kunzisoft.keepass.settings.preference.DialogListExplanationPreference
android:key="@string/database_data_compression_key" android:key="@string/database_data_compression_key"
android:persistent="false" android:persistent="false"
android:enabled="false"
android:title="@string/database_data_compression_title"/> android:title="@string/database_data_compression_title"/>
</PreferenceCategory> </PreferenceCategory>