Fix incomplete attachment deletion #684

This commit is contained in:
J-Jamet
2020-09-13 13:11:08 +02:00
parent 09616a594c
commit 66e68092d5
11 changed files with 135 additions and 12 deletions

View File

@@ -1,5 +1,5 @@
KeePassDX(2.9)
*
KeePassDX(2.8.4)
* Fix incomplete attachment deletion #684
KeePassDX(2.8.3)
* Upload attachments

View File

@@ -45,7 +45,6 @@ import com.kunzisoft.keepass.database.element.*
import com.kunzisoft.keepass.database.element.icon.IconImage
import com.kunzisoft.keepass.database.element.icon.IconImageStandard
import com.kunzisoft.keepass.database.element.node.NodeId
import com.kunzisoft.keepass.database.element.security.ProtectedString
import com.kunzisoft.keepass.education.EntryEditActivityEducation
import com.kunzisoft.keepass.model.*
import com.kunzisoft.keepass.notifications.AttachmentFileNotificationService
@@ -65,6 +64,7 @@ import com.kunzisoft.keepass.view.showActionError
import com.kunzisoft.keepass.view.updateLockPaddingLeft
import org.joda.time.DateTime
import java.util.*
import kotlin.collections.ArrayList
class EntryEditActivity : LockingActivity(),
IconPickerDialogFragment.IconPickerListener,
@@ -99,6 +99,7 @@ class EntryEditActivity : LockingActivity(),
private var mSelectFileHelper: SelectFileHelper? = null
private var mAttachmentFileBinderManager: AttachmentFileBinderManager? = null
private var mAllowMultipleAttachments: Boolean = false
private var mTempAttachments = ArrayList<Attachment>()
// Education
private var entryEditActivityEducation: EntryEditActivityEducation? = null
@@ -206,6 +207,10 @@ class EntryEditActivity : LockingActivity(),
mFocusedEditExtraField = savedInstanceState.getParcelable(EXTRA_FIELD_FOCUSED_ENTRY)
}
if (savedInstanceState?.containsKey(TEMP_ATTACHMENTS) == true) {
mTempAttachments = savedInstanceState.getParcelableArrayList(TEMP_ATTACHMENTS) ?: mTempAttachments
}
// Close the activity if entry or parent can't be retrieve
if (mNewEntry == null || mParent == null) {
finish()
@@ -317,6 +322,7 @@ class EntryEditActivity : LockingActivity(),
scrollView?.smoothScrollTo(0, it.toInt())
}
}
mTempAttachments.add(entryAttachmentState.attachment)
}
AttachmentState.IN_PROGRESS -> {
entryEditContentsView?.putAttachment(entryAttachmentState)
@@ -536,6 +542,15 @@ class EntryEditActivity : LockingActivity(),
populateEntryWithViews(newEntry)
// Delete temp attachment if not used
mTempAttachments.forEach {
mDatabase?.binaryPool?.let { binaryPool ->
if (!newEntry.getAttachments(binaryPool).contains(it)) {
mDatabase?.removeAttachmentIfNotUsed(it)
}
}
}
// Open a progress dialog and save entry
if (mIsNew) {
mParent?.let { parent ->
@@ -705,6 +720,8 @@ class EntryEditActivity : LockingActivity(),
outState.putParcelable(EXTRA_FIELD_FOCUSED_ENTRY, it)
}
outState.putParcelableArrayList(TEMP_ATTACHMENTS, mTempAttachments)
super.onSaveInstanceState(outState)
}
@@ -763,6 +780,7 @@ class EntryEditActivity : LockingActivity(),
// SaveInstanceState
const val KEY_NEW_ENTRY = "new_entry"
const val EXTRA_FIELD_FOCUSED_ENTRY = "EXTRA_FIELD_FOCUSED_ENTRY"
const val TEMP_ATTACHMENTS = "TEMP_ATTACHMENTS"
// Keys for callback
const val ADD_ENTRY_RESULT_CODE = 31

View File

@@ -0,0 +1,80 @@
/*
* Copyright 2020 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePassDX.
*
* KeePassDX 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.
*
* KeePassDX 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 KeePassDX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.activities.dialogs
import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.text.SpannableStringBuilder
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment
import com.kunzisoft.keepass.R
/**
* Custom Dialog to confirm big file to upload
*/
class RemoveUnlinkedAttachmentsDialogFragment : DialogFragment() {
private var mActionChooseListener: ActionChooseListener? = null
override fun onAttach(context: Context) {
super.onAttach(context)
// Verify that the host activity implements the callback interface
try {
mActionChooseListener = context as ActionChooseListener
} catch (e: ClassCastException) {
throw ClassCastException(context.toString()
+ " must implement " + ActionChooseListener::class.java.name)
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
activity?.let { activity ->
// Use the Builder class for convenient dialog construction
val builder = AlertDialog.Builder(activity)
builder.setMessage(SpannableStringBuilder().apply {
append(getString(R.string.warning_remove_unlinked_attachment))
append("\n\n")
append(getString(R.string.warning_sure_remove_data))
})
builder.setPositiveButton(android.R.string.yes) { _, _ ->
mActionChooseListener?.onValidateRemoveUnlinkedAttachments()
}
builder.setNegativeButton(android.R.string.no) { _, _ ->
dismiss()
}
// Create the AlertDialog object and return it
return builder.create()
}
return super.onCreateDialog(savedInstanceState)
}
interface ActionChooseListener {
fun onValidateRemoveUnlinkedAttachments()
}
companion object {
fun build(): RemoveUnlinkedAttachmentsDialogFragment {
val fragment = RemoveUnlinkedAttachmentsDialogFragment()
fragment.arguments = Bundle().apply {}
return fragment
}
}
}

View File

@@ -598,6 +598,8 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
binariesToRemove.forEach {
try {
binaryPool.remove(it)
// bug with big attachment, not needed to be delete here
// it.clear()
} catch (e: Exception) {
Log.w(TAG, "Unable to clean binaries", e)
}

View File

@@ -30,6 +30,7 @@ import androidx.preference.SwitchPreference
import com.kunzisoft.androidclearchroma.ChromaUtil
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.dialogs.AssignMasterKeyDialogFragment
import com.kunzisoft.keepass.activities.dialogs.RemoveUnlinkedAttachmentsDialogFragment
import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper
import com.kunzisoft.keepass.crypto.keyDerivation.KdfEngine
import com.kunzisoft.keepass.database.element.Database
@@ -135,7 +136,7 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment() {
findPreference<Preference>(getString(R.string.database_version_key))
?.summary = mDatabase.version
val dbCompressionPrefCategory: PreferenceCategory? = findPreference(getString(R.string.database_category_compression_key))
val dbCompressionPrefCategory: PreferenceCategory? = findPreference(getString(R.string.database_category_data_key))
// Database compression
dbDataCompressionPref = findPreference(getString(R.string.database_data_compression_key))
@@ -149,6 +150,12 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment() {
val dbRecycleBinPrefCategory: PreferenceCategory? = findPreference(getString(R.string.database_category_recycle_bin_key))
recycleBinGroupPref = findPreference(getString(R.string.recycle_bin_group_key))
val removeUnlinkedAttachments: Preference? = findPreference(getString(R.string.database_data_remove_unlinked_attachments_key))
removeUnlinkedAttachments?.setOnPreferenceClickListener {
RemoveUnlinkedAttachmentsDialogFragment.build().show(parentFragmentManager, "remove_unlinked_dialog")
true
}
// Recycle bin
if (mDatabase.allowConfigurableRecycleBin) {
val recycleBinEnablePref: SwitchPreference? = findPreference(getString(R.string.recycle_bin_enable_key))

View File

@@ -33,6 +33,7 @@ import androidx.fragment.app.Fragment
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.dialogs.AssignMasterKeyDialogFragment
import com.kunzisoft.keepass.activities.dialogs.PasswordEncodingDialogFragment
import com.kunzisoft.keepass.activities.dialogs.RemoveUnlinkedAttachmentsDialogFragment
import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper
import com.kunzisoft.keepass.activities.lock.LockingActivity
import com.kunzisoft.keepass.database.element.Database
@@ -42,7 +43,8 @@ import com.kunzisoft.keepass.view.showActionError
open class SettingsActivity
: LockingActivity(),
MainPreferenceFragment.Callback,
AssignMasterKeyDialogFragment.AssignPasswordDialogListener {
AssignMasterKeyDialogFragment.AssignPasswordDialogListener,
RemoveUnlinkedAttachmentsDialogFragment.ActionChooseListener {
private var backupManager: BackupManager? = null
@@ -164,7 +166,10 @@ open class SettingsActivity
override fun onAssignKeyDialogNegativeClick(masterPasswordChecked: Boolean,
masterPassword: String?,
keyFileChecked: Boolean,
keyFile: Uri?) {
keyFile: Uri?) {}
override fun onValidateRemoveUnlinkedAttachments() {
Database.getInstance().removeUnlinkedAttachments()
}
private fun hideOrShowLockButton(key: NestedSettingsFragment.Screen) {

View File

@@ -178,8 +178,9 @@
<string name="database_custom_color_key" translatable="false">database_custom_color_key</string>
<string name="database_version_key" translatable="false">database_version_key</string>
<string name="database_category_compression_key" translatable="false">database_category_compression_key</string>
<string name="database_category_data_key" translatable="false">database_category_data_key</string>
<string name="database_data_compression_key" translatable="false">database_data_compression_key</string>
<string name="database_data_remove_unlinked_attachments_key" translatable="false">database_data_remove_unlinked_attachments_key</string>
<string name="database_category_recycle_bin_key" translatable="false">database_category_recycle_bin_key</string>
<string name="recycle_bin_enable_key" translatable="false">recycle_bin_enable_key</string>

View File

@@ -260,6 +260,8 @@
<string name="warning_file_too_big">A KeePass database is supposed to contain only small utility files (such as PGP key files).\n\nYour database may get very large and reduce performance with this upload.</string>
<string name="warning_replace_file">Uploading this file will replace the existing one.</string>
<string name="warning_sure_add_file">Add the file anyway?</string>
<string name="warning_remove_unlinked_attachment">Removing unlinked data may decrease the size of your database but may also delete data used for KeePass plugins.</string>
<string name="warning_sure_remove_data">Remove this data anyway?</string>
<string name="version_label">Version %1$s</string>
<string name="build_label">Build %1$s</string>
<string name="configure_biometric">Biometric prompt is supported, but not set up.</string>
@@ -318,8 +320,11 @@
<string name="file_name">Filename</string>
<string name="path">Path</string>
<string name="assign_master_key">Assign a master key</string>
<string name="data">Data</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="database_data_compression_summary">Data compression reduces the size of the database</string>
<string name="database_data_remove_unlinked_attachments_title">Remove unlinked attachments</string>
<string name="database_data_remove_unlinked_attachments_summary">Removes attachments contained in the database but not linked to an entry</string>
<string name="recycle_bin_title">Recycle bin usage</string>
<string name="recycle_bin_summary">Moves groups and entries to \"Recycle bin\" group before deleting</string>
<string name="recycle_bin_group_title">Recycle bin group</string>

View File

@@ -59,14 +59,19 @@
</PreferenceCategory>
<PreferenceCategory
android:key="@string/database_category_compression_key"
android:title="@string/compression">
android:key="@string/database_category_data_key"
android:title="@string/data">
<com.kunzisoft.keepass.settings.preference.DialogListExplanationPreference
android:key="@string/database_data_compression_key"
android:persistent="false"
android:title="@string/database_data_compression_title"/>
<Preference
android:key="@string/database_data_remove_unlinked_attachments_key"
android:persistent="false"
android:title="@string/database_data_remove_unlinked_attachments_title"
android:summary="@string/database_data_remove_unlinked_attachments_summary"/>
</PreferenceCategory>
<PreferenceCategory

View File

@@ -1 +1 @@
*
* Fix incomplete attachment deletion #684

View File

@@ -1 +1 @@
*
* Correction de la suppression incomplète des fichiers joints #684