summaryrefslogtreecommitdiff
path: root/app/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java')
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/PasswordStore.java138
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/UserPreference.java96
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/crypto/PgpHandler.java1
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/git/GitActivity.java73
4 files changed, 225 insertions, 83 deletions
diff --git a/app/src/main/java/com/zeapo/pwdstore/PasswordStore.java b/app/src/main/java/com/zeapo/pwdstore/PasswordStore.java
index 33b6bd29..96e58d89 100644
--- a/app/src/main/java/com/zeapo/pwdstore/PasswordStore.java
+++ b/app/src/main/java/com/zeapo/pwdstore/PasswordStore.java
@@ -1,13 +1,19 @@
package com.zeapo.pwdstore;
+import android.Manifest;
import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.graphics.Color;
import android.os.Bundle;
import android.preference.PreferenceManager;
+import android.support.design.widget.Snackbar;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.content.ContextCompat;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
@@ -16,6 +22,7 @@ import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
+import android.widget.TextView;
import com.zeapo.pwdstore.crypto.PgpHandler;
import com.zeapo.pwdstore.git.GitActivity;
@@ -47,19 +54,76 @@ public class PasswordStore extends AppCompatActivity {
private final static int NEW_REPO_BUTTON = 402;
private final static int HOME = 403;
+ private final static int REQUEST_EXTERNAL_STORAGE = 50;
@Override
protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_pwdstore);
settings = PreferenceManager.getDefaultSharedPreferences(this.getApplicationContext());
activity = this;
PRNGFixes.apply();
+
+ // If user opens app with permission granted then revokes and returns,
+ // prevent attempt to create password list fragment
+ if (savedInstanceState != null && (!settings.getBoolean("git_external", false)
+ || ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)) {
+ savedInstanceState = null;
+ }
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_pwdstore);
}
@Override
public void onResume(){
super.onResume();
- checkLocalRepository();
+ // do not attempt to checkLocalRepository() if no storage permission: immediate crash
+ if (settings.getBoolean("git_external", false)) {
+ if (ContextCompat.checkSelfPermission(activity,
+ Manifest.permission.READ_EXTERNAL_STORAGE)
+ != PackageManager.PERMISSION_GRANTED) {
+
+ if (ActivityCompat.shouldShowRequestPermissionRationale(activity,
+ Manifest.permission.READ_EXTERNAL_STORAGE)) {
+ Snackbar snack = Snackbar.make(findViewById(R.id.main_layout), "The store is on the sdcard but the app does not have permission to access it. Please give permission.",
+ Snackbar.LENGTH_INDEFINITE)
+ .setAction(R.string.dialog_ok, new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ ActivityCompat.requestPermissions(activity,
+ new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
+ REQUEST_EXTERNAL_STORAGE);
+ }
+ });
+ snack.show();
+ View view = snack.getView();
+ TextView tv = (TextView) view.findViewById(android.support.design.R.id.snackbar_text);
+ tv.setTextColor(Color.WHITE);
+ tv.setMaxLines(10);
+ } else {
+ // No explanation needed, we can request the permission.
+ ActivityCompat.requestPermissions(activity,
+ new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
+ REQUEST_EXTERNAL_STORAGE);
+ }
+ } else {
+ checkLocalRepository();
+ }
+
+ } else {
+ checkLocalRepository();
+ }
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode,
+ String permissions[], int[] grantResults) {
+ switch (requestCode) {
+ case REQUEST_EXTERNAL_STORAGE: {
+ // If request is cancelled, the result arrays are empty.
+ if (grantResults.length > 0
+ && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ checkLocalRepository();
+ }
+ }
+ }
}
@Override
@@ -495,33 +559,9 @@ public class PasswordStore extends AppCompatActivity {
PasswordRepository.closeRepository();
new AlertDialog.Builder(this)
- .setTitle("Repositiory location")
+ .setTitle("Repository location")
.setMessage("Select where to create or clone your password repository.")
- .setPositiveButton("External", new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int whichButton) {
- settings.edit().putBoolean("git_external", true).apply();
-
- if (settings.getString("git_external_repo", null) == null) {
- Intent intent = new Intent(activity, UserPreference.class);
- intent.putExtra("operation", "git_external");
- startActivityForResult(intent, operation);
- } else {
- switch (operation) {
- case NEW_REPO_BUTTON:
- initializeRepositoryInfo();
- break;
- case CLONE_REPO_BUTTON:
- PasswordRepository.initialize(PasswordStore.this);
-
- Intent intent = new Intent(activity, GitActivity.class);
- intent.putExtra("Operation", GitActivity.REQUEST_CLONE);
- startActivityForResult(intent, GitActivity.REQUEST_CLONE);
- break;
- }
- }
- }
- })
- .setNegativeButton("Internal", new DialogInterface.OnClickListener() {
+ .setPositiveButton("Hidden (preferred)", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
settings.edit().putBoolean("git_external", false).apply();
@@ -539,6 +579,46 @@ public class PasswordStore extends AppCompatActivity {
}
}
})
+ .setNegativeButton("SD-Card", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ settings.edit().putBoolean("git_external", true).apply();
+
+ if (settings.getString("git_external_repo", null) == null) {
+ Intent intent = new Intent(activity, UserPreference.class);
+ intent.putExtra("operation", "git_external");
+ startActivityForResult(intent, operation);
+ } else {
+ new AlertDialog.Builder(activity).
+ setTitle("Directory already selected").
+ setMessage("Do you want to use \"" + settings.getString("git_external_repo", null) + "\"?").
+ setPositiveButton("Use", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ switch (operation) {
+ case NEW_REPO_BUTTON:
+ initializeRepositoryInfo();
+ break;
+ case CLONE_REPO_BUTTON:
+ PasswordRepository.initialize(PasswordStore.this);
+
+ Intent intent = new Intent(activity, GitActivity.class);
+ intent.putExtra("Operation", GitActivity.REQUEST_CLONE);
+ startActivityForResult(intent, GitActivity.REQUEST_CLONE);
+ break;
+ }
+ }
+ }).
+ setNegativeButton("Change", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Intent intent = new Intent(activity, UserPreference.class);
+ intent.putExtra("operation", "git_external");
+ startActivityForResult(intent, operation);
+ }
+ }).show();
+ }
+ }
+ })
.show();
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/UserPreference.java b/app/src/main/java/com/zeapo/pwdstore/UserPreference.java
index 8f8e8d66..5fb710cf 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.accessibilityservice.AccessibilityServiceInfo;
+import android.app.Activity;
import android.app.DialogFragment;
import android.content.Context;
import android.content.DialogInterface;
@@ -8,6 +9,7 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Environment;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.PreferenceFragment;
@@ -15,7 +17,6 @@ import android.preference.PreferenceManager;
import android.provider.Settings;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
-import android.text.SpannableStringBuilder;
import android.view.MenuItem;
import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
@@ -23,13 +24,12 @@ import android.widget.Toast;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.Iterables;
+import com.nononsenseapps.filepicker.FilePickerActivity;
import com.zeapo.pwdstore.autofill.AutofillPreferenceActivity;
import com.zeapo.pwdstore.crypto.PgpHandler;
import com.zeapo.pwdstore.git.GitActivity;
import com.zeapo.pwdstore.utils.PasswordRepository;
-import net.rdrei.android.dirchooser.DirectoryChooserActivity;
-
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.openintents.openpgp.util.OpenPgpKeyPreference;
@@ -124,7 +124,8 @@ public class UserPreference extends AppCompatActivity {
public boolean onPreferenceClick(Preference preference) {
new AlertDialog.Builder(callingActivity).
setTitle(R.string.pref_dialog_delete_title).
- setMessage(R.string.pref_dialog_delete_msg).
+ setMessage(getResources().getString(R.string.dialog_delete_msg)
+ + " \n" + PasswordRepository.getWorkTree().toString()).
setCancelable(false).
setPositiveButton(R.string.dialog_delete, new DialogInterface.OnClickListener() {
@Override
@@ -230,6 +231,7 @@ public class UserPreference extends AppCompatActivity {
public void onStart() {
super.onStart();
final SharedPreferences sharedPreferences = getPreferenceManager().getSharedPreferences();
+ findPreference("pref_select_external").setSummary(getPreferenceManager().getSharedPreferences().getString("git_external_repo", "No external repository selected"));
findPreference("ssh_see_key").setEnabled(sharedPreferences.getBoolean("use_generated_key", false));
// see if the autofill service is enabled and check the preference accordingly
@@ -264,11 +266,32 @@ public class UserPreference extends AppCompatActivity {
}
public void selectExternalGitRepository() {
- Intent intent = new Intent(this, DirectoryChooserActivity.class);
- intent.putExtra(DirectoryChooserActivity.EXTRA_NEW_DIR_NAME,
- "passwordstore");
+ final Activity activity = this;
+ new AlertDialog.Builder(this).
+ setTitle("Choose where to store the passwords").
+ setMessage("You must select a directory where to store your passwords. If you want " +
+ "to store your passwords within the hidden storage of the application, " +
+ "cancel this dialog and disable the \"External Repository\" option.").
+ setPositiveButton(R.string.dialog_ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ // This always works
+ Intent i = new Intent(activity.getApplicationContext(), FilePickerActivity.class);
+ // This works if you defined the intent filter
+ // Intent i = new Intent(Intent.ACTION_GET_CONTENT);
+
+ // Set these depending on your use case. These are the defaults.
+ i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false);
+ i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, true);
+ i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR);
+
+ i.putExtra(FilePickerActivity.EXTRA_START_PATH, Environment.getExternalStorageDirectory().getPath());
+
+ startActivityForResult(i, SELECT_GIT_DIRECTORY);
+ }
+ }).
+ setNegativeButton(R.string.dialog_cancel, null).show();
- startActivityForResult(intent, SELECT_GIT_DIRECTORY);
}
@Override
@@ -344,6 +367,11 @@ public class UserPreference extends AppCompatActivity {
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("use_generated_key", false);
editor.apply();
+
+ //delete the public key from generation
+ File file = new File(getFilesDir() + "/.ssh_key.pub");
+ file.delete();
+
setResult(RESULT_OK);
finish();
} catch (IOException e) {
@@ -371,17 +399,53 @@ public class UserPreference extends AppCompatActivity {
}
}
break;
+ case SELECT_GIT_DIRECTORY: {
+ final Uri uri = data.getData();
+
+ if (uri.getPath().equals(Environment.getExternalStorageDirectory().getPath())) {
+ // the user wants to use the root of the sdcard as a store...
+ new AlertDialog.Builder(this).
+ setTitle("SD-Card root selected").
+ setMessage("You have selected the root of your sdcard for the store. " +
+ "This is extremely dangerous and you will lose your data " +
+ "as its content will be deleted").
+ setPositiveButton("Remove everything", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ PreferenceManager.getDefaultSharedPreferences(getApplicationContext())
+ .edit()
+ .putString("git_external_repo", uri.getPath())
+ .apply();
+ }
+ }).
+ setNegativeButton(R.string.dialog_cancel, null).show();
+ } else if (new File(uri.getPath()).listFiles().length != 0) {
+ new AlertDialog.Builder(this).
+ setTitle("Directory not empty").
+ setMessage("You have selected a non-empty directory for the store. " +
+ "This is extremely dangerous and you will lose your data " +
+ "as its content will be deleted").
+ setPositiveButton("Remove everything", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ PreferenceManager.getDefaultSharedPreferences(getApplicationContext())
+ .edit()
+ .putString("git_external_repo", uri.getPath())
+ .apply();
+ }
+ }).
+ setNegativeButton(R.string.dialog_cancel, null).show();
+ } else {
+ PreferenceManager.getDefaultSharedPreferences(getApplicationContext())
+ .edit()
+ .putString("git_external_repo", uri.getPath())
+ .apply();
+ }
+ }
+ break;
default:
break;
}
}
-
- // why do they have to use a different resultCode than OK :/
- if (requestCode == SELECT_GIT_DIRECTORY && resultCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) {
- PreferenceManager.getDefaultSharedPreferences(getApplicationContext())
- .edit()
- .putString("git_external_repo", data.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR))
- .apply();
- }
}
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/crypto/PgpHandler.java b/app/src/main/java/com/zeapo/pwdstore/crypto/PgpHandler.java
index a620bd33..fd92a1f7 100644
--- a/app/src/main/java/com/zeapo/pwdstore/crypto/PgpHandler.java
+++ b/app/src/main/java/com/zeapo/pwdstore/crypto/PgpHandler.java
@@ -560,6 +560,7 @@ public class PgpHandler extends AppCompatActivity implements OpenPgpServiceConne
}
+ // TODO (low priority but still...) android M potential permissions crashes
@Override
public void onBound(IOpenPgpService2 service) {
Log.i("PGP", "ISBOUND!!");
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/GitActivity.java b/app/src/main/java/com/zeapo/pwdstore/git/GitActivity.java
index 00d5be35..a1ca9519 100644
--- a/app/src/main/java/com/zeapo/pwdstore/git/GitActivity.java
+++ b/app/src/main/java/com/zeapo/pwdstore/git/GitActivity.java
@@ -45,7 +45,6 @@ public class GitActivity extends AppCompatActivity {
private File localDir;
private String hostname;
- private String username;
private String port;
private SharedPreferences settings;
@@ -404,7 +403,7 @@ public class GitActivity extends AppCompatActivity {
/**
* Saves the configuration found in the form
*/
- private void saveConfiguration() {
+ private boolean saveConfiguration() {
// remember the settings
SharedPreferences.Editor editor = settings.edit();
@@ -416,11 +415,39 @@ public class GitActivity extends AppCompatActivity {
editor.putString("git_remote_port", ((EditText) findViewById(R.id.server_port)).getText().toString());
editor.putString("git_remote_uri", ((EditText) findViewById(R.id.clone_uri)).getText().toString());
+ // 'save' hostname variable for use by addRemote() either here or later
+ // in syncRepository()
+ hostname = ((EditText) findViewById(R.id.clone_uri)).getText().toString();
+ port = ((EditText) findViewById(R.id.server_port)).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);
+
+ if (!protocol.equals("ssh://")) {
+ hostname = protocol + hostname;
+ } else {
+
+ // if the port is explicitly given, jgit requires the ssh://
+ if (!port.isEmpty())
+ hostname = protocol + hostname;
+
+ // did he forget the username?
+ if (!hostname.matches("^.+@.+")) {
+ new AlertDialog.Builder(this).
+ setMessage(activity.getResources().getString(R.string.forget_username_dialog_text)).
+ setPositiveButton(activity.getResources().getString(R.string.dialog_oops), null).
+ show();
+ return false;
+ }
+ }
if (PasswordRepository.isInitialized()) {
- PasswordRepository.addRemote("origin", ((EditText) findViewById(R.id.clone_uri)).getText().toString(), true);
+ // don't just use the clone_uri text, need to use hostname which has
+ // had the proper protocol prepended
+ PasswordRepository.addRemote("origin", hostname, true);
}
editor.apply();
+ return true;
}
/**
@@ -429,7 +456,8 @@ public class GitActivity extends AppCompatActivity {
* @param view
*/
public void saveConfiguration(View view) {
- saveConfiguration();
+ if (!saveConfiguration())
+ return;
finish();
}
@@ -443,45 +471,14 @@ public class GitActivity extends AppCompatActivity {
PasswordRepository.initialize(this);
}
localDir = PasswordRepository.getWorkTree();
- hostname = ((EditText) findViewById(R.id.clone_uri)).getText().toString();
- port = ((EditText) findViewById(R.id.server_port)).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 = protocol + hostname;
- } else {
-
- // if the port is explicitly given, jgit requires the ssh://
- if (!port.isEmpty())
- hostname = protocol + hostname;
-
- // did he forget the username?
- if (!hostname.matches("^.+@.+")) {
- new AlertDialog.Builder(this).
- setMessage(activity.getResources().getString(R.string.forget_username_dialog_text)).
- setPositiveButton(activity.getResources().getString(R.string.dialog_oops), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
-
- }
- }).
- show();
- return;
- }
- username = hostname.split("@")[0];
- }
-
- saveConfiguration();
+ if (!saveConfiguration())
+ return;
if (localDir.exists() && localDir.listFiles().length != 0) {
new AlertDialog.Builder(this).
setTitle(R.string.dialog_delete_title).
- setMessage(R.string.dialog_delete_msg).
+ setMessage(getResources().getString(R.string.dialog_delete_msg) + " " + localDir.toString()).
setCancelable(false).
setPositiveButton(R.string.dialog_delete,
new DialogInterface.OnClickListener() {