diff options
Diffstat (limited to 'app')
17 files changed, 543 insertions, 246 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index edec0fa1..822ad8cd 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,10 +2,6 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.zeapo.pwdstore" > - <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> - <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> - <uses-permission android:name="android.permission.INTERNET" /> - <application android:allowBackup="true" android:icon="@drawable/ic_launcher" @@ -22,27 +18,35 @@ </activity> <activity android:name=".GitClone" - android:label="@string/title_activity_git_clone" > + android:label="@string/title_activity_git_clone" + android:parentActivityName=".PasswordStore"> + <meta-data + android:name="android.PARENT_ACTIVITY1" + android:value="com.zeapo.pwdstore.PasswordStore" /> </activity> - <activity android:name=".OpenPgpProviderActivity" /> - <activity android:name=".UserPreference" /> - <activity - android:name=".PgpHandler" - android:label="@string/title_activity_pgp_handler" > + <activity android:name=".crypto.OpenPgpProviderActivity" /> + + <activity android:name=".UserPreference" + android:parentActivityName=".PasswordStore"> + + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value="com.zeapo.pwdstore.PasswordStore" /> </activity> - </application> - <!-- - To retrieve OAuth 2.0 tokens or invalidate tokens to disconnect a user. This disconnect - option is required to comply with the Google+ Sign-In developer policies - --> - <uses-permission android:name="android.permission.USE_CREDENTIALS" /> + <activity + android:name=".crypto.PgpHandler" + android:label="@string/title_activity_pgp_handler" + android:parentActivityName=".PasswordStore"> - <!-- To retrieve the account name (email) as part of sign-in: --> - <uses-permission android:name="android.permission.GET_ACCOUNTS" /> + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value="com.zeapo.pwdstore.PasswordStore" /> + </activity> + </application> - <!-- To auto-complete the email text field in the login form with the user's emails --> - <uses-permission android:name="android.permission.READ_PROFILE" /> - <uses-permission android:name="android.permission.READ_CONTACTS" /> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.INTERNET" /> </manifest> diff --git a/app/src/main/java/com/zeapo/pwdstore/GitClone.java b/app/src/main/java/com/zeapo/pwdstore/GitClone.java index 6166ba2c..de0cbde0 100644 --- a/app/src/main/java/com/zeapo/pwdstore/GitClone.java +++ b/app/src/main/java/com/zeapo/pwdstore/GitClone.java @@ -74,6 +74,8 @@ public class GitClone extends Activity { context = getApplicationContext(); activity = this; + getActionBar().setDisplayHomeAsUpEnabled(true); + // init the spinner for protocols Spinner protcol_spinner = (Spinner) findViewById(R.id.clone_protocol); ArrayAdapter<CharSequence> protocol_adapter = ArrayAdapter.createFromResource(this, diff --git a/app/src/main/java/com/zeapo/pwdstore/PasswordAdapter.java b/app/src/main/java/com/zeapo/pwdstore/PasswordAdapter.java deleted file mode 100644 index 172f8756..00000000 --- a/app/src/main/java/com/zeapo/pwdstore/PasswordAdapter.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.zeapo.pwdstore; - -import android.content.Context; -import android.util.Pair; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.TextView; - -import com.zeapo.pwdstore.R; - -import java.util.ArrayList; -import java.util.HashMap; - -public class PasswordAdapter extends ArrayAdapter<String> { - private final Context context; - private final ArrayList<String> values; - - static class ViewHolder { - public TextView text; - } - - public PasswordAdapter(Context context, ArrayList<String> values) { - super(context, R.layout.password_row_layout, values); - this.context = context; - this.values = values; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - View rowView = convertView; - - // reuse for performance, holder pattern! - if (rowView == null) { - LayoutInflater inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - rowView = inflater.inflate(R.layout.password_row_layout, null); - - ViewHolder viewHolder = new ViewHolder(); - viewHolder.text = (TextView) rowView.findViewById(R.id.label); - rowView.setTag(viewHolder); - } - - ViewHolder holder = (ViewHolder) rowView.getTag(); - holder.text.setText( values.get(position) ); - - return rowView; - } -}
\ No newline at end of file diff --git a/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.java b/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.java index 9023320a..261729eb 100644 --- a/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.java +++ b/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.java @@ -1,7 +1,6 @@ package com.zeapo.pwdstore; import android.app.Activity; -import android.content.Context; import android.os.Bundle; import android.app.Fragment; import android.view.LayoutInflater; @@ -11,9 +10,14 @@ import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListAdapter; -import android.widget.TextView; +import android.widget.ListView; -import java.util.ArrayList; +import com.zeapo.pwdstore.utils.PasswordAdapter; +import com.zeapo.pwdstore.utils.PasswordItem; +import com.zeapo.pwdstore.utils.PasswordRepository; + +import java.io.File; +import java.util.List; /** * A fragment representing a list of Items. @@ -29,13 +33,13 @@ public class PasswordFragment extends Fragment implements AbsListView.OnItemClic /** * The fragment's ListView/GridView. */ - private AbsListView mListView; + private ListView mListView; /** * The Adapter which will be used to populate the ListView/GridView with * Views. */ - private ListAdapter mAdapter; + private PasswordAdapter mAdapter; /** * Mandatory empty constructor for the fragment manager to instantiate the @@ -47,8 +51,8 @@ public class PasswordFragment extends Fragment implements AbsListView.OnItemClic public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - System.out.println(PasswordRepository.getFilesList().size()); - mAdapter = new PasswordAdapter(getActivity(), PasswordRepository.getFilesList()); + String path = getArguments().getString("Path"); + mAdapter = new PasswordAdapter(getActivity(), PasswordRepository.getPasswords(new File(path))); } @Override @@ -57,11 +61,12 @@ public class PasswordFragment extends Fragment implements AbsListView.OnItemClic View view = inflater.inflate(R.layout.fragment_password, container, false); // Set the adapter - mListView = (AbsListView) view.findViewById(R.id.pass_list); + mListView = (ListView) view.findViewById(R.id.pass_list); ((AdapterView<ListAdapter>) mListView).setAdapter(mAdapter); // Set OnItemClickListener so we can be notified on item clicks mListView.setOnItemClickListener(this); + mListView.setSelectionFromTop(getArguments().getInt("Position"), 0); return view; } @@ -84,17 +89,29 @@ public class PasswordFragment extends Fragment implements AbsListView.OnItemClic } @Override + public void onPause() { + super.onPause(); + mListener.savePosition(mListView.getFirstVisiblePosition()); + + } + + @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if (null != mListener) { // Notify the active callbacks interface (the activity, if the // fragment is attached to one) that an item has been selected. - mListener.onFragmentInteraction((String) mAdapter.getItem(position)); + mListener.onFragmentInteraction(mAdapter.getItem(position)); } } public interface OnFragmentInteractionListener { - // TODO: Update argument type and name - public void onFragmentInteraction(String id); + public void onFragmentInteraction(PasswordItem item); + public void savePosition(Integer position); + } + + public void updateAdapter() { + mAdapter.clear(); + mAdapter.addAll(PasswordRepository.getPasswords()); } } diff --git a/app/src/main/java/com/zeapo/pwdstore/PasswordRepository.java b/app/src/main/java/com/zeapo/pwdstore/PasswordRepository.java deleted file mode 100644 index 30181e69..00000000 --- a/app/src/main/java/com/zeapo/pwdstore/PasswordRepository.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.zeapo.pwdstore; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.filefilter.TrueFileFilter; -import org.eclipse.jgit.api.Git; -import org.eclipse.jgit.internal.storage.file.FileRepository; -import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.lib.RepositoryBuilder; -import org.eclipse.jgit.storage.file.FileRepositoryBuilder; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; - -public class PasswordRepository { - - private static Repository repository; - private static LinkedHashMap<String, ArrayList<String>> mainPasswordMap; - private static ArrayList<String> mainListOfFiles; - - protected PasswordRepository(){ } - - public static Repository getRepository(File localDir) { - if (repository == null) { - FileRepositoryBuilder builder = new FileRepositoryBuilder(); - try { - repository = builder.setGitDir(localDir) - .readEnvironment() - .findGitDir() - .build(); - - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - return repository; - } - - public static void closeRepository() { - repository.close(); - } - - public static ArrayList<String> getFilesList(){ - return getFilesList(repository.getWorkTree()); - } - - public static LinkedHashMap<String, ArrayList<String>> getPasswords() { - return getPasswords(repository.getWorkTree()); - } - - public static File getFile(String name) { - return new File(repository.getWorkTree() + "/" + name); - } - - public static ArrayList<String> getFilesList(File path){ - if (!path.exists()) return new ArrayList<String>(); - - List<File> files = (List<File>) FileUtils.listFiles(path, new String[] {"gpg"}, true); - ArrayList<String> filePaths = new ArrayList<String>(); - for (File file : files) { - filePaths.add(file.getAbsolutePath().replace(repository.getWorkTree().getAbsolutePath() + "/", "")); - } - return filePaths; - } - - public static LinkedHashMap<String, ArrayList<String>> getPasswords(File path) { - //We need to recover the passwords then parse the files - ArrayList<String> passList = getFilesList(path); - - if (passList.size() == 0) return new LinkedHashMap<String, ArrayList<String>>(); - - LinkedHashMap<String, ArrayList<String>> passMap = new LinkedHashMap<String, ArrayList<String>>(); - passMap.put("Without Category", new ArrayList<String>()); - - for (String file : passList) { - String[] parts = file.split("/"); - if (parts.length == 1) { - passMap.get("Without Category").add(parts[0]); - } else { - if (passMap.containsKey(parts[0])) { - passMap.get(parts[0]).add(parts[1]); - } else { - ArrayList<String> tempList = new ArrayList<String>(); - tempList.add(parts[1]); - passMap.put(parts[0], tempList); - } - } - } - return passMap; - } -} diff --git a/app/src/main/java/com/zeapo/pwdstore/PasswordStore.java b/app/src/main/java/com/zeapo/pwdstore/PasswordStore.java index 031f1063..6a601a3b 100644 --- a/app/src/main/java/com/zeapo/pwdstore/PasswordStore.java +++ b/app/src/main/java/com/zeapo/pwdstore/PasswordStore.java @@ -11,34 +11,41 @@ import android.view.Menu; import android.view.MenuItem; import android.view.View; +import com.zeapo.pwdstore.crypto.PgpHandler; +import com.zeapo.pwdstore.utils.PasswordItem; +import com.zeapo.pwdstore.utils.PasswordRepository; + import org.apache.commons.io.FileUtils; import org.apache.commons.io.filefilter.FileFilterUtils; import org.eclipse.jgit.lib.Repository; -import org.openintents.openpgp.util.OpenPgpListPreference; +import org.eclipse.jgit.transport.CredentialItem; import java.io.File; import java.io.FileFilter; import java.io.IOException; -import java.io.InputStream; +import java.util.Stack; public class PasswordStore extends Activity implements ToCloneOrNot.OnFragmentInteractionListener, PasswordFragment.OnFragmentInteractionListener { private int listState = 0; + private Stack<Integer> scrollPositions; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_pwdstore); + scrollPositions = new Stack<Integer>(); } @Override public void onResume(){ super.onResume(); + + // create the repository static variable in PasswordRepository + PasswordRepository.getRepository(new File(getFilesDir() + "/store/.git")); + // re-check that there was no change with the repository state checkLocalRepository(); - Repository repository = PasswordRepository.getRepository(new File(getFilesDir() + "/store/.git")); - PasswordRepository.getFilesList(); - PasswordRepository.getPasswords(); } @Override @@ -54,16 +61,29 @@ public class PasswordStore extends Activity implements ToCloneOrNot.OnFragmentI // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); - if (id == R.id.user_pref) { - try { - Intent intent = new Intent(this, UserPreference.class); - startActivity(intent); - } catch (Exception e) { - System.out.println("Exception caught :("); - e.printStackTrace(); - } - return true; + switch (id) { + case R.id.user_pref: + try { + Intent intent = new Intent(this, UserPreference.class); + startActivity(intent); + } catch (Exception e) { + System.out.println("Exception caught :("); + e.printStackTrace(); + } + return true; + + case R.id.referesh: + PasswordFragment plist; + if (null != + (plist = (PasswordFragment) getFragmentManager().findFragmentByTag("PasswordsList"))) { + plist.updateAdapter(); + } + return true; + + default: + break; } + return super.onOptionsItemSelected(item); } @@ -78,62 +98,83 @@ public class PasswordStore extends Activity implements ToCloneOrNot.OnFragmentI } private void checkLocalRepository() { +// final File localDir = new File(getFilesDir() + "/store/.git"); + checkLocalRepository(PasswordRepository.getWorkTree()); + } + + private void checkLocalRepository(File localDir) { int status = 0; - final File localDir = new File(getFilesDir() + "/store/.git"); FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); if (localDir.exists()) { - File[] folders = localDir.listFiles((FileFilter) FileFilterUtils.directoryFileFilter()); + File[] folders = localDir.listFiles(); status = folders.length; } // either the repo is empty or it was not correctly cloned switch (status) { case 0: + if(!localDir.equals(PasswordRepository.getWorkTree())) + break; + ToCloneOrNot cloneFrag = new ToCloneOrNot(); fragmentTransaction.replace(R.id.main_layout, cloneFrag, "ToCloneOrNot"); fragmentTransaction.commit(); break; - case 1: - // empty - break; default: PasswordFragment passFrag = new PasswordFragment(); + Bundle args = new Bundle(); + args.putString("Path", localDir.getAbsolutePath()); - if (fragmentManager.findFragmentByTag("ToCloneOrNot") == null) { - fragmentTransaction.add(R.id.main_layout, passFrag); - } else { - fragmentTransaction.replace(R.id.main_layout, passFrag); - } + if (!scrollPositions.isEmpty()) + args.putInt("Position", scrollPositions.pop()); + else + args.putInt("Position", 0); + + passFrag.setArguments(args); + + if (fragmentManager.findFragmentByTag("PasswordsList") != null) + fragmentTransaction.addToBackStack("passlist"); + + fragmentTransaction.replace(R.id.main_layout, passFrag, "PasswordsList"); fragmentTransaction.commit(); } } - /* If an item is clicked in the list of passwords, this will be triggered */ + /** Stack the positions the different fragments were at */ @Override - public void onFragmentInteraction(String id) { - + public void savePosition(Integer position) { + this.scrollPositions.push(position); + } - try { - byte[] data = new byte[0]; + /* If an item is clicked in the list of passwords, this will be triggered */ + @Override + public void onFragmentInteraction(PasswordItem item) { + if (item.getType() == PasswordItem.TYPE_CATEGORY) { + checkLocalRepository(item.getFile()); + } else { try { - data = FileUtils.readFileToByteArray(PasswordRepository.getFile(id)); + byte[] data = new byte[0]; + try { + data = FileUtils.readFileToByteArray(PasswordRepository.getFile(item.getName())); + + Intent intent = new Intent(this, PgpHandler.class); + intent.putExtra("PGP-ID", FileUtils.readFileToString(PasswordRepository.getFile("/.gpg-id"))); + intent.putExtra("NAME", item.getName()); + intent.putExtra("FILE_PATH", PasswordRepository.getFile(item.getName()).getAbsolutePath()); + startActivity(intent); + + } catch (IOException e) { + e.printStackTrace(); + } - Intent intent = new Intent(this, PgpHandler.class); - intent.putExtra("FILE_CONTENT", data); - intent.putExtra("FILE_PATH", PasswordRepository.getFile(id).getAbsolutePath()); - startActivity(intent); - } catch (IOException e) { + } catch (Exception e) { +// TODO handle problems e.printStackTrace(); } - - - } catch (Exception e) { -// TODO handle problems - e.printStackTrace(); } } diff --git a/app/src/main/java/com/zeapo/pwdstore/UserPreference.java b/app/src/main/java/com/zeapo/pwdstore/UserPreference.java index cc6c1495..a0c5d49c 100644 --- a/app/src/main/java/com/zeapo/pwdstore/UserPreference.java +++ b/app/src/main/java/com/zeapo/pwdstore/UserPreference.java @@ -9,5 +9,7 @@ public class UserPreference extends PreferenceActivity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preference); + + getActionBar().setDisplayHomeAsUpEnabled(true); } } diff --git a/app/src/main/java/com/zeapo/pwdstore/OpenPgpProviderActivity.java b/app/src/main/java/com/zeapo/pwdstore/crypto/OpenPgpProviderActivity.java index 3d0e09c3..8bc4b9d3 100644 --- a/app/src/main/java/com/zeapo/pwdstore/OpenPgpProviderActivity.java +++ b/app/src/main/java/com/zeapo/pwdstore/crypto/OpenPgpProviderActivity.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.zeapo.pwdstore; +package com.zeapo.pwdstore.crypto; import android.app.Activity; import android.app.PendingIntent; @@ -29,6 +29,8 @@ import android.widget.Button; import android.widget.EditText; import android.widget.Toast; +import com.zeapo.pwdstore.R; + import org.openintents.openpgp.OpenPgpError; import org.openintents.openpgp.OpenPgpSignatureResult; import org.openintents.openpgp.util.OpenPgpApi; @@ -39,7 +41,6 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.UnsupportedEncodingException; -import java.util.Arrays; public class OpenPgpProviderActivity extends Activity { private EditText mMessage; diff --git a/app/src/main/java/com/zeapo/pwdstore/PgpHandler.java b/app/src/main/java/com/zeapo/pwdstore/crypto/PgpHandler.java index c97e0156..0132c4cd 100644 --- a/app/src/main/java/com/zeapo/pwdstore/PgpHandler.java +++ b/app/src/main/java/com/zeapo/pwdstore/crypto/PgpHandler.java @@ -1,4 +1,4 @@ -package com.zeapo.pwdstore; +package com.zeapo.pwdstore.crypto; import android.app.Activity; import android.app.PendingIntent; @@ -52,13 +52,21 @@ public class PgpHandler extends Activity { super.onCreate(savedInstanceState); setContentView(R.layout.activity_pgp_handler); + // Setup action buttons + getActionBar().setDisplayHomeAsUpEnabled(true); + getActionBar().setHomeButtonEnabled(true); + + Bundle extra = getIntent().getExtras(); + ((TextView) findViewById(R.id.crypto_handler_name)).setText(extra.getString("NAME")); + // some persistance SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this); String providerPackageName = settings.getString("openpgp_provider_list", ""); + String accountName = settings.getString("openpgp_account_name", ""); - System.out.println(getIntent().getExtras().getString("FILE_PATH")); - Bundle extra = getIntent().getExtras(); - ((TextView) findViewById(R.id.hhh)).setText(extra.getString("FILE_PATH")); + if (accountName.isEmpty()) { + ((TextView) findViewById(R.id.crypto_account_name)).setText("No account selected"); + } if (TextUtils.isEmpty(providerPackageName)) { Toast.makeText(this, "No OpenPGP Provider selected!", Toast.LENGTH_LONG).show(); @@ -91,6 +99,10 @@ public class PgpHandler extends Activity { return super.onOptionsItemSelected(item); } + public void decrypt(View view) { + decryptAndVerify(new Intent()); +// getKeyIds(new Intent()); + } private void handleError(final OpenPgpError error) { runOnUiThread(new Runnable() { @@ -140,6 +152,12 @@ public class PgpHandler extends Activity { try { Log.d(OpenPgpApi.TAG, "result: " + os.toByteArray().length + " str=" + os.toString("UTF-8")); + showToast(os.toString("UTF-8")); + if (returnToCiphertextField) { +// mCiphertext.setText(os.toString("UTF-8")); + } else { +// mMessage.setText(os.toString("UTF-8")); + } } catch (UnsupportedEncodingException e) { Log.e(Constants.TAG, "UnsupportedEncodingException", e); } @@ -187,14 +205,10 @@ public class PgpHandler extends Activity { } } - public void getKey(View view) { - decryptAndVerify(new Intent()); - } public void decryptAndVerify(Intent data) { data.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY); data.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); - data.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, "Mohamed Zenadi"); try { InputStream is = FileUtils.openInputStream(new File(getIntent().getExtras().getString("FILE_PATH"))); @@ -207,4 +221,56 @@ public class PgpHandler extends Activity { e.printStackTrace(); } } + + + public void getKeyIds(Intent data) { + data.setAction(OpenPgpApi.ACTION_GET_KEY_IDS); + data.putExtra(OpenPgpApi.EXTRA_USER_IDS, new String[]{getIntent().getExtras().getString("PGP-ID")}); + + OpenPgpApi api = new OpenPgpApi(this, mServiceConnection.getService()); + api.executeApiAsync(data, null, null, new MyCallback(false, null, REQUEST_CODE_GET_KEY_IDS)); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + Log.d(Constants.TAG, "onActivityResult resultCode: " + resultCode); + + // try again after user interaction + if (resultCode == RESULT_OK) { + /* + * The data originally given to one of the methods above, is again + * returned here to be used when calling the method again after user + * interaction. The Intent now also contains results from the user + * interaction, for example selected key ids. + */ + switch (requestCode) { +// case REQUEST_CODE_SIGN: { +// sign(data); +// break; +// } +// case REQUEST_CODE_ENCRYPT: { +// encrypt(data); +// break; +// } +// case REQUEST_CODE_SIGN_AND_ENCRYPT: { +// signAndEncrypt(data); +// break; +// } + case REQUEST_CODE_DECRYPT_AND_VERIFY: { + decryptAndVerify(data); + break; + } +// case REQUEST_CODE_GET_KEY: { +// getKey(data); +// break; +// } + case REQUEST_CODE_GET_KEY_IDS: { + getKeyIds(data); + break; + } + } + } + } + } diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/PasswordAdapter.java b/app/src/main/java/com/zeapo/pwdstore/utils/PasswordAdapter.java new file mode 100644 index 00000000..b0cdb5a5 --- /dev/null +++ b/app/src/main/java/com/zeapo/pwdstore/utils/PasswordAdapter.java @@ -0,0 +1,63 @@ +package com.zeapo.pwdstore.utils; + +import android.content.Context; +import android.graphics.Typeface; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.TextView; + +import com.zeapo.pwdstore.R; + +import java.util.ArrayList; + +public class PasswordAdapter extends ArrayAdapter<PasswordItem> { + private final Context context; + private final ArrayList<PasswordItem> values; + + static class ViewHolder { + public TextView name; + public TextView type; + } + + public PasswordAdapter(Context context, ArrayList<PasswordItem> values) { + super(context, R.layout.password_row_layout, values); + this.context = context; + this.values = values; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View rowView = convertView; + PasswordItem pass = values.get(position); + + // reuse for performance, holder pattern! + if (rowView == null) { + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + rowView = inflater.inflate(R.layout.password_row_layout, null); + + ViewHolder viewHolder = new ViewHolder(); + viewHolder.name = (TextView) rowView.findViewById(R.id.label); + viewHolder.type = (TextView) rowView.findViewById(R.id.type); + rowView.setTag(viewHolder); + } + + ViewHolder holder = (ViewHolder) rowView.getTag(); + + holder.name.setText(pass.toString()); + + if (pass.getType() == PasswordItem.TYPE_CATEGORY) { + holder.name.setTextColor(this.context.getResources().getColor(android.R.color.holo_blue_dark)); + holder.name.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD)); + holder.type.setText("Category: "); + } else { + holder.type.setText("Password: "); + holder.name.setTextColor(this.context.getResources().getColor(android.R.color.holo_orange_dark)); + holder.name.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.NORMAL)); + } + + return rowView; + } +}
\ No newline at end of file diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/PasswordItem.java b/app/src/main/java/com/zeapo/pwdstore/utils/PasswordItem.java new file mode 100644 index 00000000..4403d16b --- /dev/null +++ b/app/src/main/java/com/zeapo/pwdstore/utils/PasswordItem.java @@ -0,0 +1,103 @@ +package com.zeapo.pwdstore.utils; + +import java.io.File; + +public class PasswordItem implements Comparable{ + + public final static char TYPE_CATEGORY = 'c'; + public final static char TYPE_PASSWORD = 'p'; + + private char type; + private String name; + private PasswordItem parent; + private File file; + + /** Create a password item + * + * Make it protected so that we use a builder + * @param name + * @param parent + * @param type + */ + protected PasswordItem(String name, PasswordItem parent, char type, File file) { + this.name = name; + this.parent = parent; + this.type = type; + this.file = file; + } + + /** Create a new Category item + * + * @param name + * @param parent + * @return + */ + public static PasswordItem newCategory(String name, File file, PasswordItem parent) { + return new PasswordItem(name, parent, TYPE_CATEGORY, file); + } + + /** Create a new parentless category item + * + * @param name + * @return + */ + public static PasswordItem newCategory(String name, File file) { + return new PasswordItem(name, null, TYPE_CATEGORY, file); + } + + /** Create a new password item + * + * @param name + * @param parent + * @return + */ + public static PasswordItem newPassword(String name, File file, PasswordItem parent) { + return new PasswordItem(name, parent, TYPE_PASSWORD, file); + } + + /** Create a new parentless password item + * + * @param name + * @return + */ + public static PasswordItem newPassword(String name, File file) { + return new PasswordItem(name, null, TYPE_PASSWORD, file); + } + + public char getType(){ + return this.type; + } + + public String getName(){ + return this.name; + } + + public PasswordItem getParent() { + return this.parent; + } + + public File getFile() { + return this.file; + } + + @Override + public String toString(){ + return this.getName().replace(".gpg", ""); + } + + @Override + public boolean equals(Object o){ + PasswordItem other = (PasswordItem) o; + // Makes it possible to have a category and a password with the same name + return (other.getType() + other.getName()) + .equals(this.getType() + this.getName()); + } + + @Override + public int compareTo(Object o) { + PasswordItem other = (PasswordItem) o; + // Appending the type will make the sort type dependent + return (this.getType() + this.getName()) + .compareTo(other.getType() + other.getName()); + } +} diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRepository.java b/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRepository.java new file mode 100644 index 00000000..5f42b956 --- /dev/null +++ b/app/src/main/java/com/zeapo/pwdstore/utils/PasswordRepository.java @@ -0,0 +1,88 @@ +package com.zeapo.pwdstore.utils; + +import org.apache.commons.io.FileUtils; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.storage.file.FileRepositoryBuilder; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static java.util.Collections.sort; + +public class PasswordRepository { + + private static Repository repository; + + protected PasswordRepository(){ } + + public static Repository getRepository(File localDir) { + if (repository == null) { + FileRepositoryBuilder builder = new FileRepositoryBuilder(); + try { + repository = builder.setGitDir(localDir) + .readEnvironment() + .findGitDir() + .build(); + + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + return repository; + } + + public static void closeRepository() { + repository.close(); + } + + public static ArrayList<File> getFilesList(){ + return getFilesList(repository.getWorkTree()); + } + + public static ArrayList<PasswordItem> getPasswords() { + return getPasswords(repository.getWorkTree()); + } + + public static File getWorkTree() { + return repository.getWorkTree(); + } + + public static File getFile(String name) { + return new File(repository.getWorkTree() + "/" + name); + } + + public static ArrayList<File> getFilesList(File path){ + if (!path.exists()) return new ArrayList<File>(); + + List<File> files = (List<File>) FileUtils.listFiles(path, new String[] {"gpg"}, true); + return new ArrayList<File>(files); + } + + public static ArrayList<PasswordItem> getPasswords(File path) { + //We need to recover the passwords then parse the files + ArrayList<File> passList = getFilesList(path); + + if (passList.size() == 0) return new ArrayList<PasswordItem>(); + + // TODO replace with a set + ArrayList<PasswordItem> passwordList = new ArrayList<PasswordItem>(); + + for (File file : passList) { + String fileName = file.getAbsolutePath().replace(path.getAbsolutePath() + "/", ""); + + String[] parts = fileName.split("/"); + if (parts.length == 1) { + passwordList.add(PasswordItem.newPassword(parts[0], file.getParentFile())); + } else { + if (!passwordList.contains(PasswordItem.newCategory(parts[0], file.getParentFile()))) { + passwordList.add(PasswordItem.newCategory(parts[0], file.getParentFile())); + } + } + } + sort(passwordList); + return passwordList; + } +} diff --git a/app/src/main/res/layout/activity_pgp_handler.xml b/app/src/main/res/layout/activity_pgp_handler.xml index 159a6a9b..5095b32c 100644 --- a/app/src/main/res/layout/activity_pgp_handler.xml +++ b/app/src/main/res/layout/activity_pgp_handler.xml @@ -6,18 +6,58 @@ android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" - tools:context="com.zeapo.pwdstore.PgpHandler"> + tools:context="com.zeapo.pwdstore.crypto.PgpHandler"> - <TextView - android:id="@+id/hhh" - android:text="@string/hello_world" - android:layout_width="wrap_content" - android:layout_height="wrap_content" /> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> - <Button - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:onClick="getKey" - android:text="getkey"/> + <GridLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceLarge" + android:text="Large Text" + android:id="@+id/crypto_account_name" + android:layout_row="0" + android:layout_column="0" /> + + <Button + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Change account" + android:id="@+id/button" + android:layout_row="0" + android:layout_column="2" /> + </GridLayout> + + <View + android:layout_width="fill_parent" + android:layout_marginBottom="4dp" + android:layout_height="1dp" + android:background="@android:color/darker_gray"/> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="New Text" + android:id="@+id/crypto_handler_name"/> + + + <Button + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Select Key-id" + android:onClick="getKeyID"/> + + <Button + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Show password" + android:onClick="decrypt"/> + </LinearLayout> </RelativeLayout> diff --git a/app/src/main/res/layout/password_row_layout.xml b/app/src/main/res/layout/password_row_layout.xml index 4a562f76..85f576e8 100644 --- a/app/src/main/res/layout/password_row_layout.xml +++ b/app/src/main/res/layout/password_row_layout.xml @@ -1,13 +1,23 @@ <?xml version="1.0" encoding="utf-8"?> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" +<GridLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/pass_row_layout" - android:background="@drawable/rectangle"> + android:background="@drawable/rectangle" + android:orientation="horizontal"> + <TextView + android:id="@+id/type" + android:text="TYPE" + android:layout_column="0" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:padding="8dp" + android:textStyle="bold" + /> <TextView android:id="@+id/label" - android:layout_width="match_parent" - android:layout_height="match_parent" + android:text="FILE_NAME" + android:layout_width="wrap_content" + android:layout_height="wrap_content" android:padding="8dp"/> - -</LinearLayout> +</GridLayout> diff --git a/app/src/main/res/menu/pgp_handler.xml b/app/src/main/res/menu/pgp_handler.xml index bf981e24..26347a3a 100644 --- a/app/src/main/res/menu/pgp_handler.xml +++ b/app/src/main/res/menu/pgp_handler.xml @@ -1,6 +1,6 @@ <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" - tools:context="com.zeapo.pwdstore.PgpHandler" > + tools:context="com.zeapo.pwdstore.crypto.PgpHandler" > <item android:id="@+id/action_settings" android:title="@string/action_settings" android:orderInCategory="100" diff --git a/app/src/main/res/menu/pwdstore.xml b/app/src/main/res/menu/pwdstore.xml index a9c41638..c8acb162 100644 --- a/app/src/main/res/menu/pwdstore.xml +++ b/app/src/main/res/menu/pwdstore.xml @@ -1,6 +1,10 @@ <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" tools:context=".pwdstore" > + <item android:id="@+id/referesh" + android:title="Refresh" + android:showAsAction="ifRoom" + android:icon="@android:drawable/ic_popup_sync"/> <item android:id="@+id/user_pref" android:title="Settings" @@ -8,3 +12,4 @@ android:showAsAction="ifRoom" android:icon="@android:drawable/ic_menu_manage"/> </menu> + diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index ff6c9d2c..e0c5aaeb 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,7 +1,7 @@ <resources> <!-- Base application theme. --> - <style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar"> + <style name="AppTheme" parent="android:Theme.Holo.Light"> <!-- Customize your theme here. --> </style> |