diff options
| author | Harsh Shandilya <msfjarvis@gmail.com> | 2020-04-17 18:36:07 +0530 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-04-17 18:36:07 +0530 |
| commit | b94b52a42ddc2325b539d0956fd0adcf35308b52 (patch) | |
| tree | 21f35526cfc444db82e1b4b08d083e49a3c1843b /app/src/main/java/com/zeapo/pwdstore/git/GitServerConfigActivity.kt | |
| parent | 4ffd7ed9bffa5139277ffb91de5a69f2b714222c (diff) | |
| download | HardenedPass-b94b52a42ddc2325b539d0956fd0adcf35308b52.tar.gz HardenedPass-b94b52a42ddc2325b539d0956fd0adcf35308b52.zip | |
Refactor Git related activities (#685)
* Refactor git logic into separate parts
* Extract hardcoded strings
* Add KDoc to updateHostname, remove unused field
* Cleanups
* Fix dialog message
* Wire in repository clone flow
* spotless
* Remove unused method
* Cleanup GitActivity
- Rename to GitOperationActivity.
- Ensure identityBuilder is always closed regardless of what fragment uses it.
- Remove hardcoded "Operation" strings and replace with REQUEST_ARG_OP.
- Apply a transparent theme to GitOperationActivity make the UI less jarring.
* Tweak some stupidly worded dialog messages
As pointed out in #629, these strings are shoddily worded and do not express any clear intent to the
user, leaving them confused and angry.
* GitOperationActivity: wrap Context to ensure right theme is used
* spotless
* undo build.gradle change
* Use correct parent theme, remove now useless wrapping
* GitServerConfigActivity: fix repository clone flow
* temp: disable leakcanary
framework leaks on Samsung are pissing me off
* Make system bars transparent in git activity
* Tweak HTTPS password layout
* Unhardcode wrong passphrase string
* Store SSH passphrase in EncryptedSharedPreferences
Also revamp the dialog to look a bit better
* Implement support for remembering HTTPS password
Fixes #521
* Try to patch HTTPS remote creation logic
* Update security-crypto
* Clear saved passphrase/password on auth failure
* Revert "Update security-crypto"
Broken on R DP2.1
This reverts commit 4b20371dd42c512a3dd3b759859abb6c1ffd2961.
* Revert "temp: disable leakcanary"
This reverts commit 2db7d41bd67b79c6dc8c5b359a7b27100379f45f.
* Update CHANGELOG
* Remove spacer
* Remove useless override
* Wrap git server activity in a ScrollView
* GitOperation: always finish calling activity when dialogs are dismissed
* Wipe saved password/passphrase when hostname changes
* Don't commit prefs updates
* Don't call listFiles excessively
* Finish activity after saving configuration
* Make ConnectionMode and Protocol enum classes
* Change SSH key passphrase key, don't wipe on host change
* Reimplement BaseGitActivity.updateUrl (was updateHostname)
* Use SharedPreferences.edit KTX extension
* Disable inapplicable connection modes depending on scheme
* BaseGitActivity: annotate onDestroy with CallSuper
We'll leak the identityBuilder connection otherwise
* Move input hack for AlertDialog into an extension function
We re-use this in many places
* Fix protocol/mode toggle issue and consistenly name options
* Fix a crash when opening GitServerConfigActivity without a repo
* Fix OpenKeychain callbacks by moving onActivityResult to BaseGitActivity
* Run spotlessApply
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
Co-authored-by: Fabian Henneke <fabian@henneke.me>
Diffstat (limited to 'app/src/main/java/com/zeapo/pwdstore/git/GitServerConfigActivity.kt')
| -rw-r--r-- | app/src/main/java/com/zeapo/pwdstore/git/GitServerConfigActivity.kt | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/GitServerConfigActivity.kt b/app/src/main/java/com/zeapo/pwdstore/git/GitServerConfigActivity.kt new file mode 100644 index 00000000..a10f3460 --- /dev/null +++ b/app/src/main/java/com/zeapo/pwdstore/git/GitServerConfigActivity.kt @@ -0,0 +1,185 @@ +/* + * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved. + * SPDX-License-Identifier: GPL-3.0-only + */ +package com.zeapo.pwdstore.git + +import android.os.Bundle +import android.os.Handler +import androidx.core.content.edit +import androidx.core.os.postDelayed +import androidx.core.widget.doOnTextChanged +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.google.android.material.snackbar.Snackbar +import com.zeapo.pwdstore.R +import com.zeapo.pwdstore.databinding.ActivityGitCloneBinding +import com.zeapo.pwdstore.git.config.ConnectionMode +import com.zeapo.pwdstore.git.config.Protocol +import com.zeapo.pwdstore.utils.PasswordRepository +import java.io.IOException + +/** + * Activity that encompasses both the initial clone as well as editing the server config for future + * changes. + */ +class GitServerConfigActivity : BaseGitActivity() { + + lateinit var binding: ActivityGitCloneBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityGitCloneBinding.inflate(layoutInflater) + val isClone = intent?.extras?.getInt(REQUEST_ARG_OP) ?: -1 == REQUEST_CLONE + if (isClone) { + binding.saveButton.text = getString(R.string.clone_button) + } + setContentView(binding.root) + supportActionBar?.setDisplayHomeAsUpEnabled(true) + + val protocolIdToCheck = when (protocol) { + Protocol.Ssh -> R.id.clone_protocol_ssh + Protocol.Https -> R.id.clone_protocol_https + } + binding.cloneProtocolGroup.check(protocolIdToCheck) + binding.cloneProtocolGroup.addOnButtonCheckedListener { _, checkedId, checked -> + if (checked) { + when (checkedId) { + R.id.clone_protocol_https -> protocol = Protocol.Https + R.id.clone_protocol_ssh -> protocol = Protocol.Ssh + } + updateConnectionModeToggleGroup() + } + } + + val connectionModeIdToCheck = when (connectionMode) { + ConnectionMode.SshKey -> R.id.connection_mode_ssh_key + ConnectionMode.Password -> R.id.connection_mode_password + ConnectionMode.OpenKeychain -> R.id.connection_mode_open_keychain + } + binding.connectionModeGroup.check(connectionModeIdToCheck) + binding.connectionModeGroup.addOnButtonCheckedListener { _, checkedId, checked -> + if (checked) { + when (checkedId) { + R.id.connection_mode_ssh_key -> connectionMode = ConnectionMode.SshKey + R.id.connection_mode_open_keychain -> connectionMode = ConnectionMode.OpenKeychain + R.id.connection_mode_password -> connectionMode = ConnectionMode.Password + } + } + } + updateConnectionModeToggleGroup() + + binding.serverUrl.apply { + setText(serverHostname) + doOnTextChanged { text, _, _, _ -> + serverHostname = text.toString().trim() + } + } + + binding.serverPort.apply { + setText(serverPort) + doOnTextChanged { text, _, _, _ -> + serverPort = text.toString().trim() + } + } + + binding.serverUser.apply { + setText(serverUser) + doOnTextChanged { text, _, _, _ -> + serverUser = text.toString().trim() + } + } + + binding.serverPath.apply { + setText(serverPath) + doOnTextChanged { text, _, _, _ -> + serverPath = text.toString().trim() + } + } + + binding.saveButton.setOnClickListener { + if (isClone && PasswordRepository.getRepository(null) == null) + PasswordRepository.initialize(this) + if (updateUrl()) { + settings.edit { + putString("git_remote_protocol", protocol.pref) + putString("git_remote_auth", connectionMode.pref) + putString("git_remote_server", serverHostname) + putString("git_remote_port", serverPort) + putString("git_remote_username", serverUser) + putString("git_remote_location", serverPath) + } + 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_failure), Snackbar.LENGTH_LONG).show() + } + } + } + + private fun updateConnectionModeToggleGroup() { + if (protocol == Protocol.Ssh) { + binding.connectionModeSshKey.isEnabled = true + binding.connectionModeOpenKeychain.isEnabled = true + } else { + // Reset connection mode to the only one possible via HTTPS: password. + // Important note: This has to happen before disabling the other toggle buttons or they + // won't uncheck. + binding.connectionModeGroup.check(R.id.connection_mode_password) + binding.connectionModeSshKey.isEnabled = false + binding.connectionModeOpenKeychain.isEnabled = false + } + } + + /** + * Clones the repository, the directory exists, deletes it + */ + private fun cloneRepository() { + val localDir = requireNotNull(PasswordRepository.getRepositoryDirectory(this)) + val localDirFiles = localDir.listFiles() ?: emptyArray() + // Warn if non-empty folder unless it's a just-initialized store that has just a .git folder + if (localDir.exists() && localDirFiles.isNotEmpty() && + !(localDirFiles.size == 1 && localDirFiles[0].name == ".git")) { + MaterialAlertDialogBuilder(this) + .setTitle(R.string.dialog_delete_title) + .setMessage(resources.getString(R.string.dialog_delete_msg) + " " + localDir.toString()) + .setCancelable(false) + .setPositiveButton(R.string.dialog_delete) { dialog, _ -> + try { + localDir.deleteRecursively() + launchGitOperation(REQUEST_CLONE) + } catch (e: IOException) { + // TODO Handle the exception correctly if we are unable to delete the directory... + e.printStackTrace() + MaterialAlertDialogBuilder(this).setMessage(e.message).show() + } finally { + dialog.cancel() + } + } + .setNegativeButton(R.string.dialog_do_not_delete) { dialog, _ -> + dialog.cancel() + } + .show() + } else { + try { + // Silently delete & replace the lone .git folder if it exists + if (localDir.exists() && localDirFiles.size == 1 && localDirFiles[0].name == ".git") { + try { + localDir.deleteRecursively() + } catch (e: IOException) { + e.printStackTrace() + MaterialAlertDialogBuilder(this).setMessage(e.message).show() + } + } + } catch (e: Exception) { + // This is what happens when JGit fails :( + // TODO Handle the different cases of exceptions + e.printStackTrace() + MaterialAlertDialogBuilder(this).setMessage(e.message).show() + } + launchGitOperation(REQUEST_CLONE) + } + } +} |
