aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/com/zeapo/pwdstore/git/GitServerConfigActivity.kt
diff options
context:
space:
mode:
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)
+ }
+ }
+}