diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index df3349851..9a7f47446 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -156,6 +156,8 @@ android:name="com.kunzisoft.keepass.settings.SettingsAdvancedUnlockActivity" /> + hardwareKeyCheckBox.isChecked = true hardwareKeySelectionView.error = - if (!HardwareKeyResponseHelper.isHardwareKeyAvailable(requireActivity(), hardwareKey)) { + if (!HardwareKeyActivity.isHardwareKeyAvailable(requireActivity(), hardwareKey)) { // show hardware driver dialog if required getString(R.string.error_driver_required, hardwareKey.toString()) } else { @@ -231,7 +231,7 @@ class SetMainCredentialDialogFragment : DatabaseDialogFragment() { showEmptyPasswordConfirmationDialog() } else if (!error && hardwareKey != null - && !HardwareKeyResponseHelper.isHardwareKeyAvailable( + && !HardwareKeyActivity.isHardwareKeyAvailable( requireActivity(), hardwareKey, false) ) { // show hardware driver dialog if required diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/legacy/DatabaseActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/legacy/DatabaseActivity.kt index 8fa08476b..a71ac1434 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/legacy/DatabaseActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/legacy/DatabaseActivity.kt @@ -9,7 +9,6 @@ import com.kunzisoft.keepass.database.element.Database import com.kunzisoft.keepass.database.element.MainCredential import com.kunzisoft.keepass.model.CipherEncryptDatabase import com.kunzisoft.keepass.tasks.ActionRunnable -import com.kunzisoft.keepass.viewmodels.ChallengeResponseViewModel import com.kunzisoft.keepass.viewmodels.DatabaseViewModel abstract class DatabaseActivity: StylishActivity(), DatabaseRetrieval { @@ -18,12 +17,10 @@ abstract class DatabaseActivity: StylishActivity(), DatabaseRetrieval { protected var mDatabaseTaskProvider: DatabaseTaskProvider? = null protected var mDatabase: Database? = null - private val mChallengeResponseViewModel: ChallengeResponseViewModel by viewModels() - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - mDatabaseTaskProvider = DatabaseTaskProvider(this, mChallengeResponseViewModel) + mDatabaseTaskProvider = DatabaseTaskProvider(this) mDatabaseTaskProvider?.onDatabaseRetrieved = { database -> val databaseWasReloaded = database?.wasReloaded == true diff --git a/app/src/main/java/com/kunzisoft/keepass/database/action/DatabaseTaskProvider.kt b/app/src/main/java/com/kunzisoft/keepass/database/action/DatabaseTaskProvider.kt index a99d73b22..fff9fea66 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/action/DatabaseTaskProvider.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/action/DatabaseTaskProvider.kt @@ -19,7 +19,6 @@ */ package com.kunzisoft.keepass.database.action -import android.app.Service import android.content.* import android.content.Context.* import android.net.Uri @@ -43,13 +42,13 @@ import com.kunzisoft.keepass.database.element.database.CompressionAlgorithm import com.kunzisoft.keepass.database.element.node.Node import com.kunzisoft.keepass.database.element.node.NodeId import com.kunzisoft.keepass.database.element.node.Type -import com.kunzisoft.keepass.database.exception.InvalidCredentialsDatabaseException import com.kunzisoft.keepass.hardware.HardwareKey -import com.kunzisoft.keepass.hardware.HardwareKeyResponseHelper +import com.kunzisoft.keepass.hardware.HardwareKeyActivity import com.kunzisoft.keepass.model.CipherEncryptDatabase import com.kunzisoft.keepass.model.ProgressMessage 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 import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_CREATE_ENTRY_TASK @@ -86,7 +85,6 @@ import com.kunzisoft.keepass.tasks.ProgressTaskDialogFragment import com.kunzisoft.keepass.tasks.ProgressTaskDialogFragment.Companion.PROGRESS_TASK_DIALOG_TAG import com.kunzisoft.keepass.utils.DATABASE_START_TASK_ACTION import com.kunzisoft.keepass.utils.DATABASE_STOP_TASK_ACTION -import com.kunzisoft.keepass.viewmodels.ChallengeResponseViewModel import kotlinx.coroutines.launch import java.util.* @@ -94,10 +92,11 @@ import java.util.* * Utility class to connect an activity or a service to the DatabaseTaskNotificationService, * Useful to retrieve a database instance and sending tasks commands */ -class DatabaseTaskProvider { +class DatabaseTaskProvider(private var context: Context) { - private var activity: FragmentActivity? = null - private var context: Context + // To show dialog only if context is an activity + private var activity: FragmentActivity? = try { context as? FragmentActivity? } + catch (_: Exception) { null } var onDatabaseRetrieved: ((database: Database?) -> Unit)? = null @@ -105,7 +104,10 @@ class DatabaseTaskProvider { actionTask: String, result: ActionRunnable.Result) -> Unit)? = null - private var intentDatabaseTask: Intent + private var intentDatabaseTask: Intent = Intent( + context.applicationContext, + DatabaseTaskNotificationService::class.java + ) private var databaseTaskBroadcastReceiver: BroadcastReceiver? = null private var mBinder: DatabaseTaskNotificationService.ActionTaskBinder? = null @@ -115,54 +117,6 @@ class DatabaseTaskProvider { private var progressTaskDialogFragment: ProgressTaskDialogFragment? = null private var databaseChangedDialogFragment: DatabaseChangedDialogFragment? = null - private var mChallengeResponseViewModel: ChallengeResponseViewModel? = null - - constructor(activity: FragmentActivity, - challengeResponseViewModel: ChallengeResponseViewModel) { - this.activity = activity - this.context = activity - this.intentDatabaseTask = Intent(activity.applicationContext, - DatabaseTaskNotificationService::class.java) - - // ViewModel used to keep response if activity recreated - this.mChallengeResponseViewModel = challengeResponseViewModel - // To manage hardware key challenge response - val hardwareKeyResponseHelper = HardwareKeyResponseHelper(activity) - hardwareKeyResponseHelper.buildHardwareKeyResponse { responseData, _ -> - // TODO Verify database - // Send to view model in case activity is restarted and not yet connected to service - challengeResponseViewModel.respond(responseData ?: ByteArray(0)) - } - challengeResponseViewModel.dataResponded.observe(activity) { response -> - // Consume the response - if (response != null) { - val binder = mBinder - if (binder != null) { - binder.getService().respondToChallenge(response) - challengeResponseViewModel.consumeResponse() - } - } - } - - this.requestChallengeListener = object: DatabaseTaskNotificationService.RequestChallengeListener { - override fun onChallengeResponseRequested(hardwareKey: HardwareKey, seed: ByteArray?) { - if (HardwareKeyResponseHelper.isHardwareKeyAvailable(activity, hardwareKey)) { - hardwareKeyResponseHelper.launchChallengeForResponse(hardwareKey, seed) - } else { - throw InvalidCredentialsDatabaseException( - context.getString(R.string.error_driver_required, hardwareKey.toString()) - ) - } - } - } - } - - constructor(service: Service) { - this.context = service - this.intentDatabaseTask = Intent(service.applicationContext, - DatabaseTaskNotificationService::class.java) - } - fun destroy() { this.activity = null this.onDatabaseRetrieved = null @@ -172,7 +126,6 @@ class DatabaseTaskProvider { this.serviceConnection = null this.progressTaskDialogFragment = null this.databaseChangedDialogFragment = null - this.mChallengeResponseViewModel = null } private val actionTaskListener = object: DatabaseTaskNotificationService.ActionTaskListener { @@ -235,7 +188,19 @@ class DatabaseTaskProvider { } } - private var requestChallengeListener: DatabaseTaskNotificationService.RequestChallengeListener? = null + private var requestChallengeListener = object: DatabaseTaskNotificationService.RequestChallengeListener { + override fun onChallengeResponseRequested( + hardwareKey: HardwareKey, + seed: ByteArray? + ) { + HardwareKeyActivity + .launchHardwareKeyActivity( + context, + hardwareKey, + seed + ) + } + } private fun startDialog(progressMessage: ProgressMessage) { activity?.let { activity -> @@ -280,7 +245,6 @@ class DatabaseTaskProvider { getService().checkDatabaseInfo() getService().checkAction() } - mChallengeResponseViewModel?.resendResponse() } override fun onServiceDisconnected(name: ComponentName?) { @@ -295,9 +259,7 @@ class DatabaseTaskProvider { service?.addDatabaseListener(databaseListener) service?.addDatabaseFileInfoListener(databaseInfoListener) service?.addActionTaskListener(actionTaskListener) - requestChallengeListener?.let { - service?.addRequestChallengeListener(it) - } + service?.setRequestChallengeListener(requestChallengeListener) } private fun removeServiceListeners(service: DatabaseTaskNotificationService.ActionTaskBinder?) { @@ -762,6 +724,13 @@ class DatabaseTaskProvider { , ACTION_DATABASE_SAVE) } + fun startChallengeResponded(response: ByteArray?) { + start(Bundle().apply { + putByteArray(DatabaseTaskNotificationService.DATA_BYTES, response) + } + , ACTION_CHALLENGE_RESPONDED) + } + companion object { private val TAG = DatabaseTaskProvider::class.java.name } diff --git a/app/src/main/java/com/kunzisoft/keepass/hardware/HardwareKeyActivity.kt b/app/src/main/java/com/kunzisoft/keepass/hardware/HardwareKeyActivity.kt new file mode 100644 index 000000000..d31dc0c5e --- /dev/null +++ b/app/src/main/java/com/kunzisoft/keepass/hardware/HardwareKeyActivity.kt @@ -0,0 +1,150 @@ +package com.kunzisoft.keepass.hardware + +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.util.Log +import androidx.activity.result.ActivityResult +import androidx.activity.result.ActivityResultCallback +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.contract.ActivityResultContracts +import androidx.appcompat.app.AlertDialog +import com.kunzisoft.keepass.R +import com.kunzisoft.keepass.activities.legacy.DatabaseActivity +import com.kunzisoft.keepass.database.element.Database +import com.kunzisoft.keepass.utils.UriUtil + +/** + * Special activity to deal with hardware key drivers, + * return the response to the database service once finished + */ +class HardwareKeyActivity: DatabaseActivity(){ + + // To manage hardware key challenge response + private val resultCallback = ActivityResultCallback { result -> + if (result.resultCode == Activity.RESULT_OK) { + val challengeResponse: ByteArray? = result.data?.getByteArrayExtra(HARDWARE_KEY_RESPONSE_KEY) + Log.d(TAG, "Response form challenge") + mDatabaseTaskProvider?.startChallengeResponded(challengeResponse ?: ByteArray(0)) + } else { + Log.e(TAG, "Response from challenge error") + mDatabaseTaskProvider?.startChallengeResponded(ByteArray(0)) + } + finish() + } + + private var activityResultLauncher: ActivityResultLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult(), + resultCallback + ) + + override fun onDatabaseRetrieved(database: Database?) { + super.onDatabaseRetrieved(database) + + val hardwareKey = HardwareKey.getHardwareKeyFromString( + intent.getStringExtra(DATA_HARDWARE_KEY) + ) + if (isHardwareKeyAvailable(this, hardwareKey)) { + when (hardwareKey) { + /* + HardwareKey.FIDO2_SECRET -> { + // TODO FIDO2 under development + throw Exception("FIDO2 not implemented") + } + */ + HardwareKey.CHALLENGE_RESPONSE_YUBIKEY -> { + launchYubikeyChallengeForResponse(intent.getByteArrayExtra(DATA_SEED)) + } + else -> { + finish() + } + } + } else { + finish() + } + } + + private fun launchYubikeyChallengeForResponse(seed: ByteArray?) { + // Transform the seed before sending + var challenge: ByteArray? = null + if (seed != null) { + challenge = ByteArray(64) + seed.copyInto(challenge, 0, 0, 32) + challenge.fill(32, 32, 64) + } + // Send to the driver + activityResultLauncher.launch( + Intent(YUBIKEY_CHALLENGE_RESPONSE_INTENT).apply { + putExtra(HARDWARE_KEY_CHALLENGE_KEY, challenge) + } + ) + Log.d(TAG, "Challenge sent") + } + + companion object { + private val TAG = HardwareKeyActivity::class.java.simpleName + + private const val DATA_HARDWARE_KEY = "DATA_HARDWARE_KEY" + private const val DATA_SEED = "DATA_SEED" + private const val YUBIKEY_CHALLENGE_RESPONSE_INTENT = "android.yubikey.intent.action.CHALLENGE_RESPONSE" + private const val HARDWARE_KEY_CHALLENGE_KEY = "challenge" + private const val HARDWARE_KEY_RESPONSE_KEY = "response" + + fun launchHardwareKeyActivity( + context: Context, + hardwareKey: HardwareKey, + seed: ByteArray? + ) { + context.startActivity(Intent(context, HardwareKeyActivity::class.java).apply { + //flags = FLAG_ACTIVITY_NEW_TASK + putExtra(DATA_HARDWARE_KEY, hardwareKey.value) + putExtra(DATA_SEED, seed) + }) + } + + fun isHardwareKeyAvailable( + context: Context, + hardwareKey: HardwareKey?, + showDialog: Boolean = true + ): Boolean { + if (hardwareKey == null) + return false + return when (hardwareKey) { + /* + HardwareKey.FIDO2_SECRET -> { + // TODO FIDO2 under development + if (showDialog) + UnderDevelopmentFeatureDialogFragment() + .show(activity.supportFragmentManager, "underDevFeatureDialog") + false + } + */ + HardwareKey.CHALLENGE_RESPONSE_YUBIKEY -> { + // Check available intent + val yubikeyDriverAvailable = + Intent(YUBIKEY_CHALLENGE_RESPONSE_INTENT) + .resolveActivity(context.packageManager) != null + if (showDialog && !yubikeyDriverAvailable) + showHardwareKeyDriverNeeded(context, hardwareKey) + yubikeyDriverAvailable + } + } + } + + private fun showHardwareKeyDriverNeeded( + context: Context, + hardwareKey: HardwareKey + ) { + val builder = AlertDialog.Builder(context) + builder + .setMessage( + context.getString(R.string.error_driver_required, hardwareKey.toString()) + ) + .setPositiveButton(R.string.download) { _, _ -> + UriUtil.openExternalApp(context, context.getString(R.string.key_driver_app_id)) + } + .setNegativeButton(android.R.string.cancel) { _, _ -> } + builder.create().show() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kunzisoft/keepass/hardware/HardwareKeyResponseHelper.kt b/app/src/main/java/com/kunzisoft/keepass/hardware/HardwareKeyResponseHelper.kt deleted file mode 100644 index 256cce671..000000000 --- a/app/src/main/java/com/kunzisoft/keepass/hardware/HardwareKeyResponseHelper.kt +++ /dev/null @@ -1,144 +0,0 @@ -package com.kunzisoft.keepass.hardware - -import android.app.Activity -import android.content.Intent -import android.os.Bundle -import android.util.Log -import androidx.activity.result.ActivityResult -import androidx.activity.result.ActivityResultCallback -import androidx.activity.result.ActivityResultLauncher -import androidx.activity.result.contract.ActivityResultContracts -import androidx.appcompat.app.AlertDialog -import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentActivity -import androidx.lifecycle.lifecycleScope -import com.kunzisoft.keepass.R -import com.kunzisoft.keepass.utils.UriUtil -import kotlinx.coroutines.launch - -class HardwareKeyResponseHelper { - - private var activity: FragmentActivity? = null - private var fragment: Fragment? = null - - private var getChallengeResponseResultLauncher: ActivityResultLauncher? = null - - constructor(context: FragmentActivity) { - this.activity = context - this.fragment = null - } - - constructor(context: Fragment) { - this.activity = context.activity - this.fragment = context - } - - fun buildHardwareKeyResponse(onChallengeResponded: (challengeResponse: ByteArray?, - extra: Bundle?) -> Unit) { - val resultCallback = ActivityResultCallback { result -> - if (result.resultCode == Activity.RESULT_OK) { - val challengeResponse: ByteArray? = result.data?.getByteArrayExtra(HARDWARE_KEY_RESPONSE_KEY) - Log.d(TAG, "Response form challenge") - onChallengeResponded.invoke(challengeResponse, - result.data?.getBundleExtra(EXTRA_BUNDLE_KEY)) - } else { - Log.e(TAG, "Response from challenge error") - onChallengeResponded.invoke(null, - result.data?.getBundleExtra(EXTRA_BUNDLE_KEY)) - } - } - - getChallengeResponseResultLauncher = if (fragment != null) { - fragment?.registerForActivityResult( - ActivityResultContracts.StartActivityForResult(), - resultCallback - ) - } else { - activity?.registerForActivityResult( - ActivityResultContracts.StartActivityForResult(), - resultCallback - ) - } - } - - fun launchChallengeForResponse(hardwareKey: HardwareKey, seed: ByteArray?) { - when (hardwareKey) { - /* - HardwareKey.FIDO2_SECRET -> { - // TODO FIDO2 under development - throw Exception("FIDO2 not implemented") - } - */ - HardwareKey.CHALLENGE_RESPONSE_YUBIKEY -> { - // Transform the seed before sending - var challenge: ByteArray? = null - if (seed != null) { - challenge = ByteArray(64) - seed.copyInto(challenge, 0, 0, 32) - challenge.fill(32, 32, 64) - } - // Send to the driver - getChallengeResponseResultLauncher!!.launch( - Intent(YUBIKEY_CHALLENGE_RESPONSE_INTENT).apply { - putExtra(HARDWARE_KEY_CHALLENGE_KEY, challenge) - } - ) - Log.d(TAG, "Challenge sent") - } - } - } - - companion object { - private val TAG = HardwareKeyResponseHelper::class.java.simpleName - - private const val YUBIKEY_CHALLENGE_RESPONSE_INTENT = "android.yubikey.intent.action.CHALLENGE_RESPONSE" - private const val HARDWARE_KEY_CHALLENGE_KEY = "challenge" - private const val HARDWARE_KEY_RESPONSE_KEY = "response" - private const val EXTRA_BUNDLE_KEY = "EXTRA_BUNDLE_KEY" - - fun isHardwareKeyAvailable( - activity: FragmentActivity, - hardwareKey: HardwareKey, - showDialog: Boolean = true - ): Boolean { - return when (hardwareKey) { - /* - HardwareKey.FIDO2_SECRET -> { - // TODO FIDO2 under development - if (showDialog) - UnderDevelopmentFeatureDialogFragment() - .show(activity.supportFragmentManager, "underDevFeatureDialog") - false - } - */ - HardwareKey.CHALLENGE_RESPONSE_YUBIKEY -> { - // Check available intent - val yubikeyDriverAvailable = - Intent(YUBIKEY_CHALLENGE_RESPONSE_INTENT) - .resolveActivity(activity.packageManager) != null - if (showDialog && !yubikeyDriverAvailable) - showHardwareKeyDriverNeeded(activity, hardwareKey) - yubikeyDriverAvailable - } - } - } - - private fun showHardwareKeyDriverNeeded( - activity: FragmentActivity, - hardwareKey: HardwareKey - ) { - activity.lifecycleScope.launch { - val builder = AlertDialog.Builder(activity) - builder - .setMessage( - activity.getString(R.string.error_driver_required, hardwareKey.toString()) - ) - .setPositiveButton(R.string.download) { _, _ -> - UriUtil.openExternalApp(activity, activity.getString(R.string.key_driver_app_id)) - } - .setNegativeButton(android.R.string.cancel) { _, _ -> } - builder.create().show() - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt b/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt index 673cb52a6..254ae5c2b 100644 --- a/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt +++ b/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt @@ -124,8 +124,8 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress mActionTaskListeners.remove(actionTaskListener) } - @ExperimentalCoroutinesApi - fun addRequestChallengeListener(requestChallengeListener: RequestChallengeListener) { + @OptIn(ExperimentalCoroutinesApi::class) + fun setRequestChallengeListener(requestChallengeListener: RequestChallengeListener) { mainScope.launch { val requestChannel = mRequestChallengeListenerChannel if (requestChannel == null || requestChannel.isEmpty) { @@ -169,7 +169,10 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress } interface RequestChallengeListener { - fun onChallengeResponseRequested(hardwareKey: HardwareKey, seed: ByteArray?) + fun onChallengeResponseRequested( + hardwareKey: HardwareKey, + seed: ByteArray? + ) } fun checkDatabase() { @@ -270,8 +273,8 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress mResponseChallengeChannel = null } - @ExperimentalCoroutinesApi - fun respondToChallenge(response: ByteArray) { + @OptIn(ExperimentalCoroutinesApi::class) + private fun respondToChallenge(response: ByteArray) { mainScope.launch { val responseChannel = mResponseChallengeChannel if (responseChannel == null || responseChannel.isEmpty) { @@ -323,6 +326,12 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress stopSelf() } + if (intentAction == ACTION_CHALLENGE_RESPONDED) { + intent.getByteArrayExtra(DATA_BYTES)?.let { + respondToChallenge(it) + } + } + val actionRunnable: ActionRunnable? = when (intentAction) { ACTION_DATABASE_CREATE_TASK -> buildDatabaseCreateActionTask(intent, database) ACTION_DATABASE_LOAD_TASK -> buildDatabaseLoadActionTask(intent, database) @@ -756,7 +765,6 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress databaseToMergeUri, databaseToMergeMainCredential, { hardwareKey, seed -> - // TODO fix first challenge response retrieveResponseFromChallenge(hardwareKey, seed) }, database, @@ -1157,6 +1165,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress const val ACTION_DATABASE_UPDATE_PARALLELISM_TASK = "ACTION_DATABASE_UPDATE_PARALLELISM_TASK" const val ACTION_DATABASE_UPDATE_ITERATIONS_TASK = "ACTION_DATABASE_UPDATE_ITERATIONS_TASK" const val ACTION_DATABASE_SAVE = "ACTION_DATABASE_SAVE" + const val ACTION_CHALLENGE_RESPONDED = "ACTION_CHALLENGE_RESPONDED" const val DATABASE_TASK_TITLE_KEY = "DATABASE_TASK_TITLE_KEY" const val DATABASE_TASK_MESSAGE_KEY = "DATABASE_TASK_MESSAGE_KEY" @@ -1180,6 +1189,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress const val NEW_NODES_KEY = "NEW_NODES_KEY" const val OLD_ELEMENT_KEY = "OLD_ELEMENT_KEY" // Warning type of this thing change every time const val NEW_ELEMENT_KEY = "NEW_ELEMENT_KEY" // Warning type of this thing change every time + const val DATA_BYTES = "DATA_BYTES" fun getListNodesFromBundle(database: Database, bundle: Bundle): List { val nodesAction = ArrayList() diff --git a/app/src/main/java/com/kunzisoft/keepass/viewmodels/ChallengeResponseViewModel.kt b/app/src/main/java/com/kunzisoft/keepass/viewmodels/ChallengeResponseViewModel.kt deleted file mode 100644 index 5134e7be8..000000000 --- a/app/src/main/java/com/kunzisoft/keepass/viewmodels/ChallengeResponseViewModel.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.kunzisoft.keepass.viewmodels - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel - -class ChallengeResponseViewModel: ViewModel() { - - val dataResponded : LiveData get() = _dataResponded - private val _dataResponded = MutableLiveData() - - fun respond(byteArray: ByteArray) { - _dataResponded.value = byteArray - } - - fun resendResponse() { - dataResponded.value?.let { - _dataResponded.value = it - } - } - - fun consumeResponse() { - _dataResponded.value = null - } -} \ No newline at end of file