mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-11-17 06:15:15 -05:00
API: Allow ACTION_SIGN_AND_ENCRYPT with no key ids or user ids extras, fix pre-selection of key ids (no revoked or expired ones, also select duplicates), refactor text using spannables
This commit is contained in:
parent
443170b876
commit
bbe986743c
@ -72,52 +72,61 @@ public class OpenPgpService extends RemoteService {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private Intent getKeyIdsFromEmails(Intent data, String[] encryptionUserIds) {
|
private Intent getKeyIdsFromEmails(Intent data, String[] encryptionUserIds) {
|
||||||
// find key ids to given emails in database
|
boolean noUserIdsCheck = (encryptionUserIds == null || encryptionUserIds.length == 0);
|
||||||
ArrayList<Long> keyIds = new ArrayList<Long>();
|
|
||||||
|
|
||||||
boolean missingUserIdsCheck = false;
|
boolean missingUserIdsCheck = false;
|
||||||
boolean duplicateUserIdsCheck = false;
|
boolean duplicateUserIdsCheck = false;
|
||||||
|
|
||||||
|
ArrayList<Long> keyIds = new ArrayList<Long>();
|
||||||
ArrayList<String> missingUserIds = new ArrayList<String>();
|
ArrayList<String> missingUserIds = new ArrayList<String>();
|
||||||
ArrayList<String> duplicateUserIds = new ArrayList<String>();
|
ArrayList<String> duplicateUserIds = new ArrayList<String>();
|
||||||
|
if (!noUserIdsCheck) {
|
||||||
|
for (String email : encryptionUserIds) {
|
||||||
|
// try to find the key for this specific email
|
||||||
|
Uri uri = KeyRings.buildUnifiedKeyRingsFindByEmailUri(email);
|
||||||
|
Cursor cursor = getContentResolver().query(uri, EMAIL_SEARCH_PROJECTION, EMAIL_SEARCH_WHERE, null, null);
|
||||||
|
try {
|
||||||
|
// result should be one entry containing the key id
|
||||||
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
long id = cursor.getLong(cursor.getColumnIndex(KeyRings.MASTER_KEY_ID));
|
||||||
|
keyIds.add(id);
|
||||||
|
} else {
|
||||||
|
missingUserIdsCheck = true;
|
||||||
|
missingUserIds.add(email);
|
||||||
|
Log.d(Constants.TAG, "user id missing");
|
||||||
|
}
|
||||||
|
// another entry for this email -> too keys with the same email inside user id
|
||||||
|
if (cursor != null && cursor.moveToNext()) {
|
||||||
|
duplicateUserIdsCheck = true;
|
||||||
|
duplicateUserIds.add(email);
|
||||||
|
|
||||||
for (String email : encryptionUserIds) {
|
// also pre-select
|
||||||
Uri uri = KeyRings.buildUnifiedKeyRingsFindByEmailUri(email);
|
long id = cursor.getLong(cursor.getColumnIndex(KeyRings.MASTER_KEY_ID));
|
||||||
Cursor cursor = getContentResolver().query(uri, EMAIL_SEARCH_PROJECTION, EMAIL_SEARCH_WHERE, null, null);
|
keyIds.add(id);
|
||||||
try {
|
Log.d(Constants.TAG, "more than one user id with the same email");
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
}
|
||||||
long id = cursor.getLong(cursor.getColumnIndex(KeyRings.MASTER_KEY_ID));
|
} finally {
|
||||||
keyIds.add(id);
|
if (cursor != null) {
|
||||||
} else {
|
cursor.close();
|
||||||
missingUserIdsCheck = true;
|
}
|
||||||
missingUserIds.add(email);
|
|
||||||
Log.d(Constants.TAG, "user id missing");
|
|
||||||
}
|
|
||||||
if (cursor != null && cursor.moveToNext()) {
|
|
||||||
duplicateUserIdsCheck = true;
|
|
||||||
duplicateUserIds.add(email);
|
|
||||||
Log.d(Constants.TAG, "more than one user id with the same email");
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (cursor != null) {
|
|
||||||
cursor.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert to long[]
|
// convert ArrayList<Long> to long[]
|
||||||
long[] keyIdsArray = new long[keyIds.size()];
|
long[] keyIdsArray = new long[keyIds.size()];
|
||||||
for (int i = 0; i < keyIdsArray.length; i++) {
|
for (int i = 0; i < keyIdsArray.length; i++) {
|
||||||
keyIdsArray[i] = keyIds.get(i);
|
keyIdsArray[i] = keyIds.get(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow the user to verify pub key selection
|
if (noUserIdsCheck || missingUserIdsCheck || duplicateUserIdsCheck) {
|
||||||
if (missingUserIdsCheck || duplicateUserIdsCheck) {
|
// allow the user to verify pub key selection
|
||||||
// build PendingIntent
|
|
||||||
Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
|
Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
|
||||||
intent.setAction(RemoteServiceActivity.ACTION_SELECT_PUB_KEYS);
|
intent.setAction(RemoteServiceActivity.ACTION_SELECT_PUB_KEYS);
|
||||||
intent.putExtra(RemoteServiceActivity.EXTRA_SELECTED_MASTER_KEY_IDS, keyIdsArray);
|
intent.putExtra(RemoteServiceActivity.EXTRA_SELECTED_MASTER_KEY_IDS, keyIdsArray);
|
||||||
|
intent.putExtra(RemoteServiceActivity.EXTRA_NO_USER_IDS_CHECK, noUserIdsCheck);
|
||||||
intent.putExtra(RemoteServiceActivity.EXTRA_MISSING_USER_IDS, missingUserIds);
|
intent.putExtra(RemoteServiceActivity.EXTRA_MISSING_USER_IDS, missingUserIds);
|
||||||
intent.putExtra(RemoteServiceActivity.EXTRA_DUBLICATE_USER_IDS, duplicateUserIds);
|
intent.putExtra(RemoteServiceActivity.EXTRA_DUPLICATE_USER_IDS, duplicateUserIds);
|
||||||
intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
|
intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
|
||||||
|
|
||||||
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,
|
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,
|
||||||
@ -129,16 +138,18 @@ public class OpenPgpService extends RemoteService {
|
|||||||
result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
|
result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
|
||||||
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED);
|
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED);
|
||||||
return result;
|
return result;
|
||||||
}
|
} else {
|
||||||
|
// everything was easy, we have exactly one key for every email
|
||||||
|
|
||||||
if (keyIdsArray.length == 0) {
|
if (keyIdsArray.length == 0) {
|
||||||
return null;
|
Log.e(Constants.TAG, "keyIdsArray.length == 0, should never happen!");
|
||||||
}
|
}
|
||||||
|
|
||||||
Intent result = new Intent();
|
Intent result = new Intent();
|
||||||
result.putExtra(OpenPgpApi.RESULT_KEY_IDS, keyIdsArray);
|
result.putExtra(OpenPgpApi.RESULT_KEY_IDS, keyIdsArray);
|
||||||
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
|
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Intent getPassphraseBundleIntent(Intent data, long keyId) {
|
private Intent getPassphraseBundleIntent(Intent data, long keyId) {
|
||||||
@ -241,10 +252,9 @@ public class OpenPgpService extends RemoteService {
|
|||||||
originalFilename = "";
|
originalFilename = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
long[] keyIds;
|
// first try to get key ids from non-ambiguous key id extra
|
||||||
if (data.hasExtra(OpenPgpApi.EXTRA_KEY_IDS)) {
|
long[] keyIds = data.getLongArrayExtra(OpenPgpApi.EXTRA_KEY_IDS);
|
||||||
keyIds = data.getLongArrayExtra(OpenPgpApi.EXTRA_KEY_IDS);
|
if (keyIds == null) {
|
||||||
} else if (data.hasExtra(OpenPgpApi.EXTRA_USER_IDS)) {
|
|
||||||
// get key ids based on given user ids
|
// get key ids based on given user ids
|
||||||
String[] userIds = data.getStringArrayExtra(OpenPgpApi.EXTRA_USER_IDS);
|
String[] userIds = data.getStringArrayExtra(OpenPgpApi.EXTRA_USER_IDS);
|
||||||
// give params through to activity...
|
// give params through to activity...
|
||||||
@ -256,14 +266,6 @@ public class OpenPgpService extends RemoteService {
|
|||||||
// if not success -> result contains a PendingIntent for user interaction
|
// if not success -> result contains a PendingIntent for user interaction
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Intent result = new Intent();
|
|
||||||
result.putExtra(OpenPgpApi.RESULT_ERROR,
|
|
||||||
new OpenPgpError(OpenPgpError.GENERIC_ERROR,
|
|
||||||
"Missing parameter user_ids or key_ids!")
|
|
||||||
);
|
|
||||||
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// build InputData and write into OutputStream
|
// build InputData and write into OutputStream
|
||||||
|
@ -18,11 +18,20 @@
|
|||||||
package org.sufficientlysecure.keychain.remote.ui;
|
package org.sufficientlysecure.keychain.remote.ui;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Typeface;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.support.v7.app.ActionBarActivity;
|
import android.support.v7.app.ActionBarActivity;
|
||||||
|
import android.text.Spannable;
|
||||||
|
import android.text.SpannableString;
|
||||||
|
import android.text.SpannableStringBuilder;
|
||||||
|
import android.text.SpannedString;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.text.style.BulletSpan;
|
||||||
|
import android.text.style.StyleSpan;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
@ -39,7 +48,6 @@ import org.sufficientlysecure.keychain.ui.SelectPublicKeyFragment;
|
|||||||
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
|
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
import java.security.Provider;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class RemoteServiceActivity extends ActionBarActivity {
|
public class RemoteServiceActivity extends ActionBarActivity {
|
||||||
@ -68,7 +76,8 @@ public class RemoteServiceActivity extends ActionBarActivity {
|
|||||||
// select pub keys action
|
// select pub keys action
|
||||||
public static final String EXTRA_SELECTED_MASTER_KEY_IDS = "master_key_ids";
|
public static final String EXTRA_SELECTED_MASTER_KEY_IDS = "master_key_ids";
|
||||||
public static final String EXTRA_MISSING_USER_IDS = "missing_user_ids";
|
public static final String EXTRA_MISSING_USER_IDS = "missing_user_ids";
|
||||||
public static final String EXTRA_DUBLICATE_USER_IDS = "dublicate_user_ids";
|
public static final String EXTRA_DUPLICATE_USER_IDS = "dublicate_user_ids";
|
||||||
|
public static final String EXTRA_NO_USER_IDS_CHECK = "no_user_ids";
|
||||||
// error message
|
// error message
|
||||||
public static final String EXTRA_ERROR_MESSAGE = "error_message";
|
public static final String EXTRA_ERROR_MESSAGE = "error_message";
|
||||||
|
|
||||||
@ -229,32 +238,41 @@ public class RemoteServiceActivity extends ActionBarActivity {
|
|||||||
|
|
||||||
} else if (ACTION_SELECT_PUB_KEYS.equals(action)) {
|
} else if (ACTION_SELECT_PUB_KEYS.equals(action)) {
|
||||||
long[] selectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS);
|
long[] selectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS);
|
||||||
|
boolean noUserIdsCheck = intent.getBooleanExtra(EXTRA_NO_USER_IDS_CHECK, true);
|
||||||
ArrayList<String> missingUserIds = intent
|
ArrayList<String> missingUserIds = intent
|
||||||
.getStringArrayListExtra(EXTRA_MISSING_USER_IDS);
|
.getStringArrayListExtra(EXTRA_MISSING_USER_IDS);
|
||||||
ArrayList<String> dublicateUserIds = intent
|
ArrayList<String> dublicateUserIds = intent
|
||||||
.getStringArrayListExtra(EXTRA_DUBLICATE_USER_IDS);
|
.getStringArrayListExtra(EXTRA_DUPLICATE_USER_IDS);
|
||||||
|
|
||||||
|
SpannableStringBuilder ssb = new SpannableStringBuilder();
|
||||||
|
final SpannableString textIntro = new SpannableString(
|
||||||
|
noUserIdsCheck ? getString(R.string.api_select_pub_keys_text_no_user_ids)
|
||||||
|
: getString(R.string.api_select_pub_keys_text)
|
||||||
|
);
|
||||||
|
textIntro.setSpan(new StyleSpan(Typeface.BOLD), 0, textIntro.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
ssb.append(textIntro);
|
||||||
|
|
||||||
// TODO: do this with spannable instead of HTML to prevent parsing failures with weird user ids
|
|
||||||
String text = "<b>" + getString(R.string.api_select_pub_keys_text) + "</b>";
|
|
||||||
text += "<br/><br/>";
|
|
||||||
if (missingUserIds != null && missingUserIds.size() > 0) {
|
if (missingUserIds != null && missingUserIds.size() > 0) {
|
||||||
text += getString(R.string.api_select_pub_keys_missing_text);
|
ssb.append("\n\n");
|
||||||
text += "<br/>";
|
ssb.append(getString(R.string.api_select_pub_keys_missing_text));
|
||||||
text += "<ul>";
|
ssb.append("\n");
|
||||||
for (String userId : missingUserIds) {
|
for (String userId : missingUserIds) {
|
||||||
text += "<li>" + userId + "</li>";
|
SpannableString ss = new SpannableString(userId + "\n");
|
||||||
|
ss.setSpan(new BulletSpan(15, Color.BLACK), 0, ss.length(),
|
||||||
|
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
ssb.append(ss);
|
||||||
}
|
}
|
||||||
text += "</ul>";
|
|
||||||
text += "<br/>";
|
|
||||||
}
|
}
|
||||||
if (dublicateUserIds != null && dublicateUserIds.size() > 0) {
|
if (dublicateUserIds != null && dublicateUserIds.size() > 0) {
|
||||||
text += getString(R.string.api_select_pub_keys_dublicates_text);
|
ssb.append("\n\n");
|
||||||
text += "<br/>";
|
ssb.append(getString(R.string.api_select_pub_keys_dublicates_text));
|
||||||
text += "<ul>";
|
ssb.append("\n");
|
||||||
for (String userId : dublicateUserIds) {
|
for (String userId : dublicateUserIds) {
|
||||||
text += "<li>" + userId + "</li>";
|
SpannableString ss = new SpannableString(userId + "\n");
|
||||||
|
ss.setSpan(new BulletSpan(15, Color.BLACK), 0, ss.length(),
|
||||||
|
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
ssb.append(ss);
|
||||||
}
|
}
|
||||||
text += "</ul>";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inflate a "Done"/"Cancel" custom action bar view
|
// Inflate a "Done"/"Cancel" custom action bar view
|
||||||
@ -284,8 +302,8 @@ public class RemoteServiceActivity extends ActionBarActivity {
|
|||||||
setContentView(R.layout.api_remote_select_pub_keys);
|
setContentView(R.layout.api_remote_select_pub_keys);
|
||||||
|
|
||||||
// set text on view
|
// set text on view
|
||||||
HtmlTextView textView = (HtmlTextView) findViewById(R.id.api_select_pub_keys_text);
|
TextView textView = (TextView) findViewById(R.id.api_select_pub_keys_text);
|
||||||
textView.setHtmlFromString(text, true);
|
textView.setText(ssb, TextView.BufferType.SPANNABLE);
|
||||||
|
|
||||||
/* Load select pub keys fragment */
|
/* Load select pub keys fragment */
|
||||||
// Check that the activity is using the layout version with
|
// Check that the activity is using the layout version with
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
android:layout_height="fill_parent"
|
android:layout_height="fill_parent"
|
||||||
android:orientation="vertical" >
|
android:orientation="vertical" >
|
||||||
|
|
||||||
<org.sufficientlysecure.htmltextview.HtmlTextView
|
<TextView
|
||||||
android:id="@+id/api_select_pub_keys_text"
|
android:id="@+id/api_select_pub_keys_text"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:padding="8dp"
|
android:paddingTop="8dp"
|
||||||
android:paddingBottom="0dip"
|
android:paddingLeft="8dp"
|
||||||
android:text="Set in-code!"
|
android:paddingRight="8dp"
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
|
@ -395,9 +395,10 @@
|
|||||||
<string name="api_register_allow">Allow access</string>
|
<string name="api_register_allow">Allow access</string>
|
||||||
<string name="api_register_disallow">Disallow access</string>
|
<string name="api_register_disallow">Disallow access</string>
|
||||||
<string name="api_register_error_select_key">Please select a key!</string>
|
<string name="api_register_error_select_key">Please select a key!</string>
|
||||||
<string name="api_select_pub_keys_missing_text">No public keys were found for these identities:</string>
|
<string name="api_select_pub_keys_missing_text">No keys were found for these identities:</string>
|
||||||
<string name="api_select_pub_keys_dublicates_text">More than one public key exist for these identities:</string>
|
<string name="api_select_pub_keys_dublicates_text">More than one key exist for these identities:</string>
|
||||||
<string name="api_select_pub_keys_text">Please review the list of recipients!</string>
|
<string name="api_select_pub_keys_text">Please review the list of recipients!</string>
|
||||||
|
<string name="api_select_pub_keys_text_no_user_ids">Please select the recipients!</string>
|
||||||
<string name="api_error_wrong_signature">Signature check failed! Have you installed this app from a different source? If you are sure that this is not an attack, revoke this app\'s registration in OpenKeychain and then register the app again.</string>
|
<string name="api_error_wrong_signature">Signature check failed! Have you installed this app from a different source? If you are sure that this is not an attack, revoke this app\'s registration in OpenKeychain and then register the app again.</string>
|
||||||
|
|
||||||
<!-- Share -->
|
<!-- Share -->
|
||||||
|
Loading…
Reference in New Issue
Block a user