diff --git a/app/src/main/java/com/zeapo/pwdstore/Migrations.kt b/app/src/main/java/com/zeapo/pwdstore/Migrations.kt index 64220aed..1922814c 100644 --- a/app/src/main/java/com/zeapo/pwdstore/Migrations.kt +++ b/app/src/main/java/com/zeapo/pwdstore/Migrations.kt @@ -12,14 +12,17 @@ import com.github.ajalt.timberkt.e import com.github.ajalt.timberkt.i import com.zeapo.pwdstore.git.config.GitSettings import com.zeapo.pwdstore.git.config.Protocol +import com.zeapo.pwdstore.git.sshj.SshKey import com.zeapo.pwdstore.utils.PreferenceKeys import com.zeapo.pwdstore.utils.getString import com.zeapo.pwdstore.utils.sharedPrefs +import java.io.File import java.net.URI fun runMigrations(context: Context) { migrateToGitUrlBasedConfig(context) migrateToHideAll(context) + migrateToSshKey(context) } private fun migrateToGitUrlBasedConfig(context: Context) { @@ -94,3 +97,19 @@ private fun migrateToHideAll(context: Context) { putBoolean(PreferenceKeys.SHOW_HIDDEN_CONTENTS, isHidden) } } + +private fun migrateToSshKey(context: Context) { + val privateKeyFile = File(context.filesDir, ".ssh_key") + if (context.sharedPrefs.contains(PreferenceKeys.USE_GENERATED_KEY) && + !SshKey.exists && + privateKeyFile.exists()) { + // Currently uses a private key imported or generated with an old version of Password Store. + // Generated keys come with a public key which the user should still be able to view after + // the migration (not possible for regular imported keys), hence the special case. + val isGeneratedKey = context.sharedPrefs.getBoolean(PreferenceKeys.USE_GENERATED_KEY, false) + SshKey.useLegacyKey(isGeneratedKey) + context.sharedPrefs.edit { + remove(PreferenceKeys.USE_GENERATED_KEY) + } + } +} diff --git a/app/src/main/java/com/zeapo/pwdstore/PasswordStore.kt b/app/src/main/java/com/zeapo/pwdstore/PasswordStore.kt index 56a6b949..284785bf 100644 --- a/app/src/main/java/com/zeapo/pwdstore/PasswordStore.kt +++ b/app/src/main/java/com/zeapo/pwdstore/PasswordStore.kt @@ -46,7 +46,6 @@ import com.zeapo.pwdstore.crypto.BasePgpActivity.Companion.getLongName import com.zeapo.pwdstore.crypto.DecryptActivity import com.zeapo.pwdstore.crypto.PasswordCreationActivity import com.zeapo.pwdstore.git.BaseGitActivity -import com.zeapo.pwdstore.git.GitServerConfigActivity import com.zeapo.pwdstore.git.config.AuthMode import com.zeapo.pwdstore.git.config.GitSettings import com.zeapo.pwdstore.ui.dialogs.FolderCreationDialogFragment @@ -89,12 +88,6 @@ class PasswordStore : BaseGitActivity() { ViewModelProvider.AndroidViewModelFactory(application) } - private val listRefreshAction = registerForActivityResult(StartActivityForResult()) { result -> - if (result.resultCode == RESULT_OK) { - refreshPasswordList() - } - } - override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { // open search view on search key, or Ctr+F if ((keyCode == KeyEvent.KEYCODE_SEARCH || keyCode == KeyEvent.KEYCODE_F && event.isCtrlPressed) && 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 7e9b1496..dd8ea731 100644 --- a/app/src/main/java/com/zeapo/pwdstore/git/BaseGitActivity.kt +++ b/app/src/main/java/com/zeapo/pwdstore/git/BaseGitActivity.kt @@ -10,8 +10,8 @@ import com.github.ajalt.timberkt.Timber.tag import com.github.ajalt.timberkt.d import com.github.ajalt.timberkt.e import com.github.michaelbull.result.Err -import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.github.michaelbull.result.Result +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.zeapo.pwdstore.R import com.zeapo.pwdstore.git.config.GitSettings import com.zeapo.pwdstore.git.operation.BreakOutOfDetached diff --git a/app/src/main/java/com/zeapo/pwdstore/git/GitCommandExecutor.kt b/app/src/main/java/com/zeapo/pwdstore/git/GitCommandExecutor.kt index 8d8648bf..6ef09537 100644 --- a/app/src/main/java/com/zeapo/pwdstore/git/GitCommandExecutor.kt +++ b/app/src/main/java/com/zeapo/pwdstore/git/GitCommandExecutor.kt @@ -7,6 +7,7 @@ package com.zeapo.pwdstore.git import android.widget.Toast import androidx.fragment.app.FragmentActivity +import com.github.michaelbull.result.Result import com.google.android.material.snackbar.Snackbar import com.zeapo.pwdstore.R import com.zeapo.pwdstore.git.GitException.PullException @@ -14,7 +15,6 @@ import com.zeapo.pwdstore.git.GitException.PushException import com.zeapo.pwdstore.git.config.GitSettings import com.zeapo.pwdstore.git.operation.GitOperation import com.zeapo.pwdstore.utils.snackbar -import com.github.michaelbull.result.Result import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import org.eclipse.jgit.api.CommitCommand diff --git a/app/src/main/java/com/zeapo/pwdstore/git/sshj/SshKey.kt b/app/src/main/java/com/zeapo/pwdstore/git/sshj/SshKey.kt index 8b657040..da49111e 100644 --- a/app/src/main/java/com/zeapo/pwdstore/git/sshj/SshKey.kt +++ b/app/src/main/java/com/zeapo/pwdstore/git/sshj/SshKey.kt @@ -76,7 +76,7 @@ object SshKey { val sshPublicKey get() = if (publicKeyFile.exists()) publicKeyFile.readText() else null val canShowSshPublicKey - get() = type in listOf(Type.KeystoreNative, Type.KeystoreWrappedEd25519) + get() = type in listOf(Type.LegacyGenerated, Type.KeystoreNative, Type.KeystoreWrappedEd25519) val exists get() = type != null val mustAuthenticate: Boolean @@ -128,6 +128,9 @@ object SshKey { Imported("imported"), KeystoreNative("keystore_native"), KeystoreWrappedEd25519("keystore_wrapped_ed25519"), + + // Behaves like `Imported`, but allows to view the public key. + LegacyGenerated("legacy_generated"), ; companion object { @@ -204,6 +207,11 @@ object SshKey { type = Type.Imported } + @Deprecated("To be used only in Migrations.kt") + fun useLegacyKey(isGenerated: Boolean) { + type = if (isGenerated) Type.LegacyGenerated else Type.Imported + } + @Suppress("BlockingMethodInNonBlockingContext") private suspend fun getOrCreateWrappingMasterKey(requireAuthentication: Boolean) = withContext(Dispatchers.IO) { MasterKey.Builder(context, KEYSTORE_ALIAS).run { @@ -268,7 +276,7 @@ object SshKey { } fun provide(client: SSHClient, passphraseFinder: InteractivePasswordFinder): KeyProvider? = when (type) { - Type.Imported -> client.loadKeys(privateKeyFile.absolutePath, passphraseFinder) + Type.LegacyGenerated, Type.Imported -> client.loadKeys(privateKeyFile.absolutePath, passphraseFinder) Type.KeystoreNative -> KeystoreNativeKeyProvider Type.KeystoreWrappedEd25519 -> KeystoreWrappedEd25519KeyProvider null -> null diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRepository.kt b/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRepository.kt index 3d0d4606..662210b2 100644 --- a/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRepository.kt +++ b/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRepository.kt @@ -178,7 +178,7 @@ open class PasswordRepository protected constructor() { val dir = getRepositoryDirectory() // uninitialize the repo if the dir does not exist or is absolutely empty settings.edit { - if (!dir.exists() || !dir.isDirectory || dir.listFiles()?.isEmpty() == true) { + if (!dir.exists() || !dir.isDirectory || requireNotNull(dir.listFiles()).isEmpty()) { putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, false) } else { putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, true) 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 5925809c..8180ccc0 100644 --- a/app/src/main/java/com/zeapo/pwdstore/utils/PreferenceKeys.kt +++ b/app/src/main/java/com/zeapo/pwdstore/utils/PreferenceKeys.kt @@ -76,4 +76,7 @@ object PreferenceKeys { const val SSH_OPENKEYSTORE_CLEAR_KEY_ID = "ssh_openkeystore_clear_keyid" const val SSH_OPENKEYSTORE_KEYID = "ssh_openkeystore_keyid" const val SSH_SEE_KEY = "ssh_see_key" + + @Deprecated("To be used only in Migrations.kt") + const val USE_GENERATED_KEY = "use_generated_key" }