combine autocrypt peer state and hand to client app

This commit is contained in:
Vincent Breitmoser
2017-06-21 20:52:17 +02:00
parent 5e01e41bcd
commit 4cf4981f1b
2 changed files with 93 additions and 30 deletions

View File

@@ -75,6 +75,7 @@ import org.sufficientlysecure.keychain.provider.KeyWritableRepository;
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;
import org.sufficientlysecure.keychain.provider.OverriddenWarningsRepository; import org.sufficientlysecure.keychain.provider.OverriddenWarningsRepository;
import org.sufficientlysecure.keychain.remote.OpenPgpServiceKeyIdExtractor.AutocryptState;
import org.sufficientlysecure.keychain.remote.OpenPgpServiceKeyIdExtractor.KeyIdResult; import org.sufficientlysecure.keychain.remote.OpenPgpServiceKeyIdExtractor.KeyIdResult;
import org.sufficientlysecure.keychain.remote.OpenPgpServiceKeyIdExtractor.KeyIdResultStatus; import org.sufficientlysecure.keychain.remote.OpenPgpServiceKeyIdExtractor.KeyIdResultStatus;
import org.sufficientlysecure.keychain.service.BackupKeyringParcel; import org.sufficientlysecure.keychain.service.BackupKeyringParcel;
@@ -306,24 +307,27 @@ public class OpenPgpService extends Service {
Intent result = new Intent(); Intent result = new Intent();
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
switch (keyIdResult.getStatus()) { AutocryptState combinedAutocryptState = keyIdResult.getCombinedAutocryptState();
case MISSING: { if (combinedAutocryptState == null) {
result.putExtra(OpenPgpApi.RESULT_AUTOCRYPT_STATUS, OpenPgpApi.AUTOCRYPT_STATUS_UNAVAILABLE); result.putExtra(OpenPgpApi.RESULT_AUTOCRYPT_STATUS, OpenPgpApi.AUTOCRYPT_STATUS_UNAVAILABLE);
break; return result;
}
case NO_KEYS: }
case NO_KEYS_ERROR: {
result.putExtra(OpenPgpApi.RESULT_AUTOCRYPT_STATUS, OpenPgpApi.AUTOCRYPT_STATUS_UNAVAILABLE); switch (combinedAutocryptState) {
break; case GOSSIP:
} case RESET: {
case DUPLICATE: {
result.putExtra(OpenPgpApi.RESULT_AUTOCRYPT_STATUS, OpenPgpApi.AUTOCRYPT_STATUS_DISCOURAGE); result.putExtra(OpenPgpApi.RESULT_AUTOCRYPT_STATUS, OpenPgpApi.AUTOCRYPT_STATUS_DISCOURAGE);
break; break;
} }
case OK: { case AVAILABLE: {
result.putExtra(OpenPgpApi.RESULT_AUTOCRYPT_STATUS, OpenPgpApi.AUTOCRYPT_STATUS_AVAILABLE); result.putExtra(OpenPgpApi.RESULT_AUTOCRYPT_STATUS, OpenPgpApi.AUTOCRYPT_STATUS_AVAILABLE);
break; break;
} }
case MUTUAL: {
result.putExtra(OpenPgpApi.RESULT_AUTOCRYPT_STATUS, OpenPgpApi.AUTOCRYPT_STATUS_RECOMMEND);
break;
}
default: { default: {
throw new IllegalStateException("unhandled case!"); throw new IllegalStateException("unhandled case!");
} }

View File

@@ -15,7 +15,7 @@ import android.support.annotation.VisibleForTesting;
import org.openintents.openpgp.util.OpenPgpApi; import org.openintents.openpgp.util.OpenPgpApi;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.provider.KeychainExternalContract; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAutocryptPeer;
import org.sufficientlysecure.keychain.provider.KeychainExternalContract.EmailStatus; import org.sufficientlysecure.keychain.provider.KeychainExternalContract.EmailStatus;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
@@ -65,7 +65,7 @@ class OpenPgpServiceKeyIdExtractor {
for (long keyId : data.getLongArrayExtra(OpenPgpApi.EXTRA_KEY_IDS_SELECTED)) { for (long keyId : data.getLongArrayExtra(OpenPgpApi.EXTRA_KEY_IDS_SELECTED)) {
encryptKeyIds.add(keyId); encryptKeyIds.add(keyId);
} }
result = createKeysOkResult(encryptKeyIds, false); result = createKeysOkResult(encryptKeyIds, false, null);
} else if (data.hasExtra(OpenPgpApi.EXTRA_USER_IDS) || askIfNoUserIdsProvided) { } else if (data.hasExtra(OpenPgpApi.EXTRA_USER_IDS) || askIfNoUserIdsProvided) {
String[] userIds = data.getStringArrayExtra(OpenPgpApi.EXTRA_USER_IDS); String[] userIds = data.getStringArrayExtra(OpenPgpApi.EXTRA_USER_IDS);
result = returnKeyIdsFromEmails(data, userIds, callingPackageName); result = returnKeyIdsFromEmails(data, userIds, callingPackageName);
@@ -92,6 +92,7 @@ class OpenPgpServiceKeyIdExtractor {
HashSet<Long> keyIds = new HashSet<>(); 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<>();
AutocryptState combinedAutocryptState = null;
if (hasAddresses) { if (hasAddresses) {
HashMap<String, AddressQueryResult> userIdEntries = getStatusMapForQueriedAddresses( HashMap<String, AddressQueryResult> userIdEntries = getStatusMapForQueriedAddresses(
@@ -104,20 +105,37 @@ class OpenPgpServiceKeyIdExtractor {
throw new IllegalStateException("No result for address - shouldn't happen!"); throw new IllegalStateException("No result for address - shouldn't happen!");
} }
if (addressQueryResult.autocryptMasterKeyId != null) {
keyIds.add(addressQueryResult.autocryptMasterKeyId);
if (addressQueryResult.autocryptKeyStatus != EmailStatus.KEY_STATUS_VERIFIED) {
anyKeyNotVerified = true;
}
if (combinedAutocryptState == null) {
combinedAutocryptState = addressQueryResult.autocryptState;
} else {
combinedAutocryptState = combinedAutocryptState.combineWith(addressQueryResult.autocryptState);
}
continue;
}
if (addressQueryResult.uidMasterKeyId != null) { if (addressQueryResult.uidMasterKeyId != null) {
keyIds.add(addressQueryResult.uidMasterKeyId); keyIds.add(addressQueryResult.uidMasterKeyId);
if (addressQueryResult.uidHasMultipleCandidates) { if (addressQueryResult.uidHasMultipleCandidates) {
duplicateEmails.add(queriedAddress); duplicateEmails.add(queriedAddress);
} }
} else {
missingEmails.add(queriedAddress); if (addressQueryResult.uidKeyStatus != EmailStatus.KEY_STATUS_VERIFIED) {
anyKeyNotVerified = true;
}
continue; continue;
} }
if (addressQueryResult.uidKeyStatus != EmailStatus.KEY_STATUS_VERIFIED) { missingEmails.add(queriedAddress);
anyKeyNotVerified = true;
}
} }
if (userIdEntries.size() != encryptionAddresses.length) { if (userIdEntries.size() != encryptionAddresses.length) {
@@ -139,7 +157,7 @@ class OpenPgpServiceKeyIdExtractor {
return createNoKeysResult(data, keyIds, missingEmails, duplicateEmails); return createNoKeysResult(data, keyIds, missingEmails, duplicateEmails);
} }
return createKeysOkResult(keyIds, allKeysConfirmed); return createKeysOkResult(keyIds, allKeysConfirmed, combinedAutocryptState);
} }
/** This method queries the KeychainExternalProvider for all addresses given in encryptionUserIds. /** This method queries the KeychainExternalProvider for all addresses given in encryptionUserIds.
@@ -169,9 +187,9 @@ class OpenPgpServiceKeyIdExtractor {
int autocryptKeyStatus = cursor.getInt(INDEX_AUTOCRYPT_KEY_STATUS); int autocryptKeyStatus = cursor.getInt(INDEX_AUTOCRYPT_KEY_STATUS);
int autocryptPeerStatus = cursor.getInt(INDEX_AUTOCRYPT_PEER_STATE); int autocryptPeerStatus = cursor.getInt(INDEX_AUTOCRYPT_PEER_STATE);
AddressQueryResult AddressQueryResult status = new AddressQueryResult(
status = new AddressQueryResult(uidMasterKeyId, uidKeyStatus, uidHasMultipleCandidates, uidMasterKeyId, uidKeyStatus, uidHasMultipleCandidates, autocryptMasterKeyId,
autocryptMasterKeyId, autocryptKeyStatus, autocryptPeerStatus); autocryptKeyStatus, AutocryptState.fromDbValue(autocryptPeerStatus));
keyRows.put(queryAddress, status); keyRows.put(queryAddress, status);
} }
@@ -187,11 +205,10 @@ class OpenPgpServiceKeyIdExtractor {
private boolean uidHasMultipleCandidates; private boolean uidHasMultipleCandidates;
private final Long autocryptMasterKeyId; private final Long autocryptMasterKeyId;
private final int autocryptKeyStatus; private final int autocryptKeyStatus;
private final int autocryptState; private final AutocryptState autocryptState;
AddressQueryResult(Long uidMasterKeyId, int uidKeyStatus, boolean uidHasMultipleCandidates, Long autocryptMasterKeyId, AddressQueryResult(Long uidMasterKeyId, int uidKeyStatus, boolean uidHasMultipleCandidates, Long autocryptMasterKeyId,
int autocryptKeyStatus, int autocryptKeyStatus, AutocryptState autocryptState) {
int autocryptState) {
this.uidMasterKeyId = uidMasterKeyId; this.uidMasterKeyId = uidMasterKeyId;
this.uidKeyStatus = uidKeyStatus; this.uidKeyStatus = uidKeyStatus;
this.uidHasMultipleCandidates = uidHasMultipleCandidates; this.uidHasMultipleCandidates = uidHasMultipleCandidates;
@@ -202,7 +219,38 @@ class OpenPgpServiceKeyIdExtractor {
} }
enum AutocryptState { enum AutocryptState {
UNAVAILABLE, DISCOURAGE, AVAILABLE, MUTUAL RESET, GOSSIP, AVAILABLE, MUTUAL;
static AutocryptState fromDbValue(int state) {
switch (state) {
case ApiAutocryptPeer.RESET:
return RESET;
case ApiAutocryptPeer.AVAILABLE:
return AVAILABLE;
case ApiAutocryptPeer.GOSSIP:
return GOSSIP;
case ApiAutocryptPeer.MUTUAL:
return MUTUAL;
default:
throw new IllegalStateException();
}
}
public AutocryptState combineWith(AutocryptState other) {
if (this == RESET || other == RESET) {
return RESET;
}
if (this == GOSSIP || other == GOSSIP) {
return GOSSIP;
}
if (this == AVAILABLE || other == AVAILABLE) {
return AVAILABLE;
}
if (this == MUTUAL && other == MUTUAL) {
return MUTUAL;
}
throw new IllegalStateException("Bug: autocrypt states can't be combined!");
}
} }
static class KeyIdResult { static class KeyIdResult {
@@ -211,6 +259,7 @@ class OpenPgpServiceKeyIdExtractor {
private final HashSet<Long> mExplicitKeyIds; private final HashSet<Long> mExplicitKeyIds;
private final KeyIdResultStatus mStatus; private final KeyIdResultStatus mStatus;
private final boolean mAllKeysConfirmed; private final boolean mAllKeysConfirmed;
private final AutocryptState mCombinedAutocryptState;
private KeyIdResult(PendingIntent keySelectionPendingIntent, KeyIdResultStatus keyIdResultStatus) { private KeyIdResult(PendingIntent keySelectionPendingIntent, KeyIdResultStatus keyIdResultStatus) {
mKeySelectionPendingIntent = keySelectionPendingIntent; mKeySelectionPendingIntent = keySelectionPendingIntent;
@@ -218,13 +267,17 @@ class OpenPgpServiceKeyIdExtractor {
mAllKeysConfirmed = false; mAllKeysConfirmed = false;
mStatus = keyIdResultStatus; mStatus = keyIdResultStatus;
mExplicitKeyIds = null; mExplicitKeyIds = null;
mCombinedAutocryptState = null;
} }
private KeyIdResult(HashSet<Long> keyIds, boolean allKeysConfirmed, KeyIdResultStatus keyIdResultStatus) {
private KeyIdResult(HashSet<Long> keyIds, boolean allKeysConfirmed, KeyIdResultStatus keyIdResultStatus,
AutocryptState combinedAutocryptState) {
mKeySelectionPendingIntent = null; mKeySelectionPendingIntent = null;
mUserKeyIds = keyIds; mUserKeyIds = keyIds;
mAllKeysConfirmed = allKeysConfirmed; mAllKeysConfirmed = allKeysConfirmed;
mStatus = keyIdResultStatus; mStatus = keyIdResultStatus;
mExplicitKeyIds = null; mExplicitKeyIds = null;
mCombinedAutocryptState = combinedAutocryptState;
} }
private KeyIdResult(KeyIdResult keyIdResult, HashSet<Long> explicitKeyIds) { private KeyIdResult(KeyIdResult keyIdResult, HashSet<Long> explicitKeyIds) {
@@ -233,6 +286,7 @@ class OpenPgpServiceKeyIdExtractor {
mAllKeysConfirmed = keyIdResult.mAllKeysConfirmed; mAllKeysConfirmed = keyIdResult.mAllKeysConfirmed;
mStatus = keyIdResult.mStatus; mStatus = keyIdResult.mStatus;
mExplicitKeyIds = explicitKeyIds; mExplicitKeyIds = explicitKeyIds;
mCombinedAutocryptState = keyIdResult.mCombinedAutocryptState;
} }
boolean hasKeySelectionPendingIntent() { boolean hasKeySelectionPendingIntent() {
@@ -274,14 +328,19 @@ class OpenPgpServiceKeyIdExtractor {
KeyIdResultStatus getStatus() { KeyIdResultStatus getStatus() {
return mStatus; return mStatus;
} }
public AutocryptState getCombinedAutocryptState() {
return mCombinedAutocryptState;
}
} }
enum KeyIdResultStatus { enum KeyIdResultStatus {
OK, MISSING, DUPLICATE, NO_KEYS, NO_KEYS_ERROR OK, MISSING, DUPLICATE, NO_KEYS, NO_KEYS_ERROR
} }
private KeyIdResult createKeysOkResult(HashSet<Long> encryptKeyIds, boolean allKeysConfirmed) { private KeyIdResult createKeysOkResult(HashSet<Long> encryptKeyIds, boolean allKeysConfirmed,
return new KeyIdResult(encryptKeyIds, allKeysConfirmed, KeyIdResultStatus.OK); AutocryptState combinedAutocryptState) {
return new KeyIdResult(encryptKeyIds, allKeysConfirmed, KeyIdResultStatus.OK, combinedAutocryptState);
} }
private KeyIdResult createNoKeysResult(Intent data, private KeyIdResult createNoKeysResult(Intent data,