def get_general_property(self, element, prop_key, prop_value): """Answers the query property(element, prop_key, prop_value). element, prop_key and prop_value are all prolog data types. If the property is not defined, it gets recorded in the list of requested but undefined properties, but only if prop_key is not a variable. """ prop_key_value = get_value(prop_key) if isinstance(prop_key_value, Atom): # property key is a constant value, which means it is # specifically requested. v_prop_value = self.query_engine.variable() q = list( self.query_engine.query( 'prop', [element, prop_key_value, v_prop_value])) if q == []: # property is not defined self.add_undefined_property(to_python(element), to_python(prop_key_value)) else: self.validate_defined_property(element, prop_key_value) for l2 in self.query_engine.query('prop', [element, prop_key, prop_value]): yield False
def get_property_help(elt, prop): a_element = a.query_engine.atom(elt) a_property = a.query_engine.atom(prop) v_value = a.query_engine.variable() v_text = a.query_engine.variable() q = a.query_engine.query('prop_text', [a_element, a_property, v_value, v_text]) return [ (to_python(v_value), to_python(v_text)) for r in q ]
def test_functor_arities(): s = compile_prolog_from_string( ''' likes(A,B) :- person(A), person(B), friend(A,B). likes(A,B,C) :- person(A),person(B), person(C), friend(A,B), friend(A,C). likes(A,B) :- person(A), person(B), person(C), foe(A,C), foe(B,C). person(mike). person(joe). person(pete). person(zack). friend(mike,pete). friend(mike,joe). foe(joe,zack). foe(pete,zack). ''', TestContext) yp = YP() yp.load_script_from_string(s, overwrite=False) X = yp.variable() Y = yp.variable() q = yp.query('likes', [X, Y]) r = [(to_python(X.get_value()), to_python(Y.get_value())) for x in q] assert set(r) == set([ ('mike', 'pete'), ('mike', 'joe'), ('joe', 'pete'), ('joe', 'joe'), ('pete', 'pete'), ('pete', 'joe'), ])
def test_model_types_defined(): a = FTOThreatAnalyzer() a.set_model(dfd_with_flows) name = a.variable() tmtype = a.variable() q = a.query('type', [name, tmtype]) r = [[to_python(name), to_python(tmtype)] for _ in q] assert r == [[t.name, t] for t in dfd_with_flows.types.values()]
def optional_attr(self, element, key, value, default): # key and default need to be instantiated elt = to_python(element) self._debug("DEBUG: element", repr(elt)) v = elt.get(to_python(key), to_python(default)) for y in unify(value, self.query_engine.atom(v)): self._debug("DEBUG: optional_attr: %s=%s" % (to_python(key), v)) yield False
def test_model_subtypes_defined(): a = FTOThreatAnalyzer() a.set_model(dfd_with_flows) tmtype = a.variable() parent_type = a.variable() q = a.query('subtype', [tmtype, parent_type]) r = [[to_python(tmtype), to_python(parent_type)] for _ in q] tmtype = dfd_with_flows.get_flows()[0].types[0] assert r == [[tmtype, t] for t in tmtype.types]
def validate_property_value(self, element, prop_key, prop_value): c_valid = self.query_engine.atom('prop_valid') l = list( self.query_engine.query('prop_valid', [element, prop_key, prop_value])) if l == []: self.invalid_properties.add( (to_python(element), to_python(prop_key), to_python(prop_value)))
def test_model_query_flow_clause(): a = FTOThreatAnalyzer() a.set_model(dfd_with_flows) v_from = a.variable() v_to = a.variable() v_elt = a.variable() q = a.query('flow', [v_elt, v_from, v_to]) r = [[to_python(v_elt), to_python(v_from), to_python(v_to)] for _ in q] flows = dfd_with_flows.get_flows() assert r == [[flows[0], flows[0].source, flows[0].target]]
def test_model_query_element_type(): a = FTOThreatAnalyzer() a.set_model(dfd_with_flows) zone = dfd_with_flows.get_zones()[0] components = dfd_with_flows.get_zone_components(zone) elt = a.atom(components[0]) value = a.variable() q = a.query('element', [elt, value]) r = [[to_python(elt), to_python(value) ] for _ in q] assert r == [[components[0], components[0].types[0]]]
def get_xpath_value(self, query, variable): try: self._debug("DEBUG: query: %s" % (to_python(query))) r = self.xml_tree.xpath(to_python(query)) for y in r: self._debug("DEBUG: %s = %s" % (to_python(query), repr(y))) for _ in unify(variable, self.query_engine.atom(y)): yield False except lxml.etree.XPathEvalError as e: print("ERROR (xpath):", e, to_python(query))
def test_model_query_element_type_inherited(): a = FTOThreatAnalyzer() a.set_model(dfd_with_flows) zone = dfd_with_flows.get_zones()[0] flows = dfd_with_flows.get_flows() elt = a.atom(flows[0]) value = a.variable() q = a.query('element', [elt, value]) r = [[to_python(elt), to_python(value)] for _ in q] assert r == [[flows[0], flows[0].types[0]]]
def test_model_query_component_zone(): a = FTOThreatAnalyzer() a.set_model(dfd_with_flows) elt = a.variable() value = a.variable() const_zone = a.atom('zone') q = a.query('property', [elt, const_zone, value]) r = [[to_python(elt), to_python(value)] for _ in q] zone = dfd_with_flows.get_zones()[0] components = dfd_with_flows.get_zone_components(zone) assert r == [[components[0], zone], [components[1], zone]]
def test_model_query_zone_zone(): a = FTOThreatAnalyzer() a.set_model(dfd_nested_zones) elt = a.variable() value = a.variable() const_zone = a.atom('zone') q = a.query('property', [elt, const_zone, value]) r = [[to_python(elt), to_python(value)] for _ in q] office_zone = dfd_nested_zones.zones['office'] company_zone = dfd_nested_zones.zones['company'] components = dfd_nested_zones.get_zone_components(office_zone) assert r == [[office_zone, company_zone], [components[0], office_zone]]
def test_model_query_undefined_property(): a = FTOThreatAnalyzer() a.set_model(dfd_with_flows) flows = dfd_with_flows.get_flows() # elt = a.variable() elt = a.atom(flows[0]) value = a.variable() const_key = a.atom('define_me') q = a.query('property', [elt, const_key, value]) r = [[to_python(elt), to_python(value)] for _ in q] assert r == [] assert len(a.undefined_properties) == 1 assert len(a.invalid_properties) == 0
def attr(self, element, key, value): elt = to_python(element) self._debug("DEBUG: element", repr(elt)) for k, v in elt.items(): for x in unify(key, self.query_engine.atom(k)): for y in unify(value, self.query_engine.atom(v)): self._debug("DEBUG: attr: %s=%s" % (k, v)) yield False
def get_xpath_value(xml_tree, query, variable): '''xpath(Tree, Query, Variable). runs the xpath query Query against the XML tree Tree, and stores its result in Variable.''' # check if tree and query are bound to a value tree_a = get_value(xml_tree) if not isinstance(tree_a, Atom): return query_a = get_value(query) if not isinstance(query, Atom): return # do the XPath query root = to_python(tree_a).getroot() q = to_python(query_a) for v in root.findall(q): for r in unify(variable, Atom(v)): yield False
def test_model_query_dataflow_has_property(): a = FTOThreatAnalyzer() a.set_model(dfd_with_flows) add_threat_library_from_source(a, ''' prop_valid(X,https,yes). prop_valid(X,https,no). ''') elt = a.variable() value = a.variable() const_key = a.atom('https') q = a.query('property', [elt, const_key, value]) r = [[to_python(elt), to_python(value)] for _ in q] flows = dfd_with_flows.get_flows() assert r == [[flows[0], 'yes']] assert len(a.invalid_properties) == 0
def test_analyzer_loads_script(): a = FTOThreatAnalyzer() a.set_model(dfd_with_flows) tl = ThreatLibrary.from_string('animal(monkey).') a.add_prolog_rules_from_threat_library(tl) v = a.variable() q = a.query('animal', [v]) r = [to_python(v) for _ in q] assert r[0] == 'monkey'
def test_model_query_invalid_dataflow_property(): a = FTOThreatAnalyzer() a.set_model(dfd_with_flows_and_invalid_property) tl = ThreatLibrary.from_string(''' prop_valid(X,https,yes). prop_valid(X,https,no). ''') a.add_prolog_rules_from_threat_library(tl) flows = dfd_with_flows_and_invalid_property.get_flows() elt = a.atom(flows[0]) value = a.variable() const_key = a.atom('https') q = a.query('property', [elt, const_key, value]) r = [[to_python(elt), to_python(value)] for _ in q] assert len(r) == 1 assert len(a.undefined_properties) == 0 assert len(a.invalid_properties) == 1
def load_xml_tree(xml_tree, filename): # first, filename must be bound to an Atom. fn_a = get_value(filename) if not isinstance(fn_a, Atom): # we could raise an exception, but we will just return and not # yield any results return with open(to_python(fn_a), 'r') as f: tree = dxml.parse(f) a = Atom(tree) for r in unify(xml_tree, a): yield False
def convert_specfile_to_prolog(infile, outf): model = parse_file(infile) a = ThreatAnalyzer() a.set_model(model) outf.write("%% DFD prolog code, generated from:\n") outf.write(f"%% {infile}\n\n") for predicate, answers in a.query_engine._predicates_store.items(): outf.write("%% %s/%d:\n" % predicate) for answer in answers: values = ",".join(obj_to_prolog(to_python(x)) for x in answer.values) outf.write("%s(%s).\n" % (predicate[0], values)) outf.write("\n")
def test_model_zone_valid_values(): a = FTOThreatAnalyzer() a.set_model(dfd_nested_zones) add_threat_library_from_source(a, ''' prop_valid(X,https,yes). prop_valid(X,https,no). ''') z = dfd_nested_zones.get_zones()[1] elt = dfd_nested_zones.get_zone_components(z)[0] elt = a.variable() value = a.variable() const_zone = a.atom('zone') q = a.query('prop_valid', [elt, const_zone, value]) r = [ to_python(value) for _ in q ] assert r == dfd_nested_zones.get_zones()
def ask(self, query): v = self.query_engine.variable() q = self.query_engine.query(query, [v]) return [to_python(v) for r in q]
def lowercase(self, val1, val2): self._debug("DEBUG: lowercase: %s=%s" % (val1, val2)) # val1 must be instantiated v = self.query_engine.atom(to_python(val1).lower()) for x in unify(val2, v): yield False
def version_at_least(self, version1, version2): # version1 and version2 must be instantiated v1 = to_python(version1).split('.') v2 = to_python(version2).split('.') if v2 >= v1: yield False
stores its result in Variable.''' # check if tree and query are bound to a value tree_a = get_value(xml_tree) if not isinstance(tree_a, Atom): return query_a = get_value(query) if not isinstance(query, Atom): return # do the XPath query root = to_python(tree_a).getroot() q = to_python(query_a) for v in root.findall(q): for r in unify(variable, Atom(v)): yield False qe = yldprolog.engine.YP() qe.register_function('xml_tree', load_xml_tree) qe.register_function('xpath', get_xpath_value) # Execute xml_tree(Tree, 'books.xml'). fn_a = qe.atom('books.xml') v = qe.variable() tree_a = [get_value(v) for r in qe.query('xml_tree', [v, fn_a])][0] # Execute xpath(Tree, 'book/author', V). q_a = qe.atom('book/author') authors = [to_python(v) for r in qe.query('xpath', [tree_a, q_a, v])] for a in authors: print(a.text)