summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/pull_request.yml7
-rw-r--r--.github/workflows/release.yml2
-rw-r--r--.github/workflows/update_publicsuffix_data.yml3
-rw-r--r--.idea/gradle.xml1
-rw-r--r--CHANGELOG.md13
-rw-r--r--README.md3
-rw-r--r--app/build.gradle142
-rw-r--r--app/build.gradle.kts147
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/PasswordFragment.kt2
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/UserPreference.kt11
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillStrategyDsl.kt3
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/autofill/oreo/FeatureAndTrustDetection.kt10
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/autofill/oreo/FormField.kt55
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/autofill/oreo/OreoAutofillService.kt2
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/crypto/PasswordCreationActivity.kt9
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/BaseGitActivity.kt9
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/BreakOutOfDetached.kt13
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/GitConfigActivity.kt2
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/GitOperation.kt7
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/GitServerConfigActivity.kt13
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/ResetToRemoteOperation.kt32
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/config/SshjConfig.kt12
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/pwgen/RandomPasswordGenerator.kt3
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/ui/adapters/PasswordItemRecyclerAdapter.kt19
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/ui/dialogs/FolderCreationDialogFragment.kt2
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/utils/PreferenceKeys.kt1
-rw-r--r--app/src/main/res/layout/activity_git_clone.xml37
-rw-r--r--app/src/main/res/layout/git_credential_layout.xml1
-rw-r--r--app/src/main/res/values/strings.xml1
-rw-r--r--app/src/main/res/xml/oreo_autofill_service.xml16
-rw-r--r--build.gradle69
-rw-r--r--build.gradle.kts66
-rw-r--r--buildSrc/.gitignore1
-rw-r--r--buildSrc/build.gradle.kts11
-rw-r--r--buildSrc/src/main/java/Dependencies.kt84
-rw-r--r--dependencies.gradle82
-rw-r--r--gradle.properties3
-rw-r--r--gradle/wrapper/gradle-wrapper.properties5
-rw-r--r--settings.gradle.kts (renamed from settings.gradle)2
39 files changed, 512 insertions, 389 deletions
diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml
index 688ac96e..8306d009 100644
--- a/.github/workflows/pull_request.yml
+++ b/.github/workflows/pull_request.yml
@@ -92,3 +92,10 @@ jobs:
adb shell settings put global transition_animation_scale 0
adb shell settings put global window_animation_scale 0
./gradlew :app:connectedNonFreeDebugAndroidTest
+
+ - name: (Fail-only) upload test report
+ if: failure()
+ uses: actions/upload-artifact@v2
+ with:
+ name: Test report
+ path: app/build/reports
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 43cd9fac..10484521 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -117,7 +117,7 @@ jobs:
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
body: ${{ steps.changelog_reader.outputs.log_entry }}
- draft: false
+ draft: true
prerelease: false
- name: Get the version
diff --git a/.github/workflows/update_publicsuffix_data.yml b/.github/workflows/update_publicsuffix_data.yml
index 27a2ab14..527f406f 100644
--- a/.github/workflows/update_publicsuffix_data.yml
+++ b/.github/workflows/update_publicsuffix_data.yml
@@ -1,3 +1,4 @@
+name: Update Publix Suffix List data
on:
schedule:
- cron: '0 0 * * 6'
@@ -20,7 +21,7 @@ jobs:
run: |
git checkout -b bot/update-psl
git add app/src/main/assets/publicsuffixes
- git commit --message "Update Public Suffix List data'
+ git commit --message "Update Public Suffix List data"
- name: Create update PR
uses: thomaseizinger/create-pull-request@1.0.0
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 2df14bed..f7e941c7 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -12,6 +12,7 @@
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
+ <option value="$PROJECT_DIR$/buildSrc" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 204704be..c6e8b397 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,19 @@ All notable changes to this project will be documented in this file.
## [Unreleased]
+### Added
+- Allow changing the branch used for Git operations
+
+### Changed
+
+- Slightly reduce APK size
+- Always show the parent path in entries
+
+### Fixed
+
+- Allow creating nested directories directly
+- I keep saying this but for real: error message for wrong SSH/HTTPS password is properly fixed now
+
## [1.10.2] - 2020-07-30
### Fixed
diff --git a/README.md b/README.md
index 367e65a5..15a18dc0 100644
--- a/README.md
+++ b/README.md
@@ -25,6 +25,9 @@ Pull requests are more than welcome (see [TODO](https://github.com/android-passw
height="80" />
</a>
+## Build types
+
+We generate release binaries under two separate configurations titled `free` and `nonFree`. The distinction was created following the merge of [#900](https://msfjarvis.dev/aps/pr/900), that introduced a dependency on closed source GMS libraries. Since F-Droid is a FOSS-only app store, we created the `free` flavor where we do not ship the GMS dependency and thus the feature to fill SMS OTPs is unavailable.
## Features
diff --git a/app/build.gradle b/app/build.gradle
deleted file mode 100644
index ca356b83..00000000
--- a/app/build.gradle
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
- * SPDX-License-Identifier: GPL-3.0-only
- */
-plugins {
- id 'kotlin-android'
-}
-
-final def keystorePropertiesFile = rootProject.file 'keystore.properties'
-
-static final def isSnapshot() {
- return System.env['GITHUB_WORKFLOW'] != null && System.env['SNAPSHOT'] != null
-}
-
-android {
- if (isSnapshot()) {
- android.applicationVariants.all { final variant ->
- variant.outputs.all {
- outputFileName = "aps-${variant.getFlavorName()}_${defaultConfig.versionName}.apk"
- }
- }
- }
-
- buildFeatures.viewBinding = true
-
- defaultConfig {
- applicationId 'dev.msfjarvis.aps'
- versionCode 11020
- versionName '1.10.2'
- }
-
- lintOptions {
- abortOnError = true // make sure build fails with lint errors!
- disable 'MissingTranslation', 'PluralsCandidate'
- }
-
- packagingOptions {
- exclude '.readme'
- exclude 'META-INF/LICENSE.txt'
- exclude 'META-INF/NOTICE.txt'
- }
-
- buildTypes {
- release {
- minifyEnabled = true
- proguardFiles 'proguard-android-optimize.txt', 'proguard-rules.pro'
- buildConfigField 'boolean', 'ENABLE_DEBUG_FEATURES', isSnapshot() ? 'true' : 'false'
- }
- debug {
- applicationIdSuffix = '.debug'
- versionNameSuffix = '-debug'
- minifyEnabled = false
- buildConfigField 'boolean', 'ENABLE_DEBUG_FEATURES', 'true'
- }
- }
-
- if (keystorePropertiesFile.exists()) {
- final def keystoreProperties = new Properties()
- keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
- signingConfigs {
- release {
- keyAlias = keystoreProperties['keyAlias']
- keyPassword = keystoreProperties['keyPassword']
- storeFile = rootProject.file keystoreProperties['storeFile']
- storePassword = keystoreProperties['storePassword']
- }
- }
- buildTypes.release.signingConfig = signingConfigs.release
- buildTypes.debug.signingConfig = signingConfigs.release
- }
-
- flavorDimensions "free"
- productFlavors {
- free {
- versionNameSuffix "-free"
- }
- nonFree {
- }
- }
-}
-
-dependencies {
- implementation deps.androidx.activity_ktx
- implementation deps.androidx.annotation
- implementation deps.androidx.autofill
- implementation deps.androidx.appcompat
- implementation deps.androidx.biometric
- implementation deps.androidx.constraint_layout
- implementation deps.androidx.core_ktx
- implementation deps.androidx.documentfile
- implementation deps.androidx.fragment_ktx
- implementation deps.androidx.lifecycle_common
- implementation deps.androidx.lifecycle_livedata_ktx
- implementation deps.androidx.lifecycle_viewmodel_ktx
- implementation deps.androidx.material
- implementation deps.androidx.preference
- implementation deps.androidx.recycler_view
- implementation deps.androidx.recycler_view_selection
- implementation deps.androidx.security
- implementation deps.androidx.swiperefreshlayout
-
- implementation deps.kotlin.coroutines.android
- implementation deps.kotlin.coroutines.core
-
- implementation deps.first_party.openpgp_ktx
- implementation deps.first_party.zxing_android_embedded
-
- implementation deps.third_party.commons_codec
- implementation deps.third_party.fastscroll
- implementation(deps.third_party.jgit) {
- exclude group: 'org.apache.httpcomponents', module: 'httpclient'
- }
- implementation deps.third_party.jsch
- implementation deps.third_party.sshj
- implementation deps.third_party.bouncycastle
- implementation deps.third_party.plumber
- implementation deps.third_party.ssh_auth
- implementation deps.third_party.timber
- implementation deps.third_party.timberkt
-
- if (isSnapshot()) {
- implementation deps.third_party.leakcanary
- implementation deps.third_party.whatthestack
- } else {
- debugImplementation deps.third_party.leakcanary
- debugImplementation deps.third_party.whatthestack
- }
-
- nonFreeImplementation deps.non_free.google_play_auth_api_phone
-
- // Testing-only dependencies
- androidTestImplementation deps.testing.junit
- androidTestImplementation deps.testing.kotlin_test_junit
- androidTestImplementation deps.testing.androidx.runner
- androidTestImplementation deps.testing.androidx.rules
- androidTestImplementation deps.testing.androidx.junit
- androidTestImplementation deps.testing.androidx.espresso_core
- androidTestImplementation deps.testing.androidx.espresso_intents
-
- testImplementation deps.testing.junit
- testImplementation deps.testing.kotlin_test_junit
-}
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
new file mode 100644
index 00000000..a8e3a058
--- /dev/null
+++ b/app/build.gradle.kts
@@ -0,0 +1,147 @@
+/*
+ * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+import java.util.Properties
+import com.android.build.gradle.internal.api.BaseVariantOutputImpl
+
+plugins {
+ kotlin("android")
+}
+
+val keystorePropertiesFile = rootProject.file("keystore.properties")
+
+fun isSnapshot(): Boolean {
+ return System.getenv("GITHUB_WORKFLOW") != null && System.getenv("SNAPSHOT") != null
+}
+
+android {
+ if (isSnapshot()) {
+ applicationVariants.all {
+ outputs.all {
+ (this as BaseVariantOutputImpl).outputFileName = "aps-${flavorName}_$versionName.apk"
+ }
+ }
+ }
+
+ buildFeatures.viewBinding = true
+
+ defaultConfig {
+ applicationId = "dev.msfjarvis.aps"
+ versionCode = 11021
+ versionName = "1.11.0-SNAPSHOT"
+ }
+
+ lintOptions {
+ isAbortOnError = true
+ isCheckReleaseBuilds = false
+ disable("MissingTranslation", "PluralsCandidate")
+ }
+
+ packagingOptions {
+ exclude("**/*.version")
+ exclude("**/*.txt")
+ exclude("**/*.kotlin_module")
+ }
+
+ buildTypes {
+ named("release") {
+ isMinifyEnabled = true
+ setProguardFiles(listOf("proguard-android-optimize.txt", "proguard-rules.pro"))
+ buildConfigField("boolean", "ENABLE_DEBUG_FEATURES", if (isSnapshot()) "true" else "false")
+ }
+ named("debug") {
+ applicationIdSuffix = ".debug"
+ versionNameSuffix = "-debug"
+ isMinifyEnabled = false
+ buildConfigField("boolean", "ENABLE_DEBUG_FEATURES", "true")
+ }
+ }
+
+ if (keystorePropertiesFile.exists()) {
+ val keystoreProperties = Properties()
+ keystoreProperties.load(keystorePropertiesFile.inputStream())
+ signingConfigs {
+ register("release") {
+ keyAlias = keystoreProperties["keyAlias"] as String
+ keyPassword = keystoreProperties["keyPassword"] as String
+ storeFile = rootProject.file(keystoreProperties["storeFile"] as String)
+ storePassword = keystoreProperties["storePassword"] as String
+ }
+ }
+ listOf("release", "debug").map {
+ buildTypes.getByName(it).signingConfig = signingConfigs.getByName(it)
+ }
+ }
+
+ flavorDimensions("free")
+ productFlavors {
+ create("free") {
+ versionNameSuffix = "-free"
+ }
+ create("nonFree") {
+ }
+ }
+}
+
+dependencies {
+ compileOnly(Dependencies.AndroidX.annotation)
+ implementation(Dependencies.AndroidX.activity_ktx)
+ implementation(Dependencies.AndroidX.autofill)
+ implementation(Dependencies.AndroidX.appcompat)
+ implementation(Dependencies.AndroidX.biometric)
+ implementation(Dependencies.AndroidX.constraint_layout)
+ implementation(Dependencies.AndroidX.core_ktx)
+ implementation(Dependencies.AndroidX.documentfile)
+ implementation(Dependencies.AndroidX.fragment_ktx)
+ implementation(Dependencies.AndroidX.lifecycle_common)
+ implementation(Dependencies.AndroidX.lifecycle_livedata_ktx)
+ implementation(Dependencies.AndroidX.lifecycle_viewmodel_ktx)
+ implementation(Dependencies.AndroidX.material)
+ implementation(Dependencies.AndroidX.preference)
+ implementation(Dependencies.AndroidX.recycler_view)
+ implementation(Dependencies.AndroidX.recycler_view_selection)
+ implementation(Dependencies.AndroidX.security)
+ implementation(Dependencies.AndroidX.swiperefreshlayout)
+
+ implementation(Dependencies.Kotlin.Coroutines.android)
+ implementation(Dependencies.Kotlin.Coroutines.core)
+
+ implementation(Dependencies.FirstParty.openpgp_ktx)
+ implementation(Dependencies.FirstParty.zxing_android_embedded)
+
+ implementation(Dependencies.ThirdParty.commons_codec)
+ implementation(Dependencies.ThirdParty.fastscroll)
+ implementation(Dependencies.ThirdParty.jgit) {
+ exclude(group = "org.apache.httpcomponents", module = "httpclient")
+ }
+ implementation(Dependencies.ThirdParty.jsch)
+ implementation(Dependencies.ThirdParty.sshj)
+ implementation(Dependencies.ThirdParty.bouncycastle)
+ implementation(Dependencies.ThirdParty.plumber)
+ implementation(Dependencies.ThirdParty.ssh_auth)
+ implementation(Dependencies.ThirdParty.timber)
+ implementation(Dependencies.ThirdParty.timberkt)
+
+ if (isSnapshot()) {
+ implementation(Dependencies.ThirdParty.leakcanary)
+ implementation(Dependencies.ThirdParty.whatthestack)
+ } else {
+ debugImplementation(Dependencies.ThirdParty.leakcanary)
+ debugImplementation(Dependencies.ThirdParty.whatthestack)
+ }
+
+ "nonFreeImplementation"(Dependencies.NonFree.google_play_auth_api_phone)
+
+ // Testing-only dependencies
+ androidTestImplementation(Dependencies.Testing.junit)
+ androidTestImplementation(Dependencies.Testing.kotlin_test_junit)
+ androidTestImplementation(Dependencies.Testing.AndroidX.runner)
+ androidTestImplementation(Dependencies.Testing.AndroidX.rules)
+ androidTestImplementation(Dependencies.Testing.AndroidX.junit)
+ androidTestImplementation(Dependencies.Testing.AndroidX.espresso_core)
+ androidTestImplementation(Dependencies.Testing.AndroidX.espresso_intents)
+
+ testImplementation(Dependencies.Testing.junit)
+ testImplementation(Dependencies.Testing.kotlin_test_junit)
+}
diff --git a/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.kt b/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.kt
index fc32b8da..1cd7c1ea 100644
--- a/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.kt
@@ -21,6 +21,7 @@ import androidx.fragment.app.activityViewModels
import androidx.fragment.app.setFragmentResultListener
import androidx.lifecycle.observe
import androidx.preference.PreferenceManager
+import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.snackbar.Snackbar
import com.zeapo.pwdstore.databinding.PasswordRecyclerViewBinding
@@ -125,6 +126,7 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) {
}
val recyclerView = binding.passRecycler
recyclerView.apply {
+ addItemDecoration(DividerItemDecoration(requireContext(), LinearLayoutManager.VERTICAL))
layoutManager = LinearLayoutManager(requireContext())
itemAnimator = OnOffItemAnimator()
adapter = recyclerAdapter
diff --git a/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt b/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt
index e2cde88e..8938df00 100644
--- a/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt
@@ -95,8 +95,11 @@ class UserPreference : AppCompatActivity() {
if (!PasswordRepository.isGitRepo()) {
listOfNotNull(
- gitServerPreference, gitConfigPreference, sshKeyPreference,
- viewSshKeyPreference, clearSavedPassPreference
+ gitServerPreference,
+ gitConfigPreference,
+ sshKeyPreference,
+ viewSshKeyPreference,
+ clearSavedPassPreference,
).forEach {
it.parent?.removePreference(it)
}
@@ -119,12 +122,12 @@ class UserPreference : AppCompatActivity() {
autoFillAppsPreference,
autoFillDefaultPreference,
autoFillAlwaysShowDialogPreference,
- autoFillShowFullNamePreference
+ autoFillShowFullNamePreference,
)
oreoAutofillDependencies = listOfNotNull(
oreoAutofillDirectoryStructurePreference,
oreoAutofillDefaultUsername,
- oreoAutofillCustomPublixSuffixes
+ oreoAutofillCustomPublixSuffixes,
)
oreoAutofillCustomPublixSuffixes?.apply {
setOnBindEditTextListener {
diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillStrategyDsl.kt b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillStrategyDsl.kt
index ec333bec..cae84d54 100644
--- a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillStrategyDsl.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/AutofillStrategyDsl.kt
@@ -232,7 +232,8 @@ class AutofillRule private constructor(
fun genericPassword(optional: Boolean = false, block: FieldMatcher.Builder.() -> Unit) {
require(matchers.none {
it.type in listOf(
- FillableFieldType.CurrentPassword, FillableFieldType.NewPassword
+ FillableFieldType.CurrentPassword,
+ FillableFieldType.NewPassword,
)
}) { "Every rule block can only have either genericPassword or {current,new}Password blocks" }
matchers.add(
diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/FeatureAndTrustDetection.kt b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/FeatureAndTrustDetection.kt
index 8864f877..5c8b6b3b 100644
--- a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/FeatureAndTrustDetection.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/FeatureAndTrustDetection.kt
@@ -74,7 +74,7 @@ private val TRUSTED_BROWSER_CERTIFICATE_HASH = mapOf(
"org.mozilla.firefox_beta" to "p4tipRZbRJSy/q2edqKA0i2Tf+5iUa7OWZRGsuoxmwQ=",
"org.mozilla.focus" to "YgOkc7421k7jf4f6UA7bx56rkwYQq5ufpMp9XB8bT/w=",
"org.mozilla.klar" to "YgOkc7421k7jf4f6UA7bx56rkwYQq5ufpMp9XB8bT/w=",
- "org.torproject.torbrowser" to "IAYfBF5zfGc3XBd5TP7bQ2oDzsa6y3y5+WZCIFyizsg="
+ "org.torproject.torbrowser" to "IAYfBF5zfGc3XBd5TP7bQ2oDzsa6y3y5+WZCIFyizsg=",
)
private fun isTrustedBrowser(context: Context, appPackage: String): Boolean {
@@ -112,7 +112,7 @@ private val BROWSER_MULTI_ORIGIN_METHOD = mapOf(
"org.mozilla.firefox_beta" to BrowserMultiOriginMethod.WebView,
"org.mozilla.focus" to BrowserMultiOriginMethod.Field,
"org.mozilla.klar" to BrowserMultiOriginMethod.Field,
- "org.torproject.torbrowser" to BrowserMultiOriginMethod.WebView
+ "org.torproject.torbrowser" to BrowserMultiOriginMethod.WebView,
)
private fun getBrowserMultiOriginMethod(appPackage: String): BrowserMultiOriginMethod =
@@ -135,7 +135,7 @@ private val BROWSER_SAVE_FLAG = mapOf(
"org.mozilla.fennec_aurora" to 0,
"com.opera.mini.native" to 0,
"com.opera.mini.native.beta" to 0,
- "com.opera.touch" to 0
+ "com.opera.touch" to 0,
)
@RequiresApi(Build.VERSION_CODES.O)
@@ -162,7 +162,7 @@ private val FLAKY_BROWSERS = listOf(
"com.android.chrome",
"com.chrome.beta",
"com.chrome.canary",
- "com.chrome.dev"
+ "com.chrome.dev",
)
enum class BrowserAutofillSupportLevel {
@@ -170,7 +170,7 @@ enum class BrowserAutofillSupportLevel {
FlakyFill,
PasswordFill,
GeneralFill,
- GeneralFillAndSave
+ GeneralFillAndSave,
}
@RequiresApi(Build.VERSION_CODES.O)
diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/FormField.kt b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/FormField.kt
index 2b18bbb6..2bfa5075 100644
--- a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/FormField.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/FormField.kt
@@ -33,19 +33,19 @@ class FormField(
private val HINTS_USERNAME = listOf(
HintConstants.AUTOFILL_HINT_USERNAME,
- HintConstants.AUTOFILL_HINT_NEW_USERNAME
+ HintConstants.AUTOFILL_HINT_NEW_USERNAME,
)
private val HINTS_NEW_PASSWORD = listOf(
- HintConstants.AUTOFILL_HINT_NEW_PASSWORD
+ HintConstants.AUTOFILL_HINT_NEW_PASSWORD,
)
private val HINTS_PASSWORD = HINTS_NEW_PASSWORD + listOf(
- HintConstants.AUTOFILL_HINT_PASSWORD
+ HintConstants.AUTOFILL_HINT_PASSWORD,
)
private val HINTS_OTP = listOf(
- HintConstants.AUTOFILL_HINT_SMS_OTP
+ HintConstants.AUTOFILL_HINT_SMS_OTP,
)
@Suppress("DEPRECATION")
@@ -54,7 +54,7 @@ class FormField(
HintConstants.AUTOFILL_HINT_NAME,
HintConstants.AUTOFILL_HINT_PERSON_NAME,
HintConstants.AUTOFILL_HINT_PHONE,
- HintConstants.AUTOFILL_HINT_PHONE_NUMBER
+ HintConstants.AUTOFILL_HINT_PHONE_NUMBER,
)
private val ANDROID_TEXT_FIELD_CLASS_NAMES = listOf(
@@ -62,7 +62,7 @@ class FormField(
"android.widget.AutoCompleteTextView",
"androidx.appcompat.widget.AppCompatEditText",
"android.support.v7.widget.AppCompatEditText",
- "com.google.android.material.textfield.TextInputEditText"
+ "com.google.android.material.textfield.TextInputEditText",
)
private const val ANDROID_WEB_VIEW_CLASS_NAME = "android.webkit.WebView"
@@ -75,15 +75,24 @@ class FormField(
InputType.TYPE_CLASS_TEXT -> typeVariation in listOf(
InputType.TYPE_TEXT_VARIATION_PASSWORD,
InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD,
- InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD
+ InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD,
)
else -> false
}
}
- private val HTML_INPUT_FIELD_TYPES_USERNAME = listOf("email", "tel", "text")
- private val HTML_INPUT_FIELD_TYPES_PASSWORD = listOf("password")
- private val HTML_INPUT_FIELD_TYPES_OTP = listOf("tel", "text")
+ private val HTML_INPUT_FIELD_TYPES_USERNAME = listOf(
+ "email",
+ "tel",
+ "text",
+ )
+ private val HTML_INPUT_FIELD_TYPES_PASSWORD = listOf(
+ "password",
+ )
+ private val HTML_INPUT_FIELD_TYPES_OTP = listOf(
+ "tel",
+ "text",
+ )
private val HTML_INPUT_FIELD_TYPES_FILLABLE =
(HTML_INPUT_FIELD_TYPES_USERNAME + HTML_INPUT_FIELD_TYPES_PASSWORD + HTML_INPUT_FIELD_TYPES_OTP).toSet().toList()
@@ -95,20 +104,29 @@ class FormField(
"url_field", // Opera address bar
"location_bar_edit_text", // Samsung address bar
"search", "find", "captcha",
- "postal" // Prevent postal code fields from being mistaken for OTP fields
+ "postal", // Prevent postal code fields from being mistaken for OTP fields
)
private val PASSWORD_HEURISTIC_TERMS = listOf(
- "pass", "pswd", "pwd"
+ "pass",
+ "pswd",
+ "pwd",
)
private val USERNAME_HEURISTIC_TERMS = listOf(
- "alias", "e-mail", "email", "login", "user"
+ "alias",
+ "e-mail",
+ "email",
+ "login",
+ "user",
)
private val OTP_HEURISTIC_TERMS = listOf(
- "einmal", "otp"
+ "einmal",
+ "otp",
+ "challenge",
+ "verification",
)
private val OTP_WEAK_HEURISTIC_TERMS = listOf(
- "code"
+ "code",
)
}
@@ -214,7 +232,8 @@ class FormField(
// TODO: Revisit this decision in the future
private val excludedByHints = excludedByAutofillHints
- val relevantField = isTextField && hasAutofillTypeText && !excludedByHints
+ // Only offer to fill into custom views if they explicitly opted into Autofill.
+ val relevantField = hasAutofillTypeText && (isTextField || autofillHints.isNotEmpty()) && !excludedByHints
// Exclude fields based on hint, resource ID or HTML name.
// Note: We still report excluded fields as relevant since they count for adjacency heuristics,
@@ -232,7 +251,7 @@ class FormField(
if (isCertainPasswordField) CertaintyLevel.Certain else if (isLikelyPasswordField) CertaintyLevel.Likely else if (isPossiblePasswordField) CertaintyLevel.Possible else CertaintyLevel.Impossible
// OTP field heuristics (based only on the current field)
- private val isPossibleOtpField = notExcluded && !isPossiblePasswordField && isTextField
+ private val isPossibleOtpField = notExcluded && !isPossiblePasswordField
private val isCertainOtpField = isPossibleOtpField && hasHintOtp
private val isLikelyOtpField = isPossibleOtpField && (
isCertainOtpField || OTP_HEURISTIC_TERMS.anyMatchesFieldInfo ||
@@ -241,7 +260,7 @@ class FormField(
if (isCertainOtpField) CertaintyLevel.Certain else if (isLikelyOtpField) CertaintyLevel.Likely else if (isPossibleOtpField) CertaintyLevel.Possible else CertaintyLevel.Impossible
// Username field heuristics (based only on the current field)
- private val isPossibleUsernameField = notExcluded && !isPossiblePasswordField && !isCertainOtpField && isTextField
+ private val isPossibleUsernameField = notExcluded && !isPossiblePasswordField && !isCertainOtpField
private val isCertainUsernameField = isPossibleUsernameField && hasHintUsername
private val isLikelyUsernameField = isPossibleUsernameField && (isCertainUsernameField || (USERNAME_HEURISTIC_TERMS.anyMatchesFieldInfo))
val usernameCertainty =
diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/OreoAutofillService.kt b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/OreoAutofillService.kt
index b6404c6e..fd2997d8 100644
--- a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/OreoAutofillService.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/OreoAutofillService.kt
@@ -33,7 +33,7 @@ class OreoAutofillService : AutofillService() {
"com.android.settings.intelligence",
"com.android.systemui",
"com.oneplus.applocker",
- "org.sufficientlysecure.keychain"
+ "org.sufficientlysecure.keychain",
)
private const val DISABLE_AUTOFILL_DURATION_MS = 1000 * 60 * 60 * 24L
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 615b695e..a05da554 100644
--- a/app/src/main/java/com/zeapo/pwdstore/crypto/PasswordCreationActivity.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/crypto/PasswordCreationActivity.kt
@@ -11,7 +11,6 @@ import android.text.InputType
import android.view.Menu
import android.view.MenuItem
import android.view.View
-import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.IntentSenderRequest
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
import androidx.activity.result.contract.ActivityResultContracts.StartIntentSenderForResult
@@ -59,7 +58,7 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
private var oldCategory: String? = null
private var copy: Boolean = false
- private val userInteractionRequiredResult: ActivityResultLauncher<IntentSenderRequest> = registerForActivityResult(StartIntentSenderForResult()) { result ->
+ private val userInteractionRequiredResult = registerForActivityResult(StartIntentSenderForResult()) { result ->
if (result.data == null) {
setResult(RESULT_CANCELED, null)
finish()
@@ -315,7 +314,11 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
.filter { it.isNotBlank() }
.map { line ->
parseGpgIdentifier(line) ?: run {
- snackbar(message = resources.getString(R.string.invalid_gpg_id))
+ if (line.removePrefix("0x").matches("[a-fA-F0-9]{8}".toRegex())) {
+ snackbar(message = resources.getString(R.string.short_key_ids_unsupported))
+ } else {
+ snackbar(message = resources.getString(R.string.invalid_gpg_id))
+ }
return@with
}
}
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 a8f4c5b3..7a818bcf 100644
--- a/app/src/main/java/com/zeapo/pwdstore/git/BaseGitActivity.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/git/BaseGitActivity.kt
@@ -41,6 +41,7 @@ abstract class BaseGitActivity : AppCompatActivity() {
lateinit var serverPath: String
lateinit var username: String
lateinit var email: String
+ lateinit var branch: String
private var identityBuilder: SshApiSessionFactory.IdentityBuilder? = null
private var identity: SshApiSessionFactory.ApiIdentity? = null
lateinit var settings: SharedPreferences
@@ -61,6 +62,7 @@ abstract class BaseGitActivity : AppCompatActivity() {
serverPath = settings.getString(PreferenceKeys.GIT_REMOTE_LOCATION, null) ?: ""
username = settings.getString(PreferenceKeys.GIT_CONFIG_USER_NAME, null) ?: ""
email = settings.getString(PreferenceKeys.GIT_CONFIG_USER_EMAIL, null) ?: ""
+ branch = settings.getString(PreferenceKeys.GIT_BRANCH_NAME, null) ?: "master"
updateUrl()
}
@@ -248,10 +250,9 @@ abstract class BaseGitActivity : AppCompatActivity() {
const val REQUEST_PULL = 101
const val REQUEST_PUSH = 102
const val REQUEST_CLONE = 103
- const val REQUEST_INIT = 104
- const val REQUEST_SYNC = 105
- const val BREAK_OUT_OF_DETACHED = 106
- const val REQUEST_RESET = 107
+ const val REQUEST_SYNC = 104
+ const val BREAK_OUT_OF_DETACHED = 105
+ const val REQUEST_RESET = 106
const val TAG = "AbstractGitActivity"
}
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/BreakOutOfDetached.kt b/app/src/main/java/com/zeapo/pwdstore/git/BreakOutOfDetached.kt
index 664497bd..149cabd8 100644
--- a/app/src/main/java/com/zeapo/pwdstore/git/BreakOutOfDetached.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/git/BreakOutOfDetached.kt
@@ -5,8 +5,10 @@
package com.zeapo.pwdstore.git
import androidx.appcompat.app.AppCompatActivity
+import androidx.preference.PreferenceManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.zeapo.pwdstore.R
+import com.zeapo.pwdstore.utils.PreferenceKeys
import java.io.File
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.api.GitCommand
@@ -16,6 +18,9 @@ import org.eclipse.jgit.api.RebaseCommand
class BreakOutOfDetached(fileDir: File, callingActivity: AppCompatActivity) : GitOperation(fileDir, callingActivity) {
private lateinit var commands: List<GitCommand<out Any>>
+ private val gitBranch = PreferenceManager
+ .getDefaultSharedPreferences(callingActivity.applicationContext)
+ .getString(PreferenceKeys.GIT_BRANCH_NAME, "master")
/**
* Sets the command
@@ -24,7 +29,7 @@ class BreakOutOfDetached(fileDir: File, callingActivity: AppCompatActivity) : Gi
*/
fun setCommands(): BreakOutOfDetached {
val git = Git(repository)
- val branchName = "conflicting-master-${System.currentTimeMillis()}"
+ val branchName = "conflicting-$gitBranch-${System.currentTimeMillis()}"
this.commands = listOf(
// abort the rebase
@@ -33,8 +38,8 @@ class BreakOutOfDetached(fileDir: File, callingActivity: AppCompatActivity) : Gi
git.checkout().setCreateBranch(true).setName(branchName),
// push the changes
git.push().setRemote("origin"),
- // switch back to master
- git.checkout().setName("master")
+ // switch back to ${gitBranch}
+ git.checkout().setName(gitBranch)
)
return this
}
@@ -76,7 +81,7 @@ class BreakOutOfDetached(fileDir: File, callingActivity: AppCompatActivity) : Gi
MaterialAlertDialogBuilder(callingActivity)
.setTitle(callingActivity.resources.getString(R.string.git_abort_and_push_title))
.setMessage("There was a conflict when trying to rebase. " +
- "Your local master branch was pushed to another branch named conflicting-master-....\n" +
+ "Your local $gitBranch branch was pushed to another branch named conflicting-$gitBranch-....\n" +
"Use this branch to resolve conflict on your computer")
.setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ ->
callingActivity.finish()
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/GitConfigActivity.kt b/app/src/main/java/com/zeapo/pwdstore/git/GitConfigActivity.kt
index 35cbc68a..0498f6ed 100644
--- a/app/src/main/java/com/zeapo/pwdstore/git/GitConfigActivity.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/git/GitConfigActivity.kt
@@ -36,7 +36,7 @@ class GitConfigActivity : BaseGitActivity() {
if (repo != null) {
try {
val objectId = repo.resolve(Constants.HEAD)
- val ref = repo.getRef("refs/heads/master")
+ val ref = repo.getRef("refs/heads/$branch")
val head = if (ref.objectId.equals(objectId)) ref.name else "DETACHED"
binding.gitCommitHash.text = String.format("%s (%s)", objectId.abbreviate(8).name(), head)
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/GitOperation.kt b/app/src/main/java/com/zeapo/pwdstore/git/GitOperation.kt
index 9d2c629f..90f72b7c 100644
--- a/app/src/main/java/com/zeapo/pwdstore/git/GitOperation.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/git/GitOperation.kt
@@ -9,12 +9,12 @@ import android.content.Intent
import android.view.LayoutInflater
import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity
-import androidx.core.content.ContextCompat
import androidx.core.content.edit
import androidx.preference.PreferenceManager
import com.google.android.material.checkbox.MaterialCheckBox
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.textfield.TextInputEditText
+import com.google.android.material.textfield.TextInputLayout
import com.zeapo.pwdstore.R
import com.zeapo.pwdstore.UserPreference
import com.zeapo.pwdstore.git.config.ConnectionMode
@@ -37,7 +37,6 @@ import org.eclipse.jgit.transport.CredentialItem
import org.eclipse.jgit.transport.CredentialsProvider
import org.eclipse.jgit.transport.SshSessionFactory
import org.eclipse.jgit.transport.URIish
-import com.google.android.material.R as materialR
private class GitOperationCredentialFinder(
@@ -78,13 +77,13 @@ private class GitOperationCredentialFinder(
@SuppressLint("InflateParams")
val dialogView = layoutInflater.inflate(R.layout.git_credential_layout, null)
+ val credentialLayout = dialogView.findViewById<TextInputLayout>(R.id.git_auth_passphrase_layout)
val editCredential = dialogView.findViewById<TextInputEditText>(R.id.git_auth_credential)
editCredential.setHint(hintRes)
val rememberCredential = dialogView.findViewById<MaterialCheckBox>(R.id.git_auth_remember_credential)
rememberCredential.setText(rememberRes)
if (isRetry)
- editCredential.setError(callingActivity.resources.getString(errorRes),
- ContextCompat.getDrawable(callingActivity, materialR.drawable.mtrl_ic_error))
+ credentialLayout.error = callingActivity.resources.getString(errorRes)
MaterialAlertDialogBuilder(callingActivity).run {
setTitle(R.string.passphrase_dialog_title)
setMessage(messageRes)
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/GitServerConfigActivity.kt b/app/src/main/java/com/zeapo/pwdstore/git/GitServerConfigActivity.kt
index 10f44960..6c87e0f6 100644
--- a/app/src/main/java/com/zeapo/pwdstore/git/GitServerConfigActivity.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/git/GitServerConfigActivity.kt
@@ -102,6 +102,13 @@ class GitServerConfigActivity : BaseGitActivity() {
}
}
+ binding.serverBranch.apply {
+ setText(branch)
+ doOnTextChanged { text, _, _, _ ->
+ branch = text.toString().trim()
+ }
+ }
+
binding.saveButton.setOnClickListener {
if (isClone && PasswordRepository.getRepository(null) == null)
PasswordRepository.initialize(this)
@@ -114,12 +121,14 @@ class GitServerConfigActivity : BaseGitActivity() {
putString(PreferenceKeys.GIT_REMOTE_PORT, serverPort)
putString(PreferenceKeys.GIT_REMOTE_USERNAME, serverUser)
putString(PreferenceKeys.GIT_REMOTE_LOCATION, serverPath)
+ putString(PreferenceKeys.GIT_BRANCH_NAME, branch)
}
if (!isClone) {
Snackbar.make(binding.root, getString(R.string.git_server_config_save_success), Snackbar.LENGTH_SHORT).show()
Handler().postDelayed(500) { finish() }
- } else
+ } else {
cloneRepository()
+ }
}
else -> Snackbar.make(binding.root, getString(R.string.git_server_config_save_error_prefix, getString(result.textRes)), Snackbar.LENGTH_LONG).show()
}
@@ -157,7 +166,7 @@ class GitServerConfigActivity : BaseGitActivity() {
!(localDirFiles.size == 1 && localDirFiles[0].name == ".git")) {
MaterialAlertDialogBuilder(this)
.setTitle(R.string.dialog_delete_title)
- .setMessage(resources.getString(R.string.dialog_delete_msg) + " " + localDir.toString())
+ .setMessage(resources.getString(R.string.dialog_delete_msg, localDir.toString()))
.setCancelable(false)
.setPositiveButton(R.string.dialog_delete) { dialog, _ ->
try {
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/ResetToRemoteOperation.kt b/app/src/main/java/com/zeapo/pwdstore/git/ResetToRemoteOperation.kt
index c570bf27..60a9fbf3 100644
--- a/app/src/main/java/com/zeapo/pwdstore/git/ResetToRemoteOperation.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/git/ResetToRemoteOperation.kt
@@ -6,13 +6,15 @@ package com.zeapo.pwdstore.git
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
+import androidx.preference.PreferenceManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.zeapo.pwdstore.R
+import com.zeapo.pwdstore.utils.PreferenceKeys
import java.io.File
-import org.eclipse.jgit.api.AddCommand
-import org.eclipse.jgit.api.FetchCommand
import org.eclipse.jgit.api.Git
+import org.eclipse.jgit.api.GitCommand
import org.eclipse.jgit.api.ResetCommand
+import org.eclipse.jgit.api.TransportCommand
/**
* Creates a new git operation
@@ -22,9 +24,7 @@ import org.eclipse.jgit.api.ResetCommand
*/
class ResetToRemoteOperation(fileDir: File, callingActivity: AppCompatActivity) : GitOperation(fileDir, callingActivity) {
- private var addCommand: AddCommand? = null
- private var fetchCommand: FetchCommand? = null
- private var resetCommand: ResetCommand? = null
+ private lateinit var commands: List<GitCommand<out Any>>
/**
* Sets the command
@@ -32,17 +32,27 @@ class ResetToRemoteOperation(fileDir: File, callingActivity: AppCompatActivity)
* @return the current object
*/
fun setCommands(): ResetToRemoteOperation {
+ val remoteBranch = PreferenceManager
+ .getDefaultSharedPreferences(callingActivity.applicationContext)
+ .getString(PreferenceKeys.GIT_BRANCH_NAME, "master")
val git = Git(repository)
- this.addCommand = git.add().addFilepattern(".")
- this.fetchCommand = git.fetch().setRemote("origin")
- this.resetCommand = git.reset().setRef("origin/master").setMode(ResetCommand.ResetType.HARD)
+ val cmds = arrayListOf(
+ git.add().addFilepattern("."),
+ git.fetch().setRemote("origin"),
+ git.reset().setRef("origin/$remoteBranch").setMode(ResetCommand.ResetType.HARD)
+ )
+ if (git.branchList().call().none { it.name == remoteBranch }) {
+ cmds.add(
+ git.branchCreate().setName(remoteBranch).setForce(true)
+ )
+ }
+ commands = cmds
return this
}
override fun execute() {
- this.fetchCommand?.setCredentialsProvider(this.provider)
- GitAsyncTask(callingActivity, this, Intent())
- .execute(this.addCommand, this.fetchCommand, this.resetCommand)
+ commands.filterIsInstance<TransportCommand<*, *>>().map { it.setCredentialsProvider(provider) }
+ GitAsyncTask(callingActivity, this, Intent()).execute(*commands.toTypedArray())
}
override fun onError(err: Exception) {
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/config/SshjConfig.kt b/app/src/main/java/com/zeapo/pwdstore/git/config/SshjConfig.kt
index 7ba246be..1ea0359c 100644
--- a/app/src/main/java/com/zeapo/pwdstore/git/config/SshjConfig.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/git/config/SshjConfig.kt
@@ -217,7 +217,7 @@ class SshjConfig : ConfigImpl() {
ECDHNistP.Factory521(),
ECDHNistP.Factory384(),
ECDHNistP.Factory256(),
- DHGexSHA256.Factory()
+ DHGexSHA256.Factory(),
)
}
@@ -228,7 +228,7 @@ class SshjConfig : ConfigImpl() {
SignatureECDSA.Factory384(),
SignatureECDSA.Factory521(),
SignatureRSA.Factory(),
- FactoryCERT()
+ FactoryCERT(),
)
}
@@ -242,7 +242,7 @@ class SshjConfig : ConfigImpl() {
PKCS8KeyFile.Factory(),
PKCS5KeyFile.Factory(),
OpenSSHKeyFile.Factory(),
- PuTTYKeyFile.Factory()
+ PuTTYKeyFile.Factory(),
)
}
@@ -251,7 +251,7 @@ class SshjConfig : ConfigImpl() {
cipherFactories = listOf(
BlockCiphers.AES128CTR(),
BlockCiphers.AES192CTR(),
- BlockCiphers.AES256CTR()
+ BlockCiphers.AES256CTR(),
)
}
@@ -260,13 +260,13 @@ class SshjConfig : ConfigImpl() {
Macs.HMACSHA2256(),
Macs.HMACSHA2256Etm(),
Macs.HMACSHA2512(),
- Macs.HMACSHA2512Etm()
+ Macs.HMACSHA2512Etm(),
)
}
private fun initCompressionFactories() {
compressionFactories = listOf(
- NoneCompression.Factory()
+ NoneCompression.Factory(),
)
}
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/pwgen/RandomPasswordGenerator.kt b/app/src/main/java/com/zeapo/pwdstore/pwgen/RandomPasswordGenerator.kt
index e841ed76..67d8fc40 100644
--- a/app/src/main/java/com/zeapo/pwdstore/pwgen/RandomPasswordGenerator.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/pwgen/RandomPasswordGenerator.kt
@@ -22,14 +22,13 @@ object RandomPasswordGenerator {
* set, the password will not contain any symbols.
* - [PasswordGenerator.NO_AMBIGUOUS]: If set, the password will not contain any ambiguous
* characters.
- * - [PasswordGenerator.NO_VOWELS]: If set, the password will not contain any vowels.
*/
fun generate(targetLength: Int, pwFlags: Int): String? {
val bank = listOfNotNull(
PasswordGenerator.DIGITS_STR.takeIf { pwFlags hasFlag PasswordGenerator.DIGITS },
PasswordGenerator.UPPERS_STR.takeIf { pwFlags hasFlag PasswordGenerator.UPPERS },
PasswordGenerator.LOWERS_STR.takeIf { pwFlags hasFlag PasswordGenerator.LOWERS },
- PasswordGenerator.SYMBOLS_STR.takeIf { pwFlags hasFlag PasswordGenerator.SYMBOLS }
+ PasswordGenerator.SYMBOLS_STR.takeIf { pwFlags hasFlag PasswordGenerator.SYMBOLS },
).joinToString("")
var password = ""
diff --git a/app/src/main/java/com/zeapo/pwdstore/ui/adapters/PasswordItemRecyclerAdapter.kt b/app/src/main/java/com/zeapo/pwdstore/ui/adapters/PasswordItemRecyclerAdapter.kt
index 15e13745..4e153b88 100644
--- a/app/src/main/java/com/zeapo/pwdstore/ui/adapters/PasswordItemRecyclerAdapter.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/ui/adapters/PasswordItemRecyclerAdapter.kt
@@ -52,7 +52,15 @@ open class PasswordItemRecyclerAdapter :
val settings =
PreferenceManager.getDefaultSharedPreferences(itemView.context.applicationContext)
val showHidden = settings.getBoolean(PreferenceKeys.SHOW_HIDDEN_FOLDERS, false)
- name.text = item.toString()
+ val parentPath = item.fullPathToParent.replace("(^/)|(/$)".toRegex(), "")
+ val source = if (parentPath.isNotEmpty()) {
+ "$parentPath\n$item"
+ } else {
+ "$item"
+ }
+ val spannable = SpannableString(source)
+ spannable.setSpan(RelativeSizeSpan(0.7f), 0, parentPath.length, 0)
+ name.text = spannable
if (item.type == PasswordItem.TYPE_CATEGORY) {
folderIndicator.visibility = View.VISIBLE
val children = item.file.listFiles { pathname ->
@@ -62,15 +70,6 @@ open class PasswordItemRecyclerAdapter :
childCount.visibility = if (count > 0) View.VISIBLE else View.GONE
childCount.text = "$count"
} else {
- val parentPath = item.fullPathToParent.replace("(^/)|(/$)".toRegex(), "")
- val source = if (parentPath.isNotEmpty()) {
- "$parentPath\n$item"
- } else {
- "$item"
- }
- val spannable = SpannableString(source)
- spannable.setSpan(RelativeSizeSpan(0.7f), 0, parentPath.length, 0)
- name.text = spannable
childCount.visibility = View.GONE
folderIndicator.visibility = View.GONE
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/ui/dialogs/FolderCreationDialogFragment.kt b/app/src/main/java/com/zeapo/pwdstore/ui/dialogs/FolderCreationDialogFragment.kt
index 5776187b..25a935bb 100644
--- a/app/src/main/java/com/zeapo/pwdstore/ui/dialogs/FolderCreationDialogFragment.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/ui/dialogs/FolderCreationDialogFragment.kt
@@ -37,7 +37,7 @@ class FolderCreationDialogFragment : DialogFragment() {
val materialTextView = dialog.findViewById<TextInputEditText>(R.id.folder_name_text)
val folderName = materialTextView.text.toString()
val newFolder = File("$currentDir/$folderName")
- newFolder.mkdir()
+ newFolder.mkdirs()
(requireActivity() as PasswordStore).refreshPasswordList(newFolder)
dismiss()
}
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 9eb549da..24bf2096 100644
--- a/app/src/main/java/com/zeapo/pwdstore/utils/PreferenceKeys.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/utils/PreferenceKeys.kt
@@ -35,6 +35,7 @@ object PreferenceKeys {
const val GIT_REMOTE_SERVER = "git_remote_server"
const val GIT_REMOTE_USERNAME = "git_remote_username"
const val GIT_SERVER_INFO = "git_server_info"
+ const val GIT_BRANCH_NAME = "git_branch"
const val HTTPS_PASSWORD = "https_password"
const val LENGTH = "length"
const val OREO_AUTOFILL_CUSTOM_PUBLIC_SUFFIXES = "oreo_autofill_custom_public_suffixes"
diff --git a/app/src/main/res/layout/activity_git_clone.xml b/app/src/main/res/layout/activity_git_clone.xml
index 8026fa4a..f9bec00a 100644
--- a/app/src/main/res/layout/activity_git_clone.xml
+++ b/app/src/main/res/layout/activity_git_clone.xml
@@ -20,7 +20,7 @@
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/server_label"
style="@style/TextAppearance.MaterialComponents.Headline5"
- android:layout_width="match_parent"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="@string/server_name"
@@ -32,7 +32,7 @@
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/label_server_protocol"
style="@style/TextAppearance.MaterialComponents.Headline6"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="@string/server_protocol"
@@ -42,7 +42,7 @@
<com.google.android.material.button.MaterialButtonToggleGroup
android:id="@+id/clone_protocol_group"
style="@style/TextAppearance.MaterialComponents.Headline1"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:layout_constraintStart_toStartOf="parent"
@@ -67,10 +67,12 @@
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/server_user_layout"
- android:layout_width="match_parent"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:hint="@string/server_user"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/clone_protocol_group">
<com.google.android.material.textfield.TextInputEditText
@@ -125,10 +127,11 @@
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/label_server_path"
- android:layout_width="match_parent"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:hint="@string/server_path"
+ app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/label_server_url">
@@ -136,11 +139,31 @@
android:id="@+id/server_path"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:imeOptions="actionDone"
+ android:imeOptions="actionNext"
+ android:nextFocusForward="@id/server_branch"
android:inputType="textWebEmailAddress" />
</com.google.android.material.textfield.TextInputLayout>
+ <com.google.android.material.textfield.TextInputLayout
+ android:id="@+id/label_server_branch"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_margin="8dp"
+ android:hint="Branch"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/label_server_path">
+
+ <com.google.android.material.textfield.TextInputEditText
+ android:id="@+id/server_branch"
+ android:imeOptions="actionDone"
+ android:layout_width="match_parent"
+ android:inputType="textNoSuggestions"
+ android:layout_height="wrap_content" />
+
+ </com.google.android.material.textfield.TextInputLayout>
+
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/label_connection_mode"
style="@style/TextAppearance.MaterialComponents.Headline6"
@@ -151,7 +174,7 @@
android:layout_marginBottom="16dp"
android:text="@string/connection_mode"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/label_server_path" />
+ app:layout_constraintTop_toBottomOf="@id/label_server_branch" />
<com.google.android.material.button.MaterialButtonToggleGroup
android:id="@+id/connection_mode_group"
diff --git a/app/src/main/res/layout/git_credential_layout.xml b/app/src/main/res/layout/git_credential_layout.xml
index 757658e6..180b904a 100644
--- a/app/src/main/res/layout/git_credential_layout.xml
+++ b/app/src/main/res/layout/git_credential_layout.xml
@@ -15,6 +15,7 @@
android:layout_height="wrap_content"
app:endIconMode="password_toggle"
app:hintEnabled="true"
+ app:errorEnabled="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a59d5965..9aaebf98 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -368,6 +368,7 @@
<string name="exporting_passwords">Exporting passwords…</string>
<string name="failed_to_find_key_id">Failed to locate .gpg-id, is your store set up correctly?</string>
<string name="invalid_gpg_id">Found .gpg-id, but it contains an invalid key ID, fingerprint or user ID</string>
+ <string name="short_key_ids_unsupported">A key ID in .gpg-id is too short, please use either long key IDs (16 characters) or fingerprints (40 characters)</string>
<string name="invalid_filename_text">File name must not contain \'/\', set directory above</string>
<string name="directory_hint">Directory</string>
</resources>
diff --git a/app/src/main/res/xml/oreo_autofill_service.xml b/app/src/main/res/xml/oreo_autofill_service.xml
index a790da21..8b76c803 100644
--- a/app/src/main/res/xml/oreo_autofill_service.xml
+++ b/app/src/main/res/xml/oreo_autofill_service.xml
@@ -3,7 +3,9 @@
~ SPDX-License-Identifier: GPL-3.0-only
-->
-<autofill-service xmlns:android="http://schemas.android.com/apk/res/android">
+<autofill-service xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:ignore="UnusedAttribute">
<compatibility-package android:name="com.android.chrome" />
<compatibility-package android:name="com.brave.browser" />
<compatibility-package android:name="com.chrome.beta" />
@@ -12,7 +14,13 @@
<compatibility-package android:name="com.microsoft.emmx" />
<compatibility-package android:name="com.opera.mini.native" />
<compatibility-package android:name="com.opera.mini.native.beta" />
- <compatibility-package android:name="org.mozilla.fennec_fdroid" />
- <compatibility-package android:name="org.mozilla.firefox" />
- <compatibility-package android:name="org.mozilla.firefox_beta" />
+ <compatibility-package
+ android:name="org.mozilla.fennec_fdroid"
+ android:maxLongVersionCode="679999" />
+ <compatibility-package
+ android:name="org.mozilla.firefox"
+ android:maxLongVersionCode="679999" />
+ <compatibility-package
+ android:name="org.mozilla.firefox_beta"
+ android:maxLongVersionCode="679999" />
</autofill-service>
diff --git a/build.gradle b/build.gradle
deleted file mode 100644
index 7490782c..00000000
--- a/build.gradle
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
- * SPDX-License-Identifier: GPL-3.0-only
- */
-buildscript {
- apply from: rootProject.file('dependencies.gradle')
- repositories {
- google()
- jcenter()
- }
- dependencies {
- classpath deps.gradle_plugin.android
- classpath deps.gradle_plugin.kotlin
- }
-}
-
-plugins {
- id 'com.github.ben-manes.versions' version '0.28.0'
-}
-
-subprojects {
- apply from: rootProject.file('dependencies.gradle')
- repositories {
- google()
- jcenter()
- maven {
- url 'https://jitpack.io'
- }
- }
- pluginManager.withPlugin('kotlin-android') {
- dependencies {
- implementation deps.kotlin.stdlib8
- }
- }
- if (name == 'app') {
- apply plugin: 'com.android.application'
- } else {
- apply plugin: 'com.android.library'
- }
- android {
- compileSdkVersion versions.compileSdk
- buildToolsVersion = versions.buildTools
- defaultConfig {
- minSdkVersion versions.minSdk
- targetSdkVersion versions.targetSdk
- testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
- }
- compileOptions {
- sourceCompatibility = JavaVersion.VERSION_1_8
- targetCompatibility = JavaVersion.VERSION_1_8
- }
- }
- tasks.withType(JavaCompile) {
- options.compilerArgs << '-Xlint:unchecked'
- options.deprecation = true
- }
- tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile) {
- kotlinOptions {
- jvmTarget = '1.8'
- freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
- }
- }
-}
-
-tasks.wrapper {
- gradleVersion = "6.5.1"
- distributionType = Wrapper.DistributionType.ALL
- distributionSha256Sum = "143a28f54f1ae93ef4f72d862dbc3c438050d81bb45b4601eb7076e998362920"
-}
diff --git a/build.gradle.kts b/build.gradle.kts
new file mode 100644
index 00000000..b4821208
--- /dev/null
+++ b/build.gradle.kts
@@ -0,0 +1,66 @@
+/*
+ * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+import com.android.build.gradle.BaseExtension
+
+buildscript {
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ classpath(Plugins.agp)
+ classpath(Plugins.kotlin)
+ }
+}
+
+plugins {
+ id("com.github.ben-manes.versions") version "0.29.0"
+ id("com.autonomousapps.dependency-analysis") version "0.53.0"
+}
+
+subprojects {
+ repositories {
+ google()
+ jcenter()
+ maven {
+ setUrl("https://jitpack.io")
+ }
+ }
+ if (name == "app") {
+ apply(plugin = "com.android.application")
+ } else {
+ apply(plugin = "com.android.library")
+ }
+ configure<BaseExtension> {
+ compileSdkVersion(29)
+ defaultConfig {
+ minSdkVersion(23)
+ targetSdkVersion(29)
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ }
+ tasks.withType<JavaCompile> {
+ options.compilerArgs.add("-Xlint:unchecked")
+ options.isDeprecation = true
+ }
+ }
+ tasks.withType<KotlinCompile> {
+ kotlinOptions {
+ jvmTarget = "1.8"
+ freeCompilerArgs = listOf("-Xopt-in=kotlin.RequiresOptIn")
+ languageVersion = "1.4"
+ }
+ }
+}
+
+tasks.wrapper {
+ gradleVersion = "6.5.1"
+ distributionType = Wrapper.DistributionType.ALL
+ distributionSha256Sum = "143a28f54f1ae93ef4f72d862dbc3c438050d81bb45b4601eb7076e998362920"
+}
diff --git a/buildSrc/.gitignore b/buildSrc/.gitignore
new file mode 100644
index 00000000..796b96d1
--- /dev/null
+++ b/buildSrc/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts
new file mode 100644
index 00000000..3457e2c2
--- /dev/null
+++ b/buildSrc/build.gradle.kts
@@ -0,0 +1,11 @@
+plugins {
+ `kotlin-dsl`
+}
+
+repositories {
+ jcenter()
+}
+
+kotlinDslPluginOptions {
+ experimentalWarning.set(false)
+}
diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt
new file mode 100644
index 00000000..63d267db
--- /dev/null
+++ b/buildSrc/src/main/java/Dependencies.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+object Plugins {
+
+ const val agp = "com.android.tools.build:gradle:4.0.1"
+ const val kotlin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.0-rc"
+}
+
+object Dependencies {
+ object Kotlin {
+ object Coroutines {
+
+ const val android = "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8-1.4.0-rc"
+ const val core = "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8-1.4.0-rc"
+ }
+ }
+
+ object AndroidX {
+
+ const val activity_ktx = "androidx.activity:activity-ktx:1.2.0-alpha07"
+ const val annotation = "androidx.annotation:annotation:1.2.0-alpha01"
+ const val autofill = "androidx.autofill:autofill:1.1.0-alpha01"
+ const val appcompat = "androidx.appcompat:appcompat:1.3.0-alpha01"
+ const val biometric = "androidx.biometric:biometric:1.1.0-alpha01"
+ const val constraint_layout = "androidx.constraintlayout:constraintlayout:2.0.0-beta8"
+ const val core_ktx = "androidx.core:core-ktx:1.5.0-alpha01"
+ const val documentfile = "androidx.documentfile:documentfile:1.0.1"
+ const val fragment_ktx = "androidx.fragment:fragment-ktx:1.3.0-alpha07"
+ const val lifecycle_common = "androidx.lifecycle:lifecycle-common-java8:2.3.0-alpha06"
+ const val lifecycle_livedata_ktx = "androidx.lifecycle:lifecycle-livedata-ktx:2.3.0-alpha06"
+ const val lifecycle_viewmodel_ktx = "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0-alpha06"
+ const val material = "com.google.android.material:material:1.3.0-alpha01"
+ 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-rc01"
+ const val security = "androidx.security:security-crypto:1.1.0-alpha01"
+ const val swiperefreshlayout = "androidx.swiperefreshlayout:swiperefreshlayout:1.2.0-alpha01"
+ }
+
+ object FirstParty {
+
+ const val openpgp_ktx = "com.github.android-password-store:openpgp-ktx:2.0.0"
+ const val zxing_android_embedded = "com.github.android-password-store:zxing-android-embedded:4.1.0-aps"
+ }
+
+ object ThirdParty {
+
+ const val bouncycastle = "org.bouncycastle:bcprov-jdk15on:1.66"
+ const val commons_codec = "commons-codec:commons-codec:1.14"
+ const val fastscroll = "me.zhanghai.android.fastscroll:library:1.1.4"
+ const val jsch = "com.jcraft:jsch:0.1.55"
+ const val jgit = "org.eclipse.jgit:org.eclipse.jgit:3.7.1.201504261725-r"
+ const val leakcanary = "com.squareup.leakcanary:leakcanary-android:2.4"
+ const val plumber = "com.squareup.leakcanary:plumber-android:2.4"
+ const val sshj = "com.hierynomus:sshj:0.29.0"
+ const val ssh_auth = "org.sufficientlysecure:sshauthentication-api:1.0"
+ const val timber = "com.jakewharton.timber:timber:4.7.1"
+ const val timberkt = "com.github.ajalt:timberkt:1.5.1"
+ const val whatthestack = "com.github.haroldadmin:WhatTheStack:0.0.4"
+ }
+
+ object NonFree {
+
+ const val google_play_auth_api_phone = "com.google.android.gms:play-services-auth-api-phone:17.4.0"
+ }
+
+ object Testing {
+
+ const val junit = "junit:junit:4.13"
+ const val kotlin_test_junit = "org.jetbrains.kotlin:kotlin-test-junit:1.3.72"
+
+ object AndroidX {
+
+ const val runner = "androidx.test:runner:1.3.0-rc01"
+ const val rules = "androidx.test:rules:1.3.0-rc01"
+ const val junit = "androidx.test.ext:junit:1.1.2-rc01"
+ const val espresso_core = "androidx.test.espresso:espresso-core:3.3.0-rc01"
+ const val espresso_intents = "androidx.test.espresso:espresso-intents:3.3.0-rc01"
+ }
+ }
+}
diff --git a/dependencies.gradle b/dependencies.gradle
deleted file mode 100644
index d05e0e6d..00000000
--- a/dependencies.gradle
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
- * SPDX-License-Identifier: GPL-3.0-only
- */
-ext.versions = [
- minSdk: 23,
- targetSdk: 29,
- compileSdk: 29,
- buildTools: '29.0.3'
-]
-
-ext.deps = [
- gradle_plugin: [
- android: 'com.android.tools.build:gradle:4.0.0',
- kotlin: 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.72',
- ],
-
- kotlin: [
- coroutines: [
- android: 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7',
- core: 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7',
- ],
- stdlib8: 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72'
- ],
-
- androidx: [
- activity_ktx: 'androidx.activity:activity-ktx:1.2.0-alpha06',
- annotation: 'androidx.annotation:annotation:1.2.0-alpha01',
- autofill: 'androidx.autofill:autofill:1.0.0',
- appcompat: 'androidx.appcompat:appcompat:1.3.0-alpha01',
- biometric: 'androidx.biometric:biometric:1.1.0-alpha01',
- constraint_layout: 'androidx.constraintlayout:constraintlayout:2.0.0-beta7',
- core_ktx: 'androidx.core:core-ktx:1.5.0-alpha01',
- documentfile: 'androidx.documentfile:documentfile:1.0.1',
- fragment_ktx: 'androidx.fragment:fragment-ktx:1.3.0-alpha06',
- lifecycle_common: 'androidx.lifecycle:lifecycle-common-java8:2.3.0-alpha05',
- lifecycle_livedata_ktx: 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.0-alpha05',
- lifecycle_viewmodel_ktx: 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0-alpha05',
- material: 'com.google.android.material:material:1.3.0-alpha01',
- preference: 'androidx.preference:preference:1.1.1',
- recycler_view: 'androidx.recyclerview:recyclerview:1.2.0-alpha04',
- recycler_view_selection: 'androidx.recyclerview:recyclerview-selection:1.1.0-rc01',
- security: 'androidx.security:security-crypto:1.1.0-alpha01',
- swiperefreshlayout: 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
- ],
-
- first_party: [
- openpgp_ktx: 'com.github.android-password-store:openpgp-ktx:2.0.0',
- zxing_android_embedded: 'com.github.android-password-store:zxing-android-embedded:v4.1.0-aps'
- ],
-
- third_party: [
- bouncycastle: 'org.bouncycastle:bcprov-jdk15on:1.65.01',
- commons_codec: 'commons-codec:commons-codec:1.13',
- fastscroll: 'me.zhanghai.android.fastscroll:library:1.1.4',
- jsch: 'com.jcraft:jsch:0.1.55',
- jgit: 'org.eclipse.jgit:org.eclipse.jgit:3.7.1.201504261725-r',
- leakcanary: 'com.squareup.leakcanary:leakcanary-android:2.4',
- plumber: 'com.squareup.leakcanary:plumber-android:2.4',
- sshj: 'com.hierynomus:sshj:0.29.0',
- ssh_auth: 'org.sufficientlysecure:sshauthentication-api:1.0',
- timber: 'com.jakewharton.timber:timber:4.7.1',
- timberkt: 'com.github.ajalt:timberkt:1.5.1',
- whatthestack: 'com.github.haroldadmin:WhatTheStack:0.0.3',
- ],
-
- non_free: [
- google_play_auth_api_phone: 'com.google.android.gms:play-services-auth-api-phone:17.4.0',
- ],
-
- testing: [
- junit: 'junit:junit:4.13',
- kotlin_test_junit: 'org.jetbrains.kotlin:kotlin-test-junit:1.3.72',
- androidx: [
- runner: 'androidx.test:runner:1.3.0-rc01',
- rules: 'androidx.test:rules:1.3.0-rc01',
- junit: 'androidx.test.ext:junit:1.1.2-rc01',
- espresso_core: 'androidx.test.espresso:espresso-core:3.3.0-rc01',
- espresso_intents: 'androidx.test.espresso:espresso-intents:3.3.0-rc01'
- ]
- ]
-]
diff --git a/gradle.properties b/gradle.properties
index 218affe7..ca214f0f 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -20,3 +20,6 @@ android.useMinimalKeepRules=true
# references to the resources it declares instead of declarations plus all
# transitive dependency references.
android.namespacedRClass=true
+
+# Gradle FS watching
+org.gradle.unsafe.watch-fs=true
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 6fa3f76a..28b21a0c 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,8 +1,3 @@
-#
-# Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
-# SPDX-License-Identifier: GPL-3.0-only
-#
-
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=143a28f54f1ae93ef4f72d862dbc3c438050d81bb45b4601eb7076e998362920
diff --git a/settings.gradle b/settings.gradle.kts
index 47fd3b82..a418994b 100644
--- a/settings.gradle
+++ b/settings.gradle.kts
@@ -2,4 +2,4 @@
* Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
* SPDX-License-Identifier: GPL-3.0-only
*/
-include ':app'
+include(":app")