From 3824e90997f0c6ac7c96f7469d3fc0dc9cf4b3a4 Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Wed, 19 Feb 2020 14:16:31 -0500 Subject: [PATCH] Improve prekey refresh logic. --- .../securesms/ApplicationContext.java | 2 ++ .../securesms/jobs/RefreshPreKeysJob.java | 30 +++++++++++++++++-- .../securesms/jobs/RotateSignedPreKeyJob.java | 6 +++- .../securesms/keyvalue/SignalStore.java | 8 +++++ 4 files changed, 42 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java index d513bfc56a..2975a33ba8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java +++ b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java @@ -48,6 +48,7 @@ import org.thoughtcrime.securesms.jobs.CreateSignedPreKeyJob; import org.thoughtcrime.securesms.jobs.FcmRefreshJob; import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob; import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob; +import org.thoughtcrime.securesms.jobs.RefreshPreKeysJob; import org.thoughtcrime.securesms.jobs.StickerPackDownloadJob; import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.megaphone.MegaphoneRepository; @@ -138,6 +139,7 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi initializeCameraX(); FeatureFlags.init(); NotificationChannels.create(this); + RefreshPreKeysJob.scheduleIfNecessary(); ProcessLifecycleOwner.get().getLifecycle().addObserver(this); if (Build.VERSION.SDK_INT < 21) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/RefreshPreKeysJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/RefreshPreKeysJob.java index 610443de76..aec4bb733e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/RefreshPreKeysJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/RefreshPreKeysJob.java @@ -9,6 +9,7 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.jobmanager.Data; import org.thoughtcrime.securesms.jobmanager.Job; import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint; +import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.libsignal.IdentityKeyPair; @@ -17,9 +18,11 @@ import org.whispersystems.libsignal.state.SignedPreKeyRecord; import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException; +import org.whispersystems.signalservice.api.storage.SignalStorageRecord; import java.io.IOException; import java.util.List; +import java.util.concurrent.TimeUnit; public class RefreshPreKeysJob extends BaseJob { @@ -29,14 +32,27 @@ public class RefreshPreKeysJob extends BaseJob { private static final int PREKEY_MINIMUM = 10; + private static final long REFRESH_INTERVAL = TimeUnit.DAYS.toMillis(3); + public RefreshPreKeysJob() { this(new Job.Parameters.Builder() .setQueue("RefreshPreKeysJob") .addConstraint(NetworkConstraint.KEY) - .setMaxAttempts(5) + .setMaxInstances(1) + .setMaxAttempts(Parameters.UNLIMITED) + .setLifespan(TimeUnit.DAYS.toMillis(30)) .build()); } + public static void scheduleIfNecessary() { + long timeSinceLastRefresh = System.currentTimeMillis() - SignalStore.getLastPrekeyRefreshTime(); + + if (timeSinceLastRefresh > REFRESH_INTERVAL) { + Log.i(TAG, "Scheduling a prekey refresh. Time since last schedule: " + timeSinceLastRefresh + " ms"); + ApplicationDependencies.getJobManager().add(new RefreshPreKeysJob()); + } + } + private RefreshPreKeysJob(@NonNull Job.Parameters parameters) { super(parameters); } @@ -53,14 +69,20 @@ public class RefreshPreKeysJob extends BaseJob { @Override public void onRun() throws IOException { - if (!TextSecurePreferences.isPushRegistered(context)) return; + if (!TextSecurePreferences.isPushRegistered(context)) { + Log.w(TAG, "Not registered. Skipping."); + return; + } SignalServiceAccountManager accountManager = ApplicationDependencies.getSignalServiceAccountManager(); int availableKeys = accountManager.getPreKeysCount(); + Log.i(TAG, "Available keys: " + availableKeys); + if (availableKeys >= PREKEY_MINIMUM && TextSecurePreferences.isSignedPreKeyRegistered(context)) { - Log.i(TAG, "Available keys sufficient: " + availableKeys); + Log.i(TAG, "Available keys sufficient."); + SignalStore.setLastPrekeyRefreshTime(System.currentTimeMillis()); return; } @@ -76,6 +98,8 @@ public class RefreshPreKeysJob extends BaseJob { TextSecurePreferences.setSignedPreKeyRegistered(context, true); ApplicationDependencies.getJobManager().add(new CleanPreKeysJob()); + SignalStore.setLastPrekeyRefreshTime(System.currentTimeMillis()); + Log.i(TAG, "Successfully refreshed prekeys."); } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/RotateSignedPreKeyJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/RotateSignedPreKeyJob.java index 9b03792d0c..ce315818d8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/RotateSignedPreKeyJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/RotateSignedPreKeyJob.java @@ -17,6 +17,8 @@ import org.whispersystems.libsignal.state.SignedPreKeyRecord; import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException; +import java.util.concurrent.TimeUnit; + public class RotateSignedPreKeyJob extends BaseJob { public static final String KEY = "RotateSignedPreKeyJob"; @@ -27,7 +29,9 @@ public class RotateSignedPreKeyJob extends BaseJob { this(new Job.Parameters.Builder() .setQueue("RotateSignedPreKeyJob") .addConstraint(NetworkConstraint.KEY) - .setMaxAttempts(5) + .setMaxInstances(1) + .setMaxAttempts(Parameters.UNLIMITED) + .setLifespan(TimeUnit.DAYS.toMillis(2)) .build()); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SignalStore.java b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SignalStore.java index 7384d99169..62e938cf72 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SignalStore.java +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SignalStore.java @@ -14,6 +14,7 @@ public final class SignalStore { private static final String REMOTE_CONFIG = "remote_config"; private static final String REMOTE_CONFIG_LAST_FETCH_TIME = "remote_config_last_fetch_time"; + private static final String LAST_PREKEY_REFRESH_TIME = "last_prekey_refresh_time"; private SignalStore() {} @@ -45,6 +46,13 @@ public final class SignalStore { putLong(REMOTE_CONFIG_LAST_FETCH_TIME, time); } + public static long getLastPrekeyRefreshTime() { + return getStore().getLong(LAST_PREKEY_REFRESH_TIME, 0); + } + + public static void setLastPrekeyRefreshTime(long time) { + putLong(LAST_PREKEY_REFRESH_TIME, time); + } /** * Ensures any pending writes are finished. Only intended to be called by