Merge pull request #57 from zeapo/feature/refactor-git

Refactoring of the git process
This commit is contained in:
Mohamed Zenadi 2015-01-04 21:49:56 +01:00
commit df8994d84f
17 changed files with 759 additions and 372 deletions

View file

@ -32,6 +32,7 @@ dependencies {
compile project(':libraries:openpgp-api-lib') compile project(':libraries:openpgp-api-lib')
compile 'org.eclipse.jgit:org.eclipse.jgit:3.6.0.201411121045-m1' compile 'org.eclipse.jgit:org.eclipse.jgit:3.6.0.201411121045-m1'
compile 'org.apache.commons:commons-io:1.3.2' compile 'org.apache.commons:commons-io:1.3.2'
compile 'com.jayway.android.robotium:robotium-solo:5.2.1'
} }
tasks.findAll { // make all tasks whose name starts with 'assemble'... tasks.findAll { // make all tasks whose name starts with 'assemble'...
it.name.startsWith 'assemble' it.name.startsWith 'assemble'

View file

@ -1,13 +0,0 @@
package com.zeapo.pwdstore;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}

View file

@ -0,0 +1,111 @@
package com.zeapo.pwdstore;
import android.app.Activity;
import android.app.Instrumentation;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import com.robotium.solo.Solo;
import com.zeapo.pwdstore.git.GitActivity;
import com.zeapo.pwdstore.utils.PasswordRepository;
import org.apache.commons.io.FileUtils;
import java.io.File;
public class GitActivityClone extends ActivityInstrumentationTestCase2<GitActivity> {
private static final String TAG = "GitActTest";
private Activity gitActivity;
private Instrumentation mInstrumentation;
private SharedPreferences settings;
private Spinner protocolSpinner;
private Spinner connectionModeSpinner;
private EditText uri;
private EditText server_url;
private EditText server_port;
private EditText server_path;
private EditText server_user;
public GitActivityClone() {
super(GitActivity.class);
}
protected void setUp() throws Exception {
super.setUp();
mInstrumentation = getInstrumentation();
Intent intent = new Intent();
intent.putExtra("Operation", GitActivity.REQUEST_CLONE);
setActivityIntent(intent);
gitActivity = getActivity(); // get a references to the app under test
assertNotNull(gitActivity);
settings = PreferenceManager.getDefaultSharedPreferences(gitActivity.getApplicationContext());
uri = (EditText) gitActivity.findViewById(R.id.clone_uri);
server_url = ((EditText) gitActivity.findViewById(R.id.server_url));
server_port = ((EditText) gitActivity.findViewById(R.id.server_port));
server_path = ((EditText) gitActivity.findViewById(R.id.server_path));
server_user = ((EditText) gitActivity.findViewById(R.id.server_user));
protocolSpinner = (Spinner) gitActivity.findViewById(R.id.clone_protocol);
connectionModeSpinner = (Spinner) gitActivity.findViewById(R.id.connection_mode);
assertNotNull(uri);
assertNotNull(server_url);
assertNotNull(server_port);
assertNotNull(server_path);
assertNotNull(server_user);
assertNotNull(protocolSpinner);
assertNotNull(connectionModeSpinner);
assertEquals(protocolSpinner.getSelectedItem(), settings.getString("git_remote_protocol", "ssh://"));
assertEquals(connectionModeSpinner.getSelectedItem(), settings.getString("git_remote_auth", "ssh-key"));
}
public void testCloneSshUser() throws Exception {
final Solo solo = new Solo(getInstrumentation(), getActivity());
FileUtils.deleteDirectory(new File(gitActivity.getFilesDir() + gitActivity.getResources().getString(R.string.store_git)));
// create the repository static variable in PasswordRepository
PasswordRepository.getRepository(new File(gitActivity.getFilesDir() + gitActivity.getResources().getString(R.string.store_git)));
gitActivity.runOnUiThread(new Runnable() {
public void run() {
protocolSpinner.setSelection(0); // ssh://
}
});
mInstrumentation.waitForIdleSync();
solo.clearEditText(server_user);
solo.enterText(server_user, "testpwd");
solo.clearEditText(server_path);
solo.enterText(server_path, "repo-test");
solo.clearEditText(server_url);
solo.enterText(server_url, "192.168.1.28");
mInstrumentation.waitForIdleSync();
gitActivity.runOnUiThread(new Runnable() {
public void run() {
connectionModeSpinner.setSelection(1); // user/pwd
((Button) gitActivity.findViewById(R.id.clone_button)).performClick();
}
});
mInstrumentation.waitForIdleSync();
assertTrue("Could not find the dialog!", solo.searchText(gitActivity.getResources().getString(R.string.passphrase_dialog_title)));
solo.enterText(solo.getEditText("Password"), "test");
solo.clickOnButton(gitActivity.getResources().getString(R.string.dialog_ok));
mInstrumentation.waitForIdleSync();
}
}

View file

@ -0,0 +1,74 @@
package com.zeapo.pwdstore;
import android.app.Activity;
import android.app.Instrumentation;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.test.ActivityInstrumentationTestCase2;
import android.test.ActivityTestCase;
import android.test.InstrumentationTestCase;
import android.util.Log;
import android.widget.EditText;
import android.widget.Spinner;
import com.zeapo.pwdstore.git.GitActivity;
public class GitActivityTest extends ActivityInstrumentationTestCase2<GitActivity> {
private Activity gitActivity;
private Instrumentation mInstrumentation;
private SharedPreferences settings;
private Spinner protocolSpinner;
private Spinner connectionModeSpinner;
private EditText uri;
private EditText server_url;
private EditText server_port;
private EditText server_path;
private EditText server_user;
public GitActivityTest() {
super(GitActivity.class);
}
protected void setUp() throws Exception {
super.setUp();
mInstrumentation = getInstrumentation();
Intent intent = new Intent();
intent.putExtra("Operation", GitActivity.EDIT_SERVER);
setActivityIntent(intent);
gitActivity = getActivity(); // get a references to the app under test
assertNotNull(gitActivity);
settings = PreferenceManager.getDefaultSharedPreferences(gitActivity.getApplicationContext());
uri = (EditText) gitActivity.findViewById(R.id.clone_uri);
server_url = ((EditText) gitActivity.findViewById(R.id.server_url));
server_port = ((EditText) gitActivity.findViewById(R.id.server_port));
server_path = ((EditText) gitActivity.findViewById(R.id.server_path));
server_user = ((EditText) gitActivity.findViewById(R.id.server_user));
protocolSpinner = (Spinner) gitActivity.findViewById(R.id.clone_protocol);
connectionModeSpinner = (Spinner) gitActivity.findViewById(R.id.connection_mode);
assertEquals(protocolSpinner.getSelectedItem(), settings.getString("git_remote_protocol", "ssh://"));
assertEquals(connectionModeSpinner.getSelectedItem(), settings.getString("git_remote_auth", "ssh-key"));
}
/**
* If we change from ssh protocol to https we automatically switch to username/password auth
* @throws Exception
*/
public void testSpinnerChange() throws Exception{
gitActivity.runOnUiThread(new Runnable() {
public void run() {
protocolSpinner.requestFocus();
protocolSpinner.setSelection(1); // 1 < is https://
}
});
mInstrumentation.waitForIdleSync();
assertEquals(connectionModeSpinner.getSelectedItem(), "username/password"); // 1 < is username/password
}
}

View file

@ -11,7 +11,7 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name=".git.GitHandler" <activity android:name=".git.GitActivity"
android:parentActivityName=".PasswordStore"> android:parentActivityName=".PasswordStore">
<meta-data android:name="android.PARENT_ACTIVITY1" <meta-data android:name="android.PARENT_ACTIVITY1"
android:value="com.zeapo.pwdstore.PasswordStore" /> android:value="com.zeapo.pwdstore.PasswordStore" />

View file

@ -18,8 +18,8 @@ import android.view.MenuItem;
import android.view.View; import android.view.View;
import com.zeapo.pwdstore.crypto.PgpHandler; import com.zeapo.pwdstore.crypto.PgpHandler;
import com.zeapo.pwdstore.git.GitActivity;
import com.zeapo.pwdstore.git.GitAsyncTask; import com.zeapo.pwdstore.git.GitAsyncTask;
import com.zeapo.pwdstore.git.GitHandler;
import com.zeapo.pwdstore.utils.PasswordItem; import com.zeapo.pwdstore.utils.PasswordItem;
import com.zeapo.pwdstore.utils.PasswordRecyclerAdapter; import com.zeapo.pwdstore.utils.PasswordRecyclerAdapter;
import com.zeapo.pwdstore.utils.PasswordRepository; import com.zeapo.pwdstore.utils.PasswordRepository;
@ -151,9 +151,9 @@ public class PasswordStore extends ActionBarActivity {
break; break;
} }
intent = new Intent(this, GitHandler.class); intent = new Intent(this, GitActivity.class);
intent.putExtra("Operation", GitHandler.REQUEST_PUSH); intent.putExtra("Operation", GitActivity.REQUEST_PUSH);
startActivityForResult(intent, GitHandler.REQUEST_PUSH); startActivityForResult(intent, GitActivity.REQUEST_PUSH);
this.leftActivity = true; this.leftActivity = true;
return true; return true;
@ -163,9 +163,9 @@ public class PasswordStore extends ActionBarActivity {
break; break;
} }
intent = new Intent(this, GitHandler.class); intent = new Intent(this, GitActivity.class);
intent.putExtra("Operation", GitHandler.REQUEST_PULL); intent.putExtra("Operation", GitActivity.REQUEST_PULL);
startActivityForResult(intent, GitHandler.REQUEST_PULL); startActivityForResult(intent, GitActivity.REQUEST_PULL);
this.leftActivity = true; this.leftActivity = true;
return true; return true;
@ -186,9 +186,9 @@ public class PasswordStore extends ActionBarActivity {
} }
public void getClone(View view){ public void getClone(View view){
Intent intent = new Intent(this, GitHandler.class); Intent intent = new Intent(this, GitActivity.class);
intent.putExtra("Operation", GitHandler.REQUEST_CLONE); intent.putExtra("Operation", GitActivity.REQUEST_CLONE);
startActivityForResult(intent, GitHandler.REQUEST_CLONE); startActivityForResult(intent, GitActivity.REQUEST_CLONE);
} }
private void createRepository() { private void createRepository() {
@ -228,7 +228,7 @@ public class PasswordStore extends ActionBarActivity {
@Override @Override
public void onClick(DialogInterface dialogInterface, int i) { public void onClick(DialogInterface dialogInterface, int i) {
Intent intent = new Intent(activity, UserPreference.class); Intent intent = new Intent(activity, UserPreference.class);
startActivityForResult(intent, GitHandler.REQUEST_INIT); startActivityForResult(intent, GitActivity.REQUEST_INIT);
} }
}) })
.setNegativeButton(this.getResources().getString(R.string.dialog_negative), new DialogInterface.OnClickListener() { .setNegativeButton(this.getResources().getString(R.string.dialog_negative), new DialogInterface.OnClickListener() {
@ -433,7 +433,7 @@ public class PasswordStore extends ActionBarActivity {
protected void onActivityResult(int requestCode, int resultCode, protected void onActivityResult(int requestCode, int resultCode,
Intent data) { Intent data) {
if (resultCode == RESULT_OK) { if (resultCode == RESULT_OK) {
if (requestCode == GitHandler.REQUEST_CLONE) if (requestCode == GitActivity.REQUEST_CLONE)
checkLocalRepository(); checkLocalRepository();
switch (requestCode) { switch (requestCode) {
@ -446,10 +446,10 @@ public class PasswordStore extends ActionBarActivity {
); );
refreshListAdapter(); refreshListAdapter();
break; break;
case GitHandler.REQUEST_INIT: case GitActivity.REQUEST_INIT:
initRepository(getCurrentFocus()); initRepository(getCurrentFocus());
break; break;
case GitHandler.REQUEST_PULL: case GitActivity.REQUEST_PULL:
updateListAdapter(); updateListAdapter();
break; break;
} }

View file

@ -10,9 +10,10 @@ import android.preference.PreferenceFragment;
import android.support.v7.app.ActionBarActivity; import android.support.v7.app.ActionBarActivity;
import android.util.Log; import android.util.Log;
import android.view.MenuItem; import android.view.MenuItem;
import android.widget.Toast;
import com.zeapo.pwdstore.crypto.PgpHandler; import com.zeapo.pwdstore.crypto.PgpHandler;
import com.zeapo.pwdstore.git.GitHandler; import com.zeapo.pwdstore.git.GitActivity;
import com.zeapo.pwdstore.utils.PasswordRepository; import com.zeapo.pwdstore.utils.PasswordRepository;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
@ -105,8 +106,8 @@ public class UserPreference extends ActionBarActivity implements Preference.OnPr
break; break;
case "git_server_info": case "git_server_info":
{ {
Intent intent = new Intent(this, GitHandler.class); Intent intent = new Intent(this, GitActivity.class);
intent.putExtra("Operation", GitHandler.EDIT_SERVER); intent.putExtra("Operation", GitActivity.EDIT_SERVER);
startActivityForResult(intent, EDIT_GIT_INFO); startActivityForResult(intent, EDIT_GIT_INFO);
} }
break; break;
@ -153,7 +154,7 @@ public class UserPreference extends ActionBarActivity implements Preference.OnPr
{ {
try { try {
copySshKey(data.getData()); copySshKey(data.getData());
Log.i("PREF", "Got key"); Toast.makeText(this, this.getResources().getString(R.string.ssh_key_success_dialog_title), Toast.LENGTH_LONG).show();
setResult(RESULT_OK); setResult(RESULT_OK);
finish(); finish();
} catch (IOException e) } catch (IOException e)

View file

@ -0,0 +1,67 @@
package com.zeapo.pwdstore.git;
import android.app.Activity;
import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.Git;
import java.io.File;
public class CloneOperation extends GitOperation {
private static final String TAG = "CLONEOPT";
/**
* Creates a new clone operation
* @param fileDir the git working tree directory
* @param callingActivity the calling activity
*/
public CloneOperation(File fileDir, Activity callingActivity) {
super(fileDir, callingActivity);
}
/**
* Sets the command using the repository uri
* @param uri the uri of the repository
* @return the current object
*/
public CloneOperation setCommand(String uri) {
this.command = Git.cloneRepository().
setCloneAllBranches(true).
setDirectory(repository.getWorkTree()).
setURI(uri);
return this;
}
/**
* sets the authentication for user/pwd scheme
* @param username the username
* @param password the password
* @return the current object
*/
@Override
public CloneOperation setAuthentication(String username, String password) {
super.setAuthentication(username, password);
return this;
}
/**
* sets the authentication for the ssh-key scheme
* @param sshKey the ssh-key file
* @param username the username
* @param passphrase the passphrase
* @return the current object
*/
@Override
public CloneOperation setAuthentication(File sshKey, String username, String passphrase) {
super.setAuthentication(sshKey, username, passphrase);
return this;
}
@Override
public void execute() throws Exception {
if (this.provider != null) {
((CloneCommand) this.command).setCredentialsProvider(this.provider);
}
new GitAsyncTask(callingActivity, true, false, CloneCommand.class).execute(this.command);
}
}

View file

@ -10,22 +10,17 @@ import android.os.Bundle;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.v7.app.ActionBarActivity; import android.support.v7.app.ActionBarActivity;
import android.text.Editable; import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.util.Log;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.EditText; import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.Spinner; import android.widget.Spinner;
import android.widget.TextView; import android.widget.TextView;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UserInfo;
import com.zeapo.pwdstore.R; import com.zeapo.pwdstore.R;
import com.zeapo.pwdstore.UserPreference; import com.zeapo.pwdstore.UserPreference;
import com.zeapo.pwdstore.utils.PasswordRepository; import com.zeapo.pwdstore.utils.PasswordRepository;
@ -34,29 +29,17 @@ import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.Git;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.eclipse.jgit.api.GitCommand;
import org.eclipse.jgit.api.PullCommand;
import org.eclipse.jgit.api.PushCommand;
import org.eclipse.jgit.errors.UnsupportedCredentialItem;
import org.eclipse.jgit.transport.CredentialItem;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.CredentialsProviderUserInfo;
import org.eclipse.jgit.transport.JschConfigSessionFactory;
import org.eclipse.jgit.transport.OpenSshConfig;
import org.eclipse.jgit.transport.SshSessionFactory;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.eclipse.jgit.util.FS;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Method;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
// TODO move the messages to strings.xml // TODO move the messages to strings.xml
public class GitHandler extends ActionBarActivity { public class GitActivity extends ActionBarActivity {
private static final String TAG = "GitAct";
private Activity activity; private Activity activity;
private Context context; private Context context;
@ -77,8 +60,6 @@ public class GitHandler extends ActionBarActivity {
public static final int REQUEST_INIT = 104; public static final int REQUEST_INIT = 104;
public static final int EDIT_SERVER = 105; public static final int EDIT_SERVER = 105;
private static final int GET_SSH_KEY_FROM_CLONE = 201;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -98,11 +79,11 @@ public class GitHandler extends ActionBarActivity {
case REQUEST_CLONE: case REQUEST_CLONE:
case EDIT_SERVER: case EDIT_SERVER:
setContentView(R.layout.activity_git_clone); setContentView(R.layout.activity_git_clone);
setTitle(R.string.title_activity_git_clone);
final Spinner protcol_spinner = (Spinner) findViewById(R.id.clone_protocol); final Spinner protcol_spinner = (Spinner) findViewById(R.id.clone_protocol);
final Spinner connection_mode_spinner = (Spinner) findViewById(R.id.connection_mode); final Spinner connection_mode_spinner = (Spinner) findViewById(R.id.connection_mode);
// init the spinner for connection modes // init the spinner for connection modes
final ArrayAdapter<CharSequence> connection_mode_adapter = ArrayAdapter.createFromResource(this, final ArrayAdapter<CharSequence> connection_mode_adapter = ArrayAdapter.createFromResource(this,
R.array.connection_modes, android.R.layout.simple_spinner_item); R.array.connection_modes, android.R.layout.simple_spinner_item);
@ -131,9 +112,9 @@ public class GitHandler extends ActionBarActivity {
new AdapterView.OnItemSelectedListener() { new AdapterView.OnItemSelectedListener() {
@Override @Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) { public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
protocol = ((Spinner)findViewById(R.id.clone_protocol)).getSelectedItem().toString(); protocol = ((Spinner) findViewById(R.id.clone_protocol)).getSelectedItem().toString();
if (protocol.equals("ssh://")) { if (protocol.equals("ssh://")) {
((EditText)findViewById(R.id.clone_uri)).setHint("user@hostname:path"); ((EditText) findViewById(R.id.clone_uri)).setHint("user@hostname:path");
((EditText) findViewById(R.id.server_port)).setHint(R.string.default_ssh_port); ((EditText) findViewById(R.id.server_port)).setHint(R.string.default_ssh_port);
@ -141,7 +122,7 @@ public class GitHandler extends ActionBarActivity {
connection_mode_spinner.setSelection(0); connection_mode_spinner.setSelection(0);
connection_mode_spinner.setEnabled(true); connection_mode_spinner.setEnabled(true);
} else { } else {
((EditText)findViewById(R.id.clone_uri)).setHint("hostname/path"); ((EditText) findViewById(R.id.clone_uri)).setHint("hostname/path");
((EditText) findViewById(R.id.server_port)).setHint(R.string.default_https_port); ((EditText) findViewById(R.id.server_port)).setHint(R.string.default_https_port);
@ -158,13 +139,24 @@ public class GitHandler extends ActionBarActivity {
} }
); );
if (protocol.equals("ssh://")) {
protcol_spinner.setSelection(0);
} else {
protcol_spinner.setSelection(1);
}
if (connectionMode.equals("ssh-key")) {
connection_mode_spinner.setSelection(0);
} else {
connection_mode_spinner.setSelection(1);
}
// init the server information // init the server information
final EditText server_url = ((EditText) findViewById(R.id.server_url)); final EditText server_url = ((EditText) findViewById(R.id.server_url));
final EditText server_port = ((EditText) findViewById(R.id.server_port)); final EditText server_port = ((EditText) findViewById(R.id.server_port));
final EditText server_path = ((EditText) findViewById(R.id.server_path)); final EditText server_path = ((EditText) findViewById(R.id.server_path));
final EditText server_user = ((EditText) findViewById(R.id.server_user)); final EditText server_user = ((EditText) findViewById(R.id.server_user));
final EditText server_uri = ((EditText)findViewById(R.id.clone_uri)); final EditText server_uri = ((EditText) findViewById(R.id.clone_uri));
View.OnFocusChangeListener updateListener = new View.OnFocusChangeListener() { View.OnFocusChangeListener updateListener = new View.OnFocusChangeListener() {
@Override @Override
@ -180,7 +172,8 @@ public class GitHandler extends ActionBarActivity {
server_url.addTextChangedListener(new TextWatcher() { server_url.addTextChangedListener(new TextWatcher() {
@Override @Override
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { } public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
}
@Override @Override
public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
@ -189,11 +182,13 @@ public class GitHandler extends ActionBarActivity {
} }
@Override @Override
public void afterTextChanged(Editable editable) { } public void afterTextChanged(Editable editable) {
}
}); });
server_port.addTextChangedListener(new TextWatcher() { server_port.addTextChangedListener(new TextWatcher() {
@Override @Override
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { } public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
}
@Override @Override
public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
@ -202,11 +197,13 @@ public class GitHandler extends ActionBarActivity {
} }
@Override @Override
public void afterTextChanged(Editable editable) { } public void afterTextChanged(Editable editable) {
}
}); });
server_user.addTextChangedListener(new TextWatcher() { server_user.addTextChangedListener(new TextWatcher() {
@Override @Override
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { } public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
}
@Override @Override
public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
@ -215,11 +212,13 @@ public class GitHandler extends ActionBarActivity {
} }
@Override @Override
public void afterTextChanged(Editable editable) { } public void afterTextChanged(Editable editable) {
}
}); });
server_path.addTextChangedListener(new TextWatcher() { server_path.addTextChangedListener(new TextWatcher() {
@Override @Override
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { } public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
}
@Override @Override
public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
@ -228,7 +227,8 @@ public class GitHandler extends ActionBarActivity {
} }
@Override @Override
public void afterTextChanged(Editable editable) { } public void afterTextChanged(Editable editable) {
}
}); });
server_uri.addTextChangedListener(new TextWatcher() { server_uri.addTextChangedListener(new TextWatcher() {
@ -247,8 +247,7 @@ public class GitHandler extends ActionBarActivity {
} }
}); });
if (operationCode == EDIT_SERVER) if (operationCode == EDIT_SERVER) {
{
findViewById(R.id.clone_button).setVisibility(View.INVISIBLE); findViewById(R.id.clone_button).setVisibility(View.INVISIBLE);
findViewById(R.id.save_button).setVisibility(View.VISIBLE); findViewById(R.id.save_button).setVisibility(View.VISIBLE);
} else { } else {
@ -256,21 +255,24 @@ public class GitHandler extends ActionBarActivity {
findViewById(R.id.save_button).setVisibility(View.INVISIBLE); findViewById(R.id.save_button).setVisibility(View.INVISIBLE);
} }
updateURI();
break; break;
case REQUEST_PULL: case REQUEST_PULL:
authenticateAndRun("pullOperation"); pullFromRepository();
break; break;
case REQUEST_PUSH: case REQUEST_PUSH:
authenticateAndRun("pushOperation"); pushToRepository();
break; break;
} }
} }
/** Fills in the server_uri field with the information coming from other fields */ /**
* Fills in the server_uri field with the information coming from other fields
*/
private void updateURI() { private void updateURI() {
EditText uri = (EditText) findViewById(R.id.clone_uri); EditText uri = (EditText) findViewById(R.id.clone_uri);
EditText server_url = ((EditText) findViewById(R.id.server_url)); EditText server_url = ((EditText) findViewById(R.id.server_url));
@ -279,10 +281,8 @@ public class GitHandler extends ActionBarActivity {
EditText server_user = ((EditText) findViewById(R.id.server_user)); EditText server_user = ((EditText) findViewById(R.id.server_user));
if (uri != null) { if (uri != null) {
switch (protocol) switch (protocol) {
{ case "ssh://": {
case "ssh://":
{
String hostname = String hostname =
server_user.getText() server_user.getText()
+ "@" + + "@" +
@ -306,8 +306,7 @@ public class GitHandler extends ActionBarActivity {
if (!hostname.equals("@:")) uri.setText(hostname); if (!hostname.equals("@:")) uri.setText(hostname);
} }
break; break;
case "https://": case "https://": {
{
StringBuilder hostname = new StringBuilder(); StringBuilder hostname = new StringBuilder();
hostname.append(server_url.getText().toString().trim()); hostname.append(server_url.getText().toString().trim());
@ -325,13 +324,15 @@ public class GitHandler extends ActionBarActivity {
} }
break; break;
default: default:
break; break;
} }
} }
} }
/** Splits the information in server_uri into the other fields */ /**
* Splits the information in server_uri into the other fields
*/
private void splitURI() { private void splitURI() {
EditText server_uri = (EditText) findViewById(R.id.clone_uri); EditText server_uri = (EditText) findViewById(R.id.clone_uri);
EditText server_url = ((EditText) findViewById(R.id.server_url)); EditText server_url = ((EditText) findViewById(R.id.server_url));
@ -397,76 +398,35 @@ public class GitHandler extends ActionBarActivity {
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
protected class GitConfigSessionFactory extends JschConfigSessionFactory { /**
* Saves the configuration found in the form
*/
private void saveConfiguration() {
// remember the settings
SharedPreferences.Editor editor = settings.edit();
protected void configure(OpenSshConfig.Host hc, Session session) { editor.putString("git_remote_server", ((EditText) findViewById(R.id.server_url)).getText().toString());
session.setConfig("StrictHostKeyChecking", "no"); editor.putString("git_remote_location", ((EditText) findViewById(R.id.server_path)).getText().toString());
} editor.putString("git_remote_username", ((EditText) findViewById(R.id.server_user)).getText().toString());
editor.putString("git_remote_protocol", protocol);
@Override editor.putString("git_remote_auth", connectionMode);
protected JSch editor.putString("git_remote_port", port);
getJSch(final OpenSshConfig.Host hc, FS fs) throws JSchException { editor.commit();
JSch jsch = super.getJSch(hc, fs);
jsch.removeAllIdentity();
return jsch;
}
} }
protected class SshConfigSessionFactory extends GitConfigSessionFactory { /**
private String sshKey; * Save the repository information to the shared preferences settings
private String passphrase; *
* @param view
public SshConfigSessionFactory(String sshKey, String passphrase) { */
this.sshKey = sshKey; public void saveConfiguration(View view) {
this.passphrase = passphrase; saveConfiguration();
} PasswordRepository.addRemote("origin", ((EditText) findViewById(R.id.clone_uri)).getText().toString(), true);
@Override
protected JSch
getJSch(final OpenSshConfig.Host hc, FS fs) throws JSchException {
JSch jsch = super.getJSch(hc, fs);
jsch.removeAllIdentity();
jsch.addIdentity(sshKey);
return jsch;
}
@Override
protected void configure(OpenSshConfig.Host hc, Session session) {
session.setConfig("StrictHostKeyChecking", "no");
CredentialsProvider provider = new CredentialsProvider() {
@Override
public boolean isInteractive() {
return false;
}
@Override
public boolean supports(CredentialItem... items) {
return true;
}
@Override
public boolean get(URIish uri, CredentialItem... items) throws UnsupportedCredentialItem {
for (CredentialItem item : items) {
if (item instanceof CredentialItem.Username) {
((CredentialItem.Username) item).setValue(settings.getString("git_remote_username", "git"));
continue;
}
if (item instanceof CredentialItem.StringType) {
((CredentialItem.StringType) item).setValue(passphrase);
}
}
return true;
}
};
UserInfo userInfo = new CredentialsProviderUserInfo(session, provider);
session.setUserInfo(userInfo);
}
} }
/** /**
* Clones the repository, the directory exists, deletes it * Clones the repository, the directory exists, deletes it
*
* @param view * @param view
*/ */
public void cloneRepository(View view) { public void cloneRepository(View view) {
@ -505,8 +465,7 @@ public class GitHandler extends ActionBarActivity {
username = hostname.split("@")[0]; username = hostname.split("@")[0];
} }
if (localDir.exists() && localDir.listFiles().length != 0) {
if (localDir.exists()) {
new AlertDialog.Builder(this). new AlertDialog.Builder(this).
setTitle(R.string.dialog_delete_title). setTitle(R.string.dialog_delete_title).
setMessage(R.string.dialog_delete_msg). setMessage(R.string.dialog_delete_msg).
@ -516,7 +475,15 @@ public class GitHandler extends ActionBarActivity {
public void onClick(DialogInterface dialog, int id) { public void onClick(DialogInterface dialog, int id) {
try { try {
FileUtils.deleteDirectory(localDir); FileUtils.deleteDirectory(localDir);
authenticateAndRun("cloneOperation"); 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();
}
} catch (IOException e) { } catch (IOException e) {
//TODO Handle the exception correctly if we are unable to delete the directory... //TODO Handle the exception correctly if we are unable to delete the directory...
e.printStackTrace(); e.printStackTrace();
@ -538,8 +505,12 @@ public class GitHandler extends ActionBarActivity {
). ).
show(); show();
} else { } else {
saveConfiguration();
try { try {
authenticateAndRun("cloneOperation"); new CloneOperation(localDir, activity)
.setCommand(hostname)
.executeAfterAuthentication(connectionMode, settings.getString("git_remote_username", "git"), new File(getFilesDir() + "/.ssh_key"));
} catch (Exception e) { } catch (Exception e) {
//This is what happens when jgit fails :( //This is what happens when jgit fails :(
//TODO Handle the diffent cases of exceptions //TODO Handle the diffent cases of exceptions
@ -548,53 +519,28 @@ public class GitHandler extends ActionBarActivity {
} }
} }
/**
* Pull the latest changes from the remote repository and merges them locally
*/
public void pullFromRepository() {
syncRepository(REQUEST_PULL);
}
/** /**
* Save the repository information to the shared preferences settings * Pushes the latest changes from the local repository to the remote one
* @param view
*/ */
public void saveConfiguration(View view) { public void pushToRepository() {
// remember the settings syncRepository(REQUEST_PUSH);
SharedPreferences.Editor editor = settings.edit();
editor.putString("git_remote_server", ((EditText) findViewById(R.id.server_url)).getText().toString());
editor.putString("git_remote_location", ((EditText) findViewById(R.id.server_path)).getText().toString());
editor.putString("git_remote_username", ((EditText) findViewById(R.id.server_user)).getText().toString());
editor.putString("git_remote_protocol", protocol);
editor.putString("git_remote_auth", connectionMode);
editor.putString("git_remote_port", port);
editor.commit();
PasswordRepository.addRemote("origin", ((EditText) findViewById(R.id.clone_uri)).getText().toString(), true);
} }
public void cloneOperation(UsernamePasswordCredentialsProvider provider) { /**
* Syncs the local repository with the remote one (either pull or push)
// remember the settings * @param operation the operation to execute can be REQUEST_PULL or REQUEST_PUSH
SharedPreferences.Editor editor = settings.edit(); */
private void syncRepository(int operation) {
editor.putString("git_remote_server", ((EditText) findViewById(R.id.server_url)).getText().toString());
editor.putString("git_remote_location", ((EditText) findViewById(R.id.server_path)).getText().toString());
editor.putString("git_remote_username", ((EditText) findViewById(R.id.server_user)).getText().toString());
editor.putString("git_remote_protocol", protocol);
editor.putString("git_remote_auth", connectionMode);
editor.putString("git_remote_port", port);
editor.commit();
CloneCommand cmd = Git.cloneRepository().
setCredentialsProvider(provider).
setCloneAllBranches(true).
setDirectory(localDir).
setURI(hostname);
new GitAsyncTask(activity, true, false, CloneCommand.class).execute(cmd);
}
public void pullOperation(UsernamePasswordCredentialsProvider provider) {
if (settings.getString("git_remote_username", "").isEmpty() || if (settings.getString("git_remote_username", "").isEmpty() ||
settings.getString("git_remote_server", "").isEmpty() || settings.getString("git_remote_server", "").isEmpty() ||
settings.getString("git_remote_location", "").isEmpty() ) settings.getString("git_remote_location", "").isEmpty())
new AlertDialog.Builder(this) new AlertDialog.Builder(this)
.setMessage(activity.getResources().getString(R.string.set_information_dialog_text)) .setMessage(activity.getResources().getString(R.string.set_information_dialog_text))
.setPositiveButton(activity.getResources().getString(R.string.dialog_positive), new DialogInterface.OnClickListener() { .setPositiveButton(activity.getResources().getString(R.string.dialog_positive), new DialogInterface.OnClickListener() {
@ -616,185 +562,23 @@ public class GitHandler extends ActionBarActivity {
else { else {
// check that the remote origin is here, else add it // check that the remote origin is here, else add it
PasswordRepository.addRemote("origin", settings.getString("git_remote_username", "user") PasswordRepository.addRemote("origin", hostname, false);
+ "@" + GitOperation op;
settings.getString("git_remote_server", "server.com").trim()
+ ":" +
settings.getString("git_remote_location", "path/to/repository"), false);
GitCommand cmd; if (operation == REQUEST_PULL) {
if (provider != null) op = new PullOperation(localDir, activity).setCommand();
cmd = new Git(PasswordRepository.getRepository(new File(""))) } else if (operation == REQUEST_PUSH) {
.pull() op = new PushOperation(localDir, activity).setCommand();
.setRebase(true)
.setRemote("origin")
.setCredentialsProvider(provider);
else
cmd = new Git(PasswordRepository.getRepository(new File("")))
.pull()
.setRebase(true)
.setRemote("origin");
new GitAsyncTask(activity, true, false, PullCommand.class).execute(cmd);
}
}
public void pushOperation(UsernamePasswordCredentialsProvider provider) {
if (settings.getString("git_remote_username", "user").isEmpty() ||
settings.getString("git_remote_server", "server.com").trim().isEmpty() ||
settings.getString("git_remote_location", "path/to/repository").isEmpty() )
new AlertDialog.Builder(this)
.setMessage("You have to set the information about the server before synchronizing with the server")
.setPositiveButton("On my way!", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Intent intent = new Intent(activity, UserPreference.class);
startActivityForResult(intent, REQUEST_PUSH);
}
})
.setNegativeButton("Nah... later", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
// do nothing :(
setResult(RESULT_OK);
finish();
}
})
.show();
else {
// check that the remote origin is here, else add it
PasswordRepository.addRemote("origin", settings.getString("git_remote_username", "user")
+ "@" +
settings.getString("git_remote_server", "server.com").trim()
+ ":" +
settings.getString("git_remote_location", "path/to/repository"), false);
GitCommand cmd;
if (provider != null)
cmd = new Git(PasswordRepository.getRepository(new File("")))
.push()
.setPushAll()
.setRemote("origin")
.setCredentialsProvider(provider);
else
cmd = new Git(PasswordRepository.getRepository(new File("")))
.push()
.setPushAll()
.setRemote("origin");
new GitAsyncTask(activity, true, false, PushCommand.class).execute(cmd);
}
}
/** Finds the method and provides it with authentication paramters via invokeWithAuthentication */
private void authenticateAndRun(String operation) {
try {
invokeWithAuthentication(this, GitHandler.class.getMethod(operation, UsernamePasswordCredentialsProvider.class));
} catch (Exception e) {
e.printStackTrace();
}
}
/** Calls a method encapsulating a GitCommand and providing it with authentication parameters
*
* @param activity
* @param method
*/
private void invokeWithAuthentication(final GitHandler activity, final Method method) {
if (connectionMode.equalsIgnoreCase("ssh-key")) {
final File sshKey = new File(getFilesDir() + "/.ssh_key");
if (!sshKey.exists()) {
new AlertDialog.Builder(this)
.setMessage(activity.getResources().getString(R.string.ssh_preferences_dialog_text))
.setTitle(activity.getResources().getString(R.string.ssh_preferences_dialog_title))
.setPositiveButton(activity.getResources().getString(R.string.dialog_ok), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
try {
Intent intent = new Intent(getApplicationContext(), UserPreference.class);
intent.putExtra("operation", "get_ssh_key");
startActivityForResult(intent, GET_SSH_KEY_FROM_CLONE);
} catch (Exception e) {
System.out.println("Exception caught :(");
e.printStackTrace();
}
}
}).setNegativeButton(activity.getResources().getString(R.string.dialog_cancel), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
// Do nothing...
}
}).show();
} else { } else {
final EditText passphrase = new EditText(activity); Log.e(TAG, "Sync operation not recognized : " + operation);
passphrase.setHint("Passphrase"); return;
passphrase.setWidth(LinearLayout.LayoutParams.MATCH_PARENT);
passphrase.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
new AlertDialog.Builder(activity)
.setTitle(activity.getResources().getString(R.string.passphrase_dialog_title))
.setMessage(activity.getResources().getString(R.string.passphrase_dialog_text))
.setView(passphrase)
.setPositiveButton(activity.getResources().getString(R.string.dialog_ok), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
SshSessionFactory.setInstance(new GitConfigSessionFactory());
try {
JschConfigSessionFactory sessionFactory = new SshConfigSessionFactory(sshKey.getAbsolutePath(), passphrase.getText().toString());
SshSessionFactory.setInstance(sessionFactory);
try {
method.invoke(activity, (UsernamePasswordCredentialsProvider) null);
} catch (Exception e){
e.printStackTrace();
}
} catch (Exception e){
e.printStackTrace();
}
}
}).setNegativeButton(activity.getResources().getString(R.string.dialog_cancel), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Do nothing.
}
}).show();
} }
} else {
final EditText password = new EditText(activity);
password.setHint("Password");
password.setWidth(LinearLayout.LayoutParams.MATCH_PARENT);
password.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
new AlertDialog.Builder(activity) try {
.setTitle(activity.getResources().getString(R.string.passphrase_dialog_title)) op.executeAfterAuthentication(connectionMode, settings.getString("git_remote_username", "git"), new File(getFilesDir() + "/.ssh_key"));
.setMessage(activity.getResources().getString(R.string.password_dialog_text)) } catch (Exception e) {
.setView(password) e.printStackTrace();
.setPositiveButton(activity.getResources().getString(R.string.dialog_ok), new DialogInterface.OnClickListener() { }
public void onClick(DialogInterface dialog, int whichButton) {
SshSessionFactory.setInstance(new GitConfigSessionFactory());
try {
method.invoke(activity,
new UsernamePasswordCredentialsProvider(
settings.getString("git_remote_username", "git"),
password.getText().toString())
);
} catch (Exception e){
e.printStackTrace();
}
}
}).setNegativeButton(activity.getResources().getString(R.string.dialog_cancel), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Do nothing.
}
}).show();
} }
} }
@ -807,16 +591,31 @@ public class GitHandler extends ActionBarActivity {
} }
if (resultCode == RESULT_OK) { if (resultCode == RESULT_OK) {
GitOperation op;
switch (requestCode) { switch (requestCode) {
case REQUEST_PULL: case REQUEST_PULL:
authenticateAndRun("pullOperation"); op = new PullOperation(localDir, activity).setCommand();
break; break;
case REQUEST_PUSH: case REQUEST_PUSH:
authenticateAndRun("pushOperation"); op = new PushOperation(localDir, activity).setCommand();
break; break;
case GET_SSH_KEY_FROM_CLONE:
authenticateAndRun("cloneOperation"); case GitOperation.GET_SSH_KEY_FROM_CLONE:
op = new CloneOperation(localDir, activity).setCommand(hostname);
break;
default:
Log.e(TAG, "Operation not recognized : " + resultCode);
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();
} }
} }

View file

@ -0,0 +1,170 @@
package com.zeapo.pwdstore.git;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.support.annotation.Nullable;
import android.text.InputType;
import android.util.Log;
import android.widget.EditText;
import android.widget.LinearLayout;
import com.zeapo.pwdstore.R;
import com.zeapo.pwdstore.UserPreference;
import com.zeapo.pwdstore.git.config.GitConfigSessionFactory;
import com.zeapo.pwdstore.git.config.SshConfigSessionFactory;
import com.zeapo.pwdstore.utils.PasswordRepository;
import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.GitCommand;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.JschConfigSessionFactory;
import org.eclipse.jgit.transport.SshSessionFactory;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import java.io.File;
public abstract class GitOperation {
private static final String TAG = "GitOpt";
public static final int GET_SSH_KEY_FROM_CLONE = 201;
protected final Repository repository;
protected final Activity callingActivity;
protected UsernamePasswordCredentialsProvider provider;
protected GitCommand command;
/**
* Creates a new git operation
*
* @param fileDir the git working tree directory
* @param callingActivity the calling activity
*/
public GitOperation(File fileDir, Activity callingActivity) {
this.repository = PasswordRepository.getRepository(fileDir);
this.callingActivity = callingActivity;
}
/**
* Sets the authentication using user/pwd scheme
*
* @param username the username
* @param password the password
* @return the current object
*/
public GitOperation setAuthentication(String username, String password) {
SshSessionFactory.setInstance(new GitConfigSessionFactory());
this.provider = new UsernamePasswordCredentialsProvider(username, password);
return this;
}
/**
* Sets the authentication using ssh-key scheme
*
* @param sshKey the ssh-key file
* @param username the username
* @param passphrase the passphrase
* @return the current object
*/
public GitOperation setAuthentication(File sshKey, String username, String passphrase) {
JschConfigSessionFactory sessionFactory = new SshConfigSessionFactory(sshKey.getAbsolutePath(), username, passphrase);
SshSessionFactory.setInstance(sessionFactory);
this.provider = null;
return this;
}
/**
* Executes the GitCommand in an async task
*
* @throws Exception
*/
public abstract void execute() throws Exception;
/**
* Executes the GitCommand in an async task after creating the authentication
*
* @param connectionMode the server-connection mode
* @param username the username
* @param sshKey the ssh-key file
* @throws Exception
*/
public void executeAfterAuthentication(String connectionMode, final String username, @Nullable final File sshKey) throws Exception {
if (connectionMode.equalsIgnoreCase("ssh-key")) {
if (sshKey == null || !sshKey.exists()) {
new AlertDialog.Builder(callingActivity)
.setMessage(callingActivity.getResources().getString(R.string.ssh_preferences_dialog_text))
.setTitle(callingActivity.getResources().getString(R.string.ssh_preferences_dialog_title))
.setPositiveButton(callingActivity.getResources().getString(R.string.dialog_ok), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
try {
// Ask the UserPreference to provide us with the ssh-key
// onResult has to be handled by the callingActivity
Intent intent = new Intent(callingActivity.getApplicationContext(), UserPreference.class);
intent.putExtra("operation", "get_ssh_key");
callingActivity.startActivityForResult(intent, GET_SSH_KEY_FROM_CLONE);
} catch (Exception e) {
System.out.println("Exception caught :(");
e.printStackTrace();
}
}
}).setNegativeButton(callingActivity.getResources().getString(R.string.dialog_cancel), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
// Do nothing...
}
}).show();
} else {
final EditText passphrase = new EditText(callingActivity);
passphrase.setHint("Passphrase");
passphrase.setWidth(LinearLayout.LayoutParams.MATCH_PARENT);
passphrase.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
new AlertDialog.Builder(callingActivity)
.setTitle(callingActivity.getResources().getString(R.string.passphrase_dialog_title))
.setMessage(callingActivity.getResources().getString(R.string.passphrase_dialog_text))
.setView(passphrase)
.setPositiveButton(callingActivity.getResources().getString(R.string.dialog_ok), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
try {
// Authenticate using the ssh-key and then execute the command
setAuthentication(sshKey, username, passphrase.getText().toString()).execute();
} catch (Exception e) {
e.printStackTrace();
}
}
}).setNegativeButton(callingActivity.getResources().getString(R.string.dialog_cancel), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Do nothing.
}
}).show();
}
} else {
final EditText password = new EditText(callingActivity);
password.setHint("Password");
password.setWidth(LinearLayout.LayoutParams.MATCH_PARENT);
password.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
new AlertDialog.Builder(callingActivity)
.setTitle(callingActivity.getResources().getString(R.string.passphrase_dialog_title))
.setMessage(callingActivity.getResources().getString(R.string.password_dialog_text))
.setView(password)
.setPositiveButton(callingActivity.getResources().getString(R.string.dialog_ok), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// authenticate using the user/pwd and then execute the command
try {
setAuthentication(username, password.getText().toString()).execute();
} catch (Exception e) {
e.printStackTrace();
}
}
}).setNegativeButton(callingActivity.getResources().getString(R.string.dialog_cancel), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Do nothing.
}
}).show();
}
}
}

View file

@ -0,0 +1,41 @@
package com.zeapo.pwdstore.git;
import android.app.Activity;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.PullCommand;
import java.io.File;
public class PullOperation extends GitOperation {
/**
* Creates a new git operation
*
* @param fileDir the git working tree directory
* @param callingActivity the calling activity
*/
public PullOperation(File fileDir, Activity callingActivity) {
super(fileDir, callingActivity);
}
/**
* Sets the command
* @return the current object
*/
public PullOperation setCommand() {
this.command = new Git(repository)
.pull()
.setRebase(true)
.setRemote("origin");
return this;
}
@Override
public void execute() throws Exception {
if (this.provider != null) {
((PullCommand) this.command).setCredentialsProvider(this.provider);
}
new GitAsyncTask(callingActivity, true, false, PullCommand.class).execute(this.command);
}
}

View file

@ -0,0 +1,41 @@
package com.zeapo.pwdstore.git;
import android.app.Activity;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.PushCommand;
import java.io.File;
public class PushOperation extends GitOperation {
/**
* Creates a new git operation
*
* @param fileDir the git working tree directory
* @param callingActivity the calling activity
*/
public PushOperation(File fileDir, Activity callingActivity) {
super(fileDir, callingActivity);
}
/**
* Sets the command
* @return the current object
*/
public PushOperation setCommand() {
this.command = new Git(repository)
.push()
.setPushAll()
.setRemote("origin");
return this;
}
@Override
public void execute() throws Exception {
if (this.provider != null) {
((PushCommand) this.command).setCredentialsProvider(this.provider);
}
new GitAsyncTask(callingActivity, true, false, PushCommand.class).execute(this.command);
}
}

View file

@ -0,0 +1,24 @@
package com.zeapo.pwdstore.git.config;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import org.eclipse.jgit.transport.JschConfigSessionFactory;
import org.eclipse.jgit.transport.OpenSshConfig;
import org.eclipse.jgit.util.FS;
public class GitConfigSessionFactory extends JschConfigSessionFactory {
protected void configure(OpenSshConfig.Host hc, Session session) {
session.setConfig("StrictHostKeyChecking", "no");
}
@Override
protected JSch
getJSch(final OpenSshConfig.Host hc, FS fs) throws JSchException {
JSch jsch = super.getJSch(hc, fs);
jsch.removeAllIdentity();
return jsch;
}
}

View file

@ -0,0 +1,70 @@
package com.zeapo.pwdstore.git.config;
import android.content.SharedPreferences;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UserInfo;
import org.eclipse.jgit.errors.UnsupportedCredentialItem;
import org.eclipse.jgit.transport.CredentialItem;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.CredentialsProviderUserInfo;
import org.eclipse.jgit.transport.OpenSshConfig;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.util.FS;
public class SshConfigSessionFactory extends GitConfigSessionFactory {
private String sshKey;
private String passphrase;
private String username;
public SshConfigSessionFactory(String sshKey, String username, String passphrase) {
this.sshKey = sshKey;
this.passphrase = passphrase;
this.username = username;
}
@Override
protected JSch
getJSch(final OpenSshConfig.Host hc, FS fs) throws JSchException {
JSch jsch = super.getJSch(hc, fs);
jsch.removeAllIdentity();
jsch.addIdentity(sshKey);
return jsch;
}
@Override
protected void configure(OpenSshConfig.Host hc, Session session) {
session.setConfig("StrictHostKeyChecking", "no");
CredentialsProvider provider = new CredentialsProvider() {
@Override
public boolean isInteractive() {
return false;
}
@Override
public boolean supports(CredentialItem... items) {
return true;
}
@Override
public boolean get(URIish uri, CredentialItem... items) throws UnsupportedCredentialItem {
for (CredentialItem item : items) {
if (item instanceof CredentialItem.Username) {
((CredentialItem.Username) item).setValue(username);
continue;
}
if (item instanceof CredentialItem.StringType) {
((CredentialItem.StringType) item).setValue(passphrase);
}
}
return true;
}
};
UserInfo userInfo = new CredentialsProviderUserInfo(session, provider);
session.setUserInfo(userInfo);
}
}

View file

@ -6,7 +6,7 @@
android:paddingRight="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin" android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin"
tools:context="com.zeapo.pwdstore.git.GitHandler" tools:context="com.zeapo.pwdstore.git.GitActivity"
android:background="@android:color/white"> android:background="@android:color/white">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -1,7 +1,7 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
xmlns:pwstore="http://schemas.android.com/apk/res-auto" xmlns:pwstore="http://schemas.android.com/apk/res-auto"
tools:context="com.zeapo.pwdstore.git.GitHandler" > tools:context="com.zeapo.pwdstore.git.GitActivity" >
<item android:id="@+id/user_pref" <item android:id="@+id/user_pref"
android:title="@string/action_settings" android:title="@string/action_settings"
android:orderInCategory="100" android:orderInCategory="100"

View file

@ -12,7 +12,7 @@
<string name="dialog_delete_msg">Target directory already exist. Current version support only a single store. Do you want to delete the current password store directory?</string> <string name="dialog_delete_msg">Target directory already exist. Current version support only a single store. Do you want to delete the current password store directory?</string>
<string name="dialog_delete">Delete directory</string> <string name="dialog_delete">Delete directory</string>
<string name="dialog_do_not_delete">Cancel</string> <string name="dialog_do_not_delete">Cancel</string>
<string name="title_activity_git_clone">Clone repository</string> <string name="title_activity_git_clone">Repository information</string>
<!-- Password Store --> <!-- Password Store -->
<string name="creation_dialog_text">Please clone or create a new repository below before trying to add a password or any synchronization operation.</string> <string name="creation_dialog_text">Please clone or create a new repository below before trying to add a password or any synchronization operation.</string>
@ -41,7 +41,7 @@
<!-- Git Async Task --> <!-- Git Async Task -->
<string name="running_dialog_text">Running command...</string> <string name="running_dialog_text">Running command...</string>
<string name="jgit_error_dialog_title">Internal exception occurred</string> <string name="jgit_error_dialog_title">Internal exception occurred</string>
<string name="jgit_error_dialog_text">Message from jgit: /n</string> <string name="jgit_error_dialog_text">Message from jgit: \n</string>
<!-- Git Handler --> <!-- Git Handler -->
<string name="read_only_dialog_text">You are about to use a read-only repository, you will not be able to push to it</string> <string name="read_only_dialog_text">You are about to use a read-only repository, you will not be able to push to it</string>
@ -108,6 +108,7 @@
<string name="pref_password_dialog_title">Set the time you want the password to be in clipboard</string> <string name="pref_password_dialog_title">Set the time you want the password to be in clipboard</string>
<string name="pref_copy_title">Automatically Copy Password</string> <string name="pref_copy_title">Automatically Copy Password</string>
<string name="pref_copy_dialog_title">Automatically copy the password to the clipboard after decryption was successful.</string> <string name="pref_copy_dialog_title">Automatically copy the password to the clipboard after decryption was successful.</string>
<string name="ssh_key_success_dialog_title" translatable="false">SSH-key imported</string>
<string name="ssh_key_error_dialog_title">Error while trying to import the ssh-key</string> <string name="ssh_key_error_dialog_title">Error while trying to import the ssh-key</string>
<string name="ssh_key_error_dialog_text">Message : \n</string> <string name="ssh_key_error_dialog_text">Message : \n</string>
<string name="pref_recursive_filter">Recursive filtering</string> <string name="pref_recursive_filter">Recursive filtering</string>