Revert "feat: put new SSH layer behind a feature flag"

This reverts commit fb8d74fc1f01c73a4afc3003978ac4ad86e7b890.
This commit is contained in:
Harsh Shandilya 2023-12-15 17:34:19 +05:30
parent 424f654be0
commit 4d5b32d98b
No known key found for this signature in database
9 changed files with 32 additions and 127 deletions

View File

@ -15,6 +15,7 @@ import androidx.fragment.app.FragmentActivity
import app.passwordstore.R
import app.passwordstore.data.repo.PasswordRepository
import app.passwordstore.injection.prefs.GitPreferences
import app.passwordstore.ssh.SSHKeyManager
import app.passwordstore.ui.git.config.GitConfigActivity
import app.passwordstore.ui.git.config.GitServerConfigActivity
import app.passwordstore.ui.proxy.ProxySelectorActivity
@ -28,7 +29,6 @@ import app.passwordstore.util.extensions.snackbar
import app.passwordstore.util.extensions.unsafeLazy
import app.passwordstore.util.settings.GitSettings
import app.passwordstore.util.settings.PreferenceKeys
import app.passwordstore.util.ssh.SSHFacade
import com.github.michaelbull.result.onFailure
import com.github.michaelbull.result.runCatching
import com.google.android.material.dialog.MaterialAlertDialogBuilder
@ -44,11 +44,11 @@ import de.Maxr1998.modernpreferences.helpers.switch
class RepositorySettings(
private val activity: FragmentActivity,
private val sshFacade: SSHFacade,
private val sshKeyManager: SSHKeyManager,
) : SettingsProvider {
private val generateSshKey =
activity.registerForActivityResult(StartActivityForResult()) {
showSshKeyPref?.visible = sshFacade.canShowPublicKey()
showSshKeyPref?.visible = sshKeyManager.canShowPublicKey()
}
private val hiltEntryPoint by unsafeLazy {
@ -113,7 +113,7 @@ class RepositorySettings(
showSshKeyPref =
pref(PreferenceKeys.SSH_SEE_KEY) {
titleRes = R.string.pref_ssh_see_key_title
visible = PasswordRepository.isGitRepo() && sshFacade.canShowPublicKey()
visible = PasswordRepository.isGitRepo() && sshKeyManager.canShowPublicKey()
onClick {
ShowSshKeyFragment().show(activity.supportFragmentManager, "public_key")
true

View File

@ -11,8 +11,8 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.os.BundleCompat
import app.passwordstore.R
import app.passwordstore.databinding.ActivityPreferenceRecyclerviewBinding
import app.passwordstore.ssh.SSHKeyManager
import app.passwordstore.util.extensions.viewBinding
import app.passwordstore.util.ssh.SSHFacade
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint
import de.Maxr1998.modernpreferences.Preference
@ -24,7 +24,7 @@ import javax.inject.Inject
@AndroidEntryPoint
class SettingsActivity : AppCompatActivity() {
@Inject lateinit var sshFacade: SSHFacade
@Inject lateinit var sshKeyManager: SSHKeyManager
private lateinit var repositorySettings: RepositorySettings
private val miscSettings = MiscSettings(this)
private val autofillSettings = AutofillSettings(this)
@ -40,7 +40,7 @@ class SettingsActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
setContentView(binding.root)
Preference.Config.dialogBuilderFactory = { context -> MaterialAlertDialogBuilder(context) }
repositorySettings = RepositorySettings(this, sshFacade)
repositorySettings = RepositorySettings(this, sshKeyManager)
val screen =
screen(this) {
subScreen {

View File

@ -9,7 +9,7 @@ import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.DialogFragment
import app.passwordstore.R
import app.passwordstore.util.ssh.SSHFacade
import app.passwordstore.ssh.SSHKeyManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@ -17,11 +17,11 @@ import javax.inject.Inject
@AndroidEntryPoint
class ShowSshKeyFragment : DialogFragment() {
@Inject lateinit var sshFacade: SSHFacade
@Inject lateinit var sshKeyManager: SSHKeyManager
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val activity = requireActivity()
val publicKey = sshFacade.publicKey()
val publicKey = sshKeyManager.publicKey()
return MaterialAlertDialogBuilder(requireActivity()).run {
setMessage(getString(R.string.ssh_keygen_message, publicKey))
setTitle(R.string.your_public_key)

View File

@ -18,12 +18,12 @@ import app.passwordstore.R
import app.passwordstore.databinding.ActivitySshKeygenBinding
import app.passwordstore.injection.prefs.GitPreferences
import app.passwordstore.ssh.SSHKeyAlgorithm
import app.passwordstore.ssh.SSHKeyManager
import app.passwordstore.util.auth.BiometricAuthenticator
import app.passwordstore.util.auth.BiometricAuthenticator.Result
import app.passwordstore.util.coroutines.DispatcherProvider
import app.passwordstore.util.extensions.keyguardManager
import app.passwordstore.util.extensions.viewBinding
import app.passwordstore.util.ssh.SSHFacade
import com.github.michaelbull.result.fold
import com.github.michaelbull.result.runCatching
import com.google.android.material.dialog.MaterialAlertDialogBuilder
@ -40,7 +40,7 @@ class SshKeyGenActivity : AppCompatActivity() {
private var sshKeyAlgorithm = SSHKeyAlgorithm.ECDSA
private val binding by viewBinding(ActivitySshKeygenBinding::inflate)
@GitPreferences @Inject lateinit var gitPrefs: SharedPreferences
@Inject lateinit var sshFacade: SSHFacade
@Inject lateinit var sshKeyManager: SSHKeyManager
@Inject lateinit var dispatcherProvider: DispatcherProvider
override fun onCreate(savedInstanceState: Bundle?) {
@ -49,7 +49,7 @@ class SshKeyGenActivity : AppCompatActivity() {
supportActionBar?.setDisplayHomeAsUpEnabled(true)
with(binding) {
generate.setOnClickListener {
if (sshFacade.keyExists()) {
if (sshKeyManager.keyExists()) {
MaterialAlertDialogBuilder(this@SshKeyGenActivity).run {
setTitle(R.string.ssh_keygen_existing_title)
setMessage(R.string.ssh_keygen_existing_message)
@ -127,7 +127,7 @@ class SshKeyGenActivity : AppCompatActivity() {
if (result !is Result.Success)
throw UserNotAuthenticatedException(getString(R.string.biometric_auth_generic_failure))
}
sshFacade.generateKey(sshKeyAlgorithm, requireAuthentication)
sshKeyManager.generateKey(sshKeyAlgorithm, requireAuthentication)
}
}
// Check if we still need this

View File

@ -12,7 +12,7 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import app.passwordstore.R
import app.passwordstore.util.ssh.SSHFacade
import app.passwordstore.ssh.SSHKeyManager
import com.github.michaelbull.result.onFailure
import com.github.michaelbull.result.runCatching
import com.google.android.material.dialog.MaterialAlertDialogBuilder
@ -23,7 +23,7 @@ import kotlinx.coroutines.launch
@AndroidEntryPoint
class SshKeyImportActivity : AppCompatActivity() {
@Inject lateinit var sshFacade: SSHFacade
@Inject lateinit var sshKeyManager: SSHKeyManager
private val sshKeyImportAction =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { uri: Uri? ->
@ -33,7 +33,7 @@ class SshKeyImportActivity : AppCompatActivity() {
}
runCatching {
lifecycleScope.launch {
sshFacade.importKey(uri)
sshKeyManager.importKey(uri)
Toast.makeText(
this@SshKeyImportActivity,
resources.getString(R.string.ssh_key_success_dialog_title),
@ -55,7 +55,7 @@ class SshKeyImportActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (sshFacade.keyExists()) {
if (sshKeyManager.keyExists()) {
MaterialAlertDialogBuilder(this@SshKeyImportActivity).run {
setTitle(R.string.ssh_keygen_existing_title)
setMessage(R.string.ssh_keygen_existing_message)

View File

@ -13,9 +13,6 @@ enum class Feature(
val configKey: String,
) {
/** Opt into the new SSH layer implemented as a freestanding module. */
EnableNewSSHLayer(false, "enable_new_ssh"),
/** Opt into a cache layer for PGP passphrases. */
EnablePGPPassphraseCache(false, "enable_gpg_passphrase_cache"),
}

View File

@ -9,6 +9,7 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentActivity
import app.passwordstore.R
import app.passwordstore.data.repo.PasswordRepository
import app.passwordstore.ssh.SSHKeyManager
import app.passwordstore.ui.sshkeygen.SshKeyGenActivity
import app.passwordstore.ui.sshkeygen.SshKeyImportActivity
import app.passwordstore.util.auth.BiometricAuthenticator
@ -22,7 +23,6 @@ import app.passwordstore.util.git.GitCommandExecutor
import app.passwordstore.util.git.sshj.SshAuthMethod
import app.passwordstore.util.git.sshj.SshjSessionFactory
import app.passwordstore.util.settings.AuthMode
import app.passwordstore.util.ssh.SSHFacade
import com.github.michaelbull.result.Err
import com.github.michaelbull.result.Ok
import com.github.michaelbull.result.Result
@ -71,7 +71,7 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) {
callingActivity.applicationContext,
GitOperationEntryPoint::class.java
)
private val sshFacade = hiltEntryPoint.sshFacade()
private val sshKeyManager = hiltEntryPoint.sshKeyManager()
protected val repository = PasswordRepository.repository!!
protected val git = Git(repository)
private val authActivity
@ -121,8 +121,7 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) {
authMethod: SshAuthMethod,
credentialsProvider: CredentialsProvider? = null
) {
sshSessionFactory =
SshjSessionFactory(authMethod, hostKeyFile, sshFacade, hiltEntryPoint.dispatcherProvider())
sshSessionFactory = SshjSessionFactory(authMethod, hostKeyFile, sshKeyManager, hiltEntryPoint.dispatcherProvider())
commands.filterIsInstance<TransportCommand<*, *>>().forEach { command ->
command.setTransportConfigCallback { transport: Transport ->
(transport as? SshTransport)?.sshSessionFactory = sshSessionFactory
@ -170,8 +169,8 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) {
suspend fun executeAfterAuthentication(authMode: AuthMode): Result<Unit, Throwable> {
when (authMode) {
AuthMode.SshKey ->
if (sshFacade.keyExists()) {
if (sshFacade.needsAuthentication()) {
if (sshKeyManager.keyExists()) {
if (sshKeyManager.needsAuthentication()) {
val result =
withContext(hiltEntryPoint.dispatcherProvider().main()) {
suspendCoroutine { cont ->
@ -248,7 +247,7 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) {
@EntryPoint
@InstallIn(SingletonComponent::class)
interface GitOperationEntryPoint {
fun sshFacade(): SSHFacade
fun sshKeyManager(): SSHKeyManager
fun dispatcherProvider(): DispatcherProvider
}

View File

@ -6,10 +6,10 @@ package app.passwordstore.util.git.sshj
import android.util.Base64
import androidx.appcompat.app.AppCompatActivity
import app.passwordstore.ssh.SSHKeyManager
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
import com.github.michaelbull.result.getOrElse
import com.github.michaelbull.result.runCatching
import java.io.File
@ -71,7 +71,7 @@ abstract class InteractivePasswordFinder(private val dispatcherProvider: Dispatc
class SshjSessionFactory(
private val authMethod: SshAuthMethod,
private val hostKeyFile: File,
private val sshFacade: SSHFacade,
private val sshKeyManager: SSHKeyManager,
private val dispatcherProvider: DispatcherProvider,
) : SshSessionFactory() {
@ -84,12 +84,10 @@ class SshjSessionFactory(
tms: Int
): RemoteSession {
return currentSession
?: SshjSession(uri, uri.user, authMethod, hostKeyFile, sshFacade, dispatcherProvider)
.connect()
.also {
logcat { "New SSH connection created" }
currentSession = it
}
?: SshjSession(uri, uri.user, authMethod, hostKeyFile, dispatcherProvider, sshKeyManager).connect().also {
logcat { "New SSH connection created" }
currentSession = it
}
}
fun close() {
@ -130,8 +128,8 @@ private class SshjSession(
private val username: String,
private val authMethod: SshAuthMethod,
private val hostKeyFile: File,
private val sshFacade: SSHFacade,
private val dispatcherProvider: DispatcherProvider,
private val sshKeyManager: SSHKeyManager,
) : RemoteSession {
private lateinit var ssh: SSHClient
@ -167,10 +165,7 @@ private class SshjSession(
is SshAuthMethod.SshKey -> {
val pubkeyAuth =
AuthPublickey(
sshFacade.keyProvider(
ssh,
CredentialFinder(authMethod.activity, AuthMode.SshKey, dispatcherProvider)
)
sshKeyManager.keyProvider(ssh, CredentialFinder(authMethod.activity, AuthMode.SshKey, dispatcherProvider))
)
ssh.auth(username, pubkeyAuth, passwordAuth)
}

View File

@ -1,86 +0,0 @@
package app.passwordstore.util.ssh
import android.net.Uri
import app.passwordstore.ssh.SSHKeyAlgorithm
import app.passwordstore.ssh.SSHKeyManager
import app.passwordstore.util.features.Feature
import app.passwordstore.util.features.Features
import app.passwordstore.util.git.operation.CredentialFinder
import app.passwordstore.util.git.sshj.SshKey
import javax.inject.Inject
import net.schmizz.sshj.SSHClient
import net.schmizz.sshj.userauth.keyprovider.KeyProvider
/** A wrapper around [SshKey] and [SSHKeyManager] to allow switching between them at runtime. */
class SSHFacade
@Inject
constructor(
private val features: Features,
private val sshKeyManager: SSHKeyManager,
) {
private val useNewSSH
get() = features.isEnabled(Feature.EnableNewSSHLayer)
fun canShowPublicKey(): Boolean {
return if (useNewSSH) {
sshKeyManager.canShowPublicKey()
} else {
SshKey.canShowSshPublicKey
}
}
fun publicKey(): String? {
return if (useNewSSH) {
sshKeyManager.publicKey()
} else {
SshKey.sshPublicKey
}
}
fun keyExists(): Boolean {
return if (useNewSSH) {
sshKeyManager.keyExists()
} else {
SshKey.exists
}
}
suspend fun generateKey(keyAlgorithm: SSHKeyAlgorithm, requireAuthentication: Boolean) {
if (useNewSSH) {
sshKeyManager.generateKey(keyAlgorithm, requireAuthentication)
} else {
when (keyAlgorithm) {
SSHKeyAlgorithm.RSA ->
SshKey.generateKeystoreNativeKey(SshKey.Algorithm.Rsa, requireAuthentication)
SSHKeyAlgorithm.ECDSA ->
SshKey.generateKeystoreNativeKey(SshKey.Algorithm.Ecdsa, requireAuthentication)
SSHKeyAlgorithm.ED25519 -> SshKey.generateKeystoreWrappedEd25519Key(requireAuthentication)
}
}
}
suspend fun importKey(uri: Uri) {
if (useNewSSH) {
sshKeyManager.importKey(uri)
} else {
SshKey.import(uri)
}
}
fun needsAuthentication(): Boolean {
return if (useNewSSH) {
sshKeyManager.needsAuthentication()
} else {
SshKey.mustAuthenticate
}
}
fun keyProvider(client: SSHClient, credentialFinder: CredentialFinder): KeyProvider? {
return if (useNewSSH) {
sshKeyManager.keyProvider(client, credentialFinder)
} else {
SshKey.provide(client, credentialFinder)
}
}
}