From: Roland Häder Date: Mon, 26 Jun 2023 17:16:48 +0000 (+0200) Subject: Continued: X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=e1be335657c92533caffa48a18f4d458150007df;p=fba.git Continued: - added command recheck_obfuscation() to recheck if returned instance's obfuscated blocked peers can be de-obfuscated - I use array["fop"] outside strings and array['foo'] inside --- diff --git a/fba/boot.py b/fba/boot.py index eccd514..a8109fc 100644 --- a/fba/boot.py +++ b/fba/boot.py @@ -65,6 +65,13 @@ def init_parser(): ) parser.set_defaults(command=commands.fetch_bkali) + ### Recheck instance's obfuscated peers ### + parser = subparser_command.add_parser( + "recheck_obfuscation", + help="Checks all instance's obfuscated peers if they can be de-obfuscated now.", + ) + parser.set_defaults(command=commands.recheck_obfuscation) + ### Fetch blocks from registered instances or given ### parser = subparser_command.add_parser( "fetch_blocks", diff --git a/fba/commands.py b/fba/commands.py index c4b1d0a..82242df 100644 --- a/fba/commands.py +++ b/fba/commands.py @@ -140,10 +140,10 @@ def fetch_bkali(args: argparse.Namespace) -> int: logger.debug("fetched[]='%s'", type(fetched)) if "error_message" in fetched: - logger.warning("post_json_api() for 'gql.api.bka.li' returned error message='%s", fetched['error_message']) + logger.warning("post_json_api() for 'gql.api.bka.li' returned error message='%s", fetched["error_message"]) return 100 elif isinstance(fetched["json"], dict) and "error" in fetched["json"] and "message" in fetched["json"]["error"]: - logger.warning("post_json_api() returned error: '%s", fetched['error']['message']) + logger.warning("post_json_api() returned error: '%s", fetched["error"]["message"]) return 101 rows = fetched["json"] @@ -270,10 +270,11 @@ def fetch_blocks(args: argparse.Namespace) -> int: logger.warning("Unknown software: blocker='%s',software='%s'", blocker, software) logger.info("Checking %d entries from blocker='%s',software='%s' ...", len(blocking), blocker, software) + blockdict = list() for block in blocking: - logger.debug("blocked='%s',block_level='%s',reason='%s'", block["blocked"], block['block_level'], block["reason"]) + logger.debug("blocked='%s',block_level='%s',reason='%s'", block["blocked"], block["block_level"], block["reason"]) - if block['block_level'] == "": + if block["block_level"] == "": logger.warning("block_level is empty, blocker='%s',blocked='%s'", block["blocker"], block["blocked"]) continue @@ -285,7 +286,7 @@ def fetch_blocks(args: argparse.Namespace) -> int: if block["blocked"] == "": logger.warning("blocked is empty, blocker='%s'", blocker) continue - elif block["blocked"].count("*") > 0: + elif block["blocked"].count("*") >= 0: logger.debug("blocker='%s' uses obfuscated domains, marking ...", blocker) instances.set_has_obfuscation(blocker, True) @@ -300,7 +301,7 @@ def fetch_blocks(args: argparse.Namespace) -> int: block["blocked"] = row[0] origin = row[1] nodeinfo_url = row[2] - elif block["blocked"].count("?") > 0: + elif block["blocked"].count("?") >= 0: logger.debug("blocker='%s' uses obfuscated domains, marking ...", blocker) instances.set_has_obfuscation(blocker, True) @@ -320,21 +321,26 @@ def fetch_blocks(args: argparse.Namespace) -> int: if not utils.is_domain_wanted(block["blocked"]): logger.debug("blocked='%s' is not wanted - SKIPPED!", block["blocked"]) continue - elif block['block_level'] in ["accept", "accepted"]: + elif block["block_level"] in ["accept", "accepted"]: logger.debug("blocked='%s' is accepted, not wanted here - SKIPPED!", block["blocked"]) continue elif not instances.is_registered(block["blocked"]): logger.debug("Hash wasn't found, adding: blocked='%s',blocker='%s'", block["blocked"], blocker) federation.fetch_instances(block["blocked"], blocker, None, inspect.currentframe().f_code.co_name) - if block['block_level'] == "silence": + if block["block_level"] == "silence": logger.debug("Block level 'silence' has been changed to 'silenced'") - block['block_level'] = "silenced" - elif block['block_level'] == "suspend": + block["block_level"] = "silenced" + elif block["block_level"] == "suspend": logger.debug("Block level 'suspend' has been changed to 'suspended'") - block['block_level'] = "suspended" + block["block_level"] = "suspended" - utils.process_block(blocker, block['blocked'], block['reason'], block['block_level']) + if utils.process_block(blocker, block["blocked"], block["reason"], block["block_level"]) and block["block_level"] == "reject" and config.get("bot_enabled"): + logger.debug("Appending blocked='%s',reason='%s' for blocker='%s' ...", block["blocked"], block["block_level"], blocker) + blockdict.append({ + "blocked": block["blocked"], + "reason" : block["reason"], + }) logger.debug("Invoking cookies.clear(%s) ...", block["blocked"]) cookies.clear(block["blocked"]) @@ -352,7 +358,7 @@ def fetch_blocks(args: argparse.Namespace) -> int: logger.debug("config[bot_enabled]='%s',blockdict()=%d'", config.get("bot_enabled"), len(blockdict)) if config.get("bot_enabled") and len(blockdict) > 0: - logger.info("Sending bot POST for blocker='%s,blockdict()=%d ...", blocker, len(blockdict)) + logger.info("Sending bot POST for blocker='%s',blockdict()=%d ...", blocker, len(blockdict)) network.send_bot_post(blocker, blockdict) logger.debug("Success! - EXIT!") @@ -465,6 +471,7 @@ def fetch_todon_wiki(args: argparse.Namespace) -> int: logger.info("Checking %d suspended entries ...", len(suspended)) blocklist["reject"] = utils.find_domains(suspended, "div") + blockdict = list() for block_level in blocklist: blockers = blocklist[block_level] @@ -485,11 +492,20 @@ def fetch_todon_wiki(args: argparse.Namespace) -> int: continue logger.info("Adding new block: blocked='%s',block_level='%s'", blocked, block_level) - blocks.add_instance("todon.eu", blocked, None, block_level) + if utils.process_block("todon.eu", blocked, None, block_level) and block_level == "reject" and config.get("bot_enabled"): + logger.debug("Appending blocked='%s',reason='%s' for blocker='todon.eu' ...", block["blocked"], block["block_level"]) + blockdict.append({ + "blocked": blocked, + "reason" : None, + }) logger.debug("Invoking commit() ...") database.connection.commit() + if config.get("bot_enabled") and len(blockdict) > 0: + logger.info("Sending bot POST for blocker='todon.eu',blockdict()=%d ...", len(blockdict)) + network.send_bot_post("todon.eu", blockdict) + logger.debug("Success! - EXIT!") return 0 @@ -554,11 +570,20 @@ def fetch_cs(args: argparse.Namespace): logger.warning("Exception '%s' during fetching instances (fetch_cs) from row[domain]='%s'", type(exception), row["domain"]) instances.set_last_error(row["domain"], exception) - utils.process_block('chaos.social', row['domain'], row['reason'], block_level) + if utils.process_block("chaos.social", row["domain"], row["reason"], block_level) and block_level == "reject" and config.get("bot_enabled"): + logger.debug("Appending blocked='%s',reason='%s' for blocker='chaos.social' ...", row["domain"], block_level) + blockdict.append({ + "blocked": row["domain"], + "reason" : row["reason"], + }) logger.debug("Invoking commit() ...") database.connection.commit() + if config.get("bot_enabled") and len(blockdict) > 0: + logger.info("Sending bot POST for blocker='chaos.social',blockdict()=%d ...", len(blockdict)) + network.send_bot_post("chaos.social", blockdict) + logger.debug("Success! - EXIT!") return 0 @@ -772,7 +797,7 @@ def fetch_oliphant(args: argparse.Namespace) -> int: continue # Fetch this URL - logger.info("Fetching csv_url='%s' for blocker='%s' ...", block['csv_url'], block["blocker"]) + logger.info("Fetching csv_url='%s' for blocker='%s' ...", block["csv_url"], block["blocker"]) response = utils.fetch_url(f"{base_url}/{block['csv_url']}", network.web_headers, (config.get("connection_timeout"), config.get("read_timeout"))) logger.debug("response.ok='%s',response.status_code=%d,response.text()=%d", response.ok, response.status_code, len(response.text)) @@ -781,6 +806,7 @@ def fetch_oliphant(args: argparse.Namespace) -> int: reader = csv.DictReader(response.content.decode('utf-8').splitlines(), dialect="unix") logger.debug("reader[]='%s'", type(reader)) + blockdict = list() for row in reader: logger.debug("row[%s]='%s'", type(row), row) domain = severity = None @@ -823,11 +849,24 @@ def fetch_oliphant(args: argparse.Namespace) -> int: processed = utils.process_domain(domain, block["blocker"], inspect.currentframe().f_code.co_name) logger.debug("processed='%s'", processed) - utils.process_block(block['blocker'], domain, None, "reject") + if utils.process_block(block["blocker"], domain, None, "reject") and config.get("bot_enabled"): + logger.debug("Appending blocked='%s',reason='%s' for blocker='%s' ...", domain, block["block_level"], block["blocker"]) + blockdict.append({ + "blocked": domain, + "reason" : block["reason"], + }) + if reject_media: - utils.process_block(block['blocker'], domain, None, "reject_media") + utils.process_block(block["blocker"], domain, None, "reject_media") if reject_reports: - utils.process_block(block['blocker'], domain, None, "reject_reports") + utils.process_block(block["blocker"], domain, None, "reject_reports") + + logger.debug("Invoking commit() ...") + database.connection.commit() + + if config.get("bot_enabled") and len(blockdict) > 0: + logger.info("Sending bot POST for blocker='%s',blockdict()=%d ...", blocker, len(blockdict)) + network.send_bot_post(block["blocker"], blockdict) logger.debug("Success! - EXIT!") return 0 @@ -1040,8 +1079,13 @@ def fetch_joinfediverse(args: argparse.Namespace) -> int: logger.debug("blocked='%s' is not wanted - SKIPPED!", block["blocked"]) continue - logger.debug("blocked='%s',reason='%s'", block['blocked'], block['reason']) - utils.process_block(blocker, block['blocked'], block['reason'], "reject") + logger.debug("blocked='%s',reason='%s'", block["blocked"], block["reason"]) + if utils.process_block(blocker, block["blocked"], block["reason"], "reject") and config.get("bot_enabled"): + logger.debug("Appending blocked='%s',reason='%s' for blocker='%s' ...", block["blocked"], block["block_level"], blocker) + blockdict.append({ + "blocked": block["blocked"], + "reason" : block["reason"], + }) if instances.has_pending(blocker): logger.debug("Flushing updates for blocker='%s' ...", blocker) @@ -1050,10 +1094,96 @@ def fetch_joinfediverse(args: argparse.Namespace) -> int: logger.debug("Invoking commit() ...") database.connection.commit() - logger.debug("config[bot_enabled]='%s',blockdict()=%d'", config.get("bot_enabled"), len(blockdict)) - if config.get("bot_enabled") and len(blockdict) > 0: - logger.info("Sending bot POST for blocker='%s,blockdict()=%d ...", blocker, len(blockdict)) - network.send_bot_post(blocker, blockdict) + if config.get("bot_enabled") and len(blockdict) > 0: + logger.info("Sending bot POST for blocker='%s,blockdict()=%d ...", blocker, len(blockdict)) + network.send_bot_post(blocker, blockdict) + + logger.debug("Success! - EXIT!") + return 0 + +def recheck_obfuscation(args: argparse.Namespace) -> int: + logger.debug("args[]='%s' - CALLED!", type(args)) + + locking.acquire() + + database.cursor.execute("SELECT domain, software, nodeinfo_url FROM instances WHERE has_obfuscation = 1") + rows = database.cursor.fetchall() + logger.info("Checking %d domains ...", len(rows)) + for row in rows: + logger.debug("Fetching peers from domain='%s',software='%s',nodeinfo_url='%s' ...", row[0], row[1], row[2]) + + blocking = list() + if row[1] == "pleroma": + logger.debug("domain='%s',software='%s'", row[0], row[1]) + blocking = pleroma.fetch_blocks(row[0], row[2]) + elif row[1] == "mastodon": + logger.debug("domain='%s',software='%s'", row[0], row[1]) + blocking = mastodon.fetch_blocks(row[0], row[2]) + elif row[1] == "lemmy": + logger.debug("domain='%s',software='%s'", row[0], row[1]) + blocking = lemmy.fetch_blocks(row[0], row[2]) + elif row[1] == "friendica": + logger.debug("domain='%s',software='%s'", row[0], row[1]) + blocking = friendica.fetch_blocks(row[0]) + elif row[1] == "misskey": + logger.debug("domain='%s',software='%s'", row[0], row[1]) + blocking = misskey.fetch_blocks(row[0]) + else: + logger.warning("Unknown sofware: domain='%s',software='%s'", row[0], row[1]) + + logger.info("Checking %d block(s) from domain='%s' ...", len(blocking), row[0]) + obfuscated = 0 + for block in blocking: + logger.debug("blocked='%s'", block["blocked"]) + blocked = None + + if block["blocked"].endswith(".arpa"): + logger.debug("blocked='%s' is a reversed IP address - SKIPPED!", block["blocked"]) + continue + elif block["blocked"].endswith(".tld"): + logger.debug("blocked='%s' is a fake domain name - SKIPPED!", block["blocked"]) + continue + elif block["blocked"].endswith(".onion"): + logger.debug("blocked='%s' is a TOR onion domain name - SKIPPED!", block["blocked"]) + continue + elif block["blocked"].find("*") >= 0 or block["blocked"].find("?") >= 0: + logger.debug("block='%s' is obfuscated.", block["blocked"]) + obfuscated = obfuscated + 1 + blocked = utils.deobfuscate_domain(block["blocked"], row[0], block["hash"] if "hash" in block else None) + elif not utils.is_domain_wanted(block["blocked"]): + logger.debug("blocked='%s' is not wanted - SKIPPED!", block["blocked"]) + continue + elif blocks.is_instance_blocked(row[0], block["blocked"]): + logger.debug("blocked='%s' is already blocked - SKIPPED!", block["blocked"]) + continue + + if blocked is not None and blocked != block["blocked"]: + logger.debug("blocked='%s' was deobfuscated to blocked='%s'", block["blocked"], blocked) + obfuscated = obfuscated - 1 + if blocks.is_instance_blocked(row[0], blocked): + logger.debug("blocked='%s' is already blocked by domain='%s' - SKIPPED!", blocked, row[0]) + continue + + if block["block_level"] == "silence": + logger.debug("Block level 'silence' has been changed to 'silenced'") + block["block_level"] = "silenced" + elif block["block_level"] == "suspend": + logger.debug("Block level 'suspend' has been changed to 'suspended'") + block["block_level"] = "suspended" + + logger.info("blocked='%s' has been deobfuscated to blocked='%s', adding ...", block["blocked"], blocked) + if utils.process_block(row[0], blocked, block["reason"], block["block_level"]) and block["block_level"] == "reject" and config.get("bot_enabled"): + logger.debug("Appending blocked='%s',reason='%s' for blocker='%s' ...", block["blocked"], block["block_level"], blocker) + blockdict.append({ + "blocked": block["blocked"], + "reason" : block["reason"], + }) + + logger.info("domain='%s' has %d obfuscated domain(s)", row[0], obfuscated) + if obfuscated == 0 and len(blocking) > 0: + logger.info("Block list from domain='%s' has been fully deobfuscated.", row[0]) + instances.set_has_obfuscation(row[0], False) + instances.update_data(row[0]) logger.debug("Success! - EXIT!") return 0 diff --git a/fba/helpers/software.py b/fba/helpers/software.py index 1987871..2308d2c 100644 --- a/fba/helpers/software.py +++ b/fba/helpers/software.py @@ -24,7 +24,7 @@ logger = logging.getLogger(__name__) def alias(software: str) -> str: logger.debug("software='%s'- CALLED!", software) if not isinstance(software, str) and software is not None: - raise ValueError(f"software[]='%s' is not type 'str'") + raise ValueError(f"software[]='{type(software)}' is not type 'str'") logger.debug("software='%s'- BEFORE!", software) software = tidyup.domain(software) diff --git a/fba/http/federation.py b/fba/http/federation.py index 2fa7561..e203c16 100644 --- a/fba/http/federation.py +++ b/fba/http/federation.py @@ -241,6 +241,7 @@ def fetch_nodeinfo(domain: str, path: str = None) -> dict: "/nodeinfo/2.1", "/nodeinfo/2.0.json", "/nodeinfo/2.0", + "/nodeinfo/1.0.json", "/nodeinfo/1.0", "/api/v1/instance", ] diff --git a/fba/http/network.py b/fba/http/network.py index d15b563..fdb5dcf 100644 --- a/fba/http/network.py +++ b/fba/http/network.py @@ -263,14 +263,16 @@ def json_from_response(response: requests.models.Response) -> list: logger.debug("response[]='%s' - CALLED!", type(response)) if not isinstance(response, requests.models.Response): raise ValueError(f"Parameter response[]='{type(response)}' is not type of 'Response'") + elif response.headers.get("content-type") != "application/json": + logger.warning("response.headers[content-type]='%s' is not a JSON type, below json() invocation may raise an exception", response.headers.get("content-type")) data = list() if response.text.strip() != "": logger.debug("response.text()=%d is not empty, invoking response.json() ...", len(response.text)) try: data = response.json() - except json.decoder.JSONDecodeError: - pass + except json.decoder.JSONDecodeError as exception: + logger.warning("Exception '%s' during decoding JSON", type(exception)) logger.debug("data[]='%s' - EXIT!", type(data)) return data diff --git a/fba/models/blocks.py b/fba/models/blocks.py index 2f66445..ec4fed2 100644 --- a/fba/models/blocks.py +++ b/fba/models/blocks.py @@ -95,7 +95,7 @@ def update_last_seen(blocker: str, blocked: str, block_level: str): logger.debug("EXIT!") -def is_instance_blocked(blocker: str, blocked: str, block_level: str) -> bool: +def is_instance_blocked(blocker: str, blocked: str, block_level: str = None) -> bool: logger.debug("blocker='%s',blocked='%s',block_level='%s' - CALLED!", blocker, blocked, block_level) if not isinstance(blocker, str): raise ValueError(f"Parameter blocker[]='{type(blocker)}' is not of type 'str'") @@ -109,21 +109,30 @@ def is_instance_blocked(blocker: str, blocked: str, block_level: str) -> bool: raise ValueError("Parameter 'blocked' is empty") elif blocked.lower() != blocked: raise ValueError(f"Parameter blocked='{blocked}' must be all lower-case") - elif not isinstance(block_level, str): + elif not isinstance(block_level, str) and block_level is not None: raise ValueError(f"Parameter block_level[]='{type(block_level)}' is not of type 'str'") elif block_level == "": raise ValueError("Parameter 'block_level' is empty") elif block_level in ["accept", "suspend", "silence"]: raise ValueError(f"blocked='{blocked}' has unwanted block_level='{block_level}'") - database.cursor.execute( - "SELECT * FROM blocks WHERE blocker = ? AND blocked = ? AND block_level = ? LIMIT 1", - ( - blocker, - blocked, - block_level - ), - ) + if block_level is None: + database.cursor.execute( + "SELECT * FROM blocks WHERE blocker = ? AND blocked = ? LIMIT 1", + [ + blocker, + blocked + ] + ) + else: + database.cursor.execute( + "SELECT * FROM blocks WHERE blocker = ? AND blocked = ? AND block_level = ? LIMIT 1", + [ + blocker, + blocked, + block_level + ] + ) is_blocked = database.cursor.fetchone() is not None diff --git a/fba/networks/mastodon.py b/fba/networks/mastodon.py index 7402ee5..fcfbc6e 100644 --- a/fba/networks/mastodon.py +++ b/fba/networks/mastodon.py @@ -180,7 +180,7 @@ def fetch_blocks(domain: str, nodeinfo_url: str) -> list: rows = fetch_blocks_from_about(domain) if len(rows) > 0: - logger.info("Checking %d entries from domain='%s' ...", len(rows), domain) + logger.debug("Checking %d entries from domain='%s' ...", len(rows), domain) for block in rows: # Check type logger.debug("block[]='%s'", type(block)) @@ -188,9 +188,9 @@ def fetch_blocks(domain: str, nodeinfo_url: str) -> list: logger.debug("block[]='%s' is of type 'dict' - SKIPPED!", type(block)) continue - reason = tidyup.reason(block["comment"]) if "comment" in block and block['comment'] is not None and block['comment'] != "" else None + reason = tidyup.reason(block["comment"]) if "comment" in block and block["comment"] is not None and block["comment"] != "" else None - logger.debug("Appending blocker='%s',blocked='%s',reason='%s',block_level='%s'", domain, block['domain'], reason, block['severity']) + logger.debug("Appending blocker='%s',blocked='%s',reason='%s',block_level='%s'", domain, block["domain"], reason, block["severity"]) blocklist.append({ "blocker" : domain, "blocked" : block["domain"], diff --git a/fba/utils.py b/fba/utils.py index 7ef3e01..8814ea1 100644 --- a/fba/utils.py +++ b/fba/utils.py @@ -179,28 +179,34 @@ def is_domain_wanted(domain: str) -> bool: logger.debug("wanted='%s' - EXIT!", wanted) return wanted -def deobfuscate_domain(domain: str, blocker: str) -> str: - logger.debug("domain='%s',blocker='%s' - CALLED!", domain, blocker) - domain_helper.raise_on(domain) +def deobfuscate_domain(domain: str, blocker: str, domain_hash: str = None) -> str: + logger.debug("domain='%s',blocker='%s',domain_hash='%s' - CALLED!", domain, blocker, domain_hash) domain_helper.raise_on(blocker) - if domain.count("*") > 0: + if not isinstance(domain, str): + raise ValueError(f"Parameter domain[]='{type(domain)}' is not of type 'str'") + elif domain == "": + raise ValueError("Parameter domain is empty") + elif not isinstance(domain_hash, str) and domain_hash is not None: + raise ValueError(f"Parameter domain_hash[]='{type(domain_hash)}' is not of type 'str'") + + if domain.count("*") >= 0: logger.debug("blocker='%s' uses obfuscated domains, marking ...", blocker) instances.set_has_obfuscation(blocker, True) # Obscured domain name with no hash - row = instances.deobfuscate("*", domain) + row = instances.deobfuscate("*", domain, domain_hash) logger.debug("row[]='%s'", type(row)) if row is not None: logger.debug("domain='%s' de-obscured to '%s'", domain, row[0]) domain = row[0] - elif domain.count("?") > 0: + elif domain.count("?") >= 0: logger.debug("blocker='%s' uses obfuscated domains, marking ...", blocker) instances.set_has_obfuscation(blocker, True) # Obscured domain name with no hash - row = instances.deobfuscate("?", domain) + row = instances.deobfuscate("?", domain, domain_hash) logger.debug("row[]='%s'", type(row)) if row is not None: @@ -212,29 +218,27 @@ def deobfuscate_domain(domain: str, blocker: str) -> str: logger.debug("domain='%s' - EXIT!", domain) return domain -def process_block(blocker: str, blocked: str, reason: str, block_level: str): +def process_block(blocker: str, blocked: str, reason: str, block_level: str) -> bool: logger.debug("blocker='%s',blocked='%s',reason='%s',block_level='%s' - CALLED!", blocker, blocked, reason, block_level) domain_helper.raise_on(blocker) domain_helper.raise_on(blocked) + procesed = False if not isinstance(reason, str) and reason is not None: - raise ValueError("Parameter reason[]='%s' is not of type 'str'", type(reason)) + raise ValueError(f"Parameter reason[]='{type(reason)}' is not of type 'str'") elif not isinstance(block_level, str): - raise ValueError("Parameter block_level[]='%s' is not of type 'str'", type(block_level)) + raise ValueError(f"Parameter block_level[]='{type(block_level)}' is not of type 'str'") elif block_level == "": raise ValueError("Parameter block_level is empty") if not blocks.is_instance_blocked(blocker, blocked, block_level): - logger.debug("Invoking blocks.add_instance(%s, %s, %s, %s)", blocker, blocked, reason, block_level) + logger.debug("Invoking blocks.add_instance(%s, %s, %s, %s) ...", blocker, blocked, reason, block_level) blocks.add_instance(blocker, blocked, reason, block_level) - - logger.debug("block_level='%s',config[bot_enabled]='%s'", block_level, config.get("bot_enabled")) - if config.get("bot_enabled"): - logger.debug("blocker='%s' has blocked '%s' with reason='%s' - Adding to bot notification ...", blocker, blocked, reason) - blockdict.append({ - "blocked": blocked, - "reason" : reason, - }) + added = True else: logger.debug("Updating block last seen and reason for blocker='%s',blocked='%s' ...", blocker, blocked) blocks.update_last_seen(blocker, blocked, block_level) + + logger.debug("added='%s' - EXIT!", added) + return procesed + \ No newline at end of file