wip
This commit is contained in:
@@ -18,6 +18,17 @@
|
|||||||
|
|
||||||
package org.sufficientlysecure.keychain.remote;
|
package org.sufficientlysecure.keychain.remote;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -42,6 +53,8 @@ import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
|||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogEntryParcel;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogEntryParcel;
|
||||||
import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult;
|
import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.KeyRing.UserId;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
|
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyOperation;
|
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyOperation;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants;
|
import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants;
|
||||||
@@ -60,18 +73,9 @@ import org.sufficientlysecure.keychain.util.InputData;
|
|||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
import org.sufficientlysecure.keychain.util.Passphrase;
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class OpenPgpService extends Service {
|
public class OpenPgpService extends Service {
|
||||||
|
|
||||||
static final String[] EMAIL_SEARCH_PROJECTION = new String[]{
|
static final String[] KEY_SEARCH_PROJECTION = new String[]{
|
||||||
KeyRings._ID,
|
KeyRings._ID,
|
||||||
KeyRings.MASTER_KEY_ID,
|
KeyRings.MASTER_KEY_ID,
|
||||||
KeyRings.IS_EXPIRED,
|
KeyRings.IS_EXPIRED,
|
||||||
@@ -79,7 +83,7 @@ public class OpenPgpService extends Service {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// do not pre-select revoked or expired keys
|
// do not pre-select revoked or expired keys
|
||||||
static final String EMAIL_SEARCH_WHERE = Tables.KEYS + "." + KeychainContract.KeyRings.IS_REVOKED
|
static final String KEY_SEARCH_WHERE = Tables.KEYS + "." + KeychainContract.KeyRings.IS_REVOKED
|
||||||
+ " = 0 AND " + KeychainContract.KeyRings.IS_EXPIRED + " = 0";
|
+ " = 0 AND " + KeychainContract.KeyRings.IS_EXPIRED + " = 0";
|
||||||
|
|
||||||
private ApiPermissionHelper mApiPermissionHelper;
|
private ApiPermissionHelper mApiPermissionHelper;
|
||||||
@@ -94,22 +98,35 @@ public class OpenPgpService extends Service {
|
|||||||
mApiDao = new ApiDataAccessObject(this);
|
mApiDao = new ApiDataAccessObject(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static class KeyIdResult {
|
||||||
* Search database for key ids based on emails.
|
final Intent mRequiredUserInteraction;
|
||||||
*/
|
final HashSet<Long> mKeyIds;
|
||||||
private Intent returnKeyIdsFromEmails(Intent data, String[] encryptionUserIds) {
|
|
||||||
|
KeyIdResult(Intent requiredUserInteraction) {
|
||||||
|
mRequiredUserInteraction = requiredUserInteraction;
|
||||||
|
mKeyIds = null;
|
||||||
|
}
|
||||||
|
KeyIdResult(HashSet<Long> keyIds) {
|
||||||
|
mRequiredUserInteraction = null;
|
||||||
|
mKeyIds = keyIds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private KeyIdResult returnKeyIdsFromEmails(Intent data, String[] encryptionUserIds) {
|
||||||
boolean noUserIdsCheck = (encryptionUserIds == null || encryptionUserIds.length == 0);
|
boolean noUserIdsCheck = (encryptionUserIds == null || encryptionUserIds.length == 0);
|
||||||
boolean missingUserIdsCheck = false;
|
boolean missingUserIdsCheck = false;
|
||||||
boolean duplicateUserIdsCheck = false;
|
boolean duplicateUserIdsCheck = false;
|
||||||
|
|
||||||
ArrayList<Long> keyIds = new ArrayList<>();
|
HashSet<Long> keyIds = new HashSet<>();
|
||||||
ArrayList<String> missingEmails = new ArrayList<>();
|
ArrayList<String> missingEmails = new ArrayList<>();
|
||||||
ArrayList<String> duplicateEmails = new ArrayList<>();
|
ArrayList<String> duplicateEmails = new ArrayList<>();
|
||||||
if (!noUserIdsCheck) {
|
if (!noUserIdsCheck) {
|
||||||
for (String email : encryptionUserIds) {
|
for (String rawUserId : encryptionUserIds) {
|
||||||
|
UserId userId = KeyRing.splitUserId(rawUserId);
|
||||||
|
String email = userId.email != null ? userId.email : rawUserId;
|
||||||
// try to find the key for this specific email
|
// try to find the key for this specific email
|
||||||
Uri uri = KeyRings.buildUnifiedKeyRingsFindByEmailUri(email);
|
Uri uri = KeyRings.buildUnifiedKeyRingsFindByEmailUri(email);
|
||||||
Cursor cursor = getContentResolver().query(uri, EMAIL_SEARCH_PROJECTION, EMAIL_SEARCH_WHERE, null, null);
|
Cursor cursor = getContentResolver().query(uri, KEY_SEARCH_PROJECTION, KEY_SEARCH_WHERE, null, null);
|
||||||
try {
|
try {
|
||||||
// result should be one entry containing the key id
|
// result should be one entry containing the key id
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
@@ -138,15 +155,11 @@ public class OpenPgpService extends Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert ArrayList<Long> to long[]
|
|
||||||
long[] keyIdsArray = new long[keyIds.size()];
|
|
||||||
for (int i = 0; i < keyIdsArray.length; i++) {
|
|
||||||
keyIdsArray[i] = keyIds.get(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (noUserIdsCheck || missingUserIdsCheck || duplicateUserIdsCheck) {
|
if (noUserIdsCheck || missingUserIdsCheck || duplicateUserIdsCheck) {
|
||||||
// allow the user to verify pub key selection
|
// allow the user to verify pub key selection
|
||||||
|
|
||||||
|
// convert ArrayList<Long> to long[]
|
||||||
|
long[] keyIdsArray = getUnboxedLongArray(keyIds);
|
||||||
ApiPendingIntentFactory piFactory = new ApiPendingIntentFactory(getBaseContext());
|
ApiPendingIntentFactory piFactory = new ApiPendingIntentFactory(getBaseContext());
|
||||||
PendingIntent pi = piFactory.createSelectPublicKeyPendingIntent(data, keyIdsArray,
|
PendingIntent pi = piFactory.createSelectPublicKeyPendingIntent(data, keyIdsArray,
|
||||||
missingEmails, duplicateEmails, noUserIdsCheck);
|
missingEmails, duplicateEmails, noUserIdsCheck);
|
||||||
@@ -155,18 +168,15 @@ public class OpenPgpService extends Service {
|
|||||||
Intent result = new Intent();
|
Intent result = new Intent();
|
||||||
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 new KeyIdResult(result);
|
||||||
} else {
|
} else {
|
||||||
// everything was easy, we have exactly one key for every email
|
// everything was easy, we have exactly one key for every email
|
||||||
|
|
||||||
if (keyIdsArray.length == 0) {
|
if (keyIds.isEmpty()) {
|
||||||
Log.e(Constants.TAG, "keyIdsArray.length == 0, should never happen!");
|
Log.e(Constants.TAG, "keyIdsArray.length == 0, should never happen!");
|
||||||
}
|
}
|
||||||
|
|
||||||
Intent result = new Intent();
|
return new KeyIdResult(keyIds);
|
||||||
result.putExtra(OpenPgpApi.RESULT_KEY_IDS, keyIdsArray);
|
|
||||||
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,20 +291,31 @@ public class OpenPgpService extends Service {
|
|||||||
compressionId = PgpSecurityConstants.OpenKeychainCompressionAlgorithmTags.UNCOMPRESSED;
|
compressionId = PgpSecurityConstants.OpenKeychainCompressionAlgorithmTags.UNCOMPRESSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// first try to get key ids from non-ambiguous key id extra
|
long[] keyIds;
|
||||||
long[] keyIds = data.getLongArrayExtra(OpenPgpApi.EXTRA_KEY_IDS);
|
{
|
||||||
if (keyIds == null) {
|
HashSet<Long> encryptKeyIds = new HashSet<>();
|
||||||
// get key ids based on given user ids
|
|
||||||
String[] userIds = data.getStringArrayExtra(OpenPgpApi.EXTRA_USER_IDS);
|
|
||||||
// give params through to activity...
|
|
||||||
Intent result = returnKeyIdsFromEmails(data, userIds);
|
|
||||||
|
|
||||||
if (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0) == OpenPgpApi.RESULT_CODE_SUCCESS) {
|
// get key ids based on given user ids
|
||||||
keyIds = result.getLongArrayExtra(OpenPgpApi.RESULT_KEY_IDS);
|
if (data.hasExtra(OpenPgpApi.EXTRA_USER_IDS)) {
|
||||||
} else {
|
String[] userIds = data.getStringArrayExtra(OpenPgpApi.EXTRA_USER_IDS);
|
||||||
// if not success -> result contains a PendingIntent for user interaction
|
data.removeExtra(OpenPgpApi.EXTRA_USER_IDS);
|
||||||
return result;
|
// give params through to activity...
|
||||||
|
KeyIdResult result = returnKeyIdsFromEmails(data, userIds);
|
||||||
|
|
||||||
|
if (result.mRequiredUserInteraction != null) {
|
||||||
|
return result.mRequiredUserInteraction;
|
||||||
|
}
|
||||||
|
encryptKeyIds.addAll(result.mKeyIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add key ids from non-ambiguous key id extra
|
||||||
|
if (data.hasExtra(OpenPgpApi.EXTRA_KEY_IDS)) {
|
||||||
|
for (long keyId : data.getLongArrayExtra(OpenPgpApi.EXTRA_KEY_IDS)) {
|
||||||
|
encryptKeyIds.add(keyId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keyIds = getUnboxedLongArray(encryptKeyIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO this is not correct!
|
// TODO this is not correct!
|
||||||
@@ -670,10 +691,35 @@ public class OpenPgpService extends Service {
|
|||||||
} else {
|
} else {
|
||||||
// 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);
|
||||||
return returnKeyIdsFromEmails(data, userIds);
|
data.removeExtra(OpenPgpApi.EXTRA_USER_IDS);
|
||||||
|
KeyIdResult keyResult = returnKeyIdsFromEmails(data, userIds);
|
||||||
|
if (keyResult.mRequiredUserInteraction != null) {
|
||||||
|
return keyResult.mRequiredUserInteraction;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyResult.mKeyIds == null) {
|
||||||
|
throw new AssertionError("one of requiredUserInteraction and keyIds must be non-null, this is a bug!");
|
||||||
|
}
|
||||||
|
|
||||||
|
long[] keyIds = getUnboxedLongArray(keyResult.mKeyIds);
|
||||||
|
|
||||||
|
Intent resultIntent = new Intent();
|
||||||
|
resultIntent.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
|
||||||
|
resultIntent.putExtra(OpenPgpApi.RESULT_KEY_IDS, keyIds);
|
||||||
|
return resultIntent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private static long[] getUnboxedLongArray(@NonNull Collection<Long> arrayList) {
|
||||||
|
long[] result = new long[arrayList.size()];
|
||||||
|
int i = 0;
|
||||||
|
for (Long e : arrayList) {
|
||||||
|
result[i++] = e;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private Intent checkPermissionImpl(@NonNull Intent data) {
|
private Intent checkPermissionImpl(@NonNull Intent data) {
|
||||||
Intent permissionIntent = mApiPermissionHelper.isAllowedOrReturnIntent(data);
|
Intent permissionIntent = mApiPermissionHelper.isAllowedOrReturnIntent(data);
|
||||||
if (permissionIntent != null) {
|
if (permissionIntent != null) {
|
||||||
|
|||||||
Reference in New Issue
Block a user