Improve Git server config activity (#1051)

This commit is contained in:
Fabian Henneke 2020-08-24 12:03:33 +02:00 committed by GitHub
parent cbe780f31c
commit d0b15cec49
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 94 additions and 44 deletions

View file

@ -9,9 +9,14 @@ All notable changes to this project will be documented in this file.
- Allow sorting by recently used - Allow sorting by recently used
- Add [Bromite](https://www.bromite.org/) and [Ungoogled Chromium](https://git.droidware.info/wchen342/ungoogled-chromium-android) to supported browsers list for Autofill - Add [Bromite](https://www.bromite.org/) and [Ungoogled Chromium](https://git.droidware.info/wchen342/ungoogled-chromium-android) to supported browsers list for Autofill
### Changed
- A descriptive error message is shown if no username is specified in the Git server settings
### Fixed ### Fixed
- Password creation UI will scroll if it does not fit on the screen - Password creation UI will scroll if it does not fit on the screen
- Git server protocol and authentication mode are only updated when explicitly saved
## [1.11.2] - 2020-08-24 ## [1.11.2] - 2020-08-24

View file

@ -8,6 +8,8 @@ package com.zeapo.pwdstore
import android.content.Context import android.content.Context
import androidx.core.content.edit import androidx.core.content.edit
import com.zeapo.pwdstore.git.config.ConnectionMode
import com.zeapo.pwdstore.git.config.Protocol
import com.zeapo.pwdstore.utils.PreferenceKeys import com.zeapo.pwdstore.utils.PreferenceKeys
import com.zeapo.pwdstore.utils.getString import com.zeapo.pwdstore.utils.getString
import com.zeapo.pwdstore.utils.sharedPrefs import com.zeapo.pwdstore.utils.sharedPrefs
@ -33,7 +35,8 @@ class MigrationsTest {
putString(PreferenceKeys.GIT_REMOTE_USERNAME, "msfjarvis") putString(PreferenceKeys.GIT_REMOTE_USERNAME, "msfjarvis")
putString(PreferenceKeys.GIT_REMOTE_LOCATION, "/mnt/disk3/pass-repo") putString(PreferenceKeys.GIT_REMOTE_LOCATION, "/mnt/disk3/pass-repo")
putString(PreferenceKeys.GIT_REMOTE_SERVER, "192.168.0.102") putString(PreferenceKeys.GIT_REMOTE_SERVER, "192.168.0.102")
putString(PreferenceKeys.GIT_REMOTE_PROTOCOL, "ssh://") putString(PreferenceKeys.GIT_REMOTE_PROTOCOL, Protocol.Ssh.pref)
putString(PreferenceKeys.GIT_REMOTE_AUTH, ConnectionMode.Password.pref)
} }
runMigrations(context) runMigrations(context)
checkOldKeysAreRemoved(context) checkOldKeysAreRemoved(context)
@ -51,7 +54,8 @@ class MigrationsTest {
putString(PreferenceKeys.GIT_REMOTE_USERNAME, "msfjarvis") putString(PreferenceKeys.GIT_REMOTE_USERNAME, "msfjarvis")
putString(PreferenceKeys.GIT_REMOTE_LOCATION, "/mnt/disk3/pass-repo") putString(PreferenceKeys.GIT_REMOTE_LOCATION, "/mnt/disk3/pass-repo")
putString(PreferenceKeys.GIT_REMOTE_SERVER, "192.168.0.102") putString(PreferenceKeys.GIT_REMOTE_SERVER, "192.168.0.102")
putString(PreferenceKeys.GIT_REMOTE_PROTOCOL, "ssh://") putString(PreferenceKeys.GIT_REMOTE_PROTOCOL, Protocol.Ssh.pref)
putString(PreferenceKeys.GIT_REMOTE_AUTH, ConnectionMode.SshKey.pref)
} }
runMigrations(context) runMigrations(context)
checkOldKeysAreRemoved(context) checkOldKeysAreRemoved(context)
@ -69,7 +73,8 @@ class MigrationsTest {
putString(PreferenceKeys.GIT_REMOTE_USERNAME, "msfjarvis") putString(PreferenceKeys.GIT_REMOTE_USERNAME, "msfjarvis")
putString(PreferenceKeys.GIT_REMOTE_LOCATION, "Android-Password-Store/pass-test") putString(PreferenceKeys.GIT_REMOTE_LOCATION, "Android-Password-Store/pass-test")
putString(PreferenceKeys.GIT_REMOTE_SERVER, "github.com") putString(PreferenceKeys.GIT_REMOTE_SERVER, "github.com")
putString(PreferenceKeys.GIT_REMOTE_PROTOCOL, "https://") putString(PreferenceKeys.GIT_REMOTE_PROTOCOL, Protocol.Https.pref)
putString(PreferenceKeys.GIT_REMOTE_AUTH, ConnectionMode.None.pref)
} }
runMigrations(context) runMigrations(context)
checkOldKeysAreRemoved(context) checkOldKeysAreRemoved(context)

View file

@ -76,7 +76,11 @@ private fun migrateToGitUrlBasedConfig(context: Context) {
remove(PreferenceKeys.GIT_REMOTE_SERVER) remove(PreferenceKeys.GIT_REMOTE_SERVER)
remove(PreferenceKeys.GIT_REMOTE_USERNAME) remove(PreferenceKeys.GIT_REMOTE_USERNAME)
} }
if (url == null || !GitSettings.updateUrlIfValid(url)) { if (url == null || GitSettings.updateConnectionSettingsIfValid(
newProtocol = protocol,
newConnectionMode = GitSettings.connectionMode,
newUrl = url,
newBranch = GitSettings.branch) != GitSettings.UpdateConnectionSettingsResult.Valid) {
e { "Failed to migrate to URL-based Git config, generated URL is invalid" } e { "Failed to migrate to URL-based Git config, generated URL is invalid" }
} }
} }

View file

@ -32,6 +32,9 @@ class GitServerConfigActivity : BaseGitActivity() {
private val binding by viewBinding(ActivityGitCloneBinding::inflate) private val binding by viewBinding(ActivityGitCloneBinding::inflate)
private lateinit var newProtocol: Protocol
private lateinit var newConnectionMode: ConnectionMode
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val isClone = intent?.extras?.getInt(REQUEST_ARG_OP) ?: -1 == REQUEST_CLONE val isClone = intent?.extras?.getInt(REQUEST_ARG_OP) ?: -1 == REQUEST_CLONE
@ -41,22 +44,26 @@ class GitServerConfigActivity : BaseGitActivity() {
setContentView(binding.root) setContentView(binding.root)
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
binding.cloneProtocolGroup.check(when (GitSettings.protocol) { newProtocol = GitSettings.protocol
Protocol.Ssh -> R.id.clone_protocol_ssh binding.cloneProtocolGroup.apply {
Protocol.Https -> R.id.clone_protocol_https when (newProtocol) {
}) Protocol.Ssh -> check(R.id.clone_protocol_ssh)
binding.cloneProtocolGroup.addOnButtonCheckedListener { _, checkedId, checked -> Protocol.Https -> check(R.id.clone_protocol_https)
if (checked) { }
when (checkedId) { addOnButtonCheckedListener { _, checkedId, checked ->
R.id.clone_protocol_https -> GitSettings.protocol = Protocol.Https if (checked) {
R.id.clone_protocol_ssh -> GitSettings.protocol = Protocol.Ssh when (checkedId) {
R.id.clone_protocol_https -> newProtocol = Protocol.Https
R.id.clone_protocol_ssh -> newProtocol = Protocol.Ssh
}
updateConnectionModeToggleGroup()
} }
updateConnectionModeToggleGroup()
} }
} }
newConnectionMode = GitSettings.connectionMode
binding.connectionModeGroup.apply { binding.connectionModeGroup.apply {
when (GitSettings.connectionMode) { when (newConnectionMode) {
ConnectionMode.SshKey -> check(R.id.connection_mode_ssh_key) ConnectionMode.SshKey -> check(R.id.connection_mode_ssh_key)
ConnectionMode.Password -> check(R.id.connection_mode_password) ConnectionMode.Password -> check(R.id.connection_mode_password)
ConnectionMode.OpenKeychain -> check(R.id.connection_mode_open_keychain) ConnectionMode.OpenKeychain -> check(R.id.connection_mode_open_keychain)
@ -64,10 +71,10 @@ class GitServerConfigActivity : BaseGitActivity() {
} }
addOnButtonCheckedListener { _, _, _ -> addOnButtonCheckedListener { _, _, _ ->
when (checkedButtonId) { when (checkedButtonId) {
R.id.connection_mode_ssh_key -> GitSettings.connectionMode = ConnectionMode.SshKey R.id.connection_mode_ssh_key -> newConnectionMode = ConnectionMode.SshKey
R.id.connection_mode_open_keychain -> GitSettings.connectionMode = ConnectionMode.OpenKeychain R.id.connection_mode_open_keychain -> newConnectionMode = ConnectionMode.OpenKeychain
R.id.connection_mode_password -> GitSettings.connectionMode = ConnectionMode.Password R.id.connection_mode_password -> newConnectionMode = ConnectionMode.Password
View.NO_ID -> GitSettings.connectionMode = ConnectionMode.None View.NO_ID -> newConnectionMode = ConnectionMode.None
} }
} }
} }
@ -77,36 +84,50 @@ class GitServerConfigActivity : BaseGitActivity() {
binding.serverBranch.setText(GitSettings.branch) binding.serverBranch.setText(GitSettings.branch)
binding.saveButton.setOnClickListener { binding.saveButton.setOnClickListener {
if (isClone && PasswordRepository.getRepository(null) == null) when (GitSettings.updateConnectionSettingsIfValid(
PasswordRepository.initialize() newProtocol = newProtocol,
GitSettings.branch = binding.serverBranch.text.toString().trim() newConnectionMode = newConnectionMode,
if (GitSettings.updateUrlIfValid(binding.serverUrl.text.toString().trim())) { newUrl = binding.serverUrl.text.toString().trim(),
if (!isClone) { newBranch = binding.serverBranch.text.toString().trim())) {
Snackbar.make(binding.root, getString(R.string.git_server_config_save_success), Snackbar.LENGTH_SHORT).show() GitSettings.UpdateConnectionSettingsResult.FailedToParseUrl -> {
Handler().postDelayed(500) { finish() } Snackbar.make(binding.root, getString(R.string.git_server_config_save_error), Snackbar.LENGTH_LONG).show()
} else { }
cloneRepository() GitSettings.UpdateConnectionSettingsResult.MissingUsername -> {
when (newProtocol) {
Protocol.Https -> Snackbar.make(binding.root, getString(R.string.git_server_config_save_missing_username_https), Snackbar.LENGTH_LONG).show()
Protocol.Ssh -> Snackbar.make(binding.root, getString(R.string.git_server_config_save_missing_username_ssh), Snackbar.LENGTH_LONG).show()
}
}
else -> {
if (isClone && PasswordRepository.getRepository(null) == null)
PasswordRepository.initialize()
if (!isClone) {
Snackbar.make(binding.root, getString(R.string.git_server_config_save_success), Snackbar.LENGTH_SHORT).show()
Handler().postDelayed(500) { finish() }
} else {
cloneRepository()
}
} }
} else {
Snackbar.make(binding.root, getString(R.string.git_server_config_save_error), Snackbar.LENGTH_LONG).show()
} }
} }
} }
private fun updateConnectionModeToggleGroup() { private fun updateConnectionModeToggleGroup() {
if (GitSettings.protocol == Protocol.Ssh) { if (newProtocol == Protocol.Ssh) {
// Reset connection mode to SSH key if the current value (none) is not valid for SSH
if (binding.connectionModeGroup.checkedButtonIds.isEmpty())
binding.connectionModeGroup.check(R.id.connection_mode_ssh_key)
binding.connectionModeSshKey.isEnabled = true binding.connectionModeSshKey.isEnabled = true
binding.connectionModeOpenKeychain.isEnabled = true binding.connectionModeOpenKeychain.isEnabled = true
// Reset connection mode to SSH key if the current value (none) is not valid for SSH.
// Important note: This has to happen after enabling the other toggle buttons or they
// won't check.
if (binding.connectionModeGroup.checkedButtonIds.isEmpty())
binding.connectionModeGroup.check(R.id.connection_mode_ssh_key)
binding.connectionModeGroup.isSelectionRequired = true binding.connectionModeGroup.isSelectionRequired = true
} else { } else {
binding.connectionModeGroup.isSelectionRequired = false binding.connectionModeGroup.isSelectionRequired = false
// Reset connection mode to password if the current value is not valid for HTTPS // Reset connection mode to password if the current value is not valid for HTTPS
// Important note: This has to happen before disabling the other toggle buttons or they // Important note: This has to happen before disabling the other toggle buttons or they
// won't uncheck. // won't uncheck.
if (GitSettings.connectionMode !in listOf(ConnectionMode.None, ConnectionMode.Password)) if (newConnectionMode !in listOf(ConnectionMode.None, ConnectionMode.Password))
binding.connectionModeGroup.check(R.id.connection_mode_password) binding.connectionModeGroup.check(R.id.connection_mode_password)
binding.connectionModeSshKey.isEnabled = false binding.connectionModeSshKey.isEnabled = false
binding.connectionModeOpenKeychain.isEnabled = false binding.connectionModeOpenKeychain.isEnabled = false

View file

@ -55,14 +55,14 @@ object GitSettings {
var protocol var protocol
get() = Protocol.fromString(settings.getString(PreferenceKeys.GIT_REMOTE_PROTOCOL)) get() = Protocol.fromString(settings.getString(PreferenceKeys.GIT_REMOTE_PROTOCOL))
set(value) { private set(value) {
settings.edit { settings.edit {
putString(PreferenceKeys.GIT_REMOTE_PROTOCOL, value.pref) putString(PreferenceKeys.GIT_REMOTE_PROTOCOL, value.pref)
} }
} }
var connectionMode var connectionMode
get() = ConnectionMode.fromString(settings.getString(PreferenceKeys.GIT_REMOTE_AUTH)) get() = ConnectionMode.fromString(settings.getString(PreferenceKeys.GIT_REMOTE_AUTH))
set(value) { private set(value) {
settings.edit { settings.edit {
putString(PreferenceKeys.GIT_REMOTE_AUTH, value.pref) putString(PreferenceKeys.GIT_REMOTE_AUTH, value.pref)
} }
@ -71,6 +71,8 @@ object GitSettings {
get() = settings.getString(PreferenceKeys.GIT_REMOTE_URL) get() = settings.getString(PreferenceKeys.GIT_REMOTE_URL)
private set(value) { private set(value) {
require(value != null) require(value != null)
if (value == url)
return
settings.edit { settings.edit {
putString(PreferenceKeys.GIT_REMOTE_URL, value) putString(PreferenceKeys.GIT_REMOTE_URL, value)
} }
@ -96,20 +98,31 @@ object GitSettings {
} }
var branch var branch
get() = settings.getString(PreferenceKeys.GIT_BRANCH_NAME) ?: DEFAULT_BRANCH get() = settings.getString(PreferenceKeys.GIT_BRANCH_NAME) ?: DEFAULT_BRANCH
set(value) { private set(value) {
settings.edit { settings.edit {
putString(PreferenceKeys.GIT_BRANCH_NAME, value) putString(PreferenceKeys.GIT_BRANCH_NAME, value)
} }
} }
fun updateUrlIfValid(newUrl: String): Boolean { enum class UpdateConnectionSettingsResult {
try { Valid,
FailedToParseUrl,
MissingUsername,
}
fun updateConnectionSettingsIfValid(newProtocol: Protocol, newConnectionMode: ConnectionMode, newUrl: String, newBranch: String): UpdateConnectionSettingsResult {
val parsedUrl = try {
URIish(newUrl) URIish(newUrl)
} catch (_: Exception) { } catch (_: Exception) {
return false return UpdateConnectionSettingsResult.FailedToParseUrl
} }
if (newUrl != url) if (newConnectionMode != ConnectionMode.None && parsedUrl.user.isNullOrBlank())
url = newUrl return UpdateConnectionSettingsResult.MissingUsername
return true
url = newUrl
protocol = newProtocol
connectionMode = newConnectionMode
branch = newBranch
return UpdateConnectionSettingsResult.Valid
} }
} }

View file

@ -328,6 +328,8 @@
<string name="connection_mode_openkeychain" translatable="false">OpenKeychain</string> <string name="connection_mode_openkeychain" translatable="false">OpenKeychain</string>
<string name="git_server_config_save_success">Successfully saved configuration</string> <string name="git_server_config_save_success">Successfully saved configuration</string>
<string name="git_server_config_save_error">The provided repository URL is not valid</string> <string name="git_server_config_save_error">The provided repository URL is not valid</string>
<string name="git_server_config_save_missing_username_https">Please specify the HTTPS username in the form https://username@example.com/…</string>
<string name="git_server_config_save_missing_username_ssh">Please specify the SSH username in the form username@example.com:…</string>
<string name="git_config_error_hostname_empty">empty hostname</string> <string name="git_config_error_hostname_empty">empty hostname</string>
<string name="git_config_error_generic">please verify your settings and try again</string> <string name="git_config_error_generic">please verify your settings and try again</string>
<string name="git_config_error_nonnumeric_port">port must be numeric</string> <string name="git_config_error_nonnumeric_port">port must be numeric</string>