diff --git a/posts.py b/posts.py index f0728783b..863c62011 100644 --- a/posts.py +++ b/posts.py @@ -60,6 +60,7 @@ from content import replaceEmojiFromTags from content import removeTextFormatting from auth import createBasicAuthHeader from blocking import isBlocked +from blocking import isBlockedDomain from filters import isFiltered from git import convertPostToPatch from jsonldsig import jsonldSign @@ -507,6 +508,66 @@ def getPostDomains(session, outboxUrl: str, maxPosts: int, return postDomains +def getPostsForBlockedDomains(baseDir: str, + session, outboxUrl: str, maxPosts: int, + maxMentions: int, + maxEmoji: int, maxAttachments: int, + federationList: [], + personCache: {}, + debug: bool, + projectVersion: str, httpPrefix: str, + domain: str) -> {}: + """Returns a dictionary of posts for blocked domains + """ + if not outboxUrl: + return {} + profileStr = 'https://www.w3.org/ns/activitystreams' + asHeader = { + 'Accept': 'application/activity+json; profile="' + profileStr + '"' + } + if '/outbox/' in outboxUrl: + asHeader = { + 'Accept': 'application/ld+json; profile="' + profileStr + '"' + } + + blockedPosts = {} + + i = 0 + userFeed = parseUserFeed(session, outboxUrl, asHeader, + projectVersion, httpPrefix, domain) + for item in userFeed: + i += 1 + if i > maxPosts: + break + if not item.get('object'): + continue + if not isinstance(item['object'], dict): + continue + if item['object'].get('inReplyTo'): + if isinstance(item['object']['inReplyTo'], str): + postDomain, postPort = \ + getDomainFromActor(item['object']['inReplyTo']) + if isBlockedDomain(baseDir, postDomain): + if not blockedPosts.get(postDomain): + blockedPosts[postDomain] = [item] + else: + blockedPosts[postDomain].append(item) + + if item['object'].get('tag'): + for tagItem in item['object']['tag']: + tagType = tagItem['type'].lower() + if tagType == 'mention': + if tagItem.get('href'): + postDomain, postPort = \ + getDomainFromActor(tagItem['href']) + if isBlockedDomain(baseDir, postDomain): + if not blockedPosts.get(postDomain): + blockedPosts[postDomain] = [item] + else: + blockedPosts[postDomain].append(item) + return blockedPosts + + def deleteAllPosts(baseDir: str, nickname: str, domain: str, boxname: str) -> None: """Deletes all posts for a person from inbox or outbox @@ -3340,6 +3401,69 @@ def getPublicPostDomains(session, baseDir: str, nickname: str, domain: str, return postDomains +def getPublicPostInfo(session, baseDir: str, nickname: str, domain: str, + proxyType: str, port: int, httpPrefix: str, + debug: bool, projectVersion: str) -> []: + """ Returns a dict of domains referenced within public posts + """ + if not session: + session = createSession(proxyType) + if not session: + return {} + personCache = {} + cachedWebfingers = {} + federationList = [] + + domainFull = getFullDomain(domain, port) + handle = httpPrefix + "://" + domainFull + "/@" + nickname + wfRequest = \ + webfingerHandle(session, handle, httpPrefix, cachedWebfingers, + domain, projectVersion) + if not wfRequest: + return {} + if not isinstance(wfRequest, dict): + print('Webfinger for ' + handle + ' did not return a dict. ' + + str(wfRequest)) + return {} + + (personUrl, pubKeyId, pubKey, + personId, sharedInbox, + avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest, + personCache, + projectVersion, httpPrefix, + nickname, domain, 'outbox') + maxMentions = 99 + maxEmoji = 99 + maxAttachments = 5 + maxPosts = 64 + postDomains = \ + getPostDomains(session, personUrl, maxPosts, maxMentions, maxEmoji, + maxAttachments, federationList, + personCache, debug, + projectVersion, httpPrefix, domain, []) + postDomains.sort() + domainsInfo = {} + for d in postDomains: + if not domainsInfo.get(d): + domainsInfo[d] = [] + + blockedPosts = \ + getPostsForBlockedDomains(baseDir, session, personUrl, maxPosts, + maxMentions, + maxEmoji, maxAttachments, + federationList, + personCache, + debug, + projectVersion, httpPrefix, + domain) + for blockedDomain, postList in blockedPosts.items(): + if not domainsInfo.get(blockedDomain): + continue + domainsInfo[blockedDomain] = postList.copy() + + return domainsInfo + + def getPublicPostDomainsBlocked(session, baseDir: str, nickname: str, domain: str, proxyType: str, port: int, httpPrefix: str, diff --git a/webapp_moderation.py b/webapp_moderation.py index bb8859c11..1b9f3ea93 100644 --- a/webapp_moderation.py +++ b/webapp_moderation.py @@ -9,8 +9,9 @@ __status__ = "Production" import os from utils import getNicknameFromActor from utils import getDomainFromActor -from posts import getPublicPostDomains +from posts import getPublicPostInfo from webapp_timeline import htmlTimeline +from webapp_utils import getContentWarningButton from webapp_utils import htmlHeaderWithExternalStyle from webapp_utils import htmlFooter from blocking import isBlockedDomain @@ -78,23 +79,36 @@ def htmlAccountInfo(cssCache: {}, translate: {}, infoForm += translate[msgStr1] + '

' proxyType = 'tor' - domainList = [] - domainList = getPublicPostDomains(None, - baseDir, searchNickname, searchDomain, - proxyType, searchPort, - httpPrefix, debug, - __version__, domainList) + domainDict = getPublicPostInfo(None, + baseDir, searchNickname, searchDomain, + proxyType, searchPort, + httpPrefix, debug, + __version__) infoForm += '
' usersPath = '/users/' + nickname + '/accountinfo' - for postDomain in domainList: + ctr = 1 + for postDomain, blockedPosts in domainDict.items(): infoForm += '' + postDomain + ' ' if isBlockedDomain(baseDir, postDomain): + blockedPostsLinks = '' + for blockedPostJson in blockedPosts: + if not blockedPostJson['object'].get('url'): + continue + url = blockedPostJson['object']['url'] + blockedPostsLinks += \ + '' + url + '
' + blockedPostsHtml = \ + getContentWarningButton('blockNumber' + str(ctr), + translate, blockedPostsLinks) + ctr += 1 + infoForm += \ '' infoForm += '' + translate['Unblock'] + ' ' + \ + blockedPostsHtml else: infoForm += \ '