First commit for autofill blocklist

This commit is contained in:
J-Jamet
2020-06-09 18:35:40 +02:00
parent e2a1e3f327
commit 65e4cf83d8
12 changed files with 435 additions and 11 deletions

View File

@@ -307,9 +307,8 @@ class GroupActivity : LockingActivity(),
val searchInfo: SearchInfo? = intent.getParcelableExtra(KEY_SEARCH_INFO) val searchInfo: SearchInfo? = intent.getParcelableExtra(KEY_SEARCH_INFO)
if (searchInfo != null) { if (searchInfo != null) {
intent.action = Intent.ACTION_SEARCH intent.action = Intent.ACTION_SEARCH
val searchQuery = searchInfo.webDomain ?: searchInfo.applicationId
intent.removeExtra(KEY_SEARCH_INFO) intent.removeExtra(KEY_SEARCH_INFO)
intent.putExtra(SearchManager.QUERY, searchQuery) intent.putExtra(SearchManager.QUERY, searchInfo.toString())
return true return true
} }
return false return false

View File

@@ -406,12 +406,9 @@ class Database {
fun createVirtualGroupFromSearch(searchInfo: SearchInfo, fun createVirtualGroupFromSearch(searchInfo: SearchInfo,
max: Int = Integer.MAX_VALUE): Group? { max: Int = Integer.MAX_VALUE): Group? {
val query = (if (searchInfo.webDomain != null) if (searchInfo.isNull())
searchInfo.webDomain return null
else return mSearchHelper?.createVirtualGroupWithSearchResult(this, searchInfo.toString(), SearchParameters().apply {
searchInfo.applicationId)
?: return null
return mSearchHelper?.createVirtualGroupWithSearchResult(this, query, SearchParameters().apply {
searchInTitles = false searchInTitles = false
searchInUserNames = false searchInUserNames = false
searchInPasswords = false searchInPasswords = false

View File

@@ -1,13 +1,17 @@
package com.kunzisoft.keepass.model package com.kunzisoft.keepass.model
import android.content.res.Resources
import android.os.Parcel import android.os.Parcel
import android.os.Parcelable import android.os.Parcelable
import com.kunzisoft.keepass.utils.ObjectNameResource
class SearchInfo : Parcelable { class SearchInfo : ObjectNameResource, Parcelable {
var applicationId: String? = null var applicationId: String? = null
var webDomain: String? = null var webDomain: String? = null
var genericInfo: String? = null
constructor() constructor()
private constructor(parcel: Parcel) { private constructor(parcel: Parcel) {
@@ -15,6 +19,8 @@ class SearchInfo : Parcelable {
applicationId = if (readAppId.isNullOrEmpty()) null else readAppId applicationId = if (readAppId.isNullOrEmpty()) null else readAppId
val readDomain = parcel.readString() val readDomain = parcel.readString()
webDomain = if (readDomain.isNullOrEmpty()) null else readDomain webDomain = if (readDomain.isNullOrEmpty()) null else readDomain
val readGeneric = parcel.readString()
genericInfo = if (readGeneric.isNullOrEmpty()) null else readGeneric
} }
override fun describeContents(): Int { override fun describeContents(): Int {
@@ -24,6 +30,39 @@ class SearchInfo : Parcelable {
override fun writeToParcel(parcel: Parcel, flags: Int) { override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(applicationId ?: "") parcel.writeString(applicationId ?: "")
parcel.writeString(webDomain ?: "") parcel.writeString(webDomain ?: "")
parcel.writeString(genericInfo ?: "")
}
override fun getName(resources: Resources): String {
return applicationId ?: webDomain ?: genericInfo ?: ""
}
fun isNull(): Boolean {
return applicationId == null && webDomain == null && genericInfo == null
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as SearchInfo
if (applicationId != other.applicationId) return false
if (webDomain != other.webDomain) return false
if (genericInfo != other.genericInfo) return false
return true
}
override fun hashCode(): Int {
var result = applicationId?.hashCode() ?: 0
result = 31 * result + (webDomain?.hashCode() ?: 0)
result = 31 * result + (genericInfo?.hashCode() ?: 0)
return result
}
override fun toString(): String {
return applicationId ?: webDomain ?: genericInfo ?: ""
} }
companion object { companion object {

View File

@@ -20,9 +20,11 @@
package com.kunzisoft.keepass.settings package com.kunzisoft.keepass.settings
import android.os.Bundle import android.os.Bundle
import androidx.fragment.app.DialogFragment
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.settings.preferencedialogfragment.AutofillBlacklistPreferenceDialogFragmentCompat
class AutofillSettingsFragment : PreferenceFragmentCompat() { class AutofillSettingsFragment : PreferenceFragmentCompat() {
@@ -30,4 +32,31 @@ class AutofillSettingsFragment : PreferenceFragmentCompat() {
// Load the preferences from an XML resource // Load the preferences from an XML resource
setPreferencesFromResource(R.xml.preferences_autofill, rootKey) setPreferencesFromResource(R.xml.preferences_autofill, rootKey)
} }
override fun onDisplayPreferenceDialog(preference: Preference?) {
var otherDialogFragment = false
var dialogFragment: DialogFragment? = null
when (preference?.key) {
getString(R.string.autofill_blocklist_key) -> {
dialogFragment = AutofillBlacklistPreferenceDialogFragmentCompat.newInstance(preference.key)
}
else -> otherDialogFragment = true
}
if (dialogFragment != null) {
dialogFragment.setTargetFragment(this, 0)
dialogFragment.show(parentFragmentManager, TAG_AUTOFILL_PREF_FRAGMENT)
}
// Could not be handled here. Try with the super method.
else if (otherDialogFragment) {
super.onDisplayPreferenceDialog(preference)
}
}
companion object {
private const val TAG_AUTOFILL_PREF_FRAGMENT = "TAG_AUTOFILL_PREF_FRAGMENT"
}
} }

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2019 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePassDX.
*
* KeePassDX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePassDX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.settings.preference
import android.content.Context
import android.util.AttributeSet
import androidx.preference.DialogPreference
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.icons.IconPackChooser
import java.util.ArrayList
open class InputListPreference @JvmOverloads constructor(context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = R.attr.dialogPreferenceStyle,
defStyleRes: Int = defStyleAttr)
: DialogPreference(context, attrs, defStyleAttr, defStyleRes) {
override fun getDialogLayoutResource(): Int {
return R.layout.pref_dialog_input_list
}
}

View File

@@ -0,0 +1,94 @@
/*
* Copyright 2020 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePassDX.
*
* KeePassDX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePassDX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.settings.preferencedialogfragment
import android.os.Bundle
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.model.SearchInfo
import com.kunzisoft.keepass.settings.preferencedialogfragment.adapter.AutofillBlacklistAdapter
class AutofillBlacklistPreferenceDialogFragmentCompat
: InputPreferenceDialogFragmentCompat(),
AutofillBlacklistAdapter.ItemDeletedCallback<SearchInfo> {
private var persistedItems = HashSet<SearchInfo>()
private var filterAdapter: AutofillBlacklistAdapter<SearchInfo>? = null
override fun onBindDialogView(view: View) {
super.onBindDialogView(view)
// TODO persistedItems.add
val addItemButton = view.findViewById<View>(R.id.add_item_button)
addItemButton?.setOnClickListener {
persistedItems.add(SearchInfo().apply {
genericInfo = inputText
})
filterAdapter?.replaceItems(persistedItems.toList())
}
val recyclerView = view.findViewById<RecyclerView>(R.id.pref_dialog_list)
recyclerView.layoutManager = LinearLayoutManager(context)
activity?.let { activity ->
filterAdapter = AutofillBlacklistAdapter(activity)
filterAdapter?.setItemDeletedCallback(this)
recyclerView.adapter = filterAdapter
filterAdapter?.replaceItems(persistedItems.toList())
}
}
override fun onItemDeleted(item: SearchInfo) {
persistedItems.remove(item)
filterAdapter?.replaceItems(persistedItems.toList())
}
private fun getStringItems(): Set<String> {
val setItems = HashSet<String>()
persistedItems.forEach {
it.getName(resources).let { item ->
setItems.add(item)
}
}
return setItems
}
override fun onDialogClosed(positiveResult: Boolean) {
if (positiveResult) {
preference.persistStringSet(getStringItems())
}
}
companion object {
fun newInstance(key: String): AutofillBlacklistPreferenceDialogFragmentCompat {
val fragment = AutofillBlacklistPreferenceDialogFragmentCompat()
val bundle = Bundle(1)
bundle.putString(ARG_KEY, key)
fragment.arguments = bundle
return fragment
}
}
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright 2020 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePassDX.
*
* KeePassDX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePassDX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.settings.preferencedialogfragment.adapter
import android.content.Context
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.utils.ObjectNameResource
import java.util.ArrayList
class AutofillBlacklistAdapter<T : ObjectNameResource>(private val context: Context)
: RecyclerView.Adapter<AutofillBlacklistAdapter.BlacklistItemViewHolder>() {
private val inflater: LayoutInflater = LayoutInflater.from(context)
val items: MutableList<T> = ArrayList()
private var itemDeletedCallback: ItemDeletedCallback<T>? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BlacklistItemViewHolder {
val view = inflater.inflate(R.layout.pref_dialog_list_removable_item, parent, false)
return BlacklistItemViewHolder(view)
}
override fun onBindViewHolder(holder: BlacklistItemViewHolder, position: Int) {
val item = this.items[position]
holder.textItem.text = item.getName(context.resources)
holder.deleteButton.setOnClickListener(OnItemDeleteClickListener(item))
}
override fun getItemCount(): Int {
return items.size
}
fun replaceItems(items: List<T>) {
this.items.clear()
this.items.addAll(items)
notifyDataSetChanged()
}
private inner class OnItemDeleteClickListener(private val itemClicked: T) : View.OnClickListener {
override fun onClick(view: View) {
itemDeletedCallback?.onItemDeleted(itemClicked)
notifyDataSetChanged()
}
}
fun setItemDeletedCallback(itemDeletedCallback: ItemDeletedCallback<T>) {
this.itemDeletedCallback = itemDeletedCallback
}
interface ItemDeletedCallback<T> {
fun onItemDeleted(item: T)
}
class BlacklistItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var textItem: TextView = itemView.findViewById(R.id.pref_dialog_list_text)
var deleteButton: ImageView = itemView.findViewById(R.id.pref_dialog_list_delete_button)
}
}

View File

@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2020 Jeremy Jamet / Kunzisoft.
This file is part of KeePassDX.
KeePassDX is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
KeePassDX is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
-->
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/edit"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:importantForAutofill="noExcludeDescendants"
tools:targetApi="o">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/explanation_text"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:gravity="center"
android:layout_marginBottom="8dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
style="@style/KeepassDXStyle.TextAppearance.SmallTitle"/>
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/switch_element"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:text="@string/enable"
android:background="@drawable/background_button_small"
android:textColor="?attr/textColorInverse"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:minHeight="48dp"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/add_item_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/switch_element"
android:orientation="horizontal">
<EditText
android:id="@+id/input_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@+id/add_item_button"
app:layout_constraintBottom_toBottomOf="@id/add_item_button"
android:inputType="textUri"
android:hint="New item"/>
<ImageButton
android:id="@+id/add_item_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:contentDescription="@string/content_description_add_item"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:src="@drawable/ic_add_white_24dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/pref_dialog_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:layout_constraintTop_toBottomOf="@id/add_item_container"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2019 Jeremy Jamet / Kunzisoft.
This file is part of KeePassDX.
KeePassDX is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
KeePassDX is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
-->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/pref_dialog_list_container"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/pref_dialog_list_text"
android:layout_width="0dp"
android:layout_height="0dp"
android:gravity="center_vertical"
app:layout_constraintTop_toTopOf="@+id/pref_dialog_list_delete_button"
app:layout_constraintBottom_toBottomOf="@+id/pref_dialog_list_delete_button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@+id/pref_dialog_list_delete_button"/>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/pref_dialog_list_delete_button"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:src="@drawable/ic_content_delete_white_24dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -132,6 +132,7 @@
<bool name="keyboard_key_sound_default" translatable="false">false</bool> <bool name="keyboard_key_sound_default" translatable="false">false</bool>
<string name="autofill_auto_search_key" translatable="false">autofill_auto_search_key</string> <string name="autofill_auto_search_key" translatable="false">autofill_auto_search_key</string>
<bool name="autofill_auto_search_default" translatable="false">true</bool> <bool name="autofill_auto_search_default" translatable="false">true</bool>
<string name="autofill_blocklist_key" translatable="false">autofill_blocklist_key</string>
<!-- Advanced Unlock Settings --> <!-- Advanced Unlock Settings -->
<string name="settings_advanced_unlock_key" translatable="false">settings_advanced_unlock_key</string> <string name="settings_advanced_unlock_key" translatable="false">settings_advanced_unlock_key</string>

View File

@@ -52,6 +52,7 @@
<string name="content_description_add_node">Add node</string> <string name="content_description_add_node">Add node</string>
<string name="content_description_add_entry">Add entry</string> <string name="content_description_add_entry">Add entry</string>
<string name="content_description_add_group">Add group</string> <string name="content_description_add_group">Add group</string>
<string name="content_description_add_item">Add item</string>
<string name="content_description_file_information">File information</string> <string name="content_description_file_information">File information</string>
<string name="content_description_password_checkbox">Password checkbox</string> <string name="content_description_password_checkbox">Password checkbox</string>
<string name="content_description_keyfile_checkbox">Keyfile checkbox</string> <string name="content_description_keyfile_checkbox">Keyfile checkbox</string>
@@ -230,6 +231,7 @@
<string name="do_not_kill_app">Do not kill the app…</string> <string name="do_not_kill_app">Do not kill the app…</string>
<string name="space">Space</string> <string name="space">Space</string>
<string name="search_label">Search</string> <string name="search_label">Search</string>
<string name="filter">Filter</string>
<string name="sort_menu">Sort</string> <string name="sort_menu">Sort</string>
<string name="sort_ascending">Lowest first ↓</string> <string name="sort_ascending">Lowest first ↓</string>
<string name="sort_groups_before">Groups before</string> <string name="sort_groups_before">Groups before</string>
@@ -379,6 +381,7 @@
<string name="keyboard_key_sound_title">Audible keypresses</string> <string name="keyboard_key_sound_title">Audible keypresses</string>
<string name="autofill_auto_search_title">Auto search</string> <string name="autofill_auto_search_title">Auto search</string>
<string name="autofill_auto_search_summary">Automatically suggest search results from the web domain or application Id</string> <string name="autofill_auto_search_summary">Automatically suggest search results from the web domain or application Id</string>
<string name="autofill_blocklist_title">Blacklist</string>
<string name="allow_no_password_title">Allow no master key</string> <string name="allow_no_password_title">Allow no master key</string>
<string name="allow_no_password_summary">Enable the \"Open\" button if no credentials are selected</string> <string name="allow_no_password_summary">Enable the \"Open\" button if no credentials are selected</string>
<string name="delete_entered_password_title">Delete password</string> <string name="delete_entered_password_title">Delete password</string>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- <!--
Copyright 2018 Jeremy Jamet / Kunzisoft. Copyright 2020 Jeremy Jamet / Kunzisoft.
This file is part of KeePassDX. This file is part of KeePassDX.
@@ -26,4 +26,10 @@
android:summary="@string/autofill_auto_search_summary" android:summary="@string/autofill_auto_search_summary"
android:defaultValue="@bool/autofill_auto_search_default"/> android:defaultValue="@bool/autofill_auto_search_default"/>
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory
android:title="@string/filter">
<com.kunzisoft.keepass.settings.preference.InputListPreference
android:key="@string/autofill_blocklist_key"
android:title="@string/autofill_blocklist_title"/>
</PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>