forked from indymedia/epicyon
				
			
		
			
				
	
	
		
			683 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			683 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Python
		
	
	
| __filename__ = "bookmarks.py"
 | |
| __author__ = "Bob Mottram"
 | |
| __license__ = "AGPL3+"
 | |
| __version__ = "1.1.0"
 | |
| __maintainer__ = "Bob Mottram"
 | |
| __email__ = "bob@freedombone.net"
 | |
| __status__ = "Production"
 | |
| 
 | |
| import os
 | |
| from pprint import pprint
 | |
| from utils import removeIdEnding
 | |
| from utils import removePostFromCache
 | |
| from utils import urlPermitted
 | |
| from utils import getNicknameFromActor
 | |
| from utils import getDomainFromActor
 | |
| from utils import locatePost
 | |
| from utils import getCachedPostFilename
 | |
| from utils import loadJson
 | |
| from utils import saveJson
 | |
| from session import postJson
 | |
| from webfinger import webfingerHandle
 | |
| from auth import createBasicAuthHeader
 | |
| from posts import getPersonBox
 | |
| 
 | |
| 
 | |
| def undoBookmarksCollectionEntry(recentPostsCache: {},
 | |
|                                  baseDir: str, postFilename: str,
 | |
|                                  objectUrl: str,
 | |
|                                  actor: str, domain: str, debug: bool) -> None:
 | |
|     """Undoes a bookmark for a particular actor
 | |
|     """
 | |
|     postJsonObject = loadJson(postFilename)
 | |
|     if not postJsonObject:
 | |
|         return
 | |
| 
 | |
|     # remove any cached version of this post so that the
 | |
|     # bookmark icon is changed
 | |
|     nickname = getNicknameFromActor(actor)
 | |
|     cachedPostFilename = getCachedPostFilename(baseDir, nickname,
 | |
|                                                domain, postJsonObject)
 | |
|     if cachedPostFilename:
 | |
|         if os.path.isfile(cachedPostFilename):
 | |
|             os.remove(cachedPostFilename)
 | |
|     removePostFromCache(postJsonObject, recentPostsCache)
 | |
| 
 | |
|     # remove from the index
 | |
|     bookmarksIndexFilename = baseDir + '/accounts/' + \
 | |
|         nickname + '@' + domain + '/bookmarks.index'
 | |
|     if not os.path.isfile(bookmarksIndexFilename):
 | |
|         return
 | |
|     if '/' in postFilename:
 | |
|         bookmarkIndex = postFilename.split('/')[-1].strip()
 | |
|     else:
 | |
|         bookmarkIndex = postFilename.strip()
 | |
|     bookmarkIndex = bookmarkIndex.replace('\n', '').replace('\r', '')
 | |
|     if bookmarkIndex not in open(bookmarksIndexFilename).read():
 | |
|         return
 | |
|     indexStr = ''
 | |
|     with open(bookmarksIndexFilename, 'r') as indexFile:
 | |
|         indexStr = indexFile.read().replace(bookmarkIndex + '\n', '')
 | |
|         bookmarksIndexFile = open(bookmarksIndexFilename, 'w+')
 | |
|         if bookmarksIndexFile:
 | |
|             bookmarksIndexFile.write(indexStr)
 | |
|             bookmarksIndexFile.close()
 | |
| 
 | |
|     if not postJsonObject.get('type'):
 | |
|         return
 | |
|     if postJsonObject['type'] != 'Create':
 | |
|         return
 | |
|     if not postJsonObject.get('object'):
 | |
|         if debug:
 | |
|             pprint(postJsonObject)
 | |
|             print('DEBUG: post ' + objectUrl + ' has no object')
 | |
|         return
 | |
|     if not isinstance(postJsonObject['object'], dict):
 | |
|         return
 | |
|     if not postJsonObject['object'].get('bookmarks'):
 | |
|         return
 | |
|     if not isinstance(postJsonObject['object']['bookmarks'], dict):
 | |
|         return
 | |
|     if not postJsonObject['object']['bookmarks'].get('items'):
 | |
|         return
 | |
|     totalItems = 0
 | |
|     if postJsonObject['object']['bookmarks'].get('totalItems'):
 | |
|         totalItems = postJsonObject['object']['bookmarks']['totalItems']
 | |
|         itemFound = False
 | |
|     for bookmarkItem in postJsonObject['object']['bookmarks']['items']:
 | |
|         if bookmarkItem.get('actor'):
 | |
|             if bookmarkItem['actor'] == actor:
 | |
|                 if debug:
 | |
|                     print('DEBUG: bookmark was removed for ' + actor)
 | |
|                 bmIt = bookmarkItem
 | |
|                 postJsonObject['object']['bookmarks']['items'].remove(bmIt)
 | |
|                 itemFound = True
 | |
|                 break
 | |
| 
 | |
|     if not itemFound:
 | |
|         return
 | |
| 
 | |
|     if totalItems == 1:
 | |
|         if debug:
 | |
|             print('DEBUG: bookmarks was removed from post')
 | |
|         del postJsonObject['object']['bookmarks']
 | |
|     else:
 | |
|         bmItLen = len(postJsonObject['object']['bookmarks']['items'])
 | |
|         postJsonObject['object']['bookmarks']['totalItems'] = bmItLen
 | |
|     saveJson(postJsonObject, postFilename)
 | |
| 
 | |
| 
 | |
| def bookmarkedByPerson(postJsonObject: {}, nickname: str, domain: str) -> bool:
 | |
|     """Returns True if the given post is bookmarked by the given person
 | |
|     """
 | |
|     if noOfBookmarks(postJsonObject) == 0:
 | |
|         return False
 | |
|     actorMatch = domain + '/users/' + nickname
 | |
|     for item in postJsonObject['object']['bookmarks']['items']:
 | |
|         if item['actor'].endswith(actorMatch):
 | |
|             return True
 | |
|     return False
 | |
| 
 | |
| 
 | |
| def noOfBookmarks(postJsonObject: {}) -> int:
 | |
|     """Returns the number of bookmarks ona  given post
 | |
|     """
 | |
|     if not postJsonObject.get('object'):
 | |
|         return 0
 | |
|     if not isinstance(postJsonObject['object'], dict):
 | |
|         return 0
 | |
|     if not postJsonObject['object'].get('bookmarks'):
 | |
|         return 0
 | |
|     if not isinstance(postJsonObject['object']['bookmarks'], dict):
 | |
|         return 0
 | |
|     if not postJsonObject['object']['bookmarks'].get('items'):
 | |
|         postJsonObject['object']['bookmarks']['items'] = []
 | |
|         postJsonObject['object']['bookmarks']['totalItems'] = 0
 | |
|     return len(postJsonObject['object']['bookmarks']['items'])
 | |
| 
 | |
| 
 | |
| def updateBookmarksCollection(recentPostsCache: {},
 | |
|                               baseDir: str, postFilename: str,
 | |
|                               objectUrl: str,
 | |
|                               actor: str, domain: str, debug: bool) -> None:
 | |
|     """Updates the bookmarks collection within a post
 | |
|     """
 | |
|     postJsonObject = loadJson(postFilename)
 | |
|     if postJsonObject:
 | |
|         # remove any cached version of this post so that the
 | |
|         # bookmark icon is changed
 | |
|         nickname = getNicknameFromActor(actor)
 | |
|         cachedPostFilename = getCachedPostFilename(baseDir, nickname,
 | |
|                                                    domain, postJsonObject)
 | |
|         if cachedPostFilename:
 | |
|             if os.path.isfile(cachedPostFilename):
 | |
|                 os.remove(cachedPostFilename)
 | |
|         removePostFromCache(postJsonObject, recentPostsCache)
 | |
| 
 | |
|         if not postJsonObject.get('object'):
 | |
|             if debug:
 | |
|                 pprint(postJsonObject)
 | |
|                 print('DEBUG: post ' + objectUrl + ' has no object')
 | |
|             return
 | |
|         if not objectUrl.endswith('/bookmarks'):
 | |
|             objectUrl = objectUrl + '/bookmarks'
 | |
|         if not postJsonObject['object'].get('bookmarks'):
 | |
|             if debug:
 | |
|                 print('DEBUG: Adding initial bookmarks to ' + objectUrl)
 | |
|             bookmarksJson = {
 | |
|                 "@context": "https://www.w3.org/ns/activitystreams",
 | |
|                 'id': objectUrl,
 | |
|                 'type': 'Collection',
 | |
|                 "totalItems": 1,
 | |
|                 'items': [{
 | |
|                     'type': 'Bookmark',
 | |
|                     'actor': actor
 | |
|                 }]
 | |
|             }
 | |
|             postJsonObject['object']['bookmarks'] = bookmarksJson
 | |
|         else:
 | |
|             if not postJsonObject['object']['bookmarks'].get('items'):
 | |
|                 postJsonObject['object']['bookmarks']['items'] = []
 | |
|             for bookmarkItem in postJsonObject['object']['bookmarks']['items']:
 | |
|                 if bookmarkItem.get('actor'):
 | |
|                     if bookmarkItem['actor'] == actor:
 | |
|                         return
 | |
|                     newBookmark = {
 | |
|                         'type': 'Bookmark',
 | |
|                         'actor': actor
 | |
|                     }
 | |
|                     nb = newBookmark
 | |
|                     bmIt = len(postJsonObject['object']['bookmarks']['items'])
 | |
|                     postJsonObject['object']['bookmarks']['items'].append(nb)
 | |
|                     postJsonObject['object']['bookmarks']['totalItems'] = bmIt
 | |
| 
 | |
|         if debug:
 | |
|             print('DEBUG: saving post with bookmarks added')
 | |
|             pprint(postJsonObject)
 | |
| 
 | |
|         saveJson(postJsonObject, postFilename)
 | |
| 
 | |
|         # prepend to the index
 | |
|         bookmarksIndexFilename = baseDir + '/accounts/' + \
 | |
|             nickname + '@' + domain + '/bookmarks.index'
 | |
|         bookmarkIndex = postFilename.split('/')[-1]
 | |
|         if os.path.isfile(bookmarksIndexFilename):
 | |
|             if bookmarkIndex not in open(bookmarksIndexFilename).read():
 | |
|                 try:
 | |
|                     with open(bookmarksIndexFilename, 'r+') as bmIndexFile:
 | |
|                         content = bmIndexFile.read()
 | |
|                         bmIndexFile.seek(0, 0)
 | |
|                         bmIndexFile.write(bookmarkIndex + '\n' + content)
 | |
|                         if debug:
 | |
|                             print('DEBUG: bookmark added to index')
 | |
|                 except Exception as e:
 | |
|                     print('WARN: Failed to write entry to bookmarks index ' +
 | |
|                           bookmarksIndexFilename + ' ' + str(e))
 | |
|         else:
 | |
|             bookmarksIndexFile = open(bookmarksIndexFilename, 'w+')
 | |
|             if bookmarksIndexFile:
 | |
|                 bookmarksIndexFile.write(bookmarkIndex + '\n')
 | |
|                 bookmarksIndexFile.close()
 | |
| 
 | |
| 
 | |
| def bookmark(recentPostsCache: {},
 | |
|              session, baseDir: str, federationList: [],
 | |
|              nickname: str, domain: str, port: int,
 | |
|              ccList: [], httpPrefix: str,
 | |
|              objectUrl: str, actorBookmarked: str,
 | |
|              clientToServer: bool,
 | |
|              sendThreads: [], postLog: [],
 | |
|              personCache: {}, cachedWebfingers: {},
 | |
|              debug: bool, projectVersion: str) -> {}:
 | |
|     """Creates a bookmark
 | |
|     actor is the person doing the bookmarking
 | |
|     'to' might be a specific person (actor) whose post was bookmarked
 | |
|     object is typically the url of the message which was bookmarked
 | |
|     """
 | |
|     if not urlPermitted(objectUrl, federationList):
 | |
|         return None
 | |
| 
 | |
|     fullDomain = domain
 | |
|     if port:
 | |
|         if port != 80 and port != 443:
 | |
|             if ':' not in domain:
 | |
|                 fullDomain = domain + ':' + str(port)
 | |
| 
 | |
|     newBookmarkJson = {
 | |
|         "@context": "https://www.w3.org/ns/activitystreams",
 | |
|         'type': 'Bookmark',
 | |
|         'actor': httpPrefix+'://'+fullDomain+'/users/'+nickname,
 | |
|         'object': objectUrl
 | |
|     }
 | |
|     if ccList:
 | |
|         if len(ccList) > 0:
 | |
|             newBookmarkJson['cc'] = ccList
 | |
| 
 | |
|     # Extract the domain and nickname from a statuses link
 | |
|     bookmarkedPostNickname = None
 | |
|     bookmarkedPostDomain = None
 | |
|     bookmarkedPostPort = None
 | |
|     if actorBookmarked:
 | |
|         acBm = actorBookmarked
 | |
|         bookmarkedPostNickname = getNicknameFromActor(acBm)
 | |
|         bookmarkedPostDomain, bookmarkedPostPort = getDomainFromActor(acBm)
 | |
|     else:
 | |
|         if '/users/' in objectUrl or \
 | |
|            '/accounts/' in objectUrl or \
 | |
|            '/channel/' in objectUrl or \
 | |
|            '/profile/' in objectUrl:
 | |
|             ou = objectUrl
 | |
|             bookmarkedPostNickname = getNicknameFromActor(ou)
 | |
|             bookmarkedPostDomain, bookmarkedPostPort = getDomainFromActor(ou)
 | |
| 
 | |
|     if bookmarkedPostNickname:
 | |
|         postFilename = locatePost(baseDir, nickname, domain, objectUrl)
 | |
|         if not postFilename:
 | |
|             print('DEBUG: bookmark baseDir: ' + baseDir)
 | |
|             print('DEBUG: bookmark nickname: ' + nickname)
 | |
|             print('DEBUG: bookmark domain: ' + domain)
 | |
|             print('DEBUG: bookmark objectUrl: ' + objectUrl)
 | |
|             return None
 | |
| 
 | |
|         updateBookmarksCollection(recentPostsCache,
 | |
|                                   baseDir, postFilename, objectUrl,
 | |
|                                   newBookmarkJson['actor'], domain, debug)
 | |
| 
 | |
|     return newBookmarkJson
 | |
| 
 | |
| 
 | |
| def bookmarkPost(recentPostsCache: {},
 | |
|                  session, baseDir: str, federationList: [],
 | |
|                  nickname: str, domain: str, port: int, httpPrefix: str,
 | |
|                  bookmarkNickname: str, bookmarkedomain: str,
 | |
|                  bookmarkPort: int,
 | |
|                  ccList: [],
 | |
|                  bookmarkStatusNumber: int, clientToServer: bool,
 | |
|                  sendThreads: [], postLog: [],
 | |
|                  personCache: {}, cachedWebfingers: {},
 | |
|                  debug: bool, projectVersion: str) -> {}:
 | |
|     """Bookmarks a given status post. This is only used by unit tests
 | |
|     """
 | |
|     bookmarkedomain = bookmarkedomain
 | |
|     if bookmarkPort:
 | |
|         if bookmarkPort != 80 and bookmarkPort != 443:
 | |
|             if ':' not in bookmarkedomain:
 | |
|                 bookmarkedomain = bookmarkedomain + ':' + str(bookmarkPort)
 | |
| 
 | |
|     actorBookmarked = httpPrefix + '://' + bookmarkedomain + \
 | |
|         '/users/' + bookmarkNickname
 | |
|     objectUrl = actorBookmarked + '/statuses/' + str(bookmarkStatusNumber)
 | |
| 
 | |
|     return bookmark(recentPostsCache,
 | |
|                     session, baseDir, federationList, nickname, domain, port,
 | |
|                     ccList, httpPrefix, objectUrl, actorBookmarked,
 | |
|                     clientToServer,
 | |
|                     sendThreads, postLog, personCache, cachedWebfingers,
 | |
|                     debug, projectVersion)
 | |
| 
 | |
| 
 | |
| def undoBookmark(recentPostsCache: {},
 | |
|                  session, baseDir: str, federationList: [],
 | |
|                  nickname: str, domain: str, port: int,
 | |
|                  ccList: [], httpPrefix: str,
 | |
|                  objectUrl: str, actorBookmarked: str,
 | |
|                  clientToServer: bool,
 | |
|                  sendThreads: [], postLog: [],
 | |
|                  personCache: {}, cachedWebfingers: {},
 | |
|                  debug: bool, projectVersion: str) -> {}:
 | |
|     """Removes a bookmark
 | |
|     actor is the person doing the bookmarking
 | |
|     'to' might be a specific person (actor) whose post was bookmarked
 | |
|     object is typically the url of the message which was bookmarked
 | |
|     """
 | |
|     if not urlPermitted(objectUrl, federationList):
 | |
|         return None
 | |
| 
 | |
|     fullDomain = domain
 | |
|     if port:
 | |
|         if port != 80 and port != 443:
 | |
|             if ':' not in domain:
 | |
|                 fullDomain = domain + ':' + str(port)
 | |
| 
 | |
|     newUndoBookmarkJson = {
 | |
|         "@context": "https://www.w3.org/ns/activitystreams",
 | |
|         'type': 'Undo',
 | |
|         'actor': httpPrefix+'://'+fullDomain+'/users/'+nickname,
 | |
|         'object': {
 | |
|             'type': 'Bookmark',
 | |
|             'actor': httpPrefix+'://'+fullDomain+'/users/'+nickname,
 | |
|             'object': objectUrl
 | |
|         }
 | |
|     }
 | |
|     if ccList:
 | |
|         if len(ccList) > 0:
 | |
|             newUndoBookmarkJson['cc'] = ccList
 | |
|             newUndoBookmarkJson['object']['cc'] = ccList
 | |
| 
 | |
|     # Extract the domain and nickname from a statuses link
 | |
|     bookmarkedPostNickname = None
 | |
|     bookmarkedPostDomain = None
 | |
|     bookmarkedPostPort = None
 | |
|     if actorBookmarked:
 | |
|         acBm = actorBookmarked
 | |
|         bookmarkedPostNickname = getNicknameFromActor(acBm)
 | |
|         bookmarkedPostDomain, bookmarkedPostPort = getDomainFromActor(acBm)
 | |
|     else:
 | |
|         if '/users/' in objectUrl or \
 | |
|            '/accounts/' in objectUrl or \
 | |
|            '/channel/' in objectUrl or \
 | |
|            '/profile/' in objectUrl:
 | |
|             ou = objectUrl
 | |
|             bookmarkedPostNickname = getNicknameFromActor(ou)
 | |
|             bookmarkedPostDomain, bookmarkedPostPort = getDomainFromActor(ou)
 | |
| 
 | |
|     if bookmarkedPostNickname:
 | |
|         postFilename = locatePost(baseDir, nickname, domain, objectUrl)
 | |
|         if not postFilename:
 | |
|             return None
 | |
| 
 | |
|         undoBookmarksCollectionEntry(recentPostsCache,
 | |
|                                      baseDir, postFilename, objectUrl,
 | |
|                                      newUndoBookmarkJson['actor'],
 | |
|                                      domain, debug)
 | |
|     else:
 | |
|         return None
 | |
| 
 | |
|     return newUndoBookmarkJson
 | |
| 
 | |
| 
 | |
| def undoBookmarkPost(session, baseDir: str, federationList: [],
 | |
|                      nickname: str, domain: str, port: int, httpPrefix: str,
 | |
|                      bookmarkNickname: str, bookmarkedomain: str,
 | |
|                      bookmarkPort: int, ccList: [],
 | |
|                      bookmarkStatusNumber: int, clientToServer: bool,
 | |
|                      sendThreads: [], postLog: [],
 | |
|                      personCache: {}, cachedWebfingers: {},
 | |
|                      debug: bool) -> {}:
 | |
|     """Removes a bookmarked post
 | |
|     """
 | |
|     bookmarkedomain = bookmarkedomain
 | |
|     if bookmarkPort:
 | |
|         if bookmarkPort != 80 and bookmarkPort != 443:
 | |
|             if ':' not in bookmarkedomain:
 | |
|                 bookmarkedomain = bookmarkedomain + ':' + str(bookmarkPort)
 | |
| 
 | |
|     objectUrl = httpPrefix + '://' + bookmarkedomain + \
 | |
|         '/users/' + bookmarkNickname + \
 | |
|         '/statuses/' + str(bookmarkStatusNumber)
 | |
| 
 | |
|     return undoBookmark(session, baseDir, federationList,
 | |
|                         nickname, domain, port,
 | |
|                         ccList, httpPrefix, objectUrl, clientToServer,
 | |
|                         sendThreads, postLog, personCache,
 | |
|                         cachedWebfingers, debug)
 | |
| 
 | |
| 
 | |
| def sendBookmarkViaServer(baseDir: str, session,
 | |
|                           fromNickname: str, password: str,
 | |
|                           fromDomain: str, fromPort: int,
 | |
|                           httpPrefix: str, bookmarkUrl: str,
 | |
|                           cachedWebfingers: {}, personCache: {},
 | |
|                           debug: bool, projectVersion: str) -> {}:
 | |
|     """Creates a bookmark via c2s
 | |
|     """
 | |
|     if not session:
 | |
|         print('WARN: No session for sendBookmarkViaServer')
 | |
|         return 6
 | |
| 
 | |
|     fromDomainFull = fromDomain
 | |
|     if fromPort:
 | |
|         if fromPort != 80 and fromPort != 443:
 | |
|             if ':' not in fromDomain:
 | |
|                 fromDomainFull = fromDomain + ':' + str(fromPort)
 | |
| 
 | |
|     newBookmarkJson = {
 | |
|         "@context": "https://www.w3.org/ns/activitystreams",
 | |
|         'type': 'Bookmark',
 | |
|         'actor': httpPrefix+'://'+fromDomainFull+'/users/'+fromNickname,
 | |
|         'object': bookmarkUrl
 | |
|     }
 | |
| 
 | |
|     handle = httpPrefix + '://' + fromDomainFull + '/@' + fromNickname
 | |
| 
 | |
|     # lookup the inbox for the To handle
 | |
|     wfRequest = webfingerHandle(session, handle, httpPrefix,
 | |
|                                 cachedWebfingers,
 | |
|                                 fromDomain, projectVersion)
 | |
|     if not wfRequest:
 | |
|         if debug:
 | |
|             print('DEBUG: announce webfinger failed for ' + handle)
 | |
|         return 1
 | |
|     if not isinstance(wfRequest, dict):
 | |
|         print('WARN: Webfinger for ' + handle + ' did not return a dict. ' +
 | |
|               str(wfRequest))
 | |
|         return 1
 | |
| 
 | |
|     postToBox = 'outbox'
 | |
| 
 | |
|     # get the actor inbox for the To handle
 | |
|     (inboxUrl, pubKeyId, pubKey,
 | |
|      fromPersonId, sharedInbox, avatarUrl,
 | |
|      displayName) = getPersonBox(baseDir, session, wfRequest, personCache,
 | |
|                                  projectVersion, httpPrefix, fromNickname,
 | |
|                                  fromDomain, postToBox)
 | |
| 
 | |
|     if not inboxUrl:
 | |
|         if debug:
 | |
|             print('DEBUG: No ' + postToBox + ' was found for ' + handle)
 | |
|         return 3
 | |
|     if not fromPersonId:
 | |
|         if debug:
 | |
|             print('DEBUG: No actor was found for ' + handle)
 | |
|         return 4
 | |
| 
 | |
|     authHeader = createBasicAuthHeader(fromNickname, password)
 | |
| 
 | |
|     headers = {
 | |
|         'host': fromDomain,
 | |
|         'Content-type': 'application/json',
 | |
|         'Authorization': authHeader
 | |
|     }
 | |
|     postResult = postJson(session, newBookmarkJson, [],
 | |
|                           inboxUrl, headers)
 | |
|     if not postResult:
 | |
|         if debug:
 | |
|             print('DEBUG: POST announce failed for c2s to ' + inboxUrl)
 | |
|         return 5
 | |
| 
 | |
|     if debug:
 | |
|         print('DEBUG: c2s POST bookmark success')
 | |
| 
 | |
|     return newBookmarkJson
 | |
| 
 | |
| 
 | |
| def sendUndoBookmarkViaServer(baseDir: str, session,
 | |
|                               fromNickname: str, password: str,
 | |
|                               fromDomain: str, fromPort: int,
 | |
|                               httpPrefix: str, bookmarkUrl: str,
 | |
|                               cachedWebfingers: {}, personCache: {},
 | |
|                               debug: bool, projectVersion: str) -> {}:
 | |
|     """Undo a bookmark via c2s
 | |
|     """
 | |
|     if not session:
 | |
|         print('WARN: No session for sendUndoBookmarkViaServer')
 | |
|         return 6
 | |
| 
 | |
|     fromDomainFull = fromDomain
 | |
|     if fromPort:
 | |
|         if fromPort != 80 and fromPort != 443:
 | |
|             if ':' not in fromDomain:
 | |
|                 fromDomainFull = fromDomain + ':' + str(fromPort)
 | |
| 
 | |
|     newUndoBookmarkJson = {
 | |
|         "@context": "https://www.w3.org/ns/activitystreams",
 | |
|         'type': 'Undo',
 | |
|         'actor': httpPrefix+'://'+fromDomainFull+'/users/'+fromNickname,
 | |
|         'object': {
 | |
|             'type': 'Bookmark',
 | |
|             'actor': httpPrefix+'://'+fromDomainFull+'/users/'+fromNickname,
 | |
|             'object': bookmarkUrl
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     handle = httpPrefix + '://' + fromDomainFull + '/@' + fromNickname
 | |
| 
 | |
|     # lookup the inbox for the To handle
 | |
|     wfRequest = webfingerHandle(session, handle, httpPrefix, cachedWebfingers,
 | |
|                                 fromDomain, projectVersion)
 | |
|     if not wfRequest:
 | |
|         if debug:
 | |
|             print('DEBUG: announce webfinger failed for ' + handle)
 | |
|         return 1
 | |
|     if not isinstance(wfRequest, dict):
 | |
|         print('WARN: Webfinger for ' + handle + ' did not return a dict. ' +
 | |
|               str(wfRequest))
 | |
|         return 1
 | |
| 
 | |
|     postToBox = 'outbox'
 | |
| 
 | |
|     # get the actor inbox for the To handle
 | |
|     (inboxUrl, pubKeyId, pubKey,
 | |
|      fromPersonId, sharedInbox, avatarUrl,
 | |
|      displayName) = getPersonBox(baseDir, session, wfRequest, personCache,
 | |
|                                  projectVersion, httpPrefix, fromNickname,
 | |
|                                  fromDomain, postToBox)
 | |
| 
 | |
|     if not inboxUrl:
 | |
|         if debug:
 | |
|             print('DEBUG: No ' + postToBox + ' was found for ' + handle)
 | |
|         return 3
 | |
|     if not fromPersonId:
 | |
|         if debug:
 | |
|             print('DEBUG: No actor was found for ' + handle)
 | |
|         return 4
 | |
| 
 | |
|     authHeader = createBasicAuthHeader(fromNickname, password)
 | |
| 
 | |
|     headers = {
 | |
|         'host': fromDomain,
 | |
|         'Content-type': 'application/json',
 | |
|         'Authorization': authHeader
 | |
|     }
 | |
|     postResult = postJson(session, newUndoBookmarkJson, [],
 | |
|                           inboxUrl, headers)
 | |
|     if not postResult:
 | |
|         if debug:
 | |
|             print('DEBUG: POST announce failed for c2s to ' + inboxUrl)
 | |
|         return 5
 | |
| 
 | |
|     if debug:
 | |
|         print('DEBUG: c2s POST undo bookmark success')
 | |
| 
 | |
|     return newUndoBookmarkJson
 | |
| 
 | |
| 
 | |
| def outboxBookmark(recentPostsCache: {},
 | |
|                    baseDir: str, httpPrefix: str,
 | |
|                    nickname: str, domain: str, port: int,
 | |
|                    messageJson: {}, debug: bool) -> None:
 | |
|     """ When a bookmark request is received by the outbox from c2s
 | |
|     """
 | |
|     if not messageJson.get('type'):
 | |
|         if debug:
 | |
|             print('DEBUG: bookmark - no type')
 | |
|         return
 | |
|     if not messageJson['type'] == 'Bookmark':
 | |
|         if debug:
 | |
|             print('DEBUG: not a bookmark')
 | |
|         return
 | |
|     if not messageJson.get('object'):
 | |
|         if debug:
 | |
|             print('DEBUG: no object in bookmark')
 | |
|         return
 | |
|     if not isinstance(messageJson['object'], str):
 | |
|         if debug:
 | |
|             print('DEBUG: bookmark object is not string')
 | |
|         return
 | |
|     if messageJson.get('to'):
 | |
|         if not isinstance(messageJson['to'], list):
 | |
|             return
 | |
|         if len(messageJson['to']) != 1:
 | |
|             print('WARN: Bookmark should only be sent to one recipient')
 | |
|             return
 | |
|         if messageJson['to'][0] != messageJson['actor']:
 | |
|             print('WARN: Bookmark should be addressed to the same actor')
 | |
|             return
 | |
|     if debug:
 | |
|         print('DEBUG: c2s bookmark request arrived in outbox')
 | |
| 
 | |
|     messageId = removeIdEnding(messageJson['object'])
 | |
|     if ':' in domain:
 | |
|         domain = domain.split(':')[0]
 | |
|     postFilename = locatePost(baseDir, nickname, domain, messageId)
 | |
|     if not postFilename:
 | |
|         if debug:
 | |
|             print('DEBUG: c2s bookmark post not found in inbox or outbox')
 | |
|             print(messageId)
 | |
|         return True
 | |
|     updateBookmarksCollection(recentPostsCache,
 | |
|                               baseDir, postFilename, messageId,
 | |
|                               messageJson['actor'], domain, debug)
 | |
|     if debug:
 | |
|         print('DEBUG: post bookmarked via c2s - ' + postFilename)
 | |
| 
 | |
| 
 | |
| def outboxUndoBookmark(recentPostsCache: {},
 | |
|                        baseDir: str, httpPrefix: str,
 | |
|                        nickname: str, domain: str, port: int,
 | |
|                        messageJson: {}, debug: bool) -> None:
 | |
|     """ When an undo bookmark request is received by the outbox from c2s
 | |
|     """
 | |
|     if not messageJson.get('type'):
 | |
|         return
 | |
|     if not messageJson['type'] == 'Undo':
 | |
|         return
 | |
|     if not messageJson.get('object'):
 | |
|         return
 | |
|     if not isinstance(messageJson['object'], dict):
 | |
|         if debug:
 | |
|             print('DEBUG: undo bookmark object is not dict')
 | |
|         return
 | |
|     if not messageJson['object'].get('type'):
 | |
|         if debug:
 | |
|             print('DEBUG: undo bookmark - no type')
 | |
|         return
 | |
|     if not messageJson['object']['type'] == 'Bookmark':
 | |
|         if debug:
 | |
|             print('DEBUG: not a undo bookmark')
 | |
|         return
 | |
|     if not messageJson['object'].get('object'):
 | |
|         if debug:
 | |
|             print('DEBUG: no object in undo bookmark')
 | |
|         return
 | |
|     if not isinstance(messageJson['object']['object'], str):
 | |
|         if debug:
 | |
|             print('DEBUG: undo bookmark object is not string')
 | |
|         return
 | |
|     if messageJson.get('to'):
 | |
|         if not isinstance(messageJson['to'], list):
 | |
|             return
 | |
|         if len(messageJson['to']) != 1:
 | |
|             print('WARN: Bookmark should only be sent to one recipient')
 | |
|             return
 | |
|         if messageJson['to'][0] != messageJson['actor']:
 | |
|             print('WARN: Bookmark should be addressed to the same actor')
 | |
|             return
 | |
|     if debug:
 | |
|         print('DEBUG: c2s undo bookmark request arrived in outbox')
 | |
| 
 | |
|     messageId = removeIdEnding(messageJson['object']['object'])
 | |
|     if ':' in domain:
 | |
|         domain = domain.split(':')[0]
 | |
|     postFilename = locatePost(baseDir, nickname, domain, messageId)
 | |
|     if not postFilename:
 | |
|         if debug:
 | |
|             print('DEBUG: c2s undo bookmark post not found in inbox or outbox')
 | |
|             print(messageId)
 | |
|         return True
 | |
|     undoBookmarksCollectionEntry(recentPostsCache,
 | |
|                                  baseDir, postFilename, messageId,
 | |
|                                  messageJson['actor'], domain, debug)
 | |
|     if debug:
 | |
|         print('DEBUG: post undo bookmarked via c2s - ' + postFilename)
 |