diff --git a/blocking.py b/blocking.py index 206682efc..53346c136 100644 --- a/blocking.py +++ b/blocking.py @@ -9,6 +9,7 @@ __module_group__ = "ActivityPub" import os import json +import time from datetime import datetime from utils import isAccountDir from utils import getCachedPostFilename @@ -167,7 +168,32 @@ def getDomainBlocklist(baseDir: str) -> str: return blockedStr -def isBlockedDomain(baseDir: str, domain: str) -> bool: +def updateBlockedCache(baseDir: str, + blockedCache: [], + blockedCacheLastUpdated: int, + blockedCacheUpdateSecs: int) -> int: + """Updates the cache of globally blocked domains held in memory + """ + currTime = int(time.time()) + if blockedCacheLastUpdated > currTime: + print('WARN: Cache updated in the future') + blockedCacheLastUpdated = 0 + secondsSinceLastUpdate = currTime - blockedCacheLastUpdated + if secondsSinceLastUpdate < blockedCacheUpdateSecs: + return blockedCacheLastUpdated + globalBlockingFilename = baseDir + '/accounts/blocking.txt' + if not os.path.isfile(globalBlockingFilename): + return blockedCacheLastUpdated + with open(globalBlockingFilename, 'r') as fpBlocked: + blockedLines = fpBlocked.readlines() + blockedCache.clear() + for line in blockedLines: + blockedCache.append(line.replace('\n', '')) + return currTime + + +def isBlockedDomain(baseDir: str, domain: str, + blockedCache: [] = None) -> bool: """Is the given domain blocked? """ if '.' not in domain: @@ -186,16 +212,24 @@ def isBlockedDomain(baseDir: str, domain: str) -> bool: allowFilename = baseDir + '/accounts/allowedinstances.txt' if not os.path.isfile(allowFilename): - # instance block list - globalBlockingFilename = baseDir + '/accounts/blocking.txt' - if os.path.isfile(globalBlockingFilename): - with open(globalBlockingFilename, 'r') as fpBlocked: - blockedStr = fpBlocked.read() + if blockedCache: + for blockedStr in blockedCache: if '*@' + domain in blockedStr: return True if shortDomain: if '*@' + shortDomain in blockedStr: return True + else: + # instance block list + globalBlockingFilename = baseDir + '/accounts/blocking.txt' + if os.path.isfile(globalBlockingFilename): + with open(globalBlockingFilename, 'r') as fpBlocked: + blockedStr = fpBlocked.read() + if '*@' + domain in blockedStr: + return True + if shortDomain: + if '*@' + shortDomain in blockedStr: + return True else: # instance allow list if not shortDomain: diff --git a/daemon.py b/daemon.py index 955bebeee..b53021918 100644 --- a/daemon.py +++ b/daemon.py @@ -114,6 +114,7 @@ from media import attachMedia from media import pathIsImage from media import pathIsVideo from media import pathIsAudio +from blocking import updateBlockedCache from blocking import mutePost from blocking import unmutePost from blocking import setBrochMode @@ -487,7 +488,14 @@ class PubServer(BaseHTTPRequestHandler): # is the User-Agent domain blocked blockedUA = False if not agentDomain.startswith(callingDomain): - blockedUA = isBlockedDomain(self.server.baseDir, agentDomain) + self.server.blockedCacheLastUpdated = \ + updateBlockedCache(self.server.baseDir, + self.server.blockedCache, + self.server.blockedCacheLastUpdated, + self.server.blockedCacheUpdateSecs) + + blockedUA = isBlockedDomain(self.server.baseDir, agentDomain, + self.server.blockedCache) # if self.server.debug: if blockedUA: print('Blocked User agent: ' + agentDomain) @@ -1212,7 +1220,15 @@ class PubServer(BaseHTTPRequestHandler): messageDomain, messagePort = \ getDomainFromActor(messageJson['actor']) - if isBlockedDomain(self.server.baseDir, messageDomain): + + self.server.blockedCacheLastUpdated = \ + updateBlockedCache(self.server.baseDir, + self.server.blockedCache, + self.server.blockedCacheLastUpdated, + self.server.blockedCacheUpdateSecs) + + if isBlockedDomain(self.server.baseDir, messageDomain, + self.server.blockedCache): print('POST from blocked domain ' + messageDomain) self._400() self.server.POSTbusy = False @@ -15180,6 +15196,16 @@ def runDaemon(userAgentsBlocked: [], # contains threads used to send posts to followers httpd.followersThreads = [] + # create a cache of blocked domains in memory. + # This limits the amount of slow disk reads which need to be done + httpd.blockedCache = [] + httpd.blockedCacheLastUpdated = 0 + httpd.blockedCacheUpdateSecs = 120 + httpd.blockedCacheLastUpdated = \ + updateBlockedCache(baseDir, httpd.blockedCache, + httpd.blockedCacheLastUpdated, + httpd.blockedCacheUpdateSecs) + # cache to store css files httpd.cssCache = {} diff --git a/utils.py b/utils.py index ad277004b..fd159e8af 100644 --- a/utils.py +++ b/utils.py @@ -1441,7 +1441,9 @@ def _isReservedName(nickname: str) -> bool: 'shares', 'fonts', 'icons', 'avatars', 'welcome', 'helpimages', 'bookmark', 'bookmarks', 'tlbookmarks', - 'ignores') + 'ignores', 'linksmobile', 'newswiremobile', + 'minimal', 'search', 'eventdelete', + 'searchemoji') if nickname in reservedNames: return True return False