Remove machinery for setting/storing APNs VOIP tokens
This commit is contained in:
parent
b693cb98d0
commit
92698efd39
|
@ -120,7 +120,6 @@ public class AccountController {
|
||||||
|
|
||||||
accounts.updateDevice(account, device.getId(), d -> {
|
accounts.updateDevice(account, device.getId(), d -> {
|
||||||
d.setApnId(null);
|
d.setApnId(null);
|
||||||
d.setVoipApnId(null);
|
|
||||||
d.setGcmId(registrationId.gcmRegistrationId());
|
d.setGcmId(registrationId.gcmRegistrationId());
|
||||||
d.setFetchesMessages(false);
|
d.setFetchesMessages(false);
|
||||||
});
|
});
|
||||||
|
@ -153,7 +152,6 @@ public class AccountController {
|
||||||
// unconditionally
|
// unconditionally
|
||||||
accounts.updateDevice(account, device.getId(), d -> {
|
accounts.updateDevice(account, device.getId(), d -> {
|
||||||
d.setApnId(registrationId.apnRegistrationId());
|
d.setApnId(registrationId.apnRegistrationId());
|
||||||
d.setVoipApnId(registrationId.voipRegistrationId());
|
|
||||||
d.setGcmId(null);
|
d.setGcmId(null);
|
||||||
d.setFetchesMessages(false);
|
d.setFetchesMessages(false);
|
||||||
});
|
});
|
||||||
|
@ -167,7 +165,6 @@ public class AccountController {
|
||||||
|
|
||||||
accounts.updateDevice(account, device.getId(), d -> {
|
accounts.updateDevice(account, device.getId(), d -> {
|
||||||
d.setApnId(null);
|
d.setApnId(null);
|
||||||
d.setVoipApnId(null);
|
|
||||||
d.setFetchesMessages(false);
|
d.setFetchesMessages(false);
|
||||||
if (d.getId() == 1) {
|
if (d.getId() == 1) {
|
||||||
d.setUserAgent("OWI");
|
d.setUserAgent("OWI");
|
||||||
|
|
|
@ -7,6 +7,5 @@ package org.whispersystems.textsecuregcm.entities;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.validation.constraints.NotEmpty;
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
|
||||||
public record ApnRegistrationId(@NotEmpty String apnRegistrationId,
|
public record ApnRegistrationId(@NotEmpty String apnRegistrationId) {
|
||||||
@Nullable String voipRegistrationId) {
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,8 +54,7 @@ abstract class IdleDevicePushNotificationExperiment implements PushNotificationE
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
boolean hasPushToken(final Device device) {
|
boolean hasPushToken(final Device device) {
|
||||||
// Exclude VOIP tokens since they have their own, distinct delivery mechanism
|
return !StringUtils.isAllBlank(device.getApnId(), device.getGcmId());
|
||||||
return !StringUtils.isAllBlank(device.getApnId(), device.getGcmId()) && StringUtils.isBlank(device.getVoipApnId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -110,7 +110,6 @@ public class DevicesGrpcService extends ReactorDevicesGrpc.DevicesImplBase {
|
||||||
final AuthenticatedDevice authenticatedDevice = AuthenticationUtil.requireAuthenticatedDevice();
|
final AuthenticatedDevice authenticatedDevice = AuthenticationUtil.requireAuthenticatedDevice();
|
||||||
|
|
||||||
@Nullable final String apnsToken;
|
@Nullable final String apnsToken;
|
||||||
@Nullable final String apnsVoipToken;
|
|
||||||
@Nullable final String fcmToken;
|
@Nullable final String fcmToken;
|
||||||
|
|
||||||
switch (request.getTokenRequestCase()) {
|
switch (request.getTokenRequestCase()) {
|
||||||
|
@ -118,12 +117,11 @@ public class DevicesGrpcService extends ReactorDevicesGrpc.DevicesImplBase {
|
||||||
case APNS_TOKEN_REQUEST -> {
|
case APNS_TOKEN_REQUEST -> {
|
||||||
final SetPushTokenRequest.ApnsTokenRequest apnsTokenRequest = request.getApnsTokenRequest();
|
final SetPushTokenRequest.ApnsTokenRequest apnsTokenRequest = request.getApnsTokenRequest();
|
||||||
|
|
||||||
if (StringUtils.isAllBlank(apnsTokenRequest.getApnsToken(), apnsTokenRequest.getApnsVoipToken())) {
|
if (StringUtils.isBlank(apnsTokenRequest.getApnsToken())) {
|
||||||
throw Status.INVALID_ARGUMENT.withDescription("APNs tokens may not both be blank").asRuntimeException();
|
throw Status.INVALID_ARGUMENT.withDescription("APNs token must not be blank").asRuntimeException();
|
||||||
}
|
}
|
||||||
|
|
||||||
apnsToken = StringUtils.stripToNull(apnsTokenRequest.getApnsToken());
|
apnsToken = StringUtils.stripToNull(apnsTokenRequest.getApnsToken());
|
||||||
apnsVoipToken = StringUtils.stripToNull(apnsTokenRequest.getApnsVoipToken());
|
|
||||||
fcmToken = null;
|
fcmToken = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +133,6 @@ public class DevicesGrpcService extends ReactorDevicesGrpc.DevicesImplBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
apnsToken = null;
|
apnsToken = null;
|
||||||
apnsVoipToken = null;
|
|
||||||
fcmToken = StringUtils.stripToNull(fcmTokenRequest.getFcmToken());
|
fcmToken = StringUtils.stripToNull(fcmTokenRequest.getFcmToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,14 +147,12 @@ public class DevicesGrpcService extends ReactorDevicesGrpc.DevicesImplBase {
|
||||||
|
|
||||||
final boolean tokenUnchanged =
|
final boolean tokenUnchanged =
|
||||||
Objects.equals(device.getApnId(), apnsToken) &&
|
Objects.equals(device.getApnId(), apnsToken) &&
|
||||||
Objects.equals(device.getVoipApnId(), apnsVoipToken) &&
|
|
||||||
Objects.equals(device.getGcmId(), fcmToken);
|
Objects.equals(device.getGcmId(), fcmToken);
|
||||||
|
|
||||||
return tokenUnchanged
|
return tokenUnchanged
|
||||||
? Mono.empty()
|
? Mono.empty()
|
||||||
: Mono.fromFuture(() -> accountsManager.updateDeviceAsync(account, authenticatedDevice.deviceId(), d -> {
|
: Mono.fromFuture(() -> accountsManager.updateDeviceAsync(account, authenticatedDevice.deviceId(), d -> {
|
||||||
d.setApnId(apnsToken);
|
d.setApnId(apnsToken);
|
||||||
d.setVoipApnId(apnsVoipToken);
|
|
||||||
d.setGcmId(fcmToken);
|
d.setGcmId(fcmToken);
|
||||||
d.setFetchesMessages(false);
|
d.setFetchesMessages(false);
|
||||||
}));
|
}));
|
||||||
|
@ -172,14 +167,13 @@ public class DevicesGrpcService extends ReactorDevicesGrpc.DevicesImplBase {
|
||||||
return Mono.fromFuture(() -> accountsManager.getByAccountIdentifierAsync(authenticatedDevice.accountIdentifier()))
|
return Mono.fromFuture(() -> accountsManager.getByAccountIdentifierAsync(authenticatedDevice.accountIdentifier()))
|
||||||
.map(maybeAccount -> maybeAccount.orElseThrow(Status.UNAUTHENTICATED::asRuntimeException))
|
.map(maybeAccount -> maybeAccount.orElseThrow(Status.UNAUTHENTICATED::asRuntimeException))
|
||||||
.flatMap(account -> Mono.fromFuture(() -> accountsManager.updateDeviceAsync(account, authenticatedDevice.deviceId(), device -> {
|
.flatMap(account -> Mono.fromFuture(() -> accountsManager.updateDeviceAsync(account, authenticatedDevice.deviceId(), device -> {
|
||||||
if (StringUtils.isNotBlank(device.getApnId()) || StringUtils.isNotBlank(device.getVoipApnId())) {
|
if (StringUtils.isNotBlank(device.getApnId())) {
|
||||||
device.setUserAgent(device.isPrimary() ? "OWI" : "OWP");
|
device.setUserAgent(device.isPrimary() ? "OWI" : "OWP");
|
||||||
} else if (StringUtils.isNotBlank(device.getGcmId())) {
|
} else if (StringUtils.isNotBlank(device.getGcmId())) {
|
||||||
device.setUserAgent("OWA");
|
device.setUserAgent("OWA");
|
||||||
}
|
}
|
||||||
|
|
||||||
device.setApnId(null);
|
device.setApnId(null);
|
||||||
device.setVoipApnId(null);
|
|
||||||
device.setGcmId(null);
|
device.setGcmId(null);
|
||||||
device.setFetchesMessages(true);
|
device.setFetchesMessages(true);
|
||||||
})))
|
})))
|
||||||
|
|
|
@ -34,12 +34,6 @@ public class APNSender implements Managed, PushNotificationSender {
|
||||||
private final String bundleId;
|
private final String bundleId;
|
||||||
private final ApnsClient apnsClient;
|
private final ApnsClient apnsClient;
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
static final String APN_VOIP_NOTIFICATION_PAYLOAD = new SimpleApnsPayloadBuilder()
|
|
||||||
.setSound("default")
|
|
||||||
.setLocalizedAlertMessage("APN_Message")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static final String APN_NSE_NOTIFICATION_PAYLOAD = new SimpleApnsPayloadBuilder()
|
static final String APN_NSE_NOTIFICATION_PAYLOAD = new SimpleApnsPayloadBuilder()
|
||||||
.setMutableContent(true)
|
.setMutableContent(true)
|
||||||
|
@ -80,22 +74,8 @@ public class APNSender implements Managed, PushNotificationSender {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<SendPushNotificationResult> sendNotification(final PushNotification notification) {
|
public CompletableFuture<SendPushNotificationResult> sendNotification(final PushNotification notification) {
|
||||||
final String topic = switch (notification.tokenType()) {
|
|
||||||
case APN -> bundleId;
|
|
||||||
case APN_VOIP -> bundleId + ".voip";
|
|
||||||
default -> throw new IllegalArgumentException("Unsupported token type: " + notification.tokenType());
|
|
||||||
};
|
|
||||||
|
|
||||||
final boolean isVoip = notification.tokenType() == PushNotification.TokenType.APN_VOIP;
|
|
||||||
|
|
||||||
final String payload = switch (notification.notificationType()) {
|
final String payload = switch (notification.notificationType()) {
|
||||||
case NOTIFICATION -> {
|
case NOTIFICATION -> notification.urgent() ? APN_NSE_NOTIFICATION_PAYLOAD : APN_BACKGROUND_PAYLOAD;
|
||||||
if (isVoip) {
|
|
||||||
yield APN_VOIP_NOTIFICATION_PAYLOAD;
|
|
||||||
} else {
|
|
||||||
yield notification.urgent() ? APN_NSE_NOTIFICATION_PAYLOAD : APN_BACKGROUND_PAYLOAD;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case ATTEMPT_LOGIN_NOTIFICATION_HIGH_PRIORITY -> new SimpleApnsPayloadBuilder()
|
case ATTEMPT_LOGIN_NOTIFICATION_HIGH_PRIORITY -> new SimpleApnsPayloadBuilder()
|
||||||
.setMutableContent(true)
|
.setMutableContent(true)
|
||||||
|
@ -115,13 +95,7 @@ public class APNSender implements Managed, PushNotificationSender {
|
||||||
};
|
};
|
||||||
|
|
||||||
final PushType pushType = switch (notification.notificationType()) {
|
final PushType pushType = switch (notification.notificationType()) {
|
||||||
case NOTIFICATION -> {
|
case NOTIFICATION -> notification.urgent() ? PushType.ALERT : PushType.BACKGROUND;
|
||||||
if (isVoip) {
|
|
||||||
yield PushType.VOIP;
|
|
||||||
} else {
|
|
||||||
yield notification.urgent() ? PushType.ALERT : PushType.BACKGROUND;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case ATTEMPT_LOGIN_NOTIFICATION_HIGH_PRIORITY -> PushType.ALERT;
|
case ATTEMPT_LOGIN_NOTIFICATION_HIGH_PRIORITY -> PushType.ALERT;
|
||||||
case CHALLENGE, RATE_LIMIT_CHALLENGE -> PushType.BACKGROUND;
|
case CHALLENGE, RATE_LIMIT_CHALLENGE -> PushType.BACKGROUND;
|
||||||
};
|
};
|
||||||
|
@ -131,19 +105,17 @@ public class APNSender implements Managed, PushNotificationSender {
|
||||||
if (pushType == PushType.BACKGROUND) {
|
if (pushType == PushType.BACKGROUND) {
|
||||||
deliveryPriority = DeliveryPriority.CONSERVE_POWER;
|
deliveryPriority = DeliveryPriority.CONSERVE_POWER;
|
||||||
} else {
|
} else {
|
||||||
deliveryPriority = (notification.urgent() || isVoip)
|
deliveryPriority = notification.urgent() ? DeliveryPriority.IMMEDIATE : DeliveryPriority.CONSERVE_POWER;
|
||||||
? DeliveryPriority.IMMEDIATE
|
|
||||||
: DeliveryPriority.CONSERVE_POWER;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final String collapseId =
|
final String collapseId =
|
||||||
(notification.notificationType() == PushNotification.NotificationType.NOTIFICATION && notification.urgent() && !isVoip)
|
(notification.notificationType() == PushNotification.NotificationType.NOTIFICATION && notification.urgent())
|
||||||
? "incoming-message" : null;
|
? "incoming-message" : null;
|
||||||
|
|
||||||
final Instant start = Instant.now();
|
final Instant start = Instant.now();
|
||||||
|
|
||||||
return apnsClient.sendNotification(new SimpleApnsPushNotification(notification.deviceToken(),
|
return apnsClient.sendNotification(new SimpleApnsPushNotification(notification.deviceToken(),
|
||||||
topic,
|
bundleId,
|
||||||
payload,
|
payload,
|
||||||
MAX_EXPIRATION,
|
MAX_EXPIRATION,
|
||||||
deliveryPriority,
|
deliveryPriority,
|
||||||
|
|
|
@ -26,7 +26,6 @@ public record PushNotification(String deviceToken,
|
||||||
|
|
||||||
public enum TokenType {
|
public enum TokenType {
|
||||||
FCM,
|
FCM,
|
||||||
APN,
|
APN
|
||||||
APN_VOIP,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,8 +90,6 @@ public class PushNotificationManager {
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(device.getGcmId())) {
|
if (StringUtils.isNotBlank(device.getGcmId())) {
|
||||||
tokenAndType = new Pair<>(device.getGcmId(), PushNotification.TokenType.FCM);
|
tokenAndType = new Pair<>(device.getGcmId(), PushNotification.TokenType.FCM);
|
||||||
} else if (StringUtils.isNotBlank(device.getVoipApnId())) {
|
|
||||||
tokenAndType = new Pair<>(device.getVoipApnId(), PushNotification.TokenType.APN_VOIP);
|
|
||||||
} else if (StringUtils.isNotBlank(device.getApnId())) {
|
} else if (StringUtils.isNotBlank(device.getApnId())) {
|
||||||
tokenAndType = new Pair<>(device.getApnId(), PushNotification.TokenType.APN);
|
tokenAndType = new Pair<>(device.getApnId(), PushNotification.TokenType.APN);
|
||||||
} else {
|
} else {
|
||||||
|
@ -115,7 +113,7 @@ public class PushNotificationManager {
|
||||||
|
|
||||||
final PushNotificationSender sender = switch (pushNotification.tokenType()) {
|
final PushNotificationSender sender = switch (pushNotification.tokenType()) {
|
||||||
case FCM -> fcmSender;
|
case FCM -> fcmSender;
|
||||||
case APN, APN_VOIP -> apnSender;
|
case APN -> apnSender;
|
||||||
};
|
};
|
||||||
|
|
||||||
return sender.sendNotification(pushNotification).whenComplete((result, throwable) -> {
|
return sender.sendNotification(pushNotification).whenComplete((result, throwable) -> {
|
||||||
|
@ -171,7 +169,7 @@ public class PushNotificationManager {
|
||||||
tokenInvalidationTimestamp.isAfter(Instant.ofEpochMilli(device.getPushTimestamp()))).orElse(true);
|
tokenInvalidationTimestamp.isAfter(Instant.ofEpochMilli(device.getPushTimestamp()))).orElse(true);
|
||||||
|
|
||||||
if (tokenExpired) {
|
if (tokenExpired) {
|
||||||
if (tokenType == PushNotification.TokenType.APN || tokenType == PushNotification.TokenType.APN_VOIP) {
|
if (tokenType == PushNotification.TokenType.APN) {
|
||||||
pushNotificationScheduler.cancelScheduledNotifications(account, device).whenComplete(logErrors());
|
pushNotificationScheduler.cancelScheduledNotifications(account, device).whenComplete(logErrors());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,7 +201,6 @@ public class PushNotificationManager {
|
||||||
switch (tokenType) {
|
switch (tokenType) {
|
||||||
case FCM -> d.setGcmId(null);
|
case FCM -> d.setGcmId(null);
|
||||||
case APN -> d.setApnId(null);
|
case APN -> d.setApnId(null);
|
||||||
case APN_VOIP -> d.setVoipApnId(null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})));
|
})));
|
||||||
|
@ -213,7 +210,6 @@ public class PushNotificationManager {
|
||||||
return switch (tokenType) {
|
return switch (tokenType) {
|
||||||
case FCM -> device.getGcmId();
|
case FCM -> device.getGcmId();
|
||||||
case APN -> device.getApnId();
|
case APN -> device.getApnId();
|
||||||
case APN_VOIP -> device.getVoipApnId();
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,9 +49,6 @@ public class Device {
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private String apnId;
|
private String apnId;
|
||||||
|
|
||||||
@JsonProperty
|
|
||||||
private String voipApnId;
|
|
||||||
|
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private long pushTimestamp;
|
private long pushTimestamp;
|
||||||
|
|
||||||
|
@ -89,14 +86,6 @@ public class Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getVoipApnId() {
|
|
||||||
return voipApnId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVoipApnId(String voipApnId) {
|
|
||||||
this.voipApnId = voipApnId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLastSeen(long lastSeen) {
|
public void setLastSeen(long lastSeen) {
|
||||||
this.lastSeen = lastSeen;
|
this.lastSeen = lastSeen;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,13 +39,8 @@ public record DeviceSpec(
|
||||||
device.setLastSeen(Util.todayInMillis());
|
device.setLastSeen(Util.todayInMillis());
|
||||||
device.setUserAgent(signalAgent());
|
device.setUserAgent(signalAgent());
|
||||||
|
|
||||||
apnRegistrationId().ifPresent(apnRegistrationId -> {
|
apnRegistrationId().ifPresent(apnRegistrationId -> device.setApnId(apnRegistrationId.apnRegistrationId()));
|
||||||
device.setApnId(apnRegistrationId.apnRegistrationId());
|
gcmRegistrationId().ifPresent(gcmRegistrationId -> device.setGcmId(gcmRegistrationId.gcmRegistrationId()));
|
||||||
device.setVoipApnId(apnRegistrationId.voipRegistrationId());
|
|
||||||
});
|
|
||||||
|
|
||||||
gcmRegistrationId().ifPresent(gcmRegistrationId ->
|
|
||||||
device.setGcmId(gcmRegistrationId.gcmRegistrationId()));
|
|
||||||
|
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,7 +182,6 @@ public class NotifyIdleDevicesCommand extends AbstractSinglePassCrawlAccountsCom
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static boolean hasPushToken(final Device device) {
|
static boolean hasPushToken(final Device device) {
|
||||||
// Exclude VOIP tokens since they have their own, distinct delivery mechanism
|
return !StringUtils.isAllBlank(device.getApnId(), device.getGcmId());
|
||||||
return !StringUtils.isAllBlank(device.getApnId(), device.getGcmId()) && StringUtils.isBlank(device.getVoipApnId());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,13 +107,6 @@ message SetPushTokenRequest {
|
||||||
* A "standard" APNs device token.
|
* A "standard" APNs device token.
|
||||||
*/
|
*/
|
||||||
string apns_token = 1;
|
string apns_token = 1;
|
||||||
|
|
||||||
/**
|
|
||||||
* A VoIP APNs device token. If present, the server will prefer to send
|
|
||||||
* message notifications to the device using this token on a VOIP APNs
|
|
||||||
* topic.
|
|
||||||
*/
|
|
||||||
string apns_voip_token = 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message FcmTokenRequest {
|
message FcmTokenRequest {
|
||||||
|
|
|
@ -308,29 +308,11 @@ class AccountControllerTest {
|
||||||
.request()
|
.request()
|
||||||
.header(HttpHeaders.AUTHORIZATION,
|
.header(HttpHeaders.AUTHORIZATION,
|
||||||
AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_3, AuthHelper.VALID_PASSWORD_3_PRIMARY))
|
AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_3, AuthHelper.VALID_PASSWORD_3_PRIMARY))
|
||||||
.put(Entity.json(new ApnRegistrationId("first", "second")))) {
|
.put(Entity.json(new ApnRegistrationId("first")))) {
|
||||||
|
|
||||||
assertThat(response.getStatus()).isEqualTo(204);
|
assertThat(response.getStatus()).isEqualTo(204);
|
||||||
|
|
||||||
verify(AuthHelper.VALID_DEVICE_3_PRIMARY, times(1)).setApnId(eq("first"));
|
verify(AuthHelper.VALID_DEVICE_3_PRIMARY, times(1)).setApnId(eq("first"));
|
||||||
verify(AuthHelper.VALID_DEVICE_3_PRIMARY, times(1)).setVoipApnId(eq("second"));
|
|
||||||
verify(accountsManager, times(1)).updateDevice(eq(AuthHelper.VALID_ACCOUNT_3), anyByte(), any());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testSetApnIdNoVoip() {
|
|
||||||
try (final Response response = resources.getJerseyTest()
|
|
||||||
.target("/v1/accounts/apn/")
|
|
||||||
.request()
|
|
||||||
.header(HttpHeaders.AUTHORIZATION,
|
|
||||||
AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_3, AuthHelper.VALID_PASSWORD_3_PRIMARY))
|
|
||||||
.put(Entity.json(new ApnRegistrationId("first", null)))) {
|
|
||||||
|
|
||||||
assertThat(response.getStatus()).isEqualTo(204);
|
|
||||||
|
|
||||||
verify(AuthHelper.VALID_DEVICE_3_PRIMARY, times(1)).setApnId(eq("first"));
|
|
||||||
verify(AuthHelper.VALID_DEVICE_3_PRIMARY, times(1)).setVoipApnId(null);
|
|
||||||
verify(accountsManager, times(1)).updateDevice(eq(AuthHelper.VALID_ACCOUNT_3), anyByte(), any());
|
verify(accountsManager, times(1)).updateDevice(eq(AuthHelper.VALID_ACCOUNT_3), anyByte(), any());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,7 +177,6 @@ class DeviceControllerTest {
|
||||||
final Optional<ApnRegistrationId> apnRegistrationId,
|
final Optional<ApnRegistrationId> apnRegistrationId,
|
||||||
final Optional<GcmRegistrationId> gcmRegistrationId,
|
final Optional<GcmRegistrationId> gcmRegistrationId,
|
||||||
final Optional<String> expectedApnsToken,
|
final Optional<String> expectedApnsToken,
|
||||||
final Optional<String> expectedApnsVoipToken,
|
|
||||||
final Optional<String> expectedGcmToken) {
|
final Optional<String> expectedGcmToken) {
|
||||||
|
|
||||||
final Device existingDevice = mock(Device.class);
|
final Device existingDevice = mock(Device.class);
|
||||||
|
@ -240,9 +239,6 @@ class DeviceControllerTest {
|
||||||
expectedApnsToken.ifPresentOrElse(expectedToken -> assertEquals(expectedToken, device.getApnId()),
|
expectedApnsToken.ifPresentOrElse(expectedToken -> assertEquals(expectedToken, device.getApnId()),
|
||||||
() -> assertNull(device.getApnId()));
|
() -> assertNull(device.getApnId()));
|
||||||
|
|
||||||
expectedApnsVoipToken.ifPresentOrElse(expectedToken -> assertEquals(expectedToken, device.getVoipApnId()),
|
|
||||||
() -> assertNull(device.getVoipApnId()));
|
|
||||||
|
|
||||||
expectedGcmToken.ifPresentOrElse(expectedToken -> assertEquals(expectedToken, device.getGcmId()),
|
expectedGcmToken.ifPresentOrElse(expectedToken -> assertEquals(expectedToken, device.getGcmId()),
|
||||||
() -> assertNull(device.getGcmId()));
|
() -> assertNull(device.getGcmId()));
|
||||||
|
|
||||||
|
@ -251,14 +247,13 @@ class DeviceControllerTest {
|
||||||
|
|
||||||
private static Stream<Arguments> linkDeviceAtomic() {
|
private static Stream<Arguments> linkDeviceAtomic() {
|
||||||
final String apnsToken = "apns-token";
|
final String apnsToken = "apns-token";
|
||||||
final String apnsVoipToken = "apns-voip-token";
|
|
||||||
final String gcmToken = "gcm-token";
|
final String gcmToken = "gcm-token";
|
||||||
|
|
||||||
return Stream.of(
|
return Stream.of(
|
||||||
Arguments.of(true, Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty()),
|
Arguments.of(true, Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty()),
|
||||||
Arguments.of(false, Optional.of(new ApnRegistrationId(apnsToken, null)), Optional.empty(), Optional.of(apnsToken), Optional.empty(), Optional.empty()),
|
Arguments.of(false, Optional.of(new ApnRegistrationId(apnsToken)), Optional.empty(), Optional.of(apnsToken), Optional.empty()),
|
||||||
Arguments.of(false, Optional.of(new ApnRegistrationId(apnsToken, apnsVoipToken)), Optional.empty(), Optional.of(apnsToken), Optional.of(apnsVoipToken), Optional.empty()),
|
Arguments.of(false, Optional.of(new ApnRegistrationId(apnsToken)), Optional.empty(), Optional.of(apnsToken), Optional.empty()),
|
||||||
Arguments.of(false, Optional.empty(), Optional.of(new GcmRegistrationId(gcmToken)), Optional.empty(), Optional.empty(), Optional.of(gcmToken))
|
Arguments.of(false, Optional.empty(), Optional.of(new GcmRegistrationId(gcmToken)), Optional.empty(), Optional.of(gcmToken))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -496,10 +491,10 @@ class DeviceControllerTest {
|
||||||
|
|
||||||
private static Stream<Arguments> linkDeviceAtomicConflictingChannel() {
|
private static Stream<Arguments> linkDeviceAtomicConflictingChannel() {
|
||||||
return Stream.of(
|
return Stream.of(
|
||||||
Arguments.of(true, Optional.of(new ApnRegistrationId("apns-token", null)), Optional.of(new GcmRegistrationId("gcm-token"))),
|
Arguments.of(true, Optional.of(new ApnRegistrationId("apns-token")), Optional.of(new GcmRegistrationId("gcm-token"))),
|
||||||
Arguments.of(true, Optional.empty(), Optional.of(new GcmRegistrationId("gcm-token"))),
|
Arguments.of(true, Optional.empty(), Optional.of(new GcmRegistrationId("gcm-token"))),
|
||||||
Arguments.of(true, Optional.of(new ApnRegistrationId("apns-token", null)), Optional.empty()),
|
Arguments.of(true, Optional.of(new ApnRegistrationId("apns-token")), Optional.empty()),
|
||||||
Arguments.of(false, Optional.of(new ApnRegistrationId("apns-token", null)), Optional.of(new GcmRegistrationId("gcm-token")))
|
Arguments.of(false, Optional.of(new ApnRegistrationId("apns-token")), Optional.of(new GcmRegistrationId("gcm-token")))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -737,7 +732,7 @@ class DeviceControllerTest {
|
||||||
|
|
||||||
final LinkDeviceRequest request = new LinkDeviceRequest(deviceCode.verificationCode(),
|
final LinkDeviceRequest request = new LinkDeviceRequest(deviceCode.verificationCode(),
|
||||||
new AccountAttributes(false, registrationId, pniRegistrationId, null, null, true, new DeviceCapabilities(true, true, true, false, false)),
|
new AccountAttributes(false, registrationId, pniRegistrationId, null, null, true, new DeviceCapabilities(true, true, true, false, false)),
|
||||||
new DeviceActivationRequest(aciSignedPreKey, pniSignedPreKey, aciPqLastResortPreKey, pniPqLastResortPreKey, Optional.of(new ApnRegistrationId("apn", null)), Optional.empty()));
|
new DeviceActivationRequest(aciSignedPreKey, pniSignedPreKey, aciPqLastResortPreKey, pniPqLastResortPreKey, Optional.of(new ApnRegistrationId("apn")), Optional.empty()));
|
||||||
|
|
||||||
try (final Response response = resources.getJerseyTest()
|
try (final Response response = resources.getJerseyTest()
|
||||||
.target("/v1/devices/link")
|
.target("/v1/devices/link")
|
||||||
|
|
|
@ -543,7 +543,7 @@ class RegistrationControllerTest {
|
||||||
pniSignedPreKey,
|
pniSignedPreKey,
|
||||||
aciPqLastResortPreKey,
|
aciPqLastResortPreKey,
|
||||||
pniPqLastResortPreKey,
|
pniPqLastResortPreKey,
|
||||||
Optional.of(new ApnRegistrationId("apns-token", null)),
|
Optional.of(new ApnRegistrationId("apns-token")),
|
||||||
Optional.empty())),
|
Optional.empty())),
|
||||||
|
|
||||||
// "Fetches messages" is true, but an FCM (GCM) token is provided
|
// "Fetches messages" is true, but an FCM (GCM) token is provided
|
||||||
|
@ -571,7 +571,7 @@ class RegistrationControllerTest {
|
||||||
pniSignedPreKey,
|
pniSignedPreKey,
|
||||||
aciPqLastResortPreKey,
|
aciPqLastResortPreKey,
|
||||||
pniPqLastResortPreKey,
|
pniPqLastResortPreKey,
|
||||||
Optional.of(new ApnRegistrationId("apns-token", null)),
|
Optional.of(new ApnRegistrationId("apns-token")),
|
||||||
Optional.of(new GcmRegistrationId("gcm-token"))))
|
Optional.of(new GcmRegistrationId("gcm-token"))))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -795,7 +795,6 @@ class RegistrationControllerTest {
|
||||||
new AccountAttributes(false, registrationId, pniRegistrationId, "test".getBytes(StandardCharsets.UTF_8), null, true, new Device.DeviceCapabilities(false, false, false, false, false));
|
new AccountAttributes(false, registrationId, pniRegistrationId, "test".getBytes(StandardCharsets.UTF_8), null, true, new Device.DeviceCapabilities(false, false, false, false, false));
|
||||||
|
|
||||||
final String apnsToken = "apns-token";
|
final String apnsToken = "apns-token";
|
||||||
final String apnsVoipToken = "apns-voip-token";
|
|
||||||
final String gcmToken = "gcm-token";
|
final String gcmToken = "gcm-token";
|
||||||
|
|
||||||
return Stream.of(
|
return Stream.of(
|
||||||
|
@ -840,7 +839,7 @@ class RegistrationControllerTest {
|
||||||
pniSignedPreKey,
|
pniSignedPreKey,
|
||||||
aciPqLastResortPreKey,
|
aciPqLastResortPreKey,
|
||||||
pniPqLastResortPreKey,
|
pniPqLastResortPreKey,
|
||||||
Optional.of(new ApnRegistrationId(apnsToken, apnsVoipToken)),
|
Optional.of(new ApnRegistrationId(apnsToken)),
|
||||||
Optional.empty()),
|
Optional.empty()),
|
||||||
aciIdentityKey,
|
aciIdentityKey,
|
||||||
pniIdentityKey,
|
pniIdentityKey,
|
||||||
|
@ -852,7 +851,7 @@ class RegistrationControllerTest {
|
||||||
registrationId,
|
registrationId,
|
||||||
pniRegistrationId,
|
pniRegistrationId,
|
||||||
false,
|
false,
|
||||||
Optional.of(new ApnRegistrationId(apnsToken, apnsVoipToken)),
|
Optional.of(new ApnRegistrationId(apnsToken)),
|
||||||
Optional.empty(),
|
Optional.empty(),
|
||||||
aciSignedPreKey,
|
aciSignedPreKey,
|
||||||
pniSignedPreKey,
|
pniSignedPreKey,
|
||||||
|
|
|
@ -56,15 +56,6 @@ abstract class IdleDevicePushNotificationExperimentTest {
|
||||||
arguments.add(Arguments.of(device, true));
|
arguments.add(Arguments.of(device, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
// APNs VOIP token
|
|
||||||
final Device device = mock(Device.class);
|
|
||||||
when(device.getApnId()).thenReturn("apns-token");
|
|
||||||
when(device.getVoipApnId()).thenReturn("apns-voip-token");
|
|
||||||
|
|
||||||
arguments.add(Arguments.of(device, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
return arguments;
|
return arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -217,7 +217,6 @@ class DevicesGrpcServiceTest extends SimpleBaseGrpcTest<DevicesGrpcService, Devi
|
||||||
void setPushToken(final byte deviceId,
|
void setPushToken(final byte deviceId,
|
||||||
final SetPushTokenRequest request,
|
final SetPushTokenRequest request,
|
||||||
@Nullable final String expectedApnsToken,
|
@Nullable final String expectedApnsToken,
|
||||||
@Nullable final String expectedApnsVoipToken,
|
|
||||||
@Nullable final String expectedFcmToken) {
|
@Nullable final String expectedFcmToken) {
|
||||||
|
|
||||||
mockAuthenticationInterceptor().setAuthenticatedDevice(AUTHENTICATED_ACI, deviceId);
|
mockAuthenticationInterceptor().setAuthenticatedDevice(AUTHENTICATED_ACI, deviceId);
|
||||||
|
@ -228,14 +227,12 @@ class DevicesGrpcServiceTest extends SimpleBaseGrpcTest<DevicesGrpcService, Devi
|
||||||
final SetPushTokenResponse ignored = authenticatedServiceStub().setPushToken(request);
|
final SetPushTokenResponse ignored = authenticatedServiceStub().setPushToken(request);
|
||||||
|
|
||||||
verify(device).setApnId(expectedApnsToken);
|
verify(device).setApnId(expectedApnsToken);
|
||||||
verify(device).setVoipApnId(expectedApnsVoipToken);
|
|
||||||
verify(device).setGcmId(expectedFcmToken);
|
verify(device).setGcmId(expectedFcmToken);
|
||||||
verify(device).setFetchesMessages(false);
|
verify(device).setFetchesMessages(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Stream<Arguments> setPushToken() {
|
private static Stream<Arguments> setPushToken() {
|
||||||
final String apnsToken = "apns-token";
|
final String apnsToken = "apns-token";
|
||||||
final String apnsVoipToken = "apns-voip-token";
|
|
||||||
final String fcmToken = "fcm-token";
|
final String fcmToken = "fcm-token";
|
||||||
|
|
||||||
final Stream.Builder<Arguments> streamBuilder = Stream.builder();
|
final Stream.Builder<Arguments> streamBuilder = Stream.builder();
|
||||||
|
@ -245,18 +242,9 @@ class DevicesGrpcServiceTest extends SimpleBaseGrpcTest<DevicesGrpcService, Devi
|
||||||
SetPushTokenRequest.newBuilder()
|
SetPushTokenRequest.newBuilder()
|
||||||
.setApnsTokenRequest(SetPushTokenRequest.ApnsTokenRequest.newBuilder()
|
.setApnsTokenRequest(SetPushTokenRequest.ApnsTokenRequest.newBuilder()
|
||||||
.setApnsToken(apnsToken)
|
.setApnsToken(apnsToken)
|
||||||
.setApnsVoipToken(apnsVoipToken)
|
|
||||||
.build())
|
.build())
|
||||||
.build(),
|
.build(),
|
||||||
apnsToken, apnsVoipToken, null));
|
apnsToken, null));
|
||||||
|
|
||||||
streamBuilder.add(Arguments.of(deviceId,
|
|
||||||
SetPushTokenRequest.newBuilder()
|
|
||||||
.setApnsTokenRequest(SetPushTokenRequest.ApnsTokenRequest.newBuilder()
|
|
||||||
.setApnsToken(apnsToken)
|
|
||||||
.build())
|
|
||||||
.build(),
|
|
||||||
apnsToken, null, null));
|
|
||||||
|
|
||||||
streamBuilder.add(Arguments.of(deviceId,
|
streamBuilder.add(Arguments.of(deviceId,
|
||||||
SetPushTokenRequest.newBuilder()
|
SetPushTokenRequest.newBuilder()
|
||||||
|
@ -264,7 +252,7 @@ class DevicesGrpcServiceTest extends SimpleBaseGrpcTest<DevicesGrpcService, Devi
|
||||||
.setFcmToken(fcmToken)
|
.setFcmToken(fcmToken)
|
||||||
.build())
|
.build())
|
||||||
.build(),
|
.build(),
|
||||||
null, null, fcmToken));
|
null, fcmToken));
|
||||||
}
|
}
|
||||||
|
|
||||||
return streamBuilder.build();
|
return streamBuilder.build();
|
||||||
|
@ -274,12 +262,10 @@ class DevicesGrpcServiceTest extends SimpleBaseGrpcTest<DevicesGrpcService, Devi
|
||||||
@MethodSource
|
@MethodSource
|
||||||
void setPushTokenUnchanged(final SetPushTokenRequest request,
|
void setPushTokenUnchanged(final SetPushTokenRequest request,
|
||||||
@Nullable final String apnsToken,
|
@Nullable final String apnsToken,
|
||||||
@Nullable final String apnsVoipToken,
|
|
||||||
@Nullable final String fcmToken) {
|
@Nullable final String fcmToken) {
|
||||||
|
|
||||||
final Device device = mock(Device.class);
|
final Device device = mock(Device.class);
|
||||||
when(device.getApnId()).thenReturn(apnsToken);
|
when(device.getApnId()).thenReturn(apnsToken);
|
||||||
when(device.getVoipApnId()).thenReturn(apnsVoipToken);
|
|
||||||
when(device.getGcmId()).thenReturn(fcmToken);
|
when(device.getGcmId()).thenReturn(fcmToken);
|
||||||
|
|
||||||
when(authenticatedAccount.getDevice(AUTHENTICATED_DEVICE_ID)).thenReturn(Optional.of(device));
|
when(authenticatedAccount.getDevice(AUTHENTICATED_DEVICE_ID)).thenReturn(Optional.of(device));
|
||||||
|
@ -291,31 +277,22 @@ class DevicesGrpcServiceTest extends SimpleBaseGrpcTest<DevicesGrpcService, Devi
|
||||||
|
|
||||||
private static Stream<Arguments> setPushTokenUnchanged() {
|
private static Stream<Arguments> setPushTokenUnchanged() {
|
||||||
final String apnsToken = "apns-token";
|
final String apnsToken = "apns-token";
|
||||||
final String apnsVoipToken = "apns-voip-token";
|
|
||||||
final String fcmToken = "fcm-token";
|
final String fcmToken = "fcm-token";
|
||||||
|
|
||||||
return Stream.of(
|
return Stream.of(
|
||||||
Arguments.of(SetPushTokenRequest.newBuilder()
|
Arguments.of(SetPushTokenRequest.newBuilder()
|
||||||
.setApnsTokenRequest(SetPushTokenRequest.ApnsTokenRequest.newBuilder()
|
.setApnsTokenRequest(SetPushTokenRequest.ApnsTokenRequest.newBuilder()
|
||||||
.setApnsToken(apnsToken)
|
.setApnsToken(apnsToken)
|
||||||
.setApnsVoipToken(apnsVoipToken)
|
|
||||||
.build())
|
.build())
|
||||||
.build(),
|
.build(),
|
||||||
apnsToken, apnsVoipToken, null, false),
|
apnsToken, null, false),
|
||||||
|
|
||||||
Arguments.of(SetPushTokenRequest.newBuilder()
|
|
||||||
.setApnsTokenRequest(SetPushTokenRequest.ApnsTokenRequest.newBuilder()
|
|
||||||
.setApnsToken(apnsToken)
|
|
||||||
.build())
|
|
||||||
.build(),
|
|
||||||
apnsToken, null, null, false),
|
|
||||||
|
|
||||||
Arguments.of(SetPushTokenRequest.newBuilder()
|
Arguments.of(SetPushTokenRequest.newBuilder()
|
||||||
.setFcmTokenRequest(SetPushTokenRequest.FcmTokenRequest.newBuilder()
|
.setFcmTokenRequest(SetPushTokenRequest.FcmTokenRequest.newBuilder()
|
||||||
.setFcmToken(fcmToken)
|
.setFcmToken(fcmToken)
|
||||||
.build())
|
.build())
|
||||||
.build(),
|
.build(),
|
||||||
null, null, fcmToken, false)
|
null, fcmToken, false)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,7 +323,6 @@ class DevicesGrpcServiceTest extends SimpleBaseGrpcTest<DevicesGrpcService, Devi
|
||||||
@MethodSource
|
@MethodSource
|
||||||
void clearPushToken(final byte deviceId,
|
void clearPushToken(final byte deviceId,
|
||||||
@Nullable final String apnsToken,
|
@Nullable final String apnsToken,
|
||||||
@Nullable final String apnsVoipToken,
|
|
||||||
@Nullable final String fcmToken,
|
@Nullable final String fcmToken,
|
||||||
@Nullable final String expectedUserAgent) {
|
@Nullable final String expectedUserAgent) {
|
||||||
|
|
||||||
|
@ -356,14 +332,12 @@ class DevicesGrpcServiceTest extends SimpleBaseGrpcTest<DevicesGrpcService, Devi
|
||||||
when(device.getId()).thenReturn(deviceId);
|
when(device.getId()).thenReturn(deviceId);
|
||||||
when(device.isPrimary()).thenReturn(deviceId == Device.PRIMARY_ID);
|
when(device.isPrimary()).thenReturn(deviceId == Device.PRIMARY_ID);
|
||||||
when(device.getApnId()).thenReturn(apnsToken);
|
when(device.getApnId()).thenReturn(apnsToken);
|
||||||
when(device.getVoipApnId()).thenReturn(apnsVoipToken);
|
|
||||||
when(device.getGcmId()).thenReturn(fcmToken);
|
when(device.getGcmId()).thenReturn(fcmToken);
|
||||||
when(authenticatedAccount.getDevice(deviceId)).thenReturn(Optional.of(device));
|
when(authenticatedAccount.getDevice(deviceId)).thenReturn(Optional.of(device));
|
||||||
|
|
||||||
final ClearPushTokenResponse ignored = authenticatedServiceStub().clearPushToken(ClearPushTokenRequest.newBuilder().build());
|
final ClearPushTokenResponse ignored = authenticatedServiceStub().clearPushToken(ClearPushTokenRequest.newBuilder().build());
|
||||||
|
|
||||||
verify(device).setApnId(null);
|
verify(device).setApnId(null);
|
||||||
verify(device).setVoipApnId(null);
|
|
||||||
verify(device).setGcmId(null);
|
verify(device).setGcmId(null);
|
||||||
verify(device).setFetchesMessages(true);
|
verify(device).setFetchesMessages(true);
|
||||||
|
|
||||||
|
@ -376,16 +350,12 @@ class DevicesGrpcServiceTest extends SimpleBaseGrpcTest<DevicesGrpcService, Devi
|
||||||
|
|
||||||
private static Stream<Arguments> clearPushToken() {
|
private static Stream<Arguments> clearPushToken() {
|
||||||
return Stream.of(
|
return Stream.of(
|
||||||
Arguments.of(Device.PRIMARY_ID, "apns-token", null, null, "OWI"),
|
Arguments.of(Device.PRIMARY_ID, "apns-token", null, "OWI"),
|
||||||
Arguments.of(Device.PRIMARY_ID, "apns-token", "apns-voip-token", null, "OWI"),
|
Arguments.of(Device.PRIMARY_ID, null, "fcm-token", "OWA"),
|
||||||
Arguments.of(Device.PRIMARY_ID, null, "apns-voip-token", null, "OWI"),
|
Arguments.of(Device.PRIMARY_ID, null, null, null),
|
||||||
Arguments.of(Device.PRIMARY_ID, null, null, "fcm-token", "OWA"),
|
Arguments.of((byte) (Device.PRIMARY_ID + 1), "apns-token", null, "OWP"),
|
||||||
Arguments.of(Device.PRIMARY_ID, null, null, null, null),
|
Arguments.of((byte) (Device.PRIMARY_ID + 1), null, "fcm-token", "OWA"),
|
||||||
Arguments.of((byte) (Device.PRIMARY_ID + 1), "apns-token", null, null, "OWP"),
|
Arguments.of((byte) (Device.PRIMARY_ID + 1), null, null, null)
|
||||||
Arguments.of((byte) (Device.PRIMARY_ID + 1), "apns-token", "apns-voip-token", null, "OWP"),
|
|
||||||
Arguments.of((byte) (Device.PRIMARY_ID + 1), null, "apns-voip-token", null, "OWP"),
|
|
||||||
Arguments.of((byte) (Device.PRIMARY_ID + 1), null, null, "fcm-token", "OWA"),
|
|
||||||
Arguments.of((byte) (Device.PRIMARY_ID + 1), null, null, null, null)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,38 +58,6 @@ class APNSenderTest {
|
||||||
when(destinationDevice.getApnId()).thenReturn(DESTINATION_DEVICE_TOKEN);
|
when(destinationDevice.getApnId()).thenReturn(DESTINATION_DEVICE_TOKEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
|
||||||
@ValueSource(booleans = {true, false})
|
|
||||||
void testSendVoip(final boolean urgent) {
|
|
||||||
PushNotificationResponse<SimpleApnsPushNotification> response = mock(PushNotificationResponse.class);
|
|
||||||
when(response.isAccepted()).thenReturn(true);
|
|
||||||
|
|
||||||
when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class)))
|
|
||||||
.thenAnswer(
|
|
||||||
(Answer) invocationOnMock -> new MockPushNotificationFuture<>(invocationOnMock.getArgument(0), response));
|
|
||||||
|
|
||||||
PushNotification pushNotification = new PushNotification(DESTINATION_DEVICE_TOKEN, PushNotification.TokenType.APN_VOIP,
|
|
||||||
PushNotification.NotificationType.NOTIFICATION, null, destinationAccount, destinationDevice, urgent);
|
|
||||||
|
|
||||||
final SendPushNotificationResult result = apnSender.sendNotification(pushNotification).join();
|
|
||||||
|
|
||||||
ArgumentCaptor<SimpleApnsPushNotification> notification = ArgumentCaptor.forClass(SimpleApnsPushNotification.class);
|
|
||||||
verify(apnsClient).sendNotification(notification.capture());
|
|
||||||
|
|
||||||
assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_DEVICE_TOKEN);
|
|
||||||
assertThat(notification.getValue().getExpiration()).isEqualTo(APNSender.MAX_EXPIRATION);
|
|
||||||
assertThat(notification.getValue().getPayload()).isEqualTo(APNSender.APN_VOIP_NOTIFICATION_PAYLOAD);
|
|
||||||
// Delivery priority should always be `IMMEDIATE` for VOIP notifications
|
|
||||||
assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE);
|
|
||||||
assertThat(notification.getValue().getTopic()).isEqualTo(BUNDLE_ID + ".voip");
|
|
||||||
|
|
||||||
assertThat(result.accepted()).isTrue();
|
|
||||||
assertThat(result.errorCode()).isEmpty();
|
|
||||||
assertThat(result.unregistered()).isFalse();
|
|
||||||
|
|
||||||
verifyNoMoreInteractions(apnsClient);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@ValueSource(booleans = {true, false})
|
@ValueSource(booleans = {true, false})
|
||||||
void testSendApns(final boolean urgent) {
|
void testSendApns(final boolean urgent) {
|
||||||
|
@ -144,7 +112,7 @@ class APNSenderTest {
|
||||||
.thenAnswer(
|
.thenAnswer(
|
||||||
(Answer) invocationOnMock -> new MockPushNotificationFuture<>(invocationOnMock.getArgument(0), response));
|
(Answer) invocationOnMock -> new MockPushNotificationFuture<>(invocationOnMock.getArgument(0), response));
|
||||||
|
|
||||||
PushNotification pushNotification = new PushNotification(DESTINATION_DEVICE_TOKEN, PushNotification.TokenType.APN_VOIP,
|
PushNotification pushNotification = new PushNotification(DESTINATION_DEVICE_TOKEN, PushNotification.TokenType.APN,
|
||||||
PushNotification.NotificationType.NOTIFICATION, null, destinationAccount, destinationDevice, true);
|
PushNotification.NotificationType.NOTIFICATION, null, destinationAccount, destinationDevice, true);
|
||||||
|
|
||||||
when(destinationDevice.getApnId()).thenReturn(DESTINATION_DEVICE_TOKEN);
|
when(destinationDevice.getApnId()).thenReturn(DESTINATION_DEVICE_TOKEN);
|
||||||
|
@ -157,7 +125,7 @@ class APNSenderTest {
|
||||||
|
|
||||||
assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_DEVICE_TOKEN);
|
assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_DEVICE_TOKEN);
|
||||||
assertThat(notification.getValue().getExpiration()).isEqualTo(APNSender.MAX_EXPIRATION);
|
assertThat(notification.getValue().getExpiration()).isEqualTo(APNSender.MAX_EXPIRATION);
|
||||||
assertThat(notification.getValue().getPayload()).isEqualTo(APNSender.APN_VOIP_NOTIFICATION_PAYLOAD);
|
assertThat(notification.getValue().getPayload()).isEqualTo(APNSender.APN_NSE_NOTIFICATION_PAYLOAD);
|
||||||
assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE);
|
assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE);
|
||||||
|
|
||||||
assertThat(result.accepted()).isFalse();
|
assertThat(result.accepted()).isFalse();
|
||||||
|
@ -175,7 +143,7 @@ class APNSenderTest {
|
||||||
.thenAnswer(
|
.thenAnswer(
|
||||||
(Answer) invocationOnMock -> new MockPushNotificationFuture<>(invocationOnMock.getArgument(0), response));
|
(Answer) invocationOnMock -> new MockPushNotificationFuture<>(invocationOnMock.getArgument(0), response));
|
||||||
|
|
||||||
PushNotification pushNotification = new PushNotification(DESTINATION_DEVICE_TOKEN, PushNotification.TokenType.APN_VOIP,
|
PushNotification pushNotification = new PushNotification(DESTINATION_DEVICE_TOKEN, PushNotification.TokenType.APN,
|
||||||
PushNotification.NotificationType.NOTIFICATION, null, destinationAccount, destinationDevice, true);
|
PushNotification.NotificationType.NOTIFICATION, null, destinationAccount, destinationDevice, true);
|
||||||
|
|
||||||
final SendPushNotificationResult result = apnSender.sendNotification(pushNotification).join();
|
final SendPushNotificationResult result = apnSender.sendNotification(pushNotification).join();
|
||||||
|
@ -185,7 +153,7 @@ class APNSenderTest {
|
||||||
|
|
||||||
assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_DEVICE_TOKEN);
|
assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_DEVICE_TOKEN);
|
||||||
assertThat(notification.getValue().getExpiration()).isEqualTo(APNSender.MAX_EXPIRATION);
|
assertThat(notification.getValue().getExpiration()).isEqualTo(APNSender.MAX_EXPIRATION);
|
||||||
assertThat(notification.getValue().getPayload()).isEqualTo(APNSender.APN_VOIP_NOTIFICATION_PAYLOAD);
|
assertThat(notification.getValue().getPayload()).isEqualTo(APNSender.APN_NSE_NOTIFICATION_PAYLOAD);
|
||||||
assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE);
|
assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE);
|
||||||
|
|
||||||
assertThat(result.accepted()).isFalse();
|
assertThat(result.accepted()).isFalse();
|
||||||
|
@ -202,7 +170,7 @@ class APNSenderTest {
|
||||||
.thenAnswer((Answer) invocationOnMock -> new MockPushNotificationFuture<>(invocationOnMock.getArgument(0),
|
.thenAnswer((Answer) invocationOnMock -> new MockPushNotificationFuture<>(invocationOnMock.getArgument(0),
|
||||||
new IOException("lost connection")));
|
new IOException("lost connection")));
|
||||||
|
|
||||||
PushNotification pushNotification = new PushNotification(DESTINATION_DEVICE_TOKEN, PushNotification.TokenType.APN_VOIP,
|
PushNotification pushNotification = new PushNotification(DESTINATION_DEVICE_TOKEN, PushNotification.TokenType.APN,
|
||||||
PushNotification.NotificationType.NOTIFICATION, null, destinationAccount, destinationDevice, true);
|
PushNotification.NotificationType.NOTIFICATION, null, destinationAccount, destinationDevice, true);
|
||||||
|
|
||||||
assertThatThrownBy(() -> apnSender.sendNotification(pushNotification).join())
|
assertThatThrownBy(() -> apnSender.sendNotification(pushNotification).join())
|
||||||
|
|
|
@ -77,8 +77,8 @@ class PushNotificationManagerTest {
|
||||||
when(apnSender.sendNotification(any()))
|
when(apnSender.sendNotification(any()))
|
||||||
.thenReturn(CompletableFuture.completedFuture(new SendPushNotificationResult(true, Optional.empty(), false, Optional.empty())));
|
.thenReturn(CompletableFuture.completedFuture(new SendPushNotificationResult(true, Optional.empty(), false, Optional.empty())));
|
||||||
|
|
||||||
pushNotificationManager.sendRegistrationChallengeNotification(deviceToken, PushNotification.TokenType.APN_VOIP, challengeToken);
|
pushNotificationManager.sendRegistrationChallengeNotification(deviceToken, PushNotification.TokenType.APN, challengeToken);
|
||||||
verify(apnSender).sendNotification(new PushNotification(deviceToken, PushNotification.TokenType.APN_VOIP, PushNotification.NotificationType.CHALLENGE, challengeToken, null, null, true));
|
verify(apnSender).sendNotification(new PushNotification(deviceToken, PushNotification.TokenType.APN, PushNotification.NotificationType.CHALLENGE, challengeToken, null, null, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -220,13 +220,12 @@ class PushNotificationManagerTest {
|
||||||
final UUID aci = UUID.randomUUID();
|
final UUID aci = UUID.randomUUID();
|
||||||
when(device.getId()).thenReturn(Device.PRIMARY_ID);
|
when(device.getId()).thenReturn(Device.PRIMARY_ID);
|
||||||
when(device.getApnId()).thenReturn("apns-token");
|
when(device.getApnId()).thenReturn("apns-token");
|
||||||
when(device.getVoipApnId()).thenReturn("apns-voip-token");
|
|
||||||
when(account.getDevice(Device.PRIMARY_ID)).thenReturn(Optional.of(device));
|
when(account.getDevice(Device.PRIMARY_ID)).thenReturn(Optional.of(device));
|
||||||
when(account.getUuid()).thenReturn(aci);
|
when(account.getUuid()).thenReturn(aci);
|
||||||
when(accountsManager.getByAccountIdentifier(aci)).thenReturn(Optional.of(account));
|
when(accountsManager.getByAccountIdentifier(aci)).thenReturn(Optional.of(account));
|
||||||
|
|
||||||
final PushNotification pushNotification = new PushNotification(
|
final PushNotification pushNotification = new PushNotification(
|
||||||
"token", PushNotification.TokenType.APN_VOIP, PushNotification.NotificationType.NOTIFICATION, null, account, device, true);
|
"token", PushNotification.TokenType.APN, PushNotification.NotificationType.NOTIFICATION, null, account, device, true);
|
||||||
|
|
||||||
when(apnSender.sendNotification(pushNotification))
|
when(apnSender.sendNotification(pushNotification))
|
||||||
.thenReturn(CompletableFuture.completedFuture(new SendPushNotificationResult(false, Optional.empty(), true, Optional.empty())));
|
.thenReturn(CompletableFuture.completedFuture(new SendPushNotificationResult(false, Optional.empty(), true, Optional.empty())));
|
||||||
|
@ -238,8 +237,7 @@ class PushNotificationManagerTest {
|
||||||
|
|
||||||
verifyNoInteractions(fcmSender);
|
verifyNoInteractions(fcmSender);
|
||||||
verify(accountsManager).updateDevice(eq(account), eq(Device.PRIMARY_ID), any());
|
verify(accountsManager).updateDevice(eq(account), eq(Device.PRIMARY_ID), any());
|
||||||
verify(device).setVoipApnId(null);
|
verify(device).setApnId(null);
|
||||||
verify(device, never()).setApnId(any());
|
|
||||||
verify(pushNotificationScheduler).cancelScheduledNotifications(account, device);
|
verify(pushNotificationScheduler).cancelScheduledNotifications(account, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,14 +250,13 @@ class PushNotificationManagerTest {
|
||||||
final UUID aci = UUID.randomUUID();
|
final UUID aci = UUID.randomUUID();
|
||||||
when(device.getId()).thenReturn(Device.PRIMARY_ID);
|
when(device.getId()).thenReturn(Device.PRIMARY_ID);
|
||||||
when(device.getApnId()).thenReturn("apns-token");
|
when(device.getApnId()).thenReturn("apns-token");
|
||||||
when(device.getVoipApnId()).thenReturn("apns-voip-token");
|
|
||||||
when(device.getPushTimestamp()).thenReturn(tokenTimestamp.toEpochMilli());
|
when(device.getPushTimestamp()).thenReturn(tokenTimestamp.toEpochMilli());
|
||||||
when(account.getDevice(Device.PRIMARY_ID)).thenReturn(Optional.of(device));
|
when(account.getDevice(Device.PRIMARY_ID)).thenReturn(Optional.of(device));
|
||||||
when(account.getUuid()).thenReturn(aci);
|
when(account.getUuid()).thenReturn(aci);
|
||||||
when(accountsManager.getByAccountIdentifier(aci)).thenReturn(Optional.of(account));
|
when(accountsManager.getByAccountIdentifier(aci)).thenReturn(Optional.of(account));
|
||||||
|
|
||||||
final PushNotification pushNotification = new PushNotification(
|
final PushNotification pushNotification = new PushNotification(
|
||||||
"token", PushNotification.TokenType.APN_VOIP, PushNotification.NotificationType.NOTIFICATION, null, account, device, true);
|
"token", PushNotification.TokenType.APN, PushNotification.NotificationType.NOTIFICATION, null, account, device, true);
|
||||||
|
|
||||||
when(apnSender.sendNotification(pushNotification))
|
when(apnSender.sendNotification(pushNotification))
|
||||||
.thenReturn(CompletableFuture.completedFuture(new SendPushNotificationResult(false, Optional.empty(), true, Optional.of(tokenTimestamp.minusSeconds(60)))));
|
.thenReturn(CompletableFuture.completedFuture(new SendPushNotificationResult(false, Optional.empty(), true, Optional.of(tokenTimestamp.minusSeconds(60)))));
|
||||||
|
@ -271,7 +268,6 @@ class PushNotificationManagerTest {
|
||||||
|
|
||||||
verifyNoInteractions(fcmSender);
|
verifyNoInteractions(fcmSender);
|
||||||
verify(accountsManager, never()).updateDevice(eq(account), eq(Device.PRIMARY_ID), any());
|
verify(accountsManager, never()).updateDevice(eq(account), eq(Device.PRIMARY_ID), any());
|
||||||
verify(device, never()).setVoipApnId(any());
|
|
||||||
verify(device, never()).setApnId(any());
|
verify(device, never()).setApnId(any());
|
||||||
verify(pushNotificationScheduler, never()).cancelScheduledNotifications(account, device);
|
verify(pushNotificationScheduler, never()).cancelScheduledNotifications(account, device);
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,6 @@ class PushNotificationSchedulerTest {
|
||||||
private static final String ACCOUNT_NUMBER = "+18005551234";
|
private static final String ACCOUNT_NUMBER = "+18005551234";
|
||||||
private static final byte DEVICE_ID = 1;
|
private static final byte DEVICE_ID = 1;
|
||||||
private static final String APN_ID = RandomStringUtils.randomAlphanumeric(32);
|
private static final String APN_ID = RandomStringUtils.randomAlphanumeric(32);
|
||||||
private static final String VOIP_APN_ID = RandomStringUtils.randomAlphanumeric(32);
|
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() throws Exception {
|
void setUp() throws Exception {
|
||||||
|
@ -64,7 +63,6 @@ class PushNotificationSchedulerTest {
|
||||||
device = mock(Device.class);
|
device = mock(Device.class);
|
||||||
when(device.getId()).thenReturn(DEVICE_ID);
|
when(device.getId()).thenReturn(DEVICE_ID);
|
||||||
when(device.getApnId()).thenReturn(APN_ID);
|
when(device.getApnId()).thenReturn(APN_ID);
|
||||||
when(device.getVoipApnId()).thenReturn(VOIP_APN_ID);
|
|
||||||
when(device.getLastSeen()).thenReturn(System.currentTimeMillis());
|
when(device.getLastSeen()).thenReturn(System.currentTimeMillis());
|
||||||
|
|
||||||
account = mock(Account.class);
|
account = mock(Account.class);
|
||||||
|
|
|
@ -77,7 +77,7 @@ public class AccountCreationDeletionIntegrationTest {
|
||||||
private KeysManager keysManager;
|
private KeysManager keysManager;
|
||||||
private ClientPublicKeysManager clientPublicKeysManager;
|
private ClientPublicKeysManager clientPublicKeysManager;
|
||||||
|
|
||||||
record DeliveryChannels(boolean fetchesMessages, String apnsToken, String apnsVoipToken, String fcmToken) {}
|
record DeliveryChannels(boolean fetchesMessages, String apnsToken, String fcmToken) {}
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() {
|
void setUp() {
|
||||||
|
@ -212,8 +212,8 @@ public class AccountCreationDeletionIntegrationTest {
|
||||||
final KEMSignedPreKey pniPqLastResortPreKey = KeysHelper.signedKEMPreKey(4, pniKeyPair);
|
final KEMSignedPreKey pniPqLastResortPreKey = KeysHelper.signedKEMPreKey(4, pniKeyPair);
|
||||||
|
|
||||||
final Optional<ApnRegistrationId> maybeApnRegistrationId =
|
final Optional<ApnRegistrationId> maybeApnRegistrationId =
|
||||||
deliveryChannels.apnsToken() != null || deliveryChannels.apnsVoipToken() != null
|
deliveryChannels.apnsToken() != null
|
||||||
? Optional.of(new ApnRegistrationId(deliveryChannels.apnsToken(), deliveryChannels.apnsVoipToken()))
|
? Optional.of(new ApnRegistrationId(deliveryChannels.apnsToken()))
|
||||||
: Optional.empty();
|
: Optional.empty();
|
||||||
|
|
||||||
final Optional<GcmRegistrationId> maybeGcmRegistrationId = deliveryChannels.fcmToken() != null
|
final Optional<GcmRegistrationId> maybeGcmRegistrationId = deliveryChannels.fcmToken() != null
|
||||||
|
@ -271,10 +271,10 @@ public class AccountCreationDeletionIntegrationTest {
|
||||||
return ArgumentSets
|
return ArgumentSets
|
||||||
// deliveryChannels
|
// deliveryChannels
|
||||||
.argumentsForFirstParameter(
|
.argumentsForFirstParameter(
|
||||||
new DeliveryChannels(true, null, null, null),
|
new DeliveryChannels(true, null, null),
|
||||||
new DeliveryChannels(false, "apns-token", null, null),
|
new DeliveryChannels(false, "apns-token", null),
|
||||||
new DeliveryChannels(false, "apns-token", "apns-voip-token", null),
|
new DeliveryChannels(false, "apns-token", null),
|
||||||
new DeliveryChannels(false, null, null, "fcm-token"))
|
new DeliveryChannels(false, null, "fcm-token"))
|
||||||
|
|
||||||
// discoverableByPhoneNumber
|
// discoverableByPhoneNumber
|
||||||
.argumentsForNextParameter(true, false);
|
.argumentsForNextParameter(true, false);
|
||||||
|
@ -359,8 +359,8 @@ public class AccountCreationDeletionIntegrationTest {
|
||||||
final KEMSignedPreKey pniPqLastResortPreKey = KeysHelper.signedKEMPreKey(4, pniKeyPair);
|
final KEMSignedPreKey pniPqLastResortPreKey = KeysHelper.signedKEMPreKey(4, pniKeyPair);
|
||||||
|
|
||||||
final Optional<ApnRegistrationId> maybeApnRegistrationId =
|
final Optional<ApnRegistrationId> maybeApnRegistrationId =
|
||||||
deliveryChannels.apnsToken() != null || deliveryChannels.apnsVoipToken() != null
|
deliveryChannels.apnsToken() != null
|
||||||
? Optional.of(new ApnRegistrationId(deliveryChannels.apnsToken(), deliveryChannels.apnsVoipToken()))
|
? Optional.of(new ApnRegistrationId(deliveryChannels.apnsToken()))
|
||||||
: Optional.empty();
|
: Optional.empty();
|
||||||
|
|
||||||
final Optional<GcmRegistrationId> maybeGcmRegistrationId = deliveryChannels.fcmToken() != null
|
final Optional<GcmRegistrationId> maybeGcmRegistrationId = deliveryChannels.fcmToken() != null
|
||||||
|
@ -519,19 +519,13 @@ public class AccountCreationDeletionIntegrationTest {
|
||||||
assertEquals(deviceCapabilities, primaryDevice.getCapabilities());
|
assertEquals(deviceCapabilities, primaryDevice.getCapabilities());
|
||||||
assertEquals(badges, account.getBadges());
|
assertEquals(badges, account.getBadges());
|
||||||
|
|
||||||
maybeApnRegistrationId.ifPresentOrElse(apnRegistrationId -> {
|
maybeApnRegistrationId.ifPresentOrElse(
|
||||||
assertEquals(apnRegistrationId.apnRegistrationId(), primaryDevice.getApnId());
|
apnRegistrationId -> assertEquals(apnRegistrationId.apnRegistrationId(), primaryDevice.getApnId()),
|
||||||
assertEquals(apnRegistrationId.voipRegistrationId(), primaryDevice.getVoipApnId());
|
() -> assertNull(primaryDevice.getApnId()));
|
||||||
}, () -> {
|
|
||||||
assertNull(primaryDevice.getApnId());
|
|
||||||
assertNull(primaryDevice.getVoipApnId());
|
|
||||||
});
|
|
||||||
|
|
||||||
maybeGcmRegistrationId.ifPresentOrElse(gcmRegistrationId -> {
|
maybeGcmRegistrationId.ifPresentOrElse(
|
||||||
assertEquals(deliveryChannels.fcmToken(), primaryDevice.getGcmId());
|
gcmRegistrationId -> assertEquals(deliveryChannels.fcmToken(), primaryDevice.getGcmId()),
|
||||||
}, () -> {
|
() -> assertNull(primaryDevice.getGcmId()));
|
||||||
assertNull(primaryDevice.getGcmId());
|
|
||||||
});
|
|
||||||
|
|
||||||
assertTrue(account.getRegistrationLock().verify(registrationLockSecret));
|
assertTrue(account.getRegistrationLock().verify(registrationLockSecret));
|
||||||
assertTrue(primaryDevice.getAuthTokenHash().verify(password));
|
assertTrue(primaryDevice.getAuthTokenHash().verify(password));
|
||||||
|
|
|
@ -986,7 +986,6 @@ class AccountsManagerTest {
|
||||||
assertEquals(pniRegistrationId, device.getPhoneNumberIdentityRegistrationId().getAsInt());
|
assertEquals(pniRegistrationId, device.getPhoneNumberIdentityRegistrationId().getAsInt());
|
||||||
assertTrue(device.getFetchesMessages());
|
assertTrue(device.getFetchesMessages());
|
||||||
assertNull(device.getApnId());
|
assertNull(device.getApnId());
|
||||||
assertNull(device.getVoipApnId());
|
|
||||||
assertNull(device.getGcmId());
|
assertNull(device.getGcmId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -364,15 +364,6 @@ class NotifyIdleDevicesCommandTest {
|
||||||
arguments.add(Arguments.of(device, true));
|
arguments.add(Arguments.of(device, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
// APNs VOIP token
|
|
||||||
final Device device = mock(Device.class);
|
|
||||||
when(device.getApnId()).thenReturn("apns-token");
|
|
||||||
when(device.getVoipApnId()).thenReturn("apns-voip-token");
|
|
||||||
|
|
||||||
arguments.add(Arguments.of(device, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
return arguments;
|
return arguments;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
"salt": null,
|
"salt": null,
|
||||||
"gcmId": null,
|
"gcmId": null,
|
||||||
"apnId": null,
|
"apnId": null,
|
||||||
"voipApnId": null,
|
|
||||||
"pushTimestamp": 0,
|
"pushTimestamp": 0,
|
||||||
"uninstalledFeedback": 0,
|
"uninstalledFeedback": 0,
|
||||||
"fetchesMessages": true,
|
"fetchesMessages": true,
|
||||||
|
|
Loading…
Reference in New Issue