aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/com/zeapo/pwdstore/git/GitServerConfigActivity.kt
diff options
context:
space:
mode:
authorHarsh Shandilya <msfjarvis@gmail.com>2020-04-17 18:36:07 +0530
committerGitHub <noreply@github.com>2020-04-17 18:36:07 +0530
commitb94b52a42ddc2325b539d0956fd0adcf35308b52 (patch)
tree21f35526cfc444db82e1b4b08d083e49a3c1843b /app/src/main/java/com/zeapo/pwdstore/git/GitServerConfigActivity.kt
parent4ffd7ed9bffa5139277ffb91de5a69f2b714222c (diff)
downloadHardenedPass-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.kt185
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)
+ }
+ }
+}