mirror of
https://github.com/signalapp/Signal-Server
synced 2026-05-21 17:48:45 +01:00
Replace device creation timestamps with registration IDs in experiment logic
This commit is contained in:
+5
-1
@@ -3,7 +3,11 @@ package org.whispersystems.textsecuregcm.experiment;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public record DeviceLastSeenState(boolean deviceExists,
|
||||
long createdAtMillis,
|
||||
// Registration IDs are not guaranteed to be unique across devices and re-registrations.
|
||||
// However, for this use case, we accept the possibility of collisions in order to
|
||||
// avoid storing plaintext device creation timestamps on the server.
|
||||
// This tradeoff is intentional and aligned with our privacy goals.
|
||||
int registrationId,
|
||||
boolean hasPushToken,
|
||||
long lastSeenMillis,
|
||||
@Nullable PushTokenType pushTokenType) {
|
||||
|
||||
+3
-2
@@ -4,6 +4,7 @@ import com.google.common.annotations.VisibleForTesting;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.whispersystems.textsecuregcm.identity.IdentityType;
|
||||
import org.whispersystems.textsecuregcm.storage.Account;
|
||||
import org.whispersystems.textsecuregcm.storage.Device;
|
||||
import org.whispersystems.textsecuregcm.workers.IdleWakeupEligibilityChecker;
|
||||
@@ -64,7 +65,7 @@ abstract class IdleDevicePushNotificationExperiment implements PushNotificationE
|
||||
} else {
|
||||
pushTokenType = null;
|
||||
}
|
||||
return new DeviceLastSeenState(true, device.getCreated(), hasPushToken(device), device.getLastSeen(), pushTokenType);
|
||||
return new DeviceLastSeenState(true, device.getRegistrationId(IdentityType.ACI), hasPushToken(device), device.getLastSeen(), pushTokenType);
|
||||
} else {
|
||||
return DeviceLastSeenState.MISSING_DEVICE_STATE;
|
||||
}
|
||||
@@ -116,7 +117,7 @@ abstract class IdleDevicePushNotificationExperiment implements PushNotificationE
|
||||
|
||||
assert sample.finalState() != null;
|
||||
|
||||
if (!sample.finalState().deviceExists() || sample.initialState().createdAtMillis() != sample.finalState().createdAtMillis()) {
|
||||
if (!sample.finalState().deviceExists() || sample.initialState().registrationId() != sample.finalState().registrationId()) {
|
||||
outcome = Outcome.DELETED;
|
||||
} else if (!sample.finalState().hasPushToken()) {
|
||||
outcome = Outcome.UNINSTALLED;
|
||||
|
||||
+11
-10
@@ -4,6 +4,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.whispersystems.textsecuregcm.identity.IdentityType;
|
||||
import org.whispersystems.textsecuregcm.storage.Account;
|
||||
import org.whispersystems.textsecuregcm.storage.Device;
|
||||
import reactor.core.publisher.Flux;
|
||||
@@ -66,37 +67,37 @@ abstract class IdleDevicePushNotificationExperimentTest {
|
||||
assertEquals(DeviceLastSeenState.MISSING_DEVICE_STATE, experiment.getState(null, null));
|
||||
assertEquals(DeviceLastSeenState.MISSING_DEVICE_STATE, experiment.getState(mock(Account.class), null));
|
||||
|
||||
final long createdAtMillis = CURRENT_TIME.minus(Duration.ofDays(14)).toEpochMilli();
|
||||
final int registrationId = 123;
|
||||
|
||||
{
|
||||
final Device apnsDevice = mock(Device.class);
|
||||
when(apnsDevice.getApnId()).thenReturn("apns-token");
|
||||
when(apnsDevice.getCreated()).thenReturn(createdAtMillis);
|
||||
when(apnsDevice.getRegistrationId(IdentityType.ACI)).thenReturn(registrationId);
|
||||
when(apnsDevice.getLastSeen()).thenReturn(CURRENT_TIME.toEpochMilli());
|
||||
|
||||
assertEquals(
|
||||
new DeviceLastSeenState(true, createdAtMillis, true, CURRENT_TIME.toEpochMilli(), DeviceLastSeenState.PushTokenType.APNS),
|
||||
new DeviceLastSeenState(true, registrationId, true, CURRENT_TIME.toEpochMilli(), DeviceLastSeenState.PushTokenType.APNS),
|
||||
experiment.getState(mock(Account.class), apnsDevice));
|
||||
}
|
||||
|
||||
{
|
||||
final Device fcmDevice = mock(Device.class);
|
||||
when(fcmDevice.getGcmId()).thenReturn("fcm-token");
|
||||
when(fcmDevice.getCreated()).thenReturn(createdAtMillis);
|
||||
when(fcmDevice.getRegistrationId(IdentityType.ACI)).thenReturn(registrationId);
|
||||
when(fcmDevice.getLastSeen()).thenReturn(CURRENT_TIME.toEpochMilli());
|
||||
|
||||
assertEquals(
|
||||
new DeviceLastSeenState(true, createdAtMillis, true, CURRENT_TIME.toEpochMilli(), DeviceLastSeenState.PushTokenType.FCM),
|
||||
new DeviceLastSeenState(true, registrationId, true, CURRENT_TIME.toEpochMilli(), DeviceLastSeenState.PushTokenType.FCM),
|
||||
experiment.getState(mock(Account.class), fcmDevice));
|
||||
}
|
||||
|
||||
{
|
||||
final Device noTokenDevice = mock(Device.class);
|
||||
when(noTokenDevice.getCreated()).thenReturn(createdAtMillis);
|
||||
when(noTokenDevice.getRegistrationId(IdentityType.ACI)).thenReturn(registrationId);
|
||||
when(noTokenDevice.getLastSeen()).thenReturn(CURRENT_TIME.toEpochMilli());
|
||||
|
||||
assertEquals(
|
||||
new DeviceLastSeenState(true, createdAtMillis, false, CURRENT_TIME.toEpochMilli(), null),
|
||||
new DeviceLastSeenState(true, registrationId, false, CURRENT_TIME.toEpochMilli(), null),
|
||||
experiment.getState(mock(Account.class), noTokenDevice));
|
||||
}
|
||||
}
|
||||
@@ -150,10 +151,10 @@ abstract class IdleDevicePushNotificationExperimentTest {
|
||||
IdleDevicePushNotificationExperiment.Outcome.DELETED
|
||||
),
|
||||
|
||||
// Device re-registered (i.e. "created" timestamp changed)
|
||||
// Device re-registered (i.e. registration ID changed)
|
||||
Arguments.of(
|
||||
new DeviceLastSeenState(true, 0, true, 0, DeviceLastSeenState.PushTokenType.APNS),
|
||||
new DeviceLastSeenState(true, 1, true, 1, DeviceLastSeenState.PushTokenType.APNS),
|
||||
new DeviceLastSeenState(true, 123, true, 0, DeviceLastSeenState.PushTokenType.APNS),
|
||||
new DeviceLastSeenState(true, 1234, true, 1, DeviceLastSeenState.PushTokenType.APNS),
|
||||
IdleDevicePushNotificationExperiment.Outcome.DELETED
|
||||
),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user