| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  | __filename__ = "like.py" | 
					
						
							|  |  |  | __author__ = "Bob Mottram" | 
					
						
							|  |  |  | __license__ = "AGPL3+" | 
					
						
							|  |  |  | __version__ = "1.1.0" | 
					
						
							|  |  |  | __maintainer__ = "Bob Mottram" | 
					
						
							|  |  |  | __email__ = "bob@freedombone.net" | 
					
						
							|  |  |  | __status__ = "Production" | 
					
						
							| 
									
										
										
										
											2019-07-02 11:13:45 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | from utils import urlPermitted | 
					
						
							| 
									
										
										
										
											2019-07-10 09:47:07 +00:00
										 |  |  | from utils import getNicknameFromActor | 
					
						
							|  |  |  | from utils import getDomainFromActor | 
					
						
							| 
									
										
										
										
											2019-07-11 12:29:31 +00:00
										 |  |  | from utils import locatePost | 
					
						
							| 
									
										
										
										
											2020-06-06 18:16:16 +00:00
										 |  |  | from utils import updateLikesCollection | 
					
						
							|  |  |  | from utils import undoLikesCollectionEntry | 
					
						
							| 
									
										
										
										
											2019-07-11 12:29:31 +00:00
										 |  |  | from posts import sendSignedJson | 
					
						
							| 
									
										
										
										
											2019-07-17 19:31:52 +00:00
										 |  |  | from session import postJson | 
					
						
							|  |  |  | from webfinger import webfingerHandle | 
					
						
							|  |  |  | from auth import createBasicAuthHeader | 
					
						
							|  |  |  | from posts import getPersonBox | 
					
						
							| 
									
										
										
										
											2019-07-11 12:29:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def likedByPerson(postJsonObject: {}, nickname: str, domain: str) -> bool: | 
					
						
							| 
									
										
										
										
											2019-08-01 09:31:38 +00:00
										 |  |  |     """Returns True if the given post is liked by the given person
 | 
					
						
							| 
									
										
										
										
											2019-08-01 09:05:09 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     if noOfLikes(postJsonObject) == 0: | 
					
						
							| 
									
										
										
										
											2019-08-01 09:05:09 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     actorMatch = domain+'/users/'+nickname | 
					
						
							| 
									
										
										
										
											2019-08-01 09:05:09 +00:00
										 |  |  |     for item in postJsonObject['object']['likes']['items']: | 
					
						
							|  |  |  |         if item['actor'].endswith(actorMatch): | 
					
						
							|  |  |  |             return True | 
					
						
							|  |  |  |     return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-30 20:48:52 +00:00
										 |  |  | def noOfLikes(postJsonObject: {}) -> int: | 
					
						
							|  |  |  |     """Returns the number of likes ona  given post
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not postJsonObject.get('object'): | 
					
						
							|  |  |  |         return 0 | 
					
						
							|  |  |  |     if not isinstance(postJsonObject['object'], dict): | 
					
						
							|  |  |  |         return 0 | 
					
						
							|  |  |  |     if not postJsonObject['object'].get('likes'): | 
					
						
							|  |  |  |         return 0 | 
					
						
							| 
									
										
										
										
											2019-09-05 19:19:52 +00:00
										 |  |  |     if not isinstance(postJsonObject['object']['likes'], dict): | 
					
						
							|  |  |  |         return 0 | 
					
						
							| 
									
										
										
										
											2019-08-30 20:48:52 +00:00
										 |  |  |     if not postJsonObject['object']['likes'].get('items'): | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |         postJsonObject['object']['likes']['items'] = [] | 
					
						
							|  |  |  |         postJsonObject['object']['likes']['totalItems'] = 0 | 
					
						
							| 
									
										
										
										
											2019-08-30 20:48:52 +00:00
										 |  |  |     return len(postJsonObject['object']['likes']['items']) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def like(recentPostsCache: {}, | 
					
						
							|  |  |  |          session, baseDir: str, federationList: [], | 
					
						
							|  |  |  |          nickname: str, domain: str, port: int, | 
					
						
							|  |  |  |          ccList: [], httpPrefix: str, | 
					
						
							|  |  |  |          objectUrl: str, actorLiked: str, | 
					
						
							|  |  |  |          clientToServer: bool, | 
					
						
							|  |  |  |          sendThreads: [], postLog: [], | 
					
						
							|  |  |  |          personCache: {}, cachedWebfingers: {}, | 
					
						
							|  |  |  |          debug: bool, projectVersion: str) -> {}: | 
					
						
							| 
									
										
										
										
											2019-07-02 11:13:45 +00:00
										 |  |  |     """Creates a like
 | 
					
						
							| 
									
										
										
										
											2019-07-12 09:10:09 +00:00
										 |  |  |     actor is the person doing the liking | 
					
						
							|  |  |  |     'to' might be a specific person (actor) whose post was liked | 
					
						
							|  |  |  |     object is typically the url of the message which was liked | 
					
						
							| 
									
										
										
										
											2019-07-02 11:13:45 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     if not urlPermitted(objectUrl, federationList, "inbox:write"): | 
					
						
							| 
									
										
										
										
											2019-07-02 11:13:45 +00:00
										 |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     fullDomain = domain | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |     if port: | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |         if port != 80 and port != 443: | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |             if ':' not in domain: | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |                 fullDomain = domain+':'+str(port) | 
					
						
							| 
									
										
										
										
											2019-08-07 11:02:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     newLikeJson = { | 
					
						
							| 
									
										
										
										
											2019-08-18 11:07:06 +00:00
										 |  |  |         "@context": "https://www.w3.org/ns/activitystreams", | 
					
						
							| 
									
										
										
										
											2019-07-02 11:13:45 +00:00
										 |  |  |         'type': 'Like', | 
					
						
							| 
									
										
										
										
											2020-04-03 16:36:21 +00:00
										 |  |  |         'actor': httpPrefix + '://' + fullDomain + '/users/' + nickname, | 
					
						
							| 
									
										
										
										
											2019-08-18 16:58:50 +00:00
										 |  |  |         'object': objectUrl | 
					
						
							| 
									
										
										
										
											2019-07-02 11:13:45 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-07-11 12:29:31 +00:00
										 |  |  |     if ccList: | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |         if len(ccList) > 0: | 
					
						
							|  |  |  |             newLikeJson['cc'] = ccList | 
					
						
							| 
									
										
										
										
											2019-07-10 09:47:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Extract the domain and nickname from a statuses link | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     likedPostNickname = None | 
					
						
							|  |  |  |     likedPostDomain = None | 
					
						
							|  |  |  |     likedPostPort = None | 
					
						
							| 
									
										
										
										
											2019-11-15 09:54:19 +00:00
										 |  |  |     if actorLiked: | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |         likedPostNickname = getNicknameFromActor(actorLiked) | 
					
						
							|  |  |  |         likedPostDomain, likedPostPort = getDomainFromActor(actorLiked) | 
					
						
							| 
									
										
										
										
											2019-11-15 09:54:19 +00:00
										 |  |  |     else: | 
					
						
							|  |  |  |         if '/users/' in objectUrl or \ | 
					
						
							|  |  |  |            '/channel/' in objectUrl or \ | 
					
						
							|  |  |  |            '/profile/' in objectUrl: | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |             likedPostNickname = getNicknameFromActor(objectUrl) | 
					
						
							|  |  |  |             likedPostDomain, likedPostPort = getDomainFromActor(objectUrl) | 
					
						
							| 
									
										
										
										
											2019-07-10 09:47:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if likedPostNickname: | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |         postFilename = locatePost(baseDir, nickname, domain, objectUrl) | 
					
						
							| 
									
										
										
										
											2019-07-11 12:29:31 +00:00
										 |  |  |         if not postFilename: | 
					
						
							| 
									
										
										
										
											2020-04-03 16:36:21 +00:00
										 |  |  |             print('DEBUG: like baseDir: ' + baseDir) | 
					
						
							|  |  |  |             print('DEBUG: like nickname: ' + nickname) | 
					
						
							|  |  |  |             print('DEBUG: like domain: ' + domain) | 
					
						
							|  |  |  |             print('DEBUG: like objectUrl: ' + objectUrl) | 
					
						
							| 
									
										
										
										
											2019-07-11 12:29:31 +00:00
										 |  |  |             return None | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |         updateLikesCollection(recentPostsCache, | 
					
						
							|  |  |  |                               baseDir, postFilename, objectUrl, | 
					
						
							|  |  |  |                               newLikeJson['actor'], domain, debug) | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |         sendSignedJson(newLikeJson, session, baseDir, | 
					
						
							|  |  |  |                        nickname, domain, port, | 
					
						
							|  |  |  |                        likedPostNickname, likedPostDomain, likedPostPort, | 
					
						
							|  |  |  |                        'https://www.w3.org/ns/activitystreams#Public', | 
					
						
							|  |  |  |                        httpPrefix, True, clientToServer, federationList, | 
					
						
							|  |  |  |                        sendThreads, postLog, cachedWebfingers, personCache, | 
					
						
							|  |  |  |                        debug, projectVersion) | 
					
						
							| 
									
										
										
										
											2019-07-10 09:47:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return newLikeJson | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def likePost(recentPostsCache: {}, | 
					
						
							|  |  |  |              session, baseDir: str, federationList: [], | 
					
						
							|  |  |  |              nickname: str, domain: str, port: int, httpPrefix: str, | 
					
						
							|  |  |  |              likeNickname: str, likeDomain: str, likePort: int, | 
					
						
							|  |  |  |              ccList: [], | 
					
						
							|  |  |  |              likeStatusNumber: int, clientToServer: bool, | 
					
						
							|  |  |  |              sendThreads: [], postLog: [], | 
					
						
							|  |  |  |              personCache: {}, cachedWebfingers: {}, | 
					
						
							|  |  |  |              debug: bool, projectVersion: str) -> {}: | 
					
						
							| 
									
										
										
										
											2019-11-15 09:54:19 +00:00
										 |  |  |     """Likes a given status post. This is only used by unit tests
 | 
					
						
							| 
									
										
										
										
											2019-07-02 14:02:58 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     likeDomain = likeDomain | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |     if likePort: | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |         if likePort != 80 and likePort != 443: | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |             if ':' not in likeDomain: | 
					
						
							| 
									
										
										
										
											2020-04-03 16:36:21 +00:00
										 |  |  |                 likeDomain = likeDomain + ':' + str(likePort) | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 16:36:21 +00:00
										 |  |  |     actorLiked = httpPrefix + '://' + likeDomain + '/users/' + likeNickname | 
					
						
							|  |  |  |     objectUrl = actorLiked + '/statuses/' + str(likeStatusNumber) | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return like(recentPostsCache, | 
					
						
							|  |  |  |                 session, baseDir, federationList, nickname, domain, port, | 
					
						
							|  |  |  |                 ccList, httpPrefix, objectUrl, actorLiked, clientToServer, | 
					
						
							|  |  |  |                 sendThreads, postLog, personCache, cachedWebfingers, | 
					
						
							|  |  |  |                 debug, projectVersion) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def undolike(recentPostsCache: {}, | 
					
						
							|  |  |  |              session, baseDir: str, federationList: [], | 
					
						
							|  |  |  |              nickname: str, domain: str, port: int, | 
					
						
							|  |  |  |              ccList: [], httpPrefix: str, | 
					
						
							|  |  |  |              objectUrl: str, actorLiked: str, | 
					
						
							|  |  |  |              clientToServer: bool, | 
					
						
							|  |  |  |              sendThreads: [], postLog: [], | 
					
						
							|  |  |  |              personCache: {}, cachedWebfingers: {}, | 
					
						
							|  |  |  |              debug: bool, projectVersion: str) -> {}: | 
					
						
							| 
									
										
										
										
											2019-07-12 09:10:09 +00:00
										 |  |  |     """Removes a like
 | 
					
						
							|  |  |  |     actor is the person doing the liking | 
					
						
							|  |  |  |     'to' might be a specific person (actor) whose post was liked | 
					
						
							|  |  |  |     object is typically the url of the message which was liked | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     if not urlPermitted(objectUrl, federationList, "inbox:write"): | 
					
						
							| 
									
										
										
										
											2019-07-12 09:10:09 +00:00
										 |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     fullDomain = domain | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |     if port: | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |         if port != 80 and port != 443: | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |             if ':' not in domain: | 
					
						
							| 
									
										
										
										
											2020-04-03 16:36:21 +00:00
										 |  |  |                 fullDomain = domain + ':' + str(port) | 
					
						
							| 
									
										
										
										
											2019-08-07 11:02:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     newUndoLikeJson = { | 
					
						
							| 
									
										
										
										
											2019-08-18 11:07:06 +00:00
										 |  |  |         "@context": "https://www.w3.org/ns/activitystreams", | 
					
						
							| 
									
										
										
										
											2019-07-12 09:10:09 +00:00
										 |  |  |         'type': 'Undo', | 
					
						
							|  |  |  |         'actor': httpPrefix+'://'+fullDomain+'/users/'+nickname, | 
					
						
							|  |  |  |         'object': { | 
					
						
							|  |  |  |             'type': 'Like', | 
					
						
							| 
									
										
										
										
											2020-04-03 16:36:21 +00:00
										 |  |  |             'actor': httpPrefix + '://' + fullDomain + '/users/' + nickname, | 
					
						
							| 
									
										
										
										
											2019-08-18 16:58:50 +00:00
										 |  |  |             'object': objectUrl | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-07-12 09:10:09 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |     if ccList: | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |         if len(ccList) > 0: | 
					
						
							|  |  |  |             newUndoLikeJson['cc'] = ccList | 
					
						
							|  |  |  |             newUndoLikeJson['object']['cc'] = ccList | 
					
						
							| 
									
										
										
										
											2019-07-12 09:10:09 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Extract the domain and nickname from a statuses link | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     likedPostNickname = None | 
					
						
							|  |  |  |     likedPostDomain = None | 
					
						
							|  |  |  |     likedPostPort = None | 
					
						
							| 
									
										
										
										
											2019-11-15 09:54:19 +00:00
										 |  |  |     if actorLiked: | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |         likedPostNickname = getNicknameFromActor(actorLiked) | 
					
						
							|  |  |  |         likedPostDomain, likedPostPort = getDomainFromActor(actorLiked) | 
					
						
							| 
									
										
										
										
											2019-11-15 09:54:19 +00:00
										 |  |  |     else: | 
					
						
							|  |  |  |         if '/users/' in objectUrl or \ | 
					
						
							|  |  |  |            '/channel/' in objectUrl or \ | 
					
						
							|  |  |  |            '/profile/' in objectUrl: | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |             likedPostNickname = getNicknameFromActor(objectUrl) | 
					
						
							|  |  |  |             likedPostDomain, likedPostPort = getDomainFromActor(objectUrl) | 
					
						
							| 
									
										
										
										
											2019-07-12 09:10:09 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if likedPostNickname: | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |         postFilename = locatePost(baseDir, nickname, domain, objectUrl) | 
					
						
							| 
									
										
										
										
											2019-07-12 09:10:09 +00:00
										 |  |  |         if not postFilename: | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |         undoLikesCollectionEntry(baseDir, postFilename, objectUrl, | 
					
						
							|  |  |  |                                  newUndoLikeJson['actor'], domain, debug) | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |         sendSignedJson(newUndoLikeJson, session, baseDir, | 
					
						
							|  |  |  |                        nickname, domain, port, | 
					
						
							|  |  |  |                        likedPostNickname, likedPostDomain, likedPostPort, | 
					
						
							|  |  |  |                        'https://www.w3.org/ns/activitystreams#Public', | 
					
						
							|  |  |  |                        httpPrefix, True, clientToServer, federationList, | 
					
						
							|  |  |  |                        sendThreads, postLog, cachedWebfingers, personCache, | 
					
						
							|  |  |  |                        debug, projectVersion) | 
					
						
							| 
									
										
										
										
											2019-07-12 09:10:09 +00:00
										 |  |  |     else: | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-12 09:41:57 +00:00
										 |  |  |     return newUndoLikeJson | 
					
						
							| 
									
										
										
										
											2019-07-12 09:10:09 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  | def sendLikeViaServer(baseDir: str, session, | 
					
						
							|  |  |  |                       fromNickname: str, password: str, | 
					
						
							|  |  |  |                       fromDomain: str, fromPort: int, | 
					
						
							|  |  |  |                       httpPrefix: str, likeUrl: str, | 
					
						
							|  |  |  |                       cachedWebfingers: {}, personCache: {}, | 
					
						
							|  |  |  |                       debug: bool, projectVersion: str) -> {}: | 
					
						
							| 
									
										
										
										
											2019-07-17 18:33:41 +00:00
										 |  |  |     """Creates a like via c2s
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not session: | 
					
						
							|  |  |  |         print('WARN: No session for sendLikeViaServer') | 
					
						
							|  |  |  |         return 6 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     fromDomainFull = fromDomain | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |     if fromPort: | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |         if fromPort != 80 and fromPort != 443: | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |             if ':' not in fromDomain: | 
					
						
							| 
									
										
										
										
											2020-04-03 16:36:21 +00:00
										 |  |  |                 fromDomainFull = fromDomain + ':' + str(fromPort) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     actor = httpPrefix + '://' + fromDomainFull + '/users/' + fromNickname | 
					
						
							| 
									
										
										
										
											2019-07-17 18:33:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     newLikeJson = { | 
					
						
							| 
									
										
										
										
											2019-08-18 11:07:06 +00:00
										 |  |  |         "@context": "https://www.w3.org/ns/activitystreams", | 
					
						
							| 
									
										
										
										
											2019-07-17 18:33:41 +00:00
										 |  |  |         'type': 'Like', | 
					
						
							| 
									
										
										
										
											2020-04-03 16:36:21 +00:00
										 |  |  |         'actor': actor, | 
					
						
							| 
									
										
										
										
											2019-08-18 16:58:50 +00:00
										 |  |  |         'object': likeUrl | 
					
						
							| 
									
										
										
										
											2019-07-17 18:33:41 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 16:36:21 +00:00
										 |  |  |     handle = httpPrefix + '://' + fromDomainFull + '/@' + fromNickname | 
					
						
							| 
									
										
										
										
											2019-07-17 18:33:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # lookup the inbox for the To handle | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     wfRequest = webfingerHandle(session, handle, httpPrefix, | 
					
						
							|  |  |  |                                 cachedWebfingers, | 
					
						
							|  |  |  |                                 fromDomain, projectVersion) | 
					
						
							| 
									
										
										
										
											2019-07-17 18:33:41 +00:00
										 |  |  |     if not wfRequest: | 
					
						
							|  |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 16:36:21 +00:00
										 |  |  |             print('DEBUG: announce webfinger failed for ' + handle) | 
					
						
							| 
									
										
										
										
											2019-07-17 18:33:41 +00:00
										 |  |  |         return 1 | 
					
						
							| 
									
										
										
										
											2020-06-23 10:41:12 +00:00
										 |  |  |     if not isinstance(wfRequest, dict): | 
					
						
							|  |  |  |         print('WARN: Webfinger for ' + handle + ' did not return a dict. ' + | 
					
						
							|  |  |  |               str(wfRequest)) | 
					
						
							|  |  |  |         return 1 | 
					
						
							| 
									
										
										
										
											2019-07-17 18:33:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     postToBox = 'outbox' | 
					
						
							| 
									
										
										
										
											2019-07-17 18:33:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # get the actor inbox for the To handle | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     (inboxUrl, pubKeyId, pubKey, fromPersonId, | 
					
						
							|  |  |  |      sharedInbox, capabilityAcquisition, | 
					
						
							|  |  |  |      avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest, | 
					
						
							|  |  |  |                                             personCache, | 
					
						
							|  |  |  |                                             projectVersion, httpPrefix, | 
					
						
							|  |  |  |                                             fromNickname, fromDomain, | 
					
						
							|  |  |  |                                             postToBox) | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-17 18:33:41 +00:00
										 |  |  |     if not inboxUrl: | 
					
						
							|  |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 16:36:21 +00:00
										 |  |  |             print('DEBUG: No ' + postToBox + ' was found for ' + handle) | 
					
						
							| 
									
										
										
										
											2019-07-17 18:33:41 +00:00
										 |  |  |         return 3 | 
					
						
							|  |  |  |     if not fromPersonId: | 
					
						
							|  |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 16:36:21 +00:00
										 |  |  |             print('DEBUG: No actor was found for ' + handle) | 
					
						
							| 
									
										
										
										
											2019-07-17 18:33:41 +00:00
										 |  |  |         return 4 | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     authHeader = createBasicAuthHeader(fromNickname, password) | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     headers = { | 
					
						
							|  |  |  |         'host': fromDomain, | 
					
						
							|  |  |  |         'Content-type': 'application/json', | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         'Authorization': authHeader | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     postResult = postJson(session, newLikeJson, [], inboxUrl, | 
					
						
							|  |  |  |                           headers, "inbox:write") | 
					
						
							|  |  |  |     if not postResult: | 
					
						
							|  |  |  |         print('WARN: POST announce failed for c2s to ' + inboxUrl) | 
					
						
							|  |  |  |         return 5 | 
					
						
							| 
									
										
										
										
											2019-07-17 18:33:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if debug: | 
					
						
							|  |  |  |         print('DEBUG: c2s POST like success') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return newLikeJson | 
					
						
							| 
									
										
										
										
											2019-07-17 19:04:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def sendUndoLikeViaServer(baseDir: str, session, | 
					
						
							|  |  |  |                           fromNickname: str, password: str, | 
					
						
							|  |  |  |                           fromDomain: str, fromPort: int, | 
					
						
							|  |  |  |                           httpPrefix: str, likeUrl: str, | 
					
						
							|  |  |  |                           cachedWebfingers: {}, personCache: {}, | 
					
						
							|  |  |  |                           debug: bool, projectVersion: str) -> {}: | 
					
						
							| 
									
										
										
										
											2019-07-17 19:04:00 +00:00
										 |  |  |     """Undo a like via c2s
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not session: | 
					
						
							|  |  |  |         print('WARN: No session for sendUndoLikeViaServer') | 
					
						
							|  |  |  |         return 6 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     fromDomainFull = fromDomain | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |     if fromPort: | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |         if fromPort != 80 and fromPort != 443: | 
					
						
							| 
									
										
										
										
											2019-08-16 20:35:11 +00:00
										 |  |  |             if ':' not in fromDomain: | 
					
						
							| 
									
										
										
										
											2020-04-03 16:36:21 +00:00
										 |  |  |                 fromDomainFull = fromDomain + ':' + str(fromPort) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     actor = httpPrefix + '://' + fromDomainFull + '/users/' + fromNickname | 
					
						
							| 
									
										
										
										
											2019-07-17 19:04:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     newUndoLikeJson = { | 
					
						
							| 
									
										
										
										
											2019-08-18 11:07:06 +00:00
										 |  |  |         "@context": "https://www.w3.org/ns/activitystreams", | 
					
						
							| 
									
										
										
										
											2019-07-17 19:04:00 +00:00
										 |  |  |         'type': 'Undo', | 
					
						
							| 
									
										
										
										
											2020-04-03 16:36:21 +00:00
										 |  |  |         'actor': actor, | 
					
						
							| 
									
										
										
										
											2019-07-17 19:04:00 +00:00
										 |  |  |         'object': { | 
					
						
							|  |  |  |             'type': 'Like', | 
					
						
							| 
									
										
										
										
											2020-04-03 16:36:21 +00:00
										 |  |  |             'actor': actor, | 
					
						
							| 
									
										
										
										
											2019-08-18 16:58:50 +00:00
										 |  |  |             'object': likeUrl | 
					
						
							| 
									
										
										
										
											2019-07-17 19:04:00 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 16:36:21 +00:00
										 |  |  |     handle = httpPrefix + '://' + fromDomainFull + '/@' + fromNickname | 
					
						
							| 
									
										
										
										
											2019-07-17 19:04:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # lookup the inbox for the To handle | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     wfRequest = webfingerHandle(session, handle, httpPrefix, | 
					
						
							|  |  |  |                                 cachedWebfingers, | 
					
						
							|  |  |  |                                 fromDomain, projectVersion) | 
					
						
							| 
									
										
										
										
											2019-07-17 19:04:00 +00:00
										 |  |  |     if not wfRequest: | 
					
						
							|  |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 16:36:21 +00:00
										 |  |  |             print('DEBUG: announce webfinger failed for ' + handle) | 
					
						
							| 
									
										
										
										
											2019-07-17 19:04:00 +00:00
										 |  |  |         return 1 | 
					
						
							| 
									
										
										
										
											2020-06-23 10:41:12 +00:00
										 |  |  |     if not isinstance(wfRequest, dict): | 
					
						
							|  |  |  |         print('WARN: Webfinger for ' + handle + ' did not return a dict. ' + | 
					
						
							|  |  |  |               str(wfRequest)) | 
					
						
							|  |  |  |         return 1 | 
					
						
							| 
									
										
										
										
											2019-07-17 19:04:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     postToBox = 'outbox' | 
					
						
							| 
									
										
										
										
											2019-07-17 19:04:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # get the actor inbox for the To handle | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     (inboxUrl, pubKeyId, pubKey, fromPersonId, | 
					
						
							|  |  |  |      sharedInbox, capabilityAcquisition, | 
					
						
							|  |  |  |      avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest, | 
					
						
							|  |  |  |                                             personCache, projectVersion, | 
					
						
							|  |  |  |                                             httpPrefix, fromNickname, | 
					
						
							|  |  |  |                                             fromDomain, postToBox) | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-17 19:04:00 +00:00
										 |  |  |     if not inboxUrl: | 
					
						
							|  |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 16:36:21 +00:00
										 |  |  |             print('DEBUG: No ' + postToBox + ' was found for ' + handle) | 
					
						
							| 
									
										
										
										
											2019-07-17 19:04:00 +00:00
										 |  |  |         return 3 | 
					
						
							|  |  |  |     if not fromPersonId: | 
					
						
							|  |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 16:36:21 +00:00
										 |  |  |             print('DEBUG: No actor was found for ' + handle) | 
					
						
							| 
									
										
										
										
											2019-07-17 19:04:00 +00:00
										 |  |  |         return 4 | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     authHeader = createBasicAuthHeader(fromNickname, password) | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     headers = { | 
					
						
							|  |  |  |         'host': fromDomain, | 
					
						
							|  |  |  |         'Content-type': 'application/json', | 
					
						
							| 
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 |  |  |         'Authorization': authHeader | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     postResult = postJson(session, newUndoLikeJson, [], inboxUrl, | 
					
						
							|  |  |  |                           headers, "inbox:write") | 
					
						
							|  |  |  |     if not postResult: | 
					
						
							|  |  |  |         print('WARN: POST announce failed for c2s to ' + inboxUrl) | 
					
						
							|  |  |  |         return 5 | 
					
						
							| 
									
										
										
										
											2019-07-17 19:04:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if debug: | 
					
						
							|  |  |  |         print('DEBUG: c2s POST undo like success') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return newUndoLikeJson | 
					
						
							| 
									
										
										
										
											2019-07-17 19:31:52 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def outboxLike(recentPostsCache: {}, | 
					
						
							|  |  |  |                baseDir: str, httpPrefix: str, | 
					
						
							|  |  |  |                nickname: str, domain: str, port: int, | 
					
						
							|  |  |  |                messageJson: {}, debug: bool) -> None: | 
					
						
							| 
									
										
										
										
											2019-07-17 19:31:52 +00:00
										 |  |  |     """ When a like request is received by the outbox from c2s
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not messageJson.get('type'): | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: like - no type') | 
					
						
							|  |  |  |         return | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     if not messageJson['type'] == 'Like': | 
					
						
							| 
									
										
										
										
											2019-07-17 19:31:52 +00:00
										 |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: not a like') | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     if not messageJson.get('object'): | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: no object in like') | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     if not isinstance(messageJson['object'], str): | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: like object is not string') | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     if debug: | 
					
						
							|  |  |  |         print('DEBUG: c2s like request arrived in outbox') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     messageId = messageJson['object'].replace('/activity', '') | 
					
						
							| 
									
										
										
										
											2019-07-17 19:31:52 +00:00
										 |  |  |     if ':' in domain: | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |         domain = domain.split(':')[0] | 
					
						
							|  |  |  |     postFilename = locatePost(baseDir, nickname, domain, messageId) | 
					
						
							| 
									
										
										
										
											2019-07-17 19:31:52 +00:00
										 |  |  |     if not postFilename: | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: c2s like post not found in inbox or outbox') | 
					
						
							|  |  |  |             print(messageId) | 
					
						
							|  |  |  |         return True | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     updateLikesCollection(recentPostsCache, | 
					
						
							|  |  |  |                           baseDir, postFilename, messageId, | 
					
						
							|  |  |  |                           messageJson['actor'], domain, debug) | 
					
						
							| 
									
										
										
										
											2019-07-17 19:31:52 +00:00
										 |  |  |     if debug: | 
					
						
							| 
									
										
										
										
											2020-04-03 16:36:21 +00:00
										 |  |  |         print('DEBUG: post liked via c2s - ' + postFilename) | 
					
						
							| 
									
										
										
										
											2019-07-17 19:55:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def outboxUndoLike(recentPostsCache: {}, | 
					
						
							|  |  |  |                    baseDir: str, httpPrefix: str, | 
					
						
							|  |  |  |                    nickname: str, domain: str, port: int, | 
					
						
							|  |  |  |                    messageJson: {}, debug: bool) -> None: | 
					
						
							| 
									
										
										
										
											2019-07-17 19:55:24 +00:00
										 |  |  |     """ When an undo like request is received by the outbox from c2s
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if not messageJson.get('type'): | 
					
						
							|  |  |  |         return | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     if not messageJson['type'] == 'Undo': | 
					
						
							| 
									
										
										
										
											2019-07-17 19:55:24 +00:00
										 |  |  |         return | 
					
						
							|  |  |  |     if not messageJson.get('object'): | 
					
						
							|  |  |  |         return | 
					
						
							| 
									
										
										
										
											2019-08-01 12:49:16 +00:00
										 |  |  |     if not isinstance(messageJson['object'], dict): | 
					
						
							| 
									
										
										
										
											2019-07-17 19:55:24 +00:00
										 |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: undo like object is not dict') | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2019-07-17 19:55:24 +00:00
										 |  |  |     if not messageJson['object'].get('type'): | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: undo like - no type') | 
					
						
							|  |  |  |         return | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     if not messageJson['object']['type'] == 'Like': | 
					
						
							| 
									
										
										
										
											2019-07-17 19:55:24 +00:00
										 |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: not a undo like') | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     if not messageJson['object'].get('object'): | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: no object in undo like') | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     if not isinstance(messageJson['object']['object'], str): | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: undo like object is not string') | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     if debug: | 
					
						
							|  |  |  |         print('DEBUG: c2s undo like request arrived in outbox') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     messageId = messageJson['object']['object'].replace('/activity', '') | 
					
						
							| 
									
										
										
										
											2019-07-17 19:55:24 +00:00
										 |  |  |     if ':' in domain: | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |         domain = domain.split(':')[0] | 
					
						
							|  |  |  |     postFilename = locatePost(baseDir, nickname, domain, messageId) | 
					
						
							| 
									
										
										
										
											2019-07-17 19:55:24 +00:00
										 |  |  |     if not postFilename: | 
					
						
							|  |  |  |         if debug: | 
					
						
							|  |  |  |             print('DEBUG: c2s undo like post not found in inbox or outbox') | 
					
						
							|  |  |  |             print(messageId) | 
					
						
							|  |  |  |         return True | 
					
						
							| 
									
										
										
										
											2020-04-01 10:44:33 +00:00
										 |  |  |     undoLikesCollectionEntry(recentPostsCache, baseDir, postFilename, | 
					
						
							|  |  |  |                              messageId, messageJson['actor'], | 
					
						
							|  |  |  |                              domain, debug) | 
					
						
							| 
									
										
										
										
											2019-07-17 19:55:24 +00:00
										 |  |  |     if debug: | 
					
						
							|  |  |  |         print('DEBUG: post undo liked via c2s - '+postFilename) |