Authentication works correctly for clone, some cleaning is still required
This commit is contained in:
parent
bbf0175d69
commit
6532252f31
6 changed files with 244 additions and 136 deletions
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="" />
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
|
||||
|
|
|
@ -24,78 +24,118 @@ import android.widget.Spinner;
|
|||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
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 org.eclipse.jgit.api.CloneCommand;
|
||||
import org.eclipse.jgit.api.Git;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.eclipse.jgit.api.errors.InvalidRemoteException;
|
||||
import org.eclipse.jgit.diff.Edit;
|
||||
import org.eclipse.jgit.errors.NoRemoteRepositoryException;
|
||||
import org.eclipse.jgit.errors.UnsupportedCredentialItem;
|
||||
import org.eclipse.jgit.lib.TextProgressMonitor;
|
||||
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.util.FS;
|
||||
import org.eclipse.jgit.util.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
|
||||
public class GitClone extends Activity implements AdapterView.OnItemSelectedListener {
|
||||
public class GitClone extends Activity {
|
||||
|
||||
private Activity activity;
|
||||
private Context context;
|
||||
|
||||
/* The clone process has to be on a different thread than the main one */
|
||||
private class CloneTask extends AsyncTask<File, Integer, Long> {
|
||||
private ProgressDialog dialog;
|
||||
private Activity activity;
|
||||
private Context context;
|
||||
private String protocol;
|
||||
private String connectionMode;
|
||||
|
||||
public CloneTask(Activity activity) {
|
||||
this.activity = activity;
|
||||
context = activity;
|
||||
dialog = new ProgressDialog(context);
|
||||
}
|
||||
|
||||
protected void onPreExecute() {
|
||||
this.dialog.setMessage("Cloning...");
|
||||
this.dialog.setCancelable(false);
|
||||
this.dialog.show();
|
||||
}
|
||||
|
||||
protected void onPostExecute(Long result) {
|
||||
this.dialog.dismiss();
|
||||
}
|
||||
|
||||
|
||||
protected Long doInBackground(File... remote) {
|
||||
int count = remote.length;
|
||||
long totalSize = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
try {
|
||||
Git.cloneRepository().
|
||||
setCloneAllBranches(true).
|
||||
setDirectory(remote[i]).
|
||||
setURI(((TextView) findViewById(R.id.clone_uri)).getText().toString())
|
||||
.call();
|
||||
totalSize++;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
totalSize++;
|
||||
}
|
||||
}
|
||||
return totalSize;
|
||||
}
|
||||
}
|
||||
private File localDir;
|
||||
private String hostname;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_git_clone);
|
||||
|
||||
// init the spinner
|
||||
context = getApplicationContext();
|
||||
activity = this;
|
||||
|
||||
// init the spinner for protocols
|
||||
Spinner protcol_spinner = (Spinner) findViewById(R.id.clone_protocol);
|
||||
ArrayAdapter<CharSequence> protocol_adapter = ArrayAdapter.createFromResource(this,
|
||||
R.array.clone_protocols, android.R.layout.simple_spinner_item);
|
||||
protocol_adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
protcol_spinner.setAdapter(protocol_adapter);
|
||||
protcol_spinner.setOnItemSelectedListener(
|
||||
new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
protocol = ((Spinner)findViewById(R.id.clone_protocol)).getSelectedItem().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> adapterView) {
|
||||
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// init the spinner for connection modes
|
||||
Spinner connection_mode_spinner = (Spinner) findViewById(R.id.connection_mode);
|
||||
ArrayAdapter<CharSequence> connection_mode_adapter = ArrayAdapter.createFromResource(this,
|
||||
R.array.connection_modes, android.R.layout.simple_spinner_item);
|
||||
connection_mode_adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
connection_mode_spinner.setAdapter(connection_mode_adapter);
|
||||
connection_mode_spinner.setOnItemSelectedListener(this);
|
||||
connection_mode_spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
String selection = ((Spinner) findViewById(R.id.connection_mode)).getSelectedItem().toString();
|
||||
|
||||
if (selection.equalsIgnoreCase("ssh-key")) {
|
||||
new AlertDialog.Builder(activity)
|
||||
.setMessage("Authentication method not implemented yet")
|
||||
.setPositiveButton("OK",
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
dialog.cancel();
|
||||
}
|
||||
}
|
||||
).show();
|
||||
((Button) findViewById(R.id.clone_button)).setEnabled(false);
|
||||
} else {
|
||||
((Button) findViewById(R.id.clone_button)).setEnabled(true);
|
||||
}
|
||||
connectionMode = selection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> adapterView) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -117,54 +157,140 @@ public class GitClone extends Activity implements AdapterView.OnItemSelectedList
|
|||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
public void cloneRepository(View view) {
|
||||
/* The clone process has to be on a different thread than the main one */
|
||||
private class CloneTask extends AsyncTask<CloneCommand, Integer, Long> {
|
||||
private ProgressDialog dialog;
|
||||
|
||||
final File localDir = new File(getApplicationContext().getCacheDir().getAbsoluteFile() + "/store");
|
||||
public CloneTask(Activity activity) {
|
||||
context = activity;
|
||||
dialog = new ProgressDialog(context);
|
||||
}
|
||||
|
||||
protected void onPreExecute() {
|
||||
this.dialog.setMessage("Cloning...");
|
||||
this.dialog.setCancelable(false);
|
||||
this.dialog.show();
|
||||
}
|
||||
|
||||
protected void onPostExecute(Long result) {
|
||||
if (result < 0) {
|
||||
new AlertDialog.Builder(activity).
|
||||
setTitle("Invalid remote repository path").
|
||||
setMessage("Please check that the repository path is correct.\nDid you forget to specify the path after the hostname?").
|
||||
setPositiveButton("OK", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
|
||||
if (localDir.exists()) {
|
||||
AlertDialog.Builder builder1 = new AlertDialog.Builder(this);
|
||||
builder1.setMessage(R.string.dialog_delete_msg);
|
||||
builder1.setCancelable(true);
|
||||
builder1.setPositiveButton(R.string.dialog_delete,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
try {
|
||||
FileUtils.deleteDirectory(localDir);
|
||||
} catch (IOException e) {
|
||||
//TODO Handle the exception correctly
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
dialog.cancel();
|
||||
}
|
||||
}
|
||||
);
|
||||
builder1.setNegativeButton(R.string.dialog_do_not_delete,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
dialog.cancel();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
AlertDialog alert11 = builder1.create();
|
||||
alert11.show();
|
||||
}).show();
|
||||
}
|
||||
this.dialog.dismiss();
|
||||
}
|
||||
|
||||
|
||||
protected Long doInBackground(CloneCommand... cmd) {
|
||||
int count = cmd.length;
|
||||
long totalSize = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
try {
|
||||
cmd[i].call();
|
||||
} catch (InvalidRemoteException e) {
|
||||
return new Long(-1);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
totalSize++;
|
||||
}
|
||||
return totalSize;
|
||||
}
|
||||
}
|
||||
|
||||
protected class GitConfigSessionFactory extends JschConfigSessionFactory {
|
||||
|
||||
public 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void cloneRepository(View view) {
|
||||
localDir = new File(getApplicationContext().getCacheDir().getAbsoluteFile() + "/store");
|
||||
|
||||
hostname = ((TextView) findViewById(R.id.clone_uri)).getText().toString();
|
||||
// don't ask the user, take off the protocol that he puts in
|
||||
hostname = hostname.replaceFirst("^.+://", "");
|
||||
((TextView) findViewById(R.id.clone_uri)).setText(hostname);
|
||||
|
||||
// now cheat a little and prepend the real protocol
|
||||
// jGit does not accept a ssh:// but requires https://
|
||||
if (!protocol.equals("ssh://")) hostname = new String(protocol + hostname);
|
||||
|
||||
if (localDir.exists()) {
|
||||
new AlertDialog.Builder(this).
|
||||
setTitle(R.string.dialog_delete_title).
|
||||
setMessage(R.string.dialog_delete_msg).
|
||||
setCancelable(false).
|
||||
setPositiveButton(R.string.dialog_delete,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
try {
|
||||
FileUtils.deleteDirectory(localDir);
|
||||
authenticateThenClone(localDir);
|
||||
} catch (IOException e) {
|
||||
//TODO Handle the exception correctly if we are unable to delete the directory...
|
||||
e.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
//This is what happens when jgit fails :(
|
||||
//TODO Handle the diffent cases of exceptions
|
||||
}
|
||||
|
||||
dialog.cancel();
|
||||
}
|
||||
}
|
||||
).
|
||||
setNegativeButton(R.string.dialog_do_not_delete,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
dialog.cancel();
|
||||
}
|
||||
}
|
||||
).
|
||||
show();
|
||||
} else {
|
||||
try {
|
||||
authenticateThenClone(localDir);
|
||||
} catch (Exception e) {
|
||||
//This is what happens when jgit fails :(
|
||||
//TODO Handle the diffent cases of exceptions
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void authenticateThenClone(final File localDir) {
|
||||
String connectionMode = ((Spinner) findViewById(R.id.connection_mode)).getSelectedItem().toString();
|
||||
|
||||
if (connectionMode.equalsIgnoreCase("ssh-key")) {
|
||||
|
||||
} else {
|
||||
// Set an EditText view to get user input
|
||||
final LinearLayout layout = new LinearLayout(this);
|
||||
final LinearLayout layout = new LinearLayout(activity);
|
||||
layout.setOrientation(LinearLayout.VERTICAL);
|
||||
|
||||
final EditText username = new EditText(this);
|
||||
final EditText username = new EditText(activity);
|
||||
username.setHint("Username");
|
||||
username.setWidth(LinearLayout.LayoutParams.MATCH_PARENT);
|
||||
|
||||
final EditText password = new EditText(this);
|
||||
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);
|
||||
|
@ -172,54 +298,31 @@ public class GitClone extends Activity implements AdapterView.OnItemSelectedList
|
|||
layout.addView(username);
|
||||
layout.addView(password);
|
||||
|
||||
|
||||
new AlertDialog.Builder(this)
|
||||
new AlertDialog.Builder(activity)
|
||||
.setTitle("Authenticate")
|
||||
.setMessage("Please provide your usename and password for this repository")
|
||||
.setView(layout)
|
||||
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
|
||||
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
//TODO use Jsch to set the authentication method
|
||||
|
||||
SshSessionFactory.setInstance(new GitConfigSessionFactory());
|
||||
|
||||
CloneCommand cmd = Git.cloneRepository().
|
||||
setCredentialsProvider(new UsernamePasswordCredentialsProvider("git", "nicomint")).
|
||||
setCloneAllBranches(true).
|
||||
setDirectory(localDir).
|
||||
setURI(hostname);
|
||||
|
||||
new CloneTask(activity).execute(cmd);
|
||||
}
|
||||
}).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
// Do nothing.
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
|
||||
new CloneTask(this).execute(localDir);
|
||||
}
|
||||
|
||||
|
||||
public void selectConnectionMode(View view) {
|
||||
|
||||
}
|
||||
|
||||
/* when the connection mode is selected */
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
String selection = ((Spinner) findViewById(R.id.connection_mode)).getSelectedItem().toString();
|
||||
|
||||
if (selection.equalsIgnoreCase("ssh-key")) {
|
||||
new AlertDialog.Builder(this)
|
||||
.setMessage("Authentication method not implemented yet")
|
||||
.setPositiveButton("OK",
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
dialog.cancel();
|
||||
}
|
||||
}
|
||||
).show();
|
||||
((Button) findViewById(R.id.clone_button)).setEnabled(false);
|
||||
} else {
|
||||
((Button) findViewById(R.id.clone_button)).setEnabled(true);
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
// Do nothing.
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> adapterView) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,21 +13,25 @@
|
|||
android:layoutDirection="ltr"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="match_parent">
|
||||
<EditText
|
||||
android:hint="Repository"
|
||||
android:id="@+id/clone_uri"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
android:layout_height="wrap_content">
|
||||
<Spinner
|
||||
android:id="@+id/clone_protocol"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"></Spinner>
|
||||
<EditText
|
||||
android:hint="Repository URI"
|
||||
android:id="@+id/clone_uri"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
|
||||
<Spinner
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/connection_mode"></Spinner>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/config_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"></LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/clone_button"
|
||||
android:text="Clone!"
|
||||
|
|
|
@ -8,10 +8,4 @@
|
|||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
tools:context=".pwdstore">
|
||||
|
||||
<Button
|
||||
android:text="@string/clone"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:onClick="getClone"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:context=".pwdstore" >
|
||||
<item android:id="@+id/action_settings"
|
||||
android:title="@string/action_settings"
|
||||
<item android:id="@+id/clone_setting"
|
||||
android:title="@string/clone_setting"
|
||||
android:orderInCategory="100"
|
||||
android:showAsAction="never" />
|
||||
android:showAsAction="ifRoom"
|
||||
android:onClick="getClone"/>
|
||||
</menu>
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
|
||||
<string name="app_name">PwdStore</string>
|
||||
<string name="clone">Clone!</string>
|
||||
<string name="action_settings">Settings</string>
|
||||
<string name="clone_setting">Clone</string>
|
||||
<string name="hello_world">Hello world!</string>
|
||||
|
||||
<string name="dialog_delete_title">Remove dir</string>
|
||||
<string name="dialog_delete_title">Directory already exist</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_do_not_delete">Cancel</string>
|
||||
|
@ -16,4 +16,10 @@
|
|||
<item>ssh-key</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="clone_protocols">
|
||||
<item>ssh://</item>
|
||||
<item>https://</item>
|
||||
<item>http://</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue