mirror of
https://github.com/android-password-store/Android-Password-Store.git
synced 2025-09-07 16:09:38 +02:00
fix: part 2 of NIO bugfixing
This commit is contained in:
parent
9de25f751c
commit
911d6ba563
|
@ -13,8 +13,6 @@ import java.nio.file.Path
|
|||
import kotlin.io.path.absolutePathString
|
||||
import kotlin.io.path.name
|
||||
import kotlin.io.path.nameWithoutExtension
|
||||
import kotlin.io.path.pathString
|
||||
import kotlin.io.path.relativeTo
|
||||
|
||||
data class PasswordItem(
|
||||
val parent: PasswordItem? = null,
|
||||
|
@ -25,7 +23,8 @@ data class PasswordItem(
|
|||
|
||||
val name = file.nameWithoutExtension
|
||||
|
||||
val fullPathToParent = file.absolutePathString().replace(rootDir.absolutePathString(), "").replace(file.name, "")
|
||||
val fullPathToParent =
|
||||
file.absolutePathString().replace(rootDir.absolutePathString(), "").replace(file.name, "")
|
||||
|
||||
val longName =
|
||||
BasePGPActivity.getLongName(fullPathToParent, rootDir.absolutePathString(), toString())
|
||||
|
|
|
@ -10,6 +10,7 @@ import android.view.MotionEvent
|
|||
import android.view.View
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.selection.ItemDetailsLookup
|
||||
import androidx.recyclerview.selection.Selection
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
@ -18,9 +19,11 @@ import app.passwordstore.data.password.PasswordItem
|
|||
import app.passwordstore.util.coroutines.DispatcherProvider
|
||||
import app.passwordstore.util.viewmodel.SearchableRepositoryAdapter
|
||||
import app.passwordstore.util.viewmodel.stableId
|
||||
import kotlin.io.path.ExperimentalPathApi
|
||||
import kotlin.io.path.PathWalkOption
|
||||
import kotlin.io.path.extension
|
||||
import kotlin.io.path.isDirectory
|
||||
import kotlin.io.path.listDirectoryEntries
|
||||
import kotlin.io.path.walk
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
|
@ -52,6 +55,7 @@ open class PasswordItemRecyclerAdapter(
|
|||
return super.onSelectionChanged(listener) as PasswordItemRecyclerAdapter
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalPathApi::class)
|
||||
class PasswordItemViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
|
||||
private val name: AppCompatTextView = itemView.findViewById(R.id.label)
|
||||
|
@ -75,11 +79,12 @@ open class PasswordItemRecyclerAdapter(
|
|||
val count =
|
||||
withContext(dispatcherProvider.io()) {
|
||||
item.file
|
||||
.listDirectoryEntries()
|
||||
.walk(PathWalkOption.INCLUDE_DIRECTORIES)
|
||||
.filter { it.isDirectory() || it.extension == "gpg" }
|
||||
.toSet()
|
||||
.size
|
||||
}
|
||||
childCount.visibility = if (count > 0) View.VISIBLE else View.GONE
|
||||
childCount.isVisible = count > 0
|
||||
childCount.text = "$count"
|
||||
} else {
|
||||
childCount.visibility = View.GONE
|
||||
|
|
|
@ -161,7 +161,8 @@ open class BasePGPActivity : AppCompatActivity() {
|
|||
*/
|
||||
fun getPGPIdentifiers(subDir: String): List<PGPIdentifier>? {
|
||||
val repoRoot = PasswordRepository.getRepositoryDirectory()
|
||||
// This should ideally be `repoRoot.resolve(subDir)` but for some reason doing that returns `/subDir` as the path
|
||||
// This should ideally be `repoRoot.resolve(subDir)` but for some reason doing that returns
|
||||
// `/subDir` as the path
|
||||
// which doesn't work inside `findTillRoot`, so we're doing this manual dance.
|
||||
val gpgIdentifierFile =
|
||||
Paths.get(repoRoot.absolutePathString(), subDir).findTillRoot(".gpg-id", repoRoot)
|
||||
|
|
|
@ -58,6 +58,7 @@ import java.nio.file.Path
|
|||
import java.nio.file.Paths
|
||||
import javax.inject.Inject
|
||||
import kotlin.io.path.ExperimentalPathApi
|
||||
import kotlin.io.path.PathWalkOption
|
||||
import kotlin.io.path.absolute
|
||||
import kotlin.io.path.absolutePathString
|
||||
import kotlin.io.path.createDirectories
|
||||
|
@ -65,12 +66,12 @@ import kotlin.io.path.deleteRecursively
|
|||
import kotlin.io.path.exists
|
||||
import kotlin.io.path.isDirectory
|
||||
import kotlin.io.path.isRegularFile
|
||||
import kotlin.io.path.listDirectoryEntries
|
||||
import kotlin.io.path.moveTo
|
||||
import kotlin.io.path.name
|
||||
import kotlin.io.path.nameWithoutExtension
|
||||
import kotlin.io.path.pathString
|
||||
import kotlin.io.path.relativeTo
|
||||
import kotlin.io.path.walk
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import logcat.LogPriority.ERROR
|
||||
|
@ -79,6 +80,7 @@ import logcat.logcat
|
|||
|
||||
const val PASSWORD_FRAGMENT_TAG = "PasswordsList"
|
||||
|
||||
@OptIn(ExperimentalPathApi::class)
|
||||
@AndroidEntryPoint
|
||||
class PasswordStore : BaseGitActivity() {
|
||||
|
||||
|
@ -446,7 +448,8 @@ class PasswordStore : BaseGitActivity() {
|
|||
fun deletePasswords(selectedItems: List<PasswordItem>) {
|
||||
var size = 0
|
||||
selectedItems.forEach {
|
||||
if (it.file.isRegularFile()) size++ else size += it.file.listDirectoryEntries().size
|
||||
if (it.file.isRegularFile()) size++
|
||||
else size += it.file.walk(PathWalkOption.INCLUDE_DIRECTORIES).toSet().size
|
||||
}
|
||||
if (size == 0) {
|
||||
selectedItems.map { item -> item.file.deleteRecursively() }
|
||||
|
@ -458,7 +461,7 @@ class PasswordStore : BaseGitActivity() {
|
|||
.setPositiveButton(resources.getString(R.string.dialog_yes)) { _, _ ->
|
||||
val filesToDelete = arrayListOf<Path>()
|
||||
selectedItems.forEach { item ->
|
||||
if (item.file.isDirectory()) filesToDelete.addAll(item.file.listDirectoryEntries())
|
||||
if (item.file.isDirectory()) filesToDelete.addAll(item.file.walk())
|
||||
else filesToDelete.add(item.file)
|
||||
}
|
||||
selectedItems.map { item -> item.file.deleteRecursively() }
|
||||
|
@ -599,9 +602,7 @@ class PasswordStore : BaseGitActivity() {
|
|||
// Recursively list all files (not directories) below `source`, then
|
||||
// obtain the corresponding target file by resolving the relative path
|
||||
// starting at the destination folder.
|
||||
source.listDirectoryEntries().associateWith {
|
||||
destinationFile.resolve(it.relativeTo(source))
|
||||
}
|
||||
source.walk().associateWith { destinationFile.resolve(it.relativeTo(source)) }
|
||||
} else {
|
||||
mapOf(source to destinationFile)
|
||||
}
|
||||
|
|
|
@ -23,12 +23,12 @@ import com.github.michaelbull.result.runCatching
|
|||
import com.github.michaelbull.result.unwrap
|
||||
import java.nio.file.Paths
|
||||
import javax.inject.Inject
|
||||
import kotlin.io.path.ExperimentalPathApi
|
||||
import kotlin.io.path.createDirectories
|
||||
import kotlin.io.path.deleteIfExists
|
||||
import kotlin.io.path.exists
|
||||
import kotlin.io.path.isRegularFile
|
||||
import kotlin.io.path.listDirectoryEntries
|
||||
import kotlin.io.path.readBytes
|
||||
import kotlin.io.path.walk
|
||||
import kotlin.io.path.writeBytes
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.withContext
|
||||
|
@ -37,6 +37,7 @@ import org.bouncycastle.openpgp.PGPSecretKeyRing
|
|||
import org.pgpainless.PGPainless
|
||||
import org.pgpainless.util.selection.userid.SelectUserId
|
||||
|
||||
@OptIn(ExperimentalPathApi::class)
|
||||
public class PGPKeyManager
|
||||
@Inject
|
||||
constructor(filesDir: String, private val dispatcher: CoroutineDispatcher) :
|
||||
|
@ -98,7 +99,7 @@ constructor(filesDir: String, private val dispatcher: CoroutineDispatcher) :
|
|||
withContext(dispatcher) {
|
||||
runSuspendCatching {
|
||||
if (!keyDirExists()) throw KeyDirectoryUnavailableException
|
||||
val keyFiles = keyDir.listDirectoryEntries().filter { it.isRegularFile() }
|
||||
val keyFiles = keyDir.walk().toSet()
|
||||
if (keyFiles.isEmpty()) throw NoKeysAvailableException
|
||||
val keys = keyFiles.map { file -> PGPKey(file.readBytes()) }
|
||||
|
||||
|
@ -134,7 +135,7 @@ constructor(filesDir: String, private val dispatcher: CoroutineDispatcher) :
|
|||
withContext(dispatcher) {
|
||||
runSuspendCatching {
|
||||
if (!keyDirExists()) throw KeyDirectoryUnavailableException
|
||||
val keyFiles = keyDir.listDirectoryEntries().filter { it.isRegularFile() }
|
||||
val keyFiles = keyDir.walk().toSet()
|
||||
if (keyFiles.isEmpty()) return@runSuspendCatching emptyList()
|
||||
keyFiles.map { keyFile -> PGPKey(keyFile.readBytes()) }.toList()
|
||||
}
|
||||
|
|
|
@ -9,9 +9,10 @@ import app.passwordstore.crypto.errors.NoKeysAvailableException
|
|||
import app.passwordstore.crypto.errors.UnusableKeyException
|
||||
import com.github.michaelbull.result.unwrap
|
||||
import com.github.michaelbull.result.unwrapError
|
||||
import kotlin.io.path.ExperimentalPathApi
|
||||
import kotlin.io.path.absolutePathString
|
||||
import kotlin.io.path.listDirectoryEntries
|
||||
import kotlin.io.path.name
|
||||
import kotlin.io.path.walk
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertContentEquals
|
||||
import kotlin.test.assertEquals
|
||||
|
@ -24,6 +25,7 @@ import kotlinx.coroutines.test.runTest
|
|||
import org.junit.Rule
|
||||
import org.junit.rules.TemporaryFolder
|
||||
|
||||
@OptIn(ExperimentalPathApi::class)
|
||||
class PGPKeyManagerTest {
|
||||
|
||||
@get:Rule val temporaryFolder: TemporaryFolder = TemporaryFolder()
|
||||
|
@ -44,9 +46,9 @@ class PGPKeyManagerTest {
|
|||
val keyId = keyManager.getKeyId(keyManager.addKey(secretKey).unwrap())
|
||||
assertEquals(KeyId(CryptoConstants.KEY_ID), keyId)
|
||||
// Check if the keys directory have one file
|
||||
assertEquals(1, filesDir.listDirectoryEntries().size)
|
||||
assertEquals(1, filesDir.walk().toSet().size)
|
||||
// Check if the file name is correct
|
||||
val keyFile = keysDir.listDirectoryEntries().first()
|
||||
val keyFile = keysDir.walk().toSet().first()
|
||||
assertEquals(keyFile.name, "$keyId.${PGPKeyManager.KEY_EXTENSION}")
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue