diff --git a/blurhash.py b/blurhash.py index edb1d59f..e31b5ff1 100644 --- a/blurhash.py +++ b/blurhash.py @@ -31,19 +31,22 @@ Very close port of the original Swift implementation by Dag Ă…gren. import math + # Alphabet for base 83 -alphabet="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~" -alphabet_values=dict(zip(alphabet,range(len(alphabet)))) +alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~" +alphabet_values = dict(zip(alphabet, range(len(alphabet)))) + def base83_decode(base83_str): """ Decodes a base83 string, as used in blurhash, to an integer. """ - value=0 + value = 0 for base83_char in base83_str: - value=value*83+alphabet_values[base83_char] + value = value * 83 + alphabet_values[base83_char] return value + def base83_encode(value, length): """ Decodes an integer to a base83 string, as used in blurhash. @@ -54,20 +57,22 @@ def base83_encode(value, length): if int(value) // (83 ** (length)) != 0: raise ValueError("Specified length is too short to encode given value.") - result="" - for i in range(1,length+1): - digit=int(value) // (83 ** (length - i)) % 83 + result = "" + for i in range(1, length+1): + digit = int(value) // (83 ** (length - i)) % 83 result += alphabet[int(digit)] return result + def srgb_to_linear(value): """ srgb 0-255 integer to linear 0.0-1.0 floating point conversion. """ - value=float(value) / 255.0 + value = float(value) / 255.0 if value <= 0.04045: return value / 12.92 - return math.pow((value+0.055) / 1.055, 2.4) + return math.pow((value + 0.055) / 1.055, 2.4) + def sign_pow(value, exp): """ @@ -75,14 +80,16 @@ def sign_pow(value, exp): """ return math.copysign(math.pow(abs(value), exp), value) + def linear_to_srgb(value): """ linear 0.0-1.0 floating point to srgb 0-255 integer conversion. """ - value=max(0.0, min(1.0, value)) + value = max(0.0, min(1.0, value)) if value <= 0.0031308: - return int(value*12.92*255+0.5) - return int((1.055*math.pow(value, 1 / 2.4)-0.055)*255+0.5) + return int(value * 12.92 * 255 + 0.5) + return int((1.055 * math.pow(value, 1 / 2.4) - 0.055) * 255 + 0.5) + def blurhash_components(blurhash): """ @@ -92,13 +99,14 @@ def blurhash_components(blurhash): raise ValueError("BlurHash must be at least 6 characters long.") # Decode metadata - size_info=base83_decode(blurhash[0]) - size_y=int(size_info / 9)+1 - size_x=(size_info % 9)+1 + size_info = base83_decode(blurhash[0]) + size_y = int(size_info / 9) + 1 + size_x = (size_info % 9) + 1 return size_x, size_y -def blurhash_decode(blurhash,width,height,punch=1.0,linear=False): + +def blurhash_decode(blurhash, width, height, punch=1.0, linear=False): """ Decodes the given blurhash to an image of the specified size. @@ -117,20 +125,20 @@ def blurhash_decode(blurhash,width,height,punch=1.0,linear=False): raise ValueError("BlurHash must be at least 6 characters long.") # Decode metadata - size_info=base83_decode(blurhash[0]) - size_y=int(size_info / 9)+1 - size_x=(size_info % 9)+1 + size_info = base83_decode(blurhash[0]) + size_y = int(size_info / 9) + 1 + size_x = (size_info % 9) + 1 - quant_max_value=base83_decode(blurhash[1]) - real_max_value=(float(quant_max_value+1)/166.0)*punch + quant_max_value = base83_decode(blurhash[1]) + real_max_value = (float(quant_max_value+1) / 166.0) * punch # Make sure we at least have the right number of characters - if len(blurhash) != 4+2*size_x*size_y: + if len(blurhash) != 4 + 2 * size_x * size_y: raise ValueError("Invalid BlurHash length.") # Decode DC component - dc_value=base83_decode(blurhash[2:6]) - colours=[( + dc_value = base83_decode(blurhash[2:6]) + colours = [( srgb_to_linear(dc_value >> 16), srgb_to_linear((dc_value >> 8) & 255), srgb_to_linear(dc_value & 255) @@ -138,7 +146,7 @@ def blurhash_decode(blurhash,width,height,punch=1.0,linear=False): # Decode AC components for component in range(1, size_x * size_y): - ac_value=base83_decode(blurhash[4+component*2:4+(component+1)*2]) + ac_value = base83_decode(blurhash[4+component*2:4+(component+1)*2]) colours.append(( sign_pow((float(int(ac_value / (19 * 19))) - 9.0) / 9.0, 2.0) * real_max_value, sign_pow((float(int(ac_value / 19) % 19) - 9.0) / 9.0, 2.0) * real_max_value, @@ -147,21 +155,20 @@ def blurhash_decode(blurhash,width,height,punch=1.0,linear=False): # Return image RGB values, as a list of lists of lists, # consumable by something like numpy or PIL. - pixels=[] + pixels = [] for y in range(height): - pixel_row=[] + pixel_row = [] for x in range(width): - pixel=[0.0, 0.0, 0.0] + pixel = [0.0, 0.0, 0.0] for j in range(size_y): for i in range(size_x): - basis= \ - math.cos(math.pi*float(x)*float(i)/float(width))* \ - math.cos(math.pi*float(y)*float(j)/float(height)) - colour=colours[i+j*size_x] - pixel[0] += colour[0]*basis - pixel[1] += colour[1]*basis - pixel[2] += colour[2]*basis + basis = math.cos(math.pi * float(x) * float(i) / float(width)) * \ + math.cos(math.pi * float(y) * float(j) / float(height)) + colour = colours[i + j * size_x] + pixel[0] += colour[0] * basis + pixel[1] += colour[1] * basis + pixel[2] += colour[2] * basis if linear == False: pixel_row.append([ linear_to_srgb(pixel[0]), @@ -173,7 +180,8 @@ def blurhash_decode(blurhash,width,height,punch=1.0,linear=False): pixels.append(pixel_row) return pixels -def blurhash_encode(image,components_x=4,components_y=4,linear=False): + +def blurhash_encode(image, components_x=4, components_y=4, linear=False): """ Calculates the blurhash for an image using the given x and y component counts. @@ -185,16 +193,18 @@ def blurhash_encode(image,components_x=4,components_y=4,linear=False): useful if you want to encode a version of your image resized to a smaller size (which you should ideally do in linear colour). """ - if components_x < 1 or components_x > 9 or components_y < 1 or components_y > 9: - raise ValueError("x and y component counts must be between 1 and 9 inclusive.") - height=float(len(image)) - width=float(len(image[0])) + if components_x < 1 or components_x > 9 or \ + components_y < 1 or components_y > 9: + raise ValueError("x and y component counts must be " + + "between 1 and 9 inclusive.") + height = float(len(image)) + width = float(len(image[0])) # Convert to linear if neeeded - image_linear=[] - if linear==False: + image_linear = [] + if linear == False: for y in range(int(height)): - image_linear_line=[] + image_linear_line = [] for x in range(int(width)): image_linear_line.append([ srgb_to_linear(image[y][x][0]), @@ -203,19 +213,18 @@ def blurhash_encode(image,components_x=4,components_y=4,linear=False): ]) image_linear.append(image_linear_line) else: - image_linear=image + image_linear = image # Calculate components - components=[] - max_ac_component=0.0 + components = [] + max_ac_component = 0.0 for j in range(components_y): for i in range(components_x): - norm_factor=1.0 if (i==0 and j==0) else 2.0 - component=[0.0,0.0,0.0] + norm_factor = 1.0 if (i == 0 and j == 0) else 2.0 + component = [0.0, 0.0, 0.0] for y in range(int(height)): for x in range(int(width)): - basis= \ - norm_factor * math.cos(math.pi * float(i) * float(x) / width) * \ + basis = norm_factor * math.cos(math.pi * float(i) * float(x) / width) * \ math.cos(math.pi * float(j) * float(y) / height) component[0] += basis * image_linear[y][x][0] component[1] += basis * image_linear[y][x][1] @@ -227,22 +236,20 @@ def blurhash_encode(image,components_x=4,components_y=4,linear=False): components.append(component) if not (i==0 and j==0): - max_ac_component= \ - max(max_ac_component,abs(component[0]), \ - abs(component[1]),abs(component[2])) + max_ac_component = max(max_ac_component,abs(component[0]), + abs(component[1]),abs(component[2])) # Encode components - dc_value= \ - (linear_to_srgb(components[0][0]) << 16)+ \ - (linear_to_srgb(components[0][1]) << 8)+ \ + dc_value = (linear_to_srgb(components[0][0]) << 16) + \ + (linear_to_srgb(components[0][1]) << 8) + \ linear_to_srgb(components[0][2]) - quant_max_ac_component= \ - int(max(0, min(82, math.floor(max_ac_component * 166 - 0.5)))) - ac_component_norm_factor= \ - float(quant_max_ac_component+1) / 166.0 + quant_max_ac_component = int(max(0, min(82, + math.floor(max_ac_component * + 166 - 0.5)))) + ac_component_norm_factor = float(quant_max_ac_component + 1) / 166.0 - ac_values=[] + ac_values = [] for r, g, b in components[1:]: ac_values.append( int(max(0.0,min(18.0,math.floor(sign_pow(r / ac_component_norm_factor, 0.5) * 9.0 + 9.5)))) * 19 * 19 + \ @@ -251,7 +258,7 @@ def blurhash_encode(image,components_x=4,components_y=4,linear=False): ) # Build final blurhash - blurhash="" + blurhash = "" blurhash += base83_encode((components_x - 1) + (components_y - 1) * 9, 1) blurhash += base83_encode(quant_max_ac_component, 1) blurhash += base83_encode(dc_value, 4) diff --git a/bookmarks.py b/bookmarks.py index c5f89503..d010291c 100644 --- a/bookmarks.py +++ b/bookmarks.py @@ -1,14 +1,12 @@ -__filename__="bookmarks.py" -__author__="Bob Mottram" -__license__="AGPL3+" -__version__="1.1.0" -__maintainer__="Bob Mottram" -__email__="bob@freedombone.net" -__status__="Production" +__filename__ = "bookmarks.py" +__author__ = "Bob Mottram" +__license__ = "AGPL3+" +__version__ = "1.1.0" +__maintainer__ = "Bob Mottram" +__email__ = "bob@freedombone.net" +__status__ = "Production" import os -import json -import time from pprint import pprint from utils import removePostFromCache from utils import urlPermitted @@ -24,32 +22,35 @@ 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: + +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) + 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) + # 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) + removePostFromCache(postJsonObject, recentPostsCache) if not postJsonObject.get('type'): return - if postJsonObject['type']!='Create': + if postJsonObject['type'] != 'Create': return if not postJsonObject.get('object'): if debug: pprint(postJsonObject) - print('DEBUG: post '+objectUrl+' has no object') + print('DEBUG: post ' + objectUrl + ' has no object') return if not isinstance(postJsonObject['object'], dict): return @@ -59,64 +60,67 @@ def undoBookmarksCollectionEntry(recentPostsCache: {}, \ return if not postJsonObject['object']['bookmarks'].get('items'): return - totalItems=0 + totalItems = 0 if postJsonObject['object']['bookmarks'].get('totalItems'): - totalItems=postJsonObject['object']['bookmarks']['totalItems'] - itemFound=False + totalItems = postJsonObject['object']['bookmarks']['totalItems'] + itemFound = False for bookmarkItem in postJsonObject['object']['bookmarks']['items']: if bookmarkItem.get('actor'): - if bookmarkItem['actor']==actor: + if bookmarkItem['actor'] == actor: if debug: - print('DEBUG: bookmark was removed for '+actor) - postJsonObject['object']['bookmarks']['items'].remove(bookmarkItem) - itemFound=True + 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 totalItems == 1: if debug: print('DEBUG: bookmarks was removed from post') del postJsonObject['object']['bookmarks'] else: - postJsonObject['object']['bookmarks']['totalItems']= \ - len(postJsonObject['bookmarks']['items']) - saveJson(postJsonObject,postFilename) + bmItLen = len(postJsonObject['object']['bookmarks']['items']) + postJsonObject['object']['bookmarks']['totalItems'] = bmItLen + saveJson(postJsonObject, postFilename) # remove from the index - bookmarksIndexFilename= \ - baseDir+'/accounts/'+nickname+'@'+domain+'/bookmarks.index' + bookmarksIndexFilename = baseDir + '/accounts/' + \ + nickname + '@' + domain + '/bookmarks.index' if not os.path.isfile(bookmarksIndexFilename): return if '/' in postFilename: - bookmarkIndex=postFilename.split('/')[-1].strip() + bookmarkIndex = postFilename.split('/')[-1].strip() else: - bookmarkIndex=postFilename.strip() + bookmarkIndex = postFilename.strip() if bookmarkIndex not in open(bookmarksIndexFilename).read(): return - indexStr='' - indexStrChanged=False + indexStr = '' + indexStrChanged = False with open(bookmarksIndexFilename, 'r') as indexFile: - indexStr=indexFile.read().replace(bookmarkIndex+'\n','') - indexStrChanged=True + indexStr = indexFile.read().replace(bookmarkIndex + '\n', '') + indexStrChanged = True if indexStrChanged: - bookmarksIndexFile=open(bookmarksIndexFilename,'w') + bookmarksIndexFile = open(bookmarksIndexFilename, 'w') if bookmarksIndexFile: bookmarksIndexFile.write(indexStr) bookmarksIndexFile.close() -def bookmarkedByPerson(postJsonObject: {}, nickname: str,domain: str) -> bool: + +def bookmarkedByPerson(postJsonObject: {}, nickname: str, domain: str) -> bool: """Returns True if the given post is bookmarked by the given person """ - if noOfBookmarks(postJsonObject)==0: + if noOfBookmarks(postJsonObject) == 0: return False - actorMatch=domain+'/users/'+nickname + 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 """ @@ -129,38 +133,40 @@ def noOfBookmarks(postJsonObject: {}) -> int: 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 + 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: + +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) + 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) + # 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) + removePostFromCache(postJsonObject, recentPostsCache) if not postJsonObject.get('object'): if debug: pprint(postJsonObject) - print('DEBUG: post '+objectUrl+' has no object') + print('DEBUG: post ' + objectUrl + ' has no object') return if not objectUrl.endswith('/bookmarks'): - objectUrl=objectUrl+'/bookmarks' + objectUrl = objectUrl + '/bookmarks' if not postJsonObject['object'].get('bookmarks'): if debug: - print('DEBUG: Adding initial bookmarks to '+objectUrl) - bookmarksJson={ + print('DEBUG: Adding initial bookmarks to ' + objectUrl) + bookmarksJson = { "@context": "https://www.w3.org/ns/activitystreams", 'id': objectUrl, 'type': 'Collection', @@ -170,190 +176,180 @@ def updateBookmarksCollection(recentPostsCache: {}, \ 'actor': actor }] } - postJsonObject['object']['bookmarks']=bookmarksJson + postJsonObject['object']['bookmarks'] = bookmarksJson else: if not postJsonObject['object']['bookmarks'].get('items'): - postJsonObject['object']['bookmarks']['items']=[] + postJsonObject['object']['bookmarks']['items'] = [] for bookmarkItem in postJsonObject['object']['bookmarks']['items']: if bookmarkItem.get('actor'): - if bookmarkItem['actor']==actor: + if bookmarkItem['actor'] == actor: return - newBookmark={ + newBookmark = { 'type': 'Bookmark', 'actor': actor } - postJsonObject['object']['bookmarks']['items'].append(newBookmark) - postJsonObject['object']['bookmarks']['totalItems']= \ - len(postJsonObject['object']['bookmarks']['items']) + 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) + saveJson(postJsonObject, postFilename) # prepend to the index - bookmarksIndexFilename= \ - baseDir+'/accounts/'+nickname+'@'+domain+'/bookmarks.index' - bookmarkIndex=postFilename.split('/')[-1] + 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 bookmarksIndexFile: - content=bookmarksIndexFile.read() - bookmarksIndexFile.seek(0, 0) - bookmarksIndexFile.write(bookmarkIndex+'\n'+content) + 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)) + print('WARN: Failed to write entry to bookmarks index ' + + bookmarksIndexFilename + ' ' + str(e)) else: - bookmarksIndexFile=open(bookmarksIndexFilename,'w') + bookmarksIndexFile = open(bookmarksIndexFilename, 'w') if bookmarksIndexFile: - bookmarksIndexFile.write(bookmarkIndex+'\n') + 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) -> {}: + +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,"inbox:write"): + if not urlPermitted(objectUrl, federationList, "inbox:write"): return None - fullDomain=domain + fullDomain = domain if port: - if port!=80 and port!=443: + if port != 80 and port != 443: if ':' not in domain: - fullDomain=domain+':'+str(port) + fullDomain = domain + ':' + str(port) - bookmarkTo=[] - if '/statuses/' in objectUrl: - bookmarkTo=[objectUrl.split('/statuses/')[0]] - - newBookmarkJson={ + 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 + if len(ccList) > 0: + newBookmarkJson['cc'] = ccList # Extract the domain and nickname from a statuses link - bookmarkedPostNickname=None - bookmarkedPostDomain=None - bookmarkedPostPort=None + bookmarkedPostNickname = None + bookmarkedPostDomain = None + bookmarkedPostPort = None if actorBookmarked: - bookmarkedPostNickname=getNicknameFromActor(actorBookmarked) - bookmarkedPostDomain,bookmarkedPostPort= \ - getDomainFromActor(actorBookmarked) + acBm = actorBookmarked + bookmarkedPostNickname = getNicknameFromActor(acBm) + bookmarkedPostDomain, bookmarkedPostPort = getDomainFromActor(acBm) else: if '/users/' in objectUrl or \ '/channel/' in objectUrl or \ '/profile/' in objectUrl: - bookmarkedPostNickname=getNicknameFromActor(objectUrl) - bookmarkedPostDomain,bookmarkedPostPort= \ - getDomainFromActor(objectUrl) + ou = objectUrl + bookmarkedPostNickname = getNicknameFromActor(ou) + bookmarkedPostDomain, bookmarkedPostPort = getDomainFromActor(ou) if bookmarkedPostNickname: - postFilename=locatePost(baseDir,nickname,domain,objectUrl) + 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) + 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) + updateBookmarksCollection(recentPostsCache, + baseDir, postFilename, objectUrl, + newBookmarkJson['actor'], domain, debug) - 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) + 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) 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) -> {}: + +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 + bookmarkedomain = bookmarkedomain if bookmarkPort: - if bookmarkPort!=80 and bookmarkPort!=443: + if bookmarkPort != 80 and bookmarkPort != 443: if ':' not in bookmarkedomain: - bookmarkedomain=bookmarkedomain+':'+str(bookmarkPort) + bookmarkedomain = bookmarkedomain + ':' + str(bookmarkPort) - actorBookmarked= \ - httpPrefix + '://'+bookmarkedomain+'/users/'+bookmarkNickname - objectUrl=actorBookmarked+'/statuses/'+str(bookmarkStatusNumber) + actorBookmarked = httpPrefix + '://' + bookmarkedomain + \ + '/users/' + bookmarkNickname + objectUrl = actorBookmarked + '/statuses/' + str(bookmarkStatusNumber) - ccUrl=httpPrefix+'://'+bookmarkedomain+'/users/'+bookmarkNickname - if bookmarkPort: - if bookmarkPort!=80 and bookmarkPort!=443: - if ':' not in bookmarkedomain: - ccUrl= \ - httpPrefix+'://'+bookmarkedomain+':'+ \ - str(bookmarkPort)+'/users/'+bookmarkNickname + return bookmark(recentPostsCache, + session, baseDir, federationList, nickname, domain, port, + ccList, httpPrefix, objectUrl, actorBookmarked, + clientToServer, + sendThreads, postLog, personCache, cachedWebfingers, + debug, projectVersion) - 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) -> {}: +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,"inbox:write"): + if not urlPermitted(objectUrl, federationList, "inbox:write"): return None - fullDomain=domain + fullDomain = domain if port: - if port!=80 and port!=443: + if port != 80 and port != 443: if ':' not in domain: - fullDomain=domain+':'+str(port) + fullDomain = domain + ':' + str(port) - bookmarkTo=[] - if '/statuses/' in objectUrl: - bookmarkTo=[objectUrl.split('/statuses/')[0]] - - newUndoBookmarkJson={ + newUndoBookmarkJson = { "@context": "https://www.w3.org/ns/activitystreams", 'type': 'Undo', 'actor': httpPrefix+'://'+fullDomain+'/users/'+nickname, @@ -364,181 +360,171 @@ def undoBookmark(recentPostsCache: {}, \ } } if ccList: - if len(ccList)>0: - newUndoBookmarkJson['cc']=ccList - newUndoBookmarkJson['object']['cc']=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 + bookmarkedPostNickname = None + bookmarkedPostDomain = None + bookmarkedPostPort = None if actorBookmarked: - bookmarkedPostNickname=getNicknameFromActor(actorBookmarked) - bookmarkedPostDomain,bookmarkedPostPort= \ - getDomainFromActor(actorBookmarked) + acBm = actorBookmarked + bookmarkedPostNickname = getNicknameFromActor(acBm) + bookmarkedPostDomain, bookmarkedPostPort = getDomainFromActor(acBm) else: if '/users/' in objectUrl or \ '/channel/' in objectUrl or \ '/profile/' in objectUrl: - bookmarkedPostNickname=getNicknameFromActor(objectUrl) - bookmarkedPostDomain,bookmarkedPostPort= \ - getDomainFromActor(objectUrl) + ou = objectUrl + bookmarkedPostNickname = getNicknameFromActor(ou) + bookmarkedPostDomain, bookmarkedPostPort = getDomainFromActor(ou) if bookmarkedPostNickname: - postFilename=locatePost(baseDir,nickname,domain,objectUrl) + postFilename = locatePost(baseDir, nickname, domain, objectUrl) if not postFilename: return None - undoBookmarksCollectionEntry(recentPostsCache, \ - baseDir,postFilename,objectUrl, \ - newBookmarkJson['actor'],domain,debug) + 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) + 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) 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: {}, \ + +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 + bookmarkedomain = bookmarkedomain if bookmarkPort: - if bookmarkPort!=80 and bookmarkPort!=443: + if bookmarkPort != 80 and bookmarkPort != 443: if ':' not in bookmarkedomain: - bookmarkedomain=bookmarkedomain+':'+str(bookmarkPort) + bookmarkedomain = bookmarkedomain + ':' + str(bookmarkPort) - objectUrl= \ - httpPrefix+'://'+bookmarkedomain+'/users/'+bookmarkNickname+ \ - '/statuses/'+str(bookmarkStatusNumber) + objectUrl = httpPrefix + '://' + bookmarkedomain + \ + '/users/' + bookmarkNickname + \ + '/statuses/' + str(bookmarkStatusNumber) - ccUrl=httpPrefix+'://'+bookmarkedomain+'/users/'+bookmarkNickname - if bookmarkPort: - if bookmarkPort!=80 and bookmarkPort!=443: - if ':' not in bookmarkedomain: - ccUrl= \ - httpPrefix+'://'+bookmarkedomain+':'+ \ - str(bookmarkPort)+'/users/'+bookmarkNickname + return undoBookmark(session, baseDir, federationList, + nickname, domain, port, + ccList, httpPrefix, objectUrl, clientToServer, + sendThreads, postLog, personCache, + cachedWebfingers, debug) - 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) -> {}: +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 + fromDomainFull = fromDomain if fromPort: - if fromPort!=80 and fromPort!=443: + if fromPort != 80 and fromPort != 443: if ':' not in fromDomain: - fromDomainFull=fromDomain+':'+str(fromPort) + fromDomainFull = fromDomain + ':' + str(fromPort) - toUrl=['https://www.w3.org/ns/activitystreams#Public'] - ccUrl=httpPrefix+'://'+fromDomainFull+'/users/'+fromNickname+'/followers' - - if '/statuses/' in bookmarkUrl: - toUrl=[bookmarkUrl.split('/statuses/')[0]] - - newBookmarkJson={ + newBookmarkJson = { "@context": "https://www.w3.org/ns/activitystreams", 'type': 'Bookmark', 'actor': httpPrefix+'://'+fromDomainFull+'/users/'+fromNickname, 'object': bookmarkUrl } - handle=httpPrefix+'://'+fromDomainFull+'/@'+fromNickname + handle = httpPrefix + '://' + fromDomainFull + '/@' + fromNickname # lookup the inbox for the To handle - wfRequest=webfingerHandle(session,handle,httpPrefix,cachedWebfingers, \ - fromDomain,projectVersion) + wfRequest = webfingerHandle(session, handle, httpPrefix, + cachedWebfingers, + fromDomain, projectVersion) if not wfRequest: if debug: - print('DEBUG: announce webfinger failed for '+handle) + print('DEBUG: announce webfinger failed for ' + handle) return 1 - postToBox='outbox' + postToBox = 'outbox' # get the actor inbox for the To handle - inboxUrl,pubKeyId,pubKey,fromPersonId,sharedInbox,capabilityAcquisition,avatarUrl,displayName= \ - getPersonBox(baseDir,session,wfRequest,personCache, \ - projectVersion,httpPrefix,fromNickname, \ - fromDomain,postToBox) + (inboxUrl, pubKeyId, pubKey, + fromPersonId, sharedInbox, + capabilityAcquisition, 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) + print('DEBUG: No ' + postToBox + ' was found for ' + handle) return 3 if not fromPersonId: if debug: - print('DEBUG: No actor was found for '+handle) + print('DEBUG: No actor was found for ' + handle) return 4 - authHeader=createBasicAuthHeader(fromNickname,password) + authHeader = createBasicAuthHeader(fromNickname, password) - headers={ - 'host': fromDomain, \ - 'Content-type': 'application/json', \ + headers = { + 'host': fromDomain, + 'Content-type': 'application/json', 'Authorization': authHeader } - postResult= \ - postJson(session,newBookmarkJson,[],inboxUrl,headers,"inbox:write") - #if not postResult: - # if debug: - # print('DEBUG: POST announce failed for c2s to '+inboxUrl) - # return 5 + postResult = postJson(session, newBookmarkJson, [], + inboxUrl, headers, "inbox:write") + 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) -> {}: + +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 + fromDomainFull = fromDomain if fromPort: - if fromPort!=80 and fromPort!=443: + if fromPort != 80 and fromPort != 443: if ':' not in fromDomain: - fromDomainFull=fromDomain+':'+str(fromPort) + fromDomainFull = fromDomain + ':' + str(fromPort) - toUrl=['https://www.w3.org/ns/activitystreams#Public'] - ccUrl=httpPrefix+'://'+fromDomainFull+'/users/'+fromNickname+'/followers' - - if '/statuses/' in bookmarkUrl: - toUrl=[bookmarkUrl.split('/statuses/')[0]] - - newUndoBookmarkJson={ + newUndoBookmarkJson = { "@context": "https://www.w3.org/ns/activitystreams", 'type': 'Undo', 'actor': httpPrefix+'://'+fromDomainFull+'/users/'+fromNickname, @@ -549,63 +535,66 @@ def sendUndoBookmarkViaServer(baseDir: str,session, \ } } - handle=httpPrefix+'://'+fromDomainFull+'/@'+fromNickname + handle = httpPrefix + '://' + fromDomainFull + '/@' + fromNickname # lookup the inbox for the To handle - wfRequest=webfingerHandle(session,handle,httpPrefix,cachedWebfingers, \ - fromDomain,projectVersion) + wfRequest = webfingerHandle(session, handle, httpPrefix, cachedWebfingers, + fromDomain, projectVersion) if not wfRequest: if debug: - print('DEBUG: announce webfinger failed for '+handle) + print('DEBUG: announce webfinger failed for ' + handle) return 1 - postToBox='outbox' + postToBox = 'outbox' # get the actor inbox for the To handle - inboxUrl,pubKeyId,pubKey,fromPersonId,sharedInbox,capabilityAcquisition,avatarUrl,displayName= \ - getPersonBox(baseDir,session,wfRequest,personCache, \ - projectVersion,httpPrefix,fromNickname, \ - fromDomain,postToBox) + (inboxUrl, pubKeyId, pubKey, + fromPersonId, sharedInbox, + capabilityAcquisition, 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) + print('DEBUG: No ' + postToBox + ' was found for ' + handle) return 3 if not fromPersonId: if debug: - print('DEBUG: No actor was found for '+handle) + print('DEBUG: No actor was found for ' + handle) return 4 - authHeader=createBasicAuthHeader(fromNickname,password) + authHeader = createBasicAuthHeader(fromNickname, password) - headers={ - 'host': fromDomain, \ - 'Content-type': 'application/json', \ + headers = { + 'host': fromDomain, + 'Content-type': 'application/json', 'Authorization': authHeader } - postResult= \ - postJson(session,newUndoBookmarkJson,[],inboxUrl,headers,"inbox:write") - #if not postResult: - # if debug: - # print('DEBUG: POST announce failed for c2s to '+inboxUrl) - # return 5 + postResult = postJson(session, newUndoBookmarkJson, [], + inboxUrl, headers, "inbox:write") + 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: + +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 not messageJson['type'] == 'Bookmark': if debug: print('DEBUG: not a bookmark') return @@ -620,39 +609,40 @@ def outboxBookmark(recentPostsCache: {}, \ if messageJson.get('to'): if not isinstance(messageJson['to'], list): return - if len(messageJson['to'])!=1: + if len(messageJson['to']) != 1: print('WARN: Bookmark should only be sent to one recipient') return - if messageJson['to'][0]!=messageJson['actor']: + 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=messageJson['object'].replace('/activity','') + messageId = messageJson['object'].replace('/activity', '') if ':' in domain: - domain=domain.split(':')[0] - postFilename=locatePost(baseDir,nickname,domain,messageId) + 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) + updateBookmarksCollection(recentPostsCache, + baseDir, postFilename, messageId, + messageJson['actor'], domain, debug) if debug: - print('DEBUG: post bookmarked via c2s - '+postFilename) + print('DEBUG: post bookmarked via c2s - ' + postFilename) -def outboxUndoBookmark(recentPostsCache: {}, \ - baseDir: str,httpPrefix: str, \ - nickname: str,domain: str,port: int, \ - messageJson: {},debug: bool) -> None: + +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': + if not messageJson['type'] == 'Undo': return if not messageJson.get('object'): return @@ -664,7 +654,7 @@ def outboxUndoBookmark(recentPostsCache: {}, \ if debug: print('DEBUG: undo bookmark - no type') return - if not messageJson['object']['type']=='Bookmark': + if not messageJson['object']['type'] == 'Bookmark': if debug: print('DEBUG: not a undo bookmark') return @@ -679,26 +669,26 @@ def outboxUndoBookmark(recentPostsCache: {}, \ if messageJson.get('to'): if not isinstance(messageJson['to'], list): return - if len(messageJson['to'])!=1: + if len(messageJson['to']) != 1: print('WARN: Bookmark should only be sent to one recipient') return - if messageJson['to'][0]!=messageJson['actor']: + 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=messageJson['object']['object'].replace('/activity','') + messageId = messageJson['object']['object'].replace('/activity', '') if ':' in domain: - domain=domain.split(':')[0] - postFilename=locatePost(baseDir,nickname,domain,messageId) + 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) + undoBookmarksCollectionEntry(recentPostsCache, + baseDir, postFilename, messageId, + messageJson['actor'], domain, debug) if debug: - print('DEBUG: post undo bookmarked via c2s - '+postFilename) + print('DEBUG: post undo bookmarked via c2s - ' + postFilename)