diff options
author | Fabian Henneke <FabianHenneke@users.noreply.github.com> | 2020-08-26 16:21:27 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-08-26 19:51:27 +0530 |
commit | 8ec3320df793b58d20f632038b0b2a37f37103e3 (patch) | |
tree | cc376da0887c26b7f5929d8b64c304815fe8f387 /app | |
parent | ad17fa7cc5003cf362c74019afa13e9d28d0f4e7 (diff) |
Get rid of explicit Git server protocol (#1054)
* Double check Git server protocol
Ensure that the Git server protocol is not at odds with the URL scheme.
Also move the Protocol switches below the URL to make it clear that the
URL should be entered first.
* Remove protocol selection from server config
The protocol is now extracted from the URL, and the authentication mode selection is validated by GitSettings
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
* Don't use pref values for auth modes
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
* Apply suggestions from code review
Remove now unused protocol mismatch result type
Co-authored-by: Fabian Henneke <FabianHenneke@users.noreply.github.com>
* Simplify migration logic and fix tests
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
* Revert "Simplify migration logic and fix tests"
This reverts commit 1c4c4ba5fbc212843cb6b74dd29ac858eaea7582.
* Detect URLs with null scheme as ssh
* Add changelog entry
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
Co-authored-by: Harsh Shandilya <me@msfjarvis.dev>
Co-authored-by: Harsh Shandilya <msfjarvis@gmail.com>
Diffstat (limited to 'app')
7 files changed, 49 insertions, 107 deletions
diff --git a/app/src/androidTest/java/com/zeapo/pwdstore/MigrationsTest.kt b/app/src/androidTest/java/com/zeapo/pwdstore/MigrationsTest.kt index 531ceebf..c66bb215 100644 --- a/app/src/androidTest/java/com/zeapo/pwdstore/MigrationsTest.kt +++ b/app/src/androidTest/java/com/zeapo/pwdstore/MigrationsTest.kt @@ -24,6 +24,7 @@ class MigrationsTest { assertNull(getString(PreferenceKeys.GIT_REMOTE_USERNAME)) assertNull(getString(PreferenceKeys.GIT_REMOTE_SERVER)) assertNull(getString(PreferenceKeys.GIT_REMOTE_LOCATION)) + assertNull(getString(PreferenceKeys.GIT_REMOTE_PROTOCOL)) } @Test diff --git a/app/src/main/java/com/zeapo/pwdstore/Migrations.kt b/app/src/main/java/com/zeapo/pwdstore/Migrations.kt index cdf56bb3..7148ad7e 100644 --- a/app/src/main/java/com/zeapo/pwdstore/Migrations.kt +++ b/app/src/main/java/com/zeapo/pwdstore/Migrations.kt @@ -75,13 +75,12 @@ private fun migrateToGitUrlBasedConfig(context: Context) { remove(PreferenceKeys.GIT_REMOTE_PORT) remove(PreferenceKeys.GIT_REMOTE_SERVER) remove(PreferenceKeys.GIT_REMOTE_USERNAME) + remove(PreferenceKeys.GIT_REMOTE_PROTOCOL) } if (url == null || GitSettings.updateConnectionSettingsIfValid( - newProtocol = protocol, newAuthMode = GitSettings.authMode, newUrl = url, newBranch = GitSettings.branch) != GitSettings.UpdateConnectionSettingsResult.Valid) { e { "Failed to migrate to URL-based Git config, generated URL is invalid" } } } - diff --git a/app/src/main/java/com/zeapo/pwdstore/git/GitServerConfigActivity.kt b/app/src/main/java/com/zeapo/pwdstore/git/GitServerConfigActivity.kt index cd6747f7..5aa34201 100644 --- a/app/src/main/java/com/zeapo/pwdstore/git/GitServerConfigActivity.kt +++ b/app/src/main/java/com/zeapo/pwdstore/git/GitServerConfigActivity.kt @@ -32,7 +32,6 @@ class GitServerConfigActivity : BaseGitActivity() { private val binding by viewBinding(ActivityGitCloneBinding::inflate) - private lateinit var newProtocol: Protocol private lateinit var newAuthMode: AuthMode override fun onCreate(savedInstanceState: Bundle?) { @@ -44,24 +43,8 @@ class GitServerConfigActivity : BaseGitActivity() { setContentView(binding.root) supportActionBar?.setDisplayHomeAsUpEnabled(true) - newProtocol = GitSettings.protocol - binding.protocolGroup.apply { - when (newProtocol) { - Protocol.Ssh -> check(R.id.protocol_ssh) - Protocol.Https -> check(R.id.protocol_https) - } - addOnButtonCheckedListener { _, checkedId, checked -> - if (checked) { - when (checkedId) { - R.id.protocol_https -> newProtocol = Protocol.Https - R.id.protocol_ssh -> newProtocol = Protocol.Ssh - } - updateAuthModeToggleGroup() - } - } - } - newAuthMode = GitSettings.authMode + binding.authModeGroup.apply { when (newAuthMode) { AuthMode.SshKey -> check(R.id.auth_mode_ssh_key) @@ -78,27 +61,25 @@ class GitServerConfigActivity : BaseGitActivity() { } } } - updateAuthModeToggleGroup() binding.serverUrl.setText(GitSettings.url) binding.serverBranch.setText(GitSettings.branch) binding.saveButton.setOnClickListener { - when (GitSettings.updateConnectionSettingsIfValid( - newProtocol = newProtocol, + when (val updateResult = GitSettings.updateConnectionSettingsIfValid( newAuthMode = newAuthMode, newUrl = binding.serverUrl.text.toString().trim(), newBranch = binding.serverBranch.text.toString().trim())) { GitSettings.UpdateConnectionSettingsResult.FailedToParseUrl -> { Snackbar.make(binding.root, getString(R.string.git_server_config_save_error), Snackbar.LENGTH_LONG).show() } - GitSettings.UpdateConnectionSettingsResult.MissingUsername -> { - when (newProtocol) { + is GitSettings.UpdateConnectionSettingsResult.MissingUsername -> { + when (updateResult.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 -> { + GitSettings.UpdateConnectionSettingsResult.Valid -> { if (isClone && PasswordRepository.getRepository(null) == null) PasswordRepository.initialize() if (!isClone) { @@ -108,32 +89,18 @@ class GitServerConfigActivity : BaseGitActivity() { cloneRepository() } } + is GitSettings.UpdateConnectionSettingsResult.AuthModeMismatch -> { + val message = getString( + R.string.git_server_config_save_auth_mode_mismatch, + updateResult.newProtocol, + updateResult.validModes.joinToString(", "), + ) + Snackbar.make(binding.root, message, Snackbar.LENGTH_LONG).show() + } } } } - private fun updateAuthModeToggleGroup() { - if (newProtocol == Protocol.Ssh) { - binding.authModeSshKey.isEnabled = true - binding.authModeOpenKeychain.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.authModeGroup.checkedButtonIds.isEmpty()) - binding.authModeGroup.check(R.id.auth_mode_ssh_key) - binding.authModeGroup.isSelectionRequired = true - } else { - binding.authModeGroup.isSelectionRequired = false - // 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 - // won't uncheck. - if (newAuthMode !in listOf(AuthMode.None, AuthMode.Password)) - binding.authModeGroup.check(R.id.auth_mode_password) - binding.authModeSshKey.isEnabled = false - binding.authModeOpenKeychain.isEnabled = false - } - } - /** * Clones the repository, the directory exists, deletes it */ diff --git a/app/src/main/java/com/zeapo/pwdstore/git/config/GitSettings.kt b/app/src/main/java/com/zeapo/pwdstore/git/config/GitSettings.kt index b9c572fc..b0d931e0 100644 --- a/app/src/main/java/com/zeapo/pwdstore/git/config/GitSettings.kt +++ b/app/src/main/java/com/zeapo/pwdstore/git/config/GitSettings.kt @@ -53,13 +53,6 @@ object GitSettings { private val settings by lazy { Application.instance.sharedPrefs } private val encryptedSettings by lazy { Application.instance.getEncryptedPrefs("git_operation") } - var protocol - get() = Protocol.fromString(settings.getString(PreferenceKeys.GIT_REMOTE_PROTOCOL)) - private set(value) { - settings.edit { - putString(PreferenceKeys.GIT_REMOTE_PROTOCOL, value.pref) - } - } var authMode get() = AuthMode.fromString(settings.getString(PreferenceKeys.GIT_REMOTE_AUTH)) private set(value) { @@ -104,23 +97,39 @@ object GitSettings { } } - enum class UpdateConnectionSettingsResult { - Valid, - FailedToParseUrl, - MissingUsername, + sealed class UpdateConnectionSettingsResult { + class MissingUsername(val newProtocol: Protocol) : UpdateConnectionSettingsResult() + class AuthModeMismatch(val newProtocol: Protocol, val validModes: List<AuthMode>) : UpdateConnectionSettingsResult() + object Valid : UpdateConnectionSettingsResult() + object FailedToParseUrl : UpdateConnectionSettingsResult() } - fun updateConnectionSettingsIfValid(newProtocol: Protocol, newAuthMode: AuthMode, newUrl: String, newBranch: String): UpdateConnectionSettingsResult { + fun updateConnectionSettingsIfValid(newAuthMode: AuthMode, newUrl: String, newBranch: String): UpdateConnectionSettingsResult { val parsedUrl = try { URIish(newUrl) } catch (_: Exception) { return UpdateConnectionSettingsResult.FailedToParseUrl } + val newProtocol = when (parsedUrl.scheme) { + in listOf("http", "https") -> Protocol.Https + in listOf("ssh", null) -> Protocol.Ssh + else -> return UpdateConnectionSettingsResult.FailedToParseUrl + } if (newAuthMode != AuthMode.None && parsedUrl.user.isNullOrBlank()) - return UpdateConnectionSettingsResult.MissingUsername + return UpdateConnectionSettingsResult.MissingUsername(newProtocol) + + val validHttpsAuth = listOf(AuthMode.None, AuthMode.Password) + val validSshAuth = listOf(AuthMode.OpenKeychain, AuthMode.Password, AuthMode.SshKey) + when { + newProtocol == Protocol.Https && newAuthMode !in validHttpsAuth -> { + return UpdateConnectionSettingsResult.AuthModeMismatch(newProtocol, validHttpsAuth) + } + newProtocol == Protocol.Ssh && newAuthMode !in validSshAuth -> { + return UpdateConnectionSettingsResult.AuthModeMismatch(newProtocol, validSshAuth) + } + } url = newUrl - protocol = newProtocol authMode = newAuthMode branch = newBranch return UpdateConnectionSettingsResult.Valid 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 05fb9326..2bb48201 100644 --- a/app/src/main/java/com/zeapo/pwdstore/utils/PreferenceKeys.kt +++ b/app/src/main/java/com/zeapo/pwdstore/utils/PreferenceKeys.kt @@ -32,6 +32,7 @@ object PreferenceKeys { const val GIT_REMOTE_LOCATION = "git_remote_location" @Deprecated("Use GIT_REMOTE_URL instead") const val GIT_REMOTE_PORT = "git_remote_port" + @Deprecated("Use GIT_REMOTE_URL instead") const val GIT_REMOTE_PROTOCOL = "git_remote_protocol" const val GIT_DELETE_REPO = "git_delete_repo" @Deprecated("Use GIT_REMOTE_URL instead") diff --git a/app/src/main/res/layout/activity_git_clone.xml b/app/src/main/res/layout/activity_git_clone.xml index f16bda94..b7ec6fc1 100644 --- a/app/src/main/res/layout/activity_git_clone.xml +++ b/app/src/main/res/layout/activity_git_clone.xml @@ -29,42 +29,6 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> - <androidx.appcompat.widget.AppCompatTextView - android:id="@+id/label_server_protocol" - style="@style/TextAppearance.MaterialComponents.Headline6" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_margin="8dp" - android:text="@string/server_protocol" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/server_label" /> - - <com.google.android.material.button.MaterialButtonToggleGroup - android:id="@+id/protocol_group" - style="@style/TextAppearance.MaterialComponents.Headline1" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_margin="8dp" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/label_server_protocol" - app:selectionRequired="true" - app:singleSelection="true"> - - <com.google.android.material.button.MaterialButton - android:id="@+id/protocol_ssh" - style="?attr/materialButtonOutlinedStyle" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/clone_protocol_ssh" /> - - <com.google.android.material.button.MaterialButton - android:id="@+id/protocol_https" - style="?attr/materialButtonOutlinedStyle" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/clone_protocol_https" /> - </com.google.android.material.button.MaterialButtonToggleGroup> - <com.google.android.material.textfield.TextInputLayout android:id="@+id/label_server_url" android:layout_width="0dp" @@ -73,15 +37,15 @@ android:hint="@string/server_url" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/protocol_group"> + app:layout_constraintTop_toBottomOf="@id/server_label"> <com.google.android.material.textfield.TextInputEditText android:id="@+id/server_url" android:layout_width="match_parent" android:layout_height="wrap_content" android:imeOptions="actionNext" - android:nextFocusForward="@id/server_branch" - android:inputType="textWebEmailAddress" /> + android:inputType="textWebEmailAddress" + android:nextFocusForward="@id/server_branch" /> </com.google.android.material.textfield.TextInputLayout> @@ -91,21 +55,21 @@ android:layout_height="wrap_content" android:layout_margin="8dp" android:hint="@string/server_branch" - app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/label_server_url"> <com.google.android.material.textfield.TextInputEditText android:id="@+id/server_branch" - android:imeOptions="actionDone" android:layout_width="match_parent" - android:inputType="textNoSuggestions" - android:layout_height="wrap_content" /> + android:layout_height="wrap_content" + android:imeOptions="actionDone" + android:inputType="textNoSuggestions" /> </com.google.android.material.textfield.TextInputLayout> <androidx.appcompat.widget.AppCompatTextView - android:id="@+id/label_connection_mode" + android:id="@+id/label_auth_mode" style="@style/TextAppearance.MaterialComponents.Headline6" android:layout_width="wrap_content" android:layout_height="wrap_content" @@ -123,7 +87,7 @@ android:layout_height="wrap_content" android:layout_margin="8dp" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/label_connection_mode" + app:layout_constraintTop_toBottomOf="@id/label_auth_mode" app:singleSelection="true"> <com.google.android.material.button.MaterialButton diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 86e1c722..f27224ff 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -330,6 +330,7 @@ <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_server_config_save_auth_mode_mismatch">Valid authentication modes for %1$s: %2$s</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_nonnumeric_port">port must be numeric</string> |