def test_remove_opinion(self): os.environ["MOCK_TE_API"] = "True" os.environ["CONFIG_TABLE_NAME"] = "test-HMAConfig" writeback = WritebackTypes.RemoveOpinion writeback_message = WritebackMessage.from_match_message_and_type( self.match_message, writeback ) event = {"Records": [{"body": writeback_message.to_aws_json()}]} result = lambda_handler(event, None) assert result == { "writebacks_performed": { "te": [ "\n".join( ( "Deleted decriptor a1|2862392437204724 for indicator 2862392437204724", "Removed reaction DISAGREE_WITH_TAGS from descriptor a2|2862392437204724", "Removed reaction DISAGREE_WITH_TAGS from descriptor a3|2862392437204724", ) ), "\n".join( ( "Deleted decriptor a1|4194946153908639 for indicator 4194946153908639", "Removed reaction DISAGREE_WITH_TAGS from descriptor a2|4194946153908639", "Removed reaction DISAGREE_WITH_TAGS from descriptor a3|4194946153908639", ) ), "No writeback performed for banked content id 3027465034605137 becuase writebacks were disabled", ] } } os.environ["MOCK_TE_API"] = "False"
def lambda_handler(event, context): """ This is the main entry point for writing back to ThreatExchange. The action evaluator sends a writeback message by way of the writebacks queue and here's where they're popped off and dealt with. """ HMAConfig.initialize(os.environ["CONFIG_TABLE_NAME"]) writebacks_performed = {} for sqs_record in event["Records"]: # TODO research max # sqs records / lambda_handler invocation writeback_message = WritebackMessage.from_aws_json(sqs_record["body"]) logger.info("Writing Back: %s", writeback_message) # get all sources that are related to this writeback sources = { banked_signal.bank_source for banked_signal in writeback_message.banked_signals } source_writebackers = [ Writebacker.get_writebacker_for_source(source) for source in sources if Writebacker.get_writebacker_for_source(source) ] for writebacker in source_writebackers: result = writebacker.perform_writeback(writeback_message) logger.info("Writeback result: %s", result) writebacks_performed[writebacker.source] = result return {"writebacks_performed": writebacks_performed}
def lambda_handler(event, context): """ This lambda is called when one or more matches are found. If a single hash matches multiple datasets, this will be called only once. Action labels are generated for each match message, then an action is performed corresponding to each action label. """ config = ActionEvaluatorConfig.get() for sqs_record in event["Records"]: # TODO research max # sqs records / lambda_handler invocation sqs_record_body = json.loads(sqs_record["body"]) logger.info("sqs record body %s", sqs_record["body"]) match_message = MatchMessage.from_aws_json(sqs_record_body["Message"]) logger.info("Evaluating match_message: %s", match_message) action_rules = get_action_rules() logger.info("Evaluating against action_rules: %s", action_rules) action_label_to_action_rules = get_actions_to_take( match_message, action_rules) action_labels = list(action_label_to_action_rules.keys()) for action_label in action_labels: action_message = ( ActionMessage.from_match_message_action_label_and_action_rules( match_message, action_label, action_label_to_action_rules[action_label], )) logger.info("Sending Action message: %s", action_message) config.sqs_client.send_message( QueueUrl=config.actions_queue_url, MessageBody=action_message.to_aws_json(), ) writeback_message = WritebackMessage.from_match_message_and_type( match_message, WritebackTypes.SawThisToo) writeback_message.send_to_queue() return {"evaluation_completed": "true"}
def test_true_positve(self): os.environ["MOCK_TE_API"] = "True" os.environ["CONFIG_TABLE_NAME"] = "test-HMAConfig" writeback = WritebackTypes.TruePositive writeback_message = WritebackMessage.from_match_message_and_type( self.match_message, writeback ) event = {"Records": [{"body": writeback_message.to_aws_json()}]} result = lambda_handler(event, None) assert result == { "writebacks_performed": { "te": [ "Wrote back TruePositive for indicator 2862392437204724\nBuilt descriptor a1|2862392437204724 with privacy groups pg 4", "Wrote back TruePositive for indicator 4194946153908639\nBuilt descriptor a1|4194946153908639 with privacy groups pg 4", "No writeback performed for banked content id 3027465034605137 becuase writebacks were disabled", ] } } os.environ["MOCK_TE_API"] = "False"
def test_false_positive(self): os.environ["MOCK_TE_API"] = "True" os.environ["CONFIG_TABLE_NAME"] = "test-HMAConfig" writeback = WritebackTypes.FalsePositive writeback_message = WritebackMessage.from_match_message_and_type( self.match_message, writeback ) event = {"Records": [{"body": writeback_message.to_aws_json()}]} result = lambda_handler(event, None) assert result == { "writebacks_performed": { "te": [ "Reacted DISAGREE_WITH_TAGS to descriptor a2|2862392437204724\nReacted DISAGREE_WITH_TAGS to descriptor a3|2862392437204724", "Reacted DISAGREE_WITH_TAGS to descriptor a2|4194946153908639\nReacted DISAGREE_WITH_TAGS to descriptor a3|4194946153908639", "No writeback performed for banked content id 3027465034605137 becuase writebacks were disabled", ] } } os.environ["MOCK_TE_API"] = "False"
def request_signal_opinion_change() -> ChangeSignalOpinionResponse: """ request a change to the opinion for a signal in a dataset """ signal_id = bottle.request.query.signal_q or None signal_source = bottle.request.query.signal_source or None ds_id = bottle.request.query.dataset_q or None opinion_change = bottle.request.query.opinion_change or None if not signal_id or not signal_source or not ds_id or not opinion_change: return ChangeSignalOpinionResponse(False) signal_id = str(signal_id) pending_opinion_change = PendingOpinionChange(opinion_change) writeback_message = WritebackMessage.from_banked_signal_and_opinion_change( BankedSignal(signal_id, ds_id, signal_source), pending_opinion_change) writeback_message.send_to_queue() logger.info( f"Opinion change enqueued for {signal_source}:{signal_id} in {ds_id} change={opinion_change}" ) signal = PDQSignalMetadata( signal_id=signal_id, ds_id=ds_id, updated_at=datetime.datetime.now(), signal_source=signal_source, signal_hash="", # SignalHash not needed for update tags=[], # Tags not needed for update pending_opinion_change=pending_opinion_change, ) success = signal.update_pending_opinion_change_in_table_if_exists( dynamodb_table) if not success: logger.info(f"Attempting to update {signal} in db failed") return ChangeSignalOpinionResponse(success)
sources = { banked_signal.bank_source for banked_signal in writeback_message.banked_signals } source_writebackers = [ Writebacker.get_writebacker_for_source(source) for source in sources if Writebacker.get_writebacker_for_source(source) ] for writebacker in source_writebackers: result = writebacker.perform_writeback(writeback_message) logger.info("Writeback result: %s", result) writebacks_performed[writebacker.source] = result return {"writebacks_performed": writebacks_performed} if __name__ == "__main__": # For basic debugging # This will react to real descriptors if WRITEBACK_LOCAL is on if os.environ.get("WRITEBACK_LOCAL"): writeback_message = WritebackMessage( [ BankedSignal("2915547128556957", "303636684709969", "te"), ], WritebackTypes.RemoveOpinion, ) event = {"Records": [{"body": writeback_message.to_aws_json()}]} result = lambda_handler(event, None) print(result)