Check hash of message when determining if it is a new match

This commit is contained in:
Mark Veidemanis 2023-02-02 18:58:40 +00:00
parent 66596cda42
commit 0cbd2d8a6f
Signed by: m
GPG Key ID: 5ACFCEED46C0904F
2 changed files with 19 additions and 5 deletions

View File

@ -10,6 +10,7 @@ except ImportError:
import orjson import orjson
from asgiref.sync import async_to_sync from asgiref.sync import async_to_sync
from siphashc import siphash
from core.lib.notify import sendmsg from core.lib.notify import sendmsg
from core.lib.parsing import parse_index, parse_source from core.lib.parsing import parse_index, parse_source
@ -205,8 +206,13 @@ class NotificationRuleData(object):
Store a match result. Store a match result.
Accepts None for the index to set all indices. Accepts None for the index to set all indices.
:param index: the index to store the match for, can be None :param index: the index to store the match for, can be None
:param match: True or False, indicating if the rule matched :param match: the object that matched
""" """
if match is not False:
# Dump match to JSON while sorting the keys
match_normalised = orjson.dumps(match, option=orjson.OPT_SORT_KEYS)
match = siphash(self.db.hash_key, match_normalised)
if self.object.match is None: if self.object.match is None:
self.object.match = {} self.object.match = {}
if not isinstance(self.object.match, dict): if not isinstance(self.object.match, dict):
@ -220,7 +226,7 @@ class NotificationRuleData(object):
self.object.save() self.object.save()
log.debug(f"Stored match: {index} - {match}") log.debug(f"Stored match: {index} - {match}")
def get_match(self, index=None): def get_match(self, index=None, match=None):
""" """
Get a match result for an index. Get a match result for an index.
If the index is None, it will return True if any index has a match. If the index is None, it will return True if any index has a match.
@ -237,6 +243,13 @@ class NotificationRuleData(object):
# Check if we have any matches on all indices # Check if we have any matches on all indices
return any(self.object.match.values()) return any(self.object.match.values())
# Check if it's the same hash
if match is not None:
match_normalised = orjson.dumps(match, option=orjson.OPT_SORT_KEYS)
match = siphash(self.db.hash_key, match_normalised)
hash_matches = self.object.match.get(index) == match
return hash_matches
return self.object.match.get(index) return self.object.match.get(index)
def format_aggs(self, aggs): def format_aggs(self, aggs):
@ -268,13 +281,13 @@ class NotificationRuleData(object):
:param message: the message object that matched :param message: the message object that matched
:param aggs: the aggregations that matched :param aggs: the aggregations that matched
""" """
current_match = self.get_match(index) current_match = self.get_match(index, message)
log.debug(f"Rule matched: {index} - current match: {current_match}") log.debug(f"Rule matched: {index} - current match: {current_match}")
if current_match is False: if current_match is False:
# Matched now, but not before # Matched now, but not before
meta["matched"] = self.format_aggs(meta["aggs"]) meta["matched"] = self.format_aggs(meta["aggs"])
rule_notify(self.object, index, message, meta) rule_notify(self.object, index, message, meta)
self.store_match(index, True) self.store_match(index, message)
def rule_no_match(self, index=None): def rule_no_match(self, index=None):
""" """

View File

@ -203,7 +203,8 @@ class NotificationRule(models.Model):
Get the total number of matches for this rule. Get the total number of matches for this rule.
""" """
if isinstance(self.match, dict): if isinstance(self.match, dict):
return f"{sum(list(self.match.values()))}/{len(self.match)}" truthy_values = [x for x in self.match.values() if x is not False]
return f"{len(truthy_values)}/{len(self.match)}"
def get_notification_settings(self, check=True): def get_notification_settings(self, check=True):
""" """