mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-21 18:26:57 +00:00
Improve conditional logic around prekey refresh schedule.
This commit is contained in:
@@ -7,6 +7,6 @@ interface PreKeyMetadataStore {
|
||||
var nextSignedPreKeyId: Int
|
||||
var activeSignedPreKeyId: Int
|
||||
var isSignedPreKeyRegistered: Boolean
|
||||
var signedPreKeyFailureCount: Int
|
||||
var lastSignedPreKeyRotationTime: Long
|
||||
var nextOneTimePreKeyId: Int
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ import org.thoughtcrime.securesms.migrations.PinOptOutMigration;
|
||||
import org.thoughtcrime.securesms.migrations.PinReminderMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.PniAccountInitializationMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.PniMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.PreKeysSyncMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.ProfileMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.ProfileSharingUpdateMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.RebuildMessageSearchIndexMigrationJob;
|
||||
@@ -239,6 +240,7 @@ public final class JobManagerFactories {
|
||||
put(PinReminderMigrationJob.KEY, new PinReminderMigrationJob.Factory());
|
||||
put(PniAccountInitializationMigrationJob.KEY, new PniAccountInitializationMigrationJob.Factory());
|
||||
put(PniMigrationJob.KEY, new PniMigrationJob.Factory());
|
||||
put(PreKeysSyncMigrationJob.KEY, new PreKeysSyncMigrationJob.Factory());
|
||||
put(ProfileMigrationJob.KEY, new ProfileMigrationJob.Factory());
|
||||
put(ProfileSharingUpdateMigrationJob.KEY, new ProfileSharingUpdateMigrationJob.Factory());
|
||||
put(RebuildMessageSearchIndexMigrationJob.KEY, new RebuildMessageSearchIndexMigrationJob.Factory());
|
||||
|
||||
@@ -3,46 +3,55 @@ package org.thoughtcrime.securesms.jobs
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.signal.libsignal.protocol.state.SignalProtocolStore
|
||||
import org.signal.libsignal.protocol.state.SignedPreKeyRecord
|
||||
import org.thoughtcrime.securesms.crypto.PreKeyUtil
|
||||
import org.thoughtcrime.securesms.crypto.storage.PreKeyMetadataStore
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.jobmanager.Job
|
||||
import org.thoughtcrime.securesms.jobmanager.JsonJobData
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.signalservice.api.push.ServiceId
|
||||
import org.whispersystems.signalservice.api.push.ServiceIdType
|
||||
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException
|
||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.time.Duration.Companion.days
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.DurationUnit
|
||||
|
||||
/**
|
||||
* Regardless of the current state of affairs with respect to prekeys for either ACI or PNI identities, will
|
||||
* attempt to make the state valid.
|
||||
*
|
||||
* If prekeys aren't registered for an identity they will be created.
|
||||
*
|
||||
* If prekeys are registered but the count is below the minimum threshold, then new ones will be uploaded.
|
||||
* It will rotate/create signed prekeys for both ACI and PNI identities, as well as ensure that the user
|
||||
* has a sufficient number of one-time prekeys available on the service.
|
||||
*/
|
||||
class PreKeysSyncJob private constructor(private val forceRotate: Boolean = false, parameters: Parameters) : BaseJob(parameters) {
|
||||
class PreKeysSyncJob private constructor(parameters: Parameters) : BaseJob(parameters) {
|
||||
|
||||
companion object {
|
||||
const val KEY = "PreKeysSyncJob"
|
||||
|
||||
private val TAG = Log.tag(PreKeysSyncJob::class.java)
|
||||
private val KEY_FORCE_ROTATE = "force_rotate"
|
||||
private const val PREKEY_MINIMUM = 10
|
||||
private val REFRESH_INTERVAL = TimeUnit.DAYS.toMillis(3)
|
||||
|
||||
fun create(forceRotate: Boolean = false): PreKeysSyncJob {
|
||||
return PreKeysSyncJob(forceRotate)
|
||||
/** The minimum number of one-time prekeys we want to the service to have. If we have less than this, refill. */
|
||||
private const val ONE_TIME_PREKEY_MINIMUM = 10
|
||||
|
||||
/** How often we want to rotate signed prekeys. */
|
||||
@JvmField
|
||||
val REFRESH_INTERVAL = 2.days.inWholeMilliseconds
|
||||
|
||||
/** If signed prekeys are older than this, we will require rotation before sending messages. */
|
||||
@JvmField
|
||||
val MAXIMUM_ALLOWED_SIGNED_PREKEY_AGE = 14.days.inWholeMilliseconds
|
||||
|
||||
@JvmStatic
|
||||
fun create(): PreKeysSyncJob {
|
||||
return PreKeysSyncJob()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun enqueue(forceRotate: Boolean = false) {
|
||||
ApplicationDependencies.getJobManager().add(create(forceRotate))
|
||||
fun enqueue() {
|
||||
ApplicationDependencies.getJobManager().add(create())
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@@ -54,19 +63,20 @@ class PreKeysSyncJob private constructor(private val forceRotate: Boolean = fals
|
||||
Log.i(TAG, "Some signed prekeys aren't active yet. Enqueuing a job. ACI: ${SignalStore.account().aciPreKeys.activeSignedPreKeyId >= 0} PNI: ${SignalStore.account().pniPreKeys.activeSignedPreKeyId >= 0}")
|
||||
ApplicationDependencies.getJobManager().add(PreKeysSyncJob())
|
||||
} else {
|
||||
val timeSinceLastRefresh = System.currentTimeMillis() - SignalStore.misc().lastPrekeyRefreshTime
|
||||
val timeSinceLastFullRefresh = System.currentTimeMillis() - SignalStore.misc().lastFullPrekeyRefreshTime
|
||||
|
||||
if (timeSinceLastRefresh > REFRESH_INTERVAL) {
|
||||
Log.i(TAG, "Scheduling a prekey refresh. Time since last schedule: $timeSinceLastRefresh ms")
|
||||
if (timeSinceLastFullRefresh >= REFRESH_INTERVAL || timeSinceLastFullRefresh < 0) {
|
||||
Log.i(TAG, "Scheduling a prekey refresh. Time since last full refresh: $timeSinceLastFullRefresh ms")
|
||||
ApplicationDependencies.getJobManager().add(PreKeysSyncJob())
|
||||
} else {
|
||||
Log.d(TAG, "No prekey job needed. Time since last full refresh: $timeSinceLastFullRefresh ms")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||
constructor(forceRotate: Boolean = false) : this(
|
||||
forceRotate,
|
||||
constructor() : this(
|
||||
Parameters.Builder()
|
||||
.setQueue("PreKeysSyncJob")
|
||||
.addConstraint(NetworkConstraint.KEY)
|
||||
@@ -78,11 +88,7 @@ class PreKeysSyncJob private constructor(private val forceRotate: Boolean = fals
|
||||
|
||||
override fun getFactoryKey(): String = KEY
|
||||
|
||||
override fun serialize(): ByteArray? {
|
||||
return JsonJobData.Builder()
|
||||
.putBoolean(KEY_FORCE_ROTATE, forceRotate)
|
||||
.serialize()
|
||||
}
|
||||
override fun serialize(): ByteArray? = null
|
||||
|
||||
override fun onRun() {
|
||||
if (!SignalStore.account().isRegistered || SignalStore.account().aci == null || SignalStore.account().pni == null) {
|
||||
@@ -92,7 +98,7 @@ class PreKeysSyncJob private constructor(private val forceRotate: Boolean = fals
|
||||
|
||||
syncPreKeys(ServiceIdType.ACI, SignalStore.account().aci, ApplicationDependencies.getProtocolStore().aci(), SignalStore.account().aciPreKeys)
|
||||
syncPreKeys(ServiceIdType.PNI, SignalStore.account().pni, ApplicationDependencies.getProtocolStore().pni(), SignalStore.account().pniPreKeys)
|
||||
SignalStore.misc().lastPrekeyRefreshTime = System.currentTimeMillis()
|
||||
SignalStore.misc().lastFullPrekeyRefreshTime = System.currentTimeMillis()
|
||||
}
|
||||
|
||||
private fun syncPreKeys(serviceIdType: ServiceIdType, serviceId: ServiceId?, protocolStore: SignalProtocolStore, metadataStore: PreKeyMetadataStore) {
|
||||
@@ -101,55 +107,41 @@ class PreKeysSyncJob private constructor(private val forceRotate: Boolean = fals
|
||||
return
|
||||
}
|
||||
|
||||
if (metadataStore.isSignedPreKeyRegistered && metadataStore.activeSignedPreKeyId >= 0) {
|
||||
if (forceRotate || System.currentTimeMillis() > TextSecurePreferences.getSignedPreKeyRotationTime(context) || metadataStore.signedPreKeyFailureCount > 5) {
|
||||
log(serviceIdType, "Rotating signed prekey...")
|
||||
rotateSignedPreKey(serviceIdType, protocolStore, metadataStore)
|
||||
} else {
|
||||
log(serviceIdType, "Refreshing prekeys...")
|
||||
refreshKeys(serviceIdType, protocolStore, metadataStore)
|
||||
}
|
||||
} else {
|
||||
log(serviceIdType, "Creating signed prekey...")
|
||||
rotateSignedPreKey(serviceIdType, protocolStore, metadataStore)
|
||||
}
|
||||
}
|
||||
|
||||
private fun rotateSignedPreKey(serviceIdType: ServiceIdType, protocolStore: SignalProtocolStore, metadataStore: PreKeyMetadataStore) {
|
||||
val signedPreKeyRecord = PreKeyUtil.generateAndStoreSignedPreKey(protocolStore, metadataStore)
|
||||
ApplicationDependencies.getSignalServiceAccountManager().setSignedPreKey(serviceIdType, signedPreKeyRecord)
|
||||
|
||||
metadataStore.activeSignedPreKeyId = signedPreKeyRecord.id
|
||||
metadataStore.isSignedPreKeyRegistered = true
|
||||
metadataStore.signedPreKeyFailureCount = 0
|
||||
}
|
||||
|
||||
private fun refreshKeys(serviceIdType: ServiceIdType, protocolStore: SignalProtocolStore, metadataStore: PreKeyMetadataStore) {
|
||||
val accountManager = ApplicationDependencies.getSignalServiceAccountManager()
|
||||
val availableKeys = accountManager.getPreKeysCount(serviceIdType)
|
||||
|
||||
log(serviceIdType, "Available keys: $availableKeys")
|
||||
val signedPreKeyRegistered = metadataStore.isSignedPreKeyRegistered && metadataStore.activeSignedPreKeyId >= 0
|
||||
val timeSinceLastSignedPreKeyRotation = System.currentTimeMillis() - metadataStore.lastSignedPreKeyRotationTime
|
||||
|
||||
if (availableKeys >= PREKEY_MINIMUM && metadataStore.isSignedPreKeyRegistered) {
|
||||
log(serviceIdType, "Available keys sufficient.")
|
||||
return
|
||||
val activeSignedPreKeyRecord: SignedPreKeyRecord = if (!signedPreKeyRegistered || timeSinceLastSignedPreKeyRotation >= REFRESH_INTERVAL) {
|
||||
log(serviceIdType, "Rotating signed prekey. SignedPreKeyRegistered: $signedPreKeyRegistered, TimeSinceLastRotation: $timeSinceLastSignedPreKeyRotation ms (${timeSinceLastSignedPreKeyRotation.milliseconds.toDouble(DurationUnit.DAYS)} days)")
|
||||
|
||||
val signedPreKeyRecord: SignedPreKeyRecord = PreKeyUtil.generateAndStoreSignedPreKey(protocolStore, metadataStore)
|
||||
accountManager.setSignedPreKey(serviceIdType, signedPreKeyRecord)
|
||||
|
||||
metadataStore.activeSignedPreKeyId = signedPreKeyRecord.id
|
||||
metadataStore.isSignedPreKeyRegistered = true
|
||||
metadataStore.lastSignedPreKeyRotationTime = System.currentTimeMillis()
|
||||
|
||||
signedPreKeyRecord
|
||||
} else {
|
||||
log(serviceIdType, "No need to rotate signed prekey. TimeSinceLastRotation: $timeSinceLastSignedPreKeyRotation ms (${timeSinceLastSignedPreKeyRotation.milliseconds.toDouble(DurationUnit.DAYS)} days)")
|
||||
protocolStore.loadSignedPreKey(metadataStore.activeSignedPreKeyId)
|
||||
}
|
||||
|
||||
val preKeyRecords = PreKeyUtil.generateAndStoreOneTimePreKeys(protocolStore, metadataStore)
|
||||
val signedPreKeyRecord = PreKeyUtil.generateAndStoreSignedPreKey(protocolStore, metadataStore)
|
||||
val identityKey = protocolStore.identityKeyPair
|
||||
val availableOneTimePreKeys = accountManager.getPreKeysCount(serviceIdType)
|
||||
|
||||
log(serviceIdType, "Registering new prekeys...")
|
||||
if (availableOneTimePreKeys < ONE_TIME_PREKEY_MINIMUM) {
|
||||
log(serviceIdType, "There are $availableOneTimePreKeys one-time prekeys available, which is not sufficient. Uploading more.")
|
||||
|
||||
accountManager.setPreKeys(serviceIdType, identityKey.publicKey, signedPreKeyRecord, preKeyRecords)
|
||||
metadataStore.activeSignedPreKeyId = signedPreKeyRecord.id
|
||||
metadataStore.isSignedPreKeyRegistered = true
|
||||
val preKeyRecords = PreKeyUtil.generateAndStoreOneTimePreKeys(protocolStore, metadataStore)
|
||||
val identityKey = protocolStore.identityKeyPair
|
||||
accountManager.setPreKeys(serviceIdType, identityKey.publicKey, activeSignedPreKeyRecord, preKeyRecords)
|
||||
} else {
|
||||
log(serviceIdType, "There are $availableOneTimePreKeys one-time prekeys available, which is sufficient. No need to upload.")
|
||||
}
|
||||
|
||||
log(serviceIdType, "Cleaning prekeys...")
|
||||
PreKeyUtil.cleanSignedPreKeys(protocolStore, metadataStore)
|
||||
|
||||
SignalStore.misc().lastPrekeyRefreshTime = System.currentTimeMillis()
|
||||
log(serviceIdType, "Successfully refreshed prekeys.")
|
||||
}
|
||||
|
||||
override fun onShouldRetry(e: Exception): Boolean {
|
||||
@@ -160,15 +152,7 @@ class PreKeysSyncJob private constructor(private val forceRotate: Boolean = fals
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure() {
|
||||
val aciStore = SignalStore.account().aciPreKeys
|
||||
val pniStore = SignalStore.account().pniPreKeys
|
||||
|
||||
if ((aciStore.isSignedPreKeyRegistered || pniStore.isSignedPreKeyRegistered) && forceRotate) {
|
||||
aciStore.signedPreKeyFailureCount++
|
||||
pniStore.signedPreKeyFailureCount++
|
||||
}
|
||||
}
|
||||
override fun onFailure() = Unit
|
||||
|
||||
private fun log(serviceIdType: ServiceIdType, message: String) {
|
||||
Log.i(TAG, "[$serviceIdType] $message")
|
||||
@@ -176,8 +160,7 @@ class PreKeysSyncJob private constructor(private val forceRotate: Boolean = fals
|
||||
|
||||
class Factory : Job.Factory<PreKeysSyncJob> {
|
||||
override fun create(parameters: Parameters, serializedData: ByteArray?): PreKeysSyncJob {
|
||||
val data = JsonJobData.deserialize(serializedData)
|
||||
return PreKeysSyncJob(data.getBooleanOrDefault(KEY_FORCE_ROTATE, false), parameters)
|
||||
return PreKeysSyncJob(parameters)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,12 +39,12 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.events.PartProgressEvent;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobTracker;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.BackoffUtil;
|
||||
import org.thoughtcrime.securesms.keyvalue.CertificateType;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri;
|
||||
import org.thoughtcrime.securesms.mms.MmsException;
|
||||
import org.thoughtcrime.securesms.mms.OutgoingMessage;
|
||||
import org.thoughtcrime.securesms.mms.PartAuthority;
|
||||
import org.thoughtcrime.securesms.mms.QuoteModel;
|
||||
@@ -99,9 +99,18 @@ public abstract class PushSendJob extends SendJob {
|
||||
|
||||
@Override
|
||||
protected final void onSend() throws Exception {
|
||||
if (SignalStore.account().aciPreKeys().getSignedPreKeyFailureCount() > 5) {
|
||||
PreKeysSyncJob.enqueue(true);
|
||||
throw new TextSecureExpiredException("Too many signed prekey rotation failures");
|
||||
long timeSinceSignedPreKeyRotation = System.currentTimeMillis() - SignalStore.account().aciPreKeys().getLastSignedPreKeyRotationTime();
|
||||
|
||||
if (timeSinceSignedPreKeyRotation > PreKeysSyncJob.MAXIMUM_ALLOWED_SIGNED_PREKEY_AGE || timeSinceSignedPreKeyRotation < 0) {
|
||||
warn(TAG, "It's been too long since rotating our signed prekey (" + timeSinceSignedPreKeyRotation + " ms)! Attempting to rotate now.");
|
||||
|
||||
Optional<JobTracker.JobState> state = ApplicationDependencies.getJobManager().runSynchronously(PreKeysSyncJob.create(), TimeUnit.SECONDS.toMillis(30));
|
||||
|
||||
if (state.isPresent() && state.get() == JobTracker.JobState.SUCCESS) {
|
||||
log(TAG, "Successfully refreshed prekeys. Continuing.");
|
||||
} else {
|
||||
throw new RetryLaterException(new TextSecureExpiredException("Failed to refresh prekeys! State: " + (state.isEmpty() ? "<empty>" : state.get())));
|
||||
}
|
||||
}
|
||||
|
||||
if (!Recipient.self().isRegistered()) {
|
||||
|
||||
@@ -16,6 +16,7 @@ import org.thoughtcrime.securesms.crypto.ProfileKeyUtil
|
||||
import org.thoughtcrime.securesms.crypto.storage.PreKeyMetadataStore
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.jobs.PreKeysSyncJob
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService
|
||||
import org.thoughtcrime.securesms.util.Base64
|
||||
@@ -46,7 +47,7 @@ internal class AccountValues internal constructor(store: KeyValueStore) : Signal
|
||||
private const val KEY_ACI_SIGNED_PREKEY_REGISTERED = "account.aci_signed_prekey_registered"
|
||||
private const val KEY_ACI_NEXT_SIGNED_PREKEY_ID = "account.aci_next_signed_prekey_id"
|
||||
private const val KEY_ACI_ACTIVE_SIGNED_PREKEY_ID = "account.aci_active_signed_prekey_id"
|
||||
private const val KEY_ACI_SIGNED_PREKEY_FAILURE_COUNT = "account.aci_signed_prekey_failure_count"
|
||||
private const val KEY_ACI_LAST_SIGNED_PREKEY_ROTATION_TIME = "account.aci_last_signed_prekey_rotation_time"
|
||||
private const val KEY_ACI_NEXT_ONE_TIME_PREKEY_ID = "account.aci_next_one_time_prekey_id"
|
||||
|
||||
private const val KEY_PNI_IDENTITY_PUBLIC_KEY = "account.pni_identity_public_key"
|
||||
@@ -54,7 +55,7 @@ internal class AccountValues internal constructor(store: KeyValueStore) : Signal
|
||||
private const val KEY_PNI_SIGNED_PREKEY_REGISTERED = "account.pni_signed_prekey_registered"
|
||||
private const val KEY_PNI_NEXT_SIGNED_PREKEY_ID = "account.pni_next_signed_prekey_id"
|
||||
private const val KEY_PNI_ACTIVE_SIGNED_PREKEY_ID = "account.pni_active_signed_prekey_id"
|
||||
private const val KEY_PNI_SIGNED_PREKEY_FAILURE_COUNT = "account.pni_signed_prekey_failure_count"
|
||||
private const val KEY_PNI_LAST_SIGNED_PREKEY_ROTATION_TIME = "account.pni_last_signed_prekey_rotation_time"
|
||||
private const val KEY_PNI_NEXT_ONE_TIME_PREKEY_ID = "account.pni_next_one_time_prekey_id"
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -256,7 +257,7 @@ internal class AccountValues internal constructor(store: KeyValueStore) : Signal
|
||||
override var nextSignedPreKeyId: Int by integerValue(KEY_ACI_NEXT_SIGNED_PREKEY_ID, SecureRandom().nextInt(Medium.MAX_VALUE))
|
||||
override var activeSignedPreKeyId: Int by integerValue(KEY_ACI_ACTIVE_SIGNED_PREKEY_ID, -1)
|
||||
override var isSignedPreKeyRegistered: Boolean by booleanValue(KEY_ACI_SIGNED_PREKEY_REGISTERED, false)
|
||||
override var signedPreKeyFailureCount: Int by integerValue(KEY_ACI_SIGNED_PREKEY_FAILURE_COUNT, 0)
|
||||
override var lastSignedPreKeyRotationTime: Long by longValue(KEY_ACI_LAST_SIGNED_PREKEY_ROTATION_TIME, System.currentTimeMillis() - PreKeysSyncJob.REFRESH_INTERVAL)
|
||||
override var nextOneTimePreKeyId: Int by integerValue(KEY_ACI_NEXT_ONE_TIME_PREKEY_ID, SecureRandom().nextInt(Medium.MAX_VALUE))
|
||||
}
|
||||
|
||||
@@ -265,7 +266,7 @@ internal class AccountValues internal constructor(store: KeyValueStore) : Signal
|
||||
override var nextSignedPreKeyId: Int by integerValue(KEY_PNI_NEXT_SIGNED_PREKEY_ID, SecureRandom().nextInt(Medium.MAX_VALUE))
|
||||
override var activeSignedPreKeyId: Int by integerValue(KEY_PNI_ACTIVE_SIGNED_PREKEY_ID, -1)
|
||||
override var isSignedPreKeyRegistered: Boolean by booleanValue(KEY_PNI_SIGNED_PREKEY_REGISTERED, false)
|
||||
override var signedPreKeyFailureCount: Int by integerValue(KEY_PNI_SIGNED_PREKEY_FAILURE_COUNT, 0)
|
||||
override var lastSignedPreKeyRotationTime: Long by longValue(KEY_PNI_LAST_SIGNED_PREKEY_ROTATION_TIME, System.currentTimeMillis() - PreKeysSyncJob.REFRESH_INTERVAL)
|
||||
override var nextOneTimePreKeyId: Int by integerValue(KEY_PNI_NEXT_ONE_TIME_PREKEY_ID, SecureRandom().nextInt(Medium.MAX_VALUE))
|
||||
}
|
||||
|
||||
@@ -395,7 +396,6 @@ internal class AccountValues internal constructor(store: KeyValueStore) : Signal
|
||||
.putInteger(KEY_ACI_NEXT_SIGNED_PREKEY_ID, defaultPrefs.getInt("pref_next_signed_pre_key_id", SecureRandom().nextInt(Medium.MAX_VALUE)))
|
||||
.putInteger(KEY_ACI_ACTIVE_SIGNED_PREKEY_ID, defaultPrefs.getInt("pref_active_signed_pre_key_id", -1))
|
||||
.putInteger(KEY_ACI_NEXT_ONE_TIME_PREKEY_ID, defaultPrefs.getInt("pref_next_pre_key_id", SecureRandom().nextInt(Medium.MAX_VALUE)))
|
||||
.putInteger(KEY_ACI_SIGNED_PREKEY_FAILURE_COUNT, defaultPrefs.getInt("pref_signed_prekey_failure_count", 0))
|
||||
.putBoolean(KEY_ACI_SIGNED_PREKEY_REGISTERED, defaultPrefs.getBoolean("pref_signed_prekey_registered", false))
|
||||
.commit()
|
||||
|
||||
|
||||
@@ -47,11 +47,14 @@ public final class MiscellaneousValues extends SignalStoreValues {
|
||||
return Collections.singletonList(SMS_PHASE_1_START_MS);
|
||||
}
|
||||
|
||||
public long getLastPrekeyRefreshTime() {
|
||||
/**
|
||||
* Represents the last time a _full_ prekey refreshed finished. That means signed+one-time prekeys for both ACI and PNI.
|
||||
*/
|
||||
public long getLastFullPrekeyRefreshTime() {
|
||||
return getLong(LAST_PREKEY_REFRESH_TIME, 0);
|
||||
}
|
||||
|
||||
public void setLastPrekeyRefreshTime(long time) {
|
||||
public void setLastFullPrekeyRefreshTime(long time) {
|
||||
putLong(LAST_PREKEY_REFRESH_TIME, time);
|
||||
}
|
||||
|
||||
|
||||
@@ -128,9 +128,10 @@ public class ApplicationMigrations {
|
||||
static final int INDEX_DATABASE_MIGRATION = 84;
|
||||
static final int ACCOUNT_CONSISTENCY_CHECK = 85;
|
||||
static final int BACKUP_JITTER = 86;
|
||||
static final int PREKEY_SYNC = 87;
|
||||
}
|
||||
|
||||
public static final int CURRENT_VERSION = 86;
|
||||
public static final int CURRENT_VERSION = 87;
|
||||
|
||||
/**
|
||||
* This *must* be called after the {@link JobManager} has been instantiated, but *before* the call
|
||||
@@ -576,6 +577,10 @@ public class ApplicationMigrations {
|
||||
jobs.put(Version.BACKUP_JITTER, new BackupJitterMigrationJob());
|
||||
}
|
||||
|
||||
if (lastSeenVersion < Version.PREKEY_SYNC) {
|
||||
jobs.put(Version.PREKEY_SYNC, new PreKeysSyncMigrationJob());
|
||||
}
|
||||
|
||||
return jobs;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.thoughtcrime.securesms.migrations
|
||||
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.jobmanager.Job
|
||||
import org.thoughtcrime.securesms.jobs.PreKeysSyncJob
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
|
||||
/**
|
||||
* Schedules a prekey sync.
|
||||
*/
|
||||
internal class PreKeysSyncMigrationJob(
|
||||
parameters: Parameters = Parameters.Builder().build()
|
||||
) : MigrationJob(parameters) {
|
||||
|
||||
companion object {
|
||||
val TAG = Log.tag(PreKeysSyncMigrationJob::class.java)
|
||||
const val KEY = "PreKeysSyncIndexMigrationJob"
|
||||
}
|
||||
|
||||
override fun getFactoryKey(): String = KEY
|
||||
|
||||
override fun isUiBlocking(): Boolean = false
|
||||
|
||||
override fun performMigration() {
|
||||
SignalStore.misc().lastFullPrekeyRefreshTime = 0
|
||||
PreKeysSyncJob.enqueue()
|
||||
}
|
||||
|
||||
override fun shouldRetry(e: Exception): Boolean = false
|
||||
|
||||
class Factory : Job.Factory<PreKeysSyncMigrationJob> {
|
||||
override fun create(parameters: Parameters, serializedData: ByteArray?): PreKeysSyncMigrationJob {
|
||||
return PreKeysSyncMigrationJob(parameters)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,8 +13,6 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class RotateSignedPreKeyListener extends PersistentAlarmManagerListener {
|
||||
|
||||
private static final long INTERVAL = TimeUnit.DAYS.toMillis(2);
|
||||
|
||||
@Override
|
||||
protected long getNextScheduledExecutionTime(Context context) {
|
||||
return TextSecurePreferences.getSignedPreKeyRotationTime(context);
|
||||
@@ -23,10 +21,10 @@ public class RotateSignedPreKeyListener extends PersistentAlarmManagerListener {
|
||||
@Override
|
||||
protected long onAlarm(Context context, long scheduledTime) {
|
||||
if (scheduledTime != 0 && SignalStore.account().isRegistered()) {
|
||||
PreKeysSyncJob.enqueue(true);
|
||||
PreKeysSyncJob.enqueue();
|
||||
}
|
||||
|
||||
long nextTime = System.currentTimeMillis() + INTERVAL;
|
||||
long nextTime = System.currentTimeMillis() + PreKeysSyncJob.REFRESH_INTERVAL;
|
||||
TextSecurePreferences.setSignedPreKeyRotationTime(context, nextTime);
|
||||
|
||||
return nextTime;
|
||||
|
||||
Reference in New Issue
Block a user