예제 #1
0
    def validate(self):
        """
        Ensure the condition is valid according the local rules.

        Checks the condition against the local bitmask (supported condition types)
        and the local maximum fulfillment size.

        Returns:
            bool: Whether the condition is valid according to local rules.
        """
        # Get class for type ID, throws on error
        TypeRegistry.get_class_from_type_id(self.type_id)

        # Bitmask can have at most 32 bits with current implementation
        if self.bitmask > Condition.MAX_SAFE_BITMASK:
            raise ValueError('Bitmask too large to be safely represented')

        # Assert all requested features are supported by this implementation
        if self.bitmask & ~Condition.SUPPORTED_BITMASK:
            raise ValueError('Condition requested unsupported feature suites')

        # Assert the requested fulfillment size is supported by this implementation
        if self.max_fulfillment_length > Condition.MAX_FULFILLMENT_LENGTH:
            raise ValueError('Condition requested too large of a max fulfillment size')

        return True
예제 #2
0
    def validate(self):
        """
        Ensure the condition is valid according the local rules.

        Checks the condition against the local bitmask (supported condition types)
        and the local maximum fulfillment size.

        Returns:
            bool: Whether the condition is valid according to local rules.
        """
        # Get class for type ID, throws on error
        TypeRegistry.get_class_from_type_id(self.type_id)

        # Bitmask can have at most 32 bits with current implementation
        if self.bitmask > Condition.MAX_SAFE_BITMASK:
            raise ValueError('Bitmask too large to be safely represented')

        # Assert all requested features are supported by this implementation
        if self.bitmask & ~Condition.SUPPORTED_BITMASK:
            raise ValueError('Condition requested unsupported feature suites')

        # Assert the requested fulfillment size is supported by this implementation
        if self.max_fulfillment_length > Condition.MAX_FULFILLMENT_LENGTH:
            raise ValueError(
                'Condition requested too large of a max fulfillment size')

        return True
예제 #3
0
    def validate(self):
        """
        Ensure the condition is valid according the local rules.

        Checks the condition against the local subtypes (supported
        condition types) and the local maximum fulfillment size.

        Returns:
            bool: Whether the condition is valid according to local rules.
        """
        # Get class for type ID, throws on error
        TypeRegistry.find_by_type_id(self.type_id)

        # Subtypes can have at most 32 bits with current implementation
        if len(self.subtypes) > Condition.MAX_SAFE_SUBTYPES:
            raise ValueError('Subtypes too large to be safely represented')

        # Assert all requested features are supported by this implementation
        if any(subtype not in Condition.SUPPORTED_SUBTYPES
               for subtype in self.subtypes):
            raise ValueError('Condition requested unsupported feature suites')

        # Assert the requested fulfillment size
        # is supported by this implementation
        if self.cost > Condition.MAX_COST:
            raise ValueError(
                'Condition requested too large of a max fulfillment size')

        return True
예제 #4
0
 def to_asn1_dict(self):
     condition_type = TypeRegistry.find_by_type_id(self.type_id)
     condition_class = condition_type['class']
     payload = {'fingerprint': self.hash, 'cost': self.cost}
     if condition_class.TYPE_CATEGORY == 'compound':
         subtype_ids = [
             TypeRegistry.find_by_name(subtype)['type_id']
             for subtype in self.subtypes
         ]
         bits = ['0' for bit in range(5)]
         for subtype_id in subtype_ids:
             bits[subtype_id] = '1'
         bitstring = ''.join(bits).rstrip('0')
         payload['subtypes'] = bitstring
     return {condition_class.TYPE_ASN1: payload}
    def from_uri(serialized_fulfillment):
        """
        Create a Fulfillment object from a URI.

        This method will parse a fulfillment URI and construct a corresponding Fulfillment object.

        Args:
            serialized_fulfillment (str): URI representing the fulfillment

        Return:
            Fulfillment: Resulting object
        """
        if isinstance(serialized_fulfillment, Fulfillment):
            return serialized_fulfillment
        elif not isinstance(serialized_fulfillment, str):
            raise TypeError('Serialized fulfillment must be a string')

        pieces = serialized_fulfillment.split(':')
        if not pieces[0] == 'cf':
            raise ValueError('Serialized fulfillment must start with "cf:"')

        if not re.match(Fulfillment.REGEX, serialized_fulfillment):
            raise ValueError('Invalid fulfillment format')
        # try:
        type_id = int(pieces[1], 16)
        payload = base64.urlsafe_b64decode(base64_add_padding(pieces[2]))

        cls = TypeRegistry.get_class_from_type_id(type_id)
        fulfillment = cls()

        fulfillment.parse_payload(Reader.from_source(payload), len(payload))
        # except Exception as e:
        #     raise ParsingError(str(e))

        return fulfillment
예제 #6
0
    def from_uri(serialized_condition):
        """
        Create a Condition object from a URI.

        This method will parse a condition URI and construct a corresponding Condition object.

        Args:
            serialized_condition (str): URI representing the condition

        Returns:
            Condition: Resulting object
        """
        # TODO consider removing.
        if isinstance(serialized_condition, Condition):
            return serialized_condition
        # TODO Use static typing instead (e.g.: with mypy).
        elif not isinstance(serialized_condition, str):
            raise TypeError('Serialized condition must be a string')

        pieces = serialized_condition.split(':')
        if pieces[0] != CONDITION_URI_SCHEME:
            raise PrefixError(
                'Serialized condition must start with "{}:"'.format(
                    CONDITION_URI_SCHEME
                )
            )

        regex_match = re.match(CONDITION_REGEX_STRICT, serialized_condition)
        if not regex_match:
            raise ParsingError('Invalid condition format')

        qs_dict = parse_qs(regex_match.group(2))

        try:
            fingerprint_type = qs_dict['fpt'][0]
        except (KeyError, IndexError):
            raise ParsingError(
                'Invalid condition format: "fpt" parameter or value missing.')

        condition_type = TypeRegistry.find_by_name(fingerprint_type)
        try:
            cost = qs_dict['cost'][0]
        except (KeyError, IndexError):
            raise ParsingError(
                'Invalid condition format: "cost" parameter or value missing.')

        if not re.match(INTEGER_REGEX, cost):
            raise ParsingError('No or invalid cost provided')

        fingerprint = regex_match.group(1)
        condition = Condition()
        condition.type_id = condition_type['type_id']
        condition._subtypes = set()
        if condition_type['class'].TYPE_CATEGORY == 'compound':
            condition._subtypes.update(qs_dict['subtypes'][0].split(','))
        condition.hash = base64.urlsafe_b64decode(
            base64_add_padding(fingerprint))
        condition.cost = int(cost)
        return condition
    def from_dict(data):
        cls_type = data['type_id']
        cls = TypeRegistry.get_class_from_type_id(cls_type)

        fulfillment = cls()
        fulfillment.parse_dict(data)

        return fulfillment
예제 #8
0
    def from_asn1_dict(asn1_dict):
        asn1_type, value = asn1_dict.popitem()
        registered_type = TypeRegistry.find_by_asn1_type(asn1_type)
        # Instantiate condition
        condition = Condition()
        condition.type_id = registered_type['type_id']
        condition.hash = value['fingerprint']
        condition.cost = value['cost']
        condition._subtypes = set()
        if registered_type['class'].TYPE_CATEGORY == 'compound':
            subtypes = {
                TypeRegistry.find_by_type_id(type_id)['name']
                for type_id in compress(
                    range(Condition.MAX_SAFE_SUBTYPES),
                    map(lambda bit: int(bit), value['subtypes'])
                )
            }
            condition._subtypes.update(subtypes)

        return condition
예제 #9
0
    def serialize_uri(self):
        """
        Generate the URI form encoding of this condition.

        Turns the condition into a URI containing only URL-safe characters. This
        format is convenient for passing around conditions in URLs, JSON and other text-based formats.

        "cc:" BASE16(TYPE_ID) ":" BASE16(BITMASK) ":" BASE64URL(HASH) ":" BASE10(MAX_COST)

        Returns:
            string: Condition as a URI
        """
        condition_type = TypeRegistry.find_by_type_id(self.type_id)
        condition_class = TypeRegistry.find_by_type_id(self.type_id)['class']
        include_subtypes = condition_class.TYPE_CATEGORY == 'compound'
        uri = 'ni:///sha-256;{}?fpt={}&cost={}'.format(
            base64_remove_padding(
                base64.urlsafe_b64encode(self.hash)).decode(),
            condition_type['name'],
            self.cost,
        )
        if include_subtypes:
            uri += '&subtypes=' + ','.join(sorted(self.subtypes))
        return uri
    def from_binary(reader):
        """
        Create a Fulfillment object from a binary blob.

        This method will parse a stream of binary data and construct a
        corresponding Fulfillment object.

        Args:
            reader (Reader): Binary stream implementing the Reader interface
        Returns:
            Fulfillment: Resulting object
        """
        reader = Reader.from_source(reader)

        cls_type = reader.read_uint16()
        cls = TypeRegistry.get_class_from_type_id(cls_type)

        fulfillment = cls()
        payload_length = reader.read_length_prefix()
        fulfillment.parse_payload(reader, payload_length)

        return fulfillment
예제 #11
0
 def from_json(data):
     type_ = TypeRegistry.find_by_name(data['type'])
     fulfillment = type_['class']()
     fulfillment.parse_json(data)
     return fulfillment
예제 #12
0
 def from_asn1_dict(asn1_dict):
     asn1_type, value = asn1_dict.popitem()
     instance = TypeRegistry.find_by_asn1_type(asn1_type)['class']()
     instance.parse_asn1_dict_payload(value)
     instance.asn1_dict = {asn1_type: value}
     return instance
예제 #13
0
 def from_json(data):
     type_ = TypeRegistry.find_by_name(data['type'])
     fulfillment = type_['class']()
     fulfillment.parse_json(data)
     return fulfillment
예제 #14
0
 def from_asn1_dict(asn1_dict):
     asn1_type, value = asn1_dict.popitem()
     instance = TypeRegistry.find_by_asn1_type(asn1_type)['class']()
     instance.parse_asn1_dict_payload(value)
     instance.asn1_dict = {asn1_type: value}
     return instance
예제 #15
0
 def to_asn1_json(self):
     asn1_type, value = self.to_asn1_dict().popitem()
     condition_type = TypeRegistry.find_by_asn1_type(asn1_type)
     return {'type': condition_type['asn1_condition'], 'value': value}
예제 #16
0
 def type_name(self):
     return TypeRegistry.find_by_type_id(self.type_id)['name']