diff options
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java')
-rw-r--r-- | OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java | 97 |
1 files changed, 90 insertions, 7 deletions
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 0c37bfc2a..a6823d3ac 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -32,10 +32,15 @@ import android.support.v4.util.LongSparseArray; import org.spongycastle.bcpg.CompressionAlgorithmTags; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; +import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; +import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize; +import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.operations.ImportOperation; import org.sufficientlysecure.keychain.operations.results.ConsolidateResult; -import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; @@ -50,7 +55,6 @@ import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.UncachedPublicKey; import org.sufficientlysecure.keychain.pgp.WrappedSignature; -import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAllowedKeys; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps; @@ -59,14 +63,12 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; +import org.sufficientlysecure.keychain.provider.KeychainContract.UpdatedKeys; import org.sufficientlysecure.keychain.remote.AccountSettings; import org.sufficientlysecure.keychain.remote.AppSettings; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ParcelableFileCache; -import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize; -import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.util.ProgressFixedScaler; import org.sufficientlysecure.keychain.util.ProgressScaler; import org.sufficientlysecure.keychain.util.Utf8Util; @@ -82,6 +84,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.concurrent.TimeUnit; /** * This class contains high level methods for database access. Despite its @@ -685,6 +688,36 @@ public class ProviderHelper { mIndent -= 1; } + // before deleting key, retrieve it's last updated time + final int INDEX_MASTER_KEY_ID = 0; + final int INDEX_LAST_UPDATED = 1; + Cursor lastUpdatedCursor = mContentResolver.query( + UpdatedKeys.CONTENT_URI, + new String[]{ + UpdatedKeys.MASTER_KEY_ID, + UpdatedKeys.LAST_UPDATED + }, + UpdatedKeys.MASTER_KEY_ID + " = ?", + new String[]{"" + masterKeyId}, + null + ); + if (lastUpdatedCursor.moveToNext()) { + // there was an entry to re-insert + // this operation must happen after the new key is inserted + ContentValues lastUpdatedEntry = new ContentValues(2); + lastUpdatedEntry.put(UpdatedKeys.MASTER_KEY_ID, + lastUpdatedCursor.getLong(INDEX_MASTER_KEY_ID)); + lastUpdatedEntry.put(UpdatedKeys.LAST_UPDATED, + lastUpdatedCursor.getLong(INDEX_LAST_UPDATED)); + operations.add( + ContentProviderOperation + .newInsert(UpdatedKeys.CONTENT_URI) + .withValues(lastUpdatedEntry) + .build() + ); + } + lastUpdatedCursor.close(); + try { // delete old version of this keyRing, which also deletes all keys and userIds on cascade int deleted = mContentResolver.delete( @@ -738,6 +771,11 @@ public class ProviderHelper { if (type != o.type) { return type == null ? -1 : 1; } + // if one is *trusted* but the other isn't, that one comes first + // this overrides the primary attribute, even! + if ( (trustedCerts.size() == 0) != (o.trustedCerts.size() == 0) ) { + return trustedCerts.size() > o.trustedCerts.size() ? -1 : 1; + } // if one key is primary but the other isn't, the primary one always comes first if (isPrimary != o.isPrimary) { return isPrimary ? -1 : 1; @@ -845,7 +883,7 @@ public class ProviderHelper { } public SaveKeyringResult savePublicKeyRing(UncachedKeyRing keyRing) { - return savePublicKeyRing(keyRing, new ProgressScaler()); + return savePublicKeyRing(keyRing, new ProgressScaler(), null); } /** @@ -854,7 +892,7 @@ public class ProviderHelper { * This is a high level method, which takes care of merging all new information into the old and * keep public and secret keyrings in sync. */ - public SaveKeyringResult savePublicKeyRing(UncachedKeyRing publicRing, Progressable progress) { + public SaveKeyringResult savePublicKeyRing(UncachedKeyRing publicRing, Progressable progress, String expectedFingerprint) { try { long masterKeyId = publicRing.getMasterKeyId(); @@ -927,6 +965,17 @@ public class ProviderHelper { canSecretRing = null; } + + // If we have an expected fingerprint, make sure it matches + if (expectedFingerprint != null) { + if (!canPublicRing.containsSubkey(expectedFingerprint)) { + log(LogType.MSG_IP_FINGERPRINT_ERROR); + return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); + } else { + log(LogType.MSG_IP_FINGERPRINT_OK); + } + } + int result = saveCanonicalizedPublicKeyRing(canPublicRing, progress, canSecretRing != null); // Save the saved keyring (if any) @@ -1239,6 +1288,28 @@ public class ProviderHelper { } // 2. wipe database (IT'S DANGEROUS) + + // first, backup our list of updated key times + ArrayList<ContentValues> updatedKeysValues = new ArrayList<>(); + final int INDEX_MASTER_KEY_ID = 0; + final int INDEX_LAST_UPDATED = 1; + Cursor lastUpdatedCursor = mContentResolver.query( + UpdatedKeys.CONTENT_URI, + new String[]{ + UpdatedKeys.MASTER_KEY_ID, + UpdatedKeys.LAST_UPDATED + }, + null, null, null); + while (lastUpdatedCursor.moveToNext()) { + ContentValues values = new ContentValues(); + values.put(UpdatedKeys.MASTER_KEY_ID, + lastUpdatedCursor.getLong(INDEX_MASTER_KEY_ID)); + values.put(UpdatedKeys.LAST_UPDATED, + lastUpdatedCursor.getLong(INDEX_LAST_UPDATED)); + updatedKeysValues.add(values); + } + lastUpdatedCursor.close(); + log.add(LogType.MSG_CON_DB_CLEAR, indent); mContentResolver.delete(KeyRings.buildUnifiedKeyRingsUri(), null, null); @@ -1288,6 +1359,10 @@ public class ProviderHelper { new ProgressFixedScaler(progress, 25, 99, 100, R.string.progress_con_reimport)) .serialKeyRingImport(itPublics, numPublics, null, null); log.add(result, indent); + // re-insert our backed up list of updated key times + // TODO: can this cause issues in case a public key re-import failed? + mContentResolver.bulkInsert(UpdatedKeys.CONTENT_URI, + updatedKeysValues.toArray(new ContentValues[updatedKeysValues.size()])); } else { log.add(LogType.MSG_CON_REIMPORT_PUBLIC_SKIP, indent); } @@ -1397,6 +1472,14 @@ public class ProviderHelper { return getKeyRingAsArmoredString(data); } + public Uri renewKeyLastUpdatedTime(long masterKeyId, long time, TimeUnit timeUnit) { + ContentValues values = new ContentValues(); + values.put(UpdatedKeys.MASTER_KEY_ID, masterKeyId); + values.put(UpdatedKeys.LAST_UPDATED, timeUnit.toSeconds(time)); + + return mContentResolver.insert(UpdatedKeys.CONTENT_URI, values); + } + public ArrayList<String> getRegisteredApiApps() { Cursor cursor = mContentResolver.query(ApiApps.CONTENT_URI, null, null, null, null); |