@@ -1269,7 +1269,7 @@ def get_table(db, klass):
12691269 for e in TM ._threats + TM ._data + TM ._elements + self .findings + [self ]:
12701270 table = get_table (db , e .__class__ )
12711271 row = {}
1272- for k , v in serialize (e ).items ():
1272+ for k , v in to_serializable (e ).items ():
12731273 if k == "id" :
12741274 k = "SID"
12751275 row [k ] = ", " .join (str (i ) for i in v ) if isinstance (v , list ) else v
@@ -1278,7 +1278,6 @@ def get_table(db, klass):
12781278 db .close ()
12791279
12801280
1281-
12821281class Controls :
12831282 """Controls implemented by/on and Element"""
12841283
@@ -2003,54 +2002,99 @@ def to_serializable(val):
20032002
20042003
20052004@to_serializable .register (TM )
2006- def ts_tm (obj ):
2007- return serialize (obj , nested = True )
2005+ def _ (obj ):
2006+ ignore = ("_sf" , "_duplicate_ignored_attrs" , "_threats" , "_elements" )
2007+ result = {}
2008+ for attr_name in dir (obj ):
2009+ if (
2010+ attr_name .startswith ("__" )
2011+ or callable (getattr (obj .__class__ , attr_name , {}))
2012+ or attr_name in ignore
2013+ ):
2014+ # ignore all functions and __atrributes and ignore attributes
2015+ continue
2016+ value = getattr (obj , attr_name )
2017+ if isinstance (value , (Element , Data )):
2018+ value = value .name
2019+ result [attr_name .lstrip ("_" )] = value
2020+ result ["elements" ] = [e for e in obj ._elements if isinstance (e , (Actor , Asset ))]
2021+ return result
20082022
20092023
20102024@to_serializable .register (Controls )
20112025@to_serializable .register (Data )
2026+ @to_serializable .register (Finding )
2027+ def _ (obj ):
2028+ return serialize (obj )
2029+
2030+
20122031@to_serializable .register (Threat )
2013- @to_serializable .register (Element )
2032+ def _ (obj ):
2033+ return serialize (obj , replace = {"target" : [v .__name__ for v in obj .target ]})
2034+
2035+
20142036@to_serializable .register (Finding )
2037+ def _ (obj ):
2038+ return serialize (obj , ignore = ["element" ])
2039+
2040+
2041+ @to_serializable .register (Element )
20152042def ts_element (obj ):
2016- return serialize (obj , nested = False )
2043+ return serialize (obj ,
2044+ ignore = ("_is_drawn" , "uuid" ),
2045+ replace = {
2046+ "levels" : list (obj .levels ),
2047+ "sourceFiles" : list (obj .sourceFiles ),
2048+ "findings" : [v .id for v in obj .findings ],
2049+ })
2050+
2051+
2052+ @to_serializable .register (Actor )
2053+ @to_serializable .register (Asset )
2054+ def _ (obj ):
2055+ # Note that we use the ts_element function defined for the Element class
2056+ result = ts_element (obj )
2057+ result ["__class__" ] = obj .__class__ .__name__
2058+ return result
2059+
2060+
2061+ def serialize (obj , ignore = None , replace = None ):
2062+ """
2063+ Serialize an object into a dictionary.
20172064
2065+ Keyword arguments:
2066+ ignore -- a collection of attribute names, which are not included in the serialized dictionary
2067+ replace -- dictionary keyed with attribute names which should be replaced by the diven value.
2068+ """
2069+ if ignore is None :
2070+ ignore = []
2071+ if replace is None :
2072+ replace = {}
20182073
2019- def serialize (obj , nested = False ):
2020- """Used if *obj* is an instance of TM, Element, Threat or Finding."""
2021- klass = obj .__class__
20222074 result = {}
2023- if isinstance (obj , (Actor , Asset )):
2024- result ["__class__" ] = klass .__name__
2025- for i in dir (obj ):
2075+ for attr_name in dir (obj ):
20262076 if (
2027- i .startswith ("__" )
2028- or callable (getattr (klass , i , {}))
2029- or (
2030- isinstance (obj , TM )
2031- and i in ("_sf" , "_duplicate_ignored_attrs" , "_threats" )
2032- )
2033- or (isinstance (obj , Element ) and i in ("_is_drawn" , "uuid" ))
2034- or (isinstance (obj , Finding ) and i == "element" )
2077+ attr_name .startswith ("__" )
2078+ or callable (getattr (obj .__class__ , attr_name , {}))
2079+ or attr_name in ignore
20352080 ):
2081+ # ignore all functions and __atrributes and ignore attributes
20362082 continue
2037- value = getattr (obj , i )
2038- if isinstance (obj , TM ) and i == "_elements" :
2039- value = [e for e in value if isinstance (e , (Actor , Asset ))]
2083+ try :
2084+ result [attr_name ] = replace [attr_name ]
2085+ continue
2086+ except KeyError :
2087+ pass
2088+ value = getattr (obj , attr_name )
20402089 if value is not None :
20412090 if isinstance (value , (Element , Data )):
20422091 value = value .name
2043- elif isinstance (obj , Threat ) and i == "target" :
2044- value = [v .__name__ for v in value ]
2045- elif i in ("levels" , "sourceFiles" , "assumptions" ):
2046- value = list (value )
20472092 elif (
2048- not nested
2049- and not isinstance (value , str )
2093+ not isinstance (value , str )
20502094 and isinstance (value , Iterable )
20512095 ):
2052- value = [v .id if isinstance ( v , Finding ) else v . name for v in value ]
2053- result [i .lstrip ("_" )] = value
2096+ value = [v .name for v in value ]
2097+ result [attr_name .lstrip ("_" )] = value
20542098 return result
20552099
20562100
0 commit comments