mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Register username and password in entry
This commit is contained in:
@@ -36,6 +36,7 @@ import com.kunzisoft.keepass.autofill.AutofillHelper
|
||||
import com.kunzisoft.keepass.autofill.KeeAutofillService
|
||||
import com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.database.search.SearchHelper
|
||||
import com.kunzisoft.keepass.model.RegisterInfo
|
||||
import com.kunzisoft.keepass.model.SearchInfo
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
|
||||
@@ -44,12 +45,6 @@ class AutofillLauncherActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
||||
// Build search param
|
||||
val searchInfo = SearchInfo().apply {
|
||||
applicationId = intent.getStringExtra(KEY_SEARCH_APPLICATION_ID)
|
||||
webDomain = intent.getStringExtra(KEY_SEARCH_DOMAIN)
|
||||
}
|
||||
|
||||
// Retrieve selection mode
|
||||
EntrySelectionHelper.retrieveSpecialModeFromIntent(intent).let { specialMode ->
|
||||
when (specialMode) {
|
||||
@@ -59,6 +54,11 @@ class AutofillLauncherActivity : AppCompatActivity() {
|
||||
finish()
|
||||
}
|
||||
SpecialMode.SELECTION -> {
|
||||
// Build search param
|
||||
val searchInfo = SearchInfo().apply {
|
||||
applicationId = intent.getStringExtra(KEY_SEARCH_APPLICATION_ID)
|
||||
webDomain = intent.getStringExtra(KEY_SEARCH_DOMAIN)
|
||||
}
|
||||
// Pass extra for Autofill (EXTRA_ASSIST_STRUCTURE)
|
||||
val assistStructure = AutofillHelper.retrieveAssistStructure(intent)
|
||||
|
||||
@@ -100,6 +100,9 @@ class AutofillLauncherActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
SpecialMode.REGISTRATION -> {
|
||||
// To register info
|
||||
val registerInfo = intent.getParcelableExtra<RegisterInfo>(KEY_REGISTER_INFO)
|
||||
val searchInfo = SearchInfo(registerInfo?.searchInfo)
|
||||
if (!KeeAutofillService.autofillAllowedFor(searchInfo.applicationId,
|
||||
PreferencesUtil.applicationIdBlocklist(this))
|
||||
|| !KeeAutofillService.autofillAllowedFor(searchInfo.webDomain,
|
||||
@@ -114,17 +117,17 @@ class AutofillLauncherActivity : AppCompatActivity() {
|
||||
{ _ ->
|
||||
// Show the database UI to select the entry
|
||||
GroupActivity.launchForRegistration(this,
|
||||
searchInfo)
|
||||
registerInfo)
|
||||
},
|
||||
{
|
||||
// Show the database UI to select the entry
|
||||
GroupActivity.launchForRegistration(this,
|
||||
searchInfo)
|
||||
registerInfo)
|
||||
},
|
||||
{
|
||||
// If database not open
|
||||
FileDatabaseSelectActivity.launchForRegistration(this,
|
||||
searchInfo)
|
||||
registerInfo)
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -146,6 +149,8 @@ class AutofillLauncherActivity : AppCompatActivity() {
|
||||
private const val KEY_SEARCH_APPLICATION_ID = "KEY_SEARCH_APPLICATION_ID"
|
||||
private const val KEY_SEARCH_DOMAIN = "KEY_SEARCH_DOMAIN"
|
||||
|
||||
private const val KEY_REGISTER_INFO = "KEY_REGISTER_INFO"
|
||||
|
||||
fun getAuthIntentSenderForResponse(context: Context,
|
||||
searchInfo: SearchInfo? = null): IntentSender {
|
||||
return PendingIntent.getActivity(context, 0,
|
||||
@@ -160,13 +165,10 @@ class AutofillLauncherActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
fun launchForRegistration(context: Context,
|
||||
searchInfo: SearchInfo? = null) {
|
||||
registerInfo: RegisterInfo) {
|
||||
val intent = Intent(context, AutofillLauncherActivity::class.java)
|
||||
EntrySelectionHelper.addSpecialModeInIntent(intent, SpecialMode.REGISTRATION)
|
||||
searchInfo?.let {
|
||||
intent.putExtra(KEY_SEARCH_APPLICATION_ID, it.applicationId)
|
||||
intent.putExtra(KEY_SEARCH_DOMAIN, it.webDomain)
|
||||
}
|
||||
intent.putExtra(KEY_REGISTER_INFO, registerInfo)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
@@ -45,7 +45,6 @@ import com.kunzisoft.keepass.activities.dialogs.*
|
||||
import com.kunzisoft.keepass.activities.dialogs.FileTooBigDialogFragment.Companion.MAX_WARNING_BINARY_FILE
|
||||
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
|
||||
import com.kunzisoft.keepass.activities.helpers.SelectFileHelper
|
||||
import com.kunzisoft.keepass.activities.helpers.SpecialMode
|
||||
import com.kunzisoft.keepass.activities.lock.LockingActivity
|
||||
import com.kunzisoft.keepass.database.element.*
|
||||
import com.kunzisoft.keepass.database.element.icon.IconImage
|
||||
@@ -176,17 +175,24 @@ class EntryEditActivity : LockingActivity(),
|
||||
}
|
||||
|
||||
// Retrieve data from registration
|
||||
tempEntryInfo?.customFields
|
||||
val searchInfo = EntrySelectionHelper.retrieveSearchInfoFromIntent(intent)
|
||||
searchInfo?.webDomain?.let { webDomain ->
|
||||
tempEntryInfo?.addUniqueField(Field(EntryInfo.WEB_DOMAIN_FIELD_NAME,
|
||||
ProtectedString(false, webDomain))
|
||||
)
|
||||
} ?: run {
|
||||
searchInfo?.applicationId?.let { applicationId ->
|
||||
tempEntryInfo?.addUniqueField(Field(EntryInfo.APPLICATION_ID_FIELD_NAME,
|
||||
ProtectedString(false, applicationId))
|
||||
val registerInfo = EntrySelectionHelper.retrieveRegisterInfoFromIntent(intent)
|
||||
registerInfo?.username?.let {
|
||||
tempEntryInfo?.username = it
|
||||
}
|
||||
registerInfo?.password?.let {
|
||||
tempEntryInfo?.password = it
|
||||
}
|
||||
registerInfo?.searchInfo?.let { searchInfo ->
|
||||
searchInfo.webDomain?.let { webDomain ->
|
||||
tempEntryInfo?.addUniqueField(Field(EntryInfo.WEB_DOMAIN_FIELD_NAME,
|
||||
ProtectedString(false, webDomain))
|
||||
)
|
||||
} ?: run {
|
||||
searchInfo.applicationId?.let { applicationId ->
|
||||
tempEntryInfo?.addUniqueField(Field(EntryInfo.APPLICATION_ID_FIELD_NAME,
|
||||
ProtectedString(false, applicationId))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -774,14 +780,13 @@ class EntryEditActivity : LockingActivity(),
|
||||
*/
|
||||
fun launchForRegistration(context: Context,
|
||||
entry: Entry,
|
||||
searchInfo: SearchInfo? = null) {
|
||||
registerInfo: RegisterInfo? = null) {
|
||||
if (TimeoutHelper.checkTimeAndLockIfTimeout(context)) {
|
||||
val intent = Intent(context, EntryEditActivity::class.java)
|
||||
intent.putExtra(KEY_ENTRY, entry.nodeId)
|
||||
EntrySelectionHelper.startActivityForSpecialModeResult(context,
|
||||
EntrySelectionHelper.startActivityForRegistrationModeResult(context,
|
||||
intent,
|
||||
SpecialMode.REGISTRATION,
|
||||
searchInfo)
|
||||
registerInfo)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -790,14 +795,13 @@ class EntryEditActivity : LockingActivity(),
|
||||
*/
|
||||
fun launchForRegistration(context: Context,
|
||||
group: Group,
|
||||
searchInfo: SearchInfo? = null) {
|
||||
registerInfo: RegisterInfo? = null) {
|
||||
if (TimeoutHelper.checkTimeAndLockIfTimeout(context)) {
|
||||
val intent = Intent(context, EntryEditActivity::class.java)
|
||||
intent.putExtra(KEY_PARENT, group.nodeId)
|
||||
EntrySelectionHelper.startActivityForSpecialModeResult(context,
|
||||
EntrySelectionHelper.startActivityForRegistrationModeResult(context,
|
||||
intent,
|
||||
SpecialMode.REGISTRATION,
|
||||
searchInfo)
|
||||
registerInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ import com.kunzisoft.keepass.autofill.AutofillHelper
|
||||
import com.kunzisoft.keepass.database.action.ProgressDatabaseTaskProvider
|
||||
import com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.education.FileDatabaseSelectActivityEducation
|
||||
import com.kunzisoft.keepass.model.RegisterInfo
|
||||
import com.kunzisoft.keepass.model.SearchInfo
|
||||
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_CREATE_TASK
|
||||
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.DATABASE_URI_KEY
|
||||
@@ -503,9 +504,8 @@ class FileDatabaseSelectActivity : SpecialModeActivity(),
|
||||
|
||||
fun launchForEntrySelectionResult(activity: Activity,
|
||||
searchInfo: SearchInfo? = null) {
|
||||
EntrySelectionHelper.startActivityForSpecialModeResult(activity,
|
||||
EntrySelectionHelper.startActivityForSelectionModeResult(activity,
|
||||
Intent(activity, FileDatabaseSelectActivity::class.java),
|
||||
SpecialMode.SELECTION,
|
||||
searchInfo)
|
||||
}
|
||||
|
||||
@@ -531,11 +531,10 @@ class FileDatabaseSelectActivity : SpecialModeActivity(),
|
||||
* -------------------------
|
||||
*/
|
||||
fun launchForRegistration(context: Context,
|
||||
searchInfo: SearchInfo? = null) {
|
||||
EntrySelectionHelper.startActivityForSpecialModeResult(context,
|
||||
registerInfo: RegisterInfo? = null) {
|
||||
EntrySelectionHelper.startActivityForRegistrationModeResult(context,
|
||||
Intent(context, FileDatabaseSelectActivity::class.java),
|
||||
SpecialMode.REGISTRATION,
|
||||
searchInfo)
|
||||
registerInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,7 @@ import com.kunzisoft.keepass.database.element.node.NodeId
|
||||
import com.kunzisoft.keepass.database.element.node.Type
|
||||
import com.kunzisoft.keepass.education.GroupActivityEducation
|
||||
import com.kunzisoft.keepass.icons.assignDatabaseIcon
|
||||
import com.kunzisoft.keepass.model.RegisterInfo
|
||||
import com.kunzisoft.keepass.model.SearchInfo
|
||||
import com.kunzisoft.keepass.model.getSearchString
|
||||
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_COPY_NODES_TASK
|
||||
@@ -1050,7 +1051,7 @@ class GroupActivity : LockingActivity(),
|
||||
// Else in root, lock if needed
|
||||
else {
|
||||
intent.removeExtra(AUTO_SEARCH_KEY)
|
||||
EntrySelectionHelper.removeSearchInfoFromIntent(intent)
|
||||
EntrySelectionHelper.removeInfoFromIntent(intent)
|
||||
if (PreferencesUtil.isLockDatabaseWhenBackButtonOnRootClicked(this)) {
|
||||
lockAndExit()
|
||||
super.onBackPressed()
|
||||
@@ -1131,9 +1132,8 @@ class GroupActivity : LockingActivity(),
|
||||
readOnly: Boolean = PreferencesUtil.enableReadOnlyDatabase(context)) {
|
||||
checkTimeAndBuildIntent(context, null, readOnly) { intent ->
|
||||
intent.putExtra(AUTO_SEARCH_KEY, autoSearch)
|
||||
EntrySelectionHelper.startActivityForSpecialModeResult(context,
|
||||
EntrySelectionHelper.startActivityForSelectionModeResult(context,
|
||||
intent,
|
||||
SpecialMode.SELECTION,
|
||||
searchInfo)
|
||||
}
|
||||
}
|
||||
@@ -1164,13 +1164,12 @@ class GroupActivity : LockingActivity(),
|
||||
* -------------------------
|
||||
*/
|
||||
fun launchForRegistration(context: Context,
|
||||
searchInfo: SearchInfo? = null) {
|
||||
registerInfo: RegisterInfo? = null) {
|
||||
checkTimeAndBuildIntent(context, null, false) { intent ->
|
||||
intent.putExtra(AUTO_SEARCH_KEY, false)
|
||||
EntrySelectionHelper.startActivityForSpecialModeResult(context,
|
||||
EntrySelectionHelper.startActivityForRegistrationModeResult(context,
|
||||
intent,
|
||||
SpecialMode.REGISTRATION,
|
||||
searchInfo)
|
||||
registerInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ import com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.database.exception.DuplicateUuidDatabaseException
|
||||
import com.kunzisoft.keepass.database.search.SearchHelper
|
||||
import com.kunzisoft.keepass.education.PasswordActivityEducation
|
||||
import com.kunzisoft.keepass.model.RegisterInfo
|
||||
import com.kunzisoft.keepass.model.SearchInfo
|
||||
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_LOAD_TASK
|
||||
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.CIPHER_ENTITY_KEY
|
||||
@@ -356,19 +357,19 @@ open class PasswordActivity : SpecialModeActivity() {
|
||||
)
|
||||
}
|
||||
},
|
||||
{ searchInfo ->
|
||||
{ registerInfo ->
|
||||
SearchHelper.checkAutoSearchInfo(this,
|
||||
Database.getInstance(),
|
||||
searchInfo,
|
||||
registerInfo?.searchInfo,
|
||||
{ _ ->
|
||||
// No auto search, it's a registration
|
||||
GroupActivity.launchForRegistration(this,
|
||||
searchInfo)
|
||||
registerInfo)
|
||||
},
|
||||
{
|
||||
// Here no search info found, disable auto search
|
||||
GroupActivity.launchForRegistration(this@PasswordActivity,
|
||||
searchInfo)
|
||||
registerInfo)
|
||||
},
|
||||
{
|
||||
// Simply close if database not opened, normally not happened
|
||||
@@ -855,10 +856,9 @@ open class PasswordActivity : SpecialModeActivity() {
|
||||
keyFile: Uri?,
|
||||
searchInfo: SearchInfo?) {
|
||||
buildAndLaunchIntent(activity, databaseFile, keyFile) { intent ->
|
||||
EntrySelectionHelper.startActivityForSpecialModeResult(
|
||||
EntrySelectionHelper.startActivityForSelectionModeResult(
|
||||
activity,
|
||||
intent,
|
||||
SpecialMode.SELECTION,
|
||||
searchInfo)
|
||||
}
|
||||
}
|
||||
@@ -897,13 +897,12 @@ open class PasswordActivity : SpecialModeActivity() {
|
||||
fun launchForRegistration(activity: Activity,
|
||||
databaseFile: Uri,
|
||||
keyFile: Uri?,
|
||||
searchInfo: SearchInfo?) {
|
||||
registerInfo: RegisterInfo?) {
|
||||
buildAndLaunchIntent(activity, databaseFile, keyFile) { intent ->
|
||||
EntrySelectionHelper.startActivityForSpecialModeResult(
|
||||
EntrySelectionHelper.startActivityForRegistrationModeResult(
|
||||
activity,
|
||||
intent,
|
||||
SpecialMode.REGISTRATION,
|
||||
searchInfo)
|
||||
registerInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import com.kunzisoft.keepass.autofill.AutofillHelper
|
||||
import com.kunzisoft.keepass.model.RegisterInfo
|
||||
import com.kunzisoft.keepass.model.SearchInfo
|
||||
import java.io.Serializable
|
||||
|
||||
@@ -32,15 +33,23 @@ object EntrySelectionHelper {
|
||||
private const val KEY_SPECIAL_MODE = "com.kunzisoft.keepass.extra.SPECIAL_MODE"
|
||||
private const val KEY_TYPE_MODE = "com.kunzisoft.keepass.extra.TYPE_MODE"
|
||||
private const val KEY_SEARCH_INFO = "com.kunzisoft.keepass.extra.SEARCH_INFO"
|
||||
private const val KEY_REGISTER_INFO = "com.kunzisoft.keepass.extra.REGISTER_INFO"
|
||||
|
||||
fun startActivityForSpecialModeResult(context: Context,
|
||||
intent: Intent,
|
||||
specialMode: SpecialMode,
|
||||
searchInfo: SearchInfo?) {
|
||||
addSpecialModeInIntent(intent, specialMode)
|
||||
fun startActivityForSelectionModeResult(context: Context,
|
||||
intent: Intent,
|
||||
searchInfo: SearchInfo?) {
|
||||
addSpecialModeInIntent(intent, SpecialMode.SELECTION)
|
||||
addSearchInfoInIntent(intent, searchInfo)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
fun startActivityForRegistrationModeResult(context: Context,
|
||||
intent: Intent,
|
||||
registerInfo: RegisterInfo?) {
|
||||
addSpecialModeInIntent(intent, SpecialMode.REGISTRATION)
|
||||
// At the moment, only autofill for registration
|
||||
addTypeModeInIntent(intent, TypeMode.AUTOFILL)
|
||||
addSearchInfoInIntent(intent, searchInfo)
|
||||
addRegisterInfoInIntent(intent, registerInfo)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
@@ -54,8 +63,19 @@ object EntrySelectionHelper {
|
||||
return intent.getParcelableExtra(KEY_SEARCH_INFO)
|
||||
}
|
||||
|
||||
fun removeSearchInfoFromIntent(intent: Intent) {
|
||||
fun addRegisterInfoInIntent(intent: Intent, registerInfo: RegisterInfo?) {
|
||||
registerInfo?.let {
|
||||
intent.putExtra(KEY_REGISTER_INFO, it)
|
||||
}
|
||||
}
|
||||
|
||||
fun retrieveRegisterInfoFromIntent(intent: Intent): RegisterInfo? {
|
||||
return intent.getParcelableExtra(KEY_REGISTER_INFO)
|
||||
}
|
||||
|
||||
fun removeInfoFromIntent(intent: Intent) {
|
||||
intent.removeExtra(KEY_SEARCH_INFO)
|
||||
intent.removeExtra(KEY_REGISTER_INFO)
|
||||
}
|
||||
|
||||
fun addSpecialModeInIntent(intent: Intent, specialMode: SpecialMode) {
|
||||
@@ -93,14 +113,14 @@ object EntrySelectionHelper {
|
||||
keyboardSelectionAction: (searchInfo: SearchInfo?) -> Unit,
|
||||
autofillSelectionAction: (searchInfo: SearchInfo?,
|
||||
assistStructure: AssistStructure?) -> Unit,
|
||||
registrationAction: (searchInfo: SearchInfo?) -> Unit) {
|
||||
registrationAction: (registerInfo: RegisterInfo?) -> Unit) {
|
||||
|
||||
val searchInfo: SearchInfo? = retrieveSearchInfoFromIntent(intent)
|
||||
when (retrieveSpecialModeFromIntent(intent)) {
|
||||
SpecialMode.DEFAULT -> {
|
||||
defaultAction.invoke(searchInfo)
|
||||
defaultAction.invoke(retrieveSearchInfoFromIntent(intent))
|
||||
}
|
||||
SpecialMode.SELECTION -> {
|
||||
val searchInfo: SearchInfo? = retrieveSearchInfoFromIntent(intent)
|
||||
var assistStructureInit = false
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
AutofillHelper.retrieveAssistStructure(intent)?.let { assistStructure ->
|
||||
@@ -122,7 +142,8 @@ object EntrySelectionHelper {
|
||||
}
|
||||
}
|
||||
SpecialMode.REGISTRATION -> {
|
||||
registrationAction.invoke(searchInfo)
|
||||
val registerInfo: RegisterInfo? = retrieveRegisterInfoFromIntent(intent)
|
||||
registrationAction.invoke(registerInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,8 @@ abstract class SpecialModeActivity : StylishActivity() {
|
||||
|
||||
mSpecialMode = EntrySelectionHelper.retrieveSpecialModeFromIntent(intent)
|
||||
mTypeMode = EntrySelectionHelper.retrieveTypeModeFromIntent(intent)
|
||||
val searchInfo: SearchInfo? = EntrySelectionHelper.retrieveSearchInfoFromIntent(intent)
|
||||
val searchInfo: SearchInfo? = EntrySelectionHelper.retrieveRegisterInfoFromIntent(intent)?.searchInfo
|
||||
?: EntrySelectionHelper.retrieveSearchInfoFromIntent(intent)
|
||||
|
||||
// To show the selection mode
|
||||
mSpecialModeView = findViewById(R.id.special_mode_view)
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.AutofillLauncherActivity
|
||||
import com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.database.search.SearchHelper
|
||||
import com.kunzisoft.keepass.model.RegisterInfo
|
||||
import com.kunzisoft.keepass.model.SearchInfo
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
@@ -65,10 +66,10 @@ class KeeAutofillService : AutofillService() {
|
||||
|
||||
// Build search info only if applicationId or webDomain are not blocked
|
||||
if (autofillAllowedFor(parseResult.applicationId, applicationIdBlocklist)
|
||||
&& autofillAllowedFor(parseResult.domain, webDomainBlocklist)) {
|
||||
&& autofillAllowedFor(parseResult.webDomain, webDomainBlocklist)) {
|
||||
val searchInfo = SearchInfo().apply {
|
||||
applicationId = parseResult.applicationId
|
||||
webDomain = parseResult.domain
|
||||
webDomain = parseResult.webDomain
|
||||
}
|
||||
|
||||
SearchHelper.checkAutoSearchInfo(this,
|
||||
@@ -77,7 +78,7 @@ class KeeAutofillService : AutofillService() {
|
||||
{ items ->
|
||||
val responseBuilder = FillResponse.Builder()
|
||||
AutofillHelper.addHeader(responseBuilder, packageName,
|
||||
parseResult.domain, parseResult.applicationId)
|
||||
parseResult.webDomain, parseResult.applicationId)
|
||||
items.forEach {
|
||||
responseBuilder.addDataset(AutofillHelper.buildDataset(this, it, parseResult))
|
||||
}
|
||||
@@ -107,9 +108,9 @@ class KeeAutofillService : AutofillService() {
|
||||
val sender = AutofillLauncherActivity.getAuthIntentSenderForResponse(this,
|
||||
searchInfo)
|
||||
val responseBuilder = FillResponse.Builder()
|
||||
val remoteViewsUnlock: RemoteViews = if (!parseResult.domain.isNullOrEmpty()) {
|
||||
val remoteViewsUnlock: RemoteViews = if (!parseResult.webDomain.isNullOrEmpty()) {
|
||||
RemoteViews(packageName, R.layout.item_autofill_unlock_web_domain).apply {
|
||||
setTextViewText(R.id.autofill_web_domain_text, parseResult.domain)
|
||||
setTextViewText(R.id.autofill_web_domain_text, parseResult.webDomain)
|
||||
}
|
||||
} else if (!parseResult.applicationId.isNullOrEmpty()) {
|
||||
RemoteViews(packageName, R.layout.item_autofill_unlock_app_id).apply {
|
||||
@@ -145,38 +146,26 @@ class KeeAutofillService : AutofillService() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun showUIForEntryRegistration(parseResult: StructureParser.Result,
|
||||
searchInfo: SearchInfo,
|
||||
callback: SaveCallback) {
|
||||
|
||||
parseResult.passwordValue?.let { autofillPasswordValue ->
|
||||
|
||||
AutofillLauncherActivity.launchForRegistration(this, searchInfo)
|
||||
|
||||
// TODO Treat sender value to call
|
||||
// callback.onSuccess() or
|
||||
// callback.onFailure("Saving form canceled")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSaveRequest(request: SaveRequest, callback: SaveCallback) {
|
||||
val latestStructure = request.fillContexts.last().structure
|
||||
StructureParser(latestStructure).parse()?.let { parseResult ->
|
||||
StructureParser(latestStructure).parse(true)?.let { parseResult ->
|
||||
|
||||
if (autofillAllowedFor(parseResult.applicationId, applicationIdBlocklist)
|
||||
&& autofillAllowedFor(parseResult.domain, webDomainBlocklist)) {
|
||||
&& autofillAllowedFor(parseResult.webDomain, webDomainBlocklist)) {
|
||||
Log.d(TAG, "autofill onSaveRequest password")
|
||||
|
||||
val searchInfo = SearchInfo().apply {
|
||||
applicationId = parseResult.applicationId
|
||||
webDomain = parseResult.domain
|
||||
}
|
||||
|
||||
// TODO Save ${autofillPasswordValue.textValue}
|
||||
// Show UI to save data
|
||||
showUIForEntryRegistration(parseResult,
|
||||
searchInfo,
|
||||
callback)
|
||||
val registerInfo = RegisterInfo(SearchInfo().apply {
|
||||
applicationId = parseResult.applicationId
|
||||
webDomain = parseResult.webDomain
|
||||
},
|
||||
parseResult.usernameValue?.textValue?.toString(),
|
||||
parseResult.passwordValue?.textValue?.toString())
|
||||
AutofillLauncherActivity.launchForRegistration(this, registerInfo)
|
||||
|
||||
// TODO Treat sender value to call
|
||||
// callback.onSuccess() or
|
||||
// callback.onFailure("Saving form canceled")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,15 +35,19 @@ import java.util.*
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
internal class StructureParser(private val structure: AssistStructure) {
|
||||
private var result: Result? = null
|
||||
private var usernameCandidate: AutofillId? = null
|
||||
|
||||
private var usernameNeeded = true
|
||||
|
||||
fun parse(): Result? {
|
||||
private var usernameCandidate: AutofillId? = null
|
||||
private var usernameValueCandidate: AutofillValue? = null
|
||||
|
||||
fun parse(saveValue: Boolean = false): Result? {
|
||||
try {
|
||||
result = Result()
|
||||
result?.apply {
|
||||
allowValues = true
|
||||
allowSaveValues = saveValue
|
||||
usernameCandidate = null
|
||||
usernameValueCandidate = null
|
||||
mainLoop@ for (i in 0 until structure.windowNodeCount) {
|
||||
val windowNode = structure.getWindowNodeAt(i)
|
||||
applicationId = windowNode.title.toString().split("/")[0]
|
||||
@@ -53,8 +57,12 @@ internal class StructureParser(private val structure: AssistStructure) {
|
||||
break@mainLoop
|
||||
}
|
||||
// If not explicit username field found, add the field just before password field.
|
||||
if (usernameId == null && passwordId != null && usernameCandidate != null)
|
||||
if (usernameId == null && passwordId != null && usernameCandidate != null) {
|
||||
usernameId = usernameCandidate
|
||||
if (allowSaveValues) {
|
||||
usernameValue = usernameValueCandidate
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the result only if password field is retrieved
|
||||
@@ -72,11 +80,11 @@ internal class StructureParser(private val structure: AssistStructure) {
|
||||
// Get the domain of a web app
|
||||
node.webDomain?.let { webDomain ->
|
||||
if (webDomain.isNotEmpty()) {
|
||||
result?.domain = webDomain
|
||||
result?.webDomain = webDomain
|
||||
Log.d(TAG, "Autofill domain: $webDomain")
|
||||
}
|
||||
}
|
||||
val domainNotEmpty = result?.domain?.isNotEmpty() == true
|
||||
val domainNotEmpty = result?.webDomain?.isNotEmpty() == true
|
||||
|
||||
var returnValue = false
|
||||
// Only parse visible nodes
|
||||
@@ -116,6 +124,7 @@ internal class StructureParser(private val structure: AssistStructure) {
|
||||
|| it.contains("email", true)
|
||||
|| it.contains(View.AUTOFILL_HINT_PHONE, true)-> {
|
||||
result?.usernameId = autofillId
|
||||
result?.usernameValue = node.autofillValue
|
||||
Log.d(TAG, "Autofill username hint")
|
||||
}
|
||||
it.contains(View.AUTOFILL_HINT_PASSWORD, true) -> {
|
||||
@@ -150,10 +159,12 @@ internal class StructureParser(private val structure: AssistStructure) {
|
||||
when (pairAttribute.second.toLowerCase(Locale.ENGLISH)) {
|
||||
"tel", "email" -> {
|
||||
result?.usernameId = autofillId
|
||||
result?.usernameValue = node.autofillValue
|
||||
Log.d(TAG, "Autofill username web type: ${node.htmlInfo?.tag} ${node.htmlInfo?.attributes}")
|
||||
}
|
||||
"text" -> {
|
||||
usernameCandidate = autofillId
|
||||
usernameValueCandidate = node.autofillValue
|
||||
Log.d(TAG, "Autofill username candidate web type: ${node.htmlInfo?.tag} ${node.htmlInfo?.attributes}")
|
||||
}
|
||||
"password" -> {
|
||||
@@ -193,6 +204,7 @@ internal class StructureParser(private val structure: AssistStructure) {
|
||||
InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS,
|
||||
InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS) -> {
|
||||
result?.usernameId = autofillId
|
||||
result?.usernameValue = node.autofillValue
|
||||
Log.d(TAG, "Autofill username android text type: ${showHexInputType(inputType)}")
|
||||
}
|
||||
inputIsVariationType(inputType,
|
||||
@@ -200,6 +212,7 @@ internal class StructureParser(private val structure: AssistStructure) {
|
||||
InputType.TYPE_TEXT_VARIATION_PERSON_NAME,
|
||||
InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) -> {
|
||||
usernameCandidate = autofillId
|
||||
usernameValueCandidate = node.autofillValue
|
||||
Log.d(TAG, "Autofill username candidate android text type: ${showHexInputType(inputType)}")
|
||||
}
|
||||
inputIsVariationType(inputType,
|
||||
@@ -232,11 +245,13 @@ internal class StructureParser(private val structure: AssistStructure) {
|
||||
inputIsVariationType(inputType,
|
||||
InputType.TYPE_NUMBER_VARIATION_NORMAL) -> {
|
||||
usernameCandidate = autofillId
|
||||
usernameValueCandidate = node.autofillValue
|
||||
Log.d(TAG, "Autofill usernale candidate android number type: ${showHexInputType(inputType)}")
|
||||
}
|
||||
inputIsVariationType(inputType,
|
||||
InputType.TYPE_NUMBER_VARIATION_PASSWORD) -> {
|
||||
result?.passwordId = autofillId
|
||||
result?.passwordValue = node.autofillValue
|
||||
Log.d(TAG, "Autofill password android number type: ${showHexInputType(inputType)}")
|
||||
usernameNeeded = false
|
||||
return true
|
||||
@@ -253,7 +268,8 @@ internal class StructureParser(private val structure: AssistStructure) {
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
internal class Result {
|
||||
var applicationId: String? = null
|
||||
var domain: String? = null
|
||||
|
||||
var webDomain: String? = null
|
||||
set(value) {
|
||||
if (field == null)
|
||||
field = value
|
||||
@@ -271,14 +287,6 @@ internal class StructureParser(private val structure: AssistStructure) {
|
||||
field = value
|
||||
}
|
||||
|
||||
var allowValues = false
|
||||
|
||||
var passwordValue: AutofillValue? = null
|
||||
set(value) {
|
||||
if (allowValues && field == null)
|
||||
field = value
|
||||
}
|
||||
|
||||
fun allAutofillIds(): Array<AutofillId> {
|
||||
val all = ArrayList<AutofillId>()
|
||||
usernameId?.let {
|
||||
@@ -289,6 +297,21 @@ internal class StructureParser(private val structure: AssistStructure) {
|
||||
}
|
||||
return all.toTypedArray()
|
||||
}
|
||||
|
||||
// Only in registration mode
|
||||
var allowSaveValues = false
|
||||
|
||||
var usernameValue: AutofillValue? = null
|
||||
set(value) {
|
||||
if (allowSaveValues && field == null)
|
||||
field = value
|
||||
}
|
||||
|
||||
var passwordValue: AutofillValue? = null
|
||||
set(value) {
|
||||
if (allowSaveValues && field == null)
|
||||
field = value
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.kunzisoft.keepass.model
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
|
||||
data class RegisterInfo(val searchInfo: SearchInfo,
|
||||
val username: String?,
|
||||
val password: String?): Parcelable {
|
||||
|
||||
constructor(parcel: Parcel) : this(
|
||||
parcel.readParcelable(SearchInfo::class.java.classLoader) ?: SearchInfo(),
|
||||
parcel.readString() ?: "",
|
||||
parcel.readString() ?: "") {
|
||||
}
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
parcel.writeParcelable(searchInfo, flags)
|
||||
parcel.writeString(username)
|
||||
parcel.writeString(password)
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
companion object CREATOR : Parcelable.Creator<RegisterInfo> {
|
||||
override fun createFromParcel(parcel: Parcel): RegisterInfo {
|
||||
return RegisterInfo(parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<RegisterInfo?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,11 @@ class SearchInfo : ObjectNameResource, Parcelable {
|
||||
|
||||
constructor()
|
||||
|
||||
constructor(toCopy: SearchInfo?) {
|
||||
applicationId = toCopy?.applicationId
|
||||
webDomain = toCopy?.webDomain
|
||||
}
|
||||
|
||||
private constructor(parcel: Parcel) {
|
||||
val readAppId = parcel.readString()
|
||||
applicationId = if (readAppId.isNullOrEmpty()) null else readAppId
|
||||
|
||||
Reference in New Issue
Block a user