def resetTriggers(): from core.models import trigger print(len(trigger._trigger().getAsClass())) # Clearing any triggers with a startCheck set - Very poor as it hammers the DB, be better to do this as one mass update command to the database # This wont scale to clustering as it will clear all running triggers even if they were running by another cluster node triggers = trigger._trigger().query(query={"startCheck": { "$gt": 0 }})["results"] for triggerJson in triggers: triggerClass = trigger._trigger().get(triggerJson["_id"]) triggerClass.startCheck = 0 triggerClass.update(["startCheck"])
def uninstall(self): # deregister models model.deregisterModel("occurrence", "_occurrence", "_action", "plugins.occurrence.models.action") model.deregisterModel("occurrence clean", "_occurrenceClean", "_action", "plugins.occurrence.models.action") model.deregisterModel("occurrenceUpdate", "_occurrenceUpdate", "_action", "plugins.occurrence.models.action") conduct._conduct().api_delete(query={"name": "occurrenceCore"}) trigger._trigger().api_delete(query={"name": "occurrenceCore"}) action._occurrenceClean().api_delete(query={"name": "occurrenceCore"}) return True
def conductPage(conductID): conductObj = conduct._conduct().query(api.g["sessionData"], id=conductID)["results"] conductObj = conductObj[0] existingFlow = webui._flowData().query( query={"conductID": conductID})["results"] if len(existingFlow) == 1: existingFlow = existingFlow[0] flowData = existingFlow["flowData"] else: flowData = buildFlowData(conductObj["flow"]) if "acl" not in conductObj: conductObj["acl"] = {} return render_template("flow.html", conductID=conductObj["_id"], conductName=conductObj["name"], conductACL=conductObj["acl"], conductEnabled=conductObj["enabled"], content=conductObj, actions=action._action().query()["results"], triggers=trigger._trigger().query()["results"], flowData=flowData, CSRF=api.g["sessionData"]["CSRF"])
def newFlow(conductID): conductObj = conduct._conduct().getAsClass(api.g["sessionData"], id=conductID) if len(conductObj) == 1: conductObj = conductObj[0] else: return {}, 404 access, accessIDs, adminBypass = db.ACLAccess(api.g["sessionData"], conductObj.acl, "write") if access: data = json.loads(api.request.data) # Get new UUID store within current conduct flow and return UUID newFlowID = str(uuid.uuid4()) flow = {"flowID": newFlowID, "next": []} # Creating new object of model type _class = model._model().getAsClass(api.g["sessionData"], id=data["classID"]) if _class: subtype = _class[0].name _class = _class[0].classObject() newFlowObjectID = _class().new(flow["flowID"]).inserted_id # Working out by bruteforce which type this is ( try and load it by parent class and check for error) - get on trigger if it does not exist will return None modelFlowObjectType = "action" if len(trigger._trigger().getAsClass(api.g["sessionData"], id=newFlowObjectID)) > 0: modelFlowObjectType = "trigger" modelFlowObject = _class().getAsClass(api.g["sessionData"], id=newFlowObjectID) if len(modelFlowObject) == 1: modelFlowObject = modelFlowObject[0] else: return {}, 404 modelFlowObject.acl = { "ids": [{ "accessID": api.g["sessionData"]["primaryGroup"], "read": True, "write": True, "delete": True }] } modelFlowObject.update(["acl"], sessionData=api.g["sessionData"]) flow["type"] = modelFlowObjectType if subtype != "action" and subtype != "trigger": flow["subtype"] = subtype flow["{0}{1}".format(modelFlowObjectType, "ID")] = str(newFlowObjectID) # Adding UI position for cloned object webui._modelUI().new(conductID, conductObj.acl, flow["flowID"], data["x"], data["y"], modelFlowObject.name) # Appending new object to conduct conductObj.flow.append(flow) conductObj.update(["flow"], sessionData=api.g["sessionData"]) return {}, 201 else: return {}, 403 return {}, 404
def install(self): # Register models model.registerModel("choice","_choice","_document","plugins.choice.models.choice",True) model.registerModel("choiceRequest","_requestChoice","_action","plugins.choice.models.action") model.registerModel("choiceTrigger","_choiceTrigger","_action","plugins.choice.models.action",True) c = conduct._conduct().new("choiceCore") c = conduct._conduct().getAsClass(id=c.inserted_id)[0] t = trigger._trigger().new("choiceCore") t = trigger._trigger().getAsClass(id=t.inserted_id)[0] a = action._choiceTrigger().new("choiceCore") a = action._choiceTrigger().getAsClass(id=a.inserted_id)[0] c.triggers = [t._id] flowTriggerID = str(uuid.uuid4()) flowActionID = str(uuid.uuid4()) c.flow = [ { "flowID" : flowTriggerID, "type" : "trigger", "triggerID" : t._id, "next" : [ {"flowID": flowActionID, "logic": True } ] }, { "flowID" : flowActionID, "type" : "action", "actionID" : a._id, "next" : [] } ] webui._modelUI().new(c._id,{ "ids":[ { "accessID":"0","delete": True,"read": True,"write": True } ] },flowTriggerID,0,0,"") webui._modelUI().new(c._id,{ "ids":[ { "accessID":"0","delete": True,"read": True,"write": True } ] },flowActionID,100,0,"") c.acl = { "ids":[ { "accessID":"0","delete": True,"read": True,"write": True } ] } c.enabled = True c.update(["triggers","flow","enabled","acl"]) t.acl = { "ids":[ { "accessID":"0","delete": True,"read": True,"write": True } ] } t.schedule = "60-90s" t.enabled = True t.update(["schedule","enabled","acl"]) a.acl = { "ids":[ { "accessID":"0","delete": True,"read": True,"write": True } ] } a.enabled = True a.update(["enabled","acl"]) return True
def getConductFlowProperties(conductID, flowID): conductObj = conduct._conduct().query(api.g["sessionData"], id=conductID)["results"] if len(conductObj) == 1: conductObj = conductObj[0] else: return {}, 404 flow = [x for x in conductObj["flow"] if x["flowID"] == flowID] if len(flow) == 1: flow = flow[0] formData = None if "type" in flow: if flow["type"] == "trigger": triggerObj = trigger._trigger().query( api.g["sessionData"], id=flow["triggerID"])["results"] if len(triggerObj) == 1: triggerObj = triggerObj[0] else: return {}, 404 _class = model._model().getAsClass(api.g["sessionData"], id=triggerObj["classID"]) if len(_class) == 1: _class = _class[0].classObject() else: return {}, 404 triggerObj = _class().getAsClass(api.g["sessionData"], id=triggerObj["_id"]) if len(triggerObj) == 1: triggerObj = triggerObj[0] else: return {}, 404 if "_properties" in dir(triggerObj): formData = triggerObj._properties().generate(triggerObj) else: formData = webui._properties().generate(triggerObj) elif flow["type"] == "action": actionObj = action._action().query( api.g["sessionData"], id=flow["actionID"])["results"] if len(actionObj) == 1: actionObj = actionObj[0] else: return {}, 404 _class = model._model().getAsClass(api.g["sessionData"], id=actionObj["classID"]) if len(_class) == 1: _class = _class[0].classObject() actionObj = _class().getAsClass(api.g["sessionData"], id=actionObj["_id"]) if len(actionObj) == 1: actionObj = actionObj[0] else: return {}, 404 if "_properties" in dir(actionObj): formData = actionObj._properties().generate(actionObj) else: formData = webui._properties().generate(actionObj) return {"formData": formData}, 200
def failedTrigger(workerID, failureType, msg=""): triggers = trigger._trigger().query( query={"name": "failedTriggers"})["results"] if len(triggers) > 0: triggerWorkers = trigger._trigger().query( query={"workerID": workerID})["results"] if len(triggerWorkers) > 0: trigger_ = triggers[0] worker_ = triggerWorkers[0] _class = model._model().getAsClass(id=trigger_["classID"]) if len(_class) == 1: _class = _class[0].classObject() if _class: triggerClass = _class().getAsClass(id=trigger_["_id"]) if len(triggerClass) == 1: triggerClass = triggerClass[0] if triggerClass: events = [{ "type": "systemEvent", "eventType": failureType, "workerID": workerID, "triggerID": worker_["_id"], "triggerName": worker_["name"], "msg": msg }] audit._audit().add( "Error", failureType, { "type": "systemEvent", "eventType": failureType, "workerID": workerID, "triggerID": worker_["_id"], "triggerName": worker_["name"], "msg": msg }) # Notify conducts that have a trigger failure trigger within flow workers.workers.new("trigger:{0}".format(trigger_["_id"]), triggerClass.notify, (events, ))
def run(self, data, persistentData, actionResult): try: if "event" in data: if "triggerID" in data["event"]: failedTrigger = trigger._trigger().getAsClass( id=data["event"]["triggerID"]) if len(failedTrigger) == 1: failedTrigger = failedTrigger[0] failedTrigger.startCheck = 0 failedTrigger.update(["startCheck"]) actionResult["result"] = True actionResult["rc"] = 0 return actionResult except: pass actionResult["result"] = False actionResult["rc"] = 42 return actionResult
def forceTriggers(triggerID): data = json.loads(api.request.data) if data["action"] == "trigger": class_ = trigger._trigger().getAsClass(id=triggerID)[0] if class_: if class_.startCheck == 0: class_.startCheck = time.time() maxDuration = 60 if type(class_.maxDuration ) is int and class_.maxDuration > 0: maxDuration = class_.maxDuration try: events = json.loads(data["events"]) except json.decoder.JSONDecodeError: events = [data["events"]] # Ensure we run even if no event data was sent if events == [""]: events = ["1"] if type(events) != list: events = [events] class_.workerID = workers.workers.new( "trigger:{0}".format(triggerID), class_.notify, (events, ), maxDuration=maxDuration) class_.update(["startCheck", "workerID"]) else: logging.debug( "Error unable to force trigger, triggerID={0} as it is already running." .format(triggerID)) return { "result": False, "reason": "Trigger already running" }, 403 else: logging.debug( "Error unable to force trigger, triggerID={0} as its triggerID cannot be loaded." .format(triggerID)) return { "result": False, "reason": "triggerID could not be loaded" }, 404 return {"result": True}, 200
def statusPage(): triggers = trigger._trigger().query( fields=["_id", "name", "lastCheck", "lastResult"])["results"] actions = action._action().query( fields=["_id", "name", "lastRun", "lastResult"])["results"] # Bad programming dont just copy and past the same thing make it dynamic!!!!!!!!!! triggersContent = [] for t in triggers: if "lastCheck" in t: t["lastCheck"] = time.strftime('%d/%m/%Y %H:%M:%S', time.gmtime(t["lastCheck"])) triggersContent.append(t) actionsContent = [] for a in actions: if "lastRun" in a: a["lastRun"] = time.strftime('%d/%m/%Y %H:%M:%S', time.gmtime(a["lastRun"])) actionsContent.append(a) return render_template("status.html", triggers=triggersContent, actions=actionsContent)
def dropExistingObject(conductID): conductObj = conduct._conduct().getAsClass(api.g["sessionData"], id=conductID) if len(conductObj) == 1: conductObj = conductObj[0] else: return {}, 404 access, accessIDs, adminBypass = db.ACLAccess(api.g["sessionData"], conductObj.acl, "write") if access: data = json.loads(api.request.data) if data["action"] == "drop": newFlowID = str(uuid.uuid4()) flow = { "flowID": newFlowID, "type": data["flowType"], "{0}{1}".format(data["flowType"], "ID"): data["_id"], "next": [] } modelFlowObject = None if data["flowType"] == "trigger": modelFlowObject = trigger._trigger().getAsClass( api.g["sessionData"], id=data["_id"])[0] elif data["flowType"] == "action": modelFlowObject = action._action().getAsClass( api.g["sessionData"], id=data["_id"])[0] if modelFlowObject: name = modelFlowObject.name else: name = flow["flowID"] webui._modelUI().new(conductID, conductObj.acl, flow["flowID"], data["x"], data["y"], name) conductObj.flow.append(flow) conductObj.update(["flow"], sessionData=api.g["sessionData"]) return {}, 201 return {}, 404
def getTrigger(triggerID, sessionData): return trigger._trigger().getAsClass(id=triggerID)
def saveConduct(conductID): data = json.loads(api.request.data) conductObj = conduct._conduct().getAsClass(api.g["sessionData"], id=conductID) if len(conductObj) == 1: conductObj = conductObj[0] else: return {}, 404 if data["action"] == "new": access, accessIDs, adminBypass = db.ACLAccess(api.g["sessionData"], conductObj.acl, "write") if access: # Get new UUID store within current conduct flow and return UUID newFlowID = str(uuid.uuid4()) flow = {"flowID": newFlowID, "next": []} conductObj.flow.append(flow) conductObj.update(["flow"], sessionData=api.g["sessionData"]) return {"result": True, "flowID": newFlowID}, 201 else: return {}, 403 # Clone an existing object into a new object if data["action"] == "clone": access, accessIDs, adminBypass = db.ACLAccess(api.g["sessionData"], conductObj.acl, "write") if access: flow = [ x for x in conductObj.flow if x["flowID"] == data["operatorId"] ] if len(flow) == 1: flow = flow[0] data = json.loads(api.request.data) modelFlowObject = None # Check if the modelType and object are unchanged if "type" in flow: if flow["type"] == "trigger": modelFlowObject = trigger._trigger().getAsClass( api.g["sessionData"], id=flow["{0}{1}".format(flow["type"], "ID")]) if len(modelFlowObject) == 1: modelFlowObject = modelFlowObject[0] modelFlowObjectType = "trigger" if flow["type"] == "action": modelFlowObject = action._action().getAsClass( api.g["sessionData"], id=flow["{0}{1}".format(flow["type"], "ID")]) if len(modelFlowObject) == 1: modelFlowObject = modelFlowObject[0] modelFlowObjectType = "action" # Was it possible to load an existing object if modelFlowObject: # Create new flowItem newFlowID = str(uuid.uuid4()) flow = { "flowID": newFlowID, "type": flow["type"], "next": [] } # New object required _class = model._model().getAsClass( api.g["sessionData"], id=modelFlowObject.classID) if _class: _class = _class[0].classObject() # Bug exists as name value is not requried by db class but is for core models - this could result in an error if new model is added that does not accept name within new function override newFlowObjectID = _class().new( flow["flowID"]).inserted_id # Working out by bruteforce which type this is ( try and load it by parent class and check for error) - get on trigger if it does not exist will return None modelFlowObjectClone = _class().getAsClass( api.g["sessionData"], id=newFlowObjectID) if len(modelFlowObjectClone) == 1: modelFlowObjectClone = modelFlowObjectClone[0] else: return {}, 404 # Setting values in cloned object members = [ attr for attr in dir(modelFlowObject) if not callable(getattr(modelFlowObject, attr)) and not "__" in attr and attr ] dontCopy = ["_id", "name"] updateList = [] for member in members: if member not in dontCopy: setattr(modelFlowObjectClone, member, getattr(modelFlowObject, member)) updateList.append(member) modelFlowObjectClone.update( updateList, sessionData=api.g["sessionData"]) # Set conduct flow to correct type and objectID flow["{0}{1}".format(flow["type"], "ID")] = str(newFlowObjectID) conductObj.flow.append(flow) conductObj.update(["flow"], sessionData=api.g["sessionData"]) return {"result": True, "flowID": newFlowID}, 201 else: return {}, 403 # Add existing object to flow elif data["action"] == "existing": access, accessIDs, adminBypass = db.ACLAccess(api.g["sessionData"], conductObj.acl, "write") if access: newFlowID = str(uuid.uuid4()) flow = {"flowID": newFlowID, "next": []} if data["type"] == "trigger": flow["type"] = "trigger" flow["triggerID"] = data["triggerID"] elif data["type"] == "action": flow["type"] = "action" flow["actionID"] = data["actionID"] conductObj.flow.append(flow) conductObj.update(["flow"], sessionData=api.g["sessionData"]) return {"result": True, "flowID": newFlowID}, 201 else: return {}, 403 elif data["action"] == "save": access, accessIDs, adminBypass = db.ACLAccess(api.g["sessionData"], conductObj.acl, "write") if access: flowData = data["flowData"] newFlowData = {} flowPopList = [] for flow in flowData['links']: if flow != "{}>{}".format( flowData['links'][flow]['fromOperator'], flowData['links'][flow]['toOperator']): newFlowData["{}>{}".format( flowData['links'][flow]['fromOperator'], flowData['links'][flow] ['toOperator'])] = flowData['links'][flow] flowPopList.append(flow) if len(newFlowData) > 0: flowData['links'].update(newFlowData, sessionData=api.g["sessionData"]) for popItem in flowPopList: flowData['links'].pop(popItem) poplistOperator = [] poplistLink = [] for operatorID in flowData["operators"]: operatorFound = None for flow in conductObj.flow: flowID = flow["flowID"] if operatorID == flowID: operatorFound = flowID connections = [] for link in flowData["links"]: if flowData["links"][link][ "fromOperator"] == flowID: connections.append( flowData["links"][link]["toOperator"]) for connection in connections: foundFlow = False for index, nextFlowID in enumerate(conductObj.flow[ conductObj.flow.index(flow)]["next"]): if type(nextFlowID) is dict: if connection == nextFlowID["flowID"]: foundFlow = True conductObj.flow[conductObj.flow.index( flow)]["next"][index] = { "flowID": connection, "logic": nextFlowID["logic"] } else: if connection == nextFlowID: foundFlow = True conductObj.flow[conductObj.flow.index( flow)]["next"][index] = { "flowID": connection, "logic": True } if not foundFlow: conductObj.flow[conductObj.flow.index( flow)]["next"].append({ "flowID": connection, "logic": True }) notUpdatedPopList = [] for nextFlowID in conductObj.flow[ conductObj.flow.index(flow)]["next"]: if nextFlowID["flowID"] not in connections: notUpdatedPopList.append(nextFlowID) for notUpdatedPopItem in notUpdatedPopList: del conductObj.flow[conductObj.flow.index(flow)][ "next"][conductObj.flow[conductObj.flow.index( flow)]["next"].index(notUpdatedPopItem)] if not operatorFound: for link in flowData["links"]: if flowData["links"][link][ "toOperator"] == operatorID or flowData[ "links"][link][ "fromOperator"] == operatorID: poplistLink.append(link) poplistOperator.append(operatorID) # Checking to ensure every flow that exists is also still within the flowData i.e. it has not been deleted poplistFlow = [] for flow in conductObj.flow: flowID = flow["flowID"] if len([x for x in flowData["operators"] if x == flowID]) == 0: poplistFlow.append(flow) # Deleting any items that were found within flowData but not in the conduct flow for pop in poplistOperator: del flowData["operators"][pop] for pop in poplistLink: del flowData["links"][pop] for pop in poplistFlow: del conductObj.flow[conductObj.flow.index(pop)] # checking if conduct has been enabled or name changed if "conductName" in data: conductObj.name = data["conductName"] if "conductEnabled" in data: conductObj.enabled = data["conductEnabled"] if "conductACL" in data: try: conductObj.acl = json.loads(data["conductACL"]) except: pass # Updating all possible updated values conductObj.update(["flow", "name", "enabled", "acl"], sessionData=api.g["sessionData"]) existingFlow = webui._flowData().query( query={"conductID": conductID})["results"] if len(existingFlow) > 0: existingFlow = existingFlow[0] existingFlow = webui._flowData().load(existingFlow["_id"]) existingFlow.flowData = flowData existingFlow.update(["flowData"], sessionData=api.g["sessionData"]) else: webui._flowData().new(conductID, flowData) return {"result": True, "flowData": flowData}, 201 return {"result": True, "flowData": flowData}, 200 else: return {}, 403 return {"result": False}, 404
def setConductFlow(conductID, flowID): # List of attributes that are prevented from updating - this needs to be made more dynamic and part of class design unsafeUpdateList = [ "_id", "classID", "lastCheck", "lastRun", "lastResult", "workerID", "startCheck" ] conductObj = conduct._conduct().query(api.g["sessionData"], id=conductID)["results"] conductObj = conductObj[0] conductObj = conduct._conduct().getAsClass(api.g["sessionData"], id=conductObj["_id"]) if len(conductObj) == 1: conductObj = conductObj[0] else: return {}, 404 flow = [x for x in conductObj.flow if x["flowID"] == flowID] if len(flow) == 1: flow = flow[0] data = json.loads(api.request.data) modelFlowObject = None # Check if the modelType and object are unchanged if "type" in flow: if flow["type"] == "trigger": modelFlowObject = trigger._trigger().getAsClass( api.g["sessionData"], id=flow["{0}{1}".format(flow["type"], "ID")]) if len(modelFlowObject) == 1: modelFlowObject = modelFlowObject[0] modelFlowObjectType = "trigger" if flow["type"] == "action": modelFlowObject = action._action().getAsClass( api.g["sessionData"], id=flow["{0}{1}".format(flow["type"], "ID")]) if len(modelFlowObject) == 1: modelFlowObject = modelFlowObject[0] modelFlowObjectType = "action" # Was it possible to load an existing object if modelFlowObject: # Check that the object model is still the same if modelFlowObject.classID == data["newClassID"]: # Get flow object correct class _class = model._model().getAsClass( api.g["sessionData"], id=modelFlowObject.classID) if len(_class) == 1: _class = _class[0] _class = _class.classObject() else: return {}, 404 modelFlowObject = _class().getAsClass( api.g["sessionData"], id=modelFlowObject._id) if len(modelFlowObject) == 1: modelFlowObject = modelFlowObject[0] else: return {}, 404 else: modelFlowObject = None # New object required if not modelFlowObject: _class = model._model().getAsClass(api.g["sessionData"], id=data["newClassID"]) if _class: _class = _class[0].classObject() # Bug exists as name value is not requried by db class but is for core models - this could result in an error if new model is added that does not accept name within new function override newFlowObjectID = _class().new(flow["flowID"]).inserted_id # Working out by bruteforce which type this is ( try and load it by parent class and check for error) - get on trigger if it does not exist will return None modelFlowObjectType = "action" if len(trigger._trigger().getAsClass(api.g["sessionData"], id=newFlowObjectID)) > 0: modelFlowObjectType = "trigger" modelFlowObject = _class().getAsClass(api.g["sessionData"], id=newFlowObjectID) if len(modelFlowObject) == 1: modelFlowObject = modelFlowObject[0] else: return {}, 404 modelFlowObject.acl = { "ids": [{ "accessID": api.g["sessionData"]["primaryGroup"], "read": True, "write": True, "delete": True }] } modelFlowObject.update(["acl"]) # Set conduct flow to correct type and objectID flow["type"] = modelFlowObjectType flow["{0}{1}".format(modelFlowObjectType, "ID")] = str(newFlowObjectID) conductObj.update(["flow"], sessionData=api.g["sessionData"]) # Updating new or existing modeFlowObject if modelFlowObject: updateItemsList = [] changeLog = {} # Getting schema information so types can be set correctly class_ = model._model().getAsClass(api.g["sessionData"], id=modelFlowObject.classID) if class_: _class = modelFlowObject # Builds list of permitted ACL access, accessIDs, adminBypass = db.ACLAccess( api.g["sessionData"], _class.acl, "write") if access: for dataKey, dataValue in data.items(): fieldAccessPermitted = True # Checking if sessionData is permitted field level access if _class.acl and not adminBypass: fieldAccessPermitted = db.fieldACLAccess( api.g["sessionData"], _class.acl, dataKey, "write") if fieldAccessPermitted: # Change update database entry _id if dataKey not in unsafeUpdateList: if hasattr(_class, dataKey): changeLog[dataKey] = {} changeLog[dataKey][ "currentValue"] = getattr( _class, dataKey) if type(getattr(_class, dataKey)) is str: if dataValue: if _class.setAttribute( dataKey, str(dataValue), sessionData=api. g["sessionData"]): updateItemsList.append(dataKey) changeLog[dataKey][ "newValue"] = getattr( _class, dataKey) elif type(getattr(_class, dataKey)) is int: try: if _class.setAttribute( dataKey, int(dataValue), sessionData=api. g["sessionData"]): updateItemsList.append(dataKey) changeLog[dataKey][ "newValue"] = getattr( _class, dataKey) except ValueError: if _class.setAttribute( dataKey, 0, sessionData=api. g["sessionData"]): updateItemsList.append(dataKey) changeLog[dataKey][ "newValue"] = getattr( _class, dataKey) elif type(getattr(_class, dataKey)) is float: try: if _class.setAttribute( dataKey, float(dataValue), sessionData=api. g["sessionData"]): updateItemsList.append(dataKey) changeLog[dataKey][ "newValue"] = getattr( _class, dataKey) except ValueError: if _class.setAttribute( dataKey, 0, sessionData=api. g["sessionData"]): updateItemsList.append(dataKey) changeLog[dataKey][ "newValue"] = getattr( _class, dataKey) elif type(getattr(_class, dataKey)) is bool: if _class.setAttribute( dataKey, bool(dataValue), sessionData=api. g["sessionData"]): updateItemsList.append(dataKey) changeLog[dataKey][ "newValue"] = getattr( _class, dataKey) elif type(getattr( _class, dataKey)) is dict or type( getattr(_class, dataKey)) is list: if dataValue: if _class.setAttribute( dataKey, json.loads(dataValue), sessionData=api. g["sessionData"]): updateItemsList.append(dataKey) changeLog[dataKey][ "newValue"] = getattr( _class, dataKey) # Commit back to database if updateItemsList: _class.update(updateItemsList, sessionData=api.g["sessionData"]) # Adding audit record if "_id" in api.g["sessionData"]: audit._audit().add( "model", "update", { "_id": api.g["sessionData"]["_id"], "objects": helpers.unicodeEscapeDict(changeLog) }) else: audit._audit().add("model", "update", { "objects": helpers.unicodeEscapeDict(changeLog) }) return {"type": modelFlowObjectType}, 200 else: return {}, 403 return {}, 404
def conductFlowchartPoll(conductID): conductObj = conduct._conduct().query(api.g["sessionData"], id=conductID)["results"] if len(conductObj) == 1: conductObj = conductObj[0] else: return {}, 404 data = json.loads(api.request.data) flowchartOperators = data["operators"] flowchartLinks = data["links"] flowchartResponse = { "operators": { "delete": {}, "create": {}, "update": {} }, "links": { "delete": {}, "create": {}, "update": {} } } # Getting all UI flow details for flows in this conduct flows = [x for x in conductObj["flow"]] flowTriggers = [ db.ObjectId(x["triggerID"]) for x in flows if x["type"] == "trigger" ] flowActions = [ db.ObjectId(x["actionID"]) for x in flows if x["type"] == "action" ] flowsList = [x["flowID"] for x in flows] linksList = [] # For every refresh the entire flow object and UI is loaded from the database - this may need improvment for speed in future flowsUI = webui._modelUI().getAsClass(api.g["sessionData"], query={ "flowID": { "$in": flowsList }, "conductID": conductID }) actions = action._action().getAsClass(api.g["sessionData"], query={"_id": { "$in": flowActions }}) triggers = trigger._trigger().getAsClass( api.g["sessionData"], query={"_id": { "$in": flowTriggers }}) cache.globalCache.newCache("modelCache", sessionData=api.g["sessionData"]) for flow in flows: if "type" in flow: flowType = flow["type"] if "subtype" in flow: flowSubtype = flow["subtype"] else: flowSubtype = "" if "{0}{1}".format(flowType, "ID") in flow: objectID = "{0}{1}".format(flowType, "ID") flowID = flow["flowID"] # Default to create flowchartResponseType = "create" if flowID in flowchartOperators: # If it already exits then its an update flowchartResponseType = "update" # Setting position if it has changed since last pollTime foundFlowUI = False foundObject = False name = flow["flowID"] node = {} for flowUI in flowsUI: if flow["flowID"] == flowUI.flowID: foundFlowUI = True if flowchartResponseType == "create": node["x"] = flowUI.x node["y"] = flowUI.y node["shape"] = "box" node["widthConstraint"] = { "minimum": 125, "maximum": 125 } node["heightConstraint"] = { "minimum": 35, "maximum": 35 } node["borderWidth"] = 1.5 node["font"] = {"multi": True} elif flowUI.x != flowchartOperators[flowID]["node"][ "x"] or flowUI.y != flowchartOperators[flowID][ "node"]["y"]: node["x"] = flowUI.x node["y"] = flowUI.y if flow["type"] == "trigger": for t in triggers: if flow["triggerID"] == t._id: name = t.name modeClass = cache.globalCache.get( "modelCache", t.classID, model.getClassObject, sessionData=api.g["sessionData"])[0] color = None if t.enabled: color = "#7cbeeb" duration = t.maxDuration if duration == 0: duration = 60 if ((t.startCheck != 0) and (t.startCheck + duration > time.time())): color = "green" if ((t.startCheck != 0) and (t.startCheck + duration < time.time())): color = "red" if not t.enabled: color = "gray" label = "<b>{0}</b>\n{1}".format( t.name, modeClass.name) if flowchartResponseType == "create": node["label"] = label node["color"] = {"background": color} else: if color != flowchartOperators[flowID][ "node"]["color"]: node["color"] = { "background": color } if label != flowchartOperators[flowID][ "node"]["label"]: node["label"] = label foundObject = True break elif flow["type"] == "action": for a in actions: if flow["actionID"] == a._id: name = a.name modeClass = cache.globalCache.get( "modelCache", a.classID, model.getClassObject, sessionData=api.g["sessionData"])[0] color = None if a.enabled: color = "#7cbeeb" if not a.enabled: color = "gray" label = "<b>{0}</b>\n{1}".format( a.name, modeClass.name) if flowchartResponseType == "create": node["label"] = label node["color"] = {"background": color} else: if color != flowchartOperators[flowID][ "node"]["color"]: node["color"] = { "background": color } if label != flowchartOperators[flowID][ "node"]["label"]: node["label"] = label foundObject = True break if node: if not foundObject: node["label"] = "Unknown Object" node["color"] = {"background": "black"} flowchartResponse["operators"][ flowchartResponseType][flowID] = { "_id": flow[objectID], "flowID": flowID, "flowType": flowType, "flowSubtype": flowSubtype, "name": name, "node": node } break if not foundFlowUI: node["x"] = 0 node["y"] = 0 node["shape"] = "box" node["widthConstraint"] = {"minimum": 125, "maximum": 125} node["heightConstraint"] = {"minimum": 35, "maximum": 35} node["borderWidth"] = 1.5 node["label"] = "Unknown Object" node["color"] = {"background": "black"} flowchartResponse["operators"][flowchartResponseType][ flowID] = { "_id": flow[objectID], "flowID": flowID, "flowType": flowType, "flowSubtype": flowSubtype, "node": node } # Do any links need to be created for nextFlow in flow["next"]: linkName = "{0}->{1}".format(flowID, nextFlow["flowID"]) linksList.append(linkName) if linkName not in flowchartLinks: flowchartResponse["links"]["create"][linkName] = { "from": flowID, "to": nextFlow["flowID"], "logic": nextFlow["logic"] } #Updates (for logic for now) << needs to be readded but using same as node with color value set from server #flowchartResponse["links"]["update"][linkName] = { "from" : flowID, "to" : nextFlow["flowID"], "logic" : nextFlow["logic"] } # Checking for deleted operators for flowchartOperator in flowchartOperators: if flowchartOperator not in flowsList: flowchartResponse["operators"]["delete"][flowchartOperator] = { "flowID": flowchartOperator } # Checking for deleted links for flowchartLink in flowchartLinks: if flowchartLink not in linksList: flowchartResponse["links"]["delete"][flowchartLink] = { "linkName": flowchartLink } return flowchartResponse, 200
def getConductFlowCodify(conductID): def generateFlow(currentFlow, flowDict, triggers, actions): flowCode = "" processQueue = [] indentLevel = 0 logic = None while True: if currentFlow: obj = None if currentFlow["type"] == "trigger": for t in triggers: if flow["triggerID"] == t._id: obj = t break for nextFlow in currentFlow["next"]: processQueue.append({ "flowID": nextFlow["flowID"], "indentLevel": indentLevel + 1, "logic": nextFlow["logic"] }) elif currentFlow["type"] == "action": for a in actions: if currentFlow["actionID"] == a._id: obj = a break for nextFlow in currentFlow["next"]: processQueue.append({ "flowID": nextFlow["flowID"], "indentLevel": indentLevel + 1, "logic": nextFlow["logic"] }) if obj: classObj = _class = model._model().getAsClass( api.g["sessionData"], id=obj.classID) classObj = classObj[0] blacklist = [ "_id", "acl", "classID", "workerID", "startCheck", "nextCheck", "lastUpdateTime", "lastCheck" ] members = [ attr for attr in dir(obj) if not callable(getattr(obj, attr)) and not "__" in attr and attr ] params = [] for member in members: if member not in blacklist: value = getattr(obj, member) if type(value) == str: value = "\"{0}\"".format(value) params.append("{0}={1}".format(member, value)) if currentFlow["type"] == "action": flowCode += "\r\n{0}logic({1})->{2}({3})".format( ("\t" * indentLevel), logic, classObj.name, ",".join(params)) else: if len(flowCode) > 0: flowCode += "\r\n{0}{1}({2})".format( ("\t" * indentLevel), classObj.name, ",".join(params)) else: flowCode = "{0}({1})".format( classObj.name, ",".join(params)) if len(processQueue) == 0: break else: nextFlowID = processQueue[-1]["flowID"] indentLevel = processQueue[-1]["indentLevel"] logic = processQueue[-1]["logic"] processQueue.pop() if nextFlowID in flowDict: currentFlow = flowDict[nextFlowID] else: currentFlow = None return flowCode conductObj = conduct._conduct().getAsClass(api.g["sessionData"], id=conductID) if len(conductObj) == 1: conductObj = conductObj[0] else: return {}, 404 # Getting all UI flow details for flows in this conduct flows = [x for x in conductObj.flow] flowDict = {} for flow in flows: flowDict[flow["flowID"]] = flow flowTriggers = [ db.ObjectId(x["triggerID"]) for x in flows if x["type"] == "trigger" ] flowActions = [ db.ObjectId(x["actionID"]) for x in flows if x["type"] == "action" ] actions = action._action().getAsClass(api.g["sessionData"], query={"_id": { "$in": flowActions }}) triggers = trigger._trigger().getAsClass( api.g["sessionData"], query={"_id": { "$in": flowTriggers }}) flowCode = "" for flow in flows: if flow["type"] == "trigger": flowCode += generateFlow(flow, flowDict, triggers, actions) return render_template("blank.html", content=flowCode, CSRF=api.g["sessionData"]["CSRF"]), 200
def updateFlow(conductID, flowID): conductObj = conduct._conduct().getAsClass(api.g["sessionData"], id=conductID) if len(conductObj) == 1: conductObj = conductObj[0] else: return {}, 404 flow = [x for x in conductObj.flow if x["flowID"] == flowID] if len(flow) == 1: flow = flow[0] data = json.loads(api.request.data) if data["action"] == "update": access, accessIDs, adminBypass = db.ACLAccess( api.g["sessionData"], conductObj.acl, "write") if access: if "x" in data and "y" in data: try: x = int(data["x"]) y = int(data["y"]) except: return {}, 403 flowUI = webui._modelUI().getAsClass(api.g["sessionData"], query={ "flowID": flow["flowID"], "conductID": conductID }) if len(flowUI) == 1: flowUI = flowUI[0] if "x" in data and "y" in data: flowUI.x = x flowUI.y = y flowUI.update(["x", "y"], sessionData=api.g["sessionData"]) if "title" in data: flowUI.title = data["title"] flowUI.update(["title"], sessionData=api.g["sessionData"]) return {}, 200 else: webui._modelUI().new(conductID, conductObj.acl, flow["flowID"], x, y) return {}, 201 elif data["action"] == "copy": access, accessIDs, adminBypass = db.ACLAccess( api.g["sessionData"], conductObj.acl, "write") if access: flow = [ x for x in conductObj.flow if x["flowID"] == data["operatorId"] ] if len(flow) == 1: flow = flow[0] newFlowID = str(uuid.uuid4()) newFlow = { "flowID": newFlowID, "type": flow["type"], "{0}{1}".format(flow["type"], "ID"): flow["{0}{1}".format(flow["type"], "ID")], "next": [] } flowUI = webui._modelUI().getAsClass(api.g["sessionData"], query={ "flowID": flow["flowID"], "conductID": conductID })[0] webui._modelUI().new(conductID, conductObj.acl, newFlow["flowID"], data["x"], data["y"], flowUI.title) conductObj.flow.append(newFlow) conductObj.update(["flow"], sessionData=api.g["sessionData"]) return {}, 201 elif data["action"] == "clone": access, accessIDs, adminBypass = db.ACLAccess( api.g["sessionData"], conductObj.acl, "write") if access: flow = [ x for x in conductObj.flow if x["flowID"] == data["operatorId"] ] if len(flow) == 1: flow = flow[0] data = json.loads(api.request.data) modelFlowObject = None # Check if the modelType and object are unchanged if "type" in flow: if flow["type"] == "trigger": modelFlowObject = trigger._trigger().getAsClass( api.g["sessionData"], id=flow["{0}{1}".format(flow["type"], "ID")]) if len(modelFlowObject) == 1: modelFlowObject = modelFlowObject[0] modelFlowObjectType = "trigger" if flow["type"] == "action": modelFlowObject = action._action().getAsClass( api.g["sessionData"], id=flow["{0}{1}".format(flow["type"], "ID")]) if len(modelFlowObject) == 1: modelFlowObject = modelFlowObject[0] modelFlowObjectType = "action" # Was it possible to load an existing object if modelFlowObject: # Create new flowItem newFlowID = str(uuid.uuid4()) flow = { "flowID": newFlowID, "type": flow["type"], "next": [] } # New object required _class = model._model().getAsClass( api.g["sessionData"], id=modelFlowObject.classID) if _class: _class = _class[0].classObject() # Bug exists as name value is not requried by db class but is for core models - this could result in an error if new model is added that does not accept name within new function override newFlowObjectID = _class().new( flow["flowID"]).inserted_id # Working out by bruteforce which type this is ( try and load it by parent class and check for error) - get on trigger if it does not exist will return None modelFlowObjectClone = _class().getAsClass( api.g["sessionData"], id=newFlowObjectID) if len(modelFlowObjectClone) == 1: modelFlowObjectClone = modelFlowObjectClone[ 0] else: return {}, 404 # Setting values in cloned object members = [ attr for attr in dir(modelFlowObject) if not callable( getattr(modelFlowObject, attr)) and not "__" in attr and attr ] dontCopy = ["_id", "name"] updateList = [] for member in members: if member not in dontCopy: setattr( modelFlowObjectClone, member, getattr(modelFlowObject, member)) updateList.append(member) modelFlowObjectClone.update( updateList, sessionData=api.g["sessionData"]) # Set conduct flow to correct type and objectID flow["{0}{1}".format( flow["type"], "ID")] = str(newFlowObjectID) conductObj.flow.append(flow) # Adding UI position for cloned object flowUI = webui._modelUI().getAsClass( api.g["sessionData"], query={ "flowID": flowID, "conductID": conductID })[0] webui._modelUI().new( conductID, conductObj.acl, flow["flowID"], data["x"], data["y"], "Copy - {0}".format(flowUI.title)) conductObj.update( ["flow"], sessionData=api.g["sessionData"]) return {"result": True}, 201 return {}, 404
def systemInstall(): # Adding ENC secure systemSecure = _system().query(query={"name": "secure"})["results"] if len(systemSecure) < 1: systemSecure = _system().new("secure").inserted_id systemSecure = _system().get(systemSecure) systemSecure.data = {"string": secrets.token_hex(32)} systemSecure.update(["data"]) # Installing model if that DB is not installed if "model" not in db.list_collection_names(): logging.debug("DB Collection 'model' Not Found : Creating...") # Creating default model required so other models can be registered logging.debug("Registering default model class...") m = model._model() m.name = "model" m.classID = None m.acl = { "ids": [{ "accessID": "0", "delete": True, "read": True, "write": True }] } m.className = "_model" m.classType = "_document" m.location = "core.model" m.insert_one(m.parse()) if "conducts" not in db.list_collection_names(): logging.debug("DB Collection conducts Not Found : Creating...") model.registerModel("conduct", "_conduct", "_document", "core.models.conduct") if "triggers" not in db.list_collection_names(): logging.debug("DB Collection action Not Found : Creating...") model.registerModel("trigger", "_trigger", "_document", "core.models.trigger") if "actions" not in db.list_collection_names(): logging.debug("DB Collection action Not Found : Creating...") model.registerModel("action", "_action", "_document", "core.models.action") if "webui" not in db.list_collection_names(): logging.debug("DB Collection webui Not Found : Creating...") model.registerModel("flowData", "_flowData", "_document", "core.models.webui") if "modelUI" not in db.list_collection_names(): logging.debug("DB Collection modelUI Not Found : Creating...") model.registerModel("modelUI", "_modelUI", "_document", "core.models.webui") if "clusterMembers" not in db.list_collection_names(): logging.debug("DB Collection clusterMembers Not Found : Creating...") model.registerModel("clusterMember", "_clusterMember", "_document", "core.cluster") # System - failedTriggers from core.models import trigger triggers = trigger._trigger().query( query={"name": "failedTriggers"})["results"] if len(triggers) < 1: from system.models import trigger as systemTrigger model.registerModel("failedTriggers", "_failedTriggers", "_trigger", "system.models.trigger") if not systemTrigger._failedTriggers().new("failedTriggers"): logging.debug("Unable to register failedTriggers", -1) return False temp = model._model().getAsClass(query={"name": "failedTriggers"}) if len(temp) == 1: temp = temp[0] temp.hidden = True temp.update(["hidden"]) # System - Actions from core.models import action actions = action._action().query(query={"name": "resetTrigger"})["results"] if len(actions) < 1: from system.models import action as systemAction model.registerModel("resetTrigger", "_resetTrigger", "_action", "system.models.action") if not systemAction._resetTrigger().new("resetTrigger"): logging.debug("Unable to register resetTrigger", -1) return False temp = model._model().getAsClass(query={"name": "resetTrigger"}) if len(temp) == 1: temp = temp[0] temp.hidden = True temp.update(["hidden"]) from core import auth # Adding models for user and groups model.registerModel("user", "_user", "_document", "core.auth") model.registerModel("group", "_group", "_document", "core.auth") # Adding default admin group adminGroup = auth._group().getAsClass(query={"name": "admin"}) if len(adminGroup) == 0: adminGroup = auth._group().new("admin") adminGroup = auth._group().getAsClass(query={"name": "admin"}) adminGroup = adminGroup[0] # Adding default root user rootUser = auth._user().getAsClass(query={"username": "******"}) if len(rootUser) == 0: rootPass = randomString(30) rootUser = auth._user().new("root", "root", rootPass) rootUser = auth._user().getAsClass(query={"username": "******"}) logging.debug("Root user created! Password is: {}".format(rootPass), -1) rootUser = rootUser[0] # Adding root to group if rootUser._id not in adminGroup.members: adminGroup.members.append(rootUser._id) adminGroup.update(["members"]) # Adding primary group for root user rootUser.primaryGroup = adminGroup._id rootUser.update(["primaryGroup"]) return True
def install(self): # Register models model.registerModel("occurrence", "_occurrence", "_action", "plugins.occurrence.models.action") model.registerModel("occurrence clean", "_occurrenceClean", "_action", "plugins.occurrence.models.action") model.registerModel("occurrenceUpdate", "_occurrenceUpdate", "_action", "plugins.occurrence.models.action") # Finding conduct foundConducts = conduct._conduct().query( query={"name": "occurrenceCore"})["results"] if len(foundConducts) == 0: # Install c = conduct._conduct().new("occurrenceCore") c = conduct._conduct().get(c.inserted_id) elif len(foundConducts) == 1: # Reinstall c = conduct._conduct().get(foundConducts[0]["_id"]) else: # Count invalid return False # Finding trigger foundTriggers = trigger._trigger().query( query={"name": "occurrenceCore"})["results"] if len(foundTriggers) == 0: # Install t = trigger._trigger().new("occurrenceCore") t = trigger._trigger().get(t.inserted_id) elif len(foundTriggers) == 1: # Reinstall t = trigger._trigger().get(foundTriggers[0]["_id"]) else: # Count invalid return False # Finding action foundActions = action._occurrenceClean().query( query={"name": "occurrenceCore"})["results"] if len(foundActions) == 0: # Install a = action._occurrenceClean().new("occurrenceCore") a = action._occurrenceClean().get(a.inserted_id) elif len(foundActions) == 1: # Reinstall a = action._occurrenceClean().get(foundActions[0]["_id"]) else: # Count invalid return False c.triggers = [t._id] flowTriggerID = str(uuid.uuid4()) flowActionID = str(uuid.uuid4()) c.flow = [{ "flowID": flowTriggerID, "type": "trigger", "triggerID": t._id, "next": [{ "flowID": flowActionID, "logic": True }] }, { "flowID": flowActionID, "type": "action", "actionID": a._id, "next": [] }] webui._modelUI().new( c._id, { "ids": [{ "accessID": "0", "delete": True, "read": True, "write": True }] }, flowTriggerID, 0, 0, "") webui._modelUI().new( c._id, { "ids": [{ "accessID": "0", "delete": True, "read": True, "write": True }] }, flowActionID, 100, 0, "") c.acl = { "ids": [{ "accessID": "0", "delete": True, "read": True, "write": True }] } c.enabled = True c.update(["triggers", "flow", "enabled", "acl"]) t.acl = { "ids": [{ "accessID": "0", "delete": True, "read": True, "write": True }] } t.schedule = "60-90s" t.enabled = True t.update(["schedule", "enabled", "acl"]) a.acl = { "ids": [{ "accessID": "0", "delete": True, "read": True, "write": True }] } a.enabled = True a.update(["enabled", "acl"]) # Hide Created Models temp = model._model().getAsClass(query={"name": "occurrence clean"}) if len(temp) == 1: temp = temp[0] temp.hidden = True temp.update(["hidden"]) return True