Beispiel #1
0
 def send_notification(self, title, options, ttl=86400):
     subscription = {
         "endpoint": self.endpoint,
         "keys": {
             "auth": self.auth,
             "p256dh": self.p256dh
         }
     }
     payload = {"title": title, "options": options or {}}
     WebPusher(subscription).\
         send(json.dumps(payload), {}, ttl, GCM_KEY)
Beispiel #2
0
 def test_encode_no_crypto(self):
     subscription_info = self._gen_subscription_info()
     del(subscription_info['keys'])
     headers = {"Crypto-Key": "pre-existing",
                "Authentication": "bearer vapid"}
     data = 'Something'
     pusher = WebPusher(subscription_info)
     assert_raises(WebPushException,
                   pusher.encode,
                   data,
                   headers)
Beispiel #3
0
 def test_send_empty(self, mock_post):
     subscription_info = self._gen_subscription_info()
     headers = {"Crypto-Key": "pre-existing",
                "Authentication": "bearer vapid"}
     WebPusher(subscription_info).send('', headers)
     eq_(subscription_info.get('endpoint'), mock_post.call_args[0][0])
     pheaders = mock_post.call_args[1].get('headers')
     eq_(pheaders.get('ttl'), '0')
     ok_('encryption' not in pheaders)
     eq_(pheaders.get('AUTHENTICATION'), headers.get('Authentication'))
     ckey = pheaders.get('crypto-key')
     ok_('pre-existing' in ckey)
Beispiel #4
0
async def process_user(user, args, headers):
    """Send a message to a user or drop the user if no longer valid.

    :param user: UserID of customer to attempt to send Subscription Update
    :type user: string
    :param args: settings
    :type args: object
    :param headers: Additional headers to send
    :type headers: dict

    :returns: UserID of failed sends

    """
    sub_info = json.loads(user["subinfo"])
    try:
        result = WebPusher(sub_info).send(
            args.msg,
            headers=headers,
            ttl=args.ttl)
        print("Result: {}".format(result.status_code))
        if result.status_code > requests.codes.ok:
            # Remove any users that no longer want updates.
            if result.status_code in [404, 410]:
                try:
                    reply = json.loads(result.text)
                    reason = reply.get(
                        "message",
                        "Unknown reason")
                    if 'more_info' in reply:
                        reason += (
                            "\nFor more info, see: " +
                            reply['more_info']
                            )
                except:
                    reason = "and couldn't understand {}".format(
                        result.text
                        )
                log.error(
                    "Failed to send to {}: {}".format(
                        user["id"],
                        reason,

                    )
                )
                await drop_user(args, user["id"])
                args.db.commit()
                return None
            result.raise_for_status()
        log.info("Sent message to {}".format(user["id"]))
        return None
    except Exception as x:
        log.error("Could not process user {}".format(repr(x)))
        return user["id"]
Beispiel #5
0
def simple_push_notification(sender, receiver, notiftype, teaser=''):
    """
    Send a Push Notification to all registered endpoints of user 'receiver'.
    """
    data = {}
    ttl = 120
    gcm_url = 'https://android.googleapis.com/gcm/send'
    endpoints = receiver.endpoints.all()

    if settings.DEBUG:
        print('- ' * 30)
        print('# simple_push_notification() with:')
        print('#     sender: {}'.format(sender))
        print('#   receiver: {}'.format(receiver))
        print('#  notiftype: {}'.format(notiftype))
        print('#     teaser: {}'.format(teaser))
        print('#  endpoints: {}'.format(endpoints.count()))

    for obj in endpoints:
        # Special case Google: needs gcm_key as API key.
        gcm_key = settings.GCM_AUTHKEY if gcm_url in obj.sub else None

        # Make sure we only send one per minute at most. Further limit it on
        # the client device.
        if (obj.latest + timedelta(minutes=1)) > now():
            return False
        obj.latest = now()
        obj.save()

        if settings.DEBUG:
            print('- ' * 30)
            print('#    obj.sub: {}'.format(obj.sub))

        subscription_info = json.loads(obj.sub)

        if settings.DEBUG:
            print('# sub...info: {}'.format(subscription_info))

        headers = {'Content-Type': 'application/json'}
        data['notiftype'] = notiftype  # 'message', 'upvote', etc.
        data['username'] = sender.username  # Sender's username.
        data['teaser'] = teaser  # A few words of a message received, if any.
        data_str = json.dumps(data, ensure_ascii=True)

        if settings.DEBUG:
            print('#   data_str: {}'.format(data_str))

        try:
            WebPusher(subscription_info).send(data_str, headers, ttl, gcm_key)
        except WebPushException as e:
            # "subscription_info missing keys dictionary"
            if settings.DEBUG:
                print('WebPushException: {}'.format(e))
Beispiel #6
0
def _send_notification(push_info, payload, ttl):
    subscription = push_info.subscription
    subscription_data = _process_subscription_info(subscription)
    # Check if GCM info is provided in the settings
    if hasattr(settings, 'WEBPUSH_SETTINGS'):
        gcm_key = settings.WEBPUSH_SETTINGS.get('GCM_KEY')
    else:
        gcm_key = None
    req = WebPusher(subscription_data).send(data=payload,
                                            ttl=ttl,
                                            gcm_key=gcm_key)
    return req
Beispiel #7
0
    def _push_message(self, payload, **kwargs):
        """Send the message."""
        import jwt
        from pywebpush import WebPusher

        timestamp = int(time.time())

        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)
            if info is None:
                _LOGGER.error(
                    "%s is not a valid HTML5 push notification"
                    " target", target)
                continue

            jwt_exp = (datetime.datetime.fromtimestamp(timestamp) +
                       datetime.timedelta(days=JWT_VALID_DAYS))
            jwt_secret = info[ATTR_SUBSCRIPTION][ATTR_KEYS][ATTR_AUTH]
            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

            # 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(info[ATTR_SUBSCRIPTION]).send(
                json.dumps(payload), gcm_key=gcm_key, ttl='86400')

            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 #8
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")
Beispiel #9
0
    def test_init(self):
        # use static values so we know what to look for in the reply
        subscription_info = {
            u"endpoint": u"https://example.com/",
            u"keys": {
                u"p256dh": (u"BOrnIslXrUow2VAzKCUAE4sIbK00daEZCswOcf8m3T"
                            "F8V82B-OpOg5JbmYLg44kRcvQC1E2gMJshsUYA-_zMPR8"),
                u"auth":
                u"k8JV6sjdbhAi1n3_LDBLvA"
            }
        }
        self.assertRaises(WebPushException, WebPusher,
                          {"keys": {
                              'p256dh': 'AAA=',
                              'auth': 'AAA='
                          }})
        self.assertRaises(WebPushException, WebPusher,
                          {"endpoint": "https://example.com"})
        self.assertRaises(WebPushException, WebPusher, {
            "endpoint": "https://example.com",
            "keys": {
                'p256dh': 'AAA='
            }
        })
        self.assertRaises(WebPushException, WebPusher, {
            "endpoint": "https://example.com",
            "keys": {
                'auth': 'AAA='
            }
        })
        self.assertRaises(
            WebPushException, WebPusher, {
                "endpoint": "https://example.com",
                "keys": {
                    'p256dh': 'AAA=',
                    'auth': 'AAA='
                }
            })

        push = WebPusher(subscription_info)
        eq_(push.subscription_info, subscription_info)
        eq_(
            push.receiver_key,
            bytes_compat(b'\x04\xea\xe7"\xc9W\xadJ0\xd9P3(%\x00\x13\x8b'
                         b'\x08l\xad4u\xa1\x19\n\xcc\x0eq\xff&\xdd1'
                         b'|W\xcd\x81\xf8\xeaN\x83\x92[\x99\x82\xe0\xe3'
                         b'\x89\x11r\xf4\x02\xd4M\xa00\x9b!\xb1F\x00'
                         b'\xfb\xfc\xcc=\x1f'))
        eq_(push.auth_key,
            bytes_compat(b'\x93\xc2U\xea\xc8\xddn\x10"\xd6}\xff,0K\xbc'))
Beispiel #10
0
 def test_send(self, mock_post):
     subscription_info = self._gen_subscription_info()
     headers = {"Crypto-Key": "pre-existing",
                "Authentication": "bearer vapid"}
     data = "Mary had a little lamb"
     WebPusher(subscription_info).send(data, headers)
     eq_(subscription_info.get('endpoint'), mock_post.call_args[0][0])
     pheaders = mock_post.call_args[1].get('headers')
     eq_(pheaders.get('ttl'), '0')
     ok_('encryption' in pheaders)
     eq_(pheaders.get('AUTHENTICATION'), headers.get('Authentication'))
     ckey = pheaders.get('crypto-key')
     ok_('pre-existing' in ckey)
     eq_(pheaders.get('content-encoding'), 'aesgcm')
def send_push_worker(data):
    (
        subscr_list,
        payload,
        ttl,
    ) = data

    responses = []
    exceptions = []  # can't use logger in a worker
    for subscr in subscr_list:
        try:
            if subscr.is_gcm():
                response = WebPusher(subscr.endpoint_and_keys()).send(
                    data=payload if subscr.supports_payload() else None,
                    ttl=ttl,
                    timeout=2,
                    gcm_key=FCM_SERVER_KEY,
                    # seems to be the only encoding legacy chrome understands
                    # for payload encryption
                    content_encoding="aesgcm")
                responses.append((subscr, response))
            else:
                try:
                    response = webpush(
                        subscription_info=subscr.endpoint_and_keys(),
                        data=payload if subscr.supports_payload() else None,
                        ttl=ttl,
                        timeout=2,
                        vapid_private_key=VAPID_PRIVATE_KEY,
                        vapid_claims={
                            "sub": "mailto:" + VAPID_ADMIN_EMAIL,
                            # minus 15 minutes for clock differences between our server and
                            # push service server. This is still better than default
                            # minus 12 hours in pywebpush lib
                            "exp": int(time.time()) + ttl - 15 * 60,
                        })
                    responses.append((subscr, response))
                except WebPushException as e:
                    # WebPushException got response object but we need to count
                    # error points on subscriptions
                    responses.append((subscr, e.response))
        except Exception as e:
            exceptions.append((
                subscr,
                e,
                time.time(),
            ))

    return (responses, exceptions)
Beispiel #12
0
 def test_send_using_requests_session(self, mock_session):
     subscription_info = self._gen_subscription_info()
     headers = {
         "Crypto-Key": "pre-existing",
         "Authentication": "bearer vapid"
     }
     data = "Mary had a little lamb"
     WebPusher(subscription_info,
               requests_session=mock_session).send(data, headers)
     assert subscription_info.get(
         'endpoint') == mock_session.post.call_args[0][0]
     pheaders = mock_session.post.call_args[1].get('headers')
     assert pheaders.get('ttl') == '0'
     assert pheaders.get('AUTHENTICATION') == headers.get('Authentication')
     ckey = pheaders.get('crypto-key')
     assert 'pre-existing' in ckey
     assert pheaders.get('content-encoding') == 'aes128gcm'
def send_push_worker(data):
    (
        subscr_list,
        payload,
        ttl,
        gcm_key,
        vapid_key,
        vapid_email,
    ) = data
    
    responses = []
    exceptions = []  # can't use logger in a worker
    for subscr in subscr_list:
        try:
            if subscr.is_gcm(): 
                response = WebPusher( subscr.endpoint_and_keys() ).send(
                    data=payload if subscr.supports_payload() else None,
                    ttl=ttl,
                    timeout=3.0,
                    gcm_key=gcm_key,
                    # seems to be the only encoding legacy chrome understands
                    # for payload encryption
                    content_encoding="aesgcm"
                )
                responses.append( (subscr, response) )
            else:
                try:
                    response = webpush(
                        subscription_info=subscr.endpoint_and_keys(),
                        data=payload if subscr.supports_payload() else None,
                        ttl=ttl,
                        timeout=3.0,
                        vapid_private_key=vapid_key,
                        vapid_claims={"sub": "mailto:"+vapid_email,}
                    )
                    responses.append( (subscr, response) )
                except WebPushException as e:
                    # WebPushException got response object but we need to count
                    # error points on subscriptions
                    responses.append( (subscr, e.response) )
        except Exception as e:
            exceptions.append( (subscr, e, time.time(),) )
    
    return (responses, exceptions)
Beispiel #14
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 #15
0
with open('config.json') as config_file:
    config = json.load(config_file)

# Use grønstrøm API to get contents of push message
message = requests.get('https://grønstrøm.nu/api/v1/next-day-short').text
logging.info(f'Sending push message: {message}')

# Get all subscriptions from SQLite database
conn = sqlite3.Connection('/data/subs.db')
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.
Beispiel #16
0
    def send_message(self, message="", **kwargs):
        """Send a message to a user."""
        import jwt
        from pywebpush import WebPusher

        timestamp = int(time.time())
        tag = str(uuid.uuid4())

        payload = {
            'badge': '/static/images/notification-badge.png',
            'body': message,
            ATTR_DATA: {},
            'icon': '/static/icons/favicon-192x192.png',
            ATTR_TAG: tag,
            'timestamp': (timestamp * 1000),  # Javascript ms since epoch
            ATTR_TITLE: kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT)
        }

        data = kwargs.get(ATTR_DATA)

        if data:
            # Pick out fields that should go into the notification directly vs
            # into the notification data dictionary.

            for key, val in data.copy().items():
                if key in HTML5_SHOWNOTIFICATION_PARAMETERS:
                    payload[key] = val
                    del data[key]

            payload[ATTR_DATA] = data

        if (payload[ATTR_DATA].get(ATTR_URL) is None
                and payload.get(ATTR_ACTIONS) is None):
            payload[ATTR_DATA][ATTR_URL] = URL_ROOT

        targets = kwargs.get(ATTR_TARGET)

        if not targets:
            targets = self.registrations.keys()
        elif not isinstance(targets, list):
            targets = [targets]

        for target in targets:
            info = self.registrations.get(target)
            if info is None:
                _LOGGER.error(
                    '%s is not a valid HTML5 push notification'
                    ' target!', target)
                continue

            jwt_exp = (datetime.datetime.fromtimestamp(timestamp) +
                       datetime.timedelta(days=JWT_VALID_DAYS))
            jwt_secret = info[ATTR_SUBSCRIPTION][ATTR_KEYS][ATTR_AUTH]
            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(info[ATTR_SUBSCRIPTION]).send(json.dumps(payload),
                                                    gcm_key=self._gcm_key,
                                                    ttl='86400')
Beispiel #17
0
    def send_message(self, message="", **kwargs):
        """Send a message to a user."""
        import jwt
        from pywebpush import WebPusher

        timestamp = int(time.time())
        tag = str(uuid.uuid4())

        payload = {
            'badge': '/static/images/notification-badge.png',
            'body': message,
            ATTR_DATA: {},
            'icon': '/static/icons/favicon-192x192.png',
            ATTR_TAG: tag,
            'timestamp': (timestamp*1000),  # Javascript ms since epoch
            ATTR_TITLE: kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT)
        }

        data = kwargs.get(ATTR_DATA)

        if data:
            # Pick out fields that should go into the notification directly vs
            # into the notification data dictionary.

            data_tmp = {}

            for key, val in data.items():
                if key in HTML5_SHOWNOTIFICATION_PARAMETERS:
                    payload[key] = val
                else:
                    data_tmp[key] = val

            payload[ATTR_DATA] = data_tmp

        if (payload[ATTR_DATA].get(ATTR_URL) is None and
                payload.get(ATTR_ACTIONS) is None):
            payload[ATTR_DATA][ATTR_URL] = URL_ROOT

        targets = kwargs.get(ATTR_TARGET)

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

        for target in list(targets):
            info = self.registrations.get(target)
            if info is None:
                _LOGGER.error("%s is not a valid HTML5 push notification"
                              " target", target)
                continue

            jwt_exp = (datetime.datetime.fromtimestamp(timestamp) +
                       datetime.timedelta(days=JWT_VALID_DAYS))
            jwt_secret = info[ATTR_SUBSCRIPTION][ATTR_KEYS][ATTR_AUTH]
            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

            response = WebPusher(info[ATTR_SUBSCRIPTION]).send(
                json.dumps(payload), gcm_key=self._gcm_key, ttl='86400')

            # pylint: disable=no-member
            if response.status_code == 410:
                _LOGGER.info("Notification channel has expired")
                reg = self.registrations.pop(target)
                if not _save_config(self.registrations_json_path,
                                    self.registrations):
                    self.registrations[target] = reg
                    _LOGGER.error("Error saving registration.")
                else:
                    _LOGGER.info("Configuration saved")
Beispiel #18
0
        "p256dh":
        "BK7h-R0UgDeT89jhWi76-FlTtlEr3DbVBnrr34qmK91Husli_Fazu7vo7kW1mg9F_qhNzrs2glbrc6wfqGFsXks=",
        "auth": "CyOHiGNXPcT5Slo9UMx2uA=="
    }
}
data = 'aaaaaa'
vapid_private_key = PRIVATE_KEY = '''
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg2xyYpqQhOaIdSbqH
UwM3+ySvF47MoJyAFUNaHM7g/zOhRANCAAT554ztzCpjiIFOxNfEIicSzNPOZTIB
Y1+CGl+LDfM5RlUNERFdfZYRqMmwvX7ydq7UiASkspWqdVVKZnLCzPD3  
'''.strip()
vapid_claims = {"sub": "mailto:[email protected]"}

vapid_headers = None
if vapid_claims:
    if not vapid_claims.get('aud'):
        url = urlparse(subscription_info.get('endpoint'))
        aud = "{}://{}".format(url.scheme, url.netloc)
        vapid_claims['aud'] = aud
    if os.path.isfile(vapid_private_key):
        vv = Vapid.from_file(
            private_key_file=vapid_private_key)  # pragma no cover
    else:
        vv = Vapid.from_string(private_key=vapid_private_key)
    vapid_headers = vv.sign(vapid_claims)

result = WebPusher(subscription_info,
                   requests_session).send(data, vapid_headers)

print result.text
Beispiel #19
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 #20
0
 def get_webpusher(subscription):
     '''Return a WebPusher instance for a given subscription.'''
     return WebPusher(subscription)
Beispiel #21
0
 def push(self, message: str, icon: str = '/static/favicon.ico') -> None:
     WebPusher(self.to_dict()).send(
         json.dumps({'body': message,
                     'icon': icon}),
         gcm_key=GOOGLE_API_KEY)
Beispiel #22
0
 def test_encode_empty(self):
     subscription_info = self._gen_subscription_info()
     headers = {"Crypto-Key": "pre-existing",
                "Authentication": "bearer vapid"}
     encoded = WebPusher(subscription_info).encode('', headers)
     eq_(encoded, None)
Beispiel #23
0
        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"
Beispiel #24
0
confirmation = raw_input("Would you like to send?  (Y/n)")
if confirmation.lower() != "y":
    print "Quitting...\n"
    exit()

for token in tokens:
    subscription_info = {
        "endpoint":
        "https://android.googleapis.com/gcm/send/fuKkKlzSEEE:APA91bFKiuJ3LEx7Ke3xOEJ…Lx-t8INikH97ewASUn6OSzRAGeGf8Eu1B5Q7Lju_7QBj5VeGjwCePUufhiSzFXqEogaJ4esAqA",
        "keys": {
            "p256dh": token.p256dh,
            "auth": token.auth
        }
    }
    data = '{"data": {"message":"' + args.message + '","title":"' + args.title + '"}}'
    encoded = WebPusher(subscription_info).encode(data)
    crypto_key = "dh=" + encoded["crypto_key"]
    salt = "salt=" + encoded['salt']
    headers = {
        'Authorization': 'key=' + FCM_KEY,
        'Content-Type': 'application/json',
    }
    headers.update({
        'crypto-key': crypto_key,
        'content-encoding': 'aesgcm',
        'encryption': salt
    })
    fcm_data = {
        "raw_data": base64.b64encode(encoded.get('body')),
        "registration_ids": [token.endpoint[40:]]
    }