diff options
author | Mohamed Zenadi <zeapo@users.noreply.github.com> | 2015-07-19 13:31:00 +0200 |
---|---|---|
committer | Mohamed Zenadi <zeapo@users.noreply.github.com> | 2015-07-19 13:31:00 +0200 |
commit | 7517c650752b89acbfec691265ffda22f325783a (patch) | |
tree | 37e824f7d5e469aeea917b8696deb7380ff86984 /app | |
parent | ea899faa074ee3162186769218c62d3d254ce4ae (diff) | |
parent | 4ec3e1956f38879321b13e753294b9fee1b144bf (diff) |
Merge pull request #103 from wongma7/master
SSH key generator
Diffstat (limited to 'app')
-rw-r--r-- | app/build.gradle | 2 | ||||
-rw-r--r-- | app/src/main/AndroidManifest.xml | 7 | ||||
-rw-r--r-- | app/src/main/java/com/zeapo/pwdstore/PasswordFragment.java | 11 | ||||
-rw-r--r-- | app/src/main/java/com/zeapo/pwdstore/PasswordStore.java | 2 | ||||
-rw-r--r-- | app/src/main/java/com/zeapo/pwdstore/SshKeyGen.java | 231 | ||||
-rw-r--r-- | app/src/main/java/com/zeapo/pwdstore/UserPreference.java | 43 | ||||
-rw-r--r-- | app/src/main/java/com/zeapo/pwdstore/git/GitOperation.java | 30 | ||||
-rw-r--r-- | app/src/main/java/com/zeapo/pwdstore/pwgenDialogFragment.java | 12 | ||||
-rw-r--r-- | app/src/main/res/layout/activity_ssh_keygen.xml | 7 | ||||
-rw-r--r-- | app/src/main/res/layout/fragment_show_ssh_key.xml | 28 | ||||
-rw-r--r-- | app/src/main/res/layout/fragment_ssh_keygen.xml | 73 | ||||
-rw-r--r-- | app/src/main/res/layout/password_recycler_view.xml | 29 | ||||
-rw-r--r-- | app/src/main/res/values-v21/dimens.xml | 4 | ||||
-rw-r--r-- | app/src/main/res/values/dimens.xml | 1 | ||||
-rw-r--r-- | app/src/main/res/values/strings.xml | 17 | ||||
-rw-r--r-- | app/src/main/res/xml/preference.xml | 6 |
16 files changed, 469 insertions, 34 deletions
diff --git a/app/build.gradle b/app/build.gradle index 7d2bd5fd..8a3903d2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -32,7 +32,7 @@ dependencies { compile 'com.jcraft:jsch:0.1.52' compile 'org.apache.commons:commons-io:1.3.2' compile 'com.jayway.android.robotium:robotium-solo:5.3.1' - compile 'com.melnykov:floatingactionbutton:1.2.0' + compile 'com.android.support:design:22.2.0' compile 'net.rdrei.android.dirchooser:library:2.1@aar' compile group: 'com.google.guava', name: 'guava', version: '18.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7a566d3e..8deb8826 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -33,6 +33,13 @@ android:value="com.zeapo.pwdstore.PasswordStore" /> </activity> + <activity android:name=".SshKeyGen" + android:parentActivityName=".PasswordStore"> + + <meta-data android:name="android.support.PARENT_ACTIVITY" + android:value="com.zeapo.pwdstore.PasswordStore" /> + </activity> + <activity android:name="net.rdrei.android.dirchooser.DirectoryChooserActivity" /> </application> diff --git a/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.java b/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.java index 6bc24a8c..fed557fa 100644 --- a/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.java +++ b/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.java @@ -5,6 +5,7 @@ import android.app.Fragment; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; +import android.support.design.widget.FloatingActionButton; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; @@ -13,7 +14,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import com.melnykov.fab.FloatingActionButton; import com.zeapo.pwdstore.utils.PasswordItem; import com.zeapo.pwdstore.utils.PasswordRecyclerAdapter; import com.zeapo.pwdstore.utils.PasswordRepository; @@ -77,8 +77,13 @@ public class PasswordFragment extends Fragment{ // // Set the adapter recyclerView.setAdapter(recyclerAdapter); - FloatingActionButton fab = (FloatingActionButton) view.findViewById(R.id.fab); - fab.attachToRecyclerView(recyclerView); + final FloatingActionButton fab = (FloatingActionButton) view.findViewById(R.id.fab); + fab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + ((PasswordStore) getActivity()).createPassword(); + } + }); registerForContextMenu(recyclerView); return view; diff --git a/app/src/main/java/com/zeapo/pwdstore/PasswordStore.java b/app/src/main/java/com/zeapo/pwdstore/PasswordStore.java index 79a95c0a..aff71d74 100644 --- a/app/src/main/java/com/zeapo/pwdstore/PasswordStore.java +++ b/app/src/main/java/com/zeapo/pwdstore/PasswordStore.java @@ -326,7 +326,7 @@ public class PasswordStore extends AppCompatActivity { startActivityForResult(intent, PgpHandler.REQUEST_CODE_DECRYPT_AND_VERIFY); } - public void createPassword(View v) { + public void createPassword() { if (!PasswordRepository.isInitialized()) { new AlertDialog.Builder(this) .setMessage(this.getResources().getString(R.string.creation_dialog_text)) diff --git a/app/src/main/java/com/zeapo/pwdstore/SshKeyGen.java b/app/src/main/java/com/zeapo/pwdstore/SshKeyGen.java new file mode 100644 index 00000000..52980e5f --- /dev/null +++ b/app/src/main/java/com/zeapo/pwdstore/SshKeyGen.java @@ -0,0 +1,231 @@ +package com.zeapo.pwdstore; + +import android.app.Dialog; +import android.app.DialogFragment; +import android.app.Fragment; +import android.app.ProgressDialog; +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.content.DialogInterface; +import android.content.SharedPreferences; +import android.graphics.Typeface; +import android.os.AsyncTask; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.support.v7.app.AlertDialog; +import android.support.v7.app.AppCompatActivity; +import android.text.InputType; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.InputMethodManager; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.EditText; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.Toast; + +import com.jcraft.jsch.JSch; +import com.jcraft.jsch.KeyPair; + +import org.apache.commons.io.FileUtils; + +import java.io.File; +import java.io.FileOutputStream; + +public class SshKeyGen extends AppCompatActivity { + + // SSH key generation UI + public static class SshKeyGenFragment extends Fragment { + public SshKeyGenFragment() { + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + final View v = inflater.inflate(R.layout.fragment_ssh_keygen, container, false); + Typeface monoTypeface = Typeface.createFromAsset(getActivity().getAssets(), "fonts/sourcecodepro.ttf"); + + Spinner spinner = (Spinner) v.findViewById(R.id.length); + Integer[] lengths = new Integer[]{2048, 4096}; + ArrayAdapter<Integer> adapter = new ArrayAdapter<>(getActivity(), + android.R.layout.simple_spinner_dropdown_item, lengths); + spinner.setAdapter(adapter); + + ((EditText) v.findViewById(R.id.passphrase)).setTypeface(monoTypeface); + + CheckBox checkbox = (CheckBox) v.findViewById(R.id.show_passphrase); + checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + EditText editText = (EditText) v.findViewById(R.id.passphrase); + int selection = editText.getSelectionEnd(); + if (isChecked) { + editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD); + } else { + editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); + } + editText.setSelection(selection); + } + }); + + return v; + } + } + + // Displays the generated public key .ssh_key.pub + public static class ShowSshKeyFragment extends DialogFragment { + public ShowSshKeyFragment() { + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + LayoutInflater inflater = getActivity().getLayoutInflater(); + final View v = inflater.inflate(R.layout.fragment_show_ssh_key, null); + builder.setView(v); + + TextView textView = (TextView) v.findViewById(R.id.public_key); + File file = new File(getActivity().getFilesDir() + "/.ssh_key.pub"); + try { + textView.setText(FileUtils.readFileToString(file)); + } catch (Exception e) { + System.out.println("Exception caught :("); + e.printStackTrace(); + } + + builder.setPositiveButton(getResources().getString(R.string.dialog_ok), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (getActivity() instanceof SshKeyGen) + getActivity().finish(); + } + }); + + builder.setNegativeButton(getResources().getString(R.string.dialog_cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + } + }); + + builder.setNeutralButton(getResources().getString(R.string.ssh_keygen_copy), null); + + final AlertDialog ad = builder.setTitle("Your public key").create(); + ad.setOnShowListener(new DialogInterface.OnShowListener() { + @Override + public void onShow(DialogInterface dialog) { + Button b = ad.getButton(AlertDialog.BUTTON_NEUTRAL); + b.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + TextView textView = (TextView) v.findViewById(R.id.public_key); + ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clip = ClipData.newPlainText("public key", textView.getText().toString()); + clipboard.setPrimaryClip(clip); + } + }); + } + }); + return ad; + } + } + + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + if (getSupportActionBar() != null) + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + + setTitle("Generate SSH Key"); + + setContentView(R.layout.activity_ssh_keygen); + + if (savedInstanceState == null) { + getFragmentManager().beginTransaction() + .replace(android.R.id.content, new SshKeyGenFragment()).commit(); + } + } + + private class generateTask extends AsyncTask<View, Void, Exception> { + private ProgressDialog pd; + + protected Exception doInBackground(View... views) { + InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(views[0].getWindowToken(), 0); + + Spinner spinner = (Spinner) findViewById(R.id.length); + int length = (Integer) spinner.getSelectedItem(); + + EditText editText = (EditText) findViewById(R.id.passphrase); + String passphrase = editText.getText().toString(); + + editText = (EditText) findViewById(R.id.comment); + String comment = editText.getText().toString(); + + JSch jsch = new JSch(); + try { + KeyPair kp = KeyPair.genKeyPair(jsch, KeyPair.RSA, length); + + File file = new File(getFilesDir() + "/.ssh_key"); + FileOutputStream out = new FileOutputStream(file, false); + kp.writePrivateKey(out, passphrase.getBytes()); + + file = new File(getFilesDir() + "/.ssh_key.pub"); + out = new FileOutputStream(file, false); + kp.writePublicKey(out, comment); + return null; + } catch (Exception e) { + System.out.println("Exception caught :("); + e.printStackTrace(); + return e; + } + } + + @Override + protected void onPreExecute() { + super.onPreExecute(); + pd = ProgressDialog.show(SshKeyGen.this, "", "Generating keys"); + + } + + @Override + protected void onPostExecute(Exception e) { + super.onPostExecute(e); + pd.dismiss(); + if (e == null) { + Toast.makeText(SshKeyGen.this, "SSH-key generated", Toast.LENGTH_LONG).show(); + DialogFragment df = new ShowSshKeyFragment(); + df.show(getFragmentManager(), "public_key"); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + SharedPreferences.Editor editor = prefs.edit(); + editor.putBoolean("use_generated_key", true); + editor.apply(); + } else { + new AlertDialog.Builder(SshKeyGen.this) + .setTitle("Error while trying to generate the ssh-key") + .setMessage(getResources().getString(R.string.ssh_key_error_dialog_text) + e.getMessage()) + .setPositiveButton(getResources().getString(R.string.dialog_ok), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + // pass + } + }).show(); + } + + } + } + + // Invoked when 'Generate' button of SshKeyGenFragment clicked. Generates a + // private and public key, then replaces the SshKeyGenFragment with a + // ShowSshKeyFragment which displays the public key. + public void generate(View view) { + new generateTask().execute(view); + } +} diff --git a/app/src/main/java/com/zeapo/pwdstore/UserPreference.java b/app/src/main/java/com/zeapo/pwdstore/UserPreference.java index e2b3de9a..c94f08a6 100644 --- a/app/src/main/java/com/zeapo/pwdstore/UserPreference.java +++ b/app/src/main/java/com/zeapo/pwdstore/UserPreference.java @@ -1,6 +1,7 @@ package com.zeapo.pwdstore; import android.app.AlertDialog; +import android.app.DialogFragment; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; @@ -82,6 +83,24 @@ public class UserPreference extends AppCompatActivity { } }); + findPreference("ssh_keygen").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + callingActivity.makeSshKey(); + return true; + } + }); + + findPreference("ssh_see_key").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + DialogFragment df = new SshKeyGen.ShowSshKeyFragment(); + df.show(getFragmentManager(), "public_key"); + return true; + } + }); + + findPreference("git_server_info").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { @@ -164,6 +183,13 @@ public class UserPreference extends AppCompatActivity { findPreference("pref_select_external").setOnPreferenceChangeListener(resetRepo); findPreference("git_external").setOnPreferenceChangeListener(resetRepo); } + + @Override + public void onStart() { + super.onStart(); + final SharedPreferences sharedPreferences = getPreferenceManager().getSharedPreferences(); + findPreference("ssh_see_key").setEnabled(sharedPreferences.getBoolean("use_generated_key", false)); + } } @Override @@ -175,6 +201,9 @@ public class UserPreference extends AppCompatActivity { case "get_ssh_key": getSshKey(); break; + case "make_ssh_key": + makeSshKey(); + break; case "git_external": selectExternalGitRepository(); break; @@ -220,6 +249,16 @@ public class UserPreference extends AppCompatActivity { startActivityForResult(intent, IMPORT_SSH_KEY); } + /** + * Opens a key generator to generate a public/private key pair + */ + public void makeSshKey() { + Intent intent = new Intent(getApplicationContext(), SshKeyGen.class); + startActivity(intent); + setResult(RESULT_OK); + finish(); + } + private void copySshKey(Uri uri) throws IOException { InputStream sshKey = this.getContentResolver().openInputStream(uri); byte[] privateKey = IOUtils.toByteArray(sshKey); @@ -238,6 +277,10 @@ public class UserPreference extends AppCompatActivity { } copySshKey(data.getData()); Toast.makeText(this, this.getResources().getString(R.string.ssh_key_success_dialog_title), Toast.LENGTH_LONG).show(); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + SharedPreferences.Editor editor = prefs.edit(); + editor.putBoolean("use_generated_key", false); + editor.apply(); setResult(RESULT_OK); finish(); } catch (IOException e) { diff --git a/app/src/main/java/com/zeapo/pwdstore/git/GitOperation.java b/app/src/main/java/com/zeapo/pwdstore/git/GitOperation.java index c7b70ca4..c4d7eea4 100644 --- a/app/src/main/java/com/zeapo/pwdstore/git/GitOperation.java +++ b/app/src/main/java/com/zeapo/pwdstore/git/GitOperation.java @@ -92,7 +92,7 @@ public abstract class GitOperation { 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() { + .setPositiveButton(callingActivity.getResources().getString(R.string.ssh_preferences_dialog_import), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { try { @@ -106,12 +106,28 @@ public abstract class GitOperation { e.printStackTrace(); } } - }).setNegativeButton(callingActivity.getResources().getString(R.string.dialog_cancel), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - // Do nothing... - } - }).show(); + }) + .setNegativeButton(callingActivity.getResources().getString(R.string.ssh_preferences_dialog_generate), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + try { + // Duplicated code + Intent intent = new Intent(callingActivity.getApplicationContext(), UserPreference.class); + intent.putExtra("operation", "make_ssh_key"); + callingActivity.startActivityForResult(intent, GET_SSH_KEY_FROM_CLONE); + } catch (Exception e) { + System.out.println("Exception caught :("); + e.printStackTrace(); + } + } + }) + .setNeutralButton(callingActivity.getResources().getString(R.string.dialog_cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + // Finish the blank GitActivity so user doesn't have to press back + callingActivity.finish(); + } + }).show(); } else { final EditText passphrase = new EditText(callingActivity); passphrase.setHint("Passphrase"); diff --git a/app/src/main/java/com/zeapo/pwdstore/pwgenDialogFragment.java b/app/src/main/java/com/zeapo/pwdstore/pwgenDialogFragment.java index 1a42e2ba..019396db 100644 --- a/app/src/main/java/com/zeapo/pwdstore/pwgenDialogFragment.java +++ b/app/src/main/java/com/zeapo/pwdstore/pwgenDialogFragment.java @@ -86,16 +86,16 @@ public class pwgenDialogFragment extends DialogFragment { @Override public void onShow(DialogInterface dialog) { setPreferences(); - EditText textView = (EditText) view.findViewById(R.id.passwordText); - textView.setText(pwgen.generate(getActivity().getApplicationContext()).get(0)); + EditText editText = (EditText) view.findViewById(R.id.passwordText); + editText.setText(pwgen.generate(getActivity().getApplicationContext()).get(0)); Button b = ad.getButton(AlertDialog.BUTTON_NEUTRAL); b.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { setPreferences(); - EditText textView = (EditText) getDialog().findViewById(R.id.passwordText); - textView.setText(pwgen.generate(getActivity().getApplicationContext()).get(0)); + EditText editText = (EditText) view.findViewById(R.id.passwordText); + editText.setText(pwgen.generate(callingActivity.getApplicationContext()).get(0)); } }); } @@ -120,9 +120,9 @@ public class pwgenDialogFragment extends DialogFragment { if (!((CheckBox) getDialog().findViewById(R.id.pronounceable)).isChecked()) { preferences.add("s"); } - EditText textView = (EditText) getDialog().findViewById(R.id.lengthNumber); + EditText editText = (EditText) getDialog().findViewById(R.id.lengthNumber); try { - int length = Integer.valueOf(textView.getText().toString()); + int length = Integer.valueOf(editText.getText().toString()); return pwgen.setPrefs(getActivity().getApplicationContext(), preferences, length); } catch(NumberFormatException e) { return pwgen.setPrefs(getActivity().getApplicationContext(), preferences); diff --git a/app/src/main/res/layout/activity_ssh_keygen.xml b/app/src/main/res/layout/activity_ssh_keygen.xml new file mode 100644 index 00000000..fb3d8a25 --- /dev/null +++ b/app/src/main/res/layout/activity_ssh_keygen.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + +</LinearLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/fragment_show_ssh_key.xml b/app/src/main/res/layout/fragment_show_ssh_key.xml new file mode 100644 index 00000000..e81ae8c4 --- /dev/null +++ b/app/src/main/res/layout/fragment_show_ssh_key.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <TextView + android:id="@+id/public_key" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="16dp" + android:textIsSelectable="true"/> + + <TextView + android:id="@+id/public_key_tip" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="16dp" + android:text="@string/ssh_keygen_tip" + android:textAppearance="?android:attr/textAppearanceMedium"/> + + </LinearLayout> +</ScrollView>
\ No newline at end of file diff --git a/app/src/main/res/layout/fragment_ssh_keygen.xml b/app/src/main/res/layout/fragment_ssh_keygen.xml new file mode 100644 index 00000000..321e77d0 --- /dev/null +++ b/app/src/main/res/layout/fragment_ssh_keygen.xml @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="utf-8"?> +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingLeft="@dimen/activity_horizontal_margin" + android:paddingRight="@dimen/activity_horizontal_margin" + android:orientation="vertical"> + + <TextView + android:id="@+id/label_length" + android:layout_width="wrap_content" + android:layout_height="48dp" + android:gravity="center_vertical" + android:text="@string/ssh_keygen_length"/> + + <Spinner + android:id="@+id/length" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:spinnerMode="dropdown"/> + + <android.support.design.widget.TextInputLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + xmlns:app="http://schemas.android.com/apk/res-auto" + app:hintTextAppearance="@style/TextAppearance.AppCompat" + android:layout_marginTop="8dp"> + + <EditText + android:id="@+id/passphrase" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="@string/ssh_keygen_passphrase" + android:inputType="textPassword"/> + </android.support.design.widget.TextInputLayout> + + <CheckBox + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/ssh_keygen_show_passphrase" + android:id="@+id/show_passphrase" + android:checked="false" + android:layout_marginTop="8dp"/> + + <android.support.design.widget.TextInputLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + xmlns:app="http://schemas.android.com/apk/res-auto" + app:hintTextAppearance="@style/TextAppearance.AppCompat" + android:layout_marginTop="8dp"> + <EditText + android:id="@+id/comment" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="@string/ssh_keygen_comment" + android:inputType="textShortMessage"/> + </android.support.design.widget.TextInputLayout> + + <Button + android:id="@+id/generate_ssh_key" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:onClick="generate" + android:text="@string/ssh_keygen_generate"/> + + </LinearLayout> +</ScrollView>
\ No newline at end of file diff --git a/app/src/main/res/layout/password_recycler_view.xml b/app/src/main/res/layout/password_recycler_view.xml index b9a4231f..1b922a17 100644 --- a/app/src/main/res/layout/password_recycler_view.xml +++ b/app/src/main/res/layout/password_recycler_view.xml @@ -1,11 +1,11 @@ <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - xmlns:fab="http://schemas.android.com/apk/res-auto" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" - tools:context="com.zeapo.pwdstore.PasswordFragment"> + xmlns:tools="http://schemas.android.com/tools" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + tools:context="com.zeapo.pwdstore.PasswordFragment"> <android.support.v7.widget.RecyclerView android:id="@+id/pass_recycler" @@ -17,17 +17,18 @@ android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin"/> - <com.melnykov.fab.FloatingActionButton + <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:src="@drawable/ic_action_new" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_alignParentEnd="true" - android:layout_alignParentRight="true" + android:layout_gravity="bottom|end" + app:elevation="6dp" + app:pressedTranslationZ="12dp" + app:backgroundTint="@color/blue_grey_500" + app:rippleColor="@color/blue_grey_50" + app:borderWidth="0dp" + android:layout_margin="@dimen/fab_compat_margin" android:layout_alignParentBottom="true" - android:layout_margin="@dimen/activity_vertical_margin" - android:onClick="createPassword" - fab:fab_colorNormal="@color/blue_grey_500" - fab:fab_colorPressed="@color/blue_grey_800" - fab:fab_colorRipple="@color/blue_grey_50"/> + android:layout_alignParentRight="true"/> </RelativeLayout> diff --git a/app/src/main/res/values-v21/dimens.xml b/app/src/main/res/values-v21/dimens.xml new file mode 100644 index 00000000..daaecce2 --- /dev/null +++ b/app/src/main/res/values-v21/dimens.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <dimen name="fab_compat_margin">16dp</dimen> +</resources>
\ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 47c82246..8a517840 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -2,4 +2,5 @@ <!-- Default screen margins, per the Android Design guidelines. --> <dimen name="activity_horizontal_margin">16dp</dimen> <dimen name="activity_vertical_margin">16dp</dimen> + <dimen name="fab_compat_margin">0dp</dimen> </resources> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1f2ae926..f60e4b15 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -47,8 +47,10 @@ <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="forget_username_dialog_text">Did you forget to specify a username?</string> <string name="set_information_dialog_text">You have to set the information about the server before synchronizing with the server</string> - <string name="ssh_preferences_dialog_text">Please import your SSH key file in the preferences</string> + <string name="ssh_preferences_dialog_text">Please import or generate your SSH key file in the preferences</string> <string name="ssh_preferences_dialog_title">No SSH key</string> + <string name="ssh_preferences_dialog_import">Import</string> + <string name="ssh_preferences_dialog_generate">Generate</string> <string name="passphrase_dialog_title">Authenticate</string> <string name="passphrase_dialog_text">Please provide the passphrase for your SSH key. Leave it empty if there is no passphrase.</string> <string name="password_dialog_text">Please provide the password for this repository</string> @@ -94,7 +96,9 @@ <string name="pref_git_username_title">Username</string> <string name="pref_git_username_hint">username</string> <string name="pref_edit_server_info">Edit git server settings</string> - <string name="pref_ssh_title">Import ssh-key</string> + <string name="pref_ssh_title">Import SSH key</string> + <string name="pref_ssh_keygen_title">Generate SSH key pair</string> + <string name="pref_ssh_see_key_title">View generated public SSH key</string> <string name="pref_git_delete_repo">Delete repository</string> <string name="pref_dialog_delete_title">Clear repository</string> <string name="pref_dialog_delete_msg">Do you want to delete the current password store directory? This will not clear your configuration.</string> @@ -122,6 +126,15 @@ <string name="pwgen_uppercase">Uppercase</string> <string name="pwgen_ambiguous">Ambiguous</string> + <!-- ssh keygen fragment --> + <string name="ssh_keygen_length">Length</string> + <string name="ssh_keygen_passphrase">Passphrase</string> + <string name="ssh_keygen_comment">Comment</string> + <string name="ssh_keygen_generate">Generate</string> + <string name="ssh_keygen_copy">Copy</string> + <string name="ssh_keygen_tip">Provide this public key to your Git server.</string> + <string name="ssh_keygen_show_passphrase">Show passphrase</string> + <!-- Misc --> <string name="dialog_ok">OK</string> <string name="dialog_yes">Yes</string> diff --git a/app/src/main/res/xml/preference.xml b/app/src/main/res/xml/preference.xml index 1ddcde41..67217c9d 100644 --- a/app/src/main/res/xml/preference.xml +++ b/app/src/main/res/xml/preference.xml @@ -8,6 +8,12 @@ android:key="ssh_key" android:title="@string/pref_ssh_title" /> <Preference + android:key="ssh_keygen" + android:title="@string/pref_ssh_keygen_title" /> + <Preference + android:key="ssh_see_key" + android:title="@string/pref_ssh_see_key_title" /> + <Preference android:key="git_delete_repo" android:summary="Deletes local repository" android:title="@string/pref_git_delete_repo" /> |