aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/com/zeapo/pwdstore/git/GitAsyncTask.kt
diff options
context:
space:
mode:
authorFabian Henneke <FabianHenneke@users.noreply.github.com>2020-05-28 06:27:30 +0200
committerGitHub <noreply@github.com>2020-05-28 09:57:30 +0530
commit97911c587754a7c11e594004b77c4ac53af8a468 (patch)
tree680453c63fc3873139a3937268f73ec6985cf03a /app/src/main/java/com/zeapo/pwdstore/git/GitAsyncTask.kt
parentfea82fed47d87138a9a24eb0358fc9a917474dc7 (diff)
downloadHardenedPass-97911c587754a7c11e594004b77c4ac53af8a468.tar.gz
HardenedPass-97911c587754a7c11e594004b77c4ac53af8a468.zip
Use SSHJ for SSH public key authentication (#801)
Diffstat (limited to 'app/src/main/java/com/zeapo/pwdstore/git/GitAsyncTask.kt')
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/GitAsyncTask.kt148
1 files changed, 148 insertions, 0 deletions
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/GitAsyncTask.kt b/app/src/main/java/com/zeapo/pwdstore/git/GitAsyncTask.kt
new file mode 100644
index 00000000..631bbf88
--- /dev/null
+++ b/app/src/main/java/com/zeapo/pwdstore/git/GitAsyncTask.kt
@@ -0,0 +1,148 @@
+/*
+ * 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.app.Activity
+import android.app.ProgressDialog
+import android.content.Context
+import android.content.Intent
+import android.os.AsyncTask
+import com.github.ajalt.timberkt.e
+import com.zeapo.pwdstore.PasswordStore
+import com.zeapo.pwdstore.R
+import net.schmizz.sshj.userauth.UserAuthException
+import org.eclipse.jgit.api.CommitCommand
+import org.eclipse.jgit.api.GitCommand
+import org.eclipse.jgit.api.PullCommand
+import org.eclipse.jgit.api.PushCommand
+import org.eclipse.jgit.api.RebaseResult
+import org.eclipse.jgit.api.StatusCommand
+import org.eclipse.jgit.transport.RemoteRefUpdate
+import java.io.IOException
+import java.lang.ref.WeakReference
+
+
+class GitAsyncTask(
+ activity: Activity,
+ private val refreshListOnEnd: Boolean,
+ private val operation: GitOperation,
+ private val finishWithResultOnEnd: Intent?) : AsyncTask<GitCommand<*>, Int, GitAsyncTask.Result>() {
+
+ private val activityWeakReference: WeakReference<Activity> = WeakReference(activity)
+ private val activity: Activity?
+ get() = activityWeakReference.get()
+ private val context: Context = activity.applicationContext
+ private val dialog = ProgressDialog(activity)
+
+ sealed class Result {
+ object Ok : Result()
+ data class Err(val err: Exception) : Result()
+ }
+
+ override fun onPreExecute() {
+ dialog.run {
+ setMessage(activity!!.resources.getString(R.string.running_dialog_text))
+ setCancelable(false)
+ show()
+ }
+ }
+
+ override fun doInBackground(vararg commands: GitCommand<*>): Result? {
+ var nbChanges: Int? = null
+ for (command in commands) {
+ try {
+ when (command) {
+ is StatusCommand -> {
+ // in case we have changes, we want to keep track of it
+ val status = command.call()
+ nbChanges = status.changed.size + status.missing.size
+ }
+ is CommitCommand -> {
+ // the previous status will eventually be used to avoid a commit
+ if (nbChanges == null || nbChanges > 0) command.call()
+ }
+ is PullCommand -> {
+ val result = command.call()
+ val rr = result.rebaseResult
+ if (rr.status === RebaseResult.Status.STOPPED) {
+ return Result.Err(IOException(context.getString(R.string
+ .git_pull_fail_error)))
+ }
+ }
+ is PushCommand -> {
+ for (result in command.call()) {
+ // Code imported (modified) from Gerrit PushOp, license Apache v2
+ for (rru in result.remoteUpdates) {
+ val error = when (rru.status) {
+ RemoteRefUpdate.Status.REJECTED_NONFASTFORWARD ->
+ context.getString(R.string.git_push_nff_error)
+ RemoteRefUpdate.Status.REJECTED_NODELETE,
+ RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED,
+ RemoteRefUpdate.Status.NON_EXISTING,
+ RemoteRefUpdate.Status.NOT_ATTEMPTED ->
+ (activity!!.getString(R.string.git_push_generic_error) + rru.status.name)
+ RemoteRefUpdate.Status.REJECTED_OTHER_REASON -> {
+ if
+ ("non-fast-forward" == rru.message) {
+ context.getString(R.string.git_push_other_error)
+ } else {
+ (context.getString(R.string.git_push_generic_error)
+ + rru.message)
+ }
+ }
+ else -> null
+
+ }
+ if (error != null)
+ Result.Err(IOException(error))
+ }
+ }
+ }
+ else -> {
+ command.call()
+ }
+ }
+ } catch (e: Exception) {
+ return Result.Err(e)
+ }
+ }
+ return Result.Ok
+ }
+
+ private fun rootCauseException(e: Exception): Exception {
+ var rootCause = e
+ // JGit's TransportException hides the more helpful SSHJ exceptions.
+ // Also, SSHJ's UserAuthException about exhausting available authentication methods hides
+ // more useful exceptions.
+ while ((rootCause is org.eclipse.jgit.errors.TransportException ||
+ rootCause is org.eclipse.jgit.api.errors.TransportException ||
+ (rootCause is UserAuthException &&
+ rootCause.message == "Exhausted available authentication methods"))) {
+ rootCause = rootCause.cause as? Exception ?: break
+ }
+ return rootCause
+ }
+
+ override fun onPostExecute(maybeResult: Result?) {
+ dialog.dismiss()
+ when (val result = maybeResult ?: Result.Err(IOException("Unexpected error"))) {
+ is Result.Err -> {
+ e(result.err)
+ operation.onError(rootCauseException(result.err))
+ }
+ is Result.Ok -> {
+ operation.onSuccess()
+ if (finishWithResultOnEnd != null) {
+ activity?.setResult(Activity.RESULT_OK, finishWithResultOnEnd)
+ activity?.finish()
+ }
+ if (refreshListOnEnd) {
+ (activity as? PasswordStore)?.resetPasswordList()
+ }
+ }
+ }
+ }
+
+}