diff options
author | Dominik Schürmann <dominik@dominikschuermann.de> | 2014-09-15 10:19:55 +0200 |
---|---|---|
committer | Dominik Schürmann <dominik@dominikschuermann.de> | 2014-09-15 10:19:55 +0200 |
commit | 53bc417f8f77a9f92786457281d02431ef614ca7 (patch) | |
tree | f3b09c51520a6d7b4483cd3ca17136dc94e91251 /OpenKeychain/src/main/java/org/sufficientlysecure/keychain | |
parent | 88bbce831c30c1220e03439ffca4c8f390506ba6 (diff) | |
download | open-keychain-53bc417f8f77a9f92786457281d02431ef614ca7.tar.gz open-keychain-53bc417f8f77a9f92786457281d02431ef614ca7.tar.bz2 open-keychain-53bc417f8f77a9f92786457281d02431ef614ca7.zip |
New decrypt activity design (WIP), saner UTF8 decoding (replacing non-decodable characters)
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain')
9 files changed, 366 insertions, 139 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java index d64c3ea55..04f2c3dfb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -42,6 +42,7 @@ import org.sufficientlysecure.keychain.service.results.OperationResultParcel.Log import org.sufficientlysecure.keychain.service.results.OperationResultParcel.OperationLog; import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Utf8Util; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -365,7 +366,7 @@ public class UncachedKeyRing { ArrayList<byte[]> processedUserIds = new ArrayList<byte[]>(); for (byte[] rawUserId : new IterableIterator<byte[]>(masterKey.getRawUserIDs())) { - String userId = Strings.fromUTF8ByteArray(rawUserId); + String userId = Utf8Util.fromUTF8ByteArrayReplaceBadEncoding(rawUserId); // check for duplicate user ids if (processedUserIds.contains(rawUserId)) { @@ -439,7 +440,7 @@ public class UncachedKeyRing { continue; } // warn user if the signature was made with bad encoding - if (!cert.verifySignature(masterKey, userId)) { + if (!Utf8Util.isValidUTF8(rawUserId)) { log.add(LogLevel.WARN, LogType.MSG_KC_UID_WARN_ENCODING, indent); } } catch (PgpGeneralException e) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java index e27190bc7..7f08d121e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java @@ -32,6 +32,7 @@ import org.spongycastle.util.Strings; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Utf8Util; import java.util.ArrayList; import java.util.Arrays; @@ -185,7 +186,7 @@ public class UncachedPublicKey { } } if (found != null) { - return Strings.fromUTF8ByteArray(found); + return Utf8Util.fromUTF8ByteArrayReplaceBadEncoding(found); } else { return null; } @@ -204,8 +205,9 @@ public class UncachedPublicKey { public ArrayList<String> getUnorderedUserIds() { ArrayList<String> userIds = new ArrayList<String>(); - for (String userId : new IterableIterator<String>(mPublicKey.getUserIDs())) { - userIds.add(userId); + for (byte[] rawUserId : new IterableIterator<byte[]>(mPublicKey.getRawUserIDs())) { + // use our decoding method + userIds.add(Utf8Util.fromUTF8ByteArrayReplaceBadEncoding(rawUserId)); } return userIds; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index 8e6a0dfa5..ed65b87bd 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -65,6 +65,7 @@ import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ProgressFixedScaler; import org.sufficientlysecure.keychain.util.ProgressScaler; +import org.sufficientlysecure.keychain.util.Utf8Util; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -437,8 +438,7 @@ public class ProviderHelper { List<UserIdItem> uids = new ArrayList<UserIdItem>(); for (byte[] rawUserId : new IterableIterator<byte[]>( masterKey.getUnorderedRawUserIds().iterator())) { - String userId = Strings.fromUTF8ByteArray(rawUserId); - Log.d(Constants.TAG, "userId: "+userId); + String userId = Utf8Util.fromUTF8ByteArrayReplaceBadEncoding(rawUserId); UserIdItem item = new UserIdItem(); uids.add(item); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java new file mode 100644 index 000000000..37382051b --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package org.sufficientlysecure.keychain.ui; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; + +import org.sufficientlysecure.keychain.R; + +public class DecryptActivity extends DrawerActivity { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.decrypt_activity); + + activateDrawerNavigation(savedInstanceState); + + View actionFile = findViewById(R.id.decrypt_files); + View actionFromClipboard = findViewById(R.id.decrypt_from_clipboard); + + actionFile.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent filesDecrypt = new Intent(DecryptActivity.this, DecryptFilesActivity.class); + filesDecrypt.setAction(DecryptFilesActivity.ACTION_DECRYPT_DATA_OPEN); + startActivity(filesDecrypt); + } + }); + + actionFromClipboard.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent clipboardDecrypt = new Intent(DecryptActivity.this, DecryptTextActivity.class); + clipboardDecrypt.setAction(DecryptTextActivity.ACTION_DECRYPT_FROM_CLIPBOARD); + startActivity(clipboardDecrypt); + } + }); + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesActivity.java new file mode 100644 index 000000000..9d972d8c0 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesActivity.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package org.sufficientlysecure.keychain.ui; + +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.support.v7.app.ActionBarActivity; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.api.OpenKeychainIntents; +import org.sufficientlysecure.keychain.util.Log; + +public class DecryptFilesActivity extends ActionBarActivity { + + /* Intents */ + public static final String ACTION_DECRYPT_DATA = OpenKeychainIntents.DECRYPT_DATA; + + // intern + public static final String ACTION_DECRYPT_DATA_OPEN = Constants.INTENT_PREFIX + "DECRYPT_DATA_OPEN"; + + DecryptFilesFragment mFragment; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.decrypt_files_activity); + + // Handle intent actions + handleActions(savedInstanceState, getIntent()); + } + + /** + * Handles all actions with this intent + * + * @param intent + */ + private void handleActions(Bundle savedInstanceState, Intent intent) { + String action = intent.getAction(); + String type = intent.getType(); + Uri uri = intent.getData(); + + Bundle mFileFragmentBundle = new Bundle(); + + /* + * Android's Action + */ + if (Intent.ACTION_SEND.equals(action) && type != null) { + // When sending to Keychain Decrypt via share menu + // Binary via content provider (could also be files) + // override uri to get stream from send + uri = intent.getParcelableExtra(Intent.EXTRA_STREAM); + action = ACTION_DECRYPT_DATA; + } else if (Intent.ACTION_VIEW.equals(action)) { + // Android's Action when opening file associated to Keychain (see AndroidManifest.xml) + + // override action + action = ACTION_DECRYPT_DATA; + } + + /** + * Main Actions + */ + if (ACTION_DECRYPT_DATA.equals(action) && uri != null) { + mFileFragmentBundle.putParcelable(DecryptFilesFragment.ARG_URI, uri); + + loadFragment(savedInstanceState, uri, false); + } else if (ACTION_DECRYPT_DATA_OPEN.equals(action)) { + loadFragment(savedInstanceState, null, true); + } else if (ACTION_DECRYPT_DATA.equals(action)) { + Log.e(Constants.TAG, + "Include an Uri with setData() in your Intent!"); + } + } + + private void loadFragment(Bundle savedInstanceState, Uri uri, boolean openDialog) { + // However, if we're being restored from a previous state, + // then we don't need to do anything and should return or else + // we could end up with overlapping fragments. + if (savedInstanceState != null) { + return; + } + + // Create an instance of the fragment + mFragment = DecryptFilesFragment.newInstance(uri, openDialog); + + // Add the fragment to the 'fragment_container' FrameLayout + // NOTE: We use commitAllowingStateLoss() to prevent weird crashes! + getSupportFragmentManager().beginTransaction() + .replace(R.id.decrypt_files_fragment_container, mFragment) + .commitAllowingStateLoss(); + // do it immediately! + getSupportFragmentManager().executePendingTransactions(); + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java index 7d9b2b9b3..ccfcfc2c5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java @@ -46,9 +46,10 @@ import org.sufficientlysecure.keychain.util.Notify; import java.io.File; -public class DecryptFileFragment extends DecryptFragment { +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_FROM_VIEW_INTENT = "view_intent"; + public static final String ARG_OPEN_DIRECTLY = "open_directly"; private static final int REQUEST_CODE_INPUT = 0x00007003; private static final int REQUEST_CODE_OUTPUT = 0x00007007; @@ -63,6 +64,22 @@ public class DecryptFileFragment extends DecryptFragment { private Uri mOutputUri = null; /** + * Creates new instance of this fragment + */ + public static DecryptFilesFragment newInstance(Uri uri, boolean openDirectly) { + DecryptFilesFragment frag = new DecryptFilesFragment(); + + 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); + + return frag; + } + + /** * Inflate the layout for this fragment */ @Override @@ -75,9 +92,9 @@ public class DecryptFileFragment extends DecryptFragment { view.findViewById(R.id.decrypt_file_browse).setOnClickListener(new View.OnClickListener() { public void onClick(View v) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - FileHelper.openDocument(DecryptFileFragment.this, "*/*", REQUEST_CODE_INPUT); + FileHelper.openDocument(DecryptFilesFragment.this, "*/*", REQUEST_CODE_INPUT); } else { - FileHelper.openFile(DecryptFileFragment.this, mInputUri, "*/*", + FileHelper.openFile(DecryptFilesFragment.this, mInputUri, "*/*", REQUEST_CODE_INPUT); } } @@ -97,6 +114,15 @@ public class DecryptFileFragment extends DecryptFragment { super.onActivityCreated(savedInstanceState); setInputUri(getArguments().<Uri>getParcelable(ARG_URI)); + + if (getArguments().getBoolean(ARG_OPEN_DIRECTLY, false)) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + FileHelper.openDocument(DecryptFilesFragment.this, "*/*", REQUEST_CODE_INPUT); + } else { + FileHelper.openFile(DecryptFilesFragment.this, mInputUri, "*/*", + REQUEST_CODE_INPUT); + } + } } private void setInputUri(Uri inputUri) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptOldActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java index f6dfed5d7..5d46b351b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptOldActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java @@ -19,83 +19,56 @@ package org.sufficientlysecure.keychain.ui; import android.content.Intent; -import android.net.Uri; import android.os.Bundle; -import android.support.v4.view.PagerTabStrip; -import android.support.v4.view.ViewPager; +import android.support.v7.app.ActionBarActivity; import org.sufficientlysecure.keychain.Constants; 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.ui.adapter.PagerTabStripAdapter; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Notify; import java.util.regex.Matcher; -public class DecryptOldActivity extends DrawerActivity { +public class DecryptTextActivity extends ActionBarActivity { /* Intents */ - public static final String ACTION_DECRYPT = OpenKeychainIntents.DECRYPT; - - /* EXTRA keys for input */ + public static final String ACTION_DECRYPT_TEXT = OpenKeychainIntents.DECRYPT_TEXT; public static final String EXTRA_TEXT = OpenKeychainIntents.DECRYPT_EXTRA_TEXT; - ViewPager mViewPager; - PagerTabStrip mPagerTabStrip; - PagerTabStripAdapter mTabsAdapter; - - Bundle mMessageFragmentBundle = new Bundle(); - Bundle mFileFragmentBundle = new Bundle(); - int mSwitchToTab = PAGER_TAB_MESSAGE; - - private static final int PAGER_TAB_MESSAGE = 0; - private static final int PAGER_TAB_FILE = 1; - - private void initView() { - mViewPager = (ViewPager) findViewById(R.id.decrypt_pager); - mPagerTabStrip = (PagerTabStrip) findViewById(R.id.decrypt_pager_tab_strip); + // intern + public static final String ACTION_DECRYPT_FROM_CLIPBOARD = Constants.INTENT_PREFIX + "DECRYPT_TEXT_FROM_CLIPBOARD"; - mTabsAdapter = new PagerTabStripAdapter(this); - mViewPager.setAdapter(mTabsAdapter); - } + DecryptTextFragment mFragment; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.decrypt_activity_old); - - initView(); - - activateDrawerNavigation(savedInstanceState); - - // Handle intent actions, maybe changes the bundles - handleActions(getIntent()); + setContentView(R.layout.decrypt_text_activity); - mTabsAdapter.addTab(DecryptMessageFragment.class, - mMessageFragmentBundle, getString(R.string.label_message)); - mTabsAdapter.addTab(DecryptFileFragment.class, - mFileFragmentBundle, getString(R.string.label_file)); - mViewPager.setCurrentItem(mSwitchToTab); + // Handle intent actions + handleActions(savedInstanceState, getIntent()); } - /** * Handles all actions with this intent * * @param intent */ - private void handleActions(Intent intent) { + private void handleActions(Bundle savedInstanceState, Intent intent) { String action = intent.getAction(); Bundle extras = intent.getExtras(); String type = intent.getType(); - Uri uri = intent.getData(); if (extras == null) { extras = new Bundle(); } + String textData = null; + /* * Android's Action */ @@ -106,30 +79,17 @@ public class DecryptOldActivity extends DrawerActivity { String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT); if (sharedText != null) { // handle like normal text decryption, override action and extras to later - // executeServiceMethod ACTION_DECRYPT in main actions - extras.putString(EXTRA_TEXT, sharedText); - action = ACTION_DECRYPT; + // executeServiceMethod ACTION_DECRYPT_TEXT in main actions + textData = sharedText; } - } else { - // Binary via content provider (could also be files) - // override uri to get stream from send - uri = intent.getParcelableExtra(Intent.EXTRA_STREAM); - action = ACTION_DECRYPT; } - } else if (Intent.ACTION_VIEW.equals(action)) { - // Android's Action when opening file associated to Keychain (see AndroidManifest.xml) - - // override action - action = ACTION_DECRYPT; - mFileFragmentBundle.putBoolean(DecryptFileFragment.ARG_FROM_VIEW_INTENT, true); } - String textData = extras.getString(EXTRA_TEXT); - /** * Main Actions */ - if (ACTION_DECRYPT.equals(action) && textData != null) { + 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()) { @@ -137,9 +97,6 @@ public class DecryptOldActivity extends DrawerActivity { textData = matcher.group(1); // replace non breakable spaces textData = textData.replaceAll("\\xa0", " "); - - mMessageFragmentBundle.putString(DecryptMessageFragment.ARG_CIPHERTEXT, textData); - mSwitchToTab = PAGER_TAB_MESSAGE; } else { matcher = PgpHelper.PGP_CLEARTEXT_SIGNATURE.matcher(textData); if (matcher.matches()) { @@ -147,20 +104,55 @@ public class DecryptOldActivity extends DrawerActivity { textData = matcher.group(1); // replace non breakable spaces textData = textData.replaceAll("\\xa0", " "); - - mMessageFragmentBundle.putString(DecryptMessageFragment.ARG_CIPHERTEXT, textData); - mSwitchToTab = PAGER_TAB_MESSAGE; } else { + Notify.showNotify(this, R.string.error_invalid_data, Notify.Style.ERROR); Log.d(Constants.TAG, "Nothing matched!"); } } - } else if (ACTION_DECRYPT.equals(action) && uri != null) { - mFileFragmentBundle.putParcelable(DecryptFileFragment.ARG_URI, uri); - mSwitchToTab = PAGER_TAB_FILE; - } else if (ACTION_DECRYPT.equals(action)) { + } else if (ACTION_DECRYPT_FROM_CLIPBOARD.equals(action)) { + CharSequence clipboardText = ClipboardReflection.getClipboardText(this); + + // 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); + } + } 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' or an Uri with setData() in your Intent!"); + "Include the extra 'text' in your Intent!"); } + + loadFragment(savedInstanceState, textData); + } + + + private void loadFragment(Bundle savedInstanceState, String ciphertext) { + // However, if we're being restored from a previous state, + // then we don't need to do anything and should return or else + // we could end up with overlapping fragments. + if (savedInstanceState != null) { + return; + } + + // Create an instance of the fragment + mFragment = DecryptTextFragment.newInstance(ciphertext); + + // Add the fragment to the 'fragment_container' FrameLayout + // NOTE: We use commitAllowingStateLoss() to prevent weird crashes! + getSupportFragmentManager().beginTransaction() + .replace(R.id.decrypt_text_fragment_container, mFragment) + .commitAllowingStateLoss(); + // do it immediately! + getSupportFragmentManager().executePendingTransactions(); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptMessageFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java index a7a630be1..13dab6673 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptMessageFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java @@ -24,62 +24,70 @@ import android.os.Message; import android.os.Messenger; import android.view.LayoutInflater; import android.view.View; -import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.widget.EditText; +import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; -import org.sufficientlysecure.keychain.service.results.DecryptVerifyResult; -import org.sufficientlysecure.keychain.pgp.PgpHelper; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.service.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.Notify; - -import java.util.regex.Matcher; -public class DecryptMessageFragment extends DecryptFragment { +public class DecryptTextFragment extends DecryptFragment { public static final String ARG_CIPHERTEXT = "ciphertext"; - // view - private EditText mMessage; - private View mDecryptButton; - private View mDecryptFromCLipboardButton; - - // model +// // view + private TextView mMessage; +// private View mDecryptButton; +// private View mDecryptFromCLipboardButton; +// +// // model private String mCiphertext; /** + * Creates new instance of this fragment + */ + public static DecryptTextFragment newInstance(String ciphertext) { + DecryptTextFragment frag = new DecryptTextFragment(); + + Bundle args = new Bundle(); + args.putString(ARG_CIPHERTEXT, ciphertext); + + frag.setArguments(args); + + return frag; + } + + /** * Inflate the layout for this fragment */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.decrypt_message_fragment, container, false); - - mMessage = (EditText) view.findViewById(R.id.message); - 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(); - } - }); + 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(); +// } +// }); return view; } @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); String ciphertext = getArguments().getString(ARG_CIPHERTEXT); if (ciphertext != null) { @@ -88,31 +96,6 @@ public class DecryptMessageFragment extends DecryptFragment { } } - private void decryptClicked() { - mCiphertext = mMessage.getText().toString(); - decryptStart(null); - } - - private void decryptFromClipboardClicked() { - CharSequence clipboardText = ClipboardReflection.getClipboardText(getActivity()); - - // 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()) { - mCiphertext = matcher.group(1); - decryptStart(null); - } else { - Notify.showNotify(getActivity(), R.string.error_invalid_data, Notify.Style.ERROR); - } - } else { - Notify.showNotify(getActivity(), R.string.error_invalid_data, Notify.Style.ERROR); - } - } - @Override protected void decryptStart(String passphrase) { Log.d(Constants.TAG, "decryptStart"); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Utf8Util.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Utf8Util.java new file mode 100644 index 000000000..bed3e28ed --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Utf8Util.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package org.sufficientlysecure.keychain.util; + +import org.sufficientlysecure.keychain.Constants; + +import java.nio.ByteBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CodingErrorAction; + +public class Utf8Util { + + public static boolean isValidUTF8(byte[] input) { + CharsetDecoder cs = Charset.forName("UTF-8").newDecoder(); + + try { + cs.decode(ByteBuffer.wrap(input)); + return true; + } catch (CharacterCodingException e) { + return false; + } + } + + public static String fromUTF8ByteArrayReplaceBadEncoding(byte[] input) { + final CharsetDecoder charsetDecoder = Charset.forName("UTF-8").newDecoder(); + charsetDecoder.onMalformedInput(CodingErrorAction.REPLACE); + charsetDecoder.onUnmappableCharacter(CodingErrorAction.REPLACE); + + try { + return charsetDecoder.decode(ByteBuffer.wrap(input)).toString(); + } catch (CharacterCodingException e) { + Log.e(Constants.TAG, "Decoding failed!", e); + return charsetDecoder.replacement(); + } + } +} |