mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
fix: Copy protected field behind UV #2283
This commit is contained in:
@@ -56,10 +56,11 @@ import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper
|
||||
import com.kunzisoft.keepass.activities.legacy.DatabaseLockActivity
|
||||
import com.kunzisoft.keepass.adapters.TagsAdapter
|
||||
import com.kunzisoft.keepass.credentialprovider.SpecialMode
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationActionType
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationData
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationHelper.Companion.checkUserVerification
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationHelper.Companion.isUserVerificationNeeded
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationHelper.Companion.requestUnprotectField
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationHelper.Companion.requestShowUnprotectField
|
||||
import com.kunzisoft.keepass.credentialprovider.magikeyboard.MagikeyboardService
|
||||
import com.kunzisoft.keepass.database.ContextualDatabase
|
||||
import com.kunzisoft.keepass.database.element.Attachment
|
||||
@@ -330,11 +331,26 @@ class EntryActivity : DatabaseLockActivity() {
|
||||
when (entryState) {
|
||||
is EntryViewModel.EntryState.Loading -> {}
|
||||
is EntryViewModel.EntryState.RequestUnprotectField -> {
|
||||
requestUnprotectField(
|
||||
userVerificationViewModel = mUserVerificationViewModel,
|
||||
database = mDatabase,
|
||||
protectedFieldView = entryState.protectedFieldView
|
||||
)
|
||||
mDatabase?.let { database ->
|
||||
requestShowUnprotectField(
|
||||
userVerificationViewModel = mUserVerificationViewModel,
|
||||
database = database,
|
||||
protectedFieldView = entryState.protectedFieldView
|
||||
)
|
||||
}
|
||||
mEntryViewModel.actionPerformed()
|
||||
}
|
||||
is EntryViewModel.EntryState.RequestCopyProtectedField -> {
|
||||
mDatabase?.let { database ->
|
||||
checkUserVerification(
|
||||
userVerificationViewModel = mUserVerificationViewModel,
|
||||
dataToVerify = UserVerificationData(
|
||||
actionType = UserVerificationActionType.COPY_PROTECTED_FIELD,
|
||||
database = database,
|
||||
field = entryState.field,
|
||||
)
|
||||
)
|
||||
}
|
||||
mEntryViewModel.actionPerformed()
|
||||
}
|
||||
}
|
||||
@@ -351,10 +367,24 @@ class EntryActivity : DatabaseLockActivity() {
|
||||
mUserVerificationViewModel.onUserVerificationReceived()
|
||||
}
|
||||
is UserVerificationViewModel.UIState.OnUserVerificationSucceeded -> {
|
||||
// Edit Entry if corresponding data
|
||||
editEntry(uVState.dataToVerify.database, uVState.dataToVerify.entryId)
|
||||
// Unprotect field if corresponding data
|
||||
uVState.dataToVerify.protectedFieldView?.unprotect()
|
||||
val data = uVState.dataToVerify
|
||||
when (data.actionType) {
|
||||
UserVerificationActionType.SHOW_PROTECTED_FIELD -> {
|
||||
// Unprotect field by its view
|
||||
data.protectedFieldView?.unprotect()
|
||||
}
|
||||
UserVerificationActionType.COPY_PROTECTED_FIELD -> {
|
||||
// Copy field value
|
||||
data.field?.let {
|
||||
mEntryViewModel.copyToClipboard(it)
|
||||
}
|
||||
}
|
||||
UserVerificationActionType.EDIT_ENTRY -> {
|
||||
// Edit Entry
|
||||
editEntry(data.database, data.entryId)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
mUserVerificationViewModel.onUserVerificationReceived()
|
||||
}
|
||||
}
|
||||
@@ -531,10 +561,16 @@ class EntryActivity : DatabaseLockActivity() {
|
||||
when (item.itemId) {
|
||||
R.id.menu_edit -> {
|
||||
if (mEntryViewModel.entryInfo?.isUserVerificationNeeded() == true) {
|
||||
checkUserVerification(
|
||||
userVerificationViewModel = mUserVerificationViewModel,
|
||||
dataToVerify = UserVerificationData(mDatabase, mEntryViewModel.mainEntryId)
|
||||
)
|
||||
mDatabase?.let { database ->
|
||||
checkUserVerification(
|
||||
userVerificationViewModel = mUserVerificationViewModel,
|
||||
dataToVerify = UserVerificationData(
|
||||
actionType = UserVerificationActionType.EDIT_ENTRY,
|
||||
database = database,
|
||||
entryId = mEntryViewModel.mainEntryId
|
||||
)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
editEntry(mDatabase, mEntryViewModel.mainEntryId)
|
||||
}
|
||||
|
||||
@@ -63,7 +63,8 @@ import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.buildSpecia
|
||||
import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.retrieveRegisterInfo
|
||||
import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.retrieveSearchInfo
|
||||
import com.kunzisoft.keepass.credentialprovider.TypeMode
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationHelper.Companion.requestUnprotectField
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationActionType
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationHelper.Companion.requestShowUnprotectField
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.PasskeyHelper.buildPasskeyResponseAndSetResult
|
||||
import com.kunzisoft.keepass.database.ContextualDatabase
|
||||
import com.kunzisoft.keepass.database.element.Attachment
|
||||
@@ -403,11 +404,13 @@ class EntryEditActivity : DatabaseLockActivity(),
|
||||
mEntryEditViewModel.actionPerformed()
|
||||
}
|
||||
is EntryEditViewModel.EntryEditState.RequestUnprotectField -> {
|
||||
requestUnprotectField(
|
||||
userVerificationViewModel = mUserVerificationViewModel,
|
||||
database = mDatabase,
|
||||
protectedFieldView = uiState.protectedFieldView
|
||||
)
|
||||
mDatabase?.let { database ->
|
||||
requestShowUnprotectField(
|
||||
userVerificationViewModel = mUserVerificationViewModel,
|
||||
database = database,
|
||||
protectedFieldView = uiState.protectedFieldView
|
||||
)
|
||||
}
|
||||
mEntryEditViewModel.actionPerformed()
|
||||
}
|
||||
}
|
||||
@@ -424,7 +427,12 @@ class EntryEditActivity : DatabaseLockActivity(),
|
||||
mUserVerificationViewModel.onUserVerificationReceived()
|
||||
}
|
||||
is UserVerificationViewModel.UIState.OnUserVerificationSucceeded -> {
|
||||
uVState.dataToVerify.protectedFieldView?.unprotect()
|
||||
when (uVState.dataToVerify.actionType) {
|
||||
UserVerificationActionType.SHOW_PROTECTED_FIELD -> {
|
||||
uVState.dataToVerify.protectedFieldView?.unprotect()
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
mUserVerificationViewModel.onUserVerificationReceived()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@ import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.removeModes
|
||||
import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.retrieveSearchInfo
|
||||
import com.kunzisoft.keepass.credentialprovider.SpecialMode
|
||||
import com.kunzisoft.keepass.credentialprovider.TypeMode
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationActionType
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationData
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationHelper.Companion.checkUserVerification
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationHelper.Companion.isUserVerificationNeeded
|
||||
@@ -586,7 +587,15 @@ class GroupActivity : DatabaseLockActivity(),
|
||||
mUserVerificationViewModel.onUserVerificationReceived()
|
||||
}
|
||||
is UserVerificationViewModel.UIState.OnUserVerificationSucceeded -> {
|
||||
editEntry(uVState.dataToVerify.database, uVState.dataToVerify.entryId)
|
||||
val data = uVState.dataToVerify
|
||||
when (data.actionType) {
|
||||
UserVerificationActionType.EDIT_ENTRY -> {
|
||||
editEntry(uVState.dataToVerify.database, uVState.dataToVerify.entryId)
|
||||
}
|
||||
UserVerificationActionType.MERGE_FROM_DATABASE -> {}
|
||||
UserVerificationActionType.SAVE_TO_DATABASE -> {}
|
||||
else -> {}
|
||||
}
|
||||
mUserVerificationViewModel.onUserVerificationReceived()
|
||||
}
|
||||
}
|
||||
@@ -1101,7 +1110,11 @@ class GroupActivity : DatabaseLockActivity(),
|
||||
if ((node as Entry).getEntryInfo(database).isUserVerificationNeeded()) {
|
||||
checkUserVerification(
|
||||
userVerificationViewModel = mUserVerificationViewModel,
|
||||
dataToVerify = UserVerificationData(database, node.nodeId)
|
||||
dataToVerify = UserVerificationData(
|
||||
actionType = UserVerificationActionType.EDIT_ENTRY,
|
||||
database = database,
|
||||
entryId = node.nodeId
|
||||
)
|
||||
)
|
||||
} else {
|
||||
editEntry(database, node.nodeId)
|
||||
|
||||
@@ -16,13 +16,10 @@ import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.adapters.EntryAttachmentsItemsAdapter
|
||||
import com.kunzisoft.keepass.database.ContextualDatabase
|
||||
import com.kunzisoft.keepass.database.element.Attachment
|
||||
import com.kunzisoft.keepass.database.element.template.TemplateField
|
||||
import com.kunzisoft.keepass.database.helper.getLocalizedName
|
||||
import com.kunzisoft.keepass.model.EntryAttachmentState
|
||||
import com.kunzisoft.keepass.model.EntryInfo
|
||||
import com.kunzisoft.keepass.model.StreamDirection
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.timeout.ClipboardHelper
|
||||
import com.kunzisoft.keepass.utils.TimeUtil.getDateTimeString
|
||||
import com.kunzisoft.keepass.utils.UUIDUtils.asHexString
|
||||
import com.kunzisoft.keepass.view.TemplateView
|
||||
@@ -50,8 +47,6 @@ class EntryFragment: DatabaseFragment() {
|
||||
private lateinit var uuidContainerView: View
|
||||
private lateinit var uuidReferenceView: TextView
|
||||
|
||||
private var mClipboardHelper: ClipboardHelper? = null
|
||||
|
||||
private val mEntryViewModel: EntryViewModel by activityViewModels()
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater,
|
||||
@@ -66,10 +61,6 @@ class EntryFragment: DatabaseFragment() {
|
||||
savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
context?.let { context ->
|
||||
mClipboardHelper = ClipboardHelper(context)
|
||||
}
|
||||
|
||||
rootView = view
|
||||
// Hide only the first time
|
||||
if (savedInstanceState == null) {
|
||||
@@ -152,18 +143,14 @@ class EntryFragment: DatabaseFragment() {
|
||||
private fun assignEntryInfo(entryInfo: EntryInfo?) {
|
||||
// Set copy buttons
|
||||
templateView.apply {
|
||||
setOnUnprotectClickListener { _, textEditFieldView ->
|
||||
mEntryViewModel.requestUnprotectField(textEditFieldView)
|
||||
setOnUnprotectClickListener { protectedFieldView ->
|
||||
mEntryViewModel.requestUnprotectField(protectedFieldView)
|
||||
}
|
||||
setOnAskCopySafeClickListener {
|
||||
showClipboardDialog()
|
||||
}
|
||||
setOnCopyActionClickListener { field ->
|
||||
mClipboardHelper?.timeoutCopyToClipboard(
|
||||
TemplateField.getLocalizedName(context, field.name),
|
||||
field.protectedValue.stringValue,
|
||||
field.protectedValue.isProtected
|
||||
)
|
||||
setOnCopyActionClickListener { field, protectedFieldView ->
|
||||
mEntryViewModel.requestCopyField(field, protectedFieldView)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,7 +238,7 @@ class EntryFragment: DatabaseFragment() {
|
||||
|
||||
fun launchEntryCopyEducationAction() {
|
||||
val appNameString = getString(R.string.app_name)
|
||||
mClipboardHelper?.timeoutCopyToClipboard(appNameString, appNameString)
|
||||
mEntryViewModel.copyToClipboard(appNameString)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -1,12 +1,25 @@
|
||||
package com.kunzisoft.keepass.credentialprovider
|
||||
|
||||
import com.kunzisoft.keepass.database.ContextualDatabase
|
||||
import com.kunzisoft.keepass.database.element.Field
|
||||
import com.kunzisoft.keepass.database.element.node.NodeId
|
||||
import com.kunzisoft.keepass.view.ProtectedFieldView
|
||||
|
||||
data class UserVerificationData(
|
||||
val actionType: UserVerificationActionType,
|
||||
val database: ContextualDatabase? = null,
|
||||
val entryId: NodeId<*>? = null,
|
||||
val field: Field? = null,
|
||||
val protectedFieldView: ProtectedFieldView? = null,
|
||||
val preferenceKey: String? = null
|
||||
)
|
||||
)
|
||||
|
||||
enum class UserVerificationActionType {
|
||||
LAUNCH_PASSKEY_CEREMONY,
|
||||
SHOW_PROTECTED_FIELD,
|
||||
COPY_PROTECTED_FIELD,
|
||||
EDIT_ENTRY,
|
||||
EDIT_DATABASE_SETTING,
|
||||
MERGE_FROM_DATABASE,
|
||||
SAVE_TO_DATABASE
|
||||
}
|
||||
@@ -104,15 +104,16 @@ class UserVerificationHelper {
|
||||
activity?.checkUserVerification(userVerificationViewModel, dataToVerify)
|
||||
}
|
||||
|
||||
fun FragmentActivity.requestUnprotectField(
|
||||
fun FragmentActivity.requestShowUnprotectField(
|
||||
userVerificationViewModel: UserVerificationViewModel,
|
||||
database: ContextualDatabase?,
|
||||
database: ContextualDatabase,
|
||||
protectedFieldView: ProtectedFieldView
|
||||
) {
|
||||
if (protectedFieldView.isCurrentlyProtected()) {
|
||||
checkUserVerification(
|
||||
userVerificationViewModel = userVerificationViewModel,
|
||||
dataToVerify = UserVerificationData(
|
||||
actionType = UserVerificationActionType.SHOW_PROTECTED_FIELD,
|
||||
database = database,
|
||||
protectedFieldView = protectedFieldView
|
||||
)
|
||||
|
||||
@@ -45,6 +45,7 @@ import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.addTypeMode
|
||||
import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.setActivityResult
|
||||
import com.kunzisoft.keepass.credentialprovider.SpecialMode
|
||||
import com.kunzisoft.keepass.credentialprovider.TypeMode
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationActionType
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationData
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationHelper.Companion.addUserVerification
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationHelper.Companion.checkUserVerification
|
||||
@@ -179,12 +180,18 @@ class PasskeyLauncherActivity : DatabaseLockActivity() {
|
||||
when (uiState) {
|
||||
is UserVerificationViewModel.UIState.Loading -> {}
|
||||
is UserVerificationViewModel.UIState.OnUserVerificationSucceeded -> {
|
||||
passkeyLauncherViewModel.launchActionIfNeeded(
|
||||
userVerified = true,
|
||||
intent = intent,
|
||||
specialMode = mSpecialMode,
|
||||
database = uiState.dataToVerify.database
|
||||
)
|
||||
val data = uiState.dataToVerify
|
||||
when (data.actionType) {
|
||||
UserVerificationActionType.LAUNCH_PASSKEY_CEREMONY -> {
|
||||
passkeyLauncherViewModel.launchActionIfNeeded(
|
||||
userVerified = true,
|
||||
intent = intent,
|
||||
specialMode = mSpecialMode,
|
||||
database = uiState.dataToVerify.database
|
||||
)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
userVerificationViewModel.onUserVerificationReceived()
|
||||
}
|
||||
is UserVerificationViewModel.UIState.OnUserVerificationCanceled -> {
|
||||
@@ -207,7 +214,10 @@ class PasskeyLauncherActivity : DatabaseLockActivity() {
|
||||
if (userVerificationNeeded) {
|
||||
checkUserVerification(
|
||||
userVerificationViewModel = userVerificationViewModel,
|
||||
dataToVerify = UserVerificationData(database)
|
||||
dataToVerify = UserVerificationData(
|
||||
actionType = UserVerificationActionType.LAUNCH_PASSKEY_CEREMONY,
|
||||
database = database
|
||||
)
|
||||
)
|
||||
} else {
|
||||
passkeyLauncherViewModel.launchActionIfNeeded(
|
||||
|
||||
@@ -42,6 +42,7 @@ import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.dialogs.SetMainCredentialDialogFragment
|
||||
import com.kunzisoft.keepass.activities.legacy.DatabaseRetrieval
|
||||
import com.kunzisoft.keepass.activities.legacy.resetAppTimeoutWhenViewTouchedOrFocused
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationActionType
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationData
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationHelper.Companion.checkUserVerification
|
||||
import com.kunzisoft.keepass.database.ContextualDatabase
|
||||
@@ -188,28 +189,34 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetriev
|
||||
mUserVerificationViewModel.onUserVerificationReceived()
|
||||
}
|
||||
is UserVerificationViewModel.UIState.OnUserVerificationSucceeded -> {
|
||||
state.dataToVerify.database?.let { database ->
|
||||
state.dataToVerify.preferenceKey?.let { preferenceKey ->
|
||||
val data = state.dataToVerify
|
||||
when (data.actionType) {
|
||||
UserVerificationActionType.EDIT_DATABASE_SETTING -> {
|
||||
val database = data.database
|
||||
val preferenceKey = data.preferenceKey
|
||||
if (database != null && preferenceKey != null) {
|
||||
// Main Preferences
|
||||
when (preferenceKey) {
|
||||
// Master Key
|
||||
getString(R.string.settings_database_change_credentials_key) -> {
|
||||
SetMainCredentialDialogFragment
|
||||
.getInstance(database.allowNoMasterKey)
|
||||
.show(parentFragmentManager, "passwordDialog")
|
||||
when (preferenceKey) {
|
||||
// Master Key
|
||||
getString(R.string.settings_database_change_credentials_key) -> {
|
||||
SetMainCredentialDialogFragment
|
||||
.getInstance(database.allowNoMasterKey)
|
||||
.show(parentFragmentManager, "passwordDialog")
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
else -> {}
|
||||
// TODO Settings in compose
|
||||
@Suppress("DEPRECATION")
|
||||
mSettingsViewModel.dialogFragment?.let { dialogFragment ->
|
||||
dialogFragment.setTargetFragment(
|
||||
this@NestedDatabaseSettingsFragment, 0
|
||||
)
|
||||
dialogFragment.show(parentFragmentManager, TAG_PREF_FRAGMENT)
|
||||
}
|
||||
mSettingsViewModel.dialogFragment = null
|
||||
}
|
||||
// TODO Settings in compose
|
||||
@Suppress("DEPRECATION")
|
||||
mSettingsViewModel.dialogFragment?.let { dialogFragment ->
|
||||
dialogFragment.setTargetFragment(
|
||||
this@NestedDatabaseSettingsFragment, 0
|
||||
)
|
||||
dialogFragment.show(parentFragmentManager, TAG_PREF_FRAGMENT)
|
||||
}
|
||||
mSettingsViewModel.dialogFragment = null
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
mUserVerificationViewModel.onUserVerificationReceived()
|
||||
}
|
||||
@@ -483,6 +490,7 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetriev
|
||||
checkUserVerification(
|
||||
mUserVerificationViewModel,
|
||||
UserVerificationData(
|
||||
actionType = UserVerificationActionType.EDIT_DATABASE_SETTING,
|
||||
database = database,
|
||||
preferenceKey = changeCredentialKey
|
||||
)
|
||||
@@ -513,7 +521,7 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetriev
|
||||
// To reassign color listener after orientation change
|
||||
val chromaDialog = parentFragmentManager.findFragmentByTag(TAG_PREF_FRAGMENT) as DatabaseColorPreferenceDialogFragmentCompat?
|
||||
chromaDialog?.onColorSelectedListener = colorSelectedListener
|
||||
} catch (e: Exception) {}
|
||||
} catch (_: Exception) {}
|
||||
|
||||
return view
|
||||
}
|
||||
@@ -785,6 +793,7 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetriev
|
||||
checkUserVerification(
|
||||
mUserVerificationViewModel,
|
||||
UserVerificationData(
|
||||
actionType = UserVerificationActionType.EDIT_DATABASE_SETTING,
|
||||
database = mDatabase,
|
||||
preferenceKey = preference.key
|
||||
)
|
||||
|
||||
@@ -25,8 +25,8 @@ class TemplateView @JvmOverloads constructor(context: Context,
|
||||
: TemplateAbstractView<TextFieldView, TextFieldView, DateTimeFieldView>
|
||||
(context, attrs, defStyle) {
|
||||
|
||||
private var mOnUnprotectClickListener: ((Field, ProtectedFieldView) -> Unit)? = null
|
||||
fun setOnUnprotectClickListener(listener: ((Field, ProtectedFieldView) -> Unit)?) {
|
||||
private var mOnUnprotectClickListener: ((ProtectedFieldView) -> Unit)? = null
|
||||
fun setOnUnprotectClickListener(listener: ((ProtectedFieldView) -> Unit)?) {
|
||||
this.mOnUnprotectClickListener = listener
|
||||
}
|
||||
|
||||
@@ -34,8 +34,8 @@ class TemplateView @JvmOverloads constructor(context: Context,
|
||||
fun setOnAskCopySafeClickListener(listener: (() -> Unit)? = null) {
|
||||
this.mOnAskCopySafeClickListener = listener
|
||||
}
|
||||
private var mOnCopyActionClickListener: ((Field) -> Unit)? = null
|
||||
fun setOnCopyActionClickListener(listener: ((Field) -> Unit)? = null) {
|
||||
private var mOnCopyActionClickListener: ((Field, ProtectedFieldView) -> Unit)? = null
|
||||
fun setOnCopyActionClickListener(listener: ((Field, ProtectedFieldView) -> Unit)? = null) {
|
||||
this.mOnCopyActionClickListener = listener
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ class TemplateView @JvmOverloads constructor(context: Context,
|
||||
else TextFieldView(it)).apply {
|
||||
applyFontVisibility(mFontInVisibility)
|
||||
setProtection(field.protectedValue.isProtected) {
|
||||
mOnUnprotectClickListener?.invoke(field, this)
|
||||
mOnUnprotectClickListener?.invoke(this)
|
||||
}
|
||||
label = templateAttribute.alias
|
||||
?: TemplateField.getLocalizedName(context, field.name)
|
||||
@@ -85,7 +85,15 @@ class TemplateView @JvmOverloads constructor(context: Context,
|
||||
setCopyButtonState(TextFieldView.ButtonState.ACTIVATE)
|
||||
setCopyButtonClickListener { label, value ->
|
||||
mOnCopyActionClickListener
|
||||
?.invoke(Field(label, ProtectedString(true, value)))
|
||||
?.invoke(
|
||||
Field(
|
||||
name = label,
|
||||
value = ProtectedString(
|
||||
enableProtection = true,
|
||||
string = value
|
||||
)
|
||||
), this
|
||||
)
|
||||
}
|
||||
} else {
|
||||
setCopyButtonState(TextFieldView.ButtonState.GONE)
|
||||
@@ -96,7 +104,15 @@ class TemplateView @JvmOverloads constructor(context: Context,
|
||||
setCopyButtonState(TextFieldView.ButtonState.ACTIVATE)
|
||||
setCopyButtonClickListener { label, value ->
|
||||
mOnCopyActionClickListener
|
||||
?.invoke(Field(label, ProtectedString(false, value)))
|
||||
?.invoke(
|
||||
Field(
|
||||
name = label,
|
||||
value = ProtectedString(
|
||||
enableProtection = false,
|
||||
string = value
|
||||
)
|
||||
), this
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -184,9 +200,15 @@ class TemplateView @JvmOverloads constructor(context: Context,
|
||||
value = otpElement.tokenString
|
||||
setCopyButtonState(TextFieldView.ButtonState.ACTIVATE)
|
||||
setCopyButtonClickListener { _, _ ->
|
||||
mOnCopyActionClickListener?.invoke(Field(
|
||||
otpElement.type.name,
|
||||
ProtectedString(false, otpElement.token)))
|
||||
mOnCopyActionClickListener?.invoke(
|
||||
Field(
|
||||
name = otpElement.type.name,
|
||||
value = ProtectedString(
|
||||
enableProtection = false,
|
||||
string = otpElement.token
|
||||
)
|
||||
), this
|
||||
)
|
||||
}
|
||||
textDirection = TEXT_DIRECTION_LTR
|
||||
mLastOtpTokenView = this
|
||||
|
||||
@@ -19,17 +19,22 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.viewmodels
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.kunzisoft.keepass.database.ContextualDatabase
|
||||
import com.kunzisoft.keepass.database.element.Attachment
|
||||
import com.kunzisoft.keepass.database.element.Field
|
||||
import com.kunzisoft.keepass.database.element.node.NodeId
|
||||
import com.kunzisoft.keepass.database.element.node.NodeIdUUID
|
||||
import com.kunzisoft.keepass.database.element.template.Template
|
||||
import com.kunzisoft.keepass.database.element.template.TemplateField
|
||||
import com.kunzisoft.keepass.database.helper.getLocalizedName
|
||||
import com.kunzisoft.keepass.model.EntryAttachmentState
|
||||
import com.kunzisoft.keepass.model.EntryInfo
|
||||
import com.kunzisoft.keepass.otp.OtpElement
|
||||
import com.kunzisoft.keepass.timeout.ClipboardHelper
|
||||
import com.kunzisoft.keepass.utils.IOActionTask
|
||||
import com.kunzisoft.keepass.view.ProtectedFieldView
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@@ -37,7 +42,7 @@ import kotlinx.coroutines.flow.StateFlow
|
||||
import java.util.UUID
|
||||
|
||||
|
||||
class EntryViewModel: ViewModel() {
|
||||
class EntryViewModel(application: Application): AndroidViewModel(application) {
|
||||
|
||||
var mainEntryId: NodeId<UUID>? = null
|
||||
private set
|
||||
@@ -50,6 +55,8 @@ class EntryViewModel: ViewModel() {
|
||||
var entryLoaded = false
|
||||
private set
|
||||
|
||||
private var mClipboardHelper: ClipboardHelper = ClipboardHelper(application)
|
||||
|
||||
val entryInfoHistory : LiveData<EntryInfoHistory?> get() = _entryInfoHistory
|
||||
private val _entryInfoHistory = MutableLiveData<EntryInfoHistory?>()
|
||||
|
||||
@@ -136,6 +143,14 @@ class EntryViewModel: ViewModel() {
|
||||
mEntryState.value = EntryState.RequestUnprotectField(fieldView)
|
||||
}
|
||||
|
||||
fun requestCopyField(field: Field, fieldView: ProtectedFieldView) {
|
||||
// Only request the User Verification if the field is protected and not shown
|
||||
if (field.protectedValue.isProtected && fieldView.isCurrentlyProtected())
|
||||
mEntryState.value = EntryState.RequestCopyProtectedField(field)
|
||||
else
|
||||
copyToClipboard(field)
|
||||
}
|
||||
|
||||
fun onOtpElementUpdated(optElement: OtpElement?) {
|
||||
_onOtpElementUpdated.value = optElement
|
||||
}
|
||||
@@ -156,6 +171,18 @@ class EntryViewModel: ViewModel() {
|
||||
_sectionSelected.value = section
|
||||
}
|
||||
|
||||
fun copyToClipboard(field: Field) {
|
||||
mClipboardHelper.timeoutCopyToClipboard(
|
||||
TemplateField.getLocalizedName(getApplication(), field.name),
|
||||
field.protectedValue.stringValue,
|
||||
field.protectedValue.isProtected
|
||||
)
|
||||
}
|
||||
|
||||
fun copyToClipboard(text: String) {
|
||||
mClipboardHelper.timeoutCopyToClipboard(text, text)
|
||||
}
|
||||
|
||||
fun actionPerformed() {
|
||||
mEntryState.value = EntryState.Loading
|
||||
}
|
||||
@@ -186,6 +213,9 @@ class EntryViewModel: ViewModel() {
|
||||
data class RequestUnprotectField(
|
||||
val protectedFieldView: ProtectedFieldView
|
||||
): EntryState()
|
||||
data class RequestCopyProtectedField(
|
||||
val field: Field
|
||||
): EntryState()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -15,16 +15,17 @@ class UserVerificationViewModel: ViewModel() {
|
||||
private val mUiState = MutableStateFlow<UIState>(UIState.Loading)
|
||||
val userVerificationState: StateFlow<UIState> = mUiState
|
||||
|
||||
var dataToVerify: UserVerificationData = UserVerificationData()
|
||||
var dataToVerify: UserVerificationData? = null
|
||||
|
||||
fun checkMainCredential(checkString: String) {
|
||||
// Check the password part
|
||||
if (dataToVerify.database?.checkKey(getCheckKey(checkString)) == true)
|
||||
onUserVerificationSucceeded(dataToVerify)
|
||||
val data = dataToVerify
|
||||
if (data?.database?.checkKey(getCheckKey(checkString)) == true)
|
||||
onUserVerificationSucceeded(data)
|
||||
else {
|
||||
onUserVerificationFailed(dataToVerify, InvalidCredentialsDatabaseException())
|
||||
}
|
||||
dataToVerify = UserVerificationData()
|
||||
dataToVerify = null
|
||||
}
|
||||
|
||||
fun onUserVerificationSucceeded(dataToVerify: UserVerificationData) {
|
||||
@@ -32,7 +33,7 @@ class UserVerificationViewModel: ViewModel() {
|
||||
}
|
||||
|
||||
fun onUserVerificationFailed(
|
||||
dataToVerify: UserVerificationData = UserVerificationData(),
|
||||
dataToVerify: UserVerificationData? = null,
|
||||
error: Throwable? = null
|
||||
) {
|
||||
this.dataToVerify = dataToVerify
|
||||
@@ -45,9 +46,11 @@ class UserVerificationViewModel: ViewModel() {
|
||||
|
||||
sealed class UIState {
|
||||
object Loading: UIState()
|
||||
data class OnUserVerificationSucceeded(val dataToVerify: UserVerificationData): UIState()
|
||||
data class OnUserVerificationSucceeded(
|
||||
val dataToVerify: UserVerificationData
|
||||
): UIState()
|
||||
data class OnUserVerificationCanceled(
|
||||
val dataToVerify: UserVerificationData,
|
||||
val dataToVerify: UserVerificationData?,
|
||||
val error: Throwable?
|
||||
): UIState()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user