Beispiel #1
0
 /**
  * @dataProvider vapidProvider
  *
  * @param $audience
  * @param $vapid
  * @param $expiration
  * @param $expectedAuthorization
  * @param $expectedCryptoKey
  */
 public function testGetVapidHeaders($audience, $vapid, $expiration, $expectedAuthorization, $expectedCryptoKey)
 {
     $vapid = VAPID::validate($vapid);
     $headers = VAPID::getVapidHeaders($audience, $vapid['subject'], $vapid['publicKey'], $vapid['privateKey'], $expiration);
     $this->assertArrayHasKey('Authorization', $headers);
     $this->assertEquals(Utils::safeStrlen($expectedAuthorization), Utils::safeStrlen($headers['Authorization']));
     $this->assertEquals($this->explodeAuthorization($expectedAuthorization), $this->explodeAuthorization($headers['Authorization']));
     $this->assertArrayHasKey('Crypto-Key', $headers);
     $this->assertEquals($expectedCryptoKey, $headers['Crypto-Key']);
 }
Beispiel #2
0
 /**
  * @param array $vapid
  *
  * @return array
  *
  * @throws \ErrorException
  */
 public static function validate(array $vapid)
 {
     if (!array_key_exists('subject', $vapid)) {
         throw new \ErrorException('[VAPID] You must provide a subject that is either a mailto: or a URL.');
     }
     if (array_key_exists('pemFile', $vapid)) {
         $vapid['pem'] = file_get_contents($vapid['pemFile']);
         if (!$vapid['pem']) {
             throw new \ErrorException('Error loading PEM file.');
         }
     }
     if (array_key_exists('pem', $vapid)) {
         $pem = $vapid['pem'];
         $posStartKey = strpos($pem, '-----BEGIN EC PRIVATE KEY-----');
         $posEndKey = strpos($pem, '-----END EC PRIVATE KEY-----');
         if ($posStartKey === false || $posEndKey === false) {
             throw new \ErrorException('Invalid PEM data.');
         }
         $posStartKey += 30;
         // length of '-----BEGIN EC PRIVATE KEY-----'
         $pemSerializer = new PemPrivateKeySerializer(new DerPrivateKeySerializer());
         $keys = self::getUncompressedKeys($pemSerializer->parse(substr($pem, $posStartKey, $posEndKey - $posStartKey)));
         $vapid['publicKey'] = $keys['publicKey'];
         $vapid['privateKey'] = $keys['privateKey'];
     }
     if (!array_key_exists('publicKey', $vapid)) {
         throw new \ErrorException('[VAPID] You must provide a public key.');
     }
     $publicKey = Base64Url::decode($vapid['publicKey']);
     if (Utils::safeStrlen($publicKey) !== self::PUBLIC_KEY_LENGTH) {
         throw new \ErrorException('[VAPID] Public key should be 65 bytes long when decoded.');
     }
     if (!array_key_exists('privateKey', $vapid)) {
         throw new \ErrorException('[VAPID] You must provide a private key.');
     }
     $privateKey = Base64Url::decode($vapid['privateKey']);
     if (Utils::safeStrlen($privateKey) !== self::PRIVATE_KEY_LENGTH) {
         throw new \ErrorException('[VAPID] Private key should be 32 bytes long when decoded.');
     }
     return array('subject' => $vapid['subject'], 'publicKey' => $publicKey, 'privateKey' => $privateKey);
 }
Beispiel #3
0
 /**
  * Returns an info record. See sections 3.2 and 3.3 of
  * {@link https://tools.ietf.org/html/draft-ietf-httpbis-encryption-encoding-00}
  * From {@link https://github.com/GoogleChrome/push-encryption-node/blob/master/src/encrypt.js}.
  *
  * @param $type string The type of the info record
  * @param $context string The context for the record
  *
  * @return string
  *
  * @throws \ErrorException
  */
 private static function createInfo($type, $context)
 {
     if (Utils::safeStrlen($context) !== 135) {
         throw new \ErrorException('Context argument has invalid size');
     }
     return 'Content-Encoding: ' . $type . chr(0) . 'P-256' . $context;
 }
Beispiel #4
0
 /**
  * @dataProvider payloadProvider
  *
  * @param string $payload
  * @param integer $maxLengthToPad
  * @param integer $expectedResLength
  */
 public function testPadPayload($payload, $maxLengthToPad, $expectedResLength)
 {
     $res = Encryption::padPayload($payload, $maxLengthToPad);
     $this->assertContains('test', $res);
     $this->assertEquals($expectedResLength, Utils::safeStrlen($res));
 }
Beispiel #5
0
 private function prepareAndSend(array $notifications)
 {
     $responses = array();
     /** @var Notification $notification */
     foreach ($notifications as $notification) {
         $endpoint = $notification->getEndpoint();
         $payload = $notification->getPayload();
         $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);
             $headers = array('Content-Length' => Utils::safeStrlen($encrypted['cipherText']), 'Content-Type' => 'application/octet-stream', 'Content-Encoding' => 'aesgcm', 'Encryption' => 'salt=' . $encrypted['salt'], 'Crypto-Key' => 'dh=' . $encrypted['localPublicKey']);
             $content = $encrypted['cipherText'];
         } else {
             $headers = array('Content-Length' => 0);
             $content = '';
         }
         $headers['TTL'] = $options['TTL'];
         if (isset($options['urgency'])) {
             $headers['Urgency'] = $options['urgency'];
         }
         if (isset($options['topic'])) {
             $headers['Topic'] = $options['topic'];
         }
         // if GCM
         if (substr($endpoint, 0, strlen(self::GCM_URL)) === self::GCM_URL) {
             if (array_key_exists('GCM', $auth)) {
                 $headers['Authorization'] = 'key=' . $auth['GCM'];
             } else {
                 throw new \ErrorException('No GCM API Key specified.');
             }
         } elseif (array_key_exists('VAPID', $auth)) {
             $vapid = $auth['VAPID'];
             $audience = parse_url($endpoint, PHP_URL_SCHEME) . '://' . parse_url($endpoint, PHP_URL_HOST);
             if (!parse_url($audience)) {
                 throw new \ErrorException('Audience "' . $audience . '"" could not be generated.');
             }
             $vapidHeaders = VAPID::getVapidHeaders($audience, $vapid['subject'], $vapid['publicKey'], $vapid['privateKey']);
             $headers['Authorization'] = $vapidHeaders['Authorization'];
             if (array_key_exists('Crypto-Key', $headers)) {
                 // FUTURE replace ';' with ','
                 $headers['Crypto-Key'] .= ';' . $vapidHeaders['Crypto-Key'];
             } else {
                 $headers['Crypto-Key'] = $vapidHeaders['Crypto-Key'];
             }
         }
         $responses[] = $this->sendRequest($endpoint, $headers, $content);
     }
     return $responses;
 }