mirror of https://gitlab.com/bashrc2/epicyon
Merge branch 'main' of ssh://code.freedombone.net:2222/bashrc/epicyon
commit
e6ca85c08e
72
daemon.py
72
daemon.py
|
|
@ -207,6 +207,7 @@ from shares import addShare
|
||||||
from shares import removeShare
|
from shares import removeShare
|
||||||
from shares import expireShares
|
from shares import expireShares
|
||||||
from categories import setHashtagCategory
|
from categories import setHashtagCategory
|
||||||
|
from utils import userAgentDomain
|
||||||
from utils import isLocalNetworkAddress
|
from utils import isLocalNetworkAddress
|
||||||
from utils import permittedDir
|
from utils import permittedDir
|
||||||
from utils import isAccountDir
|
from utils import isAccountDir
|
||||||
|
|
@ -452,37 +453,43 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
else:
|
else:
|
||||||
print('ERROR: unable to create vote')
|
print('ERROR: unable to create vote')
|
||||||
|
|
||||||
def _userAgentDomain(self) -> str:
|
def _blockedUserAgent(self, callingDomain: str) -> bool:
|
||||||
"""Returns the domain specified within User-Agent header
|
|
||||||
"""
|
|
||||||
if not self.headers.get('User-Agent'):
|
|
||||||
return None
|
|
||||||
agentStr = self.headers.get('User-Agent')
|
|
||||||
if '+' not in agentStr:
|
|
||||||
return None
|
|
||||||
agentDomain = agentStr.split('+')[1].strip()
|
|
||||||
if '://' in agentDomain:
|
|
||||||
agentDomain = agentDomain.split('://')[1]
|
|
||||||
if '/' in agentDomain:
|
|
||||||
agentDomain = agentDomain.split('/')[0]
|
|
||||||
if ' ' in agentDomain:
|
|
||||||
agentDomain = agentDomain.replace(' ', '')
|
|
||||||
if ';' in agentDomain:
|
|
||||||
agentDomain = agentDomain.replace(';', '')
|
|
||||||
if '.' not in agentDomain:
|
|
||||||
return None
|
|
||||||
return agentDomain
|
|
||||||
|
|
||||||
def _blockedUserAgent(self) -> bool:
|
|
||||||
"""Should a GET or POST be blocked based upon its user agent?
|
"""Should a GET or POST be blocked based upon its user agent?
|
||||||
"""
|
"""
|
||||||
agentDomain = self._userAgentDomain()
|
agentDomain = None
|
||||||
if not agentDomain:
|
agentStr = None
|
||||||
if self.server.userAgentDomainRequired:
|
if self.headers.get('User-Agent'):
|
||||||
|
agentStr = self.headers['User-Agent']
|
||||||
|
# is this a web crawler? If so the block it
|
||||||
|
agentStrLower = agentStr.lower()
|
||||||
|
if 'bot/' in agentStrLower or 'bot-' in agentStrLower:
|
||||||
|
print('Blocked Crawler: ' + agentStr)
|
||||||
return True
|
return True
|
||||||
|
# get domain name from User-Agent
|
||||||
|
agentDomain = userAgentDomain(agentStr, self.server.debug)
|
||||||
|
else:
|
||||||
|
# no User-Agent header is present
|
||||||
|
return True
|
||||||
|
|
||||||
|
# is the User-Agent type blocked? eg. "Mastodon"
|
||||||
|
if self.server.userAgentsBlocked:
|
||||||
|
blockedUA = False
|
||||||
|
for agentName in self.server.userAgentsBlocked:
|
||||||
|
if agentName in agentStr:
|
||||||
|
blockedUA = True
|
||||||
|
break
|
||||||
|
if blockedUA:
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not agentDomain:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# is the User-Agent domain blocked
|
||||||
|
blockedUA = False
|
||||||
|
if not agentDomain.startswith(callingDomain):
|
||||||
blockedUA = isBlockedDomain(self.server.baseDir, agentDomain)
|
blockedUA = isBlockedDomain(self.server.baseDir, agentDomain)
|
||||||
if blockedUA and self.server.debug:
|
# if self.server.debug:
|
||||||
|
if blockedUA:
|
||||||
print('Blocked User agent: ' + agentDomain)
|
print('Blocked User agent: ' + agentDomain)
|
||||||
return blockedUA
|
return blockedUA
|
||||||
|
|
||||||
|
|
@ -10628,7 +10635,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self._400()
|
self._400()
|
||||||
return
|
return
|
||||||
|
|
||||||
if self._blockedUserAgent():
|
if self._blockedUserAgent(callingDomain):
|
||||||
self._400()
|
self._400()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -14130,6 +14137,10 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self._400()
|
self._400()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if self._blockedUserAgent(callingDomain):
|
||||||
|
self._400()
|
||||||
|
return
|
||||||
|
|
||||||
self.server.POSTbusy = True
|
self.server.POSTbusy = True
|
||||||
if not self.headers.get('Content-type'):
|
if not self.headers.get('Content-type'):
|
||||||
print('Content-type header missing')
|
print('Content-type header missing')
|
||||||
|
|
@ -14881,7 +14892,7 @@ def loadTokens(baseDir: str, tokensDict: {}, tokensLookup: {}) -> None:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
def runDaemon(userAgentDomainRequired: bool,
|
def runDaemon(userAgentsBlocked: [],
|
||||||
logLoginFailures: bool,
|
logLoginFailures: bool,
|
||||||
city: str,
|
city: str,
|
||||||
showNodeInfoAccounts: bool,
|
showNodeInfoAccounts: bool,
|
||||||
|
|
@ -15008,9 +15019,8 @@ def runDaemon(userAgentDomainRequired: bool,
|
||||||
httpd.keyShortcuts = {}
|
httpd.keyShortcuts = {}
|
||||||
loadAccessKeysForAccounts(baseDir, httpd.keyShortcuts, httpd.accessKeys)
|
loadAccessKeysForAccounts(baseDir, httpd.keyShortcuts, httpd.accessKeys)
|
||||||
|
|
||||||
# if set to True then the calling domain must be specified
|
# list of blocked user agent types within the User-Agent header
|
||||||
# within the User-Agent header
|
httpd.userAgentsBlocked = userAgentsBlocked
|
||||||
httpd.userAgentDomainRequired = userAgentDomainRequired
|
|
||||||
|
|
||||||
httpd.unitTest = unitTest
|
httpd.unitTest = unitTest
|
||||||
httpd.allowLocalNetworkAccess = allowLocalNetworkAccess
|
httpd.allowLocalNetworkAccess = allowLocalNetworkAccess
|
||||||
|
|
|
||||||
26
epicyon.py
26
epicyon.py
|
|
@ -104,6 +104,9 @@ def str2bool(v) -> bool:
|
||||||
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description='ActivityPub Server')
|
parser = argparse.ArgumentParser(description='ActivityPub Server')
|
||||||
|
parser.add_argument('--userAgentBlocks', type=str,
|
||||||
|
default=None,
|
||||||
|
help='List of blocked user agents, separated by commas')
|
||||||
parser.add_argument('-n', '--nickname', dest='nickname', type=str,
|
parser.add_argument('-n', '--nickname', dest='nickname', type=str,
|
||||||
default=None,
|
default=None,
|
||||||
help='Nickname of the account to use')
|
help='Nickname of the account to use')
|
||||||
|
|
@ -274,12 +277,6 @@ parser.add_argument("--repliesEnabled", "--commentsEnabled",
|
||||||
type=str2bool, nargs='?',
|
type=str2bool, nargs='?',
|
||||||
const=True, default=True,
|
const=True, default=True,
|
||||||
help="Enable replies to a post")
|
help="Enable replies to a post")
|
||||||
parser.add_argument("--userAgentDomainRequired",
|
|
||||||
dest='userAgentDomainRequired',
|
|
||||||
type=str2bool, nargs='?',
|
|
||||||
const=True, default=False,
|
|
||||||
help="Whether User-Agent header must " +
|
|
||||||
"contain the calling domain")
|
|
||||||
parser.add_argument("--showPublishAsIcon",
|
parser.add_argument("--showPublishAsIcon",
|
||||||
dest='showPublishAsIcon',
|
dest='showPublishAsIcon',
|
||||||
type=str2bool, nargs='?',
|
type=str2bool, nargs='?',
|
||||||
|
|
@ -2522,10 +2519,17 @@ showNodeInfoVersion = \
|
||||||
if showNodeInfoVersion is not None:
|
if showNodeInfoVersion is not None:
|
||||||
args.showNodeInfoVersion = bool(showNodeInfoVersion)
|
args.showNodeInfoVersion = bool(showNodeInfoVersion)
|
||||||
|
|
||||||
userAgentDomainRequired = \
|
userAgentsBlocked = []
|
||||||
getConfigParam(baseDir, 'userAgentDomainRequired')
|
if args.userAgentBlocks:
|
||||||
if userAgentDomainRequired is not None:
|
userAgentsBlockedStr = args.userAgentBlocks
|
||||||
args.userAgentDomainRequired = bool(userAgentDomainRequired)
|
setConfigParam(baseDir, 'userAgentsBlocked', userAgentsBlockedStr)
|
||||||
|
else:
|
||||||
|
userAgentsBlockedStr = \
|
||||||
|
getConfigParam(baseDir, 'userAgentsBlocked')
|
||||||
|
if userAgentsBlockedStr:
|
||||||
|
agentBlocksList = userAgentsBlockedStr.split(',')
|
||||||
|
for agentBlockStr in agentBlocksList:
|
||||||
|
userAgentsBlocked.append(agentBlockStr.strip())
|
||||||
|
|
||||||
city = \
|
city = \
|
||||||
getConfigParam(baseDir, 'city')
|
getConfigParam(baseDir, 'city')
|
||||||
|
|
@ -2563,7 +2567,7 @@ if args.registration:
|
||||||
print('New registrations closed')
|
print('New registrations closed')
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
runDaemon(args.userAgentDomainRequired,
|
runDaemon(userAgentsBlocked,
|
||||||
args.logLoginFailures,
|
args.logLoginFailures,
|
||||||
args.city,
|
args.city,
|
||||||
args.showNodeInfoAccounts,
|
args.showNodeInfoAccounts,
|
||||||
|
|
|
||||||
26
tests.py
26
tests.py
|
|
@ -37,13 +37,14 @@ from follow import clearFollows
|
||||||
from follow import clearFollowers
|
from follow import clearFollowers
|
||||||
from follow import sendFollowRequestViaServer
|
from follow import sendFollowRequestViaServer
|
||||||
from follow import sendUnfollowRequestViaServer
|
from follow import sendUnfollowRequestViaServer
|
||||||
|
from siteactive import siteIsActive
|
||||||
|
from utils import userAgentDomain
|
||||||
from utils import camelCaseSplit
|
from utils import camelCaseSplit
|
||||||
from utils import decodedHost
|
from utils import decodedHost
|
||||||
from utils import getFullDomain
|
from utils import getFullDomain
|
||||||
from utils import validNickname
|
from utils import validNickname
|
||||||
from utils import firstParagraphFromString
|
from utils import firstParagraphFromString
|
||||||
from utils import removeIdEnding
|
from utils import removeIdEnding
|
||||||
from siteactive import siteIsActive
|
|
||||||
from utils import updateRecentPostsCache
|
from utils import updateRecentPostsCache
|
||||||
from utils import followPerson
|
from utils import followPerson
|
||||||
from utils import getNicknameFromActor
|
from utils import getNicknameFromActor
|
||||||
|
|
@ -519,9 +520,9 @@ def createServerAlice(path: str, domain: str, port: int,
|
||||||
showNodeInfoVersion = True
|
showNodeInfoVersion = True
|
||||||
city = 'London, England'
|
city = 'London, England'
|
||||||
logLoginFailures = False
|
logLoginFailures = False
|
||||||
userAgentDomainRequired = False
|
userAgentsBlocked = []
|
||||||
print('Server running: Alice')
|
print('Server running: Alice')
|
||||||
runDaemon(userAgentDomainRequired,
|
runDaemon(userAgentsBlocked,
|
||||||
logLoginFailures, city,
|
logLoginFailures, city,
|
||||||
showNodeInfoAccounts,
|
showNodeInfoAccounts,
|
||||||
showNodeInfoVersion,
|
showNodeInfoVersion,
|
||||||
|
|
@ -624,9 +625,9 @@ def createServerBob(path: str, domain: str, port: int,
|
||||||
showNodeInfoVersion = True
|
showNodeInfoVersion = True
|
||||||
city = 'London, England'
|
city = 'London, England'
|
||||||
logLoginFailures = False
|
logLoginFailures = False
|
||||||
userAgentDomainRequired = False
|
userAgentsBlocked = []
|
||||||
print('Server running: Bob')
|
print('Server running: Bob')
|
||||||
runDaemon(userAgentDomainRequired,
|
runDaemon(userAgentsBlocked,
|
||||||
logLoginFailures, city,
|
logLoginFailures, city,
|
||||||
showNodeInfoAccounts,
|
showNodeInfoAccounts,
|
||||||
showNodeInfoVersion,
|
showNodeInfoVersion,
|
||||||
|
|
@ -684,9 +685,9 @@ def createServerEve(path: str, domain: str, port: int, federationList: [],
|
||||||
showNodeInfoVersion = True
|
showNodeInfoVersion = True
|
||||||
city = 'London, England'
|
city = 'London, England'
|
||||||
logLoginFailures = False
|
logLoginFailures = False
|
||||||
userAgentDomainRequired = False
|
userAgentsBlocked = []
|
||||||
print('Server running: Eve')
|
print('Server running: Eve')
|
||||||
runDaemon(userAgentDomainRequired,
|
runDaemon(userAgentsBlocked,
|
||||||
logLoginFailures, city,
|
logLoginFailures, city,
|
||||||
showNodeInfoAccounts,
|
showNodeInfoAccounts,
|
||||||
showNodeInfoVersion,
|
showNodeInfoVersion,
|
||||||
|
|
@ -3938,10 +3939,21 @@ def _testRoles() -> None:
|
||||||
assert not actorHasRole(actorJson, "artist")
|
assert not actorHasRole(actorJson, "artist")
|
||||||
|
|
||||||
|
|
||||||
|
def _testUserAgentDomain() -> None:
|
||||||
|
print('testUserAgentDomain')
|
||||||
|
userAgent = \
|
||||||
|
'http.rb/4.4.1 (Mastodon/9.10.11; +https://mastodon.something/)'
|
||||||
|
assert userAgentDomain(userAgent, False) == 'mastodon.something'
|
||||||
|
userAgent = \
|
||||||
|
'Mozilla/70.0 (X11; Linux x86_64; rv:1.0) Gecko/20450101 Firefox/1.0'
|
||||||
|
assert userAgentDomain(userAgent, False) is None
|
||||||
|
|
||||||
|
|
||||||
def runAllTests():
|
def runAllTests():
|
||||||
print('Running tests...')
|
print('Running tests...')
|
||||||
updateDefaultThemesList(os.getcwd())
|
updateDefaultThemesList(os.getcwd())
|
||||||
_testFunctions()
|
_testFunctions()
|
||||||
|
_testUserAgentDomain()
|
||||||
_testRoles()
|
_testRoles()
|
||||||
_testSkills()
|
_testSkills()
|
||||||
_testSpoofGeolocation()
|
_testSpoofGeolocation()
|
||||||
|
|
|
||||||
24
utils.py
24
utils.py
|
|
@ -2433,3 +2433,27 @@ def permittedDir(path: str) -> bool:
|
||||||
path.startswith('/accounts'):
|
path.startswith('/accounts'):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def userAgentDomain(userAgent: str, debug: bool) -> str:
|
||||||
|
"""If the User-Agent string contains a domain
|
||||||
|
then return it
|
||||||
|
"""
|
||||||
|
if '+http' not in userAgent:
|
||||||
|
return None
|
||||||
|
agentDomain = userAgent.split('+http')[1].strip()
|
||||||
|
if '://' in agentDomain:
|
||||||
|
agentDomain = agentDomain.split('://')[1]
|
||||||
|
if '/' in agentDomain:
|
||||||
|
agentDomain = agentDomain.split('/')[0]
|
||||||
|
if ')' in agentDomain:
|
||||||
|
agentDomain = agentDomain.split(')')[0].strip()
|
||||||
|
if ' ' in agentDomain:
|
||||||
|
agentDomain = agentDomain.replace(' ', '')
|
||||||
|
if ';' in agentDomain:
|
||||||
|
agentDomain = agentDomain.replace(';', '')
|
||||||
|
if '.' not in agentDomain:
|
||||||
|
return None
|
||||||
|
if debug:
|
||||||
|
print('User-Agent Domain: ' + agentDomain)
|
||||||
|
return agentDomain
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue