summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/lint-baseline.xml79
-rw-r--r--app/src/main/java/app/passwordstore/data/repo/PasswordRepository.kt6
-rw-r--r--app/src/main/java/app/passwordstore/ui/dialogs/PasswordGeneratorDialogFragment.kt26
-rw-r--r--app/src/main/java/app/passwordstore/ui/folderselect/SelectFolderFragment.kt17
-rw-r--r--app/src/main/java/app/passwordstore/ui/git/config/GitServerConfigActivity.kt5
-rw-r--r--app/src/main/java/app/passwordstore/ui/passwords/PasswordFragment.kt14
-rw-r--r--app/src/main/java/app/passwordstore/ui/passwords/PasswordStore.kt25
-rw-r--r--app/src/main/java/app/passwordstore/util/autofill/Api26AutofillResponseBuilder.kt2
-rw-r--r--app/src/main/java/app/passwordstore/util/autofill/Api30AutofillResponseBuilder.kt2
-rw-r--r--app/src/main/java/app/passwordstore/util/autofill/AutofillMatcher.kt4
-rw-r--r--app/src/main/java/app/passwordstore/util/git/operation/BreakOutOfDetached.kt3
-rw-r--r--app/src/main/java/app/passwordstore/util/git/operation/CredentialFinder.kt4
-rw-r--r--app/src/main/java/app/passwordstore/util/git/operation/GitOperation.kt11
-rw-r--r--app/src/main/java/app/passwordstore/util/git/operation/ResetToRemoteOperation.kt3
-rw-r--r--app/src/main/java/app/passwordstore/util/git/operation/SyncOperation.kt3
-rw-r--r--app/src/main/java/app/passwordstore/util/git/sshj/SshjSessionFactory.kt31
-rw-r--r--app/src/main/java/app/passwordstore/util/services/PasswordExportService.kt5
-rw-r--r--app/src/main/java/app/passwordstore/util/settings/GitSettings.kt2
-rw-r--r--app/src/nonFree/java/app/passwordstore/autofill/oreo/ui/AutofillSmsActivity.kt8
19 files changed, 115 insertions, 135 deletions
diff --git a/app/lint-baseline.xml b/app/lint-baseline.xml
index 137d61d6..b0702655 100644
--- a/app/lint-baseline.xml
+++ b/app/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.3.0-alpha01" type="baseline" client="gradle" dependencies="false" name="AGP (8.3.0-alpha01)" variant="all" version="8.3.0-alpha01">
+<issues format="6" by="lint 8.3.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (8.3.0-alpha05)" variant="all" version="8.3.0-alpha05">
<issue
id="StopShip"
@@ -27,17 +27,6 @@
</issue>
<issue
- id="RawDispatchersUse"
- message="Use SlackDispatchers."
- errorLine1=" runBlocking(Dispatchers.Main) { suspendCoroutine { cont -> askForPassword(cont, isRetry) } }"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/app/passwordstore/util/git/sshj/SshjSessionFactory.kt"
- line="60"
- column="19"/>
- </issue>
-
- <issue
id="DenyListedApi"
message="Use Context#getDrawableCompat() instead"
errorLine1=" ContextCompat.getDrawable(itemView.context, R.drawable.ic_content_copy)"
@@ -60,39 +49,6 @@
</issue>
<issue
- id="DenyListedApi"
- message="Use the structured concurrent CoroutineScope#launch and Flow#collect APIs instead of reactive Flow#onEach and Flow#launchIn. Suspend calls like Flow#collect can be refactored into standalone suspend funs and mixed in with regular control flow in a suspend context, but calls that invoke CoroutineScope#launch and Flow#collect at the same time hide the suspend context, encouraging the developer to continue working in the reactive domain."
- errorLine1=" .launchIn(lifecycleScope)"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/app/passwordstore/ui/passwords/PasswordFragment.kt"
- line="212"
- column="8"/>
- </issue>
-
- <issue
- id="DenyListedApi"
- message="Use the structured concurrent CoroutineScope#launch and Flow#collect APIs instead of reactive Flow#onEach and Flow#launchIn. Suspend calls like Flow#collect can be refactored into standalone suspend funs and mixed in with regular control flow in a suspend context, but calls that invoke CoroutineScope#launch and Flow#collect at the same time hide the suspend context, encouraging the developer to continue working in the reactive domain."
- errorLine1=" .launchIn(lifecycleScope)"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/app/passwordstore/ui/dialogs/PasswordGeneratorDialogFragment.kt"
- line="68"
- column="8"/>
- </issue>
-
- <issue
- id="DenyListedApi"
- message="Use the structured concurrent CoroutineScope#launch and Flow#collect APIs instead of reactive Flow#onEach and Flow#launchIn. Suspend calls like Flow#collect can be refactored into standalone suspend funs and mixed in with regular control flow in a suspend context, but calls that invoke CoroutineScope#launch and Flow#collect at the same time hide the suspend context, encouraging the developer to continue working in the reactive domain."
- errorLine1=" .launchIn(lifecycleScope)"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/app/passwordstore/ui/folderselect/SelectFolderFragment.kt"
- line="65"
- column="8"/>
- </issue>
-
- <issue
id="MissingQuantity"
message="For locale &quot;it&quot; (Italian) the following quantity should also be defined: `many`"
errorLine1=" &lt;plurals name=&quot;delete_title&quot;>"
@@ -227,37 +183,4 @@
column="4"/>
</issue>
- <issue
- id="UnknownNullness"
- message="Should explicitly declare type here since implicit type does not specify nullness (Lazy&lt;Array&lt;(GitCommand&lt;out (Any or Any?)> or GitCommand&lt;out (Any or Any?)>?)>>)"
- errorLine1=" override val commands by unsafeLazy {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/app/passwordstore/util/git/operation/BreakOutOfDetached.kt"
- line="33"
- column="16"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Should explicitly declare type here since implicit type does not specify nullness (Array&lt;(GitCommand&lt;out (Any or Any?)> or GitCommand&lt;out (Any or Any?)>?)>)"
- errorLine1=" override val commands ="
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/app/passwordstore/util/git/operation/ResetToRemoteOperation.kt"
- line="14"
- column="16"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Should explicitly declare type here since implicit type does not specify nullness (Array&lt;(GitCommand&lt;out (Any or Any?)> or GitCommand&lt;out (Any or Any?)>?)>)"
- errorLine1=" override val commands ="
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/app/passwordstore/util/git/operation/SyncOperation.kt"
- line="14"
- column="16"/>
- </issue>
-
</issues>
diff --git a/app/src/main/java/app/passwordstore/data/repo/PasswordRepository.kt b/app/src/main/java/app/passwordstore/data/repo/PasswordRepository.kt
index 1ddf1c61..454054cf 100644
--- a/app/src/main/java/app/passwordstore/data/repo/PasswordRepository.kt
+++ b/app/src/main/java/app/passwordstore/data/repo/PasswordRepository.kt
@@ -114,7 +114,11 @@ object PasswordRepository {
val dir = getRepositoryDirectory()
// Un-initialize the repo if the dir does not exist or is absolutely empty
settings.edit {
- if (!dir.exists() || !dir.isDirectory || requireNotNull(dir.listFiles()).isEmpty()) {
+ if (
+ !dir.exists() ||
+ !dir.isDirectory ||
+ requireNotNull(dir.listFiles()) { "Failed to list files in ${dir.path}" }.isEmpty()
+ ) {
putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, false)
} else {
putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, true)
diff --git a/app/src/main/java/app/passwordstore/ui/dialogs/PasswordGeneratorDialogFragment.kt b/app/src/main/java/app/passwordstore/ui/dialogs/PasswordGeneratorDialogFragment.kt
index da1a060a..1f37e205 100644
--- a/app/src/main/java/app/passwordstore/ui/dialogs/PasswordGeneratorDialogFragment.kt
+++ b/app/src/main/java/app/passwordstore/ui/dialogs/PasswordGeneratorDialogFragment.kt
@@ -31,9 +31,8 @@ import app.passwordstore.util.settings.PreferenceKeys
import com.github.michaelbull.result.getOrElse
import com.github.michaelbull.result.runCatching
import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.merge
-import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
import reactivecircus.flowbinding.android.widget.afterTextChanges
import reactivecircus.flowbinding.android.widget.checkedChanges
@@ -55,17 +54,18 @@ class PasswordGeneratorDialogFragment : DialogFragment() {
binding.lengthNumber.setText(prefs.getInt(PreferenceKeys.LENGTH, 20).toString())
binding.passwordText.typeface = Typeface.MONOSPACE
- merge(
- binding.numerals.checkedChanges().skipInitialValue(),
- binding.symbols.checkedChanges().skipInitialValue(),
- binding.uppercase.checkedChanges().skipInitialValue(),
- binding.lowercase.checkedChanges().skipInitialValue(),
- binding.ambiguous.checkedChanges().skipInitialValue(),
- binding.pronounceable.checkedChanges().skipInitialValue(),
- binding.lengthNumber.afterTextChanges().skipInitialValue(),
- )
- .onEach { generate(binding.passwordText) }
- .launchIn(lifecycleScope)
+ lifecycleScope.launch {
+ merge(
+ binding.numerals.checkedChanges().skipInitialValue(),
+ binding.symbols.checkedChanges().skipInitialValue(),
+ binding.uppercase.checkedChanges().skipInitialValue(),
+ binding.lowercase.checkedChanges().skipInitialValue(),
+ binding.ambiguous.checkedChanges().skipInitialValue(),
+ binding.pronounceable.checkedChanges().skipInitialValue(),
+ binding.lengthNumber.afterTextChanges().skipInitialValue(),
+ )
+ .collect { generate(binding.passwordText) }
+ }
return builder
.run {
diff --git a/app/src/main/java/app/passwordstore/ui/folderselect/SelectFolderFragment.kt b/app/src/main/java/app/passwordstore/ui/folderselect/SelectFolderFragment.kt
index a1c33e3f..9a8080a4 100644
--- a/app/src/main/java/app/passwordstore/ui/folderselect/SelectFolderFragment.kt
+++ b/app/src/main/java/app/passwordstore/ui/folderselect/SelectFolderFragment.kt
@@ -27,8 +27,7 @@ import com.github.michaelbull.result.runCatching
import dagger.hilt.android.AndroidEntryPoint
import java.io.File
import javax.inject.Inject
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
import me.zhanghai.android.fastscroll.FastScrollerBuilder
@AndroidEntryPoint
@@ -57,12 +56,16 @@ class SelectFolderFragment : Fragment(R.layout.password_recycler_view) {
FastScrollerBuilder(binding.passRecycler).build()
registerForContextMenu(binding.passRecycler)
- val path = requireNotNull(requireArguments().getString(PasswordStore.REQUEST_ARG_PATH))
+ val path =
+ requireNotNull(requireArguments().getString(PasswordStore.REQUEST_ARG_PATH)) {
+ "Cannot navigate if ${PasswordStore.REQUEST_ARG_PATH} is not provided"
+ }
model.navigateTo(File(path), listMode = ListMode.DirectoriesOnly, pushPreviousLocation = false)
- model.searchResult
- .flowWithLifecycle(lifecycle)
- .onEach { result -> recyclerAdapter.submitList(result.passwordItems) }
- .launchIn(lifecycleScope)
+ lifecycleScope.launch {
+ model.searchResult.flowWithLifecycle(lifecycle).collect { result ->
+ recyclerAdapter.submitList(result.passwordItems)
+ }
+ }
}
override fun onAttach(context: Context) {
diff --git a/app/src/main/java/app/passwordstore/ui/git/config/GitServerConfigActivity.kt b/app/src/main/java/app/passwordstore/ui/git/config/GitServerConfigActivity.kt
index 5e2bafb9..9a3029bc 100644
--- a/app/src/main/java/app/passwordstore/ui/git/config/GitServerConfigActivity.kt
+++ b/app/src/main/java/app/passwordstore/ui/git/config/GitServerConfigActivity.kt
@@ -221,7 +221,10 @@ class GitServerConfigActivity : BaseGitActivity() {
/** Clones the repository, the directory exists, deletes it */
private fun cloneRepository() {
- val localDir = requireNotNull(PasswordRepository.getRepositoryDirectory())
+ val localDir =
+ requireNotNull(PasswordRepository.getRepositoryDirectory()) {
+ "Repository directory must be set before cloning"
+ }
val localDirFiles = localDir.listFiles() ?: emptyArray()
// Warn if non-empty folder unless it's a just-initialized store that has just a .git folder
if (
diff --git a/app/src/main/java/app/passwordstore/ui/passwords/PasswordFragment.kt b/app/src/main/java/app/passwordstore/ui/passwords/PasswordFragment.kt
index d6bcce11..60580ff5 100644
--- a/app/src/main/java/app/passwordstore/ui/passwords/PasswordFragment.kt
+++ b/app/src/main/java/app/passwordstore/ui/passwords/PasswordFragment.kt
@@ -50,8 +50,6 @@ import com.github.michaelbull.result.runCatching
import dagger.hilt.android.AndroidEntryPoint
import java.io.File
import javax.inject.Inject
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import me.zhanghai.android.fastscroll.FastScrollerBuilder
@@ -177,11 +175,13 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) {
recyclerAdapter.makeSelectable(recyclerView)
registerForContextMenu(recyclerView)
- val path = requireNotNull(requireArguments().getString(PasswordStore.REQUEST_ARG_PATH))
+ val path =
+ requireNotNull(requireArguments().getString(PasswordStore.REQUEST_ARG_PATH)) {
+ "Cannot navigate if ${PasswordStore.REQUEST_ARG_PATH} is not provided"
+ }
model.navigateTo(File(path), pushPreviousLocation = false)
- model.searchResult
- .flowWithLifecycle(lifecycle)
- .onEach { result ->
+ lifecycleScope.launch {
+ model.searchResult.flowWithLifecycle(lifecycle).collect { result ->
// Only run animations when the new list is filtered, i.e., the user submitted a search,
// and not on folder navigation since the latter leads to too many removal animations.
(recyclerView.itemAnimator as OnOffItemAnimator).isEnabled = result.isFiltered
@@ -209,7 +209,7 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) {
}
}
}
- .launchIn(lifecycleScope)
+ }
}
private val actionModeCallback =
diff --git a/app/src/main/java/app/passwordstore/ui/passwords/PasswordStore.kt b/app/src/main/java/app/passwordstore/ui/passwords/PasswordStore.kt
index 8aeee609..861250c8 100644
--- a/app/src/main/java/app/passwordstore/ui/passwords/PasswordStore.kt
+++ b/app/src/main/java/app/passwordstore/ui/passwords/PasswordStore.kt
@@ -83,8 +83,16 @@ class PasswordStore : BaseGitActivity() {
private val passwordMoveAction =
registerForActivityResult(StartActivityForResult()) { result ->
val intentData = result.data ?: return@registerForActivityResult
- val filesToMove = requireNotNull(intentData.getStringArrayExtra("Files"))
- val target = File(requireNotNull(intentData.getStringExtra("SELECTED_FOLDER_PATH")))
+ val filesToMove =
+ requireNotNull(intentData.getStringArrayExtra("Files")) {
+ "'Files' intent extra must be set"
+ }
+ val target =
+ File(
+ requireNotNull(intentData.getStringExtra("SELECTED_FOLDER_PATH")) {
+ "'SELECTED_FOLDER_PATH' intent extra must be set"
+ }
+ )
val repositoryPath = PasswordRepository.getRepositoryDirectory().absolutePath
if (!target.isDirectory) {
logcat(ERROR) { "Tried moving passwords to a non-existing folder." }
@@ -103,7 +111,12 @@ class PasswordStore : BaseGitActivity() {
}
val destinationFile = File(target.absolutePath + "/" + source.name)
val basename = source.nameWithoutExtension
- val sourceLongName = getLongName(requireNotNull(source.parent), repositoryPath, basename)
+ val sourceLongName =
+ getLongName(
+ requireNotNull(source.parent) { "$file has no parent" },
+ repositoryPath,
+ basename
+ )
val destinationLongName = getLongName(target.absolutePath, repositoryPath, basename)
if (destinationFile.exists()) {
logcat(ERROR) { "Trying to move a file that already exists." }
@@ -132,7 +145,11 @@ class PasswordStore : BaseGitActivity() {
val source = File(filesToMove[0])
val basename = source.nameWithoutExtension
val sourceLongName =
- getLongName(requireNotNull(source.parent), repositoryPath, basename)
+ getLongName(
+ requireNotNull(source.parent) { "$basename has no parent" },
+ repositoryPath,
+ basename
+ )
val destinationLongName = getLongName(target.absolutePath, repositoryPath, basename)
withContext(dispatcherProvider.main()) {
commitChange(
diff --git a/app/src/main/java/app/passwordstore/util/autofill/Api26AutofillResponseBuilder.kt b/app/src/main/java/app/passwordstore/util/autofill/Api26AutofillResponseBuilder.kt
index 77322116..8b087f99 100644
--- a/app/src/main/java/app/passwordstore/util/autofill/Api26AutofillResponseBuilder.kt
+++ b/app/src/main/java/app/passwordstore/util/autofill/Api26AutofillResponseBuilder.kt
@@ -125,7 +125,7 @@ private constructor(
// https://developer.android.com/reference/android/service/autofill/SaveInfo#FLAG_DELAY_SAVE
private fun makeSaveInfo(): SaveInfo? {
if (!canBeSaved) return null
- check(saveFlags != null)
+ check(saveFlags != null) { "saveFlags must not be null" }
val idsToSave = scenario.fieldsToSave.toTypedArray()
if (idsToSave.isEmpty()) return null
var saveDataTypes = SaveInfo.SAVE_DATA_TYPE_PASSWORD
diff --git a/app/src/main/java/app/passwordstore/util/autofill/Api30AutofillResponseBuilder.kt b/app/src/main/java/app/passwordstore/util/autofill/Api30AutofillResponseBuilder.kt
index 49970fa6..ef1c302c 100644
--- a/app/src/main/java/app/passwordstore/util/autofill/Api30AutofillResponseBuilder.kt
+++ b/app/src/main/java/app/passwordstore/util/autofill/Api30AutofillResponseBuilder.kt
@@ -244,7 +244,7 @@ private constructor(
// https://developer.android.com/reference/android/service/autofill/SaveInfo#FLAG_DELAY_SAVE
private fun makeSaveInfo(): SaveInfo? {
if (!canBeSaved) return null
- check(saveFlags != null)
+ check(saveFlags != null) { "saveFlags must not be null" }
val idsToSave = scenario.fieldsToSave.toTypedArray()
if (idsToSave.isEmpty()) return null
var saveDataTypes = SaveInfo.SAVE_DATA_TYPE_PASSWORD
diff --git a/app/src/main/java/app/passwordstore/util/autofill/AutofillMatcher.kt b/app/src/main/java/app/passwordstore/util/autofill/AutofillMatcher.kt
index 52c3d778..56171f6b 100644
--- a/app/src/main/java/app/passwordstore/util/autofill/AutofillMatcher.kt
+++ b/app/src/main/java/app/passwordstore/util/autofill/AutofillMatcher.kt
@@ -40,7 +40,9 @@ class AutofillPublisherChangedException(val formOrigin: FormOrigin) :
) {
init {
- require(formOrigin is FormOrigin.App)
+ require(formOrigin is FormOrigin.App) {
+ "${this::class.java.simpleName} is only applicable for apps"
+ }
}
}
diff --git a/app/src/main/java/app/passwordstore/util/git/operation/BreakOutOfDetached.kt b/app/src/main/java/app/passwordstore/util/git/operation/BreakOutOfDetached.kt
index b6f31b18..77a19da6 100644
--- a/app/src/main/java/app/passwordstore/util/git/operation/BreakOutOfDetached.kt
+++ b/app/src/main/java/app/passwordstore/util/git/operation/BreakOutOfDetached.kt
@@ -9,6 +9,7 @@ import app.passwordstore.R
import app.passwordstore.data.repo.PasswordRepository
import app.passwordstore.util.extensions.unsafeLazy
import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import org.eclipse.jgit.api.GitCommand
import org.eclipse.jgit.api.RebaseCommand
import org.eclipse.jgit.api.ResetCommand
import org.eclipse.jgit.lib.RepositoryState
@@ -30,7 +31,7 @@ class BreakOutOfDetached(callingActivity: AppCompatActivity) : GitOperation(call
git.checkout().setName(localBranch),
)
- override val commands by unsafeLazy {
+ override val commands: Array<GitCommand<out Any>> by unsafeLazy {
if (merging) {
// We need to run some non-command operations first
repository.writeMergeCommitMsg(null)
diff --git a/app/src/main/java/app/passwordstore/util/git/operation/CredentialFinder.kt b/app/src/main/java/app/passwordstore/util/git/operation/CredentialFinder.kt
index 0210a744..e90e3b23 100644
--- a/app/src/main/java/app/passwordstore/util/git/operation/CredentialFinder.kt
+++ b/app/src/main/java/app/passwordstore/util/git/operation/CredentialFinder.kt
@@ -15,6 +15,7 @@ import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.FragmentActivity
import app.passwordstore.R
import app.passwordstore.injection.prefs.GitPreferences
+import app.passwordstore.util.coroutines.DispatcherProvider
import app.passwordstore.util.git.sshj.InteractivePasswordFinder
import app.passwordstore.util.settings.AuthMode
import app.passwordstore.util.settings.PreferenceKeys
@@ -32,7 +33,8 @@ import kotlin.coroutines.resume
class CredentialFinder(
private val callingActivity: FragmentActivity,
private val authMode: AuthMode,
-) : InteractivePasswordFinder() {
+ dispatcherProvider: DispatcherProvider,
+) : InteractivePasswordFinder(dispatcherProvider) {
private val hiltEntryPoint =
EntryPointAccessors.fromApplication(
diff --git a/app/src/main/java/app/passwordstore/util/git/operation/GitOperation.kt b/app/src/main/java/app/passwordstore/util/git/operation/GitOperation.kt
index 1cc42633..d4ccfaab 100644
--- a/app/src/main/java/app/passwordstore/util/git/operation/GitOperation.kt
+++ b/app/src/main/java/app/passwordstore/util/git/operation/GitOperation.kt
@@ -121,7 +121,8 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) {
authMethod: SshAuthMethod,
credentialsProvider: CredentialsProvider? = null
) {
- sshSessionFactory = SshjSessionFactory(authMethod, hostKeyFile, sshFacade)
+ sshSessionFactory =
+ SshjSessionFactory(authMethod, hostKeyFile, sshFacade, hiltEntryPoint.dispatcherProvider())
commands.filterIsInstance<TransportCommand<*, *>>().forEach { command ->
command.setTransportConfigCallback { transport: Transport ->
(transport as? SshTransport)?.sshSessionFactory = sshSessionFactory
@@ -217,7 +218,13 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) {
}
AuthMode.Password -> {
val httpsCredentialProvider =
- HttpsCredentialsProvider(CredentialFinder(callingActivity, AuthMode.Password))
+ HttpsCredentialsProvider(
+ CredentialFinder(
+ callingActivity,
+ AuthMode.Password,
+ hiltEntryPoint.dispatcherProvider()
+ )
+ )
registerAuthProviders(SshAuthMethod.Password(authActivity), httpsCredentialProvider)
}
AuthMode.None -> {}
diff --git a/app/src/main/java/app/passwordstore/util/git/operation/ResetToRemoteOperation.kt b/app/src/main/java/app/passwordstore/util/git/operation/ResetToRemoteOperation.kt
index 08cc195a..f6b4fdcd 100644
--- a/app/src/main/java/app/passwordstore/util/git/operation/ResetToRemoteOperation.kt
+++ b/app/src/main/java/app/passwordstore/util/git/operation/ResetToRemoteOperation.kt
@@ -6,12 +6,13 @@ package app.passwordstore.util.git.operation
import androidx.appcompat.app.AppCompatActivity
import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode.TRACK
+import org.eclipse.jgit.api.GitCommand
import org.eclipse.jgit.api.ResetCommand
class ResetToRemoteOperation(callingActivity: AppCompatActivity, remoteBranch: String) :
GitOperation(callingActivity) {
- override val commands =
+ override val commands: Array<GitCommand<out Any>> =
arrayOf(
// Fetch everything from the origin remote
git.fetch().setRemote("origin").setRemoveDeletedRefs(true),
diff --git a/app/src/main/java/app/passwordstore/util/git/operation/SyncOperation.kt b/app/src/main/java/app/passwordstore/util/git/operation/SyncOperation.kt
index e36b01b1..57be9439 100644
--- a/app/src/main/java/app/passwordstore/util/git/operation/SyncOperation.kt
+++ b/app/src/main/java/app/passwordstore/util/git/operation/SyncOperation.kt
@@ -5,13 +5,14 @@
package app.passwordstore.util.git.operation
import androidx.appcompat.app.AppCompatActivity
+import org.eclipse.jgit.api.GitCommand
class SyncOperation(
callingActivity: AppCompatActivity,
rebase: Boolean,
) : GitOperation(callingActivity) {
- override val commands =
+ override val commands: Array<GitCommand<out Any>> =
arrayOf(
// Stage all files
git.add().addFilepattern("."),
diff --git a/app/src/main/java/app/passwordstore/util/git/sshj/SshjSessionFactory.kt b/app/src/main/java/app/passwordstore/util/git/sshj/SshjSessionFactory.kt
index 54858530..20bb01d6 100644
--- a/app/src/main/java/app/passwordstore/util/git/sshj/SshjSessionFactory.kt
+++ b/app/src/main/java/app/passwordstore/util/git/sshj/SshjSessionFactory.kt
@@ -6,6 +6,7 @@ package app.passwordstore.util.git.sshj
import android.util.Base64
import androidx.appcompat.app.AppCompatActivity
+import app.passwordstore.util.coroutines.DispatcherProvider
import app.passwordstore.util.git.operation.CredentialFinder
import app.passwordstore.util.settings.AuthMode
import app.passwordstore.util.ssh.SSHFacade
@@ -20,7 +21,6 @@ import java.util.Collections
import java.util.concurrent.TimeUnit
import kotlin.coroutines.Continuation
import kotlin.coroutines.suspendCoroutine
-import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import logcat.LogPriority.WARN
import logcat.logcat
@@ -49,15 +49,18 @@ sealed class SshAuthMethod(val activity: AppCompatActivity) {
class SshKey(activity: AppCompatActivity) : SshAuthMethod(activity)
}
-abstract class InteractivePasswordFinder : PasswordFinder {
+abstract class InteractivePasswordFinder(private val dispatcherProvider: DispatcherProvider) :
+ PasswordFinder {
private var isRetry = false
abstract fun askForPassword(cont: Continuation<String?>, isRetry: Boolean)
- final override fun reqPassword(resource: Resource<*>?): CharArray {
+ override fun reqPassword(resource: Resource<*>?): CharArray {
val password =
- runBlocking(Dispatchers.Main) { suspendCoroutine { cont -> askForPassword(cont, isRetry) } }
+ runBlocking(dispatcherProvider.main()) {
+ suspendCoroutine { cont -> askForPassword(cont, isRetry) }
+ }
isRetry = true
return password?.toCharArray() ?: throw SSHException(DisconnectReason.AUTH_CANCELLED_BY_USER)
}
@@ -69,6 +72,7 @@ class SshjSessionFactory(
private val authMethod: SshAuthMethod,
private val hostKeyFile: File,
private val sshFacade: SSHFacade,
+ private val dispatcherProvider: DispatcherProvider,
) : SshSessionFactory() {
private var currentSession: SshjSession? = null
@@ -80,10 +84,12 @@ class SshjSessionFactory(
tms: Int
): RemoteSession {
return currentSession
- ?: SshjSession(uri, uri.user, authMethod, hostKeyFile, sshFacade).connect().also {
- logcat { "New SSH connection created" }
- currentSession = it
- }
+ ?: SshjSession(uri, uri.user, authMethod, hostKeyFile, sshFacade, dispatcherProvider)
+ .connect()
+ .also {
+ logcat { "New SSH connection created" }
+ currentSession = it
+ }
}
fun close() {
@@ -125,6 +131,7 @@ private class SshjSession(
private val authMethod: SshAuthMethod,
private val hostKeyFile: File,
private val sshFacade: SSHFacade,
+ private val dispatcherProvider: DispatcherProvider,
) : RemoteSession {
private lateinit var ssh: SSHClient
@@ -151,7 +158,8 @@ private class SshjSession(
ssh.addHostKeyVerifier(makeTofuHostKeyVerifier(hostKeyFile))
ssh.connect(uri.host, uri.port.takeUnless { it == -1 } ?: 22)
if (!ssh.isConnected) throw IOException()
- val passwordAuth = AuthPassword(CredentialFinder(authMethod.activity, AuthMode.Password))
+ val passwordAuth =
+ AuthPassword(CredentialFinder(authMethod.activity, AuthMode.Password, dispatcherProvider))
when (authMethod) {
is SshAuthMethod.Password -> {
ssh.auth(username, passwordAuth)
@@ -159,7 +167,10 @@ private class SshjSession(
is SshAuthMethod.SshKey -> {
val pubkeyAuth =
AuthPublickey(
- sshFacade.keyProvider(ssh, CredentialFinder(authMethod.activity, AuthMode.SshKey))
+ sshFacade.keyProvider(
+ ssh,
+ CredentialFinder(authMethod.activity, AuthMode.SshKey, dispatcherProvider)
+ )
)
ssh.auth(username, pubkeyAuth, passwordAuth)
}
diff --git a/app/src/main/java/app/passwordstore/util/services/PasswordExportService.kt b/app/src/main/java/app/passwordstore/util/services/PasswordExportService.kt
index 9243f52d..d5032f4f 100644
--- a/app/src/main/java/app/passwordstore/util/services/PasswordExportService.kt
+++ b/app/src/main/java/app/passwordstore/util/services/PasswordExportService.kt
@@ -57,7 +57,10 @@ class PasswordExportService : Service() {
*/
private fun exportPasswords(targetDirectory: DocumentFile) {
- val repositoryDirectory = requireNotNull(PasswordRepository.getRepositoryDirectory())
+ val repositoryDirectory =
+ requireNotNull(PasswordRepository.getRepositoryDirectory()) {
+ "Password directory must be set to export them"
+ }
val sourcePassDir = DocumentFile.fromFile(repositoryDirectory)
logcat { "Copying ${repositoryDirectory.path} to $targetDirectory" }
diff --git a/app/src/main/java/app/passwordstore/util/settings/GitSettings.kt b/app/src/main/java/app/passwordstore/util/settings/GitSettings.kt
index 56124104..bfbf9c85 100644
--- a/app/src/main/java/app/passwordstore/util/settings/GitSettings.kt
+++ b/app/src/main/java/app/passwordstore/util/settings/GitSettings.kt
@@ -68,7 +68,7 @@ constructor(
var url
get() = settings.getString(PreferenceKeys.GIT_REMOTE_URL)
private set(value) {
- require(value != null)
+ require(value != null) { "Cannot set a null URL" }
if (value == url) return
settings.edit { putString(PreferenceKeys.GIT_REMOTE_URL, value) }
if (PasswordRepository.isInitialized) PasswordRepository.addRemote("origin", value, true)
diff --git a/app/src/nonFree/java/app/passwordstore/autofill/oreo/ui/AutofillSmsActivity.kt b/app/src/nonFree/java/app/passwordstore/autofill/oreo/ui/AutofillSmsActivity.kt
index 61b42342..ebd10020 100644
--- a/app/src/nonFree/java/app/passwordstore/autofill/oreo/ui/AutofillSmsActivity.kt
+++ b/app/src/nonFree/java/app/passwordstore/autofill/oreo/ui/AutofillSmsActivity.kt
@@ -15,6 +15,7 @@ import android.os.Build
import android.os.Bundle
import android.view.autofill.AutofillManager
import androidx.appcompat.app.AppCompatActivity
+import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import app.passwordstore.databinding.ActivityOreoAutofillSmsBinding
import app.passwordstore.util.autofill.AutofillResponseBuilder
@@ -113,18 +114,19 @@ class AutofillSmsActivity : AppCompatActivity() {
return
}
- registerReceiver(
+ ContextCompat.registerReceiver(
+ this,
smsCodeRetrievedReceiver,
IntentFilter(SmsCodeRetriever.SMS_CODE_RETRIEVED_ACTION),
SmsRetriever.SEND_PERMISSION,
- null
+ null,
+ ContextCompat.RECEIVER_EXPORTED,
)
lifecycleScope.launch { waitForSms() }
}
// Retry starting the SMS code retriever after a permission request.
@Deprecated("Deprecated in Java")
- @Suppress("DEPRECATION")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode != Activity.RESULT_OK) return