Add support for "work/example.org.gpg" folder layout

This commit is contained in:
Fabian Henneke 2020-04-15 17:20:26 +02:00 committed by Harsh Shandilya
parent 5a3220527f
commit 441b4d3b68
5 changed files with 27 additions and 10 deletions

View file

@ -97,7 +97,7 @@ private fun PasswordItem.Companion.makeComparator(
.then(compareBy(nullsLast(CaseInsensitiveComparator)) { .then(compareBy(nullsLast(CaseInsensitiveComparator)) {
directoryStructure.getIdentifierFor(it.file) directoryStructure.getIdentifierFor(it.file)
}) })
.then(compareBy(CaseInsensitiveComparator) { .then(compareBy(nullsLast(CaseInsensitiveComparator)) {
directoryStructure.getUsernameFor(it.file) directoryStructure.getUsernameFor(it.file)
}) })
} }

View file

@ -19,6 +19,7 @@ import com.github.ajalt.timberkt.Timber.tag
import com.github.ajalt.timberkt.e import com.github.ajalt.timberkt.e
import com.zeapo.pwdstore.PasswordEntry import com.zeapo.pwdstore.PasswordEntry
import com.zeapo.pwdstore.R import com.zeapo.pwdstore.R
import com.zeapo.pwdstore.utils.PasswordRepository
import java.io.File import java.io.File
import java.security.MessageDigest import java.security.MessageDigest
@ -100,7 +101,10 @@ private fun makeRemoteView(
fun makeFillMatchRemoteView(context: Context, file: File, formOrigin: FormOrigin): RemoteViews { fun makeFillMatchRemoteView(context: Context, file: File, formOrigin: FormOrigin): RemoteViews {
val title = formOrigin.getPrettyIdentifier(context, untrusted = false) val title = formOrigin.getPrettyIdentifier(context, untrusted = false)
val summary = AutofillPreferences.directoryStructure(context).getUsernameFor(file) val directoryStructure = AutofillPreferences.directoryStructure(context)
val relativeFile = file.relativeTo(PasswordRepository.getRepositoryDirectory(context))
val summary = directoryStructure.getUsernameFor(relativeFile)
?: directoryStructure.getPathToIdentifierFor(relativeFile) ?: ""
val iconRes = R.drawable.ic_person_black_24dp val iconRes = R.drawable.ic_person_black_24dp
return makeRemoteView(context, title, summary, iconRes) return makeRemoteView(context, title, summary, iconRes)
} }

View file

@ -16,6 +16,7 @@ private val Context.defaultSharedPreferences: SharedPreferences
get() = PreferenceManager.getDefaultSharedPreferences(this) get() = PreferenceManager.getDefaultSharedPreferences(this)
enum class DirectoryStructure(val value: String) { enum class DirectoryStructure(val value: String) {
EncryptedUsername("encrypted_username"),
FileBased("file"), FileBased("file"),
DirectoryBased("directory"); DirectoryBased("directory");
@ -24,11 +25,13 @@ enum class DirectoryStructure(val value: String) {
* [DirectoryStructure]. * [DirectoryStructure].
* *
* Examples: * Examples:
* - * --> null (EncryptedUsername)
* - work/example.org/john@doe.org.gpg --> john@doe.org (FileBased) * - work/example.org/john@doe.org.gpg --> john@doe.org (FileBased)
* - work/example.org/john@doe.org/password.gpg --> john@doe.org (DirectoryBased) * - work/example.org/john@doe.org/password.gpg --> john@doe.org (DirectoryBased)
* - Temporary PIN.gpg --> Temporary PIN (DirectoryBased, fallback) * - Temporary PIN.gpg --> Temporary PIN (DirectoryBased, fallback)
*/ */
fun getUsernameFor(file: File): String = when (this) { fun getUsernameFor(file: File): String? = when (this) {
EncryptedUsername -> null
FileBased -> file.nameWithoutExtension FileBased -> file.nameWithoutExtension
DirectoryBased -> file.parentFile?.name ?: file.nameWithoutExtension DirectoryBased -> file.parentFile?.name ?: file.nameWithoutExtension
} }
@ -41,12 +44,14 @@ enum class DirectoryStructure(val value: String) {
* [DirectoryStructure.getAccountPartFor] will always return a non-null result. * [DirectoryStructure.getAccountPartFor] will always return a non-null result.
* *
* Examples: * Examples:
* - work/example.org.gpg --> example.org (EncryptedUsername)
* - work/example.org/john@doe.org.gpg --> example.org (FileBased) * - work/example.org/john@doe.org.gpg --> example.org (FileBased)
* - example.org.gpg --> example.org (FileBased, fallback) * - example.org.gpg --> example.org (FileBased, fallback)
* - work/example.org/john@doe.org/password.gpg --> example.org (DirectoryBased) * - work/example.org/john@doe.org/password.gpg --> example.org (DirectoryBased)
* - Temporary PIN.gpg --> null (DirectoryBased) * - Temporary PIN.gpg --> null (DirectoryBased)
*/ */
fun getIdentifierFor(file: File): String? = when (this) { fun getIdentifierFor(file: File): String? = when (this) {
EncryptedUsername -> file.nameWithoutExtension
FileBased -> file.parentFile?.name ?: file.nameWithoutExtension FileBased -> file.parentFile?.name ?: file.nameWithoutExtension
DirectoryBased -> file.parentFile?.parent DirectoryBased -> file.parentFile?.parent
} }
@ -55,10 +60,8 @@ enum class DirectoryStructure(val value: String) {
* Returns the path components of [file] until right before the component that contains the * Returns the path components of [file] until right before the component that contains the
* origin identifier according to the current [DirectoryStructure]. * origin identifier according to the current [DirectoryStructure].
* *
* At least one of [DirectoryStructure.getIdentifierFor] and
* [DirectoryStructure.getAccountPartFor] will always return a non-null result.
*
* Examples: * Examples:
* - work/example.org.gpg --> work (EncryptedUsername)
* - work/example.org/john@doe.org.gpg --> work (FileBased) * - work/example.org/john@doe.org.gpg --> work (FileBased)
* - example.org/john@doe.org.gpg --> null (FileBased) * - example.org/john@doe.org.gpg --> null (FileBased)
* - john@doe.org.gpg --> null (FileBased) * - john@doe.org.gpg --> null (FileBased)
@ -66,6 +69,7 @@ enum class DirectoryStructure(val value: String) {
* - example.org/john@doe.org/password.gpg --> null (DirectoryBased) * - example.org/john@doe.org/password.gpg --> null (DirectoryBased)
*/ */
fun getPathToIdentifierFor(file: File): String? = when (this) { fun getPathToIdentifierFor(file: File): String? = when (this) {
EncryptedUsername -> file.parent
FileBased -> file.parentFile?.parent FileBased -> file.parentFile?.parent
DirectoryBased -> file.parentFile?.parentFile?.parent DirectoryBased -> file.parentFile?.parentFile?.parent
} }
@ -74,13 +78,18 @@ enum class DirectoryStructure(val value: String) {
* Returns the path component of [file] following the origin identifier according to the current * Returns the path component of [file] following the origin identifier according to the current
* [DirectoryStructure] (without file extension). * [DirectoryStructure] (without file extension).
* *
* At least one of [DirectoryStructure.getIdentifierFor] and
* [DirectoryStructure.getAccountPartFor] will always return a non-null result.
*
* Examples: * Examples:
* - * --> null (EncryptedUsername)
* - work/example.org/john@doe.org.gpg --> john@doe.org (FileBased) * - work/example.org/john@doe.org.gpg --> john@doe.org (FileBased)
* - example.org.gpg --> null (FileBased, fallback) * - example.org.gpg --> null (FileBased, fallback)
* - work/example.org/john@doe.org/password.gpg --> john@doe.org/password (DirectoryBased) * - work/example.org/john@doe.org/password.gpg --> john@doe.org/password (DirectoryBased)
* - Temporary PIN.gpg --> Temporary PIN (DirectoryBased, fallback) * - Temporary PIN.gpg --> Temporary PIN (DirectoryBased, fallback)
*/ */
fun getAccountPartFor(file: File): String? = when (this) { fun getAccountPartFor(file: File): String? = when (this) {
EncryptedUsername -> null
FileBased -> file.nameWithoutExtension.takeIf { file.parentFile != null } FileBased -> file.nameWithoutExtension.takeIf { file.parentFile != null }
DirectoryBased -> file.parentFile?.let { parentFile -> DirectoryBased -> file.parentFile?.let { parentFile ->
"${parentFile.name}/${file.nameWithoutExtension}" "${parentFile.name}/${file.nameWithoutExtension}"
@ -89,11 +98,13 @@ enum class DirectoryStructure(val value: String) {
@RequiresApi(Build.VERSION_CODES.O) @RequiresApi(Build.VERSION_CODES.O)
fun getSaveFolderName(sanitizedIdentifier: String, username: String?) = when (this) { fun getSaveFolderName(sanitizedIdentifier: String, username: String?) = when (this) {
EncryptedUsername -> "/"
FileBased -> sanitizedIdentifier FileBased -> sanitizedIdentifier
DirectoryBased -> Paths.get(sanitizedIdentifier, username ?: "username").toString() DirectoryBased -> Paths.get(sanitizedIdentifier, username ?: "username").toString()
} }
fun getSaveFileName(username: String?) = when (this) { fun getSaveFileName(username: String?, identifier: String) = when (this) {
EncryptedUsername -> identifier
FileBased -> username FileBased -> username
DirectoryBased -> "password" DirectoryBased -> "password"
} }

View file

@ -60,7 +60,7 @@ class AutofillSaveActivity : Activity() {
sanitizedIdentifier = sanitizedIdentifier, sanitizedIdentifier = sanitizedIdentifier,
username = credentials?.username username = credentials?.username
) )
val fileName = directoryStructure.getSaveFileName(username = credentials?.username) val fileName = directoryStructure.getSaveFileName(username = credentials?.username, identifier = identifier)
val intent = Intent(context, AutofillSaveActivity::class.java).apply { val intent = Intent(context, AutofillSaveActivity::class.java).apply {
putExtras( putExtras(
bundleOf( bundleOf(

View file

@ -52,10 +52,12 @@
<item>xkpasswd</item> <item>xkpasswd</item>
</string-array> </string-array>
<string-array name="oreo_autofill_directory_structure_entries"> <string-array name="oreo_autofill_directory_structure_entries">
<item>/example.org/john@doe.org(.gpg)</item> <item>work/example.org(.gpg)</item>
<item>/example.org/john@doe.org/password(.gpg)</item> <item>work/example.org/john@doe.org(.gpg)</item>
<item>work/example.org/john@doe.org/password(.gpg)</item>
</string-array> </string-array>
<string-array name="oreo_autofill_directory_structure_values"> <string-array name="oreo_autofill_directory_structure_values">
<item>encrypted_username</item>
<item>file</item> <item>file</item>
<item>directory</item> <item>directory</item>
</string-array> </string-array>