"""
A set of utility functions allowing to convert
a string to a valid value of a chosen type.
"""
from typing import Any, Callable, Dict, Type
from cybsi.api.dictionary import DictItemAttributeValue
from cybsi.api.enum import CybsiAPIEnum
from cybsi.api.observable.enums import (
AttributeNames,
EntityKeyTypes,
IdentityClass,
NodeRole,
PotentialDamage,
RegionalInternetRegistry,
RelatedThreatCategory,
ThreatCategory,
)
def _str_converter(val: str):
if isinstance(val, str):
return val.strip()
raise ValueError(f"value {val} is not a string")
def _int_converter(val: str):
return int(val)
def _bool_converter(val: str):
if isinstance(val, bool):
return val
if not isinstance(val, str):
raise ValueError(f"value {val} is not string")
if val.lower() == "true":
return True
if val.lower() == "false":
return False
raise ValueError("bool value must be 'true' or 'false'")
def _new_enum_value_converter(api_enum: Type[CybsiAPIEnum], ignore_case=False):
def _enum_converter(val: Any) -> str:
return api_enum.from_string(str(val), ignore_case=ignore_case).value
return _enum_converter
def _dict_item_value_converter(val: str):
if isinstance(val, str):
return DictItemAttributeValue(key=val)
raise ValueError(f"value {val} is not a string")
_entity_key_converters: Dict[EntityKeyTypes, Callable[[Any], Any]] = {
EntityKeyTypes.String: _str_converter,
EntityKeyTypes.MD5: _str_converter,
EntityKeyTypes.SHA1: _str_converter,
EntityKeyTypes.SHA256: _str_converter,
EntityKeyTypes.IANAID: _str_converter,
EntityKeyTypes.NICHandle: _str_converter,
}
[docs]
def convert_entity_key(k_type: EntityKeyTypes, val: Any) -> Any:
"""Convert value to entity key type.
Args:
k_type: Type of entity key.
val: Value to convert. Usually string,
but value of desired type is accepted too.
Return:
Valid value of entity key, return type depends on entity key type.
"""
converter = _entity_key_converters.get(k_type)
if not converter:
raise ValueError("no converter for key type: %s", k_type)
try:
result = converter(val)
except ValueError:
raise ValueError(f'"{val}" is not convertible to {k_type} value')
return result
_attr_value_converters: Dict[AttributeNames, Callable[[str], Any]] = {
AttributeNames.Size: _int_converter,
AttributeNames.DisplayNames: _str_converter,
AttributeNames.Names: _str_converter,
AttributeNames.IsIoC: _bool_converter,
AttributeNames.IsTrusted: _bool_converter,
AttributeNames.IsDGA: _bool_converter,
AttributeNames.Class: _new_enum_value_converter(IdentityClass, ignore_case=True),
AttributeNames.NodeRoles: _new_enum_value_converter(NodeRole, ignore_case=True),
AttributeNames.Sectors: _dict_item_value_converter,
AttributeNames.MalwareClasses: _dict_item_value_converter,
AttributeNames.MalwareFamilies: _dict_item_value_converter,
AttributeNames.RelatedMalwareFamilies: _dict_item_value_converter,
AttributeNames.IsDelegated: _bool_converter,
AttributeNames.Statuses: _dict_item_value_converter,
AttributeNames.ASN: _int_converter,
AttributeNames.RelatedThreatCategory: _new_enum_value_converter(
RelatedThreatCategory, ignore_case=True
),
AttributeNames.ThreatCategory: _new_enum_value_converter(
ThreatCategory, ignore_case=True
),
AttributeNames.MalwareNames: _str_converter,
AttributeNames.RegionalInternetRegistry: _new_enum_value_converter(
RegionalInternetRegistry, ignore_case=True
),
AttributeNames.Campaigns: _dict_item_value_converter,
AttributeNames.ThreatActors: _dict_item_value_converter,
AttributeNames.AffectedCountries: _dict_item_value_converter,
AttributeNames.ExploitedVulnerabilities: _dict_item_value_converter,
AttributeNames.TargetedSectors: _dict_item_value_converter,
AttributeNames.RegistrationCountry: _dict_item_value_converter,
AttributeNames.PotentialDamage: _new_enum_value_converter(
PotentialDamage, ignore_case=True
),
AttributeNames.Platforms: _dict_item_value_converter,
AttributeNames.Tactics: _dict_item_value_converter,
AttributeNames.Techniques: _dict_item_value_converter,
AttributeNames.Labels: _dict_item_value_converter,
}
[docs]
def convert_attribute_value(attribute_name: AttributeNames, val: Any) -> Any:
"""Convert value to attribute value type.
Args:
attribute_name: attribute name.
val: value to convert.
Usually string, but value of desired type is accepted too.
Return:
Valid value of attribute, return type depends on attribute.
"""
converter = _attr_value_converters.get(attribute_name)
if not converter:
raise ValueError("no converter for attribute: %s", attribute_name)
try:
result = converter(val)
except ValueError:
raise ValueError(
f'"{val}" is not convertible to {attribute_name} value'
) from None
return result