Beispiel #1
0
    def _push_message(self, payload, **kwargs):
        """Send the message."""
        from pywebpush import WebPusher

        timestamp = int(time.time())
        ttl = int(kwargs.get(ATTR_TTL, DEFAULT_TTL))
        priority = kwargs.get(ATTR_PRIORITY, DEFAULT_PRIORITY)
        if priority not in ["normal", "high"]:
            priority = DEFAULT_PRIORITY
        payload["timestamp"] = timestamp * 1000  # Javascript ms since epoch
        targets = kwargs.get(ATTR_TARGET)

        if not targets:
            targets = self.registrations.keys()

        for target in list(targets):
            info = self.registrations.get(target)
            try:
                info = REGISTER_SCHEMA(info)
            except vol.Invalid:
                _LOGGER.error(
                    "%s is not a valid HTML5 push notification"
                    " target", target)
                continue
            payload[ATTR_DATA][ATTR_JWT] = add_jwt(
                timestamp,
                target,
                payload[ATTR_TAG],
                info[ATTR_SUBSCRIPTION][ATTR_KEYS][ATTR_AUTH],
            )
            webpusher = WebPusher(info[ATTR_SUBSCRIPTION])
            if self._vapid_prv and self._vapid_email:
                vapid_headers = create_vapid_headers(self._vapid_email,
                                                     info[ATTR_SUBSCRIPTION],
                                                     self._vapid_prv)
                vapid_headers.update({
                    "urgency": priority,
                    "priority": priority
                })
                response = webpusher.send(data=json.dumps(payload),
                                          headers=vapid_headers,
                                          ttl=ttl)
            else:
                # Only pass the gcm key if we're actually using GCM
                # If we don't, notifications break on FireFox
                gcm_key = (self._gcm_key if "googleapis.com"
                           in info[ATTR_SUBSCRIPTION][ATTR_ENDPOINT] else None)
                response = webpusher.send(json.dumps(payload),
                                          gcm_key=gcm_key,
                                          ttl=ttl)

            if response.status_code == 410:
                _LOGGER.info("Notification channel has expired")
                reg = self.registrations.pop(target)
                if not save_json(self.registrations_json_path,
                                 self.registrations):
                    self.registrations[target] = reg
                    _LOGGER.error("Error saving registration")
                else:
                    _LOGGER.info("Configuration saved")
Beispiel #2
0
 def test_gcm(self, mock_post):
     subscription_info = self._gen_subscription_info(
         None,
         endpoint="https://android.googleapis.com/gcm/send/regid123")
     headers = {"Crypto-Key": "pre-existing",
                "Authentication": "bearer vapid"}
     data = "Mary had a little lamb"
     wp = WebPusher(subscription_info)
     wp.send(data, headers, gcm_key="gcm_key_value")
     pdata = json.loads(mock_post.call_args[1].get('data'))
     pheaders = mock_post.call_args[1].get('headers')
     eq_(pdata["registration_ids"][0], "regid123")
     eq_(pheaders.get("authorization"), "key=gcm_key_value")
     eq_(pheaders.get("content-type"), "application/json")
 def test_gcm(self, mock_post):
     subscription_info = self._gen_subscription_info(
         None,
         endpoint="https://android.googleapis.com/gcm/send/regid123")
     headers = {"Crypto-Key": "pre-existing",
                "Authentication": "bearer vapid"}
     data = "Mary had a little lamb"
     wp = WebPusher(subscription_info)
     wp.send(data, headers, gcm_key="gcm_key_value")
     pdata = json.loads(mock_post.call_args[1].get('data'))
     pheaders = mock_post.call_args[1].get('headers')
     eq_(pdata["registration_ids"][0], "regid123")
     eq_(pheaders.get("authorization"), "key=gcm_key_value")
     eq_(pheaders.get("content-type"), "application/json")
Beispiel #4
0
def send(reg_id, message, **kwargs):
    """
    Site: https://developers.google.com
    API: https://developers.google.com/web/updates/2016/03/web-push-encryption
    Desc: Web Push notifications for Chrome and FireFox

    Installation:
    pip install 'pywebpush>=0.4.0'
    """

    subscription_info = kwargs.pop('subscription_info')

    payload = {
        "title": kwargs.pop("event"),
        "body": message,
        "url": kwargs.pop("push_url", None)
    }
    payload.update(kwargs)

    wp = WebPusher(subscription_info)
    response = wp.send(
        dumps(payload), gcm_key=settings.GCM_KEY,
        ttl=kwargs.pop("ttl", 60))

    if not response.ok or (
            response.text and loads(response.text).get("failure") > 0):
        raise GCMError(response.text)
    return True
Beispiel #5
0
def send_push_notification(title, url, message):
    subs = PushNotification.objects.all()
    data = {
        "title": title,
        "url": url,
        "message": message,
    }
    # print(data)
    for s in subs:
        try:
            push = json.loads(s.subscription)
            subscription_info = {
                "endpoint": push['endpoint'],
                "keys": {
                    "p256dh": push['keys']['p256dh'],
                    "auth": push['keys']['auth'],
                },
            }
            # webpush(
            #     subscription_info,
            #     data='hello',
            #     vapid_private_key='gL1krMw2MRvwTGj8VS-UXZ9FdfOSvLf8nnl8EElGd-M',
            #     vapid_claims={
            #         "sub": "mailto:[email protected]",
            #         "aud": 'http://127.0.0.1:8000'
            #     },
            # )
            wp = WebPusher(subscription_info)
            wp.send(
                'hello',
                headers={
                    'Authorization':
                    'WebPush eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJodHRwOi8vMTI3LjAuMC4xOjgwMDAiLCJleHAiOiIxNTM1MTU3MjcxIiwic3ViIjoibWFpbHRvOmhlbGxvQHRoZWxpZmVzdHlsZXN0b3JlLmNvbS5uZyJ9.nNF82Zt_6K0f87nu6YgM5Fd_JpYGRvK-U554aHqNd8V_gS0d7gaWw9zEGVCZ66Rn-e28xtEkqBeD7GnZE0a3sg',
                    'Crypto-Key':
                    'p256ecdsa=BBVgtyidgfOeXent70LBOtWewZDouTMrfn_2eWBxV5AbpVjgpw9gQvgon07RmCJQ5iDOqn_8FrjmjR16pfn2GJU'
                })
        except WebPushException as ex:
            print("Webpush not successful", ex)
            # Mozilla returns additional information in the body of the response.
            if ex.response and ex.response.json():
                extra = ex.response.json()
                print("Remote service replied with a {}:{}, {}", extra.code,
                      extra.errno, extra.message)
Beispiel #6
0
def queue_push_firefox(apids, message):
    payload_data = json.loads(message)
    ttl = 7 * 86400
    apids_to_clear = []
    for apid in apids:
        subscription = json.loads(apid.token)
        wp = WebPusher(subscription)
        response = wp.send(json.dumps(payload_data), ttl=ttl)
        if response.status_code == 410:
            apids_to_clear.append(apid)

    # Remove unregistered ids
    for apid in apids_to_clear:
        apid.delete()
Beispiel #7
0
def queue_push_chrome(apids, message):
    payload_data = json.loads(message)
    ttl = 7 * 86400
    apids_to_clear = []
    for apid in apids:
        subscription = json.loads(apid.token)
        wp = WebPusher(subscription)
        response = wp.send(json.dumps(payload_data), gcm_key=settings.GCM_KEY, ttl=ttl)

        if response.status_code == 400:
            content = response.content
            if content.find("UnauthorizedRegistration") >= 0:
                apids_to_clear.append(apid)

    # Remove unregistered ids
    for apid in apids_to_clear:
        apid.delete()
Beispiel #8
0
    def _push_message(self, payload, **kwargs):
        """Send the message."""
        from pywebpush import WebPusher

        timestamp = int(time.time())
        ttl = int(kwargs.get(ATTR_TTL, DEFAULT_TTL))
        priority = kwargs.get(ATTR_PRIORITY, DEFAULT_PRIORITY)
        if priority not in ['normal', 'high']:
            priority = DEFAULT_PRIORITY
        payload['timestamp'] = (timestamp * 1000)  # Javascript ms since epoch
        targets = kwargs.get(ATTR_TARGET)

        if not targets:
            targets = self.registrations.keys()

        for target in list(targets):
            info = self.registrations.get(target)
            try:
                info = REGISTER_SCHEMA(info)
            except vol.Invalid:
                _LOGGER.error(
                    "%s is not a valid HTML5 push notification"
                    " target", target)
                continue
            payload[ATTR_DATA][ATTR_JWT] = add_jwt(
                timestamp, target, payload[ATTR_TAG],
                info[ATTR_SUBSCRIPTION][ATTR_KEYS][ATTR_AUTH])
            import jwt
            jwt_secret = info[ATTR_SUBSCRIPTION][ATTR_KEYS][ATTR_AUTH]
            jwt_exp = (datetime.fromtimestamp(timestamp) +
                       timedelta(days=JWT_VALID_DAYS))
            jwt_claims = {
                'exp': jwt_exp,
                'nbf': timestamp,
                'iat': timestamp,
                ATTR_TARGET: target,
                ATTR_TAG: payload[ATTR_TAG]
            }
            jwt_token = jwt.encode(jwt_claims, jwt_secret).decode('utf-8')
            payload[ATTR_DATA][ATTR_JWT] = jwt_token
            webpusher = WebPusher(info[ATTR_SUBSCRIPTION])
            if self._vapid_prv and self._vapid_email:
                vapid_headers = create_vapid_headers(self._vapid_email,
                                                     info[ATTR_SUBSCRIPTION],
                                                     self._vapid_prv)
                vapid_headers.update({
                    'urgency': priority,
                    'priority': priority
                })
                response = webpusher.send(data=json.dumps(payload),
                                          headers=vapid_headers,
                                          ttl=ttl)
            else:
                # Only pass the gcm key if we're actually using GCM
                # If we don't, notifications break on FireFox
                gcm_key = self._gcm_key \
                    if 'googleapis.com' \
                    in info[ATTR_SUBSCRIPTION][ATTR_ENDPOINT] \
                    else None
                response = webpusher.send(json.dumps(payload),
                                          gcm_key=gcm_key,
                                          ttl=ttl)

            if response.status_code == 410:
                _LOGGER.info("Notification channel has expired")
                reg = self.registrations.pop(target)
                if not save_json(self.registrations_json_path,
                                 self.registrations):
                    self.registrations[target] = reg
                    _LOGGER.error("Error saving registration")
                else:
                    _LOGGER.info("Configuration saved")
Beispiel #9
0
                timestamp,
                target,
                payload[ATTR_TAG],
                info[ATTR_SUBSCRIPTION][ATTR_KEYS][ATTR_AUTH],
            )
            webpusher = WebPusher(info[ATTR_SUBSCRIPTION])
            if self._vapid_prv and self._vapid_email:
                vapid_headers = create_vapid_headers(self._vapid_email,
                                                     info[ATTR_SUBSCRIPTION],
                                                     self._vapid_prv)
                vapid_headers.update({
                    "urgency": priority,
                    "priority": priority
                })
                response = webpusher.send(data=json.dumps(payload),
                                          headers=vapid_headers,
                                          ttl=ttl)
            else:
                # Only pass the gcm key if we're actually using GCM
                # If we don't, notifications break on FireFox
                gcm_key = (self._gcm_key if "googleapis.com"
                           in info[ATTR_SUBSCRIPTION][ATTR_ENDPOINT] else None)
                response = webpusher.send(json.dumps(payload),
                                          gcm_key=gcm_key,
                                          ttl=ttl)

            if response.status_code == 410:
                _LOGGER.info("Notification channel has expired")
                reg = self.registrations.pop(target)
                try:
                    save_json(self.registrations_json_path, self.registrations)
Beispiel #10
0
try:
    c = conn.cursor()
    for i, row in enumerate(c.execute('SELECT * FROM subs')):
        try:
            # Manually recreate the push facade from the pywebpush API to be able to specify both TTL and urgency
            subscription_info = json.loads(row[0])
            pusher = WebPusher(subscription_info)
            url = urlparse(subscription_info['endpoint'])
            aud = "{}://{}".format(url.scheme, url.netloc)
            vapid_claims = {
                'sub': f'mailto:{config["sub_email"]}',
                'aud': aud,
                'exp': int(time.time()) + 12 * 60 * 60
            }
            vv = Vapid.from_string(config['vapid_key'])
            headers = vv.sign(vapid_claims)
            # Define the urgency to be "normal", corresponding to messages being delivered
            # while the device is "On neither power nor wifi".
            # https://tools.ietf.org/html/draft-ietf-webpush-protocol-12#section-5.3
            headers['Urgency'] = 'normal'
            resp = pusher.send(message, headers, ttl=12 * 60 * 60)
            # TODO: Handle cases where response status code is not 201.
            logging.debug(
                f'{i} ({resp.status_code}: {resp.text}): {subscription_info}')
        except Exception as e:
            logging.warning(f'{i} (failed): {e}')

finally:
    if conn:
        conn.close()