mirror of https://gitlab.com/bashrc2/epicyon
Remove trailing whitespace
parent
42c2021831
commit
23bb250deb
|
@ -85,7 +85,7 @@ def acceptFollow(baseDir: str,domain : str,messageJson: {}, \
|
|||
if not messageJson.get('object'):
|
||||
return
|
||||
if not messageJson['object'].get('type'):
|
||||
return
|
||||
return
|
||||
if not messageJson['object']['type']=='Follow':
|
||||
return
|
||||
if debug:
|
||||
|
@ -96,7 +96,7 @@ def acceptFollow(baseDir: str,domain : str,messageJson: {}, \
|
|||
# no, this isn't a mistake
|
||||
if not messageJson['object'].get('object'):
|
||||
print('DEBUG: no object within Follow activity')
|
||||
return
|
||||
return
|
||||
if not messageJson.get('to'):
|
||||
if debug:
|
||||
print('DEBUG: No "to" parameter in follow Accept')
|
||||
|
@ -115,7 +115,7 @@ def acceptFollow(baseDir: str,domain : str,messageJson: {}, \
|
|||
return
|
||||
if not nickname:
|
||||
if debug:
|
||||
print('DEBUG: nickname not found in '+thisActor)
|
||||
print('DEBUG: nickname not found in '+thisActor)
|
||||
return
|
||||
if acceptedPort:
|
||||
if '/'+acceptedDomain+':'+str(acceptedPort)+'/users/'+nickname not in thisActor:
|
||||
|
@ -132,7 +132,7 @@ def acceptFollow(baseDir: str,domain : str,messageJson: {}, \
|
|||
print('Expected: /'+acceptedDomain+'/users/'+nickname)
|
||||
print('Actual: '+thisActor)
|
||||
print('DEBUG: unrecognized actor '+thisActor)
|
||||
return
|
||||
return
|
||||
followedActor=messageJson['object']['object']
|
||||
followedDomain,port=getDomainFromActor(followedActor)
|
||||
if not followedDomain:
|
||||
|
@ -166,7 +166,7 @@ def acceptFollow(baseDir: str,domain : str,messageJson: {}, \
|
|||
nickname+'@'+acceptedDomainFull+ \
|
||||
' from '+followedNickname+'@'+followedDomainFull+ \
|
||||
' but they have been unfollowed')
|
||||
return
|
||||
return
|
||||
|
||||
if followPerson(baseDir, \
|
||||
nickname,acceptedDomainFull, \
|
||||
|
|
14
announce.py
14
announce.py
|
@ -78,7 +78,7 @@ def undoAnnounceCollectionEntry(recentPostsCache: {}, \
|
|||
baseDir: str,postFilename: str, \
|
||||
actor: str,domain: str,debug: bool) -> None:
|
||||
"""Undoes an announce for a particular actor by removing it from
|
||||
the "shares" collection within a post. Note that the "shares"
|
||||
the "shares" collection within a post. Note that the "shares"
|
||||
collection has no relation to shared items in shares.py. It's
|
||||
shares of posts, not shares of physical objects.
|
||||
"""
|
||||
|
@ -169,7 +169,7 @@ def updateAnnounceCollection(recentPostsCache: {}, \
|
|||
"totalItems": 1,
|
||||
'items': [{
|
||||
'type': 'Announce',
|
||||
'actor': actor
|
||||
'actor': actor
|
||||
}]
|
||||
}
|
||||
postJsonObject['object']['shares']=announcementsJson
|
||||
|
@ -274,7 +274,7 @@ def createAnnounce(session,baseDir: str,federationList: [], \
|
|||
httpPrefix,True,clientToServer,federationList, \
|
||||
sendThreads,postLog,cachedWebfingers,personCache, \
|
||||
debug,projectVersion)
|
||||
|
||||
|
||||
return newAnnounce
|
||||
|
||||
def announcePublic(session,baseDir: str,federationList: [], \
|
||||
|
@ -386,7 +386,7 @@ def undoAnnounce(session,baseDir: str,federationList: [], \
|
|||
'https://www.w3.org/ns/activitystreams#Public', \
|
||||
httpPrefix,True,clientToServer,federationList, \
|
||||
sendThreads,postLog,cachedWebfingers,personCache,debug)
|
||||
|
||||
|
||||
return newUndoAnnounce
|
||||
|
||||
def undoAnnouncePublic(session,baseDir: str,federationList: [], \
|
||||
|
@ -495,7 +495,7 @@ def sendAnnounceViaServer(baseDir: str,session, \
|
|||
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)
|
||||
|
@ -504,9 +504,9 @@ def sendAnnounceViaServer(baseDir: str,session, \
|
|||
if debug:
|
||||
print('DEBUG: No actor was found for '+handle)
|
||||
return 4
|
||||
|
||||
|
||||
authHeader=createBasicAuthHeader(fromNickname,password)
|
||||
|
||||
|
||||
headers={
|
||||
'host': fromDomain, \
|
||||
'Content-type': 'application/json', \
|
||||
|
|
2
auth.py
2
auth.py
|
@ -22,7 +22,7 @@ def hashPassword(password: str) -> str:
|
|||
salt, 100000)
|
||||
pwdhash=binascii.hexlify(pwdhash)
|
||||
return (salt+pwdhash).decode('ascii')
|
||||
|
||||
|
||||
def verifyPassword(storedPassword: str,providedPassword: str) -> bool:
|
||||
"""Verify a stored password against one provided by user
|
||||
"""
|
||||
|
|
|
@ -88,7 +88,7 @@ def sendAvailabilityViaServer(baseDir: str,session, \
|
|||
if port!=80 and port!=443:
|
||||
if ':' not in domain:
|
||||
domainFull=domain+':'+str(port)
|
||||
|
||||
|
||||
toUrl=httpPrefix+'://'+domainFull+'/users/'+nickname
|
||||
ccUrl=httpPrefix+'://'+domainFull+'/users/'+nickname+'/followers'
|
||||
|
||||
|
@ -117,7 +117,7 @@ def sendAvailabilityViaServer(baseDir: str,session, \
|
|||
inboxUrl,pubKeyId,pubKey,fromPersonId,sharedInbox,capabilityAcquisition,avatarUrl,displayName= \
|
||||
getPersonBox(baseDir,session,wfRequest,personCache, \
|
||||
projectVersion,httpPrefix,nickname,domain,postToBox)
|
||||
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
print('DEBUG: No '+postToBox+' was found for '+handle)
|
||||
|
@ -126,9 +126,9 @@ def sendAvailabilityViaServer(baseDir: str,session, \
|
|||
if debug:
|
||||
print('DEBUG: No actor was found for '+handle)
|
||||
return 4
|
||||
|
||||
|
||||
authHeader=createBasicAuthHeader(Nickname,password)
|
||||
|
||||
|
||||
headers={
|
||||
'host': domain, \
|
||||
'Content-type': 'application/json', \
|
||||
|
|
|
@ -14,7 +14,7 @@ def addGlobalBlock(baseDir: str, \
|
|||
"""Global block which applies to all accounts
|
||||
"""
|
||||
blockingFilename=baseDir+'/accounts/blocking.txt'
|
||||
if not blockNickname.startswith('#'):
|
||||
if not blockNickname.startswith('#'):
|
||||
blockHandle=blockNickname+'@'+blockDomain
|
||||
if os.path.isfile(blockingFilename):
|
||||
if blockHandle in open(blockingFilename).read():
|
||||
|
@ -54,7 +54,7 @@ def removeGlobalBlock(baseDir: str, \
|
|||
"""Unblock the given global block
|
||||
"""
|
||||
unblockingFilename=baseDir+'/accounts/blocking.txt'
|
||||
if not unblockNickname.startswith('#'):
|
||||
if not unblockNickname.startswith('#'):
|
||||
unblockHandle=unblockNickname+'@'+unblockDomain
|
||||
if os.path.isfile(unblockingFilename):
|
||||
if unblockHandle in open(unblockingFilename).read():
|
||||
|
|
12
blog.py
12
blog.py
|
@ -171,7 +171,7 @@ def htmlBlogPostContent(authorized: bool, \
|
|||
# posts from the domain are expected to have an attributedTo field
|
||||
if restrictToDomain:
|
||||
return ''
|
||||
|
||||
|
||||
if postJsonObject['object'].get('published'):
|
||||
if 'T' in postJsonObject['object']['published']:
|
||||
blogStr+='<h3>'+postJsonObject['object']['published'].split('T')[0]
|
||||
|
@ -312,7 +312,7 @@ def htmlBlogPage(authorized: bool, session, \
|
|||
"""
|
||||
if ' ' in nickname or '@' in nickname or '\n' in nickname:
|
||||
return None
|
||||
blogStr=''
|
||||
blogStr=''
|
||||
|
||||
cssFilename=baseDir+'/epicyon-profile.css'
|
||||
if os.path.isfile(baseDir+'/epicyon.css'):
|
||||
|
@ -424,7 +424,7 @@ def htmlBlogPageRSS(authorized: bool, session, \
|
|||
if not timelineJson:
|
||||
return blogRSS+rssFooter()
|
||||
|
||||
if pageNumber!=None:
|
||||
if pageNumber!=None:
|
||||
for item in timelineJson['orderedItems']:
|
||||
if item['type']!='Create':
|
||||
continue
|
||||
|
@ -556,11 +556,11 @@ def htmlEditBlog(mediaInstance: bool,translate: {}, \
|
|||
|
||||
if os.path.isfile(baseDir+'/accounts/newpost.txt'):
|
||||
with open(baseDir+'/accounts/newpost.txt', 'r') as file:
|
||||
editBlogText='<p class="new-post-text">'+file.read()+'</p>'
|
||||
editBlogText='<p class="new-post-text">'+file.read()+'</p>'
|
||||
|
||||
cssFilename=baseDir+'/epicyon-profile.css'
|
||||
if os.path.isfile(baseDir+'/epicyon.css'):
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
editBlogCSS=cssFile.read()
|
||||
if httpPrefix!='https':
|
||||
|
@ -606,7 +606,7 @@ def htmlEditBlog(mediaInstance: bool,translate: {}, \
|
|||
editBlogForm=htmlHeader(cssFilename,editBlogCSS)
|
||||
|
||||
mentionsStr=''
|
||||
|
||||
|
||||
editBlogForm+= \
|
||||
'<form enctype="multipart/form-data" method="POST" accept-charset="UTF-8" action="'+ \
|
||||
pathBase+'?'+endpoint+'?page='+str(pageNumber)+'">'
|
||||
|
|
62
blurhash.py
62
blurhash.py
|
@ -10,7 +10,7 @@ furnished to do so, subject to the following conditions:
|
|||
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
* You and any organization you work for may not promote white supremacy, hate
|
||||
* You and any organization you work for may not promote white supremacy, hate
|
||||
speech and homo- or transphobia - this license is void if you do.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
|
@ -23,7 +23,7 @@ SOFTWARE.
|
|||
|
||||
https://github.com/halcy/blurhash-python
|
||||
|
||||
Pure python blurhash decoder with no additional dependencies, for
|
||||
Pure python blurhash decoder with no additional dependencies, for
|
||||
both de- and encoding.
|
||||
|
||||
Very close port of the original Swift implementation by Dag Ågren.
|
||||
|
@ -47,13 +47,13 @@ def base83_decode(base83_str):
|
|||
def base83_encode(value, length):
|
||||
"""
|
||||
Decodes an integer to a base83 string, as used in blurhash.
|
||||
|
||||
|
||||
Length is how long the resulting string should be. Will complain
|
||||
if the specified length is too short.
|
||||
"""
|
||||
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
|
||||
|
@ -90,44 +90,44 @@ def blurhash_components(blurhash):
|
|||
"""
|
||||
if len(blurhash) < 6:
|
||||
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
|
||||
|
||||
|
||||
return size_x, size_y
|
||||
|
||||
def blurhash_decode(blurhash,width,height,punch=1.0,linear=False):
|
||||
"""
|
||||
Decodes the given blurhash to an image of the specified size.
|
||||
|
||||
|
||||
Returns the resulting image a list of lists of 3-value sRGB 8 bit integer
|
||||
lists. Set linear to True if you would prefer to get linear floating point
|
||||
lists. Set linear to True if you would prefer to get linear floating point
|
||||
RGB back.
|
||||
|
||||
|
||||
The punch parameter can be used to de- or increase the contrast of the
|
||||
resulting image.
|
||||
|
||||
|
||||
As per the original implementation it is suggested to only decode
|
||||
to a relatively small size and then scale the result up, as it
|
||||
basically looks the same anyways.
|
||||
"""
|
||||
if len(blurhash) < 6:
|
||||
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
|
||||
|
||||
|
||||
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:
|
||||
raise ValueError("Invalid BlurHash length.")
|
||||
|
||||
|
||||
# Decode DC component
|
||||
dc_value=base83_decode(blurhash[2:6])
|
||||
colours=[(
|
||||
|
@ -135,7 +135,7 @@ def blurhash_decode(blurhash,width,height,punch=1.0,linear=False):
|
|||
srgb_to_linear((dc_value >> 8) & 255),
|
||||
srgb_to_linear(dc_value & 255)
|
||||
)]
|
||||
|
||||
|
||||
# Decode AC components
|
||||
for component in range(1, size_x * size_y):
|
||||
ac_value=base83_decode(blurhash[4+component*2:4+(component+1)*2])
|
||||
|
@ -144,8 +144,8 @@ def blurhash_decode(blurhash,width,height,punch=1.0,linear=False):
|
|||
sign_pow((float(int(ac_value / 19) % 19) - 9.0) / 9.0, 2.0) * real_max_value,
|
||||
sign_pow((float(ac_value % 19) - 9.0) / 9.0, 2.0) * real_max_value
|
||||
))
|
||||
|
||||
# Return image RGB values, as a list of lists of lists,
|
||||
|
||||
# Return image RGB values, as a list of lists of lists,
|
||||
# consumable by something like numpy or PIL.
|
||||
pixels=[]
|
||||
for y in range(height):
|
||||
|
@ -172,24 +172,24 @@ def blurhash_decode(blurhash,width,height,punch=1.0,linear=False):
|
|||
pixel_row.append(pixel)
|
||||
pixels.append(pixel_row)
|
||||
return pixels
|
||||
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Image should be a 3-dimensional array, with the first dimension being y, the second
|
||||
being x, and the third being the three rgb components that are assumed to be 0-255
|
||||
being x, and the third being the three rgb components that are assumed to be 0-255
|
||||
srgb integers (incidentally, this is the format you will get from a PIL RGB image).
|
||||
|
||||
|
||||
You can also pass in already linear data - to do this, set linear to True. This is
|
||||
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:
|
||||
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:
|
||||
|
@ -204,7 +204,7 @@ def blurhash_encode(image,components_x=4,components_y=4,linear=False):
|
|||
image_linear.append(image_linear_line)
|
||||
else:
|
||||
image_linear=image
|
||||
|
||||
|
||||
# Calculate components
|
||||
components=[]
|
||||
max_ac_component=0.0
|
||||
|
@ -220,28 +220,28 @@ def blurhash_encode(image,components_x=4,components_y=4,linear=False):
|
|||
component[0] += basis * image_linear[y][x][0]
|
||||
component[1] += basis * image_linear[y][x][1]
|
||||
component[2] += basis * image_linear[y][x][2]
|
||||
|
||||
|
||||
component[0] /= (width * height)
|
||||
component[1] /= (width * height)
|
||||
component[2] /= (width * height)
|
||||
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]))
|
||||
|
||||
|
||||
# Encode components
|
||||
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
|
||||
|
||||
|
||||
ac_values=[]
|
||||
for r, g, b in components[1:]:
|
||||
ac_values.append(
|
||||
|
@ -249,7 +249,7 @@ def blurhash_encode(image,components_x=4,components_y=4,linear=False):
|
|||
int(max(0.0,min(18.0, math.floor(sign_pow(g / ac_component_norm_factor, 0.5) * 9.0 + 9.5)))) * 19 + \
|
||||
int(max(0.0,min(18.0, math.floor(sign_pow(b / ac_component_norm_factor, 0.5) * 9.0 + 9.5))))
|
||||
)
|
||||
|
||||
|
||||
# Build final blurhash
|
||||
blurhash=""
|
||||
blurhash += base83_encode((components_x - 1) + (components_y - 1) * 9, 1)
|
||||
|
@ -257,5 +257,5 @@ def blurhash_encode(image,components_x=4,components_y=4,linear=False):
|
|||
blurhash += base83_encode(dc_value, 4)
|
||||
for ac_value in ac_values:
|
||||
blurhash += base83_encode(ac_value, 2)
|
||||
|
||||
|
||||
return blurhash
|
||||
|
|
30
bookmarks.py
30
bookmarks.py
|
@ -167,7 +167,7 @@ def updateBookmarksCollection(recentPostsCache: {}, \
|
|||
'items': [{
|
||||
'type': 'Bookmark',
|
||||
'actor': actor
|
||||
}]
|
||||
}]
|
||||
}
|
||||
postJsonObject['object']['bookmarks']=bookmarksJson
|
||||
else:
|
||||
|
@ -271,11 +271,11 @@ def bookmark(recentPostsCache: {}, \
|
|||
print('DEBUG: bookmark domain: '+domain)
|
||||
print('DEBUG: bookmark objectUrl: '+objectUrl)
|
||||
return None
|
||||
|
||||
|
||||
updateBookmarksCollection(recentPostsCache, \
|
||||
baseDir,postFilename,objectUrl, \
|
||||
newBookmarkJson['actor'],domain,debug)
|
||||
|
||||
|
||||
sendSignedJson(newBookmarkJson,session,baseDir, \
|
||||
nickname,domain,port, \
|
||||
bookmarkedPostNickname,bookmarkedPostDomain,bookmarkedPostPort, \
|
||||
|
@ -385,7 +385,7 @@ def undoBookmark(recentPostsCache: {}, \
|
|||
undoBookmarksCollectionEntry(recentPostsCache, \
|
||||
baseDir,postFilename,objectUrl, \
|
||||
newBookmarkJson['actor'],domain,debug)
|
||||
|
||||
|
||||
sendSignedJson(newUndoBookmarkJson,session,baseDir, \
|
||||
nickname,domain,port, \
|
||||
bookmarkedPostNickname,bookmarkedPostDomain,bookmarkedPostPort, \
|
||||
|
@ -425,7 +425,7 @@ def undoBookmarkPost(session,baseDir: str,federationList: [], \
|
|||
ccUrl= \
|
||||
httpPrefix+'://'+bookmarkedomain+':'+ \
|
||||
str(bookmarkPort)+'/users/'+bookmarkNickname
|
||||
|
||||
|
||||
return undoBookmark(session,baseDir,federationList,nickname,domain,port, \
|
||||
ccList,httpPrefix,objectUrl,clientToServer, \
|
||||
sendThreads,postLog,personCache,cachedWebfingers,debug)
|
||||
|
@ -453,7 +453,7 @@ def sendBookmarkViaServer(baseDir: str,session, \
|
|||
|
||||
if '/statuses/' in bookmarkUrl:
|
||||
toUrl=[bookmarkUrl.split('/statuses/')[0]]
|
||||
|
||||
|
||||
newBookmarkJson={
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
'type': 'Bookmark',
|
||||
|
@ -478,7 +478,7 @@ def sendBookmarkViaServer(baseDir: str,session, \
|
|||
getPersonBox(baseDir,session,wfRequest,personCache, \
|
||||
projectVersion,httpPrefix,fromNickname, \
|
||||
fromDomain,postToBox)
|
||||
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
print('DEBUG: No '+postToBox+' was found for '+handle)
|
||||
|
@ -487,9 +487,9 @@ def sendBookmarkViaServer(baseDir: str,session, \
|
|||
if debug:
|
||||
print('DEBUG: No actor was found for '+handle)
|
||||
return 4
|
||||
|
||||
|
||||
authHeader=createBasicAuthHeader(fromNickname,password)
|
||||
|
||||
|
||||
headers={
|
||||
'host': fromDomain, \
|
||||
'Content-type': 'application/json', \
|
||||
|
@ -559,7 +559,7 @@ def sendUndoBookmarkViaServer(baseDir: str,session, \
|
|||
getPersonBox(baseDir,session,wfRequest,personCache, \
|
||||
projectVersion,httpPrefix,fromNickname, \
|
||||
fromDomain,postToBox)
|
||||
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
print('DEBUG: No '+postToBox+' was found for '+handle)
|
||||
|
@ -568,9 +568,9 @@ def sendUndoBookmarkViaServer(baseDir: str,session, \
|
|||
if debug:
|
||||
print('DEBUG: No actor was found for '+handle)
|
||||
return 4
|
||||
|
||||
|
||||
authHeader=createBasicAuthHeader(fromNickname,password)
|
||||
|
||||
|
||||
headers={
|
||||
'host': fromDomain, \
|
||||
'Content-type': 'application/json', \
|
||||
|
@ -618,7 +618,7 @@ def outboxBookmark(recentPostsCache: {}, \
|
|||
return
|
||||
if messageJson['to'][0]!=messageJson['actor']:
|
||||
print('WARN: Bookmark should be addressed to the same actor')
|
||||
return
|
||||
return
|
||||
if debug:
|
||||
print('DEBUG: c2s bookmark request arrived in outbox')
|
||||
|
||||
|
@ -652,7 +652,7 @@ def outboxUndoBookmark(recentPostsCache: {}, \
|
|||
if not isinstance(messageJson['object'], dict):
|
||||
if debug:
|
||||
print('DEBUG: undo bookmark object is not dict')
|
||||
return
|
||||
return
|
||||
if not messageJson['object'].get('type'):
|
||||
if debug:
|
||||
print('DEBUG: undo bookmark - no type')
|
||||
|
@ -677,7 +677,7 @@ def outboxUndoBookmark(recentPostsCache: {}, \
|
|||
return
|
||||
if messageJson['to'][0]!=messageJson['actor']:
|
||||
print('WARN: Bookmark should be addressed to the same actor')
|
||||
return
|
||||
return
|
||||
if debug:
|
||||
print('DEBUG: c2s undo bookmark request arrived in outbox')
|
||||
|
||||
|
|
4
cache.py
4
cache.py
|
@ -11,7 +11,7 @@ import time
|
|||
import datetime
|
||||
from utils import loadJson
|
||||
from utils import saveJson
|
||||
|
||||
|
||||
def storePersonInCache(baseDir: str,personUrl: str,personJson: {},personCache: {}) -> None:
|
||||
"""Store an actor in the cache
|
||||
"""
|
||||
|
@ -41,7 +41,7 @@ def getPersonFromCache(baseDir: str,personUrl: str,personCache: {}) -> {}:
|
|||
if personJson:
|
||||
storePersonInCache(baseDir,personUrl,personJson,personCache)
|
||||
loadedFromFile=True
|
||||
|
||||
|
||||
if personCache.get(personUrl):
|
||||
if not loadedFromFile:
|
||||
# update the timestamp for the last time the actor was retrieved
|
||||
|
|
|
@ -82,7 +82,7 @@ def CapablePost(postJson: {}, capabilityList: [], debug :bool) -> bool:
|
|||
if 'inbox:cw' in capabilityList:
|
||||
if debug:
|
||||
print('DEBUG: inbox post rejected because inbox:cw, summary missing')
|
||||
return False
|
||||
return False
|
||||
if 'inbox:write' in capabilityList:
|
||||
return True
|
||||
return True
|
||||
|
@ -102,7 +102,7 @@ def capabilitiesRequest(baseDir: str,httpPrefix: str,domain: str, \
|
|||
"actor": requestedActor
|
||||
}
|
||||
return ocapRequest
|
||||
|
||||
|
||||
def capabilitiesAccept(baseDir: str,httpPrefix: str, \
|
||||
nickname: str,domain: str, port: int, \
|
||||
acceptedActor: str, saveToFile: bool, \
|
||||
|
@ -119,7 +119,7 @@ def capabilitiesAccept(baseDir: str,httpPrefix: str, \
|
|||
if port!=80 and port !=443:
|
||||
if ':' not in domain:
|
||||
fullDomain=domain+':'+str(port)
|
||||
|
||||
|
||||
# make directories to store capabilities
|
||||
ocapFilename=getOcapFilename(baseDir,nickname,fullDomain,acceptedActor,'accept')
|
||||
if not ocapFilename:
|
||||
|
@ -129,14 +129,14 @@ def capabilitiesAccept(baseDir: str,httpPrefix: str, \
|
|||
# if the capability already exists then load it from file
|
||||
if os.path.isfile(ocapFilename):
|
||||
ocapAccept=loadJson(ocapFilename)
|
||||
# otherwise create a new capability
|
||||
# otherwise create a new capability
|
||||
if not ocapAccept:
|
||||
acceptedActorNickname=getNicknameFromActor(acceptedActor)
|
||||
if not acceptedActorNickname:
|
||||
print('WARN: unable to find nickname in '+acceptedActor)
|
||||
return None
|
||||
acceptedActorDomain,acceptedActorPort=getDomainFromActor(acceptedActor)
|
||||
if acceptedActorPort:
|
||||
if acceptedActorPort:
|
||||
ocapId=acceptedActorNickname+'@'+acceptedActorDomain+':'+str(acceptedActorPort)+'#'+createPassword(32)
|
||||
else:
|
||||
ocapId=acceptedActorNickname+'@'+acceptedActorDomain+'#'+createPassword(32)
|
||||
|
@ -185,7 +185,7 @@ def capabilitiesUpdate(baseDir: str,httpPrefix: str, \
|
|||
if port!=80 and port !=443:
|
||||
if ':' not in domain:
|
||||
fullDomain=domain+':'+str(port)
|
||||
|
||||
|
||||
# Get the filename of the capability
|
||||
ocapFilename=getOcapFilename(baseDir,nickname,fullDomain,updateActor,'accept')
|
||||
if not ocapFilename:
|
||||
|
|
16
content.py
16
content.py
|
@ -92,7 +92,7 @@ def replaceEmojiFromTags(content: str,tag: [],messageType: str) -> str:
|
|||
|
||||
htmlClass='emoji'
|
||||
if messageType=='post header':
|
||||
htmlClass='emojiheader'
|
||||
htmlClass='emojiheader'
|
||||
if messageType=='profile':
|
||||
htmlClass='emojiprofile'
|
||||
emojiHtml="<img src=\""+tagItem['icon']['url']+"\" alt=\""+tagItem['name'].replace(':','')+"\" align=\"middle\" class=\""+htmlClass+"\"/>"
|
||||
|
@ -298,7 +298,7 @@ def addMention(wordStr: str,httpPrefix: str,following: str,replaceMentions: {},r
|
|||
return True
|
||||
# @nick@domain
|
||||
if not (possibleDomain=='localhost' or '.' in possibleDomain):
|
||||
return False
|
||||
return False
|
||||
recipientActor=httpPrefix+"://"+possibleDomain+"/users/"+possibleNickname
|
||||
if recipientActor not in recipients:
|
||||
recipients.append(recipientActor)
|
||||
|
@ -389,7 +389,7 @@ def addHtmlTags(baseDir: str,httpPrefix: str, \
|
|||
content=content.replace('\n',' --linebreak-- ')
|
||||
content=addMusicTag(content,'nowplaying')
|
||||
words=content.replace(',',' ').replace(';',' ').split(' ')
|
||||
|
||||
|
||||
# remove . for words which are not mentions
|
||||
wordCtr=0
|
||||
newWords=[]
|
||||
|
@ -461,7 +461,7 @@ def addHtmlTags(baseDir: str,httpPrefix: str, \
|
|||
content=removeLongWords(content,maxWordLength,longWordsList)
|
||||
content=content.replace(' --linebreak-- ','</p><p>')
|
||||
return '<p>'+content+'</p>'
|
||||
|
||||
|
||||
def getMentionsFromHtml(htmlText: str,matchStr="<span class=\"h-card\"><a href=\"") -> []:
|
||||
"""Extracts mentioned actors from the given html content string
|
||||
"""
|
||||
|
@ -521,7 +521,7 @@ def saveMediaInFormPOST(mediaBytes,debug: bool, \
|
|||
mediaLocation=-1
|
||||
searchStr=''
|
||||
filename=None
|
||||
|
||||
|
||||
# directly search the binary array for the beginning
|
||||
# of an image
|
||||
extensionList= {
|
||||
|
@ -579,7 +579,7 @@ def saveMediaInFormPOST(mediaBytes,debug: bool, \
|
|||
def extractTextFieldsInPOST(postBytes,boundary,debug: bool) -> {}:
|
||||
"""Returns a dictionary containing the text fields of a http form POST
|
||||
The boundary argument comes from the http header
|
||||
"""
|
||||
"""
|
||||
msg=email.parser.BytesParser().parsebytes(postBytes)
|
||||
if debug:
|
||||
print('DEBUG: POST arriving '+msg.get_payload(decode=True).decode('utf-8'))
|
||||
|
@ -590,7 +590,7 @@ def extractTextFieldsInPOST(postBytes,boundary,debug: bool) -> {}:
|
|||
if f=='--':
|
||||
continue
|
||||
if ' name="' not in f:
|
||||
continue
|
||||
continue
|
||||
postStr=f.split(' name="',1)[1]
|
||||
if '"' not in postStr:
|
||||
continue
|
||||
|
@ -600,7 +600,7 @@ def extractTextFieldsInPOST(postBytes,boundary,debug: bool) -> {}:
|
|||
continue
|
||||
if '\r\n' not in postValueStr:
|
||||
continue
|
||||
postLines=postValueStr.split('\r\n')
|
||||
postLines=postValueStr.split('\r\n')
|
||||
postValue=''
|
||||
if len(postLines)>2:
|
||||
for line in range(2,len(postLines)-1):
|
||||
|
|
12
delete.py
12
delete.py
|
@ -80,7 +80,7 @@ def createDelete(session,baseDir: str,federationList: [], \
|
|||
'https://www.w3.org/ns/activitystreams#Public', \
|
||||
httpPrefix,True,clientToServer,federationList, \
|
||||
sendThreads,postLog,cachedWebfingers,personCache,debug)
|
||||
|
||||
|
||||
return newDelete
|
||||
|
||||
def sendDeleteViaServer(baseDir: str,session, \
|
||||
|
@ -131,7 +131,7 @@ def sendDeleteViaServer(baseDir: str,session, \
|
|||
getPersonBox(baseDir,session,wfRequest,personCache, \
|
||||
projectVersion,httpPrefix,fromNickname, \
|
||||
fromDomain,postToBox)
|
||||
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
print('DEBUG: No '+postToBox+' was found for '+handle)
|
||||
|
@ -140,9 +140,9 @@ def sendDeleteViaServer(baseDir: str,session, \
|
|||
if debug:
|
||||
print('DEBUG: No actor was found for '+handle)
|
||||
return 4
|
||||
|
||||
|
||||
authHeader=createBasicAuthHeader(fromNickname,password)
|
||||
|
||||
|
||||
headers={
|
||||
'host': fromDomain, \
|
||||
'Content-type': 'application/json', \
|
||||
|
@ -257,14 +257,14 @@ def outboxDelete(baseDir: str,httpPrefix: str, \
|
|||
if deleteNickname!=nickname:
|
||||
if debug:
|
||||
print("DEBUG: you can't delete a post which wasn't created by you (nickname does not match)")
|
||||
return
|
||||
return
|
||||
deleteDomain,deletePort=getDomainFromActor(messageId)
|
||||
if ':' in domain:
|
||||
domain=domain.split(':')[0]
|
||||
if deleteDomain!=domain:
|
||||
if debug:
|
||||
print("DEBUG: you can't delete a post which wasn't created by you (domain does not match)")
|
||||
return
|
||||
return
|
||||
removeModerationPostFromIndex(baseDir,messageId,debug)
|
||||
postFilename=locatePost(baseDir,deleteNickname,deleteDomain,messageId)
|
||||
if not postFilename:
|
||||
|
|
|
@ -12,7 +12,7 @@ def getDonationTypes() -> str:
|
|||
return ('patreon','paypal','gofundme','liberapay', \
|
||||
'kickstarter','indiegogo','crowdsupply', \
|
||||
'subscribestar')
|
||||
|
||||
|
||||
def getDonationUrl(actorJson: {}) -> str:
|
||||
"""Returns a link used for donations
|
||||
"""
|
||||
|
|
112
epicyon.py
112
epicyon.py
|
@ -354,7 +354,7 @@ if args.posts:
|
|||
if args.postsraw:
|
||||
if '@' not in args.postsraw:
|
||||
print('Syntax: --postsraw nickname@domain')
|
||||
sys.exit()
|
||||
sys.exit()
|
||||
if not args.http:
|
||||
args.port=443
|
||||
nickname=args.postsraw.split('@')[0]
|
||||
|
@ -398,7 +398,7 @@ if not args.blogsinstance:
|
|||
blogsInstance=getConfigParam(baseDir,'blogsInstance')
|
||||
if blogsInstance!=None:
|
||||
args.blogsinstance=blogsInstance
|
||||
|
||||
|
||||
# set the instance title in config.json
|
||||
title=getConfigParam(baseDir,'instanceTitle')
|
||||
if not title:
|
||||
|
@ -450,13 +450,13 @@ if not getConfigParam(baseDir,'registration'):
|
|||
setConfigParam(baseDir,'maxRegistrations',str(maxRegistrations))
|
||||
setConfigParam(baseDir,'registrationsRemaining',str(maxRegistrations))
|
||||
|
||||
if args.resetregistrations:
|
||||
if args.resetregistrations:
|
||||
setConfigParam(baseDir,'registrationsRemaining',str(maxRegistrations))
|
||||
print('Number of new registrations reset to '+str(maxRegistrations))
|
||||
|
||||
|
||||
# whether new registrations are open or closed
|
||||
if args.registration:
|
||||
if args.registration.lower()=='open':
|
||||
if args.registration.lower()=='open':
|
||||
registration=getConfigParam(baseDir,'registration')
|
||||
if not registration:
|
||||
setConfigParam(baseDir,'registrationsRemaining',str(maxRegistrations))
|
||||
|
@ -468,7 +468,7 @@ if args.registration:
|
|||
else:
|
||||
setConfigParam(baseDir,'registration','closed')
|
||||
print('New registrations closed')
|
||||
|
||||
|
||||
# unique ID for the instance
|
||||
instanceId=getConfigParam(baseDir,'instanceId')
|
||||
if not instanceId:
|
||||
|
@ -535,7 +535,7 @@ if args.approve:
|
|||
if '@' not in args.approve:
|
||||
print('syntax: --approve nick@domain')
|
||||
sys.exit()
|
||||
session=createSession(useTor)
|
||||
session=createSession(useTor)
|
||||
sendThreads=[]
|
||||
postLog=[]
|
||||
cachedWebfingers={}
|
||||
|
@ -559,7 +559,7 @@ if args.deny:
|
|||
if '@' not in args.deny:
|
||||
print('syntax: --deny nick@domain')
|
||||
sys.exit()
|
||||
session=createSession(useTor)
|
||||
session=createSession(useTor)
|
||||
sendThreads=[]
|
||||
postLog=[]
|
||||
cachedWebfingers={}
|
||||
|
@ -590,21 +590,21 @@ if args.followerspending:
|
|||
if approveCtr==0:
|
||||
print('There are no follow requests pending approval.')
|
||||
sys.exit()
|
||||
|
||||
|
||||
|
||||
|
||||
if args.message:
|
||||
if not args.nickname:
|
||||
print('Specify a nickname with the --nickname option')
|
||||
sys.exit()
|
||||
|
||||
|
||||
if not args.password:
|
||||
print('Specify a password with the --password option')
|
||||
sys.exit()
|
||||
|
||||
session=createSession(useTor)
|
||||
|
||||
session=createSession(useTor)
|
||||
if not args.sendto:
|
||||
print('Specify an account to sent to: --sendto [nickname@domain]')
|
||||
sys.exit()
|
||||
sys.exit()
|
||||
if '@' not in args.sendto and \
|
||||
not args.sendto.lower().endswith('public') and \
|
||||
not args.sendto.lower().endswith('followers'):
|
||||
|
@ -628,7 +628,7 @@ if args.message:
|
|||
toNickname=None
|
||||
toDomain='public'
|
||||
toPort=port
|
||||
|
||||
|
||||
#ccUrl=httpPrefix+'://'+domain+'/users/'+nickname+'/followers'
|
||||
ccUrl=None
|
||||
sendMessage=args.message
|
||||
|
@ -668,12 +668,12 @@ if args.announce:
|
|||
if not args.nickname:
|
||||
print('Specify a nickname with the --nickname option')
|
||||
sys.exit()
|
||||
|
||||
|
||||
if not args.password:
|
||||
print('Specify a password with the --password option')
|
||||
sys.exit()
|
||||
|
||||
session=createSession(useTor)
|
||||
|
||||
session=createSession(useTor)
|
||||
personCache={}
|
||||
cachedWebfingers={}
|
||||
print('Sending announce/repeat of '+args.announce)
|
||||
|
@ -717,7 +717,7 @@ if args.itemName:
|
|||
print('Specify a duration to share the object with the --duration option')
|
||||
sys.exit()
|
||||
|
||||
session=createSession(useTor)
|
||||
session=createSession(useTor)
|
||||
personCache={}
|
||||
cachedWebfingers={}
|
||||
print('Sending shared item: '+args.itemName)
|
||||
|
@ -749,7 +749,7 @@ if args.undoItemName:
|
|||
print('Specify a nickname with the --nickname option')
|
||||
sys.exit()
|
||||
|
||||
session=createSession(useTor)
|
||||
session=createSession(useTor)
|
||||
personCache={}
|
||||
cachedWebfingers={}
|
||||
print('Sending undo of shared item: '+args.undoItemName)
|
||||
|
@ -770,12 +770,12 @@ if args.like:
|
|||
if not args.nickname:
|
||||
print('Specify a nickname with the --nickname option')
|
||||
sys.exit()
|
||||
|
||||
|
||||
if not args.password:
|
||||
print('Specify a password with the --password option')
|
||||
sys.exit()
|
||||
|
||||
session=createSession(useTor)
|
||||
|
||||
session=createSession(useTor)
|
||||
personCache={}
|
||||
cachedWebfingers={}
|
||||
print('Sending like of '+args.like)
|
||||
|
@ -795,12 +795,12 @@ if args.undolike:
|
|||
if not args.nickname:
|
||||
print('Specify a nickname with the --nickname option')
|
||||
sys.exit()
|
||||
|
||||
|
||||
if not args.password:
|
||||
print('Specify a password with the --password option')
|
||||
sys.exit()
|
||||
|
||||
session=createSession(useTor)
|
||||
|
||||
session=createSession(useTor)
|
||||
personCache={}
|
||||
cachedWebfingers={}
|
||||
print('Sending undo like of '+args.undolike)
|
||||
|
@ -820,12 +820,12 @@ if args.delete:
|
|||
if not args.nickname:
|
||||
print('Specify a nickname with the --nickname option')
|
||||
sys.exit()
|
||||
|
||||
|
||||
if not args.password:
|
||||
print('Specify a password with the --password option')
|
||||
sys.exit()
|
||||
|
||||
session=createSession(useTor)
|
||||
|
||||
session=createSession(useTor)
|
||||
personCache={}
|
||||
cachedWebfingers={}
|
||||
print('Sending delete request of '+args.delete)
|
||||
|
@ -852,11 +852,11 @@ if args.follow:
|
|||
if not args.password:
|
||||
print('Please specify the password for '+args.nickname+' on '+domain)
|
||||
sys.exit()
|
||||
|
||||
|
||||
followNickname=getNicknameFromActor(args.follow)
|
||||
if not followNickname:
|
||||
print('Unable to find nickname in '+args.follow)
|
||||
sys.exit()
|
||||
sys.exit()
|
||||
followDomain,followPort=getDomainFromActor(args.follow)
|
||||
|
||||
session=createSession(useTor)
|
||||
|
@ -890,11 +890,11 @@ if args.unfollow:
|
|||
if not args.password:
|
||||
print('Please specify the password for '+args.nickname+' on '+domain)
|
||||
sys.exit()
|
||||
|
||||
|
||||
followNickname=getNicknameFromActor(args.unfollow)
|
||||
if not followNickname:
|
||||
print('WARN: unable to find nickname in '+args.unfollow)
|
||||
sys.exit()
|
||||
sys.exit()
|
||||
followDomain,followPort=getDomainFromActor(args.unfollow)
|
||||
|
||||
session=createSession(useTor)
|
||||
|
@ -927,7 +927,7 @@ if args.port:
|
|||
if args.proxyPort:
|
||||
proxyPort=args.proxyPort
|
||||
setConfigParam(baseDir,'proxyPort',proxyPort)
|
||||
ocapAlways=False
|
||||
ocapAlways=False
|
||||
if args.ocap:
|
||||
ocapAlways=args.ocap
|
||||
if args.dat:
|
||||
|
@ -995,7 +995,7 @@ if args.actor:
|
|||
personUrl=originalActor
|
||||
else:
|
||||
sys.exit()
|
||||
|
||||
|
||||
asHeader={
|
||||
'Accept': 'application/activity+json; profile="https://www.w3.org/ns/activitystreams"'
|
||||
}
|
||||
|
@ -1041,13 +1041,13 @@ if args.addaccount:
|
|||
sys.exit()
|
||||
if not validNickname(domain,nickname):
|
||||
print(nickname+' is a reserved name. Use something different.')
|
||||
sys.exit()
|
||||
sys.exit()
|
||||
if not args.password:
|
||||
print('Use the --password option to set the password for '+nickname)
|
||||
sys.exit()
|
||||
if len(args.password.strip())<8:
|
||||
print('Password should be at least 8 characters')
|
||||
sys.exit()
|
||||
sys.exit()
|
||||
if os.path.isdir(baseDir+'/accounts/'+nickname+'@'+domain):
|
||||
print('Account already exists')
|
||||
sys.exit()
|
||||
|
@ -1198,7 +1198,7 @@ if args.avatar:
|
|||
print('Avatar added for '+args.nickname)
|
||||
else:
|
||||
print('Avatar was not added for '+args.nickname)
|
||||
sys.exit()
|
||||
sys.exit()
|
||||
|
||||
if args.backgroundImage:
|
||||
if not os.path.isfile(args.backgroundImage):
|
||||
|
@ -1212,14 +1212,14 @@ if args.backgroundImage:
|
|||
print('Background image added for '+args.nickname)
|
||||
else:
|
||||
print('Background image was not added for '+args.nickname)
|
||||
sys.exit()
|
||||
sys.exit()
|
||||
|
||||
if args.project:
|
||||
if not args.delegate and not args.undelegate:
|
||||
if not args.delegate and not args.undelegate:
|
||||
if not nickname:
|
||||
print('No nickname given')
|
||||
sys.exit()
|
||||
|
||||
|
||||
if args.role.lower()=='none' or \
|
||||
args.role.lower()=='remove' or \
|
||||
args.role.lower()=='delete':
|
||||
|
@ -1236,7 +1236,7 @@ if args.skill:
|
|||
if not nickname:
|
||||
print('Specify a nickname with the --nickname option')
|
||||
sys.exit()
|
||||
|
||||
|
||||
if not args.password:
|
||||
print('Specify a password with the --password option')
|
||||
sys.exit()
|
||||
|
@ -1249,7 +1249,7 @@ if args.skill:
|
|||
print('Skill level should be a percentage in the range 0-100')
|
||||
sys.exit()
|
||||
|
||||
session=createSession(useTor)
|
||||
session=createSession(useTor)
|
||||
personCache={}
|
||||
cachedWebfingers={}
|
||||
print('Sending '+args.skill+' skill level '+str(args.skillLevelPercent)+' for '+nickname)
|
||||
|
@ -1270,12 +1270,12 @@ if args.availability:
|
|||
if not nickname:
|
||||
print('Specify a nickname with the --nickname option')
|
||||
sys.exit()
|
||||
|
||||
|
||||
if not args.password:
|
||||
print('Specify a password with the --password option')
|
||||
sys.exit()
|
||||
|
||||
session=createSession(useTor)
|
||||
session=createSession(useTor)
|
||||
personCache={}
|
||||
cachedWebfingers={}
|
||||
print('Sending availability status of '+nickname+' as '+args.availability)
|
||||
|
@ -1305,7 +1305,7 @@ if args.block:
|
|||
if not nickname:
|
||||
print('Specify a nickname with the --nickname option')
|
||||
sys.exit()
|
||||
|
||||
|
||||
if not args.password:
|
||||
print('Specify a password with the --password option')
|
||||
sys.exit()
|
||||
|
@ -1320,7 +1320,7 @@ if args.block:
|
|||
print(args.block+' does not look like an actor url')
|
||||
sys.exit()
|
||||
|
||||
session=createSession(useTor)
|
||||
session=createSession(useTor)
|
||||
personCache={}
|
||||
cachedWebfingers={}
|
||||
print('Sending block of '+args.block)
|
||||
|
@ -1339,7 +1339,7 @@ if args.delegate:
|
|||
if not nickname:
|
||||
print('Specify a nickname with the --nickname option')
|
||||
sys.exit()
|
||||
|
||||
|
||||
if not args.password:
|
||||
print('Specify a password with the --password option')
|
||||
sys.exit()
|
||||
|
@ -1356,7 +1356,7 @@ if args.delegate:
|
|||
delegatedNickname=args.delegate.split('@')[0]
|
||||
args.delegate=blockedActor
|
||||
|
||||
session=createSession(useTor)
|
||||
session=createSession(useTor)
|
||||
personCache={}
|
||||
cachedWebfingers={}
|
||||
print('Sending delegation for '+args.delegate+' with role '+args.role+' in project '+args.project)
|
||||
|
@ -1377,7 +1377,7 @@ if args.undelegate:
|
|||
if not nickname:
|
||||
print('Specify a nickname with the --nickname option')
|
||||
sys.exit()
|
||||
|
||||
|
||||
if not args.password:
|
||||
print('Specify a password with the --password option')
|
||||
sys.exit()
|
||||
|
@ -1390,7 +1390,7 @@ if args.undelegate:
|
|||
delegatedNickname=args.undelegate.split('@')[0]
|
||||
args.undelegate=blockedActor
|
||||
|
||||
session=createSession(useTor)
|
||||
session=createSession(useTor)
|
||||
personCache={}
|
||||
cachedWebfingers={}
|
||||
print('Sending delegation removal for '+args.undelegate+' from role '+args.role+' in project '+args.project)
|
||||
|
@ -1411,7 +1411,7 @@ if args.unblock:
|
|||
if not nickname:
|
||||
print('Specify a nickname with the --nickname option')
|
||||
sys.exit()
|
||||
|
||||
|
||||
if not args.password:
|
||||
print('Specify a password with the --password option')
|
||||
sys.exit()
|
||||
|
@ -1426,7 +1426,7 @@ if args.unblock:
|
|||
print(args.unblock+' does not look like an actor url')
|
||||
sys.exit()
|
||||
|
||||
session=createSession(useTor)
|
||||
session=createSession(useTor)
|
||||
personCache={}
|
||||
cachedWebfingers={}
|
||||
print('Sending undo block of '+args.unblock)
|
||||
|
@ -1458,7 +1458,7 @@ if args.unfilterStr:
|
|||
sys.exit()
|
||||
|
||||
if args.testdata:
|
||||
useBlurhash=False
|
||||
useBlurhash=False
|
||||
nickname='testuser567'
|
||||
password='boringpassword'
|
||||
print('Generating some test data for user: '+nickname)
|
||||
|
@ -1475,7 +1475,7 @@ if args.testdata:
|
|||
shutil.rmtree(baseDir+'/sharefiles')
|
||||
if os.path.isdir(baseDir+'/wfendpoints'):
|
||||
shutil.rmtree(baseDir+'/wfendpoints')
|
||||
|
||||
|
||||
setConfigParam(baseDir,'registrationsRemaining',str(maxRegistrations))
|
||||
|
||||
createPerson(baseDir,'maxboardroom',domain,port,httpPrefix,True,password)
|
||||
|
@ -1511,7 +1511,7 @@ if args.testdata:
|
|||
"City", \
|
||||
"3 months",
|
||||
debug)
|
||||
|
||||
|
||||
deleteAllPosts(baseDir,nickname,domain,'inbox')
|
||||
deleteAllPosts(baseDir,nickname,domain,'outbox')
|
||||
createPublicPost(baseDir,nickname,domain,port,httpPrefix,"like, this is totally just a #test, man",False,True,False,None,None,useBlurhash)
|
||||
|
|
|
@ -74,4 +74,3 @@ def isFiltered(baseDir: str,nickname: str,domain: str,content: str) -> bool:
|
|||
return False
|
||||
return True
|
||||
return False
|
||||
|
||||
|
|
44
follow.py
44
follow.py
|
@ -88,7 +88,7 @@ def isFollowingActor(baseDir: str,nickname: str,domain: str,actor: str) -> bool:
|
|||
handle=nickname+'@'+domain
|
||||
if not os.path.isdir(baseDir+'/accounts/'+handle):
|
||||
return False
|
||||
followingFile=baseDir+'/accounts/'+handle+'/following.txt'
|
||||
followingFile=baseDir+'/accounts/'+handle+'/following.txt'
|
||||
if not os.path.isfile(followingFile):
|
||||
return False
|
||||
if actor in open(followingFile).read():
|
||||
|
@ -284,7 +284,7 @@ def getFollowingFeed(baseDir: str,domain: str,port: int,path: str, \
|
|||
return None
|
||||
# handle page numbers
|
||||
headerOnly=True
|
||||
pageNumber=None
|
||||
pageNumber=None
|
||||
if '?page=' in path:
|
||||
pageNumber=path.split('?page=')[1]
|
||||
if pageNumber=='true' or not authenticated:
|
||||
|
@ -296,7 +296,7 @@ def getFollowingFeed(baseDir: str,domain: str,port: int,path: str, \
|
|||
pass
|
||||
path=path.split('?page=')[0]
|
||||
headerOnly=False
|
||||
|
||||
|
||||
if not path.endswith('/'+followFile):
|
||||
return None
|
||||
nickname=None
|
||||
|
@ -495,7 +495,7 @@ def receiveFollowRequest(session,baseDir: str,httpPrefix: str, \
|
|||
'/channel/' not in messageJson['actor'] and \
|
||||
'/profile/' not in messageJson['actor']:
|
||||
if debug:
|
||||
print('DEBUG: "users" or "profile" missing from actor')
|
||||
print('DEBUG: "users" or "profile" missing from actor')
|
||||
return False
|
||||
domain,tempPort=getDomainFromActor(messageJson['actor'])
|
||||
fromPort=port
|
||||
|
@ -534,7 +534,7 @@ def receiveFollowRequest(session,baseDir: str,httpPrefix: str, \
|
|||
if tempPort:
|
||||
if tempPort!=80 and tempPort!=443:
|
||||
if ':' not in domainToFollow:
|
||||
domainToFollowFull=domainToFollow+':'+str(tempPort)
|
||||
domainToFollowFull=domainToFollow+':'+str(tempPort)
|
||||
nicknameToFollow=getNicknameFromActor(messageJson['object'])
|
||||
if not nicknameToFollow:
|
||||
if debug:
|
||||
|
@ -547,7 +547,7 @@ def receiveFollowRequest(session,baseDir: str,httpPrefix: str, \
|
|||
print('DEBUG: followed account not found - '+ \
|
||||
baseDir+'/accounts/'+handleToFollow)
|
||||
return True
|
||||
|
||||
|
||||
if isFollowerOfPerson(baseDir, \
|
||||
nicknameToFollow,domainToFollowFull, \
|
||||
nickname,domainFull):
|
||||
|
@ -556,13 +556,13 @@ def receiveFollowRequest(session,baseDir: str,httpPrefix: str, \
|
|||
' is already a follower of '+ \
|
||||
nicknameToFollow+'@'+domainToFollow)
|
||||
return True
|
||||
|
||||
|
||||
# what is the followers policy?
|
||||
approveHandle=nickname+'@'+domainFull
|
||||
approveHandle=nickname+'@'+domainFull
|
||||
if followApprovalRequired(baseDir,nicknameToFollow, \
|
||||
domainToFollow,debug,approveHandle):
|
||||
print('Follow approval is required')
|
||||
if not domain.endswith('.onion'):
|
||||
if not domain.endswith('.onion'):
|
||||
if noOfFollowRequests(baseDir, \
|
||||
nicknameToFollow,domainToFollow, \
|
||||
nickname,domain,fromPort, \
|
||||
|
@ -730,10 +730,10 @@ def sendFollowRequest(session,baseDir: str, \
|
|||
personCache: {},debug : bool, \
|
||||
projectVersion: str) -> {}:
|
||||
"""Gets the json object for sending a follow request
|
||||
"""
|
||||
"""
|
||||
if not domainPermitted(followDomain,federationList):
|
||||
return None
|
||||
|
||||
|
||||
fullDomain=domain
|
||||
followActor=httpPrefix+'://'+domain+'/users/'+nickname
|
||||
if port:
|
||||
|
@ -749,7 +749,7 @@ def sendFollowRequest(session,baseDir: str, \
|
|||
requestDomain=followDomain+':'+str(followPort)
|
||||
|
||||
statusNumber,published=getStatusNumber()
|
||||
|
||||
|
||||
if followNickname:
|
||||
followedId=followHttpPrefix+'://'+requestDomain+'/users/'+followNickname
|
||||
followHandle=followNickname+'@'+requestDomain
|
||||
|
@ -812,7 +812,7 @@ def sendFollowRequestViaServer(baseDir: str,session, \
|
|||
if ':' not in followDomain:
|
||||
followDomainFull=followDomain+':'+str(followPort)
|
||||
|
||||
followActor=httpPrefix+'://'+fromDomainFull+'/users/'+fromNickname
|
||||
followActor=httpPrefix+'://'+fromDomainFull+'/users/'+fromNickname
|
||||
followedId=httpPrefix+'://'+followDomainFull+'/users/'+followNickname
|
||||
|
||||
statusNumber,published=getStatusNumber()
|
||||
|
@ -842,7 +842,7 @@ def sendFollowRequestViaServer(baseDir: str,session, \
|
|||
getPersonBox(baseDir,session,wfRequest,personCache, \
|
||||
projectVersion,httpPrefix,fromNickname, \
|
||||
fromDomain,postToBox)
|
||||
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
print('DEBUG: No '+postToBox+' was found for '+handle)
|
||||
|
@ -851,9 +851,9 @@ def sendFollowRequestViaServer(baseDir: str,session, \
|
|||
if debug:
|
||||
print('DEBUG: No actor was found for '+handle)
|
||||
return 4
|
||||
|
||||
|
||||
authHeader=createBasicAuthHeader(fromNickname,password)
|
||||
|
||||
|
||||
headers={
|
||||
'host': fromDomain, \
|
||||
'Content-type': 'application/json', \
|
||||
|
@ -895,7 +895,7 @@ def sendUnfollowRequestViaServer(baseDir: str,session, \
|
|||
if ':' not in followDomain:
|
||||
followDomainFull=followDomain+':'+str(followPort)
|
||||
|
||||
followActor=httpPrefix+'://'+fromDomainFull+'/users/'+fromNickname
|
||||
followActor=httpPrefix+'://'+fromDomainFull+'/users/'+fromNickname
|
||||
followedId=httpPrefix+'://'+followDomainFull+'/users/'+followNickname
|
||||
statusNumber,published=getStatusNumber()
|
||||
|
||||
|
@ -930,7 +930,7 @@ def sendUnfollowRequestViaServer(baseDir: str,session, \
|
|||
getPersonBox(baseDir,session,wfRequest,personCache, \
|
||||
projectVersion,httpPrefix,fromNickname, \
|
||||
fromDomain,postToBox)
|
||||
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
print('DEBUG: No '+postToBox+' was found for '+handle)
|
||||
|
@ -939,9 +939,9 @@ def sendUnfollowRequestViaServer(baseDir: str,session, \
|
|||
if debug:
|
||||
print('DEBUG: No actor was found for '+handle)
|
||||
return 4
|
||||
|
||||
|
||||
authHeader=createBasicAuthHeader(fromNickname,password)
|
||||
|
||||
|
||||
headers={
|
||||
'host': fromDomain, \
|
||||
'Content-type': 'application/json', \
|
||||
|
@ -1008,7 +1008,7 @@ def getFollowersOfActor(baseDir :str,actor :str,debug: bool) -> {}:
|
|||
if ocapJson.get('id'):
|
||||
if debug:
|
||||
print('DEBUG: capabilities id found for '+account)
|
||||
|
||||
|
||||
recipientsDict[account]=ocapJson['id']
|
||||
else:
|
||||
if debug:
|
||||
|
@ -1058,7 +1058,7 @@ def outboxUndoFollow(baseDir: str,messageJson: {},debug: bool) -> None:
|
|||
if portFollower!=80 and portFollower!=443:
|
||||
if ':' not in domainFollower:
|
||||
domainFollowerFull=domainFollower+':'+str(portFollower)
|
||||
|
||||
|
||||
nicknameFollowing=getNicknameFromActor(messageJson['object']['object'])
|
||||
if not nicknameFollowing:
|
||||
print('WARN: unable to find nickname in '+messageJson['object']['object'])
|
||||
|
|
14
happening.py
14
happening.py
|
@ -67,7 +67,7 @@ def getTodaysEvents(baseDir: str,nickname: str,domain: str, \
|
|||
|
||||
calendarPostIds=[]
|
||||
recreateEventsFile=False
|
||||
with open(calendarFilename,'r') as eventsFile:
|
||||
with open(calendarFilename,'r') as eventsFile:
|
||||
for postId in eventsFile:
|
||||
postId=postId.replace('\n','')
|
||||
postFilename=locatePost(baseDir,nickname,domain,postId)
|
||||
|
@ -134,7 +134,7 @@ def todaysEventsCheck(baseDir: str,nickname: str,domain: str) -> bool:
|
|||
return False
|
||||
|
||||
eventsExist=False
|
||||
with open(calendarFilename,'r') as eventsFile:
|
||||
with open(calendarFilename,'r') as eventsFile:
|
||||
for postId in eventsFile:
|
||||
postId=postId.replace('\n','')
|
||||
postFilename=locatePost(baseDir,nickname,domain,postId)
|
||||
|
@ -180,7 +180,7 @@ def thisWeeksEventsCheck(baseDir: str,nickname: str,domain: str) -> bool:
|
|||
return False
|
||||
|
||||
eventsExist=False
|
||||
with open(calendarFilename,'r') as eventsFile:
|
||||
with open(calendarFilename,'r') as eventsFile:
|
||||
for postId in eventsFile:
|
||||
postId=postId.replace('\n','')
|
||||
postFilename=locatePost(baseDir,nickname,domain,postId)
|
||||
|
@ -207,7 +207,7 @@ def thisWeeksEventsCheck(baseDir: str,nickname: str,domain: str) -> bool:
|
|||
int(eventTime.strftime("%m"))==monthNumber and \
|
||||
(int(eventTime.strftime("%d"))>dayNumber and \
|
||||
int(eventTime.strftime("%d"))<=dayNumber+6):
|
||||
eventsExist=True
|
||||
eventsExist=True
|
||||
break
|
||||
|
||||
return eventsExist
|
||||
|
@ -233,7 +233,7 @@ def getThisWeeksEvents(baseDir: str,nickname: str,domain: str) -> {}:
|
|||
|
||||
calendarPostIds=[]
|
||||
recreateEventsFile=False
|
||||
with open(calendarFilename,'r') as eventsFile:
|
||||
with open(calendarFilename,'r') as eventsFile:
|
||||
for postId in eventsFile:
|
||||
postId=postId.replace('\n','')
|
||||
postFilename=locatePost(baseDir,nickname,domain,postId)
|
||||
|
@ -317,7 +317,7 @@ def getCalendarEvents(baseDir: str,nickname: str,domain: str, \
|
|||
|
||||
calendarPostIds=[]
|
||||
recreateEventsFile=False
|
||||
with open(calendarFilename,'r') as eventsFile:
|
||||
with open(calendarFilename,'r') as eventsFile:
|
||||
for postId in eventsFile:
|
||||
postId=postId.replace('\n','')
|
||||
postFilename=locatePost(baseDir,nickname,domain,postId)
|
||||
|
@ -362,7 +362,7 @@ def getCalendarEvents(baseDir: str,nickname: str,domain: str, \
|
|||
for postId in calendarPostIds:
|
||||
calendarFile.write(postId+'\n')
|
||||
calendarFile.close()
|
||||
|
||||
|
||||
return events
|
||||
|
||||
def removeCalendarEvent(baseDir: str,nickname: str,domain: str, \
|
||||
|
|
|
@ -9,7 +9,7 @@ __status__="Production"
|
|||
|
||||
# see https://tools.ietf.org/html/draft-cavage-http-signatures-06
|
||||
|
||||
try:
|
||||
try:
|
||||
from Cryptodome.PublicKey import RSA
|
||||
from Cryptodome.Hash import SHA256
|
||||
from Cryptodome.Signature import pkcs1_15
|
||||
|
@ -175,7 +175,7 @@ def verifyPostHeaders(httpPrefix: str,publicKeyPem: str,headers: dict, \
|
|||
|
||||
if debug:
|
||||
print('DEBUG: verifyPostHeaders '+method)
|
||||
|
||||
|
||||
publicKeyPem=RSA.import_key(publicKeyPem)
|
||||
# Build a dictionary of the signature values
|
||||
signatureHeader=headers['signature']
|
||||
|
|
92
inbox.py
92
inbox.py
|
@ -79,7 +79,7 @@ def storeHashTags(baseDir: str,nickname: str,postJsonObject: {}) -> None:
|
|||
return
|
||||
if not isinstance(postJsonObject['object']['tag'], list):
|
||||
return
|
||||
tagsDir=baseDir+'/tags'
|
||||
tagsDir=baseDir+'/tags'
|
||||
for tag in postJsonObject['object']['tag']:
|
||||
if not tag.get('type'):
|
||||
continue
|
||||
|
@ -149,7 +149,7 @@ def validInbox(baseDir: str,nickname: str,domain: str) -> bool:
|
|||
if 'postNickname' in open(filename).read():
|
||||
print('queue file incorrectly saved to '+filename)
|
||||
return False
|
||||
return True
|
||||
return True
|
||||
|
||||
def validInboxFilenames(baseDir: str,nickname: str,domain: str, \
|
||||
expectedDomain: str,expectedPort: int) -> bool:
|
||||
|
@ -172,7 +172,7 @@ def validInboxFilenames(baseDir: str,nickname: str,domain: str, \
|
|||
print('Expected: '+expectedStr)
|
||||
print('Invalid filename: '+filename)
|
||||
return False
|
||||
return True
|
||||
return True
|
||||
|
||||
def getPersonPubKey(baseDir: str,session,personUrl: str, \
|
||||
personCache: {},debug: bool, \
|
||||
|
@ -184,7 +184,7 @@ def getPersonPubKey(baseDir: str,session,personUrl: str, \
|
|||
if personUrl.endswith('/users/inbox'):
|
||||
if debug:
|
||||
print('DEBUG: Obtaining public key for shared inbox')
|
||||
personUrl=personUrl.replace('/users/inbox','/inbox')
|
||||
personUrl=personUrl.replace('/users/inbox','/inbox')
|
||||
personJson=getPersonFromCache(baseDir,personUrl,personCache)
|
||||
if not personJson:
|
||||
if debug:
|
||||
|
@ -345,9 +345,9 @@ def savePostToInboxQueue(baseDir: str,httpPrefix: str, \
|
|||
postId=actor+'/statuses/'+statusNumber
|
||||
else:
|
||||
postId=httpPrefix+'://'+originalDomain+'/users/'+nickname+'/statuses/'+statusNumber
|
||||
|
||||
|
||||
# NOTE: don't change postJsonObject['id'] before signature check
|
||||
|
||||
|
||||
inboxQueueDir=createInboxQueueDir(nickname,domain,baseDir)
|
||||
|
||||
handle=nickname+'@'+domain
|
||||
|
@ -418,7 +418,7 @@ def inboxCheckCapabilities(baseDir :str,nickname :str,domain :str, \
|
|||
return False
|
||||
|
||||
oc=loadJson(ocapFilename)
|
||||
if not oc:
|
||||
if not oc:
|
||||
return False
|
||||
|
||||
if not oc.get('id'):
|
||||
|
@ -533,7 +533,7 @@ def inboxPostRecipients(baseDir :str,postJsonObject :{}, \
|
|||
|
||||
actor=postJsonObject['actor']
|
||||
# first get any specific people which the post is addressed to
|
||||
|
||||
|
||||
followerRecipients=False
|
||||
if postJsonObject.get('object'):
|
||||
if isinstance(postJsonObject['object'], dict):
|
||||
|
@ -649,7 +649,7 @@ def receiveUndoFollow(session,baseDir: str,httpPrefix: str, \
|
|||
if portFollower!=80 and portFollower!=443:
|
||||
if ':' not in domainFollower:
|
||||
domainFollowerFull=domainFollower+':'+str(portFollower)
|
||||
|
||||
|
||||
nicknameFollowing=getNicknameFromActor(messageJson['object']['object'])
|
||||
if not nicknameFollowing:
|
||||
print('WARN: unable to find nickname in '+messageJson['object']['object'])
|
||||
|
@ -668,7 +668,7 @@ def receiveUndoFollow(session,baseDir: str,httpPrefix: str, \
|
|||
if debug:
|
||||
print('DEBUG: Follower '+nicknameFollower+'@'+domainFollowerFull+' was removed')
|
||||
return True
|
||||
|
||||
|
||||
if debug:
|
||||
print('DEBUG: Follower '+nicknameFollower+'@'+domainFollowerFull+' was not removed')
|
||||
return False
|
||||
|
@ -693,7 +693,7 @@ def receiveUndo(session,baseDir: str,httpPrefix: str, \
|
|||
'/channel/' not in messageJson['actor'] and \
|
||||
'/profile/' not in messageJson['actor']:
|
||||
if debug:
|
||||
print('DEBUG: "users" or "profile" missing from actor')
|
||||
print('DEBUG: "users" or "profile" missing from actor')
|
||||
return False
|
||||
if not messageJson.get('object'):
|
||||
if debug:
|
||||
|
@ -755,11 +755,11 @@ def personReceiveUpdate(baseDir: str, \
|
|||
return False
|
||||
if not personJson.get('publicKey'):
|
||||
if debug:
|
||||
print('DEBUG: actor update does not contain a public key')
|
||||
print('DEBUG: actor update does not contain a public key')
|
||||
return False
|
||||
if not personJson['publicKey'].get('publicKeyPem'):
|
||||
if debug:
|
||||
print('DEBUG: actor update does not contain a public key Pem')
|
||||
print('DEBUG: actor update does not contain a public key Pem')
|
||||
return False
|
||||
actorFilename=baseDir+'/cache/actors/'+personJson['id'].replace('/','#')+'.json'
|
||||
# check that the public keys match.
|
||||
|
@ -824,7 +824,7 @@ def receiveUpdateToQuestion(recentPostsCache: {},messageJson: {}, \
|
|||
os.remove(cachedPostFilename)
|
||||
# remove from memory cache
|
||||
removePostFromCache(messageJson,recentPostsCache)
|
||||
|
||||
|
||||
def receiveUpdate(recentPostsCache: {},session,baseDir: str, \
|
||||
httpPrefix: str,domain :str,port: int, \
|
||||
sendThreads: [],postLog: [],cachedWebfingers: {}, \
|
||||
|
@ -878,7 +878,7 @@ def receiveUpdate(recentPostsCache: {},session,baseDir: str, \
|
|||
if debug:
|
||||
print('DEBUG: Unwrapped profile update was received for '+messageJson['url'])
|
||||
return True
|
||||
|
||||
|
||||
if messageJson['object']['type']=='Person' or \
|
||||
messageJson['object']['type']=='Application' or \
|
||||
messageJson['object']['type']=='Group' or \
|
||||
|
@ -1056,11 +1056,11 @@ def receiveBookmark(recentPostsCache: {}, \
|
|||
if domain not in handle.split('@')[1]:
|
||||
if debug:
|
||||
print('DEBUG: unrecognized domain '+handle)
|
||||
return False
|
||||
return False
|
||||
domainFull=domain
|
||||
if port:
|
||||
if port!=80 and port!=443:
|
||||
domainFull=domain+':'+str(port)
|
||||
domainFull=domain+':'+str(port)
|
||||
nickname=handle.split('@')[0]
|
||||
if not messageJson['actor'].endswith(domainFull+'/users/'+nickname):
|
||||
if debug:
|
||||
|
@ -1121,12 +1121,12 @@ def receiveUndoBookmark(recentPostsCache: {}, \
|
|||
domainFull=domain
|
||||
if port:
|
||||
if port!=80 and port!=443:
|
||||
domainFull=domain+':'+str(port)
|
||||
domainFull=domain+':'+str(port)
|
||||
nickname=handle.split('@')[0]
|
||||
if domain not in handle.split('@')[1]:
|
||||
if debug:
|
||||
print('DEBUG: unrecognized bookmark domain '+handle)
|
||||
return False
|
||||
return False
|
||||
if not messageJson['actor'].endswith(domainFull+'/users/'+nickname):
|
||||
if debug:
|
||||
print('DEBUG: bookmark actor should be the same as the handle sent to '+handle+' != '+messageJson['actor'])
|
||||
|
@ -1180,7 +1180,7 @@ def receiveDelete(session,handle: str,isGroup: bool,baseDir: str, \
|
|||
not messageJson['actor'].startswith(deletePrefix)):
|
||||
if debug:
|
||||
print('DEBUG: delete not permitted from other instances')
|
||||
return False
|
||||
return False
|
||||
if not messageJson.get('to'):
|
||||
if debug:
|
||||
print('DEBUG: '+messageJson['type']+' has no "to" list')
|
||||
|
@ -1197,9 +1197,9 @@ def receiveDelete(session,handle: str,isGroup: bool,baseDir: str, \
|
|||
return False
|
||||
if messageJson['actor'] not in messageJson['object']:
|
||||
if debug:
|
||||
print('DEBUG: actor is not the owner of the post to be deleted')
|
||||
print('DEBUG: actor is not the owner of the post to be deleted')
|
||||
if not os.path.isdir(baseDir+'/accounts/'+handle):
|
||||
print('DEBUG: unknown recipient of like - '+handle)
|
||||
print('DEBUG: unknown recipient of like - '+handle)
|
||||
# if this post in the outbox of the person?
|
||||
messageId=messageJson['object'].replace('/activity','').replace('/undo','')
|
||||
removeModerationPostFromIndex(baseDir,messageId,debug)
|
||||
|
@ -1227,7 +1227,7 @@ def receiveAnnounce(recentPostsCache: {}, \
|
|||
if '@' not in handle:
|
||||
if debug:
|
||||
print('DEBUG: bad handle '+handle)
|
||||
return False
|
||||
return False
|
||||
if not messageJson.get('actor'):
|
||||
if debug:
|
||||
print('DEBUG: '+messageJson['type']+' has no actor')
|
||||
|
@ -1308,7 +1308,7 @@ def receiveAnnounce(recentPostsCache: {}, \
|
|||
getPersonPubKey(baseDir,session,lookupActor, \
|
||||
personCache,debug, \
|
||||
__version__,httpPrefix, \
|
||||
domain,onionDomain)
|
||||
domain,onionDomain)
|
||||
if pubKey:
|
||||
print('DEBUG: public key obtained for announce: '+lookupActor)
|
||||
break
|
||||
|
@ -1316,7 +1316,7 @@ def receiveAnnounce(recentPostsCache: {}, \
|
|||
if debug:
|
||||
print('DEBUG: Retry '+str(tries+1)+ \
|
||||
' obtaining actor for '+lookupActor)
|
||||
time.sleep(5)
|
||||
time.sleep(5)
|
||||
if debug:
|
||||
print('DEBUG: announced/repeated post arrived in inbox')
|
||||
return True
|
||||
|
@ -1342,7 +1342,7 @@ def receiveUndoAnnounce(recentPostsCache: {}, \
|
|||
if not isinstance(messageJson['object']['object'], str):
|
||||
return False
|
||||
if messageJson['object']['type']!='Announce':
|
||||
return False
|
||||
return False
|
||||
if '/users/' not in messageJson['actor'] and \
|
||||
'/channel/' not in messageJson['actor'] and \
|
||||
'/profile/' not in messageJson['actor']:
|
||||
|
@ -1367,7 +1367,7 @@ def receiveUndoAnnounce(recentPostsCache: {}, \
|
|||
if postJsonObject['type']!='Announce':
|
||||
if debug:
|
||||
print("DEBUG: Attempt to undo something which isn't an announcement")
|
||||
return False
|
||||
return False
|
||||
undoAnnounceCollectionEntry(recentPostsCache,baseDir,postFilename, \
|
||||
messageJson['actor'],domain,debug)
|
||||
if os.path.isfile(postFilename):
|
||||
|
@ -1376,7 +1376,7 @@ def receiveUndoAnnounce(recentPostsCache: {}, \
|
|||
|
||||
def populateReplies(baseDir :str,httpPrefix :str,domain :str, \
|
||||
messageJson :{},maxReplies: int,debug :bool) -> bool:
|
||||
"""Updates the list of replies for a post on this domain if
|
||||
"""Updates the list of replies for a post on this domain if
|
||||
a reply to it arrives
|
||||
"""
|
||||
if not messageJson.get('id'):
|
||||
|
@ -1412,7 +1412,7 @@ def populateReplies(baseDir :str,httpPrefix :str,domain :str, \
|
|||
if not postFilename:
|
||||
if debug:
|
||||
print('DEBUG: post may have expired - '+replyTo)
|
||||
return False
|
||||
return False
|
||||
# populate a text file containing the ids of replies
|
||||
postRepliesFilename=postFilename.replace('.json','.replies')
|
||||
messageId=messageJson['id'].replace('/activity','').replace('/undo','')
|
||||
|
@ -1461,7 +1461,7 @@ def validPostContent(baseDir: str,nickname: str,domain: str, \
|
|||
if 'Z' not in messageJson['object']['published']:
|
||||
return False
|
||||
# check for bad html
|
||||
invalidStrings=['<script>','<canvas>','<style>','</html>','</body>','<br>','<hr>']
|
||||
invalidStrings=['<script>','<canvas>','<style>','</html>','</body>','<br>','<hr>']
|
||||
for badStr in invalidStrings:
|
||||
if badStr in messageJson['object']['content']:
|
||||
if messageJson['object'].get('id'):
|
||||
|
@ -1504,7 +1504,7 @@ def obtainAvatarForReplyPost(session,baseDir: str,httpPrefix: str, \
|
|||
"""
|
||||
if not postJsonObject.get('object'):
|
||||
return
|
||||
|
||||
|
||||
if not isinstance(postJsonObject['object'], dict):
|
||||
return
|
||||
|
||||
|
@ -1522,7 +1522,7 @@ def obtainAvatarForReplyPost(session,baseDir: str,httpPrefix: str, \
|
|||
|
||||
if '/statuses/' in lookupActor:
|
||||
lookupActor=lookupActor.split('/statuses/')[0]
|
||||
|
||||
|
||||
if debug:
|
||||
print('DEBUG: Obtaining actor for reply post '+lookupActor)
|
||||
|
||||
|
@ -1531,7 +1531,7 @@ def obtainAvatarForReplyPost(session,baseDir: str,httpPrefix: str, \
|
|||
getPersonPubKey(baseDir,session,lookupActor, \
|
||||
personCache,debug, \
|
||||
__version__,httpPrefix, \
|
||||
domain,onionDomain)
|
||||
domain,onionDomain)
|
||||
if pubKey:
|
||||
print('DEBUG: public key obtained for reply: '+lookupActor)
|
||||
break
|
||||
|
@ -1539,7 +1539,7 @@ def obtainAvatarForReplyPost(session,baseDir: str,httpPrefix: str, \
|
|||
if debug:
|
||||
print('DEBUG: Retry '+str(tries+1)+ \
|
||||
' obtaining actor for '+lookupActor)
|
||||
time.sleep(5)
|
||||
time.sleep(5)
|
||||
|
||||
def dmNotify(baseDir: str,handle: str,url: str) -> None:
|
||||
"""Creates a notification that a new DM has arrived
|
||||
|
@ -1687,7 +1687,7 @@ def inboxUpdateCalendar(baseDir: str,handle: str,postJsonObject: {}) -> None:
|
|||
if not tagDict.get('startTime'):
|
||||
continue
|
||||
# get the year and month from the event
|
||||
eventTime=datetime.datetime.strptime(tagDict['startTime'],"%Y-%m-%dT%H:%M:%S%z")
|
||||
eventTime=datetime.datetime.strptime(tagDict['startTime'],"%Y-%m-%dT%H:%M:%S%z")
|
||||
eventYear=int(eventTime.strftime("%Y"))
|
||||
eventMonthNumber=int(eventTime.strftime("%m"))
|
||||
eventDayOfMonth=int(eventTime.strftime("%d"))
|
||||
|
@ -1819,7 +1819,7 @@ def inboxAfterCapabilities(recentPostsCache: {},maxRecentPosts: int, \
|
|||
if debug:
|
||||
print('DEBUG: Undo bookmark accepted from '+actor)
|
||||
return False
|
||||
|
||||
|
||||
if receiveAnnounce(recentPostsCache, \
|
||||
session,handle,isGroup, \
|
||||
baseDir,httpPrefix, \
|
||||
|
@ -2004,7 +2004,7 @@ def runInboxQueueWatchdog(projectVersion: str,httpd) -> None:
|
|||
#httpd.thrInboxQueue=inboxQueueOriginal
|
||||
httpd.thrInboxQueue.start()
|
||||
while True:
|
||||
time.sleep(20)
|
||||
time.sleep(20)
|
||||
if not httpd.thrInboxQueue.isAlive():
|
||||
httpd.thrInboxQueue.kill()
|
||||
httpd.thrInboxQueue=inboxQueueOriginal.clone(runInboxQueue)
|
||||
|
@ -2068,7 +2068,7 @@ def runInboxQueue(recentPostsCache: {},maxRecentPosts: int, \
|
|||
if not session or currTime-sessionLastUpdate>1200:
|
||||
print('Creating inbox session')
|
||||
session=createSession(useTor)
|
||||
sessionLastUpdate=currTime
|
||||
sessionLastUpdate=currTime
|
||||
|
||||
# oldest item first
|
||||
queue.sort()
|
||||
|
@ -2081,7 +2081,7 @@ def runInboxQueue(recentPostsCache: {},maxRecentPosts: int, \
|
|||
continue
|
||||
|
||||
print('Loading queue item '+queueFilename)
|
||||
|
||||
|
||||
# Load the queue json
|
||||
queueJson=loadJson(queueFilename,1)
|
||||
if not queueJson:
|
||||
|
@ -2096,14 +2096,14 @@ def runInboxQueue(recentPostsCache: {},maxRecentPosts: int, \
|
|||
except:
|
||||
pass
|
||||
continue
|
||||
|
||||
|
||||
# clear the daily quotas for maximum numbers of received posts
|
||||
if currTime-quotasLastUpdate>60*60*24:
|
||||
quotas={
|
||||
'domains': {},
|
||||
'accounts': {}
|
||||
}
|
||||
quotasLastUpdate=currTime
|
||||
quotasLastUpdate=currTime
|
||||
|
||||
# limit the number of posts which can arrive per domain per day
|
||||
postDomain=queueJson['postDomain']
|
||||
|
@ -2138,7 +2138,7 @@ def runInboxQueue(recentPostsCache: {},maxRecentPosts: int, \
|
|||
pprint(quotas)
|
||||
|
||||
print('Obtaining public key for actor '+queueJson['actor'])
|
||||
|
||||
|
||||
# Try a few times to obtain the public key
|
||||
pubKey=None
|
||||
keyId=None
|
||||
|
@ -2169,7 +2169,7 @@ def runInboxQueue(recentPostsCache: {},maxRecentPosts: int, \
|
|||
if debug:
|
||||
print('DEBUG: public key: '+str(pubKey))
|
||||
break
|
||||
|
||||
|
||||
if debug:
|
||||
print('DEBUG: Retry '+str(tries+1)+ \
|
||||
' obtaining public key for '+keyId)
|
||||
|
@ -2210,7 +2210,7 @@ def runInboxQueue(recentPostsCache: {},maxRecentPosts: int, \
|
|||
# This makes the filename and the id consistent
|
||||
#if queueJson['post'].get('id'):
|
||||
# queueJson['post']['id']=queueJson['id']
|
||||
|
||||
|
||||
if receiveUndo(session, \
|
||||
baseDir,httpPrefix,port, \
|
||||
sendThreads,postLog, \
|
||||
|
@ -2344,7 +2344,7 @@ def runInboxQueue(recentPostsCache: {},maxRecentPosts: int, \
|
|||
saveJson(queueJson['post'],sharedInboxPostFilename)
|
||||
|
||||
# for posts addressed to specific accounts
|
||||
for handle,capsId in recipientsDict.items():
|
||||
for handle,capsId in recipientsDict.items():
|
||||
destination=queueJson['destination'].replace(inboxHandle,handle)
|
||||
# check that capabilities are accepted
|
||||
if queueJson['post'].get('capability'):
|
||||
|
@ -2395,7 +2395,7 @@ def runInboxQueue(recentPostsCache: {},maxRecentPosts: int, \
|
|||
print('No capability list within post')
|
||||
print('ocapAlways: '+str(ocapAlways))
|
||||
print('DEBUG: object capabilities check failed')
|
||||
|
||||
|
||||
if debug:
|
||||
print('DEBUG: Queue post accepted')
|
||||
if os.path.isfile(queueFilename):
|
||||
|
|
26
like.py
26
like.py
|
@ -143,7 +143,7 @@ def updateLikesCollection(recentPostsCache: {}, \
|
|||
'items': [{
|
||||
'type': 'Like',
|
||||
'actor': actor
|
||||
}]
|
||||
}]
|
||||
}
|
||||
postJsonObject['object']['likes']=likesJson
|
||||
else:
|
||||
|
@ -225,11 +225,11 @@ def like(recentPostsCache: {}, \
|
|||
print('DEBUG: like domain: '+domain)
|
||||
print('DEBUG: like objectUrl: '+objectUrl)
|
||||
return None
|
||||
|
||||
|
||||
updateLikesCollection(recentPostsCache, \
|
||||
baseDir,postFilename,objectUrl, \
|
||||
newLikeJson['actor'],domain,debug)
|
||||
|
||||
|
||||
sendSignedJson(newLikeJson,session,baseDir, \
|
||||
nickname,domain,port, \
|
||||
likedPostNickname,likedPostDomain,likedPostPort, \
|
||||
|
@ -338,7 +338,7 @@ def undolike(recentPostsCache: {}, \
|
|||
|
||||
undoLikesCollectionEntry(baseDir,postFilename,objectUrl, \
|
||||
newLikeJson['actor'],domain,debug)
|
||||
|
||||
|
||||
sendSignedJson(newUndoLikeJson,session,baseDir, \
|
||||
nickname,domain,port, \
|
||||
likedPostNickname,likedPostDomain,likedPostPort, \
|
||||
|
@ -379,7 +379,7 @@ def undoLikePost(recentPostsCache: {}, \
|
|||
ccUrl= \
|
||||
httpPrefix+'://'+likeDomain+':'+ \
|
||||
str(likePort)+'/users/'+likeNickname
|
||||
|
||||
|
||||
return undoLike(recentPostsCache, \
|
||||
session,baseDir,federationList,nickname,domain,port, \
|
||||
ccList,httpPrefix,objectUrl,clientToServer, \
|
||||
|
@ -408,7 +408,7 @@ def sendLikeViaServer(baseDir: str,session, \
|
|||
|
||||
if '/statuses/' in likeUrl:
|
||||
toUrl=[likeUrl.split('/statuses/')[0]]
|
||||
|
||||
|
||||
newLikeJson={
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
'type': 'Like',
|
||||
|
@ -433,7 +433,7 @@ def sendLikeViaServer(baseDir: str,session, \
|
|||
getPersonBox(baseDir,session,wfRequest,personCache, \
|
||||
projectVersion,httpPrefix,fromNickname, \
|
||||
fromDomain,postToBox)
|
||||
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
print('DEBUG: No '+postToBox+' was found for '+handle)
|
||||
|
@ -442,9 +442,9 @@ def sendLikeViaServer(baseDir: str,session, \
|
|||
if debug:
|
||||
print('DEBUG: No actor was found for '+handle)
|
||||
return 4
|
||||
|
||||
|
||||
authHeader=createBasicAuthHeader(fromNickname,password)
|
||||
|
||||
|
||||
headers={
|
||||
'host': fromDomain, \
|
||||
'Content-type': 'application/json', \
|
||||
|
@ -515,7 +515,7 @@ def sendUndoLikeViaServer(baseDir: str,session, \
|
|||
getPersonBox(baseDir,session,wfRequest,personCache, \
|
||||
projectVersion,httpPrefix,fromNickname, \
|
||||
fromDomain,postToBox)
|
||||
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
print('DEBUG: No '+postToBox+' was found for '+handle)
|
||||
|
@ -524,9 +524,9 @@ def sendUndoLikeViaServer(baseDir: str,session, \
|
|||
if debug:
|
||||
print('DEBUG: No actor was found for '+handle)
|
||||
return 4
|
||||
|
||||
|
||||
authHeader=createBasicAuthHeader(fromNickname,password)
|
||||
|
||||
|
||||
headers={
|
||||
'host': fromDomain, \
|
||||
'Content-type': 'application/json', \
|
||||
|
@ -598,7 +598,7 @@ def outboxUndoLike(baseDir: str,httpPrefix: str, \
|
|||
if not isinstance(messageJson['object'], dict):
|
||||
if debug:
|
||||
print('DEBUG: undo like object is not dict')
|
||||
return
|
||||
return
|
||||
if not messageJson['object'].get('type'):
|
||||
if debug:
|
||||
print('DEBUG: undo like - no type')
|
||||
|
|
|
@ -33,17 +33,17 @@ def manualDenyFollowRequest(session,baseDir: str, \
|
|||
rejectedFollowsFilename=accountsDir+'/followrejects.txt'
|
||||
if os.path.isfile(rejectedFollowsFilename):
|
||||
if denyHandle in open(rejectedFollowsFilename).read():
|
||||
removeFromFollowRequests(baseDir,nickname,domain,denyHandle,debug)
|
||||
removeFromFollowRequests(baseDir,nickname,domain,denyHandle,debug)
|
||||
print(denyHandle+' has already been rejected as a follower of '+nickname)
|
||||
return
|
||||
|
||||
removeFromFollowRequests(baseDir,nickname,domain,denyHandle,debug)
|
||||
removeFromFollowRequests(baseDir,nickname,domain,denyHandle,debug)
|
||||
|
||||
# Store rejected follows
|
||||
rejectsFile=open(rejectedFollowsFilename, "a+")
|
||||
rejectsFile.write(denyHandle+'\n')
|
||||
rejectsFile.close()
|
||||
|
||||
|
||||
denyNickname=denyHandle.split('@')[0]
|
||||
denyDomain=denyHandle.split('@')[1].replace('\n','')
|
||||
denyPort=port
|
||||
|
@ -59,11 +59,11 @@ def manualDenyFollowRequest(session,baseDir: str, \
|
|||
debug,projectVersion)
|
||||
|
||||
print('Follow request from '+denyHandle+' was denied.')
|
||||
|
||||
|
||||
def approveFollowerHandle(accountDir: str,approveHandle: str) -> None:
|
||||
""" Record manually approved handles so that if they unfollow and then
|
||||
re-follow later then they don't need to be manually approved again
|
||||
"""
|
||||
"""
|
||||
approvedFilename=accountDir+'/approved.txt'
|
||||
if os.path.isfile(approvedFilename):
|
||||
if approveHandle not in open(approvedFilename).read():
|
||||
|
@ -73,8 +73,8 @@ def approveFollowerHandle(accountDir: str,approveHandle: str) -> None:
|
|||
else:
|
||||
approvedFile=open(approvedFilename, "w+")
|
||||
approvedFile.write(approveHandle+'\n')
|
||||
approvedFile.close()
|
||||
|
||||
approvedFile.close()
|
||||
|
||||
def manualApproveFollowRequest(session,baseDir: str, \
|
||||
httpPrefix: str,
|
||||
nickname: str,domain: str,port: int, \
|
||||
|
@ -98,7 +98,7 @@ def manualApproveFollowRequest(session,baseDir: str, \
|
|||
if approveHandle not in open(approveFollowsFilename).read():
|
||||
print('Manual follow accept: '+approveHandle+' not in requests file '+approveFollowsFilename)
|
||||
return
|
||||
|
||||
|
||||
approvefilenew=open(approveFollowsFilename+'.new', 'w+')
|
||||
updateApprovedFollowers=False
|
||||
followActivityfilename=None
|
||||
|
|
12
media.py
12
media.py
|
@ -49,13 +49,13 @@ def getImageHash(imageFilename: str) -> str:
|
|||
|
||||
def isMedia(imageFilename: str) -> bool:
|
||||
permittedMedia=['png','jpg','gif','webp','mp4','ogv','mp3','ogg']
|
||||
for m in permittedMedia:
|
||||
for m in permittedMedia:
|
||||
if imageFilename.endswith('.'+m):
|
||||
return True
|
||||
print('WARN: '+imageFilename+' is not a permitted media type')
|
||||
return False
|
||||
|
||||
def createMediaDirs(baseDir: str,mediaPath: str) -> None:
|
||||
def createMediaDirs(baseDir: str,mediaPath: str) -> None:
|
||||
if not os.path.isdir(baseDir+'/media'):
|
||||
os.mkdir(baseDir+'/media')
|
||||
if not os.path.isdir(baseDir+'/'+mediaPath):
|
||||
|
@ -100,7 +100,7 @@ def updateEtag(mediaFilename: str) -> None:
|
|||
data=None
|
||||
try:
|
||||
with open(mediaFilename, 'rb') as mediaFile:
|
||||
data=mediaFile.read()
|
||||
data=mediaFile.read()
|
||||
except:
|
||||
pass
|
||||
|
||||
|
@ -125,7 +125,7 @@ def attachMedia(baseDir: str,httpPrefix: str,domain: str,port: int, \
|
|||
"""
|
||||
if not isMedia(imageFilename):
|
||||
return postJson
|
||||
|
||||
|
||||
fileExtension=None
|
||||
acceptedTypes=['png','jpg','gif','webp','mp4','webm','ogv','mp3','ogg']
|
||||
for mType in acceptedTypes:
|
||||
|
@ -135,7 +135,7 @@ def attachMedia(baseDir: str,httpPrefix: str,domain: str,port: int, \
|
|||
if mType=='mp3':
|
||||
mType='mpeg'
|
||||
fileExtension=mType
|
||||
if not fileExtension:
|
||||
if not fileExtension:
|
||||
return postJson
|
||||
mediaType=mediaType+'/'+fileExtension
|
||||
print('Attached media type: '+mediaType)
|
||||
|
@ -189,7 +189,7 @@ def archiveMedia(baseDir: str,archiveDirectory: str,maxWeeks=4) -> None:
|
|||
os.mkdir(archiveDirectory)
|
||||
if not os.path.isdir(archiveDirectory+'/media'):
|
||||
os.mkdir(archiveDirectory+'/media')
|
||||
|
||||
|
||||
for subdir, dirs, files in os.walk(baseDir+'/media'):
|
||||
for weekDir in dirs:
|
||||
if int(weekDir)<minWeek:
|
||||
|
|
|
@ -58,7 +58,7 @@ def metaDataInstance(instanceTitle: str, \
|
|||
isBot=False
|
||||
if adminActor['type']!='Person':
|
||||
isBot=True
|
||||
|
||||
|
||||
instance={
|
||||
'approval_required': False,
|
||||
'contact_account': {
|
||||
|
@ -98,5 +98,5 @@ def metaDataInstance(instanceTitle: str, \
|
|||
'urls': {},
|
||||
'version': version
|
||||
}
|
||||
|
||||
|
||||
return instance
|
||||
|
|
|
@ -272,7 +272,7 @@ def postMessageToOutbox(messageJson: {},postToNickname: str, \
|
|||
messageJson,debug)
|
||||
|
||||
if debug:
|
||||
print('DEBUG: handle delete requests')
|
||||
print('DEBUG: handle delete requests')
|
||||
outboxDelete(baseDir,httpPrefix, \
|
||||
postToNickname,domain, \
|
||||
messageJson,debug, \
|
||||
|
|
32
person.py
32
person.py
|
@ -39,7 +39,7 @@ from utils import loadJson
|
|||
from utils import saveJson
|
||||
from auth import createPassword
|
||||
from config import setConfigParam
|
||||
from config import getConfigParam
|
||||
from config import getConfigParam
|
||||
|
||||
def generateRSAKey() -> (str,str):
|
||||
key=RSA.generate(2048)
|
||||
|
@ -85,7 +85,7 @@ def setProfileImage(baseDir: str,httpPrefix :str,nickname: str,domain: str, \
|
|||
iconFilenameBase='icon'
|
||||
else:
|
||||
iconFilenameBase='image'
|
||||
|
||||
|
||||
mediaType='image/png'
|
||||
iconFilename=iconFilenameBase+'.png'
|
||||
if imageFilename.endswith('.jpg') or \
|
||||
|
@ -103,7 +103,7 @@ def setProfileImage(baseDir: str,httpPrefix :str,nickname: str,domain: str, \
|
|||
personJson[iconFilenameBase]['url']= \
|
||||
httpPrefix+'://'+fullDomain+'/users/'+nickname+'/'+iconFilename
|
||||
saveJson(personJson,personFilename)
|
||||
|
||||
|
||||
cmd= \
|
||||
'/usr/bin/convert '+imageFilename+' -size '+ \
|
||||
resolution+' -quality 50 '+profileFilename
|
||||
|
@ -365,20 +365,20 @@ def createPerson(baseDir: str,nickname: str,domain: str,port: int, \
|
|||
os.mkdir(baseDir+'/accounts')
|
||||
if not os.path.isdir(baseDir+'/accounts/'+nickname+'@'+domain):
|
||||
os.mkdir(baseDir+'/accounts/'+nickname+'@'+domain)
|
||||
|
||||
|
||||
if os.path.isfile(baseDir+'/img/default-avatar.png'):
|
||||
copyfile(baseDir+'/img/default-avatar.png',baseDir+'/accounts/'+nickname+'@'+domain+'/avatar.png')
|
||||
theme=getConfigParam(baseDir,'theme')
|
||||
defaultProfileImageFilename=baseDir+'/img/image.png'
|
||||
if theme:
|
||||
if os.path.isfile(baseDir+'/img/image_'+theme+'.png'):
|
||||
defaultBannerFilename=baseDir+'/img/image_'+theme+'.png'
|
||||
defaultBannerFilename=baseDir+'/img/image_'+theme+'.png'
|
||||
if os.path.isfile(defaultProfileImageFilename):
|
||||
copyfile(defaultProfileImageFilename,baseDir+'/accounts/'+nickname+'@'+domain+'/image.png')
|
||||
defaultBannerFilename=baseDir+'/img/banner.png'
|
||||
if theme:
|
||||
if os.path.isfile(baseDir+'/img/banner_'+theme+'.png'):
|
||||
defaultBannerFilename=baseDir+'/img/banner_'+theme+'.png'
|
||||
defaultBannerFilename=baseDir+'/img/banner_'+theme+'.png'
|
||||
if os.path.isfile(defaultBannerFilename):
|
||||
copyfile(defaultBannerFilename,baseDir+'/accounts/'+nickname+'@'+domain+'/banner.png')
|
||||
if remainingConfigExists:
|
||||
|
@ -405,7 +405,7 @@ def personUpgradeActor(baseDir: str,personJson: {},handle: str,filename: str) ->
|
|||
if not os.path.isfile(filename):
|
||||
print('WARN: actor file not found '+filename)
|
||||
return
|
||||
if not personJson:
|
||||
if not personJson:
|
||||
personJson=loadJson(filename)
|
||||
if not personJson.get('nomadicLocations'):
|
||||
personJson['nomadicLocations']=[{
|
||||
|
@ -415,7 +415,7 @@ def personUpgradeActor(baseDir: str,personJson: {},handle: str,filename: str) ->
|
|||
'locationPrimary':True,
|
||||
'locationDeleted':False
|
||||
}]
|
||||
print('Nomadic locations added to to actor '+handle)
|
||||
print('Nomadic locations added to to actor '+handle)
|
||||
updateActor=True
|
||||
|
||||
if updateActor:
|
||||
|
@ -450,7 +450,7 @@ def personLookup(domain: str,path: str,baseDir: str) -> {}:
|
|||
notPersonLookup=['/inbox','/outbox','/outboxarchive', \
|
||||
'/followers','/following','/featured', \
|
||||
'.png','.jpg','.gif','.mpv']
|
||||
for ending in notPersonLookup:
|
||||
for ending in notPersonLookup:
|
||||
if path.endswith(ending):
|
||||
return None
|
||||
nickname=None
|
||||
|
@ -494,7 +494,7 @@ def personBoxJson(recentPostsCache: {}, \
|
|||
headerOnly=True
|
||||
|
||||
# handle page numbers
|
||||
pageNumber=None
|
||||
pageNumber=None
|
||||
if '?page=' in path:
|
||||
pageNumber=path.split('?page=')[1]
|
||||
if pageNumber=='true':
|
||||
|
@ -558,7 +558,7 @@ def personInboxJson(recentPostsCache: {}, \
|
|||
headerOnly=True
|
||||
|
||||
# handle page numbers
|
||||
pageNumber=None
|
||||
pageNumber=None
|
||||
if '?page=' in path:
|
||||
pageNumber=path.split('?page=')[1]
|
||||
if pageNumber=='true':
|
||||
|
@ -594,7 +594,7 @@ def setDisplayNickname(baseDir: str,nickname: str, domain: str, \
|
|||
if not os.path.isfile(filename):
|
||||
return False
|
||||
|
||||
personJson=loadJson(filename)
|
||||
personJson=loadJson(filename)
|
||||
if not personJson:
|
||||
return False
|
||||
personJson['name']=displayName
|
||||
|
@ -616,7 +616,7 @@ def setBio(baseDir: str,nickname: str, domain: str, bio: str) -> bool:
|
|||
return False
|
||||
personJson['summary']=bio
|
||||
|
||||
saveJson(personJson,filename)
|
||||
saveJson(personJson,filename)
|
||||
return True
|
||||
|
||||
def isSuspended(baseDir: str,nickname: str) -> bool:
|
||||
|
@ -672,7 +672,7 @@ def suspendAccount(baseDir: str,nickname: str,domain: str) -> None:
|
|||
tokenFilename=baseDir+'/accounts/'+nickname+'@'+domain+'/.token'
|
||||
if os.path.isfile(tokenFilename):
|
||||
os.remove(tokenFilename)
|
||||
|
||||
|
||||
suspendedFilename=baseDir+'/accounts/suspended.txt'
|
||||
if os.path.isfile(suspendedFilename):
|
||||
with open(suspendedFilename, "r") as f:
|
||||
|
@ -746,11 +746,11 @@ def removeTagsForNickname(baseDir: str,nickname: str,domain: str,port: int) -> N
|
|||
for tagline in lines:
|
||||
if matchStr not in tagline:
|
||||
tagFile.write(tagline)
|
||||
tagFile.close()
|
||||
tagFile.close()
|
||||
|
||||
def removeAccount(baseDir: str,nickname: str,domain: str,port: int) -> bool:
|
||||
"""Removes an account
|
||||
"""
|
||||
"""
|
||||
# Don't remove the admin
|
||||
adminNickname=getConfigParam(baseDir,'admin')
|
||||
if nickname==adminNickname:
|
||||
|
|
122
posts.py
122
posts.py
|
@ -52,7 +52,7 @@ from auth import createBasicAuthHeader
|
|||
from config import getConfigParam
|
||||
from blocking import isBlocked
|
||||
from filters import isFiltered
|
||||
#try:
|
||||
#try:
|
||||
# from BeautifulSoup import BeautifulSoup
|
||||
#except ImportError:
|
||||
# from bs4 import BeautifulSoup
|
||||
|
@ -114,7 +114,7 @@ def getPersonKey(nickname: str,domain: str,baseDir: str,keyType='public', \
|
|||
print('DEBUG: private key was too short: '+keyPem)
|
||||
return ''
|
||||
return keyPem
|
||||
|
||||
|
||||
def cleanHtml(rawHtml: str) -> str:
|
||||
#text=BeautifulSoup(rawHtml, 'html.parser').get_text()
|
||||
text=rawHtml
|
||||
|
@ -159,8 +159,8 @@ def parseUserFeed(session,feedUrl: str,asHeader: {}, \
|
|||
userFeed=nextUrl
|
||||
if userFeed.get('orderedItems'):
|
||||
for item in userFeed['orderedItems']:
|
||||
yield item
|
||||
|
||||
yield item
|
||||
|
||||
def getPersonBox(baseDir: str,session,wfRequest: {},personCache: {}, \
|
||||
projectVersion: str,httpPrefix: str, \
|
||||
nickname: str,domain: str, \
|
||||
|
@ -251,7 +251,7 @@ def getPosts(session,outboxUrl: str,maxPosts: int, \
|
|||
projectVersion: str,httpPrefix: str,domain: str) -> {}:
|
||||
"""Gets public posts from an outbox
|
||||
"""
|
||||
personPosts={}
|
||||
personPosts={}
|
||||
if not outboxUrl:
|
||||
return personPosts
|
||||
asHeader={
|
||||
|
@ -315,7 +315,7 @@ def getPosts(session,outboxUrl: str,maxPosts: int, \
|
|||
break
|
||||
if not isPublic:
|
||||
continue
|
||||
|
||||
|
||||
content=item['object']['content'].replace(''',"'")
|
||||
|
||||
mentions=[]
|
||||
|
@ -371,7 +371,7 @@ def getPosts(session,outboxUrl: str,maxPosts: int, \
|
|||
if item['object']['conversation']:
|
||||
# no conversations originated in non-permitted domains
|
||||
if urlPermitted(item['object']['conversation'], \
|
||||
federationList,"objects:read"):
|
||||
federationList,"objects:read"):
|
||||
conversation=item['object']['conversation']
|
||||
|
||||
attachment=[]
|
||||
|
@ -438,7 +438,7 @@ def savePostToBox(baseDir: str,httpPrefix: str,postId: str, \
|
|||
if boxname!='inbox' and boxname!='outbox' and \
|
||||
boxname!='tlblogs' and boxname!='scheduled':
|
||||
return None
|
||||
originalDomain=domain
|
||||
originalDomain=domain
|
||||
if ':' in domain:
|
||||
domain=domain.split(':')[0]
|
||||
|
||||
|
@ -452,7 +452,7 @@ def savePostToBox(baseDir: str,httpPrefix: str,postId: str, \
|
|||
if isinstance(postJsonObject['object'], dict):
|
||||
postJsonObject['object']['id']=postId
|
||||
postJsonObject['object']['atomUri']=postId
|
||||
|
||||
|
||||
boxDir=createPersonDir(nickname,domain,baseDir,boxname)
|
||||
filename=boxDir+'/'+postId.replace('/','#')+'.json'
|
||||
saveJson(postJsonObject,filename)
|
||||
|
@ -465,7 +465,7 @@ def updateHashtagsIndex(baseDir: str,tag: {},newPostId: str) -> None:
|
|||
if tag['type']!='Hashtag':
|
||||
return
|
||||
|
||||
# create hashtags directory
|
||||
# create hashtags directory
|
||||
tagsDir=baseDir+'/tags'
|
||||
if not os.path.isdir(tagsDir):
|
||||
os.mkdir(tagsDir)
|
||||
|
@ -514,7 +514,7 @@ def addSchedulePost(baseDir: str,nickname: str,domain: str, \
|
|||
scheduleFile=open(scheduleIndexFilename,'w')
|
||||
if scheduleFile:
|
||||
scheduleFile.write(indexStr+'\n')
|
||||
scheduleFile.close()
|
||||
scheduleFile.close()
|
||||
|
||||
def createPostBase(baseDir: str,nickname: str,domain: str,port: int, \
|
||||
toUrl: str,ccUrl: str,httpPrefix: str,content: str, \
|
||||
|
@ -583,7 +583,7 @@ def createPostBase(baseDir: str,nickname: str,domain: str,port: int, \
|
|||
if not isinstance(toUrl, str):
|
||||
print('ERROR: toUrl is not a string')
|
||||
return None
|
||||
toRecipients=[toUrl]
|
||||
toRecipients=[toUrl]
|
||||
|
||||
# who to send to
|
||||
if mentionedRecipients:
|
||||
|
@ -656,7 +656,7 @@ def createPostBase(baseDir: str,nickname: str,domain: str,port: int, \
|
|||
'votersCount': 'toot:votersCount'
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
if not clientToServer:
|
||||
actorUrl=httpPrefix+'://'+domain+'/users/'+nickname
|
||||
|
||||
|
@ -714,7 +714,7 @@ def createPostBase(baseDir: str,nickname: str,domain: str,port: int, \
|
|||
newPost['object']= \
|
||||
attachMedia(baseDir,httpPrefix,domain,port, \
|
||||
newPost['object'],attachImageFilename, \
|
||||
mediaType,imageDescription,useBlurhash)
|
||||
mediaType,imageDescription,useBlurhash)
|
||||
else:
|
||||
newPost={
|
||||
"@context": postContext,
|
||||
|
@ -750,7 +750,7 @@ def createPostBase(baseDir: str,nickname: str,domain: str,port: int, \
|
|||
newPost= \
|
||||
attachMedia(baseDir,httpPrefix,domain,port, \
|
||||
newPost,attachImageFilename, \
|
||||
mediaType,imageDescription,useBlurhash)
|
||||
mediaType,imageDescription,useBlurhash)
|
||||
if ccUrl:
|
||||
if len(ccUrl)>0:
|
||||
newPost['cc']=[ccUrl]
|
||||
|
@ -772,7 +772,7 @@ def createPostBase(baseDir: str,nickname: str,domain: str,port: int, \
|
|||
modFile.close()
|
||||
|
||||
if schedulePost:
|
||||
if eventDate and eventTime:
|
||||
if eventDate and eventTime:
|
||||
# add an item to the scheduled post index file
|
||||
addSchedulePost(baseDir,nickname,domain,eventDateStr,newPostId)
|
||||
savePostToBox(baseDir,httpPrefix,newPostId, \
|
||||
|
@ -853,7 +853,7 @@ def postIsAddressedToFollowers(baseDir: str,
|
|||
toList=postJsonObject['to']
|
||||
if postJsonObject.get('cc'):
|
||||
ccList=postJsonObject['cc']
|
||||
|
||||
|
||||
followersUrl=httpPrefix+'://'+domain+'/users/'+nickname+'/followers'
|
||||
|
||||
# does the followers url exist in 'to' or 'cc' lists?
|
||||
|
@ -871,7 +871,7 @@ def postIsAddressedToPublic(baseDir: str,postJsonObject: {}) -> bool:
|
|||
return False
|
||||
if not postJsonObject['object'].get('to'):
|
||||
return False
|
||||
|
||||
|
||||
publicUrl='https://www.w3.org/ns/activitystreams#Public'
|
||||
|
||||
# does the public url exist in 'to' or 'cc' lists?
|
||||
|
@ -932,7 +932,7 @@ def createBlogPost(baseDir: str, \
|
|||
eventDate,eventTime,location)
|
||||
blog['object']['type']='Article'
|
||||
return blog
|
||||
|
||||
|
||||
|
||||
def createQuestionPost(baseDir: str,
|
||||
nickname: str,domain: str,port: int,httpPrefix: str, \
|
||||
|
@ -1017,7 +1017,7 @@ def createFollowersOnlyPost(baseDir: str,
|
|||
"""
|
||||
domainFull=domain
|
||||
if port:
|
||||
if port!=80 and port!=443:
|
||||
if port!=80 and port!=443:
|
||||
if ':' not in domain:
|
||||
domainFull=domain+':'+str(port)
|
||||
return createPostBase(baseDir,nickname,domain,port, \
|
||||
|
@ -1167,7 +1167,7 @@ def createReportPost(baseDir: str,
|
|||
postTo=moderatorsList
|
||||
postCc=None
|
||||
postJsonObject=None
|
||||
for toUrl in postTo:
|
||||
for toUrl in postTo:
|
||||
# who is this report going to?
|
||||
toNickname=toUrl.split('/users/')[1]
|
||||
handle=toNickname+'@'+domain
|
||||
|
@ -1187,7 +1187,7 @@ def createReportPost(baseDir: str,
|
|||
# update the inbox index with the report filename
|
||||
#indexFilename=baseDir+'/accounts/'+handle+'/inbox.index'
|
||||
#indexEntry=postJsonObject['id'].replace('/activity','').replace('/','#')+'.json'
|
||||
#if indexEntry not in open(indexFilename).read():
|
||||
#if indexEntry not in open(indexFilename).read():
|
||||
# try:
|
||||
# with open(indexFilename, 'a+') as fp:
|
||||
# fp.write(indexEntry)
|
||||
|
@ -1255,7 +1255,7 @@ def threadSendPost(session,postJsonStr: str,federationList: [],\
|
|||
str(sendIntervalSec)+' seconds.')
|
||||
time.sleep(sendIntervalSec)
|
||||
tries+=1
|
||||
|
||||
|
||||
def sendPost(projectVersion: str, \
|
||||
session,baseDir: str,nickname: str, domain: str, port: int, \
|
||||
toNickname: str, toDomain: str, toPort: int, cc: str, \
|
||||
|
@ -1279,7 +1279,7 @@ def sendPost(projectVersion: str, \
|
|||
if toPort:
|
||||
if toPort!=80 and toPort!=443:
|
||||
if ':' not in toDomain:
|
||||
toDomain=toDomain+':'+str(toPort)
|
||||
toDomain=toDomain+':'+str(toPort)
|
||||
|
||||
handle=httpPrefix+'://'+toDomain+'/@'+toNickname
|
||||
|
||||
|
@ -1308,7 +1308,7 @@ def sendPost(projectVersion: str, \
|
|||
inboxUrl=capabilityAcquisition
|
||||
if not capabilityAcquisition:
|
||||
return 2
|
||||
|
||||
|
||||
if not inboxUrl:
|
||||
return 3
|
||||
if not pubKey:
|
||||
|
@ -1316,7 +1316,7 @@ def sendPost(projectVersion: str, \
|
|||
if not toPersonId:
|
||||
return 5
|
||||
# sharedInbox and capabilities are optional
|
||||
|
||||
|
||||
postJsonObject= \
|
||||
createPostBase(baseDir,nickname,domain,port, \
|
||||
toPersonId,cc,httpPrefix,content, \
|
||||
|
@ -1407,7 +1407,7 @@ def sendPostViaServer(projectVersion: str, \
|
|||
getPersonBox(baseDir,session,wfRequest,personCache, \
|
||||
projectVersion,httpPrefix,fromNickname, \
|
||||
fromDomain,postToBox)
|
||||
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
print('DEBUG: No '+postToBox+' was found for '+handle)
|
||||
|
@ -1427,7 +1427,7 @@ def sendPostViaServer(projectVersion: str, \
|
|||
if fromPort:
|
||||
if fromPort!=80 and fromPort!=443:
|
||||
if ':' not in fromDomain:
|
||||
fromDomainFull=fromDomain+':'+str(fromPort)
|
||||
fromDomainFull=fromDomain+':'+str(fromPort)
|
||||
cc=httpPrefix+'://'+fromDomainFull+'/users/'+fromNickname+'/followers'
|
||||
else:
|
||||
if toDomain.lower().endswith('followers') or \
|
||||
|
@ -1440,7 +1440,7 @@ def sendPostViaServer(projectVersion: str, \
|
|||
if toPort:
|
||||
if toPort!=80 and toPort!=443:
|
||||
if ':' not in toDomain:
|
||||
toDomainFull=toDomain+':'+str(toPort)
|
||||
toDomainFull=toDomain+':'+str(toPort)
|
||||
toPersonId=httpPrefix+'://'+toDomainFull+'/users/'+toNickname
|
||||
|
||||
postJsonObject= \
|
||||
|
@ -1452,7 +1452,7 @@ def sendPostViaServer(projectVersion: str, \
|
|||
imageDescription,useBlurhash, \
|
||||
False,isArticle,inReplyTo,inReplyToAtomUri,subject, \
|
||||
False,None,None,None)
|
||||
|
||||
|
||||
authHeader=createBasicAuthHeader(fromNickname,password)
|
||||
|
||||
if attachImageFilename:
|
||||
|
@ -1467,7 +1467,7 @@ def sendPostViaServer(projectVersion: str, \
|
|||
# if debug:
|
||||
# print('DEBUG: Failed to upload image')
|
||||
# return 9
|
||||
|
||||
|
||||
headers={
|
||||
'host': fromDomain, \
|
||||
'Content-type': 'application/json', \
|
||||
|
@ -1553,7 +1553,7 @@ def sendSignedJson(postJsonObject: {},session,baseDir: str, \
|
|||
|
||||
if toDomain.endswith('.onion'):
|
||||
httpPrefix='http'
|
||||
|
||||
|
||||
sharedInbox=False
|
||||
if toNickname=='inbox':
|
||||
# shared inbox actor on @domain@domain
|
||||
|
@ -1564,7 +1564,7 @@ def sendSignedJson(postJsonObject: {},session,baseDir: str, \
|
|||
if toPort:
|
||||
if toPort!=80 and toPort!=443:
|
||||
if ':' not in toDomain:
|
||||
toDomain=toDomain+':'+str(toPort)
|
||||
toDomain=toDomain+':'+str(toPort)
|
||||
|
||||
handleBase=httpPrefix+'://'+toDomain+'/@'
|
||||
if toNickname:
|
||||
|
@ -1572,7 +1572,7 @@ def sendSignedJson(postJsonObject: {},session,baseDir: str, \
|
|||
else:
|
||||
singleUserInstanceNickname='dev'
|
||||
handle=handleBase+singleUserInstanceNickname
|
||||
|
||||
|
||||
if debug:
|
||||
print('DEBUG: handle - '+handle+' toPort '+str(toPort))
|
||||
|
||||
|
@ -1587,7 +1587,7 @@ def sendSignedJson(postJsonObject: {},session,baseDir: str, \
|
|||
if wfRequest.get('errors'):
|
||||
if debug:
|
||||
print('DEBUG: webfinger for '+handle+' failed with errors '+str(wfRequest['errors']))
|
||||
|
||||
|
||||
if not clientToServer:
|
||||
postToBox='inbox'
|
||||
else:
|
||||
|
@ -1617,7 +1617,7 @@ def sendSignedJson(postJsonObject: {},session,baseDir: str, \
|
|||
|
||||
if debug:
|
||||
print('DEBUG: Sending to endpoint '+inboxUrl)
|
||||
|
||||
|
||||
if not pubKey:
|
||||
if debug:
|
||||
print('DEBUG: missing pubkey')
|
||||
|
@ -1643,7 +1643,7 @@ def sendSignedJson(postJsonObject: {},session,baseDir: str, \
|
|||
postPath=inboxUrl.split(toDomain,1)[1]
|
||||
|
||||
addFollowersToPublicPost(postJsonObject)
|
||||
|
||||
|
||||
# convert json to string so that there are no
|
||||
# subsequent conversions after creating message body digest
|
||||
postJsonStr=json.dumps(postJsonObject)
|
||||
|
@ -1653,7 +1653,7 @@ def sendSignedJson(postJsonObject: {},session,baseDir: str, \
|
|||
createSignedHeader(privateKeyPem,nickname,domain,port, \
|
||||
toDomain,toPort, \
|
||||
postPath,httpPrefix,withDigest,postJsonStr)
|
||||
|
||||
|
||||
# Keep the number of threads being used small
|
||||
while len(sendThreads)>1000:
|
||||
print('WARN: Maximum threads reached - killing send thread')
|
||||
|
@ -1684,7 +1684,7 @@ def addToField(activityType: str,postJsonObject: {},debug: bool) -> ({},bool):
|
|||
"""
|
||||
if postJsonObject.get('to'):
|
||||
return postJsonObject,True
|
||||
|
||||
|
||||
if debug:
|
||||
pprint(postJsonObject)
|
||||
print('DEBUG: no "to" field when sending to named addresses 2')
|
||||
|
@ -1751,13 +1751,13 @@ def sendToNamedAddresses(session,baseDir: str, \
|
|||
# use the original object, which has a 'to'
|
||||
recipientsObject=postJsonObject
|
||||
isProfileUpdate=True
|
||||
|
||||
|
||||
if not isProfileUpdate:
|
||||
if not postJsonObject['object'].get('to'):
|
||||
if debug:
|
||||
pprint(postJsonObject)
|
||||
print('DEBUG: no "to" field when sending to named addresses')
|
||||
if postJsonObject['object'].get('type'):
|
||||
if postJsonObject['object'].get('type'):
|
||||
if postJsonObject['object']['type']=='Follow':
|
||||
if isinstance(postJsonObject['object']['object'], str):
|
||||
if debug:
|
||||
|
@ -1767,7 +1767,7 @@ def sendToNamedAddresses(session,baseDir: str, \
|
|||
if not postJsonObject['object'].get('to'):
|
||||
return
|
||||
recipientsObject=postJsonObject['object']
|
||||
else:
|
||||
else:
|
||||
postJsonObject,fieldAdded=addToField('Follow',postJsonObject,debug)
|
||||
if not fieldAdded:
|
||||
return
|
||||
|
@ -1881,7 +1881,7 @@ def sendToFollowers(session,baseDir: str, \
|
|||
print('Post is not addressed to followers')
|
||||
return
|
||||
print('Post is addressed to followers')
|
||||
|
||||
|
||||
grouped=groupFollowersByDomain(baseDir,nickname,domain)
|
||||
if not grouped:
|
||||
if debug:
|
||||
|
@ -1960,7 +1960,7 @@ def sendToFollowers(session,baseDir: str, \
|
|||
if debug:
|
||||
print('DEBUG: Sending to '+handle)
|
||||
toNickname=handle.split('@')[0]
|
||||
|
||||
|
||||
if debug:
|
||||
if postJsonObject['type']!='Update':
|
||||
print('DEBUG: Sending from '+ \
|
||||
|
@ -2133,7 +2133,7 @@ def isDM(postJsonObject: {}) -> bool:
|
|||
if postJsonObject['object'].get('moderationStatus'):
|
||||
return False
|
||||
fields=['to','cc']
|
||||
for f in fields:
|
||||
for f in fields:
|
||||
if not postJsonObject['object'].get(f):
|
||||
continue
|
||||
for toAddress in postJsonObject['object'][f]:
|
||||
|
@ -2192,7 +2192,7 @@ def isReply(postJsonObject: {},actor: str) -> bool:
|
|||
return False
|
||||
if postJsonObject['object'].get('inReplyTo'):
|
||||
if postJsonObject['object']['inReplyTo'].startswith(actor):
|
||||
return True
|
||||
return True
|
||||
if not postJsonObject['object'].get('tag'):
|
||||
return False
|
||||
if not isinstance(postJsonObject['object']['tag'], list):
|
||||
|
@ -2233,14 +2233,14 @@ def createSharedInboxIndex(baseDir: str,sharedBoxDir: str, \
|
|||
followingFilename=baseDir+'/accounts/'+handle+'/following.txt'
|
||||
postsInSharedInbox=os.scandir(sharedBoxDir)
|
||||
followingHandles=None
|
||||
for postFilename in postsInSharedInbox:
|
||||
for postFilename in postsInSharedInbox:
|
||||
postFilename=postFilename.name
|
||||
if not postFilename.endswith('.json'):
|
||||
continue
|
||||
statusNumber=getStatusNumberFromPostFilename(postFilename)
|
||||
if not statusNumber:
|
||||
continue
|
||||
|
||||
|
||||
sharedInboxFilename=os.path.join(sharedBoxDir, postFilename)
|
||||
# get the actor from the shared post
|
||||
postJsonObject=loadJson(sharedInboxFilename,0)
|
||||
|
@ -2266,7 +2266,7 @@ def createSharedInboxIndex(baseDir: str,sharedBoxDir: str, \
|
|||
capsList=None
|
||||
# Note: should this be in the Create or the object of a post?
|
||||
if postJsonObject.get('capability'):
|
||||
if isinstance(postJsonObject['capability'], list):
|
||||
if isinstance(postJsonObject['capability'], list):
|
||||
capsList=postJsonObject['capability']
|
||||
|
||||
# Have capabilities been granted for the sender?
|
||||
|
@ -2282,7 +2282,7 @@ def createSharedInboxIndex(baseDir: str,sharedBoxDir: str, \
|
|||
print('WARN: json load exception createSharedInboxIndex')
|
||||
else:
|
||||
if ocapJson.get('id'):
|
||||
if ocapJson['id'] in capsList:
|
||||
if ocapJson['id'] in capsList:
|
||||
postsInBoxDict[statusNumber]=sharedInboxFilename
|
||||
postsCtr+=1
|
||||
else:
|
||||
|
@ -2418,7 +2418,7 @@ def createBoxIndexed(recentPostsCache: {}, \
|
|||
continue
|
||||
|
||||
# Skip through any posts previous to the current page
|
||||
if postsCtr<int((pageNumber-1)*itemsPerPage):
|
||||
if postsCtr<int((pageNumber-1)*itemsPerPage):
|
||||
postsCtr+=1
|
||||
continue
|
||||
|
||||
|
@ -2485,7 +2485,7 @@ def createBoxIndexed(recentPostsCache: {}, \
|
|||
# Don't show likes, replies or shares (announces) to unauthorized viewers
|
||||
if not authorized:
|
||||
if p.get('object'):
|
||||
if isinstance(p['object'], dict):
|
||||
if isinstance(p['object'], dict):
|
||||
if p['object'].get('likes'):
|
||||
p['likes']={'items': []}
|
||||
if p['object'].get('replies'):
|
||||
|
@ -2528,9 +2528,9 @@ def archivePosts(baseDir: str,httpPrefix: str,archiveDir: str, \
|
|||
archiveSubdir=None
|
||||
if archiveDir:
|
||||
if not os.path.isdir(archiveDir+'/accounts/'+handle):
|
||||
os.mkdir(archiveDir+'/accounts/'+handle)
|
||||
os.mkdir(archiveDir+'/accounts/'+handle)
|
||||
if not os.path.isdir(archiveDir+'/accounts/'+handle+'/inbox'):
|
||||
os.mkdir(archiveDir+'/accounts/'+handle+'/inbox')
|
||||
os.mkdir(archiveDir+'/accounts/'+handle+'/inbox')
|
||||
if not os.path.isdir(archiveDir+'/accounts/'+handle+'/outbox'):
|
||||
os.mkdir(archiveDir+'/accounts/'+handle+'/outbox')
|
||||
archiveSubdir=archiveDir+'/accounts/'+handle+'/inbox'
|
||||
|
@ -2552,7 +2552,7 @@ def archivePostsForPerson(httpPrefix: str,nickname: str,domain: str,baseDir: str
|
|||
return
|
||||
if archiveDir:
|
||||
if not os.path.isdir(archiveDir):
|
||||
os.mkdir(archiveDir)
|
||||
os.mkdir(archiveDir)
|
||||
boxDir=createPersonDir(nickname,domain,baseDir,boxname)
|
||||
postsInBox=os.scandir(boxDir)
|
||||
noOfPosts=0
|
||||
|
@ -2615,7 +2615,7 @@ def archivePostsForPerson(httpPrefix: str,nickname: str,domain: str,baseDir: str
|
|||
|
||||
removeCtr=0
|
||||
for publishedStr,postFilename in postsInBoxSorted.items():
|
||||
filePath=os.path.join(boxDir,postFilename)
|
||||
filePath=os.path.join(boxDir,postFilename)
|
||||
if not os.path.isfile(filePath):
|
||||
continue
|
||||
if archiveDir:
|
||||
|
@ -2724,7 +2724,7 @@ def populateRepliesJson(baseDir: str,nickname: str,domain: str, \
|
|||
repliesJson: {}) -> None:
|
||||
# populate the items list with replies
|
||||
repliesBoxes=['outbox','inbox']
|
||||
with open(postRepliesFilename,'r') as repliesFile:
|
||||
with open(postRepliesFilename,'r') as repliesFile:
|
||||
for messageId in repliesFile:
|
||||
replyFound=False
|
||||
# examine inbox and outbox
|
||||
|
@ -2740,7 +2740,7 @@ def populateRepliesJson(baseDir: str,nickname: str,domain: str, \
|
|||
'https://www.w3.org/ns/activitystreams#Public' in open(searchFilename).read():
|
||||
postJsonObject=loadJson(searchFilename)
|
||||
if postJsonObject:
|
||||
if postJsonObject['object'].get('cc'):
|
||||
if postJsonObject['object'].get('cc'):
|
||||
if authorized or \
|
||||
('https://www.w3.org/ns/activitystreams#Public' in postJsonObject['object']['to'] or \
|
||||
'https://www.w3.org/ns/activitystreams#Public' in postJsonObject['object']['cc']):
|
||||
|
@ -2765,7 +2765,7 @@ def populateRepliesJson(baseDir: str,nickname: str,domain: str, \
|
|||
# get the json of the reply and append it to the collection
|
||||
postJsonObject=loadJson(searchFilename)
|
||||
if postJsonObject:
|
||||
if postJsonObject['object'].get('cc'):
|
||||
if postJsonObject['object'].get('cc'):
|
||||
if authorized or \
|
||||
('https://www.w3.org/ns/activitystreams#Public' in postJsonObject['object']['to'] or \
|
||||
'https://www.w3.org/ns/activitystreams#Public' in postJsonObject['object']['cc']):
|
||||
|
@ -2844,7 +2844,7 @@ def downloadAnnounce(session,baseDir: str,httpPrefix: str, \
|
|||
if not isinstance(announcedJson, dict):
|
||||
print('WARN: announce json is not a dict - '+postJsonObject['object'])
|
||||
rejectAnnounce(announceFilename)
|
||||
return None
|
||||
return None
|
||||
if not announcedJson.get('id'):
|
||||
rejectAnnounce(announceFilename)
|
||||
return None
|
||||
|
@ -2867,7 +2867,7 @@ def downloadAnnounce(session,baseDir: str,httpPrefix: str, \
|
|||
return None
|
||||
if not announcedJson.get('content'):
|
||||
rejectAnnounce(announceFilename)
|
||||
return None
|
||||
return None
|
||||
if isFiltered(baseDir,nickname,domain,announcedJson['content']):
|
||||
rejectAnnounce(announceFilename)
|
||||
return None
|
||||
|
|
|
@ -104,7 +104,7 @@ def questionUpdateVotes(baseDir: str,nickname: str,domain: str,replyJson: {}) ->
|
|||
lines=votersFile.readlines()
|
||||
for voteLine in lines:
|
||||
if voteLine.endswith(votersFileSeparator+possibleAnswer['name']+'\n'):
|
||||
totalItems+=1
|
||||
totalItems+=1
|
||||
if possibleAnswer['replies']['totalItems']!=totalItems:
|
||||
possibleAnswer['replies']['totalItems']=totalItems
|
||||
questionTotalsChanged=True
|
||||
|
|
20
roles.py
20
roles.py
|
@ -27,7 +27,7 @@ def clearModeratorStatus(baseDir: str) -> None:
|
|||
for f in os.scandir(directory):
|
||||
f=f.name
|
||||
filename=os.fsdecode(f)
|
||||
if filename.endswith(".json") and '@' in filename:
|
||||
if filename.endswith(".json") and '@' in filename:
|
||||
filename=os.path.join(baseDir+'/accounts/', filename)
|
||||
if '"moderator"' in open(filename).read():
|
||||
actorJson=loadJson(filename)
|
||||
|
@ -62,7 +62,7 @@ def addModerator(baseDir: str,nickname: str,domain: str) -> None:
|
|||
with open(moderatorsFile, "w+") as f:
|
||||
if os.path.isdir(baseDir+'/accounts/'+nickname+'@'+domain):
|
||||
f.write(nickname+'\n')
|
||||
|
||||
|
||||
def removeModerator(baseDir: str,nickname: str):
|
||||
"""Removes a moderator nickname from the file
|
||||
"""
|
||||
|
@ -90,7 +90,7 @@ def setRole(baseDir: str,nickname: str,domain: str, \
|
|||
return False
|
||||
|
||||
actorJson=loadJson(actorFilename)
|
||||
if actorJson:
|
||||
if actorJson:
|
||||
if role:
|
||||
# add the role
|
||||
if project=='instance' and 'role'=='moderator':
|
||||
|
@ -196,13 +196,13 @@ def outboxDelegate(baseDir: str,authenticatedNickname: str,messageJson: {},debug
|
|||
if not role:
|
||||
setRole(baseDir,nickname,domain,project,None)
|
||||
return True
|
||||
|
||||
|
||||
# what roles is this person already assigned to?
|
||||
existingRoles=getRoles(baseDir,nickname,domain,project)
|
||||
if existingRoles:
|
||||
if role in existingRoles:
|
||||
if debug:
|
||||
print(nickname+'@'+domain+' is already assigned to the role '+role+' within the project '+project)
|
||||
print(nickname+'@'+domain+' is already assigned to the role '+role+' within the project '+project)
|
||||
return False
|
||||
setRole(baseDir,nickname,domain,project,role)
|
||||
if debug:
|
||||
|
@ -228,7 +228,7 @@ def sendRoleViaServer(baseDir: str,session, \
|
|||
if fromPort!=80 and fromPort!=443:
|
||||
if ':' not in delegatorDomain:
|
||||
delegatorDomainFull=delegatorDomain+':'+str(fromPort)
|
||||
|
||||
|
||||
toUrl= \
|
||||
httpPrefix+'://'+delegatorDomainFull+'/users/'+nickname
|
||||
ccUrl= \
|
||||
|
@ -247,7 +247,7 @@ def sendRoleViaServer(baseDir: str,session, \
|
|||
'actor': httpPrefix+'://'+delegatorDomainFull+'/users/'+nickname,
|
||||
'object': roleStr,
|
||||
'to': [toUrl],
|
||||
'cc': [ccUrl]
|
||||
'cc': [ccUrl]
|
||||
},
|
||||
'to': [toUrl],
|
||||
'cc': [ccUrl]
|
||||
|
@ -270,7 +270,7 @@ def sendRoleViaServer(baseDir: str,session, \
|
|||
getPersonBox(baseDir,session,wfRequest,personCache, \
|
||||
projectVersion,httpPrefix, \
|
||||
delegatorNickname,delegatorDomain,postToBox)
|
||||
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
print('DEBUG: No '+postToBox+' was found for '+handle)
|
||||
|
@ -279,9 +279,9 @@ def sendRoleViaServer(baseDir: str,session, \
|
|||
if debug:
|
||||
print('DEBUG: No actor was found for '+handle)
|
||||
return 4
|
||||
|
||||
|
||||
authHeader=createBasicAuthHeader(delegatorNickname,password)
|
||||
|
||||
|
||||
headers={
|
||||
'host': delegatorDomain, \
|
||||
'Content-type': 'application/json', \
|
||||
|
|
|
@ -147,7 +147,7 @@ def runPostScheduleWatchdog(projectVersion: str,httpd) -> None:
|
|||
httpd.thrPostSchedule.clone(runPostSchedule)
|
||||
httpd.thrPostSchedule.start()
|
||||
while True:
|
||||
time.sleep(20)
|
||||
time.sleep(20)
|
||||
if not httpd.thrPostSchedule.isAlive():
|
||||
httpd.thrPostSchedule.kill()
|
||||
httpd.thrPostSchedule= \
|
||||
|
|
|
@ -59,7 +59,7 @@ def postJson(session,postJsonObject: {},federationList: [], \
|
|||
"""
|
||||
|
||||
# always allow capability requests
|
||||
if not capability.startswith('cap'):
|
||||
if not capability.startswith('cap'):
|
||||
# check that we are posting to a permitted domain
|
||||
if not urlPermitted(inboxUrl,federationList,capability):
|
||||
print('postJson: '+inboxUrl+' not permitted')
|
||||
|
@ -88,7 +88,7 @@ def postJsonString(session,postJsonStr: str, \
|
|||
"""
|
||||
|
||||
# always allow capability requests
|
||||
if not capability.startswith('cap'):
|
||||
if not capability.startswith('cap'):
|
||||
# check that we are posting to a permitted domain
|
||||
if not urlPermitted(inboxUrl,federationList,capability):
|
||||
print('postJson: '+inboxUrl+' not permitted by capabilities')
|
||||
|
@ -118,7 +118,7 @@ def postImage(session,attachImageFilename: str,federationList: [], \
|
|||
Supplying a capability, such as "inbox:write"
|
||||
"""
|
||||
# always allow capability requests
|
||||
if not capability.startswith('cap'):
|
||||
if not capability.startswith('cap'):
|
||||
# check that we are posting to a permitted domain
|
||||
if not urlPermitted(inboxUrl,federationList,capability):
|
||||
print('postJson: '+inboxUrl+' not permitted')
|
||||
|
|
20
shares.py
20
shares.py
|
@ -187,7 +187,7 @@ def expireSharesForAccount(baseDir: str,nickname: str,domain: str) -> None:
|
|||
if ':' in handleDomain:
|
||||
handleDomain=domain.split(':')[0]
|
||||
handle=nickname+'@'+handleDomain
|
||||
sharesFilename=baseDir+'/accounts/'+handle+'/shares.json'
|
||||
sharesFilename=baseDir+'/accounts/'+handle+'/shares.json'
|
||||
if os.path.isfile(sharesFilename):
|
||||
sharesJson=loadJson(sharesFilename)
|
||||
if sharesJson:
|
||||
|
@ -219,7 +219,7 @@ def getSharesFeedForPerson(baseDir: str, \
|
|||
return None
|
||||
# handle page numbers
|
||||
headerOnly=True
|
||||
pageNumber=None
|
||||
pageNumber=None
|
||||
if '?page=' in path:
|
||||
pageNumber=path.split('?page=')[1]
|
||||
if pageNumber=='true':
|
||||
|
@ -231,7 +231,7 @@ def getSharesFeedForPerson(baseDir: str, \
|
|||
pass
|
||||
path=path.split('?page=')[0]
|
||||
headerOnly=False
|
||||
|
||||
|
||||
if not path.endswith('/shares'):
|
||||
return None
|
||||
nickname=None
|
||||
|
@ -253,7 +253,7 @@ def getSharesFeedForPerson(baseDir: str, \
|
|||
if ':' in handleDomain:
|
||||
handleDomain=domain.split(':')[0]
|
||||
handle=nickname+'@'+handleDomain
|
||||
sharesFilename=baseDir+'/accounts/'+handle+'/shares.json'
|
||||
sharesFilename=baseDir+'/accounts/'+handle+'/shares.json'
|
||||
|
||||
if headerOnly:
|
||||
noOfShares=0
|
||||
|
@ -374,7 +374,7 @@ def sendShareViaServer(baseDir,session, \
|
|||
getPersonBox(baseDir,session,wfRequest,personCache, \
|
||||
projectVersion,httpPrefix, \
|
||||
fromNickname,fromDomain,postToBox)
|
||||
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
print('DEBUG: No '+postToBox+' was found for '+handle)
|
||||
|
@ -383,7 +383,7 @@ def sendShareViaServer(baseDir,session, \
|
|||
if debug:
|
||||
print('DEBUG: No actor was found for '+handle)
|
||||
return 4
|
||||
|
||||
|
||||
authHeader=createBasicAuthHeader(fromNickname,password)
|
||||
|
||||
if imageFilename:
|
||||
|
@ -393,7 +393,7 @@ def sendShareViaServer(baseDir,session, \
|
|||
}
|
||||
postResult= \
|
||||
postImage(session,imageFilename,[],inboxUrl.replace('/'+postToBox,'/shares'),headers,"inbox:write")
|
||||
|
||||
|
||||
headers={
|
||||
'host': fromDomain, \
|
||||
'Content-type': 'application/json', \
|
||||
|
@ -465,7 +465,7 @@ def sendUndoShareViaServer(baseDir: str,session, \
|
|||
getPersonBox(baseDir,session,wfRequest,personCache, \
|
||||
projectVersion,httpPrefix, \
|
||||
fromNickname,fromDomain,postToBox)
|
||||
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
print('DEBUG: No '+postToBox+' was found for '+handle)
|
||||
|
@ -474,9 +474,9 @@ def sendUndoShareViaServer(baseDir: str,session, \
|
|||
if debug:
|
||||
print('DEBUG: No actor was found for '+handle)
|
||||
return 4
|
||||
|
||||
|
||||
authHeader=createBasicAuthHeader(fromNickname,password)
|
||||
|
||||
|
||||
headers={
|
||||
'host': fromDomain, \
|
||||
'Content-type': 'application/json', \
|
||||
|
|
|
@ -108,7 +108,7 @@ def sendSkillViaServer(baseDir: str,session,nickname: str,password: str,
|
|||
if port!=80 and port!=443:
|
||||
if ':' not in domain:
|
||||
domainFull=domain+':'+str(port)
|
||||
|
||||
|
||||
toUrl=httpPrefix+'://'+domainFull+'/users/'+nickname
|
||||
ccUrl=httpPrefix+'://'+domainFull+'/users/'+nickname+'/followers'
|
||||
|
||||
|
@ -140,7 +140,7 @@ def sendSkillViaServer(baseDir: str,session,nickname: str,password: str,
|
|||
inboxUrl,pubKeyId,pubKey,fromPersonId,sharedInbox,capabilityAcquisition,avatarUrl,displayName= \
|
||||
getPersonBox(baseDir,session,wfRequest,personCache, \
|
||||
projectVersion,httpPrefix,nickname,domain,postToBox)
|
||||
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
print('DEBUG: No '+postToBox+' was found for '+handle)
|
||||
|
@ -149,9 +149,9 @@ def sendSkillViaServer(baseDir: str,session,nickname: str,password: str,
|
|||
if debug:
|
||||
print('DEBUG: No actor was found for '+handle)
|
||||
return 4
|
||||
|
||||
|
||||
authHeader=createBasicAuthHeader(Nickname,password)
|
||||
|
||||
|
||||
headers={
|
||||
'host': domain, \
|
||||
'Content-type': 'application/json', \
|
||||
|
|
62
tests.py
62
tests.py
|
@ -383,7 +383,7 @@ def testPostMessageBetweenServers():
|
|||
os.mkdir(baseDir+'/.tests')
|
||||
|
||||
ocapAlways=False
|
||||
|
||||
|
||||
# create the servers
|
||||
aliceDir=baseDir+'/.tests/alice'
|
||||
aliceDomain='127.0.0.50'
|
||||
|
@ -432,7 +432,7 @@ def testPostMessageBetweenServers():
|
|||
# wait for both servers to be running
|
||||
while not (testServerAliceRunning and testServerBobRunning):
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
print('\n\n*******************************************************')
|
||||
|
@ -483,7 +483,7 @@ def testPostMessageBetweenServers():
|
|||
time.sleep(1)
|
||||
|
||||
# Image attachment created
|
||||
assert len([name for name in os.listdir(mediaPath) if os.path.isfile(os.path.join(mediaPath, name))])>0
|
||||
assert len([name for name in os.listdir(mediaPath) if os.path.isfile(os.path.join(mediaPath, name))])>0
|
||||
# inbox item created
|
||||
assert len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])==1
|
||||
# queue item removed
|
||||
|
@ -539,7 +539,7 @@ def testPostMessageBetweenServers():
|
|||
alicePostJson=loadJson(outboxPostFilename,0)
|
||||
if alicePostJson:
|
||||
pprint(alicePostJson)
|
||||
|
||||
|
||||
assert 'likes' in open(outboxPostFilename).read()
|
||||
|
||||
print('\n\n*******************************************************')
|
||||
|
@ -714,7 +714,7 @@ def testFollowBetweenServers():
|
|||
|
||||
queuePath=bobDir+'/accounts/bob@'+bobDomain+'/queue'
|
||||
inboxPath=bobDir+'/accounts/bob@'+bobDomain+'/inbox'
|
||||
aliceMessageArrived=False
|
||||
aliceMessageArrived=False
|
||||
for i in range(20):
|
||||
time.sleep(1)
|
||||
if os.path.isdir(inboxPath):
|
||||
|
@ -734,14 +734,14 @@ def testFollowBetweenServers():
|
|||
thrBob.kill()
|
||||
thrBob.join()
|
||||
assert thrBob.isAlive()==False
|
||||
|
||||
|
||||
assert 'alice@'+aliceDomain in open(bobDir+'/accounts/bob@'+bobDomain+'/followers.txt').read()
|
||||
assert 'bob@'+bobDomain in open(aliceDir+'/accounts/alice@'+aliceDomain+'/following.txt').read()
|
||||
|
||||
# queue item removed
|
||||
time.sleep(4)
|
||||
assert len([name for name in os.listdir(queuePath) if os.path.isfile(os.path.join(queuePath, name))])==0
|
||||
|
||||
|
||||
os.chdir(baseDir)
|
||||
shutil.rmtree(baseDir+'/.tests')
|
||||
|
||||
|
@ -758,7 +758,7 @@ def testFollowersOfPerson():
|
|||
if os.path.isdir(baseDir):
|
||||
shutil.rmtree(baseDir)
|
||||
os.mkdir(baseDir)
|
||||
os.chdir(baseDir)
|
||||
os.chdir(baseDir)
|
||||
createPerson(baseDir,nickname,domain,port,httpPrefix,True,password)
|
||||
createPerson(baseDir,'maxboardroom',domain,port,httpPrefix,True,password)
|
||||
createPerson(baseDir,'ultrapancake',domain,port,httpPrefix,True,password)
|
||||
|
@ -796,7 +796,7 @@ def testNoOfFollowersOnDomain():
|
|||
if os.path.isdir(baseDir):
|
||||
shutil.rmtree(baseDir)
|
||||
os.mkdir(baseDir)
|
||||
os.chdir(baseDir)
|
||||
os.chdir(baseDir)
|
||||
createPerson(baseDir,nickname,domain,port,httpPrefix,True,password)
|
||||
createPerson(baseDir,'maxboardroom',otherdomain,port,httpPrefix,True,password)
|
||||
createPerson(baseDir,'ultrapancake',otherdomain,port,httpPrefix,True,password)
|
||||
|
@ -806,7 +806,7 @@ def testNoOfFollowersOnDomain():
|
|||
followPerson(baseDir,'drokk',otherdomain,nickname,domain,federationList,False)
|
||||
followPerson(baseDir,'sausagedog',otherdomain,nickname,domain,federationList,False)
|
||||
followPerson(baseDir,'maxboardroom',otherdomain,nickname,domain,federationList,False)
|
||||
|
||||
|
||||
followerOfPerson(baseDir,nickname,domain,'cucumber','sandwiches.party',federationList,False)
|
||||
followerOfPerson(baseDir,nickname,domain,'captainsensible','damned.zone',federationList,False)
|
||||
followerOfPerson(baseDir,nickname,domain,'pilchard','zombies.attack',federationList,False)
|
||||
|
@ -820,7 +820,7 @@ def testNoOfFollowersOnDomain():
|
|||
unfollowerOfPerson(baseDir,nickname,domain,'sausagedog',otherdomain)
|
||||
followersOnOtherDomain=noOfFollowersOnDomain(baseDir,nickname+'@'+domain, otherdomain)
|
||||
assert followersOnOtherDomain==2
|
||||
|
||||
|
||||
os.chdir(currDir)
|
||||
shutil.rmtree(baseDir)
|
||||
|
||||
|
@ -838,7 +838,7 @@ def testGroupFollowers():
|
|||
if os.path.isdir(baseDir):
|
||||
shutil.rmtree(baseDir)
|
||||
os.mkdir(baseDir)
|
||||
os.chdir(baseDir)
|
||||
os.chdir(baseDir)
|
||||
createPerson(baseDir,nickname,domain,port,httpPrefix,True,password)
|
||||
|
||||
clearFollowers(baseDir,nickname,domain)
|
||||
|
@ -857,11 +857,11 @@ def testGroupFollowers():
|
|||
assert len(grouped['zzz.domain'])==2
|
||||
assert len(grouped['wild.domain'])==3
|
||||
assert len(grouped['clutterly.domain'])==1
|
||||
|
||||
|
||||
os.chdir(currDir)
|
||||
shutil.rmtree(baseDir)
|
||||
|
||||
|
||||
|
||||
def testFollows():
|
||||
print('testFollows')
|
||||
currDir=os.getcwd()
|
||||
|
@ -875,7 +875,7 @@ def testFollows():
|
|||
if os.path.isdir(baseDir):
|
||||
shutil.rmtree(baseDir)
|
||||
os.mkdir(baseDir)
|
||||
os.chdir(baseDir)
|
||||
os.chdir(baseDir)
|
||||
createPerson(baseDir,nickname,domain,port,httpPrefix,True,password)
|
||||
|
||||
clearFollows(baseDir,nickname,domain)
|
||||
|
@ -937,7 +937,7 @@ def testCreatePerson():
|
|||
shutil.rmtree(baseDir)
|
||||
os.mkdir(baseDir)
|
||||
os.chdir(baseDir)
|
||||
|
||||
|
||||
privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(baseDir,nickname,domain,port,httpPrefix,True,password)
|
||||
assert os.path.isfile(baseDir+'/accounts/passwords')
|
||||
deleteAllPosts(baseDir,nickname,domain,'inbox')
|
||||
|
@ -967,7 +967,7 @@ def testDelegateRoles():
|
|||
shutil.rmtree(baseDir)
|
||||
os.mkdir(baseDir)
|
||||
os.chdir(baseDir)
|
||||
|
||||
|
||||
privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(baseDir,nickname,domain,port,httpPrefix,True,password)
|
||||
privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(baseDir,nicknameDelegated,domain,port,httpPrefix,True,'insecure')
|
||||
|
||||
|
@ -982,7 +982,7 @@ def testDelegateRoles():
|
|||
'actor': httpPrefix+'://'+domain+'/users/'+nicknameDelegated,
|
||||
'object': project+';'+role,
|
||||
'to': [],
|
||||
'cc': []
|
||||
'cc': []
|
||||
},
|
||||
'to': [],
|
||||
'cc': []
|
||||
|
@ -994,7 +994,7 @@ def testDelegateRoles():
|
|||
|
||||
assert '"delegator"' in open(baseDir+'/accounts/'+nickname+'@'+domain+'.json').read()
|
||||
assert '"delegator"' in open(baseDir+'/accounts/'+nicknameDelegated+'@'+domain+'.json').read()
|
||||
|
||||
|
||||
newRoleJson={
|
||||
'type': 'Delegate',
|
||||
'actor': httpPrefix+'://'+domain+'/users/'+nicknameDelegated,
|
||||
|
@ -1003,7 +1003,7 @@ def testDelegateRoles():
|
|||
'actor': httpPrefix+'://'+domain+'/users/'+nickname,
|
||||
'object': 'otherproject;otherrole',
|
||||
'to': [],
|
||||
'cc': []
|
||||
'cc': []
|
||||
},
|
||||
'to': [],
|
||||
'cc': []
|
||||
|
@ -1094,7 +1094,7 @@ def testClientToServer():
|
|||
args=(aliceDir,aliceDomain,alicePort,bobAddress, \
|
||||
federationList,False,False, \
|
||||
ocapAlways,aliceSendThreads),daemon=True)
|
||||
|
||||
|
||||
global thrBob
|
||||
if thrBob:
|
||||
while thrBob.isAlive():
|
||||
|
@ -1124,7 +1124,7 @@ def testClientToServer():
|
|||
print('Bob online: '+str(testServerBobRunning))
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
print('\n\n*******************************************************')
|
||||
print('Alice sends to Bob via c2s')
|
||||
|
||||
|
@ -1162,7 +1162,7 @@ def testClientToServer():
|
|||
|
||||
assert len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])==1
|
||||
print(">>> c2s post arrived in Alice's outbox")
|
||||
|
||||
|
||||
for i in range(30):
|
||||
if os.path.isdir(inboxPath):
|
||||
if len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])==1:
|
||||
|
@ -1196,7 +1196,7 @@ def testClientToServer():
|
|||
'bob',bobDomain,bobPort, \
|
||||
httpPrefix, \
|
||||
cachedWebfingers,personCache, \
|
||||
True,__version__)
|
||||
True,__version__)
|
||||
aliceFollowingFilename=aliceDir+'/accounts/alice@'+aliceDomain+'/following.txt'
|
||||
bobFollowersFilename=bobDir+'/accounts/bob@'+bobDomain+'/followers.txt'
|
||||
for t in range(10):
|
||||
|
@ -1254,7 +1254,7 @@ def testClientToServer():
|
|||
cachedWebfingers,personCache, \
|
||||
True,__version__)
|
||||
for i in range(20):
|
||||
if os.path.isdir(outboxPath) and os.path.isdir(inboxPath):
|
||||
if os.path.isdir(outboxPath) and os.path.isdir(inboxPath):
|
||||
if len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])==2:
|
||||
if len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])==1:
|
||||
break
|
||||
|
@ -1262,7 +1262,7 @@ def testClientToServer():
|
|||
assert len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])==2
|
||||
assert len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])==1
|
||||
print('Post liked')
|
||||
|
||||
|
||||
print('\n\nBob repeats the post')
|
||||
print(str(len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])))
|
||||
assert len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])==2
|
||||
|
@ -1274,7 +1274,7 @@ def testClientToServer():
|
|||
cachedWebfingers, \
|
||||
personCache,True,__version__)
|
||||
for i in range(20):
|
||||
if os.path.isdir(outboxPath) and os.path.isdir(inboxPath):
|
||||
if os.path.isdir(outboxPath) and os.path.isdir(inboxPath):
|
||||
if len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])==3:
|
||||
if len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])==2:
|
||||
break
|
||||
|
@ -1306,7 +1306,7 @@ def testClientToServer():
|
|||
assert validInbox(bobDir,'bob',bobDomain)
|
||||
assert validInboxFilenames(bobDir,'bob',bobDomain,aliceDomain,alicePort)
|
||||
|
||||
|
||||
|
||||
print('\n\nAlice unfollows Bob')
|
||||
password='alicepass'
|
||||
sendUnfollowRequestViaServer(baseDir,sessionAlice, \
|
||||
|
@ -1411,12 +1411,12 @@ def testAddEmoji():
|
|||
path=baseDir+'/.tests/emoji'
|
||||
if os.path.isdir(path):
|
||||
shutil.rmtree(path)
|
||||
os.mkdir(path)
|
||||
os.mkdir(path)
|
||||
baseDir=path
|
||||
path=baseDir+'/emoji'
|
||||
if os.path.isdir(path):
|
||||
shutil.rmtree(path)
|
||||
os.mkdir(path)
|
||||
os.mkdir(path)
|
||||
copytree(baseDirOriginal+'/emoji',baseDir+'/emoji')
|
||||
os.chdir(baseDir)
|
||||
privateKeyPem,publicKeyPem,person,wfEndpoint= \
|
||||
|
@ -1528,4 +1528,4 @@ def runAllTests():
|
|||
testFollows()
|
||||
testGroupFollowers()
|
||||
testDelegateRoles()
|
||||
print('Tests succeeded\n')
|
||||
print('Tests succeeded\n')
|
||||
|
|
7
theme.py
7
theme.py
|
@ -18,7 +18,7 @@ def setThemeInConfig(baseDir: str,name: str) -> bool:
|
|||
if not configJson:
|
||||
return False
|
||||
configJson['theme']=name
|
||||
return saveJson(configJson,configFilename)
|
||||
return saveJson(configJson,configFilename)
|
||||
|
||||
def removeTheme(baseDir: str):
|
||||
themeFiles=('epicyon.css','login.css','follow.css','suspended.css','calendar.css','blog.css')
|
||||
|
@ -60,7 +60,7 @@ def setCSSparam(css: str,param: str,value: str) -> str:
|
|||
else:
|
||||
newcss+=searchStr+' '+sectionStr
|
||||
return newcss.strip()
|
||||
|
||||
|
||||
def setThemeFromDict(baseDir: str,name: str,themeParams: {}):
|
||||
"""Uses a dictionary to set a theme
|
||||
"""
|
||||
|
@ -197,7 +197,7 @@ def setThemeLight(baseDir: str):
|
|||
"gallery-text-color": "black"
|
||||
}
|
||||
setThemeFromDict(baseDir,'light',themeParams)
|
||||
|
||||
|
||||
def setTheme(baseDir: str,name: str) -> bool:
|
||||
if name=='default':
|
||||
setThemeDefault(baseDir)
|
||||
|
@ -215,4 +215,3 @@ def setTheme(baseDir: str,name: str) -> bool:
|
|||
setThemeHighVis(baseDir)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
|
34
threads.py
34
threads.py
|
@ -21,20 +21,20 @@ class threadWithTrace(threading.Thread):
|
|||
while tries<3:
|
||||
try:
|
||||
self._args,self._keywords=args,keywords
|
||||
threading.Thread.__init__(self,*self._args,**self._keywords)
|
||||
threading.Thread.__init__(self,*self._args,**self._keywords)
|
||||
self.killed=False
|
||||
break
|
||||
except Exception as e:
|
||||
print('ERROR: threads.py/__init__ failed - '+str(e))
|
||||
time.sleep(1)
|
||||
tries+=1
|
||||
|
||||
def start(self):
|
||||
|
||||
def start(self):
|
||||
tries=0
|
||||
while tries<3:
|
||||
try:
|
||||
self.__run_backup=self.run
|
||||
self.run=self.__run
|
||||
self.__run_backup=self.run
|
||||
self.run=self.__run
|
||||
threading.Thread.start(self)
|
||||
break
|
||||
except Exception as e:
|
||||
|
@ -49,25 +49,25 @@ class threadWithTrace(threading.Thread):
|
|||
self.__run_backup()
|
||||
self.run=self.__run_backup
|
||||
|
||||
def globaltrace(self, frame, event, arg):
|
||||
if event == 'call':
|
||||
def globaltrace(self, frame, event, arg):
|
||||
if event == 'call':
|
||||
return self.localtrace
|
||||
else:
|
||||
return None
|
||||
|
||||
def localtrace(self, frame, event, arg):
|
||||
if self.killed:
|
||||
if event == 'line':
|
||||
raise SystemExit()
|
||||
return self.localtrace
|
||||
|
||||
def kill(self):
|
||||
def localtrace(self, frame, event, arg):
|
||||
if self.killed:
|
||||
if event == 'line':
|
||||
raise SystemExit()
|
||||
return self.localtrace
|
||||
|
||||
def kill(self):
|
||||
self.killed=True
|
||||
|
||||
def clone(self,fn):
|
||||
return threadWithTrace(target=fn, \
|
||||
args=self._args, \
|
||||
daemon=True)
|
||||
daemon=True)
|
||||
|
||||
def removeDormantThreads(baseDir: str,threadsList: [],debug: bool) -> None:
|
||||
"""Removes threads whose execution has completed
|
||||
|
@ -82,7 +82,7 @@ def removeDormantThreads(baseDir: str,threadsList: [],debug: bool) -> None:
|
|||
# which threads are dormant?
|
||||
noOfActiveThreads=0
|
||||
for th in threadsList:
|
||||
removeThread=False
|
||||
removeThread=False
|
||||
|
||||
if th.isStarted:
|
||||
if not th.is_alive():
|
||||
|
@ -114,7 +114,7 @@ def removeDormantThreads(baseDir: str,threadsList: [],debug: bool) -> None:
|
|||
for th in dormantThreads:
|
||||
if debug:
|
||||
print('DEBUG: Removing dormant thread '+str(dormantCtr))
|
||||
dormantCtr+=1
|
||||
dormantCtr+=1
|
||||
threadsList.remove(th)
|
||||
th.kill()
|
||||
changed=True
|
||||
|
|
12
utils.py
12
utils.py
|
@ -220,7 +220,7 @@ def getDomainFromActor(actor: str) -> (str,int):
|
|||
port=int(portStr)
|
||||
domain=domain.split(':')[0]
|
||||
return domain,port
|
||||
|
||||
|
||||
def followPerson(baseDir: str,nickname: str, domain: str, \
|
||||
followNickname: str, followDomain: str, \
|
||||
federationList: [],debug: bool, \
|
||||
|
@ -282,7 +282,7 @@ def followPerson(baseDir: str,nickname: str, domain: str, \
|
|||
print('DEBUG: follow added')
|
||||
return True
|
||||
except Exception as e:
|
||||
print('WARN: Failed to write entry to follow file '+filename+' '+str(e))
|
||||
print('WARN: Failed to write entry to follow file '+filename+' '+str(e))
|
||||
if debug:
|
||||
print('DEBUG: creating new following file to follow '+handleToFollow)
|
||||
with open(filename, "w") as followfile:
|
||||
|
@ -385,9 +385,9 @@ def deletePost(baseDir: str,httpPrefix: str,nickname: str,domain: str,postFilena
|
|||
getCachedPostFilename(baseDir,nickname,domain,postJsonObject)
|
||||
if cachedPostFilename:
|
||||
if os.path.isfile(cachedPostFilename):
|
||||
os.remove(cachedPostFilename)
|
||||
os.remove(cachedPostFilename)
|
||||
#removePostFromCache(postJsonObject,recentPostsCache)
|
||||
|
||||
|
||||
hasObject=False
|
||||
if postJsonObject.get('object'):
|
||||
hasObject=True
|
||||
|
@ -451,7 +451,7 @@ def deletePost(baseDir: str,httpPrefix: str,nickname: str,domain: str,postFilena
|
|||
# remove the replies file
|
||||
os.remove(repliesFilename)
|
||||
# finally, remove the post itself
|
||||
os.remove(postFilename)
|
||||
os.remove(postFilename)
|
||||
|
||||
def validNickname(domain: str,nickname: str) -> bool:
|
||||
forbiddenChars=['.',' ','/','?',':',';','@']
|
||||
|
@ -646,4 +646,4 @@ def isBlogPost(postJsonObject: {}) -> bool:
|
|||
return False
|
||||
if postJsonObject['object']['type']!='Article':
|
||||
return False
|
||||
return True
|
||||
return True
|
||||
|
|
|
@ -60,7 +60,7 @@ def webfingerHandle(session,handle: str,httpPrefix: str,cachedWebfingers: {}, \
|
|||
wfDomain=wfDomain.split(':')[0]
|
||||
wf=getWebfingerFromCache(nickname+'@'+wfDomain,cachedWebfingers)
|
||||
if wf:
|
||||
return wf
|
||||
return wf
|
||||
url='{}://{}/.well-known/webfinger'.format(httpPrefix,domain)
|
||||
par={
|
||||
'resource': 'acct:{}'.format(nickname+'@'+wfDomain)
|
||||
|
@ -85,7 +85,7 @@ def generateMagicKey(publicKeyPem) -> str:
|
|||
"""See magic_key method in
|
||||
https://github.com/tootsuite/mastodon/blob/707ddf7808f90e3ab042d7642d368c2ce8e95e6f/app/models/account.rb
|
||||
"""
|
||||
privkey=RSA.importKey(publicKeyPem)
|
||||
privkey=RSA.importKey(publicKeyPem)
|
||||
mod=base64.urlsafe_b64encode(number.long_to_bytes(privkey.n)).decode("utf-8")
|
||||
pubexp=base64.urlsafe_b64encode(number.long_to_bytes(privkey.e)).decode("utf-8")
|
||||
return f"data:application/magic-public-key,RSA.{mod}.{pubexp}"
|
||||
|
@ -130,7 +130,7 @@ def createWebfingerEndpoint(nickname: str,domain: str,port: int, \
|
|||
personId=httpPrefix+"://"+domain+"/"+personName
|
||||
subjectStr="acct:"+originalDomain+"@"+originalDomain
|
||||
profilePageHref=httpPrefix+'://'+domain+'/about/more?instance_actor=true'
|
||||
|
||||
|
||||
account={
|
||||
"aliases": [
|
||||
httpPrefix+"://"+domain+"/@"+personName,
|
||||
|
@ -195,7 +195,7 @@ def webfingerLookup(path: str,baseDir: str, \
|
|||
port: int,debug: bool) -> {}:
|
||||
"""Lookup the webfinger endpoint for an account
|
||||
"""
|
||||
if not path.startswith('/.well-known/webfinger?'):
|
||||
if not path.startswith('/.well-known/webfinger?'):
|
||||
return None
|
||||
handle=None
|
||||
if 'resource=acct:' in path:
|
||||
|
|
195
webinterface.py
195
webinterface.py
|
@ -118,7 +118,7 @@ def updateAvatarImageCache(session,baseDir: str,httpPrefix: str, \
|
|||
f.write(result.content)
|
||||
print('avatar image downloaded for '+actor)
|
||||
return avatarImageFilename.replace(baseDir+'/cache','')
|
||||
except Exception as e:
|
||||
except Exception as e:
|
||||
print('Failed to download avatar image: '+str(avatarUrl))
|
||||
print(e)
|
||||
if '/channel/' not in actor:
|
||||
|
@ -155,7 +155,7 @@ def updateAvatarImageCache(session,baseDir: str,httpPrefix: str, \
|
|||
def getPersonAvatarUrl(baseDir: str,personUrl: str,personCache: {}) -> str:
|
||||
"""Returns the avatar url for the person
|
||||
"""
|
||||
personJson=getPersonFromCache(baseDir,personUrl,personCache)
|
||||
personJson=getPersonFromCache(baseDir,personUrl,personCache)
|
||||
if not personJson:
|
||||
return None
|
||||
# get from locally stored image
|
||||
|
@ -171,7 +171,7 @@ def getPersonAvatarUrl(baseDir: str,personUrl: str,personCache: {}) -> str:
|
|||
return '/avatars/'+actorStr+'.webp'
|
||||
if os.path.isfile(avatarImagePath):
|
||||
return '/avatars/'+actorStr
|
||||
|
||||
|
||||
if personJson.get('icon'):
|
||||
if personJson['icon'].get('url'):
|
||||
return personJson['icon']['url']
|
||||
|
@ -183,14 +183,14 @@ def htmlSearchEmoji(translate: {},baseDir: str,httpPrefix: str, \
|
|||
"""
|
||||
|
||||
# emoji.json is generated so that it can be customized and the changes
|
||||
# will be retained even if default_emoji.json is subsequently updated
|
||||
# will be retained even if default_emoji.json is subsequently updated
|
||||
if not os.path.isfile(baseDir+'/emoji/emoji.json'):
|
||||
copyfile(baseDir+'/emoji/default_emoji.json',baseDir+'/emoji/emoji.json')
|
||||
|
||||
searchStr=searchStr.lower().replace(':','').strip('\n')
|
||||
cssFilename=baseDir+'/epicyon-profile.css'
|
||||
if os.path.isfile(baseDir+'/epicyon.css'):
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
emojiCSS=cssFile.read()
|
||||
if httpPrefix!='https':
|
||||
|
@ -285,7 +285,7 @@ def htmlSearchSharedItems(translate: {}, \
|
|||
sharesJson=loadJson(sharesFilename)
|
||||
if not sharesJson:
|
||||
continue
|
||||
|
||||
|
||||
for name,sharedItem in sharesJson.items():
|
||||
matched=True
|
||||
for searchSubstr in searchStrLowerList:
|
||||
|
@ -370,13 +370,13 @@ def htmlSearchSharedItems(translate: {}, \
|
|||
if not resultsExist:
|
||||
sharedItemsForm+='<center><h5>'+translate['No results']+'</h5></center>'
|
||||
sharedItemsForm+=htmlFooter()
|
||||
return sharedItemsForm
|
||||
return sharedItemsForm
|
||||
|
||||
def htmlModerationInfo(translate: {},baseDir: str,httpPrefix: str) -> str:
|
||||
infoForm=''
|
||||
cssFilename=baseDir+'/epicyon-profile.css'
|
||||
if os.path.isfile(baseDir+'/epicyon.css'):
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
infoCSS=cssFile.read()
|
||||
if httpPrefix!='https':
|
||||
|
@ -386,7 +386,7 @@ def htmlModerationInfo(translate: {},baseDir: str,httpPrefix: str) -> str:
|
|||
infoForm+= \
|
||||
'<center><h1>'+translate['Moderation Information']+'</h1></center>'
|
||||
|
||||
infoShown=False
|
||||
infoShown=False
|
||||
suspendedFilename=baseDir+'/accounts/suspended.txt'
|
||||
if os.path.isfile(suspendedFilename):
|
||||
with open(suspendedFilename, "r") as f:
|
||||
|
@ -412,7 +412,7 @@ def htmlModerationInfo(translate: {},baseDir: str,httpPrefix: str) -> str:
|
|||
infoForm+= \
|
||||
' <textarea id="message" name="blocked" style="height:400px">'+ \
|
||||
blockedStr+'</textarea>'
|
||||
infoForm+='</div>'
|
||||
infoForm+='</div>'
|
||||
infoShown=True
|
||||
if not infoShown:
|
||||
infoForm+= \
|
||||
|
@ -420,7 +420,7 @@ def htmlModerationInfo(translate: {},baseDir: str,httpPrefix: str) -> str:
|
|||
translate['Any blocks or suspensions made by moderators will be shown here.']+ \
|
||||
'</p></center>'
|
||||
infoForm+=htmlFooter()
|
||||
return infoForm
|
||||
return infoForm
|
||||
|
||||
def htmlHashtagSearch(nickname: str,domain: str,port: int, \
|
||||
recentPostsCache: {},maxRecentPosts: int, \
|
||||
|
@ -450,7 +450,7 @@ def htmlHashtagSearch(nickname: str,domain: str,port: int, \
|
|||
# read the css
|
||||
cssFilename=baseDir+'/epicyon-profile.css'
|
||||
if os.path.isfile(baseDir+'/epicyon.css'):
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
hashtagSearchCSS=cssFile.read()
|
||||
if httpPrefix!='https':
|
||||
|
@ -467,7 +467,7 @@ def htmlHashtagSearch(nickname: str,domain: str,port: int, \
|
|||
startIndex=int((pageNumber-1)*postsPerPage)
|
||||
endIndex=startIndex+postsPerPage
|
||||
noOfLines=len(lines)
|
||||
if endIndex>=noOfLines and noOfLines>0:
|
||||
if endIndex>=noOfLines and noOfLines>0:
|
||||
endIndex=noOfLines-1
|
||||
|
||||
# add the page title
|
||||
|
@ -506,7 +506,7 @@ def htmlHashtagSearch(nickname: str,domain: str,port: int, \
|
|||
if postJsonObject:
|
||||
if not isPublicPost(postJsonObject):
|
||||
index+=1
|
||||
continue
|
||||
continue
|
||||
showIndividualPostIcons=False
|
||||
if nickname:
|
||||
showIndividualPostIcons=True
|
||||
|
@ -606,7 +606,7 @@ def htmlSkillsSearch(translate: {},baseDir: str, \
|
|||
if skillLevel<100:
|
||||
skillLevelStr='0'+skillLevelStr
|
||||
if skillLevel<10:
|
||||
skillLevelStr='0'+skillLevelStr
|
||||
skillLevelStr='0'+skillLevelStr
|
||||
indexStr= \
|
||||
skillLevelStr+';'+actor+';'+actorJson['name']+ \
|
||||
';'+actorJson['icon']['url']
|
||||
|
@ -617,7 +617,7 @@ def htmlSkillsSearch(translate: {},baseDir: str, \
|
|||
|
||||
cssFilename=baseDir+'/epicyon-profile.css'
|
||||
if os.path.isfile(baseDir+'/epicyon.css'):
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
skillSearchCSS=cssFile.read()
|
||||
if httpPrefix!='https':
|
||||
|
@ -733,7 +733,7 @@ def htmlEditProfile(translate: {},baseDir: str,path: str, \
|
|||
if mediaInstance:
|
||||
if mediaInstance==True:
|
||||
mediaInstanceStr='checked'
|
||||
|
||||
|
||||
filterStr=''
|
||||
filterFilename=baseDir+'/accounts/'+nickname+'@'+domain+'/filters.txt'
|
||||
if os.path.isfile(filterFilename):
|
||||
|
@ -783,7 +783,7 @@ def htmlEditProfile(translate: {},baseDir: str,path: str, \
|
|||
|
||||
cssFilename=baseDir+'/epicyon-profile.css'
|
||||
if os.path.isfile(baseDir+'/epicyon.css'):
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
editProfileCSS=cssFile.read()
|
||||
if httpPrefix!='https':
|
||||
|
@ -818,7 +818,7 @@ def htmlEditProfile(translate: {},baseDir: str,path: str, \
|
|||
' <input type="file" id="instanceLogo" name="instanceLogo"'
|
||||
instanceStr+=' accept="'+imageFormats+'">'
|
||||
instanceStr+='</div>'
|
||||
|
||||
|
||||
moderators=''
|
||||
moderatorsFile=baseDir+'/accounts/moderators.txt'
|
||||
if os.path.isfile(moderatorsFile):
|
||||
|
@ -1017,7 +1017,7 @@ def htmlLogin(translate: {},baseDir: str,autocomplete=True) -> str:
|
|||
if os.path.isfile(baseDir+'/accounts/login.txt'):
|
||||
# custom login message
|
||||
with open(baseDir+'/accounts/login.txt', 'r') as file:
|
||||
loginText='<p class="login-text">'+file.read()+'</p>'
|
||||
loginText='<p class="login-text">'+file.read()+'</p>'
|
||||
|
||||
cssFilename=baseDir+'/epicyon-login.css'
|
||||
if os.path.isfile(baseDir+'/login.css'):
|
||||
|
@ -1096,17 +1096,17 @@ def htmlTermsOfService(baseDir: str,httpPrefix: str,domainFull: str) -> str:
|
|||
TOSText='Terms of Service go here.'
|
||||
if os.path.isfile(baseDir+'/accounts/tos.txt'):
|
||||
with open(baseDir+'/accounts/tos.txt', 'r') as file:
|
||||
TOSText=file.read()
|
||||
TOSText=file.read()
|
||||
|
||||
TOSForm=''
|
||||
cssFilename=baseDir+'/epicyon-profile.css'
|
||||
if os.path.isfile(baseDir+'/epicyon.css'):
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
termsCSS=cssFile.read()
|
||||
if httpPrefix!='https':
|
||||
termsCSS=termsCSS.replace('https://',httpPrefix+'://')
|
||||
|
||||
|
||||
TOSForm=htmlHeader(cssFilename,termsCSS)
|
||||
TOSForm+='<div class="container">'+TOSText+'</div>'
|
||||
if adminNickname:
|
||||
|
@ -1131,12 +1131,12 @@ def htmlAbout(baseDir: str,httpPrefix: str,domainFull: str) -> str:
|
|||
aboutText='Information about this instance goes here.'
|
||||
if os.path.isfile(baseDir+'/accounts/about.txt'):
|
||||
with open(baseDir+'/accounts/about.txt', 'r') as file:
|
||||
aboutText=file.read()
|
||||
aboutText=file.read()
|
||||
|
||||
aboutForm=''
|
||||
cssFilename=baseDir+'/epicyon-profile.css'
|
||||
if os.path.isfile(baseDir+'/epicyon.css'):
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
termsCSS=cssFile.read()
|
||||
if httpPrefix!='http':
|
||||
|
@ -1160,7 +1160,7 @@ def htmlHashtagBlocked(baseDir: str) -> str:
|
|||
if os.path.isfile(baseDir+'/suspended.css'):
|
||||
cssFilename=baseDir+'/suspended.css'
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
blockedHashtagCSS=cssFile.read()
|
||||
blockedHashtagCSS=cssFile.read()
|
||||
blockedHashtagForm=htmlHeader(cssFilename,blockedHashtagCSS)
|
||||
blockedHashtagForm+='<div><center>'
|
||||
blockedHashtagForm+=' <p class="screentitle">Hashtag Blocked</p>'
|
||||
|
@ -1168,7 +1168,7 @@ def htmlHashtagBlocked(baseDir: str) -> str:
|
|||
blockedHashtagForm+='</center></div>'
|
||||
blockedHashtagForm+=htmlFooter()
|
||||
return blockedHashtagForm
|
||||
|
||||
|
||||
def htmlSuspended(baseDir: str) -> str:
|
||||
"""Show the screen for suspended accounts
|
||||
"""
|
||||
|
@ -1177,7 +1177,7 @@ def htmlSuspended(baseDir: str) -> str:
|
|||
if os.path.isfile(baseDir+'/suspended.css'):
|
||||
cssFilename=baseDir+'/suspended.css'
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
suspendedCSS=cssFile.read()
|
||||
suspendedCSS=cssFile.read()
|
||||
suspendedForm=htmlHeader(cssFilename,suspendedCSS)
|
||||
suspendedForm+='<div><center>'
|
||||
suspendedForm+=' <p class="screentitle">Account Suspended</p>'
|
||||
|
@ -1251,11 +1251,11 @@ def htmlNewPost(mediaInstance: bool,translate: {}, \
|
|||
|
||||
if os.path.isfile(baseDir+'/accounts/newpost.txt'):
|
||||
with open(baseDir+'/accounts/newpost.txt', 'r') as file:
|
||||
newPostText='<p class="new-post-text">'+file.read()+'</p>'
|
||||
newPostText='<p class="new-post-text">'+file.read()+'</p>'
|
||||
|
||||
cssFilename=baseDir+'/epicyon-profile.css'
|
||||
if os.path.isfile(baseDir+'/epicyon.css'):
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
newPostCSS=cssFile.read()
|
||||
if httpPrefix!='https':
|
||||
|
@ -1272,7 +1272,7 @@ def htmlNewPost(mediaInstance: bool,translate: {}, \
|
|||
newPostImageSection+=' <input type="file" id="attachpic" name="attachpic"'
|
||||
newPostImageSection+=' accept=".png, .jpg, .jpeg, .gif, .webp, .mp4, .webm, .ogv, .mp3, .ogg">'
|
||||
newPostImageSection+=' </div>'
|
||||
|
||||
|
||||
scopeIcon='scope_public.png'
|
||||
scopeDescription=translate['Public']
|
||||
placeholderSubject=translate['Subject or Content Warning (optional)']+'...'
|
||||
|
@ -1320,7 +1320,7 @@ def htmlNewPost(mediaInstance: bool,translate: {}, \
|
|||
scopeDescription=translate['Shared Item']
|
||||
placeholderSubject=translate['Name of the shared item']+'...'
|
||||
placeholderMessage=translate['Description of the item being shared']+'...'
|
||||
endpoint='newshare'
|
||||
endpoint='newshare'
|
||||
extraFields='<div class="container">'
|
||||
extraFields+= \
|
||||
' <label class="labels">'+ \
|
||||
|
@ -1403,14 +1403,14 @@ def htmlNewPost(mediaInstance: bool,translate: {}, \
|
|||
dropdownNewBlogSuffix='/newblog'
|
||||
dropdownUnlistedSuffix='/newunlisted'
|
||||
dropdownFollowersSuffix='/newfollowers'
|
||||
dropdownDMSuffix='/newdm'
|
||||
dropdownReportSuffix='/newreport'
|
||||
dropdownDMSuffix='/newdm'
|
||||
dropdownReportSuffix='/newreport'
|
||||
if inReplyTo or mentions:
|
||||
dropdownNewPostSuffix=''
|
||||
dropdownNewBlogSuffix=''
|
||||
dropdownUnlistedSuffix=''
|
||||
dropdownFollowersSuffix=''
|
||||
dropdownDMSuffix=''
|
||||
dropdownDMSuffix=''
|
||||
dropdownReportSuffix=''
|
||||
if inReplyTo:
|
||||
dropdownNewPostSuffix+='?replyto='+inReplyTo
|
||||
|
@ -1425,7 +1425,7 @@ def htmlNewPost(mediaInstance: bool,translate: {}, \
|
|||
dropdownFollowersSuffix+='?mention='+mentionedActor
|
||||
dropdownDMSuffix+='?mention='+mentionedActor
|
||||
dropdownReportSuffix+='?mention='+mentionedActor
|
||||
|
||||
|
||||
dropDownContent=''
|
||||
if not reportUrl:
|
||||
dropDownContent+=' <div id="myDropdown" class="dropdown-content">'
|
||||
|
@ -1468,7 +1468,7 @@ def htmlNewPost(mediaInstance: bool,translate: {}, \
|
|||
dropDownContent+=' </div>'
|
||||
else:
|
||||
mentionsStr='Re: '+reportUrl+'\n\n'+mentionsStr
|
||||
|
||||
|
||||
newPostForm+= \
|
||||
'<form enctype="multipart/form-data" method="POST" accept-charset="UTF-8" action="'+ \
|
||||
path+'?'+endpoint+'?page='+str(pageNumber)+'">'
|
||||
|
@ -1556,7 +1556,7 @@ def htmlHeader(cssFilename: str,css=None,refreshSec=0,lang='en') -> str:
|
|||
htmlStr+='<html lang="'+lang+'">\n'
|
||||
htmlStr+=meta
|
||||
htmlStr+=' <style>\n'+css+'</style>\n'
|
||||
htmlStr+=' <body>\n'
|
||||
htmlStr+=' <body>\n'
|
||||
return htmlStr
|
||||
|
||||
def htmlFooter() -> str:
|
||||
|
@ -1764,7 +1764,7 @@ def sharesTimelineJson(actor: str,pageNumber: int,itemsPerPage: int, \
|
|||
resultJson={}
|
||||
for published,item in sharesJson.items():
|
||||
if ctr>=startIndex+itemsPerPage:
|
||||
break
|
||||
break
|
||||
if ctr<startIndex:
|
||||
ctr+=1
|
||||
continue
|
||||
|
@ -1813,7 +1813,7 @@ def htmlSharesTimeline(translate: {},pageNumber: int,itemsPerPage: int, \
|
|||
str(pageNumber+1)+'"><img loading="lazy" class="pageicon" src="/'+ \
|
||||
iconsDir+'/pagedown.png" title="'+translate['Page down']+ \
|
||||
'" alt="'+translate['Page down']+'"></a></center>'
|
||||
|
||||
|
||||
return timelineStr
|
||||
|
||||
def htmlProfile(defaultTimeline: str, \
|
||||
|
@ -1835,14 +1835,14 @@ def htmlProfile(defaultTimeline: str, \
|
|||
displayName= \
|
||||
addEmojiToDisplayName(baseDir,httpPrefix, \
|
||||
nickname,domain, \
|
||||
profileJson['name'],True)
|
||||
profileJson['name'],True)
|
||||
domainFull=domain
|
||||
if port:
|
||||
domainFull=domain+':'+str(port)
|
||||
profileDescription= \
|
||||
addEmojiToDisplayName(baseDir,httpPrefix, \
|
||||
nickname,domain, \
|
||||
profileJson['summary'],False)
|
||||
profileJson['summary'],False)
|
||||
postsButton='button'
|
||||
followingButton='button'
|
||||
followersButton='button'
|
||||
|
@ -2032,10 +2032,10 @@ def htmlProfile(defaultTimeline: str, \
|
|||
profileStr+='</div>'
|
||||
|
||||
profileStr+=followApprovalsSection
|
||||
|
||||
|
||||
cssFilename=baseDir+'/epicyon-profile.css'
|
||||
if os.path.isfile(baseDir+'/epicyon.css'):
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
profileStyle= \
|
||||
cssFile.read().replace('image.png', \
|
||||
|
@ -2354,7 +2354,7 @@ def addEmbeddedVideoFromSites(translate: {},content: str,width=400,height=300) -
|
|||
if '"https://'+site in content:
|
||||
url=content.split('"https://'+site)[1]
|
||||
if '"' in url:
|
||||
url=url.split('"')[0].replace('/watch/','/embed/')
|
||||
url=url.split('"')[0].replace('/watch/','/embed/')
|
||||
content= \
|
||||
content+"<center><iframe loading=\"lazy\" sandbox=\"allow-same-origin allow-scripts\" src=\"https://"+ \
|
||||
site+url+"\" width=\""+str(width)+"\" height=\""+str(height)+ \
|
||||
|
@ -2518,7 +2518,7 @@ def postContainsPublic(postJsonObject: {}) -> bool:
|
|||
containsPublic=False
|
||||
if not postJsonObject['object'].get('to'):
|
||||
return containsPublic
|
||||
|
||||
|
||||
for toAddress in postJsonObject['object']['to']:
|
||||
if toAddress.endswith('#Public'):
|
||||
containsPublic=True
|
||||
|
@ -2543,10 +2543,10 @@ def loadIndividualPostAsHtmlFromCache(baseDir: str,nickname: str,domain: str, \
|
|||
postHtml=''
|
||||
if not cachedPostFilename:
|
||||
return postHtml
|
||||
|
||||
|
||||
if not os.path.isfile(cachedPostFilename):
|
||||
return postHtml
|
||||
|
||||
|
||||
tries=0
|
||||
while tries<3:
|
||||
try:
|
||||
|
@ -2682,7 +2682,7 @@ def getPostAttachmentsAsHtml(postJsonObject: {},boxName: str,translate: {}, \
|
|||
'<img loading="lazy" src="'+attach['url']+ \
|
||||
'" alt="'+imageDescription+'" title="'+ \
|
||||
imageDescription+'" class="attachment"></a>\n'
|
||||
attachmentCtr+=1
|
||||
attachmentCtr+=1
|
||||
elif mediaType=='video/mp4' or \
|
||||
mediaType=='video/webm' or \
|
||||
mediaType=='video/ogv':
|
||||
|
@ -2743,7 +2743,7 @@ def getPostAttachmentsAsHtml(postJsonObject: {},boxName: str,translate: {}, \
|
|||
mediaType=='audio/ogg':
|
||||
extension='.mp3'
|
||||
if attach['url'].endswith('.ogg'):
|
||||
extension='.ogg'
|
||||
extension='.ogg'
|
||||
if attach['url'].endswith(extension):
|
||||
if attachmentCtr>0:
|
||||
attachmentStr+='<br>'
|
||||
|
@ -2884,7 +2884,7 @@ def individualPostAsHtml(recentPostsCache: {},maxRecentPosts: int, \
|
|||
avatarLink+= \
|
||||
' <img loading="lazy" src="'+avatarUrl+'" title="'+ \
|
||||
translate['Show profile']+'" alt=" "'+avatarPosition+'/></a>'
|
||||
|
||||
|
||||
if showAvatarOptions and fullDomain+'/users/'+nickname not in postActor:
|
||||
avatarLink= \
|
||||
' <a href="/users/'+nickname+'?options='+postActor+ \
|
||||
|
@ -2914,7 +2914,7 @@ def individualPostAsHtml(recentPostsCache: {},maxRecentPosts: int, \
|
|||
else:
|
||||
if not isPublicPost(postJsonObject):
|
||||
isPublicRepeat=True
|
||||
|
||||
|
||||
titleStr=''
|
||||
galleryStr=''
|
||||
isAnnounced=False
|
||||
|
@ -2933,7 +2933,7 @@ def individualPostAsHtml(recentPostsCache: {},maxRecentPosts: int, \
|
|||
if showPublicOnly:
|
||||
if not postContainsPublic(postJsonObject):
|
||||
return ''
|
||||
|
||||
|
||||
isModerationPost=False
|
||||
if postJsonObject['object'].get('moderationStatus'):
|
||||
isModerationPost=True
|
||||
|
@ -2993,7 +2993,7 @@ def individualPostAsHtml(recentPostsCache: {},maxRecentPosts: int, \
|
|||
if len(replyToLink)>500:
|
||||
break
|
||||
replyToLink+=pageNumberParam
|
||||
|
||||
|
||||
replyStr=''
|
||||
if isPublicRepeat:
|
||||
replyStr+= \
|
||||
|
@ -3031,7 +3031,7 @@ def individualPostAsHtml(recentPostsCache: {},maxRecentPosts: int, \
|
|||
translate['Edit blog post']+' |" alt="'+ \
|
||||
translate['Edit blog post']+ \
|
||||
' |" src="/'+iconsDir+'/edit.png"/></a>'
|
||||
|
||||
|
||||
announceStr=''
|
||||
if not isModerationPost and showRepeatIcon:
|
||||
# don't allow announce/repeat of your own posts
|
||||
|
@ -3131,7 +3131,7 @@ def individualPostAsHtml(recentPostsCache: {},maxRecentPosts: int, \
|
|||
'<img loading="lazy" alt="'+translate['Undo mute']+ \
|
||||
' |" title="'+translate['Undo mute']+ \
|
||||
' |" src="/'+iconsDir+'/unmute.png"/></a>'
|
||||
|
||||
|
||||
replyAvatarImageInPost=''
|
||||
if showRepeatIcon:
|
||||
if isAnnounced:
|
||||
|
@ -3419,7 +3419,7 @@ def htmlTimeline(defaultTimeline: str, \
|
|||
manuallyApproveFollowers: bool) -> str:
|
||||
"""Show the timeline as html
|
||||
"""
|
||||
accountDir=baseDir+'/accounts/'+nickname+'@'+domain
|
||||
accountDir=baseDir+'/accounts/'+nickname+'@'+domain
|
||||
|
||||
# should the calendar icon be highlighted?
|
||||
calendarImage='calendar.png'
|
||||
|
@ -3477,8 +3477,8 @@ def htmlTimeline(defaultTimeline: str, \
|
|||
bannerFilename=baseDir+'/accounts/'+nickname+'@'+domain+'/'+bannerFile
|
||||
if not os.path.isfile(bannerFilename):
|
||||
bannerFile='banner.webp'
|
||||
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
profileStyle= \
|
||||
cssFile.read().replace('banner.png', \
|
||||
'/users/'+nickname+'/'+bannerFile)
|
||||
|
@ -3538,7 +3538,7 @@ def htmlTimeline(defaultTimeline: str, \
|
|||
actor=httpPrefix+'://'+fullDomain+'/users/'+nickname
|
||||
|
||||
showIndividualPostIcons=True
|
||||
|
||||
|
||||
followApprovals=''
|
||||
followRequestsFilename= \
|
||||
baseDir+'/accounts/'+nickname+'@'+domain+'/followrequests.txt'
|
||||
|
@ -3577,7 +3577,7 @@ def htmlTimeline(defaultTimeline: str, \
|
|||
#tlStr=htmlHeader(cssFilename,profileStyle,240)
|
||||
|
||||
if boxName!='dm':
|
||||
if boxName!='tlblogs':
|
||||
if boxName!='tlblogs':
|
||||
if not manuallyApproveFollowers:
|
||||
newPostButtonStr= \
|
||||
'<a href="'+actor+'/newpost"><img loading="lazy" src="/'+ \
|
||||
|
@ -3605,7 +3605,7 @@ def htmlTimeline(defaultTimeline: str, \
|
|||
tlStr+= \
|
||||
'<a href="/users/'+nickname+'"><label class="transparent">'+ \
|
||||
translate['Switch to profile view']+'</label></a>'
|
||||
|
||||
|
||||
# banner and row of buttons
|
||||
tlStr+= \
|
||||
'<a href="/users/'+nickname+'" title="'+ \
|
||||
|
@ -3785,7 +3785,7 @@ def htmlTimeline(defaultTimeline: str, \
|
|||
postId=item['id'].replace('/activity','').replace('/','#')
|
||||
if postId in recentPostsCache['index']:
|
||||
if not item.get('muted'):
|
||||
if recentPostsCache['html'].get(postId):
|
||||
if recentPostsCache['html'].get(postId):
|
||||
currTlStr=recentPostsCache['html'][postId]
|
||||
currTlStr= \
|
||||
preparePostFromHtmlCache(currTlStr,boxName,pageNumber)
|
||||
|
@ -3973,7 +3973,7 @@ def htmlIndividualPost(recentPostsCache: {},maxRecentPosts: int, \
|
|||
"""Show an individual post as html
|
||||
"""
|
||||
iconsDir=getIconsDir(baseDir)
|
||||
postStr='<script>'+contentWarningScript()+'</script>'
|
||||
postStr='<script>'+contentWarningScript()+'</script>'
|
||||
postStr+= \
|
||||
individualPostAsHtml(recentPostsCache,maxRecentPosts, \
|
||||
iconsDir,translate,None, \
|
||||
|
@ -4023,7 +4023,7 @@ def htmlIndividualPost(recentPostsCache: {},maxRecentPosts: int, \
|
|||
False,authorized,False,False,False)
|
||||
cssFilename=baseDir+'/epicyon-profile.css'
|
||||
if os.path.isfile(baseDir+'/epicyon.css'):
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
postsCSS=cssFile.read()
|
||||
if httpPrefix!='https':
|
||||
|
@ -4051,7 +4051,7 @@ def htmlPostReplies(recentPostsCache: {},maxRecentPosts: int, \
|
|||
|
||||
cssFilename=baseDir+'/epicyon-profile.css'
|
||||
if os.path.isfile(baseDir+'/epicyon.css'):
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
postsCSS=cssFile.read()
|
||||
if httpPrefix!='https':
|
||||
|
@ -4068,7 +4068,7 @@ def htmlRemoveSharedItem(translate: {},baseDir: str,actor: str,shareName: str) -
|
|||
if not os.path.isfile(sharesFile):
|
||||
print('ERROR: no shares file '+sharesFile)
|
||||
return None
|
||||
sharesJson=loadJson(sharesFile)
|
||||
sharesJson=loadJson(sharesFile)
|
||||
if not sharesJson:
|
||||
print('ERROR: unable to load shares.json')
|
||||
return None
|
||||
|
@ -4087,7 +4087,7 @@ def htmlRemoveSharedItem(translate: {},baseDir: str,actor: str,shareName: str) -
|
|||
|
||||
cssFilename=baseDir+'/epicyon-follow.css'
|
||||
if os.path.isfile(baseDir+'/follow.css'):
|
||||
cssFilename=baseDir+'/follow.css'
|
||||
cssFilename=baseDir+'/follow.css'
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
profileStyle=cssFile.read()
|
||||
sharesStr=htmlHeader(cssFilename,profileStyle)
|
||||
|
@ -4145,7 +4145,7 @@ def htmlDeletePost(recentPostsCache: {},maxRecentPosts: int, \
|
|||
deletePostStr=None
|
||||
cssFilename=baseDir+'/epicyon-profile.css'
|
||||
if os.path.isfile(baseDir+'/epicyon.css'):
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
profileStyle=cssFile.read()
|
||||
if httpPrefix!='https':
|
||||
|
@ -4209,7 +4209,7 @@ def htmlCalendarDeleteConfirm(translate: {},baseDir: str, \
|
|||
deletePostStr=None
|
||||
cssFilename=baseDir+'/epicyon-profile.css'
|
||||
if os.path.isfile(baseDir+'/epicyon.css'):
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
profileStyle=cssFile.read()
|
||||
if httpPrefix!='https':
|
||||
|
@ -4245,7 +4245,7 @@ def htmlFollowConfirm(translate: {},baseDir: str, \
|
|||
"""Asks to confirm a follow
|
||||
"""
|
||||
followDomain,port=getDomainFromActor(followActor)
|
||||
|
||||
|
||||
if os.path.isfile(baseDir+'/img/follow-background.png'):
|
||||
if not os.path.isfile(baseDir+'/accounts/follow-background.png'):
|
||||
copyfile(baseDir+'/img/follow-background.png', \
|
||||
|
@ -4253,7 +4253,7 @@ def htmlFollowConfirm(translate: {},baseDir: str, \
|
|||
|
||||
cssFilename=baseDir+'/epicyon-follow.css'
|
||||
if os.path.isfile(baseDir+'/follow.css'):
|
||||
cssFilename=baseDir+'/follow.css'
|
||||
cssFilename=baseDir+'/follow.css'
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
profileStyle=cssFile.read()
|
||||
followStr=htmlHeader(cssFilename,profileStyle)
|
||||
|
@ -4287,7 +4287,7 @@ def htmlUnfollowConfirm(translate: {},baseDir: str, \
|
|||
"""Asks to confirm unfollowing an actor
|
||||
"""
|
||||
followDomain,port=getDomainFromActor(followActor)
|
||||
|
||||
|
||||
if os.path.isfile(baseDir+'/img/follow-background.png'):
|
||||
if not os.path.isfile(baseDir+'/accounts/follow-background.png'):
|
||||
copyfile(baseDir+'/img/follow-background.png', \
|
||||
|
@ -4295,7 +4295,7 @@ def htmlUnfollowConfirm(translate: {},baseDir: str, \
|
|||
|
||||
cssFilename=baseDir+'/epicyon-follow.css'
|
||||
if os.path.isfile(baseDir+'/follow.css'):
|
||||
cssFilename=baseDir+'/follow.css'
|
||||
cssFilename=baseDir+'/follow.css'
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
profileStyle=cssFile.read()
|
||||
followStr=htmlHeader(cssFilename,profileStyle)
|
||||
|
@ -4338,7 +4338,7 @@ def htmlPersonOptions(translate: {},baseDir: str, \
|
|||
"""Show options for a person: view/follow/block/report
|
||||
"""
|
||||
optionsDomain,optionsPort=getDomainFromActor(optionsActor)
|
||||
|
||||
|
||||
if os.path.isfile(baseDir+'/img/options-background.png'):
|
||||
if not os.path.isfile(baseDir+'/accounts/options-background.png'):
|
||||
copyfile(baseDir+'/img/options-background.png', \
|
||||
|
@ -4370,7 +4370,7 @@ def htmlPersonOptions(translate: {},baseDir: str, \
|
|||
optionsLinkStr=' <input type="hidden" name="postUrl" value="'+optionsLink+'">'
|
||||
cssFilename=baseDir+'/epicyon-follow.css'
|
||||
if os.path.isfile(baseDir+'/follow.css'):
|
||||
cssFilename=baseDir+'/follow.css'
|
||||
cssFilename=baseDir+'/follow.css'
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
profileStyle=cssFile.read()
|
||||
|
||||
|
@ -4452,7 +4452,7 @@ def htmlPersonOptions(translate: {},baseDir: str, \
|
|||
# """Asks to confirm a block
|
||||
# """
|
||||
# blockDomain,port=getDomainFromActor(blockActor)
|
||||
#
|
||||
#
|
||||
# if os.path.isfile(baseDir+'/img/block-background.png'):
|
||||
# if not os.path.isfile(baseDir+'/accounts/block-background.png'):
|
||||
# copyfile(baseDir+'/img/block-background.png',baseDir+'/accounts/block-background.png')
|
||||
|
@ -4484,7 +4484,7 @@ def htmlUnblockConfirm(translate: {},baseDir: str, \
|
|||
"""Asks to confirm unblocking an actor
|
||||
"""
|
||||
blockDomain,port=getDomainFromActor(blockActor)
|
||||
|
||||
|
||||
if os.path.isfile(baseDir+'/img/block-background.png'):
|
||||
if not os.path.isfile(baseDir+'/accounts/block-background.png'):
|
||||
copyfile(baseDir+'/img/block-background.png', \
|
||||
|
@ -4492,7 +4492,7 @@ def htmlUnblockConfirm(translate: {},baseDir: str, \
|
|||
|
||||
cssFilename=baseDir+'/epicyon-follow.css'
|
||||
if os.path.isfile(baseDir+'/follow.css'):
|
||||
cssFilename=baseDir+'/follow.css'
|
||||
cssFilename=baseDir+'/follow.css'
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
profileStyle=cssFile.read()
|
||||
blockStr=htmlHeader(cssFilename,profileStyle)
|
||||
|
@ -4524,7 +4524,7 @@ def htmlSearchEmojiTextEntry(translate: {}, \
|
|||
"""Search for an emoji by name
|
||||
"""
|
||||
# emoji.json is generated so that it can be customized and the changes
|
||||
# will be retained even if default_emoji.json is subsequently updated
|
||||
# will be retained even if default_emoji.json is subsequently updated
|
||||
if not os.path.isfile(baseDir+'/emoji/emoji.json'):
|
||||
copyfile(baseDir+'/emoji/default_emoji.json', \
|
||||
baseDir+'/emoji/emoji.json')
|
||||
|
@ -4532,7 +4532,7 @@ def htmlSearchEmojiTextEntry(translate: {}, \
|
|||
actor=path.replace('/search','')
|
||||
nickname=getNicknameFromActor(actor)
|
||||
domain,port=getDomainFromActor(actor)
|
||||
|
||||
|
||||
if os.path.isfile(baseDir+'/img/search-background.png'):
|
||||
if not os.path.isfile(baseDir+'/accounts/search-background.png'):
|
||||
copyfile(baseDir+'/img/search-background.png', \
|
||||
|
@ -4540,13 +4540,13 @@ def htmlSearchEmojiTextEntry(translate: {}, \
|
|||
|
||||
cssFilename=baseDir+'/epicyon-follow.css'
|
||||
if os.path.isfile(baseDir+'/follow.css'):
|
||||
cssFilename=baseDir+'/follow.css'
|
||||
cssFilename=baseDir+'/follow.css'
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
profileStyle=cssFile.read()
|
||||
emojiStr=htmlHeader(cssFilename,profileStyle)
|
||||
emojiStr+='<div class="follow">'
|
||||
emojiStr+=' <div class="followAvatar">'
|
||||
emojiStr+=' <center>'
|
||||
emojiStr+=' <center>'
|
||||
emojiStr+= \
|
||||
' <p class="followText">'+ \
|
||||
translate['Enter an emoji name to search for']+'</p>'
|
||||
|
@ -4585,7 +4585,7 @@ def htmlCalendarDay(translate: {}, \
|
|||
|
||||
cssFilename=baseDir+'/epicyon-calendar.css'
|
||||
if os.path.isfile(baseDir+'/calendar.css'):
|
||||
cssFilename=baseDir+'/calendar.css'
|
||||
cssFilename=baseDir+'/calendar.css'
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
calendarStyle=cssFile.read()
|
||||
|
||||
|
@ -4617,15 +4617,15 @@ def htmlCalendarDay(translate: {}, \
|
|||
if ev.get('startTime'):
|
||||
eventDate= \
|
||||
datetime.strptime(ev['startTime'], \
|
||||
"%Y-%m-%dT%H:%M:%S%z")
|
||||
"%Y-%m-%dT%H:%M:%S%z")
|
||||
eventTime=eventDate.strftime("%H:%M").strip()
|
||||
if ev.get('name'):
|
||||
eventDescription=ev['name'].strip()
|
||||
elif ev['type']=='Place':
|
||||
if ev.get('name'):
|
||||
eventPlace=ev['name']
|
||||
|
||||
deleteButtonStr=''
|
||||
|
||||
deleteButtonStr=''
|
||||
if postId:
|
||||
deleteButtonStr= \
|
||||
'<td class="calendar__day__icons"><a href="'+actor+ \
|
||||
|
@ -4668,7 +4668,7 @@ def htmlCalendarDay(translate: {}, \
|
|||
calendarStr+=htmlFooter()
|
||||
|
||||
return calendarStr
|
||||
|
||||
|
||||
def htmlCalendar(translate: {}, \
|
||||
baseDir: str,path: str, \
|
||||
httpPrefix: str,domainFull: str) -> str:
|
||||
|
@ -4678,7 +4678,7 @@ def htmlCalendar(translate: {}, \
|
|||
domain=domainFull
|
||||
if ':' in domainFull:
|
||||
domain=domainFull.split(':')[0]
|
||||
|
||||
|
||||
monthNumber=0
|
||||
dayNumber=None
|
||||
year=1970
|
||||
|
@ -4732,7 +4732,7 @@ def htmlCalendar(translate: {}, \
|
|||
year,monthNumber,dayNumber, \
|
||||
nickname,domain,dayEvents, \
|
||||
monthName,actor)
|
||||
|
||||
|
||||
events= \
|
||||
getCalendarEvents(baseDir,nickname,domain,year,monthNumber)
|
||||
|
||||
|
@ -4758,10 +4758,10 @@ def htmlCalendar(translate: {}, \
|
|||
|
||||
cssFilename=baseDir+'/epicyon-calendar.css'
|
||||
if os.path.isfile(baseDir+'/calendar.css'):
|
||||
cssFilename=baseDir+'/calendar.css'
|
||||
cssFilename=baseDir+'/calendar.css'
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
calendarStyle=cssFile.read()
|
||||
|
||||
|
||||
calendarStr=htmlHeader(cssFilename,calendarStyle)
|
||||
calendarStr+='<main><table class="calendar">\n'
|
||||
calendarStr+='<caption class="calendar__banner--month">\n'
|
||||
|
@ -4831,7 +4831,7 @@ def htmlCalendar(translate: {}, \
|
|||
else:
|
||||
calendarStr+=' <td class="calendar__day__cell"></td>\n'
|
||||
calendarStr+=' </tr>\n'
|
||||
|
||||
|
||||
calendarStr+='</tbody>\n'
|
||||
calendarStr+='</table></main>\n'
|
||||
calendarStr+=htmlFooter()
|
||||
|
@ -4914,7 +4914,7 @@ def htmlSearch(translate: {}, \
|
|||
followStr=htmlHeader(cssFilename,profileStyle)
|
||||
followStr+='<div class="follow">'
|
||||
followStr+=' <div class="followAvatar">'
|
||||
followStr+=' <center>'
|
||||
followStr+=' <center>'
|
||||
followStr+= \
|
||||
' <p class="followText">'+ \
|
||||
translate['Enter an address, shared item, #hashtag, *skill or :emoji: to search for']+'</p>'
|
||||
|
@ -4978,11 +4978,11 @@ def htmlProfileAfterSearch(recentPostsCache: {},maxRecentPosts: int, \
|
|||
if searchPort!=80 and searchPort!=443:
|
||||
if ':' not in searchDomain:
|
||||
searchDomainFull=searchDomain+':'+str(searchPort)
|
||||
|
||||
|
||||
profileStr=''
|
||||
cssFilename=baseDir+'/epicyon-profile.css'
|
||||
if os.path.isfile(baseDir+'/epicyon.css'):
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
cssFilename=baseDir+'/epicyon.css'
|
||||
with open(cssFilename, 'r') as cssFile:
|
||||
wf= \
|
||||
webfingerHandle(session, \
|
||||
|
@ -4996,7 +4996,7 @@ def htmlProfileAfterSearch(recentPostsCache: {},maxRecentPosts: int, \
|
|||
personUrl=None
|
||||
if wf.get('errors'):
|
||||
personUrl=httpPrefix+'://'+searchDomainFull+'/users/'+searchNickname
|
||||
|
||||
|
||||
asHeader={
|
||||
'Accept': 'application/activity+json; profile="https://www.w3.org/ns/activitystreams"'
|
||||
}
|
||||
|
@ -5119,4 +5119,3 @@ def htmlProfileAfterSearch(recentPostsCache: {},maxRecentPosts: int, \
|
|||
break
|
||||
|
||||
return htmlHeader(cssFilename,profileStyle)+profileStr+htmlFooter()
|
||||
|
||||
|
|
Loading…
Reference in New Issue