Source code for rdfframework.processors.rdfprocessors

import os
import hashlib
import datetime
import re
from base64 import b64encode
from dateutil.parser import parse as parse_date
from passlib.hash import sha256_crypt
from rdfframework.utilities import is_not_null, make_set, make_list, pyuri,\
        slugify, clean_iri, iri, cbool, remove_null, pp, ttluri, get_attr
from rdfframework import get_framework
from .imageprocessor import image_processor

__author__ = "Mike Stabile, Jeremy Nelson"
DEBUG = False
[docs]def run_processor(processor, obj, prop=None, mode="save"): '''runs the passed in processor and returns the saveData''' if isinstance(processor, dict): processor_type = processor.get('rdf_type') else: processor_type = processor processor_type = processor_type.replace(\ "http://knowledgelinks.io/ns/data-resources/", "kdr_") if processor_type == "kdr_SaltProcessor": return salt_processor(processor, obj, prop, mode) elif processor_type == "kdr_PasswordProcessor": return password_processor(processor, obj, prop, mode) elif processor_type == "kdr_CalculationProcessor": return calculation_processor(processor, obj, prop, mode) elif processor_type == "kdr_CSVstringToMultiPropertyProcessor": return csv_to_multi_prop_processor(processor, obj, prop, mode) elif processor_type == "kdr_AssertionImageBakingProcessor": return assert_img_baking_processor(processor, obj, prop, mode) elif processor_type == "kdr_EmailVerificationProcessor": return email_verification_processor(processor, obj, prop, mode) elif processor_type == "kdr_ImageProcessor": return image_processor(processor, obj, prop, mode) elif processor_type == "kdr_MultiPropertyToArray": return prop_to_array_processor(processor, obj, prop, mode) else: if mode == "load": return prop.query_data elif mode == "save": return obj return obj
[docs]def assert_img_baking_processor(processor, obj, prop, mode="save"): ''' Application sends badge image to the a badge baking service with the assertion.''' if mode == "save": obj['prop']['calcValue'] = True obj['processedData'][obj['propUri']] = "obi_testing_image_uri" elif mode == "load": return obj return obj
[docs]def csv_to_multi_prop_processor(processor, obj, prop=None, mode="save"): ''' Application takes a CSV string and adds each value as a separate triple to the class instance.''' if mode == "save": _value_string = obj['prop']['new'] if is_not_null(_value_string): vals = list(make_set(make_list(_value_string.split(', ')))) obj['processedData'][obj['propUri']] = vals obj['prop']['calcValue'] = True return obj elif mode == "load": prop_val = calculate_value("<<%s|%s>>" % \ (prop.kds_propUri, prop.kds_classUri), obj, prop) if prop_val is not None: prop.processed_data = ", ".join(make_list(prop_val)) return ", ".join(make_list(prop_val)) else: return "" return obj
[docs]def email_verification_processor(processor, obj, prop, mode="save"): ''' Application application initiates a proccess to verify the email address is a valid working address.''' if mode == "load": return obj return obj
[docs]def password_processor(processor, obj, prop, mode="save"): """Function handles application password actions Returns: modified passed in obj """ if DEBUG: debug = True else: debug = False if debug: print("START password_processor --------------------------\n") salt_url = "kdr_SaltProcessor" if mode == "save": # find the salt property _class_uri = obj['prop'].get("classUri") _class_properties = getattr(get_framework(), _class_uri).kds_properties salt_property = None # find the property Uri that stores the salt value for _class_prop in _class_properties.values(): _processors = clean_processors([make_list(\ _class_prop.get("kds_propertyProcessing",{}))]) for _processor in _processors.values(): if _processor.get("rdf_type") == salt_url: salt_property = _class_prop.get("kds_propUri") salt_processor_dict = _processor # if in save mode create a hashed password if mode == "save": # if the there is not a new password in the data return the obj if is_not_null(obj['prop']['new']) or obj['prop']['new'] != 'None': # if a salt has not been created call the salt processor if not obj['processedData'].get(salt_property): obj = salt_processor(salt_processor_dict, obj, mode, salt_property=salt_property) # create the hash salt = obj['processedData'].get(salt_property) _hash_value = sha256_crypt.encrypt(obj['prop']['new']+salt) # assign the hashed password to the processedData obj['processedData'][obj['propUri']] = _hash_value obj['prop']['calcValue'] = True if debug: print("END password_processor mode = save-------\n") return obj elif mode == "verify": # verify the supplied password matches the saved password if not len(obj.query_data) > 0: setattr(prop, "password_verified", False) return obj _class_uri = prop.kds_classUri _class_properties = getattr(get_framework(), _class_uri).kds_properties salt_property = None # find the property Uri that stores the salt value for _class_prop in _class_properties.values(): _processors = clean_processors([make_list(\ _class_prop.get("kds_propertyProcessing",{}))]) for _processor in _processors.values(): if _processor.get("rdf_type") == salt_url: salt_property = _class_prop.get("kds_propUri") salt_processor_dict = _processor # find the salt value in the query_data salt_value = None for subject, props in obj.query_data.items(): if clean_iri(props.get("rdf_type")) == _class_uri: salt_value = props.get(salt_property) hashed_password = props.get(prop.kds_propUri) break if debug: print(salt_value, " - ", hashed_password, " - ", prop.data) setattr(prop, "password_verified", \ sha256_crypt.verify(prop.data + salt_value, hashed_password)) if debug: print("END password_processor mode = verify -------\n") return obj if mode == "load": if debug: print("END password_processor mode = load -------\n") return obj return obj
[docs]def salt_processor(processor, obj, prop, mode="save", **kwargs): '''Generates a random string for salting''' if mode == "load": return obj.get("dataValue") length = 32 obj['prop']['calcValue'] = True # if called from the password processor the kwargs will have a # salt_property and we can automatically generate a new one if kwargs.get('salt_property'): obj['processedData'][kwargs['salt_property']] = \ b64encode(os.urandom(length)).decode('utf-8') return obj # if the salt already exists in the processed data return the obj # the processor may have been called by the password processor if is_not_null(obj['processedData'].get(obj['propUri'])): return obj # find the password property _class_uri = obj['prop'].get("classUri") _class_properties = getattr(get_framework(), _class_uri).kds_properties password_property = None for _class_prop in _class_properties.values(): if _class_prop.get("kds_propertyProcessing",{}).get("rdf_type") \ == "kds_PasswordProcessor": password_property = obj['preSaveData'].get(\ _class_prop.get("kds_propUri")) # check if there is a new password in the preSaveData # or # if the salt property is required and the old salt is empty if password_property is not None: if is_not_null(password_property.get('new')) or \ (obj['prop'].get('required') and \ not is_not_null(obj['prop']['old'])): obj['processedData'][obj['propUri']] = \ b64encode(os.urandom(length)).decode('utf-8') elif not is_not_null(obj['prop']['old']): obj['processedData'][obj['propUri']] = \ b64encode(os.urandom(length)).decode('utf-8') obj['prop']['calcValue'] = True return obj
[docs]def calculation_processor(processor, obj, prop, mode="save", return_type="prop"): ''' Application should proccess the property according to the rules listed in the kds:calulation property.''' if DEBUG: debug = True else: debug = False if debug: print("START calculation_processor ------------------------\n") if mode == "save": calculation = processor.get('kds_calculation') if calculation: if calculation.startswith("slugify"): _prop_uri = calculation[calculation.find("(")+1:\ calculation.find(")")] _prop_uri = pyuri(_prop_uri) _value_to_slug = obj['processedData'].get(_prop_uri, \ obj['preSaveData'].get(_prop_uri, {}\ ).get('new', None)) if is_not_null(_value_to_slug): obj['processedData'][obj['propUri']] = \ slugify(_value_to_slug) obj['prop']['calcValue'] = True else: pass elif mode == "load": if debug: print("prop.kds_propUri: ", prop.kds_propUri) _calc_type = processor.get('kds_calculationType') if debug: print("prop.kds_propUri: ", prop.kds_propUri, " calc_type: ", _calc_type) if _calc_type == "kdr_Concat": return_val = calculator_concat(processor, obj, prop, mode, return_type) elif _calc_type == "kdr_ObjectGenerator": return_val = calculator_object_generator(processor, obj, prop, mode, return_type) elif _calc_type == "kdr_DateConvertor": return_val = calculator_date_convertor(processor, obj, prop, mode, return_type) elif _calc_type == "kdr_UriTruncation": return_val = calculator_uir_truncation(processor, obj, prop, mode, return_type) if return_type == "value": return return_val if debug: print("END calculation_processor --------------------------\n\n") return obj
[docs]def clean_processors(processor_list_of_list, _class_uri=None): ''' some of the processors are stored as objects and need to retrun them as a list of string names''' debug = False _return_obj = {} # cycle through the each list of list of processors for processor_list in processor_list_of_list: # cylce through each processor in the list if isinstance(processor_list, list): for processor in processor_list: processor_to_add = None if isinstance(processor, dict): # filter out processors that do not apply to the current # rdf_class if _class_uri: if processor.get("kds_appliesTo", _class_uri) == \ _class_uri: processor_to_add = processor else: processor_to_add = processor else: processor_to_add = {"rdf_type": processor} # add the processor to the return_obj if it does not aleady # exist. This will allow for precedence of the first instance # of the processor if processor_to_add: if not _return_obj.get(processor_to_add.get(\ "rdf_type")) and processor_to_add.get(\ "rdf_type") is not None : if debug: if "kdr_AssertionImageBakingProcessor" == \ processor_to_add.get("rdf_type"): x=y _return_obj[processor_to_add.get(\ "rdf_type")] = processor if len(_return_obj)>0: x=1 return _return_obj
[docs]def calculate_value(value, obj, prop): if DEBUG: debug = True else: debug = False if value.startswith("<<"): _lookup_value = value.replace("<<","").replace(">>","") if debug: print(value) if "|" in _lookup_value: value_array = _lookup_value.split("|") _lookup_value = pyuri(value_array[0]) _class_uri = iri(pyuri(value_array[1])) else: _lookup_value = pyuri(_lookup_value) _class_uri = iri(prop.kds_classUri) _query_data = obj.query_data for _subject, _data in _query_data.items(): if _class_uri in make_list(_data.get("rdf_type")): #if _class_uri == "<obi_Assertion>": x=y return cbool(_data.get(pyuri(_lookup_value)), False) elif value.startswith("!--"): return_val = value if value == "!--api_url": return_val = obj.api_url if value == "!--base_url": return_val = obj.base_url if value == "!--base_api_url": return_val = obj.base_api_url if value == "!--subjectUri": _query_data = obj.query_data _class_uri = iri(prop.kds_classUri) for _subject, _data in _query_data.items(): if _class_uri in make_list(_data.get("rdf_type")): return_val = _subject return return_val else: return cbool(value, False)
[docs]def calculator_concat(processor, obj, prop, mode="save", return_type="prop"): ''' Does a concatition based on the the provided args and kwargs ''' if DEBUG: debug = True else: debug = True if debug: print("START calculator_concat ---------------------\n") if debug: print(prop.kds_propUri) _seperator = processor.get("kds_calculationSeparator",",") _calc_string = processor.get("kds_calculation") _concat_list = make_list(_calc_string.split(_seperator)) prop_val = calculate_value("<<%s|%s>>" % \ (prop.kds_propUri, prop.kds_classUri), obj, prop) if prop_val is None: prop.processed_data = None return None if debug: print(get_attr(prop, "kds_apiFieldName", \ get_attr(prop, "kds_formFieldName")),": ", prop_val) for i, _item in enumerate(_concat_list): item_val = "" if "||" in _item: _sub_calc = _item.split("||") new_processor = {} for val in _sub_calc: val_parts = val.split("|") new_processor[pyuri(val_parts[0])] = pyuri(val_parts[1]) if len(new_processor) > 0: item_val = calculation_processor(new_processor, obj, prop, mode, return_type="value") else: item_val = calculate_value(_item, obj, prop) _concat_list[i] = item_val if return_type == "prop": prop.processed_data = "".join(remove_null(_concat_list)) #if prop.kds_apiFieldName == "image": #S prop.processed_data = "adfadsf" else: return "".join(remove_null(_concat_list))
[docs]def calculator_object_generator(processor, obj, prop, mode, return_type="prop"): ''' returns and object of calculated values ''' if DEBUG: debug = True else: debug = False object_list = make_list(processor.get("kds_calculationObject")) return_obj = {} counter = 0 for _object in object_list: key = calculate_value(_object.get("kds_objectKey"), obj, prop) if _object.get("kds_calculationType") == "kdr_ValueHasher": value = calculator_value_hasher(_object.get("kds_objectValue"), obj, prop) else: value = calculate_value(_object.get("kds_objectValue"), obj, prop) return_obj[key] = value counter += 1 if debug: print(counter, " ", key, "-", value, " | ", _object) if return_type == "prop": prop.processed_data = return_obj else: return return_obj
[docs]def calculator_value_hasher(value, obj, prop): ''' hashes a value and returns the hashed value ''' value_to_hash = calculate_value(value, obj, prop) if value_to_hash: salt_list = find_salt_prop(obj, prop) for salt_ref in salt_list: salt = calculate_value("<<%s|%s>>" % (salt_ref['kds_propUri'], salt_ref['kds_classUri']), obj, prop) if salt: salt_value = salt return 'sha256$' + hashlib.sha256(value_to_hash.encode('utf-8') + \ salt.encode('utf-8')).hexdigest()
[docs]def find_salt_prop(obj, prop): ''' finds the property that stores the salt ''' def _salt_class_search(class_uri): _class_properties = getattr(get_framework(), class_uri).kds_properties _salt_property = None _salt_url = "kdr_SaltProcessor" for _class_prop in _class_properties.values(): _processors = clean_processors([make_list(\ _class_prop.get("kds_propertyProcessing",{}))]) for _processor in _processors.values(): if _processor.get("rdf_type") == _salt_url: _salt_property = {"kds_classUri": class_uri, \ "kds_propUri": _class_prop.get("kds_propUri")} salt_processor_dict = _processor return _salt_property salt_list = [] for _class in obj.class_set: salt_uri = _salt_class_search(_class) if salt_uri: salt_list.append(salt_uri) return salt_list
[docs]def calculator_date_convertor(processor, obj, prop, mode, return_type="prop"): if DEBUG: debug = True else: debug = False if debug: print("START calculator_date_convertor ---------------------\n") if debug: print(prop.kds_propUri) # get the data value value = calculate_value("<<%s|%s>>" % (prop.kds_propUri, prop.kds_classUri), obj, prop) if debug: print(prop.kds_propUri, " - value: ", value) _date_type = processor.get("kds_calculation") return_val = None if value: if isinstance(value, str): value = parse_date(value) if isinstance(value, datetime.datetime): if _date_type == "Unix timestamp": return_val = value.timestamp() else: return_val = str(value) if debug: print("END calculator_date_convertor ----------------------\n\n") if return_type == "prop": prop.processed_data = return_val else: return return_val
[docs]def calculator_uir_truncation(processor, obj, prop, mode, return_type="prop"): if DEBUG: debug = True else: debug = False if debug: print("START calculator_uir_truncation ---------------------\n") if debug: print(prop.kds_propUri) # get the data value value = calculate_value(processor.get("kds_calculationField"), obj, prop) return_val = value if value: calculation = processor.get("kds_calculation") if calculation == "!--afterLastSlash": return_val = re.sub(r'^(.*[#/])','', value) if return_type == "prop": prop.processed_data = return_val else: return return_val if debug: print("END calculator_uir_truncation ----------------------\n\n")
[docs]def prop_to_array_processor(processor, obj, prop, mode): ''' This will take a property data and convert it to an array ''' if DEBUG: debug = True else: debug = True if debug: print("START prop_to_array_processor - rdfprocessors.py-----\n") if debug: print(prop.kds_propUri) return_val = obj # get the data value value = calculate_value("<<%s|%s>>" % (prop.kds_propUri, prop.kds_classUri), obj, prop) if mode == "save": return_val = obj elif mode == "load": if value is not None: prop.processed_data = make_list(value) return_val = make_list(value) else: prop.processed_data = [] return_val = [] if debug: print("return_val: ", return_val) if debug: print("\nEND prop_to_array_processor - rdfprocessors.py-----\n") return return_val