Replace device creation timestamps with registration IDs in experiment logic

This commit is contained in:
Katherine
2025-07-23 10:24:28 -04:00
committed by GitHub
parent 876bf15a11
commit 74c7e49cea
3 changed files with 19 additions and 13 deletions

View File

@@ -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) {

View File

@@ -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;