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")
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 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
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)
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()
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()
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")
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)
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()