fix: Refactoring database actions

This commit is contained in:
J-Jamet 2023-05-14 23:38:08 +02:00
parent 939b319563
commit 4bd12b8a95
16 changed files with 215 additions and 194 deletions

View file

@ -1126,15 +1126,19 @@ class GroupActivity : DatabaseLockActivity(),
return true
}
override fun onAskMainCredentialDialogPositiveClick(databaseUri: Uri?,
mainCredential: MainCredential) {
override fun onAskMainCredentialDialogPositiveClick(
databaseUri: Uri?,
mainCredential: MainCredential
) {
databaseUri?.let {
mergeDatabaseFrom(it, mainCredential)
}
}
override fun onAskMainCredentialDialogNegativeClick(databaseUri: Uri?,
mainCredential: MainCredential) { }
override fun onAskMainCredentialDialogNegativeClick(
databaseUri: Uri?,
mainCredential: MainCredential
) { }
override fun onResume() {
super.onResume()

View file

@ -6,10 +6,10 @@ import androidx.activity.viewModels
import com.kunzisoft.keepass.activities.stylish.StylishActivity
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.MainCredential
import com.kunzisoft.keepass.database.action.DatabaseTaskProvider
import com.kunzisoft.keepass.services.DatabaseTaskProvider
import com.kunzisoft.keepass.model.CipherEncryptDatabase
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.utils.UriUtil.getBinaryDir
import com.kunzisoft.keepass.utils.UriHelper.getBinaryDir
import com.kunzisoft.keepass.viewmodels.DatabaseViewModel
abstract class DatabaseActivity: StylishActivity(), DatabaseRetrieval {
@ -63,16 +63,20 @@ abstract class DatabaseActivity: StylishActivity(), DatabaseRetrieval {
// optional method implementation
}
fun createDatabase(databaseUri: Uri,
mainCredential: MainCredential) {
fun createDatabase(
databaseUri: Uri,
mainCredential: MainCredential
) {
mDatabaseTaskProvider?.startDatabaseCreate(databaseUri, mainCredential)
}
fun loadDatabase(databaseUri: Uri,
fun loadDatabase(
databaseUri: Uri,
mainCredential: MainCredential,
readOnly: Boolean,
cipherEncryptDatabase: CipherEncryptDatabase?,
fixDuplicateUuid: Boolean) {
fixDuplicateUuid: Boolean
) {
mDatabaseTaskProvider?.startDatabaseLoad(databaseUri, mainCredential, readOnly, cipherEncryptDatabase, fixDuplicateUuid)
}

View file

@ -36,7 +36,7 @@ import androidx.autofill.inline.v1.InlineSuggestionUi
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.AutofillLauncherActivity
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.action.DatabaseTaskProvider
import com.kunzisoft.keepass.services.DatabaseTaskProvider
import com.kunzisoft.keepass.database.helper.SearchHelper
import com.kunzisoft.keepass.model.CreditCard
import com.kunzisoft.keepass.model.RegisterInfo

View file

@ -21,8 +21,6 @@ package com.kunzisoft.keepass.database.action
import android.content.Context
import android.net.Uri
import com.kunzisoft.keepass.app.database.CipherDatabaseAction
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.MainCredential
import com.kunzisoft.keepass.hardware.HardwareKey
@ -32,8 +30,15 @@ open class AssignMainCredentialInDatabaseRunnable (
database: ContextualDatabase,
protected val mDatabaseUri: Uri,
mainCredential: MainCredential,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray
) : SaveDatabaseRunnable(context, database, true, mainCredential, challengeResponseRetriever) {
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray,
private val assignMainCredentialResult: ((Result) -> Unit)?
) : SaveDatabaseRunnable(
context,
database,
true,
mainCredential,
challengeResponseRetriever
) {
private var mBackupKey: ByteArray? = null
@ -53,13 +58,6 @@ open class AssignMainCredentialInDatabaseRunnable (
override fun onFinishRun() {
super.onFinishRun()
// Erase the biometric
CipherDatabaseAction.getInstance(context)
.deleteByDatabaseUri(mDatabaseUri)
// Erase the register keyfile
FileDatabaseHistoryAction.getInstance(context)
.deleteKeyFileByDatabaseUri(mDatabaseUri)
if (!result.isSuccess) {
// Erase the current master key
erase(database.masterKey)
@ -67,6 +65,8 @@ open class AssignMainCredentialInDatabaseRunnable (
database.masterKey = it
}
}
assignMainCredentialResult?.invoke(result)
}
/**

View file

@ -21,13 +21,10 @@ package com.kunzisoft.keepass.database.action
import android.content.Context
import android.net.Uri
import android.util.Log
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.MainCredential
import com.kunzisoft.keepass.hardware.HardwareKey
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.utils.UriUtil.getBinaryDir
import com.kunzisoft.keepass.utils.UriHelper.getBinaryDir
class CreateDatabaseRunnable(
context: Context,
@ -39,7 +36,14 @@ class CreateDatabaseRunnable(
val mainCredential: MainCredential,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray,
private val createDatabaseResult: ((Result) -> Unit)?
) : AssignMainCredentialInDatabaseRunnable(context, mDatabase, databaseUri, mainCredential, challengeResponseRetriever) {
) : AssignMainCredentialInDatabaseRunnable(
context,
mDatabase,
databaseUri,
mainCredential,
challengeResponseRetriever,
createDatabaseResult
) {
override fun onStartRun() {
try {
@ -56,27 +60,6 @@ class CreateDatabaseRunnable(
super.onStartRun()
}
override fun onActionRun() {
super.onActionRun()
if (result.isSuccess) {
// Add database to recent files
if (PreferencesUtil.rememberDatabaseLocations(context)) {
FileDatabaseHistoryAction.getInstance(context.applicationContext)
.addOrUpdateDatabaseUri(
mDatabaseUri,
if (PreferencesUtil.rememberKeyFileLocations(context)) mainCredential.keyFileUri else null,
if (PreferencesUtil.rememberHardwareKey(context)) mainCredential.hardwareKey else null,
)
}
// Register the current time to init the lock timer
PreferencesUtil.saveCurrentTime(context)
} else {
Log.e("CreateDatabaseRunnable", "Unable to create the database")
}
}
override fun onFinishRun() {
super.onFinishRun()

View file

@ -21,20 +21,16 @@ package com.kunzisoft.keepass.database.action
import android.content.Context
import android.net.Uri
import com.kunzisoft.keepass.app.database.CipherDatabaseAction
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.MainCredential
import com.kunzisoft.keepass.database.element.binary.BinaryData
import com.kunzisoft.keepass.database.exception.DatabaseInputException
import com.kunzisoft.keepass.database.exception.UnknownDatabaseLocationException
import com.kunzisoft.keepass.hardware.HardwareKey
import com.kunzisoft.keepass.model.CipherEncryptDatabase
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
import com.kunzisoft.keepass.utils.UriHelper.getBinaryDir
import com.kunzisoft.keepass.utils.UriHelper.getUriInputStream
import com.kunzisoft.keepass.utils.UriUtil.getBinaryDir
class LoadDatabaseRunnable(
private val context: Context,
@ -43,10 +39,9 @@ class LoadDatabaseRunnable(
private val mMainCredential: MainCredential,
private val mChallengeResponseRetriever: (hardwareKey: HardwareKey, seed: ByteArray?) -> ByteArray,
private val mReadonly: Boolean,
private val mCipherEncryptDatabase: CipherEncryptDatabase?,
private val mFixDuplicateUUID: Boolean,
private val progressTaskUpdater: ProgressTaskUpdater?,
private val mLoadDatabaseResult: ((Result) -> Unit)?,
private val loadDatabaseResult: ((Result) -> Unit)?,
) : ActionRunnable() {
private val binaryDir = context.getBinaryDir()
@ -78,31 +73,12 @@ class LoadDatabaseRunnable(
setError(e)
}
if (result.isSuccess) {
// Save keyFile in app database
if (PreferencesUtil.rememberDatabaseLocations(context)) {
FileDatabaseHistoryAction.getInstance(context)
.addOrUpdateDatabaseUri(
mDatabaseUri,
if (PreferencesUtil.rememberKeyFileLocations(context)) mMainCredential.keyFileUri else null,
if (PreferencesUtil.rememberHardwareKey(context)) mMainCredential.hardwareKey else null,
)
}
// Register the biometric
mCipherEncryptDatabase?.let { cipherDatabase ->
CipherDatabaseAction.getInstance(context)
.addOrUpdateCipherDatabase(cipherDatabase) // return value not called
}
// Register the current time to init the lock timer
PreferencesUtil.saveCurrentTime(context)
} else {
if (!result.isSuccess) {
mDatabase.clearAndClose(binaryDir)
}
}
override fun onFinishRun() {
mLoadDatabaseResult?.invoke(result)
loadDatabaseResult?.invoke(result)
}
}

View file

@ -27,7 +27,6 @@ import com.kunzisoft.keepass.database.element.binary.BinaryData
import com.kunzisoft.keepass.database.exception.DatabaseException
import com.kunzisoft.keepass.database.exception.UnknownDatabaseLocationException
import com.kunzisoft.keepass.hardware.HardwareKey
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
import com.kunzisoft.keepass.utils.UriHelper.getUriInputStream
@ -40,7 +39,7 @@ class MergeDatabaseRunnable(
saveDatabase: Boolean,
challengeResponseRetriever: (HardwareKey, ByteArray?) -> ByteArray,
private val progressTaskUpdater: ProgressTaskUpdater?,
private val mLoadDatabaseResult: ((Result) -> Unit)?
private val mergeDatabaseResult: ((Result) -> Unit)?
) : SaveDatabaseRunnable(context, database, saveDatabase, null, challengeResponseRetriever) {
override fun onStartRun() {
@ -66,15 +65,11 @@ class MergeDatabaseRunnable(
setError(e)
}
if (result.isSuccess) {
// Register the current time to init the lock timer
PreferencesUtil.saveCurrentTime(context)
}
super.onActionRun()
}
override fun onFinishRun() {
super.onFinishRun()
mLoadDatabaseResult?.invoke(result)
mergeDatabaseResult?.invoke(result)
}
}

View file

@ -24,17 +24,16 @@ import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.binary.BinaryData
import com.kunzisoft.keepass.database.exception.DatabaseException
import com.kunzisoft.keepass.database.exception.UnknownDatabaseLocationException
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
import com.kunzisoft.keepass.utils.UriHelper.getBinaryDir
import com.kunzisoft.keepass.utils.UriHelper.getUriInputStream
import com.kunzisoft.keepass.utils.UriUtil.getBinaryDir
class ReloadDatabaseRunnable(
private val context: Context,
private val mDatabase: ContextualDatabase,
private val progressTaskUpdater: ProgressTaskUpdater?,
private val mLoadDatabaseResult: ((Result) -> Unit)?
private val reloadDatabaseResult: ((Result) -> Unit)?
) : ActionRunnable() {
private val binaryDir = context.getBinaryDir()
@ -58,15 +57,12 @@ class ReloadDatabaseRunnable(
setError(e)
}
if (result.isSuccess) {
// Register the current time to init the lock timer
PreferencesUtil.saveCurrentTime(context)
} else {
if (!result.isSuccess) {
mDatabase.clearAndClose(binaryDir)
}
}
override fun onFinishRun() {
mLoadDatabaseResult?.invoke(result)
reloadDatabaseResult?.invoke(result)
}
}

View file

@ -50,7 +50,7 @@ open class SaveDatabaseRunnable(
// Build temp database file to avoid file corruption if error
database.saveData(
cacheFile = File(context.cacheDir, databaseCopyUri.hashCode().toString()),
databaseOutputStream = context.contentResolver
databaseOutputStream = contentResolver
.getUriOutputStream(databaseCopyUri ?: database.fileUri),
isNewLocation = databaseCopyUri == null,
mainCredential?.toMasterCredential(contentResolver),

View file

@ -44,7 +44,7 @@ import com.kunzisoft.keepass.activities.EntrySelectionLauncherActivity
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
import com.kunzisoft.keepass.adapters.FieldsAdapter
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.action.DatabaseTaskProvider
import com.kunzisoft.keepass.services.DatabaseTaskProvider
import com.kunzisoft.keepass.database.element.Field
import com.kunzisoft.keepass.database.element.node.NodeIdUUID
import com.kunzisoft.keepass.database.helper.SearchHelper

View file

@ -30,7 +30,6 @@ import android.util.Log
import androidx.core.app.ServiceCompat
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.action.DatabaseTaskProvider
import com.kunzisoft.keepass.database.element.Attachment
import com.kunzisoft.keepass.model.AttachmentState
import com.kunzisoft.keepass.model.EntryAttachmentState

View file

@ -31,6 +31,8 @@ import androidx.annotation.StringRes
import androidx.media.app.NotificationCompat
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.GroupActivity
import com.kunzisoft.keepass.app.database.CipherDatabaseAction
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.MainCredential
import com.kunzisoft.keepass.database.action.*
@ -47,6 +49,7 @@ import com.kunzisoft.keepass.hardware.HardwareKey
import com.kunzisoft.keepass.hardware.HardwareKeyActivity
import com.kunzisoft.keepass.model.CipherEncryptDatabase
import com.kunzisoft.keepass.model.SnapFileDatabaseInfo
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
import com.kunzisoft.keepass.timeout.TimeoutHelper
@ -348,7 +351,8 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
// Build and launch the action
if (actionRunnable != null) {
mainScope.launch {
executeAction(this@DatabaseTaskNotificationService,
executeAction(
this@DatabaseTaskNotificationService,
{
mActionRunning++
if (isMainAction) {
@ -715,6 +719,25 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
retrieveResponseFromChallenge(hardwareKey, seed)
}
) { result ->
afterAssignMainCredential(databaseUri)
if (result.isSuccess) {
// Add database to recent files
if (PreferencesUtil.rememberDatabaseLocations(applicationContext)) {
FileDatabaseHistoryAction.getInstance(applicationContext)
.addOrUpdateDatabaseUri(
databaseUri,
if (PreferencesUtil.rememberKeyFileLocations(applicationContext))
mainCredential.keyFileUri else null,
if (PreferencesUtil.rememberHardwareKey(applicationContext))
mainCredential.hardwareKey else null,
)
}
// Register the current time to init the lock timer
PreferencesUtil.saveCurrentTime(applicationContext)
} else {
Log.e(TAG, "Unable to create the database")
}
// Pass result to activity
result.data = Bundle().apply {
putParcelable(DATABASE_URI_KEY, databaseUri)
putParcelable(MAIN_CREDENTIAL_KEY, mainCredential)
@ -754,10 +777,31 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
retrieveResponseFromChallenge(hardwareKey, seed)
},
readOnly,
cipherEncryptDatabase,
intent.getBooleanExtra(FIX_DUPLICATE_UUID_KEY, false),
this
) { result ->
if (result.isSuccess) {
// Save keyFile in app database
if (PreferencesUtil.rememberDatabaseLocations(applicationContext)) {
FileDatabaseHistoryAction.getInstance(applicationContext)
.addOrUpdateDatabaseUri(
databaseUri,
if (PreferencesUtil.rememberKeyFileLocations(applicationContext))
mainCredential.keyFileUri else null,
if (PreferencesUtil.rememberHardwareKey(applicationContext))
mainCredential.hardwareKey else null,
)
}
// Register the biometric
cipherEncryptDatabase?.let { cipherDatabase ->
CipherDatabaseAction.getInstance(applicationContext)
.addOrUpdateCipherDatabase(cipherDatabase) // return value not called
}
// Register the current time to init the lock timer
PreferencesUtil.saveCurrentTime(applicationContext)
}
// Add each info to reload database after thrown duplicate UUID exception
result.data = Bundle().apply {
putParcelable(DATABASE_URI_KEY, databaseUri)
@ -798,6 +842,9 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
},
this
) { result ->
if (result.isSuccess) {
PreferencesUtil.saveCurrentTime(applicationContext)
}
// No need to add each info to reload database
result.data = Bundle()
}
@ -811,6 +858,9 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
database,
this
) { result ->
if (result.isSuccess) {
PreferencesUtil.saveCurrentTime(applicationContext)
}
// No need to add each info to reload database
result.data = Bundle()
}
@ -828,15 +878,27 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
this,
database,
databaseUri,
intent.getParcelableExtra(MAIN_CREDENTIAL_KEY) ?: MainCredential()
) { hardwareKey, seed ->
intent.getParcelableExtra(MAIN_CREDENTIAL_KEY) ?: MainCredential(),
{ hardwareKey, seed ->
retrieveResponseFromChallenge(hardwareKey, seed)
}
) {
afterAssignMainCredential(databaseUri)
}
} else {
null
}
}
private fun afterAssignMainCredential(databaseUri: Uri) {
// Erase the biometric
CipherDatabaseAction.getInstance(this)
.deleteByDatabaseUri(databaseUri)
// Erase the register keyfile
FileDatabaseHistoryAction.getInstance(this)
.deleteKeyFileByDatabaseUri(databaseUri)
}
private inner class AfterActionNodesRunnable : AfterActionNodesFinish() {
override fun onActionNodesFinish(
result: ActionRunnable.Result,

View file

@ -17,7 +17,7 @@
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.database.action
package com.kunzisoft.keepass.services
import android.app.AlertDialog
import android.content.BroadcastReceiver
@ -41,6 +41,7 @@ import com.kunzisoft.keepass.activities.dialogs.DatabaseChangedDialogFragment
import com.kunzisoft.keepass.activities.dialogs.DatabaseChangedDialogFragment.Companion.DATABASE_CHANGED_DIALOG_TAG
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.MainCredential
import com.kunzisoft.keepass.database.action.ProgressMessage
import com.kunzisoft.keepass.database.crypto.EncryptionAlgorithm
import com.kunzisoft.keepass.database.crypto.kdf.KdfEngine
import com.kunzisoft.keepass.database.element.Entry
@ -51,7 +52,6 @@ import com.kunzisoft.keepass.database.element.node.NodeId
import com.kunzisoft.keepass.database.element.node.Type
import com.kunzisoft.keepass.model.CipherEncryptDatabase
import com.kunzisoft.keepass.model.SnapFileDatabaseInfo
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_CHALLENGE_RESPONDED
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_ASSIGN_PASSWORD_TASK
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_COPY_NODES_TASK

View file

@ -36,7 +36,7 @@ import com.kunzisoft.keepass.services.ClipboardEntryNotificationService
import com.kunzisoft.keepass.services.KeyboardEntryNotificationService
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.timeout.TimeoutHelper
import com.kunzisoft.keepass.utils.UriUtil.getBinaryDir
import com.kunzisoft.keepass.utils.UriHelper.getBinaryDir
import com.kunzisoft.keepass.utils.UriUtil.releaseAllUnnecessaryPermissionUris
const val DATABASE_START_TASK_ACTION = "com.kunzisoft.keepass.DATABASE_START_TASK_ACTION"

View file

@ -267,13 +267,5 @@ object UriUtil {
}
}
fun Context.getBinaryDir(): File {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
this.applicationContext.noBackupFilesDir
} else {
this.applicationContext.filesDir
}
}
private const val TAG = "UriUtil"
}

View file

@ -21,7 +21,9 @@ package com.kunzisoft.keepass.utils
import android.annotation.SuppressLint
import android.content.ContentResolver
import android.content.Context
import android.net.Uri
import android.os.Build
import android.util.Log
import java.io.*
import java.util.*
@ -37,6 +39,14 @@ object UriHelper {
return Uri.decode(this) ?: ""
}
fun Context.getBinaryDir(): File {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
this.applicationContext.noBackupFilesDir
} else {
this.applicationContext.filesDir
}
}
@Throws(FileNotFoundException::class)
fun ContentResolver.getUriInputStream(fileUri: Uri?): InputStream? {
if (fileUri == null)