def create_analysis( analysis: AnalysisCreate, request: Request, response: Response, db: Session = Depends(get_db), ): # Create the new analysis Node using the data from the request new_analysis: Analysis = create_node(node_create=analysis, db_node_type=Analysis, db=db, exclude={"parent_observable_uuid"}) # If an analysis module type was given, get it from the database to use with the new analysis if analysis.analysis_module_type: new_analysis.analysis_module_type = crud.read( uuid=analysis.analysis_module_type, db_table=AnalysisModuleType, db=db) # Set the parent observable if one was given if analysis.parent_observable_uuid: new_analysis.parent_observable = crud.read( uuid=analysis.parent_observable_uuid, db_table=ObservableInstance, db=db) # This counts as editing the observable instance, so it should receive an updated version new_analysis.parent_observable.version = uuid4() # Save the new analysis to the database db.add(new_analysis) crud.commit(db) response.headers["Content-Location"] = request.url_for( "get_analysis", uuid=new_analysis.uuid)
def update_node_comment( uuid: UUID, node_comment: NodeCommentUpdate, request: Request, response: Response, db: Session = Depends(get_db), ): # Read the current node comment from the database db_node_comment: NodeComment = crud.read(uuid=uuid, db_table=NodeComment, db=db) # Read the node from the database db_node = crud.read(uuid=db_node_comment.node_uuid, db_table=Node, db=db) # Set the new comment value db_node_comment.value = node_comment.value # Modifying the comment counts as modifying the node, so it should receive a new version db_node.version = uuid4() crud.commit(db) response.headers["Content-Location"] = request.url_for("get_node_comment", uuid=uuid)
def update_observable_instance( uuid: UUID, observable_instance: ObservableInstanceUpdate, request: Request, response: Response, db: Session = Depends(get_db), ): # Update the Node attributes db_observable_instance: ObservableInstance = update_node( node_update=observable_instance, uuid=uuid, db_table=ObservableInstance, db=db, ) # Get the data that was given in the request and use it to update the database object update_data = observable_instance.dict(exclude_unset=True) if "context" in update_data: db_observable_instance.context = update_data["context"] # Any UUIDs given in this list add to the existing ones and do not replace them if "performed_analysis_uuids" in update_data: for performed_analysis_uuid in update_data["performed_analysis_uuids"]: db_analysis = crud.read(uuid=performed_analysis_uuid, db_table=Analysis, db=db) db_observable_instance.performed_analyses.append(db_analysis) # This counts as editing the analysis, so it should receive an updated version db_analysis.version = uuid4() if "redirection_uuid" in update_data: db_observable_instance.redirection = crud.read( uuid=update_data["redirection_uuid"], db_table=ObservableInstance, db=db) # TODO: Figure out why setting the redirection field above does not set the redirection_uuid # the same way it does in the create endpoint. db_observable_instance.redirection_uuid = update_data[ "redirection_uuid"] if "time" in update_data: db_observable_instance.time = update_data["time"] crud.commit(db) response.headers["Content-Location"] = request.url_for( "get_observable_instance", uuid=uuid)
def create_node_comment( node_comment: NodeCommentCreate, request: Request, response: Response, db: Session = Depends(get_db), ): # Create the new node comment new_comment = NodeComment(**node_comment.dict()) # Make sure the node actually exists db_node = crud.read(uuid=node_comment.node_uuid, db_table=Node, db=db) # This counts a modifying the node, so it should receive a new version. db_node.version = uuid4() # Set the user on the comment new_comment.user = crud.read_user_by_username(username=node_comment.user, db=db) # Save the new comment to the database db.add(new_comment) crud.commit(db) response.headers["Content-Location"] = request.url_for( "get_node_comment", uuid=new_comment.uuid)
def update_observable( uuid: UUID, observable: ObservableUpdate, request: Request, response: Response, db: Session = Depends(get_db), ): # Read the current observable from the database db_observable: Observable = crud.read(uuid=uuid, db_table=Observable, db=db) # Get the data that was given in the request and use it to update the database object update_data = observable.dict(exclude_unset=True) if "expires_on" in update_data: db_observable.expires_on = update_data["expires_on"] if "for_detection" in update_data: db_observable.for_detection = update_data["for_detection"] if "type" in update_data: db_observable.type = crud.read_by_value(value=update_data["type"], db_table=ObservableType, db=db) if "value" in update_data: db_observable.value = update_data["value"] crud.commit(db) response.headers["Content-Location"] = request.url_for("get_observable", uuid=uuid)
def update_node_threat( uuid: UUID, node_threat: NodeThreatUpdate, request: Request, response: Response, db: Session = Depends(get_db), ): # Read the current node threat from the database db_node_threat: NodeThreat = crud.read(uuid=uuid, db_table=NodeThreat, db=db) # Get the data that was given in the request and use it to update the database object update_data = node_threat.dict(exclude_unset=True) if "description" in update_data: db_node_threat.description = update_data["description"] if "value" in update_data: db_node_threat.value = update_data["value"] if "types" in update_data: db_node_threat.types = crud.read_by_values(values=update_data["types"], db_table=NodeThreatType, db=db) crud.commit(db) response.headers["Content-Location"] = request.url_for("get_node_threat", uuid=uuid)
def test_update_password(client, db, initial_value, updated_value): # Create an alert queue client.post("/api/alert/queue/", json={"value": "test_queue"}) # Create a user role client.post("/api/user/role/", json={"value": "test_role"}) # Create the object create_json = { "default_alert_queue": "test_queue", "display_name": "John Doe", "email": "*****@*****.**", "password": initial_value, "roles": ["test_role"], "username": "******", } create = client.post("/api/user/", json=create_json) assert create.status_code == status.HTTP_201_CREATED # Read it back to get the UUID get = client.get(create.headers["Content-Location"]) # Manually retrieve the user from the database so we have the initial password hash initial_user = crud.read(uuid=get.json()["uuid"], db_table=User, db=db) initial_hash = initial_user.password # Make sure the initial password validates against its hash assert verify_password(initial_value, initial_hash) is True # Update it update = client.patch(create.headers["Content-Location"], json={"password": updated_value}) assert update.status_code == status.HTTP_204_NO_CONTENT # Manually retrieve the user from the database so we have the updated password hash updated_user = crud.read(uuid=get.json()["uuid"], db_table=User, db=db) updated_hash = updated_user.password # Make sure the two hashes are not the same assert initial_hash != updated_hash # Make sure the updated password validates against its hash assert verify_password(updated_value, updated_hash) is True
def update_analysis_module_type( uuid: UUID, analysis_module_type: AnalysisModuleTypeUpdate, request: Request, response: Response, db: Session = Depends(get_db), ): # Read the current analysis module type from the database db_analysis_module_type: AnalysisModuleType = crud.read( uuid=uuid, db_table=AnalysisModuleType, db=db) # Get the data that was given in the request and use it to update the database object update_data = analysis_module_type.dict(exclude_unset=True) if "description" in update_data: db_analysis_module_type.description = update_data["description"] if "extended_version" in update_data: db_analysis_module_type.extended_version = update_data[ "extended_version"] if "manual" in update_data: db_analysis_module_type.manual = update_data["manual"] if "value" in update_data: db_analysis_module_type.value = update_data["value"] if "observable_types" in update_data: db_analysis_module_type.observable_types = crud.read_by_values( values=update_data["observable_types"], db_table=ObservableType, db=db) if "required_directives" in update_data: db_analysis_module_type.required_directives = crud.read_by_values( values=update_data["required_directives"], db_table=NodeDirective, db=db) if "required_tags" in update_data: db_analysis_module_type.required_tags = crud.read_by_values( values=update_data["required_tags"], db_table=NodeTag, db=db) if "version" in update_data: db_analysis_module_type.version = update_data["version"] crud.commit(db) response.headers["Content-Location"] = request.url_for( "get_analysis_module_type", uuid=uuid)
def update_user( uuid: UUID, user: UserUpdate, request: Request, response: Response, db: Session = Depends(get_db), ): # Read the current user from the database db_user: User = crud.read(uuid=uuid, db_table=User, db=db) # Get the data that was given in the request and use it to update the database object update_data = user.dict(exclude_unset=True) if "default_alert_queue" in update_data: db_user.default_alert_queue = crud.read_by_value( value=update_data["default_alert_queue"], db_table=AlertQueue, db=db) if "display_name" in update_data: db_user.display_name = update_data["display_name"] if "email" in update_data: db_user.email = update_data["email"] if "enabled" in update_data: db_user.enabled = update_data["enabled"] if "password" in update_data: db_user.password = hash_password(update_data["password"]) if "roles" in update_data: db_user.roles = crud.read_by_values(values=update_data["roles"], db_table=UserRole, db=db) if "timezone" in update_data: db_user.timezone = update_data["timezone"] if "username" in update_data: db_user.username = update_data["username"] crud.commit(db) response.headers["Content-Location"] = request.url_for("get_user", uuid=uuid)
def update_node(node_update: NodeUpdate, uuid: UUID, db_table: DeclarativeMeta, db: Session) -> DeclarativeMeta: """ Helper function when updating a Node that enforces version matching and updates the attributes inherited from Node. """ # Fetch the Node from the database db_node: Node = crud.read(uuid=uuid, db_table=db_table, db=db) # Get the data that was given in the request and use it to update the database object update_data = node_update.dict(exclude_unset=True) # Return an exception if the passed in version does not match the Node's current version if update_data["version"] != db_node.version: raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail="Unable to update Node due to version mismatch") if "directives" in update_data: db_node.directives = crud.read_by_values( values=update_data["directives"], db_table=NodeDirective, db=db) if "tags" in update_data: db_node.tags = crud.read_by_values(values=update_data["tags"], db_table=NodeTag, db=db) if "threat_actor" in update_data: db_node.threat_actor = crud.read_by_value( value=update_data["threat_actor"], db_table=NodeThreatActor, db=db) if "threats" in update_data: db_node.threats = crud.read_by_values(values=update_data["threats"], db_table=NodeThreat, db=db) # Update the node version db_node.version = uuid4() return db_node
def update_analysis( uuid: UUID, analysis: AnalysisUpdate, request: Request, response: Response, db: Session = Depends(get_db), ): # Update the Node attributes db_analysis: Analysis = update_node(node_update=analysis, uuid=uuid, db_table=Analysis, db=db) # Get the data that was given in the request and use it to update the database object update_data = analysis.dict(exclude_unset=True) if "analysis_module_type" in update_data: db_analysis_module_type = crud.read( uuid=update_data["analysis_module_type"], db_table=AnalysisModuleType, db=db) db_analysis.analysis_module_type = db_analysis_module_type if "details" in update_data: db_analysis.details = update_data["details"] if "error_message" in update_data: db_analysis.error_message = update_data["error_message"] if "stack_trace" in update_data: db_analysis.stack_trace = update_data["stack_trace"] if "summary" in update_data: db_analysis.summary = update_data["summary"] crud.commit(db) response.headers["Content-Location"] = request.url_for("get_analysis", uuid=uuid)
def get_observable(uuid: UUID, db: Session = Depends(get_db)): return crud.read(uuid=uuid, db_table=Observable, db=db)
def get_alert_tool(uuid: UUID, db: Session = Depends(get_db)): return crud.read(uuid=uuid, db_table=AlertTool, db=db)
def get_node_history_action(uuid: UUID, db: Session = Depends(get_db)): return crud.read(uuid=uuid, db_table=NodeHistoryAction, db=db)
def get_user_role(uuid: UUID, db: Session = Depends(get_db)): return crud.read(uuid=uuid, db_table=UserRole, db=db)
def get_event_prevention_tool(uuid: UUID, db: Session = Depends(get_db)): return crud.read(uuid=uuid, db_table=EventPreventionTool, db=db)
def get_event_risk_level(uuid: UUID, db: Session = Depends(get_db)): return crud.read(uuid=uuid, db_table=EventRiskLevel, db=db)
def get_node_threat(uuid: UUID, db: Session = Depends(get_db)): return crud.read(uuid=uuid, db_table=NodeThreat, db=db)
def get_node_comment(uuid: UUID, db: Session = Depends(get_db)): return crud.read(uuid=uuid, db_table=NodeComment, db=db)
def get_event_source(uuid: UUID, db: Session = Depends(get_db)): return crud.read(uuid=uuid, db_table=EventSource, db=db)
def get_event_vector(uuid: UUID, db: Session = Depends(get_db)): return crud.read(uuid=uuid, db_table=EventVector, db=db)
def get_disposition(uuid: UUID, db: Session = Depends(get_db)): return crud.read(uuid=uuid, db_table=AlertDisposition, db=db)
def get_analysis(uuid: UUID, db: Session = Depends(get_db)): return crud.read(uuid=uuid, db_table=Analysis, db=db)
def get_analysis_module_type(uuid: UUID, db: Session = Depends(get_db)): return crud.read(uuid=uuid, db_table=AnalysisModuleType, db=db)
def get_event_remediation(uuid: UUID, db: Session = Depends(get_db)): return crud.read(uuid=uuid, db_table=EventRemediation, db=db)
def get_event_status(uuid: UUID, db: Session = Depends(get_db)): return crud.read(uuid=uuid, db_table=EventStatus, db=db)
def get_alert_queue(uuid: UUID, db: Session = Depends(get_db)): return crud.read(uuid=uuid, db_table=AlertQueue, db=db)
def update_alert( uuid: UUID, alert: AlertUpdate, request: Request, response: Response, db: Session = Depends(get_db), ): # Update the Node attributes db_alert: Alert = update_node(node_update=alert, uuid=uuid, db_table=Alert, db=db) # Get the data that was given in the request and use it to update the database object update_data = alert.dict(exclude_unset=True) if "description" in update_data: db_alert.description = update_data["description"] if "disposition" in update_data: db_alert.disposition = crud.read_by_value( value=update_data["disposition"], db_table=AlertDisposition, db=db) if "event_uuid" in update_data: db_alert.event = crud.read(uuid=update_data["event_uuid"], db_table=Event, db=db) # This counts as editing the event, so it should receive a new version. db_alert.event.version = uuid4() if "event_time" in update_data: db_alert.event_time = update_data["event_time"] if "instructions" in update_data: db_alert.instructions = update_data["instructions"] if "name" in update_data: db_alert.name = update_data["name"] if "owner" in update_data: db_alert.owner = crud.read_user_by_username( username=update_data["owner"], db=db) if "queue" in update_data: db_alert.queue = crud.read_by_value(value=update_data["queue"], db_table=AlertQueue, db=db) if "tool" in update_data: db_alert.tool = crud.read_by_value(value=update_data["tool"], db_table=AlertTool, db=db) if "tool_instance" in update_data: db_alert.tool_instance = crud.read_by_value( value=update_data["tool_instance"], db_table=AlertToolInstance, db=db, ) if "type" in update_data: db_alert.type = crud.read_by_value(value=update_data["type"], db_table=AlertType, db=db) crud.commit(db) response.headers["Content-Location"] = request.url_for("get_alert", uuid=uuid)
def create_observable_instance( observable_instance: ObservableInstanceCreate, request: Request, response: Response, db: Session = Depends(get_db), ): # Create the new observable instance Node using the data from the request new_observable_instance: ObservableInstance = create_node( node_create=observable_instance, db_node_type=ObservableInstance, db=db, exclude={ "parent_analysis_uuid", "performed_analysis_uuids", "type", "value" }, ) # Read the required fields from the database to use with the new observable instance new_observable_instance.alert = crud.read( uuid=observable_instance.alert_uuid, db_table=Alert, db=db) new_observable_instance.parent_analysis = crud.read( uuid=observable_instance.parent_analysis_uuid, db_table=Analysis, db=db) # Adding an observable instance counts as modifying the alert and the analysis, so they should both get new versions new_observable_instance.alert.version = uuid4() new_observable_instance.parent_analysis.version = uuid4() # Set any performed analyses that were given for performed_analysis_uuid in observable_instance.performed_analysis_uuids: db_analysis = crud.read(uuid=performed_analysis_uuid, db_table=Analysis, db=db) new_observable_instance.performed_analyses.append(db_analysis) # This counts as editing the analysis, so it should receive an updated version db_analysis.version = uuid4() # Set the redirection observable instance if one was given if observable_instance.redirection_uuid: new_observable_instance.redirection = crud.read( uuid=observable_instance.redirection_uuid, db_table=ObservableInstance, db=db, ) # Lastly, check if the Observable represented by this instance already exists. Create it if it does not. db_observable = crud.read_observable(type=observable_instance.type, value=observable_instance.value, db=db) if not db_observable: db_observable_type = crud.read_by_value(value=observable_instance.type, db_table=ObservableType, db=db) db_observable = Observable(type=db_observable_type, value=observable_instance.value) # Associate the observable instance with its observable new_observable_instance.observable = db_observable # Save the new analysis to the database db.add(new_observable_instance) crud.commit(db) response.headers["Content-Location"] = request.url_for( "get_observable_instance", uuid=new_observable_instance.uuid)