remove pgp handler
This commit is contained in:
parent
a69b6392aa
commit
55db404f14
2 changed files with 0 additions and 844 deletions
|
@ -34,14 +34,6 @@
|
|||
android:value="com.zeapo.pwdstore.PasswordStore" />
|
||||
</activity>
|
||||
|
||||
<activity android:name=".crypto.PgpHandler"
|
||||
android:parentActivityName=".PasswordStore"
|
||||
android:configChanges="orientation|screenSize">
|
||||
|
||||
<meta-data android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="com.zeapo.pwdstore.PasswordStore" />
|
||||
</activity>
|
||||
|
||||
<activity android:name=".SshKeyGen"
|
||||
android:parentActivityName=".PasswordStore">
|
||||
|
||||
|
|
|
@ -1,836 +0,0 @@
|
|||
package com.zeapo.pwdstore.crypto;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.DialogFragment;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.SystemClock;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.text.TextUtils;
|
||||
import android.text.method.PasswordTransformationMethod;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.zeapo.pwdstore.BuildConfig;
|
||||
import com.zeapo.pwdstore.PasswordEntry;
|
||||
import com.zeapo.pwdstore.R;
|
||||
import com.zeapo.pwdstore.SelectFolderFragment;
|
||||
import com.zeapo.pwdstore.UserPreference;
|
||||
import com.zeapo.pwdstore.pwgenDialogFragment;
|
||||
import com.zeapo.pwdstore.utils.PasswordRepository;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.openintents.openpgp.IOpenPgpService2;
|
||||
import org.openintents.openpgp.OpenPgpError;
|
||||
import org.openintents.openpgp.util.OpenPgpApi;
|
||||
import org.openintents.openpgp.util.OpenPgpServiceConnection;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class PgpHandler extends AppCompatActivity implements OpenPgpServiceConnection.OnBound {
|
||||
private static DelayShow delayTask;
|
||||
private OpenPgpServiceConnection mServiceConnection;
|
||||
private Set<String> keyIDs = new HashSet<>();
|
||||
SharedPreferences settings;
|
||||
private Activity activity;
|
||||
ClipboardManager clipboard;
|
||||
|
||||
SelectFolderFragment passwordList;
|
||||
private Intent selectFolderData;
|
||||
|
||||
private boolean registered;
|
||||
|
||||
public static final int REQUEST_CODE_SIGN = 9910;
|
||||
public static final int REQUEST_CODE_ENCRYPT = 9911;
|
||||
public static final int REQUEST_CODE_SIGN_AND_ENCRYPT = 9912;
|
||||
public static final int REQUEST_CODE_DECRYPT_AND_VERIFY = 9913;
|
||||
public static final int REQUEST_CODE_GET_KEY = 9914;
|
||||
public static final int REQUEST_CODE_GET_KEY_IDS = 9915;
|
||||
public static final int REQUEST_CODE_EDIT = 9916;
|
||||
public static final int REQUEST_CODE_SELECT_FOLDER = 9917;
|
||||
|
||||
private PasswordEntry passwordEntry = null;
|
||||
|
||||
public final class Constants {
|
||||
public static final String TAG = "Keychain";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
|
||||
WindowManager.LayoutParams.FLAG_SECURE);
|
||||
|
||||
this.activity = this;
|
||||
this.clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
|
||||
|
||||
if (getIntent().getStringExtra("Operation").equals("ENCRYPT")) {
|
||||
setTitle("New password");
|
||||
}
|
||||
|
||||
// some persistance
|
||||
settings = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
String providerPackageName = settings.getString("openpgp_provider_list", "");
|
||||
keyIDs = settings.getStringSet("openpgp_key_ids_set", new HashSet<String>());
|
||||
|
||||
registered = false;
|
||||
|
||||
if (TextUtils.isEmpty(providerPackageName)) {
|
||||
Toast.makeText(this, this.getResources().getString(R.string.provider_toast_text), Toast.LENGTH_LONG).show();
|
||||
Intent intent = new Intent(this, UserPreference.class);
|
||||
startActivity(intent);
|
||||
// a small hack to avoid eternal loop later, have to be solved via a startactivityforresult()
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
|
||||
} else {
|
||||
|
||||
// bind to service
|
||||
mServiceConnection = new OpenPgpServiceConnection(
|
||||
PgpHandler.this, providerPackageName, this);
|
||||
mServiceConnection.bindToService();
|
||||
registered = true;
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
if (this.registered && this.mServiceConnection.isBound())
|
||||
try {
|
||||
this.mServiceConnection.unbindFromService();
|
||||
} catch (Exception e) {
|
||||
// ignore any errors, we'll stop anyway.
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
// Inflate the menu; this adds items to the action bar if it is present.
|
||||
switch (getIntent().getStringExtra("Operation")) {
|
||||
case "ENCRYPT":
|
||||
getMenuInflater().inflate(R.menu.pgp_handler_new_password, menu);
|
||||
break;
|
||||
case "SELECTFOLDER":
|
||||
getMenuInflater().inflate(R.menu.pgp_handler_select_folder, menu);
|
||||
break;
|
||||
default:
|
||||
getMenuInflater().inflate(R.menu.pgp_handler, menu);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
// Handle action bar item clicks here. The action bar will
|
||||
// automatically handle clicks on the Home/Up button, so long
|
||||
// as you specify a parent activity in AndroidManifest.xml.
|
||||
int id = item.getItemId();
|
||||
switch (id) {
|
||||
case android.R.id.home:
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
return true;
|
||||
case R.id.copy_password:
|
||||
copyPasswordToClipBoard();
|
||||
break;
|
||||
case R.id.share_password_as_plaintext:
|
||||
shareAsPlaintext();
|
||||
break;
|
||||
case R.id.edit_password:
|
||||
editPassword();
|
||||
break;
|
||||
case R.id.crypto_confirm_add:
|
||||
encrypt(new Intent());
|
||||
break;
|
||||
case R.id.crypto_cancel_add:
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
return true;
|
||||
case R.id.crypto_select:
|
||||
selectFolder();
|
||||
break;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void selectFolder() {
|
||||
if (selectFolderData == null || passwordList == null) {
|
||||
Log.wtf(Constants.TAG, "Folder selected while the app didn't ask for one to be selected?");
|
||||
}
|
||||
selectFolderData.putExtra("SELECTED_FOLDER_PATH", passwordList.getCurrentDir().getAbsolutePath());
|
||||
setResult(RESULT_OK, selectFolderData);
|
||||
finish();
|
||||
}
|
||||
|
||||
public void editPassword() {
|
||||
// if in encrypt or in decrypt and password is invisible
|
||||
// (because !showPassword, so this will instantly close), do nothing
|
||||
if (findViewById(R.id.crypto_password_show) == null
|
||||
|| findViewById(R.id.crypto_container).getVisibility() != View.VISIBLE)
|
||||
return;
|
||||
|
||||
CharSequence category = ((TextView) findViewById(R.id.crypto_password_category_decrypt)).getText();
|
||||
CharSequence file = ((TextView) findViewById(R.id.crypto_password_file)).getText();
|
||||
CharSequence password = ((TextView) findViewById(R.id.crypto_password_show)).getText();
|
||||
CharSequence extra = ((TextView) findViewById(R.id.crypto_extra_show)).getText();
|
||||
|
||||
setContentView(R.layout.encrypt_layout);
|
||||
Typeface monoTypeface = Typeface.createFromAsset(getAssets(), "fonts/sourcecodepro.ttf");
|
||||
((EditText) findViewById(R.id.crypto_password_edit)).setTypeface(monoTypeface);
|
||||
((EditText) findViewById(R.id.crypto_extra_edit)).setTypeface(monoTypeface);
|
||||
|
||||
((TextView) findViewById(R.id.crypto_password_category_decrypt)).setText(category);
|
||||
((EditText) findViewById(R.id.crypto_password_file_edit)).setText(file);
|
||||
((EditText) findViewById(R.id.crypto_password_edit)).setText(password);
|
||||
((EditText) findViewById(R.id.crypto_extra_edit)).setText(extra);
|
||||
|
||||
// strictly editing only i.e. can't save this password's info to another file by changing name
|
||||
findViewById(R.id.crypto_password_file_edit).setEnabled(false);
|
||||
|
||||
// the original intent was to decrypt so FILE_PATH will have the file, not enclosing dir
|
||||
// PgpCallback expects the dir when encrypting
|
||||
String filePath = getIntent().getExtras().getString("FILE_PATH");
|
||||
String directoryPath = filePath.substring(0, filePath.lastIndexOf(File.separator));
|
||||
Intent intent = new Intent(this, PgpHandler.class);
|
||||
intent.putExtra("FILE_PATH", directoryPath);
|
||||
intent.putExtra("Operation", "ENCRYPT");
|
||||
intent.putExtra("fromDecrypt", true);
|
||||
setIntent(intent);
|
||||
|
||||
// recreate the options menu to be the encrypt one
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
public void shareAsPlaintext() {
|
||||
|
||||
if (findViewById(R.id.share_password_as_plaintext) == null)
|
||||
return;
|
||||
|
||||
final String decodedPassword = passwordEntry != null ? passwordEntry.getPassword() : "";
|
||||
Intent sendIntent = new Intent();
|
||||
sendIntent.setAction(Intent.ACTION_SEND);
|
||||
sendIntent.putExtra(Intent.EXTRA_TEXT, decodedPassword);
|
||||
sendIntent.setType("text/plain");
|
||||
startActivity(Intent.createChooser(sendIntent, getResources().getText(R.string.send_plaintext_password_to)));//Always show a picker to give the user a chance to cancel
|
||||
}
|
||||
|
||||
public void copyPasswordToClipBoard() {
|
||||
|
||||
if (findViewById(R.id.crypto_password_show) == null)
|
||||
return;
|
||||
|
||||
setTimer();
|
||||
|
||||
final String decodedPassword = passwordEntry != null ? passwordEntry.getPassword() : "";
|
||||
ClipData clip = ClipData.newPlainText("pgp_handler_result_pm", decodedPassword);
|
||||
clipboard.setPrimaryClip(clip);
|
||||
|
||||
int clearAfter = 45;
|
||||
try {
|
||||
clearAfter = Integer.parseInt(settings.getString("general_show_time", "45"));
|
||||
} catch (NumberFormatException e) {
|
||||
// ignore and keep default
|
||||
}
|
||||
showToast(this.getResources().getString(R.string.clipboard_password_toast_text, clearAfter));
|
||||
}
|
||||
|
||||
public void copyUsernameToClipBoard(final String username) {
|
||||
ClipData clip = ClipData.newPlainText("pgp_handler_result_pm", username);
|
||||
clipboard.setPrimaryClip(clip);
|
||||
showToast(this.getResources().getString(R.string.clipboard_username_toast_text));
|
||||
}
|
||||
|
||||
public void handleClick(View view) {
|
||||
switch (view.getId()) {
|
||||
case R.id.generate_password:
|
||||
DialogFragment df = new pwgenDialogFragment();
|
||||
df.show(getFragmentManager(), "generator");
|
||||
default:
|
||||
Log.wtf(Constants.TAG, "This should not happen.... PgpHandler.java#handleClick(View) default reached.");
|
||||
// should not happen
|
||||
}
|
||||
}
|
||||
|
||||
private void handleError(final OpenPgpError error) {
|
||||
runOnUiThread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(PgpHandler.this,
|
||||
"Error from OpenKeyChain : " + error.getMessage(),
|
||||
Toast.LENGTH_LONG).show();
|
||||
Log.e(Constants.TAG, "onError getErrorId:" + error.getErrorId());
|
||||
Log.e(Constants.TAG, "onError getMessage:" + error.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void showToast(final String message) {
|
||||
runOnUiThread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(PgpHandler.this,
|
||||
message,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public class DelayShow extends AsyncTask<Void, Integer, Boolean> {
|
||||
ProgressBar pb;
|
||||
boolean clearClipboard = true;
|
||||
int current, showTime;
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
try {
|
||||
showTime = Integer.parseInt(settings.getString("general_show_time", "45"));
|
||||
} catch (NumberFormatException e) {
|
||||
showTime = 45;
|
||||
}
|
||||
current = 0;
|
||||
|
||||
LinearLayout container = (LinearLayout) findViewById(R.id.crypto_container);
|
||||
container.setVisibility(View.VISIBLE);
|
||||
|
||||
TextView extraText = (TextView) findViewById(R.id.crypto_extra_show);
|
||||
|
||||
if (extraText.getText().length() != 0)
|
||||
findViewById(R.id.crypto_extra_show_layout).setVisibility(View.VISIBLE);
|
||||
|
||||
if (showTime == 0) {
|
||||
// treat 0 as forever, and the user must exit and/or clear clipboard on their own
|
||||
cancel(true);
|
||||
} else {
|
||||
this.pb = (ProgressBar) findViewById(R.id.pbLoading);
|
||||
this.pb.setMax(showTime);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
while (current < showTime) {
|
||||
SystemClock.sleep(1000);
|
||||
current++;
|
||||
publishProgress(current);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean b) {
|
||||
// only clear the clipboard if we automatically copied the password to it
|
||||
if (settings.getBoolean("copy_on_decrypt", true) && clearClipboard) {
|
||||
Log.d("DELAY_SHOW", "Clearing the clipboard");
|
||||
ClipData clip = ClipData.newPlainText("pgp_handler_result_pm", "");
|
||||
clipboard.setPrimaryClip(clip);
|
||||
if (settings.getBoolean("clear_clipboard_20x", false)) {
|
||||
Handler handler = new Handler();
|
||||
for (int i = 0; i < 19; i++) {
|
||||
final String count = String.valueOf(i);
|
||||
handler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
clipboard.setPrimaryClip(ClipData.newPlainText(count, count));
|
||||
}
|
||||
}, i * 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
passwordEntry = null;
|
||||
if (findViewById(R.id.crypto_password_show) != null) {
|
||||
// clear password; if decrypt changed to encrypt layout via edit button, no need
|
||||
((TextView) findViewById(R.id.crypto_password_show)).setText("");
|
||||
((TextView) findViewById(R.id.crypto_extra_show)).setText("");
|
||||
findViewById(R.id.crypto_extra_show_layout).setVisibility(View.INVISIBLE);
|
||||
findViewById(R.id.crypto_container).setVisibility(View.INVISIBLE);
|
||||
activity.setResult(RESULT_CANCELED);
|
||||
activity.finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(Integer... values) {
|
||||
this.pb.setProgress(values[0]);
|
||||
}
|
||||
|
||||
public void setClearClipboard(boolean value) {
|
||||
clearClipboard = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
Log.d(Constants.TAG, "onActivityResult resultCode: " + resultCode);
|
||||
|
||||
if (data == null) {
|
||||
setResult(RESULT_CANCELED, null);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
// 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_ENCRYPT: {
|
||||
encrypt(data);
|
||||
break;
|
||||
}
|
||||
case REQUEST_CODE_DECRYPT_AND_VERIFY: {
|
||||
decryptAndVerify(data);
|
||||
break;
|
||||
}
|
||||
case REQUEST_CODE_GET_KEY_IDS:
|
||||
getKeyIds(data);
|
||||
break;
|
||||
case REQUEST_CODE_EDIT: {
|
||||
edit(data);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
setResult(RESULT_OK);
|
||||
finish();
|
||||
}
|
||||
} else if (resultCode == RESULT_CANCELED) {
|
||||
setResult(RESULT_CANCELED, data);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
private void selectFolder(Intent data) {
|
||||
|
||||
if (data.getStringExtra("Operation") == null || !data.getStringExtra("Operation").equals("SELECTFOLDER")) {
|
||||
Log.e(Constants.TAG, "PgpHandler#selectFolder(Intent) triggered with incorrect intent.");
|
||||
if (BuildConfig.DEBUG) {
|
||||
throw new UnsupportedOperationException("Triggered with incorrect intent.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(Constants.TAG, "PgpHandler#selectFolder(Intent).");
|
||||
|
||||
|
||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
|
||||
|
||||
|
||||
passwordList = new SelectFolderFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putString("Path", PasswordRepository.getRepositoryDirectory(getApplicationContext()).getAbsolutePath());
|
||||
|
||||
passwordList.setArguments(args);
|
||||
|
||||
getSupportActionBar().show();
|
||||
|
||||
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
|
||||
|
||||
fragmentTransaction.replace(R.id.pgp_handler_linearlayout, passwordList, "PasswordsList");
|
||||
fragmentTransaction.commit();
|
||||
|
||||
this.selectFolderData = data;
|
||||
}
|
||||
|
||||
public class PgpCallback implements OpenPgpApi.IOpenPgpCallback {
|
||||
boolean returnToCiphertextField;
|
||||
ByteArrayOutputStream os;
|
||||
int requestCode;
|
||||
|
||||
private PgpCallback(boolean returnToCiphertextField, ByteArrayOutputStream os, int requestCode) {
|
||||
this.returnToCiphertextField = returnToCiphertextField;
|
||||
this.os = os;
|
||||
this.requestCode = requestCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReturn(Intent result) {
|
||||
|
||||
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
|
||||
case OpenPgpApi.RESULT_CODE_SUCCESS: {
|
||||
// encrypt/decrypt/sign/verify
|
||||
final TextView textViewPassword = (TextView) findViewById(R.id.crypto_password_show);
|
||||
if (requestCode == REQUEST_CODE_DECRYPT_AND_VERIFY && os != null) {
|
||||
try {
|
||||
if (returnToCiphertextField) {
|
||||
final boolean showPassword = settings.getBoolean("show_password", true);
|
||||
final boolean showExtraContent = settings.getBoolean("show_extra_content", true);
|
||||
findViewById(R.id.crypto_container).setVisibility(View.VISIBLE);
|
||||
|
||||
Typeface monoTypeface = Typeface.createFromAsset(getAssets(), "fonts/sourcecodepro.ttf");
|
||||
final PasswordEntry entry = new PasswordEntry(os);
|
||||
passwordEntry = entry;
|
||||
textViewPassword.setTypeface(monoTypeface);
|
||||
textViewPassword.setText(entry.getPassword());
|
||||
|
||||
Button toggleVisibilityButton = (Button) findViewById(R.id.crypto_password_toggle_show);
|
||||
toggleVisibilityButton.setVisibility(showPassword ? View.GONE : View.VISIBLE);
|
||||
textViewPassword.setTransformationMethod(showPassword ? null : new HoldToShowPasswordTransformation(toggleVisibilityButton, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
textViewPassword.setText(entry.getPassword());
|
||||
}
|
||||
}));
|
||||
|
||||
if (entry.hasExtraContent()) {
|
||||
findViewById(R.id.crypto_extra_show_layout).setVisibility(showExtraContent ? View.VISIBLE : View.GONE);
|
||||
final TextView extraView = (TextView) findViewById(R.id.crypto_extra_show);
|
||||
extraView.setTypeface(monoTypeface);
|
||||
extraView.setText(entry.getExtraContent());
|
||||
if (entry.hasUsername()) {
|
||||
findViewById(R.id.crypto_username_show).setVisibility(View.VISIBLE);
|
||||
findViewById(R.id.crypto_username_show_label).setVisibility(View.VISIBLE);
|
||||
findViewById(R.id.crypto_copy_username).setVisibility(View.VISIBLE);
|
||||
findViewById(R.id.crypto_copy_username).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
copyUsernameToClipBoard(entry.getUsername());
|
||||
}
|
||||
});
|
||||
final TextView usernameView = (TextView) findViewById(R.id.crypto_username_show);
|
||||
usernameView.setTypeface(monoTypeface);
|
||||
usernameView.setText(entry.getUsername());
|
||||
} else {
|
||||
findViewById(R.id.crypto_username_show).setVisibility(View.GONE);
|
||||
findViewById(R.id.crypto_username_show_label).setVisibility(View.GONE);
|
||||
findViewById(R.id.crypto_copy_username).setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
if (settings.getBoolean("copy_on_decrypt", true)) {
|
||||
copyPasswordToClipBoard();
|
||||
}
|
||||
} else {
|
||||
Log.d("PGPHANDLER", "Error message after decrypt : " + os.toString());
|
||||
}
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
Log.e(Constants.TAG, "UnsupportedEncodingException", e);
|
||||
}
|
||||
}
|
||||
// encrypt
|
||||
if (requestCode == REQUEST_CODE_ENCRYPT && os != null) {
|
||||
try {
|
||||
String path = getIntent().getExtras().getString("FILE_PATH")
|
||||
+ "/" + ((EditText) findViewById(R.id.crypto_password_file_edit)).getText().toString()
|
||||
+ ".gpg";
|
||||
OutputStream outputStream = FileUtils.openOutputStream(new File(path));
|
||||
outputStream.write(os.toByteArray());
|
||||
outputStream.close();
|
||||
Intent data = new Intent();
|
||||
data.putExtra("CREATED_FILE", path);
|
||||
data.putExtra("NAME", ((EditText) findViewById(R.id.crypto_password_file_edit)).getText().toString());
|
||||
// if coming from decrypt screen->edit button
|
||||
if (getIntent().getBooleanExtra("fromDecrypt", false)) {
|
||||
data.putExtra("needCommit", true);
|
||||
}
|
||||
setResult(RESULT_OK, data);
|
||||
finish();
|
||||
} catch (Exception e) {
|
||||
Log.e(Constants.TAG, "UnsupportedEncodingException", e);
|
||||
}
|
||||
}
|
||||
|
||||
// get key ids
|
||||
if (result.hasExtra(OpenPgpApi.RESULT_KEY_IDS)) {
|
||||
long[] ids = result.getLongArrayExtra(OpenPgpApi.RESULT_KEY_IDS);
|
||||
Set<String> keys = new HashSet<>();
|
||||
|
||||
for (long id : ids) keys.add(String.valueOf(id)); // use Long
|
||||
settings.edit().putStringSet("openpgp_key_ids_set", keys).apply();
|
||||
|
||||
showToast("PGP key selected");
|
||||
setResult(RESULT_OK);
|
||||
finish();
|
||||
}
|
||||
|
||||
// edit
|
||||
if (requestCode == REQUEST_CODE_EDIT && os != null) {
|
||||
try {
|
||||
if (returnToCiphertextField) {
|
||||
findViewById(R.id.crypto_container).setVisibility(View.VISIBLE);
|
||||
|
||||
Typeface monoTypeface = Typeface.createFromAsset(getAssets(), "fonts/sourcecodepro.ttf");
|
||||
final PasswordEntry entry = new PasswordEntry(os);
|
||||
passwordEntry = entry;
|
||||
textViewPassword
|
||||
.setTypeface(monoTypeface);
|
||||
textViewPassword
|
||||
.setText(entry.getPassword());
|
||||
|
||||
String extraContent = os.toString("UTF-8").replaceFirst(".*\n", "");
|
||||
if (extraContent.length() != 0) {
|
||||
((TextView) findViewById(R.id.crypto_extra_show))
|
||||
.setTypeface(monoTypeface);
|
||||
((TextView) findViewById(R.id.crypto_extra_show))
|
||||
.setText(extraContent);
|
||||
}
|
||||
|
||||
editPassword();
|
||||
} else {
|
||||
Log.d("PGPHANDLER", "Error message after decrypt : " + os.toString());
|
||||
}
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
Log.e(Constants.TAG, "UnsupportedEncodingException", e);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED: {
|
||||
Log.i("PgpHandler", "RESULT_CODE_USER_INTERACTION_REQUIRED");
|
||||
|
||||
PendingIntent pi = result.getParcelableExtra(OpenPgpApi.RESULT_INTENT);
|
||||
try {
|
||||
PgpHandler.this.startIntentSenderForResult(pi.getIntentSender(),
|
||||
requestCode, null, 0, 0, 0);
|
||||
} catch (IntentSender.SendIntentException e) {
|
||||
Log.e(Constants.TAG, "SendIntentException", e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpenPgpApi.RESULT_CODE_ERROR: {
|
||||
// TODO show what kind of error it is
|
||||
/* For example:
|
||||
* No suitable key found -> no key in OpenKeyChain
|
||||
*
|
||||
* Check in open-pgp-lib how their definitions and error code
|
||||
*/
|
||||
OpenPgpError error = result.getParcelableExtra(OpenPgpApi.RESULT_ERROR);
|
||||
handleError(error);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void getKeyIds(Intent data) {
|
||||
data.setAction(OpenPgpApi.ACTION_GET_KEY_IDS);
|
||||
OpenPgpApi api = new OpenPgpApi(this, mServiceConnection.getService());
|
||||
api.executeApiAsync(data, null, null, new PgpCallback(false, null, PgpHandler.REQUEST_CODE_GET_KEY_IDS));
|
||||
}
|
||||
|
||||
public void decryptAndVerify(Intent data) {
|
||||
data.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY);
|
||||
|
||||
try {
|
||||
InputStream is = FileUtils.openInputStream(new File(getIntent().getExtras().getString("FILE_PATH")));
|
||||
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
|
||||
OpenPgpApi api = new OpenPgpApi(this, mServiceConnection.getService());
|
||||
api.executeApiAsync(data, is, os, new PgpCallback(true, os, REQUEST_CODE_DECRYPT_AND_VERIFY));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a password file
|
||||
*/
|
||||
public void encrypt(Intent data) {
|
||||
data.setAction(OpenPgpApi.ACTION_ENCRYPT);
|
||||
|
||||
// EXTRA_KEY_IDS requires long[]
|
||||
long[] longKeys = new long[keyIDs.size()];
|
||||
int i = 0;
|
||||
for (String keyId : keyIDs) {
|
||||
longKeys[i] = Long.valueOf(keyId);
|
||||
++i;
|
||||
}
|
||||
data.putExtra(OpenPgpApi.EXTRA_KEY_IDS, longKeys);
|
||||
|
||||
data.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
|
||||
|
||||
String name = ((EditText) findViewById(R.id.crypto_password_file_edit)).getText().toString();
|
||||
String pass = ((EditText) findViewById(R.id.crypto_password_edit)).getText().toString();
|
||||
String extra = ((EditText) findViewById(R.id.crypto_extra_edit)).getText().toString();
|
||||
|
||||
if (name.isEmpty()) {
|
||||
showToast(this.getResources().getString(R.string.file_toast_text));
|
||||
return;
|
||||
}
|
||||
|
||||
if (pass.isEmpty() && extra.isEmpty()) {
|
||||
showToast(this.getResources().getString(R.string.empty_toast_text));
|
||||
return;
|
||||
}
|
||||
|
||||
ByteArrayInputStream is;
|
||||
|
||||
try {
|
||||
is = new ByteArrayInputStream((pass + "\n" + extra).getBytes("UTF-8"));
|
||||
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
|
||||
OpenPgpApi api = new OpenPgpApi(this, mServiceConnection.getService());
|
||||
api.executeApiAsync(data, is, os, new PgpCallback(true, os, REQUEST_CODE_ENCRYPT));
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void edit(Intent data) {
|
||||
// exactly same as decrypt, only we want a different callback
|
||||
data.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY);
|
||||
|
||||
try {
|
||||
InputStream is = FileUtils.openInputStream(new File(getIntent().getExtras().getString("FILE_PATH")));
|
||||
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
|
||||
OpenPgpApi api = new OpenPgpApi(this, mServiceConnection.getService());
|
||||
api.executeApiAsync(data, is, os, new PgpCallback(true, os, REQUEST_CODE_EDIT));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO (low priority but still...) android M potential permissions crashes
|
||||
@SuppressLint("SetTextI18n")
|
||||
@Override
|
||||
public void onBound(IOpenPgpService2 service) {
|
||||
Log.i("PGP", "ISBOUND!!");
|
||||
|
||||
Bundle extra = getIntent().getExtras();
|
||||
final String operation = extra.getString("Operation");
|
||||
if (operation == null) {
|
||||
return;
|
||||
}
|
||||
switch (operation) {
|
||||
case "DECRYPT": {
|
||||
setContentView(R.layout.decrypt_layout);
|
||||
((TextView) findViewById(R.id.crypto_password_file)).setText(extra.getString("NAME"));
|
||||
String path = extra
|
||||
.getString("FILE_PATH")
|
||||
.replace(PasswordRepository.getRepositoryDirectory(getApplicationContext()).getAbsolutePath(), "");
|
||||
String cat = new File(path).getParentFile().getName();
|
||||
|
||||
((TextView) findViewById(R.id.crypto_password_category_decrypt)).setText(cat + "/");
|
||||
decryptAndVerify(new Intent());
|
||||
break;
|
||||
}
|
||||
case "ENCRYPT": {
|
||||
setContentView(R.layout.encrypt_layout);
|
||||
Typeface monoTypeface = Typeface.createFromAsset(getAssets(), "fonts/sourcecodepro.ttf");
|
||||
((EditText) findViewById(R.id.crypto_password_edit)).setTypeface(monoTypeface);
|
||||
((EditText) findViewById(R.id.crypto_extra_edit)).setTypeface(monoTypeface);
|
||||
String cat = extra.getString("FILE_PATH");
|
||||
cat = cat.replace(PasswordRepository.getRepositoryDirectory(getApplicationContext()).getAbsolutePath(), "");
|
||||
cat = cat + "/";
|
||||
((TextView) findViewById(R.id.crypto_password_category_decrypt)).setText(cat);
|
||||
break;
|
||||
}
|
||||
case "GET_KEY_ID":
|
||||
getKeyIds(new Intent());
|
||||
|
||||
// setContentView(R.layout.key_id);
|
||||
// if (!keyIDs.isEmpty()) {
|
||||
// String keys = keyIDs.split(",").length > 1 ? keyIDs : keyIDs.split(",")[0];
|
||||
// ((TextView) findViewById(R.id.crypto_key_ids)).setText(keys);
|
||||
// }
|
||||
break;
|
||||
case "EDIT": {
|
||||
setContentView(R.layout.decrypt_layout);
|
||||
((TextView) findViewById(R.id.crypto_password_file)).setText(extra.getString("NAME"));
|
||||
String cat = new File(extra.getString("FILE_PATH").replace(PasswordRepository.getRepositoryDirectory(getApplicationContext()).getAbsolutePath(), ""))
|
||||
.getParentFile().getName();
|
||||
|
||||
((TextView) findViewById(R.id.crypto_password_category_decrypt)).setText(cat + "/");
|
||||
edit(new Intent());
|
||||
break;
|
||||
}
|
||||
case "SELECTFOLDER":
|
||||
setContentView(R.layout.select_folder_layout);
|
||||
selectFolder(getIntent());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception e) {
|
||||
|
||||
}
|
||||
|
||||
private class HoldToShowPasswordTransformation extends PasswordTransformationMethod implements View.OnTouchListener {
|
||||
private final Runnable onToggle;
|
||||
private boolean shown = false;
|
||||
|
||||
private HoldToShowPasswordTransformation(Button button, Runnable onToggle) {
|
||||
this.onToggle = onToggle;
|
||||
button.setOnTouchListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTransformation(CharSequence charSequence, View view) {
|
||||
return shown ? charSequence : super.getTransformation("12345", view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View view, MotionEvent motionEvent) {
|
||||
switch (motionEvent.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
shown = true;
|
||||
onToggle.run();
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
shown = false;
|
||||
onToggle.run();
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void setTimer() {
|
||||
// If a task already exist, let it finish without clearing the clipboard
|
||||
if (delayTask != null) {
|
||||
delayTask.setClearClipboard(false);
|
||||
}
|
||||
|
||||
delayTask = new DelayShow();
|
||||
delayTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue