예제 #1
0
def create_vapid_headers(vapid_email, subscription_info, vapid_private_key):
    """Create encrypted headers to send to WebPusher."""

    if vapid_email and vapid_private_key and ATTR_ENDPOINT in subscription_info:
        url = urlparse(subscription_info.get(ATTR_ENDPOINT))
        vapid_claims = {
            "sub": f"mailto:{vapid_email}",
            "aud": f"{url.scheme}://{url.netloc}",
        }
        vapid = Vapid.from_string(private_key=vapid_private_key)
        return vapid.sign(vapid_claims)
    return None
예제 #2
0
def create_vapid_headers(vapid_email, subscription_info, vapid_private_key):
    """Create encrypted headers to send to WebPusher."""
    from py_vapid import Vapid

    if vapid_email and vapid_private_key and ATTR_ENDPOINT in subscription_info:
        url = urlparse(subscription_info.get(ATTR_ENDPOINT))
        vapid_claims = {
            "sub": "mailto:{}".format(vapid_email),
            "aud": "{}://{}".format(url.scheme, url.netloc),
        }
        vapid = Vapid.from_string(private_key=vapid_private_key)
        return vapid.sign(vapid_claims)
    return None
예제 #3
0
def create_vapid_headers(vapid_email, subscription_info, vapid_private_key):
    """Create encrypted headers to send to WebPusher."""
    from py_vapid import Vapid
    try:
        from urllib.parse import urlparse
    except ImportError:  # pragma: no cover
        from urlparse import urlparse
    if (vapid_email and vapid_private_key
            and ATTR_ENDPOINT in subscription_info):
        url = urlparse(subscription_info.get(ATTR_ENDPOINT))
        vapid_claims = {
            'sub': 'mailto:{}'.format(vapid_email),
            'aud': "{}://{}".format(url.scheme, url.netloc)
        }
        vapid = Vapid.from_string(private_key=vapid_private_key)
        return vapid.sign(vapid_claims)
    return None
예제 #4
0
def webpush(subscription_info,
            data=None,
            vapid_private_key=None,
            vapid_claims=None,
            content_encoding="aes128gcm",
            curl=False,
            timeout=None,
            ttl=0,
            verbose=False,
            headers=None):
    """
        One call solution to endcode and send `data` to the endpoint
        contained in `subscription_info` using optional VAPID auth headers.

        in example:

        .. code-block:: python

        from pywebpush import python

        webpush(
            subscription_info={
                "endpoint": "https://push.example.com/v1/abcd",
                "keys": {"p256dh": "0123abcd...",
                         "auth": "001122..."}
                 },
            data="Mary had a little lamb, with a nice mint jelly",
            vapid_private_key="path/to/key.pem",
            vapid_claims={"sub": "*****@*****.**"}
            )

        No additional method call is required. Any non-success will throw a
        `WebPushException`.

    :param subscription_info: Provided by the client call
    :type subscription_info: dict
    :param data: Serialized data to send
    :type data: str
    :param vapid_private_key: Vapid instance or path to vapid private key PEM \
                              or encoded str
    :type vapid_private_key: Union[Vapid, str]
    :param vapid_claims: Dictionary of claims ('sub' required)
    :type vapid_claims: dict
    :param content_encoding: Optional content type string
    :type content_encoding: str
    :param curl: Return as "curl" string instead of sending
    :type curl: bool
    :param timeout: POST requests timeout
    :type timeout: float or tuple
    :param ttl: Time To Live
    :type ttl: int
    :param verbose: Provide verbose feedback
    :type verbose: bool
    :return requests.Response or string
    :param headers: Dictionary of extra HTTP headers to include
    :type headers: dict

    """
    if headers is None:
        headers = dict()
    else:
        # Ensure we don't leak VAPID headers by mutating the passed in dict.
        headers = headers.copy()

    vapid_headers = None
    if vapid_claims:
        if verbose:
            print("Generating VAPID headers...")
        if not vapid_claims.get('aud'):
            url = urlparse(subscription_info.get('endpoint'))
            aud = "{}://{}".format(url.scheme, url.netloc)
            vapid_claims['aud'] = aud
        # Remember, passed structures are mutable in python.
        # It's possible that a previously set `exp` field is no longer valid.
        if (not vapid_claims.get('exp')
                or vapid_claims.get('exp') < int(time.time())):
            # encryption lives for 12 hours
            vapid_claims['exp'] = int(time.time()) + (12 * 60 * 60)
            if verbose:
                print("Setting VAPID expry to {}...".format(
                    vapid_claims['exp']))
        if not vapid_private_key:
            raise WebPushException("VAPID dict missing 'private_key'")
        if isinstance(vapid_private_key, Vapid):
            vv = vapid_private_key
        elif os.path.isfile(vapid_private_key):
            # Presume that key from file is handled correctly by
            # py_vapid.
            vv = Vapid.from_file(
                private_key_file=vapid_private_key)  # pragma no cover
        else:
            vv = Vapid.from_string(private_key=vapid_private_key)
        if verbose:
            print("\t claims: {}".format(vapid_claims))
        vapid_headers = vv.sign(vapid_claims)
        if verbose:
            print("\t headers: {}".format(vapid_headers))
        headers.update(vapid_headers)

    response = WebPusher(subscription_info, verbose=verbose).send(
        data,
        headers,
        ttl=ttl,
        content_encoding=content_encoding,
        curl=curl,
        timeout=timeout,
    )
    if not curl and response.status_code > 202:
        raise WebPushException("Push failed: {} {}\nResponse body:{}".format(
            response.status_code, response.reason, response.text),
                               response=response)
    return response
예제 #5
0
def webpush(subscription_info,
            data=None,
            vapid_private_key=None,
            vapid_claims=None,
            content_encoding="aes128gcm",
            curl=False,
            timeout=None,
            ttl=0):
    """
        One call solution to endcode and send `data` to the endpoint
        contained in `subscription_info` using optional VAPID auth headers.

        in example:

        .. code-block:: python

        from pywebpush import python

        webpush(
            subscription_info={
                "endpoint": "https://push.example.com/v1/abcd",
                "keys": {"p256dh": "0123abcd...",
                         "auth": "001122..."}
                 },
            data="Mary had a little lamb, with a nice mint jelly",
            vapid_private_key="path/to/key.pem",
            vapid_claims={"sub": "*****@*****.**"}
            )

        No additional method call is required. Any non-success will throw a
        `WebPushException`.

    :param subscription_info: Provided by the client call
    :type subscription_info: dict
    :param data: Serialized data to send
    :type data: str
    :param vapid_private_key: Vapid instance or path to vapid private key PEM \
                              or encoded str
    :type vapid_private_key: Union[Vapid, str]
    :param vapid_claims: Dictionary of claims ('sub' required)
    :type vapid_claims: dict
    :param content_encoding: Optional content type string
    :type content_encoding: str
    :param curl: Return as "curl" string instead of sending
    :type curl: bool
    :param timeout: POST requests timeout
    :type timeout: float or tuple
    :param ttl: Time To Live
    :type ttl: int
    :return requests.Response or string

    """
    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 not vapid_claims.get('exp'):
            # encryption lives for 12 hours
            vapid_claims['exp'] = int(time.time()) + (12 * 60 * 60)
        if not vapid_private_key:
            raise WebPushException("VAPID dict missing 'private_key'")
        if isinstance(vapid_private_key, Vapid):
            vv = vapid_private_key
        elif os.path.isfile(vapid_private_key):
            # Presume that key from file is handled correctly by
            # py_vapid.
            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)
    response = WebPusher(subscription_info).send(
        data,
        vapid_headers,
        ttl=ttl,
        content_encoding=content_encoding,
        curl=curl,
        timeout=timeout,
    )
    if not curl and response.status_code > 202:
        raise WebPushException("Push failed: {} {}".format(
            response.status_code, response.reason),
                               response=response)
    return response
예제 #6
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
예제 #7
0
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.
            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()
예제 #8
0
def webpush(subscription_info,
            data=None,
            vapid_private_key=None,
            vapid_claims=None,
            content_encoding="aes128gcm",
            curl=False,
            timeout=None,
            ttl=0):
    """
        One call solution to endcode and send `data` to the endpoint
        contained in `subscription_info` using optional VAPID auth headers.

        in example:

        .. code-block:: python

        from pywebpush import python

        webpush(
            subscription_info={
                "endpoint": "https://push.example.com/v1/abcd",
                "keys": {"p256dh": "0123abcd...",
                         "auth": "001122..."}
                 },
            data="Mary had a little lamb, with a nice mint jelly",
            vapid_private_key="path/to/key.pem",
            vapid_claims={"sub": "*****@*****.**"}
            )

        No additional method call is required. Any non-success will throw a
        `WebPushException`.

    :param subscription_info: Provided by the client call
    :type subscription_info: dict
    :param data: Serialized data to send
    :type data: str
    :param vapid_private_key: Vapid instance or path to vapid private key PEM \
                              or encoded str
    :type vapid_private_key: Union[Vapid, str]
    :param vapid_claims: Dictionary of claims ('sub' required)
    :type vapid_claims: dict
    :param content_encoding: Optional content type string
    :type content_encoding: str
    :param curl: Return as "curl" string instead of sending
    :type curl: bool
    :param timeout: POST requests timeout
    :type timeout: float or tuple
    :param ttl: Time To Live
    :type ttl: int
    :return requests.Response or string

    """
    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 not vapid_claims.get('exp'):
            # encryption lives for 12 hours
            vapid_claims['exp'] = int(time.time()) + (12 * 60 * 60)
        if not vapid_private_key:
            raise WebPushException("VAPID dict missing 'private_key'")
        if isinstance(vapid_private_key, Vapid):
            vv = vapid_private_key
        elif os.path.isfile(vapid_private_key):
            # Presume that key from file is handled correctly by
            # py_vapid.
            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)
    response = WebPusher(subscription_info).send(
        data,
        vapid_headers,
        ttl=ttl,
        content_encoding=content_encoding,
        curl=curl,
        timeout=timeout,
    )
    if not curl and response.status_code > 202:
        raise WebPushException("Push failed: {} {}".format(
            response.status_code, response.reason),
            response=response)
    return response