diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml new file mode 100644 index 00000000..83c2e089 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -0,0 +1,53 @@ +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: 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 below + - type: input + id: version + attributes: + label: "What version of Keepass2Android are you using?" + validations: + required: true + - 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?" + 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..fdb2ed38 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,8 @@ +--- +name: Feature Request +about: Suggest an idea for this project. +title: '[FEAT] ' +labels: enhancement +assignees: '' + +--- diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 00000000..8953e6b7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,16 @@ +--- +name: Question +about: Ask a question about 'Keepass2Android'. +title: '[QUESTION] ' +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: + diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f8f4cb64..bafa83ef 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. @@ -330,6 +332,9 @@ 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: | 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/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 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) diff --git a/src/KeePass.sln b/src/KeePass.sln index 07b0f025..bcd542c4 100644 --- a/src/KeePass.sln +++ b/src/KeePass.sln @@ -25,6 +25,10 @@ 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("{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 Debug|Any CPU = Debug|Any CPU @@ -283,6 +287,54 @@ 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 + {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/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/Kp2aAutofillParser/AutofillParser.cs b/src/Kp2aAutofillParser/AutofillParser.cs new file mode 100644 index 00000000..fe1cc823 --- /dev/null +++ b/src/Kp2aAutofillParser/AutofillParser.cs @@ -0,0 +1,987 @@ +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.EMAIL, + 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 ConvertToCanonicalLowerCaseHints(string[] supportedHints) + { + List result = new List(); + foreach (string hint in supportedHints) + { + 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++) + { + 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 + { + 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(InputField inputField) + : this(inputField, inputField.AutofillHints) + { + + } + + public FilledAutofillField(InputField 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.ConvertToCanonicalLowerCaseHints(hintList.ToArray()).ToArray(); + inputField.FillFilledAutofillValue(this); + + + } + + 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 (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 + { + 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); + + } + + /// + /// 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(); + + 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..."); + + if (LogAutofillView) + { + string debugInfo = JsonConvert.SerializeObject(autofillView, Newtonsoft.Json.Formatting.Indented); + _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).Select(AutofillHintsHelper.ToCanonicalHint).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.Select(AutofillHintsHelper.ToCanonicalHint).Intersect(_autofillHintsForLogin).Any()) + { + AddFieldToHintMap(viewNode, viewHints.Select(AutofillHintsHelper.ToCanonicalHint).ToHashSet().ToArray()); + } + + } + } + 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()) + { + 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.Where(IsEditText) + .TakeWhile(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) + AddFieldToHintMap(uf, new string[] { AutofillHintsHelper.AutofillHintUsername }); + foreach (var pf in passwordFields.Except(usernameFields)) + AddFieldToHintMap(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 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) + { + 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", "user id" }; + + private static bool HasUsernameHint(InputField f) + { + return IsAny(f.IdEntry?.ToLower(), _usernameHints) || + IsAny(f.Hint?.ToLower(), _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.FirstOrDefault() == "passwordAuto") + || (f.HtmlInfoTypeAttribute == "password") + ); + } + + + + + + + } +} 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/Kp2aAutofillParserTest/AutofillTest.cs b/src/Kp2aAutofillParserTest/AutofillTest.cs new file mode 100644 index 00000000..80c15003 --- /dev/null +++ b/src/Kp2aAutofillParserTest/AutofillTest.cs @@ -0,0 +1,145 @@ +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; } + public override void FillFilledAutofillValue(FilledAutofillField filledField) + { + } + } + + [Fact] + public void TestNotFocusedPasswordAutoIsNotFilled() + { + var resourceName = "Kp2aAutofillParserTest.com-servicenet-mobile-no-focus.json"; + 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"); + } + + [Fact] + public void TestMulitpleUnfocusedLoginsIsFilled() + { + var resourceName = "Kp2aAutofillParserTest.firefox-amazon-it.json"; + 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(); + + + 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 ?? new string[]{})}"); + _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..d702da41 --- /dev/null +++ b/src/Kp2aAutofillParserTest/Kp2aAutofillParserTest.csproj @@ -0,0 +1,62 @@ + + + + net6.0 + enable + enable + + false + + + + + + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + 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/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/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/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" +} 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/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 28f2065d..290e57b3 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 @@ -27,6 +27,7 @@ import com.jcraft.jsch.UserInfo; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.util.Log; @SuppressWarnings("unused") // Exposed by JavaFileStorageBindings public class SftpStorage extends JavaFileStorageBase { @@ -423,6 +424,8 @@ public class SftpStorage extends JavaFileStorageBase { ChannelSftp init(ConnectionInfo cInfo) throws JSchException, UnsupportedEncodingException { jsch = new JSch(); + Log.d("KP2AJFS", "init SFTP"); + String base_dir = getBaseDir(); jsch.setKnownHosts(base_dir + "/known_hosts"); @@ -434,7 +437,9 @@ public class SftpStorage extends JavaFileStorageBase { } + Log.e("KP2AJFS[thread]", "getting session..."); Session session = jsch.getSession(cInfo.username, cInfo.host, cInfo.port); + Log.e("KP2AJFS", "creating SftpUserInfo"); UserInfo ui = new SftpUserInfo(cInfo.password, cInfo.keyPassphrase, _appContext); session.setUserInfo(ui); @@ -475,12 +480,20 @@ public class SftpStorage extends JavaFileStorageBase { return _keyUtils.createKeyPair(jsch); } - @SuppressWarnings("unused") // Exposed by JavaFileStorageBindings public void savePrivateKeyContent(String keyName, String keyContent) throws IOException, Exception { _keyUtils.savePrivateKeyContent(keyName, keyContent); } + @SuppressWarnings("unused") // Exposed by JavaFileStorageBindings + public void setJschLogging(boolean enabled, String logFilename) { + if (enabled) { + JSch.setLogger(new Kp2aJSchLogger(logFilename)); + } else { + JSch.setLogger(null); + } + } + /** * Exposed for testing purposes only. * @param keyName 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 569996da..b8177b49 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); 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/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" 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\"(ø, ö, ô, ó κ.τ.λ.)\" - \"Αλλαγή σε αριθμούς και σύμβολα με το πάτημα αυτού του πλήκτρου\" + Αλλαγή σε αριθμούς και σύμβολα με το πάτημα αυτού του πλήκτρου - \"Επιστρέψτε στα γράμματα αγγίζοντας ξανά αυτό το πλήκτρο\" + Επιστρέψτε στα γράμματα αγγίζοντας ξανά αυτό το πλήκτρο - \"Αγγίξτε και κρατήστε πατημένο αυτό το πληκτρολόγιο για να αλλάξετε τις ρυθμίσεις πληκτρολογίου, όπως η αυτόματη συμπλήρωση\" + Αγγίξτε και κρατήστε πατημένο αυτό το πλήκτρο για να αλλάξετε τις ρυθμίσεις πληκτρολογίου, όπως η αυτόματη συμπλήρωση - \"Δοκιμάστε το!\" + Δοκιμάστε το! - Μετ. + Μετάβαση Επόμενο 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 @@ 二元语法分词建议 - 使用曾经使用过的词语改进建议 + 使用前一个单词来改进建议 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/app/src/main/java/keepass2android/kp2afilechooser/Kp2aFileProvider.java b/src/java/android-filechooser-AS/app/src/main/java/keepass2android/kp2afilechooser/Kp2aFileProvider.java index cdb5f0ed..f46fb622 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 @@ -529,7 +529,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); 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 … 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 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 - - + + - + diff --git a/src/keepass2android/Properties/AndroidManifest_net.xml b/src/keepass2android/Properties/AndroidManifest_net.xml index 4d54acfc..f79550f7 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" @@ -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 ee2d0df0..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 + 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 + + 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 + + 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 + + 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 + + diff --git a/src/keepass2android/Resources/values-da/strings.xml b/src/keepass2android/Resources/values-da/strings.xml index 16af75d7..514c3a2d 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: @@ -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 @@ -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 @@ -685,6 +685,12 @@ 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é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 Implementeret understøttelse af MEGA-skylager diff --git a/src/keepass2android/Resources/values-de/strings.xml b/src/keepass2android/Resources/values-de/strings.xml index 1b0ebfbc..efb1b49f 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 Passwortbildschirm anzeigen, um den App-Prozess zu beenden (für paranoide Benutzer) Anwendung Anwendungseinstellungen Gruppennamen im Suchergebnis anzeigen @@ -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 @@ -84,32 +84,32 @@ 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 - Bitte authentifizieren um fortzufahren - Kann Biometrisches Entsperren nicht einrichten: + Systemsprache + 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 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 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 Abbrechen Notizen Tags - Override URL - Kennwort wiederholen + URL überschreiben + 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 @@ -156,10 +156,10 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Passwort Name URL - Override URL + URL überschreiben tag1, tag2 Benutzername - Passwort oder Schlüssel-Datei ungültig. + Passwort oder Schlüsseldatei ungültig. Ungültiger Algorithmus. Datenbank-Format wurde nicht erkannt. Schlüssel-Datei existiert nicht. @@ -178,8 +178,8 @@ 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 - Kennwort kopieren + Hauptschlüssel ändern + Passwort kopieren Benutzername kopieren TOTP kopieren Erstellen @@ -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 + Datenbankpasswort 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,15 +233,15 @@ 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! Schlüsseldatei erfolgreich exportiert! Leerzeichen Suchen - Kennwort anzeigen - Sortiere nach... + Passwort anzeigen + Sortieren nach … Sortieren nach Name Sortieren nach Erstellung Sortiere nach Änderungsdatum @@ -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. @@ -293,8 +293,8 @@ 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 - Zeige Benutzernamen in Liste + TAN-Einträge als abgelaufen markieren, wenn sie verwendet werden + 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. @@ -303,14 +303,14 @@ 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 - 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 @@ -321,34 +321,34 @@ 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 - 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. + 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! + 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 Passwort! Anhang speichern - Bitte wähle den Ort zum Speichern. - In Datei exportieren... + Bitte den Ort zum Speichern wählen. + In Datei exportieren … Im Cache speichern und öffnen Mit internem Bildbetrachter anzeigen 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). Feldname Feldwert Geschütztes Feld - Dateianhang hinzufügen... + Dateianhang hinzufügen … Zusätzliches Feld hinzufügen TOTP konfigurieren Geheimer Schlüssel @@ -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. @@ -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! + 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 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,90 +409,90 @@ 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 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? - Gruppe permanent löschen? - Ausgewählte Elemente 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 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. + 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. - Synchronisiere gecachte Datenbank… - 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. (Hast du 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. + 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 … + 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: @@ -502,9 +502,9 @@ 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: + 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,54 +529,54 @@ 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 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 - 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. - Master-Passwort - 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. + Hauptpasswort + 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. 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: - Schlüsseldatei benutzen + 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 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 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 - 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. + 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. 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,83 +635,84 @@ 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 - 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 - • 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 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 - 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. + 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 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. - 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 + 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 - 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 +721,38 @@ Anbei einige Hinweise, 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 +776,43 @@ Anbei einige Hinweise, 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 +831,20 @@ Anbei einige Hinweise, 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 +856,11 @@ Anbei einige Hinweise, 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 +869,14 @@ Anbei einige Hinweise, 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 @@ -883,11 +884,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 @@ -901,101 +902,101 @@ Anbei einige Hinweise, 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 +1013,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 +1039,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. + Bitte sicherstellen, dass dies auf diesem System funktioniert; falls nicht, die Standardtastatur verwenden. 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 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 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. + 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! + 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 diff --git a/src/keepass2android/Resources/values-el/strings.xml b/src/keepass2android/Resources/values-el/strings.xml index 086457ee..236a0b03 100644 --- a/src/keepass2android/Resources/values-el/strings.xml +++ b/src/keepass2android/Resources/values-el/strings.xml @@ -301,6 +301,8 @@ Απενεργοποιεί τον έλεγχο αν ταιριάζει ο τομέας και το πακέτο εφαρμογής Ενσωμάτωση με πληκτρολόγιο Δείχνει τις προτάσεις αυτόματης συμπλήρωσης ως γραμμές μέσα στο πρηκτρολόγιο + Προβολή αυτόματης συμπλήρωσης αρχείου καταγραφής + Εγγραφή λεπτομερειών σχετικά με την προβολή αυτόματης συμπλήρωσης στο αρχείο καταγραφής αποσφαλμάτωσης (αν η καταγραφή αποσφαλμάτωσης είναι ενεργοποιημένη). Αυτές οι λεπτομέρειες μπορούν να σταλούν στον προγραμματιστή αν η αυτόματη συμπλήρωση δε λειτουργεί όπως αναμενόταν. Απαιτείται Android 11 ή νεότερη έκδοση Εύρεση συνθηματικού Εξαίρεση ληγμένων εγγραφών @@ -330,7 +332,7 @@ Απόκρυψη μήκους QuickUnlock Αν ενεργοποιηθεί, αποκρύπτει το μήκος του κωδικού QuickUnlock στη σχετική οθόνη. Κλειδί QuickUnlock από τη βάση δεδομένων - Εάν η ενεργή βάση δεδομένων περιέχει μια καταχώρηση με τίτλο QuickUnlock στην ομάδα ρίζας της, ο κωδικός πρόσβασης αυτής της καταχώρησης χρησιμοποιείται ως κωδικός QuickUnlock. + Εάν η ενεργή βάση δεδομένων περιέχει μια καταχώριση με τίτλο QuickUnlock στην ομάδα ρίζας της, ο κωδικός πρόσβασης αυτής της καταχώρισης χρησιμοποιείται ως κωδικός QuickUnlock. Αποτυχία QuickUnlock: λανθασμένο συνθηματικό! Αποθήκευση συνημμένου Επιλέξτε πού θα αποθηκεύσετε το συνημμένο. @@ -427,7 +429,7 @@ Μετονομασία Απέτυχε η προσθήκη του συνημμένου αρχείου. Κάδος ανακύκλωσης - Θέλετε να διαγράψετε οριστικά αυτή την καταχώριση; Πατήστε όχι για να ανακύκλωση. + Θέλετε να διαγράψετε οριστικά αυτή την καταχώριση; Πατήστε όχι για ανακύκλωση. Θέλετε να διαγράψετε οριστικά αυτή την ομάδα; Πατήστε όχι για ανακύκλωση. Θέλετε να διαγράψετε οριστικά τα επιλεγμένα στοιχεία; Πατήστε όχι για ανακύκλωση. Θέλετε να διαγράψετε οριστικά αυτή την καταχώριση; @@ -540,7 +542,7 @@ Η βάση δεδομένων είναι κρυπτογραφημένη με το συνθηματικό που εισάγετε εδώ. Επιλέξτε ένα ισχυρό συνθηματικό προκειμένου να διατηρείτε τη βάση δεδομένων ασφαλή! Συμβουλή: Συνθέστε μια-δυο φράσεις και χρησιμοποιήστε τα πρώτα γράμματα των λέξεων ως συνθηματικό. Συμπεριλάβετε σημεία στίξης. Επιλέξτε κύριο συνθηματικό για την προστασία της βάσης δεδομένων: Αρχείο κλειδιού - Το αρχείο κλειδιού είναι βασικά ένα συνθηματικό αποθηκευμένο σε ένα αρχείο. Τα αρχείο κλειδιού είναισυνήθως ισχυρότερα από τα κύρια συνθηματικά, γιατί το κλειδί μπορεί να είναι πιο σύνθετο, ωστόσο είναι ε΄πίσης δυσκολότερο να διατηρηθούν μυστικά. Αν αποθηκεύεις τη βάση δεδομένων στο σύννεφο, μην αποθηκεύσεις και το αρχείο κλειδί εκεί! Αυτό θα το έκανε εντελώς άχρηστο! Σημαντικό: Μην αλλάζετε τα περιεχόμενο του αρχείου κλειδιού αφού δημιουργηθεί η βάση δεδομένων! + Το αρχείο κλειδιού είναι βασικά ένα συνθηματικό αποθηκευμένο σε ένα αρχείο. Τα αρχεία κλειδιού είναι συνήθως ισχυρότερα από τα κύρια συνθηματικά, γιατί το κλειδί μπορεί να είναι πιο σύνθετο, ωστόσο είναι επίσης δυσκολότερο να διατηρηθούν μυστικά. Αν αποθηκεύεις τη βάση δεδομένων στο σύννεφο, μην αποθηκεύσεις και το αρχείο κλειδιού εκεί! Αυτό θα το έκανε εντελώς άχρηστο! Σημαντικό: Μην αλλάζετε τα περιεχόμενο του αρχείου κλειδιού αφού δημιουργηθεί η βάση δεδομένων! Επιλέξτε αν θέλετε να χρησιμοποιήσετε ένα αρχείο κλειδιού, εκτός από το κύριο συνθηματικό: Χρήση αρχείου κλειδιού Παρουσιάστηκε σφάλμα κατά την προσθήκη του αρχείου κλειδιού! @@ -570,9 +572,9 @@ Όνομα πεδίου στις ρυθμίσεις TOTP Εισάγετε όνομα πεδίου από ρυθμίσεις TrayTotp. TrayTotp - Αρχείο καταχώρησης για αποσφαλματοποίηση - Χρήση αρχείου καταχώρησης - Καταγραφή στοιχείων εφαρμογής σε τοπικό αρχείο καταχώρησης + Αρχείο καταγραφών για αποσφαλμάτωση + Χρήση αρχείου καταγραφών + Καταγραφή στοιχείων της εφαρμογής σε τοπικό αρχείο καταγραφών Αποστολή αρχείων καταγραφής εκσφαλμάτωσης... Φόρτωση… Πρόσθετα @@ -682,6 +684,12 @@ Ειδοποίηση για απλοποιημένη πρόσβαση στην τρέχουσα καταχώριση. Κλείσιμο της βάσης δεδομένων μετά από 3 ανεπιτυχείς προσπάθειες βιομετρικού ξεκλειδώματος. Προσοχή! Ο βιομετρικός έλεγχος ταυτότητας μπορεί να ακυρωθεί από το Android, π.χ. μετά την προσθήκη ενός νέου δακτυλικού αποτυπώματος στις ρυθμίσεις της συσκευής σας. Βεβαιωθείτε ότι ξέρετε πάντα πώς να ξεκλειδώσετε με τον κύριο κωδικό πρόσβασης! + + Διόρθωση σφάλματος για απότομα κλεισίματα εφαρμογής και μη αναμενόμενες αποσυνδέσεις + Μετάβαση σε νέα υλοποίηση SFTP, υποστηρίζοντας σύγχρονους αλγόριθμους δημόσιου κλειδιού όπως rsa-sha2-256 + Μαρκάρισμα κωδικών πρόσβασης ως ευαίσθητοι κατά την αντιγραφή στο πρόχειρο (Android 13) + Βελτιώσεις Autofill + Υποστηρίζεται πλέον προβολή, διαγραφή και ανάκτηση των διαγραμμένων εγγραφών Υλοποιήθηκε υποστήριξη για αποθήκευση στο νέφος MEGA diff --git a/src/keepass2android/Resources/values-fi/strings.xml b/src/keepass2android/Resources/values-fi/strings.xml index 15c20c16..50e80297 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. @@ -946,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 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 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 diff --git a/src/keepass2android/Resources/values-ja/strings.xml b/src/keepass2android/Resources/values-ja/strings.xml index 77b48817..3cd8c640 100644 --- a/src/keepass2android/Resources/values-ja/strings.xml +++ b/src/keepass2android/Resources/values-ja/strings.xml @@ -36,8 +36,8 @@ アカウント情報の保存を提案 エントリー画面にグループ名を表示 申し訳ありません! Keepass2Android は、返された URI %1$s を処理できませんでした。開発者にお問い合わせください! - 1 エントリー - %1$d エントリー + 1 件のエントリー + %1$d 件のエントリー アイコンセット さらに探す… セキュリティ @@ -301,6 +301,8 @@ ドメインとアプリパッケージが一致するかどうかの確認を無効にします キーボードとの統合 自動入力のサジェストをキーボード内に表示します (対応する入力方法のみ) + 自動入力表示のログ + (デバッグログが有効な場合) 自動入力表示に関する詳細をデバッグログに書き込みます。自動入力が予想に反する動作をした場合、これらの詳細を開発者に送信することができます。 Android 11 以上が必要 パスワードを探す 期限切れのエントリーを除外する @@ -389,9 +391,9 @@ 証明書の検証に失敗したときの動作を指定します。注意: 検証に失敗したときは、デバイスに証明書をインストールすることができます。 キャッシュをクリアしますか? すべてのキャッシュされたデータベースファイルを削除します。元のデータベースにアクセスできない間に行った、同期されていない変更がすべて失われます! 続行しますか? - 変更をチェック + 変更を確認 変更を保存する前に、ファイルが外部から変更されているか確認します。 - UUID の重複をチェック + UUID の重複を確認 同じ ID で複数のエントリーがあるかによってデータベース ファイルの破損を確認します。これは予期しない動作が発生する可能性があります。 クリップボード通知 ユーザー名とパスワードが、通知バーとクリップボードからアクセス可能になります。パスワード盗聴アプリに気をつけてください! @@ -482,7 +484,7 @@ OTP 補助ファイル エラーが発生しました: データベースが破損しています: 重複する ID が見つかりました。(Minikeepass で保存しましたか?) PC 用 Keepass 2 で新しいデータベースに再インポートして「新しい ID の作成」を選択してください。 - 設定/アプリ設定/ファイル処理/UUID の重複をチェック で、このエラーメッセージを無効にできます。予期しない動作が発生する可能性があることにご注意ください。データベースを修正することをお勧めします。 + 設定/アプリ設定/ファイル処理/UUID の重複を確認 で、このエラーメッセージを無効にできます。予期しない動作が発生する可能性があることにご注意ください。データベースを修正することをお勧めします。 データベースを同期... このグループにグループを移動できません。 今日はオクトーバーフェスト! Keepass2Android を気に入ってくださったなら、今日は私にビールを買っていただくのにいい日ではありませんか? @@ -690,6 +692,7 @@ クラッシュと突発的にログアウトするバグを修正 rsa-sha2-256 などの最新の公開鍵アルゴリズムをサポートする、新しい SFTP 実装に切り替え パスワードをクリップボードにコピーしたとき、機密コンテンツとしてマークするよう変更 (Android 13) + 自動入力の改善 エントリーバックアップの表示、削除、および復元に対応 diff --git a/src/keepass2android/Resources/values-nl/strings.xml b/src/keepass2android/Resources/values-nl/strings.xml index 65d1b352..37331b86 100644 --- a/src/keepass2android/Resources/values-nl/strings.xml +++ b/src/keepass2android/Resources/values-nl/strings.xml @@ -301,6 +301,8 @@ 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 + 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 @@ -687,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 diff --git a/src/keepass2android/Resources/values-pl/strings.xml b/src/keepass2android/Resources/values-pl/strings.xml index f1666033..dc0afe48 100644 --- a/src/keepass2android/Resources/values-pl/strings.xml +++ b/src/keepass2android/Resources/values-pl/strings.xml @@ -687,9 +687,10 @@ 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) + Autofill improvements Dodano wsparcie dla przeglądania, usuwania i przywracania kopii zapasowych wpisów diff --git a/src/keepass2android/Resources/values-pt-rBR/strings.xml b/src/keepass2android/Resources/values-pt-rBR/strings.xml index 5eac17ae..04cfc8dc 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 @@ -690,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) + Melhorias no preenchimento automático Adicionado suporte para visualização, remoção e restauração de backups de entrada diff --git a/src/keepass2android/Resources/values-sk/strings.xml b/src/keepass2android/Resources/values-sk/strings.xml index 549c6622..74edea9f 100644 --- a/src/keepass2android/Resources/values-sk/strings.xml +++ b/src/keepass2android/Resources/values-sk/strings.xml @@ -686,6 +686,12 @@ 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) + Autofill improvements + Pridaná podpora prehliadania, odstraňovania a obnovovania záloh záznamu Implementovaná podpora pre cloudové úložisko MEGA diff --git a/src/keepass2android/Resources/values-sl/strings.xml b/src/keepass2android/Resources/values-sl/strings.xml index 49c868fe..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,6 +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) + Izboljšave samodejnega izpolnjevanja Dodana podpora za ogled, odstranjevanje in obnavljanje varnostnih kopij vnosov diff --git a/src/keepass2android/Resources/values-uk/strings.xml b/src/keepass2android/Resources/values-uk/strings.xml index 510299c7..74531af0 100644 --- a/src/keepass2android/Resources/values-uk/strings.xml +++ b/src/keepass2android/Resources/values-uk/strings.xml @@ -301,6 +301,8 @@ Вимкнення перевірки, якщо збігаються домен і пакунок програми Інтегрувати до клавіатури Показує пропозиції автозаповнення як вбудовану опцію в клавіатурі (якщо підтримується методом вводу) + Журнал перегляду автозаповнення + Записувати подробиці про перегляд автозаповнення до журналу зневадження (якщо увімкнено журнал зневадження). Ці подробиці можна надсилати розробникам, якщо автозаповнення працює некоректно. Потрібна версія Android 11 або новіша Знайти пароль Виключити прострочені елементи @@ -690,6 +692,7 @@ Виправлено помилку зі збоями та несподіваними виходами Перехід на нову реалізацію SFTP з підтримкою сучасних алгоритмів публічного ключа, як-от rsa-sha2-256 Позначати паролі як вразливі під час копіювання до буфера обміну (Android 13) + Вдосконалене автозаповнення Додано підтримку перегляду, видалення та відновлення резервних копій записів diff --git a/src/keepass2android/Resources/values-zh-rTW/strings.xml b/src/keepass2android/Resources/values-zh-rTW/strings.xml index f558af11..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,6 +692,7 @@ 修正當機和意外登出的錯誤 切換成新 SFTP 實作,支援現代公鑰演算法,如 rsa-sha2-256 複製密碼到剪貼簿時設為機密 (Android 13) + 自動填入改進 支援查看、移除和還原項目備份 diff --git a/src/keepass2android/Resources/values-zh/strings.xml b/src/keepass2android/Resources/values-zh/strings.xml index b993ac8c..33c84018 100644 --- a/src/keepass2android/Resources/values-zh/strings.xml +++ b/src/keepass2android/Resources/values-zh/strings.xml @@ -301,6 +301,8 @@ 不检查域名和应用程序包是否匹配 与键盘集成 将自动填充建议显示为键盘中的内联选项(如果输入法支持的话) + 记录自动填充视图 + 将自动填充视图的详情写入调试日志 (如果启用了调试日志)。 如果自动填充无法正常工作,这些细节可以发送给开发者。 需要 Android 11 或更高版本 找回密码 排除过期的条目 @@ -689,6 +691,7 @@ 修复崩溃和意外注销的 bug 切换到新的 SFTP 实现,支持现代公钥算法,例如 rsa-sha2-256 复制到剪贴板时将密码标记为敏感 (Android 13) + 自动填充改进 新增查看、移除和恢复条目备份的功能 diff --git a/src/keepass2android/Resources/values/config.xml b/src/keepass2android/Resources/values/config.xml index 071e9645..3b0f4916 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 @@ -97,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 2b068947..b6de5b13 100644 --- a/src/keepass2android/Resources/values/strings.xml +++ b/src/keepass2android/Resources/values/strings.xml @@ -333,6 +333,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 @@ -692,6 +695,7 @@ TrayTotp Log-File for Debugging Use log file + SFTP debug logging Write app output to a local log file Send debug log... @@ -865,6 +869,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 diff --git a/src/keepass2android/Resources/xml/preferences.xml b/src/keepass2android/Resources/xml/preferences.xml index c159d477..f6e7f871 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" /> + + + + + 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/keepass2android-app.csproj b/src/keepass2android/keepass2android-app.csproj index 4e0ec5a3..07af894c 100644 --- a/src/keepass2android/keepass2android-app.csproj +++ b/src/keepass2android/keepass2android-app.csproj @@ -1,7 +1,7 @@  - + @@ -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/AutofillFieldMetadata.cs b/src/keepass2android/services/AutofillBase/AutofillFieldMetadata.cs index 28c19adc..6b802552 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 { @@ -38,9 +39,8 @@ 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()); - } void SetHints(string[] value) diff --git a/src/keepass2android/services/AutofillBase/AutofillHelper.cs b/src/keepass2android/services/AutofillBase/AutofillHelper.cs index 70581811..28328862 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..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 { @@ -137,7 +138,7 @@ namespace keepass2android.services.AutofillBase return; } - AutofillFieldMetadataCollection autofillFields = parser.AutofillFields; + InlineSuggestionsRequest inlineSuggestionsRequest = null; IList inlinePresentationSpecs = null; if (((int) Build.VERSION.SdkInt >= 30) @@ -149,7 +150,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(); @@ -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 c7a5d330..14fa2367 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"; @@ -37,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 29dd7416..5fb6227a 100644 --- a/src/keepass2android/services/AutofillBase/StructureParser.cs +++ b/src/keepass2android/services/AutofillBase/StructureParser.cs @@ -1,334 +1,206 @@ 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 FilledAutofillFieldCollection = keepass2android.services.AutofillBase.model.FilledAutofillFieldCollection; +using Kp2aAutofillParser; +using Newtonsoft.Json; 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)); + + 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 /// 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; } - 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; } public StructureParser(Context context, AssistStructure structure) + : base(new Kp2aLogger(), new Kp2aDigitalAssetLinksDataSource(context)) { - kp2aDigitalAssetLinksDataSource = new Kp2aDigitalAssetLinksDataSource(context); - mContext = context; - Structure = structure; - AutofillFields = new AutofillFieldMetadataCollection(); - domainSuffixParserCache = new PublicSuffixRuleCache(context); - } + _context = context; + _structure = structure; + AutofillFields = new AutofillFieldMetadataCollection(); + LogAutofillView = PreferenceManager.GetDefaultSharedPreferences(context).GetBoolean(context.GetString(Resource.String.LogAutofillView_key), false); - 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; - } - } } - 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); - var nodes = Structure.WindowNodeCount; - ClientFormData = new FilledAutofillFieldCollection(); - String webDomain = null; - _editTextsWithoutHint.Clear(); + if (autofillView == null) + Kp2aLog.Log("Received null autofill view!"); + var result = base.Parse(forFill, isManualRequest, autofillView); - for (int i = 0; i < nodes; i++) - { - var node = Structure.GetWindowNodeAt(i); - - var view = node.RootViewNode; - ParseLocked(forFill, isManualRequest, view, ref webDomain); - } - - - - 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.AutofillId != passwordField.AutofillId).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 (AssistStructure.ViewNode 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, new[] { View.AutofillHintUsername })); - foreach (var pf in passwordFields) - AutofillFields.Add(new AutofillFieldMetadata(pf, new[] { View.AutofillHintPassword })); + Kp2aLog.Log("Parsing done"); + if (forFill) + { + 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, new[] { View.AutofillHintUsername })); - foreach (var pf in passwordFields) - ClientFormData.Add(new FilledAutofillField(pf, new[] { View.AutofillHintPassword })); - } - - - result.WebDomain = webDomain; - result.PackageName = Structure.ActivityComponent.PackageName; - if (!string.IsNullOrEmpty(webDomain) && !PreferenceManager.GetDefaultSharedPreferences(mContext).GetBoolean(mContext.GetString(Resource.String.NoDalVerification_key), false)) - { - result.IncompatiblePackageAndDomain = !kp2aDigitalAssetLinksDataSource.IsTrustedLink(webDomain, result.PackageName); - if (result.IncompatiblePackageAndDomain) - { - CommonUtil.loge($"DAL verification failed for {result.PackageName}/{result.WebDomain}"); - } - } else { - result.IncompatiblePackageAndDomain = false; + ClientFormData = new FilledAutofillFieldCollection(); + foreach (var p in FieldsMappedToHints) + ClientFormData.Add(new FilledAutofillField(p.Key, p.Value)); } - return result; - } - private static readonly HashSet _passwordHints = new HashSet { "password","passwort" }; - private static bool HasPasswordHint(AssistStructure.ViewNode 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 static bool HasUsernameHint(AssistStructure.ViewNode 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(AssistStructure.ViewNode 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.HtmlInfo?.Attributes.Any(p => p.First.ToString() == "type" && p.Second.ToString() == "password") ?? false) - ); - } + return result; + } - + public AutofillTargetId ParseForSave() + { + var autofillView = new AutofillViewFromAssistStructureFinder(_context, _structure).GetAutofillView(true); + return Parse(false, true, autofillView); + } - 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; - } + public StructureParserBase.AutofillTargetId ParseForFill(bool isManual) + { + var autofillView = new AutofillViewFromAssistStructureFinder(_context, _structure).GetAutofillView(isManual); + return Parse(true, isManual, autofillView); + } + - 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); - } - } - } - - } + public class Kp2aLogger : ILogger + { + public void Log(string x) + { + Kp2aLog.Log(x); + } + } } 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 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 + } }; } diff --git a/src/keepass2android/services/Kp2aAutofill/ChooseForAutofillActivity.cs b/src/keepass2android/services/Kp2aAutofill/ChooseForAutofillActivity.cs index bd2f9b3c..49a9e893 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,11 +51,11 @@ 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()) 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/settings/DatabaseSettingsActivity.cs b/src/keepass2android/settings/DatabaseSettingsActivity.cs index d857824a..bfe934da 100644 --- a/src/keepass2android/settings/DatabaseSettingsActivity.cs +++ b/src/keepass2android/settings/DatabaseSettingsActivity.cs @@ -176,6 +176,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" }; ListPreference appLanguagePref = (ListPreference)FindPreference(GetString(Resource.String.app_language_pref_key)); @@ -417,18 +423,37 @@ 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(); - } +#if !EXCLUDE_JAVAFILESTORAGE && !NoNet + bool jschLogEnable = PreferenceManager.GetDefaultSharedPreferences(Application.Context) + .GetBoolean(Application.Context.GetString(Resource.String.JSchDebug_key), false); + SetJSchLogging(jschLogEnable); +#endif + } - private void AlgorithmPrefChange(object sender, Preference.PreferenceChangeEventArgs preferenceChangeEventArgs) +#if !EXCLUDE_JAVAFILESTORAGE && !NoNet + 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); + } +#endif + + private void AlgorithmPrefChange(object sender, Preference.PreferenceChangeEventArgs preferenceChangeEventArgs) { var db = App.Kp2a.CurrentDb; var previousCipher = db.KpDatabase.DataCipherUuid; @@ -871,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) 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; 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;