Compare commits
143 Commits
1.09e-r1
...
bug-2378-p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3ae3233fe | ||
|
|
bc464b0eba | ||
|
|
9b3d7250ec | ||
|
|
b04f7f6c81 | ||
|
|
41151a184b | ||
|
|
9d9b24cb98 | ||
|
|
087e3f5931 | ||
|
|
100ed6e58e | ||
|
|
a5bce53a12 | ||
|
|
c9be806b01 | ||
|
|
c16eeff130 | ||
|
|
03ea073426 | ||
|
|
cde5d31845 | ||
|
|
85709e4058 | ||
|
|
3f6e51b126 | ||
|
|
c0345d1309 | ||
|
|
746dcd4c6b | ||
|
|
37a6da5a3b | ||
|
|
1efe2e16a5 | ||
|
|
5cbddb4fcc | ||
|
|
b3a73f20d4 | ||
|
|
badf99c20d | ||
|
|
b8318f7fa5 | ||
|
|
f0e30459a2 | ||
|
|
e101ffb01e | ||
|
|
a05ef51d44 | ||
|
|
8aacdf683b | ||
|
|
0502efde14 | ||
|
|
94ede3a696 | ||
|
|
9933fa1f9d | ||
|
|
4910c73a5e | ||
|
|
cf222a2db1 | ||
|
|
a9ad3725dc | ||
|
|
40d3fe1cd9 | ||
|
|
1e90a52275 | ||
|
|
8596edaa67 | ||
|
|
38f1aa4d3d | ||
|
|
984da3fd3b | ||
|
|
ed7138991d | ||
|
|
1e78527164 | ||
|
|
a6540b4462 | ||
|
|
230b3941e8 | ||
|
|
554f88c723 | ||
|
|
4cd32d30c6 | ||
|
|
a76c43a800 | ||
|
|
d0da83182f | ||
|
|
ec5f26e0cd | ||
|
|
6110166af8 | ||
|
|
6f10a04589 | ||
|
|
eedeeafd80 | ||
|
|
e0c003fcb2 | ||
|
|
ad3b1500bb | ||
|
|
5f2a976fde | ||
|
|
dd0becdfd8 | ||
|
|
cacd204ac2 | ||
|
|
728fd2f8ae | ||
|
|
944f44bc4b | ||
|
|
58047d5386 | ||
|
|
c0a06c9f3a | ||
|
|
d0c041a0e2 | ||
|
|
df060e2f4b | ||
|
|
aea55dad45 | ||
|
|
5442dbf441 | ||
|
|
317476d9b5 | ||
|
|
ad0acb7a69 | ||
|
|
b66ae5d264 | ||
|
|
d87706fa43 | ||
|
|
cb25d12709 | ||
|
|
dce536009e | ||
|
|
656e785214 | ||
|
|
35d50a6eb0 | ||
|
|
786bb646c2 | ||
|
|
72cc6ff768 | ||
|
|
404e07e5c0 | ||
|
|
1c7159ede9 | ||
|
|
2378cd0d7c | ||
|
|
b149bab761 | ||
|
|
5ebd8e5e33 | ||
|
|
db6b266a59 | ||
|
|
7de28c5aba | ||
|
|
ed79df0c6d | ||
|
|
4949fede32 | ||
|
|
bddef6442c | ||
|
|
48a6d0a2ad | ||
|
|
ac5f3c9ca5 | ||
|
|
93e1cf1147 | ||
|
|
a805787a95 | ||
|
|
85315d0ecc | ||
|
|
595a451f77 | ||
|
|
914224e4fa | ||
|
|
e350e8788c | ||
|
|
ca5f6dc43c | ||
|
|
0d4955622d | ||
|
|
886daa6b27 | ||
|
|
8fa0803474 | ||
|
|
4cad70e750 | ||
|
|
c29b789a2b | ||
|
|
cd34896661 | ||
|
|
1e02db86d6 | ||
|
|
994741cbf5 | ||
|
|
58844be6eb | ||
|
|
2d899fa067 | ||
|
|
060bf6a6ee | ||
|
|
890f1bd704 | ||
|
|
139abcaec6 | ||
|
|
78a48b75b8 | ||
|
|
3918b06b1f | ||
|
|
40847ebe31 | ||
|
|
34cac86a9b | ||
|
|
d8598a53e0 | ||
|
|
92d9eb1512 | ||
|
|
1be7b33f6b | ||
|
|
8464fa4f29 | ||
|
|
eff9a96bd5 | ||
|
|
bd4e321b0e | ||
|
|
47aaedbfb5 | ||
|
|
3043f8981d | ||
|
|
cfd413f1f4 | ||
|
|
30df03eec6 | ||
|
|
5048f63204 | ||
|
|
7557c0b9fd | ||
|
|
9346f6bb32 | ||
|
|
23d7efff53 | ||
|
|
c7eb2bf873 | ||
|
|
632121f3ec | ||
|
|
f7feddcf1f | ||
|
|
e745fee6e2 | ||
|
|
bcc17d91bd | ||
|
|
8c8a8e3968 | ||
|
|
3c41550404 | ||
|
|
76107b1207 | ||
|
|
bb0c13b9d8 | ||
|
|
405166ba9d | ||
|
|
f5cb60770e | ||
|
|
fd287b8da7 | ||
|
|
9bea5b13e3 | ||
|
|
aa6a728e8c | ||
|
|
1c8431a3f9 | ||
|
|
6a0eacd8f1 | ||
|
|
d27976b737 | ||
|
|
f312b50f0c | ||
|
|
deb169fece | ||
|
|
2df656211d |
53
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
Normal file
@@ -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
|
||||
|
||||
8
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
name: Feature Request
|
||||
about: Suggest an idea for this project.
|
||||
title: '[FEAT] '
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
16
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
@@ -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:
|
||||
|
||||
165
.github/workflows/build.yml
vendored
@@ -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: |
|
||||
|
||||
12
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:
|
||||
|
||||
@@ -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 <repo_name> mono-devel msbuild`. A value for `<repo_name>` 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
|
||||
|
||||
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 87 KiB |
@@ -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)
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 2.9 KiB |
@@ -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
|
||||
|
||||
987
src/Kp2aAutofillParser/AutofillParser.cs
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// FilledAutofillFieldCollection is the model that holds all of the data on a client app's page,
|
||||
/// plus the dataset name associated with it.
|
||||
/// </summary>
|
||||
public class FilledAutofillFieldCollection<FieldT> where FieldT:InputField
|
||||
{
|
||||
public Dictionary<string, FilledAutofillField> HintMap { get; }
|
||||
public string DatasetName { get; set; }
|
||||
|
||||
public FilledAutofillFieldCollection(Dictionary<string, FilledAutofillField> 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<string, FilledAutofillField> BuildHintMap()
|
||||
{
|
||||
return new Dictionary<string, FilledAutofillField>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a filledAutofillField to the collection, indexed by all of its hints.
|
||||
/// </summary>
|
||||
/// <returns>The add.</returns>
|
||||
/// <param name="filledAutofillField">Filled autofill field.</param>
|
||||
public void Add(FilledAutofillField filledAutofillField)
|
||||
{
|
||||
foreach (string hint in filledAutofillField.AutofillHints)
|
||||
{
|
||||
if (AutofillHintsHelper.IsSupportedHint(hint))
|
||||
{
|
||||
HintMap.TryAdd(hint, filledAutofillField);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c>, if with hints was helpsed, <c>false</c> otherwise.</returns>
|
||||
/// <param name="autofillHints">Autofill hints.</param>
|
||||
public bool HelpsWithHints(List<string> 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<string> _allSupportedHints = new HashSet<string>(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<HashSet<string>> partitionsOfCanonicalHints = new List<HashSet<string>>()
|
||||
{
|
||||
|
||||
new HashSet<string>(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<string>(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<string>(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<string, string> hintToCanonicalReplacement = new Dictionary<string, string>(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<string>();
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// transforms hints by replacing some W3cHints by their Android counterparts and transforming everything to lowercase
|
||||
/// </summary>
|
||||
public static List<string> ConvertToCanonicalLowerCaseHints(string[] supportedHints)
|
||||
{
|
||||
List<string> result = new List<string>();
|
||||
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<FieldT> FilterForPartition<FieldT>(FilledAutofillFieldCollection<FieldT> autofillFields, int partitionIndex) where FieldT: InputField
|
||||
{
|
||||
FilledAutofillFieldCollection<FieldT> filteredCollection =
|
||||
new FilledAutofillFieldCollection<FieldT> { 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<FieldT> FilterForPartition<FieldT>(FilledAutofillFieldCollection<FieldT> filledAutofillFieldCollection, List<string> 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;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// This enum represents the Android.Text.InputTypes values. For testability, this is duplicated here.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// returns the autofill hints for the filled field. These are always lowercased for simpler string comparison.
|
||||
/// </summary>
|
||||
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<string> hintList = new List<string>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializable structure defining the contents of the current view (from an autofill perspective)
|
||||
/// </summary>
|
||||
/// <typeparam name="TField"></typeparam>
|
||||
public class AutofillView<TField> where TField : InputField
|
||||
{
|
||||
public List<TField> InputFields { get; set; } = new List<TField>();
|
||||
|
||||
public string PackageId { get; set; } = null;
|
||||
public string WebDomain { get; set; } = null;
|
||||
}
|
||||
|
||||
public interface ILogger
|
||||
{
|
||||
void Log(string x);
|
||||
}
|
||||
|
||||
public class StructureParserBase<FieldT> where FieldT: InputField
|
||||
{
|
||||
private readonly ILogger _log;
|
||||
private readonly IKp2aDigitalAssetLinksDataSource _digitalAssetLinksDataSource;
|
||||
|
||||
private readonly List<string> _autofillHintsForLogin = new List<string>
|
||||
{
|
||||
AutofillHintsHelper.AutofillHintPassword,
|
||||
AutofillHintsHelper.AutofillHintUsername,
|
||||
AutofillHintsHelper.AutofillHintEmailAddress
|
||||
};
|
||||
|
||||
public string PackageId { get; set; }
|
||||
|
||||
public Dictionary<FieldT, string[]> FieldsMappedToHints = new Dictionary<FieldT, string[]>();
|
||||
|
||||
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; }
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public bool IncompatiblePackageAndDomain { get; set; }
|
||||
|
||||
public string DomainOrPackage
|
||||
{
|
||||
get
|
||||
{
|
||||
return WebDomain ?? PackageNameWithPseudoSchema;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public AutofillTargetId ParseForFill(bool isManual, AutofillView<FieldT> autofillView)
|
||||
{
|
||||
return Parse(true, isManual, autofillView);
|
||||
}
|
||||
|
||||
public AutofillTargetId ParseForSave(AutofillView<FieldT> autofillView)
|
||||
{
|
||||
return Parse(false, true, autofillView);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Traverse AssistStructure and add ViewNode metadata to a flat list.
|
||||
/// </summary>
|
||||
/// <returns>The parse.</returns>
|
||||
/// <param name="forFill">If set to <c>true</c> for fill.</param>
|
||||
/// <param name="isManualRequest"></param>
|
||||
protected virtual AutofillTargetId Parse(bool forFill, bool isManualRequest, AutofillView<FieldT> 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<string> 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<FieldT> editTexts = autofillView.InputFields.Where(f => IsEditText(f)).ToList();
|
||||
List<FieldT> 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<FieldT> 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<string> _passwordHints = new HashSet<string> { "password", "passwort", "passwordAuto", "pswd" };
|
||||
private static bool HasPasswordHint(InputField f)
|
||||
{
|
||||
return IsAny(f.IdEntry, _passwordHints) ||
|
||||
IsAny(f.Hint, _passwordHints);
|
||||
}
|
||||
|
||||
private static readonly HashSet<string> _usernameHints = new HashSet<string> { "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<string> 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")
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
12
src/Kp2aAutofillParser/Kp2aAutofillParser.csproj
Normal file
@@ -0,0 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
145
src/Kp2aAutofillParserTest/AutofillTest.cs
Normal file
@@ -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<TestInputField>? autofillView =
|
||||
JsonConvert.DeserializeObject<AutofillView<TestInputField>>(input);
|
||||
|
||||
StructureParserBase<TestInputField> parser =
|
||||
new StructureParserBase<TestInputField>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
62
src/Kp2aAutofillParserTest/Kp2aAutofillParserTest.csproj
Normal file
@@ -0,0 +1,62 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="chrome-android10-amazon-it.json" />
|
||||
<None Remove="com-expressvpn-vpn-android13.json" />
|
||||
<None Remove="com-ifs-banking-fiid3364-android13.json" />
|
||||
<None Remove="com-servicenet-mobile-focused.json" />
|
||||
<None Remove="com-servicenet-mobile-no-focus.json" />
|
||||
<None Remove="firefox-amazon-it.json" />
|
||||
<None Remove="imdb.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
|
||||
<PackageReference Include="xunit" Version="2.4.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="3.1.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Kp2aAutofillParser\Kp2aAutofillParser.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="chrome-android10-amazon-it.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="com-expressvpn-vpn-android13.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="com-ifs-banking-fiid3364-android13.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="firefox-amazon-it.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="com-servicenet-mobile-focused.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="com-servicenet-mobile-no-focus.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="imdb.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
1
src/Kp2aAutofillParserTest/Usings.cs
Normal file
@@ -0,0 +1 @@
|
||||
global using Xunit;
|
||||
2018
src/Kp2aAutofillParserTest/chrome-android10-amazon-it.json
Normal file
226
src/Kp2aAutofillParserTest/com-expressvpn-vpn-android13.json
Normal file
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
121
src/Kp2aAutofillParserTest/com-servicenet-mobile-focused.json
Normal file
@@ -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
|
||||
}
|
||||
119
src/Kp2aAutofillParserTest/com-servicenet-mobile-no-focus.json
Normal file
@@ -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
|
||||
}
|
||||
469
src/Kp2aAutofillParserTest/firefox-amazon-it.json
Normal file
@@ -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"
|
||||
}
|
||||
728
src/Kp2aAutofillParserTest/imdb.json
Normal file
@@ -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"
|
||||
}
|
||||
@@ -3,14 +3,15 @@ using Android.Content;
|
||||
|
||||
namespace keepass2android.Io
|
||||
{
|
||||
public partial class PCloudFileStorage: JavaFileStorage
|
||||
public class PCloudFileStorage: JavaFileStorage
|
||||
{
|
||||
private const string ClientId = "CkRWTQXY6Lm";
|
||||
|
||||
public PCloudFileStorage(Context ctx, IKp2aApp app) :
|
||||
base(new Keepass2android.Javafilestorage.PCloudFileStorage(ctx, ClientId), app)
|
||||
base(new Keepass2android.Javafilestorage.PCloudFileStorage(ctx, ClientId, "pcloud", ""), app)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public override bool UserShouldBackup
|
||||
@@ -18,6 +19,23 @@ namespace keepass2android.Io
|
||||
get { return false; }
|
||||
}
|
||||
}
|
||||
public class PCloudFileStorageAll : JavaFileStorage
|
||||
{
|
||||
private const string ClientId = "FLm22de7bdS";
|
||||
|
||||
public PCloudFileStorageAll(Context ctx, IKp2aApp app) :
|
||||
base(new Keepass2android.Javafilestorage.PCloudFileStorage(ctx, ClientId, "pcloudall", "PCLOUDALL_"), app)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public override bool UserShouldBackup
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
BIN
src/PCloudBindings/Jars/pcloud-sdk-android-1.8.1.aar
Normal file
BIN
src/PCloudBindings/Jars/pcloud-sdk-java-core-1.8.1.jar
Normal file
@@ -56,7 +56,7 @@
|
||||
<ItemGroup>
|
||||
<None Include="Jars\AboutJars.txt" />
|
||||
<None Include="Additions\AboutAdditions.txt" />
|
||||
<LibraryProjectZip Include="Jars\pcloud-sdk-android-1.2.0.aar" />
|
||||
<LibraryProjectZip Include="Jars\pcloud-sdk-android-1.8.1.aar" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<TransformFile Include="Transforms\Metadata.xml" />
|
||||
@@ -72,6 +72,6 @@
|
||||
</Target>
|
||||
-->
|
||||
<ItemGroup>
|
||||
<EmbeddedReferenceJar Include="Jars\pcloud-sdk-java-core-1.2.0.jar" />
|
||||
<EmbeddedReferenceJar Include="Jars\pcloud-sdk-java-core-1.8.1.jar" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<PropertyGroup>
|
||||
|
||||
|
||||
<Flavor>NoNet</Flavor>
|
||||
<xFlavor>Net</xFlavor>
|
||||
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
@@ -47,8 +47,8 @@ dependencies {
|
||||
implementation('com.onedrive.sdk:onedrive-sdk-android:1.2.0') {
|
||||
transitive = false
|
||||
}
|
||||
implementation 'com.pcloud.sdk:java-core:1.2.0'
|
||||
implementation 'com.pcloud.sdk:android:1.2.0'
|
||||
implementation 'com.pcloud.sdk:java-core:1.8.1'
|
||||
implementation 'com.pcloud.sdk:android:1.8.1'
|
||||
implementation 'com.google.code.gson:gson:2.8.6'
|
||||
implementation 'com.microsoft.services.msa:msa-auth:0.8.6'
|
||||
implementation 'com.microsoft.aad:adal:1.14.0'
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.pcloud.sdk.ApiError;
|
||||
import com.pcloud.sdk.Authenticators;
|
||||
import com.pcloud.sdk.AuthorizationActivity;
|
||||
import com.pcloud.sdk.AuthorizationData;
|
||||
import com.pcloud.sdk.AuthorizationRequest;
|
||||
import com.pcloud.sdk.AuthorizationResult;
|
||||
import com.pcloud.sdk.Call;
|
||||
import com.pcloud.sdk.DataSource;
|
||||
@@ -47,11 +48,19 @@ public class PCloudFileStorage extends JavaFileStorageBase
|
||||
|
||||
private ApiClient apiClient;
|
||||
private String clientId;
|
||||
private String protocolId;
|
||||
|
||||
public PCloudFileStorage(Context ctx, String clientId) {
|
||||
///prefix for SHARED_PREF keys so we can distinguish between different instances
|
||||
private String sharedPrefPrefix;
|
||||
|
||||
public PCloudFileStorage(Context ctx, String clientId, String protocolId, String sharedPrefPrefix) {
|
||||
this.ctx = ctx;
|
||||
this.clientId = clientId;
|
||||
this.protocolId = protocolId;
|
||||
this.sharedPrefPrefix = sharedPrefPrefix;
|
||||
|
||||
this.apiClient = createApiClientFromSharedPrefs();
|
||||
android.util.Log.d("KP2A", "Init pcloud with protocol " + protocolId + ", prefix=" + sharedPrefPrefix + ", clientId=" + clientId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -86,7 +95,8 @@ public class PCloudFileStorage extends JavaFileStorageBase
|
||||
|
||||
@Override
|
||||
public String getProtocolId() {
|
||||
return "pcloud";
|
||||
|
||||
return protocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -228,11 +238,17 @@ public class PCloudFileStorage extends JavaFileStorageBase
|
||||
finishActivityWithSuccess(activity);
|
||||
} else if (!activity.getState().getBoolean("hasStartedAuth", false)) {
|
||||
Activity castedActivity = (Activity)activity;
|
||||
Intent authIntent = AuthorizationActivity.createIntent(castedActivity, this.clientId);
|
||||
AuthorizationRequest req = AuthorizationRequest.create()
|
||||
.setClientId(this.clientId)
|
||||
.setType(AuthorizationRequest.Type.TOKEN)
|
||||
.setForceAccessApproval(true)
|
||||
.build();
|
||||
Intent authIntent = AuthorizationActivity.createIntent(castedActivity, req);
|
||||
castedActivity.startActivityForResult(authIntent, PCLOUD_AUTHORIZATION_REQUEST_CODE);
|
||||
activity.getState().putBoolean("hasStartedAuth", true);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -273,7 +289,7 @@ public class PCloudFileStorage extends JavaFileStorageBase
|
||||
}
|
||||
|
||||
private ApiClient createApiClientFromSharedPrefs() {
|
||||
SharedPreferences prefs = this.ctx.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE);
|
||||
SharedPreferences prefs = this.ctx.getSharedPreferences(sharedPrefPrefix + SHARED_PREF_NAME, Context.MODE_PRIVATE);
|
||||
String authToken = prefs.getString(SHARED_PREF_AUTH_TOKEN, null);
|
||||
String apiHost = prefs.getString(SHARED_PREF_API_HOST, null);
|
||||
return this.createApiClient(authToken, apiHost);
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.jcraft.jsch.UserInfo;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
public class SftpStorage extends JavaFileStorageBase {
|
||||
|
||||
@@ -323,6 +324,8 @@ public class SftpStorage extends JavaFileStorageBase {
|
||||
jsch = new JSch();
|
||||
ConnectionInfo ci = splitStringToConnectionInfo(filename);
|
||||
|
||||
Log.d("KP2AJFS", "init SFTP");
|
||||
|
||||
String base_dir = getBaseDir();
|
||||
jsch.setKnownHosts(base_dir + "/known_hosts");
|
||||
|
||||
@@ -340,7 +343,9 @@ public class SftpStorage extends JavaFileStorageBase {
|
||||
|
||||
}
|
||||
|
||||
Log.e("KP2AJFS[thread]", "getting session...");
|
||||
Session session = jsch.getSession(ci.username, ci.host, ci.port);
|
||||
Log.e("KP2AJFS", "creating SftpUserInfo");
|
||||
UserInfo ui = new SftpUserInfo(ci.password,_appContext);
|
||||
session.setUserInfo(ui);
|
||||
|
||||
@@ -395,12 +400,16 @@ public class SftpStorage extends JavaFileStorageBase {
|
||||
ci.password = decode(userPwd.substring(userPwd.indexOf(":")+1));
|
||||
ci.host = ci.host.substring(ci.host.indexOf('@') + 1);
|
||||
ci.port = DEFAULT_SFTP_PORT;
|
||||
int portSeparatorIndex = ci.host.indexOf(":");
|
||||
int portSeparatorIndex = ci.host.lastIndexOf(":");
|
||||
if (portSeparatorIndex >= 0)
|
||||
{
|
||||
ci.port = Integer.parseInt(ci.host.substring(portSeparatorIndex+1));
|
||||
ci.host = ci.host.substring(0, portSeparatorIndex);
|
||||
}
|
||||
// Encode/decode required to support IPv6 (colons break host:port parse logic)
|
||||
// See Bug #2350
|
||||
ci.host = decode(ci.host);
|
||||
|
||||
ci.localPath = extractSessionPath(filename);
|
||||
return ci;
|
||||
}
|
||||
@@ -471,6 +480,10 @@ public class SftpStorage extends JavaFileStorageBase {
|
||||
|
||||
public String buildFullPath( String host, int port, String localPath, String username, String password) throws UnsupportedEncodingException
|
||||
{
|
||||
// Encode/decode required to support IPv6 (colons break host:port parse logic)
|
||||
// See Bug #2350
|
||||
host = encode(host);
|
||||
|
||||
if (port != DEFAULT_SFTP_PORT)
|
||||
host += ":"+String.valueOf(port);
|
||||
return getProtocolPrefix()+encode(username)+":"+encode(password)+"@"+host+localPath;
|
||||
|
||||
@@ -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,7 +50,16 @@ public class SftpUserInfo implements UserInfo {
|
||||
intent.putExtra("keepass2android.sftp.prompt", text);
|
||||
intent.setData((Uri.parse("suckit://"+SystemClock.elapsedRealtime())));
|
||||
|
||||
PendingIntent contentIntent = PendingIntent.getActivity(_appContext, 0, intent, 0);
|
||||
|
||||
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);
|
||||
|
||||
builder.setContentIntent(contentIntent);
|
||||
|
||||
{
|
||||
|
||||
|
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 11 KiB |
1
src/java/JavaFileStorage/gradle.properties
Normal file
@@ -0,0 +1 @@
|
||||
org.gradle.jvmargs=-Xmx1536m
|
||||
1
src/java/JavaFileStorage/settings.gradle
Normal file
@@ -0,0 +1 @@
|
||||
include ':app'
|
||||
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 7.9 KiB |
@@ -19,4 +19,4 @@
|
||||
|
||||
android.enableJetifier=true
|
||||
android.useAndroidX=true
|
||||
org.gradle.jvmargs=-Xmx2048m
|
||||
org.gradle.jvmargs=-Xmx1536m
|
||||
|
||||
1
src/java/KP2AKdbLibrary/gradle.properties
Normal file
@@ -0,0 +1 @@
|
||||
org.gradle.jvmargs=-Xmx1536m
|
||||
|
Before Width: | Height: | Size: 511 B After Width: | Height: | Size: 391 B |
|
Before Width: | Height: | Size: 760 B After Width: | Height: | Size: 634 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 913 B |
|
Before Width: | Height: | Size: 730 B After Width: | Height: | Size: 434 B |
|
Before Width: | Height: | Size: 940 B After Width: | Height: | Size: 540 B |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 461 B After Width: | Height: | Size: 277 B |
|
Before Width: | Height: | Size: 332 B After Width: | Height: | Size: 192 B |
|
Before Width: | Height: | Size: 498 B After Width: | Height: | Size: 326 B |
|
Before Width: | Height: | Size: 811 B After Width: | Height: | Size: 659 B |
|
Before Width: | Height: | Size: 715 B After Width: | Height: | Size: 442 B |
|
Before Width: | Height: | Size: 1001 B After Width: | Height: | Size: 577 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 892 B |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 745 B After Width: | Height: | Size: 451 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 614 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 903 B |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 833 B After Width: | Height: | Size: 432 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 226 B After Width: | Height: | Size: 166 B |
|
Before Width: | Height: | Size: 807 B After Width: | Height: | Size: 507 B |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 690 B |
|
Before Width: | Height: | Size: 681 B After Width: | Height: | Size: 427 B |
|
Before Width: | Height: | Size: 548 B After Width: | Height: | Size: 345 B |
|
Before Width: | Height: | Size: 438 B After Width: | Height: | Size: 274 B |
|
Before Width: | Height: | Size: 200 B After Width: | Height: | Size: 152 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 972 B |
|
Before Width: | Height: | Size: 379 B After Width: | Height: | Size: 227 B |
|
Before Width: | Height: | Size: 301 B After Width: | Height: | Size: 186 B |
|
Before Width: | Height: | Size: 404 B After Width: | Height: | Size: 237 B |
|
Before Width: | Height: | Size: 413 B After Width: | Height: | Size: 240 B |
|
Before Width: | Height: | Size: 341 B After Width: | Height: | Size: 214 B |
|
Before Width: | Height: | Size: 388 B After Width: | Height: | Size: 227 B |
|
Before Width: | Height: | Size: 413 B After Width: | Height: | Size: 244 B |