Use UUIDs instead of e164s to associate accounts with push notifications.

This commit is contained in:
Jon Chambers
2021-06-30 16:57:47 -04:00
committed by Jon Chambers
parent ce5edbb7fc
commit 73c368ea86
11 changed files with 69 additions and 60 deletions

View File

@@ -179,9 +179,9 @@ public class AccountController {
pendingAccounts.store(number, storedVerificationCode);
if ("fcm".equals(pushType)) {
gcmSender.sendMessage(new GcmMessage(pushToken, number, 0, GcmMessage.Type.CHALLENGE, Optional.of(storedVerificationCode.getPushCode())));
gcmSender.sendMessage(new GcmMessage(pushToken, null, 0, GcmMessage.Type.CHALLENGE, Optional.of(storedVerificationCode.getPushCode())));
} else if ("apn".equals(pushType)) {
apnSender.sendMessage(new ApnMessage(pushToken, number, 0, useVoip.orElse(true), ApnMessage.Type.CHALLENGE, Optional.of(storedVerificationCode.getPushCode())));
apnSender.sendMessage(new ApnMessage(pushToken, null, 0, useVoip.orElse(true), ApnMessage.Type.CHALLENGE, Optional.of(storedVerificationCode.getPushCode())));
} else {
throw new AssertionError();
}

View File

@@ -69,10 +69,10 @@ public class PushChallengeManager {
sent = true;
if (StringUtils.isNotBlank(masterDevice.getGcmId())) {
gcmSender.sendMessage(new GcmMessage(masterDevice.getGcmId(), account.getNumber(), 0, GcmMessage.Type.RATE_LIMIT_CHALLENGE, Optional.of(tokenHex)));
gcmSender.sendMessage(new GcmMessage(masterDevice.getGcmId(), account.getUuid(), 0, GcmMessage.Type.RATE_LIMIT_CHALLENGE, Optional.of(tokenHex)));
platform = ClientPlatform.ANDROID.name().toLowerCase();
} else if (StringUtils.isNotBlank(masterDevice.getApnId())) {
apnSender.sendMessage(new ApnMessage(masterDevice.getApnId(), account.getNumber(), 0, false, Type.RATE_LIMIT_CHALLENGE, Optional.of(tokenHex)));
apnSender.sendMessage(new ApnMessage(masterDevice.getApnId(), account.getUuid(), 0, false, Type.RATE_LIMIT_CHALLENGE, Optional.of(tokenHex)));
platform = ClientPlatform.IOS.name().toLowerCase();
} else {
throw new AssertionError();

View File

@@ -27,8 +27,8 @@ import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import static com.codahale.metrics.MetricRegistry.name;
@@ -84,17 +84,19 @@ public class APNSender implements Managed {
Instant.ofEpochMilli(message.getExpirationTime()),
message.isVoip());
Futures.addCallback(future, new FutureCallback<ApnResult>() {
Futures.addCallback(future, new FutureCallback<>() {
@Override
public void onSuccess(@Nullable ApnResult result) {
if (message.getChallengeData().isPresent()) return;
if (message.getChallengeData().isPresent()) {
return;
}
if (result == null) {
logger.warn("*** RECEIVED NULL APN RESULT ***");
} else if (result.getStatus() == ApnResult.Status.NO_SUCH_USER) {
handleUnregisteredUser(message.getApnId(), message.getNumber(), message.getDeviceId());
message.getUuid().ifPresent(uuid -> handleUnregisteredUser(message.getApnId(), uuid, message.getDeviceId()));
} else if (result.getStatus() == ApnResult.Status.GENERIC_FAILURE) {
logger.warn("*** Got APN generic failure: " + result.getReason() + ", " + message.getNumber());
logger.warn("*** Got APN generic failure: " + result.getReason() + ", " + message.getUuid());
}
}
@@ -120,21 +122,21 @@ public class APNSender implements Managed {
this.fallbackManager = fallbackManager;
}
private void handleUnregisteredUser(String registrationId, String number, long deviceId) {
private void handleUnregisteredUser(String registrationId, UUID uuid, long deviceId) {
// logger.info("Got APN Unregistered: " + number + "," + deviceId);
Optional<Account> account = accountsManager.get(number);
Optional<Account> account = accountsManager.get(uuid);
if (!account.isPresent()) {
logger.info("No account found: " + number);
if (account.isEmpty()) {
logger.info("No account found: {}", uuid);
unregisteredEventStale.mark();
return;
}
Optional<Device> device = account.get().getDevice(deviceId);
if (!device.isPresent()) {
logger.info("No device found: " + number);
if (device.isEmpty()) {
logger.info("No device found: {}", uuid);
unregisteredEventStale.mark();
return;
}
@@ -157,7 +159,7 @@ public class APNSender implements Managed {
if (tokenTimestamp != 0 && System.currentTimeMillis() < tokenTimestamp + TimeUnit.SECONDS.toMillis(10))
{
logger.info("APN Unregister push timestamp is more recent: " + tokenTimestamp + ", " + number);
logger.info("APN Unregister push timestamp is more recent: {}, {}", tokenTimestamp, uuid);
unregisteredEventStale.mark();
return;
}

View File

@@ -193,7 +193,7 @@ public class ApnFallbackManager implements Managed {
return;
}
apnSender.sendMessage(new ApnMessage(apnId, account.getNumber(), device.getId(), true, Type.NOTIFICATION, Optional.empty()));
apnSender.sendMessage(new ApnMessage(apnId, account.getUuid(), device.getId(), true, Type.NOTIFICATION, Optional.empty()));
retry.mark();
}

View File

@@ -7,7 +7,9 @@ package org.whispersystems.textsecuregcm.push;
import com.google.common.annotations.VisibleForTesting;
import javax.annotation.Nullable;
import java.util.Optional;
import java.util.UUID;
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
public class ApnMessage {
@@ -23,15 +25,17 @@ public class ApnMessage {
public static final long MAX_EXPIRATION = Integer.MAX_VALUE * 1000L;
private final String apnId;
private final String number;
private final long deviceId;
private final boolean isVoip;
private final Type type;
private final Optional<String> challengeData;
public ApnMessage(String apnId, String number, long deviceId, boolean isVoip, Type type, Optional<String> challengeData) {
@Nullable
private final UUID uuid;
public ApnMessage(String apnId, @Nullable UUID uuid, long deviceId, boolean isVoip, Type type, Optional<String> challengeData) {
this.apnId = apnId;
this.number = number;
this.uuid = uuid;
this.deviceId = deviceId;
this.isVoip = isVoip;
this.type = type;
@@ -71,8 +75,8 @@ public class ApnMessage {
return MAX_EXPIRATION;
}
public String getNumber() {
return number;
public Optional<UUID> getUuid() {
return Optional.ofNullable(uuid);
}
public long getDeviceId() {

View File

@@ -119,8 +119,8 @@ public class GCMSender {
}
private void handleCanonicalRegistrationId(GcmMessage message, Result result) {
logger.warn(String.format("Actually received 'CanonicalRegistrationId' ::: (canonical=%s), (original=%s)",
result.getCanonicalRegistrationId(), message.getGcmId()));
logger.warn("Actually received 'CanonicalRegistrationId' ::: (canonical={}}), (original={}})",
result.getCanonicalRegistrationId(), message.getGcmId());
getAccountForEvent(message).ifPresent(account ->
accountsManager.updateDevice(
@@ -132,15 +132,14 @@ public class GCMSender {
}
private void handleGenericError(GcmMessage message, Result result) {
logger.warn(String.format("Unrecoverable Error ::: (error=%s), (gcm_id=%s), " +
"(destination=%s), (device_id=%d)",
result.getError(), message.getGcmId(), message.getNumber(),
message.getDeviceId()));
logger.warn("Unrecoverable Error ::: (error={}}), (gcm_id={}}), (destination={}}), (device_id={}})",
result.getError(), message.getGcmId(), message.getUuid(), message.getDeviceId());
failure.mark();
}
private Optional<Account> getAccountForEvent(GcmMessage message) {
Optional<Account> account = accountsManager.get(message.getNumber());
Optional<Account> account = message.getUuid().flatMap(accountsManager::get);
if (account.isPresent()) {
Optional<Device> device = account.get().getDevice(message.getDeviceId());

View File

@@ -6,7 +6,9 @@
package org.whispersystems.textsecuregcm.push;
import javax.annotation.Nullable;
import java.util.Optional;
import java.util.UUID;
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
public class GcmMessage {
@@ -16,14 +18,16 @@ public class GcmMessage {
}
private final String gcmId;
private final String number;
private final int deviceId;
private final Type type;
private final Optional<String> data;
public GcmMessage(String gcmId, String number, int deviceId, Type type, Optional<String> data) {
@Nullable
private final UUID uuid;
public GcmMessage(String gcmId, @Nullable UUID uuid, int deviceId, Type type, Optional<String> data) {
this.gcmId = gcmId;
this.number = number;
this.uuid = uuid;
this.deviceId = deviceId;
this.type = type;
this.data = data;
@@ -33,8 +37,8 @@ public class GcmMessage {
return gcmId;
}
public String getNumber() {
return number;
public Optional<UUID> getUuid() {
return Optional.ofNullable(uuid);
}
public Type getType() {

View File

@@ -120,7 +120,7 @@ public class MessageSender implements Managed {
}
private void sendGcmNotification(Account account, Device device) {
GcmMessage gcmMessage = new GcmMessage(device.getGcmId(), account.getNumber(),
GcmMessage gcmMessage = new GcmMessage(device.getGcmId(), account.getUuid(),
(int)device.getId(), GcmMessage.Type.NOTIFICATION, Optional.empty());
gcmSender.sendMessage(gcmMessage);
@@ -132,10 +132,10 @@ public class MessageSender implements Managed {
ApnMessage apnMessage;
if (!Util.isEmpty(device.getVoipApnId())) {
apnMessage = new ApnMessage(device.getVoipApnId(), account.getNumber(), device.getId(), true, Type.NOTIFICATION, Optional.empty());
apnMessage = new ApnMessage(device.getVoipApnId(), account.getUuid(), device.getId(), true, Type.NOTIFICATION, Optional.empty());
RedisOperation.unchecked(() -> apnFallbackManager.schedule(account, device));
} else {
apnMessage = new ApnMessage(device.getApnId(), account.getNumber(), device.getId(), false, Type.NOTIFICATION, Optional.empty());
apnMessage = new ApnMessage(device.getApnId(), account.getUuid(), device.getId(), false, Type.NOTIFICATION, Optional.empty());
}
apnSender.sendMessage(apnMessage);