def _deserialize_function(tag): # type: (bytes) -> Callable """Identifies the correct deserialization function based on the provided tag. :param tag: Identifying tag, read from start of serialized object :type tag: dynamodb_encryption_sdk.internal.identifiers.Tag :rtype: callable """ # for some reason pylint can't follow the Enum member attributes deserialize_functions = { Tag.BINARY.tag: _deserialize_binary, # pylint: disable=no-member Tag.BINARY_SET.tag: _deserialize_binary_set, # pylint: disable=no-member Tag.NUMBER.tag: _deserialize_number, # pylint: disable=no-member Tag.NUMBER_SET.tag: _deserialize_number_set, # pylint: disable=no-member Tag.STRING.tag: _deserialize_string, # pylint: disable=no-member Tag.STRING_SET.tag: _deserialize_string_set, # pylint: disable=no-member Tag.BOOLEAN.tag: _deserialize_boolean, # pylint: disable=no-member Tag.NULL.tag: _deserialize_null, # pylint: disable=no-member Tag.LIST.tag: _deserialize_list, # pylint: disable=no-member Tag.MAP.tag: _deserialize_map, # pylint: disable=no-member } try: return deserialize_functions[tag] except KeyError: raise DeserializationError('Unsupported tag: "{}"'.format(tag))
def _deserialize(stream): # type: (io.BytesIO) -> Dict[Text, dynamodb_types.RAW_ATTRIBUTE] """Deserializes a serialized object. :param stream: Stream containing serialized object :type stream: io.BytesIO :rtype: dict """ try: tag = decode_tag(stream) return _deserialize_function(tag)(stream) except struct.error: raise DeserializationError("Malformed serialized data")
def decode_tag(stream): """Decode a tag value from a serialized stream. :param stream: Source data stream :type stream: io.BytesIO :returns: Decoded tag :rtype: bytes """ (reserved, tag) = unpack_value(">cc", stream) if reserved != b"\x00": raise DeserializationError("Invalid tag: reserved byte is not null") return tag
def _deserialize_map(stream): # type: (io.BytesIO) -> Dict[Text, dynamodb_types.MAP] """Deserializes a map object. :param stream: Stream containing serialized object :type stream: io.BytesIO :rtype: dict """ member_count = decode_length(stream) members = {} # type: dynamodb_types.MAP for _ in range(member_count): key = _deserialize(stream) if Tag.STRING.dynamodb_tag not in key: raise DeserializationError( 'Malformed serialized map: found "{}" as map key.'.format(list(key.keys())[0]) ) value = _deserialize(stream) members[key[Tag.STRING.dynamodb_tag]] = value return {Tag.MAP.dynamodb_tag: members}
def deserialize_attribute(serialized_attribute): # noqa: C901 pylint: disable=too-many-locals # type: (bytes) -> dynamodb_types.RAW_ATTRIBUTE """Deserializes serialized attributes for decryption. :param bytes serialized_attribute: Serialized attribute bytes :returns: Deserialized attribute :rtype: dict """ def _transform_binary_value(value): # (bytes) -> bytes """Transforms a serialized binary value. :param bytes value: Raw deserialized value :rtype: bytes """ if isinstance(value, Binary): return value.value return value def _deserialize_binary(stream): # type: (io.BytesIO) -> Dict[Text, bytes] """Deserializes a binary object. :param stream: Stream containing serialized object :type stream: io.BytesIO :rtype: dict """ value = decode_value(stream) return {Tag.BINARY.dynamodb_tag: _transform_binary_value(value)} def _transform_string_value(value): # (bytes) -> dynamodb_types.STRING """Transforms a serialized string value. :param bytes value: Raw deserialized value :rtype: dynamodb_encryption_sdk.internal.dynamodb_types.STRING """ return codecs.decode(value, TEXT_ENCODING) def _deserialize_string(stream): # type: (io.BytesIO) -> Dict[Text, dynamodb_types.STRING] """Deserializes a string object. :param stream: Stream containing serialized object :type stream: io.BytesIO :rtype: dict """ value = decode_value(stream) return {Tag.STRING.dynamodb_tag: _transform_string_value(value)} def _transform_number_value(value): # (bytes) -> dynamodb_types.STRING """Transforms a serialized number value. :param bytes value: Raw deserialized value :rtype: dynamodb_encryption_sdk.internal.dynamodb_types.STRING """ raw_value = codecs.decode(value, TEXT_ENCODING) decimal_value = Decimal(to_str(raw_value)).normalize() return "{0:f}".format(decimal_value) def _deserialize_number(stream): # type: (io.BytesIO) -> Dict[Text, dynamodb_types.STRING] """Deserializes a number object. :param stream: Stream containing serialized object :type stream: io.BytesIO :rtype: dict """ value = decode_value(stream) return {Tag.NUMBER.dynamodb_tag: _transform_number_value(value)} _boolean_map = {TagValues.FALSE.value: False, TagValues.TRUE.value: True} def _deserialize_boolean(stream): # type: (io.BytesIO) -> Dict[Text, dynamodb_types.BOOLEAN] """Deserializes a boolean object. :param stream: Stream containing serialized object :type stream: io.BytesIO :rtype: dict """ value = decode_byte(stream) return {Tag.BOOLEAN.dynamodb_tag: _boolean_map[value]} def _deserialize_null(stream): # we want a consistent API but don't use stream, so pylint: disable=unused-argument # type: (io.BytesIO) -> Dict[Text, dynamodb_types.BOOLEAN] """Deserializes a null object. :param stream: Stream containing serialized object :type stream: io.BytesIO :rtype: dict """ return {Tag.NULL.dynamodb_tag: True} def _deserialize_set(stream, member_transform): # type: (io.BytesIO, Callable) -> List[Union[dynamodb_types.BINARY, dynamodb_types.STRING]] """Deserializes contents of serialized set. :param stream: Stream containing serialized object :type stream: io.BytesIO :rtype: list """ member_count = decode_length(stream) return sorted([member_transform(decode_value(stream)) for _ in range(member_count)]) def _deserialize_binary_set(stream): # type: (io.BytesIO) -> Dict[Text, dynamodb_types.SET[dynamodb_types.BINARY]] """Deserializes a binary set object. :param stream: Stream containing serialized object :type stream: io.BytesIO :rtype: dict """ return {Tag.BINARY_SET.dynamodb_tag: _deserialize_set(stream, _transform_binary_value)} def _deserialize_string_set(stream): # type: (io.BytesIO) -> Dict[Text, dynamodb_types.SET[dynamodb_types.STRING]] """Deserializes a string set object. :param stream: Stream containing serialized object :type stream: io.BytesIO :rtype: dict """ return {Tag.STRING_SET.dynamodb_tag: _deserialize_set(stream, _transform_string_value)} def _deserialize_number_set(stream): # type: (io.BytesIO) -> Dict[Text, dynamodb_types.SET[dynamodb_types.STRING]] """Deserializes a number set object. :param stream: Stream containing serialized object :type stream: io.BytesIO :rtype: dict """ return {Tag.NUMBER_SET.dynamodb_tag: _deserialize_set(stream, _transform_number_value)} def _deserialize_list(stream): # type: (io.BytesIO) -> Dict[Text, dynamodb_types.LIST] """Deserializes a list object. :param stream: Stream containing serialized object :type stream: io.BytesIO :rtype: dict """ member_count = decode_length(stream) return {Tag.LIST.dynamodb_tag: [_deserialize(stream) for _ in range(member_count)]} def _deserialize_map(stream): # type: (io.BytesIO) -> Dict[Text, dynamodb_types.MAP] """Deserializes a map object. :param stream: Stream containing serialized object :type stream: io.BytesIO :rtype: dict """ member_count = decode_length(stream) members = {} # type: dynamodb_types.MAP for _ in range(member_count): key = _deserialize(stream) if Tag.STRING.dynamodb_tag not in key: raise DeserializationError( 'Malformed serialized map: found "{}" as map key.'.format(list(key.keys())[0]) ) value = _deserialize(stream) members[key[Tag.STRING.dynamodb_tag]] = value return {Tag.MAP.dynamodb_tag: members} def _deserialize_function(tag): # type: (bytes) -> Callable """Identifies the correct deserialization function based on the provided tag. :param tag: Identifying tag, read from start of serialized object :type tag: dynamodb_encryption_sdk.internal.identifiers.Tag :rtype: callable """ deserialize_functions = { Tag.BINARY.tag: _deserialize_binary, Tag.BINARY_SET.tag: _deserialize_binary_set, Tag.NUMBER.tag: _deserialize_number, Tag.NUMBER_SET.tag: _deserialize_number_set, Tag.STRING.tag: _deserialize_string, Tag.STRING_SET.tag: _deserialize_string_set, Tag.BOOLEAN.tag: _deserialize_boolean, Tag.NULL.tag: _deserialize_null, Tag.LIST.tag: _deserialize_list, Tag.MAP.tag: _deserialize_map, } try: return deserialize_functions[tag] except KeyError: raise DeserializationError('Unsupported tag: "{}"'.format(tag)) def _deserialize(stream): # type: (io.BytesIO) -> Dict[Text, dynamodb_types.RAW_ATTRIBUTE] """Deserializes a serialized object. :param stream: Stream containing serialized object :type stream: io.BytesIO :rtype: dict """ try: tag = decode_tag(stream) return _deserialize_function(tag)(stream) except struct.error: raise DeserializationError("Malformed serialized data") if not serialized_attribute: raise DeserializationError("Empty serialized attribute data") stream = io.BytesIO(serialized_attribute) return _deserialize(stream)