__filename__ = "acceptreject.py" __author__ = "Bob Mottram" __license__ = "AGPL3+" __version__ = "1.2.0" __maintainer__ = "Bob Mottram" __email__ = "bob@libreserver.org" __status__ = "Production" __module_group__ = "ActivityPub" import os from utils import hasObjectStringObject from utils import hasUsersPath from utils import getFullDomain from utils import urlPermitted from utils import getDomainFromActor from utils import getNicknameFromActor from utils import domainPermitted from utils import followPerson from utils import acctDir from utils import hasGroupType from utils import localActorUrl from utils import hasActor from utils import hasObjectStringType def _create_accept_reject(base_dir: str, federation_list: [], nickname: str, domain: str, port: int, toUrl: str, ccUrl: str, http_prefix: str, objectJson: {}, acceptType: str) -> {}: """Accepts or rejects something (eg. a follow request or offer) Typically toUrl will be https://www.w3.org/ns/activitystreams#Public and ccUrl might be a specific person favorited or repeated and the followers url objectUrl is typically the url of the message, corresponding to url or atomUri in createPostBase """ if not objectJson.get('actor'): return None if not urlPermitted(objectJson['actor'], federation_list): return None domain = getFullDomain(domain, port) new_accept = { "@context": "https://www.w3.org/ns/activitystreams", 'type': acceptType, 'actor': localActorUrl(http_prefix, nickname, domain), 'to': [toUrl], 'cc': [], 'object': objectJson } if ccUrl: if len(ccUrl) > 0: new_accept['cc'] = [ccUrl] return new_accept def createAccept(base_dir: str, federation_list: [], nickname: str, domain: str, port: int, toUrl: str, ccUrl: str, http_prefix: str, objectJson: {}) -> {}: return _create_accept_reject(base_dir, federation_list, nickname, domain, port, toUrl, ccUrl, http_prefix, objectJson, 'Accept') def createReject(base_dir: str, federation_list: [], nickname: str, domain: str, port: int, toUrl: str, ccUrl: str, http_prefix: str, objectJson: {}) -> {}: return _create_accept_reject(base_dir, federation_list, nickname, domain, port, toUrl, ccUrl, http_prefix, objectJson, 'Reject') def _accept_follow(base_dir: str, domain: str, message_json: {}, federation_list: [], debug: bool) -> None: """Receiving a follow Accept activity """ if not hasObjectStringType(message_json, debug): return if not message_json['object']['type'] == 'Follow': if not message_json['object']['type'] == 'Join': return if debug: print('DEBUG: receiving Follow activity') if not message_json['object'].get('actor'): print('DEBUG: no actor in Follow activity') return # no, this isn't a mistake if not hasObjectStringObject(message_json, debug): return if not message_json.get('to'): if debug: print('DEBUG: No "to" parameter in follow Accept') return if debug: print('DEBUG: follow Accept received') this_actor = message_json['object']['actor'] nickname = getNicknameFromActor(this_actor) if not nickname: print('WARN: no nickname found in ' + this_actor) return acceptedDomain, acceptedPort = getDomainFromActor(this_actor) if not acceptedDomain: if debug: print('DEBUG: domain not found in ' + this_actor) return if not nickname: if debug: print('DEBUG: nickname not found in ' + this_actor) return if acceptedPort: if '/' + acceptedDomain + ':' + str(acceptedPort) + \ '/users/' + nickname not in this_actor: if debug: print('Port: ' + str(acceptedPort)) print('Expected: /' + acceptedDomain + ':' + str(acceptedPort) + '/users/' + nickname) print('Actual: ' + this_actor) print('DEBUG: unrecognized actor ' + this_actor) return else: if not '/' + acceptedDomain + '/users/' + nickname in this_actor: if debug: print('Expected: /' + acceptedDomain + '/users/' + nickname) print('Actual: ' + this_actor) print('DEBUG: unrecognized actor ' + this_actor) return followed_actor = message_json['object']['object'] followed_domain, port = getDomainFromActor(followed_actor) if not followed_domain: print('DEBUG: no domain found within Follow activity object ' + followed_actor) return followed_domain_full = followed_domain if port: followed_domain_full = followed_domain + ':' + str(port) followed_nickname = getNicknameFromActor(followed_actor) if not followed_nickname: print('DEBUG: no nickname found within Follow activity object ' + followed_actor) return accepted_domain_full = acceptedDomain if acceptedPort: accepted_domain_full = acceptedDomain + ':' + str(acceptedPort) # has this person already been unfollowed? unfollowed_filename = \ acctDir(base_dir, nickname, accepted_domain_full) + '/unfollowed.txt' if os.path.isfile(unfollowed_filename): if followed_nickname + '@' + followed_domain_full in \ open(unfollowed_filename).read(): if debug: print('DEBUG: follow accept arrived for ' + nickname + '@' + accepted_domain_full + ' from ' + followed_nickname + '@' + followed_domain_full + ' but they have been unfollowed') return # does the url path indicate that this is a group actor group_account = hasGroupType(base_dir, followed_actor, None, debug) if debug: print('Accepted follow is a group: ' + str(group_account) + ' ' + followed_actor + ' ' + base_dir) if followPerson(base_dir, nickname, accepted_domain_full, followed_nickname, followed_domain_full, federation_list, debug, group_account): if debug: print('DEBUG: ' + nickname + '@' + accepted_domain_full + ' followed ' + followed_nickname + '@' + followed_domain_full) else: if debug: print('DEBUG: Unable to create follow - ' + nickname + '@' + acceptedDomain + ' -> ' + followed_nickname + '@' + followed_domain) def receiveAcceptReject(session, base_dir: str, http_prefix: str, domain: str, port: int, send_threads: [], postLog: [], cached_webfingers: {}, person_cache: {}, message_json: {}, federation_list: [], debug: bool) -> bool: """Receives an Accept or Reject within the POST section of HTTPServer """ if message_json['type'] != 'Accept' and message_json['type'] != 'Reject': return False if not hasActor(message_json, debug): return False if not hasUsersPath(message_json['actor']): if debug: print('DEBUG: "users" or "profile" missing from actor in ' + message_json['type'] + '. Assuming single user instance.') domain, _ = getDomainFromActor(message_json['actor']) if not domainPermitted(domain, federation_list): if debug: print('DEBUG: ' + message_json['type'] + ' from domain not permitted - ' + domain) return False nickname = getNicknameFromActor(message_json['actor']) if not nickname: # single user instance nickname = 'dev' if debug: print('DEBUG: ' + message_json['type'] + ' does not contain a nickname. ' + 'Assuming single user instance.') # receive follow accept _accept_follow(base_dir, domain, message_json, federation_list, debug) if debug: print('DEBUG: Uh, ' + message_json['type'] + ', I guess') return True