show Snackbar if clipboard contains key data

This commit is contained in:
Vincent Breitmoser
2018-06-14 16:26:40 +02:00
committed by Dominik Schürmann
parent 700e06dcb9
commit 89aa99a13f
6 changed files with 115 additions and 24 deletions

View File

@@ -34,6 +34,9 @@ public class ClipboardReflection {
return null; return null;
} }
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
if (clipboard == null) {
return null;
}
ClipData clip = clipboard.getPrimaryClip(); ClipData clip = clipboard.getPrimaryClip();
if (clip == null || clip.getItemCount() == 0) { if (clip == null || clip.getItemCount() == 0) {
@@ -48,4 +51,16 @@ public class ClipboardReflection {
} }
return null; return null;
} }
public static void clearClipboard(@Nullable Context context) {
if (context == null) {
return;
}
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
if (clipboard == null) {
return;
}
clipboard.setPrimaryClip(ClipData.newPlainText("", ""));
}
} }

View File

@@ -84,22 +84,16 @@ public class PgpHelper {
} }
public static String getPgpMessageContent(@NonNull CharSequence input) { public static String getPgpMessageContent(@NonNull CharSequence input) {
Timber.d("input: %s");
Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(input); Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(input);
if (matcher.matches()) { if (matcher.matches()) {
String text = matcher.group(1); String text = matcher.group(1);
text = fixPgpMessage(text); text = fixPgpMessage(text);
Timber.d("input fixed: %s", text);
return text; return text;
} else { } else {
matcher = PgpHelper.PGP_CLEARTEXT_SIGNATURE.matcher(input); matcher = PgpHelper.PGP_CLEARTEXT_SIGNATURE.matcher(input);
if (matcher.matches()) { if (matcher.matches()) {
String text = matcher.group(1); String text = matcher.group(1);
text = fixPgpCleartextSignature(text); text = fixPgpCleartextSignature(text);
Timber.d("input fixed: %s", text);
return text; return text;
} else { } else {
return null; return null;
@@ -108,8 +102,6 @@ public class PgpHelper {
} }
public static String getPgpPublicKeyContent(@NonNull CharSequence input) { public static String getPgpPublicKeyContent(@NonNull CharSequence input) {
Timber.d("input: %s", input);
Matcher matcher = PgpHelper.PGP_PUBLIC_KEY.matcher(input); Matcher matcher = PgpHelper.PGP_PUBLIC_KEY.matcher(input);
if (!matcher.matches()) { if (!matcher.matches()) {
return null; return null;

View File

@@ -117,25 +117,23 @@ public class EncryptDecryptFragment extends Fragment {
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
// get text from clipboard checkClipboardForEncryptedText();
final CharSequence clipboardText = ClipboardReflection.getClipboardText(getActivity()); }
// if it's null, nothing to do here /o/ private void checkClipboardForEncryptedText() {
if (clipboardText == null) { CharSequence clipboardText = ClipboardReflection.getClipboardText(getActivity());
return;
}
new AsyncTask<String, Void, Boolean>() { new AsyncTask<Void, Void, Boolean>() {
@Override @Override
protected Boolean doInBackground(String... clipboardText) { protected Boolean doInBackground(Void... voids) {
// see if it looks like a pgp thing // see if it looks like a pgp thing
Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(clipboardText[0]); Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(clipboardText);
boolean animate = matcher.matches(); boolean animate = matcher.matches();
// see if it looks like another pgp thing // see if it looks like another pgp thing
if (!animate) { if (!animate) {
matcher = PgpHelper.PGP_CLEARTEXT_SIGNATURE.matcher(clipboardText[0]); matcher = PgpHelper.PGP_CLEARTEXT_SIGNATURE.matcher(clipboardText);
animate = matcher.matches(); animate = matcher.matches();
} }
return animate; return animate;
@@ -150,7 +148,7 @@ public class EncryptDecryptFragment extends Fragment {
SubtleAttentionSeeker.tada(mClipboardIcon, 1.5f).start(); SubtleAttentionSeeker.tada(mClipboardIcon, 1.5f).start();
} }
} }
}.execute(clipboardText.toString()); }.execute();
} }
@Override @Override

View File

@@ -17,6 +17,11 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
@@ -25,10 +30,11 @@ import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager;
import android.view.ViewGroup; import android.text.TextUtils;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
import org.sufficientlysecure.keychain.keyimport.FacebookKeyserverClient; import org.sufficientlysecure.keychain.keyimport.FacebookKeyserverClient;
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress; import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress;
import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;
@@ -38,19 +44,17 @@ import org.sufficientlysecure.keychain.keyimport.processing.ImportKeysOperationC
import org.sufficientlysecure.keychain.keyimport.processing.LoaderState; import org.sufficientlysecure.keychain.keyimport.processing.LoaderState;
import org.sufficientlysecure.keychain.operations.ImportOperation; import org.sufficientlysecure.keychain.operations.ImportOperation;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel; import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.ui.base.BaseActivity;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
import org.sufficientlysecure.keychain.util.ParcelableFileCache; import org.sufficientlysecure.keychain.util.ParcelableFileCache;
import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.util.Preferences;
import timber.log.Timber; import timber.log.Timber;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class ImportKeysActivity extends BaseActivity implements ImportKeysListener { public class ImportKeysActivity extends BaseActivity implements ImportKeysListener {
public static final String ACTION_IMPORT_KEY = Constants.IMPORT_KEY; public static final String ACTION_IMPORT_KEY = Constants.IMPORT_KEY;
@@ -69,6 +73,8 @@ public class ImportKeysActivity extends BaseActivity implements ImportKeysListen
+ "IMPORT_KEY_FROM_FILE"; + "IMPORT_KEY_FROM_FILE";
public static final String ACTION_SEARCH_KEYSERVER_FROM_URL = Constants.INTENT_PREFIX public static final String ACTION_SEARCH_KEYSERVER_FROM_URL = Constants.INTENT_PREFIX
+ "SEARCH_KEYSERVER_FROM_URL"; + "SEARCH_KEYSERVER_FROM_URL";
public static final String ACTION_IMPORT_KEY_FROM_CLIPBOARD = Constants.INTENT_PREFIX
+ "IMPORT_KEY_FROM_CLIPBOARD";
public static final String EXTRA_RESULT = "result"; public static final String EXTRA_RESULT = "result";
// only used by ACTION_IMPORT_KEY // only used by ACTION_IMPORT_KEY
@@ -257,6 +263,10 @@ public class ImportKeysActivity extends BaseActivity implements ImportKeysListen
startListFragment(null, null, null, null); startListFragment(null, null, null, null);
break; break;
} }
case ACTION_IMPORT_KEY_FROM_CLIPBOARD: {
startListFragmentFromClipboard();
break;
}
default: { default: {
startTopCloudFragment(null, null); startTopCloudFragment(null, null);
startListFragment(null, null, null, null); startListFragment(null, null, null, null);
@@ -265,6 +275,22 @@ public class ImportKeysActivity extends BaseActivity implements ImportKeysListen
} }
} }
private void startListFragmentFromClipboard() {
CharSequence clipboardText = ClipboardReflection.getClipboardText(this);
if (TextUtils.isEmpty(clipboardText)) {
Notify.create(this, R.string.error_clipboard_empty, Style.ERROR).show();
return;
}
String keyText = PgpHelper.getPgpPublicKeyContent(clipboardText);
if (keyText == null) {
Notify.create(this, R.string.error_clipboard_bad, Style.ERROR).show();
return;
}
startListFragment(keyText.getBytes(), null, null, null);
}
/** /**
* Shows the list of keys to be imported. * Shows the list of keys to be imported.
* If the fragment is started with non-null bytes/dataUri/serverQuery, it will immediately * If the fragment is started with non-null bytes/dataUri/serverQuery, it will immediately
@@ -387,6 +413,10 @@ public class ImportKeysActivity extends BaseActivity implements ImportKeysListen
setResult(Activity.RESULT_OK, intent); setResult(Activity.RESULT_OK, intent);
finish(); finish();
} else if (result.isOkNew() || result.isOkUpdated()) { } else if (result.isOkNew() || result.isOkUpdated()) {
if (ACTION_IMPORT_KEY_FROM_CLIPBOARD.equals(intentAction)) {
ClipboardReflection.clearClipboard(getApplicationContext());
}
// User has successfully imported a key, hide first time dialog // User has successfully imported a key, hide first time dialog
Preferences.getPreferences(this).setFirstTime(false); Preferences.getPreferences(this).setFirstTime(false);

View File

@@ -26,6 +26,7 @@ import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager; import android.support.v4.app.LoaderManager;
@@ -50,11 +51,13 @@ import com.getbase.floatingactionbutton.FloatingActionsMenu;
import com.tonicartos.superslim.LayoutManager; import com.tonicartos.superslim.LayoutManager;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress; import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
import org.sufficientlysecure.keychain.operations.results.BenchmarkResult; import org.sufficientlysecure.keychain.operations.results.BenchmarkResult;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.provider.KeyRepository; import org.sufficientlysecure.keychain.provider.KeyRepository;
import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
@@ -66,6 +69,8 @@ import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
import org.sufficientlysecure.keychain.ui.base.RecyclerFragment; import org.sufficientlysecure.keychain.ui.base.RecyclerFragment;
import org.sufficientlysecure.keychain.ui.keyview.ViewKeyActivity; import org.sufficientlysecure.keychain.ui.keyview.ViewKeyActivity;
import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener;
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
import org.sufficientlysecure.keychain.util.FabContainer; import org.sufficientlysecure.keychain.util.FabContainer;
import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.util.Preferences;
import timber.log.Timber; import timber.log.Timber;
@@ -254,6 +259,54 @@ public class KeyListFragment extends RecyclerFragment<KeySectionedListAdapter>
getLoaderManager().initLoader(0, null, this); getLoaderManager().initLoader(0, null, this);
} }
@Override
public void onStart() {
super.onStart();
checkClipboardForPublicKeyMaterial();
}
private void checkClipboardForPublicKeyMaterial() {
CharSequence clipboardText = ClipboardReflection.getClipboardText(getActivity());
new AsyncTask<Void, Void, Boolean>() {
@Override
protected Boolean doInBackground(Void... voids) {
if (clipboardText == null) {
return false;
}
// see if it looks like a pgp thing
String publicKeyContent = PgpHelper.getPgpPublicKeyContent(clipboardText);
return publicKeyContent != null;
}
@Override
protected void onPostExecute(Boolean clipboardDataFound) {
super.onPostExecute(clipboardDataFound);
if (clipboardDataFound) {
showClipboardDataSnackbar();
}
}
}.execute();
}
private void showClipboardDataSnackbar() {
Activity activity = getActivity();
if (activity == null) {
return;
}
Notify.create(activity, R.string.snack_keylist_clipboard_title, Notify.LENGTH_INDEFINITE, Style.OK,
() -> {
Intent intentImportExisting = new Intent(getActivity(), ImportKeysActivity.class);
intentImportExisting.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_CLIPBOARD);
startActivity(intentImportExisting);
}, R.string.snack_keylist_clipboard_action).show(this);
}
private void startSearchForQuery() { private void startSearchForQuery() {
Activity activity = getActivity(); Activity activity = getActivity();
if (activity == null) { if (activity == null) {

View File

@@ -2021,4 +2021,7 @@
<string name="button_goto_openkeychain">Go to OpenKeychain</string> <string name="button_goto_openkeychain">Go to OpenKeychain</string>
<string name="backup_code_checkbox">I have written down this backup code. Without it, I will be unable to restore the backup.</string> <string name="backup_code_checkbox">I have written down this backup code. Without it, I will be unable to restore the backup.</string>
<string name="msg_get_query_not_implemented">The server does not support the current query! Some servers only accept mailaddresses. Please redefine or try a different server.</string> <string name="msg_get_query_not_implemented">The server does not support the current query! Some servers only accept mailaddresses. Please redefine or try a different server.</string>
<string name="snack_keylist_clipboard_title">Found key data in clipboard!</string>
<string name="snack_keylist_clipboard_action">View</string>
</resources> </resources>