From df48983aaef20eb5ae620dd3cecfcb05e65d4f17 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Wed, 8 Jul 2020 11:09:51 +0100 Subject: [PATCH] Option to list referenced domains --- epicyon.py | 39 +++++++++++++++++++++ posts.py | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+) diff --git a/epicyon.py b/epicyon.py index 0aec050d..d6513506 100644 --- a/epicyon.py +++ b/epicyon.py @@ -15,6 +15,7 @@ from person import deactivateAccount from skills import setSkillLevel from roles import setRole from webfinger import webfingerHandle +from posts import getPublicPostDomains from posts import sendBlockViaServer from posts import sendUndoBlockViaServer from posts import createPublicPost @@ -146,6 +147,10 @@ parser.add_argument('--actor', dest='actor', type=str, parser.add_argument('--posts', dest='posts', type=str, default=None, help='Show posts for the given handle') +parser.add_argument('--postDomains', dest='postDomains', type=str, + default=None, + help='Show domains referenced in public ' + 'posts for the given handle') parser.add_argument('--postsraw', dest='postsraw', type=str, default=None, help='Show raw json of posts for the given handle') @@ -416,6 +421,40 @@ if args.posts: __version__) sys.exit() +if args.postDomains: + if '@' not in args.postDomains: + if '/users/' in args.postDomains: + postsNickname = getNicknameFromActor(args.posts) + postsDomain, postsPort = getDomainFromActor(args.posts) + args.postDomains = postsNickname + '@' + postsDomain + if postsPort: + if postsPort != 80 and postsPort != 443: + args.postDomains += ':' + str(postsPort) + else: + print('Syntax: --posts nickname@domain') + sys.exit() + if not args.http: + args.port = 443 + nickname = args.postDomains.split('@')[0] + domain = args.postDomains.split('@')[1] + proxyType = None + if args.tor or domain.endswith('.onion'): + proxyType = 'tor' + if domain.endswith('.onion'): + args.port = 80 + elif args.i2p or domain.endswith('.i2p'): + proxyType = 'i2p' + if domain.endswith('.i2p'): + args.port = 80 + elif args.gnunet: + proxyType = 'gnunet' + domainList = getPublicPostDomains(baseDir, nickname, domain, False, True, + proxyType, args.port, httpPrefix, debug, + __version__) + for postDomain in domainList: + print(postDomain) + sys.exit() + if args.postsraw: if '@' not in args.postsraw: print('Syntax: --postsraw nickname@domain') diff --git a/posts.py b/posts.py index 31319e82..3754cd82 100644 --- a/posts.py +++ b/posts.py @@ -440,6 +440,58 @@ def getPosts(session, outboxUrl: str, maxPosts: int, return personPosts +def getPostDomains(session, outboxUrl: str, maxPosts: int, + maxMentions: int, + maxEmoji: int, maxAttachments: int, + federationList: [], + personCache: {}, raw: bool, + simple: bool, debug: bool, + projectVersion: str, httpPrefix: str, + domain: str) -> []: + """Returns a list of domains referenced within public posts + """ + 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 + '"' + } + + postDomains = [] + + i = 0 + userFeed = parseUserFeed(session, outboxUrl, asHeader, + projectVersion, httpPrefix, domain) + for item in userFeed: + if not item.get('object'): + continue + if not isinstance(item['object'], dict): + continue + if item['object'].get('inReplyTo'): + postDomain, postPort = \ + getDomainFromActor(item['object']['inReplyTo']) + if postDomain not in postDomains: + postDomains.append(postDomain) + + 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 postDomain not in postDomains: + postDomains.append(postDomain) + i += 1 + if i == maxPosts: + break + return postDomains + + def deleteAllPosts(baseDir: str, nickname: str, domain: str, boxname: str) -> None: """Deletes all posts for a person from inbox or outbox @@ -2933,6 +2985,54 @@ def getPublicPostsOfPerson(baseDir: str, nickname: str, domain: str, projectVersion, httpPrefix, domain) +def getPublicPostDomains(baseDir: str, nickname: str, domain: str, + raw: bool, simple: bool, proxyType: str, + port: int, httpPrefix: str, + debug: bool, projectVersion: str) -> []: + """ Returns a list of domains referenced within public posts + """ + session = createSession(proxyType) + if not session: + return + personCache = {} + cachedWebfingers = {} + federationList = [] + + domainFull = domain + if port: + if port != 80 and port != 443: + if ':' not in domain: + domainFull = domain + ':' + str(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, shaedInbox, + capabilityAcquisition, + avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest, + personCache, + projectVersion, httpPrefix, + nickname, domain, 'outbox') + maxMentions = 99 + maxEmoji = 99 + maxAttachments = 5 + postDomains = \ + getPostDomains(session, personUrl, 60, maxMentions, maxEmoji, + maxAttachments, federationList, + personCache, raw, simple, debug, + projectVersion, httpPrefix, domain) + postDomains.sort() + return postDomains + + def sendCapabilitiesUpdate(session, baseDir: str, httpPrefix: str, nickname: str, domain: str, port: int, followerUrl, updateCaps: [],