Merge pull request #2296 from open-keychain/last-update-fixes

Last update fixes
This commit is contained in:
Dominik Schürmann
2018-03-13 08:53:58 +01:00
committed by GitHub
8 changed files with 116 additions and 62 deletions

View File

@@ -41,6 +41,7 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException; import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.provider.KeyWritableRepository; import org.sufficientlysecure.keychain.provider.KeyWritableRepository;
import org.sufficientlysecure.keychain.provider.LastUpdateInteractor;
import org.sufficientlysecure.keychain.service.CertifyActionsParcel; import org.sufficientlysecure.keychain.service.CertifyActionsParcel;
import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction; import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
import org.sufficientlysecure.keychain.service.ContactSyncAdapterService; import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
@@ -61,10 +62,13 @@ import org.sufficientlysecure.keychain.util.Passphrase;
* @see CertifyActionsParcel * @see CertifyActionsParcel
*/ */
public class CertifyOperation extends BaseReadWriteOperation<CertifyActionsParcel> { public class CertifyOperation extends BaseReadWriteOperation<CertifyActionsParcel> {
private final LastUpdateInteractor lastUpdateInteractor;
public CertifyOperation(Context context, KeyWritableRepository databaseInteractor, Progressable progressable, AtomicBoolean public CertifyOperation(Context context, KeyWritableRepository databaseInteractor, Progressable progressable, AtomicBoolean
cancelled) { cancelled) {
super(context, databaseInteractor, progressable, cancelled); super(context, databaseInteractor, progressable, cancelled);
this.lastUpdateInteractor = LastUpdateInteractor.create(context);
} }
@NonNull @NonNull
@@ -230,6 +234,8 @@ public class CertifyOperation extends BaseReadWriteOperation<CertifyActionsParce
log.add(uploadResult, 2); log.add(uploadResult, 2);
if (uploadResult.success()) { if (uploadResult.success()) {
lastUpdateInteractor.renewKeyLastUpdatedTime(certifiedKey.getMasterKeyId(), true);
uploadOk += 1; uploadOk += 1;
} else { } else {
uploadError += 1; uploadError += 1;

View File

@@ -37,6 +37,7 @@ import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException; import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.provider.KeyWritableRepository; import org.sufficientlysecure.keychain.provider.KeyWritableRepository;
import org.sufficientlysecure.keychain.provider.LastUpdateInteractor;
import org.sufficientlysecure.keychain.service.ContactSyncAdapterService; import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.service.UploadKeyringParcel; import org.sufficientlysecure.keychain.service.UploadKeyringParcel;
@@ -56,10 +57,14 @@ import org.sufficientlysecure.keychain.util.ProgressScaler;
* *
*/ */
public class EditKeyOperation extends BaseReadWriteOperation<SaveKeyringParcel> { public class EditKeyOperation extends BaseReadWriteOperation<SaveKeyringParcel> {
private final LastUpdateInteractor lastUpdateInteractor;
public EditKeyOperation(Context context, KeyWritableRepository databaseInteractor, public EditKeyOperation(Context context, KeyWritableRepository databaseInteractor,
Progressable progressable, AtomicBoolean cancelled) { Progressable progressable, AtomicBoolean cancelled) {
super(context, databaseInteractor, progressable, cancelled); super(context, databaseInteractor, progressable, cancelled);
this.lastUpdateInteractor = LastUpdateInteractor.create(context);
} }
/** /**
@@ -167,7 +172,7 @@ public class EditKeyOperation extends BaseReadWriteOperation<SaveKeyringParcel>
log.add(saveResult, 1); log.add(saveResult, 1);
if (isNewKey) { if (isNewKey) {
mKeyWritableRepository.renewKeyLastUpdatedTime(ring.getMasterKeyId(), saveParcel.isShouldUpload()); lastUpdateInteractor.renewKeyLastUpdatedTime(ring.getMasterKeyId(), saveParcel.isShouldUpload());
} }
// If the save operation didn't succeed, exit here // If the save operation didn't succeed, exit here

View File

@@ -55,6 +55,7 @@ import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeyWritableRepository; import org.sufficientlysecure.keychain.provider.KeyWritableRepository;
import org.sufficientlysecure.keychain.provider.LastUpdateInteractor;
import org.sufficientlysecure.keychain.service.ContactSyncAdapterService; import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel; import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
@@ -88,16 +89,23 @@ public class ImportOperation extends BaseReadWriteOperation<ImportKeyringParcel>
private static final int MAX_THREADS = 10; private static final int MAX_THREADS = 10;
public static final String CACHE_FILE_NAME = "key_import.pcl"; public static final String CACHE_FILE_NAME = "key_import.pcl";
private final LastUpdateInteractor lastUpdateInteractor;
private FacebookKeyserverClient facebookServer; private FacebookKeyserverClient facebookServer;
private KeybaseKeyserverClient keybaseServer; private KeybaseKeyserverClient keybaseServer;
public ImportOperation(Context context, KeyWritableRepository databaseInteractor, Progressable progressable) { public ImportOperation(Context context, KeyWritableRepository databaseInteractor, Progressable progressable) {
super(context, databaseInteractor, progressable); super(context, databaseInteractor, progressable);
this.lastUpdateInteractor = LastUpdateInteractor.create(context);
} }
public ImportOperation(Context context, KeyWritableRepository databaseInteractor, public ImportOperation(Context context, KeyWritableRepository databaseInteractor,
Progressable progressable, AtomicBoolean cancelled) { Progressable progressable, AtomicBoolean cancelled) {
super(context, databaseInteractor, progressable, cancelled); super(context, databaseInteractor, progressable, cancelled);
this.lastUpdateInteractor = LastUpdateInteractor.create(context);
} }
// Overloaded functions for using progressable supplied in constructor during import // Overloaded functions for using progressable supplied in constructor during import
@@ -192,7 +200,7 @@ public class ImportOperation extends BaseReadWriteOperation<ImportKeyringParcel>
byte[] fingerprintHex = entry.getExpectedFingerprint(); byte[] fingerprintHex = entry.getExpectedFingerprint();
if (fingerprintHex != null) { if (fingerprintHex != null) {
mKeyWritableRepository.renewKeyLastUpdatedTime( lastUpdateInteractor.renewKeyLastUpdatedTime(
KeyFormattingUtils.getKeyIdFromFingerprint(fingerprintHex), false); KeyFormattingUtils.getKeyIdFromFingerprint(fingerprintHex), false);
} }
continue; continue;
@@ -242,7 +250,7 @@ public class ImportOperation extends BaseReadWriteOperation<ImportKeyringParcel>
} }
if (!skipSave) { if (!skipSave) {
mKeyWritableRepository.renewKeyLastUpdatedTime(key.getMasterKeyId(), keyWasDownloaded); lastUpdateInteractor.renewKeyLastUpdatedTime(key.getMasterKeyId(), keyWasDownloaded);
} }
} }

View File

@@ -304,32 +304,6 @@ public class KeyRepository {
return lastUpdateTime; return lastUpdateTime;
} }
@Nullable
Boolean getSeenOnKeyservers(long masterKeyId) {
Cursor cursor = mContentResolver.query(
UpdatedKeys.CONTENT_URI,
new String[] { UpdatedKeys.SEEN_ON_KEYSERVERS },
UpdatedKeys.MASTER_KEY_ID + " = ?",
new String[] { "" + masterKeyId },
null
);
if (cursor == null) {
return null;
}
Boolean seenOnKeyservers;
try {
if (!cursor.moveToNext()) {
return null;
}
seenOnKeyservers = cursor.isNull(0) ? null : cursor.getInt(0) != 0;
} finally {
cursor.close();
}
return seenOnKeyservers;
}
public final byte[] loadPublicKeyRingData(long masterKeyId) throws NotFoundException { public final byte[] loadPublicKeyRingData(long masterKeyId) throws NotFoundException {
byte[] data = (byte[]) getGenericDataOrNull(KeyRingData.buildPublicKeyRingUri(masterKeyId), byte[] data = (byte[]) getGenericDataOrNull(KeyRingData.buildPublicKeyRingUri(masterKeyId),
KeyRingData.KEY_RING_DATA, FIELD_TYPE_BLOB); KeyRingData.KEY_RING_DATA, FIELD_TYPE_BLOB);

View File

@@ -23,7 +23,6 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List; import java.util.List;
import android.content.ContentProviderOperation; import android.content.ContentProviderOperation;
@@ -85,23 +84,27 @@ public class KeyWritableRepository extends KeyRepository {
private static final int MAX_CACHED_KEY_SIZE = 1024 * 50; private static final int MAX_CACHED_KEY_SIZE = 1024 * 50;
private final Context mContext; private final Context mContext;
private final LastUpdateInteractor lastUpdateInteractor;
public static KeyWritableRepository create(Context context) { public static KeyWritableRepository create(Context context) {
LocalPublicKeyStorage localPublicKeyStorage = LocalPublicKeyStorage.getInstance(context); LocalPublicKeyStorage localPublicKeyStorage = LocalPublicKeyStorage.getInstance(context);
LastUpdateInteractor lastUpdateInteractor = LastUpdateInteractor.create(context);
return new KeyWritableRepository(context, localPublicKeyStorage); return new KeyWritableRepository(context, localPublicKeyStorage, lastUpdateInteractor);
} }
@VisibleForTesting @VisibleForTesting
KeyWritableRepository(Context context, LocalPublicKeyStorage localPublicKeyStorage) { KeyWritableRepository(Context context, LocalPublicKeyStorage localPublicKeyStorage,
this(context, localPublicKeyStorage, new OperationLog(), 0); LastUpdateInteractor lastUpdateInteractor) {
this(context, localPublicKeyStorage, lastUpdateInteractor, new OperationLog(), 0);
} }
private KeyWritableRepository( private KeyWritableRepository(Context context, LocalPublicKeyStorage localPublicKeyStorage,
Context context, LocalPublicKeyStorage localPublicKeyStorage, OperationLog log, int indent) { LastUpdateInteractor lastUpdateInteractor, OperationLog log, int indent) {
super(context.getContentResolver(), localPublicKeyStorage, log, indent); super(context.getContentResolver(), localPublicKeyStorage, log, indent);
mContext = context; mContext = context;
this.lastUpdateInteractor = lastUpdateInteractor;
} }
private LongSparseArray<CanonicalizedPublicKey> getTrustedMasterKeys() { private LongSparseArray<CanonicalizedPublicKey> getTrustedMasterKeys() {
@@ -560,9 +563,14 @@ public class KeyWritableRepository extends KeyRepository {
return null; return null;
} }
Boolean seenOnKeyservers = lastUpdateInteractor.getSeenOnKeyservers(masterKeyId);
ContentValues lastUpdatedEntry = new ContentValues(2); ContentValues lastUpdatedEntry = new ContentValues(2);
lastUpdatedEntry.put(UpdatedKeys.MASTER_KEY_ID, masterKeyId); lastUpdatedEntry.put(UpdatedKeys.MASTER_KEY_ID, masterKeyId);
lastUpdatedEntry.put(UpdatedKeys.LAST_UPDATED, lastUpdateTime); lastUpdatedEntry.put(UpdatedKeys.LAST_UPDATED, lastUpdateTime);
if (seenOnKeyservers != null){
lastUpdatedEntry.put(UpdatedKeys.SEEN_ON_KEYSERVERS, seenOnKeyservers);
}
return ContentProviderOperation return ContentProviderOperation
.newInsert(UpdatedKeys.CONTENT_URI) .newInsert(UpdatedKeys.CONTENT_URI)
.withValues(lastUpdatedEntry) .withValues(lastUpdatedEntry)
@@ -1126,26 +1134,4 @@ public class KeyWritableRepository extends KeyRepository {
return ContentProviderOperation.newInsert(uri).withValues(values).build(); return ContentProviderOperation.newInsert(uri).withValues(values).build();
} }
public Uri renewKeyLastUpdatedTime(long masterKeyId, boolean seenOnKeyservers) {
boolean isFirstKeyserverStatusCheck = getSeenOnKeyservers(masterKeyId) == null;
ContentValues values = new ContentValues();
values.put(UpdatedKeys.MASTER_KEY_ID, masterKeyId);
values.put(UpdatedKeys.LAST_UPDATED, GregorianCalendar.getInstance().getTimeInMillis() / 1000);
if (seenOnKeyservers || isFirstKeyserverStatusCheck) {
values.put(UpdatedKeys.SEEN_ON_KEYSERVERS, seenOnKeyservers);
}
// this will actually update/replace, doing the right thing™ for seenOnKeyservers value
// see `KeychainProvider.insert()`
return mContentResolver.insert(UpdatedKeys.CONTENT_URI, values);
}
public void resetAllLastUpdatedTimes() {
ContentValues values = new ContentValues();
values.putNull(UpdatedKeys.LAST_UPDATED);
values.putNull(UpdatedKeys.SEEN_ON_KEYSERVERS);
mContentResolver.update(UpdatedKeys.CONTENT_URI, values, null, null);
}
} }

View File

@@ -0,0 +1,74 @@
package org.sufficientlysecure.keychain.provider;
import java.util.GregorianCalendar;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.support.annotation.Nullable;
import org.sufficientlysecure.keychain.provider.KeychainContract.UpdatedKeys;
public class LastUpdateInteractor {
private final ContentResolver contentResolver;
public static LastUpdateInteractor create(Context context) {
return new LastUpdateInteractor(context.getContentResolver());
}
private LastUpdateInteractor(ContentResolver contentResolver) {
this.contentResolver = contentResolver;
}
@Nullable
public Boolean getSeenOnKeyservers(long masterKeyId) {
Cursor cursor = contentResolver.query(
UpdatedKeys.CONTENT_URI,
new String[] { UpdatedKeys.SEEN_ON_KEYSERVERS },
UpdatedKeys.MASTER_KEY_ID + " = ?",
new String[] { "" + masterKeyId },
null
);
if (cursor == null) {
return null;
}
Boolean seenOnKeyservers;
try {
if (!cursor.moveToNext()) {
return null;
}
seenOnKeyservers = cursor.isNull(0) ? null : cursor.getInt(0) != 0;
} finally {
cursor.close();
}
return seenOnKeyservers;
}
public void resetAllLastUpdatedTimes() {
ContentValues values = new ContentValues();
values.putNull(UpdatedKeys.LAST_UPDATED);
values.putNull(UpdatedKeys.SEEN_ON_KEYSERVERS);
contentResolver.update(UpdatedKeys.CONTENT_URI, values, null, null);
}
public Uri renewKeyLastUpdatedTime(long masterKeyId, boolean seenOnKeyservers) {
boolean isFirstKeyserverStatusCheck = getSeenOnKeyservers(masterKeyId) == null;
ContentValues values = new ContentValues();
values.put(UpdatedKeys.MASTER_KEY_ID, masterKeyId);
values.put(UpdatedKeys.LAST_UPDATED, GregorianCalendar.getInstance().getTimeInMillis() / 1000);
if (seenOnKeyservers || isFirstKeyserverStatusCheck) {
values.put(UpdatedKeys.SEEN_ON_KEYSERVERS, seenOnKeyservers);
}
// this will actually update/replace, doing the right thing™ for seenOnKeyservers value
// see `KeychainProvider.insert()`
return contentResolver.insert(UpdatedKeys.CONTENT_URI, values);
}
}

View File

@@ -43,7 +43,7 @@ import android.widget.TextView;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress; import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress;
import org.sufficientlysecure.keychain.provider.KeyWritableRepository; import org.sufficientlysecure.keychain.provider.LastUpdateInteractor;
import org.sufficientlysecure.keychain.ui.dialog.AddEditKeyserverDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.AddEditKeyserverDialogFragment;
import org.sufficientlysecure.keychain.ui.util.FormattingUtils; import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify;
@@ -63,7 +63,7 @@ public class SettingsKeyserverFragment extends Fragment implements RecyclerItemC
private List<HkpKeyserverAddress> mKeyservers; private List<HkpKeyserverAddress> mKeyservers;
private KeyserverListAdapter mAdapter; private KeyserverListAdapter mAdapter;
private KeyWritableRepository databaseReadWriteInteractor; private LastUpdateInteractor lastUpdateInteractor;
public static SettingsKeyserverFragment newInstance(ArrayList<HkpKeyserverAddress> keyservers) { public static SettingsKeyserverFragment newInstance(ArrayList<HkpKeyserverAddress> keyservers) {
Bundle args = new Bundle(); Bundle args = new Bundle();
@@ -78,7 +78,7 @@ public class SettingsKeyserverFragment extends Fragment implements RecyclerItemC
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) { savedInstanceState) {
databaseReadWriteInteractor = KeyWritableRepository.create(getContext()); lastUpdateInteractor = LastUpdateInteractor.create(getContext());
return inflater.inflate(R.layout.settings_keyserver_fragment, null); return inflater.inflate(R.layout.settings_keyserver_fragment, null);
} }
@@ -230,7 +230,7 @@ public class SettingsKeyserverFragment extends Fragment implements RecyclerItemC
Preferences.getPreferences(getActivity()).setKeyServers(mKeyserversMutable); Preferences.getPreferences(getActivity()).setKeyServers(mKeyserversMutable);
mKeyservers = Collections.unmodifiableList(new ArrayList<>(mKeyserversMutable)); mKeyservers = Collections.unmodifiableList(new ArrayList<>(mKeyserversMutable));
databaseReadWriteInteractor.resetAllLastUpdatedTimes(); lastUpdateInteractor.resetAllLastUpdatedTimes();
} }
@Override @Override

View File

@@ -243,7 +243,8 @@ public class InteropTest {
KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(verify.getMasterKeyId()) : null; KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(verify.getMasterKeyId()) : null;
KeyWritableRepository helper = new KeyWritableRepository(RuntimeEnvironment.application, KeyWritableRepository helper = new KeyWritableRepository(RuntimeEnvironment.application,
LocalPublicKeyStorage.getInstance(RuntimeEnvironment.application)) { LocalPublicKeyStorage.getInstance(RuntimeEnvironment.application),
LastUpdateInteractor.create(RuntimeEnvironment.application)) {
@Override @Override
public CachedPublicKeyRing getCachedPublicKeyRing(Uri queryUri) throws PgpKeyNotFoundException { public CachedPublicKeyRing getCachedPublicKeyRing(Uri queryUri) throws PgpKeyNotFoundException {