From b9cfb32a20a2084fb55eda49d915708a7f309e21 Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Tue, 12 Nov 2019 11:56:19 +0100 Subject: [PATCH] Fix OTP dialog --- .../dialogs/SetOTPDialogFragment.kt | 50 +++++++++++-------- .../com/kunzisoft/keepass/otp/OtpElement.kt | 18 ++++--- .../kunzisoft/keepass/otp/OtpEntryFields.kt | 18 +++---- 3 files changed, 51 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/dialogs/SetOTPDialogFragment.kt b/app/src/main/java/com/kunzisoft/keepass/activities/dialogs/SetOTPDialogFragment.kt index a5842a7a0..5cb840453 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/dialogs/SetOTPDialogFragment.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/dialogs/SetOTPDialogFragment.kt @@ -55,7 +55,11 @@ class SetOTPDialogFragment : DialogFragment() { private var otpAlgorithmAdapter: ArrayAdapter? = null private var mManualEvent = false - private var touchListener = View.OnTouchListener { _, event -> + private var mOnFocusChangeListener = View.OnFocusChangeListener { _, isFocus -> + if (!isFocus) + mManualEvent = true + } + private var mOnTouchListener = View.OnTouchListener { _, event -> when (event.action) { MotionEvent.ACTION_DOWN -> { mManualEvent = true @@ -117,13 +121,17 @@ class SetOTPDialogFragment : DialogFragment() { otpDigitsTextView = root?.findViewById(R.id.setup_otp_digits) // To fix init element - otpTypeSpinner?.setOnTouchListener(touchListener) - otpTokenTypeSpinner?.setOnTouchListener(touchListener) - otpAlgorithmSpinner?.setOnTouchListener(touchListener) - otpSecretTextView?.setOnTouchListener(touchListener) - otpPeriodTextView?.setOnTouchListener(touchListener) - otpCounterTextView?.setOnTouchListener(touchListener) - otpDigitsTextView?.setOnTouchListener(touchListener) + // With tab keyboard selection + otpSecretTextView?.onFocusChangeListener = mOnFocusChangeListener + // With finger selection + otpTypeSpinner?.setOnTouchListener(mOnTouchListener) + otpTokenTypeSpinner?.setOnTouchListener(mOnTouchListener) + otpSecretTextView?.setOnTouchListener(mOnTouchListener) + otpAlgorithmSpinner?.setOnTouchListener(mOnTouchListener) + otpPeriodTextView?.setOnTouchListener(mOnTouchListener) + otpCounterTextView?.setOnTouchListener(mOnTouchListener) + otpDigitsTextView?.setOnTouchListener(mOnTouchListener) + // HOTP / TOTP Type selection val otpTypeArray = OtpType.values() @@ -178,8 +186,8 @@ class SetOTPDialogFragment : DialogFragment() { return super.onCreateDialog(savedInstanceState) } - override fun onStart() { - super.onStart() + override fun onResume() { + super.onResume() (dialog as AlertDialog).getButton(Dialog.BUTTON_POSITIVE).setOnClickListener { if (mSecretWellFormed && mCounterWellFormed @@ -236,16 +244,14 @@ class SetOTPDialogFragment : DialogFragment() { // Set secret in OtpElement otpSecretTextView?.addTextChangedListener(object: TextWatcher { override fun afterTextChanged(s: Editable?) { - if (mManualEvent) { - s?.toString()?.let { userString -> - try { - mOtpElement.setBase32Secret(userString) - otpSecretContainer?.error = null - } catch (exception: Exception) { - otpSecretContainer?.error = getString(R.string.error_otp_secret_key) - } - mSecretWellFormed = otpSecretContainer?.error == null + s?.toString()?.let { userString -> + try { + mOtpElement.setBase32Secret(userString) + otpSecretContainer?.error = null + } catch (exception: Exception) { + otpSecretContainer?.error = getString(R.string.error_otp_secret_key) } + mSecretWellFormed = otpSecretContainer?.error == null } } override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} @@ -339,7 +345,11 @@ class SetOTPDialogFragment : DialogFragment() { private fun upgradeParameters() { otpAlgorithmSpinner?.setSelection(TokenCalculator.HashAlgorithm.values() .indexOf(mOtpElement.algorithm)) - otpSecretTextView?.setText(mOtpElement.getBase32Secret()) + otpSecretTextView?.apply { + setText(mOtpElement.getBase32Secret()) + // Cursor at end + setSelection(this.text.length) + } otpCounterTextView?.setText(mOtpElement.counter.toString()) otpPeriodTextView?.setText(mOtpElement.period.toString()) otpDigitsTextView?.setText(mOtpElement.digits.toString()) diff --git a/app/src/main/java/com/kunzisoft/keepass/otp/OtpElement.kt b/app/src/main/java/com/kunzisoft/keepass/otp/OtpElement.kt index 7d8beea2d..ce9393d7e 100644 --- a/app/src/main/java/com/kunzisoft/keepass/otp/OtpElement.kt +++ b/app/src/main/java/com/kunzisoft/keepass/otp/OtpElement.kt @@ -1,7 +1,6 @@ package com.kunzisoft.keepass.otp import com.kunzisoft.keepass.model.OtpModel -import org.apache.commons.codec.DecoderException import org.apache.commons.codec.binary.Base32 import org.apache.commons.codec.binary.Base64 import org.apache.commons.codec.binary.Hex @@ -68,15 +67,17 @@ data class OtpElement(var otpModel: OtpModel = OtpModel()) { var counter get() = otpModel.counter + @Throws(NumberFormatException::class) set(value) { otpModel.counter = if (value < MIN_HOTP_COUNTER || value > MAX_HOTP_COUNTER) { TokenCalculator.HOTP_INITIAL_COUNTER - throw NumberFormatException() + throw IllegalArgumentException() } else value } var period get() = otpModel.period + @Throws(NumberFormatException::class) set(value) { otpModel.period = if (value < MIN_TOTP_PERIOD || value > MAX_TOTP_PERIOD) { TokenCalculator.TOTP_DEFAULT_PERIOD @@ -86,6 +87,7 @@ data class OtpElement(var otpModel: OtpModel = OtpModel()) { var digits get() = otpModel.digits + @Throws(NumberFormatException::class) set(value) { otpModel.digits = if (value < MIN_OTP_DIGITS|| value > MAX_OTP_DIGITS) { TokenCalculator.OTP_DEFAULT_DIGITS @@ -99,18 +101,20 @@ data class OtpElement(var otpModel: OtpModel = OtpModel()) { otpModel.algorithm = value } + @Throws(IllegalArgumentException::class) fun setUTF8Secret(secret: String) { if (secret.isNotEmpty()) otpModel.secret = secret.toByteArray(Charset.forName("UTF-8")) else - throw DecoderException() + throw IllegalArgumentException() } + @Throws(IllegalArgumentException::class) fun setHexSecret(secret: String) { if (secret.isNotEmpty()) otpModel.secret = Hex.decodeHex(secret) else - throw DecoderException() + throw IllegalArgumentException() } fun getBase32Secret(): String { @@ -119,18 +123,20 @@ data class OtpElement(var otpModel: OtpModel = OtpModel()) { } ?: "" } + @Throws(IllegalArgumentException::class) fun setBase32Secret(secret: String) { if (secret.isNotEmpty() && checkBase32Secret(secret)) otpModel.secret = Base32().decode(secret.toByteArray()) else - throw DecoderException() + throw IllegalArgumentException() } + @Throws(IllegalArgumentException::class) fun setBase64Secret(secret: String) { if (secret.isNotEmpty() && checkBase64Secret(secret)) otpModel.secret = Base64().decode(secret.toByteArray()) else - throw DecoderException() + throw IllegalArgumentException() } val token: String diff --git a/app/src/main/java/com/kunzisoft/keepass/otp/OtpEntryFields.kt b/app/src/main/java/com/kunzisoft/keepass/otp/OtpEntryFields.kt index 21bd8854f..6af0f1028 100644 --- a/app/src/main/java/com/kunzisoft/keepass/otp/OtpEntryFields.kt +++ b/app/src/main/java/com/kunzisoft/keepass/otp/OtpEntryFields.kt @@ -158,29 +158,29 @@ object OtpEntryFields { val digitsParam = uri.getQueryParameter(DIGITS_URL_PARAM) if (digitsParam != null && digitsParam.isNotEmpty()) - otpElement.digits = try { - digitsParam.toIntOrNull() ?: OTP_DEFAULT_DIGITS + try { + otpElement.digits = digitsParam.toIntOrNull() ?: OTP_DEFAULT_DIGITS } catch (exception: Exception) { Log.e(TAG, "Unable to retrieve OTP digits.", exception) - OTP_DEFAULT_DIGITS + otpElement.digits = OTP_DEFAULT_DIGITS } val counterParam = uri.getQueryParameter(COUNTER_URL_PARAM) if (counterParam != null && counterParam.isNotEmpty()) - otpElement.counter = try { - counterParam.toLongOrNull() ?: HOTP_INITIAL_COUNTER + try { + otpElement.counter = counterParam.toLongOrNull() ?: HOTP_INITIAL_COUNTER } catch (exception: Exception) { Log.e(TAG, "Unable to retrieve HOTP counter.", exception) - HOTP_INITIAL_COUNTER + otpElement.counter = HOTP_INITIAL_COUNTER } val stepParam = uri.getQueryParameter(PERIOD_URL_PARAM) if (stepParam != null && stepParam.isNotEmpty()) - otpElement.period = try { - stepParam.toIntOrNull() ?: TOTP_DEFAULT_PERIOD + try { + otpElement.period = stepParam.toIntOrNull() ?: TOTP_DEFAULT_PERIOD } catch (exception: Exception) { Log.e(TAG, "Unable to retrieve TOTP period.", exception) - TOTP_DEFAULT_PERIOD + otpElement.period = TOTP_DEFAULT_PERIOD } val algorithmParam = uri.getQueryParameter(ALGORITHM_URL_PARAM)