diff --git a/src/keepass2android/services/Kp2aAutofillParser/AutofillParser.cs b/src/keepass2android/services/Kp2aAutofillParser/AutofillParser.cs
deleted file mode 100644
index 2824d35be..000000000
--- a/src/keepass2android/services/Kp2aAutofillParser/AutofillParser.cs
+++ /dev/null
@@ -1,956 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using Newtonsoft.Json;
-using Formatting = System.Xml.Formatting;
-
-namespace Kp2aAutofillParser
-{
- public class W3cHints
- {
-
- // Supported W3C autofill tokens (https://html.spec.whatwg.org/multipage/forms.html#autofill)
- public const string HONORIFIC_PREFIX = "honorific-prefix";
- public const string NAME = "name";
- public const string GIVEN_NAME = "given-name";
- public const string ADDITIONAL_NAME = "additional-name";
- public const string FAMILY_NAME = "family-name";
- public const string HONORIFIC_SUFFIX = "honorific-suffix";
- public const string USERNAME = "username";
- public const string NEW_PASSWORD = "new-password";
- public const string CURRENT_PASSWORD = "current-password";
- public const string ORGANIZATION_TITLE = "organization-title";
- public const string ORGANIZATION = "organization";
- public const string STREET_ADDRESS = "street-address";
- public const string ADDRESS_LINE1 = "address-line1";
- public const string ADDRESS_LINE2 = "address-line2";
- public const string ADDRESS_LINE3 = "address-line3";
- public const string ADDRESS_LEVEL4 = "address-level4";
- public const string ADDRESS_LEVEL3 = "address-level3";
- public const string ADDRESS_LEVEL2 = "address-level2";
- public const string ADDRESS_LEVEL1 = "address-level1";
- public const string COUNTRY = "country";
- public const string COUNTRY_NAME = "country-name";
- public const string POSTAL_CODE = "postal-code";
- public const string CC_NAME = "cc-name";
- public const string CC_GIVEN_NAME = "cc-given-name";
- public const string CC_ADDITIONAL_NAME = "cc-additional-name";
- public const string CC_FAMILY_NAME = "cc-family-name";
- public const string CC_NUMBER = "cc-number";
- public const string CC_EXPIRATION = "cc-exp";
- public const string CC_EXPIRATION_MONTH = "cc-exp-month";
- public const string CC_EXPIRATION_YEAR = "cc-exp-year";
- public const string CC_CSC = "cc-csc";
- public const string CC_TYPE = "cc-type";
- public const string TRANSACTION_CURRENCY = "transaction-currency";
- public const string TRANSACTION_AMOUNT = "transaction-amount";
- public const string LANGUAGE = "language";
- public const string BDAY = "bday";
- public const string BDAY_DAY = "bday-day";
- public const string BDAY_MONTH = "bday-month";
- public const string BDAY_YEAR = "bday-year";
- public const string SEX = "sex";
- public const string URL = "url";
- public const string PHOTO = "photo";
- // Optional W3C prefixes
- public const string PREFIX_SECTION = "section-";
- public const string SHIPPING = "shipping";
- public const string BILLING = "billing";
- // W3C prefixes below...
- public const string PREFIX_HOME = "home";
- public const string PREFIX_WORK = "work";
- public const string PREFIX_FAX = "fax";
- public const string PREFIX_PAGER = "pager";
- // ... require those suffix
- public const string TEL = "tel";
- public const string TEL_COUNTRY_CODE = "tel-country-code";
- public const string TEL_NATIONAL = "tel-national";
- public const string TEL_AREA_CODE = "tel-area-code";
- public const string TEL_LOCAL = "tel-local";
- public const string TEL_LOCAL_PREFIX = "tel-local-prefix";
- public const string TEL_LOCAL_SUFFIX = "tel-local-suffix";
- public const string TEL_EXTENSION = "tel_extension";
- public const string EMAIL = "email";
- public const string IMPP = "impp";
-
- private W3cHints()
- {
- }
-
-
-
- public static bool isW3cSectionPrefix(string hint)
- {
- return hint.ToLower().StartsWith(W3cHints.PREFIX_SECTION);
- }
-
- public static bool isW3cAddressType(string hint)
- {
- switch (hint.ToLower())
- {
- case W3cHints.SHIPPING:
- case W3cHints.BILLING:
- return true;
- }
- return false;
- }
-
- public static bool isW3cTypePrefix(string hint)
- {
- switch (hint.ToLower())
- {
- case W3cHints.PREFIX_WORK:
- case W3cHints.PREFIX_FAX:
- case W3cHints.PREFIX_HOME:
- case W3cHints.PREFIX_PAGER:
- return true;
- }
- return false;
- }
-
- public static bool isW3cTypeHint(string hint)
- {
- switch (hint.ToLower())
- {
- case W3cHints.TEL:
- case W3cHints.TEL_COUNTRY_CODE:
- case W3cHints.TEL_NATIONAL:
- case W3cHints.TEL_AREA_CODE:
- case W3cHints.TEL_LOCAL:
- case W3cHints.TEL_LOCAL_PREFIX:
- case W3cHints.TEL_LOCAL_SUFFIX:
- case W3cHints.TEL_EXTENSION:
- case W3cHints.EMAIL:
- case W3cHints.IMPP:
- return true;
- }
- return false;
- }
- }
- ///
- /// FilledAutofillFieldCollection is the model that holds all of the data on a client app's page,
- /// plus the dataset name associated with it.
- ///
- public class FilledAutofillFieldCollection where FieldT:InputField
- {
- public Dictionary> HintMap { get; }
- public string DatasetName { get; set; }
-
- public FilledAutofillFieldCollection(Dictionary> hintMap, string datasetName = "")
- {
- //recreate hint map making sure we compare case insensitive
- HintMap = BuildHintMap();
- foreach (var p in hintMap)
- HintMap.Add(p.Key, p.Value);
- DatasetName = datasetName;
- }
-
- public FilledAutofillFieldCollection() : this(BuildHintMap())
- { }
-
- private static Dictionary> BuildHintMap()
- {
- return new Dictionary>(StringComparer.OrdinalIgnoreCase);
- }
-
- ///
- /// Adds a filledAutofillField to the collection, indexed by all of its hints.
- ///
- /// The add.
- /// Filled autofill field.
- public void Add(FilledAutofillField filledAutofillField)
- {
- foreach (string hint in filledAutofillField.AutofillHints)
- {
- if (AutofillHintsHelper.IsSupportedHint(hint))
- {
- HintMap.TryAdd(hint, filledAutofillField);
- }
- }
-
- }
-
-
-
-
- ///
- /// Takes in a list of autofill hints (`autofillHints`), usually associated with a View or set of
- /// Views. Returns whether any of the filled fields on the page have at least 1 of these
- /// `autofillHint`s.
- ///
- /// true, if with hints was helpsed, false otherwise.
- /// Autofill hints.
- public bool HelpsWithHints(List autofillHints)
- {
- for (int i = 0; i < autofillHints.Count; i++)
- {
- var autofillHint = autofillHints[i];
- if (HintMap.ContainsKey(autofillHint) && !HintMap[autofillHint].IsNull())
- {
- return true;
- }
- }
- return false;
- }
- }
- public class AutofillHintsHelper
- {
- public const string AutofillHint2faAppOtp = "2faAppOTPCode";
- public const string AutofillHintBirthDateDay = "birthDateDay";
- public const string AutofillHintBirthDateFull = "birthDateFull";
- public const string AutofillHintBirthDateMonth = "birthDateMonth";
- public const string AutofillHintBirthDateYear = "birthDateYear";
- public const string AutofillHintCreditCardExpirationDate = "creditCardExpirationDate";
- public const string AutofillHintCreditCardExpirationDay = "creditCardExpirationDay";
- public const string AutofillHintCreditCardExpirationMonth = "creditCardExpirationMonth";
- public const string AutofillHintCreditCardExpirationYear = "creditCardExpirationYear";
- public const string AutofillHintCreditCardNumber = "creditCardNumber";
- public const string AutofillHintCreditCardSecurityCode = "creditCardSecurityCode";
- public const string AutofillHintEmailAddress = "emailAddress";
- public const string AutofillHintEmailOtp = "emailOTPCode";
- public const string AutofillHintGender = "gender";
- public const string AutofillHintName = "name";
- public const string AutofillHintNewPassword = "newPassword";
- public const string AutofillHintNewUsername = "newUsername";
- public const string AutofillHintNotApplicable = "notApplicable";
- public const string AutofillHintPassword = "password";
- public const string AutofillHintPersonName = "personName";
- public const string AutofillHintPersonNameFAMILY = "personFamilyName";
- public const string AutofillHintPersonNameGIVEN = "personGivenName";
- public const string AutofillHintPersonNameMIDDLE = "personMiddleName";
- public const string AutofillHintPersonNameMIDDLE_INITIAL = "personMiddleInitial";
- public const string AutofillHintPersonNamePREFIX = "personNamePrefix";
- public const string AutofillHintPersonNameSUFFIX = "personNameSuffix";
- public const string AutofillHintPhone = "phone";
- public const string AutofillHintPhoneContryCode = "phoneCountryCode";
- public const string AutofillHintPostalAddressAPT_NUMBER = "aptNumber";
- public const string AutofillHintPostalAddressCOUNTRY = "addressCountry";
- public const string AutofillHintPostalAddressDEPENDENT_LOCALITY = "dependentLocality";
- public const string AutofillHintPostalAddressEXTENDED_ADDRESS = "extendedAddress";
- public const string AutofillHintPostalAddressEXTENDED_POSTAL_CODE = "extendedPostalCode";
- public const string AutofillHintPostalAddressLOCALITY = "addressLocality";
- public const string AutofillHintPostalAddressREGION = "addressRegion";
- public const string AutofillHintPostalAddressSTREET_ADDRESS = "streetAddress";
- public const string AutofillHintPostalCode = "postalCode";
- public const string AutofillHintPromoCode = "promoCode";
- public const string AutofillHintSMS_OTP = "smsOTPCode";
- public const string AutofillHintUPI_VPA = "upiVirtualPaymentAddress";
- public const string AutofillHintUsername = "username";
- public const string AutofillHintWifiPassword = "wifiPassword";
- public const string AutofillHintPhoneNational = "phoneNational";
- public const string AutofillHintPhoneNumber = "phoneNumber";
- public const string AutofillHintPhoneNumberDevice = "phoneNumberDevice";
- public const string AutofillHintPostalAddress = "postalAddress";
-
- private static readonly HashSet _allSupportedHints = new HashSet(StringComparer.OrdinalIgnoreCase)
- {
- AutofillHintCreditCardExpirationDate,
- AutofillHintCreditCardExpirationDay,
- AutofillHintCreditCardExpirationMonth,
- AutofillHintCreditCardExpirationYear,
- AutofillHintCreditCardNumber,
- AutofillHintCreditCardSecurityCode,
- AutofillHintEmailAddress,
- AutofillHintPhone,
- AutofillHintName,
- AutofillHintPassword,
- AutofillHintPostalAddress,
- AutofillHintPostalCode,
- AutofillHintUsername,
- W3cHints.HONORIFIC_PREFIX,
- W3cHints.NAME,
- W3cHints.GIVEN_NAME,
- W3cHints.ADDITIONAL_NAME,
- W3cHints.FAMILY_NAME,
- W3cHints.HONORIFIC_SUFFIX,
- W3cHints.USERNAME,
- W3cHints.NEW_PASSWORD,
- W3cHints.CURRENT_PASSWORD,
- W3cHints.ORGANIZATION_TITLE,
- W3cHints.ORGANIZATION,
- W3cHints.STREET_ADDRESS,
- W3cHints.ADDRESS_LINE1,
- W3cHints.ADDRESS_LINE2,
- W3cHints.ADDRESS_LINE3,
- W3cHints.ADDRESS_LEVEL4,
- W3cHints.ADDRESS_LEVEL3,
- W3cHints.ADDRESS_LEVEL2,
- W3cHints.ADDRESS_LEVEL1,
- W3cHints.COUNTRY,
- W3cHints.COUNTRY_NAME,
- W3cHints.POSTAL_CODE,
- W3cHints.CC_NAME,
- W3cHints.CC_GIVEN_NAME,
- W3cHints.CC_ADDITIONAL_NAME,
- W3cHints.CC_FAMILY_NAME,
- W3cHints.CC_NUMBER,
- W3cHints.CC_EXPIRATION,
- W3cHints.CC_EXPIRATION_MONTH,
- W3cHints.CC_EXPIRATION_YEAR,
- W3cHints.CC_CSC,
- W3cHints.CC_TYPE,
- W3cHints.TRANSACTION_CURRENCY,
- W3cHints.TRANSACTION_AMOUNT,
- W3cHints.LANGUAGE,
- W3cHints.BDAY,
- W3cHints.BDAY_DAY,
- W3cHints.BDAY_MONTH,
- W3cHints.BDAY_YEAR,
- W3cHints.SEX,
- W3cHints.URL,
- W3cHints.PHOTO,
- W3cHints.TEL,
- W3cHints.TEL_COUNTRY_CODE,
- W3cHints.TEL_NATIONAL,
- W3cHints.TEL_AREA_CODE,
- W3cHints.TEL_LOCAL,
- W3cHints.TEL_LOCAL_PREFIX,
- W3cHints.TEL_LOCAL_SUFFIX,
- W3cHints.TEL_EXTENSION,
- W3cHints.EMAIL,
- W3cHints.IMPP,
- };
-
- private static readonly List> partitionsOfCanonicalHints = new List>()
- {
-
- new HashSet(StringComparer.OrdinalIgnoreCase)
- {
- AutofillHintEmailAddress,
- AutofillHintPhone,
- AutofillHintName,
- AutofillHintPassword,
- AutofillHintUsername,
- W3cHints.HONORIFIC_PREFIX,
- W3cHints.NAME,
- W3cHints.GIVEN_NAME,
- W3cHints.ADDITIONAL_NAME,
- W3cHints.FAMILY_NAME,
- W3cHints.HONORIFIC_SUFFIX,
- W3cHints.ORGANIZATION_TITLE,
- W3cHints.ORGANIZATION,
- W3cHints.LANGUAGE,
- W3cHints.BDAY,
- W3cHints.BDAY_DAY,
- W3cHints.BDAY_MONTH,
- W3cHints.BDAY_YEAR,
- W3cHints.SEX,
- W3cHints.URL,
- W3cHints.PHOTO,
- W3cHints.TEL,
- W3cHints.TEL_COUNTRY_CODE,
- W3cHints.TEL_NATIONAL,
- W3cHints.TEL_AREA_CODE,
- W3cHints.TEL_LOCAL,
- W3cHints.TEL_LOCAL_PREFIX,
- W3cHints.TEL_LOCAL_SUFFIX,
- W3cHints.TEL_EXTENSION,
- W3cHints.IMPP,
- },
- new HashSet(StringComparer.OrdinalIgnoreCase)
- {
- AutofillHintPostalAddress,
- AutofillHintPostalCode,
-
- W3cHints.STREET_ADDRESS,
- W3cHints.ADDRESS_LINE1,
- W3cHints.ADDRESS_LINE2,
- W3cHints.ADDRESS_LINE3,
- W3cHints.ADDRESS_LEVEL4,
- W3cHints.ADDRESS_LEVEL3,
- W3cHints.ADDRESS_LEVEL2,
- W3cHints.ADDRESS_LEVEL1,
- W3cHints.COUNTRY,
- W3cHints.COUNTRY_NAME
- },
- new HashSet(StringComparer.OrdinalIgnoreCase)
- {
- AutofillHintCreditCardExpirationDate,
- AutofillHintCreditCardExpirationDay,
- AutofillHintCreditCardExpirationMonth,
- AutofillHintCreditCardExpirationYear,
- AutofillHintCreditCardNumber,
- AutofillHintCreditCardSecurityCode,
-
- W3cHints.CC_NAME,
- W3cHints.CC_GIVEN_NAME,
- W3cHints.CC_ADDITIONAL_NAME,
- W3cHints.CC_FAMILY_NAME,
- W3cHints.CC_TYPE,
- W3cHints.TRANSACTION_CURRENCY,
- W3cHints.TRANSACTION_AMOUNT,
- },
-
- };
-
- private static readonly Dictionary hintToCanonicalReplacement = new Dictionary(StringComparer.OrdinalIgnoreCase)
- {
- {W3cHints.EMAIL, AutofillHintEmailAddress},
- {W3cHints.USERNAME, AutofillHintUsername},
- {W3cHints.CURRENT_PASSWORD, AutofillHintPassword},
- {W3cHints.NEW_PASSWORD, AutofillHintPassword},
- {W3cHints.CC_EXPIRATION_MONTH, AutofillHintCreditCardExpirationMonth },
- {W3cHints.CC_EXPIRATION_YEAR, AutofillHintCreditCardExpirationYear },
- {W3cHints.CC_EXPIRATION, AutofillHintCreditCardExpirationDate },
- {W3cHints.CC_NUMBER, AutofillHintCreditCardNumber },
- {W3cHints.CC_CSC, AutofillHintCreditCardSecurityCode },
- {W3cHints.POSTAL_CODE, AutofillHintPostalCode },
-
-
- };
-
- public static bool IsSupportedHint(string hint)
- {
- return _allSupportedHints.Contains(hint);
- }
-
-
- public static string[] FilterForSupportedHints(string[] hints)
- {
- if (hints == null)
- return Array.Empty();
- var filteredHints = new string[hints.Length];
- int i = 0;
- foreach (var hint in hints)
- {
- if (IsSupportedHint(hint))
- {
- filteredHints[i++] = hint;
- }
-
- }
- var finalFilteredHints = new string[i];
- Array.Copy(filteredHints, 0, finalFilteredHints, 0, i);
- return finalFilteredHints;
- }
-
-
-
- ///
- /// transforms hints by replacing some W3cHints by their Android counterparts and transforming everything to lowercase
- ///
- public static List ConvertToCanonicalHints(string[] supportedHints)
- {
- List result = new List();
- foreach (string hint in supportedHints)
- {
- string canonicalHint;
- if (!hintToCanonicalReplacement.TryGetValue(hint, out canonicalHint))
- canonicalHint = hint;
- result.Add(canonicalHint.ToLower());
- }
- return result;
-
- }
-
- public static int GetPartitionIndex(string hint)
- {
- for (int i = 0; i < partitionsOfCanonicalHints.Count; i++)
- {
- if (partitionsOfCanonicalHints[i].Contains(hint))
- {
- return i;
- }
- }
- return -1;
- }
-
- public static FilledAutofillFieldCollection FilterForPartition(FilledAutofillFieldCollection autofillFields, int partitionIndex) where FieldT: InputField
- {
- FilledAutofillFieldCollection filteredCollection =
- new FilledAutofillFieldCollection { DatasetName = autofillFields.DatasetName };
-
- if (partitionIndex == -1)
- return filteredCollection;
-
- foreach (var field in autofillFields.HintMap.Values.Distinct())
- {
- foreach (var hint in field.AutofillHints)
- {
- if (GetPartitionIndex(hint) == partitionIndex)
- {
- filteredCollection.Add(field);
- break;
- }
- }
- }
-
- return filteredCollection;
- }
-
- public static FilledAutofillFieldCollection FilterForPartition(FilledAutofillFieldCollection filledAutofillFieldCollection, List autofillFieldsFocusedAutofillCanonicalHints) where FieldT: InputField
- {
-
- //only apply partition data if we have FocusedAutofillCanonicalHints. This may be empty on buggy Firefox.
- if (autofillFieldsFocusedAutofillCanonicalHints.Any())
- {
- int partitionIndex = AutofillHintsHelper.GetPartitionIndex(autofillFieldsFocusedAutofillCanonicalHints.FirstOrDefault());
- return AutofillHintsHelper.FilterForPartition(filledAutofillFieldCollection, partitionIndex);
- }
-
- return filledAutofillFieldCollection;
- }
- }
- ///
- /// This enum represents the Android.Text.InputTypes values. For testability, this is duplicated here.
- ///
- public enum InputTypes
- {
- ClassDatetime = 4,
- ClassNumber = 2,
- ClassPhone = 3,
- ClassText = 1,
- DatetimeVariationDate = 16,
- DatetimeVariationNormal = 0,
- DatetimeVariationTime = 32,
- MaskClass = 15,
- MaskFlags = 16773120,
- MaskVariation = 4080,
- Null = 0,
- NumberFlagDecimal = 8192,
- NumberFlagSigned = 4096,
- NumberVariationNormal = 0,
- NumberVariationPassword = 16,
- TextFlagAutoComplete = 65536,
- TextFlagAutoCorrect = 32768,
- TextFlagCapCharacters = 4096,
- TextFlagCapSentences = 16384,
- TextFlagCapWords = 8192,
- TextFlagEnableTextConversionSuggestions = 1048576,
- TextFlagImeMultiLine = 262144,
- TextFlagMultiLine = 131072,
- TextFlagNoSuggestions = 524288,
- TextVariationEmailAddress = 32,
- TextVariationEmailSubject = 48,
- TextVariationFilter = 176,
- TextVariationLongMessage = 80,
- TextVariationNormal = 0,
- TextVariationPassword = 128,
- TextVariationPersonName = 96,
- TextVariationPhonetic = 192,
- TextVariationPostalAddress = 112,
- TextVariationShortMessage = 64,
- TextVariationUri = 16,
- TextVariationVisiblePassword = 144,
- TextVariationWebEditText = 160,
- TextVariationWebEmailAddress = 208,
- TextVariationWebPassword = 224
- }
-
- public interface IKp2aDigitalAssetLinksDataSource
- {
- bool IsTrustedApp(string packageName);
- bool IsTrustedLink(string domain, string targetPackage);
- bool IsEnabled();
-
- }
-
- class TimeUtil
- {
- private static DateTime? m_dtUnixRoot = null;
- public static DateTime ConvertUnixTime(double dtUnix)
- {
- try
- {
- if (!m_dtUnixRoot.HasValue)
- m_dtUnixRoot = (new DateTime(1970, 1, 1, 0, 0, 0, 0,
- DateTimeKind.Utc)).ToLocalTime();
-
- return m_dtUnixRoot.Value.AddSeconds(dtUnix);
- }
- catch (Exception) { Debug.Assert(false); }
-
- return DateTime.UtcNow;
- }
- }
-
- public class FilledAutofillField where FieldT : InputField
- {
- private string[] _autofillHints;
- public string TextValue { get; set; }
- public long? DateValue { get; set; }
- public bool? ToggleValue { get; set; }
-
- public string ValueToString()
- {
- if (DateValue != null)
- {
- return TimeUtil.ConvertUnixTime((long)DateValue / 1000.0).ToLongDateString();
- }
- if (ToggleValue != null)
- return ToggleValue.ToString();
- return TextValue;
- }
-
- ///
- /// returns the autofill hints for the filled field. These are always lowercased for simpler string comparison.
- ///
- public string[] AutofillHints
- {
- get
- {
- return _autofillHints;
- }
- set
- {
- _autofillHints = value;
- for (int i = 0; i < _autofillHints.Length; i++)
- _autofillHints[i] = _autofillHints[i].ToLower();
- }
- }
-
-
- public FilledAutofillField()
- { }
-
- public FilledAutofillField(FieldT inputField)
- : this(inputField, inputField.AutofillHints)
- {
-
- }
-
- public FilledAutofillField(FieldT inputField, string[] hints)
- {
-
- string[] rawHints = AutofillHintsHelper.FilterForSupportedHints(hints);
- List hintList = new List();
-
- string nextHint = null;
- for (int i = 0; i < rawHints.Length; i++)
- {
- string hint = rawHints[i];
- if (i < rawHints.Length - 1)
- {
- nextHint = rawHints[i + 1];
- }
- // First convert the compound W3C autofill hints
- if (W3cHints.isW3cSectionPrefix(hint) && i < rawHints.Length - 1)
- {
- hint = rawHints[++i];
-
- if (i < rawHints.Length - 1)
- {
- nextHint = rawHints[i + 1];
- }
- }
- if (W3cHints.isW3cTypePrefix(hint) && nextHint != null && W3cHints.isW3cTypeHint(nextHint))
- {
- hint = nextHint;
- i++;
-
- }
- if (W3cHints.isW3cAddressType(hint) && nextHint != null)
- {
- hint = nextHint;
- i++;
-
- }
-
- // Then check if the "actual" hint is supported.
- if (AutofillHintsHelper.IsSupportedHint(hint))
- {
- hintList.Add(hint);
- }
- else
- {
-
- }
- }
- AutofillHints = AutofillHintsHelper.ConvertToCanonicalHints(hintList.ToArray()).ToArray();
-
-
- }
-
- public bool IsNull()
- {
- return TextValue == null && DateValue == null && ToggleValue == null;
- }
-
- public override bool Equals(object obj)
- {
- if (this == obj) return true;
- if (obj == null || GetType() != obj.GetType()) return false;
-
- FilledAutofillField that = (FilledAutofillField)obj;
-
- if (!TextValue?.Equals(that.TextValue) ?? that.TextValue != null)
- return false;
- if (DateValue != null ? !DateValue.Equals(that.DateValue) : that.DateValue != null)
- return false;
- return ToggleValue != null ? ToggleValue.Equals(that.ToggleValue) : that.ToggleValue == null;
- }
-
- public override int GetHashCode()
- {
- unchecked
- {
- var result = TextValue != null ? TextValue.GetHashCode() : 0;
- result = 31 * result + (DateValue != null ? DateValue.GetHashCode() : 0);
- result = 31 * result + (ToggleValue != null ? ToggleValue.GetHashCode() : 0);
- return result;
- }
- }
- }
-
- ///
- /// Base class for everything that is a input field which might (or might not) be autofilled.
- /// For testability, this is independent from Android classes like ViewNode
- ///
- public abstract class InputField
- {
- public string IdEntry { get; set; }
- public string Hint { get; set; }
- public string ClassName { get; set; }
- public string[] AutofillHints { get; set; }
- public bool IsFocused { get; set; }
-
- public InputTypes InputType { get; set; }
-
- public string HtmlInfoTag { get; set; }
- public string HtmlInfoTypeAttribute { get; set; }
-
- }
-
- public class AutofillView where TField : InputField
- {
- public List InputFields { get; set; } = new List();
-
- public string PackageId { get; set; } = null;
- public string WebDomain { get; set; } = null;
- }
-
- public interface ILogger
- {
- void Log(string x);
- }
-
- public class StructureParserBase where FieldT: InputField
- {
- private readonly ILogger _log;
- private readonly IKp2aDigitalAssetLinksDataSource _digitalAssetLinksDataSource;
-
- private readonly List _autofillHintsForLogin = new List
- {
- AutofillHintsHelper.AutofillHintPassword,
- AutofillHintsHelper.AutofillHintUsername,
- AutofillHintsHelper.AutofillHintEmailAddress
- };
-
- public string PackageId { get; set; }
-
- public Dictionary FieldsMappedToHints = new Dictionary();
-
- public StructureParserBase(ILogger logger, IKp2aDigitalAssetLinksDataSource digitalAssetLinksDataSource)
- {
- _log = logger;
- _digitalAssetLinksDataSource = digitalAssetLinksDataSource;
- }
-
- public class AutofillTargetId
- {
- public string PackageName { get; set; }
-
- public string PackageNameWithPseudoSchema
- {
- get { return AndroidAppScheme + PackageName; }
- }
-
- public const string AndroidAppScheme = "androidapp://";
-
- public string WebDomain { get; set; }
-
- ///
- /// If PackageName and WebDomain are not compatible (by DAL or because PackageName is a trusted browser in which case we treat all domains as "compatible"
- /// we need to issue a warning. If we would fill credentials for the package, a malicious website could try to get credentials for the app.
- /// If we would fill credentials for the domain, a malicious app could get credentials for the domain.
- ///
- public bool IncompatiblePackageAndDomain { get; set; }
-
- public string DomainOrPackage
- {
- get
- {
- return WebDomain ?? PackageNameWithPseudoSchema;
- }
- }
- }
-
- public AutofillTargetId ParseForFill(bool isManual, AutofillView autofillView)
- {
- return Parse(true, isManual, autofillView);
- }
-
- public AutofillTargetId ParseForSave(AutofillView autofillView)
- {
- return Parse(false, true, autofillView);
- }
-
- ///
- /// Traverse AssistStructure and add ViewNode metadata to a flat list.
- ///
- /// The parse.
- /// If set to true for fill.
- ///
- protected virtual AutofillTargetId Parse(bool forFill, bool isManualRequest, AutofillView autofillView)
- {
- AutofillTargetId result = new AutofillTargetId()
- {
- PackageName = autofillView.PackageId,
- WebDomain = autofillView.WebDomain
- };
-
- _log.Log("parsing autofillStructure...");
-
- //TODO remove from production
- _log.Log("will log the autofillStructure...");
- string debugInfo = JsonConvert.SerializeObject(autofillView, Newtonsoft.Json.Formatting.Indented);
- _log.Log("will log the autofillStructure... size is " + debugInfo.Length);
- _log.Log("This is the autofillStructure: \n\n " + debugInfo);
-
- //go through each input field and determine username/password fields.
- //Depending on the target this can require more or less heuristics.
- // * if there is a valid & supported autofill hint, we assume that all fields which should be filled do have an appropriate Autofill hint
- // * if there is no such autofill hint, we use IsPassword to
-
- HashSet autofillHintsOfAllFields = autofillView.InputFields.Where(f => f.AutofillHints != null)
- .SelectMany(f => f.AutofillHints).ToHashSet();
- bool hasLoginAutofillHints = autofillHintsOfAllFields.Intersect(_autofillHintsForLogin).Any();
-
- if (hasLoginAutofillHints)
- {
- foreach (var viewNode in autofillView.InputFields)
- {
- string[] viewHints = viewNode.AutofillHints;
- if (viewHints == null)
- continue;
- if (viewHints.Intersect(_autofillHintsForLogin).Any())
- {
- FieldsMappedToHints.Add(viewNode, viewHints);
- }
-
- }
- }
- else
- {
- //determine password fields, first by type, then by hint:
- List passwordFields = autofillView.InputFields.Where(f => IsEditText(f) && IsPassword(f)).ToList();
- if (!passwordFields.Any())
- {
- passwordFields = autofillView.InputFields.Where(f => IsEditText(f) && HasPasswordHint(f)).ToList();
- }
-
- //determine username fields. Try by hint, if that fails use the one before the password
- List usernameFields = autofillView.InputFields.Where(f => IsEditText(f) && HasUsernameHint(f)).ToList();
- if (!usernameFields.Any())
- {
- foreach (var passwordField in passwordFields)
- {
- var lastInputBeforePassword = autofillView.InputFields
- .TakeWhile(f => IsEditText(f) && f != passwordField && !passwordFields.Contains(f)).LastOrDefault();
- if (lastInputBeforePassword != null)
- usernameFields.Add(lastInputBeforePassword);
- }
-
- }
-
- //for "heuristic determination" we demand that one of the filled fields is focused:
- if (passwordFields.Concat(usernameFields).Any(f => f.IsFocused))
- {
- foreach (var uf in usernameFields)
- FieldsMappedToHints.Add(uf, new string[] { AutofillHintsHelper.AutofillHintUsername });
- foreach (var pf in passwordFields)
- FieldsMappedToHints.Add(pf, new string[] { AutofillHintsHelper.AutofillHintPassword });
- }
- }
-
-
- if (!string.IsNullOrEmpty(autofillView.WebDomain) && _digitalAssetLinksDataSource.IsEnabled())
- {
- result.IncompatiblePackageAndDomain = !_digitalAssetLinksDataSource.IsTrustedLink(autofillView.WebDomain, result.PackageName);
- if (result.IncompatiblePackageAndDomain)
- {
- _log.Log($"DAL verification failed for {result.PackageName}/{result.WebDomain}");
- }
- }
- else
- {
- result.IncompatiblePackageAndDomain = false;
- }
- return result;
- }
-
- private bool IsEditText(FieldT f)
- {
- return (f.ClassName == "android.widget.EditText"
- || f.ClassName == "android.widget.AutoCompleteTextView"
- || f.HtmlInfoTag == "input");
- }
-
- private static readonly HashSet _passwordHints = new HashSet { "password", "passwort"
- /*, "passwordAuto", "pswd"*/ };
- private static bool HasPasswordHint(InputField f)
- {
- return IsAny(f.IdEntry, _passwordHints) ||
- IsAny(f.Hint, _passwordHints);
- }
-
- private static readonly HashSet _usernameHints = new HashSet { "email", "e-mail", "username" };
-
- private static bool HasUsernameHint(InputField f)
- {
- return IsAny(f.IdEntry, _usernameHints) ||
- IsAny(f.Hint, _usernameHints);
- }
-
- private static bool IsAny(string value, IEnumerable terms)
- {
- if (string.IsNullOrWhiteSpace(value))
- {
- return false;
- }
- var lowerValue = value.ToLowerInvariant();
- return terms.Any(t => lowerValue == t);
- }
-
- private static bool IsInputTypeClass(InputTypes inputType, InputTypes inputTypeClass)
- {
- if (!InputTypes.MaskClass.HasFlag(inputTypeClass))
- throw new Exception("invalid inputTypeClass");
- return (((int)inputType) & (int)InputTypes.MaskClass) == (int)(inputTypeClass);
- }
- private static bool IsInputTypeVariation(InputTypes inputType, InputTypes inputTypeVariation)
- {
- if (!InputTypes.MaskVariation.HasFlag(inputTypeVariation))
- throw new Exception("invalid inputTypeVariation");
- return (((int)inputType) & (int)InputTypes.MaskVariation) == (int)(inputTypeVariation);
- }
-
- private static bool IsPassword(InputField f)
- {
- InputTypes inputType = f.InputType;
-
- return
- (!f.IdEntry?.ToLowerInvariant().Contains("search") ?? true) &&
- (!f.Hint?.ToLowerInvariant().Contains("search") ?? true) &&
- (
- (IsInputTypeClass(inputType, InputTypes.ClassText)
- &&
- (
- IsInputTypeVariation(inputType, InputTypes.TextVariationPassword)
- || IsInputTypeVariation(inputType, InputTypes.TextVariationVisiblePassword)
- || IsInputTypeVariation(inputType, InputTypes.TextVariationWebPassword)
- )
- )
- || (f.AutofillHints != null && f.AutofillHints.First() == "passwordAuto")
- || (f.HtmlInfoTypeAttribute == "password")
- );
- }
-
-
-
-
-
-
- }
-}
diff --git a/src/keepass2android/services/Kp2aAutofillParser/Kp2aAutofillParser.csproj b/src/keepass2android/services/Kp2aAutofillParser/Kp2aAutofillParser.csproj
deleted file mode 100644
index 375762cdd..000000000
--- a/src/keepass2android/services/Kp2aAutofillParser/Kp2aAutofillParser.csproj
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
- netstandard2.1
- enable
-
-
-
-
-
-
-