Merge remote-tracking branch 'origin/master'

Conflicts:
	OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java
This commit is contained in:
Vincent Breitmoser 2014-09-24 01:42:17 +02:00
commit c871891f49
18 changed files with 335 additions and 204 deletions

View file

@ -96,7 +96,8 @@
<activity
android:name=".ui.CreateKeyActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
android:label="@string/title_create_key">
android:label="@string/title_create_key"
android:parentActivityName=".ui.KeyListActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".ui.KeyListActivity" />
@ -198,7 +199,11 @@
android:name=".ui.DecryptTextActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
android:label="@string/title_decrypt"
android:windowSoftInputMode="stateHidden">
android:windowSoftInputMode="stateHidden"
android:parentActivityName=".ui.DecryptActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".ui.DecryptActivity" />
<!-- Keychain's own Actions -->
<!-- DECRYPT with text as extra -->
@ -221,7 +226,11 @@
android:name=".ui.DecryptFilesActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
android:label="@string/title_decrypt"
android:windowSoftInputMode="stateHidden">
android:windowSoftInputMode="stateHidden"
android:parentActivityName=".ui.DecryptActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".ui.DecryptActivity" />
<!-- VIEW with mimeType application/octet-stream, application/pgp and text/pgp -->
<intent-filter android:label="@string/intent_send_decrypt">

View file

@ -107,9 +107,8 @@ public class AccountSettingsActivity extends ActionBarActivity {
private void save() {
new ProviderHelper(this).updateApiAccount(mAccountUri, mAccountSettingsFragment.getAccSettings());
// TODO: show "account saved" instead of "operation succeeded"
SingletonResult result = new SingletonResult(
SingletonResult.RESULT_OK, LogLevel.OK, LogType.MSG_ACC_SAVED);
SingletonResult.RESULT_OK, LogType.MSG_ACC_SAVED);
Intent intent = new Intent();
intent.putExtra(SingletonResult.EXTRA_RESULT, result);
setResult(RESULT_OK, intent);

View file

@ -140,15 +140,16 @@ public class KeychainIntentService extends IntentService implements Progressable
public static final String ENCRYPT_ENCRYPTION_KEYS_IDS = "encryption_keys_ids";
public static final String ENCRYPT_COMPRESSION_ID = "compression_id";
public static final String ENCRYPT_MESSAGE_BYTES = "message_bytes";
public static final String ENCRYPT_INPUT_URI = "input_uri";
public static final String ENCRYPT_DECRYPT_INPUT_URI = "input_uri";
public static final String ENCRYPT_INPUT_URIS = "input_uris";
public static final String ENCRYPT_OUTPUT_URI = "output_uri";
public static final String ENCRYPT_DECRYPT_OUTPUT_URI = "output_uri";
public static final String ENCRYPT_OUTPUT_URIS = "output_uris";
public static final String ENCRYPT_SYMMETRIC_PASSPHRASE = "passphrase";
// decrypt/verify
public static final String DECRYPT_CIPHERTEXT_BYTES = "ciphertext_bytes";
public static final String DECRYPT_PASSPHRASE = "passphrase";
public static final String DECRYPT_NFC_DECRYPTED_SESSION_KEY = "nfc_decrypted_session_key";
// save keyring
public static final String EDIT_KEYRING_PARCEL = "save_parcel";
@ -337,6 +338,7 @@ public class KeychainIntentService extends IntentService implements Progressable
try {
/* Input */
String passphrase = data.getString(DECRYPT_PASSPHRASE);
byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY);
InputData inputData = createDecryptInputData(data);
OutputStream outStream = createCryptOutputStream(data);
@ -353,7 +355,8 @@ public class KeychainIntentService extends IntentService implements Progressable
);
builder.setProgressable(this)
.setAllowSymmetricDecryption(true)
.setPassphrase(passphrase);
.setPassphrase(passphrase)
.setNfcState(nfcDecryptedSessionKey);
DecryptVerifyResult decryptVerifyResult = builder.build().execute();
@ -375,6 +378,7 @@ public class KeychainIntentService extends IntentService implements Progressable
try {
/* Input */
String passphrase = data.getString(DECRYPT_PASSPHRASE);
byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY);
InputData inputData = createDecryptInputData(data);
@ -391,7 +395,8 @@ public class KeychainIntentService extends IntentService implements Progressable
builder.setProgressable(this)
.setAllowSymmetricDecryption(true)
.setPassphrase(passphrase)
.setDecryptMetadataOnly(true);
.setDecryptMetadataOnly(true)
.setNfcState(nfcDecryptedSessionKey);
DecryptVerifyResult decryptVerifyResult = builder.build().execute();
@ -860,7 +865,7 @@ public class KeychainIntentService extends IntentService implements Progressable
return new InputData(new ByteArrayInputStream(bytes), bytes.length);
case IO_URI: /* encrypting content uri */
Uri providerUri = data.getParcelable(ENCRYPT_INPUT_URI);
Uri providerUri = data.getParcelable(ENCRYPT_DECRYPT_INPUT_URI);
// InputStream
return new InputData(getContentResolver().openInputStream(providerUri), FileHelper.getFileSize(this, providerUri, 0));
@ -912,7 +917,7 @@ public class KeychainIntentService extends IntentService implements Progressable
return "";
case IO_URI:
Uri providerUri = data.getParcelable(ENCRYPT_INPUT_URI);
Uri providerUri = data.getParcelable(ENCRYPT_DECRYPT_INPUT_URI);
return FileHelper.getFilename(this, providerUri);
@ -933,7 +938,7 @@ public class KeychainIntentService extends IntentService implements Progressable
return new ByteArrayOutputStream();
case IO_URI:
Uri providerUri = data.getParcelable(ENCRYPT_OUTPUT_URI);
Uri providerUri = data.getParcelable(ENCRYPT_DECRYPT_OUTPUT_URI);
return getContentResolver().openOutputStream(providerUri);

View file

@ -519,7 +519,9 @@ public abstract class OperationResult implements Parcelable {
MSG_CRT_UPLOAD_SUCCESS (LogLevel.OK, R.string.msg_crt_upload_success),
MSG_CRT_SUCCESS (LogLevel.OK, R.string.msg_crt_success),
MSG_ACC_SAVED (LogLevel.INFO, R.string.api_settings_save)
MSG_ACC_SAVED (LogLevel.INFO, R.string.api_settings_save_msg),
MSG_NO_VALID_ENC (LogLevel.ERROR, R.string.error_invalid_data)
;

View file

@ -34,7 +34,7 @@ public class SingletonResult extends OperationResult {
super(source);
}
public SingletonResult(int result, LogLevel level, LogType reason) {
public SingletonResult(int result, LogType reason) {
super(result, new OperationLog());
// Prepare the log
mLog.add(reason, 0);

View file

@ -330,7 +330,7 @@ public class CertifyKeyFragment extends LoaderFragment
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
SingletonResult result = new SingletonResult(
SingletonResult.RESULT_OK, LogLevel.OK, LogType.MSG_CRT_SUCCESS);
SingletonResult.RESULT_OK, LogType.MSG_CRT_SUCCESS);
Intent intent = new Intent();
intent.putExtra(SingletonResult.EXTRA_RESULT, result);
mActivity.setResult(CertifyKeyActivity.RESULT_OK, intent);
@ -384,7 +384,7 @@ public class CertifyKeyFragment extends LoaderFragment
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
SingletonResult result = new SingletonResult(SingletonResult.RESULT_OK,
LogLevel.OK, LogType.MSG_CRT_UPLOAD_SUCCESS);
LogType.MSG_CRT_UPLOAD_SUCCESS);
Intent intent = new Intent();
intent.putExtra(SingletonResult.EXTRA_RESULT, result);
mActivity.setResult(CertifyKeyActivity.RESULT_OK, intent);

View file

@ -22,6 +22,7 @@ import android.os.Bundle;
import android.view.View;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.service.results.OperationResult;
public class DecryptActivity extends DrawerActivity {
@ -50,8 +51,19 @@ public class DecryptActivity extends DrawerActivity {
public void onClick(View v) {
Intent clipboardDecrypt = new Intent(DecryptActivity.this, DecryptTextActivity.class);
clipboardDecrypt.setAction(DecryptTextActivity.ACTION_DECRYPT_FROM_CLIPBOARD);
startActivity(clipboardDecrypt);
startActivityForResult(clipboardDecrypt, 0);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// if a result has been returned, display a notify
if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) {
OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
result.createNotify(this).show();
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
}

View file

@ -23,7 +23,6 @@ import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.text.TextUtils;
@ -33,6 +32,7 @@ import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.TextView;
import org.openintents.openpgp.util.OpenPgpApi;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.util.FileHelper;
@ -40,7 +40,6 @@ import org.sufficientlysecure.keychain.service.results.DecryptVerifyResult;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.ui.util.Notify;
@ -48,7 +47,6 @@ import java.io.File;
public class DecryptFilesFragment extends DecryptFragment {
public static final String ARG_URI = "uri";
// public static final String ARG_FROM_VIEW_INTENT = "view_intent";
public static final String ARG_OPEN_DIRECTLY = "open_directly";
private static final int REQUEST_CODE_INPUT = 0x00007003;
@ -71,7 +69,6 @@ public class DecryptFilesFragment extends DecryptFragment {
Bundle args = new Bundle();
args.putParcelable(ARG_URI, uri);
// args.putBoolean(ARG_FROM_VIEW_INTENT, fromViewIntent);
args.putBoolean(ARG_OPEN_DIRECTLY, openDirectly);
frag.setArguments(args);
@ -143,7 +140,7 @@ public class DecryptFilesFragment extends DecryptFragment {
}
// askForOutputFilename();
decryptOriginalFilename(null);
decryptOriginalFilename();
}
private String removeEncryptedAppend(String name) {
@ -171,7 +168,7 @@ public class DecryptFilesFragment extends DecryptFragment {
}
}
private void decryptOriginalFilename(String passphrase) {
private void decryptOriginalFilename() {
Log.d(Constants.TAG, "decryptOriginalFilename");
Intent intent = new Intent(getActivity(), KeychainIntentService.class);
@ -184,12 +181,13 @@ public class DecryptFilesFragment extends DecryptFragment {
Log.d(Constants.TAG, "mInputUri=" + mInputUri + ", mOutputUri=" + mOutputUri);
data.putInt(KeychainIntentService.SOURCE, KeychainIntentService.IO_URI);
data.putParcelable(KeychainIntentService.ENCRYPT_INPUT_URI, mInputUri);
data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_INPUT_URI, mInputUri);
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_URI);
data.putParcelable(KeychainIntentService.ENCRYPT_OUTPUT_URI, mOutputUri);
data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_OUTPUT_URI, mOutputUri);
data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, passphrase);
data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase);
data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey);
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
@ -210,13 +208,13 @@ public class DecryptFilesFragment extends DecryptFragment {
if (pgpResult.isPending()) {
if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) ==
DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) {
showPassphraseDialog(pgpResult.getKeyIdPassphraseNeeded());
startPassphraseDialog(pgpResult.getKeyIdPassphraseNeeded());
} else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) ==
DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) {
showPassphraseDialog(Constants.key.symmetric);
startPassphraseDialog(Constants.key.symmetric);
} else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_NFC) ==
DecryptVerifyResult.RESULT_PENDING_NFC) {
// TODO
startNfcDecrypt(pgpResult.getNfcPassphrase(), pgpResult.getNfcEncryptedSessionKey());
} else {
throw new RuntimeException("Unhandled pending result!");
}
@ -241,23 +239,8 @@ public class DecryptFilesFragment extends DecryptFragment {
getActivity().startService(intent);
}
protected void showPassphraseDialogForFilename(long keyId) {
PassphraseDialogFragment.show(getActivity(), keyId,
new Handler() {
@Override
public void handleMessage(Message message) {
if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
String passphrase =
message.getData().getString(PassphraseDialogFragment.MESSAGE_DATA_PASSPHRASE);
decryptOriginalFilename(passphrase);
}
}
}
);
}
@Override
protected void decryptStart(String passphrase) {
protected void decryptStart() {
Log.d(Constants.TAG, "decryptStart");
// Send all information needed to service to decrypt in other thread
@ -272,12 +255,13 @@ public class DecryptFilesFragment extends DecryptFragment {
Log.d(Constants.TAG, "mInputUri=" + mInputUri + ", mOutputUri=" + mOutputUri);
data.putInt(KeychainIntentService.SOURCE, KeychainIntentService.IO_URI);
data.putParcelable(KeychainIntentService.ENCRYPT_INPUT_URI, mInputUri);
data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_INPUT_URI, mInputUri);
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_URI);
data.putParcelable(KeychainIntentService.ENCRYPT_OUTPUT_URI, mOutputUri);
data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_OUTPUT_URI, mOutputUri);
data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, passphrase);
data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase);
data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey);
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
@ -298,13 +282,13 @@ public class DecryptFilesFragment extends DecryptFragment {
if (pgpResult.isPending()) {
if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) ==
DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) {
showPassphraseDialog(pgpResult.getKeyIdPassphraseNeeded());
startPassphraseDialog(pgpResult.getKeyIdPassphraseNeeded());
} else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) ==
DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) {
showPassphraseDialog(Constants.key.symmetric);
startPassphraseDialog(Constants.key.symmetric);
} else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_NFC) ==
DecryptVerifyResult.RESULT_PENDING_NFC) {
// TODO
startNfcDecrypt(pgpResult.getNfcPassphrase(), pgpResult.getNfcEncryptedSessionKey());
} else {
throw new RuntimeException("Unhandled pending result!");
}
@ -350,25 +334,40 @@ public class DecryptFilesFragment extends DecryptFragment {
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CODE_PASSPHRASE: {
if (resultCode == Activity.RESULT_OK && data != null) {
mPassphrase = data.getStringExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE);
decryptOriginalFilename();
}
return;
}
case REQUEST_CODE_NFC_DECRYPT: {
if (resultCode == Activity.RESULT_OK && data != null) {
mNfcDecryptedSessionKey = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_DECRYPTED_SESSION_KEY);
decryptOriginalFilename();
}
return;
}
case REQUEST_CODE_INPUT: {
if (resultCode == Activity.RESULT_OK && data != null) {
setInputUri(data.getData());
}
return;
}
case REQUEST_CODE_OUTPUT: {
// This happens after output file was selected, so start our operation
if (resultCode == Activity.RESULT_OK && data != null) {
mOutputUri = data.getData();
decryptStart(null);
decryptStart();
}
return;
}
default: {
super.onActivityResult(requestCode, resultCode, data);
break;
}
}
}

View file

@ -17,11 +17,8 @@
package org.sufficientlysecure.keychain.ui;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.Fragment;
import android.view.View;
import android.view.View.OnClickListener;
@ -33,14 +30,17 @@ import android.widget.TextView;
import org.openintents.openpgp.OpenPgpSignatureResult;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.nfc.NfcActivity;
import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.service.results.DecryptVerifyResult;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
public abstract class DecryptFragment extends Fragment {
private static final int RESULT_CODE_LOOKUP_KEY = 0x00007006;
public static final int REQUEST_CODE_PASSPHRASE = 0x00008001;
public static final int REQUEST_CODE_NFC_DECRYPT = 0x00008002;
protected long mSignatureKeyId = 0;
protected LinearLayout mResultLayout;
@ -53,6 +53,9 @@ public abstract class DecryptFragment extends Fragment {
protected Button mLookupKey;
// State
protected String mPassphrase;
protected byte[] mNfcDecryptedSessionKey;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
@ -81,23 +84,23 @@ public abstract class DecryptFragment extends Fragment {
startActivityForResult(intent, RESULT_CODE_LOOKUP_KEY);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
protected void startPassphraseDialog(long subkeyId) {
Intent intent = new Intent(getActivity(), PassphraseDialogActivity.class);
intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, subkeyId);
startActivityForResult(intent, REQUEST_CODE_PASSPHRASE);
}
case RESULT_CODE_LOOKUP_KEY: {
if (resultCode == Activity.RESULT_OK) {
// TODO: generate new OpenPgpSignatureResult and display it
}
return;
}
protected void startNfcDecrypt(String pin, byte[] encryptedSessionKey) {
// build PendingIntent for Yubikey NFC operations
Intent intent = new Intent(getActivity(), NfcActivity.class);
intent.setAction(NfcActivity.ACTION_DECRYPT_SESSION_KEY);
intent.putExtra(NfcActivity.EXTRA_DATA, new Intent()); // not used, only relevant to OpenPgpService
intent.putExtra(NfcActivity.EXTRA_PIN, pin);
default: {
super.onActivityResult(requestCode, resultCode, data);
intent.putExtra(NfcActivity.EXTRA_NFC_ENC_SESSION_KEY, encryptedSessionKey);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
break;
}
}
startActivityForResult(intent, REQUEST_CODE_NFC_DECRYPT);
}
protected void onResult(DecryptVerifyResult decryptVerifyResult) {
@ -197,26 +200,9 @@ public abstract class DecryptFragment extends Fragment {
}
}
protected void showPassphraseDialog(long keyId) {
PassphraseDialogFragment.show(getActivity(), keyId,
new Handler() {
@Override
public void handleMessage(Message message) {
if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
String passphrase =
message.getData().getString(PassphraseDialogFragment.MESSAGE_DATA_PASSPHRASE);
decryptStart(passphrase);
}
}
}
);
}
/**
* Should be overridden by MessageFragment and FileFragment to start actual decryption
*
* @param passphrase
*/
protected abstract void decryptStart(String passphrase);
protected abstract void decryptStart();
}

View file

@ -27,6 +27,8 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.api.OpenKeychainIntents;
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.service.results.OperationResult;
import org.sufficientlysecure.keychain.service.results.SingletonResult;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.ui.util.Notify;
@ -53,6 +55,48 @@ public class DecryptTextActivity extends ActionBarActivity {
handleActions(savedInstanceState, getIntent());
}
/**
* Fix the message a bit, trailing spaces and newlines break stuff,
* because GMail sends as HTML and such things break ASCII Armor
* TODO: things like "<" and ">" also make problems
* <p/>
* NOTE: Do not use on cleartext signatures, only on ASCII-armored ciphertext,
* it would change the signed message
*/
private String fixAsciiArmoredCiphertext(String message) {
message = message.replaceAll(" +\n", "\n");
message = message.replaceAll("\n\n+", "\n\n");
message = message.replaceFirst("^\n+", "");
// make sure there'll be exactly one newline at the end
message = message.replaceFirst("\n*$", "\n");
// replace non breakable spaces
message = message.replaceAll("\\xa0", " ");
return message;
}
private String getPgpContent(String input) {
// only decrypt if clipboard content is available and a pgp message or cleartext signature
if (input != null) {
Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(input);
if (matcher.matches()) {
String message = matcher.group(1);
message = fixAsciiArmoredCiphertext(message);
return message;
} else {
matcher = PgpHelper.PGP_CLEARTEXT_SIGNATURE.matcher(input);
if (matcher.matches()) {
// return cleartext signature
return matcher.group(1);
} else {
return null;
}
}
} else {
return null;
}
}
/**
* Handles all actions with this intent
*
@ -67,73 +111,58 @@ public class DecryptTextActivity extends ActionBarActivity {
extras = new Bundle();
}
String textData = null;
/*
* Android's Action
*/
if (Intent.ACTION_SEND.equals(action) && type != null) {
// Android action
// When sending to Keychain Decrypt via share menu
if ("text/plain".equals(type)) {
// Plain text
String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
sharedText = getPgpContent(sharedText);
if (sharedText != null) {
// handle like normal text decryption, override action and extras to later
// executeServiceMethod ACTION_DECRYPT_TEXT in main actions
textData = sharedText;
loadFragment(savedInstanceState, sharedText);
} else {
Notify.showNotify(this, R.string.error_invalid_data, Notify.Style.ERROR);
}
}
}
/**
* Main Actions
*/
textData = extras.getString(EXTRA_TEXT);
if (ACTION_DECRYPT_TEXT.equals(action) && textData != null) {
Log.d(Constants.TAG, "textData not null, matching text ...");
Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(textData);
if (matcher.matches()) {
Log.d(Constants.TAG, "PGP_MESSAGE matched");
textData = matcher.group(1);
// replace non breakable spaces
textData = textData.replaceAll("\\xa0", " ");
} else {
matcher = PgpHelper.PGP_CLEARTEXT_SIGNATURE.matcher(textData);
if (matcher.matches()) {
Log.d(Constants.TAG, "PGP_CLEARTEXT_SIGNATURE matched");
textData = matcher.group(1);
// replace non breakable spaces
textData = textData.replaceAll("\\xa0", " ");
} else {
Notify.showNotify(this, R.string.error_invalid_data, Notify.Style.ERROR);
Log.d(Constants.TAG, "Nothing matched!");
}
Log.e(Constants.TAG, "ACTION_SEND received non-plaintext, this should not happen in this activity!");
}
} else if (ACTION_DECRYPT_FROM_CLIPBOARD.equals(action)) {
CharSequence clipboardText = ClipboardReflection.getClipboardText(this);
} else if (ACTION_DECRYPT_TEXT.equals(action)) {
Log.d(Constants.TAG, "ACTION_DECRYPT_TEXT textData not null, matching text...");
// only decrypt if clipboard content is available and a pgp message or cleartext signature
if (clipboardText != null) {
Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(clipboardText);
if (!matcher.matches()) {
matcher = PgpHelper.PGP_CLEARTEXT_SIGNATURE.matcher(clipboardText);
}
if (matcher.matches()) {
textData = matcher.group(1);
} else {
Notify.showNotify(this, R.string.error_invalid_data, Notify.Style.ERROR);
}
String extraText = extras.getString(EXTRA_TEXT);
extraText = getPgpContent(extraText);
if (extraText != null) {
loadFragment(savedInstanceState, extraText);
} else {
Notify.showNotify(this, R.string.error_invalid_data, Notify.Style.ERROR);
}
} else if (ACTION_DECRYPT_TEXT.equals(action)) {
Log.e(Constants.TAG,
"Include the extra 'text' in your Intent!");
}
} else if (ACTION_DECRYPT_FROM_CLIPBOARD.equals(action)) {
Log.d(Constants.TAG, "ACTION_DECRYPT_FROM_CLIPBOARD");
loadFragment(savedInstanceState, textData);
String clipboardText = ClipboardReflection.getClipboardText(this).toString();
clipboardText = getPgpContent(clipboardText);
if (clipboardText != null) {
loadFragment(savedInstanceState, clipboardText);
} else {
returnInvalidResult();
}
} else if (ACTION_DECRYPT_TEXT.equals(action)) {
Log.e(Constants.TAG, "Include the extra 'text' in your Intent!");
finish();
}
}
private void returnInvalidResult() {
SingletonResult result = new SingletonResult(
SingletonResult.RESULT_ERROR, OperationResult.LogType.MSG_NO_VALID_ENC);
Intent intent = new Intent();
intent.putExtra(SingletonResult.EXTRA_RESULT, result);
setResult(RESULT_OK, intent);
finish();
}
private void loadFragment(Bundle savedInstanceState, String ciphertext) {
// However, if we're being restored from a previous state,

View file

@ -17,6 +17,7 @@
package org.sufficientlysecure.keychain.ui;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
@ -27,22 +28,26 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.openintents.openpgp.util.OpenPgpApi;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.service.results.DecryptVerifyResult;
import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ShareHelper;
public class DecryptTextFragment extends DecryptFragment {
public static final String ARG_CIPHERTEXT = "ciphertext";
// // view
private TextView mMessage;
// private View mDecryptButton;
// private View mDecryptFromCLipboardButton;
//
// // model
// view
private TextView mText;
private View mShareButton;
private View mCopyButton;
// model
private String mCiphertext;
/**
@ -66,25 +71,53 @@ public class DecryptTextFragment extends DecryptFragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.decrypt_text_fragment, container, false);
mMessage = (TextView) view.findViewById(R.id.decrypt_text_plaintext);
// mDecryptButton = view.findViewById(R.id.action_decrypt);
// mDecryptFromCLipboardButton = view.findViewById(R.id.action_decrypt_from_clipboard);
// mDecryptButton.setOnClickListener(new OnClickListener() {
// @Override
// public void onClick(View v) {
// decryptClicked();
// }
// });
// mDecryptFromCLipboardButton.setOnClickListener(new OnClickListener() {
// @Override
// public void onClick(View v) {
// decryptFromClipboardClicked();
// }
// });
mText = (TextView) view.findViewById(R.id.decrypt_text_plaintext);
mShareButton = view.findViewById(R.id.action_decrypt_share_plaintext);
mCopyButton = view.findViewById(R.id.action_decrypt_copy_plaintext);
mShareButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(sendWithChooserExcludingEncrypt(mText.getText().toString()));
}
});
mCopyButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
copyToClipboard(mText.getText().toString());
}
});
return view;
}
/**
* Create Intent Chooser but exclude decrypt activites
*/
private Intent sendWithChooserExcludingEncrypt(String text) {
Intent prototype = createSendIntent(text);
String title = getString(R.string.title_share_file);
// we don't want to decrypt the decypted, no inception ;)
String[] blacklist = new String[]{
Constants.PACKAGE_NAME + ".ui.DecryptTextActivity",
"org.thialfihar.android.apg.ui.DecryptActivity"
};
return new ShareHelper(getActivity()).createChooserExcluding(prototype, title, blacklist);
}
private Intent createSendIntent(String text) {
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, text);
sendIntent.setType("text/plain");
return sendIntent;
}
private void copyToClipboard(String text) {
ClipboardReflection.copyToClipboard(getActivity(), text);
Notify.showNotify(getActivity(), R.string.text_copied_to_clipboard, Notify.Style.INFO);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -92,12 +125,12 @@ public class DecryptTextFragment extends DecryptFragment {
String ciphertext = getArguments().getString(ARG_CIPHERTEXT);
if (ciphertext != null) {
mCiphertext = ciphertext;
decryptStart(null);
decryptStart();
}
}
@Override
protected void decryptStart(String passphrase) {
protected void decryptStart() {
Log.d(Constants.TAG, "decryptStart");
// Send all information needed to service to decrypt in other thread
@ -111,7 +144,8 @@ public class DecryptTextFragment extends DecryptFragment {
// data
data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_BYTES);
data.putByteArray(KeychainIntentService.DECRYPT_CIPHERTEXT_BYTES, mCiphertext.getBytes());
data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, passphrase);
data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase);
data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey);
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
@ -132,13 +166,13 @@ public class DecryptTextFragment extends DecryptFragment {
if (pgpResult.isPending()) {
if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) ==
DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) {
showPassphraseDialog(pgpResult.getKeyIdPassphraseNeeded());
startPassphraseDialog(pgpResult.getKeyIdPassphraseNeeded());
} else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) ==
DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) {
showPassphraseDialog(Constants.key.symmetric);
startPassphraseDialog(Constants.key.symmetric);
} else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_NFC) ==
DecryptVerifyResult.RESULT_PENDING_NFC) {
// TODO
startNfcDecrypt(pgpResult.getNfcPassphrase(), pgpResult.getNfcEncryptedSessionKey());
} else {
throw new RuntimeException("Unhandled pending result!");
}
@ -146,8 +180,8 @@ public class DecryptTextFragment extends DecryptFragment {
byte[] decryptedMessage = returnData
.getByteArray(KeychainIntentService.RESULT_DECRYPTED_BYTES);
mMessage.setText(new String(decryptedMessage));
mMessage.setHorizontallyScrolling(false);
mText.setText(new String(decryptedMessage));
mText.setHorizontallyScrolling(false);
pgpResult.createNotify(getActivity()).show();
@ -171,4 +205,34 @@ public class DecryptTextFragment extends DecryptFragment {
getActivity().startService(intent);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CODE_PASSPHRASE: {
if (resultCode == Activity.RESULT_OK && data != null) {
mPassphrase = data.getStringExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE);
decryptStart();
} else {
getActivity().finish();
}
return;
}
case REQUEST_CODE_NFC_DECRYPT: {
if (resultCode == Activity.RESULT_OK && data != null) {
mNfcDecryptedSessionKey = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_DECRYPTED_SESSION_KEY);
decryptStart();
} else {
getActivity().finish();
}
return;
}
default: {
super.onActivityResult(requestCode, resultCode, data);
}
}
}
}

View file

@ -654,7 +654,7 @@ public class EditKeyFragment extends LoaderFragment implements
// Prepare an intent with an EXTRA_RESULT
Intent intent = new Intent();
intent.putExtra(OperationResult.EXTRA_RESULT,
new SingletonResult(SingletonResult.RESULT_ERROR, LogLevel.ERROR, reason));
new SingletonResult(SingletonResult.RESULT_ERROR, reason));
// Finish with result
getActivity().setResult(EditKeyActivity.RESULT_OK, intent);

View file

@ -12,27 +12,18 @@ public class EncryptActivity extends DrawerActivity {
public static final int REQUEST_CODE_NFC = 0x00008002;
protected void startPassphraseDialog(long subkeyId) {
Intent data = new Intent();
// build PendingIntent for Yubikey NFC operations
Intent intent = new Intent(this, PassphraseDialogActivity.class);
// pass params through to activity that it can be returned again later to repeat pgp operation
intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, subkeyId);
// intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivityForResult(intent, REQUEST_CODE_PASSPHRASE);
}
protected void startNfcSign(String pin, byte[] hashToSign, int hashAlgo) {
Intent data = new Intent();
// build PendingIntent for Yubikey NFC operations
Intent intent = new Intent(this, NfcActivity.class);
intent.setAction(NfcActivity.ACTION_SIGN_HASH);
// pass params through to activity that it can be returned again later to repeat pgp operation
intent.putExtra(NfcActivity.EXTRA_DATA, data);
intent.putExtra(NfcActivity.EXTRA_DATA, new Intent()); // not used, only relevant to OpenPgpService
intent.putExtra(NfcActivity.EXTRA_PIN, pin);
intent.putExtra(NfcActivity.EXTRA_NFC_HASH_TO_SIGN, hashToSign);
intent.putExtra(NfcActivity.EXTRA_NFC_HASH_ALGO, hashAlgo);

View file

@ -135,7 +135,7 @@ public class EncryptAsymmetricFragment extends Fragment implements EncryptActivi
try {
CachedPublicKeyRing keyring = mProviderHelper.getCachedPublicKeyRing(
KeyRings.buildUnifiedKeyRingUri(signatureKey));
if(keyring.hasAnySecret()) {
if (keyring.hasAnySecret()) {
setSignatureKeyId(keyring.getMasterKeyId());
mSign.setSelectedKeyId(mEncryptInterface.getSignatureKey());
}

View file

@ -191,8 +191,6 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi
super.handleMessage(message);
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
Notify.showNotify(EncryptFilesActivity.this, R.string.encrypt_sign_successful, Notify.Style.INFO);
SignEncryptResult pgpResult =
message.getData().getParcelable(SignEncryptResult.EXTRA_RESULT);
@ -224,8 +222,7 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi
startActivity(sendWithChooserExcludingEncrypt(message));
} else {
// Save encrypted file
Notify.showNotify(EncryptFilesActivity.this,
R.string.encrypt_sign_clipboard_successful, Notify.Style.INFO);
pgpResult.createNotify(EncryptFilesActivity.this).show();
}
} else {
pgpResult.createNotify(EncryptFilesActivity.this).show();

View file

@ -21,7 +21,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Files" />
android:text="@string/section_decrypt_files" />
<TextView
@ -34,7 +34,7 @@
android:minHeight="?android:attr/listPreferredItemHeight"
android:clickable="true"
style="@style/SelectableItem"
android:text="Decrypt files"
android:text="@string/btn_decrypt_files"
android:drawableRight="@drawable/ic_action_collection"
android:drawablePadding="8dp"
android:gravity="center_vertical" />
@ -50,22 +50,51 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:text="Text" />
android:text="@string/section_decrypt_text" />
<TextView
<LinearLayout
android:id="@+id/decrypt_from_clipboard"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:layout_height="?android:attr/listPreferredItemHeight"
android:clickable="true"
android:paddingRight="4dp"
style="@style/SelectableItem"
android:text="Decrypt from clipboard"
android:drawableRight="@drawable/ic_action_paste"
android:drawablePadding="8dp"
android:gravity="center_vertical" />
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:paddingRight="4dp"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView
android:paddingLeft="8dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/btn_decrypt_clipboard" />
<TextView
android:paddingLeft="8dp"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/tertiary_text_light"
android:text="@string/btn_decrypt_and_verify"
android:gravity="center_vertical" />
</LinearLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:padding="8dp"
android:src="@drawable/ic_action_paste"
android:layout_gravity="center_vertical" />
</LinearLayout>
<View
android:layout_width="match_parent"
@ -75,4 +104,5 @@
</LinearLayout>
</LinearLayout>

View file

@ -43,7 +43,7 @@
<LinearLayout
android:id="@+id/action_encrypt_share_plaintext"
android:id="@+id/action_decrypt_share_plaintext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
@ -57,7 +57,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:text="Share plaintext"
android:text="@string/btn_add_share_decrypted_text"
android:drawableRight="@drawable/ic_action_share"
android:drawablePadding="8dp"
android:gravity="center_vertical"
@ -72,7 +72,7 @@
android:background="?android:attr/listDivider" />
<ImageButton
android:id="@+id/action_copy_plaintext"
android:id="@+id/action_decrypt_copy_plaintext"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:padding="8dp"

View file

@ -51,6 +51,8 @@
<string name="section_key_server">"Keyserver"</string>
<string name="section_fingerprint">"Fingerprint"</string>
<string name="section_key_to_certify">"Key to be certified"</string>
<string name="section_decrypt_files">"Files"</string>
<string name="section_decrypt_text">"Text"</string>
<!-- button -->
<string name="btn_decrypt_verify_file">"Decrypt, verify, and save file"</string>
@ -70,6 +72,10 @@
<string name="btn_view_cert_key">"View certification key"</string>
<string name="btn_create_key">"Create key"</string>
<string name="btn_add_files">"Add file(s)"</string>
<string name="btn_add_share_decrypted_text">"Share decrypted text"</string>
<string name="btn_decrypt_clipboard">"Decrypt from clipboard"</string>
<string name="btn_decrypt_and_verify">"and verify signatures"</string>
<string name="btn_decrypt_files">"Decrypt files"</string>
<!-- menu -->
<string name="menu_preferences">"Settings"</string>
@ -225,6 +231,7 @@
<string name="fingerprint_copied_to_clipboard">"Fingerprint has been copied to the clipboard!"</string>
<string name="select_key_to_certify">"Please select a key to be used for certification!"</string>
<string name="key_too_big_for_sharing">"Key is too big to be shared this way!"</string>
<string name="text_copied_to_clipboard">"Text has been copied to the clipboard!"</string>
<!--
errors
@ -241,7 +248,7 @@
<string name="error_key_needs_a_user_id">"need at least one identity"</string>
<string name="error_no_signature_passphrase">"no passphrase given"</string>
<string name="error_no_signature_key">"no signature key given"</string>
<string name="error_invalid_data">"not valid encryption data"</string>
<string name="error_invalid_data">"No valid encrypted or signed OpenPGP content!"</string>
<string name="error_integrity_check_failed">"integrity check failed! Data has been modified!"</string>
<string name="error_wrong_passphrase">"wrong passphrase"</string>
<string name="error_could_not_extract_private_key">"could not extract private key"</string>
@ -424,6 +431,7 @@
<string name="api_settings_select_key">"Select key"</string>
<string name="api_settings_create_key">"Create new key for this account"</string>
<string name="api_settings_save">"Save"</string>
<string name="api_settings_save_msg">"Account has been saved"</string>
<string name="api_settings_cancel">"Cancel"</string>
<string name="api_settings_revoke">"Revoke access"</string>
<string name="api_settings_start">"Start application"</string>