From 07bd808c820f1b2e69ada9f61e79f7e2bf54f9ca Mon Sep 17 00:00:00 2001 From: Louis Lagrange Date: Tue, 15 Nov 2016 14:27:41 +0100 Subject: [PATCH] auth can be customized per notification, close #58 --- README.md | 3 +++ src/Notification.php | 18 ++++++++++++++++-- src/VAPID.php | 3 +-- src/WebPush.php | 18 ++++++++++++------ 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index d73a35f6..eb680876 100644 --- a/README.md +++ b/README.md @@ -249,6 +249,9 @@ Your installation lacks some certificates. You can also force using a client without peer verification. +### I lost my VAPID keys! +See [issue #58](https://github.com/web-push-libs/web-push-php/issues/58). + ### I need to send notifications to native apps. (eg. APNS for iOS) WebPush is for web apps. You need something like [RMSPushNotificationsBundle](https://github.com/richsage/RMSPushNotificationsBundle) (Symfony). diff --git a/src/Notification.php b/src/Notification.php index ffca9a19..df8f8cfd 100644 --- a/src/Notification.php +++ b/src/Notification.php @@ -25,16 +25,20 @@ class Notification /** @var string */ private $userAuthToken; - /** @var array Options : TTL, urgency, topic * */ + /** @var array Options : TTL, urgency, topic */ private $options; - public function __construct($endpoint, $payload, $userPublicKey, $userAuthToken, $options) + /** @var array Auth details : GCM, VAPID */ + private $auth; + + public function __construct($endpoint, $payload, $userPublicKey, $userAuthToken, $options, $auth) { $this->endpoint = $endpoint; $this->payload = $payload; $this->userPublicKey = $userPublicKey; $this->userAuthToken = $userAuthToken; $this->options = $options; + $this->auth = $auth; } /** @@ -83,4 +87,14 @@ public function getOptions(array $defaultOptions = array()) return $options; } + + /** + * @param array $defaultAuth + * + * @return array + */ + public function getAuth(array $defaultAuth) + { + return count($this->auth) > 0 ? $this->auth : $defaultAuth; + } } diff --git a/src/VAPID.php b/src/VAPID.php index 8f1ca2cc..401926a2 100644 --- a/src/VAPID.php +++ b/src/VAPID.php @@ -134,7 +134,6 @@ public static function getVapidHeaders($audience, $subject, $publicKey, $private ); } - /** * This method creates VAPID keys in case you would not be able to have a Linux bash. * DO NOT create keys at each initialization! Save those keys and reuse them. @@ -152,7 +151,7 @@ private static function getUncompressedKeys(PrivateKeyInterface $privateKeyObjec { $pointSerializer = new UncompressedPointSerializer(EccFactory::getAdapter()); $vapid['publicKey'] = base64_encode(hex2bin($pointSerializer->serialize($privateKeyObject->getPublicKey()->getPoint()))); - $vapid['privateKey'] = base64_encode(hex2bin(str_pad(gmp_strval($privateKeyObject->getSecret(), 16), 2*self::PRIVATE_KEY_LENGTH, '0', STR_PAD_LEFT))); + $vapid['privateKey'] = base64_encode(hex2bin(str_pad(gmp_strval($privateKeyObject->getSecret(), 16), 2 * self::PRIVATE_KEY_LENGTH, '0', STR_PAD_LEFT))); return $vapid; } diff --git a/src/WebPush.php b/src/WebPush.php index 0157a0e1..3e540480 100644 --- a/src/WebPush.php +++ b/src/WebPush.php @@ -73,13 +73,14 @@ public function __construct(array $auth = array(), $defaultOptions = array(), $t * @param string|null $userAuthToken * @param bool $flush If you want to flush directly (usually when you send only one notification) * @param array $options Array with several options tied to this notification. If not set, will use the default options that you can set in the WebPush object + * @param array $auth Use this auth details instead of what you provided when creating WebPush * * @return array|bool Return an array of information if $flush is set to true and the queued requests has failed. * Else return true * * @throws \ErrorException */ - public function sendNotification($endpoint, $payload = null, $userPublicKey = null, $userAuthToken = null, $flush = false, $options = array()) + public function sendNotification($endpoint, $payload = null, $userPublicKey = null, $userAuthToken = null, $flush = false, $options = array(), $auth = array()) { if (isset($payload)) { if (Utils::safeStrlen($payload) > Encryption::MAX_PAYLOAD_LENGTH) { @@ -89,7 +90,11 @@ public function sendNotification($endpoint, $payload = null, $userPublicKey = nu $payload = Encryption::padPayload($payload, $this->automaticPadding); } - $this->notifications[] = new Notification($endpoint, $payload, $userPublicKey, $userAuthToken, $options); + if (array_key_exists('VAPID', $auth)) { + $auth['VAPID'] = VAPID::validate($auth['VAPID']); + } + + $this->notifications[] = new Notification($endpoint, $payload, $userPublicKey, $userAuthToken, $options, $auth); if ($flush) { $res = $this->flush(); @@ -180,6 +185,7 @@ private function prepareAndSend(array $notifications) $userPublicKey = $notification->getUserPublicKey(); $userAuthToken = $notification->getUserAuthToken(); $options = $notification->getOptions($this->getDefaultOptions()); + $auth = $notification->getAuth($this->auth); if (isset($payload) && isset($userPublicKey) && isset($userAuthToken)) { $encrypted = Encryption::encrypt($payload, $userPublicKey, $userAuthToken, $this->nativePayloadEncryptionSupport); @@ -213,15 +219,15 @@ private function prepareAndSend(array $notifications) // if GCM if (substr($endpoint, 0, strlen(self::GCM_URL)) === self::GCM_URL) { - if (array_key_exists('GCM', $this->auth)) { - $headers['Authorization'] = 'key='.$this->auth['GCM']; + if (array_key_exists('GCM', $auth)) { + $headers['Authorization'] = 'key='.$auth['GCM']; } else { throw new \ErrorException('No GCM API Key specified.'); } } // if VAPID (GCM doesn't support it but FCM does) - elseif (array_key_exists('VAPID', $this->auth)) { - $vapid = $this->auth['VAPID']; + elseif (array_key_exists('VAPID', $auth)) { + $vapid = $auth['VAPID']; $audience = parse_url($endpoint, PHP_URL_SCHEME).'://'.parse_url($endpoint, PHP_URL_HOST);