From 3c41550404abbc6d94943dce24de9f8c1b32590a Mon Sep 17 00:00:00 2001 From: PhilippC Date: Thu, 9 Feb 2023 16:44:10 +0100 Subject: [PATCH 001/101] New translations strings.xml (Polish) --- src/keepass2android/Resources/values-pl/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keepass2android/Resources/values-pl/strings.xml b/src/keepass2android/Resources/values-pl/strings.xml index f1666033..fa5dd72e 100644 --- a/src/keepass2android/Resources/values-pl/strings.xml +++ b/src/keepass2android/Resources/values-pl/strings.xml @@ -687,7 +687,7 @@ Zamknij bazę danych po trzech nieudanych próbach odblokowania biometrycznego. Uwaga! Uwierzytelnienie biometryczne może zostać unieważnione przez Androida, np. po dodaniu nowego odcisku palca w ustawieniach urządzenia. Upewnij się, że zawsze wiesz, jak odblokować przy użyciu hasła głównego! - Bug fix to crashes and unexpected log-outs + Naprawa błędów awarii i nieoczekiwanych wylogowań Przełącz się na nową implementację SFTP, wspierając nowoczesne algorytmy klucza publicznego, takie jak rsa-sha2-256 Oznacz hasła jako wrażliwe podczas kopiowania do schowka (Android 13) From 8c8a8e39687dc7ac01cc048404da06251eb50937 Mon Sep 17 00:00:00 2001 From: Rick Brown Date: Thu, 9 Feb 2023 20:20:03 -0500 Subject: [PATCH 002/101] Normalize gradle jvmargs to reuse a single GradleDaemon Set max heap to 1.5G across all java projects. Inspection via VisualVM found 1G to be a little too aggressive, while 2G seemed overkill. In any case a full build now can reuse a single GradleDaemon instance instead of three. --- src/java/JavaFileStorage/gradle.properties | 1 + src/java/JavaFileStorageTest-AS/gradle.properties | 2 +- src/java/KP2AKdbLibrary/gradle.properties | 1 + src/java/KP2ASoftkeyboard_AS/gradle.properties | 2 +- src/java/Keepass2AndroidPluginSDK2/gradle.properties | 1 + src/java/PluginQR/gradle.properties | 2 +- src/java/android-filechooser-AS/gradle.properties | 2 +- 7 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 src/java/JavaFileStorage/gradle.properties create mode 100644 src/java/KP2AKdbLibrary/gradle.properties create mode 100644 src/java/Keepass2AndroidPluginSDK2/gradle.properties diff --git a/src/java/JavaFileStorage/gradle.properties b/src/java/JavaFileStorage/gradle.properties new file mode 100644 index 00000000..6ed0f8f9 --- /dev/null +++ b/src/java/JavaFileStorage/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx1536m diff --git a/src/java/JavaFileStorageTest-AS/gradle.properties b/src/java/JavaFileStorageTest-AS/gradle.properties index 469f8a4e..76e5562c 100644 --- a/src/java/JavaFileStorageTest-AS/gradle.properties +++ b/src/java/JavaFileStorageTest-AS/gradle.properties @@ -19,4 +19,4 @@ android.enableJetifier=true android.useAndroidX=true -org.gradle.jvmargs=-Xmx2048m +org.gradle.jvmargs=-Xmx1536m diff --git a/src/java/KP2AKdbLibrary/gradle.properties b/src/java/KP2AKdbLibrary/gradle.properties new file mode 100644 index 00000000..6ed0f8f9 --- /dev/null +++ b/src/java/KP2AKdbLibrary/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx1536m diff --git a/src/java/KP2ASoftkeyboard_AS/gradle.properties b/src/java/KP2ASoftkeyboard_AS/gradle.properties index 0bb15d79..6ed0f8f9 100644 --- a/src/java/KP2ASoftkeyboard_AS/gradle.properties +++ b/src/java/KP2ASoftkeyboard_AS/gradle.properties @@ -1 +1 @@ -org.gradle.jvmargs=-Xmx1024m \ No newline at end of file +org.gradle.jvmargs=-Xmx1536m diff --git a/src/java/Keepass2AndroidPluginSDK2/gradle.properties b/src/java/Keepass2AndroidPluginSDK2/gradle.properties new file mode 100644 index 00000000..6ed0f8f9 --- /dev/null +++ b/src/java/Keepass2AndroidPluginSDK2/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx1536m diff --git a/src/java/PluginQR/gradle.properties b/src/java/PluginQR/gradle.properties index 0bb15d79..6ed0f8f9 100644 --- a/src/java/PluginQR/gradle.properties +++ b/src/java/PluginQR/gradle.properties @@ -1 +1 @@ -org.gradle.jvmargs=-Xmx1024m \ No newline at end of file +org.gradle.jvmargs=-Xmx1536m diff --git a/src/java/android-filechooser-AS/gradle.properties b/src/java/android-filechooser-AS/gradle.properties index 57d1a3df..5e2afb41 100644 --- a/src/java/android-filechooser-AS/gradle.properties +++ b/src/java/android-filechooser-AS/gradle.properties @@ -1,2 +1,2 @@ -org.gradle.jvmargs=-Xmx1024m +org.gradle.jvmargs=-Xmx1536m android.useAndroidX=true From bcc17d91bd931a323ca061730e112385164ea7dd Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Sat, 11 Feb 2023 06:50:52 +0100 Subject: [PATCH 003/101] fix potential crash on newer Android versions when trying to close notification drawer --- .../Properties/AndroidManifest_net.xml | 4 ++-- .../Properties/AndroidManifest_nonet.xml | 4 ++-- .../services/CopyToClipboardService.cs | 14 +++++++++++--- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/keepass2android/Properties/AndroidManifest_net.xml b/src/keepass2android/Properties/AndroidManifest_net.xml index 4d54acfc..b008d5dd 100644 --- a/src/keepass2android/Properties/AndroidManifest_net.xml +++ b/src/keepass2android/Properties/AndroidManifest_net.xml @@ -1,7 +1,7 @@  diff --git a/src/keepass2android/Properties/AndroidManifest_nonet.xml b/src/keepass2android/Properties/AndroidManifest_nonet.xml index ee2d0df0..839d80be 100644 --- a/src/keepass2android/Properties/AndroidManifest_nonet.xml +++ b/src/keepass2android/Properties/AndroidManifest_nonet.xml @@ -1,7 +1,7 @@  diff --git a/src/keepass2android/services/CopyToClipboardService.cs b/src/keepass2android/services/CopyToClipboardService.cs index 18424a78..173d9bff 100644 --- a/src/keepass2android/services/CopyToClipboardService.cs +++ b/src/keepass2android/services/CopyToClipboardService.cs @@ -241,6 +241,7 @@ namespace keepass2android .SetWhen(Java.Lang.JavaSystem.CurrentTimeMillis()) .SetTicker(entryName + ": " + desc) .SetVisibility((int)Android.App.NotificationVisibility.Secret) + .SetAutoCancel(true) .SetContentIntent(pending); if (entryIcon != null) builder.SetLargeIcon(entryIcon); @@ -951,7 +952,9 @@ namespace keepass2android { CopyToClipboardService.CopyValueToClipboardWithTimeout(context, username, false); } - context.SendBroadcast(new Intent(Intent.ActionCloseSystemDialogs)); //close notification drawer + + CloseNotificationDrawer(context); + } else if (action.Equals(Intents.CopyPassword)) { @@ -960,7 +963,7 @@ namespace keepass2android { CopyToClipboardService.CopyValueToClipboardWithTimeout(context, password, true); } - context.SendBroadcast(new Intent(Intent.ActionCloseSystemDialogs)); //close notification drawer + CloseNotificationDrawer(context); } else if (action.Equals(Intents.CopyTotp)) { @@ -969,7 +972,7 @@ namespace keepass2android { CopyToClipboardService.CopyValueToClipboardWithTimeout(context, totp, true); } - context.SendBroadcast(new Intent(Intent.ActionCloseSystemDialogs)); //close notification drawer + CloseNotificationDrawer(context); } else if (action.Equals(Intents.CheckKeyboard)) { @@ -977,6 +980,11 @@ namespace keepass2android } } + private static void CloseNotificationDrawer(Context context) + { + if ((int)Build.VERSION.SdkInt < 31) //sending this intent is no longer allowed since Android 31 + context.SendBroadcast(new Intent(Intent.ActionCloseSystemDialogs)); //close notification drawer + } }; } From f7feddcf1f1b8f1b84dc4ee72bfd84f738473a36 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Sat, 11 Feb 2023 06:56:02 +0100 Subject: [PATCH 004/101] start to refactor Autofill code to extract some logic into an non-Androidlibrary --- src/KeePass.sln | 26 + src/Kp2aAutofillParser/AutofillParser.cs | 983 ++++++++++++++++++ .../Kp2aAutofillParser.csproj | 12 + .../keepass2android-app.csproj | 4 + .../services/AutofillBase/AutofillHelper.cs | 109 +- .../AutofillBase/AutofillHintsHelper.cs | 253 +---- .../AutofillBase/AutofillServiceBase.cs | 4 +- .../Kp2aDigitalAssetLinksDataSource.cs | 4 +- .../services/AutofillBase/StructureParser.cs | 315 ++++-- .../AutofillBase/model/FilledAutofillField.cs | 149 +-- .../model/FilledAutofillFieldCollection.cs | 161 +-- .../services/AutofillBase/model/W3cHints.cs | 123 +-- 12 files changed, 1344 insertions(+), 799 deletions(-) create mode 100644 src/Kp2aAutofillParser/AutofillParser.cs create mode 100644 src/Kp2aAutofillParser/Kp2aAutofillParser.csproj diff --git a/src/KeePass.sln b/src/KeePass.sln index 07b0f025..27d6c9ae 100644 --- a/src/KeePass.sln +++ b/src/KeePass.sln @@ -25,6 +25,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PCloudBindings", "PCloudBin EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "keepass2android-app", "keepass2android\keepass2android-app.csproj", "{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kp2aAutofillParser", "Kp2aAutofillParser\Kp2aAutofillParser.csproj", "{39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -283,6 +285,30 @@ Global {D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU {D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.ReleaseNoNet|x64.Build.0 = Release|Any CPU {D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.ReleaseNoNet|x64.Deploy.0 = Release|Any CPU + {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.Debug|Win32.ActiveCfg = Debug|Any CPU + {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.Debug|Win32.Build.0 = Debug|Any CPU + {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.Debug|x64.ActiveCfg = Debug|Any CPU + {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.Debug|x64.Build.0 = Debug|Any CPU + {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.Release|Any CPU.Build.0 = Release|Any CPU + {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.Release|Win32.ActiveCfg = Release|Any CPU + {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.Release|Win32.Build.0 = Release|Any CPU + {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.Release|x64.ActiveCfg = Release|Any CPU + {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.Release|x64.Build.0 = Release|Any CPU + {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU + {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU + {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU + {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU + {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU + {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.ReleaseNoNet|Win32.Build.0 = Release|Any CPU + {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU + {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.ReleaseNoNet|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Kp2aAutofillParser/AutofillParser.cs b/src/Kp2aAutofillParser/AutofillParser.cs new file mode 100644 index 00000000..489f81b4 --- /dev/null +++ b/src/Kp2aAutofillParser/AutofillParser.cs @@ -0,0 +1,983 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml; + +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; + } + } + class AutofillHintsHelper + { + const string AutofillHint2faAppOtp = "2faAppOTPCode"; + const string AutofillHintBirthDateDay = "birthDateDay"; + const string AutofillHintBirthDateFull = "birthDateFull"; + const string AutofillHintBirthDateMonth = "birthDateMonth"; + const string AutofillHintBirthDateYear = "birthDateYear"; + const string AutofillHintCreditCardExpirationDate = "creditCardExpirationDate"; + const string AutofillHintCreditCardExpirationDay = "creditCardExpirationDay"; + const string AutofillHintCreditCardExpirationMonth = "creditCardExpirationMonth"; + const string AutofillHintCreditCardExpirationYear = "creditCardExpirationYear"; + const string AutofillHintCreditCardNumber = "creditCardNumber"; + const string AutofillHintCreditCardSecurityCode = "creditCardSecurityCode"; + const string AutofillHintEmailAddress = "emailAddress"; + const string AutofillHintEmailOtp = "emailOTPCode"; + const string AutofillHintGender = "gender"; + const string AutofillHintName = "name"; + const string AutofillHintNewPassword = "newPassword"; + const string AutofillHintNewUsername = "newUsername"; + const string AutofillHintNotApplicable = "notApplicable"; + const string AutofillHintPassword = "password"; + const string AutofillHintPersonName = "personName"; + const string AutofillHintPersonNameFAMILY = "personFamilyName"; + const string AutofillHintPersonNameGIVEN = "personGivenName"; + const string AutofillHintPersonNameMIDDLE = "personMiddleName"; + const string AutofillHintPersonNameMIDDLE_INITIAL = "personMiddleInitial"; + const string AutofillHintPersonNamePREFIX = "personNamePrefix"; + const string AutofillHintPersonNameSUFFIX = "personNameSuffix"; + const string AutofillHintPhone = "phone"; + const string AutofillHintPhoneContryCode = "phoneCountryCode"; + const string AutofillHintPostalAddressAPT_NUMBER = "aptNumber"; + const string AutofillHintPostalAddressCOUNTRY = "addressCountry"; + const string AutofillHintPostalAddressDEPENDENT_LOCALITY = "dependentLocality"; + const string AutofillHintPostalAddressEXTENDED_ADDRESS = "extendedAddress"; + const string AutofillHintPostalAddressEXTENDED_POSTAL_CODE = "extendedPostalCode"; + const string AutofillHintPostalAddressLOCALITY = "addressLocality"; + const string AutofillHintPostalAddressREGION = "addressRegion"; + const string AutofillHintPostalAddressSTREET_ADDRESS = "streetAddress"; + const string AutofillHintPostalCode = "postalCode"; + const string AutofillHintPromoCode = "promoCode"; + const string AutofillHintSMS_OTP = "smsOTPCode"; + const string AutofillHintUPI_VPA = "upiVirtualPaymentAddress"; + const string AutofillHintUsername = "username"; + const string AutofillHintWifiPassword = "wifiPassword"; + const string AutofillHintPhoneNational = "phoneNational"; + const string AutofillHintPhoneNumber = "phoneNumber"; + const string AutofillHintPhoneNumberDevice = "phoneNumberDevice"; + 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); + + } + 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 abstract void FillFilledAutofillValue(FilledAutofillField filledField); + + + } + + 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; + + public string PackageId { get; set; } + + 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. + /// + AutofillTargetId Parse(bool forFill, bool isManualRequest, AutofillView autofillView) + { + AutofillTargetId result = new AutofillTargetId(); + + + _editTextsWithoutHint.Clear(); + + _log.Log("parsing autofillStructure..."); + + //TODO remove from production + _log.Log("will log the autofillStructure..."); + string debugInfo = JsonConvert.SerializeObject(autofillView, Formatting.Indented); + _log.Log("will log the autofillStructure... size is " + debugInfo.Length); + _log.Log("This is the autofillStructure: \n\n " + debugInfo); + + foreach (var viewNode in autofillView.InputFields) + { + string[] viewHints = viewNode.AutofillHints; + if (viewHints != null && viewHints.Length == 1 && viewHints.First() == "off" && viewNode.IsFocused && + isManualRequest) + viewHints[0] = "on"; + /*if (viewHints != null && viewHints.Any()) + { + CommonUtil.logd("viewHints=" + viewHints); + CommonUtil.logd("class=" + viewNode.ClassName); + CommonUtil.logd("tag=" + (viewNode?.HtmlInfo?.Tag ?? "(null)")); + }*/ + + if (IsPassword(viewNode) || HasPasswordHint(viewNode) || (HasUsernameHint(viewNode))) + { + if (forFill) + { + AutofillFields.Add(new AutofillFieldMetadata(viewNode.ViewNode)); + } + else + { + FilledAutofillField filledAutofillField = new FilledAutofillField(viewNode.ViewNode); + ClientFormData.Add(filledAutofillField); + } + } + else if (viewNode.ClassName == "android.widget.EditText" + || viewNode.ClassName == "android.widget.AutoCompleteTextView" + || viewNode.HtmlInfoTag == "input" + || ((viewHints?.Length ?? 0) > 0)) + { + _log.Log("Found something that looks fillable " + viewNode.ClassName); + + } + + if (viewHints != null && viewHints.Length > 0 && viewHints.First() != "on" /*if hint is "on", treat as if there is no hint*/) + { + } + else + { + + if (viewNode.ClassName == "android.widget.EditText" + || viewNode.ClassName == "android.widget.AutoCompleteTextView" + || viewNode.HtmlInfoTag == "input") + { + _editTextsWithoutHint.Add(viewNode); + } + + } + } + + List passwordFields = new List(); + List usernameFields = new List(); + if (AutofillFields.Empty) + { + passwordFields = _editTextsWithoutHint.Where(IsPassword).ToList(); + if (!passwordFields.Any()) + { + passwordFields = _editTextsWithoutHint.Where(HasPasswordHint).ToList(); + } + + usernameFields = _editTextsWithoutHint.Where(HasUsernameHint).ToList(); + + if (usernameFields.Any() == false) + { + + foreach (var passwordField in passwordFields) + { + var usernameField = _editTextsWithoutHint + .TakeWhile(f => f != passwordField).LastOrDefault(); + if (usernameField != null) + { + usernameFields.Add(usernameField); + } + } + } + if (usernameFields.Any() == false) + { + //for some pages with two-step login, we don't see a password field and don't display the autofill for non-manual requests. But if the user forces autofill, + //let's assume it is a username field: + if (isManualRequest && !passwordFields.Any() && _editTextsWithoutHint.Count == 1) + { + usernameFields.Add(_editTextsWithoutHint.First()); + } + } + + + } + + //force focused fields to be included in autofill fields when request was triggered manually. This allows to fill fields which are "off" or don't have a hint (in case there are hints) + if (isManualRequest) + { + foreach (var editText in _editTextsWithoutHint) + { + if (editText.IsFocused) + { + if (IsPassword(editText) || HasPasswordHint(editText)) + passwordFields.Add(editText); + else + usernameFields.Add(editText); + break; + } + + } + } + + if (forFill) + { + foreach (var uf in usernameFields) + AutofillFields.Add(new AutofillFieldMetadata(uf.ViewNode, new[] { View.AutofillHintUsername })); + foreach (var pf in passwordFields) + AutofillFields.Add(new AutofillFieldMetadata(pf.ViewNode, new[] { View.AutofillHintPassword })); + + } + else + { + foreach (var uf in usernameFields) + ClientFormData.Add(new FilledAutofillField(uf.ViewNode, new[] { View.AutofillHintUsername })); + foreach (var pf in passwordFields) + ClientFormData.Add(new FilledAutofillField(pf.ViewNode, new[] { View.AutofillHintPassword })); + } + + + result.WebDomain = autofillView.WebDomain; + result.PackageName = Structure.ActivityComponent.PackageName; + if (!string.IsNullOrEmpty(autofillView.WebDomain) && !PreferenceManager.GetDefaultSharedPreferences(mContext).GetBoolean(mContext.GetString(Resource.String.NoDalVerification_key), false)) + { + result.IncompatiblePackageAndDomain = !kp2aDigitalAssetLinksDataSource.IsTrustedLink(autofillView.WebDomain, result.PackageName); + if (result.IncompatiblePackageAndDomain) + { + CommonUtil.loge($"DAL verification failed for {result.PackageName}/{result.WebDomain}"); + } + } + else + { + result.IncompatiblePackageAndDomain = false; + } + return result; + } + private static readonly HashSet _passwordHints = new HashSet { "password", "passwort", "passwordAuto", "pswd" }; + private static bool HasPasswordHint(InputField f) + { + return ContainsAny(f.IdEntry, _passwordHints) || + ContainsAny(f.Hint, _passwordHints); + } + + private static readonly HashSet _usernameHints = new HashSet { "email", "e-mail", "username" }; + + private static bool HasUsernameHint(InputField f) + { + return ContainsAny(f.IdEntry, _usernameHints) || + ContainsAny(f.Hint, _usernameHints); + } + + private static bool ContainsAny(string value, IEnumerable terms) + { + if (string.IsNullOrWhiteSpace(value)) + { + return false; + } + var lowerValue = value.ToLowerInvariant(); + return terms.Any(t => lowerValue.Contains(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.HtmlInfoTypeAttribute == "password") + ); + } + + AssistStructure Structure; + private List _editTextsWithoutHint = new List(); + + + + } +} diff --git a/src/Kp2aAutofillParser/Kp2aAutofillParser.csproj b/src/Kp2aAutofillParser/Kp2aAutofillParser.csproj new file mode 100644 index 00000000..375762cd --- /dev/null +++ b/src/Kp2aAutofillParser/Kp2aAutofillParser.csproj @@ -0,0 +1,12 @@ + + + + netstandard2.1 + enable + + + + + + + diff --git a/src/keepass2android/keepass2android-app.csproj b/src/keepass2android/keepass2android-app.csproj index 4e0ec5a3..522e0e33 100644 --- a/src/keepass2android/keepass2android-app.csproj +++ b/src/keepass2android/keepass2android-app.csproj @@ -1944,6 +1944,10 @@ {545b4a6b-8bba-4fbe-92fc-4ac060122a54} KeePassLib2Android + + {39b12571-bafe-4d3a-aee2-4d74f14dfd96} + Kp2aAutofillParser + {53a9cb7f-6553-4bc0-b56b-9410bb2e59aa} Kp2aBusinessLogic diff --git a/src/keepass2android/services/AutofillBase/AutofillHelper.cs b/src/keepass2android/services/AutofillBase/AutofillHelper.cs index 70581811..fbc865b0 100644 --- a/src/keepass2android/services/AutofillBase/AutofillHelper.cs +++ b/src/keepass2android/services/AutofillBase/AutofillHelper.cs @@ -7,11 +7,12 @@ using Android.Runtime; using Android.Service.Autofill; using Android.Util; using Android.Views; +using Android.Views.Autofill; using Android.Widget; using Android.Widget.Inline; using AndroidX.AutoFill.Inline; using AndroidX.AutoFill.Inline.V1; -using FilledAutofillFieldCollection = keepass2android.services.AutofillBase.model.FilledAutofillFieldCollection; +using Kp2aAutofillParser; namespace keepass2android.services.AutofillBase { @@ -93,13 +94,9 @@ namespace keepass2android.services.AutofillBase /// Wraps autofill data in a LoginCredential Dataset object which can then be sent back to the /// client View. /// - /// The dataset. - /// Context. - /// Autofill fields. - /// Filled autofill field collection. public static Dataset NewDataset(Context context, AutofillFieldMetadataCollection autofillFields, - FilledAutofillFieldCollection filledAutofillFieldCollection, + FilledAutofillFieldCollection filledAutofillFieldCollection, IAutofillIntentBuilder intentBuilder, Android.Widget.Inline.InlinePresentationSpec inlinePresentationSpec) { @@ -108,21 +105,115 @@ namespace keepass2android.services.AutofillBase var datasetBuilder = new Dataset.Builder(NewRemoteViews(context.PackageName, datasetName, intentBuilder.AppIconResource)); datasetBuilder.SetId(datasetName); - var setValueAtLeastOnce = filledAutofillFieldCollection.ApplyToFields(autofillFields, datasetBuilder); + var setValueAtLeastOnce = ApplyToFields(filledAutofillFieldCollection, autofillFields, datasetBuilder); AddInlinePresentation(context, inlinePresentationSpec, datasetName, datasetBuilder, intentBuilder.AppIconResource, null); if (setValueAtLeastOnce) { return datasetBuilder.Build(); } - else + /*else { Kp2aLog.Log("Failed to set at least one value. #fields=" + autofillFields.GetAutofillIds().Length + " " + autofillFields.FocusedAutofillCanonicalHints); - } + }*/ return null; } + /// + /// Populates a Dataset.Builder with appropriate values for each AutofillId + /// in a AutofillFieldMetadataCollection. + /// + /// In other words, it constructs an autofill Dataset.Builder + /// by applying saved values (from this FilledAutofillFieldCollection) + /// to Views specified in a AutofillFieldMetadataCollection, which represents the current + /// page the user is on. + /// + /// true, if to fields was applyed, false otherwise. + /// + /// Autofill field metadata collection. + /// Dataset builder. + public static bool ApplyToFields(FilledAutofillFieldCollection filledAutofillFieldCollection, + AutofillFieldMetadataCollection autofillFieldMetadataCollection, Dataset.Builder datasetBuilder) + { + bool setValueAtLeastOnce = false; + + foreach (string hint in autofillFieldMetadataCollection.AllAutofillCanonicalHints) + { + foreach (AutofillFieldMetadata autofillFieldMetadata in autofillFieldMetadataCollection.GetFieldsForHint(hint)) + { + FilledAutofillField filledAutofillField; + if (!filledAutofillFieldCollection.HintMap.TryGetValue(hint, out filledAutofillField) || (filledAutofillField == null)) + { + continue; + } + + var autofillId = autofillFieldMetadata.AutofillId; + var autofillType = autofillFieldMetadata.AutofillType; + switch (autofillType) + { + case AutofillType.List: + var listValue = autofillFieldMetadata.GetAutofillOptionIndex(filledAutofillField.TextValue); + if (listValue != -1) + { + datasetBuilder.SetValue(autofillId, AutofillValue.ForList(listValue)); + setValueAtLeastOnce = true; + } + break; + case AutofillType.Date: + var dateValue = filledAutofillField.DateValue; + datasetBuilder.SetValue(autofillId, AutofillValue.ForDate((long)dateValue)); + setValueAtLeastOnce = true; + break; + case AutofillType.Text: + var textValue = filledAutofillField.TextValue; + if (textValue != null) + { + datasetBuilder.SetValue(autofillId, AutofillValue.ForText(textValue)); + setValueAtLeastOnce = true; + } + break; + case AutofillType.Toggle: + var toggleValue = filledAutofillField.ToggleValue; + if (toggleValue != null) + { + datasetBuilder.SetValue(autofillId, AutofillValue.ForToggle(toggleValue.Value)); + setValueAtLeastOnce = true; + } + break; + default: + Log.Warn(CommonUtil.Tag, "Invalid autofill type - " + autofillType); + break; + } + } + } + /* + if (!setValueAtLeastOnce) + { + Kp2aLog.Log("No value set. Hint keys : " + string.Join(",", HintMap.Keys)); + foreach (string hint in autofillFieldMetadataCollection.AllAutofillCanonicalHints) + { + Kp2aLog.Log("No value set. Hint = " + hint); + foreach (AutofillFieldMetadata autofillFieldMetadata in autofillFieldMetadataCollection + .GetFieldsForHint(hint)) + { + Kp2aLog.Log("No value set. fieldForHint = " + autofillFieldMetadata.AutofillId.ToString()); + FilledAutofillField filledAutofillField; + if (!HintMap.TryGetValue(hint, out filledAutofillField) || (filledAutofillField == null)) + { + Kp2aLog.Log("No value set. Hint map does not contain value, " + + (filledAutofillField == null)); + continue; + } + + Kp2aLog.Log("autofill type=" + autofillFieldMetadata.AutofillType); + } + } + }*/ + + return setValueAtLeastOnce; + } + public static void AddInlinePresentation(Context context, InlinePresentationSpec inlinePresentationSpec, string datasetName, Dataset.Builder datasetBuilder, int iconId, PendingIntent pendingIntent) { diff --git a/src/keepass2android/services/AutofillBase/AutofillHintsHelper.cs b/src/keepass2android/services/AutofillBase/AutofillHintsHelper.cs index 27a6fa29..7bcd9a2f 100644 --- a/src/keepass2android/services/AutofillBase/AutofillHintsHelper.cs +++ b/src/keepass2android/services/AutofillBase/AutofillHintsHelper.cs @@ -14,256 +14,5 @@ using keepass2android.services.AutofillBase.model; namespace keepass2android.services.AutofillBase { - class AutofillHintsHelper - { - private static readonly HashSet _allSupportedHints = new HashSet(StringComparer.OrdinalIgnoreCase) - { - View.AutofillHintCreditCardExpirationDate, - View.AutofillHintCreditCardExpirationDay, - View.AutofillHintCreditCardExpirationMonth, - View.AutofillHintCreditCardExpirationYear, - View.AutofillHintCreditCardNumber, - View.AutofillHintCreditCardSecurityCode, - View.AutofillHintEmailAddress, - View.AutofillHintPhone, - View.AutofillHintName, - View.AutofillHintPassword, - View.AutofillHintPostalAddress, - View.AutofillHintPostalCode, - View.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) - { - View.AutofillHintEmailAddress, - View.AutofillHintPhone, - View.AutofillHintName, - View.AutofillHintPassword, - View.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) - { - View.AutofillHintPostalAddress, - View.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) - { - View.AutofillHintCreditCardExpirationDate, - View.AutofillHintCreditCardExpirationDay, - View.AutofillHintCreditCardExpirationMonth, - View.AutofillHintCreditCardExpirationYear, - View.AutofillHintCreditCardNumber, - View.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, View.AutofillHintEmailAddress}, - {W3cHints.USERNAME, View.AutofillHintUsername}, - {W3cHints.CURRENT_PASSWORD, View.AutofillHintPassword}, - {W3cHints.NEW_PASSWORD, View.AutofillHintPassword}, - {W3cHints.CC_EXPIRATION_MONTH, View.AutofillHintCreditCardExpirationMonth }, - {W3cHints.CC_EXPIRATION_YEAR, View.AutofillHintCreditCardExpirationYear }, - {W3cHints.CC_EXPIRATION, View.AutofillHintCreditCardExpirationDate }, - {W3cHints.CC_NUMBER, View.AutofillHintCreditCardNumber }, - {W3cHints.CC_CSC, View.AutofillHintCreditCardSecurityCode }, - {W3cHints.POSTAL_CODE, View.AutofillHintPostalCode }, - - - }; - - public static bool IsSupportedHint(string hint) - { - return _allSupportedHints.Contains(hint); - } - - - public static string[] FilterForSupportedHints(string[] hints) - { - var filteredHints = new string[hints.Length]; - int i = 0; - foreach (var hint in hints) - { - if (IsSupportedHint(hint)) - { - filteredHints[i++] = hint; - } - else - { - CommonUtil.logd("Invalid autofill hint: " + 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) - { - 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) - { - - //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; - } - } + } \ No newline at end of file diff --git a/src/keepass2android/services/AutofillBase/AutofillServiceBase.cs b/src/keepass2android/services/AutofillBase/AutofillServiceBase.cs index 1df5c66c..874725bd 100644 --- a/src/keepass2android/services/AutofillBase/AutofillServiceBase.cs +++ b/src/keepass2android/services/AutofillBase/AutofillServiceBase.cs @@ -137,7 +137,7 @@ namespace keepass2android.services.AutofillBase return; } - AutofillFieldMetadataCollection autofillFields = parser.AutofillFields; + InlineSuggestionsRequest inlineSuggestionsRequest = null; IList inlinePresentationSpecs = null; if (((int) Build.VERSION.SdkInt >= 30) @@ -149,7 +149,7 @@ namespace keepass2android.services.AutofillBase } - var autofillIds = autofillFields.GetAutofillIds(); + var autofillIds = parser.AutofillFields.GetAutofillIds(); if (autofillIds.Length != 0 && CanAutofill(query, isManual)) { var responseBuilder = new FillResponse.Builder(); diff --git a/src/keepass2android/services/AutofillBase/Kp2aDigitalAssetLinksDataSource.cs b/src/keepass2android/services/AutofillBase/Kp2aDigitalAssetLinksDataSource.cs index c7a5d330..31c01157 100644 --- a/src/keepass2android/services/AutofillBase/Kp2aDigitalAssetLinksDataSource.cs +++ b/src/keepass2android/services/AutofillBase/Kp2aDigitalAssetLinksDataSource.cs @@ -2,11 +2,13 @@ using System.Linq; using Android.Content; using Android.Preferences; +using Kp2aAutofillParser; namespace keepass2android.services.AutofillBase { + - internal class Kp2aDigitalAssetLinksDataSource + internal class Kp2aDigitalAssetLinksDataSource : IKp2aDigitalAssetLinksDataSource { private const string Autofilltrustedapps = "AutoFillTrustedApps"; diff --git a/src/keepass2android/services/AutofillBase/StructureParser.cs b/src/keepass2android/services/AutofillBase/StructureParser.cs index 29dd7416..820e9241 100644 --- a/src/keepass2android/services/AutofillBase/StructureParser.cs +++ b/src/keepass2android/services/AutofillBase/StructureParser.cs @@ -11,10 +11,138 @@ using Android.Views.Autofill; using Android.Views.InputMethods; using DomainNameParser; using keepass2android.services.AutofillBase.model; +using Kp2aAutofillParser; +using Newtonsoft.Json; +using static Android.App.Assist.AssistStructure; +using static Java.IO.ObjectOutputStream; using FilledAutofillFieldCollection = keepass2android.services.AutofillBase.model.FilledAutofillFieldCollection; +using InputTypes = Kp2aAutofillParser.InputTypes; namespace keepass2android.services.AutofillBase { + public class ViewNodeInputField : Kp2aAutofillParser.InputField + { + public ViewNodeInputField(AssistStructure.ViewNode viewNode) + { + ViewNode = viewNode; + IdEntry = viewNode.IdEntry; + Hint = viewNode.Hint; + ClassName = viewNode.ClassName; + AutofillHints = viewNode.GetAutofillHints(); + IsFocused = viewNode.IsFocused; + InputType = (Kp2aAutofillParser.InputTypes) ((int)viewNode.InputType); + HtmlInfoTag = viewNode.HtmlInfo?.Tag; + HtmlInfoTypeAttribute = viewNode.HtmlInfo?.Attributes?.FirstOrDefault(p => p.First?.ToString() == "type")?.Second?.ToString(); + + } + [JsonIgnore] + public AssistStructure.ViewNode ViewNode { get; set; } + + public override void FillFilledAutofillValue(FilledAutofillField filledField) + { + AutofillValue autofillValue = ViewNode.AutofillValue; + if (autofillValue != null) + { + if (autofillValue.IsList) + { + string[] autofillOptions = ViewNode.GetAutofillOptions(); + int index = autofillValue.ListValue; + if (autofillOptions != null && autofillOptions.Length > 0) + { + filledField.TextValue = autofillOptions[index]; + } + } + else if (autofillValue.IsDate) + { + filledField.DateValue = autofillValue.DateValue; + } + else if (autofillValue.IsText) + { + filledField.TextValue = autofillValue.TextValue; + } + } + } + } + + /// + /// Converts an AssistStructure into a list of InputFields + /// + class AutofillViewFromAssistStructureFinder + { + private readonly Context _context; + private readonly AssistStructure _structure; + private PublicSuffixRuleCache domainSuffixParserCache; + + public AutofillViewFromAssistStructureFinder(Context context, AssistStructure structure) + { + _context = context; + _structure = structure; + domainSuffixParserCache = new PublicSuffixRuleCache(context); + } + + public AutofillView GetAutofillView(bool isManualRequest) + { + AutofillView autofillView = new AutofillView(); + + + int nodeCount = _structure.WindowNodeCount; + for (int i = 0; i < nodeCount; i++) + { + var node = _structure.GetWindowNodeAt(i); + + var view = node.RootViewNode; + ParseRecursive(autofillView, view, isManualRequest); + } + + return autofillView; + + } + + + void ParseRecursive(AutofillView autofillView, AssistStructure.ViewNode viewNode, bool isManualRequest) + { + String webDomain = viewNode.WebDomain; + if ((autofillView.PackageId == null) && (!string.IsNullOrWhiteSpace(viewNode.IdPackage)) && + (viewNode.IdPackage != "android")) + { + autofillView.PackageId = viewNode.IdPackage; + } + + DomainName outDomain; + if (DomainName.TryParse(webDomain, domainSuffixParserCache, out outDomain)) + { + webDomain = outDomain.RawDomainName; + } + + if (webDomain != null) + { + if (!string.IsNullOrEmpty(autofillView.WebDomain)) + { + if (webDomain != autofillView.WebDomain) + { + throw new Java.Lang.SecurityException($"Found multiple web domains: valid= {autofillView.WebDomain}, child={webDomain}"); + } + } + else + { + autofillView.WebDomain = webDomain; + } + } + + autofillView.InputFields.Add(new ViewNodeInputField(viewNode)); + Kp2aLog.Log($"Now we have {autofillView.InputFields.Count} fields, just added {autofillView.InputFields.Last().IdEntry} of type {autofillView.InputFields.Last().ClassName}"); + + var childrenSize = viewNode.ChildCount; + if (childrenSize > 0) + { + for (int i = 0; i < childrenSize; i++) + { + ParseRecursive(autofillView, viewNode.GetChildAt(i), isManualRequest); + } + } + } + } + /// /// Parser for an AssistStructure object. This is invoked when the Autofill Service receives an /// AssistStructure from the client Activity, representing its View hierarchy. In this sample, it @@ -24,10 +152,7 @@ namespace keepass2android.services.AutofillBase { public Context mContext { get; } public AutofillFieldMetadataCollection AutofillFields { get; set; } - AssistStructure Structure; - private List _editTextsWithoutHint = new List(); - private PublicSuffixRuleCache domainSuffixParserCache; - public FilledAutofillFieldCollection ClientFormData { get; set; } + public FilledAutofillFieldCollection ClientFormData { get; set; } public string PackageId { get; set; } @@ -37,7 +162,7 @@ namespace keepass2android.services.AutofillBase mContext = context; Structure = structure; AutofillFields = new AutofillFieldMetadataCollection(); - domainSuffixParserCache = new PublicSuffixRuleCache(context); + } public class AutofillTargetId @@ -87,23 +212,73 @@ namespace keepass2android.services.AutofillBase { AutofillTargetId result = new AutofillTargetId(); CommonUtil.logd("Parsing structure for " + Structure.ActivityComponent); - var nodes = Structure.WindowNodeCount; + ClientFormData = new FilledAutofillFieldCollection(); - String webDomain = null; + _editTextsWithoutHint.Clear(); - for (int i = 0; i < nodes; i++) - { - var node = Structure.GetWindowNodeAt(i); + Kp2aLog.Log("parsing autofillStructure..."); - var view = node.RootViewNode; - ParseLocked(forFill, isManualRequest, view, ref webDomain); - } + AutofillView autofillView = new AutofillViewFromAssistStructureFinder(mContext, Structure).GetAutofillView(isManualRequest); + //TODO remove from production + Kp2aLog.Log("will log the autofillStructure..."); + string debugInfo = JsonConvert.SerializeObject(autofillView, Formatting.Indented); + Kp2aLog.Log("will log the autofillStructure... size is " + debugInfo.Length); + Kp2aLog.Log("This is the autofillStructure: \n\n " + debugInfo); + foreach (var viewNode in autofillView.InputFields) + { + string[] viewHints = viewNode.AutofillHints; + if (viewHints != null && viewHints.Length == 1 && viewHints.First() == "off" && viewNode.IsFocused && + isManualRequest) + viewHints[0] = "on"; + /*if (viewHints != null && viewHints.Any()) + { + CommonUtil.logd("viewHints=" + viewHints); + CommonUtil.logd("class=" + viewNode.ClassName); + CommonUtil.logd("tag=" + (viewNode?.HtmlInfo?.Tag ?? "(null)")); + }*/ - List passwordFields = new List(); - List usernameFields = new List(); + if (IsPassword(viewNode) || HasPasswordHint(viewNode) || (HasUsernameHint(viewNode))) + { + if (forFill) + { + AutofillFields.Add(new AutofillFieldMetadata(viewNode.ViewNode)); + } + else + { + FilledAutofillField filledAutofillField = new FilledAutofillField(viewNode.ViewNode); + ClientFormData.Add(filledAutofillField); + } + } + else if (viewNode.ClassName == "android.widget.EditText" + || viewNode.ClassName == "android.widget.AutoCompleteTextView" + || viewNode.HtmlInfoTag == "input" + || ((viewHints?.Length ?? 0) > 0)) + { + Kp2aLog.Log("Found something that looks fillable " + viewNode.ClassName); + + } + + if (viewHints != null && viewHints.Length > 0 && viewHints.First() != "on" /*if hint is "on", treat as if there is no hint*/) + { + } + else + { + + if (viewNode.ClassName == "android.widget.EditText" + || viewNode.ClassName == "android.widget.AutoCompleteTextView" + || viewNode.HtmlInfoTag == "input") + { + _editTextsWithoutHint.Add(viewNode); + } + + } + } + + List passwordFields = new List(); + List usernameFields = new List(); if (AutofillFields.Empty) { passwordFields = _editTextsWithoutHint.Where(IsPassword).ToList(); @@ -120,7 +295,7 @@ namespace keepass2android.services.AutofillBase foreach (var passwordField in passwordFields) { var usernameField = _editTextsWithoutHint - .TakeWhile(f => f.AutofillId != passwordField.AutofillId).LastOrDefault(); + .TakeWhile(f => f != passwordField).LastOrDefault(); if (usernameField != null) { usernameFields.Add(usernameField); @@ -143,7 +318,7 @@ namespace keepass2android.services.AutofillBase //force focused fields to be included in autofill fields when request was triggered manually. This allows to fill fields which are "off" or don't have a hint (in case there are hints) if (isManualRequest) { - foreach (AssistStructure.ViewNode editText in _editTextsWithoutHint) + foreach (var editText in _editTextsWithoutHint) { if (editText.IsFocused) { @@ -160,25 +335,25 @@ namespace keepass2android.services.AutofillBase if (forFill) { foreach (var uf in usernameFields) - AutofillFields.Add(new AutofillFieldMetadata(uf, new[] { View.AutofillHintUsername })); + AutofillFields.Add(new AutofillFieldMetadata(uf.ViewNode, new[] { View.AutofillHintUsername })); foreach (var pf in passwordFields) - AutofillFields.Add(new AutofillFieldMetadata(pf, new[] { View.AutofillHintPassword })); + AutofillFields.Add(new AutofillFieldMetadata(pf.ViewNode, new[] { View.AutofillHintPassword })); } else { foreach (var uf in usernameFields) - ClientFormData.Add(new FilledAutofillField(uf, new[] { View.AutofillHintUsername })); + ClientFormData.Add(new FilledAutofillField(uf.ViewNode, new[] { View.AutofillHintUsername })); foreach (var pf in passwordFields) - ClientFormData.Add(new FilledAutofillField(pf, new[] { View.AutofillHintPassword })); + ClientFormData.Add(new FilledAutofillField(pf.ViewNode, new[] { View.AutofillHintPassword })); } - result.WebDomain = webDomain; + result.WebDomain = autofillView.WebDomain; result.PackageName = Structure.ActivityComponent.PackageName; - if (!string.IsNullOrEmpty(webDomain) && !PreferenceManager.GetDefaultSharedPreferences(mContext).GetBoolean(mContext.GetString(Resource.String.NoDalVerification_key), false)) + if (!string.IsNullOrEmpty(autofillView.WebDomain) && !PreferenceManager.GetDefaultSharedPreferences(mContext).GetBoolean(mContext.GetString(Resource.String.NoDalVerification_key), false)) { - result.IncompatiblePackageAndDomain = !kp2aDigitalAssetLinksDataSource.IsTrustedLink(webDomain, result.PackageName); + result.IncompatiblePackageAndDomain = !kp2aDigitalAssetLinksDataSource.IsTrustedLink(autofillView.WebDomain, result.PackageName); if (result.IncompatiblePackageAndDomain) { CommonUtil.loge($"DAL verification failed for {result.PackageName}/{result.WebDomain}"); @@ -190,17 +365,17 @@ namespace keepass2android.services.AutofillBase } return result; } - private static readonly HashSet _passwordHints = new HashSet { "password","passwort" }; - private static bool HasPasswordHint(AssistStructure.ViewNode f) + private static readonly HashSet _passwordHints = new HashSet { "password","passwort", "passwordAuto", "pswd" }; + private static bool HasPasswordHint(InputField f) { return ContainsAny(f.IdEntry, _passwordHints) || ContainsAny(f.Hint, _passwordHints); } private static readonly HashSet _usernameHints = new HashSet { "email","e-mail","username" }; - private Kp2aDigitalAssetLinksDataSource kp2aDigitalAssetLinksDataSource; + private readonly Kp2aDigitalAssetLinksDataSource kp2aDigitalAssetLinksDataSource; - private static bool HasUsernameHint(AssistStructure.ViewNode f) + private static bool HasUsernameHint(InputField f) { return ContainsAny(f.IdEntry, _usernameHints) || ContainsAny(f.Hint, _usernameHints); @@ -233,7 +408,7 @@ namespace keepass2android.services.AutofillBase } - private static bool IsPassword(AssistStructure.ViewNode f) + private static bool IsPassword(InputField f) { InputTypes inputType = f.InputType; @@ -249,86 +424,14 @@ namespace keepass2android.services.AutofillBase || IsInputTypeVariation(inputType, InputTypes.TextVariationWebPassword) ) ) - || (f.HtmlInfo?.Attributes.Any(p => p.First.ToString() == "type" && p.Second.ToString() == "password") ?? false) + || (f.HtmlInfoTypeAttribute == "password") ); } - - - void ParseLocked(bool forFill, bool isManualRequest, AssistStructure.ViewNode viewNode, ref string validWebdomain) - { - String webDomain = viewNode.WebDomain; - if ((PackageId == null) && (!string.IsNullOrWhiteSpace(viewNode.IdPackage)) && - (viewNode.IdPackage != "android")) - { - PackageId = viewNode.IdPackage; - } - - DomainName outDomain; - if (DomainName.TryParse(webDomain, domainSuffixParserCache, out outDomain)) - { - webDomain = outDomain.RawDomainName; - } - - if (webDomain != null) - { - if (!string.IsNullOrEmpty(validWebdomain)) - { - if (webDomain != validWebdomain) - { - throw new Java.Lang.SecurityException($"Found multiple web domains: valid= {validWebdomain}, child={webDomain}"); - } - } - else - { - validWebdomain = webDomain; - } - } - - string[] viewHints = viewNode.GetAutofillHints(); - if (viewHints != null && viewHints.Length == 1 && viewHints.First() == "off" && viewNode.IsFocused && - isManualRequest) - viewHints[0] = "on"; - /*if (viewHints != null && viewHints.Any()) - { - CommonUtil.logd("viewHints=" + viewHints); - CommonUtil.logd("class=" + viewNode.ClassName); - CommonUtil.logd("tag=" + (viewNode?.HtmlInfo?.Tag ?? "(null)")); - }*/ - - - if (viewHints != null && viewHints.Length > 0 && viewHints.First() != "on" /*if hint is "on", treat as if there is no hint*/) - { - if (forFill) - { - AutofillFields.Add(new AutofillFieldMetadata(viewNode)); - } - else - { - FilledAutofillField filledAutofillField = new FilledAutofillField(viewNode); - ClientFormData.Add(filledAutofillField); - } - } - else - { - - if (viewNode.ClassName == "android.widget.EditText" - || viewNode.ClassName == "android.widget.AutoCompleteTextView" - || viewNode?.HtmlInfo?.Tag == "input") - { - _editTextsWithoutHint.Add(viewNode); - } - - } - var childrenSize = viewNode.ChildCount; - if (childrenSize > 0) - { - for (int i = 0; i < childrenSize; i++) - { - ParseLocked(forFill, isManualRequest, viewNode.GetChildAt(i), ref validWebdomain); - } - } - } + AssistStructure Structure; + private List _editTextsWithoutHint = new List(); + + } } diff --git a/src/keepass2android/services/AutofillBase/model/FilledAutofillField.cs b/src/keepass2android/services/AutofillBase/model/FilledAutofillField.cs index 119b2437..5f36b01f 100644 --- a/src/keepass2android/services/AutofillBase/model/FilledAutofillField.cs +++ b/src/keepass2android/services/AutofillBase/model/FilledAutofillField.cs @@ -2,154 +2,9 @@ using Android.App.Assist; using Android.Views.Autofill; using KeePassLib.Utility; +using Kp2aAutofillParser; namespace keepass2android.services.AutofillBase.model { - public class FilledAutofillField - { - 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(AssistStructure.ViewNode viewNode) - : this(viewNode, viewNode.GetAutofillHints()) - { - - } - - public FilledAutofillField(AssistStructure.ViewNode viewNode, 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]; - CommonUtil.logd($"Hint is a W3C section prefix; using {hint} instead"); - if (i < rawHints.Length - 1) - { - nextHint = rawHints[i + 1]; - } - } - if (W3cHints.isW3cTypePrefix(hint) && nextHint != null && W3cHints.isW3cTypeHint(nextHint)) - { - hint = nextHint; - i++; - CommonUtil.logd($"Hint is a W3C type prefix; using {hint} instead"); - } - if (W3cHints.isW3cAddressType(hint) && nextHint != null) - { - hint = nextHint; - i++; - CommonUtil.logd($"Hint is a W3C address prefix; using {hint} instead"); - } - - // Then check if the "actual" hint is supported. - if (AutofillHintsHelper.IsSupportedHint(hint)) - { - hintList.Add(hint); - } - else - { - CommonUtil.loge($"Invalid hint: {rawHints[i]}"); - } - } - AutofillHints = AutofillHintsHelper.ConvertToCanonicalHints(hintList.ToArray()).ToArray(); - - AutofillValue autofillValue = viewNode.AutofillValue; - if (autofillValue != null) - { - if (autofillValue.IsList) - { - string[] autofillOptions = viewNode.GetAutofillOptions(); - int index = autofillValue.ListValue; - if (autofillOptions != null && autofillOptions.Length > 0) - { - TextValue = autofillOptions[index]; - } - } - else if (autofillValue.IsDate) - { - DateValue = autofillValue.DateValue; - } - else if (autofillValue.IsText) - { - TextValue = autofillValue.TextValue; - } - } - } - - 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; - } - } - } + } diff --git a/src/keepass2android/services/AutofillBase/model/FilledAutofillFieldCollection.cs b/src/keepass2android/services/AutofillBase/model/FilledAutofillFieldCollection.cs index 44f0cb1f..4fc5738a 100644 --- a/src/keepass2android/services/AutofillBase/model/FilledAutofillFieldCollection.cs +++ b/src/keepass2android/services/AutofillBase/model/FilledAutofillFieldCollection.cs @@ -7,164 +7,5 @@ using Android.Views.Autofill; namespace keepass2android.services.AutofillBase.model { - /// - /// 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 - { - 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); - } - else - { - CommonUtil.loge($"Invalid hint: {hint}"); - } - } - - } - - - /// - /// Populates a Dataset.Builder with appropriate values for each AutofillId - /// in a AutofillFieldMetadataCollection. - /// - /// In other words, it constructs an autofill Dataset.Builder - /// by applying saved values (from this FilledAutofillFieldCollection) - /// to Views specified in a AutofillFieldMetadataCollection, which represents the current - /// page the user is on. - /// - /// true, if to fields was applyed, false otherwise. - /// Autofill field metadata collection. - /// Dataset builder. - public bool ApplyToFields(AutofillFieldMetadataCollection autofillFieldMetadataCollection, Dataset.Builder datasetBuilder) - { - bool setValueAtLeastOnce = false; - - foreach (string hint in autofillFieldMetadataCollection.AllAutofillCanonicalHints) - { - foreach (AutofillFieldMetadata autofillFieldMetadata in autofillFieldMetadataCollection.GetFieldsForHint(hint)) - { - FilledAutofillField filledAutofillField; - if (!HintMap.TryGetValue(hint, out filledAutofillField) || (filledAutofillField == null)) - { - continue; - } - - var autofillId = autofillFieldMetadata.AutofillId; - var autofillType = autofillFieldMetadata.AutofillType; - switch (autofillType) - { - case AutofillType.List: - var listValue = autofillFieldMetadata.GetAutofillOptionIndex(filledAutofillField.TextValue); - if (listValue != -1) - { - datasetBuilder.SetValue(autofillId, AutofillValue.ForList(listValue)); - setValueAtLeastOnce = true; - } - break; - case AutofillType.Date: - var dateValue = filledAutofillField.DateValue; - datasetBuilder.SetValue(autofillId, AutofillValue.ForDate((long)dateValue)); - setValueAtLeastOnce = true; - break; - case AutofillType.Text: - var textValue = filledAutofillField.TextValue; - if (textValue != null) - { - datasetBuilder.SetValue(autofillId, AutofillValue.ForText(textValue)); - setValueAtLeastOnce = true; - } - break; - case AutofillType.Toggle: - var toggleValue = filledAutofillField.ToggleValue; - if (toggleValue != null) - { - datasetBuilder.SetValue(autofillId, AutofillValue.ForToggle(toggleValue.Value)); - setValueAtLeastOnce = true; - } - break; - default: - Log.Warn(CommonUtil.Tag, "Invalid autofill type - " + autofillType); - break; - } - } - } - /* - if (!setValueAtLeastOnce) - { - Kp2aLog.Log("No value set. Hint keys : " + string.Join(",", HintMap.Keys)); - foreach (string hint in autofillFieldMetadataCollection.AllAutofillCanonicalHints) - { - Kp2aLog.Log("No value set. Hint = " + hint); - foreach (AutofillFieldMetadata autofillFieldMetadata in autofillFieldMetadataCollection - .GetFieldsForHint(hint)) - { - Kp2aLog.Log("No value set. fieldForHint = " + autofillFieldMetadata.AutofillId.ToString()); - FilledAutofillField filledAutofillField; - if (!HintMap.TryGetValue(hint, out filledAutofillField) || (filledAutofillField == null)) - { - Kp2aLog.Log("No value set. Hint map does not contain value, " + - (filledAutofillField == null)); - continue; - } - - Kp2aLog.Log("autofill type=" + autofillFieldMetadata.AutofillType); - } - } - }*/ - - return setValueAtLeastOnce; - } - - /// - /// 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; - } - } + } diff --git a/src/keepass2android/services/AutofillBase/model/W3cHints.cs b/src/keepass2android/services/AutofillBase/model/W3cHints.cs index 8078ddfc..01c8f6a5 100644 --- a/src/keepass2android/services/AutofillBase/model/W3cHints.cs +++ b/src/keepass2android/services/AutofillBase/model/W3cHints.cs @@ -2,126 +2,5 @@ namespace keepass2android.services.AutofillBase.model { - 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; - } - Log.Warn(CommonUtil.Tag, "Invalid W3C type hint: " + hint); - return false; - } - } + } \ No newline at end of file From 632121f3ecefd3bc87df36e34f960e117d1a8bc9 Mon Sep 17 00:00:00 2001 From: Rick Brown Date: Sat, 11 Feb 2023 17:58:23 -0500 Subject: [PATCH 005/101] Get JavaFileStorage working in Android Studio Resolve issue where AS would fail to import Android API jar --- src/java/JavaFileStorage/settings.gradle | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/java/JavaFileStorage/settings.gradle diff --git a/src/java/JavaFileStorage/settings.gradle b/src/java/JavaFileStorage/settings.gradle new file mode 100644 index 00000000..e7b4def4 --- /dev/null +++ b/src/java/JavaFileStorage/settings.gradle @@ -0,0 +1 @@ +include ':app' From c7eb2bf87322ea60cd877dbbfcbdf275ec6de173 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Sun, 12 Feb 2023 17:02:59 +0100 Subject: [PATCH 006/101] New translations strings.xml (Japanese) --- src/keepass2android/Resources/values-ja/strings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/keepass2android/Resources/values-ja/strings.xml b/src/keepass2android/Resources/values-ja/strings.xml index 77b48817..f7e6a874 100644 --- a/src/keepass2android/Resources/values-ja/strings.xml +++ b/src/keepass2android/Resources/values-ja/strings.xml @@ -389,9 +389,9 @@ 証明書の検証に失敗したときの動作を指定します。注意: 検証に失敗したときは、デバイスに証明書をインストールすることができます。 キャッシュをクリアしますか? すべてのキャッシュされたデータベースファイルを削除します。元のデータベースにアクセスできない間に行った、同期されていない変更がすべて失われます! 続行しますか? - 変更をチェック + 変更を確認 変更を保存する前に、ファイルが外部から変更されているか確認します。 - UUID の重複をチェック + UUID の重複を確認 同じ ID で複数のエントリーがあるかによってデータベース ファイルの破損を確認します。これは予期しない動作が発生する可能性があります。 クリップボード通知 ユーザー名とパスワードが、通知バーとクリップボードからアクセス可能になります。パスワード盗聴アプリに気をつけてください! @@ -482,7 +482,7 @@ OTP 補助ファイル エラーが発生しました: データベースが破損しています: 重複する ID が見つかりました。(Minikeepass で保存しましたか?) PC 用 Keepass 2 で新しいデータベースに再インポートして「新しい ID の作成」を選択してください。 - 設定/アプリ設定/ファイル処理/UUID の重複をチェック で、このエラーメッセージを無効にできます。予期しない動作が発生する可能性があることにご注意ください。データベースを修正することをお勧めします。 + 設定/アプリ設定/ファイル処理/UUID の重複を確認 で、このエラーメッセージを無効にできます。予期しない動作が発生する可能性があることにご注意ください。データベースを修正することをお勧めします。 データベースを同期... このグループにグループを移動できません。 今日はオクトーバーフェスト! Keepass2Android を気に入ってくださったなら、今日は私にビールを買っていただくのにいい日ではありませんか? From 23d7efff53a304c21978a9a63d4b141d9acf32d9 Mon Sep 17 00:00:00 2001 From: Rick Brown Date: Sun, 12 Feb 2023 12:24:25 -0500 Subject: [PATCH 007/101] Bugfix for #2223 - crash after import database by SFTP Add FLAG_MUTABLE flag to PendingIntent call for API >= 31 to fix an issue where trying to open an SFTP database (transition to choose a remote database file) crashes and returns to the Open/New database screen. --- .../java/keepass2android/javafilestorage/SftpUserInfo.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpUserInfo.java b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpUserInfo.java index 4f43ce7d..6737535c 100644 --- a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpUserInfo.java +++ b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpUserInfo.java @@ -51,7 +51,12 @@ public class SftpUserInfo implements UserInfo { intent.putExtra("keepass2android.sftp.prompt", text); intent.setData((Uri.parse("suckit://"+SystemClock.elapsedRealtime()))); - PendingIntent contentIntent = PendingIntent.getActivity(_appContext, 0, intent, 0); + int flags = 0; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) { + flags |= PendingIntent.FLAG_MUTABLE; + } + PendingIntent contentIntent = PendingIntent.getActivity(_appContext, 0, intent, flags); + builder.setContentIntent(contentIntent); { From cfd413f1f45876a3f309811970d72d363cb3c077 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Mon, 13 Feb 2023 09:42:55 +0100 Subject: [PATCH 008/101] add more hints for password fields to fix issues with autofill (maybe on newer Android versions only), closes #2184 --- src/keepass2android/services/AutofillBase/StructureParser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keepass2android/services/AutofillBase/StructureParser.cs b/src/keepass2android/services/AutofillBase/StructureParser.cs index 29dd7416..c85e56bf 100644 --- a/src/keepass2android/services/AutofillBase/StructureParser.cs +++ b/src/keepass2android/services/AutofillBase/StructureParser.cs @@ -190,7 +190,7 @@ namespace keepass2android.services.AutofillBase } return result; } - private static readonly HashSet _passwordHints = new HashSet { "password","passwort" }; + private static readonly HashSet _passwordHints = new HashSet { "password","passwort", "passwordAuto", "pswd" }; private static bool HasPasswordHint(AssistStructure.ViewNode f) { return ContainsAny(f.IdEntry, _passwordHints) || From 3043f8981dd8c64d9a4ad0c995498b0655e9aa40 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Sat, 18 Feb 2023 06:48:55 +0100 Subject: [PATCH 009/101] New translations strings.xml (German) --- src/keepass2android/Resources/values-de/strings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/keepass2android/Resources/values-de/strings.xml b/src/keepass2android/Resources/values-de/strings.xml index 1b0ebfbc..b642da4c 100644 --- a/src/keepass2android/Resources/values-de/strings.xml +++ b/src/keepass2android/Resources/values-de/strings.xml @@ -159,7 +159,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Override URL tag1, tag2 Benutzername - Passwort oder Schlüssel-Datei ungültig. + Kennwort oder Schlüsseldatei ist falsch. Ungültiger Algorithmus. Datenbank-Format wurde nicht erkannt. Schlüssel-Datei existiert nicht. @@ -178,7 +178,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Keine Option, um Autofill zu deaktivieren Wenn aktiviert, wird die App die Option zum Abschalten von Autofill für bestimmte Einträge nicht anzeigen. Über - Master-Passwort ändern + Masterpasswort ändern Kennwort kopieren Benutzername kopieren TOTP kopieren @@ -334,7 +334,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Wenn die aktive Datenbank einen Eintrag mit dem Titel \"QuickUnlock\" in der Root-Gruppe enthält, wird das Passwort dieses Eintrags als QuickUnlock-Code verwendet. QuickUnlock fehlgeschlagen: falsches Kennwort! Anhang speichern - Bitte wähle den Ort zum Speichern. + Bitte den Ort zum Speichern wählen. In Datei exportieren... Im Cache speichern und öffnen Mit internem Bildbetrachter anzeigen From 47aaedbfb5c6df9e50d9288ef408f34a146d2f94 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Sat, 18 Feb 2023 06:48:56 +0100 Subject: [PATCH 010/101] New translations strings.xml (German) --- .../app/src/main/res/values-de/strings.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/java/android-filechooser-AS/app/src/main/res/values-de/strings.xml b/src/java/android-filechooser-AS/app/src/main/res/values-de/strings.xml index 246460a7..e6366232 100644 --- a/src/java/android-filechooser-AS/app/src/main/res/values-de/strings.xml +++ b/src/java/android-filechooser-AS/app/src/main/res/values-de/strings.xml @@ -56,15 +56,15 @@ Sortieren nach… Gestern - Verzeichnis wählen… + Ordner wählen … Verzeichnisse wählen… Datei wählen… - Dateien wählen… + Dateien wählen … - Datei/Ordner wählen… - Dateien/Ordner wählen… + Datei/Ordner wählen … + Dateien/Ordner wählen … From bd4e321b0e2855b9049c389ffc358a86edaa06f4 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Sat, 18 Feb 2023 06:48:57 +0100 Subject: [PATCH 011/101] New translations strings.xml (German) --- .../app/src/main/res/values-de/strings.xml | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/java/KP2ASoftkeyboard_AS/app/src/main/res/values-de/strings.xml b/src/java/KP2ASoftkeyboard_AS/app/src/main/res/values-de/strings.xml index 50e9b8e5..dd3af7ab 100644 --- a/src/java/KP2ASoftkeyboard_AS/app/src/main/res/values-de/strings.xml +++ b/src/java/KP2ASoftkeyboard_AS/app/src/main/res/values-de/strings.xml @@ -25,7 +25,7 @@ Eingabeoptionen - Vibrieren b. Tastendruck + Bei Tastendruck vibrieren Ton bei Tastendruck @@ -120,13 +120,13 @@ \"Halten Sie eine Taste gedrückt, um Akzente anzuzeigen\"\n\"(ø, ö, ô, ó usw.).\" - \"Wechseln Sie zu Ziffern und Symbolen, indem Sie diese Taste berühren.\" + „Wechseln Sie zu Ziffern und Symbolen, indem Sie diese Taste berühren.“ - \"Durch erneutes Drücken dieser Taste gelangen Sie zurück zu den Buchstaben.\" + „Durch erneutes Drücken dieser Taste gelangen Sie zurück zu den Buchstaben.“ - \"Halten Sie diese Taste gedrückt, um die Tastatureinstellungen, wie beispielsweise die automatische Vervollständigung, zu ändern.\" + „Halten Sie diese Taste gedrückt, um die Tastatureinstellungen, wie beispielsweise die automatische Vervollständigung, zu ändern.“ - \"Probieren Sie es aus!\" + „Probieren Sie es aus!“ Los @@ -166,7 +166,7 @@ Vorgang läuft - Fehler. Versuchen Sie es erneut.. + Fehler. Versuchen Sie es erneut. Keine Verbindung Sprachsuche nicht installiert - \"Hinweis:\"\" Ziehen Sie zum Sprechen den Finger über die Tastatur.\" + „Hinweis:“„ Ziehen Sie zum Sprechen den Finger über die Tastatur.“ - \"Hinweis:\"\" Versuchen Sie beim nächsten Mal, Satzzeichen wie \"Punkt\", \"Komma\" oder \"Fragezeichen\" per Sprachbefehl einzugeben.\" + „Hinweis:“„ Versuchen Sie beim nächsten Mal, Satzzeichen wie „Punkt“, „Komma“ oder „Fragezeichen“ per Sprachbefehl einzugeben.“ Abbrechen @@ -214,13 +214,13 @@ Drücken Sie auf die Eingabetaste, wenn Sie einen Suchvorgang durchführen oder zum nächsten Feld wechseln. - \"Tastatur öffnen\"\n\n\"Berühren Sie ein beliebiges Textfeld.\" + „Tastatur öffnen“\n\n„Berühren Sie ein beliebiges Textfeld.“ - \"Tastatur schließen\"\n\n\"Drücken Sie die Zurücktaste.\" + „Tastatur schließen“\n\n„Drücken Sie die Zurücktaste.“ - \"Für Optionen eine Taste berühren und gedrückt halten\"\n\n\"Greifen Sie auf Satzzeichen und Akzente zu.\" + „Für Optionen eine Taste berühren und gedrückt halten“\n\n„Greifen Sie auf Satzzeichen und Akzente zu.“ - \"Tastatureinstellungen\"\n\n\"Berühren und halten Sie die Taste \"\"?123\"\" gedrückt.\" + „Tastatureinstellungen“\n\n„Berühren und halten Sie die Taste „\"?123\"“ gedrückt.“ ".com" From eff9a96bd550b7667fd58142df5420918d8e78da Mon Sep 17 00:00:00 2001 From: PhilippC Date: Sat, 18 Feb 2023 07:44:12 +0100 Subject: [PATCH 012/101] New translations strings.xml (German) --- src/keepass2android/Resources/values-de/strings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/keepass2android/Resources/values-de/strings.xml b/src/keepass2android/Resources/values-de/strings.xml index b642da4c..fbe07ee0 100644 --- a/src/keepass2android/Resources/values-de/strings.xml +++ b/src/keepass2android/Resources/values-de/strings.xml @@ -25,7 +25,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Bei inaktiver Anwendung wird die Datenbank nach Ablauf der eingestellten Zeit automatisch gesperrt. App-Prozess beenden Schließen-Button - Zeige eine Schaltfläche auf dem Kennwort-Bildschirm, um den App-Prozess zu beenden (für paranoide Benutzer) + Eine Schaltfläche auf dem Kennwortbildschirm anzeigen, um den App-Prozess zu beenden (für paranoide Benutzer) Anwendung Anwendungseinstellungen Gruppennamen im Suchergebnis anzeigen @@ -370,7 +370,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Leere das Eingabefeld für das Master-Passwort, wenn der Passwort-Eingabebildschirm verlassen wird, ohne dass die Datenbank entsperrt wurde. Beim Verlassen der App sperren Datenbank sperren, wenn die App mit dem Zurück-Knopf verlassen wird. - Benutze integrierte Tastatur in Keepass2Android + Integrierte Tastatur in Keepass2Android verwenden Wenn Sie ihrer Standardtastatur nicht vertrauen, setzen Sie diese Option, um die Built-In-Tastatur beim Eingeben des Masterkennworts oder beim Bearbeiten von Einträgen zu benutzen. Suchfeld beim Start aktivieren Aktiviert das Suchfeld in der Gruppenansicht nach dem Entsperren oder wenn ein Eintrag gesucht wird. @@ -659,7 +659,7 @@ Anbei einige Hinweise, die bei der Diagnose des Problems helfen können:\n • Wenn du die Datei auf dem PC noch öffnen kannst, nimm bitte Kontakt mit dem Support auf. Du kannst versuchen, die Datei mit anderen Einstellungen auf dem PC zu speichern (z.B. nicht ZIP-komprimiert) und sie dann noch einmal in Keepass2Android zu öffnen. Öffne weitere Datenbank… Datenbank auswählen - Konfiguriere Kinddatenbanken… + Kinddatenbanken konfigurieren … Kinddatenbanken nicht spezifiziert Kinddatenbanken sind andere Datenbanken, die automatisch geöffnet werden können, wenn die übergeordnete Datenbank geöffnet wird. Dazu werden das Master-Passwort und der Dateipfad der Kinddatenbank in der Hauptdatenbank gespeichert. Diese Funktion erlaubt es, einige deiner Passwörter mit einer anderen Person zu teilen. Die Implementierung ist kompatibel mit KeeAutoExec für PC. From 8464fa4f29734b35fae9b7870bf6cdde0f1f8a34 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Sat, 18 Feb 2023 09:11:16 +0100 Subject: [PATCH 013/101] New translations strings.xml (German) --- .../Resources/values-de/strings.xml | 74 +++++++++---------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/src/keepass2android/Resources/values-de/strings.xml b/src/keepass2android/Resources/values-de/strings.xml index fbe07ee0..ec90d7c6 100644 --- a/src/keepass2android/Resources/values-de/strings.xml +++ b/src/keepass2android/Resources/values-de/strings.xml @@ -33,7 +33,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Angezeigte Gruppe ist jetzt: %1$s Deaktivierte AutoFill-Ziele Zeigt eine Liste von Apps und Webseiten, für die AutoFill deaktiviert ist. - Wenn aktiviert fragt Android, ob du die Anmeldedaten speichern möchtest, die du manuell in AutoFill-Felder eingegeben hast. + Wenn aktiviert, fragt Android, ob die Anmeldedaten gespeichert werden sollen, die manuell in AutoFill-Felder eingegeben wurden. Speichern von Zugangsdaten anbieten Gruppennamen in der Eintragsansicht anzeigen Tut mir Leid! Keepass2Android kann die zurückgegebene URI %1$s nicht verarbeiten. Bitte kontaktiere den Entwickler! @@ -43,7 +43,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Weitere finden... Sicherheit Anzeige - Passwort-Zugriff + Passwortzugriff QuickUnlock Umgang mit Dateien Tastatur @@ -76,7 +76,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die ist verfügbar Der Dialog zum Auswählen der Eingabemethode konnte nicht geöffnet werden. Bitte die Tastatur manuell aktivieren. Bitte Keepass2Android Tastatur in den Einstellungen aktivieren. - Datenbank-Schlüsseldatei erzeugen\u2026 + Datenbankschlüsseldatei erzeugen … Aktuelle Gruppe Start Datenbank @@ -85,13 +85,13 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die In Zwischenablage kopieren System Sprache - Bitte authentifizieren um fortzufahren - Kann Biometrisches Entsperren nicht einrichten: + Bitte authentifizieren, um fortzufahren + Biometrisches Entsperren kann nicht eingerichtet werden: Biometrische Authentifizierung fehlgeschlagen. Versuche es erneut Biometrische Authentifizierung erfolgreich Biometrische Entsperrung erfordert Android 6.0 oder höher. Keine biometrische Hardware erkannt. - Sie haben keine biometrische Authentifizierung auf diesem Gerät konfiguriert. Bitte gehen Sie zuerst zu den Systemeinstellungen. + Es wurde keine biometrische Authentifizierung auf diesem Gerät konfiguriert. Bitte zuerst zu den Systemeinstellungen gehen. Biometrisches Entsperren deaktivieren Komplettes biometrisches Entsperren aktivieren Biometrisches Entsperren für QuickUnlock @@ -101,7 +101,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Bitte mit Kennwort entsperren und anschließend in den Datenbankeinstellungen das biometrische Entsperren erneut aktivieren. Initialisierung der biometrischen Authentifizierung fehlgeschlagen. Daten konnten nicht verschlüsselt werden. Dies kann passieren, wenn Fingerabdrücke in den Systemeinstellungen hinzugefügt oder gelöscht wurden, während Keepass2Android auf deinen Fingerabdruck wartet. - Mit dieser Option wird das Master-Passwort verschlüsselt im Android-Keystore auf dem Gerät gespeichert, geschützt durch einen Fingerabdruck. Dadurch kann die Datenbank per biometrischer Authentifizierung entsperrt werden. + Mit dieser Option wird das Hauptpasswort verschlüsselt im Android-Keystore auf dem Gerät gespeichert, geschützt durch einen Fingerabdruck. Dadurch kann die Datenbank per biometrischer Authentifizierung entsperrt werden. Erlaubt es, den biometrische Authentifizierung anstelle des QuickUnlock-Codes zu nutzen. Speichert keine Informationen bezüglich des Masterpassworts. Dateinamen der Datenbank eingeben Letzter Zugriff @@ -178,7 +178,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Keine Option, um Autofill zu deaktivieren Wenn aktiviert, wird die App die Option zum Abschalten von Autofill für bestimmte Einträge nicht anzeigen. Über - Masterpasswort ändern + Hauptschlüssel ändern Kennwort kopieren Benutzername kopieren TOTP kopieren @@ -213,19 +213,19 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Papierkorb und Sicherungen nicht durchsuchen Papierkorb und Sicherungseinträge werden bei der Suche nicht berücksichtigt. KeePass Datenbankdatei - Datenbank-Kennwort eingeben - Master-Passwort-Typ auswählen: - Neue Datenbank anlegen\u2026 + Datenbankkennwort eingeben + Hauptschlüsseltyp auswählen: + Neue Datenbank wird angelegt … Datenbank anlegen - In Bearbeitung\u2026 + In Bearbeitung … Speicherort der Schlüsseldateien merken Schlüsseldatei speichern Entfernen Bearbeiten Rijndael (AES) Root - Kehre automatisch vom Abfragebildschirm zurück - Beim Suchen eines Eintrags für eine App oder Webseite: Kehre automatisch vom Abfragebildschirm zurück, wenn nur ein passender Eintrag in der Datenbank existiert. + Automatisch vom Abfragebildschirm zurückkehren + Beim Suchen eines Eintrags für eine App oder Webseite: Automatisch vom Abfragebildschirm zurückkehren, wenn nur ein passender Eintrag in der Datenbank existiert. Schlüsselableitungsfunktion Schlüsseltransformationen Je höher die Anzahl der Schlüsseltransformationen, desto besser ist der Schutz gegen Wörterbuch- oder Brute-Force-Angriffe. Allerdings dauert dann auch das Laden und Speichern der Datenbank entsprechend länger. @@ -233,7 +233,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Speicher für Argon 2 (in Bytes) Parallelisierung für Argon 2 Datenbankname - Standard-Benutzername für neue Einträge + Standardbenutzername für neue Einträge Speichere Datenbank\u2026 Datenbank exportieren… Datenbank erfolgreich exportiert! @@ -241,7 +241,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Leerzeichen Suchen Kennwort anzeigen - Sortiere nach... + Sortieren nach … Sortieren nach Name Sortieren nach Erstellung Sortiere nach Änderungsdatum @@ -293,7 +293,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Bei Konflikt immer vereinigen Die lokalen Änderungen immer mit den entfernten Änderungen vereinigen, wenn Keepass2Android erkennt, dass die entfernte Datei verändert wurde. TAN verfällt bei Verwendung - TAN Einträge als abgelaufen markieren, wenn sie geöffnet werden + TAN-Einträge als abgelaufen markieren, wenn sie verwendet werden Zeige Benutzernamen in Liste Zeige Benutzernamen unter den Titeln der Einträge. Hilfreich bei mehreren Accounts für einen Dienst oder bei TANs. Datenbanken merken @@ -307,10 +307,10 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Abgelaufene Einträge ausschließen Optionen Groß-/Kleinschreibung beachten - Datei öffnen... - Neue Datenbank erstellen... - URL öffnen... - Datei in neue Datenbank importieren... + Datei öffnen … + Neue Datenbank erstellen … + URL öffnen … + Datei in neue Datenbank importieren … Die vollständige URL muss einschließlich Protokoll, z.B. http://, angegeben werden. Zu importierende Datei wird im nächsten Schritt gewählt. QuickUnlock aktivieren @@ -325,7 +325,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die QuickUnlock-Symbol verstecken QuickUnlock funktioniert leider nicht ohne ein Benachrichtigungssymbol. Wähle diese Option, um ein transparentes Symbol zu verwenden. QuickUnlock-Symbol verstecken - QuickUnlock benötigt eine Benachrichtigung um richtig zu funktionieren. Wähle diese Option um eine Benachrichtigung ohne Symbol anzuzeigen. + QuickUnlock benötigt eine Benachrichtigung, um ordnungsgemäß zu funktionieren. Diese Option wählen, um eine Benachrichtigung ohne Symbol anzuzeigen. Länge des QuickUnlock-Schlüssels Maximale Anzahl von Zeichen, die als QuickUnlock-Kennwort verwendet werden. Länge des QuickUnlock-Codes verstecken @@ -335,7 +335,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die QuickUnlock fehlgeschlagen: falsches Kennwort! Anhang speichern Bitte den Ort zum Speichern wählen. - In Datei exportieren... + In Datei exportieren … Im Cache speichern und öffnen Mit internem Bildbetrachter anzeigen Datei unter %1$s gespeichert. @@ -348,7 +348,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Feldname Feldwert Geschütztes Feld - Dateianhang hinzufügen... + Dateianhang hinzufügen … Zusätzliches Feld hinzufügen TOTP konfigurieren Geheimer Schlüssel @@ -428,7 +428,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Umbenennen Fehler beim Hinzufügen des Anhangs. Papierkorb - Soll dieser Eintrag endgültig gelöscht werden? Drücke nein, um ihn in den Papierkorb zu verschieben. + Soll dieser Eintrag endgültig gelöscht werden? Nein drücken, um ihn in den Papierkorb zu verschieben. Soll diese Gruppe endgültig gelöscht werden? Drücke nein, um sie in den Papierkorb zu verschieben. Gewählte Elemente permanent löschen? Nein wählen, um in den Papierkorb zu verschieben. Eintrag permanent löschen? @@ -462,7 +462,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Zwischengespeicherte Kopie mit der Quelldatei synchronisieren Datenbank wird vom internen Cache geladen. Änderungen werden nur im internen Cache gespeichert und nur synchronisiert, wenn eine Datenbanksynchronisierung manuell ausgewählt wird. Verwende nur internen Zwischenspeicher. - Synchronisiere gecachte Datenbank… + Gecachte Datenbank synchronisieren … Quelldatei wird geladen… Datei speichern… Quelldatei wird wiederhergestellt… @@ -482,7 +482,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Datenbankdatei OTP-Hilfsdatei Ein Fehler ist aufgetreten: - Datenbank ist beschädigt: IDs kommen mehrfach vor. (Hast du mit Minikeepass gespeichert?) Bitte am PC mit Keepass 2 in eine neue Datenbank re-importieren und \'Neue IDs erstellen\' auswählen. + Datenbank ist beschädigt: IDs kommen mehrfach vor. (Wurde mit Minikeepass gespeichert?) Bitte am PC mit Keepass 2 in eine neue Datenbank re-importieren und „Neue IDs erstellen“ auswählen. Diese Fehlermeldung kann unter Einstellungen/Anwendungs-Einstellungen/Umgang mit Dateien/Prüfe auf doppelte UUIDs deaktiviert werden. Bitte beachten: Dies kann zu unerwartetem Verhalten führen. Es wird empfohlen, die Datenbank zu reparieren. Datenbank synchronisieren… Kann Gruppe nicht hierher verschieben. @@ -502,7 +502,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Startverzeichnis (optional): SFTP-Zugangsdaten eingeben: Authentifizierungsmodus - Sende öffentlichen Schlüssel... + Öffentlichen Schlüssel senden … FTP-Zugangsdaten eingeben: Geben Sie Ihre MEGA-Zugangsdaten ein: Speichertyp wählen: @@ -537,12 +537,12 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Wähle, wo du deine Datenbank speichern möchtest: Speicherort ändern Wenn aktiviert, läuft Keepass2Android im Hintergrund weiter, auch wenn die Datenbank gesperrt ist. Das ermöglicht das Öffnen der Datenbank mit QuickUnlock. - Master-Passwort + Hauptpasswort Deine Datenbank wird mit dem hier eingegebenen Passwort verschlüsselt. Wähle ein starkes Passwort, um deine Datenbank zu schützen! Tipp: Denke dir ein oder zwei Sätze aus und nutze die Anfangsbuchstaben als Passwort. Übernimm auch die Satzzeichen. Wähle ein Master-Passwort, mit dem deine Datenbank geschützt wird: Schlüsseldatei - Eine Schlüsseldatei ist im Grunde ein Kennwort, das in einer Datei gespeichert ist. Schlüsseldateien sind üblicherweise stärker als Kennwörter, weil sie deutlich komplexer sein können; allerdings ist es schwerer, sie geheim zu halten. Wenn du deine Datenbank in der Cloud speicherst, solltest du die Schlüsseldatei keinesfalls auch dort ablegen. Das würde sie nutzlos machen! Wichtig: Ändere die Schlüsseldatei nicht mehr, nachdem du die Datenbank angelegt hast! - Wähle, ob du eine Schlüsseldatei zusätzlich zum Master-Passwort nutzen möchtest: + Eine Schlüsseldatei ist im Grunde ein Kennwort, das in einer Datei gespeichert ist. Schlüsseldateien sind üblicherweise stärker als Kennwörter, weil sie deutlich komplexer sein können; allerdings ist es schwerer, sie geheim zu halten. Wird die Datenbank in der Cloud gespeichert, sollte die Schlüsseldatei keinesfalls ebenfalls dort abgelegt werden! Das würde sie völlig nutzlos machen! Wichtig: Den Inhalt der Schlüsseldatei nicht mehr ändern, nachdem die Datenbank angelegt wurde! + Wählen, ob eine Schlüsseldatei zusätzlich zum Hauptpasswort verwendet werden soll: Schlüsseldatei benutzen Fehler beim Hinzufügen der Schlüsseldatei! OTP-Hilfsdatei laden… @@ -683,7 +683,7 @@ Anbei einige Hinweise, die bei der Diagnose des Problems helfen können:\n Eintrag-Benachrichtigungen Benachrichtigung zum schnellen Zugriff auf den aktuell gewählten Eintrag. Datenbank nach drei fehlgeschlagenen biometrischen Entsperrversuchen schließen. - Warnung! Biometrische Authentifizierung kann von Android ungültig gemacht werden, z.B. nach dem Hinzufügen eines neuen Fingerabdrucks in den Geräteeinstellungen. Stelle sicher, dass du immer weißt, wie du mit deinem Master-Passwort entsperren kannst! + Achtung! Die biometrische Authentifizierung kann von Android ungültig gemacht werden, z. B. nach dem Hinzufügen eines neuen Fingerabdrucks in den Geräteeinstellungen. Bitte sicherstellen, dass jederzeit klar ist, wie mit dem eigenen Hauptpasswort entsperrt werden kann! Bugfix um Abstürze und unerwartetes Ausloggen zu vermeiden Wechsel auf eine neue SFTP-Implementierung, jetzt mit Unterstützung von modernen Public-Key-Algorithmen wie rsa-sha2-256 @@ -883,11 +883,11 @@ Anbei einige Hinweise, die bei der Diagnose des Problems helfen können:\n * App-Logo und Benachrichtigungsdesign aktualisiert, Design von Stefano Pignataro (http://www.spstudio.at)\n * Keepass2Android merkt sich die letzten Einstellungen\n * Sichtbarkeit von Benachrichtigungen unter Android 5 gesetzt \n - * Eingegebenes Master-Passwort wird gelöscht, wenn die App verlassen wird, ohne OK zu drücken\n + * Eingegebenes Hauptpasswort wird gelöscht, wenn die App verlassen wird, ohne OK zu drücken\n * Problem mit fehlenden Tastatur-Eingabesprachen auf manchen Geräten behoben\n * Problem mit automatischem Tastatur-Umschalten behoben\n * Prüfung auf korrupte Datenbanken mit doppelten UUIDs\n - * Datenbank wird automatisch neu geladen, wenn eine Änderung erkannt wird (löst Sicherheitsbedenken bzgl. Möglichkeit, Masterpasswort sehen zu können)\n + * Datenbank wird automatisch neu geladen, wenn eine Änderung erkannt wird (löst Sicherheitsbedenken bzgl. Möglichkeit, Hauptpasswort sehen zu können)\n * Design der Tastatureinstellungen korrigiert (danke an Wiktor Ławski)\n Version 0.9.5\n * Probleme bei Dateiauswahl behoben (bes. auf Android 4.4)\n @@ -1069,9 +1069,9 @@ Erstes öffentliches Release Keepass2Android hat biometrische Hardware erkannt. Möchtest du Biometrisches Entsperren für diese Datenbank aktivieren? Ich verstehe Nicht erneut anzeigen - Kennst du dein Master-Passwort? - Bitte beachte, dass du deine Datenbank nicht ohne Master-Passwort öffnen kannst. Es gibt keine Möglichkeit, das Passwort zurückzusetzen. - Beachte auch, dass für das biometrische Entsperren dein Masterkennwort durch Android in einem gesicherten Speicher abgelegt wird. Dieser Speicher kann aber von Android gelöscht oder ungültig gemacht werden, z.B. wenn du einen Fingerabdruck in den Systemeinstellungen hinterlegst. Verlass dich daher bitte nicht auf das biometrische Entsperren sondern merke dir dein Masterkennwort! + Ist das Hauptpasswort bekannt? + Bitte beachten, dass die Datenbank ohne den Hauptschlüssel nicht geöffnet werden kann. Es gibt keine Möglichkeit, das Hauptpasswort „zurückzusetzen“. + Bitte auch bedenken, dass die biometrische Entsperrung durch das Speichern des Hauptschlüssels im sicheren Speicher von Android funktioniert. Dieser Speicher kann von Android jederzeit gelöscht werden, z. B. wenn ein neuer Fingerabdruck in den Systemeinstellungen hinzugefügt wird. Daher sich nicht auf das biometrische Entsperren verlassen, sondern sich bitte das eigene Hauptpasswort merken! Ist deine Datenbank gesichert? Keepass2Android speichert deine Passwörter in eine Datei an einem Ort deiner Wahl. Bist du sicher, dass du auf diese Datei auch noch Zugriff hast wenn dein Telefon verloren geht oder gestohlen wird? Oder wenn die Datei zerstört oder gelöscht wird? Bitte stelle sicher, dass du immer eine aktuelle Kopie an einem sichern Ort aufbewahrst! Um jetzt eine Sicherung zu erstellen, gehe nach %1$s > %2$s > %3$s. From 1be7b33f6b72d04a8d41de507fcdb78d7a2f4c9b Mon Sep 17 00:00:00 2001 From: PhilippC Date: Sat, 18 Feb 2023 10:09:38 +0100 Subject: [PATCH 014/101] New translations strings.xml (German) --- .../Resources/values-de/strings.xml | 68 +++++++++---------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/src/keepass2android/Resources/values-de/strings.xml b/src/keepass2android/Resources/values-de/strings.xml index ec90d7c6..0a490f61 100644 --- a/src/keepass2android/Resources/values-de/strings.xml +++ b/src/keepass2android/Resources/values-de/strings.xml @@ -84,7 +84,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Der Autor übernimmt keine Verantwortung gibt KEINERLEI GARANTIE bei der Nutzung der Anwendung; Die Anwendung ist kostenlos und kann unter den Bedingungen der GPL v2 oder später verbreitet werden. In Zwischenablage kopieren - System Sprache + Systemsprache Bitte authentifizieren, um fortzufahren Biometrisches Entsperren kann nicht eingerichtet werden: Biometrische Authentifizierung fehlgeschlagen. Versuche es erneut @@ -270,7 +270,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Suchergebnisse Suche in Anderen Eintrag wählen - Gehe zur gewünschten Gruppe, dann drücke \"%1$s\"! + Die gewünschte Gruppe öffnen, dann „%1$s“ drücken! Hier einfügen Twofish Unterstrich @@ -281,7 +281,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Version Versionsinformationen Keepass2Android wird von Philipp Crocoll entwickelt. - Danke an %1$s für Beiträge zum Source-Code! + Danke an %1$s für Beiträge zum Quellcode! Danke für das Icon und Layoutdesign erstellt von %1$s. Danke für die finanzielle Unterstützung durch %1$s. Das Twofish-Plugin für Keepass wurde von Scott Greenberg entwickelt und ist in KP2A enthalten. @@ -294,7 +294,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Die lokalen Änderungen immer mit den entfernten Änderungen vereinigen, wenn Keepass2Android erkennt, dass die entfernte Datei verändert wurde. TAN verfällt bei Verwendung TAN-Einträge als abgelaufen markieren, wenn sie verwendet werden - Zeige Benutzernamen in Liste + Benutzernamen in Liste anzeigen Zeige Benutzernamen unter den Titeln der Einträge. Hilfreich bei mehreren Accounts für einen Dienst oder bei TANs. Datenbanken merken Dateinamen der bisher geöffneten Datenbanken speichern und im Bildschirm zum Öffnen der Datenbank anzeigen. @@ -331,7 +331,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Länge des QuickUnlock-Codes verstecken Wenn aktiviert, wird die Länge des QuickUnlock-Codes nicht auf dem QuickUnlock-Bildschirm angezeigt. QuickUnlock-Taste aus dem Datenbankeintrag. - Wenn die aktive Datenbank einen Eintrag mit dem Titel \"QuickUnlock\" in der Root-Gruppe enthält, wird das Passwort dieses Eintrags als QuickUnlock-Code verwendet. + Wenn die aktive Datenbank einen Eintrag mit dem Titel „QuickUnlock“ in der Root-Gruppe enthält, wird das Passwort dieses Eintrags als QuickUnlock-Code verwendet. QuickUnlock fehlgeschlagen: falsches Kennwort! Anhang speichern Bitte den Ort zum Speichern wählen. @@ -341,7 +341,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Datei unter %1$s gespeichert. Datei konnte nicht unter %1$s gespeichert werden. Suchtext merken? - Soll der Suchtext \"%1$s\" im gewählten Eintrag gespeichert werden? Dann wird er bei der nächsten Suche automatisch gefunden! + Soll der Suchtext „%1$s“ im gewählten Eintrag gespeichert werden? Dann wird er bei der nächsten Suche automatisch gefunden! Ungültiges Datums-/Zeitformat für Ablaufdatum! Ein Feldname ist für jeden Eintrag erforderlich. Ein Feldname kann nicht doppelt genutzt werden (%1$s). @@ -382,25 +382,25 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Datenbank-Caching Bewahrt eine Kopie der Datenbankdateien im Cache-Ordner der App auf. Dies ermöglicht die Verwendung von Datenbanken, auch wenn die Datenbankdatei nicht zugänglich ist. Lokale Backups - Erstelle eine lokale Sicherungskopie der Datenbank, nachdem diese erfolgreich geladen wurde. - Aktualisiere lokale Sicherungskopie\u2026 + Eine lokale Sicherungskopie der Datenbank erstellen, nachdem diese erfolgreich geladen wurde. + Lokale Sicherung wird aktualisiert … Lokale Sicherung von %1$s Lokale Backups anzeigen SSL-Zertifikate Bestimme das Verhalten, wenn Zertifikate nicht validiert werden können. Hinweis: du kannst auf deinem Android-Gerät Root-Zertifikate installieren, damit die Validierung gelingt! Cache löschen? - Dadurch werden alle zwischengespeicherten Datenbankdateien gelöscht. Alle Änderungen, die Sie ohne Zugriff auf die Quelldatenbank vorgenommen haben und die noch nicht synchronisiert wurden, gehen verloren! Dennoch fortfahren? + Dadurch werden alle zwischengespeicherten Datenbankdateien gelöscht. Alle Änderungen, die ohne Zugriff auf die Quelldatenbank vorgenommen wurden und noch nicht synchronisiert sind, gehen verloren! Dennoch fortfahren? Auf Änderungen prüfen Vor dem Speichern prüfen, ob die Datei von außerhalb geändert wurde. - Prüfe auf doppelte UUIDs + Auf doppelte UUIDs prüfen Prüfe ob die Datenbank-Datei korrupt ist, weil mehrere Einträge dieselbe ID haben. Das könnte zu unerwartetem Verhalten führen. Zwischenablage-Benachrichtigungen Benutzername und Passwort über die Benachrichtigungsleiste und die Zwischenablage verfügbar machen. Achtung vor Passwort-Sniffern! Separate Benachrichtigungen - Zeige separate Benachrichtigungen zum Kopieren von Benutzername und Passwort in die Zwischenablage und zur Aktivierung der Eingabemethode. + Getrennte Benachrichtigungen zum Kopieren von Benutzername und Passwort in die Zwischenablage und zur Aktivierung der Eingabemethode anzeigen. AutoFill Accessibility-Service AutoFill-Dienst - KP2A-Tastatur Benachrichtigung + KP2A-Tastatur-Benachrichtigung Kompletten Eintrag über die KP2A-Tastatur bereitstellen (empfohlen). Tastatur umschalten Dialog zum Auswählen der Eingabemethode öffnen, wenn ein Eintrag nach Suche aus dem Browser heraus verfügbar ist. @@ -409,20 +409,20 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die KeyboardSwap-Plugin installieren Dieses Plugin erlaubt es, auch ohne gerootetes Gerät automatisch zur KP2A-Tastatur zu wechseln. Benötigt ADB. Automatischer Wechsel nur nach Suche - Nur nach dem Nutzen der \"URL teilen\"-Funktion automatisch zur KP2A-Tastatur wechseln (aber nicht beim Öffnen des Eintrags auf einem anderen Weg) - Tastatur zurück wechseln - Wechsel zur vorigen Eingabemethode wenn kein Eintrag ausgewählt ist + Nur nach Nutzen der Funktion „URL teilen“ automatisch zur KP2A-Tastatur wechseln (aber nicht beim Öffnen des Eintrags auf einem anderen Weg) + Tastatur zurückwechseln + Wechsel zur vorigen Eingabemethode, wenn kein Eintrag ausgewählt ist Benachrichtungssymbol anzeigen, solange entsperrt - Zeige ein Symbol in der Benachrichtigungsleiste, solange die Datenbank entsperrt ist. - Mit Android 8 wurde ein neues Verhalten für Benachrichtigungen eingeführt. Wenn du das Icon für die Benachrichtigungen von Keepass2Android ausblenden möchtest, konfiguriere dies bitte in den Systemeinstellungen. Setze dazu die Wichtigkeit der Benachrichtigungskategorie auf Minimum. + Symbol in der Benachrichtigungsleiste anzeigen, solange die Datenbank entsperrt ist. + Mit Android 8 wurde ein neues Verhalten für Benachrichtigungen eingeführt. Wenn das Symbol für die Benachrichtigungen von Keepass2Android ausgeblendet werden soll, dies bitte in den Systemeinstellungen konfigurieren. Dazu die Wichtigkeit der Benachrichtigungskategorie auf Minimum setzen. Einstellungen öffnen Ist mir egal - Keepass2Android kann nicht mehr auf die Datei zugreifen. Entweder wurde sie entfernt oder die Zugriffsrechte wurden entzogen. Bitte öffne sie erneut, z.B. durch Klick auf \"Datenbank wechseln\". - Datenbank vor-laden - Starte das Laden oder Herunterladen von Datenbank-Dateien im Hintergrund während der Passwort-Eingabe. + Keepass2Android kann nicht mehr auf die Datei zugreifen. Entweder wurde sie entfernt oder die Zugriffsrechte wurden entzogen. Bitte die Datei erneut öffnen, z. B. über „Datenbank wechseln“. + Datenbankdatei vorladen + Das Laden oder Herunterladen von Datenbankdateien im Hintergrund während der Passworteingabe starten. Nach QuickUnlock synchronisieren Datenbank nach Entsperren mit QuickUnlock mit der Remote-Kopie synchronisieren. - Möchtest du den vorhandenen Anhang mit dem gleichen Namen überschreiben? + Soll der vorhandenen Anhang mit dem gleichen Namen überschrieben werden? Vorhandenen Anhang überschreiben? Überschreiben Umbenennen @@ -442,17 +442,17 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Verbesserungen vorschlagen Diese App bewerten KP2A übersetzen - Füge Eintrag hinzu… - Füge Gruppe hinzu… - Lösche Eintrag… - Lösche Gruppe… - Lösche Elemente… - Setze Passwort… - Nehme Änderungen zurück… - Führe Schlüsseltransformationen durch… - Entschlüssele Datenbank… + Eintrag wird hinzugefügt … + Gruppe wird hinzugefügt … + Eintrag wird gelöscht … + Gruppe wird gelöscht … + Elemente werden gelöscht … + Passwort wird gesetzt … + Änderungen werden zurückgenommen … + Schlüsseltransformationen wird durchführt … + Datenbank wird entschlüsselt … Lese Datenbank ein… - Prüfe ob Zieldatei geändert wurde… + Prüfen, ob Zieldatei geändert wurde … Änderungen zusammenführen? Die Datenbankdatei wurde von außerhalb geändert. Sollen diese Änderungen geladen und mit den in Keepass2Android gemachten Änderungen zusammengeführt werden, bevor die Datenbank gespeichert wird? Wähle Nein, um die externen Änderungen zu überschreiben. Führe Änderungen zusammen… @@ -483,7 +483,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die OTP-Hilfsdatei Ein Fehler ist aufgetreten: Datenbank ist beschädigt: IDs kommen mehrfach vor. (Wurde mit Minikeepass gespeichert?) Bitte am PC mit Keepass 2 in eine neue Datenbank re-importieren und „Neue IDs erstellen“ auswählen. - Diese Fehlermeldung kann unter Einstellungen/Anwendungs-Einstellungen/Umgang mit Dateien/Prüfe auf doppelte UUIDs deaktiviert werden. Bitte beachten: Dies kann zu unerwartetem Verhalten führen. Es wird empfohlen, die Datenbank zu reparieren. + Diese Fehlermeldung kann unter Einstellungen/Anwendungseinstellungen/Umgang mit Dateien/Auf doppelte UUIDs prüfen deaktiviert werden. Bitte beachten: Dies kann zu unerwartetem Verhalten führen. Es wird empfohlen, die Datenbank zu reparieren. Datenbank synchronisieren… Kann Gruppe nicht hierher verschieben. Heute ist Oktoberfest! Wenn dir Keepass2Android gefällt: Wäre heute nicht ein guter Tag, um mir ein Bier zu spendieren? @@ -538,7 +538,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Speicherort ändern Wenn aktiviert, läuft Keepass2Android im Hintergrund weiter, auch wenn die Datenbank gesperrt ist. Das ermöglicht das Öffnen der Datenbank mit QuickUnlock. Hauptpasswort - Deine Datenbank wird mit dem hier eingegebenen Passwort verschlüsselt. Wähle ein starkes Passwort, um deine Datenbank zu schützen! Tipp: Denke dir ein oder zwei Sätze aus und nutze die Anfangsbuchstaben als Passwort. Übernimm auch die Satzzeichen. + Die eigene Datenbank wird mit dem hier eingegebenen Passwort verschlüsselt. Dazu ein starkes Passwort verwenden, um die Datenbank zu schützen! Tipp: Sich ein oder zwei Sätze ausdenken und die Anfangsbuchstaben als Passwort nutzen. Auch die Satzzeichen mit einschließen. Wähle ein Master-Passwort, mit dem deine Datenbank geschützt wird: Schlüsseldatei Eine Schlüsseldatei ist im Grunde ein Kennwort, das in einer Datei gespeichert ist. Schlüsseldateien sind üblicherweise stärker als Kennwörter, weil sie deutlich komplexer sein können; allerdings ist es schwerer, sie geheim zu halten. Wird die Datenbank in der Cloud gespeichert, sollte die Schlüsseldatei keinesfalls ebenfalls dort abgelegt werden! Das würde sie völlig nutzlos machen! Wichtig: Den Inhalt der Schlüsseldatei nicht mehr ändern, nachdem die Datenbank angelegt wurde! @@ -648,7 +648,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die • Stelle sicher, dass du die richtige Datenbankdatei gewählt hast. \n - • Hinweis: Wenn du denkst, dass deine Datenbank-Datei beschädigt sein könnte oder du das Passwort nicht mehr weißt, nachdem du es geändert hast, kannst du zur zuletzt erfolgreich geöffneten Datei wechseln. Klicke dazu auf \"%1$s\" und wähle das lokale Backup. + • Tipp: Wenn die Vermutung besteht, die eigene Datenbankdatei könnte beschädigt sein oder sich nach einer Änderung nicht mehr an den Hauptschlüssel erinnern, kann man es mit der zuletzt erfolgreich geöffnete Dateiversion versuchen, indem auf „%1$s“ getippt und die lokale Sicherung ausgewählt wird. \n • Hinweis: Keepass2Android hat die zuletzt erfolgreich geöffnete Dateiversion im internen Speicher gesichert. Du kannst diese öffnen, indem du \"%1$s\" klickst und das lokale Backup wählst. Die Datei ist beschädigt.\n From 92d9eb151272096a84a467ff56e25f2f47898e3f Mon Sep 17 00:00:00 2001 From: PhilippC Date: Sat, 18 Feb 2023 11:15:28 +0100 Subject: [PATCH 015/101] New translations strings.xml (German) --- .../Resources/values-de/strings.xml | 96 +++++++++---------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/src/keepass2android/Resources/values-de/strings.xml b/src/keepass2android/Resources/values-de/strings.xml index 0a490f61..95c3fbd9 100644 --- a/src/keepass2android/Resources/values-de/strings.xml +++ b/src/keepass2android/Resources/values-de/strings.xml @@ -432,8 +432,8 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Soll diese Gruppe endgültig gelöscht werden? Drücke nein, um sie in den Papierkorb zu verschieben. Gewählte Elemente permanent löschen? Nein wählen, um in den Papierkorb zu verschieben. Eintrag permanent löschen? - Gruppe permanent löschen? - Ausgewählte Elemente permanent löschen? + Gruppe endgültig löschen? + Ausgewählte Elemente endgültig löschen? Endgültig löschen? Datei neu laden? Die geöffnete Datei wurde von einem anderen Programm geändert. Möchtest du sie neu laden? @@ -454,45 +454,45 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Lese Datenbank ein… Prüfen, ob Zieldatei geändert wurde … Änderungen zusammenführen? - Die Datenbankdatei wurde von außerhalb geändert. Sollen diese Änderungen geladen und mit den in Keepass2Android gemachten Änderungen zusammengeführt werden, bevor die Datenbank gespeichert wird? Wähle Nein, um die externen Änderungen zu überschreiben. + Die Datenbankdatei wurde von außerhalb geändert. Sollen diese Änderungen geladen und mit den in Keepass2Android gemachten Änderungen zusammengeführt werden, bevor die Datenbank gespeichert wird? Nein wählen, um die externen Änderungen zu überschreiben. Führe Änderungen zusammen… Ja, zusammenführen Nein, überschreiben Nur internen Zwischenspeicher verwenden Zwischengespeicherte Kopie mit der Quelldatei synchronisieren Datenbank wird vom internen Cache geladen. Änderungen werden nur im internen Cache gespeichert und nur synchronisiert, wenn eine Datenbanksynchronisierung manuell ausgewählt wird. - Verwende nur internen Zwischenspeicher. - Gecachte Datenbank synchronisieren … - Quelldatei wird geladen… - Datei speichern… - Quelldatei wird wiederhergestellt… + Nur internen Zwischenspeicher verwenden. + Zwischengespeicherte Datenbank synchronisieren … + Quelldatei wird geladen … + Datei speichern … + Quelldatei wird wiederhergestellt … Remote- und Cache-Dateien sind identisch. Datenbank erfolgreich synchronisiert! Prüfe auf Änderungen der Datenbank… - Quelldatei konnte nicht gespeichert werden: %1$s. Erneut speichern oder verwende das Menü „Synchronisieren”, sobald die Datei wieder verfügbar ist. - Auf die Quelldatei konnte nicht zugegriffen werden: %1$s. Datei wurde aus dem internen Zwischenspeicher geladen. Du kannst weiterhin Änderungen in der Datenbank vornehmen und diese später synchronisieren. + Quelldatei konnte nicht gespeichert werden: %1$s. Erneut speichern oder das Menü „Synchronisieren” verwenden, sobald die Datei wieder verfügbar ist. + Auf die Quelldatei konnte nicht zugegriffen werden: %1$s. Die Datei wurde aus dem internen Zwischenspeicher geladen. Es können weiterhin Änderungen in der Datenbank vorgenommen und diese später synchronisiert werden. Quelldatei aktualisiert. - Interne Datei aus dem Zwischenspeicher geöffnet wegen Konflikten mit Änderungen in der Quelldatei. Verwende das Menü „Synchronisieren” zum Zusammenführen. + Intern zwischengespeicherte Datei wurde aufgrund eines Konflikts mit Änderungen in der Quelldatei geöffnet. Bitte das Menü „Synchronisieren” zum Zusammenführen verwenden. Quelldatei und Zwischenspeicher sind auf dem gleichen Stand. Die intern zwischengespeicherte Kopie der %1$s wurde aktualisiert. Keine Änderungen gefunden. Die zwischengespeicherte OTP-Hilfsdatei wurde aktualisiert: Der Quellenzähler war höher. Die zwischengespeicherte OTP-Hilfsdatei wurde aktualisiert: Der lokale Zähler war höher. - Synchronisiere OTP-Hilfsdatei… + OTP-Hilfsdatei wird synchronisiert … Datenbankdatei OTP-Hilfsdatei Ein Fehler ist aufgetreten: Datenbank ist beschädigt: IDs kommen mehrfach vor. (Wurde mit Minikeepass gespeichert?) Bitte am PC mit Keepass 2 in eine neue Datenbank re-importieren und „Neue IDs erstellen“ auswählen. Diese Fehlermeldung kann unter Einstellungen/Anwendungseinstellungen/Umgang mit Dateien/Auf doppelte UUIDs prüfen deaktiviert werden. Bitte beachten: Dies kann zu unerwartetem Verhalten führen. Es wird empfohlen, die Datenbank zu reparieren. - Datenbank synchronisieren… - Kann Gruppe nicht hierher verschieben. + Datenbank synchronisieren … + Die Gruppe kann nicht in diese Gruppe verschoben werden. Heute ist Oktoberfest! Wenn dir Keepass2Android gefällt: Wäre heute nicht ein guter Tag, um mir ein Bier zu spendieren? 10. Mai? Heute ist mein Geburtstag! Wenn du diese App magst, warum schickst du mir nicht ein paar Geburtstagsgrüße zusammen mit einem kleinen Geburtstagsgeschenk? Das würde mich wirklich freuen! :-) - Oh, du hast meinen Geburtstag am 10. Mai verpasst! Wenn du diese App magst, warum schickst du mir nicht ein paar Geburtstagsgrüße zusammen mit einem kleinen Geburtstagsgeschenk? Es ist noch nicht zu spät um mir eine Freude zu machen! :-) + Oh, mein Geburtstag am 10. Mai wurde verpasst! Wenn diese App gefällt, warum nicht ein paar Geburtstagsgrüße zusammen mit einem kleinen Geburtstagsgeschenk an mich senden? Es ist noch nicht zu spät, um mir eine Freude zu machen! :-) Warum nicht? So gut gefällt\'s mir dann auch nicht WebDav-Zugangsdaten eingeben: - URL des Ordners oder der Datei (z.B. mycloud.me.com/webdav/) + URL des Ordners oder der Datei (z. B. mycloud.me.com/webdav/) OwnCloud-Zugangsdaten eingeben: OwnCloud-URL (z.B. owncloud.me.com) Nextcloud Logindaten eingeben: @@ -504,7 +504,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Authentifizierungsmodus Öffentlichen Schlüssel senden … FTP-Zugangsdaten eingeben: - Geben Sie Ihre MEGA-Zugangsdaten ein: + MEGA-Zugangsdaten eingeben: Speichertyp wählen: Lokale Datei Mit externer App suchen @@ -519,9 +519,9 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Wenn du Keepass2Android nicht den Zugriff auf die gesamte Dropbox erlauben möchtest, kannst du diese Option wählen. Dann musst du nur Zugriff auf den Ordner Apps/Keepass2Android gewähren. Das ist besonders sinnvoll, wenn du eine neue Datenbank anlegst. Wenn du schon eine Datenbank hast, wähle diese Option aus um den Ordner anzulegen, kopiere die Datei (vom PC aus) in den neuen Ordner und wähle die Option dann erneut zum Laden der Datei. Google Drive Google Drive (KP2A-Dateien) - Wenn Sie KP2A keinen Zugriff auf Ihr vollständiges Google Drive geben möchten, können Sie diese Option auswählen. Beachten Sie, dass Sie zuerst eine Datenbankdatei erstellen müssen; vorhandene Dateien sind für die App nicht sichtbar. Wählen Sie diese Option entweder auf dem \"Datenbank erstellen\" Bildschirm oder, wenn Sie bereits eine Datenbank geöffnet haben, indem Sie die Datenbank mit dieser Option exportieren. + Wenn KP2A keinen Zugriff auf das komplette eigenen Google Drive erhalten soll, kann diese Option gewählte werden. Bitte beachten, dass zuerst eine Datenbankdatei erstellt werden muss; vorhandene Dateien sind für die App nicht sichtbar. Diese Option entweder auf dem Bildschirm „Datenbank erstellen“ auswählen oder, wenn bereits eine Datenbank geöffnet wurde, indem die Datenbank mit dieser Option exportiert wird. PCloud - Dieser Speichertyp verlangt nur Zugriff auf den pCloud-Ordner \"Applications/Keepass2Android\". Wenn Sie eine existierende Datenbank aus Ihrem pCloud-Konto verwenden möchten, stellen Sie bitte sicher, dass die Datei in diesem pCloud-Ordner gespeichert ist. + Dieser Speichertyp verlangt nur Zugriff auf den pCloud-Ordner „Applications/Keepass2Android“. Wenn eine vorhandene Datenbank aus dem eigenen pCloud-Konto verwendet werden soll, bitte sicherstellen, dass die Datei in diesem pCloud-Ordner gespeichert ist. OneDrive OneDrive Alle Dateien und freigegebene Dateien @@ -529,12 +529,12 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Ordner der Keepass2Android-App SFTP (SSH File Transfer) MEGA - Bitte beachten: Keepass2Android muss die Liste aller Dateien in Ihrem Mega-Konto herunterladen, um ordnungsgemäß zu funktionieren. Aus diesem Grund ist der Zugriff auf Konten mit vielen Dateien möglicherweise langsam. + Bitte beachten: Keepass2Android muss die Liste aller Dateien des Mega-Konto herunterladen, um ordnungsgemäß zu funktionieren. Aus diesem Grund ist der Zugriff auf Konten mit vielen Dateien möglicherweise langsam. Android-Dateibrowser Dateizugriff initialisieren Speicherort der Datenbank - Du kannst deine Datenbank lokal auf deinem Android-Gerät oder in der Cloud speichern (nur in der Nicht-Offline-Version). Keepass2Android macht die Datenbank dann auch verfügbar, wenn du offline bist. Da die Datenbank sicher mit der AES 256-Bit-Verschlüsselung geschützt ist, erhält auch dann niemand außer dir Zugriff auf deine Datenbank. Wir empfehlen die Benutzung von Dropbox: Es ist auf allen Geräten verfügbar und bietet automatisch Backups aller Dateiversionen. - Wähle, wo du deine Datenbank speichern möchtest: + Die eigene Datenbank kann lokal auf diesem Android-Gerät oder in der Cloud gespeichert werden (nur in der Nicht-Offline-Version). Keepass2Android macht die Datenbank dann auch verfügbar, wenn man offline ist. Da die Datenbank sicher mit der AES 256-Bit-Verschlüsselung geschützt ist, erhält auch dann niemand außer man selbst Zugriff auf die Datenbank. Wir empfehlen die Nutzung von Dropbox: Es ist auf allen Geräten verfügbar und bietet automatisch Backups aller Dateiversionen. + Wählen, wo die Datenbank gespeichert werden soll: Speicherort ändern Wenn aktiviert, läuft Keepass2Android im Hintergrund weiter, auch wenn die Datenbank gesperrt ist. Das ermöglicht das Öffnen der Datenbank mit QuickUnlock. Hauptpasswort @@ -543,40 +543,40 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Schlüsseldatei Eine Schlüsseldatei ist im Grunde ein Kennwort, das in einer Datei gespeichert ist. Schlüsseldateien sind üblicherweise stärker als Kennwörter, weil sie deutlich komplexer sein können; allerdings ist es schwerer, sie geheim zu halten. Wird die Datenbank in der Cloud gespeichert, sollte die Schlüsseldatei keinesfalls ebenfalls dort abgelegt werden! Das würde sie völlig nutzlos machen! Wichtig: Den Inhalt der Schlüsseldatei nicht mehr ändern, nachdem die Datenbank angelegt wurde! Wählen, ob eine Schlüsseldatei zusätzlich zum Hauptpasswort verwendet werden soll: - Schlüsseldatei benutzen + Schlüsseldatei verwenden Fehler beim Hinzufügen der Schlüsseldatei! - OTP-Hilfsdatei laden… - Gib die nächsten Einmalkennwörter (OTPs - One-Time-Passwords) an. Bewege deinen Yubikey NEO an der Rückseite deines Gerätes, für die Eingabe per NFC (erfordert Yubiclip-App). + OTP-Hilfsdatei laden … + Nächsten Einmalkennwörter (OTPs) eingeben. Den Yubikey NEO für die Eingabe per NFC an der Rückseite dieses Gerätes vorbeiziehen (erfordert Yubiclip-App). OTP %1$d - Konnte OTP-Hilfsdatei nicht laden! - Bitte nutze das OtpKeyProv-Plugin in Keepass 2.x (PC) um deine Datenbank zur Verwendung von One-Time-Passwords einzurichten! + OTP-Hilfsdatei konnte nicht geladen werden! + Bitte das OtpKeyProv-Plugin in Keepass 2.x (PC) verwenden, um die Datenbank zur Verwendung von One-Time-Passwords einzurichten! Bitte erst Datenbank laden. OTP wird aus Sicherheitsgründen verworfen. OTP verworfen. Alle OTPs bereits eingegeben! Bitte zuerst die aktuelle Datenbank schließen. OTP wird verworfen. (Ein oder mehrere OTPs bereits verfügbar) - OTP Secret (z.B. 01 23 ab cd…) + OTP-Secret (z. B. 01 23 ab cd …) Fehler beim Parsen des OTP-Secrets! - Fehler beim Erstellen des OTP-Schlüssels! Bitte stelle sicher, dass du die richtigen OTPs eingegeben hast. + Fehler beim Erstellen des OTP-Schlüssels! Bitte sicherstellen, dass die richtigen OTPs eingegeben wurden. Fehler beim Aktualisieren der OTP-Hilfsdatei! - Speichere OTP-Hilfsdatei… + OTP-Hilfsdatei wird gespeichert … Es konnte keine App gefunden werden, die diese Anforderung verarbeiten kann. - Bitte installiere %1$s von Google Play. + Bitte %1$s von Google Play installieren. %1$s wird nicht mehr unterstützt. Die Challenge-Antwort ist falsch. Die externe Challenge-Datei konnte nicht geladen werden! - Bitte verwende das KeeChallenge-Plugin in KeePass 2.x (PC) um die Datenbank für die Verwendung von Challenge-Response zu konfigurieren! + Bitte das KeeChallenge-Plugin in KeePass 2.x (PC) verwenden, um die Datenbank für die Verwendung von Challenge-Response zu konfigurieren! Fehler beim Aktualisieren der OTP-Hilfsdatei! TOTP-Seed-Feldname - Wenn du das Keepass 2-Plugin \"TrayTotp\" nicht mit Standard-Einstellungen verwendest, gib den Feldnamen für das Seed-Feld entsprechend der Einstellungen am PC an. + Wenn das Keepass 2-Plugin „TrayTotp“ nicht mit Standardeinstellungen verwendet wird, den Feldnamen für das Seed-Feld entsprechend der Einstellungen am PC angeben. Feldname für TOTP-Einstellungen Feldnamen für TOTP-Einstellungen entsprechend den TrayTotp-Einstellungen eingeben. TrayTotp - Log-Datei (für Debugging) - Log-Datei benutzen - Ausgabe der Anwendung in eine lokale Log-Datei schreiben - Debug-Log senden\u2026 + Logdatei (für Debugging) + Logdatei verwenden + Ausgabe der Anwendung in eine lokale Logdatei schreiben + Debug-Log senden … Lade… - Plug-ins + Plugins Paketname: Beschreibung (nicht überprüft): Autor (nicht überprüft): @@ -597,21 +597,21 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Anmeldeinformationen abfragen Das Plugin wird berechtigt, Anmeldeinformationen für selbst ausgewählte Websites oder Anwendungen abzufragen. Weitere Speichertypen bekommen - Warnung: Server-Zertifikat konnte nicht validiert werden: %1$s. Installiere ein passendes Root-Zertifikat auf deinem Gerät oder s. Einstellungen. - Fehler: Server-Zertifikat konnte nicht validiert werden! Installiere ein passendes Root-Zertifikat auf deinem Android-Gerät oder s. Einstellungen! + Warnung: Serverzertifikatsüberprüfung fehlgeschlagen: %1$s. Bitte ein passendes Root-Zertifikat auf diesem Gerät installieren oder in die Einstellungen schauen! + Fehler: Serverzertifikatsüberprüfung fehlgeschlagen: %1$s. Bitte ein passendes Root-Zertifikat auf diesem Gerät installieren oder in die Einstellungen schauen! Dateiformat wählen - Entschuldigung! Keepass2Android wurde vom Android OS beendet! Aus Sicherheitsgründen hat Keepass2Android die ausgewählten Anmeldeinformationen nicht dauerhaft gespeichert, weshalb die Datenbank erneut geöffnet werden muss. Hinweis: Dies sollte nur sehr selten vorkommen. Wenn das passiert, schreibe mir bitte eine Nachricht an crocoapps@gmail.com. + Entschuldigung! Keepass2Android wurde vom Android OS beendet! Aus Sicherheitsgründen hat Keepass2Android die ausgewählten Anmeldeinformationen nicht dauerhaft gespeichert, weshalb die Datenbank erneut geöffnet werden muss. Hinweis: Dies sollte nur sehr selten vorkommen. Wenn das passiert, mir bitte eine Nachricht an crocoapps@gmail.com zukommen lassen. Die Datei ist nur kurzzeitig für Keepass2Android verfügbar. The gewählte Datei ist schreibgeschützt. - The gewählte Datei kann aufgrund von Beschränkungen in Android 4.4+ von Keepass2Android nicht geändert werden. - Um sie zu benutzen, musst sie an einen anderen Speicherort kopiert werden. + Die gewählte Datei kann aufgrund von Beschränkungen in Android 4.4+ von Keepass2Android nicht geändert werden. + Um sie verwenden zu können, muss sie an einen anderen Speicherort kopiert werden. Um sie zu bearbeiten, muss sie an einen anderen Speicherort kopiert werden. - Tippe auf OK, um einen Speicherort zu wählen. + Auf OK tippen, um einen Speicherort zu wählen. Datenbank ist schreibgeschützt Keepass2Android hat die Datenbank im Lese-Modus geöffnet. - Es scheint als hättest du die Datei über eine externe App geöffnet. Diese Vorgehensweise unterstützt keinen Schreibzugriff. Wenn du Änderungen in der Datenbank vornehmen möchtest, schließe die Datenbank und wähle Datenbank wechseln. Öffne dann die Datei mit einer der angebotenen Optionen. - Datei ist schreibgeschützt. Entferne das Attribut, um Änderungen an der Datenbank vorzunehmen. - Das Speichern ist aufgrund von Einschränkungen, die in Android KitKat eingeführt wurden, nicht möglich. Wenn du Änderungen in der Datenbank vornehmen möchtest, schließe die Datenbank und wähle Datenbank wechseln. Öffne die Datei dann über die System-Dateiauswahl. + Es scheint, dass die Datei von einer externen Anwendung aus geöffnet wurde. Über diesen Weg ist das Schreiben nicht möglich. Wenn Änderungen an der Datenbank vorgenommen werden sollen, bitte die Datenbank schließen und „Datenbank wechseln“ wählen. Danach die Datei über eine der verfügbaren Optionen öffnen, sofern möglich. + Datei ist schreibgeschützt. Diese Attribut entfernen, wenn Änderungen an der Datenbank vorgenommen werden sollen. + Das Speichern ist aufgrund von Einschränkungen, die in Android KitKat eingeführt wurden, nicht möglich. Wenn Änderungen an der Datenbank vorgenommen werden sollen, bitte die Datenbank schließen und „Datenbank wechseln“ wählen. Danach die Datei über die systeminterne Dateiauswahl öffnen. Lokale Sicherungskopien können nicht bearbeitet werden. Du kannst über \"Datenbank-Einstellungen\" - \"Datenbank exportieren\" dieses Backup an einen anderen Ort exportieren und dann von dort öffnen. Dann kannst du auch wieder Änderungen vornehmen. Icon aus Datei hinzufügen... Kopiere Datei\u2026 @@ -635,7 +635,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Mitgliedschaft Neuigkeiten Vorlagen hinzufügen? - Keepass2Android kann Vorlagen für E-Mail Accounts, W-LAN-Passwörter, sichere Notizen und mehr erstellen. Sollen diese der Datenbank hinzugefügt werden? Dies kann auch später über die Datenbankeinstellungen gemacht werden. + Keepass2Android kann Vorlagen für E-Mail-Konten, WLAN-Passwörter, sichere Notizen und mehr erstellen. Sollen diese der Datenbank hinzugefügt werden? Diese können auch später über die Datenbankeinstellungen hinzugefügt werden. Vorlagen zu Datenbank hinzufügen Bitte beachten! Dies ist eine Vorab-Version, die einige Fehler enthalten könnte! Wenn du *irgendetwas* unerwartetes feststellen solltest, lass es mich bitte wissen (über die Google+ Beta-Tester-Community oder per E-Mail). Fortfahren From d8598a53e0ea2e261d7e1eb33d2409bc4c4509f5 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Sat, 18 Feb 2023 17:41:17 +0100 Subject: [PATCH 016/101] New translations strings.xml (Japanese) --- src/keepass2android/Resources/values-ja/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keepass2android/Resources/values-ja/strings.xml b/src/keepass2android/Resources/values-ja/strings.xml index f7e6a874..878416a0 100644 --- a/src/keepass2android/Resources/values-ja/strings.xml +++ b/src/keepass2android/Resources/values-ja/strings.xml @@ -37,7 +37,7 @@ エントリー画面にグループ名を表示 申し訳ありません! Keepass2Android は、返された URI %1$s を処理できませんでした。開発者にお問い合わせください! 1 エントリー - %1$d エントリー + %1$d 件のエントリー アイコンセット さらに探す… セキュリティ From 34cac86a9b48a0ef2d43a18783e74b484b554535 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Sat, 18 Feb 2023 18:58:40 +0100 Subject: [PATCH 017/101] New translations strings.xml (German) --- .../Resources/values-de/strings.xml | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/keepass2android/Resources/values-de/strings.xml b/src/keepass2android/Resources/values-de/strings.xml index 95c3fbd9..a9e8845e 100644 --- a/src/keepass2android/Resources/values-de/strings.xml +++ b/src/keepass2android/Resources/values-de/strings.xml @@ -639,25 +639,25 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Vorlagen zu Datenbank hinzufügen Bitte beachten! Dies ist eine Vorab-Version, die einige Fehler enthalten könnte! Wenn du *irgendetwas* unerwartetes feststellen solltest, lass es mich bitte wissen (über die Google+ Beta-Tester-Community oder per E-Mail). Fortfahren - Der eingegebene Pfad scheint kein gültiger Dateiname zu sein. Bist du sicher, dass es sich um eine gültige Datei handelt? + Der eingegebene Pfad scheint kein gültiger Dateiname zu sein. Ist dies wirklich eine gültige Datei? Ungültiger zusammengesetzter Schlüssel! Bitte erneut probieren. - Ungültiger zusammengesetzter Schlüssel! Bitte probiere die folgenden Schritte, um die Datenbank zu entsperren:\n + Ungültiger zusammengesetzter Schlüssel! Bitte folgenden Schritte probieren, um die Datenbank zu entsperren:\n - • Stelle sicher, dass du das richtige Passwort eingegeben hast. Das Augensymbol kann genutzt werden um das eingegebene Passwort anzuzeigen.\n - • Stelle sicher, dass du den richtigen Passworttyp ausgewählt hast. Er muss mit dem Typ übereinstimmen, der beim Erstellen der Datenbank gewählt wurde.\n - • Stelle sicher, dass du die richtige Datenbankdatei gewählt hast. + • Sicherstellen, dass das richtige Passwort eingegeben wurde. Das Augensymbol dafür nutzen, um das eingegebene Passwort anzuzeigen.\n + • Sicherstellen, dass der richtigen Passworttyp ausgewählt wurde. Er muss mit dem Typ übereinstimmen, der beim Erstellen der Datenbank gewählt wurde.\n + • Sicherstellen, dass die richtige Datenbankdatei gewählt wurde. \n - • Tipp: Wenn die Vermutung besteht, die eigene Datenbankdatei könnte beschädigt sein oder sich nach einer Änderung nicht mehr an den Hauptschlüssel erinnern, kann man es mit der zuletzt erfolgreich geöffnete Dateiversion versuchen, indem auf „%1$s“ getippt und die lokale Sicherung ausgewählt wird. + • Tipp: Wenn die Vermutung besteht, die eigene Datenbankdatei könnte beschädigt sein oder sich nach einer Änderung nicht mehr an den Hauptschlüssel erinnern wird, kann man es mit der zuletzt erfolgreich geöffnete Dateiversion versuchen, indem auf „%1$s“ getippt und die lokale Sicherung ausgewählt wird. \n -• Hinweis: Keepass2Android hat die zuletzt erfolgreich geöffnete Dateiversion im internen Speicher gesichert. Du kannst diese öffnen, indem du \"%1$s\" klickst und das lokale Backup wählst. +• Tipp: Keepass2Android hat die zuletzt erfolgreich geöffnete Dateiversion im internen Speicher gesichert. Diese kann geöffnet werden, indem „%1$s“ angetippt und das lokale Backup gewählte wird. Die Datei ist beschädigt.\n -Anbei einige Hinweise, die bei der Diagnose des Problems helfen können:\n +Anbei einige Tipps, die bei der Diagnose des Problems helfen können:\n -• Wenn du die Datei über USB kopiert hast (MTP-Modus), versuche es noch einmal mit Tools wie MyPhoneExplorer. MTP schneidet die Dateien in manchen Fällen ab.\n -• Wenn du die Datei nicht von der gleichen Stelle auf deinem PC öffnen kannst, ist es sehr wahrscheinlich, dass die Datei tatsächlich beschädigt ist. Bitte verwende in diesem Fall eine Datenbanksicherung. Wenn du annimmst, dass Keepass2Android die Datei beschädigt hat, nimm bitte Kontakt mit dem Support auf.\n -• Wenn du die Datei auf dem PC noch öffnen kannst, nimm bitte Kontakt mit dem Support auf. Du kannst versuchen, die Datei mit anderen Einstellungen auf dem PC zu speichern (z.B. nicht ZIP-komprimiert) und sie dann noch einmal in Keepass2Android zu öffnen. - Öffne weitere Datenbank… +• Wenn die Datei über USB kopiert wurde (MTP-Modus), es noch einmal mit Tools wie MyPhoneExplorer versuchen. MTP schneidet in manchen Fällen die Dateien ab.\n +• Wenn sich die Datei vom gleichen Speicherort nicht auf dem PC öffnen lässt, ist es sehr wahrscheinlich, dass die Datei tatsächlich beschädigt ist. Bitte in diesem Fall eine Datenbanksicherung verwenden. Wenn der Verdacht besteht, dass Keepass2Android die Datei beschädigt hat, bitte Kontakt mit dem Support aufnehmen.\n +• Wenn sich die Datei auf dem PC noch öffnen lässt, bitte Kontakt mit dem Support aufnehmen. Man kann versuchen, die Datei mit anderen Einstellungen auf dem PC zu speichern (z. B. unkomprimiert) und sie dann noch einmal in Keepass2Android zu öffnen. + Weitere Datenbank öffnen … Datenbank auswählen Kinddatenbanken konfigurieren … Kinddatenbanken From 40847ebe31c74d2b598ca02a008520a776a803b7 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Sat, 18 Feb 2023 19:55:30 +0100 Subject: [PATCH 018/101] New translations strings.xml (German) --- .../Resources/values-de/strings.xml | 108 +++++++++--------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/src/keepass2android/Resources/values-de/strings.xml b/src/keepass2android/Resources/values-de/strings.xml index a9e8845e..4b88a337 100644 --- a/src/keepass2android/Resources/values-de/strings.xml +++ b/src/keepass2android/Resources/values-de/strings.xml @@ -667,51 +667,51 @@ Anbei einige Tipps, die bei der Diagnose des Problems helfen können:\n Auf diesem Gerät aktivieren Auf diesem Gerät deaktivieren Kopie für dieses Gerät - Deine Datenbank enthält neue Kinddatenbanken in der Gruppe \"AutoOpen\". Bitte gib an, wenn diese Kinddatenbanken auf diesem Gerät verwendet werden sollen. - Füge Kinddatenbank hinzu\u2026 + Die Datenbank enthält neue Kinddatenbanken in der Gruppe „AutoOpen“. Bitte angeben, ob diese Kinddatenbanken auf diesem Gerät verwendet werden sollen. + Kinddatenbank hinzufügen … Hiermit wird eine Kopie der Kinddatenbank-Einstellungen erstellt und aktiviert. Diese kopierten Einstellungen können dann speziell für dieses Gerät verändert werden. Sichtbar Automatisch öffnen Datenbankdatei - Aktiviere für %1$s + Für %1$s aktivieren Diese Version wiederherstellen Diese Version entfernen Datenbank entsperrt - Benachrichtigung wenn die Datenbank entsperrt ist + Benachrichtigung über das Entsperren der Datenbank QuickUnlock - Benachrichtigung wenn die Datenbank mit QuickUnlock gesperrt ist + Benachrichtigung über das Sperren der Datenbank mit QuickUnlock Eintrag-Benachrichtigungen Benachrichtigung zum schnellen Zugriff auf den aktuell gewählten Eintrag. Datenbank nach drei fehlgeschlagenen biometrischen Entsperrversuchen schließen. Achtung! Die biometrische Authentifizierung kann von Android ungültig gemacht werden, z. B. nach dem Hinzufügen eines neuen Fingerabdrucks in den Geräteeinstellungen. Bitte sicherstellen, dass jederzeit klar ist, wie mit dem eigenen Hauptpasswort entsperrt werden kann! - Bugfix um Abstürze und unerwartetes Ausloggen zu vermeiden + Fehlerbehebung, um Abstürze und unerwartetes Abmelden zu vermeiden Wechsel auf eine neue SFTP-Implementierung, jetzt mit Unterstützung von modernen Public-Key-Algorithmen wie rsa-sha2-256 Passwörter werden beim Kopieren in die Zwischenablage als vertraulich markiert (Android 13) Unterstützung für das Ansehen, Entfernen und Wiederherstellen von Eintragssicherungen hinzugefügt - Unterstützung für MEGA Cloudspeicher hinzugefügt + Unterstützung für MEGA-Cloudspeicher hinzugefügt Unterstützung für Google Drive mit eingeschränktem Anwendungsbereich hinzugefügt - Google Drive Authentifizierung wieder eingebaut, Google Drive Unterstützung wieder aktiviert + Google-Drive-Authentifizierung erneut implementiert, Google-Drive-Unterstützung wieder aktiviert - Bugfix für schnell verschwindende Autofill-Anzeige in Firefox + Verschwundenen Nachfrage für Autofill in Firefox korrigiert Vorschläge für automatisches Ausfüllen in die Tastatur integriert (benötigt Android 11+) - Option zum Verändern der Sprache innerhalb der App + Ändern der App-Sprache in den Einstellungen zulassen Option zum Synchronisieren der Datenbank nach QuickUnlock hinzugefügt - Bugfix: Dateinamen werden beim Speichern auf Dropbox nicht mehr in Kleinbuchstaben gewandelt + Fehlerbehebung: Dateinamen beim Speichern in Dropbox nicht in Kleinbuchstaben umwandeln Unterstützung für das KDBX-4.1-Dateiformat (in KeePass 2.48 eingeführt) implementiert Dialog zum Konfigurieren der TOTP-Einstellungen von Einträgen hinzugefügt - Passwort-Generator verbessert: Unterstützung für Passphrases, mehr Einstellmöglichkeiten, Profile und Schätzung der Passwortstärke hinzugefügt + Passwortgenerator verbessert: Unterstützung für Passphrases, mehr Einstellmöglichkeiten, Profile und Schätzung der Passwortstärke hinzugefügt Verbesserungen bei Autofill: Bugfix bzgl. nicht angezeigtem Popup in Chrome, bessere Unterstützung für Subdomains Verbesserungen bei OneDrive: keine Größenbegrenzung mehr, keine unnötigen Authentifizierungsanfragen - Option hinzugefügt, um das helle/dunkel Design anhand der Systemeinstellungen zu wählen, erfordert Android 10+ - Dropbox-Implementierung aktualisiert um neue Authentifizierungsmethode zu unterstützen. + Option hinzugefügt, um das helle/dunkle Design anhand der Systemeinstellungen zu wählen, erfordert Android 10+ + Dropbox-Implementierung aktualisiert, um neue Authentifizierungsmethode zu unterstützen. Neu eingerichtetes Entsperren mit Fingerabdruck wird ungültig, wenn ein Fingerabdruck in den Systemeinstellungen hinzugefügt wird (um die Sicherheit zu erhöhen). Öffnen von Dateien über den Systemdialog ermöglicht, das Nur-Lesen-Attribut wird ignoriert. Das Verschieben von Einträgen kann nun aus der Eintragsansicht begonnen werden. @@ -720,38 +720,38 @@ Anbei einige Tipps, die bei der Diagnose des Problems helfen können:\n Unterstützung für neues Schlüsseldateiformat aus KeePass 2.47 integriert Unterstützung für Argon2id als Schlüsselableitungsfunktion integriert Kompatibilität von Autofill mit Firefox und Chrome verbessert - Unterstützung für zeitbasierte One-Time-Passwords (TOTP) von Desktop-Programmen verbessert + Unterstützung für zeitbasierte Einmal-Passwörter (TOTP) von Desktop-Programmen verbessert pCloud-SDK aktualisiert, um ein Authentifizierungsproblem zu beheben Jsch auf Version 0.1.55 aktualisiert - Menü zum Datenbank-Auswahl-Bildschirm hinzugefügt + Menü zum Datenbankauswahlbildschirm hinzugefügt Importierte Schlüsseldateien können nun exportiert werden Paketnamen von Android-Apps werden nicht mehr im URL-Feld gespeichert - Verbessertes Sperrverhalten - Keine Anzeige der biometrischen Eingabeaufforderung direkt nach dem Entsperren - OkHttp aktualisiert um HTTP/2 zu unterstützen + Verbessertes Sperrverhalten – keine Anzeige der biometrischen Eingabeaufforderung direkt nach dem Entsperren + OkHttp aktualisiert, um HTTP/2 zu unterstützen Fehlende Übersetzungen behoben - Erzwingen von HTTP/1.1 aufgrund eines Problems mit der HTTP/2-Implementierung von OkHttp + HTTP/1.1 aufgrund eines Problems mit HTTP/2-Implementierung von OkHttp erzwingen Tastaturdialog auf Android 9+ verbessert Dateizuordnungen der App geändert, um unnötige Verknüpfungen zu vermeiden Sicherstellen, dass der Passworttext nicht hinter dem Augensymbol versteckt ist - Ändern des Auto-Fill-Verhaltens, um beim Ausfüllen von Anmeldedaten für eine Domain un eine unbekannte App zu warnen + Ändern des Auto-Fill-Verhaltens, um beim Ausfüllen von Anmeldedaten für eine Domain in eine unbekannte App zu warnen FTP-Bibliothek aktualisiert Mögliche Abstürze der App behoben Weitere kleinere Korrekturen Schalfläche in der Benachrichtigung hinzugefügt, um TOTPs in die Zwischenablage zu kopieren - Wechsel zu FluentFTP um TLS 1.2 zu unterstützen - Wechsel zur BiometricPrompt-API, um die Fingerabdruckentsperrung zu verbessern; erlaubt die Verwendung von Face-Unlock z.B. auf Pixel 4. - Fehlerbehebungen + Wechsel zu FluentFTP, um TLS 1.2 zu unterstützen + Wechsel zur BiometricPrompt-API, um die Fingerabdruckentsperrung zu verbessern; erlaubt die Verwendung von Face-Unlock z. B. auf Pixel 4. + Fehlerkorrekturen Version 1.07b\n * Verbesserung der Leistung von Argon2 durch die Verwendung einer nativen Implementierung (Danke an Chih-Hsuan Yen!)\n - * Der Fingerabdruck-Leser kann durch anklicken des Fingerabdruck-Symbols deaktiviert werden (das vermeidet Probleme mit Lesern unter der Displayoberfläche, Danke an marcoDallas!)\n - * Cursor-Position wird nach Änderung der Sichtbarkeit von KennwÖrtern wiederhergestellt (Danke an DDoSolitary!)\n + * Der Fingerabdruck-Leser kann durch Anklicken des Fingerabdrucksymbols deaktiviert werden (das vermeidet Probleme mit Lesern unter der Displayoberfläche, Danke an marcoDallas!)\n + * Cursorposition wird nach Änderung der Sichtbarkeit von Kennwörtern wiederhergestellt (Danke an DDoSolitary!)\n * Verbesserungen bei der pCloud-Implementierung (noch einmal Danke an gilbsgilbs!)\n * AutoFill-Unterstützung für verschiedene weitere Browser hinzugefügt \n * Neue Implementierung für OneDrive: einschließlich Unterstützung für OneDrive for Business, geteilte Dateien, auswählbare Zugriffsbereiche, mehrere Konten und Behebung von Problemen mit Offline-Zugriff\n @@ -775,43 +775,43 @@ Anbei einige Tipps, die bei der Diagnose des Problems helfen können:\n * TLS-Implementierung für FTPS gewechselt, Workaround wegen eines JSch-Bugs integriert (betrifft Server, die gssapi-with-mic unterstützen)\n * Fehler behoben\n Version 1.05\n - • Verwendung von Benachrichtigungskanälen in Android 8. So können Benachrichtigungen über die Systemeinstellungen konfiguriert werden.\n - • Eintrags-Icon wird in Benachrichtigungen angezeigt\n - • Adaptive App-Launcher-Icons für Android 8 und rundes App-Launcher-Icon für Android 7\n + • Verwenden von Benachrichtigungskanälen in Android 8. So können Benachrichtigungen über die Systemeinstellungen konfiguriert werden.\n + • Eintragsymbol wird in Benachrichtigungen angezeigt\n + • Adaptive App-Launcher-Symbol für Android 8 und rundes App-Launcher-Symbol für Android 7\n • Suche kann nach dem Entsperren aktiviert werden (s. Einstellungen)\n • Fehler beim Schreiben von Dateien über das Storage-Access-Framework behoben. Dadurch wird ein Problem behoben, wenn Dateien über den Android-Dateibrowser aus Google Drive geöffnet werden.\n • Einige Infotexte ergänzt, um häufig auftretende Missverständnisse zu vermeiden.\n • Nach erfolgreichem Öffnen wird eine lokale Sicherungskopie der Datenbank angelegt, um das Risiko von Datenverlust zu reduzieren.\n - • JSch aktualisiert um aktuelle SSH-Verschlüsselungsalgorithmen zu unterstützen\n + • JSch aktualisiert, um aktuelle SSH-Verschlüsselungsalgorithmen zu unterstützen\n • Unterstützung für den statischen Passwortmodus des Yubikey Neo integriert.\n • Die Autofill-Empfehlung kann leichter deaktiviert werden\n - • Fix für u.U. nach Logcat geschriebene private Daten.\n - • Bugfixes\n + • Fix für gegebenenfalls nach Logcat geschriebene private Daten.\n + • Fehlerkorrekturen\n Version 1.04b\n -• Fix für App-Crash beim Aktivieren von Autofill auf Huawei-Geräten.\n +• Korrektur für App-Crash beim Aktivieren von Autofill auf Huawei-Geräten.\n Version 1.04\n • Autofill-Dienst für Android 8.0 und höher implementiert.\n • Bibliotheken und Build-Tools aktualisiert.\n Version 1.03\n -* Accessibility-Service für AutoFill entfernt, da dies von Google gefordert wurde. Gehe in die Passwort-Zugriff-Einstellungen für einen Link zu einem Plugin, das die zuvor integrierte Funktionalität wieder bereitstellen kann.\n +* Accessibility-Service für AutoFill entfernt, da dies von Google gefordert wurde. Unter Passwortzugangseinstellungen findet sich ein Plugin, das die frühere Funktionalität nachbildet.\n * Drittanwendungen können wieder genutzt werden, um Dateien zu öffnen\n -* Image-Viewer integriert, um angehängte Bilder zu öffnen, ohne diese in andere Apps übertragen zu müssen\n -* OkHttp aktualisiert um Probleme mit manchen Verbindungen zu behoben.\n +* Bildbetrachter integriert, um angehängte Bilder zu öffnen, ohne diese in andere Apps übertragen zu müssen\n +* OkHttp aktualisiert, um Probleme mit manchen Verbindungen zu beheben.\n * Unterstützung für KeeTrayTOTP-Einträge, so dass jetzt auch Steam-Einträge möglich sind\n Version 1.02\n - * mehrere Sicherheitsverbesserungen. Danke an jean-baptiste.cayrou@thalesgroup.com und vincent.fargues@thalesgroup.com für die Analyse und Zusammenarbeit! \n - * Unterstützung für KeyboardSwapPlugin (siehe Passwort-Eingabe-Optionen): erlaubt es, die Eingabemethode automatisch auf die KP2A-Tastatur zu wechseln, auch ohne gerootetes Gerät. Danke an Mishaal Rahman von XDA-Developers! \n - * Fix für Accessibility-Service mit neueren Chrome-Versionen\n - * Fix für unnötiges Löschen der Fingerabdruckdaten\n - * Fix für kleinere Crashes\n + * Mehrere Sicherheitsverbesserungen. Danke an jean-baptiste.cayrou@thalesgroup.com und vincent.fargues@thalesgroup.com für die Analyse und Zusammenarbeit!\n + * Unterstützung für KeyboardSwapPlugin (siehe Passworteingabe-Optionen): erlaubt es, die Eingabemethode automatisch auf die KP2A-Tastatur zu wechseln, auch ohne gerootetes Gerät. Danke an Mishaal Rahman von XDA-Developers! \n + * Korrektur für Accessibility-Service mit neueren Chrome-Versionen\n + * Korrektur für unnötiges Löschen der Fingerabdruckdaten\n + * Korrektur für kleinere Crashes\n * Dropbox-SDK aktualisiert, um zukünftige Kompatibilität zu gewährleisten \n * Fehlerberichterstattung mittels Xamarin Insights entfernt\n * Build-Tools aktualisiert\n Version 1.01-g\n -* Fix für Absturz wenn \"Offline-Arbeiten\" aktviert ist\n -* Fix für Encoding der FTP(S)-Zugangsdaten\n -* Fix für Abstürze bei Verwendung von OneDrive und auf älteren Android-Versionen\n +* Korrektur für Absturz, wenn „Offline-Arbeiten“ aktviert ist\n +* Korrektur für Encoding der FTP(S)-Zugangsdaten\n +* Korrektur für Abstürze bei Verwendung von OneDrive und auf älteren Android-Versionen\n * Zeiten werden als lokale Zeiten dargestellt\n Version 1.01-d\n * Fix beim Auflisten von Dateien mit OneDrive\n @@ -830,20 +830,20 @@ Anbei einige Tipps, die bei der Diagnose des Problems helfen können:\n * Unterstützung für OwnCloud integriert.\n * Frage nach Speicherzugriffsberechtigung vor dem Öffnen von lokalen Dateien. Version 1.0.0e\n -* Bugfix für Fingerabdruckerkennung auf älteren Samsunggeräten mit Android 6\n +* Fehlerkorrektur für Fingerabdruckerkennung auf älteren Samsunggeräten mit Android 6\n * Native x86-Unterstützung hinzugefügt\n * Bildschirmtastatur kann während Fingerabdruckerkennung deaktiviert werden\n * Update des Buildsystems Version 1.0.0\n * Entsperren mit Fingerabdruck (benötigt Android 6.0+ oder ein Samsung-Gerät)\n -* Auto-Fill-Dienst hinzugefügt (benötigt Android 5.0+)\n -* Unterstützung für Eintrags-Vorlagen hinzugefügt\n -* Modus \"offline arbeiten\" hinzugefügt\n +* Autofill-Dienst hinzugefügt (benötigt Android 5.0+)\n +* Unterstützung für Eintragsvorlagen hinzugefügt\n +* Modus „Offline arbeiten“ hinzugefügt\n * Kopieren von Einträgen ermöglicht\n * Automatische Vervollständigung für Feldnamen\n * Einträge können aus der Liste der zuletzt verwendeten Dateien entfernt werden\n * Rechte werden in Android 6.0 zur Laufzeit angefragt\n -* Fehlerbehebungen (integrierte Tastatatur wenn Icons ausgewählt werden)\n +* Fehlerbehebungen (integrierte Tastatatur wenn Symbole ausgewählt werden)\n * Option zum Senden von Fehlerberichten hinzugefügt\n * Hilfemeldungen an verschiedenen Stellen hinzugefügt\n \n Version 0.9.9\n @@ -855,11 +855,11 @@ Anbei einige Tipps, die bei der Diagnose des Problems helfen können:\n Version 0.9.9c\n * Dark Theme ist zurück\n -* Man kann jetzt weitere Icon-Packs installieren (Icons im alten Windows-Stil sind im Play Store verfügbar)\n +* Man kann jetzt weitere Icon-Packs installieren (Symbole im alten Windows-Stil sind im Play Store verfügbar)\n * Bestätigungsabfrage für das Löschen von Elementen ohne Papierkorb hinzugefügt\n -* Fehlerbehebungen (falsche Anzeige des OTP Secret Encoding, falsches App-Icon an manchen Stellen)\n +* Fehlerbehebungen (falsche Anzeige des OTP Secret Encoding, falsches Appsymbol an manchen Stellen)\n Version 0.9.8b\n - * Bug fixes (Speichern funktionierte bei einigen Datenbanken nicht, Export zum lokalen Gerät funktionierte nicht, einige Einstellungsoptionen verursachten einen Absturz der App)\n + * Fehlerkorrektur (Speichern funktionierte bei einigen Datenbanken nicht, Export zum lokalen Gerät funktionierte nicht, einige Einstellungsoptionen verursachten einen Absturz der App)\n Version 0.9.8\n * Unterstützung des Storage Access Framework (erlaubt schreiben auf SD Kartr und Google Drive in KP2A Offline)\n * Versuche, fehlerhafte Nutzereingaben bei der Eingabe von WebDAV URLs zu erkennen (Verzeichnis statt Datei)\n @@ -868,14 +868,14 @@ Anbei einige Tipps, die bei der Diagnose des Problems helfen können:\n * Bug Fix: Speichern des OTP-Passwort-Modus Version 0.9.7b\n * Übersetzungen aktualisiert\n - * Bugs behoben: Passwort-Schriftart fehlte in 0.9.7, Gruppen wurden nicht sortiert, wenn \"Sortieren nach Namen\" ausgewählt war\n + * Fehlr behoben: Passwortschriftart fehlte in 0.9.7, Gruppen wurden nicht sortiert, wenn „Sortieren nach Namen“ ausgewählt war\n Version 0.9.7\n * Schreibunterstützung für Keepass 1 (kdb) Datenbanken (Beta!)\n * Verbessertes Zurückschalten zur vorherigen Eingabemethode (funktioniert auch auf nicht gerooteten Geräten)\n * Unterstützung für KeeChallenge mit variablen Challenge-Längen\n - * Screenshots vom QuickUnlock-Bildschirm und Passwort-Eingabe-Bildschirm nicht mehr möglich\n + * Screenshots vom QuickUnlock-Bildschirm und Passworteingabebildschirm nicht mehr möglich\n * Sortierreihenfolge bei Sortierung nach Änderungsdatum (jetzt absteigend)\n - * Bugfixes: Notiz-Ansicht wird nach Änderung korrekt aktualisiert; Passwortfelder sollten nun auf allen Geräten korrekt versteckt werden; Problem behoben, wegen dem ein Eintrag doppelt angelegt werden konnte; Problem mit Anzeige der Warnung wegen doppelten UUIDs behoben\n + * Fehlerkorrektur: Notizansicht wird nach Änderung korrekt aktualisiert; Passwortfelder sollten nun auf allen Geräten korrekt versteckt werden; Problem behoben, wegen dem ein Eintrag doppelt angelegt werden konnte; Problem mit Anzeige der Warnung wegen doppelten UUIDs behoben\n Version 0.9.6\n * Schlüsseldatei und/oder lokale Datenbank können in ein App-internes Verzeichnis kopiert werden (siehe Einstellungen)\n * verschiedene Sortieroptionen\n From 3918b06b1fd4f1c7dd3ec8d764b3227abb61c3e7 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Sat, 18 Feb 2023 21:04:46 +0100 Subject: [PATCH 019/101] New translations strings.xml (German) --- .../Resources/values-de/strings.xml | 144 +++++++++--------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/src/keepass2android/Resources/values-de/strings.xml b/src/keepass2android/Resources/values-de/strings.xml index 4b88a337..d482a04b 100644 --- a/src/keepass2android/Resources/values-de/strings.xml +++ b/src/keepass2android/Resources/values-de/strings.xml @@ -108,7 +108,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Abbrechen Notizen Tags - Override URL + URL überschreiben Kennwort wiederholen Erstellt Gültig bis @@ -321,7 +321,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die QuickUnlock standardmäßig aktiviert Definiert, ob QuickUnlock standardmäßig aktiviert ist oder nicht. Datenbankanzeige schützen - Wenn aktiviert, können keine Screenshots gemacht werden und es wird kein Vorschaubild der App in der Letzte-Apps-Liste angezeigt. + Wenn aktiviert, können keine Bildschirmfotos gemacht werden und es wird kein Vorschaubild der App in der Liste der zuletzt verwendeten Apps angezeigt. QuickUnlock-Symbol verstecken QuickUnlock funktioniert leider nicht ohne ein Benachrichtigungssymbol. Wähle diese Option, um ein transparentes Symbol zu verwenden. QuickUnlock-Symbol verstecken @@ -387,7 +387,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Lokale Sicherung von %1$s Lokale Backups anzeigen SSL-Zertifikate - Bestimme das Verhalten, wenn Zertifikate nicht validiert werden können. Hinweis: du kannst auf deinem Android-Gerät Root-Zertifikate installieren, damit die Validierung gelingt! + Das Verhalten bei fehlgeschlagener Zertifikatsüberprüfung festlegen. Hinweis: Es ist möglich, Zertifikate auf diesem Gerät zu installieren, falls die Gültigkeitsprüfung fehlschlägt! Cache löschen? Dadurch werden alle zwischengespeicherten Datenbankdateien gelöscht. Alle Änderungen, die ohne Zugriff auf die Quelldatenbank vorgenommen wurden und noch nicht synchronisiert sind, gehen verloren! Dennoch fortfahren? Auf Änderungen prüfen @@ -901,101 +901,101 @@ Anbei einige Tipps, die bei der Diagnose des Problems helfen können:\n Version 0.9.4 \n * Plugin-Unterstützung hinzugefügt: siehe Einstellungen, um Plugins zu bekommen! \n * QR-Plugin veröffentlicht (Passwörter erfassen, Passwörter als QR-Code anzeigen, Einträge auf andere KP2A-Geräte übertragen)\n - * InputStick-Plugin veröffentlicht (Anmeldeinformationen per Bluetooth auf den PC übertragen - erfordert InputStick-USB-Stick)\n - * Apps von Drittanbieter können nun einfach Funktionen implementieren, um Anmeldeinformationen direkt von KP2A abzufragen. Du bist ein Entwickler? Bitte bau das in deiner App ein, wenn geeignet!\n + * InputStick-Plugin veröffentlicht (Anmeldeinformationen per Bluetooth auf den PC übertragen – erfordert InputStick-USB-Stick)\n + * Apps von Drittanbieter können nun einfach Funktionen implementieren, um Anmeldeinformationen direkt von KP2A abzufragen. Selbst ein Entwickler? Dies bitte in die eigene App einbauen, wenn sie sich dafür eignet!\n * TOTP-Unterstützung hinzugefügt (kompatibel mit KeeOTP und TrayTotp)\n * App sollte von Android nicht mehr beendet werden, wenn die Datenbank geöffnet ist\n - * Datenbank ist nicht mehr gesperrt, wenn die App mit dem Zurück-Knopf verlassen wird (siehe Einstellungen)\n + * Datenbank ist nicht mehr gesperrt, wenn die App mit dem Zurück-Knopf verlassen wird (siehe Einstellungen)\n * Gruppennamen können in Suchergebnissen angezeigt werden (*)\n - * Kontextmenü in der Ergebnisansicht der Suche hinzugefügt, einschließlich der Option \"Zu übergeordneter Gruppe navigieren\" (*)\n + * Kontextmenü in der Ergebnisansicht der Suche hinzugefügt, einschließlich der Option „Zu übergeordneter Gruppe navigieren“ (*)\n * Option zum Anzeigen des Gruppennamen von Einträgen (*)\n * (*) Danke an Matthieu für die Umsetzung dieser Features!\n * Unterstützung von KeeChallenge (mit Yubikey NEO). Danke an Ben Rush für die Implementierung des Connectors!\n * verbesserte Benutzerschnittstelle.\n - * Fehler in der Google Drive-Schnittstelle behoben.\n - * Option zum Deaktivieren der \"Spenden\"-Option hinzugefügt\n + * Fehler in der Google-Drive-Schnittstelle behoben.\n + * Option zum Deaktivieren der „Spenden“-Option hinzugefügt\n * QuickUnlock-Symbol jetzt standardmäßig ausgeblendet bei Geräten mit Android 4.2+\n Version 0.9.3 r5\n * Korrekturen von Xamarin übernommen: Keepass2Android ist jetzt kompatibel mit ART auf Android 4.4.2. Endlich!\n - * Fehlerkorrekturen: Fehler bei der Synchronization (Anzeigeaktualisierung, korrekte Prüfung auf Änderungen über HTTP), Fehler auf Android 2.x-Geräten, Fehler in den Implementierungen für Google Drive und OneDrive, Zwischenablage wird beim Schließen der Datenbank geleert, Fehler beim Öffnen von Anhängen, Anzeigeprobleme mit der Tastatur\n + * Fehlerkorrekturen: Fehler bei der Synchronization (Anzeigeaktualisierung, korrekte Prüfung auf Änderungen über HTTP), Fehler auf Android-2.x-Geräten, Fehler in den Implementierungen für Google Drive und OneDrive, Zwischenablage wird beim Schließen der Datenbank geleert, Fehler beim Öffnen von Anhängen, Anzeigeprobleme mit der Tastatur\n Version 0.9.3\n * Neue Tastatur mit einigen Verbesserungen. Siehe Einstellungen zum personalisieren.\n - * Leseunterstützung für kdb (Keepass 1) Dateien Experimentell!\n + * Leseunterstützung für kdb (Keepass-1-Dateien). Experimentell!\n * SFTP-Unterstützung\n - * Workaround für Bug in ART (Android 4.4.2) eingebaut\n - * Bugs gefixt\n + * Workaround für Fehler in ART (Android 4.4.2) eingebaut\n + * Fehler korrigiert\n Version 0.9.2\n * Unterstützung für OTPs (One Time Passwords) integriert (kompatibel zum OtpKeyProv-Plugin)\n * NFC-Support zur Eingabe von OTPs über YubiKey NEO integriert\n * Verbesserungen an der Benutzeroberfläche\n -* Keepass 2.24-Bibliothek integriert \n +* Keepass-2.24-Bibliothek integriert \n * Option zum Beenden des App-Prozesses eingebaut (s. Einstellungen)\n -* Bugs behoben\n +* Fehler behoben\n Version 0.9.1\n * SkyDrive-Unterstützung integriert (Nur in der Nicht-Offline-Version von Keepass2Android)\n * Probleme mit Google Drive Integration behoben\n * NTLM-Unterstützung integriert Version 0.9\n - * Dropbox und Google Drive Unterstützung integriert (Lesen und Schreiben von Datenbank; Nur in der Nicht-Offline-Version von Keepass2Android)\n - * Datei-Browser integriert (basiert auf android-filechooser von HBA)\n + * Unterstützung für Dropbox und Google Drive integriert (Datenbank lesen und schreiben; Nur in der Nicht-Offline-Version von Keepass2Android)\n + * Dateibrowser integriert (basiert auf android-filechooser von HBA)\n * Verbesserte Benutzeroberfläche zum Anlegen von Datenbanken\n * Schriftart DejaVu Sans Mono integriert zur Anzeige von Passwörtern\n - * Bugfixes + * Fehlerkorrekturen Version 0.8.6\n * Unterstützung für Twofish-Verschlüsselung\n -* Ermöglicht Bearbeiten von Gruppen\n -* Ermöglich Verschieben von Einträgen und Gruppen\n -* Das QuickUnlock-Icon kann transparent gemacht werden (s. Einstellungen)\n +* Bearbeiten von Gruppen ermöglicht\n +* Verschieben von Einträgen und Gruppen ermöglicht\n +* Das QuickUnlock-Symbol kann transparent gemacht werden (s. Einstellungen)\n * Bugs behoben Version 0.8.5\n * Remote-Dateien werden im lokalen Cache gespeichert. Das erlaubt Offline-Nutzung (inkl. Bearbeiten und späterem Synchronisieren). S. Einstellungen.\n - * Benachrichtigungssymbol zum Visualisieren des Sperr-Zustands (s. Einstellungen)\n + * Benachrichtigungssymbol zum Visualisieren des Sperrzustands (s. Einstellungen)\n * Verbesserungen, um die Datenbank zur richtigen Zeit zu sperren\n - * Datenbank-Dateien werden in den Speicher geladen, während du das Passwort eingibst. Dadurch erhöhte Ladegeschwindigkeit.\n - * Einträge können zur Root Gruppe hinzugefügt werden.\n - * Bug Fixes (Auflösen von von Referenzfeldern, Probleme mit der tastatur auf Italienischen und Chinesischen Geräten) + * Datenbankdateien werden in den Speicher geladen, während du das Passwort eingibst. Dadurch erhöhte Ladegeschwindigkeit.\n + * Einträge können zur Root-Gruppe hinzugefügt werden.\n + * Fehlerkorrekturen (Auflösen von von Referenzfeldern, Probleme mit der Tastatur auf italienischen und chinesischen Geräten) Version 0.8.4\n * Externe Änderungen an der Datenbank werden erkannt und beim Speichern zusammengeführt\n - * Verbesserte Geschwindigkeit beim starten\n + * Verbesserte Geschwindigkeit beim Starten\n * Verbesserte Suchleiste mit Vorschlägen\n - * Neues App logo!\n - * Unterstützung für .kdbp Format für schnelleres laden und speichern hinzugefügt\n - * Verbesserung beim bearbeiten von zusätzlichen Feldern und versteckte Darstellung von geschützten Feldern\n + * Neues App-Logo!\n + * Unterstützung für .kdbp-Format für schnelleres Laden und Speichern hinzugefügt\n + * Verbesserung beim Bearbeiten von zusätzlichen Feldern und versteckte Darstellung von geschützten Feldern\n Danke an Alex Vallat für seine Mitwirkung beim Code!\n Danke an Niki Hüttner (www.close-cut.de) für das neue Logo!\n Version 0.8.3\n -* Benutzername/TAN index wird in Liste der Einträge angezeigt (s. Einstellungen)\n +* Benutzername/TAN-Index wird in Liste der Einträge angezeigt (s. Einstellungen)\n * Einträge können neu angelegt werden, wenn Suche aus Browser kein Ergebnis gebracht hat\n * KP2A-Tastatur erlaubt Suche nach Zugangsdaten für die aktive App\n * App schließt sich automatisch nach Auswahl eines Eintrags über die Tastatur\n -* Dialog zur Tastatur-Auswahl öffnet sich automatisch nach Suche nach einer URL (s. Einstellungen)\n -* Platzhalter in Eintragsfeldern werden ersetzt vor dem Kopieren (die meisten Platzhalter werden unterstützt)\n -* kleinere Bug-Fixes +* Dialog zur Tastaturauswahl öffnet sich automatisch nach Suche nach einer URL (s. Einstellungen)\n +* Platzhalter in Eintragsfeldern werden vor dem Kopieren ersetzt (die meisten Platzhalter werden unterstützt)\n +* kleinere Fehlerkorrekturen Version 0.8.2\n * Unterstützung für Digest Authentication in WebDAV\n -* Bugfixes (OI File manager, URL öffnen) +* Fehlerkorrekturen (OI File manager, URL öffnen) Version 0.8.1\n -* KP2A Offline and \"Online\" können wieder parallel zueinander installiert werden\n +* KP2A Offline and „Online“ können wieder parallel zueinander installiert werden\n * Neue Übersetzungen hinzugefügt (Danke an alle Helfer!) Version 0.8\n * Verbesserte Benutzeroberfläche, vor allem für Android 4.x-Geräte\n * Möglichkeit, Dateimanager zur Auswahl von existierenden Dateien zu verwenden\n * Sicherer Weg zum Öffnen von Anhängen hinzugefügt (über das Cache-Verzeichnis)\n -* Bugs beim Editieren von Einträgen gefixt\n -* vermutlich neue Bugs eingeführt :-) - Möglichkeit, ein Bier zu spendieren (oder was anderes) verlängert +* Fehler beim Bearbeiten von Einträgen korrigiert\n +* vermutlich neue Fehler eingeführt :-) + Erweiterte Möglichkeit, ein Bier oder etwas anderes zu spenden Version 0.7\n -* Erhöhte Ladegeschwindigkeit: Schlüsseltransformationen sind jetzt 10x schneller!\n -* Neu: Keepass2Android Software-Tastatur: Wechsle zu dieser Tastatur, um deine Zugangsdaten einzugeben. Das schützt vor Zwischenablage-basierten Passwort-Sniffern! (du kannst die bisherigen Benachrichtigungen für das Kopieren in die Zwischenablage in den Einstellungen deaktivieren)\n +* Erhöhte Ladegeschwindigkeit: Schlüsseltransformationen sind jetzt 10× schneller!\n +* Neu: Keepass2Android-Software-Tastatur: Zu dieser Tastatur wechseln, um die Zugangsdaten einzugeben. Das schützt vor Zwischenablage-basierten Passwort-Sniffern! (die bisherigen Benachrichtigungen für das Kopieren in die Zwischenablage lassen sich in den Einstellungen deaktivieren)\n * Option eingefügt, um mir ein Bier oder was anderes zu spendieren (s. Menü) Version 0.6.2\n -* Google Drive/Dropbox/... Integration: Nutze die offizielle Google Drive oder Dropbox App und öffne daraus deine .kdbx-Datei. Das wird KP2A starten.\n -* Verbesserter Such-Dialog \n -* Verbesserte Suche bei \"Teilen\" mit Subdomains\n +* Integration für Google Drive/Dropbox/…: Die offizielle App für Google Drive oder Dropbox nutzen und daraus die .kdbx-Datei öffnen. Das startet dann KP2A.\n +* Verbesserter Suchdialog \n +* Verbesserte Suche bei „Teilen“ mit Subdomains\n * Optionen für Feedback, Bewerten und Übersetzen zum Menü hinzugefügt\n \n Version 0.6.1\n -* Erkennung, wenn sich eine Datenbank im Hingrund ändert (z.B. durch eine Sync-App)\n +* Erkennung, wenn sich eine Datenbank im Hingrund ändert (z. B. durch eine Sync-App)\n * Suche aus dem Browser verbessert\n * Bestätigungsdialog, wenn Änderungen verworfen werden sollen\n \n @@ -1012,9 +1012,9 @@ Erstes öffentliches Release Nie - Keepass 2 database (.kdbx) - Keepass 2 XML (unverschlüsselt) (.xml) - Keepass CSV (unverschlüsselt) (.csv) + Keepass2-Datenbank (.kdbx) + Keepass2-XML (unverschlüsselt) (.xml) + Keepass-CSV (unverschlüsselt) (.csv) Klein @@ -1038,51 +1038,51 @@ Erstes öffentliches Release Benutzername und Passwort merken - Nur Kennwort - Kennwort + Schlüsseldatei - Kennwort + OTP - Kennwort + OTP Secret (Recovery-Modus) - Passwort + Challenge-Response - Passwort + Challenge-Response-Secret (Recovery-Modus) - Passwort + Challenge-Response für Keepass XC - Kennwort + Schlüsseldatei + Challenge-Response für Keepass XC + Nur Passwort + Passwort und Schlüsseldatei + Passwort und OTP + Passwort und OTP-Secret (Recovery-Modus) + Passwort und Challenge-Response + Passwort und Challenge-Response-Secret (Recovery-Modus) + Passwort und Challenge-Response für Keepass XC + Kennwort und Schlüsseldatei und Challenge-Response für Keepass XC Passwort Privater/Öffentlicher Schlüssel - Fehler bei Zertifikatsvalidierung ignorieren - Warnen, wenn die Validierung fehlschlägt + Fehler bei Zertifikatsüberprüfung ignorieren + Warnen, wenn die Überprüfung fehlschlägt Ungültige Zertifikate nicht akzeptieren Bitte stelle sicher, dass dies auf deinem System funktioniert; falls nicht, nutze bitte die Standard-Tastatur. Vom Plugin gelieferte Beschreibung: - Keepass2Android unterstützt das Autofill-Feature von Android, aber du hast es anscheinend noch nicht aktiviert. + Keepass2Android unterstützt die Autofill-Funktion von Android, aber es wurde anscheinend noch nicht aktiviert. Autofill aktivieren - Sorry, anscheinend unterstützt dein Gerät es nicht, dass man die Einstellungen aus einer App heraus öffnet. Bitte gehe in die Systemeinstellungen und suche dort nach Autofill, um den Dienst zu aktivieren. + Entschuldigung, anscheinend unterstützt dieses Gerät nicht, dass die Einstellungen aus einer App heraus geöffnet werden. Bitte in die Systemeinstellungen gehen und dort nach Autofill suchen, um den Dienst zu aktivieren. Autofill-Hilfe anzeigen Mit Keepass2Android ausfüllen AutoFill für %1$s deaktivieren AutoFill für %1$s aktivieren - Webdomain %1$s konnte nicht mit App %2$s in Verbindung gebracht werden - Keepass2Android hat biometrische Hardware erkannt. Möchtest du Biometrisches Entsperren für diese Datenbank aktivieren? - Ich verstehe + Webdomain %1$s konnte nicht mit App %2$s verknüpft werden + Keepass2Android hat biometrische Hardware erkannt. Soll Biometrisches Entsperren für diese Datenbank aktiviert werden? + Okay, verstanden Nicht erneut anzeigen Ist das Hauptpasswort bekannt? Bitte beachten, dass die Datenbank ohne den Hauptschlüssel nicht geöffnet werden kann. Es gibt keine Möglichkeit, das Hauptpasswort „zurückzusetzen“. Bitte auch bedenken, dass die biometrische Entsperrung durch das Speichern des Hauptschlüssels im sicheren Speicher von Android funktioniert. Dieser Speicher kann von Android jederzeit gelöscht werden, z. B. wenn ein neuer Fingerabdruck in den Systemeinstellungen hinzugefügt wird. Daher sich nicht auf das biometrische Entsperren verlassen, sondern sich bitte das eigene Hauptpasswort merken! - Ist deine Datenbank gesichert? - Keepass2Android speichert deine Passwörter in eine Datei an einem Ort deiner Wahl. Bist du sicher, dass du auf diese Datei auch noch Zugriff hast wenn dein Telefon verloren geht oder gestohlen wird? Oder wenn die Datei zerstört oder gelöscht wird? Bitte stelle sicher, dass du immer eine aktuelle Kopie an einem sichern Ort aufbewahrst! - Um jetzt eine Sicherung zu erstellen, gehe nach %1$s > %2$s > %3$s. - Hast du für Notfälle vorgesorgt? - Hast du je darüber nachgedacht, was passiert, wenn du nicht mehr auf deine Passwort-Datenbank zugreifen kannst? Was, wenn du einen Unfall hast? Ein bewährtes Verfahren ist, einer vertrauenswürdigen Person dein Masterpasswort für Notfälle mitzuteilen. Ansonsten wird niemand auf deine Passwörter Zugriff haben. - Der aktuell gültige Bildschirm ist als unsicher eingestuft. Das bedeutet, dass Bildschirmfotos von anderen Anwendungen erstellt werden könnten. Keepass2Android ist so konfiguriert, dass sensible Informationen nur auf sicheren Bildschirmen angezeigt werden. Bitte wechsle zu einem sicheren Bildschirm (z.B. durch Abtrennen eines HDMI-Monitors) oder ändere die App-Einstellungen. + Gibt es eine Sicherung der Datenbank? + Keepass2Android speichert die Passwörter in einer Datei an einem frei wählbarem Speicherort.Ist sichergestellt, dass die Datei auch dann noch verfügbar ist, wenn das Telefon verloren geht oder gestohlen wird, oder wenn die Datei zerstört oder gelöscht wird? Bitte sicherstellen, dass immer eine aktuelle Kopie an einem sichern Ort aufbewahrt wird! + Um jetzt eine Sicherung zu erstellen, nach %1$s > %2$s > %3$s gehen. + Ist man auf Notfälle vorbereitet? + Wurde schon einmal darüber nachgedacht, was passiert, wenn man keinen Zugriff mehr zu seiner Passwortdatenbank hat? Was ist, wenn man einen Unfall hat? Es ist eine vernünftige Maßnahme, den Hauptschlüssel für Notfälle an eine vertrauenswürdige Person weiterzugeben. Andernfalls hat niemand Zugang zu den Passwörtern. + Der aktuell gültige Bildschirm ist nicht als sicher eingestuft. Das bedeutet, dass Bildschirmfotos von anderen Anwendungen erstellt werden könnten. Keepass2Android ist so konfiguriert, dass sensible Informationen nur auf sicheren Bildschirmen angezeigt werden. Bitte zu einem sicheren Bildschirm wechseln (z. B. durch Abklemmen eines HDMI-Monitors) oder die App-Einstellungen ändern. Diese Nachricht deaktivieren - Bitte aktiviere die Keepass2Android-Tastatur. + Bitte die Keepass2Android-Tastatur aktivieren. Erneut versuchen Sicherheitswarnung: Unbekannte Domain/App-Verknüpfung - Du bist dabei, Anmeldedaten für die Domain \"%1$s\" in die App \"%2$s \" einzufügen. - Wenn du \"%2$s\" vertraust, dass es zu \"%1$s\" gehört oder du der App \"%2$s\" vertraust, dass sie keine Anmeldedaten missbraucht (z.B. da es sich um eine vertrauenswürdige Browser-App handelt) ist es in Ordnung, fortzufahren. Falls nicht, brich den Vorgang bitte ab. - Für \"%1$s \" immer akzeptieren + Hiermit werden Anmeldeinformationen für die Domäne „%1$s“ in die Anwendung „%2$s“ eingefügt. + Wenn darauf vertraut wird, dass „%2$s“ zu „%1$s“ gehört, oder wenn darauf vertraut wird, dass die App „%2$s“ die Anmeldeinformationen nicht missbraucht (z. B. weil es sich um eine vertrauenswürdige Browser-App handelt), kann fortgefahren werden. Falls nicht, bitte abbrechen. + Für „%1$s“ immer akzeptieren From 78a48b75b8752d75a17cf0f3796f7f69a087306a Mon Sep 17 00:00:00 2001 From: PhilippC Date: Sat, 18 Feb 2023 22:13:41 +0100 Subject: [PATCH 020/101] New translations strings.xml (German) --- .../Resources/values-de/strings.xml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/keepass2android/Resources/values-de/strings.xml b/src/keepass2android/Resources/values-de/strings.xml index d482a04b..acd225fe 100644 --- a/src/keepass2android/Resources/values-de/strings.xml +++ b/src/keepass2android/Resources/values-de/strings.xml @@ -156,7 +156,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Passwort Name URL - Override URL + URL überschreiben tag1, tag2 Benutzername Kennwort oder Schlüsseldatei ist falsch. @@ -431,13 +431,13 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Soll dieser Eintrag endgültig gelöscht werden? Nein drücken, um ihn in den Papierkorb zu verschieben. Soll diese Gruppe endgültig gelöscht werden? Drücke nein, um sie in den Papierkorb zu verschieben. Gewählte Elemente permanent löschen? Nein wählen, um in den Papierkorb zu verschieben. - Eintrag permanent löschen? + Soll der Eintrag wirklich endgültig gelöscht werden? Gruppe endgültig löschen? Ausgewählte Elemente endgültig löschen? Endgültig löschen? Datei neu laden? - Die geöffnete Datei wurde von einem anderen Programm geändert. Möchtest du sie neu laden? - Möchtest du die gerade gemachten Änderungen wirklich verwerfen? (Der Button zum Speichern befindet sich oberhalb des Formulars.) + Die geöffnete Datei wurde von einem anderen Programm geändert. Soll sie neu geladen werden? + Sollen die vorgenommenen Änderungen wirklich verworfen werden? (Die Schaltfläche zum Speichern befindet sich oberhalb des Formulars.) Änderungen verwerfen? Verbesserungen vorschlagen Diese App bewerten @@ -538,7 +538,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Speicherort ändern Wenn aktiviert, läuft Keepass2Android im Hintergrund weiter, auch wenn die Datenbank gesperrt ist. Das ermöglicht das Öffnen der Datenbank mit QuickUnlock. Hauptpasswort - Die eigene Datenbank wird mit dem hier eingegebenen Passwort verschlüsselt. Dazu ein starkes Passwort verwenden, um die Datenbank zu schützen! Tipp: Sich ein oder zwei Sätze ausdenken und die Anfangsbuchstaben als Passwort nutzen. Auch die Satzzeichen mit einschließen. + Die eigene Datenbank wird mit dem hier eingegebenen Passwort verschlüsselt. Dazu ein starkes Passwort verwenden, um die Datenbank abzusichern! Tipp: Sich ein oder zwei Sätze ausdenken und die Anfangsbuchstaben als Passwort nutzen. Auch die Satzzeichen mit einschließen. Wähle ein Master-Passwort, mit dem deine Datenbank geschützt wird: Schlüsseldatei Eine Schlüsseldatei ist im Grunde ein Kennwort, das in einer Datei gespeichert ist. Schlüsseldateien sind üblicherweise stärker als Kennwörter, weil sie deutlich komplexer sein können; allerdings ist es schwerer, sie geheim zu halten. Wird die Datenbank in der Cloud gespeichert, sollte die Schlüsseldatei keinesfalls ebenfalls dort abgelegt werden! Das würde sie völlig nutzlos machen! Wichtig: Den Inhalt der Schlüsseldatei nicht mehr ändern, nachdem die Datenbank angelegt wurde! @@ -567,7 +567,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Bitte das KeeChallenge-Plugin in KeePass 2.x (PC) verwenden, um die Datenbank für die Verwendung von Challenge-Response zu konfigurieren! Fehler beim Aktualisieren der OTP-Hilfsdatei! TOTP-Seed-Feldname - Wenn das Keepass 2-Plugin „TrayTotp“ nicht mit Standardeinstellungen verwendet wird, den Feldnamen für das Seed-Feld entsprechend der Einstellungen am PC angeben. + Wenn das Keepass2-Plugin „TrayTotp“ nicht mit Standardeinstellungen verwendet wird, den Feldnamen für das Seed-Feld entsprechend der Einstellungen am PC angeben. Feldname für TOTP-Einstellungen Feldnamen für TOTP-Einstellungen entsprechend den TrayTotp-Einstellungen eingeben. TrayTotp @@ -608,7 +608,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Um sie zu bearbeiten, muss sie an einen anderen Speicherort kopiert werden. Auf OK tippen, um einen Speicherort zu wählen. Datenbank ist schreibgeschützt - Keepass2Android hat die Datenbank im Lese-Modus geöffnet. + Keepass2Android hat die aktuelle Datenbank im schreibgeschützten Modus geöffnet. Es scheint, dass die Datei von einer externen Anwendung aus geöffnet wurde. Über diesen Weg ist das Schreiben nicht möglich. Wenn Änderungen an der Datenbank vorgenommen werden sollen, bitte die Datenbank schließen und „Datenbank wechseln“ wählen. Danach die Datei über eine der verfügbaren Optionen öffnen, sofern möglich. Datei ist schreibgeschützt. Diese Attribut entfernen, wenn Änderungen an der Datenbank vorgenommen werden sollen. Das Speichern ist aufgrund von Einschränkungen, die in Android KitKat eingeführt wurden, nicht möglich. Wenn Änderungen an der Datenbank vorgenommen werden sollen, bitte die Datenbank schließen und „Datenbank wechseln“ wählen. Danach die Datei über die systeminterne Dateiauswahl öffnen. @@ -1056,7 +1056,7 @@ Erstes öffentliches Release Warnen, wenn die Überprüfung fehlschlägt Ungültige Zertifikate nicht akzeptieren - Bitte stelle sicher, dass dies auf deinem System funktioniert; falls nicht, nutze bitte die Standard-Tastatur. + Bitte sicherstellen, dass dies auf diesem System funktioniert; falls nicht, die Standardtastatur verwenden. Vom Plugin gelieferte Beschreibung: Keepass2Android unterstützt die Autofill-Funktion von Android, aber es wurde anscheinend noch nicht aktiviert. Autofill aktivieren From 139abcaec6179eafbb42bbdedfae84f3b72c7ba0 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Sat, 18 Feb 2023 23:26:56 +0100 Subject: [PATCH 021/101] New translations strings.xml (German) --- .../Resources/values-de/strings.xml | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/keepass2android/Resources/values-de/strings.xml b/src/keepass2android/Resources/values-de/strings.xml index acd225fe..c381fd39 100644 --- a/src/keepass2android/Resources/values-de/strings.xml +++ b/src/keepass2android/Resources/values-de/strings.xml @@ -25,7 +25,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Bei inaktiver Anwendung wird die Datenbank nach Ablauf der eingestellten Zeit automatisch gesperrt. App-Prozess beenden Schließen-Button - Eine Schaltfläche auf dem Kennwortbildschirm anzeigen, um den App-Prozess zu beenden (für paranoide Benutzer) + Eine Schaltfläche auf dem Passwortbildschirm anzeigen, um den App-Prozess zu beenden (für paranoide Benutzer) Anwendung Anwendungseinstellungen Gruppennamen im Suchergebnis anzeigen @@ -97,8 +97,8 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Biometrisches Entsperren für QuickUnlock Biometrisches Entsperren fehlgeschlagen. Entschlüsselungsschlüssel wurde vom Android-System für ungültig erklärt. Das kommt üblicherweise vor, wenn die Biometrische Authentifizierung oder die Sicherheitseinstellungen geändert wurden. Entsperren der Datenbank fehlgeschlagen: Ungültiger zusammengesetzter Schlüssel. Biometrisches Entsperren wurde deaktiviert, da das gespeicherte Masterpasswort nicht länger gültig ist. - Bitte biometrisches Entsperren für das neue Masterkennwort erneut aktivieren. - Bitte mit Kennwort entsperren und anschließend in den Datenbankeinstellungen das biometrische Entsperren erneut aktivieren. + Bitte Biometrisches Entsperren für das neue Hauptpasswort erneut aktivieren. + Bitte mit Passwort entsperren und anschließend in den Datenbankeinstellungen das Biometrische Entsperren erneut aktivieren. Initialisierung der biometrischen Authentifizierung fehlgeschlagen. Daten konnten nicht verschlüsselt werden. Dies kann passieren, wenn Fingerabdrücke in den Systemeinstellungen hinzugefügt oder gelöscht wurden, während Keepass2Android auf deinen Fingerabdruck wartet. Mit dieser Option wird das Hauptpasswort verschlüsselt im Android-Keystore auf dem Gerät gespeichert, geschützt durch einen Fingerabdruck. Dadurch kann die Datenbank per biometrischer Authentifizierung entsperrt werden. @@ -109,7 +109,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Notizen Tags URL überschreiben - Kennwort wiederholen + Passwort bestätigen Erstellt Gültig bis Name der Gruppe @@ -147,7 +147,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Passwort erzeugen Gruppe Notizen - Kennwort wiederholen + Passwort bestätigen Erzeugtes Kennwort Name der Gruppe Schlüsseldatei @@ -159,7 +159,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die URL überschreiben tag1, tag2 Benutzername - Kennwort oder Schlüsseldatei ist falsch. + Passwort oder Schlüsseldatei ungültig. Ungültiger Algorithmus. Datenbank-Format wurde nicht erkannt. Schlüssel-Datei existiert nicht. @@ -179,7 +179,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Wenn aktiviert, wird die App die Option zum Abschalten von Autofill für bestimmte Einträge nicht anzeigen. Über Hauptschlüssel ändern - Kennwort kopieren + Passwort kopieren Benutzername kopieren TOTP kopieren Erstellen @@ -213,7 +213,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Papierkorb und Sicherungen nicht durchsuchen Papierkorb und Sicherungseinträge werden bei der Suche nicht berücksichtigt. KeePass Datenbankdatei - Datenbankkennwort eingeben + Datenbankpasswort eingeben Hauptschlüsseltyp auswählen: Neue Datenbank wird angelegt … Datenbank anlegen @@ -240,7 +240,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Schlüsseldatei erfolgreich exportiert! Leerzeichen Suchen - Kennwort anzeigen + Passwort anzeigen Sortieren nach … Sortieren nach Name Sortieren nach Erstellung @@ -303,7 +303,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die In die Tastatur integrieren Zeigt Vorschläge für automatisches Ausfüllen innerhalb der virtuellen Tastatur (wenn von dieser unterstützt) Benötigt Android 11 oder neuer - Kennwort finden + Passwort finden Abgelaufene Einträge ausschließen Optionen Groß-/Kleinschreibung beachten @@ -327,12 +327,12 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die QuickUnlock-Symbol verstecken QuickUnlock benötigt eine Benachrichtigung, um ordnungsgemäß zu funktionieren. Diese Option wählen, um eine Benachrichtigung ohne Symbol anzuzeigen. Länge des QuickUnlock-Schlüssels - Maximale Anzahl von Zeichen, die als QuickUnlock-Kennwort verwendet werden. + Maximale Anzahl von Zeichen, die als QuickUnlock-Passwort verwendet werden. Länge des QuickUnlock-Codes verstecken Wenn aktiviert, wird die Länge des QuickUnlock-Codes nicht auf dem QuickUnlock-Bildschirm angezeigt. QuickUnlock-Taste aus dem Datenbankeintrag. Wenn die aktive Datenbank einen Eintrag mit dem Titel „QuickUnlock“ in der Root-Gruppe enthält, wird das Passwort dieses Eintrags als QuickUnlock-Code verwendet. - QuickUnlock fehlgeschlagen: falsches Kennwort! + QuickUnlock fehlgeschlagen: falsches Passwort! Anhang speichern Bitte den Ort zum Speichern wählen. In Datei exportieren … @@ -662,7 +662,7 @@ Anbei einige Tipps, die bei der Diagnose des Problems helfen können:\n Kinddatenbanken konfigurieren … Kinddatenbanken nicht spezifiziert - Kinddatenbanken sind andere Datenbanken, die automatisch geöffnet werden können, wenn die übergeordnete Datenbank geöffnet wird. Dazu werden das Master-Passwort und der Dateipfad der Kinddatenbank in der Hauptdatenbank gespeichert. Diese Funktion erlaubt es, einige deiner Passwörter mit einer anderen Person zu teilen. Die Implementierung ist kompatibel mit KeeAutoExec für PC. + Kinddatenbanken sind weitere Datenbanken, die automatisch geöffnet werden können, wenn die übergeordnete Datenbank geöffnet wird. Dazu werden das Hauptpasswort und der Dateipfad der Kinddatenbank in der Hauptdatenbank gespeichert. Diese Funktion erlaubt es, einige der eigenen Passwörter mit einer anderen Person zu teilen. Die Implementierung ist kompatibel mit KeeAutoExec für PC. Auf diesem Gerät aktiviert Auf diesem Gerät aktivieren Auf diesem Gerät deaktivieren @@ -1071,7 +1071,7 @@ Erstes öffentliches Release Nicht erneut anzeigen Ist das Hauptpasswort bekannt? Bitte beachten, dass die Datenbank ohne den Hauptschlüssel nicht geöffnet werden kann. Es gibt keine Möglichkeit, das Hauptpasswort „zurückzusetzen“. - Bitte auch bedenken, dass die biometrische Entsperrung durch das Speichern des Hauptschlüssels im sicheren Speicher von Android funktioniert. Dieser Speicher kann von Android jederzeit gelöscht werden, z. B. wenn ein neuer Fingerabdruck in den Systemeinstellungen hinzugefügt wird. Daher sich nicht auf das biometrische Entsperren verlassen, sondern sich bitte das eigene Hauptpasswort merken! + Bitte auch bedenken, dass das Biometrische Entsperren über das Speichern des Hauptschlüssels im sicheren Speicher von Android funktioniert. Dieser Speicher kann von Android jederzeit gelöscht werden, z. B. wenn ein neuer Fingerabdruck in den Systemeinstellungen hinzugefügt wird. Daher sich nicht auf das biometrische Entsperren verlassen, sondern sich bitte das eigene Hauptpasswort merken! Gibt es eine Sicherung der Datenbank? Keepass2Android speichert die Passwörter in einer Datei an einem frei wählbarem Speicherort.Ist sichergestellt, dass die Datei auch dann noch verfügbar ist, wenn das Telefon verloren geht oder gestohlen wird, oder wenn die Datei zerstört oder gelöscht wird? Bitte sicherstellen, dass immer eine aktuelle Kopie an einem sichern Ort aufbewahrt wird! Um jetzt eine Sicherung zu erstellen, nach %1$s > %2$s > %3$s gehen. From 890f1bd7042454962b134593ab217d094cd42ed0 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Sun, 19 Feb 2023 20:33:39 +0100 Subject: [PATCH 022/101] New translations strings.xml (Danish) --- src/keepass2android/Resources/values-da/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/keepass2android/Resources/values-da/strings.xml b/src/keepass2android/Resources/values-da/strings.xml index 16af75d7..6a83b078 100644 --- a/src/keepass2android/Resources/values-da/strings.xml +++ b/src/keepass2android/Resources/values-da/strings.xml @@ -685,6 +685,11 @@ Notificering til forenkelse af adgang til den aktuelt valgte indtastning. Luk database efter tre mislykkede forsøg med biometrisk oplåsning. Advarsel! Biometrisk godkendelse kan ugyldiggøres af Android, f.eks. efter tilføjelse af et nyt fingeraftryk i dine enhedsindstillinger. Sørg for, at du altid ved, hvordan du låser op med din hovedadgangskode! + + Fejlrettelse til nedbrud og uventede log-outs + Skift til ny SFTP-implementering, som understøtter moderne offentlige nøglealgoritmer såsom rsa-sha2-256 + Mark passwords as sensitive when copying to clipboard (Android 13) + Tilføjet understøttelse af visning, fjernelse og gendannelse af sikkerhedskopierede poster Implementeret understøttelse af MEGA-skylager From 060bf6a6eeef18f699cdc3596868fe36e7eb5d42 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Sun, 19 Feb 2023 21:31:30 +0100 Subject: [PATCH 023/101] New translations strings.xml (Danish) --- src/keepass2android/Resources/values-da/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keepass2android/Resources/values-da/strings.xml b/src/keepass2android/Resources/values-da/strings.xml index 6a83b078..e9838062 100644 --- a/src/keepass2android/Resources/values-da/strings.xml +++ b/src/keepass2android/Resources/values-da/strings.xml @@ -688,7 +688,7 @@ Fejlrettelse til nedbrud og uventede log-outs Skift til ny SFTP-implementering, som understøtter moderne offentlige nøglealgoritmer såsom rsa-sha2-256 - Mark passwords as sensitive when copying to clipboard (Android 13) + Markér adgangskoder som følsomme ved kopiering til udklipsholder (Android 13) Tilføjet understøttelse af visning, fjernelse og gendannelse af sikkerhedskopierede poster From 2d899fa0674b09153acdbfb7ca9c8d6743e4fc5a Mon Sep 17 00:00:00 2001 From: PhilippC Date: Sun, 19 Feb 2023 22:32:16 +0100 Subject: [PATCH 024/101] New translations strings.xml (Danish) --- .../Resources/values-da/strings.xml | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/keepass2android/Resources/values-da/strings.xml b/src/keepass2android/Resources/values-da/strings.xml index e9838062..c483b192 100644 --- a/src/keepass2android/Resources/values-da/strings.xml +++ b/src/keepass2android/Resources/values-da/strings.xml @@ -90,20 +90,20 @@ Biometrisk verifikation lykkedes Biometrisk oplåsning kræver Android 6.0 eller nyere. Ingen biometrisk hardware fundet. - Du har ikke konfigureret biometrisk verifikation på denne enhed. Gå til systemindstillinger. + Du har ikke konfigureret biometrisk verifikation på denne enhed. Gå til systemindstillinger først. Deaktivér biometrisk oplåsning Aktivér fuld biometrisk oplåsning Aktivér biometrisk oplåsning for hurtig oplåsning - Biometrisk oplåsning mislykkedes. Dekrypteringsnøglen blev ugyldiggjort af Android OS\'et. Dette sker sædvanligvis, hvis en biometrik godkendelse eller sikkerhedsindstillingerne ændres. - Databaseoplåsning mislykkedes: Ugyldig kombinøgle. Biometrisk oplåsning blev deaktiveret, da den lagrede hovedadgangskode tilsyneladende ikke længere er gyldig. - Genaktivér biometrisk oplåsning for den nye hovedadgangskode. + Biometrisk oplåsning mislykkedes. Dekrypteringsnøglen blev ugyldiggjort af Android OS. Det sker normalt, hvis en biometrik godkendelse eller sikkerhedsindstillinger ændres. + Databaseoplåsning mislykkedes: Ugyldig kombinøgle. Biometrisk oplåsning blev deaktiveret, da den lagrede hovedadgangskode tilsyneladende ikke længere er gyldig. + Genaktivér venligst biometrisk oplåsning for den nye hovedadgangskode. Oplås med din adgangskode og genaktivér så biometrisk oplåsning i databaseindstillingerne. - Kunne ikke initialisere biometrisk verifikation. - Mislykkedes at kryptere data. Dette kan ske, hvis du tilføjer eller fjerner fingeraftryk i systemindstillingerne, mens Keepass2Android moniterer for brug af fingeraftryk. - Dette gemmer din hovedadgangskode på denne enhed, krypteret med Android Keystore og beskyttet af biometrisk verifikation. Tillader dig at oplåse din database alene via biometri. + Kunne ikke initialisere biometrisk verifikation. + Kryptering af data fejlede. Dette kan ske, hvis du tilføjer eller fjerner fingeraftryk i systemindstillingerne, mens Keepass2Android moniterer for brug af fingeraftryk. + Dette gemmer hovedadgangskoden på denne enhed, krypteret med Android Keystore og beskyttet af biometrisk verifikation. Tillader oplåsning af databasen alene med biometri. Tillader brug af biometrisk verifikation i stedet for hurtigoplåsningskoden. Gemmer ingen information relateret til din hovedadgangskode. - Angiv databasefilnavn - Tilgået + Angiv navn på databasefil + Åbnet Annullér Notater Tags @@ -120,27 +120,27 @@ Navn URL Brugernavn - Ekstra strengfelter - Filvedhæftninger + Ekstra felter + Vedhæftede filer Tidligere versioner Keepass2Android kan ikke håndtere denne URI. - Fejl under gruppeoprettelse. + Fejl under oprettelse af gruppe. Overordnet mappe kunne ikke oprettes. - Filen findes allerede. + Denne fil eksisterer allerede. Mislykkedes at bestemme databaseindstillinger. Mislykkedes at åbne link. - Et filnavn er obligatorisk. + Et filnavn er påkrævet. Kunne ikke oprette fil Ugyldig database. Ugyldig sti. - Et navn er obligatorisk. - En adgangskode eller nøglefil er obligatorisk. + Et navn er påkrævet. + En adgangskode eller nøglefil er påkrævet. Mindst én adgangskodegenereringstype skal vælges - Adgangskoder matcher ikke. + Adgangskoder stemmer ikke overens. Gentagelser skal udgøre et tal. Parameter skal udgøre et tal. - En titel er obligatorisk. - Angiv et positivt heltal i længdefeltet + En titel er påkrævet. + Angiv et positivt helt tal i længdefeltet Fil ikke fundet. Filbrowser Generér adgangskode @@ -216,7 +216,7 @@ Vælg type af hovednøgle: Opretter ny database… Opret database - Behandler… + Arbejder… Husker placeringen af nøglefiler Gem nøglefil Fjern From 58844be6eb0ebe6d795ac99d0985a2795ff0fc75 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Sun, 19 Feb 2023 23:50:16 +0100 Subject: [PATCH 025/101] New translations strings.xml (Danish) --- .../Resources/values-da/strings.xml | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/keepass2android/Resources/values-da/strings.xml b/src/keepass2android/Resources/values-da/strings.xml index c483b192..8b260dbd 100644 --- a/src/keepass2android/Resources/values-da/strings.xml +++ b/src/keepass2android/Resources/values-da/strings.xml @@ -5,15 +5,15 @@ Keepass2Android er en adgangskodehåndterings-app, der giver læse-/skriveadgang til KeePass 2.x-databaser på Android. Brugerfladen er baseret på en portering af KeePassDroid, udviklet af Brian Pellin. Koden til databaseoperationerne baserer sig på KeePass af Dominik Reichl. Android-robotten er reproduceret eller ændret fra arbejde skabt og delt af Google og anvendt jf. betingelserne beskrevet i \"Creative Commons 3.0 Attribution License\". SFTP-understøttelse er implementeret vha. JSch-biblioteket under BSD-licensen, skabt af JCraft, Inc. - Hammerikonet er kreéret af John Caserta fra Noun Project. Pingvinikonet er kreéret af Adriano Emerick fra Noun Project. Fjerikonet er kreéret af Jon Testa fra Noun Project. Æbleikonet er kreéret af Ava Rowell fra Noun Project. Billedikonet stammer fra https://icons8.com/icon/5570/Picture. + Hammerikonet er lavet af John Caserta fra Noun Project. Pingvinikonet er lavet af Adriano Emerick fra Noun Project. Fjerikonet er lavet af Jon Testa fra Noun Project. Æbleikonet er lavet af Ava Rowell fra Noun Project. Billedikonet er fra https://icons8.com/icon/5570/Picture. Acceptér Afvis Tilføj post Redigér post - Opret indtastning for URL + Opret post for webadresse Tilføj gruppe Tilføj Gruppe - Redigér gruppe + Rediger gruppe Algoritme Algoritme Keepass2Android @@ -32,31 +32,31 @@ Visningsgruppe er nu: %1$s Deaktivér Autoudfyldmål Viser en liste over apps og websteder, hvor Autoudfyld er blevet deaktiveret - Hvis aktiveret, spørger Android, om du vil gemme akkreditiver, når du manuelt har angivet data i autofyldbare felter. + Hvis aktiveret spørger Android, om du vil gemme akkreditiver, når du manuelt har angivet data i autofyldbare felter. Tilbyd at gemme akkreditiver Vis gruppenavn i indtastningsvisning - Beklager! Keepass2Android kan ikke håndtere den returnerede URI %1$s. Kontakt udvikleren! + Beklager! Keepass2Android kan ikke håndtere den returnerede URI %1$s. Kontakt venligst udvikleren! Én indtastning %1$d poster Ikonsæt Find flere... Sikkerhed Visning - Adgangskodetilgang + Adgang til adgangskoden Hurtigoplåsning Filhåndtering Tastatur - Eksportere database... + Eksporter database… Biometrisk oplåsning - Importere database til intern mappe + Importer database til intern mappe Importer nøglefilen til intern mappe Eksporter nøglefil fra intern mappe - Tastaturskiftning + Tastaturskifte Kun tilgængelig for lokale filer. - Fil lagres i den interne mappe. - Databasefilen blev kopieret til den interne mappe. Tryk på OK for at åbne den fra den nye placering. Bemærk: Husk regelmæssigt at eksportere databasen til et sikkert lagermedie! - Nøglefilen blev kopieret til den interne mappe. Inden du sletter den fra dens nuværende placering, så tjek at du har en god sikkerhedskopi! - Kan ikke benytte den interne mappe, når nøglefilens placering ikke er husket. Ændr sikkerhedsindstillingerne. + Fil er gemt i intern mappe. + Databasefil blev kopieret til intern mappe. Tryk OK for at åbne fra den nye placering. Bemærk: Husk regelmæssigt at eksportere databasen til et sikkert lagermedie! + Nøglefil blev kopieret til interne mappe. Før du sletter den fra den nuværende placering, så tjek at du har en god sikkerhedskopi! + Kan ikke bruge intern mappe når nøglefilens placering ikke er husket. Ændr sikkerhedsindstillingerne. Oplås Oplås database Parenteser @@ -73,8 +73,8 @@ Post er tilgængelig via KP2A-tastaturet App-sprog er tilgængelig - Kunne ikke åbne dialogboksen til valg af inputmetode. Aktivér tastaturet manuelt. - Aktivér Keepass2Android-tastaturet i systemindstillingerne. + Kunne ikke åbne dialogboksen for valg af inputmetode. Aktiver venligst tastaturet manuelt. + Aktiver venligst Keepass2Android-tastaturet i systemindstillingerne. Opretter databasenøgle… Aktuel Gruppe Aktuel gruppe: Root @@ -82,7 +82,7 @@ Cifre Keepass2Android leveres ABSOLUT UDEN GARANTI. Det er gratis software, og du er velkommen til at videredistribuere det jf. betingelserne i GPL version 2 eller senere. \u2026 - Kopiér til Upklipsholder + Kopiér til udklipsholder Systemsprog Verificér for at fortsætte Kan ikke opsætte biometrisk oplåsning: @@ -228,7 +228,7 @@ Nøgleafledningsfunktion Krypteringsgentagelser Flere krypteringsgentagelser giver øget beskyttelse imod brute force-angreb, men kan reduceredownload- og lagringstigheden mærkbart. - repetitioner + gentagelser Hukommelse til Argon 2 (bytes) Parallelisme til Argon 2 Databasenavn @@ -240,10 +240,10 @@ Mellemrum Søg Vis adgangskode - Sortér efter... - Sortér efter navn + Sorter efter... + Sorter efter navn Sortér efter oprettelsestidspunkt - Sortér efter ændringsdato + Sorter efter ændringsdato Behold standardrækkefølgen Speciel Udvidet Speciel From 994741cbf55297bb168dfe0e7350987bb8193653 Mon Sep 17 00:00:00 2001 From: Rick Brown Date: Sun, 19 Feb 2023 22:47:29 -0500 Subject: [PATCH 026/101] Update build documentation based on my experience --- docs/Build.readme.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/Build.readme.md b/docs/Build.readme.md index ee5baa77..16b9b57a 100644 --- a/docs/Build.readme.md +++ b/docs/Build.readme.md @@ -43,7 +43,7 @@ By using the command line, you can build on Windows, macOS or Linux. - On Debian, after having added the repo from above, install with `apt install -t mono-devel msbuild`. A value for `` could be `stable-buster` for example, depending on which one you chose. You could also install the `mono-complete` package if you prefer. - Install Xamarin.Android - - Option 1: Use the mono-project [CI builds](https://dev.azure.com/xamarin/public/_build/latest?definitionId=48&branchName=main&stageName=Linux) + - ~~Option 1: Use the mono-project [CI builds](https://dev.azure.com/xamarin/public/_build/latest?definitionId=48&branchName=main&stageName=Linux)~~ **NOTE:** KP2A now requires Xamarin.Android v13, which is newer than the current CI build; until a more recent CI build is available, this option is unfortunately no longer viable. - Option 2: [Build it from source](https://github.com/xamarin/xamarin-android/blob/master/Documentation/README.md#building-from-source) - Install NuGet package of your distribution @@ -64,9 +64,11 @@ This is done on the command line and requires the Android SDK & NDK and Java JDK ### On Windows - Setup your environment: - Set these environment variables for Android's SDK & NDK - - `ANDROID_HOME` (for example `set ANDROID_HOME=C:\PATH\TO\android-sdk\`) - - `ANDROID_SDK_ROOT` (for example `set ANDROID_SDK_ROOT=C:\PATH\TO\android-sdk\`) - - `ANDROID_NDK_ROOT` (for example `set ANDROID_NDK_ROOT=C:\PATH\TO\android-sdk\ndk\version\`) + - `ANDROID_HOME` (for example `set ANDROID_HOME=C:\PATH\TO\android-sdk`) + - `ANDROID_SDK_ROOT` (for example `set ANDROID_SDK_ROOT=C:\PATH\TO\android-sdk`) + - `ANDROID_NDK_ROOT` (for example `set ANDROID_NDK_ROOT=C:\PATH\TO\android-sdk\ndk\version`) + + **Note:** Care must be taken when setting the above variables to **not** include a trailing backslash in the path. A trailing backslash may cause `make` to fail. **Note**: If the path to the Android SDK contains spaces, you **must** do one of these: - either put the Android SDK into a path without spaces. @@ -103,6 +105,10 @@ This is done on the command line and requires the Android SDK & NDK and Java JDK - For building the java parts, it is suggested to keep a short name (e.g. "c:\projects\keepass2android") for the root project directory. Otherwise the Windows path length limit might be hit when building. - Before building the java parts, make sure you have set the ANDROID_HOME variable or create a local.properties file inside the directories with a gradlew file. It is recommended to use the same SDK location as that of the Xamarin build. + - On some environments, `make` can fail to properly use the detected `MSBUILD` tools. This seems to be due to long pathnames and/or spaces in pathnames. It may be required to explicitly set the `MSBUILD` path using 8.3 "short" path notation: + - Determine the location of `MSBUILD` (e.g. `C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\MSBuild.exe`) + - [Generate the "short" path](https://superuser.com/a/728792) of that location (e.g.: `C:\PROGRA~1\MICROS~2\2022\COMMUN~1\MSBuild\Current\Bin\MSBuild.exe`) + - When running `make` specify the location of ``MSBUILD` explicitly (e.g.: `make MSBUILD="C:\PROGRA~1\MICROS~2\2022\COMMUN~1\MSBuild\Current\Bin\MSBuild.exe` ### On Linux/macOS From 1e02db86d6dd589237fd2342c656940912ba8108 Mon Sep 17 00:00:00 2001 From: WreckingBANG <86848811+WreckingBANG@users.noreply.github.com> Date: Thu, 23 Feb 2023 14:59:13 +0100 Subject: [PATCH 027/101] Update ic_launcher_online.xml --- .../Resources/mipmap-anydpi-v26/ic_launcher_online.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/keepass2android/Resources/mipmap-anydpi-v26/ic_launcher_online.xml b/src/keepass2android/Resources/mipmap-anydpi-v26/ic_launcher_online.xml index 87c6a570..3844054f 100644 --- a/src/keepass2android/Resources/mipmap-anydpi-v26/ic_launcher_online.xml +++ b/src/keepass2android/Resources/mipmap-anydpi-v26/ic_launcher_online.xml @@ -2,4 +2,5 @@ - \ No newline at end of file + + From cd348966619de716ecae9aa986291de572411cb0 Mon Sep 17 00:00:00 2001 From: WreckingBANG <86848811+WreckingBANG@users.noreply.github.com> Date: Thu, 23 Feb 2023 14:59:31 +0100 Subject: [PATCH 028/101] Update ic_launcher_online_round.xml --- .../Resources/mipmap-anydpi-v26/ic_launcher_online_round.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/keepass2android/Resources/mipmap-anydpi-v26/ic_launcher_online_round.xml b/src/keepass2android/Resources/mipmap-anydpi-v26/ic_launcher_online_round.xml index 87c6a570..3844054f 100644 --- a/src/keepass2android/Resources/mipmap-anydpi-v26/ic_launcher_online_round.xml +++ b/src/keepass2android/Resources/mipmap-anydpi-v26/ic_launcher_online_round.xml @@ -2,4 +2,5 @@ - \ No newline at end of file + + From c29b789a2b2ee26ec46638b045f95d83a3b1e29f Mon Sep 17 00:00:00 2001 From: WreckingBANG <86848811+WreckingBANG@users.noreply.github.com> Date: Thu, 23 Feb 2023 14:59:40 +0100 Subject: [PATCH 029/101] Update ic_launcher_offline.xml --- .../Resources/mipmap-anydpi-v26/ic_launcher_offline.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/keepass2android/Resources/mipmap-anydpi-v26/ic_launcher_offline.xml b/src/keepass2android/Resources/mipmap-anydpi-v26/ic_launcher_offline.xml index c6e4e584..e81ba0f7 100644 --- a/src/keepass2android/Resources/mipmap-anydpi-v26/ic_launcher_offline.xml +++ b/src/keepass2android/Resources/mipmap-anydpi-v26/ic_launcher_offline.xml @@ -2,4 +2,5 @@ - \ No newline at end of file + + From 4cad70e75019c29f02de382c4129de18be40f308 Mon Sep 17 00:00:00 2001 From: WreckingBANG <86848811+WreckingBANG@users.noreply.github.com> Date: Thu, 23 Feb 2023 14:59:54 +0100 Subject: [PATCH 030/101] Update ic_launcher_offline_round.xml --- .../Resources/mipmap-anydpi-v26/ic_launcher_offline_round.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/keepass2android/Resources/mipmap-anydpi-v26/ic_launcher_offline_round.xml b/src/keepass2android/Resources/mipmap-anydpi-v26/ic_launcher_offline_round.xml index c6e4e584..e81ba0f7 100644 --- a/src/keepass2android/Resources/mipmap-anydpi-v26/ic_launcher_offline_round.xml +++ b/src/keepass2android/Resources/mipmap-anydpi-v26/ic_launcher_offline_round.xml @@ -2,4 +2,5 @@ - \ No newline at end of file + + From 8fa08034747eafb6c9fe19c3cb20ef496d6f74e7 Mon Sep 17 00:00:00 2001 From: WreckingBANG <86848811+WreckingBANG@users.noreply.github.com> Date: Thu, 23 Feb 2023 15:03:48 +0100 Subject: [PATCH 031/101] Create main.yml --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1 @@ + From 886daa6b279b3878df21f9fbb967d02e8dd6f581 Mon Sep 17 00:00:00 2001 From: WreckingBANG <86848811+WreckingBANG@users.noreply.github.com> Date: Thu, 23 Feb 2023 15:04:18 +0100 Subject: [PATCH 032/101] Update main.yml --- .github/workflows/main.yml | 324 +++++++++++++++++++++++++++++++++++++ 1 file changed, 324 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8b137891..3daaccf2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1 +1,325 @@ +name: Build keepass2android app +on: [push, pull_request] + +jobs: + macos: + + runs-on: macos-12 + + steps: + - uses: actions/checkout@v3 + + - name: Fetch submodules + run: git submodule init && git submodule update + + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 + + - name: Cache NuGet packages + uses: actions/cache@v3 + with: + path: ~/.nuget/packages + key: ${{ runner.os }}-nuget-${{ hashFiles('src/**/*.csproj', 'src/**/packages.config') }} + restore-keys: | + ${{ runner.os }}-nuget- + # As per https://github.com/actions/runner-images/blob/main/images/macos/macos-12-Readme.md#visual-studio-for-mac + - name: Switch to Visual Studio 2019 + if: ${{ false }} # Not needed. We stay with the default 'Visual Studio 2022' of macos-12 runner. + run: | + mv "/Applications/Visual Studio.app" "/Applications/Visual Studio 2022.app" + mv "/Applications/Visual Studio 2019.app" "/Applications/Visual Studio.app" + # As of 2022-12-02, keepass2android doesn't build with Xamarin >= 12.1 because there is some issue with SamsungPass. Removing SamsungPass would make the build succeed. + - name: Set default Xamarin SDK versions + run: | + # If using the github runner 'macos-12' + #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=11.3 + #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=12.0 + #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=12.1 # Build fails in this case, as of 2022-12-02 : Xamarin/Android/Xamarin.Android.D8.targets(79,5): error : java.lang.ArrayIndexOutOfBoundsException : Index 4 out of bounds for length 4 + #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=12.2 # Build fails in this case, as of 2022-12-02 : Xamarin/Android/Xamarin.Android.D8.targets(79,5): error : java.lang.ArrayIndexOutOfBoundsException : Index 4 out of bounds for length 4 + #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=12.3 # Build fails in this case, as of 2022-12-02 + $VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=13.1 + # If using the github runner 'macos-11' + #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=11.0 + #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=12.0 + # If using the github runner 'macos-10.15' + # $VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=11.2 + - name: Switch to JDK-11 + uses: actions/setup-java@v3 + with: + java-version: '11' + distribution: 'temurin' + + - name: Display java version + run: java -version + + # Some components of Keepass2Android currently target android API 26 which are not available on the runner + - name: Download android-26 API + run: $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager --install "platforms;android-26" + + - name: Build native dependencies + run: make native + + - name: Build java dependencies + run: make java + + - name: Install NuGet dependencies (net) + run: make nuget Flavor=Net + + - name: Build keepass2android (net) + run: | + make msbuild Flavor=Net + - name: Build APK (net) + run: | + make apk Flavor=Net + - name: Archive production artifacts (net) + uses: actions/upload-artifact@v3 + with: + name: signed APK ('net' built on ${{ github.job }}) + path: | + src/keepass2android/bin/*/*-Signed.apk + - name: Install NuGet dependencies (nonet) + run: make nuget Flavor=NoNet + + - name: Build keepass2android (nonet) + run: | + make msbuild Flavor=NoNet + - name: Build APK (nonet) + run: | + make apk Flavor=NoNet + - name: Archive production artifacts (nonet) + uses: actions/upload-artifact@v3 + with: + name: signed APK ('nonet' built on ${{ github.job }}) + path: | + src/keepass2android/bin/*/*-Signed.apk + - name: Perform "make distclean" + run: make distclean + + # linux: + # disabled. + # As per: xamarin/xamarin-android#7235 (comment) + # > Unfortunately the Classic OSS Xamarin.Android packages for Linux are no longer being built and as such they are not available for the v13.0 tag. + # we can re-enable this after porting to .net 6.0 + + # runs-on: ubuntu-22.04 + + # env: + # # Build Artifact of xamarin.android-oss dated 2021-02-02, master branch (= version 11.2.99) - *.deb cannot be installed because "lxd" package is not anymore shipped in current ubuntu version + # #xamarin_url: https://artprodcus3.artifacts.visualstudio.com/Ad0adf05a-e7d7-4b65-96fe-3f3884d42038/6fd3d886-57a5-4e31-8db7-52a1b47c07a8/_apis/artifact/cGlwZWxpbmVhcnRpZmFjdDovL3hhbWFyaW4vcHJvamVjdElkLzZmZDNkODg2LTU3YTUtNGUzMS04ZGI3LTUyYTFiNDdjMDdhOC9idWlsZElkLzM0NTE3L2FydGlmYWN0TmFtZS9JbnN0YWxsZXJzKy0rTGludXg1/content?format=zip + + # # Build Artifact of xamarin.android-oss dated 2021-03-23, d16-9 branch (= version 11.2.2) - *.deb cannot be installed because "lxd" package is not anymore shipped in current ubuntu version + # #xamarin_url: https://artprodcus3.artifacts.visualstudio.com/Ad0adf05a-e7d7-4b65-96fe-3f3884d42038/6fd3d886-57a5-4e31-8db7-52a1b47c07a8/_apis/artifact/cGlwZWxpbmVhcnRpZmFjdDovL3hhbWFyaW4vcHJvamVjdElkLzZmZDNkODg2LTU3YTUtNGUzMS04ZGI3LTUyYTFiNDdjMDdhOC9idWlsZElkLzM3Njg0L2FydGlmYWN0TmFtZS9JbnN0YWxsZXJzKy0rTGludXg1/content?format=zip + + # # Build Artifact of xamarin.android-oss dated 2021-07-21, master branch (= version 11.4.99) + # # xamarin_url: https://artprodcus3.artifacts.visualstudio.com/Ad0adf05a-e7d7-4b65-96fe-3f3884d42038/6fd3d886-57a5-4e31-8db7-52a1b47c07a8/_apis/artifact/cGlwZWxpbmVhcnRpZmFjdDovL3hhbWFyaW4vcHJvamVjdElkLzZmZDNkODg2LTU3YTUtNGUzMS04ZGI3LTUyYTFiNDdjMDdhOC9idWlsZElkLzQzNjU5L2FydGlmYWN0TmFtZS9pbnN0YWxsZXJzLXVuc2lnbmVkKy0rTGludXg1/content?format=zip + + # # Build Artifact of xamarin.android-oss dated 2022-02-16, master branch (= version 12.2.99) + # xamarin_url: https://artprodcus3.artifacts.visualstudio.com/Ad0adf05a-e7d7-4b65-96fe-3f3884d42038/6fd3d886-57a5-4e31-8db7-52a1b47c07a8/_apis/artifact/cGlwZWxpbmVhcnRpZmFjdDovL3hhbWFyaW4vcHJvamVjdElkLzZmZDNkODg2LTU3YTUtNGUzMS04ZGI3LTUyYTFiNDdjMDdhOC9idWlsZElkLzU0OTUzL2FydGlmYWN0TmFtZS9pbnN0YWxsZXJzLXVuc2lnbmVkKy0rTGludXg1/content?format=zip + # steps: + # - uses: actions/checkout@v3 + + # - name: Fetch submodules + # run: git submodule init && git submodule update + + # - name: Setup Gradle + # uses: gradle/gradle-build-action@v2 + + # - name: Cache NuGet packages + # uses: actions/cache@v3 + # with: + # path: ~/.nuget/packages + # key: ${{ runner.os }}-nuget-${{ hashFiles('src/**/*.csproj', 'src/**/packages.config') }} + # restore-keys: | + # ${{ runner.os }}-nuget- + + # - name: Cache Xamarin.Android packages + # id: xamarin_cache + # uses: actions/cache@v3 + # with: + # path: ~/xamarin.android-oss + # key: ${{ runner.os }}-xamarin.android-oss-${{ env.xamarin_url }} + # restore-keys: | + # ${{ runner.os }}-xamarin.android-oss-${{ env.xamarin_url }} + + # - name: Install Mono + # if: ${{ false }} # disable for now since it is already installed on the runner which uses the same repo https://github.com/actions/runner-images/blob/main/images/linux/Ubuntu2204-Readme.md#language-and-runtime + # run: | + # sudo apt install gnupg ca-certificates && + # sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF && + # echo "deb https://download.mono-project.com/repo/ubuntu stable-focal main" | sudo tee /etc/apt/sources.list.d/mono-official-stable.list && + # sudo apt update && + # sudo apt-get -y -t stable-focal install mono-complete + + # - name: Download & unpack Xamarin.Android + # if: steps.xamarin_cache.outputs.cache-hit != 'true' + # run: | + # set -x + # cd $HOME && + # wget -O "installers-unsigned - Linux.zip" ${{ env.xamarin_url }} && + # unzip "installers-unsigned - Linux.zip" && + # mkdir -p xamarin.android-oss && + # DIR=$(unzip -Z -1 installers-unsigned\ -\ Linux.zip | cut -d '/' -f1 | sort -u) && + # tar -xvf "$DIR"/xamarin.android-oss-*.tar.* --strip-components=1 -C xamarin.android-oss && + # mv "$DIR"/*.deb xamarin.android-oss + + # - name: Setup Xamarin.Android + # run: | + # cd $HOME && + # sudo apt install -y ./xamarin.android-oss/*.deb && + # echo "$HOME/xamarin.android-oss/bin/Release/bin" >> $GITHUB_PATH + + # - name: Switch to JDK-11 + # uses: actions/setup-java@v3 + # with: + # java-version: '11' + # distribution: 'temurin' + + # - name: Display java version + # run: java -version + + # # Some components of Keepass2Android currently target android API 26 which are not available on the runner + # - name: Download android-26 API + # run: $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager --install "platforms;android-26" + + # - name: Install libzip4 + # if: ${{ false }} # disable for now since it is already installed on the runner + # run: sudo apt -y install libzip4 + + # - name: Build native dependencies + # run: make native + + # - name: Build java dependencies + # run: make java + + # - name: Install NuGet dependencies (net) + # run: make nuget Flavor=Net + + # - name: Build keepass2android (net) + # run: | + # make msbuild Flavor=Net + + # - name: Build APK (net) + # run: | + # make apk Flavor=Net + + # - name: Archive production artifacts (net) + # uses: actions/upload-artifact@v3 + # with: + # name: signed APK ('net' built on ${{ github.job }}) + # path: | + # src/keepass2android/bin/*/*-Signed.apk + + # - name: Install NuGet dependencies (nonet) + # run: make nuget Flavor=NoNet + + # - name: Build keepass2android (nonet) + # run: | + # make msbuild Flavor=NoNet + + # - name: Build APK (nonet) + # run: | + # make apk Flavor=NoNet + + # - name: Archive production artifacts (nonet) + # uses: actions/upload-artifact@v3 + # with: + # name: signed APK ('nonet' built on ${{ github.job }}) + # path: | + # src/keepass2android/bin/*/*-Signed.apk + + # - name: Perform "make distclean" + # run: make distclean + + windows: + + # on windows-2022 it builds with: + # Microsoft Visual Studio\2022\Enterprise + # Found Java SDK version 11.0.12 + # Found Xamarin.Android 13.1.0.1 + # + runs-on: windows-2022 + + steps: + - uses: actions/checkout@v3 + + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 + + - name: Cache NuGet packages + uses: actions/cache@v3 + with: + path: ~/.nuget/packages + key: ${{ runner.os }}-nuget-${{ hashFiles('src/**/*.csproj', 'src/**/packages.config') }} + restore-keys: | + ${{ runner.os }}-nuget- + - name: Fetch submodules + run: git submodule init && git submodule update + + # Workaround an issue when building on windows-2022. Error was + # D8 : OpenJDK 64-Bit Server VM warning : INFO: os::commit_memory(0x00000000ae400000, 330301440, 0) failed; error='The paging file is too small for this operation to complete' (DOS error/errno=1455) [D:\a\keepass2android\keepass2android\src\keepass2android\keepass2android-app.csproj] + # C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Xamarin\Android\Xamarin.Android.D8.targets(81,5): error MSB6006: "java.exe" exited with code 1. [D:\a\keepass2android\keepass2android\src\keepass2android\keepass2android-app.csproj] + - name: Configure Pagefile + uses: al-cheb/configure-pagefile-action@v1.3 + with: + minimum-size: 8GB + + - name: Add msbuild to PATH + uses: microsoft/setup-msbuild@v1.1 + # If we want to also have nmake, use this instead + #uses: ilammy/msvc-dev-cmd@v1 + + - name: Switch to JDK-11 + uses: actions/setup-java@v3 + with: + java-version: '11' + distribution: 'temurin' + + - name: Display java version + run: java -version + + # Some components of Keepass2Android currently target android API 26 which are not available on the runner + - name: Download android-26 API + shell: cmd + run: | + %ANDROID_SDK_ROOT%\cmdline-tools\latest\bin\sdkmanager --install "platforms;android-26" + - name: Build native dependencies + shell: cmd + run: | + make native + - name: Build java dependencies + shell: cmd + run: | + make java + - name: Install NuGet dependencies (net) + run: make nuget Flavor=Net + + - name: Build keepass2android (net) + run: | + make msbuild Flavor=Net + - name: Build APK (net) + run: | + make apk Flavor=Net + - name: Archive production artifacts (net) + uses: actions/upload-artifact@v3 + with: + name: signed APK ('net' built on ${{ github.job }}) + path: | + src/keepass2android/bin/*/*-Signed.apk + - name: Install NuGet dependencies (nonet) + run: make nuget Flavor=NoNet + + - name: Build keepass2android (nonet) + run: | + make msbuild Flavor=NoNet + - name: Build APK (nonet) + run: | + make apk Flavor=NoNet + - name: Archive production artifacts (nonet) + uses: actions/upload-artifact@v3 + with: + name: signed APK ('nonet' built on ${{ github.job }}) + path: | + src/keepass2android/bin/*/*-Signed.apk + - name: Perform "make distclean" + run: make distclean From 0d4955622d7824f9040912c688e3bbdc6e12b6d8 Mon Sep 17 00:00:00 2001 From: WreckingBANG <86848811+WreckingBANG@users.noreply.github.com> Date: Thu, 23 Feb 2023 15:04:55 +0100 Subject: [PATCH 033/101] Delete main.yml --- .github/workflows/main.yml | 325 ------------------------------------- 1 file changed, 325 deletions(-) delete mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index 3daaccf2..00000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,325 +0,0 @@ -name: Build keepass2android app - -on: [push, pull_request] - -jobs: - macos: - - runs-on: macos-12 - - steps: - - uses: actions/checkout@v3 - - - name: Fetch submodules - run: git submodule init && git submodule update - - - name: Setup Gradle - uses: gradle/gradle-build-action@v2 - - - name: Cache NuGet packages - uses: actions/cache@v3 - with: - path: ~/.nuget/packages - key: ${{ runner.os }}-nuget-${{ hashFiles('src/**/*.csproj', 'src/**/packages.config') }} - restore-keys: | - ${{ runner.os }}-nuget- - # As per https://github.com/actions/runner-images/blob/main/images/macos/macos-12-Readme.md#visual-studio-for-mac - - name: Switch to Visual Studio 2019 - if: ${{ false }} # Not needed. We stay with the default 'Visual Studio 2022' of macos-12 runner. - run: | - mv "/Applications/Visual Studio.app" "/Applications/Visual Studio 2022.app" - mv "/Applications/Visual Studio 2019.app" "/Applications/Visual Studio.app" - # As of 2022-12-02, keepass2android doesn't build with Xamarin >= 12.1 because there is some issue with SamsungPass. Removing SamsungPass would make the build succeed. - - name: Set default Xamarin SDK versions - run: | - # If using the github runner 'macos-12' - #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=11.3 - #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=12.0 - #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=12.1 # Build fails in this case, as of 2022-12-02 : Xamarin/Android/Xamarin.Android.D8.targets(79,5): error : java.lang.ArrayIndexOutOfBoundsException : Index 4 out of bounds for length 4 - #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=12.2 # Build fails in this case, as of 2022-12-02 : Xamarin/Android/Xamarin.Android.D8.targets(79,5): error : java.lang.ArrayIndexOutOfBoundsException : Index 4 out of bounds for length 4 - #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=12.3 # Build fails in this case, as of 2022-12-02 - $VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=13.1 - # If using the github runner 'macos-11' - #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=11.0 - #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=12.0 - # If using the github runner 'macos-10.15' - # $VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=11.2 - - name: Switch to JDK-11 - uses: actions/setup-java@v3 - with: - java-version: '11' - distribution: 'temurin' - - - name: Display java version - run: java -version - - # Some components of Keepass2Android currently target android API 26 which are not available on the runner - - name: Download android-26 API - run: $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager --install "platforms;android-26" - - - name: Build native dependencies - run: make native - - - name: Build java dependencies - run: make java - - - name: Install NuGet dependencies (net) - run: make nuget Flavor=Net - - - name: Build keepass2android (net) - run: | - make msbuild Flavor=Net - - name: Build APK (net) - run: | - make apk Flavor=Net - - name: Archive production artifacts (net) - uses: actions/upload-artifact@v3 - with: - name: signed APK ('net' built on ${{ github.job }}) - path: | - src/keepass2android/bin/*/*-Signed.apk - - name: Install NuGet dependencies (nonet) - run: make nuget Flavor=NoNet - - - name: Build keepass2android (nonet) - run: | - make msbuild Flavor=NoNet - - name: Build APK (nonet) - run: | - make apk Flavor=NoNet - - name: Archive production artifacts (nonet) - uses: actions/upload-artifact@v3 - with: - name: signed APK ('nonet' built on ${{ github.job }}) - path: | - src/keepass2android/bin/*/*-Signed.apk - - name: Perform "make distclean" - run: make distclean - - # linux: - # disabled. - # As per: xamarin/xamarin-android#7235 (comment) - # > Unfortunately the Classic OSS Xamarin.Android packages for Linux are no longer being built and as such they are not available for the v13.0 tag. - # we can re-enable this after porting to .net 6.0 - - # runs-on: ubuntu-22.04 - - # env: - # # Build Artifact of xamarin.android-oss dated 2021-02-02, master branch (= version 11.2.99) - *.deb cannot be installed because "lxd" package is not anymore shipped in current ubuntu version - # #xamarin_url: https://artprodcus3.artifacts.visualstudio.com/Ad0adf05a-e7d7-4b65-96fe-3f3884d42038/6fd3d886-57a5-4e31-8db7-52a1b47c07a8/_apis/artifact/cGlwZWxpbmVhcnRpZmFjdDovL3hhbWFyaW4vcHJvamVjdElkLzZmZDNkODg2LTU3YTUtNGUzMS04ZGI3LTUyYTFiNDdjMDdhOC9idWlsZElkLzM0NTE3L2FydGlmYWN0TmFtZS9JbnN0YWxsZXJzKy0rTGludXg1/content?format=zip - - # # Build Artifact of xamarin.android-oss dated 2021-03-23, d16-9 branch (= version 11.2.2) - *.deb cannot be installed because "lxd" package is not anymore shipped in current ubuntu version - # #xamarin_url: https://artprodcus3.artifacts.visualstudio.com/Ad0adf05a-e7d7-4b65-96fe-3f3884d42038/6fd3d886-57a5-4e31-8db7-52a1b47c07a8/_apis/artifact/cGlwZWxpbmVhcnRpZmFjdDovL3hhbWFyaW4vcHJvamVjdElkLzZmZDNkODg2LTU3YTUtNGUzMS04ZGI3LTUyYTFiNDdjMDdhOC9idWlsZElkLzM3Njg0L2FydGlmYWN0TmFtZS9JbnN0YWxsZXJzKy0rTGludXg1/content?format=zip - - # # Build Artifact of xamarin.android-oss dated 2021-07-21, master branch (= version 11.4.99) - # # xamarin_url: https://artprodcus3.artifacts.visualstudio.com/Ad0adf05a-e7d7-4b65-96fe-3f3884d42038/6fd3d886-57a5-4e31-8db7-52a1b47c07a8/_apis/artifact/cGlwZWxpbmVhcnRpZmFjdDovL3hhbWFyaW4vcHJvamVjdElkLzZmZDNkODg2LTU3YTUtNGUzMS04ZGI3LTUyYTFiNDdjMDdhOC9idWlsZElkLzQzNjU5L2FydGlmYWN0TmFtZS9pbnN0YWxsZXJzLXVuc2lnbmVkKy0rTGludXg1/content?format=zip - - # # Build Artifact of xamarin.android-oss dated 2022-02-16, master branch (= version 12.2.99) - # xamarin_url: https://artprodcus3.artifacts.visualstudio.com/Ad0adf05a-e7d7-4b65-96fe-3f3884d42038/6fd3d886-57a5-4e31-8db7-52a1b47c07a8/_apis/artifact/cGlwZWxpbmVhcnRpZmFjdDovL3hhbWFyaW4vcHJvamVjdElkLzZmZDNkODg2LTU3YTUtNGUzMS04ZGI3LTUyYTFiNDdjMDdhOC9idWlsZElkLzU0OTUzL2FydGlmYWN0TmFtZS9pbnN0YWxsZXJzLXVuc2lnbmVkKy0rTGludXg1/content?format=zip - # steps: - # - uses: actions/checkout@v3 - - # - name: Fetch submodules - # run: git submodule init && git submodule update - - # - name: Setup Gradle - # uses: gradle/gradle-build-action@v2 - - # - name: Cache NuGet packages - # uses: actions/cache@v3 - # with: - # path: ~/.nuget/packages - # key: ${{ runner.os }}-nuget-${{ hashFiles('src/**/*.csproj', 'src/**/packages.config') }} - # restore-keys: | - # ${{ runner.os }}-nuget- - - # - name: Cache Xamarin.Android packages - # id: xamarin_cache - # uses: actions/cache@v3 - # with: - # path: ~/xamarin.android-oss - # key: ${{ runner.os }}-xamarin.android-oss-${{ env.xamarin_url }} - # restore-keys: | - # ${{ runner.os }}-xamarin.android-oss-${{ env.xamarin_url }} - - # - name: Install Mono - # if: ${{ false }} # disable for now since it is already installed on the runner which uses the same repo https://github.com/actions/runner-images/blob/main/images/linux/Ubuntu2204-Readme.md#language-and-runtime - # run: | - # sudo apt install gnupg ca-certificates && - # sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF && - # echo "deb https://download.mono-project.com/repo/ubuntu stable-focal main" | sudo tee /etc/apt/sources.list.d/mono-official-stable.list && - # sudo apt update && - # sudo apt-get -y -t stable-focal install mono-complete - - # - name: Download & unpack Xamarin.Android - # if: steps.xamarin_cache.outputs.cache-hit != 'true' - # run: | - # set -x - # cd $HOME && - # wget -O "installers-unsigned - Linux.zip" ${{ env.xamarin_url }} && - # unzip "installers-unsigned - Linux.zip" && - # mkdir -p xamarin.android-oss && - # DIR=$(unzip -Z -1 installers-unsigned\ -\ Linux.zip | cut -d '/' -f1 | sort -u) && - # tar -xvf "$DIR"/xamarin.android-oss-*.tar.* --strip-components=1 -C xamarin.android-oss && - # mv "$DIR"/*.deb xamarin.android-oss - - # - name: Setup Xamarin.Android - # run: | - # cd $HOME && - # sudo apt install -y ./xamarin.android-oss/*.deb && - # echo "$HOME/xamarin.android-oss/bin/Release/bin" >> $GITHUB_PATH - - # - name: Switch to JDK-11 - # uses: actions/setup-java@v3 - # with: - # java-version: '11' - # distribution: 'temurin' - - # - name: Display java version - # run: java -version - - # # Some components of Keepass2Android currently target android API 26 which are not available on the runner - # - name: Download android-26 API - # run: $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager --install "platforms;android-26" - - # - name: Install libzip4 - # if: ${{ false }} # disable for now since it is already installed on the runner - # run: sudo apt -y install libzip4 - - # - name: Build native dependencies - # run: make native - - # - name: Build java dependencies - # run: make java - - # - name: Install NuGet dependencies (net) - # run: make nuget Flavor=Net - - # - name: Build keepass2android (net) - # run: | - # make msbuild Flavor=Net - - # - name: Build APK (net) - # run: | - # make apk Flavor=Net - - # - name: Archive production artifacts (net) - # uses: actions/upload-artifact@v3 - # with: - # name: signed APK ('net' built on ${{ github.job }}) - # path: | - # src/keepass2android/bin/*/*-Signed.apk - - # - name: Install NuGet dependencies (nonet) - # run: make nuget Flavor=NoNet - - # - name: Build keepass2android (nonet) - # run: | - # make msbuild Flavor=NoNet - - # - name: Build APK (nonet) - # run: | - # make apk Flavor=NoNet - - # - name: Archive production artifacts (nonet) - # uses: actions/upload-artifact@v3 - # with: - # name: signed APK ('nonet' built on ${{ github.job }}) - # path: | - # src/keepass2android/bin/*/*-Signed.apk - - # - name: Perform "make distclean" - # run: make distclean - - windows: - - # on windows-2022 it builds with: - # Microsoft Visual Studio\2022\Enterprise - # Found Java SDK version 11.0.12 - # Found Xamarin.Android 13.1.0.1 - # - runs-on: windows-2022 - - steps: - - uses: actions/checkout@v3 - - - name: Setup Gradle - uses: gradle/gradle-build-action@v2 - - - name: Cache NuGet packages - uses: actions/cache@v3 - with: - path: ~/.nuget/packages - key: ${{ runner.os }}-nuget-${{ hashFiles('src/**/*.csproj', 'src/**/packages.config') }} - restore-keys: | - ${{ runner.os }}-nuget- - - name: Fetch submodules - run: git submodule init && git submodule update - - # Workaround an issue when building on windows-2022. Error was - # D8 : OpenJDK 64-Bit Server VM warning : INFO: os::commit_memory(0x00000000ae400000, 330301440, 0) failed; error='The paging file is too small for this operation to complete' (DOS error/errno=1455) [D:\a\keepass2android\keepass2android\src\keepass2android\keepass2android-app.csproj] - # C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Xamarin\Android\Xamarin.Android.D8.targets(81,5): error MSB6006: "java.exe" exited with code 1. [D:\a\keepass2android\keepass2android\src\keepass2android\keepass2android-app.csproj] - - name: Configure Pagefile - uses: al-cheb/configure-pagefile-action@v1.3 - with: - minimum-size: 8GB - - - name: Add msbuild to PATH - uses: microsoft/setup-msbuild@v1.1 - # If we want to also have nmake, use this instead - #uses: ilammy/msvc-dev-cmd@v1 - - - name: Switch to JDK-11 - uses: actions/setup-java@v3 - with: - java-version: '11' - distribution: 'temurin' - - - name: Display java version - run: java -version - - # Some components of Keepass2Android currently target android API 26 which are not available on the runner - - name: Download android-26 API - shell: cmd - run: | - %ANDROID_SDK_ROOT%\cmdline-tools\latest\bin\sdkmanager --install "platforms;android-26" - - name: Build native dependencies - shell: cmd - run: | - make native - - name: Build java dependencies - shell: cmd - run: | - make java - - name: Install NuGet dependencies (net) - run: make nuget Flavor=Net - - - name: Build keepass2android (net) - run: | - make msbuild Flavor=Net - - name: Build APK (net) - run: | - make apk Flavor=Net - - name: Archive production artifacts (net) - uses: actions/upload-artifact@v3 - with: - name: signed APK ('net' built on ${{ github.job }}) - path: | - src/keepass2android/bin/*/*-Signed.apk - - name: Install NuGet dependencies (nonet) - run: make nuget Flavor=NoNet - - - name: Build keepass2android (nonet) - run: | - make msbuild Flavor=NoNet - - name: Build APK (nonet) - run: | - make apk Flavor=NoNet - - name: Archive production artifacts (nonet) - uses: actions/upload-artifact@v3 - with: - name: signed APK ('nonet' built on ${{ github.job }}) - path: | - src/keepass2android/bin/*/*-Signed.apk - - name: Perform "make distclean" - run: make distclean From ca5f6dc43c7c1c28c1e656a5cebef8e845aa1874 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Fri, 24 Feb 2023 20:38:56 +0100 Subject: [PATCH 034/101] New translations strings.xml (Slovak) --- src/keepass2android/Resources/values-sk/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/keepass2android/Resources/values-sk/strings.xml b/src/keepass2android/Resources/values-sk/strings.xml index 549c6622..2c2ef1b6 100644 --- a/src/keepass2android/Resources/values-sk/strings.xml +++ b/src/keepass2android/Resources/values-sk/strings.xml @@ -686,6 +686,11 @@ Notifikácia na zjednodušenie prístupu k práve vybranému záznamu. Zavrieť databázu po troch neúspešných odomykaniach s biometriou Varovanie! Biometrická autentifikácia môže byť zneplatnená systémom Android, nap. po pridaní nového odtlačku prsta do nastavení zariadenia. Vždy sa uistite, že viete ako odomknúť zariadenia primárnym heslom. + + Oprava chyby vedúcej k pádom a neočakávaným odhláseniam + Prepnutie na novú implementáciu SFTP, s podporou pre moderné algoritmy verejných kľúčov, ako je rsa-sha2-256 + Označiť heslá ako citlivé údaje pri kopírovaní do schránky (Android 13) + Pridaná podpora prehliadania, odstraňovania a obnovovania záloh záznamu Implementovaná podpora pre cloudové úložisko MEGA From 914224e4fad8d29444c271e80bc384e933cc5f53 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Tue, 28 Feb 2023 22:31:28 +0100 Subject: [PATCH 035/101] refactoring of autofill implementation, extracted some pieces to be independant of Android framework, added some xUnit tests --- src/KeePass.sln | 28 +- src/Kp2aAutofillParser/AutofillParser.cs | 350 +++---- src/Kp2aAutofillParserTest/AutofillTest.cs | 114 +++ .../Kp2aAutofillParserTest.csproj | 46 + src/Kp2aAutofillParserTest/Usings.cs | 1 + .../com-servicenet-mobile-focused.json | 121 +++ .../com-servicenet-mobile-no-focus.json | 119 +++ .../firefox-amazon-it.json | 469 +++++++++ .../AutofillBase/AutofillFieldMetadata.cs | 2 +- .../AutofillBase/AutofillServiceBase.cs | 5 +- .../ChooseForAutofillActivityBase.cs | 5 +- .../Kp2aDigitalAssetLinksDataSource.cs | 5 + .../services/AutofillBase/StructureParser.cs | 318 +----- .../Kp2aAutofill/ChooseForAutofillActivity.cs | 21 +- .../Kp2aAutofill/Kp2aAutofillService.cs | 5 +- .../Kp2aAutofillParser/AutofillParser.cs | 956 ++++++++++++++++++ .../Kp2aAutofillParser.csproj | 12 + 17 files changed, 2096 insertions(+), 481 deletions(-) create mode 100644 src/Kp2aAutofillParserTest/AutofillTest.cs create mode 100644 src/Kp2aAutofillParserTest/Kp2aAutofillParserTest.csproj create mode 100644 src/Kp2aAutofillParserTest/Usings.cs create mode 100644 src/Kp2aAutofillParserTest/com-servicenet-mobile-focused.json create mode 100644 src/Kp2aAutofillParserTest/com-servicenet-mobile-no-focus.json create mode 100644 src/Kp2aAutofillParserTest/firefox-amazon-it.json create mode 100644 src/keepass2android/services/Kp2aAutofillParser/AutofillParser.cs create mode 100644 src/keepass2android/services/Kp2aAutofillParser/Kp2aAutofillParser.csproj diff --git a/src/KeePass.sln b/src/KeePass.sln index 27d6c9ae..bcd542c4 100644 --- a/src/KeePass.sln +++ b/src/KeePass.sln @@ -25,7 +25,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PCloudBindings", "PCloudBin EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "keepass2android-app", "keepass2android\keepass2android-app.csproj", "{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kp2aAutofillParser", "Kp2aAutofillParser\Kp2aAutofillParser.csproj", "{39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kp2aAutofillParser", "Kp2aAutofillParser\Kp2aAutofillParser.csproj", "{39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kp2aAutofillParserTest", "Kp2aAutofillParserTest\Kp2aAutofillParserTest.csproj", "{3D1560FF-86BB-4CB4-8367-80BA13B81C38}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -309,6 +311,30 @@ Global {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.ReleaseNoNet|Win32.Build.0 = Release|Any CPU {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU {39B12571-BAFE-4D3A-AEE2-4D74F14DFD96}.ReleaseNoNet|x64.Build.0 = Release|Any CPU + {3D1560FF-86BB-4CB4-8367-80BA13B81C38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3D1560FF-86BB-4CB4-8367-80BA13B81C38}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3D1560FF-86BB-4CB4-8367-80BA13B81C38}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {3D1560FF-86BB-4CB4-8367-80BA13B81C38}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {3D1560FF-86BB-4CB4-8367-80BA13B81C38}.Debug|Win32.ActiveCfg = Debug|Any CPU + {3D1560FF-86BB-4CB4-8367-80BA13B81C38}.Debug|Win32.Build.0 = Debug|Any CPU + {3D1560FF-86BB-4CB4-8367-80BA13B81C38}.Debug|x64.ActiveCfg = Debug|Any CPU + {3D1560FF-86BB-4CB4-8367-80BA13B81C38}.Debug|x64.Build.0 = Debug|Any CPU + {3D1560FF-86BB-4CB4-8367-80BA13B81C38}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3D1560FF-86BB-4CB4-8367-80BA13B81C38}.Release|Any CPU.Build.0 = Release|Any CPU + {3D1560FF-86BB-4CB4-8367-80BA13B81C38}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {3D1560FF-86BB-4CB4-8367-80BA13B81C38}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {3D1560FF-86BB-4CB4-8367-80BA13B81C38}.Release|Win32.ActiveCfg = Release|Any CPU + {3D1560FF-86BB-4CB4-8367-80BA13B81C38}.Release|Win32.Build.0 = Release|Any CPU + {3D1560FF-86BB-4CB4-8367-80BA13B81C38}.Release|x64.ActiveCfg = Release|Any CPU + {3D1560FF-86BB-4CB4-8367-80BA13B81C38}.Release|x64.Build.0 = Release|Any CPU + {3D1560FF-86BB-4CB4-8367-80BA13B81C38}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU + {3D1560FF-86BB-4CB4-8367-80BA13B81C38}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU + {3D1560FF-86BB-4CB4-8367-80BA13B81C38}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU + {3D1560FF-86BB-4CB4-8367-80BA13B81C38}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU + {3D1560FF-86BB-4CB4-8367-80BA13B81C38}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU + {3D1560FF-86BB-4CB4-8367-80BA13B81C38}.ReleaseNoNet|Win32.Build.0 = Release|Any CPU + {3D1560FF-86BB-4CB4-8367-80BA13B81C38}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU + {3D1560FF-86BB-4CB4-8367-80BA13B81C38}.ReleaseNoNet|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Kp2aAutofillParser/AutofillParser.cs b/src/Kp2aAutofillParser/AutofillParser.cs index 489f81b4..049aeb0c 100644 --- a/src/Kp2aAutofillParser/AutofillParser.cs +++ b/src/Kp2aAutofillParser/AutofillParser.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; -using System.Xml; +using Newtonsoft.Json; +using Formatting = System.Xml.Formatting; namespace Kp2aAutofillParser { @@ -192,54 +194,54 @@ namespace Kp2aAutofillParser return false; } } - class AutofillHintsHelper + public class AutofillHintsHelper { - const string AutofillHint2faAppOtp = "2faAppOTPCode"; - const string AutofillHintBirthDateDay = "birthDateDay"; - const string AutofillHintBirthDateFull = "birthDateFull"; - const string AutofillHintBirthDateMonth = "birthDateMonth"; - const string AutofillHintBirthDateYear = "birthDateYear"; - const string AutofillHintCreditCardExpirationDate = "creditCardExpirationDate"; - const string AutofillHintCreditCardExpirationDay = "creditCardExpirationDay"; - const string AutofillHintCreditCardExpirationMonth = "creditCardExpirationMonth"; - const string AutofillHintCreditCardExpirationYear = "creditCardExpirationYear"; - const string AutofillHintCreditCardNumber = "creditCardNumber"; - const string AutofillHintCreditCardSecurityCode = "creditCardSecurityCode"; - const string AutofillHintEmailAddress = "emailAddress"; - const string AutofillHintEmailOtp = "emailOTPCode"; - const string AutofillHintGender = "gender"; - const string AutofillHintName = "name"; - const string AutofillHintNewPassword = "newPassword"; - const string AutofillHintNewUsername = "newUsername"; - const string AutofillHintNotApplicable = "notApplicable"; - const string AutofillHintPassword = "password"; - const string AutofillHintPersonName = "personName"; - const string AutofillHintPersonNameFAMILY = "personFamilyName"; - const string AutofillHintPersonNameGIVEN = "personGivenName"; - const string AutofillHintPersonNameMIDDLE = "personMiddleName"; - const string AutofillHintPersonNameMIDDLE_INITIAL = "personMiddleInitial"; - const string AutofillHintPersonNamePREFIX = "personNamePrefix"; - const string AutofillHintPersonNameSUFFIX = "personNameSuffix"; - const string AutofillHintPhone = "phone"; - const string AutofillHintPhoneContryCode = "phoneCountryCode"; - const string AutofillHintPostalAddressAPT_NUMBER = "aptNumber"; - const string AutofillHintPostalAddressCOUNTRY = "addressCountry"; - const string AutofillHintPostalAddressDEPENDENT_LOCALITY = "dependentLocality"; - const string AutofillHintPostalAddressEXTENDED_ADDRESS = "extendedAddress"; - const string AutofillHintPostalAddressEXTENDED_POSTAL_CODE = "extendedPostalCode"; - const string AutofillHintPostalAddressLOCALITY = "addressLocality"; - const string AutofillHintPostalAddressREGION = "addressRegion"; - const string AutofillHintPostalAddressSTREET_ADDRESS = "streetAddress"; - const string AutofillHintPostalCode = "postalCode"; - const string AutofillHintPromoCode = "promoCode"; - const string AutofillHintSMS_OTP = "smsOTPCode"; - const string AutofillHintUPI_VPA = "upiVirtualPaymentAddress"; - const string AutofillHintUsername = "username"; - const string AutofillHintWifiPassword = "wifiPassword"; - const string AutofillHintPhoneNational = "phoneNational"; - const string AutofillHintPhoneNumber = "phoneNumber"; - const string AutofillHintPhoneNumberDevice = "phoneNumberDevice"; - const string AutofillHintPostalAddress = "postalAddress"; + 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) { @@ -540,8 +542,29 @@ namespace Kp2aAutofillParser { 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; @@ -671,7 +694,7 @@ namespace Kp2aAutofillParser } /// - /// Base class for everything that is a input field which might (or might not) be autofilled. + /// Base class for everything that is (or could be) an input field which might (or might not) be autofilled. /// For testability, this is independent from Android classes like ViewNode /// public abstract class InputField @@ -687,11 +710,12 @@ namespace Kp2aAutofillParser public string HtmlInfoTag { get; set; } public string HtmlInfoTypeAttribute { get; set; } - public abstract void FillFilledAutofillValue(FilledAutofillField filledField); - - } + /// + /// Serializable structure defining the contents of the current view (from an autofill perspective) + /// + /// public class AutofillView where TField : InputField { public List InputFields { get; set; } = new List(); @@ -710,8 +734,17 @@ namespace Kp2aAutofillParser 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; @@ -763,151 +796,86 @@ namespace Kp2aAutofillParser /// The parse. /// If set to true for fill. /// - AutofillTargetId Parse(bool forFill, bool isManualRequest, AutofillView autofillView) + protected virtual AutofillTargetId Parse(bool forFill, bool isManualRequest, AutofillView autofillView) { - AutofillTargetId result = new AutofillTargetId(); + AutofillTargetId result = new AutofillTargetId() + { + PackageName = autofillView.PackageId, + WebDomain = autofillView.WebDomain + }; - - _editTextsWithoutHint.Clear(); - _log.Log("parsing autofillStructure..."); - - //TODO remove from production - _log.Log("will log the autofillStructure..."); - string debugInfo = JsonConvert.SerializeObject(autofillView, Formatting.Indented); - _log.Log("will log the autofillStructure... size is " + debugInfo.Length); - _log.Log("This is the autofillStructure: \n\n " + debugInfo); - foreach (var viewNode in autofillView.InputFields) + if (LogAutofillView) { - string[] viewHints = viewNode.AutofillHints; - if (viewHints != null && viewHints.Length == 1 && viewHints.First() == "off" && viewNode.IsFocused && - isManualRequest) - viewHints[0] = "on"; - /*if (viewHints != null && viewHints.Any()) - { - CommonUtil.logd("viewHints=" + viewHints); - CommonUtil.logd("class=" + viewNode.ClassName); - CommonUtil.logd("tag=" + (viewNode?.HtmlInfo?.Tag ?? "(null)")); - }*/ - - if (IsPassword(viewNode) || HasPasswordHint(viewNode) || (HasUsernameHint(viewNode))) - { - if (forFill) - { - AutofillFields.Add(new AutofillFieldMetadata(viewNode.ViewNode)); - } - else - { - FilledAutofillField filledAutofillField = new FilledAutofillField(viewNode.ViewNode); - ClientFormData.Add(filledAutofillField); - } - } - else if (viewNode.ClassName == "android.widget.EditText" - || viewNode.ClassName == "android.widget.AutoCompleteTextView" - || viewNode.HtmlInfoTag == "input" - || ((viewHints?.Length ?? 0) > 0)) - { - _log.Log("Found something that looks fillable " + viewNode.ClassName); - - } - - if (viewHints != null && viewHints.Length > 0 && viewHints.First() != "on" /*if hint is "on", treat as if there is no hint*/) - { - } - else - { - - if (viewNode.ClassName == "android.widget.EditText" - || viewNode.ClassName == "android.widget.AutoCompleteTextView" - || viewNode.HtmlInfoTag == "input") - { - _editTextsWithoutHint.Add(viewNode); - } - - } + string debugInfo = JsonConvert.SerializeObject(autofillView, Newtonsoft.Json.Formatting.Indented); + _log.Log("This is the autofillStructure: \n\n " + debugInfo); } - List passwordFields = new List(); - List usernameFields = new List(); - if (AutofillFields.Empty) + + //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) { - passwordFields = _editTextsWithoutHint.Where(IsPassword).ToList(); - if (!passwordFields.Any()) + foreach (var viewNode in autofillView.InputFields) { - passwordFields = _editTextsWithoutHint.Where(HasPasswordHint).ToList(); - } - - usernameFields = _editTextsWithoutHint.Where(HasUsernameHint).ToList(); - - if (usernameFields.Any() == false) - { - - foreach (var passwordField in passwordFields) + string[] viewHints = viewNode.AutofillHints; + if (viewHints == null) + continue; + if (viewHints.Intersect(_autofillHintsForLogin).Any()) { - var usernameField = _editTextsWithoutHint - .TakeWhile(f => f != passwordField).LastOrDefault(); - if (usernameField != null) - { - usernameFields.Add(usernameField); - } - } - } - if (usernameFields.Any() == false) - { - //for some pages with two-step login, we don't see a password field and don't display the autofill for non-manual requests. But if the user forces autofill, - //let's assume it is a username field: - if (isManualRequest && !passwordFields.Any() && _editTextsWithoutHint.Count == 1) - { - usernameFields.Add(_editTextsWithoutHint.First()); - } - } - - - } - - //force focused fields to be included in autofill fields when request was triggered manually. This allows to fill fields which are "off" or don't have a hint (in case there are hints) - if (isManualRequest) - { - foreach (var editText in _editTextsWithoutHint) - { - if (editText.IsFocused) - { - if (IsPassword(editText) || HasPasswordHint(editText)) - passwordFields.Add(editText); - else - usernameFields.Add(editText); - break; + FieldsMappedToHints.Add(viewNode, viewHints); } } } - - if (forFill) - { - foreach (var uf in usernameFields) - AutofillFields.Add(new AutofillFieldMetadata(uf.ViewNode, new[] { View.AutofillHintUsername })); - foreach (var pf in passwordFields) - AutofillFields.Add(new AutofillFieldMetadata(pf.ViewNode, new[] { View.AutofillHintPassword })); - - } else { - foreach (var uf in usernameFields) - ClientFormData.Add(new FilledAutofillField(uf.ViewNode, new[] { View.AutofillHintUsername })); - foreach (var pf in passwordFields) - ClientFormData.Add(new FilledAutofillField(pf.ViewNode, new[] { View.AutofillHintPassword })); + //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 }); + } } + - - result.WebDomain = autofillView.WebDomain; - result.PackageName = Structure.ActivityComponent.PackageName; - if (!string.IsNullOrEmpty(autofillView.WebDomain) && !PreferenceManager.GetDefaultSharedPreferences(mContext).GetBoolean(mContext.GetString(Resource.String.NoDalVerification_key), false)) + if (!string.IsNullOrEmpty(autofillView.WebDomain) && _digitalAssetLinksDataSource.IsEnabled()) { - result.IncompatiblePackageAndDomain = !kp2aDigitalAssetLinksDataSource.IsTrustedLink(autofillView.WebDomain, result.PackageName); + result.IncompatiblePackageAndDomain = !_digitalAssetLinksDataSource.IsTrustedLink(autofillView.WebDomain, result.PackageName); if (result.IncompatiblePackageAndDomain) { - CommonUtil.loge($"DAL verification failed for {result.PackageName}/{result.WebDomain}"); + _log.Log($"DAL verification failed for {result.PackageName}/{result.WebDomain}"); } } else @@ -916,29 +884,40 @@ namespace Kp2aAutofillParser } return result; } - private static readonly HashSet _passwordHints = new HashSet { "password", "passwort", "passwordAuto", "pswd" }; + + public bool LogAutofillView { get; set; } + + 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 ContainsAny(f.IdEntry, _passwordHints) || - ContainsAny(f.Hint, _passwordHints); + 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 ContainsAny(f.IdEntry, _usernameHints) || - ContainsAny(f.Hint, _usernameHints); + return IsAny(f.IdEntry, _usernameHints) || + IsAny(f.Hint, _usernameHints); } - private static bool ContainsAny(string value, IEnumerable terms) + private static bool IsAny(string value, IEnumerable terms) { if (string.IsNullOrWhiteSpace(value)) { return false; } var lowerValue = value.ToLowerInvariant(); - return terms.Any(t => lowerValue.Contains(t)); + return terms.Any(t => lowerValue == t); } private static bool IsInputTypeClass(InputTypes inputType, InputTypes inputTypeClass) @@ -970,12 +949,13 @@ namespace Kp2aAutofillParser || IsInputTypeVariation(inputType, InputTypes.TextVariationWebPassword) ) ) + || (f.AutofillHints != null && f.AutofillHints.First() == "passwordAuto") || (f.HtmlInfoTypeAttribute == "password") ); } - AssistStructure Structure; - private List _editTextsWithoutHint = new List(); + + diff --git a/src/Kp2aAutofillParserTest/AutofillTest.cs b/src/Kp2aAutofillParserTest/AutofillTest.cs new file mode 100644 index 00000000..fe4a44de --- /dev/null +++ b/src/Kp2aAutofillParserTest/AutofillTest.cs @@ -0,0 +1,114 @@ +using Kp2aAutofillParser; +using Newtonsoft.Json; +using System.IO; +using System.Reflection; +using Xunit.Abstractions; + +namespace Kp2aAutofillParserTest +{ + public class AutofillTest + { + private readonly ITestOutputHelper _testOutputHelper; + + public AutofillTest(ITestOutputHelper testOutputHelper) + { + _testOutputHelper = testOutputHelper; + } + + class TestInputField: InputField + { + public string[] ExpectedAssignedHints { get; set; } + } + + [Fact] + public void TestNotFocusedPasswordAutoIsNotFilled() + { + var resourceName = "Kp2aAutofillParserTest.com-servicenet-mobile-no-focus.json"; + RunTestFromAutofillInput(resourceName, "com.servicenet.mobile"); + } + + [Fact] + public void TestFocusedPasswordAutoIsFilled() + { + var resourceName = "Kp2aAutofillParserTest.com-servicenet-mobile-focused.json"; + RunTestFromAutofillInput(resourceName, "com.servicenet.mobile" ); + } + + [Fact] + public void TestMulitpleUnfocusedLoginsIsFilled() + { + var resourceName = "Kp2aAutofillParserTest.firefox-amazon-it.json"; + RunTestFromAutofillInput(resourceName, "org.mozilla.firefox", "www.amazon.it"); + } + + private void RunTestFromAutofillInput(string resourceName, string expectedPackageName = null, string expectedWebDomain = null) + { + var assembly = Assembly.GetExecutingAssembly(); + + + string input; + using (Stream stream = assembly.GetManifestResourceStream(resourceName)) + using (StreamReader reader = new StreamReader(stream)) + { + input = reader.ReadToEnd(); + } + + AutofillView? autofillView = + JsonConvert.DeserializeObject>(input); + + StructureParserBase parser = + new StructureParserBase(new TestLogger(), new TestDalSourceTrustAll()); + + var result = parser.ParseForFill(false, autofillView); + if (expectedPackageName != null) + Assert.Equal(expectedPackageName, result.PackageName); + if (expectedWebDomain != null) + Assert.Equal(expectedWebDomain, result.WebDomain); + foreach (var field in autofillView.InputFields) + { + string[] expectedHints = field.ExpectedAssignedHints; + if (expectedHints == null) + expectedHints = new string[0]; + string[] actualHints; + parser.FieldsMappedToHints.TryGetValue(field, out actualHints); + if (actualHints == null) + actualHints = new string[0]; + if (actualHints.Any() || expectedHints.Any()) + { + _testOutputHelper.WriteLine($"field = {field.IdEntry} {field.Hint} {string.Join(",", field.AutofillHints)}"); + _testOutputHelper.WriteLine("actual Hints = " + string.Join(", ", actualHints)); + _testOutputHelper.WriteLine("expected Hints = " + string.Join(", ", expectedHints)); + } + + Assert.Equal(expectedHints.Length, actualHints.Length); + Assert.Equal(expectedHints.OrderBy(x => x), actualHints.OrderBy(x => x)); + } + } + } + + public class TestDalSourceTrustAll : IKp2aDigitalAssetLinksDataSource + { + public bool IsTrustedApp(string packageName) + { + return true; + } + + public bool IsTrustedLink(string domain, string targetPackage) + { + return true; + } + + public bool IsEnabled() + { + return true; + } + } + + public class TestLogger : ILogger + { + public void Log(string x) + { + Console.WriteLine(x); + } + } +} \ No newline at end of file diff --git a/src/Kp2aAutofillParserTest/Kp2aAutofillParserTest.csproj b/src/Kp2aAutofillParserTest/Kp2aAutofillParserTest.csproj new file mode 100644 index 00000000..bda6ab66 --- /dev/null +++ b/src/Kp2aAutofillParserTest/Kp2aAutofillParserTest.csproj @@ -0,0 +1,46 @@ + + + + net6.0 + enable + enable + + false + + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + diff --git a/src/Kp2aAutofillParserTest/Usings.cs b/src/Kp2aAutofillParserTest/Usings.cs new file mode 100644 index 00000000..8c927eb7 --- /dev/null +++ b/src/Kp2aAutofillParserTest/Usings.cs @@ -0,0 +1 @@ +global using Xunit; \ No newline at end of file diff --git a/src/Kp2aAutofillParserTest/com-servicenet-mobile-focused.json b/src/Kp2aAutofillParserTest/com-servicenet-mobile-focused.json new file mode 100644 index 00000000..60885b56 --- /dev/null +++ b/src/Kp2aAutofillParserTest/com-servicenet-mobile-focused.json @@ -0,0 +1,121 @@ +{ + "InputFields": [ + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": true, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "action_bar_root", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "action_mode_bar_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "content", + "Hint": null, + "ClassName": "android.view.ViewGroup", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "username_text_input_layout", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "username", + "Hint": "Username", + "ClassName": "android.widget.EditText", + "AutofillHints": null, + "IsFocused": true, + "InputType": 97, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null, + "ExpectedAssignedHints": [ "username" ] + }, + { + "IdEntry": "password_text_input_layout", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "password", + "Hint": "Password", + "ClassName": "android.widget.EditText", + "AutofillHints": [ + "passwordAuto" + ], + "IsFocused": false, + "InputType": 129, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null, + + "ExpectedAssignedHints": [ "password" ] + }, + { + "IdEntry": "login_button", + "Hint": null, + "ClassName": "android.widget.Button", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "progressBar", + "Hint": null, + "ClassName": "android.widget.ProgressBar", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "forgot_password", + "Hint": null, + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + } + ], + "PackageId": "com.servicenet.mobile", + "WebDomain": null +} \ No newline at end of file diff --git a/src/Kp2aAutofillParserTest/com-servicenet-mobile-no-focus.json b/src/Kp2aAutofillParserTest/com-servicenet-mobile-no-focus.json new file mode 100644 index 00000000..50d7fb20 --- /dev/null +++ b/src/Kp2aAutofillParserTest/com-servicenet-mobile-no-focus.json @@ -0,0 +1,119 @@ +{ + "InputFields": [ + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": true, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "action_bar_root", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "action_mode_bar_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "content", + "Hint": null, + "ClassName": "android.view.ViewGroup", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "username_text_input_layout", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "username", + "Hint": "Username", + "ClassName": "android.widget.EditText", + "AutofillHints": null, + "IsFocused": false, + "InputType": 97, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "password_text_input_layout", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "password", + "Hint": "Password", + "ClassName": "android.widget.EditText", + "AutofillHints": [ + "passwordAuto" + ], + "IsFocused": false, + "InputType": 129, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null, + + }, + { + "IdEntry": "login_button", + "Hint": null, + "ClassName": "android.widget.Button", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "progressBar", + "Hint": null, + "ClassName": "android.widget.ProgressBar", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "forgot_password", + "Hint": null, + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + } + ], + "PackageId": "com.servicenet.mobile", + "WebDomain": null +} \ No newline at end of file diff --git a/src/Kp2aAutofillParserTest/firefox-amazon-it.json b/src/Kp2aAutofillParserTest/firefox-amazon-it.json new file mode 100644 index 00000000..149526ff --- /dev/null +++ b/src/Kp2aAutofillParserTest/firefox-amazon-it.json @@ -0,0 +1,469 @@ +{ + "InputFields": [ + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "action_bar_root", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "action_mode_bar_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "rootContainer", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "navigationToolbarStub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "container", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "container", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "gestureLayout", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "browserWindow", + "Hint": null, + "ClassName": "android.view.ViewGroup", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "browserLayout", + "Hint": null, + "ClassName": "android.view.ViewGroup", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "swipeRefresh", + "Hint": null, + "ClassName": "android.view.ViewGroup", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "engineView", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.view.ViewGroup", + "AutofillHints": null, + "IsFocused": true, + "InputType": 0, + "HtmlInfoTag": "", + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.view.ViewGroup", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": "form", + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.EditText", + "AutofillHints": [ + "password" + ], + "IsFocused": false, + "InputType": 225, + "HtmlInfoTag": "input", + "HtmlInfoTypeAttribute": "password", + "ExpectedAssignedHints": [ "password" ] + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.EditText", + "AutofillHints": [ + "emailAddress" + ], + "IsFocused": false, + "InputType": 33, + "HtmlInfoTag": "input", + "HtmlInfoTypeAttribute": "email", + "ExpectedAssignedHints": [ "emailAddress" ] + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.EditText", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": "input", + "HtmlInfoTypeAttribute": "checkbox" + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.EditText", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": "input", + "HtmlInfoTypeAttribute": "submit" + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.view.ViewGroup", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": "form", + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.EditText", + "AutofillHints": [ + "password" + ], + "IsFocused": false, + "InputType": 225, + "HtmlInfoTag": "input", + "HtmlInfoTypeAttribute": "password", + "ExpectedAssignedHints": [ "password" ] + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.EditText", + "AutofillHints": [ + "emailAddress" + ], + "IsFocused": false, + "InputType": 33, + "HtmlInfoTag": "input", + "HtmlInfoTypeAttribute": "email", + + "ExpectedAssignedHints": [ "emailAddress" ] + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.EditText", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": "input", + "HtmlInfoTypeAttribute": "submit" + }, + { + "IdEntry": "stubFindInPage", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "viewDynamicDownloadDialog", + "Hint": null, + "ClassName": "android.view.ViewGroup", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "crash_reporter_view", + "Hint": null, + "ClassName": "android.view.ViewGroup", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "toolbar", + "Hint": null, + "ClassName": "android.view.ViewGroup", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "mozac_browser_toolbar_navigation_actions", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "mozac_browser_toolbar_origin_view", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "mozac_browser_toolbar_title_view", + "Hint": null, + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "mozac_browser_toolbar_url_view", + "Hint": "Suche oder Adresse", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "mozac_browser_toolbar_page_actions", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "mozac_browser_toolbar_browser_actions", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "counter_root", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "counter_text", + "Hint": null, + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "mozac_browser_toolbar_menu", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "mozac_browser_toolbar_progress", + "Hint": null, + "ClassName": "android.widget.ProgressBar", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "mozac_browser_toolbar_container", + "Hint": null, + "ClassName": "android.view.ViewGroup", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "mozac_browser_toolbar_edit_actions_start", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "mozac_browser_toolbar_edit_url_view", + "Hint": null, + "ClassName": "android.widget.EditText", + "AutofillHints": null, + "IsFocused": false, + "InputType": 17, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "mozac_browser_toolbar_edit_actions_end", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "readerViewControlsBar", + "Hint": null, + "ClassName": "android.view.ViewGroup", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "addressSelectBar", + "Hint": null, + "ClassName": "android.view.ViewGroup", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "creditCardSelectBar", + "Hint": null, + "ClassName": "android.view.ViewGroup", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "loginSelectBar", + "Hint": null, + "ClassName": "android.view.ViewGroup", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "tabPreview", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + } + ], + "PackageId": "org.mozilla.firefox", + "WebDomain": "www.amazon.it" +} \ No newline at end of file diff --git a/src/keepass2android/services/AutofillBase/AutofillFieldMetadata.cs b/src/keepass2android/services/AutofillBase/AutofillFieldMetadata.cs index 28c19adc..a448e32b 100644 --- a/src/keepass2android/services/AutofillBase/AutofillFieldMetadata.cs +++ b/src/keepass2android/services/AutofillBase/AutofillFieldMetadata.cs @@ -5,6 +5,7 @@ using Android.App.Assist; using Android.Service.Autofill; using Android.Views; using Android.Views.Autofill; +using Kp2aAutofillParser; namespace keepass2android.services.AutofillBase { @@ -40,7 +41,6 @@ namespace keepass2android.services.AutofillBase var supportedHints = AutofillHintsHelper.FilterForSupportedHints(autofillHints); var canonicalHints = AutofillHintsHelper.ConvertToCanonicalHints(supportedHints); SetHints(canonicalHints.ToArray()); - } void SetHints(string[] value) diff --git a/src/keepass2android/services/AutofillBase/AutofillServiceBase.cs b/src/keepass2android/services/AutofillBase/AutofillServiceBase.cs index 874725bd..ccdb86d8 100644 --- a/src/keepass2android/services/AutofillBase/AutofillServiceBase.cs +++ b/src/keepass2android/services/AutofillBase/AutofillServiceBase.cs @@ -20,6 +20,7 @@ using AndroidX.AutoFill.Inline; using AndroidX.AutoFill.Inline.V1; using Java.Util.Concurrent.Atomic; using keepass2android.services.AutofillBase.model; +using Kp2aAutofillParser; namespace keepass2android.services.AutofillBase { @@ -255,7 +256,7 @@ namespace keepass2android.services.AutofillBase if (warning == DisplayWarning.None) { - FilledAutofillFieldCollection partitionData = + FilledAutofillFieldCollection partitionData = AutofillHintsHelper.FilterForPartition(filledAutofillFieldCollection, parser.AutofillFields.FocusedAutofillCanonicalHints); Kp2aLog.Log("AF: Add dataset"); @@ -299,7 +300,7 @@ namespace keepass2android.services.AutofillBase } - protected abstract List GetSuggestedEntries(string query); + protected abstract List> GetSuggestedEntries(string query); public enum DisplayWarning { diff --git a/src/keepass2android/services/AutofillBase/ChooseForAutofillActivityBase.cs b/src/keepass2android/services/AutofillBase/ChooseForAutofillActivityBase.cs index 73ba4b31..7319f80d 100644 --- a/src/keepass2android/services/AutofillBase/ChooseForAutofillActivityBase.cs +++ b/src/keepass2android/services/AutofillBase/ChooseForAutofillActivityBase.cs @@ -12,6 +12,7 @@ using Java.Util; using keepass2android.services.AutofillBase.model; using System.Linq; using Android.Content.PM; +using Kp2aAutofillParser; #if !NoNet using Com.Dropbox.Core.V2.Teamlog; #endif @@ -173,7 +174,7 @@ namespace keepass2android.services.AutofillBase ReplyIntent = null; } - protected void OnSuccess(FilledAutofillFieldCollection clientFormDataMap, bool isManual) + protected void OnSuccess(FilledAutofillFieldCollection clientFormDataMap, bool isManual) { var intent = Intent; AssistStructure structure = (AssistStructure)intent.GetParcelableExtra(AutofillManager.ExtraAssistStructure); @@ -229,7 +230,7 @@ namespace keepass2android.services.AutofillBase /// /// Creates the FilledAutofillFieldCollection from the intent returned from the query activity /// - protected abstract FilledAutofillFieldCollection GetDataset(); + protected abstract FilledAutofillFieldCollection GetDataset(); public abstract IAutofillIntentBuilder IntentBuilder { get; } diff --git a/src/keepass2android/services/AutofillBase/Kp2aDigitalAssetLinksDataSource.cs b/src/keepass2android/services/AutofillBase/Kp2aDigitalAssetLinksDataSource.cs index 31c01157..14fa2367 100644 --- a/src/keepass2android/services/AutofillBase/Kp2aDigitalAssetLinksDataSource.cs +++ b/src/keepass2android/services/AutofillBase/Kp2aDigitalAssetLinksDataSource.cs @@ -39,6 +39,11 @@ namespace keepass2android.services.AutofillBase return trustedLinks.Contains(BuildLink(domain, targetPackage)); } + public bool IsEnabled() + { + return !PreferenceManager.GetDefaultSharedPreferences(_ctx).GetBoolean(_ctx.GetString(Resource.String.NoDalVerification_key), false); + } + public void RememberAsTrustedApp(string packageName) { var prefs = PreferenceManager.GetDefaultSharedPreferences(_ctx); diff --git a/src/keepass2android/services/AutofillBase/StructureParser.cs b/src/keepass2android/services/AutofillBase/StructureParser.cs index 820e9241..932d95ac 100644 --- a/src/keepass2android/services/AutofillBase/StructureParser.cs +++ b/src/keepass2android/services/AutofillBase/StructureParser.cs @@ -1,22 +1,12 @@ using System; -using System.Collections.Generic; using System.Linq; + using Android.App.Assist; using Android.Content; -using Android.Preferences; -using Android.Text; -using Android.Util; -using Android.Views; using Android.Views.Autofill; -using Android.Views.InputMethods; using DomainNameParser; -using keepass2android.services.AutofillBase.model; using Kp2aAutofillParser; using Newtonsoft.Json; -using static Android.App.Assist.AssistStructure; -using static Java.IO.ObjectOutputStream; -using FilledAutofillFieldCollection = keepass2android.services.AutofillBase.model.FilledAutofillFieldCollection; -using InputTypes = Kp2aAutofillParser.InputTypes; namespace keepass2android.services.AutofillBase { @@ -38,7 +28,7 @@ namespace keepass2android.services.AutofillBase [JsonIgnore] public AssistStructure.ViewNode ViewNode { get; set; } - public override void FillFilledAutofillValue(FilledAutofillField filledField) + public void FillFilledAutofillValue(FilledAutofillField filledField) { AutofillValue autofillValue = ViewNode.AutofillValue; if (autofillValue != null) @@ -130,7 +120,6 @@ namespace keepass2android.services.AutofillBase } autofillView.InputFields.Add(new ViewNodeInputField(viewNode)); - Kp2aLog.Log($"Now we have {autofillView.InputFields.Count} fields, just added {autofillView.InputFields.Last().IdEntry} of type {autofillView.InputFields.Last().ClassName}"); var childrenSize = viewNode.ChildCount; if (childrenSize > 0) @@ -148,290 +137,63 @@ namespace keepass2android.services.AutofillBase /// AssistStructure from the client Activity, representing its View hierarchy. In this sample, it /// parses the hierarchy and collects autofill metadata from {@link ViewNode}s along the way. /// - public sealed class StructureParser + public sealed class StructureParser: StructureParserBase { - public Context mContext { get; } + private readonly AssistStructure _structure; + public Context _context { get; } public AutofillFieldMetadataCollection AutofillFields { get; set; } - public FilledAutofillFieldCollection ClientFormData { get; set; } + public FilledAutofillFieldCollection ClientFormData { get; set; } public string PackageId { get; set; } public StructureParser(Context context, AssistStructure structure) + : base(new Kp2aLogger(), new Kp2aDigitalAssetLinksDataSource(context)) { - kp2aDigitalAssetLinksDataSource = new Kp2aDigitalAssetLinksDataSource(context); - mContext = context; - Structure = structure; - AutofillFields = new AutofillFieldMetadataCollection(); - - } - - public class AutofillTargetId - { - public string PackageName { get; set; } - - public string PackageNameWithPseudoSchema - { - get { return KeePass.AndroidAppScheme + PackageName; } - } - - 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; - } - } + _context = context; + _structure = structure; + AutofillFields = new AutofillFieldMetadataCollection(); + } - public AutofillTargetId ParseForFill(bool isManual) - { - return Parse(true, isManual); - } - - public AutofillTargetId ParseForSave() - { - return Parse(false, true); - } - - /// - /// Traverse AssistStructure and add ViewNode metadata to a flat list. - /// - /// The parse. - /// If set to true for fill. - /// - AutofillTargetId Parse(bool forFill, bool isManualRequest) + protected override AutofillTargetId Parse(bool forFill, bool isManualRequest, AutofillView autofillView) { - AutofillTargetId result = new AutofillTargetId(); - CommonUtil.logd("Parsing structure for " + Structure.ActivityComponent); - - ClientFormData = new FilledAutofillFieldCollection(); - - _editTextsWithoutHint.Clear(); + var result = base.Parse(forFill, isManualRequest, autofillView); - Kp2aLog.Log("parsing autofillStructure..."); - - AutofillView autofillView = new AutofillViewFromAssistStructureFinder(mContext, Structure).GetAutofillView(isManualRequest); - - //TODO remove from production - Kp2aLog.Log("will log the autofillStructure..."); - string debugInfo = JsonConvert.SerializeObject(autofillView, Formatting.Indented); - Kp2aLog.Log("will log the autofillStructure... size is " + debugInfo.Length); - Kp2aLog.Log("This is the autofillStructure: \n\n " + debugInfo); - - foreach (var viewNode in autofillView.InputFields) + if (forFill) { - string[] viewHints = viewNode.AutofillHints; - if (viewHints != null && viewHints.Length == 1 && viewHints.First() == "off" && viewNode.IsFocused && - isManualRequest) - viewHints[0] = "on"; - /*if (viewHints != null && viewHints.Any()) - { - CommonUtil.logd("viewHints=" + viewHints); - CommonUtil.logd("class=" + viewNode.ClassName); - CommonUtil.logd("tag=" + (viewNode?.HtmlInfo?.Tag ?? "(null)")); - }*/ - - if (IsPassword(viewNode) || HasPasswordHint(viewNode) || (HasUsernameHint(viewNode))) - { - if (forFill) - { - AutofillFields.Add(new AutofillFieldMetadata(viewNode.ViewNode)); - } - else - { - FilledAutofillField filledAutofillField = new FilledAutofillField(viewNode.ViewNode); - ClientFormData.Add(filledAutofillField); - } - } - else if (viewNode.ClassName == "android.widget.EditText" - || viewNode.ClassName == "android.widget.AutoCompleteTextView" - || viewNode.HtmlInfoTag == "input" - || ((viewHints?.Length ?? 0) > 0)) - { - Kp2aLog.Log("Found something that looks fillable " + viewNode.ClassName); - - } - - if (viewHints != null && viewHints.Length > 0 && viewHints.First() != "on" /*if hint is "on", treat as if there is no hint*/) - { - } - else - { - - if (viewNode.ClassName == "android.widget.EditText" - || viewNode.ClassName == "android.widget.AutoCompleteTextView" - || viewNode.HtmlInfoTag == "input") - { - _editTextsWithoutHint.Add(viewNode); - } - - } - } - - List passwordFields = new List(); - List usernameFields = new List(); - if (AutofillFields.Empty) - { - passwordFields = _editTextsWithoutHint.Where(IsPassword).ToList(); - if (!passwordFields.Any()) - { - passwordFields = _editTextsWithoutHint.Where(HasPasswordHint).ToList(); - } - - usernameFields = _editTextsWithoutHint.Where(HasUsernameHint).ToList(); - - if (usernameFields.Any() == false) - { - - foreach (var passwordField in passwordFields) - { - var usernameField = _editTextsWithoutHint - .TakeWhile(f => f != passwordField).LastOrDefault(); - if (usernameField != null) - { - usernameFields.Add(usernameField); - } - } - } - if (usernameFields.Any() == false) - { - //for some pages with two-step login, we don't see a password field and don't display the autofill for non-manual requests. But if the user forces autofill, - //let's assume it is a username field: - if (isManualRequest && !passwordFields.Any() && _editTextsWithoutHint.Count == 1) - { - usernameFields.Add(_editTextsWithoutHint.First()); - } - } - - - } - - //force focused fields to be included in autofill fields when request was triggered manually. This allows to fill fields which are "off" or don't have a hint (in case there are hints) - if (isManualRequest) - { - foreach (var editText in _editTextsWithoutHint) - { - if (editText.IsFocused) - { - if (IsPassword(editText) || HasPasswordHint(editText)) - passwordFields.Add(editText); - else - usernameFields.Add(editText); - break; - } - - } - } - - if (forFill) - { - foreach (var uf in usernameFields) - AutofillFields.Add(new AutofillFieldMetadata(uf.ViewNode, new[] { View.AutofillHintUsername })); - foreach (var pf in passwordFields) - AutofillFields.Add(new AutofillFieldMetadata(pf.ViewNode, new[] { View.AutofillHintPassword })); - + foreach (var p in FieldsMappedToHints) + AutofillFields.Add(new AutofillFieldMetadata(p.Key.ViewNode, p.Value)); } - else - { - foreach (var uf in usernameFields) - ClientFormData.Add(new FilledAutofillField(uf.ViewNode, new[] { View.AutofillHintUsername })); - foreach (var pf in passwordFields) - ClientFormData.Add(new FilledAutofillField(pf.ViewNode, new[] { View.AutofillHintPassword })); - } - - - result.WebDomain = autofillView.WebDomain; - result.PackageName = Structure.ActivityComponent.PackageName; - if (!string.IsNullOrEmpty(autofillView.WebDomain) && !PreferenceManager.GetDefaultSharedPreferences(mContext).GetBoolean(mContext.GetString(Resource.String.NoDalVerification_key), false)) - { - result.IncompatiblePackageAndDomain = !kp2aDigitalAssetLinksDataSource.IsTrustedLink(autofillView.WebDomain, result.PackageName); - if (result.IncompatiblePackageAndDomain) - { - CommonUtil.loge($"DAL verification failed for {result.PackageName}/{result.WebDomain}"); - } - } else { - result.IncompatiblePackageAndDomain = false; + foreach (var p in FieldsMappedToHints) + ClientFormData.Add(new FilledAutofillField(p.Key, p.Value)); } - return result; - } - private static readonly HashSet _passwordHints = new HashSet { "password","passwort", "passwordAuto", "pswd" }; - private static bool HasPasswordHint(InputField f) - { - return ContainsAny(f.IdEntry, _passwordHints) || - ContainsAny(f.Hint, _passwordHints); - } - - private static readonly HashSet _usernameHints = new HashSet { "email","e-mail","username" }; - private readonly Kp2aDigitalAssetLinksDataSource kp2aDigitalAssetLinksDataSource; - - private static bool HasUsernameHint(InputField f) - { - return ContainsAny(f.IdEntry, _usernameHints) || - ContainsAny(f.Hint, _usernameHints); - } - - private static bool ContainsAny(string value, IEnumerable terms) - { - if (string.IsNullOrWhiteSpace(value)) - { - return false; - } - var lowerValue = value.ToLowerInvariant(); - return terms.Any(t => lowerValue.Contains(t)); - } - - private static bool IsInputTypeClass(InputTypes inputType, InputTypes inputTypeClass) - { - if (!InputTypes.MaskClass.HasFlag(inputTypeClass)) - throw new Exception("invalid inputTypeClas"); - 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"); - bool result = (((int)inputType) & (int)InputTypes.MaskVariation) == (int)(inputTypeVariation); - if (result) - Kp2aLog.Log("found " + ((int)inputTypeVariation).ToString("X") + " in " + ((int)inputType).ToString("X")); - return result; - } - 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.HtmlInfoTypeAttribute == "password") - ); - } + return result; + } - AssistStructure Structure; - private List _editTextsWithoutHint = new List(); - + public AutofillTargetId ParseForSave() + { + var autofillView = new AutofillViewFromAssistStructureFinder(_context, _structure).GetAutofillView(true); + return Parse(false, true, autofillView); + } + + public StructureParserBase.AutofillTargetId ParseForFill(bool isManual) + { + var autofillView = new AutofillViewFromAssistStructureFinder(_context, _structure).GetAutofillView(isManual); + return Parse(true, isManual, autofillView); + } - } + } + + public class Kp2aLogger : ILogger + { + public void Log(string x) + { + Kp2aLog.Log(x); + } + } } diff --git a/src/keepass2android/services/Kp2aAutofill/ChooseForAutofillActivity.cs b/src/keepass2android/services/Kp2aAutofill/ChooseForAutofillActivity.cs index bd2f9b3c..9c4fbb21 100644 --- a/src/keepass2android/services/Kp2aAutofill/ChooseForAutofillActivity.cs +++ b/src/keepass2android/services/Kp2aAutofill/ChooseForAutofillActivity.cs @@ -15,6 +15,7 @@ using keepass2android.services.AutofillBase.model; using Keepass2android.Pluginsdk; using KeePassLib; using KeePassLib.Utility; +using Kp2aAutofillParser; namespace keepass2android.services.Kp2aAutofill { @@ -41,7 +42,7 @@ namespace keepass2android.services.Kp2aAutofill protected override Result ExpectedActivityResult => KeePass.ExitCloseAfterTaskComplete; - protected override FilledAutofillFieldCollection GetDataset() + protected override FilledAutofillFieldCollection GetDataset() { if (App.Kp2a.CurrentDb==null || (App.Kp2a.QuickLocked)) return null; @@ -50,18 +51,18 @@ namespace keepass2android.services.Kp2aAutofill return GetFilledAutofillFieldCollectionFromEntry(entryOutput, this); } - public static FilledAutofillFieldCollection GetFilledAutofillFieldCollectionFromEntry(PwEntryOutput pwEntryOutput, Context context) + public static FilledAutofillFieldCollection GetFilledAutofillFieldCollectionFromEntry(PwEntryOutput pwEntryOutput, Context context) { if (pwEntryOutput == null) return null; - FilledAutofillFieldCollection fieldCollection = new FilledAutofillFieldCollection(); + FilledAutofillFieldCollection fieldCollection = new FilledAutofillFieldCollection(); var pwEntry = pwEntryOutput.Entry; foreach (string key in pwEntryOutput.OutputStrings.GetKeys()) { - FilledAutofillField field = - new FilledAutofillField + FilledAutofillField field = + new FilledAutofillField { AutofillHints = GetCanonicalHintsFromKp2aField(key).ToArray(), TextValue = pwEntryOutput.OutputStrings.ReadSafe(key) @@ -72,8 +73,8 @@ namespace keepass2android.services.Kp2aAutofill if (IsCreditCard(pwEntry, context) && pwEntry.Expires) { DateTime expTime = pwEntry.ExpiryTime; - FilledAutofillField field = - new FilledAutofillField + FilledAutofillField field = + new FilledAutofillField { AutofillHints = new[] {View.AutofillHintCreditCardExpirationDate}, DateValue = (long) (1000 * TimeUtil.SerializeUnix(expTime)) @@ -81,7 +82,7 @@ namespace keepass2android.services.Kp2aAutofill fieldCollection.Add(field); field = - new FilledAutofillField + new FilledAutofillField { AutofillHints = new[] {View.AutofillHintCreditCardExpirationDay}, TextValue = expTime.Day.ToString() @@ -89,7 +90,7 @@ namespace keepass2android.services.Kp2aAutofill fieldCollection.Add(field); field = - new FilledAutofillField + new FilledAutofillField { AutofillHints = new[] {View.AutofillHintCreditCardExpirationMonth}, TextValue = expTime.Month.ToString() @@ -97,7 +98,7 @@ namespace keepass2android.services.Kp2aAutofill fieldCollection.Add(field); field = - new FilledAutofillField + new FilledAutofillField { AutofillHints = new[] {View.AutofillHintCreditCardExpirationYear}, TextValue = expTime.Year.ToString() diff --git a/src/keepass2android/services/Kp2aAutofill/Kp2aAutofillService.cs b/src/keepass2android/services/Kp2aAutofill/Kp2aAutofillService.cs index 4098003a..e4fe1e54 100644 --- a/src/keepass2android/services/Kp2aAutofill/Kp2aAutofillService.cs +++ b/src/keepass2android/services/Kp2aAutofill/Kp2aAutofillService.cs @@ -12,6 +12,7 @@ using Keepass2android.Pluginsdk; using KeePassLib; using KeePassLib.Collections; using KeePassLib.Utility; +using Kp2aAutofillParser; using Org.Json; using AutofillServiceBase = keepass2android.services.AutofillBase.AutofillServiceBase; @@ -33,10 +34,10 @@ namespace keepass2android.services { } - protected override List GetSuggestedEntries(string query) + protected override List> GetSuggestedEntries(string query) { if (!App.Kp2a.DatabaseIsUnlocked) - return new List(); + return new List>(); var foundEntries = (ShareUrlResults.GetSearchResultsForUrl(query)?.Entries ?? new PwObjectList()) .Select(e => new PwEntryOutput(e, App.Kp2a.FindDatabaseForElement(e))) .ToList(); diff --git a/src/keepass2android/services/Kp2aAutofillParser/AutofillParser.cs b/src/keepass2android/services/Kp2aAutofillParser/AutofillParser.cs new file mode 100644 index 00000000..2824d35b --- /dev/null +++ b/src/keepass2android/services/Kp2aAutofillParser/AutofillParser.cs @@ -0,0 +1,956 @@ +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 new file mode 100644 index 00000000..375762cd --- /dev/null +++ b/src/keepass2android/services/Kp2aAutofillParser/Kp2aAutofillParser.csproj @@ -0,0 +1,12 @@ + + + + netstandard2.1 + enable + + + + + + + From 595a451f77bb38c3855a5478d01393946a217d3a Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Tue, 28 Feb 2023 22:37:32 +0100 Subject: [PATCH 036/101] fix failing test --- src/Kp2aAutofillParserTest/AutofillTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kp2aAutofillParserTest/AutofillTest.cs b/src/Kp2aAutofillParserTest/AutofillTest.cs index fe4a44de..5141dcb0 100644 --- a/src/Kp2aAutofillParserTest/AutofillTest.cs +++ b/src/Kp2aAutofillParserTest/AutofillTest.cs @@ -75,7 +75,7 @@ namespace Kp2aAutofillParserTest actualHints = new string[0]; if (actualHints.Any() || expectedHints.Any()) { - _testOutputHelper.WriteLine($"field = {field.IdEntry} {field.Hint} {string.Join(",", field.AutofillHints)}"); + _testOutputHelper.WriteLine($"field = {field.IdEntry} {field.Hint} {string.Join(",", field.AutofillHints ?? new string[]{})}"); _testOutputHelper.WriteLine("actual Hints = " + string.Join(", ", actualHints)); _testOutputHelper.WriteLine("expected Hints = " + string.Join(", ", expectedHints)); } From 85315d0ecc36fed8c0ff81d16e2a388e933adf01 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Tue, 28 Feb 2023 22:42:04 +0100 Subject: [PATCH 037/101] run unit tests in github action --- .github/workflows/build.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f8f4cb64..da6fb704 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -330,6 +330,10 @@ jobs: - name: Build keepass2android (nonet) run: | make msbuild Flavor=NoNet + + - name: Test Autofill + working-directory: ./src/Kp2aAutofillParserTest + run: dotnet test - name: Build APK (nonet) run: | From 48a6d0a2adc16a07323165ddbbd8dd7835f60b86 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Mon, 6 Mar 2023 07:58:52 +0100 Subject: [PATCH 038/101] disable macos build action --- .github/workflows/build.yml | 162 ++++++++++++++++++------------------ 1 file changed, 82 insertions(+), 80 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index da6fb704..7450d0e7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,109 +3,111 @@ name: Build keepass2android app on: [push, pull_request] jobs: - macos: + # macos: + # Disabled. Does not work, maybe due to nuget version, see https://github.com/PhilippC/keepass2android/actions/runs/4297640426/jobs/7490853348 + # should work again when the Project solution is converted to sdk style .csproj files. - runs-on: macos-12 + # runs-on: macos-12 - steps: - - uses: actions/checkout@v3 + # steps: + # - uses: actions/checkout@v3 - - name: Fetch submodules - run: git submodule init && git submodule update + # - name: Fetch submodules + # run: git submodule init && git submodule update - - name: Setup Gradle - uses: gradle/gradle-build-action@v2 + # - name: Setup Gradle + # uses: gradle/gradle-build-action@v2 - - name: Cache NuGet packages - uses: actions/cache@v3 - with: - path: ~/.nuget/packages - key: ${{ runner.os }}-nuget-${{ hashFiles('src/**/*.csproj', 'src/**/packages.config') }} - restore-keys: | - ${{ runner.os }}-nuget- + # - name: Cache NuGet packages + # uses: actions/cache@v3 + # with: + # path: ~/.nuget/packages + # key: ${{ runner.os }}-nuget-${{ hashFiles('src/**/*.csproj', 'src/**/packages.config') }} + # restore-keys: | + # ${{ runner.os }}-nuget- - # As per https://github.com/actions/runner-images/blob/main/images/macos/macos-12-Readme.md#visual-studio-for-mac - - name: Switch to Visual Studio 2019 - if: ${{ false }} # Not needed. We stay with the default 'Visual Studio 2022' of macos-12 runner. - run: | - mv "/Applications/Visual Studio.app" "/Applications/Visual Studio 2022.app" - mv "/Applications/Visual Studio 2019.app" "/Applications/Visual Studio.app" + # # As per https://github.com/actions/runner-images/blob/main/images/macos/macos-12-Readme.md#visual-studio-for-mac + # - name: Switch to Visual Studio 2019 + # if: ${{ false }} # Not needed. We stay with the default 'Visual Studio 2022' of macos-12 runner. + # run: | + # mv "/Applications/Visual Studio.app" "/Applications/Visual Studio 2022.app" + # mv "/Applications/Visual Studio 2019.app" "/Applications/Visual Studio.app" - # As of 2022-12-02, keepass2android doesn't build with Xamarin >= 12.1 because there is some issue with SamsungPass. Removing SamsungPass would make the build succeed. - - name: Set default Xamarin SDK versions - run: | - # If using the github runner 'macos-12' - #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=11.3 - #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=12.0 - #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=12.1 # Build fails in this case, as of 2022-12-02 : Xamarin/Android/Xamarin.Android.D8.targets(79,5): error : java.lang.ArrayIndexOutOfBoundsException : Index 4 out of bounds for length 4 - #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=12.2 # Build fails in this case, as of 2022-12-02 : Xamarin/Android/Xamarin.Android.D8.targets(79,5): error : java.lang.ArrayIndexOutOfBoundsException : Index 4 out of bounds for length 4 - #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=12.3 # Build fails in this case, as of 2022-12-02 - $VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=13.1 + # # As of 2022-12-02, keepass2android doesn't build with Xamarin >= 12.1 because there is some issue with SamsungPass. Removing SamsungPass would make the build succeed. + # - name: Set default Xamarin SDK versions + # run: | + # # If using the github runner 'macos-12' + # #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=11.3 + # #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=12.0 + # #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=12.1 # Build fails in this case, as of 2022-12-02 : Xamarin/Android/Xamarin.Android.D8.targets(79,5): error : java.lang.ArrayIndexOutOfBoundsException : Index 4 out of bounds for length 4 + # #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=12.2 # Build fails in this case, as of 2022-12-02 : Xamarin/Android/Xamarin.Android.D8.targets(79,5): error : java.lang.ArrayIndexOutOfBoundsException : Index 4 out of bounds for length 4 + # #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=12.3 # Build fails in this case, as of 2022-12-02 + # $VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=13.1 - # If using the github runner 'macos-11' - #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=11.0 - #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=12.0 + # # If using the github runner 'macos-11' + # #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=11.0 + # #$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=12.0 - # If using the github runner 'macos-10.15' - # $VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=11.2 + # # If using the github runner 'macos-10.15' + # # $VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=11.2 - - name: Switch to JDK-11 - uses: actions/setup-java@v3 - with: - java-version: '11' - distribution: 'temurin' + # - name: Switch to JDK-11 + # uses: actions/setup-java@v3 + # with: + # java-version: '11' + # distribution: 'temurin' - - name: Display java version - run: java -version + # - name: Display java version + # run: java -version - # Some components of Keepass2Android currently target android API 26 which are not available on the runner - - name: Download android-26 API - run: $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager --install "platforms;android-26" + # # Some components of Keepass2Android currently target android API 26 which are not available on the runner + # - name: Download android-26 API + # run: $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager --install "platforms;android-26" - - name: Build native dependencies - run: make native + # - name: Build native dependencies + # run: make native - - name: Build java dependencies - run: make java + # - name: Build java dependencies + # run: make java - - name: Install NuGet dependencies (net) - run: make nuget Flavor=Net + # - name: Install NuGet dependencies (net) + # run: make nuget Flavor=Net - - name: Build keepass2android (net) - run: | - make msbuild Flavor=Net + # - name: Build keepass2android (net) + # run: | + # make msbuild Flavor=Net - - name: Build APK (net) - run: | - make apk Flavor=Net + # - name: Build APK (net) + # run: | + # make apk Flavor=Net - - name: Archive production artifacts (net) - uses: actions/upload-artifact@v3 - with: - name: signed APK ('net' built on ${{ github.job }}) - path: | - src/keepass2android/bin/*/*-Signed.apk + # - name: Archive production artifacts (net) + # uses: actions/upload-artifact@v3 + # with: + # name: signed APK ('net' built on ${{ github.job }}) + # path: | + # src/keepass2android/bin/*/*-Signed.apk - - name: Install NuGet dependencies (nonet) - run: make nuget Flavor=NoNet + # - name: Install NuGet dependencies (nonet) + # run: make nuget Flavor=NoNet - - name: Build keepass2android (nonet) - run: | - make msbuild Flavor=NoNet + # - name: Build keepass2android (nonet) + # run: | + # make msbuild Flavor=NoNet - - name: Build APK (nonet) - run: | - make apk Flavor=NoNet + # - name: Build APK (nonet) + # run: | + # make apk Flavor=NoNet - - name: Archive production artifacts (nonet) - uses: actions/upload-artifact@v3 - with: - name: signed APK ('nonet' built on ${{ github.job }}) - path: | - src/keepass2android/bin/*/*-Signed.apk + # - name: Archive production artifacts (nonet) + # uses: actions/upload-artifact@v3 + # with: + # name: signed APK ('nonet' built on ${{ github.job }}) + # path: | + # src/keepass2android/bin/*/*-Signed.apk - - name: Perform "make distclean" - run: make distclean + # - name: Perform "make distclean" + # run: make distclean # linux: # disabled. From 4949fede3296ee4026d9752be1f421b9d7535b19 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Mon, 6 Mar 2023 08:05:57 +0100 Subject: [PATCH 039/101] remove tab in yml file --- .github/workflows/build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7450d0e7..bafa83ef 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -332,7 +332,6 @@ jobs: - name: Build keepass2android (nonet) run: | make msbuild Flavor=NoNet - - name: Test Autofill working-directory: ./src/Kp2aAutofillParserTest run: dotnet test From 7de28c5aba8294b43c5acd3a9e733fd2963d9d09 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Mon, 6 Mar 2023 10:26:33 +0100 Subject: [PATCH 040/101] add preference to control if autofill view details are written to log --- src/keepass2android/Resources/values/config.xml | 1 + src/keepass2android/Resources/values/strings.xml | 3 +++ src/keepass2android/Resources/xml/preferences.xml | 9 +++++++++ .../services/AutofillBase/StructureParser.cs | 6 ++++-- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/keepass2android/Resources/values/config.xml b/src/keepass2android/Resources/values/config.xml index 071e9645..b6bc4902 100644 --- a/src/keepass2android/Resources/values/config.xml +++ b/src/keepass2android/Resources/values/config.xml @@ -54,6 +54,7 @@ AlwaysMergeOnConflict NoDalVerification_key InlineSuggestions_key + LogAutofillView_key algorithm app app_timeout_key diff --git a/src/keepass2android/Resources/values/strings.xml b/src/keepass2android/Resources/values/strings.xml index 4a89f257..fa615243 100644 --- a/src/keepass2android/Resources/values/strings.xml +++ b/src/keepass2android/Resources/values/strings.xml @@ -332,6 +332,9 @@ Integrate with keyboard Shows the autofill suggestions as inline options in the keyboard (if supported by the input method) + + Log autofill view + Write details about the autofill view to debug log (if debug logging is enabled). These details can be sent to the developer if autofill does not work as expected. Requires Android 11 or later Find password diff --git a/src/keepass2android/Resources/xml/preferences.xml b/src/keepass2android/Resources/xml/preferences.xml index c159d477..3b18fd70 100644 --- a/src/keepass2android/Resources/xml/preferences.xml +++ b/src/keepass2android/Resources/xml/preferences.xml @@ -454,6 +454,15 @@ android:title="@string/InlineSuggestions_title" android:key="@string/InlineSuggestions_key" /> + + + p.First?.ToString() == "type")?.Second?.ToString(); - } + [JsonIgnore] public AssistStructure.ViewNode ViewNode { get; set; } @@ -152,7 +153,8 @@ namespace keepass2android.services.AutofillBase _context = context; _structure = structure; AutofillFields = new AutofillFieldMetadataCollection(); - + LogAutofillView = PreferenceManager.GetDefaultSharedPreferences(context).GetBoolean(context.GetString(Resource.String.LogAutofillView_key), false); + } protected override AutofillTargetId Parse(bool forFill, bool isManualRequest, AutofillView autofillView) From db6b266a594c92208f7899200b5a21343a7a6c09 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Mon, 6 Mar 2023 10:26:58 +0100 Subject: [PATCH 041/101] add more autofill tests and change AutofillParser to make them pass --- src/Kp2aAutofillParser/AutofillParser.cs | 52 +- src/Kp2aAutofillParserTest/AutofillTest.cs | 21 + .../Kp2aAutofillParserTest.csproj | 12 + .../chrome-android10-amazon-it.json | 2018 +++++++++++++++++ .../com-expressvpn-vpn-android13.json | 226 ++ .../com-ifs-banking-fiid3364-android13.json | 322 +++ .../AutofillBase/AutofillFieldMetadata.cs | 2 +- 7 files changed, 2633 insertions(+), 20 deletions(-) create mode 100644 src/Kp2aAutofillParserTest/chrome-android10-amazon-it.json create mode 100644 src/Kp2aAutofillParserTest/com-expressvpn-vpn-android13.json create mode 100644 src/Kp2aAutofillParserTest/com-ifs-banking-fiid3364-android13.json diff --git a/src/Kp2aAutofillParser/AutofillParser.cs b/src/Kp2aAutofillParser/AutofillParser.cs index 049aeb0c..d60f56be 100644 --- a/src/Kp2aAutofillParser/AutofillParser.cs +++ b/src/Kp2aAutofillParser/AutofillParser.cs @@ -323,6 +323,7 @@ namespace Kp2aAutofillParser AutofillHintPassword, AutofillHintUsername, W3cHints.HONORIFIC_PREFIX, + W3cHints.EMAIL, W3cHints.NAME, W3cHints.GIVEN_NAME, W3cHints.ADDITIONAL_NAME, @@ -430,20 +431,26 @@ namespace Kp2aAutofillParser /// /// transforms hints by replacing some W3cHints by their Android counterparts and transforming everything to lowercase /// - public static List ConvertToCanonicalHints(string[] supportedHints) + public static List ConvertToCanonicalLowerCaseHints(string[] supportedHints) { List result = new List(); foreach (string hint in supportedHints) { - string canonicalHint; - if (!hintToCanonicalReplacement.TryGetValue(hint, out canonicalHint)) - canonicalHint = hint; + var canonicalHint = ToCanonicalHint(hint); result.Add(canonicalHint.ToLower()); } return result; } + public static string ToCanonicalHint(string hint) + { + string canonicalHint; + if (!hintToCanonicalReplacement.TryGetValue(hint, out canonicalHint)) + canonicalHint = hint; + return canonicalHint; + } + public static int GetPartitionIndex(string hint) { for (int i = 0; i < partitionsOfCanonicalHints.Count; i++) @@ -657,7 +664,7 @@ namespace Kp2aAutofillParser } } - AutofillHints = AutofillHintsHelper.ConvertToCanonicalHints(hintList.ToArray()).ToArray(); + AutofillHints = AutofillHintsHelper.ConvertToCanonicalLowerCaseHints(hintList.ToArray()).ToArray(); } @@ -699,8 +706,8 @@ namespace Kp2aAutofillParser /// public abstract class InputField { - public string IdEntry { get; set; } - public string Hint { get; set; } + 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; } @@ -819,7 +826,7 @@ namespace Kp2aAutofillParser // * 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(); + .SelectMany(f => f.AutofillHints).Select(AutofillHintsHelper.ToCanonicalHint).ToHashSet(); bool hasLoginAutofillHints = autofillHintsOfAllFields.Intersect(_autofillHintsForLogin).Any(); if (hasLoginAutofillHints) @@ -829,9 +836,9 @@ namespace Kp2aAutofillParser string[] viewHints = viewNode.AutofillHints; if (viewHints == null) continue; - if (viewHints.Intersect(_autofillHintsForLogin).Any()) + if (viewHints.Select(AutofillHintsHelper.ToCanonicalHint).Intersect(_autofillHintsForLogin).Any()) { - FieldsMappedToHints.Add(viewNode, viewHints); + FieldsMappedToHints.Add(viewNode, viewHints.Select(AutofillHintsHelper.ToCanonicalHint).ToHashSet().ToArray()); } } @@ -839,6 +846,7 @@ namespace Kp2aAutofillParser else { //determine password fields, first by type, then by hint: + List editTexts = autofillView.InputFields.Where(f => IsEditText(f)).ToList(); List passwordFields = autofillView.InputFields.Where(f => IsEditText(f) && IsPassword(f)).ToList(); if (!passwordFields.Any()) { @@ -851,8 +859,10 @@ namespace Kp2aAutofillParser { foreach (var passwordField in passwordFields) { - var lastInputBeforePassword = autofillView.InputFields - .TakeWhile(f => IsEditText(f) && f != passwordField && !passwordFields.Contains(f)).LastOrDefault(); + + var lastInputBeforePassword = autofillView.InputFields.Where(IsEditText) + .TakeWhile(f => f != passwordField && !passwordFields.Contains(f)).LastOrDefault(); + if (lastInputBeforePassword != null) usernameFields.Add(lastInputBeforePassword); } @@ -864,7 +874,7 @@ namespace Kp2aAutofillParser { foreach (var uf in usernameFields) FieldsMappedToHints.Add(uf, new string[] { AutofillHintsHelper.AutofillHintUsername }); - foreach (var pf in passwordFields) + foreach (var pf in passwordFields.Except(usernameFields)) FieldsMappedToHints.Add(pf, new string[] { AutofillHintsHelper.AutofillHintPassword }); } } @@ -894,23 +904,22 @@ namespace Kp2aAutofillParser || f.HtmlInfoTag == "input"); } - private static readonly HashSet _passwordHints = new HashSet { "password", "passwort" - /*, "passwordAuto", "pswd"*/ }; + 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 readonly HashSet _usernameHints = new HashSet { "email", "e-mail", "username", "user id" }; private static bool HasUsernameHint(InputField f) { - return IsAny(f.IdEntry, _usernameHints) || - IsAny(f.Hint, _usernameHints); + return IsAny(f.IdEntry?.ToLower(), _usernameHints) || + IsAny(f.Hint?.ToLower(), _usernameHints); } - private static bool IsAny(string value, IEnumerable terms) + private static bool IsAny(string? value, IEnumerable terms) { if (string.IsNullOrWhiteSpace(value)) { @@ -935,6 +944,11 @@ namespace Kp2aAutofillParser private static bool IsPassword(InputField f) { + if (f.IdEntry?.Contains("password") == true) + { + f = f; + } + InputTypes inputType = f.InputType; return diff --git a/src/Kp2aAutofillParserTest/AutofillTest.cs b/src/Kp2aAutofillParserTest/AutofillTest.cs index 5141dcb0..3a5587a5 100644 --- a/src/Kp2aAutofillParserTest/AutofillTest.cs +++ b/src/Kp2aAutofillParserTest/AutofillTest.cs @@ -41,6 +41,27 @@ namespace Kp2aAutofillParserTest RunTestFromAutofillInput(resourceName, "org.mozilla.firefox", "www.amazon.it"); } + [Fact] + public void CanDetectFieldsWithoutAutofillHints() + { + var resourceName = "Kp2aAutofillParserTest.chrome-android10-amazon-it.json"; + RunTestFromAutofillInput(resourceName, "com.android.chrome", "www.amazon.it"); + } + + [Fact] + public void DetectsUsernameFieldDespitePasswordAutoHint() + { + var resourceName = "Kp2aAutofillParserTest.com-ifs-banking-fiid3364-android13.json"; + RunTestFromAutofillInput(resourceName, "com.ifs.banking.fiid3364", null); + } + + [Fact] + public void DetectsEmailAutofillHint() + { + var resourceName = "Kp2aAutofillParserTest.com-expressvpn-vpn-android13.json"; + RunTestFromAutofillInput(resourceName, "com.expressvpn.vpn", null); + } + private void RunTestFromAutofillInput(string resourceName, string expectedPackageName = null, string expectedWebDomain = null) { var assembly = Assembly.GetExecutingAssembly(); diff --git a/src/Kp2aAutofillParserTest/Kp2aAutofillParserTest.csproj b/src/Kp2aAutofillParserTest/Kp2aAutofillParserTest.csproj index bda6ab66..0a1ab633 100644 --- a/src/Kp2aAutofillParserTest/Kp2aAutofillParserTest.csproj +++ b/src/Kp2aAutofillParserTest/Kp2aAutofillParserTest.csproj @@ -9,6 +9,9 @@ + + + @@ -32,6 +35,15 @@ + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + PreserveNewest diff --git a/src/Kp2aAutofillParserTest/chrome-android10-amazon-it.json b/src/Kp2aAutofillParserTest/chrome-android10-amazon-it.json new file mode 100644 index 00000000..d642815b --- /dev/null +++ b/src/Kp2aAutofillParserTest/chrome-android10-amazon-it.json @@ -0,0 +1,2018 @@ +{ + "InputFields": [ + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "action_mode_bar_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "content", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "custom_tabs_handle_view_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "coordinator", + "Hint": null, + "ClassName": "android.view.ViewGroup", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "compositor_view_holder", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": true, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.webkit.WebView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "a-page", + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "nav-main", + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "navbar", + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "nav-logobar", + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "nav-logo", + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "nav-logo-sprites", + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "nav-progressive-subnav", + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "outer-accordion-signin-signup-page", + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "accordion-signin-signup-page", + "Hint": "", + "ClassName": "android.widget.RadioGroup", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "accordion-row-register", + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.RadioButton", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "register_accordion_header", + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "auth-verify-modal-action", + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "ap_register_form", + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "ap_customer_name", + "Hint": "Nome e cognome", + "ClassName": "android.widget.EditText", + "AutofillHints": null, + "IsFocused": false, + "InputType": 1, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "ap_email", + "Hint": "Numero di cellulare o e-mail", + "ClassName": "android.widget.EditText", + "AutofillHints": null, + "IsFocused": true, + "InputType": 209, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null, + "ExpectedAssignedHints": [ "username" ] + }, + { + "IdEntry": "auth-register-mobile-custom-message", + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "auth-password-container", + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "ap_password", + "Hint": "Crea una password", + "ClassName": "android.widget.EditText", + "AutofillHints": null, + "IsFocused": false, + "InputType": 225, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null, + "ExpectedAssignedHints": [ "password" ] + }, + { + "IdEntry": "auth-show-password-checkbox-container", + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "auth-register-show-password-checkbox", + "Hint": "", + "ClassName": "android.widget.CheckBox", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "auth-continue", + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "continue", + "Hint": "", + "ClassName": "android.widget.Button", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "legal-section", + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "legalTextRow", + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "ab-reg-link-section", + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "ab-registration-link", + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "accordion-row-login", + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.RadioButton", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "login_accordion_header", + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "nav-ftr", + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.ListView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "nav-ftr-copyright", + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "a-popover-root", + "Hint": "", + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.view.ViewGroup", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "ar_view_holder", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "capture_overlay", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "overview_list_layout_holder", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "bottom_container", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "infobar_icon", + "Hint": null, + "ClassName": "android.widget.ImageView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "translate_infobar_tabs", + "Hint": null, + "ClassName": "android.widget.HorizontalScrollView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.ImageView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "translate_infobar_tab_text", + "Hint": null, + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "translate_infobar_tab_progressbar", + "Hint": null, + "ClassName": "android.widget.ProgressBar", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.ImageView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "translate_infobar_tab_text", + "Hint": null, + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "translate_infobar_tab_progressbar", + "Hint": null, + "ClassName": "android.widget.ProgressBar", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "translate_infobar_menu_button", + "Hint": null, + "ClassName": "android.widget.ImageButton", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "infobar_close_button", + "Hint": null, + "ClassName": "android.widget.ImageButton", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "keyboard_accessory_sheet_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "bottombar_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "tab_modal_dialog_container_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "tab_modal_dialog_container_sibling_view", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "omnibox_results_container_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "action_bar_black_background", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "bottom_controls", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "bottom_controls_wrapper", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.ImageView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "bottom_container_slot", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "main_content", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "toolbar_left_button", + "Hint": null, + "ClassName": "android.widget.ImageView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "toolbar_container_view", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "tab_list_view", + "Hint": null, + "ClassName": "androidx.recyclerview.widget.RecyclerView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "toolbar_right_button", + "Hint": null, + "ClassName": "android.widget.ImageView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "tab_strip_fading_edge_start", + "Hint": null, + "ClassName": "android.widget.ImageView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "tab_strip_fading_edge_end", + "Hint": null, + "ClassName": "android.widget.ImageView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "control_container", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "toolbar_container", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "toolbar", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "home_button", + "Hint": null, + "ClassName": "android.widget.ImageButton", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "location_bar", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "location_bar_status_view_left_space", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "location_bar_status", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "location_bar_incognito_badge_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "location_bar_status_icon_view", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "location_bar_status_icon_frame", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "location_bar_status_icon_bg", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "location_bar_status_icon", + "Hint": null, + "ClassName": "android.widget.ImageView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "location_bar_status_icon_holding_space", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "location_bar_verbose_status", + "Hint": null, + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "location_bar_verbose_status_separator", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "location_bar_verbose_status_extra_space", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "location_bar_status_view_right_space", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "url_bar", + "Hint": "Suchbegriff oder Webadresse eingeben", + "ClassName": "android.widget.EditText", + "AutofillHints": null, + "IsFocused": false, + "InputType": 524305, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "url_action_container", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "toolbar_buttons", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "optional_toolbar_button_container", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "swappable_icon_secondary_background", + "Hint": null, + "ClassName": "android.widget.ImageView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "optional_toolbar_button", + "Hint": null, + "ClassName": "android.widget.ImageButton", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "action_chip_label", + "Hint": null, + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "swappable_icon_animation_image", + "Hint": null, + "ClassName": "android.widget.ImageView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "tab_switcher_button", + "Hint": null, + "ClassName": "android.widget.ImageButton", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "menu_button_wrapper", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "menu_button", + "Hint": null, + "ClassName": "android.widget.ImageButton", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "menu_badge", + "Hint": null, + "ClassName": "android.widget.ImageView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "toolbar_hairline", + "Hint": null, + "ClassName": "android.widget.ImageView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "find_toolbar_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "find_toolbar_tablet_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.ProgressBar", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.ImageView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "tab_switcher_toolbar_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "grid_tab_switcher_view_holder_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "message_container", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "status_indicator_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "empty_container_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "sheet_container", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "survey_container", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "page_zoom_container", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "dialog_parent_view", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "keyboard_accessory", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.ImageView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "accessory_bar_contents", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "tabs", + "Hint": null, + "ClassName": "android.widget.HorizontalScrollView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.ImageView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "bar_items_view", + "Hint": null, + "ClassName": "androidx.recyclerview.widget.RecyclerView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "menu_anchor_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "action_mode_bar_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "navigationBarBackground", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "statusBarBackground", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + } + ], + "PackageId": "com.android.chrome", + "WebDomain": "www.amazon.it" +} \ No newline at end of file diff --git a/src/Kp2aAutofillParserTest/com-expressvpn-vpn-android13.json b/src/Kp2aAutofillParserTest/com-expressvpn-vpn-android13.json new file mode 100644 index 00000000..03975549 --- /dev/null +++ b/src/Kp2aAutofillParserTest/com-expressvpn-vpn-android13.json @@ -0,0 +1,226 @@ +{ + "InputFields": [ + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "action_bar_root", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "action_mode_bar_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "layout", + "Hint": null, + "ClassName": "android.view.ViewGroup", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "textView2", + "Hint": null, + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "emailLayout", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "email", + "Hint": "E-Mail", + "ClassName": "android.widget.EditText", + "AutofillHints": [ + "email" + ], + "IsFocused": true, + "InputType": 33, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null, + "ExpectedAssignedHints": [ "emailAddress" ] + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "passwordLayout", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "password", + "Hint": "Passwort", + "ClassName": "android.widget.EditText", + "AutofillHints": [ + "password", + "passwordAuto" + ], + "IsFocused": false, + "InputType": 129, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null, + "ExpectedAssignedHints": [ + "password", + "passwordAuto" + ] + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "textinput_suffix_text", + "Hint": null, + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "forgotPassword", + "Hint": null, + "ClassName": "android.widget.Button", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "amazonInfo", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "signInButtonBarrier", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "signIn", + "Hint": null, + "ClassName": "android.widget.Button", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "newUser", + "Hint": null, + "ClassName": "android.widget.Button", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "focusThief", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "activatingContainer", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + } + ], + "PackageId": "com.expressvpn.vpn", + "WebDomain": null +} \ No newline at end of file diff --git a/src/Kp2aAutofillParserTest/com-ifs-banking-fiid3364-android13.json b/src/Kp2aAutofillParserTest/com-ifs-banking-fiid3364-android13.json new file mode 100644 index 00000000..4c93cb59 --- /dev/null +++ b/src/Kp2aAutofillParserTest/com-ifs-banking-fiid3364-android13.json @@ -0,0 +1,322 @@ +{ + "InputFields": [ + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "action_bar_root", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "action_mode_bar_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "loginParent", + "Hint": null, + "ClassName": "android.view.ViewGroup", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "rooted_device_error_screen", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "scroll", + "Hint": null, + "ClassName": "android.widget.ScrollView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "login_box_layout", + "Hint": null, + "ClassName": "android.view.ViewGroup", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "loginFragment_container_view", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "login_box", + "Hint": null, + "ClassName": "android.view.ViewGroup", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "Edt_UserId", + "Hint": "User ID", + "ClassName": "android.widget.EditText", + "AutofillHints": [ + "passwordAuto" + ], + "IsFocused": true, + "InputType": 145, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null, + "ExpectedAssignedHints": [ "username" ] + }, + { + "IdEntry": "login_save_userid_switch", + "Hint": null, + "ClassName": "android.widget.CompoundButton", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "Edt_Password_layout", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "Edt_Password", + "Hint": null, + "ClassName": "android.widget.EditText", + "AutofillHints": [ + "passwordAuto" + ], + "IsFocused": false, + "InputType": 129, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null, + "ExpectedAssignedHints": [ "password" ] + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "textinput_prefix_text", + "Hint": null, + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "textinput_suffix_text", + "Hint": null, + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "textinput_placeholder", + "Hint": null, + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "forgot_login_btn", + "Hint": null, + "ClassName": "android.widget.Button", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "Btn_Login", + "Hint": null, + "ClassName": "android.widget.Button", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "login_fab_fragment_container", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "biometric_fragment_container", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "biometricLayout", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "login_menu_container", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "deposit_insurance_systems_textview", + "Hint": null, + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "login_menu", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "login_menu_item_border_right", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "login_menu_item_border_left", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "sign_up_link", + "Hint": null, + "ClassName": "android.widget.Button", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "locations_link", + "Hint": null, + "ClassName": "android.widget.Button", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "more_link", + "Hint": null, + "ClassName": "android.widget.Button", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + } + ], + "PackageId": "com.ifs.banking.fiid3364", + "WebDomain": null +} \ No newline at end of file diff --git a/src/keepass2android/services/AutofillBase/AutofillFieldMetadata.cs b/src/keepass2android/services/AutofillBase/AutofillFieldMetadata.cs index a448e32b..6b802552 100644 --- a/src/keepass2android/services/AutofillBase/AutofillFieldMetadata.cs +++ b/src/keepass2android/services/AutofillBase/AutofillFieldMetadata.cs @@ -39,7 +39,7 @@ namespace keepass2android.services.AutofillBase AutofillOptions = view.GetAutofillOptions(); Focused = view.IsFocused; var supportedHints = AutofillHintsHelper.FilterForSupportedHints(autofillHints); - var canonicalHints = AutofillHintsHelper.ConvertToCanonicalHints(supportedHints); + var canonicalHints = AutofillHintsHelper.ConvertToCanonicalLowerCaseHints(supportedHints); SetHints(canonicalHints.ToArray()); } From 5ebd8e5e33c88a50492e92ae10ae46c3140d2e74 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Mon, 6 Mar 2023 14:12:17 +0100 Subject: [PATCH 042/101] New translations strings.xml (Portuguese, Brazilian) --- src/keepass2android/Resources/values-pt-rBR/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/keepass2android/Resources/values-pt-rBR/strings.xml b/src/keepass2android/Resources/values-pt-rBR/strings.xml index 5eac17ae..b457cd05 100644 --- a/src/keepass2android/Resources/values-pt-rBR/strings.xml +++ b/src/keepass2android/Resources/values-pt-rBR/strings.xml @@ -303,6 +303,8 @@ Desativa a checagem se domínio e pacote do app correspondem. Integrar com o teclado Mostra sugestões de Autopreenchimento como opção na linha no teclado (se suportado pelo método de entrada) + Registrar exibição de preenchimento automático + Escreva detalhes sobre a exibição de preenchimento automático para registro de depuração (se o registro de depuração estiver habilitado). Esses detalhes podem ser enviados ao desenvolvedor se o preenchimento automático não funcionar conforme o esperado. Requer Android 11 ou posterior Keepass2Android: Buscar senha Excluir entradas expiradas From b149bab761cfe34eef267b459536a9c335968f25 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Tue, 7 Mar 2023 03:36:36 +0100 Subject: [PATCH 043/101] New translations strings.xml (Chinese Simplified) --- src/keepass2android/Resources/values-zh/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/keepass2android/Resources/values-zh/strings.xml b/src/keepass2android/Resources/values-zh/strings.xml index b993ac8c..b158b26a 100644 --- a/src/keepass2android/Resources/values-zh/strings.xml +++ b/src/keepass2android/Resources/values-zh/strings.xml @@ -301,6 +301,8 @@ 不检查域名和应用程序包是否匹配 与键盘集成 将自动填充建议显示为键盘中的内联选项(如果输入法支持的话) + 记录自动填充视图 + 将自动填充视图的详情写入调试日志 (如果启用了调试日志)。 如果自动填充无法正常工作,这些细节可以发送给开发者。 需要 Android 11 或更高版本 找回密码 排除过期的条目 From 2378cd0d7c73b0b7d4c0cfedbf23bcc6adc2f355 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Wed, 8 Mar 2023 16:54:54 +0100 Subject: [PATCH 044/101] New translations strings.xml (Greek) --- src/keepass2android/Resources/values-el/strings.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/keepass2android/Resources/values-el/strings.xml b/src/keepass2android/Resources/values-el/strings.xml index 086457ee..e201f7c9 100644 --- a/src/keepass2android/Resources/values-el/strings.xml +++ b/src/keepass2android/Resources/values-el/strings.xml @@ -301,6 +301,8 @@ Απενεργοποιεί τον έλεγχο αν ταιριάζει ο τομέας και το πακέτο εφαρμογής Ενσωμάτωση με πληκτρολόγιο Δείχνει τις προτάσεις αυτόματης συμπλήρωσης ως γραμμές μέσα στο πρηκτρολόγιο + Προβολή αυτόματης συμπλήρωσης αρχείου καταγραφής + Εγγραφή λεπτομερειών σχετικά με την προβολή αυτόματης συμπλήρωσης στο αρχείο καταγραφής αποσφαλμάτωσης (αν η καταγραφή αποσφαλμάτωσης είναι ενεργοποιημένη). Αυτές οι λεπτομέρειες μπορούν να σταλούν στον προγραμματιστή αν η αυτόματη συμπλήρωση δε λειτουργεί όπως αναμενόταν. Απαιτείται Android 11 ή νεότερη έκδοση Εύρεση συνθηματικού Εξαίρεση ληγμένων εγγραφών @@ -682,6 +684,11 @@ Ειδοποίηση για απλοποιημένη πρόσβαση στην τρέχουσα καταχώριση. Κλείσιμο της βάσης δεδομένων μετά από 3 ανεπιτυχείς προσπάθειες βιομετρικού ξεκλειδώματος. Προσοχή! Ο βιομετρικός έλεγχος ταυτότητας μπορεί να ακυρωθεί από το Android, π.χ. μετά την προσθήκη ενός νέου δακτυλικού αποτυπώματος στις ρυθμίσεις της συσκευής σας. Βεβαιωθείτε ότι ξέρετε πάντα πώς να ξεκλειδώσετε με τον κύριο κωδικό πρόσβασης! + + Διόρθωση σφάλματος για απότομα κλεισίματα εφαρμογής και μη αναμενόμενες αποσυνδέσεις + Μετάβαση σε νέα υλοποίηση SFTP, υποστηρίζοντας σύγχρονους αλγόριθμους δημόσιου κλειδιού όπως rsa-sha2-256 + Μαρκάρισμα κωδικών πρόσβασης ως ευαίσθητοι κατά την αντιγραφή στο πρόχειρο (Android 13) + Υποστηρίζεται πλέον προβολή, διαγραφή και ανάκτηση των διαγραμμένων εγγραφών Υλοποιήθηκε υποστήριξη για αποθήκευση στο νέφος MEGA From 1c7159ede94e22562f30c06c05e3b8d6a7cdd71b Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Thu, 9 Mar 2023 19:39:51 +0100 Subject: [PATCH 045/101] changelog and manifest for 1.09e-r3 --- src/keepass2android/Properties/AndroidManifest_net.xml | 4 ++-- src/keepass2android/Properties/AndroidManifest_nonet.xml | 4 ++-- src/keepass2android/Resources/values/strings.xml | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/keepass2android/Properties/AndroidManifest_net.xml b/src/keepass2android/Properties/AndroidManifest_net.xml index b008d5dd..8d0ab320 100644 --- a/src/keepass2android/Properties/AndroidManifest_net.xml +++ b/src/keepass2android/Properties/AndroidManifest_net.xml @@ -1,7 +1,7 @@  diff --git a/src/keepass2android/Properties/AndroidManifest_nonet.xml b/src/keepass2android/Properties/AndroidManifest_nonet.xml index 839d80be..646117e2 100644 --- a/src/keepass2android/Properties/AndroidManifest_nonet.xml +++ b/src/keepass2android/Properties/AndroidManifest_nonet.xml @@ -1,7 +1,7 @@  diff --git a/src/keepass2android/Resources/values/strings.xml b/src/keepass2android/Resources/values/strings.xml index fa615243..52f858ae 100644 --- a/src/keepass2android/Resources/values/strings.xml +++ b/src/keepass2android/Resources/values/strings.xml @@ -853,6 +853,7 @@ Bug fix to crashes and unexpected log-outs Switch to new SFTP implementation, supporting modern public key algorithms such as rsa-sha2-256 Mark passwords as sensitive when copying to clipboard (Android 13) + Autofill improvements From 72cc6ff768dbb0799c2924df307a2d2eb7bff4f0 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Thu, 9 Mar 2023 19:46:28 +0100 Subject: [PATCH 046/101] wrap adding fields and hints to dictionary, avoiding to add a duplicate key. Should close #2262 (but I can't reproduce) --- src/Kp2aAutofillParser/AutofillParser.cs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Kp2aAutofillParser/AutofillParser.cs b/src/Kp2aAutofillParser/AutofillParser.cs index d60f56be..7a60e534 100644 --- a/src/Kp2aAutofillParser/AutofillParser.cs +++ b/src/Kp2aAutofillParser/AutofillParser.cs @@ -838,7 +838,7 @@ namespace Kp2aAutofillParser continue; if (viewHints.Select(AutofillHintsHelper.ToCanonicalHint).Intersect(_autofillHintsForLogin).Any()) { - FieldsMappedToHints.Add(viewNode, viewHints.Select(AutofillHintsHelper.ToCanonicalHint).ToHashSet().ToArray()); + AddFieldToHintMap(viewNode, viewHints.Select(AutofillHintsHelper.ToCanonicalHint).ToHashSet().ToArray()); } } @@ -873,9 +873,9 @@ namespace Kp2aAutofillParser if (passwordFields.Concat(usernameFields).Any(f => f.IsFocused)) { foreach (var uf in usernameFields) - FieldsMappedToHints.Add(uf, new string[] { AutofillHintsHelper.AutofillHintUsername }); + AddFieldToHintMap(uf, new string[] { AutofillHintsHelper.AutofillHintUsername }); foreach (var pf in passwordFields.Except(usernameFields)) - FieldsMappedToHints.Add(pf, new string[] { AutofillHintsHelper.AutofillHintPassword }); + AddFieldToHintMap(pf, new string[] { AutofillHintsHelper.AutofillHintPassword }); } } @@ -895,6 +895,18 @@ namespace Kp2aAutofillParser return result; } + private void AddFieldToHintMap(FieldT field, string[] hints) + { + if (FieldsMappedToHints.ContainsKey(field)) + { + FieldsMappedToHints[field] = FieldsMappedToHints[field].Concat(hints).ToArray(); + } + else + { + FieldsMappedToHints[field] = hints; + } + } + public bool LogAutofillView { get; set; } private bool IsEditText(FieldT f) From 786bb646c2bc6211691650ac2338bb566d8fa826 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Thu, 9 Mar 2023 19:55:37 +0100 Subject: [PATCH 047/101] New translations strings.xml (Slovak) --- src/keepass2android/Resources/values-sk/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keepass2android/Resources/values-sk/strings.xml b/src/keepass2android/Resources/values-sk/strings.xml index 2c2ef1b6..74edea9f 100644 --- a/src/keepass2android/Resources/values-sk/strings.xml +++ b/src/keepass2android/Resources/values-sk/strings.xml @@ -690,6 +690,7 @@ Oprava chyby vedúcej k pádom a neočakávaným odhláseniam Prepnutie na novú implementáciu SFTP, s podporou pre moderné algoritmy verejných kľúčov, ako je rsa-sha2-256 Označiť heslá ako citlivé údaje pri kopírovaní do schránky (Android 13) + Autofill improvements Pridaná podpora prehliadania, odstraňovania a obnovovania záloh záznamu From 35d50a6eb0a353f6e5e87bb1509c885c0aa5a41f Mon Sep 17 00:00:00 2001 From: PhilippC Date: Thu, 9 Mar 2023 19:55:39 +0100 Subject: [PATCH 048/101] New translations strings.xml (French) --- src/keepass2android/Resources/values-fr/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keepass2android/Resources/values-fr/strings.xml b/src/keepass2android/Resources/values-fr/strings.xml index 629d30d8..9232b2b6 100644 --- a/src/keepass2android/Resources/values-fr/strings.xml +++ b/src/keepass2android/Resources/values-fr/strings.xml @@ -687,6 +687,7 @@ Voici quelques conseils qui pourraient aider à diagnostiquer le problème : \n Correction de bugs pour les plantages et les déconnexions inattendues Passage à une nouvelle implémentation SFTP, prenant en charge les algorithmes à clé publique modernes tels que rsa-sha2-256 Marquer les mots de passe comme sensibles lors de la copie dans le presse-papiers (Android 13) + Autofill improvements Ajout du support pour la visualisation, la suppression et la restauration des sauvegardes d\'entrée From 656e78521481cbdfd45e6f6c402dbbb2738afd58 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Thu, 9 Mar 2023 19:55:44 +0100 Subject: [PATCH 049/101] New translations strings.xml (Danish) --- src/keepass2android/Resources/values-da/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keepass2android/Resources/values-da/strings.xml b/src/keepass2android/Resources/values-da/strings.xml index 8b260dbd..514c3a2d 100644 --- a/src/keepass2android/Resources/values-da/strings.xml +++ b/src/keepass2android/Resources/values-da/strings.xml @@ -689,6 +689,7 @@ Fejlrettelse til nedbrud og uventede log-outs Skift til ny SFTP-implementering, som understøtter moderne offentlige nøglealgoritmer såsom rsa-sha2-256 Markér adgangskoder som følsomme ved kopiering til udklipsholder (Android 13) + Autofill improvements Tilføjet understøttelse af visning, fjernelse og gendannelse af sikkerhedskopierede poster From dce536009ed2deae17f58bab87e95de4adf8cbf9 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Thu, 9 Mar 2023 19:55:45 +0100 Subject: [PATCH 050/101] New translations strings.xml (German) --- src/keepass2android/Resources/values-de/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keepass2android/Resources/values-de/strings.xml b/src/keepass2android/Resources/values-de/strings.xml index c381fd39..ef4975b1 100644 --- a/src/keepass2android/Resources/values-de/strings.xml +++ b/src/keepass2android/Resources/values-de/strings.xml @@ -688,6 +688,7 @@ Anbei einige Tipps, die bei der Diagnose des Problems helfen können:\n Fehlerbehebung, um Abstürze und unerwartetes Abmelden zu vermeiden Wechsel auf eine neue SFTP-Implementierung, jetzt mit Unterstützung von modernen Public-Key-Algorithmen wie rsa-sha2-256 Passwörter werden beim Kopieren in die Zwischenablage als vertraulich markiert (Android 13) + Autofill improvements Unterstützung für das Ansehen, Entfernen und Wiederherstellen von Eintragssicherungen hinzugefügt From cb25d1270920eca7d764504ef52230000bba3124 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Thu, 9 Mar 2023 19:55:46 +0100 Subject: [PATCH 051/101] New translations strings.xml (Greek) --- src/keepass2android/Resources/values-el/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keepass2android/Resources/values-el/strings.xml b/src/keepass2android/Resources/values-el/strings.xml index e201f7c9..dff0b0f5 100644 --- a/src/keepass2android/Resources/values-el/strings.xml +++ b/src/keepass2android/Resources/values-el/strings.xml @@ -688,6 +688,7 @@ Διόρθωση σφάλματος για απότομα κλεισίματα εφαρμογής και μη αναμενόμενες αποσυνδέσεις Μετάβαση σε νέα υλοποίηση SFTP, υποστηρίζοντας σύγχρονους αλγόριθμους δημόσιου κλειδιού όπως rsa-sha2-256 Μαρκάρισμα κωδικών πρόσβασης ως ευαίσθητοι κατά την αντιγραφή στο πρόχειρο (Android 13) + Autofill improvements Υποστηρίζεται πλέον προβολή, διαγραφή και ανάκτηση των διαγραμμένων εγγραφών From d87706fa436d4babcf4238bb82ac844a5e81aac5 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Thu, 9 Mar 2023 19:55:51 +0100 Subject: [PATCH 052/101] New translations strings.xml (Japanese) --- src/keepass2android/Resources/values-ja/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keepass2android/Resources/values-ja/strings.xml b/src/keepass2android/Resources/values-ja/strings.xml index 878416a0..05d93ff6 100644 --- a/src/keepass2android/Resources/values-ja/strings.xml +++ b/src/keepass2android/Resources/values-ja/strings.xml @@ -690,6 +690,7 @@ クラッシュと突発的にログアウトするバグを修正 rsa-sha2-256 などの最新の公開鍵アルゴリズムをサポートする、新しい SFTP 実装に切り替え パスワードをクリップボードにコピーしたとき、機密コンテンツとしてマークするよう変更 (Android 13) + Autofill improvements エントリーバックアップの表示、削除、および復元に対応 From b66ae5d26409e6435685a0174516bb440eb7f704 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Thu, 9 Mar 2023 19:55:53 +0100 Subject: [PATCH 053/101] New translations strings.xml (Polish) --- src/keepass2android/Resources/values-pl/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keepass2android/Resources/values-pl/strings.xml b/src/keepass2android/Resources/values-pl/strings.xml index fa5dd72e..dc0afe48 100644 --- a/src/keepass2android/Resources/values-pl/strings.xml +++ b/src/keepass2android/Resources/values-pl/strings.xml @@ -690,6 +690,7 @@ Naprawa błędów awarii i nieoczekiwanych wylogowań Przełącz się na nową implementację SFTP, wspierając nowoczesne algorytmy klucza publicznego, takie jak rsa-sha2-256 Oznacz hasła jako wrażliwe podczas kopiowania do schowka (Android 13) + Autofill improvements Dodano wsparcie dla przeglądania, usuwania i przywracania kopii zapasowych wpisów From ad0acb7a696178b28a2e0f2960c2cd3afec5ad8c Mon Sep 17 00:00:00 2001 From: PhilippC Date: Thu, 9 Mar 2023 19:55:56 +0100 Subject: [PATCH 054/101] New translations strings.xml (Slovenian) --- src/keepass2android/Resources/values-sl/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keepass2android/Resources/values-sl/strings.xml b/src/keepass2android/Resources/values-sl/strings.xml index 49c868fe..2cd4eb13 100644 --- a/src/keepass2android/Resources/values-sl/strings.xml +++ b/src/keepass2android/Resources/values-sl/strings.xml @@ -690,6 +690,7 @@ Popravek napak pri zrušitvah in nepričakovanih odjavah Preklopite na novo izvedbo SFTP, ki podpira sodobne algoritme javnih ključev, kot je rsa-sha2-256 Označi gesla kot občutljiva pri kopiranju v odložišče (Android 13) + Autofill improvements Dodana podpora za ogled, odstranjevanje in obnavljanje varnostnih kopij vnosov From 317476d9b5b0ecb466d6488e74dae3e6a6314623 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Thu, 9 Mar 2023 19:55:59 +0100 Subject: [PATCH 055/101] New translations strings.xml (Ukrainian) --- src/keepass2android/Resources/values-uk/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keepass2android/Resources/values-uk/strings.xml b/src/keepass2android/Resources/values-uk/strings.xml index 510299c7..17e0dfbd 100644 --- a/src/keepass2android/Resources/values-uk/strings.xml +++ b/src/keepass2android/Resources/values-uk/strings.xml @@ -690,6 +690,7 @@ Виправлено помилку зі збоями та несподіваними виходами Перехід на нову реалізацію SFTP з підтримкою сучасних алгоритмів публічного ключа, як-от rsa-sha2-256 Позначати паролі як вразливі під час копіювання до буфера обміну (Android 13) + Autofill improvements Додано підтримку перегляду, видалення та відновлення резервних копій записів From 5442dbf441a4027474fbfa09c7e7d53072456df2 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Thu, 9 Mar 2023 19:56:00 +0100 Subject: [PATCH 056/101] New translations strings.xml (Chinese Simplified) --- src/keepass2android/Resources/values-zh/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keepass2android/Resources/values-zh/strings.xml b/src/keepass2android/Resources/values-zh/strings.xml index b158b26a..3b1287eb 100644 --- a/src/keepass2android/Resources/values-zh/strings.xml +++ b/src/keepass2android/Resources/values-zh/strings.xml @@ -691,6 +691,7 @@ 修复崩溃和意外注销的 bug 切换到新的 SFTP 实现,支持现代公钥算法,例如 rsa-sha2-256 复制到剪贴板时将密码标记为敏感 (Android 13) + Autofill improvements 新增查看、移除和恢复条目备份的功能 From aea55dad45940aa40f7f7268304ec514617540d4 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Thu, 9 Mar 2023 19:56:01 +0100 Subject: [PATCH 057/101] New translations strings.xml (Chinese Traditional) --- src/keepass2android/Resources/values-zh-rTW/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keepass2android/Resources/values-zh-rTW/strings.xml b/src/keepass2android/Resources/values-zh-rTW/strings.xml index f558af11..8f27c04e 100644 --- a/src/keepass2android/Resources/values-zh-rTW/strings.xml +++ b/src/keepass2android/Resources/values-zh-rTW/strings.xml @@ -690,6 +690,7 @@ 修正當機和意外登出的錯誤 切換成新 SFTP 實作,支援現代公鑰演算法,如 rsa-sha2-256 複製密碼到剪貼簿時設為機密 (Android 13) + Autofill improvements 支援查看、移除和還原項目備份 From df060e2f4b4e1bf71f335fa5fd5f03eea35e9573 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Thu, 9 Mar 2023 19:56:04 +0100 Subject: [PATCH 058/101] New translations strings.xml (Portuguese, Brazilian) --- src/keepass2android/Resources/values-pt-rBR/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keepass2android/Resources/values-pt-rBR/strings.xml b/src/keepass2android/Resources/values-pt-rBR/strings.xml index b457cd05..585c31ef 100644 --- a/src/keepass2android/Resources/values-pt-rBR/strings.xml +++ b/src/keepass2android/Resources/values-pt-rBR/strings.xml @@ -692,6 +692,7 @@ Correção de bugs em falhas e logouts inesperados Mudar para nova implementação SFTP, suportando algoritmos de chave pública modernos como rsa-sha2-256 Marcar senhas como confidenciais ao copiar para a área de transferência (Android 13) + Autofill improvements Adicionado suporte para visualização, remoção e restauração de backups de entrada From d0c041a0e218f5c015e7d3aa3a5441e70551bd96 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Thu, 9 Mar 2023 20:16:24 +0100 Subject: [PATCH 059/101] remove debugging code --- src/Kp2aAutofillParser/AutofillParser.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Kp2aAutofillParser/AutofillParser.cs b/src/Kp2aAutofillParser/AutofillParser.cs index 7a60e534..9f62fba5 100644 --- a/src/Kp2aAutofillParser/AutofillParser.cs +++ b/src/Kp2aAutofillParser/AutofillParser.cs @@ -956,11 +956,6 @@ namespace Kp2aAutofillParser private static bool IsPassword(InputField f) { - if (f.IdEntry?.Contains("password") == true) - { - f = f; - } - InputTypes inputType = f.InputType; return From 944f44bc4b66463fe3708c7130121ca081f1a95d Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Thu, 9 Mar 2023 20:45:25 +0100 Subject: [PATCH 060/101] Manifest for v1.09e-r4 --- src/keepass2android/Properties/AndroidManifest_net.xml | 4 ++-- src/keepass2android/Properties/AndroidManifest_nonet.xml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/keepass2android/Properties/AndroidManifest_net.xml b/src/keepass2android/Properties/AndroidManifest_net.xml index 8d0ab320..0c029336 100644 --- a/src/keepass2android/Properties/AndroidManifest_net.xml +++ b/src/keepass2android/Properties/AndroidManifest_net.xml @@ -1,7 +1,7 @@  diff --git a/src/keepass2android/Properties/AndroidManifest_nonet.xml b/src/keepass2android/Properties/AndroidManifest_nonet.xml index 646117e2..60700392 100644 --- a/src/keepass2android/Properties/AndroidManifest_nonet.xml +++ b/src/keepass2android/Properties/AndroidManifest_nonet.xml @@ -1,7 +1,7 @@  From 728fd2f8ae928d9e56cee7f01e74e334186acdc9 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Thu, 9 Mar 2023 21:38:11 +0100 Subject: [PATCH 061/101] New translations strings.xml (Portuguese, Brazilian) --- src/keepass2android/Resources/values-pt-rBR/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keepass2android/Resources/values-pt-rBR/strings.xml b/src/keepass2android/Resources/values-pt-rBR/strings.xml index 585c31ef..04cfc8dc 100644 --- a/src/keepass2android/Resources/values-pt-rBR/strings.xml +++ b/src/keepass2android/Resources/values-pt-rBR/strings.xml @@ -692,7 +692,7 @@ Correção de bugs em falhas e logouts inesperados Mudar para nova implementação SFTP, suportando algoritmos de chave pública modernos como rsa-sha2-256 Marcar senhas como confidenciais ao copiar para a área de transferência (Android 13) - Autofill improvements + Melhorias no preenchimento automático Adicionado suporte para visualização, remoção e restauração de backups de entrada From cacd204ac2ac0186149ffb71d5707f2d321e0c25 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Fri, 10 Mar 2023 04:06:30 +0100 Subject: [PATCH 062/101] New translations strings.xml (Chinese Simplified) --- src/keepass2android/Resources/values-zh/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keepass2android/Resources/values-zh/strings.xml b/src/keepass2android/Resources/values-zh/strings.xml index 3b1287eb..33c84018 100644 --- a/src/keepass2android/Resources/values-zh/strings.xml +++ b/src/keepass2android/Resources/values-zh/strings.xml @@ -691,7 +691,7 @@ 修复崩溃和意外注销的 bug 切换到新的 SFTP 实现,支持现代公钥算法,例如 rsa-sha2-256 复制到剪贴板时将密码标记为敏感 (Android 13) - Autofill improvements + 自动填充改进 新增查看、移除和恢复条目备份的功能 From dd0becdfd82c03439777c0888ef329920544cbeb Mon Sep 17 00:00:00 2001 From: PhilippC Date: Sun, 12 Mar 2023 20:04:54 +0100 Subject: [PATCH 063/101] New translations strings.xml (Slovenian) --- src/keepass2android/Resources/values-sl/strings.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/keepass2android/Resources/values-sl/strings.xml b/src/keepass2android/Resources/values-sl/strings.xml index 2cd4eb13..1e00fc93 100644 --- a/src/keepass2android/Resources/values-sl/strings.xml +++ b/src/keepass2android/Resources/values-sl/strings.xml @@ -301,6 +301,8 @@ Onemogoči preverjanje, ali se paket domen in aplikacije ujemata Integracija s tipkovnico Prikaže predloge samodejnega izpolnjevanja kot vgrajene možnosti na tipkovnici (če to podpira način vnosa) + Pregled podrobnosti samodejnega izpolnjevanja + Zapišite podrobnosti o pogledu samodejnega izpolnjevanja v dnevnik odpravljanja napak (če je omogočeno beleženje odpravljanja napak). Te podrobnosti lahko pošljete razvijalcu, če samodejno izpolnjevanje ne deluje po pričakovanjih. Zahteva Android 11 ali novejši Najdi geslo Izključi potekle vnose @@ -690,7 +692,7 @@ Popravek napak pri zrušitvah in nepričakovanih odjavah Preklopite na novo izvedbo SFTP, ki podpira sodobne algoritme javnih ključev, kot je rsa-sha2-256 Označi gesla kot občutljiva pri kopiranju v odložišče (Android 13) - Autofill improvements + Izboljšave samodejnega izpolnjevanja Dodana podpora za ogled, odstranjevanje in obnavljanje varnostnih kopij vnosov From 5f2a976fdeb5615f58fff9e79b41fce402aec3e7 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Sun, 12 Mar 2023 22:20:54 +0100 Subject: [PATCH 064/101] New translations strings.xml (Finnish) --- src/keepass2android/Resources/values-fi/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/keepass2android/Resources/values-fi/strings.xml b/src/keepass2android/Resources/values-fi/strings.xml index 15c20c16..6b787222 100644 --- a/src/keepass2android/Resources/values-fi/strings.xml +++ b/src/keepass2android/Resources/values-fi/strings.xml @@ -172,7 +172,9 @@ ***** Piilota salasana Piilota salasanat oletuksena + Peitä TOTP-kenttä Piilota TOTP-kenttä oletuksena + Jos aktivoitu, sovellus ei näytä vaihtoehtoa poistaa automaattista täyttöä tiettyjen merkintöjen osalta. Tietoja Vaihda pääavain Kopioi salasana @@ -285,6 +287,8 @@ Huomaa Kehittäjät ja avustajat Säännöllinen lauseke + Yhdistä aina ristiriidan yhteydessä + Kun Keepass2Android havaitsee, että etätiedostoa on muokattu, yhdistetään paikalliset muutokset aina etämuutoksiin. TAN käytön lopetus Merkitse TAN-merkinnät vanhentuneiksi käytön jälkeen Näytä käyttäjänimi @@ -323,6 +327,7 @@ Pika-avauksessa käytettävien merkkien enimmäismäärä. Piilota pika-avauskoodin pituus Jos käytössä, pika-avauskoodin pituutta ei näytetä pika-avausnäytössä. + QuickUnlock-avain tietokannan syötteestä Pika-avaus epäonnistui: väärä salasana! Tallenna liite Valitse liitteen tallennuspaikka. From ad3b1500bb6db90cb9def3e8971584b25a494cc9 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Sun, 12 Mar 2023 23:25:28 +0100 Subject: [PATCH 065/101] New translations strings.xml (Finnish) --- src/keepass2android/Resources/values-fi/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keepass2android/Resources/values-fi/strings.xml b/src/keepass2android/Resources/values-fi/strings.xml index 6b787222..50e80297 100644 --- a/src/keepass2android/Resources/values-fi/strings.xml +++ b/src/keepass2android/Resources/values-fi/strings.xml @@ -951,7 +951,7 @@ Suojelee sinua Leikepöytään perustuvalta salasana sniffaukselta (Poista vanha Salasana + OTP salaus (Palautustila) Salasana + Haastemenetelmä Salasana + Haastemenetelmä (palautustila) - Salasana + Avaintiedosto + Haastemenetelmä Keepass XC:n kanssa + Salasana + Haastemenetelmä Keepass XC:n kanssa Salasana + Avaintiedosto + Haastemenetelmä Keepass XC:n kanssa From e0c003fcb2c68edef722c8fa23dec3a821b9d383 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Tue, 14 Mar 2023 20:19:08 +0100 Subject: [PATCH 066/101] add debugging output --- .../java/keepass2android/javafilestorage/SftpStorage.java | 5 +++++ .../java/keepass2android/javafilestorage/SftpUserInfo.java | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpStorage.java b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpStorage.java index ead893da..e3629030 100644 --- a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpStorage.java +++ b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpStorage.java @@ -24,6 +24,7 @@ import com.jcraft.jsch.UserInfo; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.util.Log; public class SftpStorage extends JavaFileStorageBase { @@ -323,6 +324,8 @@ public class SftpStorage extends JavaFileStorageBase { jsch = new JSch(); ConnectionInfo ci = splitStringToConnectionInfo(filename); + Log.e("KP2AJFS", "init SFTP"); + String base_dir = getBaseDir(); jsch.setKnownHosts(base_dir + "/known_hosts"); @@ -340,7 +343,9 @@ public class SftpStorage extends JavaFileStorageBase { } + Log.e("KP2AJFS[thread]", "getting session..."); Session session = jsch.getSession(ci.username, ci.host, ci.port); + Log.e("KP2AJFS", "creating SftpUserInfo"); UserInfo ui = new SftpUserInfo(ci.password,_appContext); session.setUserInfo(ui); diff --git a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpUserInfo.java b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpUserInfo.java index 6737535c..7084951d 100644 --- a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpUserInfo.java +++ b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpUserInfo.java @@ -34,7 +34,6 @@ public class SftpUserInfo implements UserInfo { builder.setContentText("SFTP prompt"); builder.setSmallIcon(R.drawable.ic_logo_green_foreground); - Handler h = new Handler() { public void handleMessage(Message M) { msg.copyFrom(M); @@ -51,8 +50,12 @@ public class SftpUserInfo implements UserInfo { intent.putExtra("keepass2android.sftp.prompt", text); intent.setData((Uri.parse("suckit://"+SystemClock.elapsedRealtime()))); + + Log.e("KP2AJFS[thread]", "built after 2023-03-14"); + int flags = 0; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) { + Log.e("KP2AJFS[thread]", "Setting mutable flag..."); flags |= PendingIntent.FLAG_MUTABLE; } PendingIntent contentIntent = PendingIntent.getActivity(_appContext, 0, intent, flags); From eedeeafd808f78f3e889d3e768599ed8bacbee1b Mon Sep 17 00:00:00 2001 From: PhilippC Date: Thu, 16 Mar 2023 03:34:05 +0100 Subject: [PATCH 067/101] New translations strings.xml (Chinese Simplified) --- .../app/src/main/res/values-zh/strings.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/java/KP2ASoftkeyboard_AS/app/src/main/res/values-zh/strings.xml b/src/java/KP2ASoftkeyboard_AS/app/src/main/res/values-zh/strings.xml index 19761150..34a16d85 100644 --- a/src/java/KP2ASoftkeyboard_AS/app/src/main/res/values-zh/strings.xml +++ b/src/java/KP2ASoftkeyboard_AS/app/src/main/res/values-zh/strings.xml @@ -21,7 +21,7 @@ == Keepass2Android 键盘 == - USB 键盘设置 + 键盘设置 输入选项 @@ -29,23 +29,23 @@ 按键声音 - 按键弹出放大 + 按键弹出显示 智能纠错 启用输入错误校正 - 横屏输入错误 + 横屏输入纠错 启用输入错误校正 - 单词联想 + 输入建议 自动更正前一个单词 - 单词联想 + 输入建议 - 词语建议设置 + 输入建议设置 在输入时启用自动补全 @@ -91,7 +91,7 @@ 二元语法分词建议 - 使用曾经使用过的词语改进建议 + 使用前一个单词来改进建议 From 6f10a04589ed5e266bf3b471dc8fdc8a14aabcbe Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Thu, 16 Mar 2023 20:25:57 +0100 Subject: [PATCH 068/101] revert most of the added debug outputs --- .../main/java/keepass2android/javafilestorage/SftpStorage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpStorage.java b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpStorage.java index e3629030..2216ccfc 100644 --- a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpStorage.java +++ b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpStorage.java @@ -324,7 +324,7 @@ public class SftpStorage extends JavaFileStorageBase { jsch = new JSch(); ConnectionInfo ci = splitStringToConnectionInfo(filename); - Log.e("KP2AJFS", "init SFTP"); + Log.d("KP2AJFS", "init SFTP"); String base_dir = getBaseDir(); jsch.setKnownHosts(base_dir + "/known_hosts"); From 6110166af87940fc18e177a353c3e72ca912c9b5 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Thu, 16 Mar 2023 20:27:22 +0100 Subject: [PATCH 069/101] code simplification and fix for Autofill not being able to save credentials, closes https://github.com/PhilippC/keepass2android/issues/2269 --- src/Kp2aAutofillParser/AutofillParser.cs | 21 +++++++++++-------- src/Kp2aAutofillParserTest/AutofillTest.cs | 3 +++ .../services/AutofillBase/AutofillHelper.cs | 2 +- .../services/AutofillBase/StructureParser.cs | 9 ++++++-- .../Kp2aAutofill/ChooseForAutofillActivity.cs | 14 ++++++------- 5 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/Kp2aAutofillParser/AutofillParser.cs b/src/Kp2aAutofillParser/AutofillParser.cs index 9f62fba5..89b58b72 100644 --- a/src/Kp2aAutofillParser/AutofillParser.cs +++ b/src/Kp2aAutofillParser/AutofillParser.cs @@ -134,10 +134,10 @@ namespace Kp2aAutofillParser /// public class FilledAutofillFieldCollection where FieldT:InputField { - public Dictionary> HintMap { get; } + public Dictionary HintMap { get; } public string DatasetName { get; set; } - public FilledAutofillFieldCollection(Dictionary> hintMap, string datasetName = "") + public FilledAutofillFieldCollection(Dictionary hintMap, string datasetName = "") { //recreate hint map making sure we compare case insensitive HintMap = BuildHintMap(); @@ -149,9 +149,9 @@ namespace Kp2aAutofillParser public FilledAutofillFieldCollection() : this(BuildHintMap()) { } - private static Dictionary> BuildHintMap() + private static Dictionary BuildHintMap() { - return new Dictionary>(StringComparer.OrdinalIgnoreCase); + return new Dictionary(StringComparer.OrdinalIgnoreCase); } /// @@ -159,7 +159,7 @@ namespace Kp2aAutofillParser /// /// The add. /// Filled autofill field. - public void Add(FilledAutofillField filledAutofillField) + public void Add(FilledAutofillField filledAutofillField) { foreach (string hint in filledAutofillField.AutofillHints) { @@ -572,7 +572,7 @@ namespace Kp2aAutofillParser } } - public class FilledAutofillField where FieldT : InputField + public class FilledAutofillField { private string[] _autofillHints; public string TextValue { get; set; } @@ -611,13 +611,13 @@ namespace Kp2aAutofillParser public FilledAutofillField() { } - public FilledAutofillField(FieldT inputField) + public FilledAutofillField(InputField inputField) : this(inputField, inputField.AutofillHints) { } - public FilledAutofillField(FieldT inputField, string[] hints) + public FilledAutofillField(InputField inputField, string[] hints) { string[] rawHints = AutofillHintsHelper.FilterForSupportedHints(hints); @@ -665,6 +665,7 @@ namespace Kp2aAutofillParser } } AutofillHints = AutofillHintsHelper.ConvertToCanonicalLowerCaseHints(hintList.ToArray()).ToArray(); + inputField.FillFilledAutofillValue(this); } @@ -679,7 +680,7 @@ namespace Kp2aAutofillParser if (this == obj) return true; if (obj == null || GetType() != obj.GetType()) return false; - FilledAutofillField that = (FilledAutofillField)obj; + FilledAutofillField that = (FilledAutofillField)obj; if (!TextValue?.Equals(that.TextValue) ?? that.TextValue != null) return false; @@ -717,6 +718,8 @@ namespace Kp2aAutofillParser public string HtmlInfoTag { get; set; } public string HtmlInfoTypeAttribute { get; set; } + public abstract void FillFilledAutofillValue(FilledAutofillField filledField); + } /// diff --git a/src/Kp2aAutofillParserTest/AutofillTest.cs b/src/Kp2aAutofillParserTest/AutofillTest.cs index 3a5587a5..3449feb7 100644 --- a/src/Kp2aAutofillParserTest/AutofillTest.cs +++ b/src/Kp2aAutofillParserTest/AutofillTest.cs @@ -18,6 +18,9 @@ namespace Kp2aAutofillParserTest class TestInputField: InputField { public string[] ExpectedAssignedHints { get; set; } + public override void FillFilledAutofillValue(FilledAutofillField filledField) + { + } } [Fact] diff --git a/src/keepass2android/services/AutofillBase/AutofillHelper.cs b/src/keepass2android/services/AutofillBase/AutofillHelper.cs index fbc865b0..28328862 100644 --- a/src/keepass2android/services/AutofillBase/AutofillHelper.cs +++ b/src/keepass2android/services/AutofillBase/AutofillHelper.cs @@ -142,7 +142,7 @@ namespace keepass2android.services.AutofillBase { foreach (AutofillFieldMetadata autofillFieldMetadata in autofillFieldMetadataCollection.GetFieldsForHint(hint)) { - FilledAutofillField filledAutofillField; + FilledAutofillField filledAutofillField; if (!filledAutofillFieldCollection.HintMap.TryGetValue(hint, out filledAutofillField) || (filledAutofillField == null)) { continue; diff --git a/src/keepass2android/services/AutofillBase/StructureParser.cs b/src/keepass2android/services/AutofillBase/StructureParser.cs index 51e06ed0..5fb6227a 100644 --- a/src/keepass2android/services/AutofillBase/StructureParser.cs +++ b/src/keepass2android/services/AutofillBase/StructureParser.cs @@ -29,7 +29,7 @@ namespace keepass2android.services.AutofillBase [JsonIgnore] public AssistStructure.ViewNode ViewNode { get; set; } - public void FillFilledAutofillValue(FilledAutofillField filledField) + public override void FillFilledAutofillValue(FilledAutofillField filledField) { AutofillValue autofillValue = ViewNode.AutofillValue; if (autofillValue != null) @@ -159,8 +159,12 @@ namespace keepass2android.services.AutofillBase protected override AutofillTargetId Parse(bool forFill, bool isManualRequest, AutofillView autofillView) { + if (autofillView == null) + Kp2aLog.Log("Received null autofill view!"); var result = base.Parse(forFill, isManualRequest, autofillView); + Kp2aLog.Log("Parsing done"); + if (forFill) { foreach (var p in FieldsMappedToHints) @@ -168,8 +172,9 @@ namespace keepass2android.services.AutofillBase } else { + ClientFormData = new FilledAutofillFieldCollection(); foreach (var p in FieldsMappedToHints) - ClientFormData.Add(new FilledAutofillField(p.Key, p.Value)); + ClientFormData.Add(new FilledAutofillField(p.Key, p.Value)); } diff --git a/src/keepass2android/services/Kp2aAutofill/ChooseForAutofillActivity.cs b/src/keepass2android/services/Kp2aAutofill/ChooseForAutofillActivity.cs index 9c4fbb21..49a9e893 100644 --- a/src/keepass2android/services/Kp2aAutofill/ChooseForAutofillActivity.cs +++ b/src/keepass2android/services/Kp2aAutofill/ChooseForAutofillActivity.cs @@ -61,8 +61,8 @@ namespace keepass2android.services.Kp2aAutofill foreach (string key in pwEntryOutput.OutputStrings.GetKeys()) { - FilledAutofillField field = - new FilledAutofillField + FilledAutofillField field = + new FilledAutofillField { AutofillHints = GetCanonicalHintsFromKp2aField(key).ToArray(), TextValue = pwEntryOutput.OutputStrings.ReadSafe(key) @@ -73,8 +73,8 @@ namespace keepass2android.services.Kp2aAutofill if (IsCreditCard(pwEntry, context) && pwEntry.Expires) { DateTime expTime = pwEntry.ExpiryTime; - FilledAutofillField field = - new FilledAutofillField + FilledAutofillField field = + new FilledAutofillField { AutofillHints = new[] {View.AutofillHintCreditCardExpirationDate}, DateValue = (long) (1000 * TimeUtil.SerializeUnix(expTime)) @@ -82,7 +82,7 @@ namespace keepass2android.services.Kp2aAutofill fieldCollection.Add(field); field = - new FilledAutofillField + new FilledAutofillField { AutofillHints = new[] {View.AutofillHintCreditCardExpirationDay}, TextValue = expTime.Day.ToString() @@ -90,7 +90,7 @@ namespace keepass2android.services.Kp2aAutofill fieldCollection.Add(field); field = - new FilledAutofillField + new FilledAutofillField { AutofillHints = new[] {View.AutofillHintCreditCardExpirationMonth}, TextValue = expTime.Month.ToString() @@ -98,7 +98,7 @@ namespace keepass2android.services.Kp2aAutofill fieldCollection.Add(field); field = - new FilledAutofillField + new FilledAutofillField { AutofillHints = new[] {View.AutofillHintCreditCardExpirationYear}, TextValue = expTime.Year.ToString() From ec5f26e0cd819cbe396759b3c2ef255742797860 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Sat, 18 Mar 2023 20:34:45 +0100 Subject: [PATCH 070/101] reduce log output --- .../java/keepass2android/kp2afilechooser/Kp2aFileProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java/android-filechooser-AS/app/src/main/java/keepass2android/kp2afilechooser/Kp2aFileProvider.java b/src/java/android-filechooser-AS/app/src/main/java/keepass2android/kp2afilechooser/Kp2aFileProvider.java index 8a2bca34..82e431c0 100644 --- a/src/java/android-filechooser-AS/app/src/main/java/keepass2android/kp2afilechooser/Kp2aFileProvider.java +++ b/src/java/android-filechooser-AS/app/src/main/java/keepass2android/kp2afilechooser/Kp2aFileProvider.java @@ -530,7 +530,7 @@ public abstract class Kp2aFileProvider extends BaseFileProvider { * parameters. */ private MatrixCursor doRetrieveFileInfo(Uri uri) { - Log.d(CLASSNAME, "retrieve file info "+uri.toString()); + MatrixCursor matrixCursor = BaseFileProviderUtils.newBaseFileCursor(); String filename = extractFile(uri); From d0da83182f0d1ac640c24e6916dd8bc2b6ad2de5 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Sun, 19 Mar 2023 10:01:25 +0100 Subject: [PATCH 071/101] manifest for 1.09e-r5 --- src/keepass2android/Properties/AndroidManifest_net.xml | 4 ++-- src/keepass2android/Properties/AndroidManifest_nonet.xml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/keepass2android/Properties/AndroidManifest_net.xml b/src/keepass2android/Properties/AndroidManifest_net.xml index 0c029336..c4ded48b 100644 --- a/src/keepass2android/Properties/AndroidManifest_net.xml +++ b/src/keepass2android/Properties/AndroidManifest_net.xml @@ -1,7 +1,7 @@  diff --git a/src/keepass2android/Properties/AndroidManifest_nonet.xml b/src/keepass2android/Properties/AndroidManifest_nonet.xml index 60700392..f72ab9bf 100644 --- a/src/keepass2android/Properties/AndroidManifest_nonet.xml +++ b/src/keepass2android/Properties/AndroidManifest_nonet.xml @@ -1,7 +1,7 @@  From a76c43a80061c34c4a5dc3a8d4660462fbf6ef11 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Sun, 19 Mar 2023 11:40:16 +0100 Subject: [PATCH 072/101] New translations strings.xml (Chinese Traditional) --- src/keepass2android/Resources/values-zh-rTW/strings.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/keepass2android/Resources/values-zh-rTW/strings.xml b/src/keepass2android/Resources/values-zh-rTW/strings.xml index 8f27c04e..6df7b4df 100644 --- a/src/keepass2android/Resources/values-zh-rTW/strings.xml +++ b/src/keepass2android/Resources/values-zh-rTW/strings.xml @@ -301,6 +301,8 @@ 不檢查域名是否符合應用程式包裹 整合到鍵盤 在鍵盤中內嵌自動填入建議選項 (如輸入法支援) + 記錄自動填入畫面 + 記下自動填入畫面的詳情到偵錯日誌(僅啟用時)。自動填入出錯時,可以發送這些詳情給開發者。 需要 Android 11 以上版本 查找密碼 排除過期的項目 @@ -690,7 +692,7 @@ 修正當機和意外登出的錯誤 切換成新 SFTP 實作,支援現代公鑰演算法,如 rsa-sha2-256 複製密碼到剪貼簿時設為機密 (Android 13) - Autofill improvements + 自動填入改進 支援查看、移除和還原項目備份 From 4cd32d30c6d6ca012badc9496e89b098e787e82b Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Mon, 20 Mar 2023 09:47:38 +0100 Subject: [PATCH 073/101] removing unused duplicated files --- .../Kp2aAutofillParser/AutofillParser.cs | 956 ------------------ .../Kp2aAutofillParser.csproj | 12 - 2 files changed, 968 deletions(-) delete mode 100644 src/keepass2android/services/Kp2aAutofillParser/AutofillParser.cs delete mode 100644 src/keepass2android/services/Kp2aAutofillParser/Kp2aAutofillParser.csproj diff --git a/src/keepass2android/services/Kp2aAutofillParser/AutofillParser.cs b/src/keepass2android/services/Kp2aAutofillParser/AutofillParser.cs deleted file mode 100644 index 2824d35b..00000000 --- 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 375762cd..00000000 --- a/src/keepass2android/services/Kp2aAutofillParser/Kp2aAutofillParser.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - - netstandard2.1 - enable - - - - - - - From 554f88c723c2b6cc8f27c8274b702d919988c2a8 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Mon, 20 Mar 2023 09:51:58 +0100 Subject: [PATCH 074/101] add make target "clean_rm" to remove build artifacts using rm. Created a new release based on this clean to see if it helps with #2263. --- Makefile | 12 ++++++++++++ .../Properties/AndroidManifest_net.xml | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 984172d4..eab24163 100644 --- a/Makefile +++ b/Makefile @@ -314,6 +314,18 @@ clean_KP2AKdbLibrary: cd src/java/KP2AKdbLibrary && $(GRADLEW) clean clean_PluginQR: cd src/java/PluginQR && $(GRADLEW) clean +clean_rm: + rm -rf src/*/obj + rm -rf src/*/bin + rm -rf src/java/*/app/build + rm -rf src/java/argon2/obj + rm -rf src/java/argon2/libs + rm -rf src/packages + rm -rf src/java/KP2AKdbLibrary/app/.cxx + rm -rf src/java/KP2ASoftkeyboard_AS/app/.cxx + rm -rf src/SamsungPass/Xamarin.SamsungPass/SamsungPass/bin + rm -rf src/SamsungPass/Xamarin.SamsungPass/SamsungPass/obj + # https://learn.microsoft.com/en-us/nuget/consume-packages/package-restore-troubleshooting#other-potential-conditions clean_nuget: diff --git a/src/keepass2android/Properties/AndroidManifest_net.xml b/src/keepass2android/Properties/AndroidManifest_net.xml index c4ded48b..1127ad33 100644 --- a/src/keepass2android/Properties/AndroidManifest_net.xml +++ b/src/keepass2android/Properties/AndroidManifest_net.xml @@ -1,7 +1,7 @@  From 230b3941e83e032d1e942a4c792429fa9132ce93 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Mon, 20 Mar 2023 12:42:13 +0100 Subject: [PATCH 075/101] New translations strings.xml (Japanese) --- src/keepass2android/Resources/values-ja/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keepass2android/Resources/values-ja/strings.xml b/src/keepass2android/Resources/values-ja/strings.xml index 05d93ff6..7aba0c84 100644 --- a/src/keepass2android/Resources/values-ja/strings.xml +++ b/src/keepass2android/Resources/values-ja/strings.xml @@ -690,7 +690,7 @@ クラッシュと突発的にログアウトするバグを修正 rsa-sha2-256 などの最新の公開鍵アルゴリズムをサポートする、新しい SFTP 実装に切り替え パスワードをクリップボードにコピーしたとき、機密コンテンツとしてマークするよう変更 (Android 13) - Autofill improvements + 自動入力の改善 エントリーバックアップの表示、削除、および復元に対応 From a6540b4462a81040d243b16057ca4907d8f55d0c Mon Sep 17 00:00:00 2001 From: PhilippC Date: Mon, 20 Mar 2023 13:56:48 +0100 Subject: [PATCH 076/101] New translations strings.xml (Japanese) --- src/keepass2android/Resources/values-ja/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/keepass2android/Resources/values-ja/strings.xml b/src/keepass2android/Resources/values-ja/strings.xml index 7aba0c84..80f23115 100644 --- a/src/keepass2android/Resources/values-ja/strings.xml +++ b/src/keepass2android/Resources/values-ja/strings.xml @@ -301,6 +301,8 @@ ドメインとアプリパッケージが一致するかどうかの確認を無効にします キーボードとの統合 自動入力のサジェストをキーボード内に表示します (対応する入力方法のみ) + 自動入力表示のログ + (デバッグログが有効な場合) 自動入力表示に関する詳細をデバッグログに書き込みます。自動入力が予想に反する動作をした場合、これらの詳細を開発者に送信することができます。 Android 11 以上が必要 パスワードを探す 期限切れのエントリーを除外する From 1e78527164c5fb3fa77e5f42af873a8af00b99ec Mon Sep 17 00:00:00 2001 From: PhilippC Date: Tue, 21 Mar 2023 00:17:53 +0100 Subject: [PATCH 077/101] New translations strings.xml (Italian) --- src/keepass2android/Resources/values-it/strings.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/keepass2android/Resources/values-it/strings.xml b/src/keepass2android/Resources/values-it/strings.xml index 89de6951..2851faf6 100644 --- a/src/keepass2android/Resources/values-it/strings.xml +++ b/src/keepass2android/Resources/values-it/strings.xml @@ -301,6 +301,8 @@ Disabilita il controllo se i pacchetti di dominio e applicazione corrispondono Integra con la tastiera Mostra i suggerimenti di completamento automatico come opzioni in linea sulla tastiera (se supportato dal metodo di inserimento) + Visualizza log autocompilazione + Scrivi i dettagli sulla visualizzazione del riempimento automatico per il log di debug (se il log di debug è abilitato). Questi dettagli possono essere inviati allo sviluppatore se il riempimento automatico non funziona come previsto. Richiede Android 11 o versioni successive Trova password Escludi voci scadute @@ -683,6 +685,12 @@ Ecco alcuni suggerimenti che ti potrebbero aiutare a diagnosticare il problema:\ Notifica per semplificare l\'accesso alla voce attualmente selezionata. Chiudi il database dopo tre tentativi di sblocco biometrici falliti. Attenzione! L\'autenticazione biometrica può essere invalidata da Android, ad es. dopo aver aggiunto una nuova impronta digitale nelle impostazioni del dispositivo. Assicurati di sapere sempre come sbloccare con la tua password principale! + + Correzione bug per crash e logout non previsti + Passa alla nuova implementazione SFTP, supportando moderni algoritmi a chiave pubblica come rsa-sha2-256 + Contrassegna le password come sensibili quando si copiano negli appunti (Android 13) + Migliorie Riempimento automatico + Aggiunto il supporto per la visualizzazione, la rimozione e il ripristino dei backup delle voci Implementato supporto per l\'archiviazione su cloud MEGA From ed7138991de02756981dffaf23309a2d45426749 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Tue, 21 Mar 2023 21:45:15 +0100 Subject: [PATCH 078/101] New translations strings.xml (German) --- src/keepass2android/Resources/values-de/strings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/keepass2android/Resources/values-de/strings.xml b/src/keepass2android/Resources/values-de/strings.xml index ef4975b1..efb1b49f 100644 --- a/src/keepass2android/Resources/values-de/strings.xml +++ b/src/keepass2android/Resources/values-de/strings.xml @@ -529,7 +529,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Ordner der Keepass2Android-App SFTP (SSH File Transfer) MEGA - Bitte beachten: Keepass2Android muss die Liste aller Dateien des Mega-Konto herunterladen, um ordnungsgemäß zu funktionieren. Aus diesem Grund ist der Zugriff auf Konten mit vielen Dateien möglicherweise langsam. + Bitte beachte: Keepass2Android muss eineListe aller Dateien des Mega-Kontos herunterladen, um ordnungsgemäß zu funktionieren. Aus diesem Grund ist der Zugriff auf Konten mit vielen Dateien möglicherweise langsam. Android-Dateibrowser Dateizugriff initialisieren Speicherort der Datenbank @@ -1070,8 +1070,8 @@ Erstes öffentliches Release Keepass2Android hat biometrische Hardware erkannt. Soll Biometrisches Entsperren für diese Datenbank aktiviert werden? Okay, verstanden Nicht erneut anzeigen - Ist das Hauptpasswort bekannt? - Bitte beachten, dass die Datenbank ohne den Hauptschlüssel nicht geöffnet werden kann. Es gibt keine Möglichkeit, das Hauptpasswort „zurückzusetzen“. + Kennst du dein Master-Passwort? + Bitte beachte, dass du deine Datenbank ohne den Hauptschlüssel nicht öffnen kannst. Es gibt keine Möglichkeit, das Hauptpasswort „zurückzusetzen“. Bitte auch bedenken, dass das Biometrische Entsperren über das Speichern des Hauptschlüssels im sicheren Speicher von Android funktioniert. Dieser Speicher kann von Android jederzeit gelöscht werden, z. B. wenn ein neuer Fingerabdruck in den Systemeinstellungen hinzugefügt wird. Daher sich nicht auf das biometrische Entsperren verlassen, sondern sich bitte das eigene Hauptpasswort merken! Gibt es eine Sicherung der Datenbank? Keepass2Android speichert die Passwörter in einer Datei an einem frei wählbarem Speicherort.Ist sichergestellt, dass die Datei auch dann noch verfügbar ist, wenn das Telefon verloren geht oder gestohlen wird, oder wenn die Datei zerstört oder gelöscht wird? Bitte sicherstellen, dass immer eine aktuelle Kopie an einem sichern Ort aufbewahrt wird! From 984da3fd3bec803a44b65ab047d68a56451acc30 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Wed, 22 Mar 2023 09:53:14 +0100 Subject: [PATCH 079/101] New translations strings.xml (Greek) --- src/keepass2android/Resources/values-el/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keepass2android/Resources/values-el/strings.xml b/src/keepass2android/Resources/values-el/strings.xml index dff0b0f5..208d2f96 100644 --- a/src/keepass2android/Resources/values-el/strings.xml +++ b/src/keepass2android/Resources/values-el/strings.xml @@ -688,7 +688,7 @@ Διόρθωση σφάλματος για απότομα κλεισίματα εφαρμογής και μη αναμενόμενες αποσυνδέσεις Μετάβαση σε νέα υλοποίηση SFTP, υποστηρίζοντας σύγχρονους αλγόριθμους δημόσιου κλειδιού όπως rsa-sha2-256 Μαρκάρισμα κωδικών πρόσβασης ως ευαίσθητοι κατά την αντιγραφή στο πρόχειρο (Android 13) - Autofill improvements + Βελτιώσεις Autofill Υποστηρίζεται πλέον προβολή, διαγραφή και ανάκτηση των διαγραμμένων εγγραφών From 38f1aa4d3dcc4cb5dc558fe29f56a3920a06b1e7 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Wed, 22 Mar 2023 10:59:34 +0100 Subject: [PATCH 080/101] New translations strings.xml (Greek) --- src/keepass2android/Resources/values-el/strings.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/keepass2android/Resources/values-el/strings.xml b/src/keepass2android/Resources/values-el/strings.xml index 208d2f96..236a0b03 100644 --- a/src/keepass2android/Resources/values-el/strings.xml +++ b/src/keepass2android/Resources/values-el/strings.xml @@ -332,7 +332,7 @@ Απόκρυψη μήκους QuickUnlock Αν ενεργοποιηθεί, αποκρύπτει το μήκος του κωδικού QuickUnlock στη σχετική οθόνη. Κλειδί QuickUnlock από τη βάση δεδομένων - Εάν η ενεργή βάση δεδομένων περιέχει μια καταχώρηση με τίτλο QuickUnlock στην ομάδα ρίζας της, ο κωδικός πρόσβασης αυτής της καταχώρησης χρησιμοποιείται ως κωδικός QuickUnlock. + Εάν η ενεργή βάση δεδομένων περιέχει μια καταχώριση με τίτλο QuickUnlock στην ομάδα ρίζας της, ο κωδικός πρόσβασης αυτής της καταχώρισης χρησιμοποιείται ως κωδικός QuickUnlock. Αποτυχία QuickUnlock: λανθασμένο συνθηματικό! Αποθήκευση συνημμένου Επιλέξτε πού θα αποθηκεύσετε το συνημμένο. @@ -429,7 +429,7 @@ Μετονομασία Απέτυχε η προσθήκη του συνημμένου αρχείου. Κάδος ανακύκλωσης - Θέλετε να διαγράψετε οριστικά αυτή την καταχώριση; Πατήστε όχι για να ανακύκλωση. + Θέλετε να διαγράψετε οριστικά αυτή την καταχώριση; Πατήστε όχι για ανακύκλωση. Θέλετε να διαγράψετε οριστικά αυτή την ομάδα; Πατήστε όχι για ανακύκλωση. Θέλετε να διαγράψετε οριστικά τα επιλεγμένα στοιχεία; Πατήστε όχι για ανακύκλωση. Θέλετε να διαγράψετε οριστικά αυτή την καταχώριση; @@ -542,7 +542,7 @@ Η βάση δεδομένων είναι κρυπτογραφημένη με το συνθηματικό που εισάγετε εδώ. Επιλέξτε ένα ισχυρό συνθηματικό προκειμένου να διατηρείτε τη βάση δεδομένων ασφαλή! Συμβουλή: Συνθέστε μια-δυο φράσεις και χρησιμοποιήστε τα πρώτα γράμματα των λέξεων ως συνθηματικό. Συμπεριλάβετε σημεία στίξης. Επιλέξτε κύριο συνθηματικό για την προστασία της βάσης δεδομένων: Αρχείο κλειδιού - Το αρχείο κλειδιού είναι βασικά ένα συνθηματικό αποθηκευμένο σε ένα αρχείο. Τα αρχείο κλειδιού είναισυνήθως ισχυρότερα από τα κύρια συνθηματικά, γιατί το κλειδί μπορεί να είναι πιο σύνθετο, ωστόσο είναι ε΄πίσης δυσκολότερο να διατηρηθούν μυστικά. Αν αποθηκεύεις τη βάση δεδομένων στο σύννεφο, μην αποθηκεύσεις και το αρχείο κλειδί εκεί! Αυτό θα το έκανε εντελώς άχρηστο! Σημαντικό: Μην αλλάζετε τα περιεχόμενο του αρχείου κλειδιού αφού δημιουργηθεί η βάση δεδομένων! + Το αρχείο κλειδιού είναι βασικά ένα συνθηματικό αποθηκευμένο σε ένα αρχείο. Τα αρχεία κλειδιού είναι συνήθως ισχυρότερα από τα κύρια συνθηματικά, γιατί το κλειδί μπορεί να είναι πιο σύνθετο, ωστόσο είναι επίσης δυσκολότερο να διατηρηθούν μυστικά. Αν αποθηκεύεις τη βάση δεδομένων στο σύννεφο, μην αποθηκεύσεις και το αρχείο κλειδιού εκεί! Αυτό θα το έκανε εντελώς άχρηστο! Σημαντικό: Μην αλλάζετε τα περιεχόμενο του αρχείου κλειδιού αφού δημιουργηθεί η βάση δεδομένων! Επιλέξτε αν θέλετε να χρησιμοποιήσετε ένα αρχείο κλειδιού, εκτός από το κύριο συνθηματικό: Χρήση αρχείου κλειδιού Παρουσιάστηκε σφάλμα κατά την προσθήκη του αρχείου κλειδιού! @@ -572,9 +572,9 @@ Όνομα πεδίου στις ρυθμίσεις TOTP Εισάγετε όνομα πεδίου από ρυθμίσεις TrayTotp. TrayTotp - Αρχείο καταχώρησης για αποσφαλματοποίηση - Χρήση αρχείου καταχώρησης - Καταγραφή στοιχείων εφαρμογής σε τοπικό αρχείο καταχώρησης + Αρχείο καταγραφών για αποσφαλμάτωση + Χρήση αρχείου καταγραφών + Καταγραφή στοιχείων της εφαρμογής σε τοπικό αρχείο καταγραφών Αποστολή αρχείων καταγραφής εκσφαλμάτωσης... Φόρτωση… Πρόσθετα From 8596edaa670db697359c41b93abcb07504384f9c Mon Sep 17 00:00:00 2001 From: PhilippC Date: Wed, 22 Mar 2023 10:59:35 +0100 Subject: [PATCH 081/101] New translations strings.xml (Greek) --- .../app/src/main/res/values-el/strings.xml | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/java/KP2ASoftkeyboard_AS/app/src/main/res/values-el/strings.xml b/src/java/KP2ASoftkeyboard_AS/app/src/main/res/values-el/strings.xml index bed2a7b0..a148bcb0 100644 --- a/src/java/KP2ASoftkeyboard_AS/app/src/main/res/values-el/strings.xml +++ b/src/java/KP2ASoftkeyboard_AS/app/src/main/res/values-el/strings.xml @@ -21,7 +21,7 @@ Πληκτρολόγιο Keepass2Android - Ρυθμίσεις πληκτρολογίου Keepass2Android + Ρυθμίσεις πληκτρολογίου Android Επιλογές εισόδου @@ -51,7 +51,7 @@ Αυτόματη συμπλήρωση - Αυξήστε το μέγεθος του πεδίου κειμένου + Αύξηση μεγέθους του πεδίου κειμένου Απόκρυψη υποδείξεων λέξεων στην οριζόντια προβολή @@ -77,7 +77,7 @@ Εμφάνιση πλήκτρου ρυθμίσεων - Αυτόματο + Αυτόματα Να εμφανίζεται πάντα @@ -110,25 +110,25 @@ Πρόσβαση σε αριθμούς και σύμβολα - Κρατήστε πατημένη τη λέξη στην άκρη αριστερά, για να την προσθέσετε στο λεξικό + Παρατεταμένη επιλογή της λέξης στα αριστερά, την προσθέτει στο λεξικό - Αγγίξτε αυτή τη συμβουλή για να συνεχίσετε » + Αγγίξτε αυτή την υπόδειξη για να συνεχίσετε » - Αγγίξτε εδώ για να κλείσετε τη συμβουλή και να ξεκινήσετε την πληκτρολόγηση! + Αγγίξτε εδώ για να κλείσετε την υπόδειξη και να ξεκινήσετε την πληκτρολόγηση! - \"Το πληκτρολόγιο ανοίγει κάθε φορά που αγγίζετε ένα πεδίο κειμένου\" + Το πληκτρολόγιο ανοίγει κάθε φορά που αγγίζετε ένα πεδίο κειμένου \"Αγγίξτε και κρατήστε κάποιο πλήκτρο για να προβάλετε τους τονισμένους χαρακτήρες\"\n\"(ø, ö, ô, ó κ.τ.λ.)\" - \"Αλλαγή σε αριθμούς και σύμβολα με το πάτημα αυτού του πλήκτρου\" + Αλλαγή σε αριθμούς και σύμβολα με το πάτημα αυτού του πλήκτρου - \"Επιστρέψτε στα γράμματα αγγίζοντας ξανά αυτό το πλήκτρο\" + Επιστρέψτε στα γράμματα αγγίζοντας ξανά αυτό το πλήκτρο - \"Αγγίξτε και κρατήστε πατημένο αυτό το πληκτρολόγιο για να αλλάξετε τις ρυθμίσεις πληκτρολογίου, όπως η αυτόματη συμπλήρωση\" + Αγγίξτε και κρατήστε πατημένο αυτό το πλήκτρο για να αλλάξετε τις ρυθμίσεις πληκτρολογίου, όπως η αυτόματη συμπλήρωση - \"Δοκιμάστε το!\" + Δοκιμάστε το! - Μετ. + Μετάβαση Επόμενο From 1e90a522757ec4e7c3bddd7daab0c4b771208d9b Mon Sep 17 00:00:00 2001 From: PhilippC Date: Wed, 22 Mar 2023 21:15:28 +0100 Subject: [PATCH 082/101] New translations strings.xml (Ukrainian) --- src/keepass2android/Resources/values-uk/strings.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/keepass2android/Resources/values-uk/strings.xml b/src/keepass2android/Resources/values-uk/strings.xml index 17e0dfbd..b4869d84 100644 --- a/src/keepass2android/Resources/values-uk/strings.xml +++ b/src/keepass2android/Resources/values-uk/strings.xml @@ -301,6 +301,7 @@ Вимкнення перевірки, якщо збігаються домен і пакунок програми Інтегрувати до клавіатури Показує пропозиції автозаповнення як вбудовану опцію в клавіатурі (якщо підтримується методом вводу) + Перегляд журналу автозаповнення Потрібна версія Android 11 або новіша Знайти пароль Виключити прострочені елементи @@ -690,7 +691,7 @@ Виправлено помилку зі збоями та несподіваними виходами Перехід на нову реалізацію SFTP з підтримкою сучасних алгоритмів публічного ключа, як-от rsa-sha2-256 Позначати паролі як вразливі під час копіювання до буфера обміну (Android 13) - Autofill improvements + Вдосконалене автозаповнення Додано підтримку перегляду, видалення та відновлення резервних копій записів From 40d3fe1cd94d0735b2363973fb7be1d8d7af37d4 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Wed, 22 Mar 2023 22:56:58 +0100 Subject: [PATCH 083/101] New translations strings.xml (Ukrainian) --- src/keepass2android/Resources/values-uk/strings.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/keepass2android/Resources/values-uk/strings.xml b/src/keepass2android/Resources/values-uk/strings.xml index b4869d84..74531af0 100644 --- a/src/keepass2android/Resources/values-uk/strings.xml +++ b/src/keepass2android/Resources/values-uk/strings.xml @@ -301,7 +301,8 @@ Вимкнення перевірки, якщо збігаються домен і пакунок програми Інтегрувати до клавіатури Показує пропозиції автозаповнення як вбудовану опцію в клавіатурі (якщо підтримується методом вводу) - Перегляд журналу автозаповнення + Журнал перегляду автозаповнення + Записувати подробиці про перегляд автозаповнення до журналу зневадження (якщо увімкнено журнал зневадження). Ці подробиці можна надсилати розробникам, якщо автозаповнення працює некоректно. Потрібна версія Android 11 або новіша Знайти пароль Виключити прострочені елементи From cf222a2db1c2418db9d65c3d79f3b9bba04a707d Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Fri, 31 Mar 2023 07:59:34 +0200 Subject: [PATCH 084/101] remove Flavor from build-properties, adjust Manifest for debug build --- src/build-properties.props | 2 +- .../Properties/AndroidManifest_debug.xml | 21 ++++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/build-properties.props b/src/build-properties.props index 8dc23bd2..23d8641a 100644 --- a/src/build-properties.props +++ b/src/build-properties.props @@ -2,7 +2,7 @@ -NoNet +Net diff --git a/src/keepass2android/Properties/AndroidManifest_debug.xml b/src/keepass2android/Properties/AndroidManifest_debug.xml index 4b1a92f2..873fdc32 100644 --- a/src/keepass2android/Properties/AndroidManifest_debug.xml +++ b/src/keepass2android/Properties/AndroidManifest_debug.xml @@ -43,7 +43,7 @@ - + - + @@ -63,7 +63,7 @@ - + @@ -83,13 +83,13 @@ - + - + @@ -99,7 +99,8 @@ + android:label="@string/language_selection_title" + android:exported="true" > @@ -107,7 +108,7 @@ - + @@ -252,13 +253,13 @@ The scheme=file is still there for old OS devices. It's also queried by apps lik - - + + - + From 4910c73a5e006a23721f5d98052c0e478f6cdaec Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Fri, 31 Mar 2023 08:00:44 +0200 Subject: [PATCH 085/101] fix to potential crash when reloading database --- src/keepass2android/app/App.cs | 34 ++++++++++++++++-------- src/keepass2android/views/PwGroupView.cs | 11 +++++--- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/keepass2android/app/App.cs b/src/keepass2android/app/App.cs index 19f05407..81b0aa7d 100644 --- a/src/keepass2android/app/App.cs +++ b/src/keepass2android/app/App.cs @@ -475,22 +475,26 @@ namespace keepass2android builder.SetMessage(activity.GetString(Resource.String.AskReloadFile)); - builder.SetPositiveButton(activity.GetString(Android.Resource.String.Yes), + bool buttonPressed = false; + + builder.SetPositiveButton(activity.GetString(Android.Resource.String.Yes), (dlgSender, dlgEvt) => - { + { + buttonPressed = true; CurrentDb.ReloadRequested = true; activity.SetResult(KeePass.ExitReloadDb); activity.Finish(); if (actionOnResult != null) - { - actionOnResult(true); - actionOnResult = null; + { + actionOnResult(true); + actionOnResult = null; } }); builder.SetNegativeButton(activity.GetString(Android.Resource.String.No), (dlgSender, dlgEvt) => - { - if (actionOnResult != null) + { + buttonPressed = true; + if (actionOnResult != null) { actionOnResult(false); actionOnResult = null; @@ -501,10 +505,18 @@ namespace keepass2android Dialog dialog = builder.Create(); dialog.SetOnDismissListener(new Util.DismissListener(() => - { - if (actionOnResult != null) - actionOnResult(false); - })); + { + //dismiss can be called when we're calling activity.Finish() during button press. + //don't do anything then. + if (buttonPressed) + return; + + if (actionOnResult != null) + { + actionOnResult(false); + actionOnResult = null; + } + })); dialog.Show(); } diff --git a/src/keepass2android/views/PwGroupView.cs b/src/keepass2android/views/PwGroupView.cs index 832c9f33..bb281fd5 100644 --- a/src/keepass2android/views/PwGroupView.cs +++ b/src/keepass2android/views/PwGroupView.cs @@ -77,10 +77,15 @@ namespace keepass2android.view AddView(gv, lp); } - private void PopulateView(View gv, PwGroup pw) { + private void PopulateView(View gv, PwGroup pw) + { _pwGroup = pw; - - ImageView iv = (ImageView) gv.FindViewById(Resource.Id.icon); + Kp2aLog.Log($"Populating group view {_groupBaseActivity.IsFinishing} {pw.Name}"); + + if (_groupBaseActivity.IsFinishing) + return; + + ImageView iv = (ImageView) gv.FindViewById(Resource.Id.icon); Database db = App.Kp2a.FindDatabaseForElement(pw); db.DrawableFactory.AssignDrawableTo(iv, _groupBaseActivity, db.KpDatabase, pw.IconId, pw.CustomIconUuid, true); gv.FindViewById(Resource.Id.icon).Visibility = ViewStates.Visible; From 9933fa1f9daa528a90d250526e946bf5eacd5e20 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Fri, 31 Mar 2023 08:01:10 +0200 Subject: [PATCH 086/101] fix to potential crash in Autofill. Couldn't add a test yet, still waiting for corresponding Autofill structure. --- src/Kp2aAutofillParser/AutofillParser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kp2aAutofillParser/AutofillParser.cs b/src/Kp2aAutofillParser/AutofillParser.cs index 89b58b72..fe1cc823 100644 --- a/src/Kp2aAutofillParser/AutofillParser.cs +++ b/src/Kp2aAutofillParser/AutofillParser.cs @@ -973,7 +973,7 @@ namespace Kp2aAutofillParser || IsInputTypeVariation(inputType, InputTypes.TextVariationWebPassword) ) ) - || (f.AutofillHints != null && f.AutofillHints.First() == "passwordAuto") + || (f.AutofillHints != null && f.AutofillHints.FirstOrDefault() == "passwordAuto") || (f.HtmlInfoTypeAttribute == "password") ); } From 94ede3a6965d686c1e6b22b3727bb71e224b59e9 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Fri, 31 Mar 2023 08:01:25 +0200 Subject: [PATCH 087/101] output current Configuration during build --- src/keepass2android/keepass2android-app.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keepass2android/keepass2android-app.csproj b/src/keepass2android/keepass2android-app.csproj index 522e0e33..07af894c 100644 --- a/src/keepass2android/keepass2android-app.csproj +++ b/src/keepass2android/keepass2android-app.csproj @@ -1,7 +1,7 @@  - + From 0502efde14be17f1273a4a5cbb78d6eb18febd6f Mon Sep 17 00:00:00 2001 From: PhilippC Date: Sun, 2 Apr 2023 09:00:39 +0200 Subject: [PATCH 088/101] New translations strings.xml (Dutch) --- src/keepass2android/Resources/values-nl/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keepass2android/Resources/values-nl/strings.xml b/src/keepass2android/Resources/values-nl/strings.xml index 65d1b352..3dafe7b0 100644 --- a/src/keepass2android/Resources/values-nl/strings.xml +++ b/src/keepass2android/Resources/values-nl/strings.xml @@ -301,6 +301,7 @@ Schakelt controle of domein en app pakket overeenkomen uit Integreer met toetsenbord Toont de suggesties voor automatisch aanvullen als inline-opties in het toetsenbord (indien ondersteund door de invoermethode) + Automatisch invullen loggen Vereist Android 11 of hoger Zoek wachtwoord Verlopen items uitsluiten From 8aacdf683bb48f495c796fa824e84ea759f469a8 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Sun, 2 Apr 2023 10:10:05 +0200 Subject: [PATCH 089/101] New translations strings.xml (Dutch) --- src/keepass2android/Resources/values-nl/strings.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/keepass2android/Resources/values-nl/strings.xml b/src/keepass2android/Resources/values-nl/strings.xml index 3dafe7b0..37331b86 100644 --- a/src/keepass2android/Resources/values-nl/strings.xml +++ b/src/keepass2android/Resources/values-nl/strings.xml @@ -302,6 +302,7 @@ Integreer met toetsenbord Toont de suggesties voor automatisch aanvullen als inline-opties in het toetsenbord (indien ondersteund door de invoermethode) Automatisch invullen loggen + Schrijf details over de autofill weergave naar debug log (als debug logging is ingeschakeld). Deze details kunnen naar de ontwikkelaar worden verzonden als het automatisch invullen niet werkt zoals verwacht. Vereist Android 11 of hoger Zoek wachtwoord Verlopen items uitsluiten @@ -688,6 +689,12 @@ Melding voor vereenvoudigde toegang van het nu geselecteerde item. Sluit de database na drie mislukte biometrische ontgrendelpogingen. Waarschuwing! Biometrische authenticatie wordt uitgeschakeld door Android, bijv. na het toevoegen van een nieuwe vingerafdruk in de instellingen van jouw apparaat. Zorg ervoor dat je de database altijd kunt ontgrendelen met het hoofdwachtwoord! + + Bug fix op crashes en onverwachte log-outs + Schakel over naar nieuwe SFTP-implementatie ter ondersteuning van moderne publieke sleutel algoritmen zoals rsa-sha2-256 + Wachtwoorden als gevoelig markeren bij het kopiëren naar klembord (Android 13) + Autofill verbeteringen + Toegevoegde ondersteuning voor het bekijken, verwijderen en herstellen van invoer back-ups Implementatie ondersteuning voor MEGA cloud opslag From a05ef51d44bcaac4f962da3eb1abab7935b4a496 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Mon, 3 Apr 2023 10:08:32 +0200 Subject: [PATCH 090/101] New translations strings.xml (Japanese) --- src/keepass2android/Resources/values-ja/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keepass2android/Resources/values-ja/strings.xml b/src/keepass2android/Resources/values-ja/strings.xml index 80f23115..3cd8c640 100644 --- a/src/keepass2android/Resources/values-ja/strings.xml +++ b/src/keepass2android/Resources/values-ja/strings.xml @@ -36,7 +36,7 @@ アカウント情報の保存を提案 エントリー画面にグループ名を表示 申し訳ありません! Keepass2Android は、返された URI %1$s を処理できませんでした。開発者にお問い合わせください! - 1 エントリー + 1 件のエントリー %1$d 件のエントリー アイコンセット さらに探す… From e101ffb01e33266c7f872608eaae6d6fa552c073 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Fri, 7 Apr 2023 08:10:10 +0200 Subject: [PATCH 091/101] add regression test for the crash fixed in 9933fa1f9daa528a90d250526e946bf5eacd5e20 --- src/Kp2aAutofillParserTest/AutofillTest.cs | 9 +- .../Kp2aAutofillParserTest.csproj | 4 + src/Kp2aAutofillParserTest/imdb.json | 728 ++++++++++++++++++ 3 files changed, 740 insertions(+), 1 deletion(-) create mode 100644 src/Kp2aAutofillParserTest/imdb.json diff --git a/src/Kp2aAutofillParserTest/AutofillTest.cs b/src/Kp2aAutofillParserTest/AutofillTest.cs index 3449feb7..80c15003 100644 --- a/src/Kp2aAutofillParserTest/AutofillTest.cs +++ b/src/Kp2aAutofillParserTest/AutofillTest.cs @@ -30,11 +30,18 @@ namespace Kp2aAutofillParserTest RunTestFromAutofillInput(resourceName, "com.servicenet.mobile"); } + [Fact] + public void TestCrashRegressionEmptySequence() + { + var resourceName = "Kp2aAutofillParserTest.imdb.json"; + RunTestFromAutofillInput(resourceName, "com.vivaldi.browser", "m.imdb.com"); + } + [Fact] public void TestFocusedPasswordAutoIsFilled() { var resourceName = "Kp2aAutofillParserTest.com-servicenet-mobile-focused.json"; - RunTestFromAutofillInput(resourceName, "com.servicenet.mobile" ); + RunTestFromAutofillInput(resourceName, "com.servicenet.mobile"); } [Fact] diff --git a/src/Kp2aAutofillParserTest/Kp2aAutofillParserTest.csproj b/src/Kp2aAutofillParserTest/Kp2aAutofillParserTest.csproj index 0a1ab633..d702da41 100644 --- a/src/Kp2aAutofillParserTest/Kp2aAutofillParserTest.csproj +++ b/src/Kp2aAutofillParserTest/Kp2aAutofillParserTest.csproj @@ -15,6 +15,7 @@ + @@ -53,6 +54,9 @@ PreserveNewest + + PreserveNewest + diff --git a/src/Kp2aAutofillParserTest/imdb.json b/src/Kp2aAutofillParserTest/imdb.json new file mode 100644 index 00000000..7c9459dc --- /dev/null +++ b/src/Kp2aAutofillParserTest/imdb.json @@ -0,0 +1,728 @@ +{ + "InputFields": [ + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "action_bar_root", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "custom_tabs_handle_view_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "coordinator", + "Hint": null, + "ClassName": "android.view.ViewGroup", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "compositor_view_holder", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": true, + "InputType": 0, + "HtmlInfoTag": "form", + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": "", + "ClassName": null, + "AutofillHints": [], + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": "input", + "HtmlInfoTypeAttribute": "checkbox" + }, + { + "IdEntry": null, + "Hint": "Search IMDb", + "ClassName": null, + "AutofillHints": [ + "off" + ], + "IsFocused": true, + "InputType": 0, + "HtmlInfoTag": "input", + "HtmlInfoTypeAttribute": "text" + }, + { + "IdEntry": "main_tab_switcher", + "Hint": null, + "ClassName": "android.widget.RelativeLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "ar_view_holder", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "capture_overlay", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "overview_list_layout_holder", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "bottom_container", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "keyboard_accessory_sheet_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "bottombar_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "tab_modal_dialog_container_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "tab_modal_dialog_container_sibling_view", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "omnibox_results_container_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "panel_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "search_engine_suggestion_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "action_bar_black_background", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "bottom_controls", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "bottom_controls_wrapper", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "tab_group_ui_bottom_container", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "tab_group_ui_toolbar_view", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "bottom_container_slot", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "bottom_toolbar", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "bottom_toolbar_browsing", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "tab_switcher_tab_layout_toggle", + "Hint": null, + "ClassName": "android.widget.RelativeLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "tab_switcher_tab_layout", + "Hint": null, + "ClassName": "android.widget.HorizontalScrollView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": null, + "Hint": null, + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "control_container", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "find_toolbar_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "find_toolbar_tablet_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "toolbar_container", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "tab_group_ui_top_container", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "toolbar", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "location_bar", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "location_bar_status_view_left_space", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "location_bar_status", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "location_bar_incognito_badge_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "location_bar_status_icon_view", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "location_bar_status_icon_frame", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "location_bar_status_icon_bg", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "location_bar_status_icon_holding_space", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "location_bar_verbose_status", + "Hint": null, + "ClassName": "android.widget.TextView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "location_bar_verbose_status_separator", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "location_bar_verbose_status_extra_space", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "location_bar_status_view_right_space", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "url_action_container", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "toolbar_buttons", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "optional_button_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "menu_button_wrapper", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "tab_switcher_toolbar_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "bottom_toolbar_tab_switcher_mode", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "grid_tab_switcher_view_holder_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "message_container", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "status_indicator_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "empty_container_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "sheet_container", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "survey_container", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "page_zoom_container", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "dialog_parent_view", + "Hint": null, + "ClassName": "android.widget.FrameLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "keyboard_accessory", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "accessory_bar_contents", + "Hint": null, + "ClassName": "android.widget.LinearLayout", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "tabs", + "Hint": null, + "ClassName": "android.widget.HorizontalScrollView", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "menu_anchor_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "navigation_popup_anchor_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + }, + { + "IdEntry": "action_mode_bar_stub", + "Hint": null, + "ClassName": "android.view.View", + "AutofillHints": null, + "IsFocused": false, + "InputType": 0, + "HtmlInfoTag": null, + "HtmlInfoTypeAttribute": null + } + ], + "PackageId": "com.vivaldi.browser", + "WebDomain": "m.imdb.com" +} From badf99c20d941075de47e19fa345b80f4d3233db Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Fri, 7 Apr 2023 10:05:22 +0200 Subject: [PATCH 092/101] Manifest for 1.09e-r6 --- src/keepass2android/Properties/AndroidManifest_net.xml | 6 +++--- src/keepass2android/Properties/AndroidManifest_nonet.xml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/keepass2android/Properties/AndroidManifest_net.xml b/src/keepass2android/Properties/AndroidManifest_net.xml index 1127ad33..86fe3024 100644 --- a/src/keepass2android/Properties/AndroidManifest_net.xml +++ b/src/keepass2android/Properties/AndroidManifest_net.xml @@ -1,7 +1,7 @@  @@ -103,8 +103,8 @@ + android:label="@string/language_selection_title" diff --git a/src/keepass2android/Properties/AndroidManifest_nonet.xml b/src/keepass2android/Properties/AndroidManifest_nonet.xml index f72ab9bf..75e8830a 100644 --- a/src/keepass2android/Properties/AndroidManifest_nonet.xml +++ b/src/keepass2android/Properties/AndroidManifest_nonet.xml @@ -1,7 +1,7 @@  From b3a73f20d4f9b5a3eb4afaf8fc1d5360ffd5e70a Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Sat, 8 Apr 2023 08:25:09 +0200 Subject: [PATCH 093/101] fix to potential crash when reloading the database. related to 4910c73a5e006a23721f5d98052c0e478f6cdaec --- src/keepass2android/views/PwEntryView.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/keepass2android/views/PwEntryView.cs b/src/keepass2android/views/PwEntryView.cs index 85fa44f8..91ad7a2a 100644 --- a/src/keepass2android/views/PwEntryView.cs +++ b/src/keepass2android/views/PwEntryView.cs @@ -67,8 +67,8 @@ namespace keepass2android.view private PwEntryView(GroupBaseActivity groupActivity, PwEntry pw, int pos):base(groupActivity) { _groupActivity = groupActivity; - - View ev = Inflate(groupActivity, Resource.Layout.entry_list_entry, null); + + View ev = Inflate(groupActivity, Resource.Layout.entry_list_entry, null); _textView = (TextView)ev.FindViewById(Resource.Id.entry_text); _textView.TextSize = PrefsUtil.GetListTextSize(groupActivity); @@ -103,7 +103,11 @@ namespace keepass2android.view private void PopulateView(View ev, PwEntry pw, int pos) { - _entry = pw; + + if (_groupBaseActivity.IsFinishing) + return; + + _entry = pw; _pos = pos; ev.FindViewById(Resource.Id.icon).Visibility = ViewStates.Visible; ev.FindViewById(Resource.Id.check_mark).Visibility = ViewStates.Invisible; From 5cbddb4fccc65cda255004ee18d05acc874bab9b Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Sat, 8 Apr 2023 08:30:36 +0200 Subject: [PATCH 094/101] explicitly remove READ_PHONE_STATE permission to close #2300; manifest for 1.09e-r7 --- src/keepass2android/Properties/AndroidManifest_net.xml | 6 +++--- src/keepass2android/Properties/AndroidManifest_nonet.xml | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/keepass2android/Properties/AndroidManifest_net.xml b/src/keepass2android/Properties/AndroidManifest_net.xml index 86fe3024..f79550f7 100644 --- a/src/keepass2android/Properties/AndroidManifest_net.xml +++ b/src/keepass2android/Properties/AndroidManifest_net.xml @@ -1,7 +1,7 @@  @@ -272,5 +272,5 @@ The scheme=file is still there for old OS devices. It's also queried by apps lik - + diff --git a/src/keepass2android/Properties/AndroidManifest_nonet.xml b/src/keepass2android/Properties/AndroidManifest_nonet.xml index 75e8830a..f6726a5f 100644 --- a/src/keepass2android/Properties/AndroidManifest_nonet.xml +++ b/src/keepass2android/Properties/AndroidManifest_nonet.xml @@ -1,7 +1,7 @@  @@ -246,5 +246,6 @@ The scheme=file is still there for old OS devices. It's also queried by apps lik + From 1efe2e16a5e211116102b46fca8e837e9ce9bcb4 Mon Sep 17 00:00:00 2001 From: Robert Ellegate Date: Sat, 8 Apr 2023 13:37:07 -0400 Subject: [PATCH 095/101] =?UTF-8?q?=F0=9F=93=9D=20chore(github):=20add=20i?= =?UTF-8?q?ssue=20templates=20for=20bug=20report,=20feature=20request,=20a?= =?UTF-8?q?nd=20question=20The=20issue=20templates=20for=20bug=20report,?= =?UTF-8?q?=20feature=20request,=20and=20question=20have=20been=20added=20?= =?UTF-8?q?to=20the=20`.github/ISSUE=5FTEMPLATE`=20directory.=20These=20te?= =?UTF-8?q?mplates=20will=20help=20standardize=20the=20information=20provi?= =?UTF-8?q?ded=20in=20issues=20and=20make=20it=20easier=20for=20contributo?= =?UTF-8?q?rs=20to=20provide=20the=20necessary=20information.=20The=20bug?= =?UTF-8?q?=20report=20template=20includes=20checkboxes=20to=20ensure=20th?= =?UTF-8?q?at=20the=20FAQ=20has=20been=20checked=20and=20open=20issues=20h?= =?UTF-8?q?ave=20been=20searched=20before=20submitting=20a=20new=20bug=20r?= =?UTF-8?q?eport.=20The=20feature=20request=20template=20is=20a=20simple?= =?UTF-8?q?=20template=20for=20suggesting=20new=20ideas=20for=20the=20proj?= =?UTF-8?q?ect.=20The=20question=20template=20asks=20for=20the=20version?= =?UTF-8?q?=20of=20Keepass2Android=20being=20used=20to=20help=20with=20tro?= =?UTF-8?q?ubleshooting.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/ISSUE_TEMPLATE/bug_report.yaml | 49 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 8 ++++ .github/ISSUE_TEMPLATE/question.md | 16 ++++++++ 3 files changed, 73 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yaml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/question.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml new file mode 100644 index 00000000..224c50a1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -0,0 +1,49 @@ +name: Bug Report +description: Report a bug. +title: "[BUG] " +labels: bug +body: + - type: markdown + attributes: + value: | + Please check out the [FAQ section](https://github.com/PhilippC/keepass2android/blob/master/docs/Documentation.md#faq) and [search for open issues](https://github.com/PhilippC/keepass2android/issues?q=is%3Aopen+is%3Aissue+label%3Abug) first. + - type: checkboxes + attributes: + label: Checks + options: + - label: I have read the FAQ section, searched the open issues, and still think this is a new bug. + required: true + - type: textarea + id: bug + attributes: + label: "Describe the bug you encountered:" + validations: + required: true + - type: textarea + id: expected + attributes: + label: "Describe what you expected to happen:" + - type: input + id: version + attributes: + label: "What version of Keepass2Android are you using?" + placeholder: | + Please follow these steps to find your app version: + 1. Click the **⁝** icon in the top right corner + 2. Select **Settings** + 3. Click **About** + 4. Find the "Version" information and provide it here + validations: + required: true + - type: textarea + id: os + attributes: + label: Which version of Android are you on? + placeholder: | + Please follow these steps to find your Android version: + 1. Open your device's **Settings** app. + 2. Scroll down and select **About phone** or **About tablet**. + 3. Find the **Android version** section and provide it here. + validations: + required: true + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..3b69df7a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,8 @@ +--- +name: Feature Request +about: Suggest an idea for this project. +title: '' +labels: enhancement +assignees: '' + +--- diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 00000000..b3d154c3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,16 @@ +--- +name: Question +about: Ask a question about 'Keepass2Android'. +title: '' +labels: question +assignees: '' + +--- + +**What version of Keepass2Android are you using?** +Please follow these steps to find your app version: +1. Click the **⁝** icon in the top right corner +2. Select **Settings** +3. Click **About** +4. Find the "Version" information and provide it here: + From 37a6da5a3b2840c7f33631a8ccc66a581fda8e8c Mon Sep 17 00:00:00 2001 From: Robert Ellegate Date: Sun, 9 Apr 2023 11:16:01 -0400 Subject: [PATCH 096/101] =?UTF-8?q?=F0=9F=8E=A8=20style(issue=5Ftemplate):?= =?UTF-8?q?=20add=20prefixes=20to=20issue=20titles=20Add=20prefixes=20to?= =?UTF-8?q?=20issue=20titles=20to=20improve=20consistency=20and=20make=20i?= =?UTF-8?q?t=20easier=20to=20identify=20the=20type=20of=20issue.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `[FEAT]` for feature requests - `[QUESTION]` for questions Also, update the bug report template to move the instructions for finding the app version to a markdown section and remove the placeholder text from the version input field. This makes it clearer and easier to follow the instructions. --- .github/ISSUE_TEMPLATE/bug_report.yaml | 14 ++++++++------ .github/ISSUE_TEMPLATE/feature_request.md | 2 +- .github/ISSUE_TEMPLATE/question.md | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 224c50a1..f594466c 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -23,16 +23,18 @@ body: id: expected attributes: label: "Describe what you expected to happen:" + - type: markdown + attributes: + value: | + Please follow these steps to find your app version: + 1. Click the **⁝** icon in the top right corner + 2. Select **Settings** + 3. Click **About** + 4. Find the "Version" information and provide it here - type: input id: version attributes: label: "What version of Keepass2Android are you using?" - placeholder: | - Please follow these steps to find your app version: - 1. Click the **⁝** icon in the top right corner - 2. Select **Settings** - 3. Click **About** - 4. Find the "Version" information and provide it here validations: required: true - type: textarea diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 3b69df7a..fdb2ed38 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,7 +1,7 @@ --- name: Feature Request about: Suggest an idea for this project. -title: '' +title: '[FEAT] ' labels: enhancement assignees: '' diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index b3d154c3..8953e6b7 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -1,7 +1,7 @@ --- name: Question about: Ask a question about 'Keepass2Android'. -title: '' +title: '[QUESTION] ' labels: question assignees: '' From 746dcd4c6ba0ac1b97c962f8fd0ce5668f1742d4 Mon Sep 17 00:00:00 2001 From: Robert Ellegate Date: Sun, 9 Apr 2023 11:20:44 -0400 Subject: [PATCH 097/101] =?UTF-8?q?=F0=9F=8E=A8=20style(issue=5Ftemplate):?= =?UTF-8?q?=20improve=20readability=20of=20bug=20report=20template=20This?= =?UTF-8?q?=20commit=20improves=20the=20readability=20of=20the=20bug=20rep?= =?UTF-8?q?ort=20template=20by=20changing=20the=20label=20of=20the=20"Vers?= =?UTF-8?q?ion"=20information=20to=20"provide=20it=20below"=20instead=20of?= =?UTF-8?q?=20"provide=20it=20here".=20Additionally,=20the=20"Which=20vers?= =?UTF-8?q?ion=20of=20Android=20are=20you=20on=3F"=20question=20is=20now?= =?UTF-8?q?=20a=20separate=20input=20field=20instead=20of=20a=20textarea,?= =?UTF-8?q?=20which=20makes=20it=20easier=20to=20answer.=20Finally,=20the?= =?UTF-8?q?=20markdown=20formatting=20of=20the=20instructions=20for=20find?= =?UTF-8?q?ing=20the=20Android=20version=20is=20improved=20for=20better=20?= =?UTF-8?q?readability.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/ISSUE_TEMPLATE/bug_report.yaml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index f594466c..83c2e089 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -30,22 +30,24 @@ body: 1. Click the **⁝** icon in the top right corner 2. Select **Settings** 3. Click **About** - 4. Find the "Version" information and provide it here + 4. Find the "Version" information and provide it below - type: input id: version attributes: label: "What version of Keepass2Android are you using?" validations: required: true - - type: textarea + - type: markdown + attributes: + value: | + Please follow these steps to find your Android version: + 1. Open your device's **Settings** app + 2. Scroll down and select **About phone** or **About tablet** + 3. Find the **Android version** section and provide it below + - type: input id: os attributes: - label: Which version of Android are you on? - placeholder: | - Please follow these steps to find your Android version: - 1. Open your device's **Settings** app. - 2. Scroll down and select **About phone** or **About tablet**. - 3. Find the **Android version** section and provide it here. + label: "Which version of Android are you on?" validations: required: true From 3f6e51b126b44dda51f9d22d8447b1f1bbf690ee Mon Sep 17 00:00:00 2001 From: PhilippC Date: Thu, 13 Apr 2023 04:36:57 +0200 Subject: [PATCH 098/101] Update Privacy-Policy.md --- docs/Privacy-Policy.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/Privacy-Policy.md b/docs/Privacy-Policy.md index 38d9197b..ca9b6e67 100644 --- a/docs/Privacy-Policy.md +++ b/docs/Privacy-Policy.md @@ -18,6 +18,8 @@ Keepass2Android does not collect personal identifiable information. For debuggin * **Internet** (Keepass2Android regular only): Required to allow the user to read/store password databases or key files on remote locations, e.g. Dropbox or via WebDav. * **Contacts/Accounts** (Keepass2Android regular only): Required by the Google Drive SDK. If you want to access files on Google Drive, you are prompted to select one of the Google Accounts on your phone to use. The permission is required to query the list of Google accounts on the device. Keepass2Android does not access your personal contacts. * **Storage**: Required to allow the user to read/store password databases or key files on the device locally. -* **Fingerprint**: Required if you want to use fingerprint unlock. +* **Fingerprint/Biometric**: Required if you want to use biometric unlock. * **Vibrate**: Required by the built-in keyboard (vibrate on key press) +* **Camera**: Required for scanning OTP QR Codes +* **Foreground service**: Required to keep the app alive for QuickUnlock (so you don't need to enter your full master password repeatedly) From 03ea07342661a7a19df6741eac19c7dc8c379d71 Mon Sep 17 00:00:00 2001 From: Rick Brown Date: Fri, 16 Jun 2023 19:18:47 -0400 Subject: [PATCH 099/101] Bugfix for issue #2350 - SFTP fails to connect to IPv6 address Since IPv6 addresses contain colons, they break the host:port URI parsing logic, since "host" will have colons in it. This fix adds URL encoding/decoding of the "host" parameter, thus removing any possible colons in that parameter that could conflict with the host:port separator. --- .../keepass2android/javafilestorage/SftpStorage.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpStorage.java b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpStorage.java index 2216ccfc..ec52613a 100644 --- a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpStorage.java +++ b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpStorage.java @@ -400,12 +400,16 @@ public class SftpStorage extends JavaFileStorageBase { ci.password = decode(userPwd.substring(userPwd.indexOf(":")+1)); ci.host = ci.host.substring(ci.host.indexOf('@') + 1); ci.port = DEFAULT_SFTP_PORT; - int portSeparatorIndex = ci.host.indexOf(":"); + int portSeparatorIndex = ci.host.lastIndexOf(":"); if (portSeparatorIndex >= 0) { ci.port = Integer.parseInt(ci.host.substring(portSeparatorIndex+1)); ci.host = ci.host.substring(0, portSeparatorIndex); } + // Encode/decode required to support IPv6 (colons break host:port parse logic) + // See Bug #2350 + ci.host = decode(ci.host); + ci.localPath = extractSessionPath(filename); return ci; } @@ -476,6 +480,10 @@ public class SftpStorage extends JavaFileStorageBase { public String buildFullPath( String host, int port, String localPath, String username, String password) throws UnsupportedEncodingException { + // Encode/decode required to support IPv6 (colons break host:port parse logic) + // See Bug #2350 + host = encode(host); + if (port != DEFAULT_SFTP_PORT) host += ":"+String.valueOf(port); return getProtocolPrefix()+encode(username)+":"+encode(password)+"@"+host+localPath; From 464fe433232654fa99cb79bedf038961997b7222 Mon Sep 17 00:00:00 2001 From: Rick Brown Date: Wed, 12 Jul 2023 16:51:17 -0400 Subject: [PATCH 100/101] Add JSch (SFTP) debug logging -App Settings->Log-File for Debugging->SFTP debug logging -Logs to android log (logcat) if log file is not enabled -Logs to Kp2a log file if it is enabled -Logs are tagged as "KP2AJFS[JSch]" -When enabled, logs ALL levels (DEBUG+). NOTE: Sensitive SSH connection information may be logged!! --- src/KeePassLib2Android/Kp2aLog.cs | 4 +- .../javafilestorage/Kp2aJSchLogger.java | 93 +++++++++++++++++++ .../javafilestorage/SftpStorage.java | 8 ++ .../Resources/values/config.xml | 1 + .../Resources/values/strings.xml | 1 + .../Resources/xml/preferences.xml | 7 ++ .../settings/DatabaseSettingsActivity.cs | 32 +++++-- 7 files changed, 136 insertions(+), 10 deletions(-) create mode 100644 src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/Kp2aJSchLogger.java diff --git a/src/KeePassLib2Android/Kp2aLog.cs b/src/KeePassLib2Android/Kp2aLog.cs index e5c484ef..2226ee87 100644 --- a/src/KeePassLib2Android/Kp2aLog.cs +++ b/src/KeePassLib2Android/Kp2aLog.cs @@ -58,12 +58,12 @@ namespace keepass2android } - private static string LogFilename + public static string LogFilename { get { return Application.Context.FilesDir.CanonicalPath +"/keepass2android.log"; } } - private static bool LogToFile + public static bool LogToFile { get { diff --git a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/Kp2aJSchLogger.java b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/Kp2aJSchLogger.java new file mode 100644 index 00000000..0640560e --- /dev/null +++ b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/Kp2aJSchLogger.java @@ -0,0 +1,93 @@ +package keepass2android.javafilestorage; + +import android.util.Log; + +import com.jcraft.jsch.Logger; + +import java.io.FileWriter; +import java.io.PrintWriter; +import java.util.Map; + +public class Kp2aJSchLogger implements Logger { + + private static final String PREFIX = "KP2AJFS[JSch]"; + + private interface ILogger { + void log(String message); + } + + private static final class LogEntry { + private final String levelTag; + private final ILogger logger; + + LogEntry(String levelTag, ILogger logger) { + this.levelTag = levelTag; + this.logger = logger; + } + } + private static final ILogger DEBUG = msg -> Log.d(PREFIX, msg); + private static final LogEntry DEBUG_ENTRY = new LogEntry("D", DEBUG); + private static final ILogger ERROR = msg -> Log.e(PREFIX, msg); + private static final LogEntry DEFAULT_ENTRY = DEBUG_ENTRY; + + private static final Map loggers = Map.of( + Logger.DEBUG, DEBUG_ENTRY, + Logger.INFO, new LogEntry("I", msg -> Log.i(PREFIX, msg)), + Logger.WARN, new LogEntry("W", msg -> Log.w(PREFIX, msg)), + Logger.ERROR, new LogEntry("E", ERROR), + Logger.FATAL, new LogEntry("F", msg -> Log.wtf(PREFIX, msg)) + ); + + + private final String logFilename; + + public Kp2aJSchLogger(String logFilename) { + this.logFilename = logFilename; + } + + @Override + public boolean isEnabled(int level) { + return true; + } + + @Override + public void log(int level, String message) { + if (isEnabled(level)) + getLogger(level).log(message); + } + + private ILogger getLogger(int level) { + LogEntry entry = loggers.get(level); + if (entry == null) + entry = DEFAULT_ENTRY; + + ILogger logger; + if (logFilename != null) { + logger = createFileLogger(entry); + } else { + logger = entry.logger; + } + + return logger; + } + + private ILogger createFileLogger(LogEntry entry) { + try { + final PrintWriter p = new PrintWriter(new FileWriter(logFilename, true)); + return msg -> { + try { + String fullMsg = String.join(" ", entry.levelTag, PREFIX, msg); + p.println(fullMsg); + } catch (Exception e) { + ERROR.log(e.getMessage()); + } finally { + p.close(); + } + }; + } catch (Exception e) { + ERROR.log(e.getMessage()); + return entry.logger; + } + } +} + diff --git a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpStorage.java b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpStorage.java index ec52613a..493ba753 100644 --- a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpStorage.java +++ b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpStorage.java @@ -375,6 +375,14 @@ public class SftpStorage extends JavaFileStorageBase { } + public void setJschLogging(boolean enabled, String logFilename) { + if (enabled) { + JSch.setLogger(new Kp2aJSchLogger(logFilename)); + } else { + JSch.setLogger(null); + } + } + private String createKeyPair(String key_filename) throws JSchException, IOException { String public_key_filename = key_filename + ".pub"; File file = new File(key_filename); diff --git a/src/keepass2android/Resources/values/config.xml b/src/keepass2android/Resources/values/config.xml index b6bc4902..3b0f4916 100644 --- a/src/keepass2android/Resources/values/config.xml +++ b/src/keepass2android/Resources/values/config.xml @@ -98,6 +98,7 @@ TrayTotp_SeedField_key TrayTotp_prefs_key DebugLog_key + JSchDebug_key DebugLog_prefs_key DebugLog_send AutofillDisabledQueriesPreference_key diff --git a/src/keepass2android/Resources/values/strings.xml b/src/keepass2android/Resources/values/strings.xml index 52f858ae..1942e3c3 100644 --- a/src/keepass2android/Resources/values/strings.xml +++ b/src/keepass2android/Resources/values/strings.xml @@ -680,6 +680,7 @@ TrayTotp Log-File for Debugging Use log file + SFTP debug logging Write app output to a local log file Send debug log... diff --git a/src/keepass2android/Resources/xml/preferences.xml b/src/keepass2android/Resources/xml/preferences.xml index 3b18fd70..f6e7f871 100644 --- a/src/keepass2android/Resources/xml/preferences.xml +++ b/src/keepass2android/Resources/xml/preferences.xml @@ -670,10 +670,17 @@ android:defaultValue="false" android:title="@string/DebugLog_title" android:key="@string/DebugLog_key" /> + + diff --git a/src/keepass2android/settings/DatabaseSettingsActivity.cs b/src/keepass2android/settings/DatabaseSettingsActivity.cs index d857824a..73655b61 100644 --- a/src/keepass2android/settings/DatabaseSettingsActivity.cs +++ b/src/keepass2android/settings/DatabaseSettingsActivity.cs @@ -175,6 +175,7 @@ namespace keepass2android FindPreference(GetString(Resource.String.DebugLog_key)).PreferenceChange += OnDebugLogChanged; FindPreference(GetString(Resource.String.DebugLog_send_key)).PreferenceClick += OnSendDebug; + FindPreference(GetString(Resource.String.JSchDebug_key)).PreferenceChange += OnJSchDebugChanged; HashSet supportedLocales = new HashSet() { "en", "af", "ar", "az", "be", "bg", "ca", "cs", "da", "de", "el", "es", "eu", "fa", "fi", "fr", "gl", "he", "hr", "hu", "id", "in", "it", "iw", "ja", "ko", "ml", "nb", "nl", "nn", "no", "pl", "pt", "ro", "ru", "si", "sk", "sl", "sr", "sv", "tr", "uk", "vi", "zh" }; @@ -417,16 +418,31 @@ namespace keepass2android private void OnDebugLogChanged(object sender, Preference.PreferenceChangeEventArgs e) { - if ((bool)e.NewValue) - { - Kp2aLog.CreateLogFile(); - } + if ((bool)e.NewValue) + Kp2aLog.CreateLogFile(); else - { - Kp2aLog.FinishLogFile(); - } + Kp2aLog.FinishLogFile(); - } + bool jschLogEnable = PreferenceManager.GetDefaultSharedPreferences(Application.Context) + .GetBoolean(Application.Context.GetString(Resource.String.JSchDebug_key), false); + SetJSchLogging(jschLogEnable); + } + + private void OnJSchDebugChanged(object sender, Preference.PreferenceChangeEventArgs e) + { + SetJSchLogging((bool)e.NewValue); + } + + private void SetJSchLogging(bool enabled) + { + var sftpStorage = new Keepass2android.Javafilestorage.SftpStorage(Context); + string? logFilename = null; + if (Kp2aLog.LogToFile) + { + logFilename = Kp2aLog.LogFilename; + } + sftpStorage.SetJschLogging(enabled, logFilename); + } private void AlgorithmPrefChange(object sender, Preference.PreferenceChangeEventArgs preferenceChangeEventArgs) { From da3665c25b7de52c3f6818213a75ed5a92102a98 Mon Sep 17 00:00:00 2001 From: Rick Brown Date: Wed, 12 Jul 2023 18:40:57 -0400 Subject: [PATCH 101/101] Fix NoNet compilation error --- .../settings/DatabaseSettingsActivity.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/keepass2android/settings/DatabaseSettingsActivity.cs b/src/keepass2android/settings/DatabaseSettingsActivity.cs index 73655b61..bfe934da 100644 --- a/src/keepass2android/settings/DatabaseSettingsActivity.cs +++ b/src/keepass2android/settings/DatabaseSettingsActivity.cs @@ -175,7 +175,12 @@ namespace keepass2android FindPreference(GetString(Resource.String.DebugLog_key)).PreferenceChange += OnDebugLogChanged; FindPreference(GetString(Resource.String.DebugLog_send_key)).PreferenceClick += OnSendDebug; + +#if !EXCLUDE_JAVAFILESTORAGE && !NoNet FindPreference(GetString(Resource.String.JSchDebug_key)).PreferenceChange += OnJSchDebugChanged; +#else + FindPreference(GetString(Resource.String.JSchDebug_key)).Enabled = false; +#endif HashSet supportedLocales = new HashSet() { "en", "af", "ar", "az", "be", "bg", "ca", "cs", "da", "de", "el", "es", "eu", "fa", "fi", "fr", "gl", "he", "hr", "hu", "id", "in", "it", "iw", "ja", "ko", "ml", "nb", "nl", "nn", "no", "pl", "pt", "ro", "ru", "si", "sk", "sl", "sr", "sv", "tr", "uk", "vi", "zh" }; @@ -423,11 +428,14 @@ namespace keepass2android else Kp2aLog.FinishLogFile(); +#if !EXCLUDE_JAVAFILESTORAGE && !NoNet bool jschLogEnable = PreferenceManager.GetDefaultSharedPreferences(Application.Context) .GetBoolean(Application.Context.GetString(Resource.String.JSchDebug_key), false); SetJSchLogging(jschLogEnable); +#endif } +#if !EXCLUDE_JAVAFILESTORAGE && !NoNet private void OnJSchDebugChanged(object sender, Preference.PreferenceChangeEventArgs e) { SetJSchLogging((bool)e.NewValue); @@ -443,8 +451,9 @@ namespace keepass2android } sftpStorage.SetJschLogging(enabled, logFilename); } +#endif - private void AlgorithmPrefChange(object sender, Preference.PreferenceChangeEventArgs preferenceChangeEventArgs) + private void AlgorithmPrefChange(object sender, Preference.PreferenceChangeEventArgs preferenceChangeEventArgs) { var db = App.Kp2a.CurrentDb; var previousCipher = db.KpDatabase.DataCipherUuid; @@ -887,7 +896,7 @@ namespace keepass2android #if DEBUG preference.Enabled = (usageCount > 1); -#else +#else preference.Enabled = (usageCount > 50); #endif preference.PreferenceChange += delegate(object sender, Preference.PreferenceChangeEventArgs args)