Skip to content
This repository was archived by the owner on Oct 15, 2024. It is now read-only.

Commit bad8e2b

Browse files
authored
Misc cleanups to build and extension functions (#1108)
1 parent 9d63b11 commit bad8e2b

File tree

11 files changed

+221
-172
lines changed

11 files changed

+221
-172
lines changed

app/build.gradle.kts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,6 @@ dependencies {
141141
androidTestImplementation(Dependencies.Testing.kotlin_test_junit)
142142
androidTestImplementation(Dependencies.Testing.AndroidX.runner)
143143
androidTestImplementation(Dependencies.Testing.AndroidX.rules)
144-
androidTestImplementation(Dependencies.Testing.AndroidX.junit)
145-
androidTestImplementation(Dependencies.Testing.AndroidX.espresso_core)
146-
androidTestImplementation(Dependencies.Testing.AndroidX.espresso_intents)
147144

148145
testImplementation(Dependencies.Testing.junit)
149146
testImplementation(Dependencies.Testing.kotlin_test_junit)

app/src/main/java/com/zeapo/pwdstore/UserPreference.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ import com.zeapo.pwdstore.utils.BiometricAuthenticator
5454
import com.zeapo.pwdstore.utils.PasswordRepository
5555
import com.zeapo.pwdstore.utils.PreferenceKeys
5656
import com.zeapo.pwdstore.utils.autofillManager
57-
import com.zeapo.pwdstore.utils.getEncryptedPrefs
57+
import com.zeapo.pwdstore.utils.getEncryptedGitPrefs
5858
import com.zeapo.pwdstore.utils.getString
5959
import com.zeapo.pwdstore.utils.sharedPrefs
6060
import java.io.File
@@ -81,7 +81,7 @@ class UserPreference : AppCompatActivity() {
8181
prefsActivity = requireActivity() as UserPreference
8282
val context = requireContext()
8383
sharedPreferences = preferenceManager.sharedPreferences
84-
encryptedPreferences = requireActivity().getEncryptedPrefs("git_operation")
84+
encryptedPreferences = requireActivity().getEncryptedGitPrefs()
8585

8686
addPreferencesFromResource(R.xml.preference)
8787

app/src/main/java/com/zeapo/pwdstore/git/BaseGitActivity.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import com.zeapo.pwdstore.git.operation.PushOperation
2121
import com.zeapo.pwdstore.git.operation.ResetToRemoteOperation
2222
import com.zeapo.pwdstore.git.operation.SyncOperation
2323
import com.zeapo.pwdstore.utils.PreferenceKeys
24-
import com.zeapo.pwdstore.utils.getEncryptedPrefs
24+
import com.zeapo.pwdstore.utils.getEncryptedGitPrefs
2525
import com.zeapo.pwdstore.utils.sharedPrefs
2626
import kotlinx.coroutines.Dispatchers
2727
import kotlinx.coroutines.withContext
@@ -86,7 +86,7 @@ abstract class BaseGitActivity : AppCompatActivity() {
8686
suspend fun promptOnErrorHandler(err: Throwable, onPromptDone: () -> Unit = {}) {
8787
val error = rootCauseException(err)
8888
if (!isExplicitlyUserInitiatedError(error)) {
89-
getEncryptedPrefs("git_operation").edit {
89+
getEncryptedGitPrefs().edit {
9090
remove(PreferenceKeys.HTTPS_PASSWORD)
9191
}
9292
sharedPrefs.edit { remove(PreferenceKeys.SSH_OPENKEYSTORE_KEYID) }

app/src/main/java/com/zeapo/pwdstore/git/config/GitSettings.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import com.github.michaelbull.result.runCatching
1010
import com.zeapo.pwdstore.Application
1111
import com.zeapo.pwdstore.utils.PasswordRepository
1212
import com.zeapo.pwdstore.utils.PreferenceKeys
13-
import com.zeapo.pwdstore.utils.getEncryptedPrefs
13+
import com.zeapo.pwdstore.utils.getEncryptedGitPrefs
1414
import com.zeapo.pwdstore.utils.getString
1515
import com.zeapo.pwdstore.utils.sharedPrefs
1616
import java.io.File
@@ -53,7 +53,7 @@ object GitSettings {
5353
private const val DEFAULT_BRANCH = "master"
5454

5555
private val settings by lazy { Application.instance.sharedPrefs }
56-
private val encryptedSettings by lazy { Application.instance.getEncryptedPrefs("git_operation") }
56+
private val encryptedSettings by lazy { Application.instance.getEncryptedGitPrefs() }
5757

5858
var authMode
5959
get() = AuthMode.fromString(settings.getString(PreferenceKeys.GIT_REMOTE_AUTH))

app/src/main/java/com/zeapo/pwdstore/git/operation/CredentialFinder.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import com.zeapo.pwdstore.R
1414
import com.zeapo.pwdstore.git.config.AuthMode
1515
import com.zeapo.pwdstore.git.sshj.InteractivePasswordFinder
1616
import com.zeapo.pwdstore.utils.PreferenceKeys
17-
import com.zeapo.pwdstore.utils.getEncryptedPrefs
17+
import com.zeapo.pwdstore.utils.getEncryptedGitPrefs
1818
import com.zeapo.pwdstore.utils.requestInputFocusOnView
1919
import kotlin.coroutines.Continuation
2020
import kotlin.coroutines.resume
@@ -25,7 +25,7 @@ class CredentialFinder(
2525
) : InteractivePasswordFinder() {
2626

2727
override fun askForPassword(cont: Continuation<String?>, isRetry: Boolean) {
28-
val gitOperationPrefs = callingActivity.getEncryptedPrefs("git_operation")
28+
val gitOperationPrefs = callingActivity.getEncryptedGitPrefs()
2929
val credentialPref: String
3030
@StringRes val messageRes: Int
3131
@StringRes val hintRes: Int

app/src/main/java/com/zeapo/pwdstore/git/sshj/SshKey.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import com.github.michaelbull.result.runCatching
2323
import com.zeapo.pwdstore.Application
2424
import com.zeapo.pwdstore.R
2525
import com.zeapo.pwdstore.utils.PreferenceKeys
26-
import com.zeapo.pwdstore.utils.getEncryptedPrefs
26+
import com.zeapo.pwdstore.utils.getEncryptedGitPrefs
2727
import com.zeapo.pwdstore.utils.getString
2828
import com.zeapo.pwdstore.utils.sharedPrefs
2929
import java.io.File
@@ -169,7 +169,7 @@ object SshKey {
169169
if (publicKeyFile.isFile) {
170170
publicKeyFile.delete()
171171
}
172-
context.getEncryptedPrefs("git_operation").edit {
172+
context.getEncryptedGitPrefs().edit {
173173
remove(PreferenceKeys.SSH_KEY_LOCAL_PASSPHRASE)
174174
}
175175
type = null

app/src/main/java/com/zeapo/pwdstore/sshkeygen/SshKeyGenActivity.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import com.zeapo.pwdstore.R
2020
import com.zeapo.pwdstore.databinding.ActivitySshKeygenBinding
2121
import com.zeapo.pwdstore.git.sshj.SshKey
2222
import com.zeapo.pwdstore.utils.BiometricAuthenticator
23-
import com.zeapo.pwdstore.utils.getEncryptedPrefs
23+
import com.zeapo.pwdstore.utils.getEncryptedGitPrefs
2424
import com.zeapo.pwdstore.utils.keyguardManager
2525
import com.zeapo.pwdstore.utils.viewBinding
2626
import kotlin.coroutines.resume
@@ -128,7 +128,7 @@ class SshKeyGenActivity : AppCompatActivity() {
128128
keyGenType.generateKey(requireAuthentication)
129129
}
130130
}
131-
getEncryptedPrefs("git_operation").edit {
131+
getEncryptedGitPrefs().edit {
132132
remove("ssh_key_local_passphrase")
133133
}
134134
binding.generate.apply {
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
/*
2+
* Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
3+
* SPDX-License-Identifier: GPL-3.0-only
4+
*/
5+
6+
package com.zeapo.pwdstore.utils
7+
8+
import android.app.KeyguardManager
9+
import android.content.ClipboardManager
10+
import android.content.Context
11+
import android.content.SharedPreferences
12+
import android.content.pm.PackageManager
13+
import android.os.Build
14+
import android.util.Base64
15+
import android.util.TypedValue
16+
import android.view.View
17+
import android.view.autofill.AutofillManager
18+
import android.view.inputmethod.InputMethodManager
19+
import androidx.annotation.IdRes
20+
import androidx.annotation.RequiresApi
21+
import androidx.appcompat.app.AlertDialog
22+
import androidx.core.content.ContextCompat
23+
import androidx.core.content.getSystemService
24+
import androidx.fragment.app.FragmentActivity
25+
import androidx.preference.PreferenceManager
26+
import androidx.security.crypto.EncryptedSharedPreferences
27+
import androidx.security.crypto.MasterKey
28+
import com.github.ajalt.timberkt.d
29+
import com.github.michaelbull.result.Ok
30+
import com.github.michaelbull.result.Result
31+
import com.google.android.material.snackbar.Snackbar
32+
import com.zeapo.pwdstore.R
33+
import com.zeapo.pwdstore.git.operation.GitOperation
34+
35+
/**
36+
* Extension function for [AlertDialog] that requests focus for the
37+
* view whose id is [id]. Solution based on a StackOverflow
38+
* answer: https://stackoverflow.com/a/13056259/297261
39+
*/
40+
fun <T : View> AlertDialog.requestInputFocusOnView(@IdRes id: Int) {
41+
setOnShowListener {
42+
findViewById<T>(id)?.apply {
43+
setOnFocusChangeListener { v, _ ->
44+
v.post {
45+
context.getSystemService<InputMethodManager>()
46+
?.showSoftInput(v, InputMethodManager.SHOW_IMPLICIT)
47+
}
48+
}
49+
requestFocus()
50+
}
51+
}
52+
}
53+
54+
/**
55+
* Get an instance of [AutofillManager]. Only
56+
* available on Android Oreo and above
57+
*/
58+
val Context.autofillManager: AutofillManager?
59+
@RequiresApi(Build.VERSION_CODES.O)
60+
get() = getSystemService()
61+
62+
/**
63+
* Get an instance of [ClipboardManager]
64+
*/
65+
val Context.clipboard
66+
get() = getSystemService<ClipboardManager>()
67+
68+
/**
69+
* Wrapper for [getEncryptedPrefs] to avoid open-coding the file name at
70+
* each call site
71+
*/
72+
fun Context.getEncryptedGitPrefs() = getEncryptedPrefs("git_operation")
73+
74+
/**
75+
* Get an instance of [EncryptedSharedPreferences] with the given [fileName]
76+
*/
77+
private fun Context.getEncryptedPrefs(fileName: String): SharedPreferences {
78+
val masterKeyAlias = MasterKey.Builder(applicationContext)
79+
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
80+
.build()
81+
return EncryptedSharedPreferences.create(
82+
applicationContext,
83+
fileName,
84+
masterKeyAlias,
85+
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
86+
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
87+
)
88+
}
89+
90+
/**
91+
* Get an instance of [KeyguardManager]
92+
*/
93+
val Context.keyguardManager: KeyguardManager
94+
get() = getSystemService()!!
95+
96+
/**
97+
* Get the default [SharedPreferences] instance
98+
*/
99+
val Context.sharedPrefs: SharedPreferences
100+
get() = PreferenceManager.getDefaultSharedPreferences(applicationContext)
101+
102+
103+
/**
104+
* Resolve [attr] from the [Context]'s theme
105+
*/
106+
fun Context.resolveAttribute(attr: Int): Int {
107+
val typedValue = TypedValue()
108+
this.theme.resolveAttribute(attr, typedValue, true)
109+
return typedValue.data
110+
}
111+
112+
/**
113+
* Commit changes to the store from a [FragmentActivity] using
114+
* a custom implementation of [GitOperation]
115+
*/
116+
suspend fun FragmentActivity.commitChange(
117+
message: String,
118+
): Result<Unit, Throwable> {
119+
if (!PasswordRepository.isGitRepo()) {
120+
return Ok(Unit)
121+
}
122+
return object : GitOperation(this@commitChange) {
123+
override val commands = arrayOf(
124+
// Stage all files
125+
git.add().addFilepattern("."),
126+
// Populate the changed files count
127+
git.status(),
128+
// Commit everything! If anything changed, that is.
129+
git.commit().setAll(true).setMessage(message),
130+
)
131+
132+
override fun preExecute(): Boolean {
133+
d { "Committing with message: '$message'" }
134+
return true
135+
}
136+
}.execute()
137+
}
138+
139+
/**
140+
* Check if [permission] has been granted to the app.
141+
*/
142+
fun FragmentActivity.isPermissionGranted(permission: String): Boolean {
143+
return ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED
144+
}
145+
146+
/**
147+
* Show a [Snackbar] in a [FragmentActivity] and correctly
148+
* anchor it to a [com.google.android.material.floatingactionbutton.FloatingActionButton]
149+
* if one exists in the [view]
150+
*/
151+
fun FragmentActivity.snackbar(
152+
view: View = findViewById(android.R.id.content),
153+
message: String,
154+
length: Int = Snackbar.LENGTH_SHORT,
155+
): Snackbar {
156+
val snackbar = Snackbar.make(view, message, length)
157+
snackbar.anchorView = findViewById(R.id.fab)
158+
snackbar.show()
159+
return snackbar
160+
}
161+
162+
/**
163+
* Simplifies the common `getString(key, null) ?: defaultValue` case slightly
164+
*/
165+
fun SharedPreferences.getString(key: String): String? = getString(key, null)
166+
167+
/**
168+
* Convert this [String] to its [Base64] representation
169+
*/
170+
fun String.base64(): String {
171+
return Base64.encodeToString(encodeToByteArray(), Base64.NO_WRAP)
172+
}

0 commit comments

Comments
 (0)