fix: better challenge channel implementation

This commit is contained in:
J-Jamet
2023-01-22 20:21:17 +01:00
parent f9dc456032
commit 9cec64ded4
3 changed files with 49 additions and 81 deletions

View File

@@ -42,8 +42,6 @@ import com.kunzisoft.keepass.database.element.database.CompressionAlgorithm
import com.kunzisoft.keepass.database.element.node.Node import com.kunzisoft.keepass.database.element.node.Node
import com.kunzisoft.keepass.database.element.node.NodeId import com.kunzisoft.keepass.database.element.node.NodeId
import com.kunzisoft.keepass.database.element.node.Type import com.kunzisoft.keepass.database.element.node.Type
import com.kunzisoft.keepass.hardware.HardwareKey
import com.kunzisoft.keepass.hardware.HardwareKeyActivity
import com.kunzisoft.keepass.model.CipherEncryptDatabase import com.kunzisoft.keepass.model.CipherEncryptDatabase
import com.kunzisoft.keepass.model.ProgressMessage import com.kunzisoft.keepass.model.ProgressMessage
import com.kunzisoft.keepass.model.SnapFileDatabaseInfo import com.kunzisoft.keepass.model.SnapFileDatabaseInfo
@@ -188,20 +186,6 @@ class DatabaseTaskProvider(private var context: Context) {
} }
} }
private var requestChallengeListener = object: DatabaseTaskNotificationService.RequestChallengeListener {
override fun onChallengeResponseRequested(
hardwareKey: HardwareKey,
seed: ByteArray?
) {
HardwareKeyActivity
.launchHardwareKeyActivity(
context,
hardwareKey,
seed
)
}
}
private fun startDialog(progressMessage: ProgressMessage) { private fun startDialog(progressMessage: ProgressMessage) {
activity?.let { activity -> activity?.let { activity ->
activity.lifecycleScope.launch { activity.lifecycleScope.launch {
@@ -259,14 +243,12 @@ class DatabaseTaskProvider(private var context: Context) {
service?.addDatabaseListener(databaseListener) service?.addDatabaseListener(databaseListener)
service?.addDatabaseFileInfoListener(databaseInfoListener) service?.addDatabaseFileInfoListener(databaseInfoListener)
service?.addActionTaskListener(actionTaskListener) service?.addActionTaskListener(actionTaskListener)
service?.setRequestChallengeListener(requestChallengeListener)
} }
private fun removeServiceListeners(service: DatabaseTaskNotificationService.ActionTaskBinder?) { private fun removeServiceListeners(service: DatabaseTaskNotificationService.ActionTaskBinder?) {
service?.removeActionTaskListener(actionTaskListener) service?.removeActionTaskListener(actionTaskListener)
service?.removeDatabaseFileInfoListener(databaseInfoListener) service?.removeDatabaseFileInfoListener(databaseInfoListener)
service?.removeDatabaseListener(databaseListener) service?.removeDatabaseListener(databaseListener)
service?.removeRequestChallengeListener()
} }
private fun bindService() { private fun bindService() {

View File

@@ -3,6 +3,7 @@ package com.kunzisoft.keepass.hardware
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.util.Log import android.util.Log
import androidx.activity.result.ActivityResult import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultCallback import androidx.activity.result.ActivityResultCallback
@@ -96,7 +97,7 @@ class HardwareKeyActivity: DatabaseActivity(){
seed: ByteArray? seed: ByteArray?
) { ) {
context.startActivity(Intent(context, HardwareKeyActivity::class.java).apply { context.startActivity(Intent(context, HardwareKeyActivity::class.java).apply {
//flags = FLAG_ACTIVITY_NEW_TASK flags = FLAG_ACTIVITY_NEW_TASK
putExtra(DATA_HARDWARE_KEY, hardwareKey.value) putExtra(DATA_HARDWARE_KEY, hardwareKey.value)
putExtra(DATA_SEED, seed) putExtra(DATA_SEED, seed)
}) })

View File

@@ -44,6 +44,7 @@ import com.kunzisoft.keepass.database.element.node.Node
import com.kunzisoft.keepass.database.element.node.NodeId import com.kunzisoft.keepass.database.element.node.NodeId
import com.kunzisoft.keepass.database.element.node.Type import com.kunzisoft.keepass.database.element.node.Type
import com.kunzisoft.keepass.hardware.HardwareKey import com.kunzisoft.keepass.hardware.HardwareKey
import com.kunzisoft.keepass.hardware.HardwareKeyActivity
import com.kunzisoft.keepass.model.CipherEncryptDatabase import com.kunzisoft.keepass.model.CipherEncryptDatabase
import com.kunzisoft.keepass.model.ProgressMessage import com.kunzisoft.keepass.model.ProgressMessage
import com.kunzisoft.keepass.model.SnapFileDatabaseInfo import com.kunzisoft.keepass.model.SnapFileDatabaseInfo
@@ -75,8 +76,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
private var mDatabaseInfoListeners = mutableListOf<DatabaseInfoListener>() private var mDatabaseInfoListeners = mutableListOf<DatabaseInfoListener>()
private var mActionTaskBinder = ActionTaskBinder() private var mActionTaskBinder = ActionTaskBinder()
private var mActionTaskListeners = mutableListOf<ActionTaskListener>() private var mActionTaskListeners = mutableListOf<ActionTaskListener>()
// Channel to connect asynchronously a listener or a response // Channel to connect asynchronously a response
private var mRequestChallengeListenerChannel: Channel<RequestChallengeListener>? = null
private var mResponseChallengeChannel: Channel<ByteArray?>? = null private var mResponseChallengeChannel: Channel<ByteArray?>? = null
private var mActionRunning = false private var mActionRunning = false
@@ -123,30 +123,6 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
fun removeActionTaskListener(actionTaskListener: ActionTaskListener) { fun removeActionTaskListener(actionTaskListener: ActionTaskListener) {
mActionTaskListeners.remove(actionTaskListener) mActionTaskListeners.remove(actionTaskListener)
} }
@OptIn(ExperimentalCoroutinesApi::class)
fun setRequestChallengeListener(requestChallengeListener: RequestChallengeListener) {
mainScope.launch {
val requestChannel = mRequestChallengeListenerChannel
if (requestChannel == null || requestChannel.isEmpty) {
initializeChallengeResponse()
mRequestChallengeListenerChannel?.send(requestChallengeListener)
} else {
cancelChallengeResponse(R.string.error_challenge_already_requested)
}
}
}
fun removeRequestChallengeListener() {
mainScope.launch {
try {
mRequestChallengeListenerChannel?.cancel()
} catch (e: Exception) {
Log.w(TAG, "Request challenge listener cannot be closed.", e)
}
mRequestChallengeListenerChannel = null
}
}
} }
interface DatabaseListener { interface DatabaseListener {
@@ -249,32 +225,8 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
} }
} }
private fun initializeChallengeResponse() {
// Init the channels
if (mRequestChallengeListenerChannel == null) {
mRequestChallengeListenerChannel = Channel(0)
}
if (mResponseChallengeChannel == null) {
mResponseChallengeChannel = Channel(0)
}
}
private fun closeChallengeResponse() {
mRequestChallengeListenerChannel?.close()
mResponseChallengeChannel?.close()
mRequestChallengeListenerChannel = null
mResponseChallengeChannel = null
}
private fun cancelChallengeResponse(@StringRes error: Int) {
mRequestChallengeListenerChannel?.cancel(CancellationException(getString(error)))
mRequestChallengeListenerChannel = null
mResponseChallengeChannel?.cancel(CancellationException(getString(error)))
mResponseChallengeChannel = null
}
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
private fun respondToChallenge(response: ByteArray) { private fun sendResponseToChallenge(response: ByteArray) {
mainScope.launch { mainScope.launch {
val responseChannel = mResponseChallengeChannel val responseChannel = mResponseChallengeChannel
if (responseChannel == null || responseChannel.isEmpty) { if (responseChannel == null || responseChannel.isEmpty) {
@@ -289,6 +241,23 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
} }
} }
private fun initializeChallengeResponse() {
// Init the channels
if (mResponseChallengeChannel == null) {
mResponseChallengeChannel = Channel(0)
}
}
private fun closeChallengeResponse() {
mResponseChallengeChannel?.close()
mResponseChallengeChannel = null
}
private fun cancelChallengeResponse(@StringRes error: Int) {
mResponseChallengeChannel?.cancel(CancellationException(getString(error)))
mResponseChallengeChannel = null
}
override fun onBind(intent: Intent): IBinder? { override fun onBind(intent: Intent): IBinder? {
super.onBind(intent) super.onBind(intent)
return mActionTaskBinder return mActionTaskBinder
@@ -326,12 +295,6 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
stopSelf() stopSelf()
} }
if (intentAction == ACTION_CHALLENGE_RESPONDED) {
intent.getByteArrayExtra(DATA_BYTES)?.let {
respondToChallenge(it)
}
}
val actionRunnable: ActionRunnable? = when (intentAction) { val actionRunnable: ActionRunnable? = when (intentAction) {
ACTION_DATABASE_CREATE_TASK -> buildDatabaseCreateActionTask(intent, database) ACTION_DATABASE_CREATE_TASK -> buildDatabaseCreateActionTask(intent, database)
ACTION_DATABASE_LOAD_TASK -> buildDatabaseLoadActionTask(intent, database) ACTION_DATABASE_LOAD_TASK -> buildDatabaseLoadActionTask(intent, database)
@@ -362,7 +325,8 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
ACTION_DATABASE_UPDATE_MEMORY_USAGE_TASK, ACTION_DATABASE_UPDATE_MEMORY_USAGE_TASK,
ACTION_DATABASE_UPDATE_PARALLELISM_TASK, ACTION_DATABASE_UPDATE_PARALLELISM_TASK,
ACTION_DATABASE_UPDATE_ITERATIONS_TASK -> buildDatabaseUpdateElementActionTask(intent, database) ACTION_DATABASE_UPDATE_ITERATIONS_TASK -> buildDatabaseUpdateElementActionTask(intent, database)
ACTION_DATABASE_SAVE -> buildDatabaseSave(intent, database) ACTION_DATABASE_SAVE -> buildDatabaseSaveActionTask(intent, database)
ACTION_CHALLENGE_RESPONDED -> buildChallengeRespondedActionTask(intent)
else -> null else -> null
} }
@@ -386,7 +350,6 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
database, mProgressMessage database, mProgressMessage
) )
} }
}, },
{ {
actionRunnable actionRunnable
@@ -659,8 +622,12 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
} }
// Send the request // Send the request
notifyProgressMessage() notifyProgressMessage()
val challengeResponseRequestListener = mRequestChallengeListenerChannel?.receive() HardwareKeyActivity
challengeResponseRequestListener?.onChallengeResponseRequested(hardwareKey, seed) .launchHardwareKeyActivity(
this@DatabaseTaskNotificationService,
hardwareKey,
seed
)
// Wait the response // Wait the response
mProgressMessage.apply { mProgressMessage.apply {
messageId = R.string.waiting_challenge_response messageId = R.string.waiting_challenge_response
@@ -1108,7 +1075,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
/** /**
* Save database without parameter * Save database without parameter
*/ */
private fun buildDatabaseSave(intent: Intent, database: Database): ActionRunnable? { private fun buildDatabaseSaveActionTask(intent: Intent, database: Database): ActionRunnable? {
return if (intent.hasExtra(SAVE_DATABASE_KEY)) { return if (intent.hasExtra(SAVE_DATABASE_KEY)) {
var databaseCopyUri: Uri? = null var databaseCopyUri: Uri? = null
@@ -1129,6 +1096,24 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
} }
} }
private fun buildChallengeRespondedActionTask(intent: Intent): ActionRunnable? {
return if (intent.hasExtra(DATA_BYTES)) {
object : ActionRunnable() {
override fun onStartRun() {}
override fun onActionRun() {
mainScope.launch {
intent.getByteArrayExtra(DATA_BYTES)?.let { response ->
sendResponseToChallenge(response)
}
}
}
override fun onFinishRun() {}
}
} else {
null
}
}
companion object { companion object {
private val TAG = DatabaseTaskNotificationService::class.java.name private val TAG = DatabaseTaskNotificationService::class.java.name