def parse_decrypted_message_id(decrypted_token): # type: (str) -> Dict[str, Any] """Parses a decrypted message-id into component parts""" topic = None sortkey_timestamp = None if decrypted_token.startswith("01:"): info = decrypted_token.split(":") if len(info) != 4: raise InvalidTokenException("Incorrect number of token parts.") api_ver, uaid, chid, topic = info elif decrypted_token.startswith("02:"): info = decrypted_token.split(":") if len(info) != 4: raise InvalidTokenException("Incorrect number of token parts.") api_ver, uaid, chid, raw_sortkey = info sortkey_timestamp = int(raw_sortkey) else: info = decrypted_token.split(":") if len(info) != 3: raise InvalidTokenException("Incorrect number of token parts.") kind, uaid, chid = decrypted_token.split(":") if kind != "m": raise InvalidTokenException("Incorrect token kind.") return dict( uaid=uaid, chid=chid, topic=topic, sortkey_timestamp=sortkey_timestamp, )
def parse_endpoint(self, metrics, token, version="v1", ckey_header=None, auth_header=None): """Parse an endpoint into component elements of UAID, CHID and optional key hash if v2 :param token: The obscured subscription data. :param version: This is the API version of the token. :param ckey_header: the Crypto-Key header bearing the public key (from Crypto-Key: p256ecdsa=) :param auth_header: The Authorization header bearing the VAPID info :raises ValueError: In the case of a malformed endpoint. :returns: a dict containing (uaid=UAID, chid=CHID, public_key=KEY) """ token = self.fernet.decrypt(repad(token).encode('utf8')) public_key = None if ckey_header: try: crypto_key = CryptoKey(ckey_header) except CryptoKeyException: raise InvalidTokenException("Invalid key data") public_key = crypto_key.get_label('p256ecdsa') if auth_header: vapid_auth = parse_auth_header(auth_header) if not vapid_auth: raise VapidAuthException("Invalid Auth token") metrics.increment("updates.notification.auth.{}".format( vapid_auth['scheme'])) # pull the public key from the VAPID auth header if needed try: if vapid_auth['version'] != 1: public_key = vapid_auth['k'] except KeyError: raise VapidAuthException("Missing Public Key") if version == 'v1' and len(token) != 32: raise InvalidTokenException("Corrupted push token") if version == 'v2': if not auth_header: raise VapidAuthException("Missing Authorization Header") if len(token) != 64: raise InvalidTokenException("Corrupted push token") if not public_key: raise VapidAuthException("Invalid key data") try: decoded_key = base64url_decode(public_key) except TypeError: raise VapidAuthException("Invalid key data") if not constant_time.bytes_eq( sha256(decoded_key).digest(), token[32:]): raise VapidAuthException("Key mismatch") return dict(uaid=token[:16].encode('hex'), chid=token[16:32].encode('hex'), version=version, public_key=public_key)
def _token_valid(self, result, func): """Handles valid token processing, then dispatches to supplied function""" info = result.split(":") if len(info) != 3: raise InvalidTokenException("Wrong message token components") kind, uaid, chid = info if kind != 'm': raise InvalidTokenException("Wrong message token kind") return func(kind, uaid, chid)
def parse_endpoint(self, token, version="v0", ckey_header=None): """Parse an endpoint into component elements of UAID, CHID and optional key hash if v2 :param token: The obscured subscription data. :param version: This is the API version of the token. :param ckey_header: the Crypto-Key header bearing the public key (from Crypto-Key: p256ecdsa=) :raises ValueError: In the case of a malformed endpoint. :returns: a dict containing (uaid=UAID, chid=CHID, public_key=KEY) """ token = self.fernet.decrypt(token.encode('utf8')) public_key = None if ckey_header: try: crypto_key = CryptoKey(ckey_header) except CryptoKeyException: raise InvalidTokenException("Invalid key data") label = crypto_key.get_label('p256ecdsa') try: public_key = base64url_decode(label) except: # Ignore missing and malformed app server keys. pass if version == 'v0': if not VALID_V0_TOKEN.match(token): raise InvalidTokenException("Corrupted push token") items = token.split(':') return dict(uaid=items[0], chid=items[1], public_key=public_key) if version == 'v1' and len(token) != 32: raise InvalidTokenException("Corrupted push token") if version == 'v2': if len(token) != 64: raise InvalidTokenException("Corrupted push token") if not public_key: raise InvalidTokenException("Invalid key data") if not constant_time.bytes_eq( sha256(public_key).digest(), token[32:]): raise InvalidTokenException("Key mismatch") return dict(uaid=token[:16].encode('hex'), chid=token[16:32].encode('hex'), public_key=public_key)
def throw_item(*args, **kwargs): raise InvalidTokenException("Not found")