Skip to content

Commit

Permalink
Merge branch 'release/2.9.19'
Browse files Browse the repository at this point in the history
  • Loading branch information
J-Jamet committed Apr 28, 2021
2 parents 5b7018f + 6de88bf commit 2afd02d
Show file tree
Hide file tree
Showing 33 changed files with 542 additions and 579 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
KeePassDX(2.9.19)
* Fix search slowdown #964
* Fix closing notification after lock request #965
* Better temp advanced unlocking code implementation #965
* Fix OTP token generation #967

KeePassDX(2.9.18)
* Move groups #658
* Improve autofill recognition #960
Expand Down
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ android {
applicationId "com.kunzisoft.keepass"
minSdkVersion 15
targetSdkVersion 30
versionCode = 72
versionName = "2.9.18"
versionCode = 73
versionName = "2.9.19"
multiDexEnabled true

testApplicationId = "com.kunzisoft.keepass.tests"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.kunzisoft.keepass.tests.utils

import com.kunzisoft.keepass.utils.UuidUtil
import junit.framework.TestCase
import java.util.*

class UUIDTest: TestCase() {

fun testUUID() {
val randomUUID = UUID.randomUUID()
val hexStringUUID = UuidUtil.toHexString(randomUUID)
val retrievedUUID = UuidUtil.fromHexString(hexStringUUID)
assertEquals(randomUUID, retrievedUUID)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ class SearchEntryCursorAdapter(private val context: Context,

private fun getEntryFrom(cursor: Cursor): Entry? {
return database.createEntry()?.apply {
database.startManageEntry(this)
entryKDB?.let { entryKDB ->
(cursor as EntryCursorKDB).populateEntry(entryKDB,
{ standardIconId ->
Expand All @@ -127,7 +126,6 @@ class SearchEntryCursorAdapter(private val context: Context,
}
)
}
database.stopManageEntry(this)
}
}

Expand All @@ -150,12 +148,14 @@ class SearchEntryCursorAdapter(private val context: Context,
if (searchGroup != null) {
// Search in hide entries but not meta-stream
for (entry in searchGroup.getFilteredChildEntries(Group.ChildFilter.getDefaults(context))) {
database.startManageEntry(entry)
entry.entryKDB?.let {
cursorKDB?.addEntry(it)
}
entry.entryKDBX?.let {
cursorKDBX?.addEntry(it)
}
database.stopManageEntry(entry)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,7 @@
*/
package com.kunzisoft.keepass.app.database

import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.content.*
import android.net.Uri
import android.os.IBinder
import android.util.Log
Expand All @@ -42,66 +39,95 @@ class CipherDatabaseAction(context: Context) {
// Temp DAO to easily remove content if object no longer in memory
private var useTempDao = PreferencesUtil.isTempAdvancedUnlockEnable(applicationContext)

private val mIntentAdvancedUnlockService = Intent(applicationContext,
AdvancedUnlockNotificationService::class.java)
private var mBinder: AdvancedUnlockNotificationService.AdvancedUnlockBinder? = null
private var mServiceConnection: ServiceConnection? = null

private var mDatabaseListeners = LinkedList<DatabaseListener>()
private var mDatabaseListeners = LinkedList<CipherDatabaseListener>()
private var mAdvancedUnlockBroadcastReceiver = AdvancedUnlockNotificationService.AdvancedUnlockReceiver {
deleteAll()
removeAllDataAndDetach()
}

fun reloadPreferences() {
useTempDao = PreferencesUtil.isTempAdvancedUnlockEnable(applicationContext)
}

@Synchronized
private fun attachService(performedAction: () -> Unit) {
// Check if a service is currently running else do nothing
if (mBinder != null) {
private fun serviceActionTask(startService: Boolean = false, performedAction: () -> Unit) {
// Check if a service is currently running else call action without info
if (startService && mServiceConnection == null) {
attachService(performedAction)
} else {
performedAction.invoke()
} else if (mServiceConnection == null) {
mServiceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, serviceBinder: IBinder?) {
mBinder = (serviceBinder as AdvancedUnlockNotificationService.AdvancedUnlockBinder)
performedAction.invoke()
}
}
}

override fun onServiceDisconnected(name: ComponentName?) {
mBinder = null
mServiceConnection = null
mDatabaseListeners.forEach {
it.onDatabaseCleared()
}
}
@Synchronized
private fun attachService(performedAction: () -> Unit) {
applicationContext.registerReceiver(mAdvancedUnlockBroadcastReceiver, IntentFilter().apply {
addAction(AdvancedUnlockNotificationService.REMOVE_ADVANCED_UNLOCK_KEY_ACTION)
})

mServiceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, serviceBinder: IBinder?) {
mBinder = (serviceBinder as AdvancedUnlockNotificationService.AdvancedUnlockBinder)
performedAction.invoke()
}
applicationContext.bindService(mIntentAdvancedUnlockService,
mServiceConnection!!,
Context.BIND_ABOVE_CLIENT)
if (mBinder == null) {
try {
applicationContext.startService(mIntentAdvancedUnlockService)
} catch (e: Exception) {
Log.e(TAG, "Unable to start cipher action", e)
}

override fun onServiceDisconnected(name: ComponentName?) {
onClear()
}
}
try {
AdvancedUnlockNotificationService.bindService(applicationContext,
mServiceConnection!!,
Context.BIND_AUTO_CREATE)
} catch (e: Exception) {
Log.e(TAG, "Unable to start cipher action", e)
performedAction.invoke()
}
}

@Synchronized
private fun detachService() {
try {
applicationContext.unregisterReceiver(mAdvancedUnlockBroadcastReceiver)
} catch (e: Exception) {}

mServiceConnection?.let {
AdvancedUnlockNotificationService.unbindService(applicationContext, it)
}
}

fun registerDatabaseListener(listener: DatabaseListener) {
mDatabaseListeners.add(listener)
private fun removeAllDataAndDetach() {
detachService()
onClear()
}

fun unregisterDatabaseListener(listener: DatabaseListener) {
mDatabaseListeners.remove(listener)
fun registerDatabaseListener(listenerCipher: CipherDatabaseListener) {
mDatabaseListeners.add(listenerCipher)
}

interface DatabaseListener {
fun onDatabaseCleared()
fun unregisterDatabaseListener(listenerCipher: CipherDatabaseListener) {
mDatabaseListeners.remove(listenerCipher)
}

private fun onClear() {
mBinder = null
mServiceConnection = null
mDatabaseListeners.forEach {
it.onCipherDatabaseCleared()
}
}

interface CipherDatabaseListener {
fun onCipherDatabaseCleared()
}

fun getCipherDatabase(databaseUri: Uri,
cipherDatabaseResultListener: (CipherDatabaseEntity?) -> Unit) {
if (useTempDao) {
attachService {
serviceActionTask {
cipherDatabaseResultListener.invoke(mBinder?.getCipherDatabase(databaseUri))
}
} else {
Expand All @@ -126,7 +152,8 @@ class CipherDatabaseAction(context: Context) {
fun addOrUpdateCipherDatabase(cipherDatabaseEntity: CipherDatabaseEntity,
cipherDatabaseResultListener: (() -> Unit)? = null) {
if (useTempDao) {
attachService {
// The only case to create service (not needed to get an info)
serviceActionTask(true) {
mBinder?.addOrUpdateCipherDatabase(cipherDatabaseEntity)
cipherDatabaseResultListener?.invoke()
}
Expand All @@ -151,7 +178,7 @@ class CipherDatabaseAction(context: Context) {
fun deleteByDatabaseUri(databaseUri: Uri,
cipherDatabaseResultListener: (() -> Unit)? = null) {
if (useTempDao) {
attachService {
serviceActionTask {
mBinder?.deleteByDatabaseUri(databaseUri)
cipherDatabaseResultListener?.invoke()
}
Expand All @@ -168,14 +195,19 @@ class CipherDatabaseAction(context: Context) {
}

fun deleteAll() {
attachService {
mBinder?.deleteAll()
if (useTempDao) {
serviceActionTask {
mBinder?.deleteAll()
}
}
// To erase the residues
IOActionTask(
{
cipherDatabaseDao.deleteAll()
}
).execute()
// Unbind
removeAllDataAndDetach()
}

companion object : SingletonHolderParameter<CipherDatabaseAction, Context>(::CipherDatabaseAction) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import com.kunzisoft.keepass.activities.stylish.StylishFragment
import com.kunzisoft.keepass.app.database.CipherDatabaseAction
import com.kunzisoft.keepass.database.exception.IODatabaseException
import com.kunzisoft.keepass.education.PasswordActivityEducation
import com.kunzisoft.keepass.services.AdvancedUnlockNotificationService
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.view.AdvancedUnlockInfoView

Expand Down Expand Up @@ -68,7 +67,7 @@ class AdvancedUnlockFragment: StylishFragment(), AdvancedUnlockManager.AdvancedU

private lateinit var cipherDatabaseAction : CipherDatabaseAction

private var cipherDatabaseListener: CipherDatabaseAction.DatabaseListener? = null
private var cipherDatabaseListener: CipherDatabaseAction.CipherDatabaseListener? = null

// Only to fix multiple fingerprint menu #332
private var mAllowAdvancedUnlockMenu = false
Expand Down Expand Up @@ -402,9 +401,10 @@ class AdvancedUnlockFragment: StylishFragment(), AdvancedUnlockManager.AdvancedU
fun connect(databaseUri: Uri) {
showViews(true)
this.databaseFileUri = databaseUri
cipherDatabaseListener = object: CipherDatabaseAction.DatabaseListener {
override fun onDatabaseCleared() {
deleteEncryptedDatabaseKey()
cipherDatabaseListener = object: CipherDatabaseAction.CipherDatabaseListener {
override fun onCipherDatabaseCleared() {
advancedUnlockManager?.closeBiometricPrompt()
checkUnlockAvailability()
}
}
cipherDatabaseAction.apply {
Expand Down Expand Up @@ -435,14 +435,12 @@ class AdvancedUnlockFragment: StylishFragment(), AdvancedUnlockManager.AdvancedU

@RequiresApi(Build.VERSION_CODES.M)
fun deleteEncryptedDatabaseKey() {
allowOpenBiometricPrompt = false
mAdvancedUnlockInfoView?.setIconViewClickListener(false, null)
advancedUnlockManager?.closeBiometricPrompt()
databaseFileUri?.let { databaseUri ->
cipherDatabaseAction.deleteByDatabaseUri(databaseUri) {
checkUnlockAvailability()
}
}
} ?: checkUnlockAvailability()
}

override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
Expand Down Expand Up @@ -479,7 +477,6 @@ class AdvancedUnlockFragment: StylishFragment(), AdvancedUnlockManager.AdvancedU
mBuilderListener?.retrieveCredentialForEncryption()?.let { credential ->
advancedUnlockManager?.encryptData(credential)
}
AdvancedUnlockNotificationService.startServiceForTimeout(requireContext())
}
Mode.EXTRACT_CREDENTIAL -> {
// retrieve the encrypted value from preferences
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,6 @@ class Database {
searchInOther = true
searchInUUIDs = false
searchInTags = false
ignoreCase = true
}, omitBackup, max)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import com.kunzisoft.keepass.database.element.DeletedObject
import com.kunzisoft.keepass.database.element.binary.BinaryData
import com.kunzisoft.keepass.database.element.database.DatabaseKDB.Companion.BACKUP_FOLDER_TITLE
import com.kunzisoft.keepass.database.element.entry.EntryKDBX
import com.kunzisoft.keepass.database.element.entry.FieldReferencesEngine
import com.kunzisoft.keepass.database.element.group.GroupKDBX
import com.kunzisoft.keepass.database.element.icon.IconImageCustom
import com.kunzisoft.keepass.database.element.icon.IconImageStandard
Expand Down Expand Up @@ -75,6 +76,7 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
private var kdfList: MutableList<KdfEngine> = ArrayList()
private var numKeyEncRounds: Long = 0
var publicCustomData = VariantDictionary()
private val mFieldReferenceEngine = FieldReferencesEngine(this)

var kdbxVersion = UnsignedInt(0)
var name = ""
Expand Down Expand Up @@ -333,6 +335,19 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
return customData.isNotEmpty()
}

fun getEntryByCustomData(customDataValue: String): EntryKDBX? {
return entryIndexes.values.find { entry ->
entry.customData.containsValue(customDataValue)
}
}

/**
* Retrieve the value of a field reference
*/
fun getFieldReferenceValue(textReference: String, recursionLevel: Int): String {
return mFieldReferenceEngine.compile(textReference, recursionLevel)
}

@Throws(IOException::class)
public override fun getMasterKey(key: String?, keyInputStream: InputStream?): ByteArray {

Expand Down Expand Up @@ -654,9 +669,20 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
this.deletedObjects.add(deletedObject)
}

override fun addEntryTo(newEntry: EntryKDBX, parent: GroupKDBX?) {
super.addEntryTo(newEntry, parent)
mFieldReferenceEngine.clear()
}

override fun updateEntry(entry: EntryKDBX) {
super.updateEntry(entry)
mFieldReferenceEngine.clear()
}

override fun removeEntryFrom(entryToRemove: EntryKDBX, parent: GroupKDBX?) {
super.removeEntryFrom(entryToRemove, parent)
deletedObjects.add(DeletedObject(entryToRemove.id))
mFieldReferenceEngine.clear()
}

override fun undoDeleteEntryFrom(entry: EntryKDBX, origParent: GroupKDBX?) {
Expand Down Expand Up @@ -727,6 +753,7 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
override fun clearCache() {
try {
super.clearCache()
mFieldReferenceEngine.clear()
attachmentPool.clear()
} catch (e: Exception) {
Log.e(TAG, "Unable to clear cache", e)
Expand Down
Loading

0 comments on commit 2afd02d

Please sign in to comment.