Fix OTP runnable

This commit is contained in:
J-Jamet
2021-06-17 20:35:42 +02:00
parent 0d376bd5b7
commit 531e345dd9
4 changed files with 80 additions and 55 deletions

View File

@@ -182,7 +182,9 @@ class EntryActivity : LockingActivity() {
}
mEntryViewModel.onOtpElementUpdated.observe(this) { otpElement ->
when (otpElement.type) {
if (otpElement == null)
entryProgress?.visibility = View.GONE
when (otpElement?.type) {
// Only add token if HOTP
OtpType.HOTP -> {
entryProgress?.visibility = View.GONE

View File

@@ -46,7 +46,6 @@ class EntryFragment: DatabaseFragment() {
private lateinit var uuidView: TextView
private lateinit var uuidReferenceView: TextView
private var mOtpRunnable: Runnable? = null
private var mClipboardHelper: ClipboardHelper? = null
private val mEntryViewModel: EntryViewModel by activityViewModels()
@@ -143,8 +142,10 @@ class EntryFragment: DatabaseFragment() {
// Populate entry views
templateView.setEntryInfo(entryInfo)
//Assign OTP field
assignOtp(entryInfo)
// OTP timer updated
templateView.setOnOtpElementUpdated { otpElementUpdated ->
mEntryViewModel.onOtpElementUpdated(otpElementUpdated)
}
// Manage attachments
assignAttachments(entryInfo?.attachments ?: listOf())
@@ -185,39 +186,6 @@ class EntryFragment: DatabaseFragment() {
templateView.reload()
}
private fun assignOtp(entryInfo: EntryInfo?) {
entryInfo?.otpModel?.let { otpModel ->
val otpElement = OtpElement(otpModel)
templateView.getOtpTokenView()?.let { otpFieldView ->
otpFieldView.removeCallbacks(mOtpRunnable)
if (otpElement.token.isEmpty()) {
otpFieldView.setLabel(R.string.entry_otp)
otpFieldView.setValue(R.string.error_invalid_OTP)
otpFieldView.setCopyButtonState(EntryFieldView.ButtonState.GONE)
} else {
otpFieldView.label = otpElement.type.name
otpFieldView.value = otpElement.token
otpFieldView.setCopyButtonState(EntryFieldView.ButtonState.ACTIVATE)
otpFieldView.setCopyButtonClickListener {
mClipboardHelper?.timeoutCopyToClipboard(
otpElement.token,
getString(R.string.copy_field, getString(R.string.entry_otp))
)
}
mOtpRunnable = Runnable {
if (otpElement.shouldRefreshToken()) {
otpFieldView.value = otpElement.token
}
mEntryViewModel.onOtpElementUpdated(otpElement)
otpFieldView.postDelayed(mOtpRunnable, 1000)
}
mEntryViewModel.onOtpElementUpdated(otpElement)
otpFieldView.post(mOtpRunnable)
}
}
}
}
private fun assignCreationDate(date: DateInstant?) {
creationDateView.text = date?.getDateTimeString(resources)
}

View File

@@ -5,6 +5,7 @@ import android.util.AttributeSet
import android.util.Log
import android.view.View
import androidx.core.view.isVisible
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.DateInstant
import com.kunzisoft.keepass.database.element.Field
import com.kunzisoft.keepass.database.element.security.ProtectedString
@@ -12,7 +13,8 @@ import com.kunzisoft.keepass.database.element.template.TemplateAttribute
import com.kunzisoft.keepass.database.element.template.TemplateAttributeType
import com.kunzisoft.keepass.database.element.template.TemplateField
import com.kunzisoft.keepass.model.EntryInfo
import com.kunzisoft.keepass.otp.OtpEntryFields
import com.kunzisoft.keepass.model.OtpModel
import com.kunzisoft.keepass.otp.OtpElement
import com.kunzisoft.keepass.otp.OtpEntryFields.OTP_TOKEN_FIELD
@@ -205,6 +207,12 @@ class TemplateView @JvmOverloads constructor(context: Context,
templateContainerView.findViewById<View>(customFieldId.viewId)
.isVisible = false
}
// Assign specific OTP dynamic view
removeOtpRunnable()
entryInfo.otpModel?.let {
assignOtp(it)
}
}
}
@@ -248,20 +256,6 @@ class TemplateView @JvmOverloads constructor(context: Context,
}
retrieveCustomFieldsFromView(templateFieldNotEmpty)
mEntryInfo?.otpModel = OtpEntryFields.parseFields { key ->
getCustomField(key).protectedValue.toString()
}?.otpModel
}
fun getOtpTokenView(): EntryFieldView? {
val indexFieldViewId = indexCustomFieldIdByName(OTP_TOKEN_FIELD)
if (indexFieldViewId >= 0) {
// Template contains the custom view
val customFieldId = mCustomFieldIds[indexFieldViewId]
return findViewById(customFieldId.viewId)
}
return null
}
override fun getCustomField(fieldName: String, templateFieldNotEmpty: Boolean): Field? {
@@ -285,6 +279,67 @@ class TemplateView @JvmOverloads constructor(context: Context,
return null
}
/*
* OTP Runnable
*/
private var mOtpRunnable: Runnable? = null
private var mLastOtpTokenView: View? = null
fun setOnOtpElementUpdated(listener: ((OtpElement?) -> Unit)?) {
this.mOnOtpElementUpdated = listener
}
private var mOnOtpElementUpdated: ((OtpElement?) -> Unit)? = null
private fun getOtpTokenView(): EntryFieldView? {
val indexFieldViewId = indexCustomFieldIdByName(OTP_TOKEN_FIELD)
if (indexFieldViewId >= 0) {
// Template contains the custom view
val customFieldId = mCustomFieldIds[indexFieldViewId]
return findViewById(customFieldId.viewId)
}
return null
}
private fun assignOtp(otpModel: OtpModel) {
getOtpTokenView()?.apply {
val otpElement = OtpElement(otpModel)
if (otpElement.token.isEmpty()) {
setLabel(R.string.entry_otp)
setValue(R.string.error_invalid_OTP)
setCopyButtonState(EntryFieldView.ButtonState.GONE)
} else {
label = otpElement.type.name
value = otpElement.token
setCopyButtonState(EntryFieldView.ButtonState.ACTIVATE)
setCopyButtonClickListener {
mOnCopyActionClickListener?.invoke(Field(
otpElement.type.name,
ProtectedString(false, otpElement.token)))
}
mLastOtpTokenView = this
mOtpRunnable = Runnable {
if (otpElement.shouldRefreshToken()) {
value = otpElement.token
}
if (mLastOtpTokenView == null) {
mOnOtpElementUpdated?.invoke(null)
} else {
mOnOtpElementUpdated?.invoke(otpElement)
postDelayed(mOtpRunnable, 1000)
}
}
mOnOtpElementUpdated?.invoke(otpElement)
post(mOtpRunnable)
}
}
}
private fun removeOtpRunnable() {
mLastOtpTokenView?.removeCallbacks(mOtpRunnable)
mLastOtpTokenView = null
}
companion object {
private val TAG = TemplateEditView::class.java.name
}

View File

@@ -37,8 +37,8 @@ class EntryViewModel: ViewModel() {
val entryHistory : LiveData<List<EntryInfo>> get() = _entryHistory
private val _entryHistory = MutableLiveData<List<EntryInfo>>()
val onOtpElementUpdated : LiveData<OtpElement> get() = _onOtpElementUpdated
private val _onOtpElementUpdated = SingleLiveEvent<OtpElement>()
val onOtpElementUpdated : LiveData<OtpElement?> get() = _onOtpElementUpdated
private val _onOtpElementUpdated = SingleLiveEvent<OtpElement?>()
val attachmentSelected : LiveData<Attachment> get() = _attachmentSelected
private val _attachmentSelected = SingleLiveEvent<Attachment>()
@@ -122,7 +122,7 @@ class EntryViewModel: ViewModel() {
return entryIsHistory.value ?: false
}
fun onOtpElementUpdated(optElement: OtpElement) {
fun onOtpElementUpdated(optElement: OtpElement?) {
_onOtpElementUpdated.value = optElement
}