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

Commit 7a58e39

Browse files
Disable SSH multiplexing if not supported (#1093)
Co-authored-by: Harsh Shandilya <[email protected]>
1 parent 9cb8551 commit 7a58e39

File tree

5 files changed

+44
-2
lines changed

5 files changed

+44
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ All notable changes to this project will be documented in this file.
2727
- Unable to use show/hide password option for password/passphrase after first attempt was wrong
2828
- TOTP values shown might some times be stale and considered invalid by sites
2929
- Symlinks are no longer clobbered by the app (only available on Android 8 and above)
30+
- Workaround lack of SSH connection reuse capabilities on some Git hosts like Bitbucket
3031

3132
## [1.11.3] - 2020-08-27
3233

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import com.github.ajalt.timberkt.d
1111
import com.github.ajalt.timberkt.e
1212
import com.github.michaelbull.result.Err
1313
import com.github.michaelbull.result.Result
14+
import com.github.michaelbull.result.andThen
15+
import com.github.michaelbull.result.mapError
1416
import com.google.android.material.dialog.MaterialAlertDialogBuilder
1517
import com.zeapo.pwdstore.R
1618
import com.zeapo.pwdstore.git.config.GitSettings
@@ -42,6 +44,11 @@ abstract class BaseGitActivity : AppCompatActivity() {
4244
if (GitSettings.url == null) {
4345
return Err(IllegalStateException("Git url is not set!"))
4446
}
47+
if (operation == REQUEST_SYNC && !GitSettings.useMultiplexing) {
48+
// If the server does not support multiple SSH channels per connection, we cannot run
49+
// a sync operation without reconnecting and thus break sync into its two parts.
50+
return launchGitOperation(REQUEST_PULL).andThen { launchGitOperation(REQUEST_PUSH) }
51+
}
4552
val op = when (operation) {
4653
REQUEST_CLONE, GitOperation.GET_SSH_KEY_FROM_CLONE -> CloneOperation(this, GitSettings.url!!)
4754
REQUEST_PULL -> PullOperation(this)
@@ -54,7 +61,15 @@ abstract class BaseGitActivity : AppCompatActivity() {
5461
return Err(IllegalArgumentException("$operation is not a valid Git operation"))
5562
}
5663
}
57-
return op.executeAfterAuthentication(GitSettings.authMode)
64+
return op.executeAfterAuthentication(GitSettings.authMode).mapError { throwable ->
65+
val err = rootCauseException(throwable)
66+
if (err.message?.contains("cannot open additional channels") == true) {
67+
GitSettings.useMultiplexing = false
68+
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.")
69+
} else {
70+
err
71+
}
72+
}
5873
}
5974

6075
fun finishOnSuccessHandler(@Suppress("UNUSED_PARAMETER") nothing: Unit) {

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,9 @@ object GitSettings {
7373
}
7474
if (PasswordRepository.isInitialized)
7575
PasswordRepository.addRemote("origin", value, true)
76-
// When the server changes, remote password and host key file should be deleted.
76+
// When the server changes, remote password, multiplexing support and host key file
77+
// should be deleted/reset.
78+
useMultiplexing = true
7779
encryptedSettings.edit { remove(PreferenceKeys.HTTPS_PASSWORD) }
7880
File("${Application.instance.filesDir}/.host_key").delete()
7981
}
@@ -98,6 +100,13 @@ object GitSettings {
98100
putString(PreferenceKeys.GIT_BRANCH_NAME, value)
99101
}
100102
}
103+
var useMultiplexing
104+
get() = settings.getBoolean(PreferenceKeys.GIT_REMOTE_USE_MULTIPLEXING, true)
105+
set(value) {
106+
settings.edit {
107+
putBoolean(PreferenceKeys.GIT_REMOTE_USE_MULTIPLEXING, value)
108+
}
109+
}
101110

102111
sealed class UpdateConnectionSettingsResult {
103112
class MissingUsername(val newProtocol: Protocol) : UpdateConnectionSettingsResult()

app/src/main/java/com/zeapo/pwdstore/git/operation/PullOperation.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,23 @@ import org.eclipse.jgit.api.GitCommand
99

1010
class PullOperation(callingActivity: AppCompatActivity) : GitOperation(callingActivity) {
1111

12+
/**
13+
* The story of why the pull operation is committing files goes like this: Once upon a time when
14+
* the world was burning and Blade Runner 2049 was real life (in the worst way), we were made
15+
* aware that Bitbucket is actually bad, and disables a neat OpenSSH feature called multiplexing.
16+
* So now, rather than being able to do a [SyncOperation], we'd have to first do a [PullOperation]
17+
* and then a [PushOperation]. To make the behavior identical despite this suboptimal situation,
18+
* we opted to replicate [SyncOperation]'s committing flow within [PullOperation], almost exactly
19+
* replicating [SyncOperation] but leaving the pushing part to [PushOperation].
20+
*/
1221
override val commands: Array<GitCommand<out Any>> = arrayOf(
22+
// Stage all files
23+
git.add().addFilepattern("."),
24+
// Populate the changed files count
25+
git.status(),
26+
// Commit everything! If needed, obviously.
27+
git.commit().setAll(true).setMessage("[Android Password Store] Sync"),
28+
// Pull and rebase on top of the remote branch
1329
git.pull().setRebase(true).setRemote("origin"),
1430
)
1531
}

app/src/main/java/com/zeapo/pwdstore/utils/PreferenceKeys.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ object PreferenceKeys {
3232

3333
@Deprecated("Use GIT_REMOTE_URL instead")
3434
const val GIT_REMOTE_LOCATION = "git_remote_location"
35+
const val GIT_REMOTE_USE_MULTIPLEXING = "git_remote_use_multiplexing"
3536

3637
@Deprecated("Use GIT_REMOTE_URL instead")
3738
const val GIT_REMOTE_PORT = "git_remote_port"

0 commit comments

Comments
 (0)