The APNs server appears to be lying to us about unregistrations

// FREEBIE
This commit is contained in:
Moxie Marlinspike 2017-05-09 15:43:16 -07:00
parent 51c3257df9
commit 9d32300612
2 changed files with 208 additions and 208 deletions

View File

@ -155,14 +155,14 @@ public class APNSender implements Managed {
return;
}
logger.info("APN Unregister timestamp matches!");
device.get().setApnId(null);
device.get().setVoipApnId(null);
device.get().setFetchesMessages(false);
accountsManager.update(account.get());
logger.info("APN Unregister timestamp matches: " + device.get().getApnId() + ", " + device.get().getVoipApnId());
// device.get().setApnId(null);
// device.get().setVoipApnId(null);
// device.get().setFetchesMessages(false);
// accountsManager.update(account.get());
if (fallbackManager != null) {
fallbackManager.cancel(new WebsocketAddress(number, deviceId));
}
// if (fallbackManager != null) {
// fallbackManager.cancel(new WebsocketAddress(number, deviceId));
// }
}
}

View File

@ -124,209 +124,209 @@ public class APNSenderTest {
verifyNoMoreInteractions(fallbackManager);
}
@Test
public void testUnregisteredUser() throws Exception {
ApnsClient apnsClient = mock(ApnsClient.class);
// @Test
// public void testUnregisteredUser() throws Exception {
// ApnsClient apnsClient = mock(ApnsClient.class);
//
// PushNotificationResponse<SimpleApnsPushNotification> response = mock(PushNotificationResponse.class);
// when(response.isAccepted()).thenReturn(false);
// when(response.getRejectionReason()).thenReturn("Unregistered");
//
// DefaultPromise<PushNotificationResponse<SimpleApnsPushNotification>> result = new DefaultPromise<>(executor);
// result.setSuccess(response);
//
// when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class)))
// .thenReturn(result);
//
// RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient, 10);
// ApnMessage message = new ApnMessage(DESTINATION_APN_ID, DESTINATION_NUMBER, 1, "message", true, 30);
// APNSender apnSender = new APNSender(new SynchronousExecutorService(), accountsManager, retryingApnsClient, "foo", false);
// apnSender.setApnFallbackManager(fallbackManager);
//
// when(destinationDevice.getApnId()).thenReturn(DESTINATION_APN_ID);
// when(destinationDevice.getPushTimestamp()).thenReturn(System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(11));
//
// ListenableFuture<ApnResult> sendFuture = apnSender.sendMessage(message);
// ApnResult apnResult = sendFuture.get();
//
// Thread.sleep(1000); // =(
//
// ArgumentCaptor<SimpleApnsPushNotification> notification = ArgumentCaptor.forClass(SimpleApnsPushNotification.class);
// verify(apnsClient, times(1)).sendNotification(notification.capture());
//
// assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_APN_ID);
// assertThat(notification.getValue().getExpiration()).isEqualTo(new Date(30));
// assertThat(notification.getValue().getPayload()).isEqualTo("message");
// assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE);
//
// assertThat(apnResult.getStatus()).isEqualTo(ApnResult.Status.NO_SUCH_USER);
//
// verifyNoMoreInteractions(apnsClient);
// verify(accountsManager, times(1)).get(eq(DESTINATION_NUMBER));
// verify(destinationAccount, times(1)).getDevice(1);
// verify(destinationDevice, times(1)).getApnId();
// verify(destinationDevice, times(1)).getPushTimestamp();
// verify(destinationDevice, times(1)).setApnId(eq((String)null));
// verify(destinationDevice, times(1)).setVoipApnId(eq((String)null));
// verify(destinationDevice, times(1)).setFetchesMessages(eq(false));
// verify(accountsManager, times(1)).update(eq(destinationAccount));
// verify(fallbackManager, times(1)).cancel(eq(new WebsocketAddress(DESTINATION_NUMBER, 1)));
//
// verifyNoMoreInteractions(accountsManager);
// verifyNoMoreInteractions(fallbackManager);
// }
PushNotificationResponse<SimpleApnsPushNotification> response = mock(PushNotificationResponse.class);
when(response.isAccepted()).thenReturn(false);
when(response.getRejectionReason()).thenReturn("Unregistered");
// @Test
// public void testVoipUnregisteredUser() throws Exception {
// ApnsClient apnsClient = mock(ApnsClient.class);
//
// PushNotificationResponse<SimpleApnsPushNotification> response = mock(PushNotificationResponse.class);
// when(response.isAccepted()).thenReturn(false);
// when(response.getRejectionReason()).thenReturn("Unregistered");
//
// DefaultPromise<PushNotificationResponse<SimpleApnsPushNotification>> result = new DefaultPromise<>(executor);
// result.setSuccess(response);
//
// when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class)))
// .thenReturn(result);
//
// RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient, 10);
// ApnMessage message = new ApnMessage(DESTINATION_APN_ID, DESTINATION_NUMBER, 1, "message", true, 30);
// APNSender apnSender = new APNSender(new SynchronousExecutorService(), accountsManager, retryingApnsClient, "foo", false);
// apnSender.setApnFallbackManager(fallbackManager);
//
// when(destinationDevice.getApnId()).thenReturn("baz");
// when(destinationDevice.getVoipApnId()).thenReturn(DESTINATION_APN_ID);
// when(destinationDevice.getPushTimestamp()).thenReturn(System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(11));
//
// ListenableFuture<ApnResult> sendFuture = apnSender.sendMessage(message);
// ApnResult apnResult = sendFuture.get();
//
// Thread.sleep(1000); // =(
//
// ArgumentCaptor<SimpleApnsPushNotification> notification = ArgumentCaptor.forClass(SimpleApnsPushNotification.class);
// verify(apnsClient, times(1)).sendNotification(notification.capture());
//
// assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_APN_ID);
// assertThat(notification.getValue().getExpiration()).isEqualTo(new Date(30));
// assertThat(notification.getValue().getPayload()).isEqualTo("message");
// assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE);
//
// assertThat(apnResult.getStatus()).isEqualTo(ApnResult.Status.NO_SUCH_USER);
//
// verifyNoMoreInteractions(apnsClient);
// verify(accountsManager, times(1)).get(eq(DESTINATION_NUMBER));
// verify(destinationAccount, times(1)).getDevice(1);
// verify(destinationDevice, times(1)).getApnId();
// verify(destinationDevice, times(1)).getVoipApnId();
// verify(destinationDevice, times(1)).getPushTimestamp();
// verify(destinationDevice, times(1)).setApnId(eq((String)null));
// verify(destinationDevice, times(1)).setVoipApnId(eq((String)null));
// verify(destinationDevice, times(1)).setFetchesMessages(eq(false));
// verify(accountsManager, times(1)).update(eq(destinationAccount));
// verify(fallbackManager, times(1)).cancel(eq(new WebsocketAddress(DESTINATION_NUMBER, 1)));
//
// verifyNoMoreInteractions(accountsManager);
// verifyNoMoreInteractions(fallbackManager);
// }
DefaultPromise<PushNotificationResponse<SimpleApnsPushNotification>> result = new DefaultPromise<>(executor);
result.setSuccess(response);
// @Test
// public void testRecentUnregisteredUser() throws Exception {
// ApnsClient apnsClient = mock(ApnsClient.class);
//
// PushNotificationResponse<SimpleApnsPushNotification> response = mock(PushNotificationResponse.class);
// when(response.isAccepted()).thenReturn(false);
// when(response.getRejectionReason()).thenReturn("Unregistered");
//
// DefaultPromise<PushNotificationResponse<SimpleApnsPushNotification>> result = new DefaultPromise<>(executor);
// result.setSuccess(response);
//
// when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class)))
// .thenReturn(result);
//
// RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient, 10);
// ApnMessage message = new ApnMessage(DESTINATION_APN_ID, DESTINATION_NUMBER, 1, "message", true, 30);
// APNSender apnSender = new APNSender(new SynchronousExecutorService(), accountsManager, retryingApnsClient, "foo", false);
// apnSender.setApnFallbackManager(fallbackManager);
//
// when(destinationDevice.getApnId()).thenReturn(DESTINATION_APN_ID);
// when(destinationDevice.getPushTimestamp()).thenReturn(System.currentTimeMillis());
//
// ListenableFuture<ApnResult> sendFuture = apnSender.sendMessage(message);
// ApnResult apnResult = sendFuture.get();
//
// Thread.sleep(1000); // =(
//
// ArgumentCaptor<SimpleApnsPushNotification> notification = ArgumentCaptor.forClass(SimpleApnsPushNotification.class);
// verify(apnsClient, times(1)).sendNotification(notification.capture());
//
// assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_APN_ID);
// assertThat(notification.getValue().getExpiration()).isEqualTo(new Date(30));
// assertThat(notification.getValue().getPayload()).isEqualTo("message");
// assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE);
//
// assertThat(apnResult.getStatus()).isEqualTo(ApnResult.Status.NO_SUCH_USER);
//
// verifyNoMoreInteractions(apnsClient);
// verify(accountsManager, times(1)).get(eq(DESTINATION_NUMBER));
// verify(destinationAccount, times(1)).getDevice(1);
// verify(destinationDevice, times(1)).getApnId();
// verify(destinationDevice, times(1)).getPushTimestamp();
//
// verifyNoMoreInteractions(destinationDevice);
// verifyNoMoreInteractions(destinationAccount);
// verifyNoMoreInteractions(accountsManager);
// verifyNoMoreInteractions(fallbackManager);
// }
when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class)))
.thenReturn(result);
RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient, 10);
ApnMessage message = new ApnMessage(DESTINATION_APN_ID, DESTINATION_NUMBER, 1, "message", true, 30);
APNSender apnSender = new APNSender(new SynchronousExecutorService(), accountsManager, retryingApnsClient, "foo", false);
apnSender.setApnFallbackManager(fallbackManager);
when(destinationDevice.getApnId()).thenReturn(DESTINATION_APN_ID);
when(destinationDevice.getPushTimestamp()).thenReturn(System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(11));
ListenableFuture<ApnResult> sendFuture = apnSender.sendMessage(message);
ApnResult apnResult = sendFuture.get();
Thread.sleep(1000); // =(
ArgumentCaptor<SimpleApnsPushNotification> notification = ArgumentCaptor.forClass(SimpleApnsPushNotification.class);
verify(apnsClient, times(1)).sendNotification(notification.capture());
assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_APN_ID);
assertThat(notification.getValue().getExpiration()).isEqualTo(new Date(30));
assertThat(notification.getValue().getPayload()).isEqualTo("message");
assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE);
assertThat(apnResult.getStatus()).isEqualTo(ApnResult.Status.NO_SUCH_USER);
verifyNoMoreInteractions(apnsClient);
verify(accountsManager, times(1)).get(eq(DESTINATION_NUMBER));
verify(destinationAccount, times(1)).getDevice(1);
verify(destinationDevice, times(1)).getApnId();
verify(destinationDevice, times(1)).getPushTimestamp();
verify(destinationDevice, times(1)).setApnId(eq((String)null));
verify(destinationDevice, times(1)).setVoipApnId(eq((String)null));
verify(destinationDevice, times(1)).setFetchesMessages(eq(false));
verify(accountsManager, times(1)).update(eq(destinationAccount));
verify(fallbackManager, times(1)).cancel(eq(new WebsocketAddress(DESTINATION_NUMBER, 1)));
verifyNoMoreInteractions(accountsManager);
verifyNoMoreInteractions(fallbackManager);
}
@Test
public void testVoipUnregisteredUser() throws Exception {
ApnsClient apnsClient = mock(ApnsClient.class);
PushNotificationResponse<SimpleApnsPushNotification> response = mock(PushNotificationResponse.class);
when(response.isAccepted()).thenReturn(false);
when(response.getRejectionReason()).thenReturn("Unregistered");
DefaultPromise<PushNotificationResponse<SimpleApnsPushNotification>> result = new DefaultPromise<>(executor);
result.setSuccess(response);
when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class)))
.thenReturn(result);
RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient, 10);
ApnMessage message = new ApnMessage(DESTINATION_APN_ID, DESTINATION_NUMBER, 1, "message", true, 30);
APNSender apnSender = new APNSender(new SynchronousExecutorService(), accountsManager, retryingApnsClient, "foo", false);
apnSender.setApnFallbackManager(fallbackManager);
when(destinationDevice.getApnId()).thenReturn("baz");
when(destinationDevice.getVoipApnId()).thenReturn(DESTINATION_APN_ID);
when(destinationDevice.getPushTimestamp()).thenReturn(System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(11));
ListenableFuture<ApnResult> sendFuture = apnSender.sendMessage(message);
ApnResult apnResult = sendFuture.get();
Thread.sleep(1000); // =(
ArgumentCaptor<SimpleApnsPushNotification> notification = ArgumentCaptor.forClass(SimpleApnsPushNotification.class);
verify(apnsClient, times(1)).sendNotification(notification.capture());
assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_APN_ID);
assertThat(notification.getValue().getExpiration()).isEqualTo(new Date(30));
assertThat(notification.getValue().getPayload()).isEqualTo("message");
assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE);
assertThat(apnResult.getStatus()).isEqualTo(ApnResult.Status.NO_SUCH_USER);
verifyNoMoreInteractions(apnsClient);
verify(accountsManager, times(1)).get(eq(DESTINATION_NUMBER));
verify(destinationAccount, times(1)).getDevice(1);
verify(destinationDevice, times(1)).getApnId();
verify(destinationDevice, times(1)).getVoipApnId();
verify(destinationDevice, times(1)).getPushTimestamp();
verify(destinationDevice, times(1)).setApnId(eq((String)null));
verify(destinationDevice, times(1)).setVoipApnId(eq((String)null));
verify(destinationDevice, times(1)).setFetchesMessages(eq(false));
verify(accountsManager, times(1)).update(eq(destinationAccount));
verify(fallbackManager, times(1)).cancel(eq(new WebsocketAddress(DESTINATION_NUMBER, 1)));
verifyNoMoreInteractions(accountsManager);
verifyNoMoreInteractions(fallbackManager);
}
@Test
public void testRecentUnregisteredUser() throws Exception {
ApnsClient apnsClient = mock(ApnsClient.class);
PushNotificationResponse<SimpleApnsPushNotification> response = mock(PushNotificationResponse.class);
when(response.isAccepted()).thenReturn(false);
when(response.getRejectionReason()).thenReturn("Unregistered");
DefaultPromise<PushNotificationResponse<SimpleApnsPushNotification>> result = new DefaultPromise<>(executor);
result.setSuccess(response);
when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class)))
.thenReturn(result);
RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient, 10);
ApnMessage message = new ApnMessage(DESTINATION_APN_ID, DESTINATION_NUMBER, 1, "message", true, 30);
APNSender apnSender = new APNSender(new SynchronousExecutorService(), accountsManager, retryingApnsClient, "foo", false);
apnSender.setApnFallbackManager(fallbackManager);
when(destinationDevice.getApnId()).thenReturn(DESTINATION_APN_ID);
when(destinationDevice.getPushTimestamp()).thenReturn(System.currentTimeMillis());
ListenableFuture<ApnResult> sendFuture = apnSender.sendMessage(message);
ApnResult apnResult = sendFuture.get();
Thread.sleep(1000); // =(
ArgumentCaptor<SimpleApnsPushNotification> notification = ArgumentCaptor.forClass(SimpleApnsPushNotification.class);
verify(apnsClient, times(1)).sendNotification(notification.capture());
assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_APN_ID);
assertThat(notification.getValue().getExpiration()).isEqualTo(new Date(30));
assertThat(notification.getValue().getPayload()).isEqualTo("message");
assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE);
assertThat(apnResult.getStatus()).isEqualTo(ApnResult.Status.NO_SUCH_USER);
verifyNoMoreInteractions(apnsClient);
verify(accountsManager, times(1)).get(eq(DESTINATION_NUMBER));
verify(destinationAccount, times(1)).getDevice(1);
verify(destinationDevice, times(1)).getApnId();
verify(destinationDevice, times(1)).getPushTimestamp();
verifyNoMoreInteractions(destinationDevice);
verifyNoMoreInteractions(destinationAccount);
verifyNoMoreInteractions(accountsManager);
verifyNoMoreInteractions(fallbackManager);
}
@Test
public void testUnregisteredUserOldApnId() throws Exception {
ApnsClient apnsClient = mock(ApnsClient.class);
PushNotificationResponse<SimpleApnsPushNotification> response = mock(PushNotificationResponse.class);
when(response.isAccepted()).thenReturn(false);
when(response.getRejectionReason()).thenReturn("Unregistered");
DefaultPromise<PushNotificationResponse<SimpleApnsPushNotification>> result = new DefaultPromise<>(executor);
result.setSuccess(response);
when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class)))
.thenReturn(result);
RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient, 10);
ApnMessage message = new ApnMessage(DESTINATION_APN_ID, DESTINATION_NUMBER, 1, "message", true, 30);
APNSender apnSender = new APNSender(new SynchronousExecutorService(), accountsManager, retryingApnsClient, "foo", false);
apnSender.setApnFallbackManager(fallbackManager);
when(destinationDevice.getApnId()).thenReturn("baz");
when(destinationDevice.getPushTimestamp()).thenReturn(System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(12));
ListenableFuture<ApnResult> sendFuture = apnSender.sendMessage(message);
ApnResult apnResult = sendFuture.get();
Thread.sleep(1000); // =(
ArgumentCaptor<SimpleApnsPushNotification> notification = ArgumentCaptor.forClass(SimpleApnsPushNotification.class);
verify(apnsClient, times(1)).sendNotification(notification.capture());
assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_APN_ID);
assertThat(notification.getValue().getExpiration()).isEqualTo(new Date(30));
assertThat(notification.getValue().getPayload()).isEqualTo("message");
assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE);
assertThat(apnResult.getStatus()).isEqualTo(ApnResult.Status.NO_SUCH_USER);
verifyNoMoreInteractions(apnsClient);
verify(accountsManager, times(1)).get(eq(DESTINATION_NUMBER));
verify(destinationAccount, times(1)).getDevice(1);
verify(destinationDevice, times(2)).getApnId();
verify(destinationDevice, times(2)).getVoipApnId();
verifyNoMoreInteractions(destinationDevice);
verifyNoMoreInteractions(destinationAccount);
verifyNoMoreInteractions(accountsManager);
verifyNoMoreInteractions(fallbackManager);
}
// @Test
// public void testUnregisteredUserOldApnId() throws Exception {
// ApnsClient apnsClient = mock(ApnsClient.class);
//
// PushNotificationResponse<SimpleApnsPushNotification> response = mock(PushNotificationResponse.class);
// when(response.isAccepted()).thenReturn(false);
// when(response.getRejectionReason()).thenReturn("Unregistered");
//
// DefaultPromise<PushNotificationResponse<SimpleApnsPushNotification>> result = new DefaultPromise<>(executor);
// result.setSuccess(response);
//
// when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class)))
// .thenReturn(result);
//
// RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient, 10);
// ApnMessage message = new ApnMessage(DESTINATION_APN_ID, DESTINATION_NUMBER, 1, "message", true, 30);
// APNSender apnSender = new APNSender(new SynchronousExecutorService(), accountsManager, retryingApnsClient, "foo", false);
// apnSender.setApnFallbackManager(fallbackManager);
//
// when(destinationDevice.getApnId()).thenReturn("baz");
// when(destinationDevice.getPushTimestamp()).thenReturn(System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(12));
//
// ListenableFuture<ApnResult> sendFuture = apnSender.sendMessage(message);
// ApnResult apnResult = sendFuture.get();
//
// Thread.sleep(1000); // =(
//
// ArgumentCaptor<SimpleApnsPushNotification> notification = ArgumentCaptor.forClass(SimpleApnsPushNotification.class);
// verify(apnsClient, times(1)).sendNotification(notification.capture());
//
// assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_APN_ID);
// assertThat(notification.getValue().getExpiration()).isEqualTo(new Date(30));
// assertThat(notification.getValue().getPayload()).isEqualTo("message");
// assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE);
//
// assertThat(apnResult.getStatus()).isEqualTo(ApnResult.Status.NO_SUCH_USER);
//
// verifyNoMoreInteractions(apnsClient);
// verify(accountsManager, times(1)).get(eq(DESTINATION_NUMBER));
// verify(destinationAccount, times(1)).getDevice(1);
// verify(destinationDevice, times(2)).getApnId();
// verify(destinationDevice, times(2)).getVoipApnId();
//
// verifyNoMoreInteractions(destinationDevice);
// verifyNoMoreInteractions(destinationAccount);
// verifyNoMoreInteractions(accountsManager);
// verifyNoMoreInteractions(fallbackManager);
// }
@Test
public void testGenericFailure() throws Exception {