Skip to content
This repository was archived by the owner on Oct 15, 2024. It is now read-only.

Commit 96b51e7

Browse files
committed
Better guidance for users to deal with host key changes (#1242)
* Provide actionable guidance for host key mismatches Signed-off-by: Harsh Shandilya <[email protected]> * Update changelog Signed-off-by: Harsh Shandilya <[email protected]> * Hide host key clear button after use Signed-off-by: Harsh Shandilya <[email protected]> (cherry picked from commit ce2e657) Signed-off-by: Harsh Shandilya <[email protected]>
1 parent 31ec316 commit 96b51e7

File tree

6 files changed

+44
-1
lines changed

6 files changed

+44
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ All notable changes to this project will be documented in this file.
1616
- Decrypt screen would stay in memory infinitely, allowing passwords to be seen without re-auth
1717
- Git commits in the store would wrongly use the 'default' committer as opposed to the user's configured one
1818
- Connection attempts now use a reasonable 10 second timeout as opposed to the default of 30 seconds
19+
- A change to the remote host key for a server would prevent the user from being able to connect to it
1920

2021
## [1.13.1] - 2020-10-23
2122

app/src/main/java/com/zeapo/pwdstore/git/BaseGitActivity.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import kotlinx.coroutines.Dispatchers
2828
import kotlinx.coroutines.withContext
2929
import net.schmizz.sshj.common.DisconnectReason
3030
import net.schmizz.sshj.common.SSHException
31+
import net.schmizz.sshj.transport.TransportException
3132
import net.schmizz.sshj.userauth.UserAuthException
3233

3334
/**
@@ -74,6 +75,10 @@ abstract class BaseGitActivity : ContinuationContainerActivity() {
7475
if (err.message?.contains("cannot open additional channels") == true) {
7576
GitSettings.useMultiplexing = false
7677
SSHException(DisconnectReason.TOO_MANY_CONNECTIONS, "The server does not support multiple Git operations per SSH session. Please try again, a slower fallback mode will be used.")
78+
} else if (err is TransportException && err.disconnectReason == DisconnectReason.HOST_KEY_NOT_VERIFIABLE) {
79+
SSHException(DisconnectReason.HOST_KEY_NOT_VERIFIABLE,
80+
"WARNING: The remote host key has changed. If this is expected, please go to Git server settings and clear the saved host key."
81+
)
7782
} else {
7883
err
7984
}

app/src/main/java/com/zeapo/pwdstore/git/GitServerConfigActivity.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,12 @@ class GitServerConfigActivity : BaseGitActivity() {
8282
setAuthModes(text.startsWith("http://") || text.startsWith("https://"))
8383
}
8484

85+
binding.clearHostKeyButton.isVisible = GitSettings.hasSavedHostKey()
86+
binding.clearHostKeyButton.setOnClickListener {
87+
GitSettings.clearSavedHostKey()
88+
Snackbar.make(binding.root, getString(R.string.clear_saved_host_key_success), Snackbar.LENGTH_LONG).show()
89+
it.isVisible = false
90+
}
8591
binding.saveButton.setOnClickListener {
8692
val newUrl = binding.serverUrl.text.toString().trim()
8793
// If url is of type [email protected]:12435/path/to/repo, then not adding `ssh://`

app/src/main/java/com/zeapo/pwdstore/git/config/GitSettings.kt

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ object GitSettings {
5656
private val settings by lazy(LazyThreadSafetyMode.PUBLICATION) { Application.instance.sharedPrefs }
5757
private val encryptedSettings by lazy(LazyThreadSafetyMode.PUBLICATION) { Application.instance.getEncryptedGitPrefs() }
5858
private val proxySettings by lazy(LazyThreadSafetyMode.PUBLICATION) { Application.instance.getEncryptedProxyPrefs() }
59+
private val hostKeyPath by lazy(LazyThreadSafetyMode.NONE) { "${Application.instance.filesDir}/.host_key" }
5960

6061
var authMode
6162
get() = AuthMode.fromString(settings.getString(PreferenceKeys.GIT_REMOTE_AUTH))
@@ -64,6 +65,7 @@ object GitSettings {
6465
putString(PreferenceKeys.GIT_REMOTE_AUTH, value.pref)
6566
}
6667
}
68+
6769
var url
6870
get() = settings.getString(PreferenceKeys.GIT_REMOTE_URL)
6971
private set(value) {
@@ -79,29 +81,33 @@ object GitSettings {
7981
// should be deleted/reset.
8082
useMultiplexing = true
8183
encryptedSettings.edit { remove(PreferenceKeys.HTTPS_PASSWORD) }
82-
File("${Application.instance.filesDir}/.host_key").delete()
84+
clearSavedHostKey()
8385
}
86+
8487
var authorName
8588
get() = settings.getString(PreferenceKeys.GIT_CONFIG_AUTHOR_NAME) ?: ""
8689
set(value) {
8790
settings.edit {
8891
putString(PreferenceKeys.GIT_CONFIG_AUTHOR_NAME, value)
8992
}
9093
}
94+
9195
var authorEmail
9296
get() = settings.getString(PreferenceKeys.GIT_CONFIG_AUTHOR_EMAIL) ?: ""
9397
set(value) {
9498
settings.edit {
9599
putString(PreferenceKeys.GIT_CONFIG_AUTHOR_EMAIL, value)
96100
}
97101
}
102+
98103
var branch
99104
get() = settings.getString(PreferenceKeys.GIT_BRANCH_NAME) ?: DEFAULT_BRANCH
100105
private set(value) {
101106
settings.edit {
102107
putString(PreferenceKeys.GIT_BRANCH_NAME, value)
103108
}
104109
}
110+
105111
var useMultiplexing
106112
get() = settings.getBoolean(PreferenceKeys.GIT_REMOTE_USE_MULTIPLEXING, true)
107113
set(value) {
@@ -179,4 +185,16 @@ object GitSettings {
179185
branch = newBranch
180186
return UpdateConnectionSettingsResult.Valid
181187
}
188+
189+
/**
190+
* Deletes a previously saved SSH host key
191+
*/
192+
fun clearSavedHostKey() {
193+
File(hostKeyPath).delete()
194+
}
195+
196+
/**
197+
* Returns true if a host key was previously saved
198+
*/
199+
fun hasSavedHostKey(): Boolean = File(hostKeyPath).exists()
182200
}

app/src/main/res/layout/activity_git_clone.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,5 +120,16 @@
120120
android:text="@string/crypto_save"
121121
app:layout_constraintEnd_toEndOf="parent"
122122
app:layout_constraintTop_toBottomOf="@id/auth_mode_group" />
123+
124+
<com.google.android.material.button.MaterialButton
125+
android:id="@+id/clear_host_key_button"
126+
android:layout_width="wrap_content"
127+
android:layout_height="wrap_content"
128+
android:layout_marginTop="8dp"
129+
android:text="@string/clear_saved_host_key"
130+
android:visibility="gone"
131+
app:layout_constraintStart_toStartOf="parent"
132+
app:layout_constraintTop_toBottomOf="@id/auth_mode_group"
133+
tools:visibility="visible" />
123134
</androidx.constraintlayout.widget.ConstraintLayout>
124135
</ScrollView>

app/src/main/res/values/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,5 +415,7 @@
415415
<string name="pref_proxy_settings">HTTP(S) proxy settings</string>
416416
<string name="invalid_proxy_url">Invalid URL</string>
417417
<string name="oreo_autofill_password_fill_and_conditional_save_support">Fill and save passwords (saving requires that no accessibility services are enabled)</string>
418+
<string name="clear_saved_host_key">Clear saved host key</string>
419+
<string name="clear_saved_host_key_success">Successfully cleared saved host key!</string>
418420

419421
</resources>

0 commit comments

Comments
 (0)