From ebaa445bee68abe97ed6fb669b1ad159e30687df Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Thu, 6 Jul 2023 12:21:31 -0400 Subject: [PATCH] Save last-known server time offset. --- .../jobs/RemoteConfigRefreshJob.java | 8 ++--- .../keyvalue/MiscellaneousValues.java | 29 +++++++++++++++++++ .../logsubmit/LogSectionSystemInfo.java | 1 + .../securesms/util/FeatureFlags.java | 5 ++-- .../signalservice/api/RemoteConfigResult.kt | 11 +++++++ .../api/SignalServiceAccountManager.java | 4 +-- .../internal/push/RemoteConfigResponse.java | 7 +++++ 7 files changed, 57 insertions(+), 8 deletions(-) create mode 100644 libsignal/service/src/main/java/org/whispersystems/signalservice/api/RemoteConfigResult.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/RemoteConfigRefreshJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/RemoteConfigRefreshJob.java index cbb3e0da3d..313ef1e5e8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/RemoteConfigRefreshJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/RemoteConfigRefreshJob.java @@ -5,14 +5,13 @@ import androidx.annotation.Nullable; import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; -import org.thoughtcrime.securesms.jobmanager.JsonJobData; import org.thoughtcrime.securesms.jobmanager.Job; import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint; import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.util.FeatureFlags; +import org.whispersystems.signalservice.api.RemoteConfigResult; import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException; -import java.util.Map; import java.util.concurrent.TimeUnit; public class RemoteConfigRefreshJob extends BaseJob { @@ -52,8 +51,9 @@ public class RemoteConfigRefreshJob extends BaseJob { return; } - Map config = ApplicationDependencies.getSignalServiceAccountManager().getRemoteConfig(); - FeatureFlags.update(config); + RemoteConfigResult result = ApplicationDependencies.getSignalServiceAccountManager().getRemoteConfig(); + FeatureFlags.update(result.getConfig()); + SignalStore.misc().setLastKnownServerTime(TimeUnit.SECONDS.toMillis(result.getServerEpochTimeSeconds()), System.currentTimeMillis()); } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/MiscellaneousValues.java b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/MiscellaneousValues.java index ced92d96bd..df6de1a080 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/MiscellaneousValues.java +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/MiscellaneousValues.java @@ -39,6 +39,8 @@ public final class MiscellaneousValues extends SignalStoreValues { private static final String KEYBOARD_LANDSCAPE_HEIGHT = "misc.keyboard.landscape_height"; private static final String KEYBOARD_PORTRAIT_HEIGHT = "misc.keyboard.protrait_height"; private static final String LAST_CONSISTENCY_CHECK_TIME = "misc.last_consistency_check_time"; + private static final String SERVER_TIME_OFFSET = "misc.server_time_offset"; + private static final String LAST_SERVER_TIME_OFFSET_UPDATE = "misc.last_server_time_offset_update"; MiscellaneousValues(@NonNull KeyValueStore store) { super(store); @@ -326,4 +328,31 @@ public final class MiscellaneousValues extends SignalStoreValues { public void setLastConsistencyCheckTime(long time) { putLong(LAST_CONSISTENCY_CHECK_TIME, time); } + + /** + * Sets the last-known server time. + */ + public void setLastKnownServerTime(long serverTime, long currentTime) { + getStore() + .beginWrite() + .putLong(SERVER_TIME_OFFSET, currentTime - serverTime) + .putLong(LAST_SERVER_TIME_OFFSET_UPDATE, System.currentTimeMillis()) + .apply(); + } + + /** + * The last-known offset between our local clock and the server. To get an estimate of the server time, take your current time and subtract this offset. e.g. + * + * estimatedServerTime = System.currentTimeMillis() - SignalStore.misc().getLastKnownServerTimeOffset() + */ + public long getLastKnownServerTimeOffset() { + return getLong(SERVER_TIME_OFFSET, 0); + } + + /** + * The last time (using our local clock) we updated the server time offset returned by {@link #getLastKnownServerTimeOffset()}}. + */ + public long getLastKnownServerTimeOffsetUpdateTime() { + return getLong(LAST_SERVER_TIME_OFFSET_UPDATE, 0); + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionSystemInfo.java b/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionSystemInfo.java index d410c04eaa..8a2bd37380 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionSystemInfo.java +++ b/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionSystemInfo.java @@ -85,6 +85,7 @@ public class LogSectionSystemInfo implements LogSection { builder.append("Emoji Version : ").append(getEmojiVersionString(context)).append("\n"); builder.append("RenderBigEmoji : ").append(FontUtil.canRenderEmojiAtFontSize(1024)).append("\n"); builder.append("DontKeepActivities: ").append(getDontKeepActivities(context)).append("\n"); + builder.append("Server Time Offset: ").append(SignalStore.misc().getLastKnownServerTimeOffset()).append(" ms (last updated: ").append(SignalStore.misc().getLastKnownServerTimeOffsetUpdateTime()).append(")").append("\n"); builder.append("Telecom : ").append(AndroidTelecomUtil.getTelecomSupported()).append("\n"); builder.append("User-Agent : ").append(StandardUserAgentInterceptor.USER_AGENT).append("\n"); builder.append("App : "); diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java b/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java index 80a5ca93ef..8a631aab44 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java @@ -18,6 +18,7 @@ import org.thoughtcrime.securesms.groups.SelectionLimits; import org.thoughtcrime.securesms.jobs.RemoteConfigRefreshJob; import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.messageprocessingalarm.MessageProcessReceiver; +import org.whispersystems.signalservice.api.RemoteConfigResult; import java.io.IOException; import java.util.HashMap; @@ -293,8 +294,8 @@ public final class FeatureFlags { @WorkerThread public static void refreshSync() throws IOException { - Map config = ApplicationDependencies.getSignalServiceAccountManager().getRemoteConfig(); - FeatureFlags.update(config); + RemoteConfigResult result = ApplicationDependencies.getSignalServiceAccountManager().getRemoteConfig(); + FeatureFlags.update(result.getConfig()); } public static synchronized void update(@NonNull Map config) { diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/RemoteConfigResult.kt b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/RemoteConfigResult.kt new file mode 100644 index 0000000000..aa86d7008b --- /dev/null +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/RemoteConfigResult.kt @@ -0,0 +1,11 @@ +/* + * Copyright 2023 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.whispersystems.signalservice.api + +data class RemoteConfigResult( + val config: Map, + val serverEpochTimeSeconds: Long +) diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceAccountManager.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceAccountManager.java index ed3a0f9584..605283f91c 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceAccountManager.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceAccountManager.java @@ -626,7 +626,7 @@ public class SignalServiceAccountManager { } } - public Map getRemoteConfig() throws IOException { + public RemoteConfigResult getRemoteConfig() throws IOException { RemoteConfigResponse response = this.pushServiceSocket.getRemoteConfig(); Map out = new HashMap<>(); @@ -634,7 +634,7 @@ public class SignalServiceAccountManager { out.put(config.getName(), config.getValue() != null ? config.getValue() : config.isEnabled()); } - return out; + return new RemoteConfigResult(out, response.getServerEpochTime()); } public String getAccountDataReport() throws IOException { diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/RemoteConfigResponse.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/RemoteConfigResponse.java index 41110d9ad6..dc055f5196 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/RemoteConfigResponse.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/RemoteConfigResponse.java @@ -8,10 +8,17 @@ public class RemoteConfigResponse { @JsonProperty private List config; + @JsonProperty + private long serverEpochTime; + public List getConfig() { return config; } + public long getServerEpochTime() { + return serverEpochTime; + } + public static class Config { @JsonProperty private String name;