epicyon/bookmarks.py

695 lines
26 KiB
Python
Raw Normal View History

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