forked from indymedia/epicyon
Hellthread mitigation
parent
11f6655530
commit
865b4c3ce9
|
@ -3939,7 +3939,8 @@ def runDaemon(projectVersion, \
|
||||||
instanceId,clientToServer: bool, \
|
instanceId,clientToServer: bool, \
|
||||||
baseDir: str,domain: str, \
|
baseDir: str,domain: str, \
|
||||||
port=80,proxyPort=80,httpPrefix='https', \
|
port=80,proxyPort=80,httpPrefix='https', \
|
||||||
fedList=[],authenticatedFetch=False, \
|
fedList=[],maxMentions=10, \
|
||||||
|
authenticatedFetch=False, \
|
||||||
noreply=False,nolike=False,nopics=False, \
|
noreply=False,nolike=False,nopics=False, \
|
||||||
noannounce=False,cw=False,ocapAlways=False, \
|
noannounce=False,cw=False,ocapAlways=False, \
|
||||||
useTor=False,maxReplies=64, \
|
useTor=False,maxReplies=64, \
|
||||||
|
@ -4078,7 +4079,8 @@ def runDaemon(projectVersion, \
|
||||||
domain,port,useTor,httpd.federationList, \
|
domain,port,useTor,httpd.federationList, \
|
||||||
httpd.ocapAlways,maxReplies, \
|
httpd.ocapAlways,maxReplies, \
|
||||||
domainMaxPostsPerDay,accountMaxPostsPerDay, \
|
domainMaxPostsPerDay,accountMaxPostsPerDay, \
|
||||||
allowDeletion,debug,httpd.acceptedCaps),daemon=True)
|
allowDeletion,debug,maxMentions, \
|
||||||
|
httpd.acceptedCaps),daemon=True)
|
||||||
if not unitTest:
|
if not unitTest:
|
||||||
httpd.thrWatchdog= \
|
httpd.thrWatchdog= \
|
||||||
threadWithTrace(target=runInboxQueueWatchdog, \
|
threadWithTrace(target=runInboxQueueWatchdog, \
|
||||||
|
|
10
epicyon.py
10
epicyon.py
|
@ -223,6 +223,8 @@ parser.add_argument("-c","--client", type=str2bool, nargs='?', \
|
||||||
help="Use as an ActivityPub client")
|
help="Use as an ActivityPub client")
|
||||||
parser.add_argument('--maxreplies', dest='maxReplies', type=int,default=64, \
|
parser.add_argument('--maxreplies', dest='maxReplies', type=int,default=64, \
|
||||||
help='Maximum number of replies to a post')
|
help='Maximum number of replies to a post')
|
||||||
|
parser.add_argument('--maxMentions','--hellthread', dest='maxMentions', type=int,default=10, \
|
||||||
|
help='Maximum number of mentions within a post')
|
||||||
parser.add_argument('--role', dest='role', type=str,default=None, \
|
parser.add_argument('--role', dest='role', type=str,default=None, \
|
||||||
help='Set a role for a person')
|
help='Set a role for a person')
|
||||||
parser.add_argument('--organization','--project', dest='project', type=str,default=None, \
|
parser.add_argument('--organization','--project', dest='project', type=str,default=None, \
|
||||||
|
@ -1335,10 +1337,16 @@ if args.testdata:
|
||||||
followerOfPerson(baseDir,nickname,domain,'maxboardroom',domainFull,federationList,False)
|
followerOfPerson(baseDir,nickname,domain,'maxboardroom',domainFull,federationList,False)
|
||||||
setConfigParam(baseDir,'admin',nickname)
|
setConfigParam(baseDir,'admin',nickname)
|
||||||
|
|
||||||
|
# set a lower bound to the maximum mentions
|
||||||
|
# so that it can't be accidentally set to zero and disable replies
|
||||||
|
if args.maxMentions<4:
|
||||||
|
args.maxMentions=4
|
||||||
|
|
||||||
runDaemon(__version__, \
|
runDaemon(__version__, \
|
||||||
instanceId,args.client,baseDir, \
|
instanceId,args.client,baseDir, \
|
||||||
domain,port,proxyPort,httpPrefix, \
|
domain,port,proxyPort,httpPrefix, \
|
||||||
federationList,args.authenticatedFetch, \
|
federationList,args.maxMentions, \
|
||||||
|
args.authenticatedFetch, \
|
||||||
args.noreply,args.nolike,args.nopics, \
|
args.noreply,args.nolike,args.nopics, \
|
||||||
args.noannounce,args.cw,ocapAlways, \
|
args.noannounce,args.cw,ocapAlways, \
|
||||||
useTor,args.maxReplies, \
|
useTor,args.maxReplies, \
|
||||||
|
|
36
inbox.py
36
inbox.py
|
@ -1096,8 +1096,20 @@ def populateReplies(baseDir :str,httpPrefix :str,domain :str, \
|
||||||
repliesFile.close()
|
repliesFile.close()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def validPostContent(messageJson: {}) -> bool:
|
def estimateNumberOfMentions(content: str) -> int:
|
||||||
|
"""Returns a rough estimate of the number of mentions
|
||||||
|
"""
|
||||||
|
words=content.split(' ')
|
||||||
|
ctr=0
|
||||||
|
for word in words:
|
||||||
|
if word.startswith('@') or '>@' in word:
|
||||||
|
ctr+=1
|
||||||
|
return ctr
|
||||||
|
|
||||||
|
def validPostContent(messageJson: {},maxMentions: int) -> bool:
|
||||||
"""Is the content of a received post valid?
|
"""Is the content of a received post valid?
|
||||||
|
Check for bad html
|
||||||
|
Check for hellthreads
|
||||||
"""
|
"""
|
||||||
if not messageJson.get('object'):
|
if not messageJson.get('object'):
|
||||||
return True
|
return True
|
||||||
|
@ -1112,6 +1124,9 @@ def validPostContent(messageJson: {}) -> bool:
|
||||||
print('REJECT: '+messageJson['object']['id'])
|
print('REJECT: '+messageJson['object']['id'])
|
||||||
print('REJECT: bad string in post - '+messageJson['object']['content'])
|
print('REJECT: bad string in post - '+messageJson['object']['content'])
|
||||||
return False
|
return False
|
||||||
|
if estimateNumberOfMentions(messageJson['object']['content'])>maxMentions:
|
||||||
|
print('REJECT: Too many mentions in post - '+messageJson['object']['content'])
|
||||||
|
return False
|
||||||
print('ACCEPT: post content is valid')
|
print('ACCEPT: post content is valid')
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -1120,9 +1135,10 @@ def inboxAfterCapabilities(session,keyId: str,handle: str,messageJson: {}, \
|
||||||
postLog: [],cachedWebfingers: {},personCache: {}, \
|
postLog: [],cachedWebfingers: {},personCache: {}, \
|
||||||
queue: [],domain: str,port: int,useTor: bool, \
|
queue: [],domain: str,port: int,useTor: bool, \
|
||||||
federationList: [],ocapAlways: bool,debug: bool, \
|
federationList: [],ocapAlways: bool,debug: bool, \
|
||||||
acceptedCaps: [],
|
acceptedCaps: [], \
|
||||||
queueFilename :str,destinationFilename :str,
|
queueFilename :str,destinationFilename :str, \
|
||||||
maxReplies: int,allowDeletion: bool) -> bool:
|
maxReplies: int,allowDeletion: bool, \
|
||||||
|
maxMentions: int) -> bool:
|
||||||
""" Anything which needs to be done after capabilities checks have passed
|
""" Anything which needs to be done after capabilities checks have passed
|
||||||
"""
|
"""
|
||||||
actor=keyId
|
actor=keyId
|
||||||
|
@ -1203,11 +1219,11 @@ def inboxAfterCapabilities(session,keyId: str,handle: str,messageJson: {}, \
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if messageJson.get('postNickname'):
|
if messageJson.get('postNickname'):
|
||||||
if validPostContent(messageJson['post']):
|
if validPostContent(messageJson['post'],maxMentions):
|
||||||
with open(destinationFilename, 'w+') as fp:
|
with open(destinationFilename, 'w+') as fp:
|
||||||
commentjson.dump(messageJson['post'], fp, indent=4, sort_keys=False)
|
commentjson.dump(messageJson['post'], fp, indent=4, sort_keys=False)
|
||||||
else:
|
else:
|
||||||
if validPostContent(messageJson):
|
if validPostContent(messageJson,maxMentions):
|
||||||
with open(destinationFilename, 'w+') as fp:
|
with open(destinationFilename, 'w+') as fp:
|
||||||
commentjson.dump(messageJson, fp, indent=4, sort_keys=False)
|
commentjson.dump(messageJson, fp, indent=4, sort_keys=False)
|
||||||
|
|
||||||
|
@ -1251,7 +1267,7 @@ def runInboxQueue(projectVersion: str, \
|
||||||
domain: str,port: int,useTor: bool,federationList: [], \
|
domain: str,port: int,useTor: bool,federationList: [], \
|
||||||
ocapAlways: bool,maxReplies: int, \
|
ocapAlways: bool,maxReplies: int, \
|
||||||
domainMaxPostsPerDay: int,accountMaxPostsPerDay: int, \
|
domainMaxPostsPerDay: int,accountMaxPostsPerDay: int, \
|
||||||
allowDeletion: bool,debug: bool, \
|
allowDeletion: bool,debug: bool,maxMentions: int, \
|
||||||
acceptedCaps=["inbox:write","objects:read"]) -> None:
|
acceptedCaps=["inbox:write","objects:read"]) -> None:
|
||||||
"""Processes received items and moves them to
|
"""Processes received items and moves them to
|
||||||
the appropriate directories
|
the appropriate directories
|
||||||
|
@ -1578,7 +1594,8 @@ def runInboxQueue(projectVersion: str, \
|
||||||
federationList,ocapAlways, \
|
federationList,ocapAlways, \
|
||||||
debug,acceptedCaps, \
|
debug,acceptedCaps, \
|
||||||
queueFilename,destination, \
|
queueFilename,destination, \
|
||||||
maxReplies,allowDeletion)
|
maxReplies,allowDeletion, \
|
||||||
|
maxMentions)
|
||||||
else:
|
else:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: object capabilities check has failed')
|
print('DEBUG: object capabilities check has failed')
|
||||||
|
@ -1595,7 +1612,8 @@ def runInboxQueue(projectVersion: str, \
|
||||||
federationList,ocapAlways, \
|
federationList,ocapAlways, \
|
||||||
debug,acceptedCaps, \
|
debug,acceptedCaps, \
|
||||||
queueFilename,destination, \
|
queueFilename,destination, \
|
||||||
maxReplies,allowDeletion)
|
maxReplies,allowDeletion, \
|
||||||
|
maxMentions)
|
||||||
if debug:
|
if debug:
|
||||||
pprint(queueJson['post'])
|
pprint(queueJson['post'])
|
||||||
print('No capability list within post')
|
print('No capability list within post')
|
||||||
|
|
2
posts.py
2
posts.py
|
@ -461,7 +461,6 @@ def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \
|
||||||
nickname,domain,content, \
|
nickname,domain,content, \
|
||||||
mentionedRecipients, \
|
mentionedRecipients, \
|
||||||
hashtagsDict)
|
hashtagsDict)
|
||||||
print('Content tagging stage 1: '+content)
|
|
||||||
|
|
||||||
statusNumber,published = getStatusNumber()
|
statusNumber,published = getStatusNumber()
|
||||||
postTo='https://www.w3.org/ns/activitystreams#Public'
|
postTo='https://www.w3.org/ns/activitystreams#Public'
|
||||||
|
@ -504,7 +503,6 @@ def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \
|
||||||
updateHashtagsIndex(baseDir,tag,newPostId)
|
updateHashtagsIndex(baseDir,tag,newPostId)
|
||||||
print('Content tags: '+str(tags))
|
print('Content tags: '+str(tags))
|
||||||
content=replaceEmojiFromTags(content,tags,'content')
|
content=replaceEmojiFromTags(content,tags,'content')
|
||||||
print('Content tagging stage 2: '+content)
|
|
||||||
|
|
||||||
if not clientToServer:
|
if not clientToServer:
|
||||||
actorUrl=httpPrefix+'://'+domain+'/users/'+nickname
|
actorUrl=httpPrefix+'://'+domain+'/users/'+nickname
|
||||||
|
|
9
tests.py
9
tests.py
|
@ -216,9 +216,10 @@ def createServerAlice(path: str,domain: str,port: int,federationList: [], \
|
||||||
False, True, clientToServer,None,None,useBlurhash)
|
False, True, clientToServer,None,None,useBlurhash)
|
||||||
global testServerAliceRunning
|
global testServerAliceRunning
|
||||||
testServerAliceRunning = True
|
testServerAliceRunning = True
|
||||||
|
maxMentions=10
|
||||||
print('Server running: Alice')
|
print('Server running: Alice')
|
||||||
runDaemon(__version__,"instanceId",False,path,domain,port,port, \
|
runDaemon(__version__,"instanceId",False,path,domain,port,port, \
|
||||||
httpPrefix,federationList,False, \
|
httpPrefix,federationList,maxMentions,False, \
|
||||||
noreply,nolike,nopics,noannounce,cw,ocapAlways, \
|
noreply,nolike,nopics,noannounce,cw,ocapAlways, \
|
||||||
useTor,maxReplies, \
|
useTor,maxReplies, \
|
||||||
domainMaxPostsPerDay,accountMaxPostsPerDay, \
|
domainMaxPostsPerDay,accountMaxPostsPerDay, \
|
||||||
|
@ -269,9 +270,10 @@ def createServerBob(path: str,domain: str,port: int,federationList: [], \
|
||||||
False, True, clientToServer,None,None,useBlurhash)
|
False, True, clientToServer,None,None,useBlurhash)
|
||||||
global testServerBobRunning
|
global testServerBobRunning
|
||||||
testServerBobRunning = True
|
testServerBobRunning = True
|
||||||
|
maxMentions=10
|
||||||
print('Server running: Bob')
|
print('Server running: Bob')
|
||||||
runDaemon(__version__,"instanceId",False,path,domain,port,port, \
|
runDaemon(__version__,"instanceId",False,path,domain,port,port, \
|
||||||
httpPrefix,federationList,False, \
|
httpPrefix,federationList,maxMentions,False, \
|
||||||
noreply,nolike,nopics,noannounce,cw,ocapAlways, \
|
noreply,nolike,nopics,noannounce,cw,ocapAlways, \
|
||||||
useTor,maxReplies, \
|
useTor,maxReplies, \
|
||||||
domainMaxPostsPerDay,accountMaxPostsPerDay, \
|
domainMaxPostsPerDay,accountMaxPostsPerDay, \
|
||||||
|
@ -302,9 +304,10 @@ def createServerEve(path: str,domain: str,port: int,federationList: [], \
|
||||||
deleteAllPosts(path,nickname,domain,'outbox')
|
deleteAllPosts(path,nickname,domain,'outbox')
|
||||||
global testServerEveRunning
|
global testServerEveRunning
|
||||||
testServerEveRunning = True
|
testServerEveRunning = True
|
||||||
|
maxMentions=10
|
||||||
print('Server running: Eve')
|
print('Server running: Eve')
|
||||||
runDaemon(__version__,"instanceId",False,path,domain,port,port, \
|
runDaemon(__version__,"instanceId",False,path,domain,port,port, \
|
||||||
httpPrefix,federationList,False, \
|
httpPrefix,federationList,maxMentions,False, \
|
||||||
noreply,nolike,nopics,noannounce,cw,ocapAlways, \
|
noreply,nolike,nopics,noannounce,cw,ocapAlways, \
|
||||||
useTor,maxReplies,allowDeletion,True,True,False)
|
useTor,maxReplies,allowDeletion,True,True,False)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue