aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/com/zeapo/pwdstore/git/GitActivity.java
diff options
context:
space:
mode:
authorvexofp <vexofp@gmail.com>2019-04-05 18:14:38 -0400
committerMohamed Zenadi <zeapo@users.noreply.github.com>2019-04-06 00:14:38 +0200
commitf272e4dde2c05de64681a0e089387ef9c54bd7c7 (patch)
tree3e75e9c7a3a996c3f6d7762dac644ab3f4e7c700 /app/src/main/java/com/zeapo/pwdstore/git/GitActivity.java
parent94bf103b337d9df1d6232d85f5edf4673ede651c (diff)
downloadHardenedPass-f272e4dde2c05de64681a0e089387ef9c54bd7c7.tar.gz
HardenedPass-f272e4dde2c05de64681a0e089387ef9c54bd7c7.zip
Authentication using OpenKeystore SSH API (#486)
* Implemented OpenKeystore SSH API as a new authentication option * Fix formatting problems Signed-off-by: Harsh Shandilya <msfjarvis@gmail.com> * Addressed review comments. Removed leftover debugging code. Wrapped excessively long lines. Added missing new parameter to Javadoc. * Merge remote-tracking branch 'upstream/master' into gpg-ssh-key
Diffstat (limited to 'app/src/main/java/com/zeapo/pwdstore/git/GitActivity.java')
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/GitActivity.java150
1 files changed, 95 insertions, 55 deletions
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/GitActivity.java b/app/src/main/java/com/zeapo/pwdstore/git/GitActivity.java
index ca451247..e945c973 100644
--- a/app/src/main/java/com/zeapo/pwdstore/git/GitActivity.java
+++ b/app/src/main/java/com/zeapo/pwdstore/git/GitActivity.java
@@ -17,11 +17,15 @@ import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
+
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
+
import com.zeapo.pwdstore.R;
import com.zeapo.pwdstore.UserPreference;
+import com.zeapo.pwdstore.git.config.SshApiSessionFactory;
import com.zeapo.pwdstore.utils.PasswordRepository;
+
import org.apache.commons.io.FileUtils;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.RebaseCommand;
@@ -53,6 +57,8 @@ public class GitActivity extends AppCompatActivity {
private File localDir;
private String hostname;
private SharedPreferences settings;
+ private SshApiSessionFactory.IdentityBuilder identityBuilder;
+ private SshApiSessionFactory.ApiIdentity identity;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -117,8 +123,10 @@ public class GitActivity extends AppCompatActivity {
connection_mode_spinner.setEnabled(true);
// however, if we have some saved that, that's more important!
- if (connectionMode.equals("ssh-key")) {
+ if (connectionMode.equalsIgnoreCase("ssh-key")) {
connection_mode_spinner.setSelection(0);
+ } else if (connectionMode.equalsIgnoreCase("OpenKeychain")) {
+ connection_mode_spinner.setSelection(2);
} else {
connection_mode_spinner.setSelection(1);
}
@@ -371,6 +379,16 @@ public class GitActivity extends AppCompatActivity {
}
@Override
+ protected void onDestroy() {
+ // Do not leak the service connection
+ if (identityBuilder != null) {
+ identityBuilder.close();
+ identityBuilder = null;
+ }
+ super.onDestroy();
+ }
+
+ @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.git_clone, menu);
@@ -556,16 +574,7 @@ public class GitActivity extends AppCompatActivity {
(dialog, id) -> {
try {
FileUtils.deleteDirectory(localDir);
- try {
- new CloneOperation(localDir, activity)
- .setCommand(hostname)
- .executeAfterAuthentication(connectionMode, settings.getString("git_remote_username", "git"), new File(getFilesDir() + "/.ssh_key"));
- } catch (Exception e) {
- //This is what happens when jgit fails :(
- //TODO Handle the diffent cases of exceptions
- e.printStackTrace();
- new AlertDialog.Builder(GitActivity.this).setMessage(e.getMessage()).show();
- }
+ launchGitOperation(REQUEST_CLONE);
} catch (IOException e) {
//TODO Handle the exception correctly if we are unable to delete the directory...
e.printStackTrace();
@@ -590,15 +599,13 @@ public class GitActivity extends AppCompatActivity {
new AlertDialog.Builder(GitActivity.this).setMessage(e.getMessage()).show();
}
}
- new CloneOperation(localDir, activity)
- .setCommand(hostname)
- .executeAfterAuthentication(connectionMode, settings.getString("git_remote_username", "git"), new File(getFilesDir() + "/.ssh_key"));
} catch (Exception e) {
//This is what happens when jgit fails :(
//TODO Handle the diffent cases of exceptions
e.printStackTrace();
new AlertDialog.Builder(this).setMessage(e.getMessage()).show();
}
+ launchGitOperation(REQUEST_CLONE);
}
}
@@ -627,47 +634,45 @@ public class GitActivity extends AppCompatActivity {
else {
// check that the remote origin is here, else add it
PasswordRepository.addRemote("origin", hostname, false);
- GitOperation op;
-
- switch (operation) {
- case REQUEST_PULL:
- op = new PullOperation(localDir, activity).setCommand();
- break;
- case REQUEST_PUSH:
- op = new PushOperation(localDir, activity).setCommand();
- break;
- case REQUEST_SYNC:
- op = new SyncOperation(localDir, activity).setCommands();
- break;
- default:
- Log.e(TAG, "Sync operation not recognized : " + operation);
- return;
- }
-
- try {
- op.executeAfterAuthentication(connectionMode, settings.getString("git_remote_username", "git"), new File(getFilesDir() + "/.ssh_key"));
- } catch (Exception e) {
- e.printStackTrace();
- }
+ launchGitOperation(operation);
}
}
- protected void onActivityResult(int requestCode, int resultCode,
- Intent data) {
- if (resultCode == RESULT_CANCELED) {
- setResult(RESULT_CANCELED);
- finish();
- return;
- }
+ /**
+ * Attempt to launch the requested GIT operation. Depending on the configured auth, it may not
+ * be possible to launch the operation immediately. In that case, this function may launch an
+ * intermediate activity instead, which will gather necessary information and post it back via
+ * onActivityResult, which will then re-call this function. This may happen multiple times,
+ * until either an error is encountered or the operation is successfully launched.
+ *
+ * @param operation The type of GIT operation to launch
+ */
+ protected void launchGitOperation(int operation) {
+ GitOperation op;
+
+ try {
+
+ // Before launching the operation with OpenKeychain auth, we need to issue several requests
+ // to the OpenKeychain API. IdentityBuild will take care of launching the relevant intents,
+ // we just need to keep calling it until it returns a completed ApiIdentity.
+ if (connectionMode.equalsIgnoreCase("OpenKeychain") && identity == null) {
+ // Lazy initialization of the IdentityBuilder
+ if (identityBuilder == null) {
+ identityBuilder = new SshApiSessionFactory.IdentityBuilder(this);
+ }
- if (resultCode == RESULT_OK) {
- GitOperation op;
+ // Try to get an ApiIdentity and bail if one is not ready yet. The builder will ensure
+ // that onActivityResult is called with operation again, which will re-invoke us here
+ identity = identityBuilder.tryBuild(operation);
+ if (identity == null)
+ return;
+ }
- switch (requestCode) {
+ switch (operation) {
case REQUEST_CLONE:
- setResult(RESULT_OK);
- finish();
- return;
+ op = new CloneOperation(localDir, activity).setCommand(hostname);
+ break;
+
case REQUEST_PULL:
op = new PullOperation(localDir, activity).setCommand();
break;
@@ -676,22 +681,57 @@ public class GitActivity extends AppCompatActivity {
op = new PushOperation(localDir, activity).setCommand();
break;
+ case REQUEST_SYNC:
+ op = new SyncOperation(localDir, activity).setCommands();
+ break;
+
case GitOperation.GET_SSH_KEY_FROM_CLONE:
op = new CloneOperation(localDir, activity).setCommand(hostname);
break;
+
+ case SshApiSessionFactory.POST_SIGNATURE:
+ return;
+
default:
- Log.e(TAG, "Operation not recognized : " + resultCode);
+ Log.e(TAG, "Operation not recognized : " + operation);
setResult(RESULT_CANCELED);
finish();
return;
}
- try {
- op.executeAfterAuthentication(connectionMode, settings.getString("git_remote_username", "git"), new File(getFilesDir() + "/.ssh_key"));
- } catch (Exception e) {
- e.printStackTrace();
- }
+ op.executeAfterAuthentication(connectionMode,
+ settings.getString("git_remote_username", "git"),
+ new File(getFilesDir() + "/.ssh_key"),
+ identity);
+ } catch (Exception e) {
+ e.printStackTrace();
+ new AlertDialog.Builder(this).setMessage(e.getMessage()).show();
+ }
+ }
+ protected void onActivityResult(int requestCode, int resultCode,
+ Intent data) {
+
+ // In addition to the pre-operation-launch series of intents for OpenKeychain auth
+ // that will pass through here and back to launchGitOperation, there is one
+ // synchronous operation that happens /after/ the operation has been launched in the
+ // background thread - the actual signing of the SSH challenge. We pass through the
+ // completed signature to the ApiIdentity, which will be blocked in the other thread
+ // waiting for it.
+ if (requestCode == SshApiSessionFactory.POST_SIGNATURE && identity != null)
+ identity.postSignature(data);
+
+ if (resultCode == RESULT_CANCELED) {
+ setResult(RESULT_CANCELED);
+ finish();
+ } else if (resultCode == RESULT_OK) {
+ // If an operation has been re-queued via this mechanism, let the
+ // IdentityBuilder attempt to extract some updated state from the intent before
+ // trying to re-launch the operation.
+ if (identityBuilder != null) {
+ identityBuilder.consume(data);
+ }
+ launchGitOperation(requestCode);
}
}