mirror of https://gitlab.com/bashrc2/epicyon
Validate sending actor of incoming post
parent
f8b62c5388
commit
0e0160a698
|
@ -869,7 +869,7 @@ def _desktopShowProfile(session, nickname: str, domain: str,
|
|||
isHttp = True
|
||||
actorJson, asHeader = \
|
||||
getActorJson(domain, actor, isHttp, False, False, True,
|
||||
signingPrivateKeyPem)
|
||||
signingPrivateKeyPem, session)
|
||||
|
||||
_desktopShowActor(baseDir, actorJson, translate,
|
||||
systemLanguage, screenreader, espeak)
|
||||
|
@ -890,7 +890,7 @@ def _desktopShowProfileFromHandle(session, nickname: str, domain: str,
|
|||
"""
|
||||
actorJson, asHeader = \
|
||||
getActorJson(domain, handle, False, False, False, True,
|
||||
signingPrivateKeyPem)
|
||||
signingPrivateKeyPem, session)
|
||||
|
||||
_desktopShowActor(baseDir, actorJson, translate,
|
||||
systemLanguage, screenreader, espeak)
|
||||
|
|
|
@ -2086,7 +2086,7 @@ if args.actor:
|
|||
else:
|
||||
print('Did not obtain instance actor key for ' + domain)
|
||||
getActorJson(domain, args.actor, args.http, args.gnunet,
|
||||
debug, False, signingPrivateKeyPem)
|
||||
debug, False, signingPrivateKeyPem, None)
|
||||
sys.exit()
|
||||
|
||||
if args.followers:
|
||||
|
|
14
filters.py
14
filters.py
|
@ -144,6 +144,20 @@ def isFilteredGlobally(baseDir: str, content: str) -> bool:
|
|||
return False
|
||||
|
||||
|
||||
def isFilteredBio(baseDir: str, nickname: str, domain: str, bio: str) -> bool:
|
||||
"""Should the given actor bio be filtered out?
|
||||
"""
|
||||
if isFilteredGlobally(baseDir, bio):
|
||||
return True
|
||||
|
||||
if not nickname or not domain:
|
||||
return False
|
||||
|
||||
accountFiltersFilename = \
|
||||
acctDir(baseDir, nickname, domain) + '/filters_bio.txt'
|
||||
return _isFilteredBase(accountFiltersFilename, bio)
|
||||
|
||||
|
||||
def isFiltered(baseDir: str, nickname: str, domain: str, content: str) -> bool:
|
||||
"""Should the given content be filtered out?
|
||||
This is a simple type of filter which just matches words, not a regex
|
||||
|
|
6
inbox.py
6
inbox.py
|
@ -113,6 +113,7 @@ from notifyOnPost import notifyWhenPersonPosts
|
|||
from conversation import updateConversation
|
||||
from content import validHashTag
|
||||
from webapp_hashtagswarm import htmlHashTagSwarm
|
||||
from person import validSendingActor
|
||||
|
||||
|
||||
def _storeLastPostId(baseDir: str, nickname: str, domain: str,
|
||||
|
@ -3408,6 +3409,11 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
|
|||
allowLocalNetworkAccess, debug,
|
||||
systemLanguage, httpPrefix,
|
||||
domainFull, personCache):
|
||||
# is the sending actor valid?
|
||||
if not validSendingActor(session, baseDir, nickname, domain,
|
||||
personCache, postJsonObject,
|
||||
signingPrivateKeyPem, debug, unitTest):
|
||||
return False
|
||||
|
||||
if postJsonObject.get('object'):
|
||||
jsonObj = postJsonObject['object']
|
||||
|
|
|
@ -86,7 +86,7 @@ def _updateMovedHandle(baseDir: str, nickname: str, domain: str,
|
|||
gnunet = True
|
||||
personJson = \
|
||||
getActorJson(domain, personUrl, httpPrefix, gnunet, debug, False,
|
||||
signingPrivateKeyPem)
|
||||
signingPrivateKeyPem, None)
|
||||
if not personJson:
|
||||
return ctr
|
||||
if not personJson.get('movedTo'):
|
||||
|
|
111
person.py
111
person.py
|
@ -38,6 +38,8 @@ from roles import setRole
|
|||
from roles import setRolesFromList
|
||||
from roles import getActorRolesList
|
||||
from media import processMetaData
|
||||
from utils import removeHtml
|
||||
from utils import containsInvalidChars
|
||||
from utils import replaceUsersWithAt
|
||||
from utils import removeLineEndings
|
||||
from utils import removeDomainPort
|
||||
|
@ -63,6 +65,8 @@ from session import getJson
|
|||
from webfinger import webfingerHandle
|
||||
from pprint import pprint
|
||||
from cache import getPersonFromCache
|
||||
from cache import storePersonInCache
|
||||
from filters import isFilteredBio
|
||||
|
||||
|
||||
def generateRSAKey() -> (str, str):
|
||||
|
@ -1415,7 +1419,8 @@ def _detectUsersPath(url: str) -> str:
|
|||
|
||||
def getActorJson(hostDomain: str, handle: str, http: bool, gnunet: bool,
|
||||
debug: bool, quiet: bool,
|
||||
signingPrivateKeyPem: str) -> ({}, {}):
|
||||
signingPrivateKeyPem: str,
|
||||
existingSession) -> ({}, {}):
|
||||
"""Returns the actor json
|
||||
"""
|
||||
if debug:
|
||||
|
@ -1498,7 +1503,10 @@ def getActorJson(hostDomain: str, handle: str, http: bool, gnunet: bool,
|
|||
httpPrefix = 'https'
|
||||
else:
|
||||
httpPrefix = 'http'
|
||||
session = createSession(proxyType)
|
||||
if existingSession:
|
||||
session = existingSession
|
||||
else:
|
||||
session = createSession(proxyType)
|
||||
if nickname == 'inbox':
|
||||
nickname = domain
|
||||
|
||||
|
@ -1634,3 +1642,102 @@ def addActorUpdateTimestamp(actorJson: {}) -> None:
|
|||
# add updated timestamp to avatar and banner
|
||||
actorJson['icon']['updated'] = currDateStr
|
||||
actorJson['image']['updated'] = currDateStr
|
||||
|
||||
|
||||
def validSendingActor(session, baseDir: str,
|
||||
nickname: str, domain: str,
|
||||
personCache: {},
|
||||
postJsonObject: {},
|
||||
signingPrivateKeyPem: str,
|
||||
debug: bool, unitTest: bool) -> bool:
|
||||
"""When a post arrives in the inbox this is used to check that
|
||||
the sending actor is valid
|
||||
"""
|
||||
# who sent this post?
|
||||
sendingActor = postJsonObject['actor']
|
||||
|
||||
# sending to yourself (reminder)
|
||||
if sendingActor.endswith(domain + '/users/' + nickname):
|
||||
return True
|
||||
|
||||
# get their actor
|
||||
actorJson = getPersonFromCache(baseDir, sendingActor, personCache, True)
|
||||
downloadedActor = False
|
||||
if not actorJson:
|
||||
# download the actor
|
||||
actorJson, _ = getActorJson(domain, sendingActor,
|
||||
True, False, debug, True,
|
||||
signingPrivateKeyPem, session)
|
||||
if actorJson:
|
||||
downloadedActor = True
|
||||
if not actorJson:
|
||||
# if the actor couldn't be obtained then proceed anyway
|
||||
return True
|
||||
if not actorJson.get('name'):
|
||||
print('REJECT: no name within actor ' + str(actorJson))
|
||||
return False
|
||||
if not actorJson.get('preferredUsername'):
|
||||
print('REJECT: no preferredUsername within actor ' + str(actorJson))
|
||||
return False
|
||||
# does the actor have a bio ?
|
||||
if not unitTest:
|
||||
if not actorJson.get('summary'):
|
||||
# allow no bio if it's an actor in this instance
|
||||
if domain not in sendingActor:
|
||||
# probably a spam actor with no bio
|
||||
print('REJECT: spam actor ' + sendingActor)
|
||||
return False
|
||||
bioStr = removeHtml(actorJson['summary'])
|
||||
bioStr += ' ' + removeHtml(actorJson['preferredUsername'])
|
||||
bioStr += ' ' + removeHtml(actorJson['name'])
|
||||
if containsInvalidChars(bioStr):
|
||||
print('REJECT: post actor bio contains invalid characters')
|
||||
return False
|
||||
if isFilteredBio(baseDir, nickname, domain, bioStr):
|
||||
print('REJECT: post actor bio contains filtered text')
|
||||
return False
|
||||
else:
|
||||
print('Skipping check for missing bio in ' + sendingActor)
|
||||
|
||||
# Check any attached fields for the actor.
|
||||
# Spam actors will sometimes have attached fields which are all empty
|
||||
if actorJson.get('attachment'):
|
||||
if isinstance(actorJson['attachment'], list):
|
||||
noOfTags = 0
|
||||
tagsWithoutValue = 0
|
||||
for tag in actorJson['attachment']:
|
||||
if not isinstance(tag, dict):
|
||||
continue
|
||||
if not tag.get('name'):
|
||||
continue
|
||||
noOfTags += 1
|
||||
if not tag.get('value'):
|
||||
tagsWithoutValue += 1
|
||||
continue
|
||||
if not isinstance(tag['value'], str):
|
||||
tagsWithoutValue += 1
|
||||
continue
|
||||
if not tag['value'].strip():
|
||||
tagsWithoutValue += 1
|
||||
continue
|
||||
if len(tag['value']) < 2:
|
||||
tagsWithoutValue += 1
|
||||
continue
|
||||
if containsInvalidChars(tag['name']):
|
||||
tagsWithoutValue += 1
|
||||
continue
|
||||
if containsInvalidChars(tag['value']):
|
||||
tagsWithoutValue += 1
|
||||
continue
|
||||
if noOfTags > 0:
|
||||
if int(tagsWithoutValue * 100 / noOfTags) > 50:
|
||||
print('REJECT: actor has empty attachments ' +
|
||||
sendingActor)
|
||||
return False
|
||||
|
||||
if downloadedActor:
|
||||
# if the actor is valid and was downloaded then
|
||||
# store it in the cache, but don't write it to file
|
||||
storePersonInCache(baseDir, sendingActor, actorJson, personCache,
|
||||
False)
|
||||
return True
|
||||
|
|
4
pgp.py
4
pgp.py
|
@ -343,7 +343,7 @@ def _getPGPPublicKeyFromActor(signingPrivateKeyPem: str,
|
|||
if not actorJson:
|
||||
actorJson, asHeader = \
|
||||
getActorJson(domain, handle, False, False, False, True,
|
||||
signingPrivateKeyPem)
|
||||
signingPrivateKeyPem, None)
|
||||
if not actorJson:
|
||||
return None
|
||||
if not actorJson.get('attachment'):
|
||||
|
@ -491,7 +491,7 @@ def pgpPublicKeyUpload(baseDir: str, session,
|
|||
|
||||
actorJson, asHeader = \
|
||||
getActorJson(domainFull, handle, False, False, debug, True,
|
||||
signingPrivateKeyPem)
|
||||
signingPrivateKeyPem, session)
|
||||
if not actorJson:
|
||||
if debug:
|
||||
print('No actor returned for ' + handle)
|
||||
|
|
|
@ -151,7 +151,7 @@ def htmlProfileAfterSearch(cssCache: {},
|
|||
gnunet = True
|
||||
profileJson, asHeader = \
|
||||
getActorJson(domain, profileHandle, http, gnunet, debug, False,
|
||||
signingPrivateKeyPem)
|
||||
signingPrivateKeyPem, session)
|
||||
if not profileJson:
|
||||
return None
|
||||
|
||||
|
|
Loading…
Reference in New Issue