summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md15
-rw-r--r--.github/ISSUE_TEMPLATE/feature_request.md17
-rwxr-xr-x.github/checksum.sh23
-rw-r--r--.github/workflows/deploy_snapshot.yml49
-rw-r--r--.github/workflows/draft_new_release.yml15
-rw-r--r--.github/workflows/pull_request.yml41
-rw-r--r--.github/workflows/release.yml34
-rw-r--r--.github/workflows/update_publicsuffix_data.yml15
-rw-r--r--.gitmodules0
-rw-r--r--CHANGELOG.md11
-rw-r--r--app/build.gradle.kts4
-rw-r--r--app/src/main/AndroidManifest.xml3
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/Application.kt12
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/ClipboardService.kt6
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/SearchableRepositoryViewModel.kt2
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/UserPreference.kt6
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillResponseBuilder.kt9
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillPublisherChangedActivity.kt14
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillSaveActivity.kt2
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/crypto/BasePgpActivity.kt10
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/crypto/DecryptActivity.kt2
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/crypto/PasswordCreationActivity.kt16
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/BaseGitActivity.kt3
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/GitCommandExecutor.kt4
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/config/GitSettings.kt38
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/log/GitLogModel.kt2
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/sshj/SshKey.kt4
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/model/PasswordEntry.kt2
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/ui/onboarding/fragments/CloneFragment.kt2
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/ui/onboarding/fragments/KeySelectionFragment.kt66
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/ui/onboarding/fragments/RepoLocationFragment.kt15
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/ui/proxy/ProxySelectorActivity.kt75
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/utils/AndroidExtensions.kt6
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/utils/BiometricAuthenticator.kt9
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/utils/PasswordRepository.kt2
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/utils/PreferenceKeys.kt6
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/utils/ProxyUtils.kt66
-rw-r--r--app/src/main/res/layout/activity_oreo_autofill_publisher_changed.xml104
-rw-r--r--app/src/main/res/layout/activity_proxy_selector.xml106
-rw-r--r--app/src/main/res/layout/fragment_key_selection.xml81
-rw-r--r--app/src/main/res/values-v23/colors.xml8
-rw-r--r--app/src/main/res/values/colors.xml2
-rw-r--r--app/src/main/res/values/strings.xml15
-rw-r--r--app/src/main/res/xml/preference.xml3
-rw-r--r--autofill-parser/api/autofill-parser.api381
-rw-r--r--autofill-parser/build.gradle.kts33
-rw-r--r--autofill-parser/gradle.properties2
-rw-r--r--autofill-parser/src/main/assets/publicsuffixesbin105817 -> 107275 bytes
-rw-r--r--autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillStrategyDsl.kt12
-rw-r--r--autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/FormField.kt2
-rw-r--r--autofill-parser/src/main/java/mozilla/components/lib/publicsuffixlist/PublicSuffixList.kt2
-rw-r--r--build.gradle.kts14
-rw-r--r--buildSrc/src/main/java/Dependencies.kt23
-rw-r--r--contrib/oisafe2pstore/oisafe2pstore.hs85
-rw-r--r--crowdin.yml3
-rwxr-xr-xrelease/deploy-github.sh12
-rwxr-xr-xrelease/signing-setup.sh2
57 files changed, 1112 insertions, 384 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 435cbdcb..a7ef0f2d 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -1,12 +1,23 @@
---
name: Bug report
-about: Create a report to help us improve
+about: Create a report to help us address issues you are facing with the app
title: "[BUG]"
-labels: bug
+labels: bug, 'triage: needed'
assignees: ''
---
+<!--
+Thanks for taking the time to file this issue! Here are a few things to check before clicking the submit button :)
+
+1. Make sure you're on the latest version of the app. The current release can be found here: https://github.com/android-password-store/android-password-store/releases/latest.
+
+2. Search through **both** open and closed issues for your bug: https://github.com/android-password-store/Android-Password-Store/issues?q=is%3Aissue+sort%3Aupdated-desc+.
+
+3. ALWAYS fill this template. If you fail to do so, your issue will be immediately closed with no response. Maintaining open source projects for free is hard work, and we expect users to respect that time and effort by putting in a little bit of their own. That helps us fix these problems faster and in return you get a better app — everybody wins.
+
+-->
+
**Describe the bug**
A clear and concise description of what the bug is.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index f4558654..66ac7d34 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -1,12 +1,23 @@
---
name: Feature request
-about: Suggest an idea for this project
+about: Suggest a new feature to be included in the app
title: "[FEATURE]"
-labels: enhancement
-assignees: ''
+labels: feature, 'triage: needed'
+assignees: 'msfjarvis'
---
+<!--
+Thanks for taking the time to file this issue! Here are a few things to check before clicking the submit button :)
+
+1. Make sure you're on the latest version of the app. Features are being added all the time and it is entirely possible what you're requesting has already been added. The current release can be found here: https://github.com/android-password-store/android-password-store/releases/latest.
+
+2. Check the changelog file to confirm that the feature hasn't been added for an upcoming release: https://github.com/android-password-store/Android-Password-Store/blob/develop/CHANGELOG.md.
+
+3. ALWAYS fill this template. If you fail to do so, your issue will be immediately closed with no response. Maintaining open source projects for free is hard work, and we expect users to respect that time and effort by putting in a little bit of their own. A feature request that is clear and explicit in its needs lets us get to work faster.
+
+-->
+
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
diff --git a/.github/checksum.sh b/.github/checksum.sh
deleted file mode 100755
index a1c7791a..00000000
--- a/.github/checksum.sh
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/env bash
-RESULT_FILE=$1
-
-if [ -f $RESULT_FILE ]; then
- rm $RESULT_FILE
-fi
-touch $RESULT_FILE
-
-checksum_file() {
- echo $(sha256sum $1 | awk '{print $1}')
-}
-
-FILES=()
-while read -r -d ''; do
- FILES+=("$REPLY")
-done < <(find . -type f \( -name "build.gradle*" -o -name "dependencies.gradle" -o -name "gradle-wrapper.properties" \) -print0)
-
-# Loop through files and append MD5 to result file
-for FILE in ${FILES[@]}; do
- echo $(checksum_file $FILE) >> $RESULT_FILE
-done
-# Now sort the file so that it is
-sort $RESULT_FILE -o $RESULT_FILE
diff --git a/.github/workflows/deploy_snapshot.yml b/.github/workflows/deploy_snapshot.yml
index 3bb5d9c8..c31bbb78 100644
--- a/.github/workflows/deploy_snapshot.yml
+++ b/.github/workflows/deploy_snapshot.yml
@@ -20,40 +20,12 @@ jobs:
- name: Copy CI gradle.properties
run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties
- - name: Generate cache key
- run: ./.github/checksum.sh checksum.txt
-
- - name: Cache gradle modules
- uses: actions/cache@v2
- with:
- path: ~/.gradle/caches/modules-2
- key: ${{ runner.os }}-gradlemodules-${{ hashFiles('checksum.txt') }}
- restore-keys: |
- ${{ runner.os }}-gradlemodules-
-
- - name: Cache gradle jars
- uses: actions/cache@v2
- with:
- path: ~/.gradle/caches/jars-3
- key: ${{ runner.os }}-gradlejars-${{ hashFiles('checksum.txt') }}
- restore-keys: |
- ${{ runner.os }}-gradlejars-
-
- - name: Cache gradle build
- uses: actions/cache@v2
- with:
- path: ~/.gradle/caches/build-cache-1
- key: ${{ runner.os }}-gradlebuildcache-${{ hashFiles('checksum.txt') }}
- restore-keys: |
- ${{ runner.os }}-gradlebuildcache-
-
- - name: Download gradle dependencies
- run: ./gradlew dependencies
-
- name: Build release app
- run: ./gradlew :app:assembleFreeRelease :app:assembleNonFreeRelease
+ uses: burrunan/gradle-cache-action@v1
env:
SNAPSHOT: "true"
+ with:
+ arguments: :app:assembleFreeRelease :app:assembleNonFreeRelease
- name: Clean secrets
run: release/signing-cleanup.sh
@@ -66,18 +38,3 @@ jobs:
SERVER_ADDRESS: ${{ secrets.SERVER_ADDRESS }}
SERVER_DESTINATION: ${{ secrets.SERVER_DESTINATION }}
SSH_PORT: ${{ secrets.SSH_PORT }}
-
- - name: Install NodeJS
- uses: actions/setup-node@v2-beta
- with:
- node-version: '12'
-
- - name: Install cfcli
- run: npm install -g cloudflare-cli
-
- - name: Purge Cloudflare cache
- run: |
- cfcli --token ${CF_TOKEN} purge "https://dl.msfjarvis.dev/APS/$(cd ./app/build/outputs/apk/nonFree/release/; ls *.apk)"
- cfcli --token ${CF_TOKEN} purge "https://dl.msfjarvis.dev/APS/$(cd ./app/build/outputs/apk/free/release/; ls *.apk)"
- env:
- CF_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
diff --git a/.github/workflows/draft_new_release.yml b/.github/workflows/draft_new_release.yml
index 91b047fb..914e6182 100644
--- a/.github/workflows/draft_new_release.yml
+++ b/.github/workflows/draft_new_release.yml
@@ -15,7 +15,7 @@ jobs:
- name: Extract version from milestone
run: |
VERSION="${{ github.event.milestone.title }}"
- echo "::set-env name=RELEASE_VERSION::$VERSION"
+ echo "RELEASE_VERSION=$VERSION" >> $GITHUB_ENV
- name: Create release branch
run: git checkout -b release-${{ env.RELEASE_VERSION }}
@@ -25,15 +25,16 @@ jobs:
with:
version: v${{ env.RELEASE_VERSION }}
- - name: Initialize git config
+ - name: Initialize git config and commit changes
run: |
git config user.name "GitHub Actions"
git config user.email noreply@github.com
+ git commit -am "Prepare release $RELEASE_VERSION"
- name: Create Pull Request
- uses: peter-evans/create-pull-request@v3
+ uses: repo-sync/pull-request@v2
with:
- commit-message: "Prepare release ${{ env.RELEASE_VERSION }}"
- branch: release-${{ env.RELEASE_VERSION }}
- base: release
- title: Release ${{ env.RELEASE_VERSION }}
+ source_branch: release-${{ env.RELEASE_VERSION }}
+ destination_branch: release
+ pr_title: Release ${{ env.RELEASE_VERSION }}
+ github_token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml
index f374c689..ec128f18 100644
--- a/.github/workflows/pull_request.yml
+++ b/.github/workflows/pull_request.yml
@@ -21,9 +21,9 @@ jobs:
pull_number: context.payload.number,
per_page: 100
})
- const serviceChanged = result.data.filter(f => f.filename.startsWith("app/") || f.filename.startsWith("buildSrc/") || f.filename.endsWith("gradle") || f.filename.startsWith(".github/workflows/pull_request.yml") || f.filename.startsWith("gradle") || f.filename.endsWith("properties")).length > 0
- console.log(serviceChanged)
- return serviceChanged
+ const shouldRun = result.data.filter(f => !f.filename.endsWith(".md") || !f.filename.endsWith(".txt") || !f.filename.startsWith("contrib/") || !f.filename.endsWith(".yml")).length > 0
+ console.log(shouldRun)
+ return shouldRun
- name: Checkout repository
if: ${{ steps.service-changed.outputs.result == 'true' }}
@@ -33,40 +33,11 @@ jobs:
if: ${{ steps.service-changed.outputs.result == 'true' }}
run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties
- - name: Generate cache key
- if: ${{ steps.service-changed.outputs.result == 'true' }}
- run: ./.github/checksum.sh checksum.txt
-
- - name: Cache gradle modules
- if: ${{ steps.service-changed.outputs.result == 'true' }}
- uses: actions/cache@v2
- with:
- path: ~/.gradle/caches/modules-2
- key: ${{ runner.os }}-gradlemodules-${{ hashFiles('checksum.txt') }}
- restore-keys: |
- ${{ runner.os }}-gradlemodules-
-
- - name: Cache gradle jars
- if: ${{ steps.service-changed.outputs.result == 'true' }}
- uses: actions/cache@v2
- with:
- path: ~/.gradle/caches/jars-3
- key: ${{ runner.os }}-gradlejars-${{ hashFiles('checksum.txt') }}
- restore-keys: |
- ${{ runner.os }}-gradlejars-
-
- - name: Cache gradle build
- if: ${{ steps.service-changed.outputs.result == 'true' }}
- uses: actions/cache@v2
- with:
- path: ~/.gradle/caches/build-cache-1
- key: ${{ runner.os }}-gradlebuildcache-${{ hashFiles('checksum.txt') }}
- restore-keys: |
- ${{ runner.os }}-gradlebuildcache-
-
- name: Run unit tests
if: ${{ steps.service-changed.outputs.result == 'true' }}
- run: ./gradlew testFreeDebug lintFreeDebug
+ uses: burrunan/gradle-cache-action@v1
+ with:
+ arguments: apiCheck testFreeDebug lintFreeDebug
- name: Run instrumentation tests
if: ${{ steps.service-changed.outputs.result == 'true' }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 10484521..521f7af1 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -20,38 +20,10 @@ jobs:
- name: Copy CI gradle.properties
run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties
- - name: Generate cache key
- run: ./.github/checksum.sh checksum.txt
-
- - name: Cache gradle modules
- uses: actions/cache@v2
- with:
- path: ~/.gradle/caches/modules-2
- key: ${{ runner.os }}-gradlemodules-${{ hashFiles('checksum.txt') }}
- restore-keys: |
- ${{ runner.os }}-gradlemodules-
-
- - name: Cache gradle jars
- uses: actions/cache@v2
- with:
- path: ~/.gradle/caches/jars-3
- key: ${{ runner.os }}-gradlejars-${{ hashFiles('checksum.txt') }}
- restore-keys: |
- ${{ runner.os }}-gradlejars-
-
- - name: Cache gradle build
- uses: actions/cache@v2
- with:
- path: ~/.gradle/caches/build-cache-1
- key: ${{ runner.os }}-gradlebuildcache-${{ hashFiles('checksum.txt') }}
- restore-keys: |
- ${{ runner.os }}-gradlebuildcache-
-
- - name: Download gradle dependencies
- run: ./gradlew dependencies
-
- name: Build release binaries
- run: ./gradlew :app:assembleFreeRelease :app:assembleNonFreeRelease :app:bundleNonFreeRelease
+ uses: burrunan/gradle-cache-action@v1
+ with:
+ arguments: :app:assembleFreeRelease :app:assembleNonFreeRelease :app:bundleNonFreeRelease
- name: Upload non-free release APK
uses: actions/upload-artifact@v2
diff --git a/.github/workflows/update_publicsuffix_data.yml b/.github/workflows/update_publicsuffix_data.yml
index 29f1777f..e0e09f86 100644
--- a/.github/workflows/update_publicsuffix_data.yml
+++ b/.github/workflows/update_publicsuffix_data.yml
@@ -14,19 +14,22 @@ jobs:
run: |
git config user.name "GitHub Actions"
git config user.email noreply@github.com
+ git checkout -b bot/update-psl
- name: Download new publicsuffix data
run: curl -L https://github.com/mozilla-mobile/android-components/raw/master/components/lib/publicsuffixlist/src/main/assets/publicsuffixes -o autofill-parser/src/main/assets/publicsuffixes
- name: Compare list changes
- run: if [[ $(git diff --binary --stat) != '' ]]; then echo "::set-env name=UPDATED::true"; fi
+ run: if [[ $(git diff --binary --stat) != '' ]]; then echo "UPDATED=true" >> $GITHUB_ENV; fi
- name: Create Pull Request
- uses: peter-evans/create-pull-request@v3
+ uses: repo-sync/pull-request@v2
if: env.UPDATED == 'true'
with:
- commit-message: Update Public Suffix List data
- branch: bot/update-psl
- base: develop
- title: 'Update Public Suffix List data'
+ source_branch: bot/update-psl
+ destination_branch: develop
+ pr_title: "Update Public Suffix List data"
+ pr_body: "This is an automated pull request to update the publicsuffixes file to the latest copy from Mozilla"
assignees: msfjarvis
+ pr_label: PSL
+ github_token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index e69de29b..00000000
--- a/.gitmodules
+++ /dev/null
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b4789e89..508b409a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file.
## [Unreleased]
+### Fixed
+
+- Some classes of errors would be swallowed by an unhelpful 'Invalid remote: origin' message
+- Repositories created within APS would contain invalid `.gpg-id` files with no ability to fix them from the app
+- Button labels were invisible in Autofill phishing warning screen
+
+### Added
+
+- Add GPG key selection step to onboarding flow
+- Allow configuring an app-wide HTTP(S) proxy
+
## [1.12.1] - 2020-10-13
### Fixed
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 013e2e4e..a5a3b4c9 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -31,8 +31,8 @@ android {
defaultConfig {
applicationId = "dev.msfjarvis.aps"
- versionCode = 11210
- versionName = "1.12.1"
+ versionCode = 11211
+ versionName = "1.13.0-SNAPSHOT"
}
lintOptions {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3b0781f4..6cad066e 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -36,6 +36,9 @@
android:name=".ui.onboarding.activity.OnboardingActivity"
android:configChanges="orientation|screenSize" />
+ <activity android:name=".ui.proxy.ProxySelectorActivity"
+ android:windowSoftInputMode="adjustResize" />
+
<activity
android:name=".LaunchActivity"
android:configChanges="orientation|screenSize"
diff --git a/app/src/main/java/com/zeapo/pwdstore/Application.kt b/app/src/main/java/com/zeapo/pwdstore/Application.kt
index 91e47793..3f3963d0 100644
--- a/app/src/main/java/com/zeapo/pwdstore/Application.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/Application.kt
@@ -14,27 +14,31 @@ import com.github.ajalt.timberkt.Timber.DebugTree
import com.github.ajalt.timberkt.Timber.plant
import com.zeapo.pwdstore.git.sshj.setUpBouncyCastleForSshj
import com.zeapo.pwdstore.utils.PreferenceKeys
+import com.zeapo.pwdstore.utils.ProxyUtils
import com.zeapo.pwdstore.utils.getString
import com.zeapo.pwdstore.utils.sharedPrefs
@Suppress("Unused")
class Application : android.app.Application(), SharedPreferences.OnSharedPreferenceChangeListener {
+ private val prefs by lazy { sharedPrefs }
+
override fun onCreate() {
super.onCreate()
instance = this
if (BuildConfig.ENABLE_DEBUG_FEATURES ||
- sharedPrefs.getBoolean(PreferenceKeys.ENABLE_DEBUG_LOGGING, false)) {
+ prefs.getBoolean(PreferenceKeys.ENABLE_DEBUG_LOGGING, false)) {
plant(DebugTree())
}
- sharedPrefs.registerOnSharedPreferenceChangeListener(this)
+ prefs.registerOnSharedPreferenceChangeListener(this)
setNightMode()
setUpBouncyCastleForSshj()
runMigrations(applicationContext)
+ ProxyUtils.setDefaultProxy()
}
override fun onTerminate() {
- sharedPrefs.unregisterOnSharedPreferenceChangeListener(this)
+ prefs.unregisterOnSharedPreferenceChangeListener(this)
super.onTerminate()
}
@@ -45,7 +49,7 @@ class Application : android.app.Application(), SharedPreferences.OnSharedPrefere
}
private fun setNightMode() {
- AppCompatDelegate.setDefaultNightMode(when (sharedPrefs.getString(PreferenceKeys.APP_THEME)
+ AppCompatDelegate.setDefaultNightMode(when (prefs.getString(PreferenceKeys.APP_THEME)
?: getString(R.string.app_theme_def)) {
"light" -> MODE_NIGHT_NO
"dark" -> MODE_NIGHT_YES
diff --git a/app/src/main/java/com/zeapo/pwdstore/ClipboardService.kt b/app/src/main/java/com/zeapo/pwdstore/ClipboardService.kt
index 46c4ecd3..0f27e5ef 100644
--- a/app/src/main/java/com/zeapo/pwdstore/ClipboardService.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/ClipboardService.kt
@@ -10,7 +10,6 @@ import android.app.PendingIntent
import android.app.Service
import android.content.ClipData
import android.content.Intent
-import android.content.SharedPreferences
import android.os.Build
import android.os.IBinder
import androidx.core.app.NotificationCompat
@@ -32,7 +31,6 @@ import kotlinx.coroutines.withContext
class ClipboardService : Service() {
private val scope = CoroutineScope(Job() + Dispatchers.Main)
- private val settings: SharedPreferences by lazy { sharedPrefs }
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (intent != null) {
@@ -45,7 +43,7 @@ class ClipboardService : Service() {
}
ACTION_START -> {
- val time = settings.getString(PreferenceKeys.GENERAL_SHOW_TIME)?.toIntOrNull() ?: 45
+ val time = sharedPrefs.getString(PreferenceKeys.GENERAL_SHOW_TIME)?.toIntOrNull() ?: 45
if (time == 0) {
stopSelf()
@@ -80,7 +78,7 @@ class ClipboardService : Service() {
}
private fun clearClipboard() {
- val deepClear = settings.getBoolean(PreferenceKeys.CLEAR_CLIPBOARD_20X, false)
+ val deepClear = sharedPrefs.getBoolean(PreferenceKeys.CLEAR_CLIPBOARD_20X, false)
val clipboard = clipboard
if (clipboard != null) {
diff --git a/app/src/main/java/com/zeapo/pwdstore/SearchableRepositoryViewModel.kt b/app/src/main/java/com/zeapo/pwdstore/SearchableRepositoryViewModel.kt
index 6da5de7a..a73dd40d 100644
--- a/app/src/main/java/com/zeapo/pwdstore/SearchableRepositoryViewModel.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/SearchableRepositoryViewModel.kt
@@ -139,7 +139,7 @@ class SearchableRepositoryViewModel(application: Application) : AndroidViewModel
private val root
get() = PasswordRepository.getRepositoryDirectory()
- private val settings by lazy { application.sharedPrefs }
+ private val settings by lazy(LazyThreadSafetyMode.NONE) { application.sharedPrefs }
private val showHiddenContents
get() = settings.getBoolean(PreferenceKeys.SHOW_HIDDEN_CONTENTS, false)
private val defaultSearchMode
diff --git a/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt b/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt
index 45915213..7f6727f2 100644
--- a/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt
@@ -50,6 +50,7 @@ import com.zeapo.pwdstore.git.sshj.SshKey
import com.zeapo.pwdstore.pwgenxkpwd.XkpwdDictionary
import com.zeapo.pwdstore.sshkeygen.ShowSshKeyFragment
import com.zeapo.pwdstore.sshkeygen.SshKeyGenActivity
+import com.zeapo.pwdstore.ui.proxy.ProxySelectorActivity
import com.zeapo.pwdstore.utils.BiometricAuthenticator
import com.zeapo.pwdstore.utils.PasswordRepository
import com.zeapo.pwdstore.utils.PreferenceKeys
@@ -418,6 +419,11 @@ class UserPreference : AppCompatActivity() {
}
}
+ findPreference<Preference>(PreferenceKeys.PROXY_SETTINGS)?.onPreferenceClickListener = ClickListener {
+ startActivity(Intent(requireContext(), ProxySelectorActivity::class.java))
+ true
+ }
+
val prefCustomXkpwdDictionary = findPreference<Preference>(PreferenceKeys.PREF_KEY_CUSTOM_DICT)
prefCustomXkpwdDictionary?.onPreferenceClickListener = ClickListener {
prefsActivity.storeCustomDictionaryPath()
diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillResponseBuilder.kt b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillResponseBuilder.kt
index 0e73b908..ec3d2b77 100644
--- a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillResponseBuilder.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillResponseBuilder.kt
@@ -15,12 +15,12 @@ import android.service.autofill.SaveInfo
import android.widget.RemoteViews
import androidx.annotation.RequiresApi
import com.github.ajalt.timberkt.e
-import com.github.michaelbull.result.fold
import com.github.androidpasswordstore.autofillparser.AutofillAction
import com.github.androidpasswordstore.autofillparser.AutofillScenario
import com.github.androidpasswordstore.autofillparser.Credentials
import com.github.androidpasswordstore.autofillparser.FillableForm
import com.github.androidpasswordstore.autofillparser.fillWith
+import com.github.michaelbull.result.fold
import com.zeapo.pwdstore.autofill.oreo.ui.AutofillDecryptActivity
import com.zeapo.pwdstore.autofill.oreo.ui.AutofillFilterView
import com.zeapo.pwdstore.autofill.oreo.ui.AutofillPublisherChangedActivity
@@ -88,8 +88,13 @@ class AutofillResponseBuilder(form: FillableForm) {
publisherChangedException: AutofillPublisherChangedException
): Dataset {
val remoteView = makeWarningRemoteView(context)
+ // If the user decides to trust the new publisher, they can choose reset the list of
+ // matches. In this case we need to immediately show a new `FillResponse` as if the app were
+ // autofilled for the first time. This `FillResponse` needs to be returned as a result from
+ // `AutofillPublisherChangedActivity`, which is why we create and pass it on here.
+ val fillResponseAfterReset = makeFillResponse(context, emptyList())
val intentSender = AutofillPublisherChangedActivity.makePublisherChangedIntentSender(
- context, publisherChangedException
+ context, publisherChangedException, fillResponseAfterReset
)
return makePlaceholderDataset(remoteView, intentSender, AutofillAction.Match)
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillPublisherChangedActivity.kt b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillPublisherChangedActivity.kt
index 44ed3446..34edf8f5 100644
--- a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillPublisherChangedActivity.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillPublisherChangedActivity.kt
@@ -12,8 +12,10 @@ import android.content.IntentSender
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
+import android.service.autofill.FillResponse
import android.text.format.DateUtils
import android.view.View
+import android.view.autofill.AutofillManager
import androidx.appcompat.app.AppCompatActivity
import com.github.ajalt.timberkt.e
import com.github.androidpasswordstore.autofillparser.FormOrigin
@@ -33,14 +35,18 @@ class AutofillPublisherChangedActivity : AppCompatActivity() {
private const val EXTRA_APP_PACKAGE =
"com.zeapo.pwdstore.autofill.oreo.ui.EXTRA_APP_PACKAGE"
+ private const val EXTRA_FILL_RESPONSE_AFTER_RESET =
+ "com.zeapo.pwdstore.autofill.oreo.ui.EXTRA_FILL_RESPONSE_AFTER_RESET"
private var publisherChangedRequestCode = 1
fun makePublisherChangedIntentSender(
context: Context,
- publisherChangedException: AutofillPublisherChangedException
+ publisherChangedException: AutofillPublisherChangedException,
+ fillResponseAfterReset: FillResponse?,
): IntentSender {
val intent = Intent(context, AutofillPublisherChangedActivity::class.java).apply {
putExtra(EXTRA_APP_PACKAGE, publisherChangedException.formOrigin.identifier)
+ putExtra(EXTRA_FILL_RESPONSE_AFTER_RESET, fillResponseAfterReset)
}
return PendingIntent.getActivity(
context, publisherChangedRequestCode++, intent, PendingIntent.FLAG_CANCEL_CURRENT
@@ -66,12 +72,16 @@ class AutofillPublisherChangedActivity : AppCompatActivity() {
with(binding) {
okButton.setOnClickListener { finish() }
advancedButton.setOnClickListener {
- advancedButton.visibility = View.INVISIBLE
+ advancedButton.visibility = View.GONE
warningAppAdvancedInfo.visibility = View.VISIBLE
resetButton.visibility = View.VISIBLE
}
resetButton.setOnClickListener {
AutofillMatcher.clearMatchesFor(this@AutofillPublisherChangedActivity, FormOrigin.App(appPackage))
+ val fillResponse = intent.getParcelableExtra<FillResponse>(EXTRA_FILL_RESPONSE_AFTER_RESET)
+ setResult(RESULT_OK, Intent().apply {
+ putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, fillResponse)
+ })
finish()
}
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillSaveActivity.kt b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillSaveActivity.kt
index 7f83d483..f4c296ee 100644
--- a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillSaveActivity.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillSaveActivity.kt
@@ -82,7 +82,7 @@ class AutofillSaveActivity : AppCompatActivity() {
}
}
- private val formOrigin: FormOrigin? by lazy {
+ private val formOrigin by lazy(LazyThreadSafetyMode.NONE) {
val shouldMatchApp: String? = intent.getStringExtra(EXTRA_SHOULD_MATCH_APP)
val shouldMatchWeb: String? = intent.getStringExtra(EXTRA_SHOULD_MATCH_WEB)
if (shouldMatchApp != null && shouldMatchWeb == null) {
diff --git a/app/src/main/java/com/zeapo/pwdstore/crypto/BasePgpActivity.kt b/app/src/main/java/com/zeapo/pwdstore/crypto/BasePgpActivity.kt
index 8380d7d0..6b6c2032 100644
--- a/app/src/main/java/com/zeapo/pwdstore/crypto/BasePgpActivity.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/crypto/BasePgpActivity.kt
@@ -45,24 +45,24 @@ open class BasePgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBou
/**
* Full path to the repository
*/
- val repoPath: String by lazy { intent.getStringExtra("REPO_PATH") }
+ val repoPath: String by lazy(LazyThreadSafetyMode.NONE) { intent.getStringExtra("REPO_PATH") }
/**
* Full path to the password file being worked on
*/
- val fullPath: String by lazy { intent.getStringExtra("FILE_PATH") }
+ val fullPath: String by lazy(LazyThreadSafetyMode.NONE) { intent.getStringExtra("FILE_PATH") }
/**
* Name of the password file
*
* Converts personal/auth.foo.org/john_doe@example.org.gpg to john_doe.example.org
*/
- val name: String by lazy { File(fullPath).nameWithoutExtension }
+ val name: String by lazy(LazyThreadSafetyMode.NONE) { File(fullPath).nameWithoutExtension }
/**
* Get the timestamp for when this file was last modified.
*/
- val lastChangedString: CharSequence by lazy {
+ val lastChangedString: CharSequence by lazy(LazyThreadSafetyMode.NONE) {
getLastChangedString(
intent.getLongExtra(
"LAST_CHANGED_TIMESTAMP",
@@ -74,7 +74,7 @@ open class BasePgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBou
/**
* [SharedPreferences] instance used by subclasses to persist settings
*/
- val settings: SharedPreferences by lazy { sharedPrefs }
+ val settings: SharedPreferences by lazy(LazyThreadSafetyMode.NONE) { sharedPrefs }
/**
* Handle to the [OpenPgpApi] instance that is used by subclasses to interface with OpenKeychain.
diff --git a/app/src/main/java/com/zeapo/pwdstore/crypto/DecryptActivity.kt b/app/src/main/java/com/zeapo/pwdstore/crypto/DecryptActivity.kt
index 3685cb17..cb43534d 100644
--- a/app/src/main/java/com/zeapo/pwdstore/crypto/DecryptActivity.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/crypto/DecryptActivity.kt
@@ -39,7 +39,7 @@ class DecryptActivity : BasePgpActivity(), OpenPgpServiceConnection.OnBound {
private val binding by viewBinding(DecryptLayoutBinding::inflate)
- private val relativeParentPath by lazy { getParentPath(fullPath, repoPath) }
+ private val relativeParentPath by lazy(LazyThreadSafetyMode.NONE) { getParentPath(fullPath, repoPath) }
private var passwordEntry: PasswordEntry? = null
private val userInteractionRequiredResult = registerForActivityResult(StartIntentSenderForResult()) { result ->
diff --git a/app/src/main/java/com/zeapo/pwdstore/crypto/PasswordCreationActivity.kt b/app/src/main/java/com/zeapo/pwdstore/crypto/PasswordCreationActivity.kt
index 07694089..01d85f2b 100644
--- a/app/src/main/java/com/zeapo/pwdstore/crypto/PasswordCreationActivity.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/crypto/PasswordCreationActivity.kt
@@ -56,12 +56,12 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
private val binding by viewBinding(PasswordCreationActivityBinding::inflate)
- private val suggestedName by lazy { intent.getStringExtra(EXTRA_FILE_NAME) }
- private val suggestedPass by lazy { intent.getStringExtra(EXTRA_PASSWORD) }
- private val suggestedExtra by lazy { intent.getStringExtra(EXTRA_EXTRA_CONTENT) }
- private val shouldGeneratePassword by lazy { intent.getBooleanExtra(EXTRA_GENERATE_PASSWORD, false) }
- private val editing by lazy { intent.getBooleanExtra(EXTRA_EDITING, false) }
- private val oldFileName by lazy { intent.getStringExtra(EXTRA_FILE_NAME) }
+ private val suggestedName by lazy(LazyThreadSafetyMode.NONE) { intent.getStringExtra(EXTRA_FILE_NAME) }
+ private val suggestedPass by lazy(LazyThreadSafetyMode.NONE) { intent.getStringExtra(EXTRA_PASSWORD) }
+ private val suggestedExtra by lazy(LazyThreadSafetyMode.NONE) { intent.getStringExtra(EXTRA_EXTRA_CONTENT) }
+ private val shouldGeneratePassword by lazy(LazyThreadSafetyMode.NONE) { intent.getBooleanExtra(EXTRA_GENERATE_PASSWORD, false) }
+ private val editing by lazy(LazyThreadSafetyMode.NONE) { intent.getBooleanExtra(EXTRA_EDITING, false) }
+ private val oldFileName by lazy(LazyThreadSafetyMode.NONE) { intent.getStringExtra(EXTRA_FILE_NAME) }
private var oldCategory: String? = null
private var copy: Boolean = false
private var encryptionIntent: Intent = Intent()
@@ -277,6 +277,7 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
@OptIn(ExperimentalUnsignedTypes::class)
private fun parseGpgIdentifier(identifier: String): GpgIdentifier? {
+ if (identifier.isEmpty()) return null
// Match long key IDs:
// FF22334455667788 or 0xFF22334455667788
val maybeLongKeyId = identifier.removePrefix("0x").takeIf {
@@ -342,6 +343,9 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
.filter { it.isNotBlank() }
.map { line ->
parseGpgIdentifier(line) ?: run {
+ // The line being empty means this is most likely an empty `.gpg-id` file
+ // we created. Skip the validation so we can make the user add a real ID.
+ if (line.isEmpty()) return@run
if (line.removePrefix("0x").matches("[a-fA-F0-9]{8}".toRegex())) {
snackbar(message = resources.getString(R.string.short_key_ids_unsupported))
} else {
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/BaseGitActivity.kt b/app/src/main/java/com/zeapo/pwdstore/git/BaseGitActivity.kt
index b0aed087..36b8b6fb 100644
--- a/app/src/main/java/com/zeapo/pwdstore/git/BaseGitActivity.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/git/BaseGitActivity.kt
@@ -128,11 +128,12 @@ abstract class BaseGitActivity : AppCompatActivity() {
*/
private fun rootCauseException(throwable: Throwable): Throwable {
var rootCause = throwable
- // JGit's TransportException hides the more helpful SSHJ exceptions.
+ // JGit's InvalidRemoteException and TransportException hide the more helpful SSHJ exceptions.
// Also, SSHJ's UserAuthException about exhausting available authentication methods hides
// more useful exceptions.
while ((rootCause is org.eclipse.jgit.errors.TransportException ||
rootCause is org.eclipse.jgit.api.errors.TransportException ||
+ rootCause is org.eclipse.jgit.api.errors.InvalidRemoteException ||
(rootCause is UserAuthException &&
rootCause.message == "Exhausted available authentication methods"))) {
rootCause = rootCause.cause ?: break
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/GitCommandExecutor.kt b/app/src/main/java/com/zeapo/pwdstore/git/GitCommandExecutor.kt
index ed5411ac..ef584cf7 100644
--- a/app/src/main/java/com/zeapo/pwdstore/git/GitCommandExecutor.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/git/GitCommandExecutor.kt
@@ -51,8 +51,10 @@ class GitCommandExecutor(
// the previous status will eventually be used to avoid a commit
if (nbChanges > 0) {
withContext(Dispatchers.IO) {
+ val name = GitSettings.authorName.ifEmpty { "root" }
+ val email = GitSettings.authorEmail.ifEmpty { "localhost" }
command
- .setAuthor(PersonIdent(GitSettings.authorName, GitSettings.authorEmail))
+ .setAuthor(PersonIdent(name, email))
.call()
}
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/config/GitSettings.kt b/app/src/main/java/com/zeapo/pwdstore/git/config/GitSettings.kt
index e43deaf4..27ceb5cb 100644
--- a/app/src/main/java/com/zeapo/pwdstore/git/config/GitSettings.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/git/config/GitSettings.kt
@@ -11,6 +11,7 @@ import com.zeapo.pwdstore.Application
import com.zeapo.pwdstore.utils.PasswordRepository
import com.zeapo.pwdstore.utils.PreferenceKeys
import com.zeapo.pwdstore.utils.getEncryptedGitPrefs
+import com.zeapo.pwdstore.utils.getEncryptedProxyPrefs
import com.zeapo.pwdstore.utils.getString
import com.zeapo.pwdstore.utils.sharedPrefs
import java.io.File
@@ -52,8 +53,9 @@ object GitSettings {
private const val DEFAULT_BRANCH = "master"
- private val settings by lazy { Application.instance.sharedPrefs }
- private val encryptedSettings by lazy { Application.instance.getEncryptedGitPrefs() }
+ private val settings by lazy(LazyThreadSafetyMode.PUBLICATION) { Application.instance.sharedPrefs }
+ private val encryptedSettings by lazy(LazyThreadSafetyMode.PUBLICATION) { Application.instance.getEncryptedGitPrefs() }
+ private val proxySettings by lazy(LazyThreadSafetyMode.PUBLICATION) { Application.instance.getEncryptedProxyPrefs() }
var authMode
get() = AuthMode.fromString(settings.getString(PreferenceKeys.GIT_REMOTE_AUTH))
@@ -108,6 +110,38 @@ object GitSettings {
}
}
+ var proxyHost
+ get() = proxySettings.getString(PreferenceKeys.PROXY_HOST)
+ set(value) {
+ proxySettings.edit {
+ putString(PreferenceKeys.PROXY_HOST, value)
+ }
+ }
+
+ var proxyPort
+ get() = proxySettings.getInt(PreferenceKeys.PROXY_PORT, -1)
+ set(value) {
+ proxySettings.edit {
+ putInt(PreferenceKeys.PROXY_PORT, value)
+ }
+ }
+
+ var proxyUsername
+ get() = settings.getString(PreferenceKeys.PROXY_USERNAME)
+ set(value) {
+ proxySettings.edit {
+ putString(PreferenceKeys.PROXY_USERNAME, value)
+ }
+ }
+
+ var proxyPassword
+ get() = proxySettings.getString(PreferenceKeys.PROXY_PASSWORD)
+ set(value) {
+ proxySettings.edit {
+ putString(PreferenceKeys.PROXY_PASSWORD, value)
+ }
+ }
+
sealed class UpdateConnectionSettingsResult {
class MissingUsername(val newProtocol: Protocol) : UpdateConnectionSettingsResult()
class AuthModeMismatch(val newProtocol: Protocol, val validModes: List<AuthMode>) : UpdateConnectionSettingsResult()
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/log/GitLogModel.kt b/app/src/main/java/com/zeapo/pwdstore/git/log/GitLogModel.kt
index ccd2f88a..15b9f64d 100644
--- a/app/src/main/java/com/zeapo/pwdstore/git/log/GitLogModel.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/git/log/GitLogModel.kt
@@ -41,7 +41,7 @@ class GitLogModel {
// This is because the commit graph is walked from HEAD to the last commit to obtain.
// Additionally, tests with 1000 commits in the log have not produced a significant delay in the
// user experience.
- private val cache: MutableList<GitCommit> by lazy {
+ private val cache: MutableList<GitCommit> by lazy(LazyThreadSafetyMode.NONE) {
commits().map {
GitCommit(it.hash, it.shortMessage, it.authorIdent.name, it.time)
}.toMutableList()
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/sshj/SshKey.kt b/app/src/main/java/com/zeapo/pwdstore/git/sshj/SshKey.kt
index 73072f7d..5e6cfb1b 100644
--- a/app/src/main/java/com/zeapo/pwdstore/git/sshj/SshKey.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/git/sshj/SshKey.kt
@@ -50,7 +50,7 @@ private const val PROVIDER_ANDROID_KEY_STORE = "AndroidKeyStore"
private const val KEYSTORE_ALIAS = "sshkey"
private const val ANDROIDX_SECURITY_KEYSET_PREF_NAME = "androidx_sshkey_keyset_prefs"
-private val androidKeystore: KeyStore by lazy {
+private val androidKeystore: KeyStore by lazy(LazyThreadSafetyMode.NONE) {
KeyStore.getInstance(PROVIDER_ANDROID_KEY_STORE).apply { load(null) }
}
@@ -119,7 +119,7 @@ object SshKey {
putString(PreferenceKeys.GIT_REMOTE_KEY_TYPE, value?.value)
}
- private val isStrongBoxSupported by lazy {
+ private val isStrongBoxSupported by lazy(LazyThreadSafetyMode.NONE) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
context.packageManager.hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE)
else
diff --git a/app/src/main/java/com/zeapo/pwdstore/model/PasswordEntry.kt b/app/src/main/java/com/zeapo/pwdstore/model/PasswordEntry.kt
index ea6255c4..556b2c87 100644
--- a/app/src/main/java/com/zeapo/pwdstore/model/PasswordEntry.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/model/PasswordEntry.kt
@@ -59,7 +59,7 @@ class PasswordEntry(content: String, private val totpFinder: TotpFinder = UriTot
return Otp.calculateCode(totpSecret, Date().time / (1000 * totpPeriod), totpAlgorithm, digits).get()
}
- val extraContentWithoutAuthData by lazy {
+ val extraContentWithoutAuthData by lazy(LazyThreadSafetyMode.NONE) {
extraContent.splitToSequence("\n").filter { line ->
return@filter when {
USERNAME_FIELDS.any { prefix -> line.startsWith(prefix, ignoreCase = true) } -> {
diff --git a/app/src/main/java/com/zeapo/pwdstore/ui/onboarding/fragments/CloneFragment.kt b/app/src/main/java/com/zeapo/pwdstore/ui/onboarding/fragments/CloneFragment.kt
index 19a14695..acd0151c 100644
--- a/app/src/main/java/com/zeapo/pwdstore/ui/onboarding/fragments/CloneFragment.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/ui/onboarding/fragments/CloneFragment.kt
@@ -25,7 +25,7 @@ class CloneFragment : Fragment(R.layout.fragment_clone) {
private val binding by viewBinding(FragmentCloneBinding::bind)
- private val settings by lazy { requireActivity().applicationContext.sharedPrefs }
+ private val settings by lazy(LazyThreadSafetyMode.NONE) { requireActivity().applicationContext.sharedPrefs }
private val cloneAction = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == AppCompatActivity.RESULT_OK) {
diff --git a/app/src/main/java/com/zeapo/pwdstore/ui/onboarding/fragments/KeySelectionFragment.kt b/app/src/main/java/com/zeapo/pwdstore/ui/onboarding/fragments/KeySelectionFragment.kt
new file mode 100644
index 00000000..3dc03954
--- /dev/null
+++ b/app/src/main/java/com/zeapo/pwdstore/ui/onboarding/fragments/KeySelectionFragment.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+package com.zeapo.pwdstore.ui.onboarding.fragments
+
+import android.content.Intent
+import android.os.Bundle
+import android.view.View
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.content.edit
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.lifecycleScope
+import com.zeapo.pwdstore.R
+import com.zeapo.pwdstore.crypto.GetKeyIdsActivity
+import com.zeapo.pwdstore.databinding.FragmentKeySelectionBinding
+import com.zeapo.pwdstore.utils.PasswordRepository
+import com.zeapo.pwdstore.utils.PreferenceKeys
+import com.zeapo.pwdstore.utils.commitChange
+import com.zeapo.pwdstore.utils.finish
+import com.zeapo.pwdstore.utils.sharedPrefs
+import com.zeapo.pwdstore.utils.viewBinding
+import java.io.File
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import me.msfjarvis.openpgpktx.util.OpenPgpApi
+
+class KeySelectionFragment : Fragment(R.layout.fragment_key_selection) {
+
+ private val settings by lazy(LazyThreadSafetyMode.NONE) { requireActivity().applicationContext.sharedPrefs }
+ private val binding by viewBinding(FragmentKeySelectionBinding::bind)
+
+ private val gpgKeySelectAction = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
+ if (result.resultCode == AppCompatActivity.RESULT_OK) {
+ result.data?.getStringArrayExtra(OpenPgpApi.EXTRA_KEY_IDS)?.let { keyIds ->
+ lifecycleScope.launch {
+ withContext(Dispatchers.IO) {
+ val gpgIdentifierFile = File(PasswordRepository.getRepositoryDirectory(), ".gpg-id")
+ gpgIdentifierFile.writeText(keyIds.joinToString("\n"))
+ }
+ settings.edit { putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, true) }
+ requireActivity().commitChange(getString(
+ R.string.git_commit_gpg_id,
+ getString(R.string.app_name)
+ ))
+ }
+ }
+ } else {
+ throw IllegalStateException("Failed to initialize repository state.")
+ }
+ finish()
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ binding.selectKey.setOnClickListener { gpgKeySelectAction.launch(Intent(requireContext(), GetKeyIdsActivity::class.java)) }
+ }
+
+ companion object {
+
+ fun newInstance() = KeySelectionFragment()
+ }
+}
diff --git a/app/src/main/java/com/zeapo/pwdstore/ui/onboarding/fragments/RepoLocationFragment.kt b/app/src/main/java/com/zeapo/pwdstore/ui/onboarding/fragments/RepoLocationFragment.kt
index 9e8a8f9d..d451fabe 100644
--- a/app/src/main/java/com/zeapo/pwdstore/ui/onboarding/fragments/RepoLocationFragment.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/ui/onboarding/fragments/RepoLocationFragment.kt
@@ -14,6 +14,7 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.edit
import androidx.fragment.app.Fragment
import com.github.ajalt.timberkt.d
+import com.github.ajalt.timberkt.e
import com.github.michaelbull.result.onFailure
import com.github.michaelbull.result.runCatching
import com.google.android.material.dialog.MaterialAlertDialogBuilder
@@ -26,14 +27,14 @@ import com.zeapo.pwdstore.utils.finish
import com.zeapo.pwdstore.utils.getString
import com.zeapo.pwdstore.utils.isPermissionGranted
import com.zeapo.pwdstore.utils.listFilesRecursively
+import com.zeapo.pwdstore.utils.performTransactionWithBackStack
import com.zeapo.pwdstore.utils.sharedPrefs
import com.zeapo.pwdstore.utils.viewBinding
import java.io.File
class RepoLocationFragment : Fragment(R.layout.fragment_repo_location) {
- private val firstRunActivity by lazy { requireActivity() }
- private val settings by lazy { firstRunActivity.applicationContext.sharedPrefs }
+ private val settings by lazy(LazyThreadSafetyMode.NONE) { requireActivity().applicationContext.sharedPrefs }
private val binding by viewBinding(FragmentRepoLocationBinding::bind)
private val sortOrder: PasswordRepository.PasswordSortOrder
get() = PasswordRepository.PasswordSortOrder.getSortOrder(settings)
@@ -151,18 +152,14 @@ class RepoLocationFragment : Fragment(R.layout.fragment_repo_location) {
if (!PasswordRepository.isInitialized) {
PasswordRepository.initialize()
}
- if (File(localDir.absolutePath + "/.gpg-id").createNewFile()) {
- settings.edit { putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, true) }
- } else {
- throw IllegalStateException("Failed to initialize repository state.")
- }
+ parentFragmentManager.performTransactionWithBackStack(KeySelectionFragment.newInstance())
}.onFailure { e ->
- e.printStackTrace()
+ e(e)
if (!localDir.delete()) {
d { "Failed to delete local repository: $localDir" }
}
+ finish()
}
- finish()
}
private fun initializeRepositoryInfo() {
diff --git a/app/src/main/java/com/zeapo/pwdstore/ui/proxy/ProxySelectorActivity.kt b/app/src/main/java/com/zeapo/pwdstore/ui/proxy/ProxySelectorActivity.kt
new file mode 100644
index 00000000..29c4d53a
--- /dev/null
+++ b/app/src/main/java/com/zeapo/pwdstore/ui/proxy/ProxySelectorActivity.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+package com.zeapo.pwdstore.ui.proxy
+
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.util.Patterns
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.content.edit
+import androidx.core.os.postDelayed
+import androidx.core.widget.doOnTextChanged
+import com.zeapo.pwdstore.R
+import com.zeapo.pwdstore.databinding.ActivityProxySelectorBinding
+import com.zeapo.pwdstore.git.config.GitSettings
+import com.zeapo.pwdstore.utils.PreferenceKeys
+import com.zeapo.pwdstore.utils.ProxyUtils
+import com.zeapo.pwdstore.utils.getEncryptedProxyPrefs
+import com.zeapo.pwdstore.utils.getString
+import com.zeapo.pwdstore.utils.viewBinding
+
+private val IP_ADDRESS_REGEX = Patterns.IP_ADDRESS.toRegex()
+private val WEB_ADDRESS_REGEX = Patterns.WEB_URL.toRegex()
+
+class ProxySelectorActivity : AppCompatActivity() {
+
+ private val binding by viewBinding(ActivityProxySelectorBinding::inflate)
+ private val proxyPrefs by lazy(LazyThreadSafetyMode.NONE) { applicationContext.getEncryptedProxyPrefs() }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(binding.root)
+ with(binding) {
+ proxyHost.setText(proxyPrefs.getString(PreferenceKeys.PROXY_HOST))
+ proxyUser.setText(proxyPrefs.getString(PreferenceKeys.PROXY_USERNAME))
+ proxyPrefs.getInt(PreferenceKeys.PROXY_PORT, -1).takeIf { it != -1 }?.let {
+ proxyPort.setText("$it")
+ }
+ proxyPassword.setText(proxyPrefs.getString(PreferenceKeys.PROXY_PASSWORD))
+ save.setOnClickListener { saveSettings() }
+ proxyHost.doOnTextChanged { text, _, _, _ ->
+ if (text != null) {
+ proxyHost.error = if (text.matches(IP_ADDRESS_REGEX) || text.matches(WEB_ADDRESS_REGEX)) {
+ null
+ } else {
+ getString(R.string.invalid_proxy_url)
+ }
+ }
+ }
+ }
+
+ }
+
+ private fun saveSettings() {
+ proxyPrefs.edit {
+ binding.proxyHost.text?.toString()?.takeIf { it.isNotEmpty() }.let {
+ GitSettings.proxyHost = it
+ }
+ binding.proxyUser.text?.toString()?.takeIf { it.isNotEmpty() }.let {
+ GitSettings.proxyUsername = it
+ }
+ binding.proxyPort.text?.toString()?.takeIf { it.isNotEmpty() }?.let {
+ GitSettings.proxyPort = it.toInt()
+ }
+ binding.proxyPassword.text?.toString()?.takeIf { it.isNotEmpty() }.let {
+ GitSettings.proxyPassword = it
+ }
+ }
+ ProxyUtils.setDefaultProxy()
+ Handler(Looper.getMainLooper()).postDelayed(500) { finish() }
+ }
+}
diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/AndroidExtensions.kt b/app/src/main/java/com/zeapo/pwdstore/utils/AndroidExtensions.kt
index 3ee1820d..408e9d5e 100644
--- a/app/src/main/java/com/zeapo/pwdstore/utils/AndroidExtensions.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/utils/AndroidExtensions.kt
@@ -72,6 +72,12 @@ val Context.clipboard
fun Context.getEncryptedGitPrefs() = getEncryptedPrefs("git_operation")
/**
+ * Wrapper for [getEncryptedPrefs] to get the encrypted preference set for the HTTP
+ * proxy.
+ */
+fun Context.getEncryptedProxyPrefs() = getEncryptedPrefs("http_proxy")
+
+/**
* Get an instance of [EncryptedSharedPreferences] with the given [fileName]
*/
private fun Context.getEncryptedPrefs(fileName: String): SharedPreferences {
diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/BiometricAuthenticator.kt b/app/src/main/java/com/zeapo/pwdstore/utils/BiometricAuthenticator.kt
index a1b4a279..12ba84f1 100644
--- a/app/src/main/java/com/zeapo/pwdstore/utils/BiometricAuthenticator.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/utils/BiometricAuthenticator.kt
@@ -6,7 +6,6 @@ package com.zeapo.pwdstore.utils
import android.app.KeyguardManager
import androidx.annotation.StringRes
-import androidx.biometric.BiometricConstants
import androidx.biometric.BiometricManager
import androidx.biometric.BiometricManager.Authenticators
import androidx.biometric.BiometricPrompt
@@ -43,12 +42,12 @@ object BiometricAuthenticator {
super.onAuthenticationError(errorCode, errString)
tag(TAG).d { "BiometricAuthentication error: errorCode=$errorCode, msg=$errString" }
callback(when (errorCode) {
- BiometricConstants.ERROR_CANCELED, BiometricConstants.ERROR_USER_CANCELED,
- BiometricConstants.ERROR_NEGATIVE_BUTTON -> {
+ BiometricPrompt.ERROR_CANCELED, BiometricPrompt.ERROR_USER_CANCELED,
+ BiometricPrompt.ERROR_NEGATIVE_BUTTON -> {
Result.Cancelled
}
- BiometricConstants.ERROR_HW_NOT_PRESENT, BiometricConstants.ERROR_HW_UNAVAILABLE,
- BiometricConstants.ERROR_NO_BIOMETRICS, BiometricConstants.ERROR_NO_DEVICE_CREDENTIAL -> {
+ BiometricPrompt.ERROR_HW_NOT_PRESENT, BiometricPrompt.ERROR_HW_UNAVAILABLE,
+ BiometricPrompt.ERROR_NO_BIOMETRICS, BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL -> {
Result.HardwareUnavailableOrDisabled
}
else -> Result.Failure(errorCode, activity.getString(R.string.biometric_auth_error_reason, errString))
diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRepository.kt b/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRepository.kt
index f1655b3b..6e090ba3 100644
--- a/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRepository.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRepository.kt
@@ -93,7 +93,7 @@ open class PasswordRepository protected constructor() {
companion object {
private var repository: Repository? = null
- private val settings by lazy { Application.instance.sharedPrefs }
+ private val settings by lazy(LazyThreadSafetyMode.NONE) { Application.instance.sharedPrefs }
private val filesDir
get() = Application.instance.filesDir
diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/PreferenceKeys.kt b/app/src/main/java/com/zeapo/pwdstore/utils/PreferenceKeys.kt
index 1b2c7abb..5ec40639 100644
--- a/app/src/main/java/com/zeapo/pwdstore/utils/PreferenceKeys.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/utils/PreferenceKeys.kt
@@ -80,4 +80,10 @@ object PreferenceKeys {
@Deprecated("To be used only in Migrations.kt")
const val USE_GENERATED_KEY = "use_generated_key"
+
+ const val PROXY_SETTINGS = "proxy_settings"
+ const val PROXY_HOST = "proxy_host"
+ const val PROXY_PORT = "proxy_port"
+ const val PROXY_USERNAME = "proxy_username"
+ const val PROXY_PASSWORD = "proxy_password"
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/ProxyUtils.kt b/app/src/main/java/com/zeapo/pwdstore/utils/ProxyUtils.kt
new file mode 100644
index 00000000..4bb3dfcb
--- /dev/null
+++ b/app/src/main/java/com/zeapo/pwdstore/utils/ProxyUtils.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+package com.zeapo.pwdstore.utils
+
+import com.zeapo.pwdstore.git.config.GitSettings
+import java.io.IOException
+import java.net.Authenticator
+import java.net.InetSocketAddress
+import java.net.PasswordAuthentication
+import java.net.Proxy
+import java.net.ProxySelector
+import java.net.SocketAddress
+import java.net.URI
+
+/**
+ * Utility class for [Proxy] handling.
+ */
+object ProxyUtils {
+
+ private const val HTTP_PROXY_USER_PROPERTY = "http.proxyUser"
+ private const val HTTP_PROXY_PASSWORD_PROPERTY = "http.proxyPassword"
+
+ /**
+ * Set the default [Proxy] and [Authenticator] for the app based on user provided settings.
+ */
+ fun setDefaultProxy() {
+ ProxySelector.setDefault(object : ProxySelector() {
+ override fun select(uri: URI?): MutableList<Proxy> {
+ val host = GitSettings.proxyHost
+ val port = GitSettings.proxyPort
+ return if (host == null || port == -1) {
+ mutableListOf(Proxy.NO_PROXY)
+ } else {
+ mutableListOf(Proxy(Proxy.Type.HTTP, InetSocketAddress.createUnresolved(host, port)))
+ }
+ }
+
+ override fun connectFailed(uri: URI?, sa: SocketAddress?, ioe: IOException?) {
+ if (uri == null || sa == null || ioe == null) {
+ throw IllegalArgumentException("Arguments can't be null.")
+ }
+ }
+ })
+ val user = GitSettings.proxyUsername ?: ""
+ val password = GitSettings.proxyPassword ?: ""
+ if (user.isEmpty() || password.isEmpty()) {
+ System.clearProperty(HTTP_PROXY_USER_PROPERTY)
+ System.clearProperty(HTTP_PROXY_PASSWORD_PROPERTY)
+ } else {
+ System.setProperty(HTTP_PROXY_USER_PROPERTY, user)
+ System.setProperty(HTTP_PROXY_PASSWORD_PROPERTY, password)
+ }
+ Authenticator.setDefault(object : Authenticator() {
+ override fun getPasswordAuthentication(): PasswordAuthentication? {
+ return if (requestorType == RequestorType.PROXY) {
+ PasswordAuthentication(user, password.toCharArray())
+ } else {
+ null
+ }
+ }
+ })
+ }
+}
diff --git a/app/src/main/res/layout/activity_oreo_autofill_publisher_changed.xml b/app/src/main/res/layout/activity_oreo_autofill_publisher_changed.xml
index 92d4e094..8a735e5b 100644
--- a/app/src/main/res/layout/activity_oreo_autofill_publisher_changed.xml
+++ b/app/src/main/res/layout/activity_oreo_autofill_publisher_changed.xml
@@ -6,57 +6,69 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="280dp"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:elevation="2dp"
+ android:paddingBottom="16dp"
android:scrollbars="vertical"
tools:context="com.zeapo.pwdstore.autofill.oreo.ui.AutofillPublisherChangedActivity">
<ImageView
android:id="@+id/cover"
- android:layout_width="0dp"
- android:layout_height="50dp"
+ android:layout_width="60dp"
+ android:layout_height="60dp"
android:background="@color/primary_color"
android:contentDescription="@string/app_name"
android:src="@mipmap/ic_launcher_foreground"
app:layout_constraintBottom_toTopOf="@id/warningSign"
- app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/app_name"
+ app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintVertical_bias="0.0"
- app:layout_constraintVertical_chainStyle="packed" />
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:id="@+id/app_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/app_name"
+ android:textSize="18sp"
+ android:textStyle="bold"
+ app:layout_constraintBottom_toBottomOf="@id/cover"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@id/cover"
+ app:layout_constraintTop_toTopOf="@id/cover" />
<ImageView
android:id="@+id/warningSign"
- android:layout_width="0dp"
- android:layout_height="50dp"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ android:layout_marginStart="@dimen/activity_horizontal_margin"
android:contentDescription="@string/oreo_autofill_warning_publisher_warning_sign_description"
android:src="@drawable/ic_warning_red_24dp"
- app:layout_constraintBottom_toTopOf="@id/warningHeader"
- app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="@id/warningHeader"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/cover" />
+ app:layout_constraintBottom_toBottomOf="@id/warningHeader" />
<TextView
android:id="@+id/warningHeader"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/activity_horizontal_margin"
+ android:layout_marginTop="@dimen/activity_vertical_margin"
+ android:layout_marginStart="8dp"
android:layout_marginEnd="@dimen/activity_horizontal_margin"
- android:layout_marginBottom="@dimen/activity_vertical_margin"
android:text="@string/oreo_autofill_warning_publisher_header"
android:textSize="12sp"
- app:layout_constraintBottom_toTopOf="@id/warningAppName"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/warningSign" />
+ app:layout_constraintStart_toEndOf="@id/warningSign"
+ app:layout_constraintTop_toBottomOf="@id/cover" />
<TextView
android:id="@+id/warningAppName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/activity_horizontal_margin"
+ android:layout_marginTop="@dimen/activity_vertical_margin"
android:layout_marginEnd="@dimen/activity_horizontal_margin"
android:gravity="center_horizontal"
android:textSize="12sp"
@@ -87,79 +99,77 @@
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:layout_marginEnd="@dimen/activity_horizontal_margin"
- android:layout_marginBottom="@dimen/activity_vertical_margin"
android:text="@string/oreo_autofill_warning_publisher_footer"
android:textSize="12sp"
- app:layout_constraintBottom_toTopOf="@id/okButton"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/warningAppInstallDate" />
- <Button
+ <com.google.android.material.button.MaterialButton
android:id="@+id/okButton"
- style="@style/Widget.MaterialComponents.Button.OutlinedButton"
+ style="@style/AppTheme.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/activity_horizontal_margin"
+ android:layout_marginTop="@dimen/activity_vertical_margin"
android:layout_marginEnd="@dimen/activity_horizontal_margin"
+ android:minWidth="240dp"
android:text="@string/oreo_autofill_warning_publisher_changed_disable_autofill_button"
android:textSize="12sp"
- app:layout_constraintBottom_toTopOf="@id/advancedButton"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/warningAppFooter" />
- <Button
+ <com.google.android.material.button.MaterialButton
android:id="@+id/advancedButton"
- style="@style/Widget.MaterialComponents.Button.OutlinedButton"
+ style="@style/AppTheme.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:layout_marginEnd="@dimen/activity_horizontal_margin"
+ android:minWidth="240dp"
android:text="@string/oreo_autofill_warning_publisher_advanced_info_button"
android:textSize="12sp"
- app:layout_constraintBottom_toTopOf="@id/warningAppAdvancedInfo"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/okButton" />
+ app:layout_constraintTop_toBottomOf="@id/okButton"
+ tools:visibility="visible" />
- <TextView
- android:id="@+id/warningAppAdvancedInfo"
- android:layout_width="0dp"
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/resetButton"
+ style="@style/AppTheme.OutlinedButton"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:layout_marginEnd="@dimen/activity_horizontal_margin"
- android:fontFamily="monospace"
- android:gravity="center_horizontal"
- android:textIsSelectable="true"
- android:textSize="10sp"
- android:visibility="invisible"
- app:layout_constraintBottom_toTopOf="@id/resetButton"
+ android:minWidth="240dp"
+ android:text="@string/oreo_autofill_warning_publisher_reenable_button"
+ android:textColor="?attr/colorOnSurface"
+ android:textSize="12sp"
+ android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/advancedButton"
- tools:ignore="SmallSp"
- tools:text="Package: com.example.banking\n\nHash:\n8P1sW0EPJcslw7UzRsiXL64w+O50Ed+RBICtay1g24M="
tools:visibility="visible" />
- <Button
- android:id="@+id/resetButton"
- style="@style/Widget.MaterialComponents.Button.TextButton"
- android:layout_width="wrap_content"
+ <TextView
+ android:id="@+id/warningAppAdvancedInfo"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/activity_horizontal_margin"
+ android:layout_marginTop="16dp"
android:layout_marginEnd="@dimen/activity_horizontal_margin"
- android:text="@string/oreo_autofill_warning_publisher_reenable_button"
+ android:fontFamily="monospace"
+ android:gravity="center_horizontal"
+ android:textIsSelectable="true"
android:textSize="10sp"
- android:visibility="invisible"
+ android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/warningAppAdvancedInfo"
+ app:layout_constraintTop_toBottomOf="@id/resetButton"
tools:ignore="SmallSp"
+ tools:text="Package: com.example.banking\n\nHash:\n8P1sW0EPJcslw7UzRsiXL64w+O50Ed+RBICtay1g24M="
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/app/src/main/res/layout/activity_proxy_selector.xml b/app/src/main/res/layout/activity_proxy_selector.xml
new file mode 100644
index 00000000..e732dfe0
--- /dev/null
+++ b/app/src/main/res/layout/activity_proxy_selector.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
+ ~ SPDX-License-Identifier: GPL-3.0-only
+ -->
+
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <com.google.android.material.textfield.TextInputLayout
+ android:id="@+id/proxy_host_input_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/activity_horizontal_margin"
+ android:layout_marginTop="@dimen/activity_vertical_margin"
+ android:layout_marginEnd="@dimen/activity_horizontal_margin"
+ android:hint="@string/proxy_hostname"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:layout_editor_absoluteY="64dp">
+
+ <com.google.android.material.textfield.TextInputEditText
+ android:id="@+id/proxy_host"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:inputType="textUri"
+ android:nextFocusForward="@id/proxy_user" />
+
+ </com.google.android.material.textfield.TextInputLayout>
+
+ <com.google.android.material.textfield.TextInputLayout
+ android:id="@+id/proxy_user_input_layout"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/activity_horizontal_margin"
+ android:layout_marginTop="@dimen/normal_margin"
+ android:layout_marginEnd="@dimen/normal_margin"
+ android:hint="@string/username"
+ app:layout_constraintEnd_toStartOf="@id/proxy_port_input_layout"
+ app:layout_constraintHorizontal_weight="0.65"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/proxy_host_input_layout">
+
+ <com.google.android.material.textfield.TextInputEditText
+ android:id="@+id/proxy_user"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:inputType="textWebEmailAddress"
+ android:nextFocusForward="@id/proxy_port" />
+
+ </com.google.android.material.textfield.TextInputLayout>
+
+ <com.google.android.material.textfield.TextInputLayout
+ android:id="@+id/proxy_port_input_layout"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/normal_margin"
+ android:layout_marginTop="@dimen/normal_margin"
+ android:layout_marginEnd="@dimen/activity_horizontal_margin"
+ android:hint="@string/port"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_weight="0.35"
+ app:layout_constraintStart_toEndOf="@id/proxy_user_input_layout"
+ app:layout_constraintTop_toBottomOf="@id/proxy_host_input_layout">
+
+ <com.google.android.material.textfield.TextInputEditText
+ android:id="@+id/proxy_port"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:inputType="number"
+ android:nextFocusForward="@id/proxy_password" />
+ </com.google.android.material.textfield.TextInputLayout>
+
+ <com.google.android.material.textfield.TextInputLayout
+ android:id="@+id/proxy_password_input_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/activity_horizontal_margin"
+ android:layout_marginTop="@dimen/normal_margin"
+ android:layout_marginEnd="@dimen/activity_horizontal_margin"
+ android:hint="@string/password"
+ app:endIconMode="password_toggle"
+ app:layout_constraintStart_toStartOf="@id/proxy_user_input_layout"
+ app:layout_constraintTop_toBottomOf="@id/proxy_user_input_layout">
+
+ <com.google.android.material.textfield.TextInputEditText
+ android:id="@+id/proxy_password"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:inputType="textPassword" />
+ </com.google.android.material.textfield.TextInputLayout>
+
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/save"
+ style="@style/AppTheme.OutlinedButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/normal_margin"
+ android:layout_marginEnd="@dimen/activity_horizontal_margin"
+ android:text="@string/crypto_save"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/proxy_password_input_layout" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/app/src/main/res/layout/fragment_key_selection.xml b/app/src/main/res/layout/fragment_key_selection.xml
new file mode 100644
index 00000000..9a391276
--- /dev/null
+++ b/app/src/main/res/layout/fragment_key_selection.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
+ ~ SPDX-License-Identifier: GPL-3.0-only
+ -->
+
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="?attr/colorPrimary"
+ android:orientation="vertical">
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/app_icon"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_marginStart="32dp"
+ android:layout_marginTop="100dp"
+ android:contentDescription="@string/app_icon_hint"
+ android:src="@mipmap/ic_launcher"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <androidx.appcompat.widget.AppCompatTextView
+ android:id="@+id/app_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_marginStart="16dp"
+ android:text="@string/app_name"
+ android:textAppearance="@style/TextAppearance.MaterialComponents.Headline5"
+ android:textColor="@color/color_control_normal"
+ android:textStyle="bold"
+ app:layout_constraintBottom_toBottomOf="@id/app_icon"
+ app:layout_constraintStart_toEndOf="@id/app_icon"
+ app:layout_constraintTop_toTopOf="@+id/app_icon" />
+
+ <TextView
+ android:id="@+id/gpg_key"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="48dp"
+ android:text="@string/select_gpg_key_title"
+ android:textAppearance="@style/TextAppearance.MaterialComponents.Headline4"
+ android:textColor="@color/color_control_normal"
+ android:textStyle="bold"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="0"
+ app:layout_constraintStart_toStartOf="@id/app_icon"
+ app:layout_constraintTop_toBottomOf="@id/app_icon" />
+
+ <TextView
+ android:id="@+id/gpg_key_text"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="48dp"
+ android:layout_marginEnd="16dp"
+ android:text="@string/select_gpg_key_message"
+ android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
+ android:textColor="@color/color_control_normal"
+ android:textStyle="bold"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="@id/gpg_key"
+ app:layout_constraintTop_toBottomOf="@id/gpg_key" />
+
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/select_key"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+ android:layout_marginTop="48dp"
+ android:layout_marginEnd="16dp"
+ android:maxWidth="300dp"
+ android:minWidth="100dp"
+ android:text="@string/gpg_key_select"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/gpg_key_text" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/app/src/main/res/values-v23/colors.xml b/app/src/main/res/values-v23/colors.xml
deleted file mode 100644
index 7c3be280..00000000
--- a/app/src/main/res/values-v23/colors.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
- ~ SPDX-License-Identifier: GPL-3.0-only
- -->
-
-<resources>
- <color name="navigation_bar_color">#000000</color>
-</resources>
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index bea2e960..b090c761 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -15,7 +15,7 @@
<!-- Theme variables -->
<color name="color_control_normal">@color/primary_text_color</color>
<color name="list_multiselect_background">#668eacbb</color>
- <color name="navigation_bar_color">@color/primary_color</color>
+ <color name="navigation_bar_color">#000000</color>
<color name="status_bar_color">@color/primary_color</color>
<color name="ripple_color">#aa003e5b</color>
<color name="button_color">#44003e5b</color>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 57c32126..cc9f1f24 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -100,10 +100,10 @@
<!-- DECRYPT Layout -->
<string name="action_search">Search</string>
- <string name="password">Password:</string>
- <string name="otp">OTP:</string>
+ <string name="password">Password</string>
+ <string name="otp">OTP</string>
<string name="extra_content">Extra content:</string>
- <string name="username">Username:</string>
+ <string name="username">Username</string>
<string name="edit_password">Edit password</string>
<string name="copy_password">Copy password</string>
<string name="share_as_plaintext">Share as plaintext</string>
@@ -400,9 +400,18 @@
<string name="select_repo_type_text">Select if you want to create a local repo or clone a remote repo.</string>
<string name="clone_remote_repo">Clone Remote Repo</string>
<string name="create_local_repo">Create Local Repo</string>
+ <string name="select_gpg_key_title">Select\nGPG\nKey</string>
+ <string name="select_gpg_key_message">Select a GPG key to initialize your store with</string>
+ <string name="gpg_key_select">Select key</string>
<!-- SSH port validation -->
<string name="ssh_scheme_needed_title">Potentially incorrect URL</string>
<string name="ssh_scheme_needed_message">It appears that your URL contains a custom port, but does not specify the ssh:// scheme.\nThis can cause the port to be considered a part of your path. Press OK here to fix the URL.</string>
+ <!-- Proxy configuration activity -->
+ <string name="proxy_hostname">Proxy hostname</string>
+ <string name="port">Port</string>
+ <string name="pref_proxy_settings">HTTP(S) proxy settings</string>
+ <string name="invalid_proxy_url">Invalid URL</string>
+
</resources>
diff --git a/app/src/main/res/xml/preference.xml b/app/src/main/res/xml/preference.xml
index 1d82df18..58a173c5 100644
--- a/app/src/main/res/xml/preference.xml
+++ b/app/src/main/res/xml/preference.xml
@@ -49,6 +49,9 @@
app:key="git_server_info"
app:title="@string/pref_edit_server_info" />
<Preference
+ app:key="proxy_settings"
+ app:title="@string/pref_proxy_settings" />
+ <Preference
app:key="git_config"
app:title="@string/pref_edit_git_config" />
<Preference
diff --git a/autofill-parser/api/autofill-parser.api b/autofill-parser/api/autofill-parser.api
new file mode 100644
index 00000000..85f02081
--- /dev/null
+++ b/autofill-parser/api/autofill-parser.api
@@ -0,0 +1,381 @@
+public final class com/github/androidpasswordstore/autofillparser/AutofillAction : java/lang/Enum {
+ public static final field FillOtpFromSms Lcom/github/androidpasswordstore/autofillparser/AutofillAction;
+ public static final field Generate Lcom/github/androidpasswordstore/autofillparser/AutofillAction;
+ public static final field Match Lcom/github/androidpasswordstore/autofillparser/AutofillAction;
+ public static final field Search Lcom/github/androidpasswordstore/autofillparser/AutofillAction;
+ public static fun valueOf (Ljava/lang/String;)Lcom/github/androidpasswordstore/autofillparser/AutofillAction;
+ public static fun values ()[Lcom/github/androidpasswordstore/autofillparser/AutofillAction;
+}
+
+public abstract interface annotation class com/github/androidpasswordstore/autofillparser/AutofillDsl : java/lang/annotation/Annotation {
+}
+
+public final class com/github/androidpasswordstore/autofillparser/AutofillHelperKt {
+ public static final fun computeCertificatesHash (Landroid/content/Context;Ljava/lang/String;)Ljava/lang/String;
+ public static final fun findNodeByAutofillId (Landroid/app/assist/AssistStructure;Landroid/view/autofill/AutofillId;)Landroid/app/assist/AssistStructure$ViewNode;
+ public static final fun getWebOrigin (Landroid/app/assist/AssistStructure$ViewNode;)Ljava/lang/String;
+}
+
+public final class com/github/androidpasswordstore/autofillparser/AutofillRule {
+ public synthetic fun <init> (Ljava/util/List;ZZLjava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public final fun match (Ljava/util/List;Ljava/util/List;Ljava/util/List;ZZ)Lcom/github/androidpasswordstore/autofillparser/AutofillScenario;
+}
+
+public final class com/github/androidpasswordstore/autofillparser/AutofillRule$AutofillRuleMatcher {
+ public fun <init> (Lcom/github/androidpasswordstore/autofillparser/AutofillRule$FillableFieldType;Lcom/github/androidpasswordstore/autofillparser/FieldMatcher;ZZ)V
+ public final fun component1 ()Lcom/github/androidpasswordstore/autofillparser/AutofillRule$FillableFieldType;
+ public final fun component2 ()Lcom/github/androidpasswordstore/autofillparser/FieldMatcher;
+ public final fun component3 ()Z
+ public final fun component4 ()Z
+ public final fun copy (Lcom/github/androidpasswordstore/autofillparser/AutofillRule$FillableFieldType;Lcom/github/androidpasswordstore/autofillparser/FieldMatcher;ZZ)Lcom/github/androidpasswordstore/autofillparser/AutofillRule$AutofillRuleMatcher;
+ public static synthetic fun copy$default (Lcom/github/androidpasswordstore/autofillparser/AutofillRule$AutofillRuleMatcher;Lcom/github/androidpasswordstore/autofillparser/AutofillRule$FillableFieldType;Lcom/github/androidpasswordstore/autofillparser/FieldMatcher;ZZILjava/lang/Object;)Lcom/github/androidpasswordstore/autofillparser/AutofillRule$AutofillRuleMatcher;
+ public fun equals (Ljava/lang/Object;)Z
+ public final fun getMatchHidden ()Z
+ public final fun getMatcher ()Lcom/github/androidpasswordstore/autofillparser/FieldMatcher;
+ public final fun getOptional ()Z
+ public final fun getType ()Lcom/github/androidpasswordstore/autofillparser/AutofillRule$FillableFieldType;
+ public fun hashCode ()I
+ public fun toString ()Ljava/lang/String;
+}
+
+public final class com/github/androidpasswordstore/autofillparser/AutofillRule$Builder {
+ public static final field Companion Lcom/github/androidpasswordstore/autofillparser/AutofillRule$Builder$Companion;
+ public fun <init> (ZZ)V
+ public final fun build ()Lcom/github/androidpasswordstore/autofillparser/AutofillRule;
+ public final fun currentPassword (ZZLkotlin/jvm/functions/Function1;)V
+ public static synthetic fun currentPassword$default (Lcom/github/androidpasswordstore/autofillparser/AutofillRule$Builder;ZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
+ public final fun genericPassword (ZLkotlin/jvm/functions/Function1;)V
+ public static synthetic fun genericPassword$default (Lcom/github/androidpasswordstore/autofillparser/AutofillRule$Builder;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
+ public final fun getName ()Ljava/lang/String;
+ public final fun newPassword (ZLkotlin/jvm/functions/Function1;)V
+ public static synthetic fun newPassword$default (Lcom/github/androidpasswordstore/autofillparser/AutofillRule$Builder;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
+ public final fun otp (ZLkotlin/jvm/functions/Function1;)V
+ public static synthetic fun otp$default (Lcom/github/androidpasswordstore/autofillparser/AutofillRule$Builder;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
+ public final fun setName (Ljava/lang/String;)V
+ public final fun username (ZZLkotlin/jvm/functions/Function1;)V
+ public static synthetic fun username$default (Lcom/github/androidpasswordstore/autofillparser/AutofillRule$Builder;ZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
+}
+
+public final class com/github/androidpasswordstore/autofillparser/AutofillRule$Builder$Companion {
+}
+
+public final class com/github/androidpasswordstore/autofillparser/AutofillRule$FillableFieldType : java/lang/Enum {
+ public static final field CurrentPassword Lcom/github/androidpasswordstore/autofillparser/AutofillRule$FillableFieldType;
+ public static final field GenericPassword Lcom/github/androidpasswordstore/autofillparser/AutofillRule$FillableFieldType;
+ public static final field NewPassword Lcom/github/androidpasswordstore/autofillparser/AutofillRule$FillableFieldType;
+ public static final field Otp Lcom/github/androidpasswordstore/autofillparser/AutofillRule$FillableFieldType;
+ public static final field Username Lcom/github/androidpasswordstore/autofillparser/AutofillRule$FillableFieldType;
+ public static fun valueOf (Ljava/lang/String;)Lcom/github/androidpasswordstore/autofillparser/AutofillRule$FillableFieldType;
+ public static fun values ()[Lcom/github/androidpasswordstore/autofillparser/AutofillRule$FillableFieldType;
+}
+
+public abstract class com/github/androidpasswordstore/autofillparser/AutofillScenario {
+ public static final field BUNDLE_KEY_CURRENT_PASSWORD_IDS Ljava/lang/String;
+ public static final field BUNDLE_KEY_FILL_USERNAME Ljava/lang/String;
+ public static final field BUNDLE_KEY_GENERIC_PASSWORD_IDS Ljava/lang/String;
+ public static final field BUNDLE_KEY_NEW_PASSWORD_IDS Ljava/lang/String;
+ public static final field BUNDLE_KEY_OTP_ID Ljava/lang/String;
+ public static final field BUNDLE_KEY_USERNAME_ID Ljava/lang/String;
+ public static final field Companion Lcom/github/androidpasswordstore/autofillparser/AutofillScenario$Companion;
+ public final fun fieldsToFillOn (Lcom/github/androidpasswordstore/autofillparser/AutofillAction;)Ljava/util/List;
+ public final fun getAllFields ()Ljava/util/List;
+ public abstract fun getAllPasswordFields ()Ljava/util/List;
+ public final fun getFieldsToSave ()Ljava/util/List;
+ public abstract fun getFillUsername ()Z
+ public abstract fun getOtp ()Ljava/lang/Object;
+ public abstract fun getPasswordFieldsToFillOnGenerate ()Ljava/util/List;
+ public abstract fun getPasswordFieldsToFillOnMatch ()Ljava/util/List;
+ public abstract fun getPasswordFieldsToFillOnSearch ()Ljava/util/List;
+ public abstract fun getPasswordFieldsToSave ()Ljava/util/List;
+ public abstract fun getUsername ()Ljava/lang/Object;
+}
+
+public final class com/github/androidpasswordstore/autofillparser/AutofillScenario$Builder {
+ public fun <init> ()V
+ public final fun build ()Lcom/github/androidpasswordstore/autofillparser/AutofillScenario;
+ public final fun getCurrentPassword ()Ljava/util/List;
+ public final fun getFillUsername ()Z
+ public final fun getGenericPassword ()Ljava/util/List;
+ public final fun getNewPassword ()Ljava/util/List;
+ public final fun getOtp ()Ljava/lang/Object;
+ public final fun getUsername ()Ljava/lang/Object;
+ public final fun setFillUsername (Z)V
+ public final fun setOtp (Ljava/lang/Object;)V
+ public final fun setUsername (Ljava/lang/Object;)V
+}
+
+public final class com/github/androidpasswordstore/autofillparser/AutofillScenario$Companion {
+ public final fun fromBundle (Landroid/os/Bundle;)Lcom/github/androidpasswordstore/autofillparser/AutofillScenario;
+}
+
+public final class com/github/androidpasswordstore/autofillparser/AutofillScenarioKt {
+ public static final fun fillWithAutofillId (Landroid/service/autofill/Dataset$Builder;Lcom/github/androidpasswordstore/autofillparser/AutofillScenario;Lcom/github/androidpasswordstore/autofillparser/AutofillAction;Lcom/github/androidpasswordstore/autofillparser/Credentials;)V
+ public static final fun fillWithFormField (Landroid/service/autofill/Dataset$Builder;Lcom/github/androidpasswordstore/autofillparser/AutofillScenario;Lcom/github/androidpasswordstore/autofillparser/AutofillAction;Lcom/github/androidpasswordstore/autofillparser/Credentials;)V
+ public static final fun getPasswordValue (Lcom/github/androidpasswordstore/autofillparser/AutofillScenario;)Ljava/lang/String;
+ public static final fun getUsernameValue (Lcom/github/androidpasswordstore/autofillparser/AutofillScenario;)Ljava/lang/String;
+ public static final fun map (Lcom/github/androidpasswordstore/autofillparser/AutofillScenario;Lkotlin/jvm/functions/Function1;)Lcom/github/androidpasswordstore/autofillparser/AutofillScenario;
+ public static final fun passesOriginCheck (Lcom/github/androidpasswordstore/autofillparser/AutofillScenario;Z)Z
+ public static final fun recoverNodes (Lcom/github/androidpasswordstore/autofillparser/AutofillScenario;Landroid/app/assist/AssistStructure;)Lcom/github/androidpasswordstore/autofillparser/AutofillScenario;
+ public static final fun toBundleFormField (Lcom/github/androidpasswordstore/autofillparser/AutofillScenario;)Landroid/os/Bundle;
+}
+
+public final class com/github/androidpasswordstore/autofillparser/AutofillStrategy {
+ public synthetic fun <init> (Ljava/util/List;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public final fun match (Ljava/util/List;ZZ)Lcom/github/androidpasswordstore/autofillparser/AutofillScenario;
+}
+
+public final class com/github/androidpasswordstore/autofillparser/AutofillStrategy$Builder {
+ public fun <init> ()V
+ public final fun build ()Lcom/github/androidpasswordstore/autofillparser/AutofillStrategy;
+ public final fun rule (ZZLkotlin/jvm/functions/Function1;)V
+ public static synthetic fun rule$default (Lcom/github/androidpasswordstore/autofillparser/AutofillStrategy$Builder;ZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
+}
+
+public final class com/github/androidpasswordstore/autofillparser/AutofillStrategyDslKt {
+ public static final fun strategy (Lkotlin/jvm/functions/Function1;)Lcom/github/androidpasswordstore/autofillparser/AutofillStrategy;
+}
+
+public final class com/github/androidpasswordstore/autofillparser/AutofillStrategyKt {
+ public static final fun getAutofillStrategy ()Lcom/github/androidpasswordstore/autofillparser/AutofillStrategy;
+}
+
+public final class com/github/androidpasswordstore/autofillparser/BrowserAutofillSupportInfo {
+ public fun <init> (Lcom/github/androidpasswordstore/autofillparser/BrowserMultiOriginMethod;Ljava/lang/Integer;)V
+ public final fun component1 ()Lcom/github/androidpasswordstore/autofillparser/BrowserMultiOriginMethod;
+ public final fun component2 ()Ljava/lang/Integer;
+ public final fun copy (Lcom/github/androidpasswordstore/autofillparser/BrowserMultiOriginMethod;Ljava/lang/Integer;)Lcom/github/androidpasswordstore/autofillparser/BrowserAutofillSupportInfo;
+ public static synthetic fun copy$default (Lcom/github/androidpasswordstore/autofillparser/BrowserAutofillSupportInfo;Lcom/github/androidpasswordstore/autofillparser/BrowserMultiOriginMethod;Ljava/lang/Integer;ILjava/lang/Object;)Lcom/github/androidpasswordstore/autofillparser/BrowserAutofillSupportInfo;
+ public fun equals (Ljava/lang/Object;)Z
+ public final fun getMultiOriginMethod ()Lcom/github/androidpasswordstore/autofillparser/BrowserMultiOriginMethod;
+ public final fun getSaveFlags ()Ljava/lang/Integer;
+ public fun hashCode ()I
+ public fun toString ()Ljava/lang/String;
+}
+
+public final class com/github/androidpasswordstore/autofillparser/BrowserAutofillSupportLevel : java/lang/Enum {
+ public static final field FlakyFill Lcom/github/androidpasswordstore/autofillparser/BrowserAutofillSupportLevel;
+ public static final field GeneralFill Lcom/github/androidpasswordstore/autofillparser/BrowserAutofillSupportLevel;
+ public static final field GeneralFillAndSave Lcom/github/androidpasswordstore/autofillparser/BrowserAutofillSupportLevel;
+ public static final field None Lcom/github/androidpasswordstore/autofillparser/BrowserAutofillSupportLevel;
+ public static final field PasswordFill Lcom/github/androidpasswordstore/autofillparser/BrowserAutofillSupportLevel;
+ public static fun valueOf (Ljava/lang/String;)Lcom/github/androidpasswordstore/autofillparser/BrowserAutofillSupportLevel;
+ public static fun values ()[Lcom/github/androidpasswordstore/autofillparser/BrowserAutofillSupportLevel;
+}
+
+public final class com/github/androidpasswordstore/autofillparser/BrowserMultiOriginMethod : java/lang/Enum {
+ public static final field Field Lcom/github/androidpasswordstore/autofillparser/BrowserMultiOriginMethod;
+ public static final field None Lcom/github/androidpasswordstore/autofillparser/BrowserMultiOriginMethod;
+ public static final field WebView Lcom/github/androidpasswordstore/autofillparser/BrowserMultiOriginMethod;
+ public static fun valueOf (Ljava/lang/String;)Lcom/github/androidpasswordstore/autofillparser/BrowserMultiOriginMethod;
+ public static fun values ()[Lcom/github/androidpasswordstore/autofillparser/BrowserMultiOriginMethod;
+}
+
+public final class com/github/androidpasswordstore/autofillparser/CertaintyLevel : java/lang/Enum {
+ public static final field Certain Lcom/github/androidpasswordstore/autofillparser/CertaintyLevel;
+ public static final field Impossible Lcom/github/androidpasswordstore/autofillparser/CertaintyLevel;
+ public static final field Likely Lcom/github/androidpasswordstore/autofillparser/CertaintyLevel;
+ public static final field Possible Lcom/github/androidpasswordstore/autofillparser/CertaintyLevel;
+ public static fun valueOf (Ljava/lang/String;)Lcom/github/androidpasswordstore/autofillparser/CertaintyLevel;
+ public static fun values ()[Lcom/github/androidpasswordstore/autofillparser/CertaintyLevel;
+}
+
+public final class com/github/androidpasswordstore/autofillparser/ClassifiedAutofillScenario : com/github/androidpasswordstore/autofillparser/AutofillScenario {
+ public fun <init> (Ljava/lang/Object;ZLjava/lang/Object;Ljava/util/List;Ljava/util/List;)V
+ public final fun component1 ()Ljava/lang/Object;
+ public final fun component2 ()Z
+ public final fun component3 ()Ljava/lang/Object;
+ public final fun component4 ()Ljava/util/List;
+ public final fun component5 ()Ljava/util/List;
+ public final fun copy (Ljava/lang/Object;ZLjava/lang/Object;Ljava/util/List;Ljava/util/List;)Lcom/github/androidpasswordstore/autofillparser/ClassifiedAutofillScenario;
+ public static synthetic fun copy$default (Lcom/github/androidpasswordstore/autofillparser/ClassifiedAutofillScenario;Ljava/lang/Object;ZLjava/lang/Object;Ljava/util/List;Ljava/util/List;ILjava/lang/Object;)Lcom/github/androidpasswordstore/autofillparser/ClassifiedAutofillScenario;
+ public fun equals (Ljava/lang/Object;)Z
+ public fun getAllPasswordFields ()Ljava/util/List;
+ public final fun getCurrentPassword ()Ljava/util/List;
+ public fun getFillUsername ()Z
+ public final fun getNewPassword ()Ljava/util/List;
+ public fun getOtp ()Ljava/lang/Object;
+ public fun getPasswordFieldsToFillOnGenerate ()Ljava/util/List;
+ public fun getPasswordFieldsToFillOnMatch ()Ljava/util/List;
+ public fun getPasswordFieldsToFillOnSearch ()Ljava/util/List;
+ public fun getPasswordFieldsToSave ()Ljava/util/List;
+ public fun getUsername ()Ljava/lang/Object;
+ public fun hashCode ()I
+ public fun toString ()Ljava/lang/String;
+}
+
+public final class com/github/androidpasswordstore/autofillparser/Credentials {
+ public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ public final fun component1 ()Ljava/lang/String;
+ public final fun component2 ()Ljava/lang/String;
+ public final fun component3 ()Ljava/lang/String;
+ public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lcom/github/androidpasswordstore/autofillparser/Credentials;
+ public static synthetic fun copy$default (Lcom/github/androidpasswordstore/autofillparser/Credentials;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lcom/github/androidpasswordstore/autofillparser/Credentials;
+ public fun equals (Ljava/lang/Object;)Z
+ public final fun getOtp ()Ljava/lang/String;
+ public final fun getPassword ()Ljava/lang/String;
+ public final fun getUsername ()Ljava/lang/String;
+ public fun hashCode ()I
+ public fun toString ()Ljava/lang/String;
+}
+
+public final class com/github/androidpasswordstore/autofillparser/FeatureAndTrustDetectionKt {
+ public static final fun getBrowserAutofillSupportInfoIfTrusted (Landroid/content/Context;Ljava/lang/String;)Lcom/github/androidpasswordstore/autofillparser/BrowserAutofillSupportInfo;
+ public static final fun getInstalledBrowsersWithAutofillSupportLevel (Landroid/content/Context;)Ljava/util/List;
+}
+
+public abstract interface class com/github/androidpasswordstore/autofillparser/FieldMatcher {
+ public abstract fun match (Ljava/util/List;Ljava/util/List;)Ljava/util/List;
+}
+
+public final class com/github/androidpasswordstore/autofillparser/FieldMatcher$Builder {
+ public fun <init> ()V
+ public final fun breakTieOnPair (Lkotlin/jvm/functions/Function2;)V
+ public final fun breakTieOnSingle (Lkotlin/jvm/functions/Function2;)V
+ public final fun build ()Lcom/github/androidpasswordstore/autofillparser/FieldMatcher;
+ public final fun takePair (Lkotlin/jvm/functions/Function2;)V
+ public static synthetic fun takePair$default (Lcom/github/androidpasswordstore/autofillparser/FieldMatcher$Builder;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)V
+ public final fun takeSingle (Lkotlin/jvm/functions/Function2;)V
+ public static synthetic fun takeSingle$default (Lcom/github/androidpasswordstore/autofillparser/FieldMatcher$Builder;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)V
+}
+
+public final class com/github/androidpasswordstore/autofillparser/FillableForm {
+ public static final field Companion Lcom/github/androidpasswordstore/autofillparser/FillableForm$Companion;
+ public synthetic fun <init> (Lcom/github/androidpasswordstore/autofillparser/FormOrigin;Lcom/github/androidpasswordstore/autofillparser/AutofillScenario;Ljava/util/List;Ljava/lang/Integer;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public final fun getFormOrigin ()Lcom/github/androidpasswordstore/autofillparser/FormOrigin;
+ public final fun getIgnoredIds ()Ljava/util/List;
+ public final fun getSaveFlags ()Ljava/lang/Integer;
+ public final fun getScenario ()Lcom/github/androidpasswordstore/autofillparser/AutofillScenario;
+ public final fun toClientState ()Landroid/os/Bundle;
+}
+
+public final class com/github/androidpasswordstore/autofillparser/FillableForm$Companion {
+ public final fun parseAssistStructure (Landroid/content/Context;Landroid/app/assist/AssistStructure;ZLkotlin/sequences/Sequence;)Lcom/github/androidpasswordstore/autofillparser/FillableForm;
+ public static synthetic fun parseAssistStructure$default (Lcom/github/androidpasswordstore/autofillparser/FillableForm$Companion;Landroid/content/Context;Landroid/app/assist/AssistStructure;ZLkotlin/sequences/Sequence;ILjava/lang/Object;)Lcom/github/androidpasswordstore/autofillparser/FillableForm;
+}
+
+public final class com/github/androidpasswordstore/autofillparser/FixedSaveCallback {
+ public fun <init> (Landroid/content/Context;Landroid/service/autofill/SaveCallback;)V
+ public final fun onFailure (Ljava/lang/CharSequence;)V
+ public final fun onSuccess (Landroid/content/IntentSender;)V
+}
+
+public final class com/github/androidpasswordstore/autofillparser/FormField {
+ public static final field Companion Lcom/github/androidpasswordstore/autofillparser/FormField$Companion;
+ public fun <init> (Landroid/app/assist/AssistStructure$ViewNode;IZLjava/lang/String;)V
+ public synthetic fun <init> (Landroid/app/assist/AssistStructure$ViewNode;IZLjava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public final fun directlyFollows (Lcom/github/androidpasswordstore/autofillparser/FormField;)Z
+ public final fun directlyFollows (Ljava/lang/Iterable;)Z
+ public final fun directlyPrecedes (Lcom/github/androidpasswordstore/autofillparser/FormField;)Z
+ public final fun directlyPrecedes (Ljava/lang/Iterable;)Z
+ public fun equals (Ljava/lang/Object;)Z
+ public final fun getAutofillId ()Landroid/view/autofill/AutofillId;
+ public final fun getCouldBeTwoStepHiddenPassword ()Z
+ public final fun getCouldBeTwoStepHiddenUsername ()Z
+ public final fun getHasAutocompleteHintCurrentPassword ()Z
+ public final fun getHasAutofillHintPassword ()Z
+ public final fun getHasHintNewPassword ()Z
+ public final fun getHasHintOtp ()Z
+ public final fun getHasHintPassword ()Z
+ public final fun getHasHintUsername ()Z
+ public final fun getOtpCertainty ()Lcom/github/androidpasswordstore/autofillparser/CertaintyLevel;
+ public final fun getPasswordCertainty ()Lcom/github/androidpasswordstore/autofillparser/CertaintyLevel;
+ public final fun getRelevantField ()Z
+ public final fun getUsernameCertainty ()Lcom/github/androidpasswordstore/autofillparser/CertaintyLevel;
+ public final fun getWebOrigin ()Ljava/lang/String;
+ public final fun getWebOriginToPassDown ()Ljava/lang/String;
+ public fun hashCode ()I
+ public final fun isFocused ()Z
+ public final fun isVisible ()Z
+ public fun toString ()Ljava/lang/String;
+}
+
+public final class com/github/androidpasswordstore/autofillparser/FormField$Companion {
+}
+
+public abstract class com/github/androidpasswordstore/autofillparser/FormOrigin {
+ public static final field Companion Lcom/github/androidpasswordstore/autofillparser/FormOrigin$Companion;
+ public synthetic fun <init> (Ljava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public fun getIdentifier ()Ljava/lang/String;
+ public final fun getPrettyIdentifier (Landroid/content/Context;Z)Ljava/lang/String;
+ public static synthetic fun getPrettyIdentifier$default (Lcom/github/androidpasswordstore/autofillparser/FormOrigin;Landroid/content/Context;ZILjava/lang/Object;)Ljava/lang/String;
+ public final fun toBundle ()Landroid/os/Bundle;
+}
+
+public final class com/github/androidpasswordstore/autofillparser/FormOrigin$App : com/github/androidpasswordstore/autofillparser/FormOrigin {
+ public fun <init> (Ljava/lang/String;)V
+ public final fun component1 ()Ljava/lang/String;
+ public final fun copy (Ljava/lang/String;)Lcom/github/androidpasswordstore/autofillparser/FormOrigin$App;
+ public static synthetic fun copy$default (Lcom/github/androidpasswordstore/autofillparser/FormOrigin$App;Ljava/lang/String;ILjava/lang/Object;)Lcom/github/androidpasswordstore/autofillparser/FormOrigin$App;
+ public fun equals (Ljava/lang/Object;)Z
+ public fun getIdentifier ()Ljava/lang/String;
+ public fun hashCode ()I
+ public fun toString ()Ljava/lang/String;
+}
+
+public final class com/github/androidpasswordstore/autofillparser/FormOrigin$Companion {
+ public final fun fromBundle (Landroid/os/Bundle;)Lcom/github/androidpasswordstore/autofillparser/FormOrigin;
+}
+
+public final class com/github/androidpasswordstore/autofillparser/FormOrigin$Web : com/github/androidpasswordstore/autofillparser/FormOrigin {
+ public fun <init> (Ljava/lang/String;)V
+ public final fun component1 ()Ljava/lang/String;
+ public final fun copy (Ljava/lang/String;)Lcom/github/androidpasswordstore/autofillparser/FormOrigin$Web;
+ public static synthetic fun copy$default (Lcom/github/androidpasswordstore/autofillparser/FormOrigin$Web;Ljava/lang/String;ILjava/lang/Object;)Lcom/github/androidpasswordstore/autofillparser/FormOrigin$Web;
+ public fun equals (Ljava/lang/Object;)Z
+ public fun getIdentifier ()Ljava/lang/String;
+ public fun hashCode ()I
+ public fun toString ()Ljava/lang/String;
+}
+
+public final class com/github/androidpasswordstore/autofillparser/GenericAutofillScenario : com/github/androidpasswordstore/autofillparser/AutofillScenario {
+ public fun <init> (Ljava/lang/Object;ZLjava/lang/Object;Ljava/util/List;)V
+ public final fun component1 ()Ljava/lang/Object;
+ public final fun component2 ()Z
+ public final fun component3 ()Ljava/lang/Object;
+ public final fun component4 ()Ljava/util/List;
+ public final fun copy (Ljava/lang/Object;ZLjava/lang/Object;Ljava/util/List;)Lcom/github/androidpasswordstore/autofillparser/GenericAutofillScenario;
+ public static synthetic fun copy$default (Lcom/github/androidpasswordstore/autofillparser/GenericAutofillScenario;Ljava/lang/Object;ZLjava/lang/Object;Ljava/util/List;ILjava/lang/Object;)Lcom/github/androidpasswordstore/autofillparser/GenericAutofillScenario;
+ public fun equals (Ljava/lang/Object;)Z
+ public fun getAllPasswordFields ()Ljava/util/List;
+ public fun getFillUsername ()Z
+ public final fun getGenericPassword ()Ljava/util/List;
+ public fun getOtp ()Ljava/lang/Object;
+ public fun getPasswordFieldsToFillOnGenerate ()Ljava/util/List;
+ public fun getPasswordFieldsToFillOnMatch ()Ljava/util/List;
+ public fun getPasswordFieldsToFillOnSearch ()Ljava/util/List;
+ public fun getPasswordFieldsToSave ()Ljava/util/List;
+ public fun getUsername ()Ljava/lang/Object;
+ public fun hashCode ()I
+ public fun toString ()Ljava/lang/String;
+}
+
+public final class com/github/androidpasswordstore/autofillparser/PublicSuffixListCacheKt {
+ public static final fun cachePublicSuffixList (Landroid/content/Context;)V
+ public static final fun getCanonicalSuffix (Landroid/content/Context;Ljava/lang/String;Lkotlin/sequences/Sequence;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+ public static final fun getPublicSuffixPlusOne (Landroid/content/Context;Ljava/lang/String;Lkotlin/sequences/Sequence;)Ljava/lang/String;
+ public static final fun getSuffixPlusUpToOne (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+}
+
+public final class com/github/androidpasswordstore/autofillparser/SingleFieldMatcher : com/github/androidpasswordstore/autofillparser/FieldMatcher {
+ public fun <init> (Lkotlin/jvm/functions/Function2;Ljava/util/List;)V
+ public fun match (Ljava/util/List;Ljava/util/List;)Ljava/util/List;
+}
+
+public final class com/github/androidpasswordstore/autofillparser/SingleFieldMatcher$Builder {
+ public fun <init> ()V
+ public final fun breakTieOnSingle (Lkotlin/jvm/functions/Function2;)V
+ public final fun build ()Lcom/github/androidpasswordstore/autofillparser/SingleFieldMatcher;
+ public final fun takeSingle (Lkotlin/jvm/functions/Function2;)V
+ public static synthetic fun takeSingle$default (Lcom/github/androidpasswordstore/autofillparser/SingleFieldMatcher$Builder;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)V
+}
+
+public final class mozilla/components/lib/publicsuffixlist/PublicSuffixList {
+ public fun <init> (Landroid/content/Context;Lkotlinx/coroutines/CoroutineDispatcher;Lkotlinx/coroutines/CoroutineScope;)V
+ public synthetic fun <init> (Landroid/content/Context;Lkotlinx/coroutines/CoroutineDispatcher;Lkotlinx/coroutines/CoroutineScope;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public final fun getPublicSuffix (Ljava/lang/String;)Lkotlinx/coroutines/Deferred;
+ public final fun getPublicSuffixPlusOne (Ljava/lang/String;)Lkotlinx/coroutines/Deferred;
+ public final fun isPublicSuffix (Ljava/lang/String;)Lkotlinx/coroutines/Deferred;
+ public final fun prefetch ()Lkotlinx/coroutines/Deferred;
+ public final fun stripPublicSuffix (Ljava/lang/String;)Lkotlinx/coroutines/Deferred;
+}
+
diff --git a/autofill-parser/build.gradle.kts b/autofill-parser/build.gradle.kts
index e668a1f3..7f2a6467 100644
--- a/autofill-parser/build.gradle.kts
+++ b/autofill-parser/build.gradle.kts
@@ -39,10 +39,37 @@ afterEvaluate {
}
publications {
create<MavenPublication>("apsMaven") {
+ fun getKey(propertyName: String): String {
+ return findProperty(propertyName)?.toString() ?: error("Failed to find property for $propertyName")
+ }
+
from(components.getByName("release"))
- groupId = findProperty("GROUP").toString()
- artifactId = findProperty("POM_ARTIFACT_ID").toString()
- version = findProperty("VERSION_NAME").toString()
+ groupId = getKey("GROUP")
+ artifactId = getKey("POM_ARTIFACT_ID")
+ version = getKey("VERSION_NAME")
+ pom {
+ name.set(getKey("POM_ARTIFACT_ID"))
+ description.set(getKey("POM_ARTIFACT_DESCRIPTION"))
+ url.set(getKey("POM_URL"))
+ licenses {
+ license {
+ name.set(getKey("POM_LICENSE_NAME"))
+ url.set(getKey("POM_LICENSE_URL"))
+ }
+ }
+ developers {
+ developer {
+ id.set(getKey("POM_DEVELOPER_ID"))
+ name.set(getKey("POM_DEVELOPER_NAME"))
+ email.set(getKey("POM_DEVELOPER_EMAIL"))
+ }
+ }
+ scm {
+ connection.set(getKey("POM_SCM_CONNECTION"))
+ developerConnection.set(getKey("POM_SCM_DEV_CONNECTION"))
+ url.set(getKey("POM_SCM_URL"))
+ }
+ }
}
}
}
diff --git a/autofill-parser/gradle.properties b/autofill-parser/gradle.properties
index 24371c01..fe1b7688 100644
--- a/autofill-parser/gradle.properties
+++ b/autofill-parser/gradle.properties
@@ -1,6 +1,7 @@
GROUP=com.github.androidpasswordstore
VERSION_NAME=1.0.0
POM_ARTIFACT_ID=autofill-parser
+POM_ARTIFACT_DESCRIPTION=Android library for low-level parsing of Autofill structures
POM_URL=https://github.com/Android-Password-Store/android-password-store
POM_SCM_URL=https://github.com/Android-Password-Store/android-password-store
@@ -13,3 +14,4 @@ POM_LICENSE_DIST=repo
POM_DEVELOPER_ID=android-password-store
POM_DEVELOPER_NAME=The Android Password Store Authors
+POM_DEVELOPER_EMAIL=aps@msfjarvis.dev
diff --git a/autofill-parser/src/main/assets/publicsuffixes b/autofill-parser/src/main/assets/publicsuffixes
index 814d4969..074a5607 100644
--- a/autofill-parser/src/main/assets/publicsuffixes
+++ b/autofill-parser/src/main/assets/publicsuffixes
Binary files differ
diff --git a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillStrategyDsl.kt b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillStrategyDsl.kt
index 86201be8..f3f6d97d 100644
--- a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillStrategyDsl.kt
+++ b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillStrategyDsl.kt
@@ -94,6 +94,10 @@ class SingleFieldMatcher(
override fun match(fields: List<FormField>, alreadyMatched: List<FormField>): List<FormField>? {
return fields.minus(alreadyMatched).filter { take(it, alreadyMatched) }.let { contestants ->
+ when (contestants.size) {
+ 1 -> return@let listOf(contestants.single())
+ 0 -> return@let null
+ }
var current = contestants
for ((i, tieBreaker) in tieBreakers.withIndex()) {
// Successively filter matched fields via tie breakers...
@@ -127,11 +131,15 @@ private class PairOfFieldsMatcher(
return fields.minus(alreadyMatched).zipWithNext()
.filter { it.first directlyPrecedes it.second }.filter { take(it, alreadyMatched) }
.let { contestants ->
+ when (contestants.size) {
+ 1 -> return@let contestants.single().toList()
+ 0 -> return@let null
+ }
var current = contestants
for ((i, tieBreaker) in tieBreakers.withIndex()) {
val new = current.filter { tieBreaker(it, alreadyMatched) }
if (new.isEmpty()) {
- d { "Tie breaker #${i + 1}: Didn't match any field; skipping" }
+ d { "Tie breaker #${i + 1}: Didn't match any pair of fields; skipping" }
continue
}
// and return if the available options have been narrowed to a single field.
@@ -140,7 +148,7 @@ private class PairOfFieldsMatcher(
current = new
break
}
- d { "Tie breaker #${i + 1}: Matched ${new.size} fields; continuing" }
+ d { "Tie breaker #${i + 1}: Matched ${new.size} pairs of fields; continuing" }
current = new
}
current.singleOrNull()?.toList()
diff --git a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/FormField.kt b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/FormField.kt
index ae16a995..91e51f5c 100644
--- a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/FormField.kt
+++ b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/FormField.kt
@@ -243,7 +243,7 @@ class FormField(
// Password field heuristics (based only on the current field)
private val isPossiblePasswordField =
- notExcluded && (isAndroidPasswordField || isHtmlPasswordField)
+ notExcluded && (isAndroidPasswordField || isHtmlPasswordField || hasHintPassword)
private val isCertainPasswordField = isPossiblePasswordField && hasHintPassword
private val isLikelyPasswordField = isPossiblePasswordField &&
(isCertainPasswordField || PASSWORD_HEURISTIC_TERMS.anyMatchesFieldInfo)
diff --git a/autofill-parser/src/main/java/mozilla/components/lib/publicsuffixlist/PublicSuffixList.kt b/autofill-parser/src/main/java/mozilla/components/lib/publicsuffixlist/PublicSuffixList.kt
index d4d1c1af..f1cdb12a 100644
--- a/autofill-parser/src/main/java/mozilla/components/lib/publicsuffixlist/PublicSuffixList.kt
+++ b/autofill-parser/src/main/java/mozilla/components/lib/publicsuffixlist/PublicSuffixList.kt
@@ -32,7 +32,7 @@ class PublicSuffixList(
private val scope: CoroutineScope = CoroutineScope(dispatcher)
) {
- private val data: PublicSuffixListData by lazy { PublicSuffixListLoader.load(context) }
+ private val data: PublicSuffixListData by lazy(LazyThreadSafetyMode.PUBLICATION) { PublicSuffixListLoader.load(context) }
/**
* Prefetch the public suffix list from disk so that it is available in memory.
diff --git a/build.gradle.kts b/build.gradle.kts
index c128f531..93b44473 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -4,20 +4,32 @@
*/
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import com.android.build.gradle.BaseExtension
+import kotlinx.validation.ApiValidationExtension
buildscript {
repositories {
google()
jcenter()
+ // For binary compatibility validator.
+ maven { url = uri("https://kotlin.bintray.com/kotlinx") }
}
dependencies {
classpath(Plugins.agp)
+ classpath(Plugins.binaryCompatibilityValidator)
classpath(Plugins.kotlin)
}
}
plugins {
- id("com.github.ben-manes.versions") version "0.31.0"
+ id("com.github.ben-manes.versions") version "0.33.0"
+}
+
+apply(plugin = "binary-compatibility-validator")
+
+extensions.configure<ApiValidationExtension> {
+ ignoredProjects = mutableSetOf(
+ "app"
+ )
}
subprojects {
diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt
index 341cb0ae..0f8c903d 100644
--- a/buildSrc/src/main/java/Dependencies.kt
+++ b/buildSrc/src/main/java/Dependencies.kt
@@ -7,7 +7,8 @@ private const val KOTLIN_VERSION = "1.4.10"
object Plugins {
- const val agp = "com.android.tools.build:gradle:4.0.1"
+ const val agp = "com.android.tools.build:gradle:4.0.2"
+ const val binaryCompatibilityValidator = "org.jetbrains.kotlinx:binary-compatibility-validator:0.2.3"
const val kotlin = "org.jetbrains.kotlin:kotlin-gradle-plugin:$KOTLIN_VERSION"
}
@@ -23,24 +24,24 @@ object Dependencies {
object AndroidX {
- private const val lifecycleVersion = "2.3.0-alpha07"
+ private const val lifecycleVersion = "2.3.0-beta01"
- const val activity_ktx = "androidx.activity:activity-ktx:1.2.0-alpha08"
+ const val activity_ktx = "androidx.activity:activity-ktx:1.2.0-beta01"
const val annotation = "androidx.annotation:annotation:1.1.0"
const val autofill = "androidx.autofill:autofill:1.1.0-alpha02"
const val appcompat = "androidx.appcompat:appcompat:1.3.0-alpha02"
- const val biometric = "androidx.biometric:biometric:1.1.0-alpha02"
- const val constraint_layout = "androidx.constraintlayout:constraintlayout:2.0.1"
- const val core_ktx = "androidx.core:core-ktx:1.5.0-alpha02"
+ const val biometric = "androidx.biometric:biometric:1.1.0-beta01"
+ const val constraint_layout = "androidx.constraintlayout:constraintlayout:2.0.2"
+ const val core_ktx = "androidx.core:core-ktx:1.5.0-alpha04"
const val documentfile = "androidx.documentfile:documentfile:1.0.1"
- const val fragment_ktx = "androidx.fragment:fragment-ktx:1.3.0-alpha08"
+ const val fragment_ktx = "androidx.fragment:fragment-ktx:1.3.0-beta01"
const val lifecycle_common = "androidx.lifecycle:lifecycle-common-java8:$lifecycleVersion"
const val lifecycle_livedata_ktx = "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion"
const val lifecycle_viewmodel_ktx = "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion"
const val material = "com.google.android.material:material:1.3.0-alpha02"
const val preference = "androidx.preference:preference:1.1.1"
- const val recycler_view = "androidx.recyclerview:recyclerview:1.2.0-alpha05"
- const val recycler_view_selection = "androidx.recyclerview:recyclerview-selection:1.1.0-rc02"
+ const val recycler_view = "androidx.recyclerview:recyclerview:1.2.0-alpha06"
+ const val recycler_view_selection = "androidx.recyclerview:recyclerview-selection:1.1.0-rc03"
const val security = "androidx.security:security-crypto:1.1.0-alpha02"
const val swiperefreshlayout = "androidx.swiperefreshlayout:swiperefreshlayout:1.2.0-alpha01"
}
@@ -60,8 +61,8 @@ object Dependencies {
const val fastscroll = "me.zhanghai.android.fastscroll:library:1.1.4"
const val jgit = "org.eclipse.jgit:org.eclipse.jgit:3.7.1.201504261725-r"
const val kotlin_result = "com.michael-bull.kotlin-result:kotlin-result:1.1.9"
- const val leakcanary = "com.squareup.leakcanary:leakcanary-android:2.4"
- const val plumber = "com.squareup.leakcanary:plumber-android:2.4"
+ const val leakcanary = "com.squareup.leakcanary:leakcanary-android:2.5"
+ const val plumber = "com.squareup.leakcanary:plumber-android:2.5"
const val sshj = "com.hierynomus:sshj:0.30.0"
const val ssh_auth = "org.sufficientlysecure:sshauthentication-api:1.0"
const val timber = "com.jakewharton.timber:timber:4.7.1"
diff --git a/contrib/oisafe2pstore/oisafe2pstore.hs b/contrib/oisafe2pstore/oisafe2pstore.hs
deleted file mode 100644
index 0417fc0a..00000000
--- a/contrib/oisafe2pstore/oisafe2pstore.hs
+++ /dev/null
@@ -1,85 +0,0 @@
-{-
- oisafe2psore - Quick and dirty script to convert OI Safe export CSV
- into the password-store tree format.
-
- Copyright 2016 Eugene Crosser
-
- License: BSD, Apache or GPLv3 - chose whatever suits you.
-
- You will need to adjust paths to the GnuPG program and the CSV
- file produced by OI Safe. Also fill in the PGP key I.D.
- Description becomes the file name. '*' in the Description is
- converted to '+', '/' - to '-'. If this is not sufficient,
- adjust the function `sanitize`.
--}
-
-{-# LANGUAGE OverloadedStrings #-}
-
-module Main where
-
---import Data.Text hiding (head, tail, reverse, length, map)
-import Control.Monad
-import Text.CSV
-import System.Directory
-import System.Process
-import System.Exit
-
---gpg = "/usr/local/bin/gpg2"
-gpg = "/usr/bin/gpg2"
-
-keyid = "01234567" -- !!!Fill in the real I.D. here!!!
-
-data Entry = Entry { fCategory :: String
- , fDescription :: String
- , fWebsite :: String
- , fUsername :: String
- , fPassword :: String
- , fNotes :: String
- };
-
-instance Show Entry where
- show e = fPassword e
- ++ nonempty "User" (fUsername e)
- ++ nonempty "Website" (fWebsite e)
- ++ nonempty "Notes" (fNotes e)
- where
- nonempty :: String -> String -> String
- nonempty l v = if length v > 0 then "\n" ++ l ++ ": " ++ v else ""
-
-pathOf e = (sanitize (fCategory e), sanitize (fDescription e))
-
-sanitize = map substsafe
- where
- substsafe '/' = '-'
- substsafe '*' = '+'
- substsafe x = x
-
-record2entry :: Record -> Maybe Entry
-record2entry [fCat,fDesc,fWeb,fUser,fPass,fNote,_] =
- Just (Entry { fCategory = fCat
- , fDescription = fDesc
- , fWebsite = fWeb
- , fUsername = fUser
- , fPassword = fPass
- , fNotes = fNote
- })
-record2entry _ = Nothing
-
-main = parseCSVFromFile "oisafe.csv"
- >>= either (error . show) ((mapM_ makeEntry) . tail)
-
-makeEntry :: Record -> IO ()
-makeEntry = buildFile . record2entry
-
-buildFile :: Maybe Entry -> IO ()
-buildFile Nothing = return ()
-buildFile (Just e) = do
- let
- (sub, file) = pathOf e
- dir = "password-store/" ++ sub
- path = dir ++ "/" ++ file ++ ".gpg"
- cont = show e
- (rc, stdout, stderr) <- readProcessWithExitCode gpg ["-ae", "-r", keyid] cont
- when (rc /= ExitSuccess) $ error $ "gpg rc " ++ (show rc) ++ " message " ++ stderr
- createDirectoryIfMissing True dir
- writeFile path stdout
diff --git a/crowdin.yml b/crowdin.yml
deleted file mode 100644
index ceaa4564..00000000
--- a/crowdin.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-files:
- - source: /app/src/main/res/values/strings.xml
- translation: /app/src/main/res/values-%two_letters_code%/strings.xml
diff --git a/release/deploy-github.sh b/release/deploy-github.sh
deleted file mode 100755
index 9480604b..00000000
--- a/release/deploy-github.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env bash
-set -ex
-
-trap 'exit 1' SIGINT SIGTERM
-
-[ -z "$(command -v hub)" ] && { echo "hub not installed; aborting!"; exit 1; }
-[ -z "${1}" ] && { echo "No tag specified!"; exit 1; }
-prev_ref="$(git rev-parse --abbrev-ref HEAD)"
-git checkout "${1}" || exit 1
-gradle clean bundleRelease assembleRelease
-hub release create "${1}" -a app/build/outputs/apk/release/app-release.apk
-git checkout "$prev_ref"
diff --git a/release/signing-setup.sh b/release/signing-setup.sh
index d46504c3..e930e04d 100755
--- a/release/signing-setup.sh
+++ b/release/signing-setup.sh
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
-set -ex
+set -e
ENCRYPT_KEY=$1