Ph3nol / NotificationPusher

Standalone PHP library for easy devices notifications push.
MIT License
1.18k stars 273 forks source link

An Invalid APNS Token Breaks Active Connection #155

Closed hanialaraj closed 7 years ago

hanialaraj commented 7 years ago

When an invalid apns token in a list of tokens (the first invalid one), all tokens in the list (regardless if any is invalid or valid) after the invalid one will not get the notification and nothing reported by the code (no exception or !RESULT_SUCCESS response code)

I'm not sure yet if this is because of the zendservice-apple-apns or because of Apple apns servers. The work around to make sure all valid tokens will get notified is resetting the connection with Apple apns server right after catching the first invalid one in the list.

Providing a sample fix:

diff sly/notification-pusher/src/Sly/NotificationPusher/Adapter/Apns.php (line 90)

if (ServiceResponse::RESULT_OK === $response->getCode()) { $pushedDevices->add($device); }else{ unset($this->openedClient); $this->getOpenedServiceClient(); }

Worth to note, a list with many invalid tokens will put you in risk of adding you to "denial attack" list especially if there is no code implemented to handle invalid tokens. Might be related to this: #123 , #61 , #90

seyfer commented 7 years ago

@hanialaraj, could you please add a test case, which demonstrates the failure. And then you could add your proposed solution as a pull request. Seems like it's a good workaround.

hanialaraj commented 7 years ago

use Sly\NotificationPusher\PushManager; use Sly\NotificationPusher\Adapter\Apns; use Sly\NotificationPusher\Collection\DeviceCollection; use Sly\NotificationPusher\Model\Device; use Sly\NotificationPusher\Model\Message; use Sly\NotificationPusher\Model\Push;

$devices = []; $devices[] = new Device('valid_token_1'); $devices[] = new Device('AN_INVALID_TOKEN_2'); $devices[] = new Device('valid_token_1'); $devices[] = new Device('valid_token_1'); $deviceCollection = new DeviceCollection($devices);

$pushManager = new PushManager(PushManager::ENVIRONMENT_DEV); $adapter = new Apns(['certificate' => 'path/to/private/key.pem']); $message = new Message('Hello, not all devices will get this!', ['sound'=>'default']);

$push = new Push($adapter, $deviceCollection, $message);

$pushManager->add($push); $pushManager->push();

Testing with one device, running the above code sample will result in delivering only one notification. This is because there is an invalid token (device with the "AN_INVALID_TOKEN_2"), Where as the expected behavior is getting 3 notifications.

After more debugging, ZendService\Apple\Apns\Client\AbstractClient suppressing errors/warning triggered by "fread" and "fwrite" php built-in functions. Also, ZendService\Apple\Apns\Client\Message->send method do a strict boolean comparison with the returned result from ZendService\Apple\Apns\Client\AbstractClient->send method; the returned result can be "false" if failed to write or "0" if nothing been written (http://php.net/manual/en/function.fwrite.php).

Now, while sending a message to APNS, the INVALID_TOKEN cause the SSL pipe to broke and the next attempt to write on the same opened connect will write nothing (0 is returned by the "fwrite") hence the connection to APNS need to be re-initiated.

seyfer commented 7 years ago

@hanialaraj, thank you for providing a description and the code example. There were some issues with code in PR. I have fixed them and merged PR. New tag v2.3.3 will be created.

kudeiro commented 6 years ago

i have this issue in the latest version