mirror of https://gitlab.com/bashrc2/epicyon
				
				
				
			Option to use dat urls
							parent
							
								
									0f5592452a
								
							
						
					
					
						commit
						86aaff3c84
					
				| 
						 | 
				
			
			@ -12,7 +12,7 @@ from utils import getStatusNumber
 | 
			
		|||
from utils import createOutboxDir
 | 
			
		||||
from utils import urlPermitted
 | 
			
		||||
 | 
			
		||||
def createAcceptReject(baseDir: str,federationList: [],nickname: str,domain: str,port: int,toUrl: str,ccUrl: str,https: bool,objectUrl: str,acceptType: str) -> {}:
 | 
			
		||||
def createAcceptReject(baseDir: str,federationList: [],nickname: str,domain: str,port: int,toUrl: str,ccUrl: str,httpPrefix: str,objectUrl: str,acceptType: str) -> {}:
 | 
			
		||||
    """Accepts or rejects something (eg. a follow request)
 | 
			
		||||
    Typically toUrl will be https://www.w3.org/ns/activitystreams#Public
 | 
			
		||||
    and ccUrl might be a specific person favorited or repeated and the followers url
 | 
			
		||||
| 
						 | 
				
			
			@ -21,16 +21,12 @@ def createAcceptReject(baseDir: str,federationList: [],nickname: str,domain: str
 | 
			
		|||
    if not urlPermitted(objectUrl,federationList):
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    prefix='https'
 | 
			
		||||
    if not https:
 | 
			
		||||
        prefix='http'
 | 
			
		||||
 | 
			
		||||
    if port!=80 and port!=443:
 | 
			
		||||
        domain=domain+':'+str(port)
 | 
			
		||||
 | 
			
		||||
    newAccept = {
 | 
			
		||||
        'type': acceptType,
 | 
			
		||||
        'actor': prefix+'://'+domain+'/users/'+nickname,
 | 
			
		||||
        'actor': httpPrefix+'://'+domain+'/users/'+nickname,
 | 
			
		||||
        'to': [toUrl],
 | 
			
		||||
        'cc': [],
 | 
			
		||||
        'object': objectUrl
 | 
			
		||||
| 
						 | 
				
			
			@ -40,8 +36,8 @@ def createAcceptReject(baseDir: str,federationList: [],nickname: str,domain: str
 | 
			
		|||
            newAccept['cc']=ccUrl
 | 
			
		||||
    return newAccept
 | 
			
		||||
 | 
			
		||||
def createAccept(baseDir: str,federationList: [],nickname: str,domain: str,port: int,toUrl: str,ccUrl: str,https: bool,objectUrl: str) -> {}:
 | 
			
		||||
    return createAcceptReject(baseDir,federationList,nickname,domain,port,toUrl,ccUrl,https,objectUrl,'Accept')
 | 
			
		||||
def createAccept(baseDir: str,federationList: [],nickname: str,domain: str,port: int,toUrl: str,ccUrl: str,httpPrefix: str,objectUrl: str) -> {}:
 | 
			
		||||
    return createAcceptReject(baseDir,federationList,nickname,domain,port,toUrl,ccUrl,httpPrefix,objectUrl,'Accept')
 | 
			
		||||
 | 
			
		||||
def createReject(baseDir: str,federationList: [],nickname: str,domain: str,port: int,toUrl: str,ccUrl: str,https: bool,objectUrl: str) -> {}:
 | 
			
		||||
    return createAcceptReject(baseDir,federationList,nickname,domain,port,toUrl,ccUrl,https,objectUrl,'Reject')
 | 
			
		||||
def createReject(baseDir: str,federationList: [],nickname: str,domain: str,port: int,toUrl: str,ccUrl: str,httpPrefix: str,objectUrl: str) -> {}:
 | 
			
		||||
    return createAcceptReject(baseDir,federationList,nickname,domain,port,toUrl,ccUrl,httpPrefix,objectUrl,'Reject')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										34
									
								
								announce.py
								
								
								
								
							
							
						
						
									
										34
									
								
								announce.py
								
								
								
								
							| 
						 | 
				
			
			@ -14,7 +14,7 @@ from utils import urlPermitted
 | 
			
		|||
 | 
			
		||||
def createAnnounce(baseDir: str,federationList: [], \
 | 
			
		||||
                   nickname: str, domain: str, port: int, \
 | 
			
		||||
                   toUrl: str, ccUrl: str, https: bool, \
 | 
			
		||||
                   toUrl: str, ccUrl: str, httpPrefix: str, \
 | 
			
		||||
                   objectUrl: str, saveToFile: bool) -> {}:
 | 
			
		||||
    """Creates an announce message
 | 
			
		||||
    Typically toUrl will be https://www.w3.org/ns/activitystreams#Public
 | 
			
		||||
| 
						 | 
				
			
			@ -24,18 +24,14 @@ def createAnnounce(baseDir: str,federationList: [], \
 | 
			
		|||
    if not urlPermitted(objectUrl,federationList):
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    prefix='https'
 | 
			
		||||
    if not https:
 | 
			
		||||
        prefix='http'
 | 
			
		||||
 | 
			
		||||
    if port!=80 and port!=443:
 | 
			
		||||
        domain=domain+':'+str(port)
 | 
			
		||||
 | 
			
		||||
    statusNumber,published = getStatusNumber()
 | 
			
		||||
    newAnnounceId=prefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber
 | 
			
		||||
    newAnnounceId=httpPrefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber
 | 
			
		||||
    newAnnounce = {
 | 
			
		||||
        'actor': prefix+'://'+domain+'/users/'+nickname,
 | 
			
		||||
        'atomUri': prefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber,
 | 
			
		||||
        'actor': httpPrefix+'://'+domain+'/users/'+nickname,
 | 
			
		||||
        'atomUri': httpPrefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber,
 | 
			
		||||
        'cc': [],
 | 
			
		||||
        'id': newAnnounceId+'/activity',
 | 
			
		||||
        'object': objectUrl,
 | 
			
		||||
| 
						 | 
				
			
			@ -56,40 +52,32 @@ def createAnnounce(baseDir: str,federationList: [], \
 | 
			
		|||
    return newAnnounce
 | 
			
		||||
 | 
			
		||||
def announcePublic(baseDir: str,federationList: [], \
 | 
			
		||||
                   nickname: str, domain: str, port: int, https: bool, \
 | 
			
		||||
                   nickname: str, domain: str, port: int, httpPrefix: str, \
 | 
			
		||||
                   objectUrl: str, saveToFile: bool) -> {}:
 | 
			
		||||
    """Makes a public announcement
 | 
			
		||||
    """
 | 
			
		||||
    prefix='https'
 | 
			
		||||
    if not https:
 | 
			
		||||
        prefix='http'
 | 
			
		||||
 | 
			
		||||
    fromDomain=domain
 | 
			
		||||
    if port!=80 and port!=443:
 | 
			
		||||
        fromDomain=fromDomain+':'+str(port)
 | 
			
		||||
 | 
			
		||||
    toUrl = 'https://www.w3.org/ns/activitystreams#Public'
 | 
			
		||||
    ccUrl = prefix + '://'+fromDomain+'/users/'+nickname+'/followers'
 | 
			
		||||
    ccUrl = httpPrefix + '://'+fromDomain+'/users/'+nickname+'/followers'
 | 
			
		||||
    return createAnnounce(baseDir,nickname, domain, port, \
 | 
			
		||||
                          toUrl, ccUrl, https, objectUrl, saveToFile)
 | 
			
		||||
                          toUrl, ccUrl, httpPrefix, objectUrl, saveToFile)
 | 
			
		||||
 | 
			
		||||
def repeatPost(baseDir: str,federationList: [], \
 | 
			
		||||
               nickname: str, domain: str, port: int, https: bool, \
 | 
			
		||||
               nickname: str, domain: str, port: int, httpPrefix: str, \
 | 
			
		||||
               announceNickname: str, announceDomain: str, \
 | 
			
		||||
               announcePort: int, announceHttps: bool, \
 | 
			
		||||
               announcePort: int, announceHttpsPrefix: str, \
 | 
			
		||||
               announceStatusNumber: int, saveToFile: bool) -> {}:
 | 
			
		||||
    """Repeats a given status post
 | 
			
		||||
    """
 | 
			
		||||
    prefix='https'
 | 
			
		||||
    if not announceHttps:
 | 
			
		||||
        prefix='http'
 | 
			
		||||
 | 
			
		||||
    announcedDomain=announceDomain
 | 
			
		||||
    if announcePort!=80 and announcePort!=443:
 | 
			
		||||
        announcedDomain=announcedDomain+':'+str(announcePort)
 | 
			
		||||
 | 
			
		||||
    objectUrl = prefix + '://'+announcedDomain+'/users/'+ \
 | 
			
		||||
    objectUrl = announceHttpsPrefix + '://'+announcedDomain+'/users/'+ \
 | 
			
		||||
        announceNickname+'/statuses/'+str(announceStatusNumber)
 | 
			
		||||
 | 
			
		||||
    return announcePublic(baseDir,nickname, domain, port, https, objectUrl, saveToFile)
 | 
			
		||||
    return announcePublic(baseDir,nickname, domain, port, httpPrefix, objectUrl, saveToFile)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										12
									
								
								daemon.py
								
								
								
								
							
							
						
						
									
										12
									
								
								daemon.py
								
								
								
								
							| 
						 | 
				
			
			@ -129,7 +129,7 @@ class PubServer(BaseHTTPRequestHandler):
 | 
			
		|||
        # get outbox feed for a person
 | 
			
		||||
        outboxFeed=personOutboxJson(self.server.baseDir,self.server.domain, \
 | 
			
		||||
                                    self.server.port,self.path, \
 | 
			
		||||
                                    self.server.https,maxPostsInFeed)
 | 
			
		||||
                                    self.server.httpPrefix,maxPostsInFeed)
 | 
			
		||||
        if outboxFeed:
 | 
			
		||||
            self._set_headers('application/json')
 | 
			
		||||
            self.wfile.write(json.dumps(outboxFeed).encode('utf-8'))
 | 
			
		||||
| 
						 | 
				
			
			@ -137,7 +137,7 @@ class PubServer(BaseHTTPRequestHandler):
 | 
			
		|||
            return
 | 
			
		||||
        following=getFollowingFeed(self.server.baseDir,self.server.domain, \
 | 
			
		||||
                                   self.server.port,self.path, \
 | 
			
		||||
                                   self.server.https,followsPerPage)
 | 
			
		||||
                                   self.server.httpPrefix,followsPerPage)
 | 
			
		||||
        if following:
 | 
			
		||||
            self._set_headers('application/json')
 | 
			
		||||
            self.wfile.write(json.dumps(following).encode('utf-8'))
 | 
			
		||||
| 
						 | 
				
			
			@ -145,7 +145,7 @@ class PubServer(BaseHTTPRequestHandler):
 | 
			
		|||
            return            
 | 
			
		||||
        followers=getFollowingFeed(self.server.baseDir,self.server.domain, \
 | 
			
		||||
                                   self.server.port,self.path, \
 | 
			
		||||
                                   self.server.https,followsPerPage,'followers')
 | 
			
		||||
                                   self.server.httpPrefix,followsPerPage,'followers')
 | 
			
		||||
        if followers:
 | 
			
		||||
            self._set_headers('application/json')
 | 
			
		||||
            self.wfile.write(json.dumps(followers).encode('utf-8'))
 | 
			
		||||
| 
						 | 
				
			
			@ -305,7 +305,7 @@ class PubServer(BaseHTTPRequestHandler):
 | 
			
		|||
        if self.server.debug:
 | 
			
		||||
            print('DEBUG: POST check signature')
 | 
			
		||||
 | 
			
		||||
        if not verifyPostHeaders(self.server.https, pubKey, self.headers, \
 | 
			
		||||
        if not verifyPostHeaders(self.server.httpPrefix, pubKey, self.headers, \
 | 
			
		||||
                                 '/inbox' ,False, json.dumps(messageJson)):
 | 
			
		||||
            print('**************** POST signature verification failed')
 | 
			
		||||
            self.send_response(401)
 | 
			
		||||
| 
						 | 
				
			
			@ -336,7 +336,7 @@ class PubServer(BaseHTTPRequestHandler):
 | 
			
		|||
        self.end_headers()
 | 
			
		||||
        self.server.POSTbusy=False
 | 
			
		||||
 | 
			
		||||
def runDaemon(domain: str,port=80,https=True,fedList=[],useTor=False,debug=False) -> None:
 | 
			
		||||
def runDaemon(domain: str,port=80,httpPrefix='https',fedList=[],useTor=False,debug=False) -> None:
 | 
			
		||||
    if len(domain)==0:
 | 
			
		||||
        domain='localhost'
 | 
			
		||||
    if '.' not in domain:
 | 
			
		||||
| 
						 | 
				
			
			@ -348,7 +348,7 @@ def runDaemon(domain: str,port=80,https=True,fedList=[],useTor=False,debug=False
 | 
			
		|||
    httpd = ThreadingHTTPServer(serverAddress, PubServer)
 | 
			
		||||
    httpd.domain=domain
 | 
			
		||||
    httpd.port=port
 | 
			
		||||
    httpd.https=https
 | 
			
		||||
    httpd.httpPrefix=httpPrefix
 | 
			
		||||
    httpd.debug=debug
 | 
			
		||||
    httpd.federationList=fedList.copy()
 | 
			
		||||
    httpd.baseDir=os.getcwd()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										13
									
								
								epicyon.py
								
								
								
								
							
							
						
						
									
										13
									
								
								epicyon.py
								
								
								
								
							| 
						 | 
				
			
			@ -67,6 +67,9 @@ parser.add_argument("--debug", type=str2bool, nargs='?',
 | 
			
		|||
parser.add_argument("--http", type=str2bool, nargs='?',
 | 
			
		||||
                        const=True, default=False,
 | 
			
		||||
                        help="Use http only")
 | 
			
		||||
parser.add_argument("--dat", type=str2bool, nargs='?',
 | 
			
		||||
                        const=True, default=False,
 | 
			
		||||
                        help="Use dat protocol only")
 | 
			
		||||
parser.add_argument("--tor", type=str2bool, nargs='?',
 | 
			
		||||
                        const=True, default=False,
 | 
			
		||||
                        help="Route via Tor")
 | 
			
		||||
| 
						 | 
				
			
			@ -110,9 +113,11 @@ if not args.domain:
 | 
			
		|||
nickname='admin'
 | 
			
		||||
domain=args.domain
 | 
			
		||||
port=args.port
 | 
			
		||||
https=True
 | 
			
		||||
httpPrefix='https'
 | 
			
		||||
if args.http:
 | 
			
		||||
    https=False
 | 
			
		||||
    httpPrefix='http'
 | 
			
		||||
if args.dat:
 | 
			
		||||
    httpPrefix='dat'
 | 
			
		||||
useTor=args.tor
 | 
			
		||||
baseDir=args.baseDir
 | 
			
		||||
if baseDir.endswith('/'):
 | 
			
		||||
| 
						 | 
				
			
			@ -126,6 +131,6 @@ if args.federationList:
 | 
			
		|||
 | 
			
		||||
if not os.path.isdir(baseDir+'/accounts/'+nickname+'@'+domain):
 | 
			
		||||
    print('Creating default admin account '+nickname+'@'+domain)
 | 
			
		||||
    privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(baseDir,nickname,domain,port,https,True)
 | 
			
		||||
    privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(baseDir,nickname,domain,port,httpPrefix,True)
 | 
			
		||||
 | 
			
		||||
runDaemon(domain,port,https,federationList,useTor,debug)
 | 
			
		||||
runDaemon(domain,port,httpPrefix,federationList,useTor,debug)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										40
									
								
								follow.py
								
								
								
								
							
							
						
						
									
										40
									
								
								follow.py
								
								
								
								
							| 
						 | 
				
			
			@ -114,7 +114,7 @@ def getNoOfFollowers(baseDir: str,nickname: str,domain: str) -> int:
 | 
			
		|||
    """
 | 
			
		||||
    return getNoOfFollows(baseDir,nickname,domain,'followers.txt')
 | 
			
		||||
 | 
			
		||||
def getFollowingFeed(baseDir: str,domain: str,port: int,path: str,https: bool, \
 | 
			
		||||
def getFollowingFeed(baseDir: str,domain: str,port: int,path: str,httpPrefix: str, \
 | 
			
		||||
                     followsPerPage=12,followFile='following') -> {}:
 | 
			
		||||
    """Returns the following and followers feeds from GET requests
 | 
			
		||||
    """
 | 
			
		||||
| 
						 | 
				
			
			@ -147,18 +147,14 @@ def getFollowingFeed(baseDir: str,domain: str,port: int,path: str,https: bool, \
 | 
			
		|||
    if not validNickname(nickname):
 | 
			
		||||
        return None
 | 
			
		||||
            
 | 
			
		||||
    prefix='https'
 | 
			
		||||
    if not https:
 | 
			
		||||
        prefix='http'
 | 
			
		||||
 | 
			
		||||
    if port!=80 and port!=443:
 | 
			
		||||
        domain=domain+':'+str(port)
 | 
			
		||||
 | 
			
		||||
    if headerOnly:
 | 
			
		||||
        following = {
 | 
			
		||||
            '@context': 'https://www.w3.org/ns/activitystreams',
 | 
			
		||||
            'first': prefix+'://'+domain+'/users/'+nickname+'/'+followFile+'?page=1',
 | 
			
		||||
            'id': prefix+'://'+domain+'/users/'+nickname+'/'+followFile,
 | 
			
		||||
            'first': httpPrefix+'://'+domain+'/users/'+nickname+'/'+followFile+'?page=1',
 | 
			
		||||
            'id': httpPrefix+'://'+domain+'/users/'+nickname+'/'+followFile,
 | 
			
		||||
            'totalItems': getNoOfFollows(nickname,domain),
 | 
			
		||||
            'type': 'OrderedCollection'}
 | 
			
		||||
        return following
 | 
			
		||||
| 
						 | 
				
			
			@ -169,9 +165,9 @@ def getFollowingFeed(baseDir: str,domain: str,port: int,path: str,https: bool, \
 | 
			
		|||
    nextPageNumber=int(pageNumber+1)
 | 
			
		||||
    following = {
 | 
			
		||||
        '@context': 'https://www.w3.org/ns/activitystreams',
 | 
			
		||||
        'id': prefix+'://'+domain+'/users/'+nickname+'/'+followFile+'?page='+str(pageNumber),
 | 
			
		||||
        'id': httpPrefix+'://'+domain+'/users/'+nickname+'/'+followFile+'?page='+str(pageNumber),
 | 
			
		||||
        'orderedItems': [],
 | 
			
		||||
        'partOf': prefix+'://'+domain+'/users/'+nickname+'/'+followFile,
 | 
			
		||||
        'partOf': httpPrefix+'://'+domain+'/users/'+nickname+'/'+followFile,
 | 
			
		||||
        'totalItems': 0,
 | 
			
		||||
        'type': 'OrderedCollectionPage'}        
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -190,10 +186,10 @@ def getFollowingFeed(baseDir: str,domain: str,port: int,path: str,https: bool, \
 | 
			
		|||
                    pageCtr += 1
 | 
			
		||||
                    totalCtr += 1
 | 
			
		||||
                    if currPage==pageNumber:
 | 
			
		||||
                        url = prefix + '://' + line.lower().replace('\n','').split('@')[1] + \
 | 
			
		||||
                        url = httpPrefix + '://' + line.lower().replace('\n','').split('@')[1] + \
 | 
			
		||||
                            '/users/' + line.lower().replace('\n','').split('@')[0]
 | 
			
		||||
                        following['orderedItems'].append(url)
 | 
			
		||||
                elif line.startswith('http') and '/users/' in line:
 | 
			
		||||
                elif (line.startswith('http') or line.startswith('dat')) and '/users/' in line:
 | 
			
		||||
                    pageCtr += 1
 | 
			
		||||
                    totalCtr += 1
 | 
			
		||||
                    if currPage==pageNumber:
 | 
			
		||||
| 
						 | 
				
			
			@ -206,7 +202,7 @@ def getFollowingFeed(baseDir: str,domain: str,port: int,path: str,https: bool, \
 | 
			
		|||
    if lastPage<1:
 | 
			
		||||
        lastPage=1
 | 
			
		||||
    if nextPageNumber>lastPage:
 | 
			
		||||
        following['next']=prefix+'://'+domain+'/users/'+nickname+'/'+followFile+'?page='+str(lastPage)
 | 
			
		||||
        following['next']=httpPrefix+'://'+domain+'/users/'+nickname+'/'+followFile+'?page='+str(lastPage)
 | 
			
		||||
    return following
 | 
			
		||||
 | 
			
		||||
def receiveFollowRequest(baseDir: str,messageJson: {},federationList: []) -> bool:
 | 
			
		||||
| 
						 | 
				
			
			@ -216,7 +212,7 @@ def receiveFollowRequest(baseDir: str,messageJson: {},federationList: []) -> boo
 | 
			
		|||
        return False
 | 
			
		||||
    if '/users/' not in messageJson['actor']:
 | 
			
		||||
        return False
 | 
			
		||||
    domain=messageJson['actor'].split('/users/')[0].replace('https://','').replace('http://','')
 | 
			
		||||
    domain=messageJson['actor'].split('/users/')[0].replace('https://','').replace('http://','').replace('dat://','')
 | 
			
		||||
    if not domainPermitted(domain,federationList):
 | 
			
		||||
        return False
 | 
			
		||||
    nickname=messageJson['actor'].split('/users/')[1].replace('@','')
 | 
			
		||||
| 
						 | 
				
			
			@ -225,7 +221,7 @@ def receiveFollowRequest(baseDir: str,messageJson: {},federationList: []) -> boo
 | 
			
		|||
        return False
 | 
			
		||||
    if '/users/' not in messageJson['object']:
 | 
			
		||||
        return False
 | 
			
		||||
    domainToFollow=messageJson['object'].split('/users/')[0].replace('https://','').replace('http://','')
 | 
			
		||||
    domainToFollow=messageJson['object'].split('/users/')[0].replace('https://','').replace('http://','').replace('dat://','')
 | 
			
		||||
    if not domainPermitted(domainToFollow,federationList):
 | 
			
		||||
        return False
 | 
			
		||||
    nicknameToFollow=messageJson['object'].split('/users/')[1].replace('@','')
 | 
			
		||||
| 
						 | 
				
			
			@ -235,22 +231,14 @@ def receiveFollowRequest(baseDir: str,messageJson: {},federationList: []) -> boo
 | 
			
		|||
            return False
 | 
			
		||||
    return followerOfPerson(baseDir,nickname,domain,nicknameToFollow,domainToFollow,federationList)
 | 
			
		||||
 | 
			
		||||
def sendFollowRequest(baseDir: str,nickname: str,domain: str,port: int,https: bool, \
 | 
			
		||||
                      followNickname: str,followDomain: str,followPort: bool,followHttps: bool, \
 | 
			
		||||
def sendFollowRequest(baseDir: str,nickname: str,domain: str,port: int,httpPrefix: str, \
 | 
			
		||||
                      followNickname: str,followDomain: str,followPort: bool,followHttpPrefix: str, \
 | 
			
		||||
                      federationList: []) -> {}:
 | 
			
		||||
    """Gets the json object for sending a follow request
 | 
			
		||||
    """
 | 
			
		||||
    if not domainPermitted(followDomain,federationList):
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    prefix='https'
 | 
			
		||||
    if not https:
 | 
			
		||||
        prefix='http'
 | 
			
		||||
 | 
			
		||||
    followPrefix='https'
 | 
			
		||||
    if not followHttps:
 | 
			
		||||
        followPrefix='http'
 | 
			
		||||
 | 
			
		||||
    if port!=80 and port!=443:
 | 
			
		||||
        domain=domain+':'+str(port)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -259,8 +247,8 @@ def sendFollowRequest(baseDir: str,nickname: str,domain: str,port: int,https: bo
 | 
			
		|||
 | 
			
		||||
    newFollow = {
 | 
			
		||||
        'type': 'Follow',
 | 
			
		||||
        'actor': prefix+'://'+domain+'/users/'+nickname,
 | 
			
		||||
        'object': followPrefix+'://'+followDomain+'/users/'+followNickname,
 | 
			
		||||
        'actor': httpPrefix+'://'+domain+'/users/'+nickname,
 | 
			
		||||
        'object': followHttpPrefix+'://'+followDomain+'/users/'+followNickname,
 | 
			
		||||
        'to': [toUrl],
 | 
			
		||||
        'cc': []
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										18
									
								
								httpsig.py
								
								
								
								
							
							
						
						
									
										18
									
								
								httpsig.py
								
								
								
								
							| 
						 | 
				
			
			@ -17,18 +17,14 @@ import json
 | 
			
		|||
 | 
			
		||||
def signPostHeaders(privateKeyPem: str, nickname: str, domain: str, \
 | 
			
		||||
                    port: int,path: str, \
 | 
			
		||||
                    https: bool, messageBodyJson: {}) -> str:
 | 
			
		||||
                    httpPrefix: str, messageBodyJson: {}) -> str:
 | 
			
		||||
    """Returns a raw signature string that can be plugged into a header and
 | 
			
		||||
    used to verify the authenticity of an HTTP transmission.
 | 
			
		||||
    """
 | 
			
		||||
    prefix='https'
 | 
			
		||||
    if not https:
 | 
			
		||||
        prefix='http'
 | 
			
		||||
 | 
			
		||||
    if port!=80 and port!=443:
 | 
			
		||||
        domain=domain+':'+str(port)
 | 
			
		||||
 | 
			
		||||
    keyID = prefix+'://'+domain+'/users/'+nickname+'/main-key'
 | 
			
		||||
    keyID = httpPrefix+'://'+domain+'/users/'+nickname+'/main-key'
 | 
			
		||||
    if not messageBodyJson:
 | 
			
		||||
        headers = {'host': domain}
 | 
			
		||||
    else:
 | 
			
		||||
| 
						 | 
				
			
			@ -63,7 +59,7 @@ def signPostHeaders(privateKeyPem: str, nickname: str, domain: str, \
 | 
			
		|||
    return signatureHeader
 | 
			
		||||
 | 
			
		||||
def createSignedHeader(privateKeyPem: str,nickname: str,domain: str,port: int, \
 | 
			
		||||
                       path: str,https: bool,withDigest: bool, \
 | 
			
		||||
                       path: str,httpPrefix: str,withDigest: bool, \
 | 
			
		||||
                       messageBodyJson: {}) -> {}:
 | 
			
		||||
    headerDomain=domain
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -79,12 +75,12 @@ def createSignedHeader(privateKeyPem: str,nickname: str,domain: str,port: int, \
 | 
			
		|||
        headers = {'host': headerDomain, 'digest': f'SHA-256={bodyDigest}'}        
 | 
			
		||||
    path='/inbox'
 | 
			
		||||
    signatureHeader = signPostHeaders(privateKeyPem, nickname, domain, port, \
 | 
			
		||||
                                      path, https, None)
 | 
			
		||||
                                      path, httpPrefix, None)
 | 
			
		||||
    headers['signature'] = signatureHeader
 | 
			
		||||
    headers['Content-type'] = 'application/json'
 | 
			
		||||
    return headers
 | 
			
		||||
 | 
			
		||||
def verifyPostHeaders(https: bool, publicKeyPem: str, headers: dict, \
 | 
			
		||||
def verifyPostHeaders(httpPrefix: str, publicKeyPem: str, headers: dict, \
 | 
			
		||||
                      path: str, GETmethod: bool, \
 | 
			
		||||
                      messageBodyJsonStr: str) -> bool:
 | 
			
		||||
    """Returns true or false depending on if the key that we plugged in here
 | 
			
		||||
| 
						 | 
				
			
			@ -100,10 +96,6 @@ def verifyPostHeaders(https: bool, publicKeyPem: str, headers: dict, \
 | 
			
		|||
    else:
 | 
			
		||||
        method='POST'
 | 
			
		||||
        
 | 
			
		||||
    prefix='https'
 | 
			
		||||
    if not https:
 | 
			
		||||
        prefix='http'
 | 
			
		||||
 | 
			
		||||
    publicKeyPem = RSA.import_key(publicKeyPem)
 | 
			
		||||
    # Build a dictionary of the signature values
 | 
			
		||||
    signatureHeader = headers['signature']
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										18
									
								
								like.py
								
								
								
								
							
							
						
						
									
										18
									
								
								like.py
								
								
								
								
							| 
						 | 
				
			
			@ -11,7 +11,7 @@ import commentjson
 | 
			
		|||
from utils import urlPermitted
 | 
			
		||||
 | 
			
		||||
def like(baseDir: str,federationList: [],nickname: str,domain: str,port: int, \
 | 
			
		||||
         toUrl: str,ccUrl: str,https: bool,objectUrl: str,saveToFile: bool) -> {}:
 | 
			
		||||
         toUrl: str,ccUrl: str,httpPrefix: str,objectUrl: str,saveToFile: bool) -> {}:
 | 
			
		||||
    """Creates a like
 | 
			
		||||
    Typically toUrl will be a followers collection
 | 
			
		||||
    and ccUrl might be a specific person whose post was liked
 | 
			
		||||
| 
						 | 
				
			
			@ -20,16 +20,12 @@ def like(baseDir: str,federationList: [],nickname: str,domain: str,port: int, \
 | 
			
		|||
    if not urlPermitted(objectUrl,federationList):
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    prefix='https'
 | 
			
		||||
    if not https:
 | 
			
		||||
        prefix='http'
 | 
			
		||||
 | 
			
		||||
    if port!=80 and port!=443:
 | 
			
		||||
        domain=domain+':'+str(port)
 | 
			
		||||
 | 
			
		||||
    newLike = {
 | 
			
		||||
        'type': 'Like',
 | 
			
		||||
        'actor': prefix+'://'+domain+'/users/'+nickname,
 | 
			
		||||
        'actor': httpPrefix+'://'+domain+'/users/'+nickname,
 | 
			
		||||
        'object': objectUrl,
 | 
			
		||||
        'to': [toUrl],
 | 
			
		||||
        'cc': []
 | 
			
		||||
| 
						 | 
				
			
			@ -44,19 +40,15 @@ def like(baseDir: str,federationList: [],nickname: str,domain: str,port: int, \
 | 
			
		|||
    return newLike
 | 
			
		||||
 | 
			
		||||
def likePost(baseDir: str,federationList: [], \
 | 
			
		||||
             nickname: str, domain: str, port: int, https: bool, \n
 | 
			
		||||
             nickname: str, domain: str, port: int, httpPrefix: str, \n
 | 
			
		||||
             likeNickname: str, likeDomain: str, likePort: int, likeHttps: bool, \n
 | 
			
		||||
             likeStatusNumber: int,saveToFile: bool) -> {}:
 | 
			
		||||
    """Likes a given status post
 | 
			
		||||
    """
 | 
			
		||||
    prefix='https'
 | 
			
		||||
    if not likeHttps:
 | 
			
		||||
        prefix='http'
 | 
			
		||||
 | 
			
		||||
    likeDomain=likeDomain
 | 
			
		||||
    if likePort!=80 and likePort!=443:
 | 
			
		||||
        likeDomain=likeDomain+':'+str(likePort)
 | 
			
		||||
 | 
			
		||||
    objectUrl = prefix + '://'+likeDomain+'/users/'+likeNickname+'/statuses/'+str(likeStatusNumber)
 | 
			
		||||
    objectUrl = httpPrefix + '://'+likeDomain+'/users/'+likeNickname+'/statuses/'+str(likeStatusNumber)
 | 
			
		||||
 | 
			
		||||
    return like(baseDir,federationList,nickname,domain,port,toUrl,ccUrl,https,objectUrl,saveToFile)
 | 
			
		||||
    return like(baseDir,federationList,nickname,domain,port,toUrl,ccUrl,httpPrefix,objectUrl,saveToFile)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										36
									
								
								person.py
								
								
								
								
							
							
						
						
									
										36
									
								
								person.py
								
								
								
								
							| 
						 | 
				
			
			@ -22,16 +22,12 @@ def generateRSAKey() -> (str,str):
 | 
			
		|||
    return privateKeyPem,publicKeyPem
 | 
			
		||||
 | 
			
		||||
def createPerson(baseDir: str,nickname: str,domain: str,port: int, \
 | 
			
		||||
                 https: bool, saveToFile: bool) -> (str,str,{},{}):
 | 
			
		||||
                 httpPrefix: str, saveToFile: bool) -> (str,str,{},{}):
 | 
			
		||||
    """Returns the private key, public key, actor and webfinger endpoint
 | 
			
		||||
    """
 | 
			
		||||
    prefix='https'
 | 
			
		||||
    if not https:
 | 
			
		||||
        prefix='http'
 | 
			
		||||
 | 
			
		||||
    privateKeyPem,publicKeyPem=generateRSAKey()
 | 
			
		||||
    webfingerEndpoint= \
 | 
			
		||||
        createWebfingerEndpoint(nickname,domain,port,https,publicKeyPem)
 | 
			
		||||
        createWebfingerEndpoint(nickname,domain,port,httpPrefix,publicKeyPem)
 | 
			
		||||
    if saveToFile:
 | 
			
		||||
        storeWebfingerEndpoint(nickname,domain,baseDir,webfingerEndpoint)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -54,29 +50,29 @@ def createPerson(baseDir: str,nickname: str,domain: str,port: int, \
 | 
			
		|||
                               'toot': 'http://joinmastodon.org/ns#',
 | 
			
		||||
                               'value': 'schema:value'}],
 | 
			
		||||
                 'attachment': [],
 | 
			
		||||
                 'endpoints': {'sharedInbox': prefix+'://'+domain+'/inbox'},
 | 
			
		||||
                 'featured': prefix+'://'+domain+'/users/'+nickname+'/collections/featured',
 | 
			
		||||
                 'followers': prefix+'://'+domain+'/users/'+nickname+'/followers',
 | 
			
		||||
                 'following': prefix+'://'+domain+'/users/'+nickname+'/following',
 | 
			
		||||
                 'endpoints': {'sharedInbox': httpPrefix+'://'+domain+'/inbox'},
 | 
			
		||||
                 'featured': httpPrefix+'://'+domain+'/users/'+nickname+'/collections/featured',
 | 
			
		||||
                 'followers': httpPrefix+'://'+domain+'/users/'+nickname+'/followers',
 | 
			
		||||
                 'following': httpPrefix+'://'+domain+'/users/'+nickname+'/following',
 | 
			
		||||
                 'icon': {'mediaType': 'image/png',
 | 
			
		||||
                          'type': 'Image',
 | 
			
		||||
                          'url': prefix+'://'+domain+'/users/'+nickname+'_icon.png'},
 | 
			
		||||
                 'id': prefix+'://'+domain+'/users/'+nickname,
 | 
			
		||||
                          'url': httpPrefix+'://'+domain+'/users/'+nickname+'_icon.png'},
 | 
			
		||||
                 'id': httpPrefix+'://'+domain+'/users/'+nickname,
 | 
			
		||||
                 'image': {'mediaType': 'image/png',
 | 
			
		||||
                           'type': 'Image',
 | 
			
		||||
                           'url': prefix+'://'+domain+'/users/'+nickname+'.png'},
 | 
			
		||||
                 'inbox': prefix+'://'+domain+'/users/'+nickname+'/inbox',
 | 
			
		||||
                           'url': httpPrefix+'://'+domain+'/users/'+nickname+'.png'},
 | 
			
		||||
                 'inbox': httpPrefix+'://'+domain+'/users/'+nickname+'/inbox',
 | 
			
		||||
                 'manuallyApprovesFollowers': False,
 | 
			
		||||
                 'name': nickname,
 | 
			
		||||
                 'outbox': prefix+'://'+domain+'/users/'+nickname+'/outbox',
 | 
			
		||||
                 'outbox': httpPrefix+'://'+domain+'/users/'+nickname+'/outbox',
 | 
			
		||||
                 'preferredUsername': ''+nickname,
 | 
			
		||||
                 'publicKey': {'id': prefix+'://'+domain+'/users/'+nickname+'/main-key',
 | 
			
		||||
                               'owner': prefix+'://'+domain+'/users/'+nickname,
 | 
			
		||||
                 'publicKey': {'id': httpPrefix+'://'+domain+'/users/'+nickname+'/main-key',
 | 
			
		||||
                               'owner': httpPrefix+'://'+domain+'/users/'+nickname,
 | 
			
		||||
                               'publicKeyPem': publicKeyPem,
 | 
			
		||||
                               'summary': '',
 | 
			
		||||
                               'tag': [],
 | 
			
		||||
                               'type': 'Person',
 | 
			
		||||
                               'url': prefix+'://'+domain+'/@'+nickname}
 | 
			
		||||
                               'url': httpPrefix+'://'+domain+'/@'+nickname}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if saveToFile:
 | 
			
		||||
| 
						 | 
				
			
			@ -170,7 +166,7 @@ def personLookup(domain: str,path: str,baseDir: str) -> {}:
 | 
			
		|||
    return personJson
 | 
			
		||||
 | 
			
		||||
def personOutboxJson(baseDir: str,domain: str,port: int,path: str, \
 | 
			
		||||
                     https: bool,noOfItems: int) -> []:
 | 
			
		||||
                     httpPrefix: str,noOfItems: int) -> []:
 | 
			
		||||
    """Obtain the outbox feed for the given person
 | 
			
		||||
    """
 | 
			
		||||
    if not '/outbox' in path:
 | 
			
		||||
| 
						 | 
				
			
			@ -204,7 +200,7 @@ def personOutboxJson(baseDir: str,domain: str,port: int,path: str, \
 | 
			
		|||
        return None
 | 
			
		||||
    if not validNickname(nickname):
 | 
			
		||||
        return None
 | 
			
		||||
    return createOutbox(baseDir,nickname,domain,port,https, \
 | 
			
		||||
    return createOutbox(baseDir,nickname,domain,port,httpPrefix, \
 | 
			
		||||
                        noOfItems,headerOnly,pageNumber)
 | 
			
		||||
 | 
			
		||||
def setPreferredNickname(baseDir: str,nickname: str, domain: str, \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										69
									
								
								posts.py
								
								
								
								
							
							
						
						
									
										69
									
								
								posts.py
								
								
								
								
							| 
						 | 
				
			
			@ -250,15 +250,11 @@ def deleteAllPosts(baseDir: str,nickname: str, domain: str) -> None:
 | 
			
		|||
            print(e)
 | 
			
		||||
            
 | 
			
		||||
def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \
 | 
			
		||||
                   toUrl: str, ccUrl: str, https: bool, content: str, \
 | 
			
		||||
                   toUrl: str, ccUrl: str, httpPrefix: str, content: str, \
 | 
			
		||||
                   followersOnly: bool, saveToFile: bool, clientToServer: bool, \
 | 
			
		||||
                   inReplyTo=None, inReplyToAtomUri=None, subject=None) -> {}:
 | 
			
		||||
    """Creates a message
 | 
			
		||||
    """
 | 
			
		||||
    prefix='https'
 | 
			
		||||
    if not https:
 | 
			
		||||
        prefix='http'
 | 
			
		||||
 | 
			
		||||
    if port!=80 and port!=443:
 | 
			
		||||
        domain=domain+':'+str(port)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -266,11 +262,11 @@ def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \
 | 
			
		|||
    conversationDate=published.split('T')[0]
 | 
			
		||||
    conversationId=statusNumber
 | 
			
		||||
    postTo='https://www.w3.org/ns/activitystreams#Public'
 | 
			
		||||
    postCC=prefix+'://'+domain+'/users/'+nickname+'/followers'
 | 
			
		||||
    postCC=httpPrefix+'://'+domain+'/users/'+nickname+'/followers'
 | 
			
		||||
    if followersOnly:
 | 
			
		||||
        postTo=postCC
 | 
			
		||||
        postCC=''
 | 
			
		||||
    newPostId=prefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber
 | 
			
		||||
    newPostId=httpPrefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber
 | 
			
		||||
    sensitive=False
 | 
			
		||||
    summary=None
 | 
			
		||||
    if subject:
 | 
			
		||||
| 
						 | 
				
			
			@ -280,7 +276,7 @@ def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \
 | 
			
		|||
        newPost = {
 | 
			
		||||
            'id': newPostId+'/activity',
 | 
			
		||||
            'type': 'Create',
 | 
			
		||||
            'actor': prefix+'://'+domain+'/users/'+nickname,
 | 
			
		||||
            'actor': httpPrefix+'://'+domain+'/users/'+nickname,
 | 
			
		||||
            'published': published,
 | 
			
		||||
            'to': [toUrl],
 | 
			
		||||
            'cc': [],
 | 
			
		||||
| 
						 | 
				
			
			@ -290,12 +286,12 @@ def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \
 | 
			
		|||
                'summary': summary,
 | 
			
		||||
                'inReplyTo': inReplyTo,
 | 
			
		||||
                'published': published,
 | 
			
		||||
                'url': prefix+'://'+domain+'/@'+nickname+'/'+statusNumber,
 | 
			
		||||
                'attributedTo': prefix+'://'+domain+'/users/'+nickname,
 | 
			
		||||
                'url': httpPrefix+'://'+domain+'/@'+nickname+'/'+statusNumber,
 | 
			
		||||
                'attributedTo': httpPrefix+'://'+domain+'/users/'+nickname,
 | 
			
		||||
                'to': [toUrl],
 | 
			
		||||
                'cc': [],
 | 
			
		||||
                'sensitive': sensitive,
 | 
			
		||||
                'atomUri': prefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber,
 | 
			
		||||
                'atomUri': httpPrefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber,
 | 
			
		||||
                'inReplyToAtomUri': inReplyToAtomUri,
 | 
			
		||||
                'conversation': 'tag:'+domain+','+conversationDate+':objectId='+conversationId+':objectType=Conversation',
 | 
			
		||||
                'content': content,
 | 
			
		||||
| 
						 | 
				
			
			@ -322,12 +318,12 @@ def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \
 | 
			
		|||
            'summary': summary,
 | 
			
		||||
            'inReplyTo': inReplyTo,
 | 
			
		||||
            'published': published,
 | 
			
		||||
            'url': prefix+'://'+domain+'/@'+nickname+'/'+statusNumber,
 | 
			
		||||
            'attributedTo': prefix+'://'+domain+'/users/'+nickname,
 | 
			
		||||
            'url': httpPrefix+'://'+domain+'/@'+nickname+'/'+statusNumber,
 | 
			
		||||
            'attributedTo': httpPrefix+'://'+domain+'/users/'+nickname,
 | 
			
		||||
            'to': [toUrl],
 | 
			
		||||
            'cc': [],
 | 
			
		||||
            'sensitive': sensitive,
 | 
			
		||||
            'atomUri': prefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber,
 | 
			
		||||
            'atomUri': httpPrefix+'://'+domain+'/users/'+nickname+'/statuses/'+statusNumber,
 | 
			
		||||
            'inReplyToAtomUri': inReplyToAtomUri,
 | 
			
		||||
            'conversation': 'tag:'+domain+','+conversationDate+':objectId='+conversationId+':objectType=Conversation',
 | 
			
		||||
            'content': content,
 | 
			
		||||
| 
						 | 
				
			
			@ -352,19 +348,16 @@ def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \
 | 
			
		|||
    return newPost
 | 
			
		||||
 | 
			
		||||
def createPublicPost(baseDir: str,
 | 
			
		||||
                     nickname: str, domain: str, port: int,https: bool, \
 | 
			
		||||
                     nickname: str, domain: str, port: int,httpPrefix: str, \
 | 
			
		||||
                     content: str, followersOnly: bool, saveToFile: bool,
 | 
			
		||||
                     clientToServer: bool, \
 | 
			
		||||
                     inReplyTo=None, inReplyToAtomUri=None, subject=None) -> {}:
 | 
			
		||||
    """Public post to the outbox
 | 
			
		||||
    """
 | 
			
		||||
    prefix='https'
 | 
			
		||||
    if not https:
 | 
			
		||||
        prefix='http'
 | 
			
		||||
    return createPostBase(baseDir,nickname, domain, port, \
 | 
			
		||||
                          'https://www.w3.org/ns/activitystreams#Public', \
 | 
			
		||||
                          prefix+'://'+domain+'/users/'+nickname+'/followers', \
 | 
			
		||||
                          https, content, followersOnly, saveToFile, clientToServer, \
 | 
			
		||||
                          httpPrefix+'://'+domain+'/users/'+nickname+'/followers', \
 | 
			
		||||
                          httpPrefix, content, followersOnly, saveToFile, clientToServer, \
 | 
			
		||||
                          inReplyTo, inReplyToAtomUri, subject)
 | 
			
		||||
 | 
			
		||||
def threadSendPost(session,postJsonObject: {},federationList: [],inboxUrl: str, \
 | 
			
		||||
| 
						 | 
				
			
			@ -394,25 +387,21 @@ def threadSendPost(session,postJsonObject: {},federationList: [],inboxUrl: str,
 | 
			
		|||
 | 
			
		||||
def sendPost(session,baseDir: str,nickname: str, domain: str, port: int, \
 | 
			
		||||
             toNickname: str, toDomain: str, toPort: int, cc: str, \
 | 
			
		||||
             https: bool, content: str, followersOnly: bool, \
 | 
			
		||||
             httpPrefix: str, content: str, followersOnly: bool, \
 | 
			
		||||
             saveToFile: bool, clientToServer: bool, federationList: [], \
 | 
			
		||||
             sendThreads: [], postLog: [], cachedWebfingers: {},personCache: {}, \
 | 
			
		||||
             inReplyTo=None, inReplyToAtomUri=None, subject=None) -> int:
 | 
			
		||||
    """Post to another inbox
 | 
			
		||||
    """
 | 
			
		||||
    prefix='https'
 | 
			
		||||
    if not https:
 | 
			
		||||
        prefix='http'
 | 
			
		||||
 | 
			
		||||
    withDigest=True
 | 
			
		||||
 | 
			
		||||
    if toPort!=80 and toPort!=443:
 | 
			
		||||
        toDomain=toDomain+':'+str(toPort)        
 | 
			
		||||
 | 
			
		||||
    handle=prefix+'://'+toDomain+'/@'+toNickname
 | 
			
		||||
    handle=httpPrefix+'://'+toDomain+'/@'+toNickname
 | 
			
		||||
 | 
			
		||||
    # lookup the inbox for the To handle
 | 
			
		||||
    wfRequest = webfingerHandle(session,handle,https,cachedWebfingers)
 | 
			
		||||
    wfRequest = webfingerHandle(session,handle,httpPrefix,cachedWebfingers)
 | 
			
		||||
    if not wfRequest:
 | 
			
		||||
        return 1
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -428,7 +417,7 @@ def sendPost(session,baseDir: str,nickname: str, domain: str, port: int, \
 | 
			
		|||
 | 
			
		||||
    postJsonObject = \
 | 
			
		||||
            createPostBase(baseDir,nickname,domain,port, \
 | 
			
		||||
                           toPersonId,cc,https,content, \
 | 
			
		||||
                           toPersonId,cc,httpPrefix,content, \
 | 
			
		||||
                           followersOnly,saveToFile,clientToServer, \
 | 
			
		||||
                           inReplyTo,inReplyToAtomUri, \
 | 
			
		||||
                           subject)
 | 
			
		||||
| 
						 | 
				
			
			@ -446,7 +435,7 @@ def sendPost(session,baseDir: str,nickname: str, domain: str, port: int, \
 | 
			
		|||
    # construct the http header
 | 
			
		||||
    signatureHeaderJson = \
 | 
			
		||||
        createSignedHeader(privateKeyPem, nickname, domain, port, \
 | 
			
		||||
                           postPath, https, withDigest, postJsonObject)
 | 
			
		||||
                           postPath, httpPrefix, withDigest, postJsonObject)
 | 
			
		||||
 | 
			
		||||
    # Keep the number of threads being used small
 | 
			
		||||
    while len(sendThreads)>10:
 | 
			
		||||
| 
						 | 
				
			
			@ -462,14 +451,10 @@ def sendPost(session,baseDir: str,nickname: str, domain: str, port: int, \
 | 
			
		|||
    thr.start()
 | 
			
		||||
    return 0
 | 
			
		||||
 | 
			
		||||
def createOutbox(baseDir: str,nickname: str,domain: str,port: int,https: bool, \
 | 
			
		||||
def createOutbox(baseDir: str,nickname: str,domain: str,port: int,httpPrefix: str, \
 | 
			
		||||
                 itemsPerPage: int,headerOnly: bool,pageNumber=None) -> {}:
 | 
			
		||||
    """Constructs the outbox feed
 | 
			
		||||
    """
 | 
			
		||||
    prefix='https'
 | 
			
		||||
    if not https:
 | 
			
		||||
        prefix='http'
 | 
			
		||||
 | 
			
		||||
    outboxDir = createOutboxDir(nickname,domain,baseDir)
 | 
			
		||||
 | 
			
		||||
    if port!=80 and port!=443:
 | 
			
		||||
| 
						 | 
				
			
			@ -482,16 +467,16 @@ def createOutbox(baseDir: str,nickname: str,domain: str,port: int,https: bool, \
 | 
			
		|||
        except:
 | 
			
		||||
            pass
 | 
			
		||||
    outboxHeader = {'@context': 'https://www.w3.org/ns/activitystreams',
 | 
			
		||||
                    'first': prefix+'://'+domain+'/users/'+nickname+'/outbox?page=true',
 | 
			
		||||
                    'id': prefix+'://'+domain+'/users/'+nickname+'/outbox',
 | 
			
		||||
                    'last': prefix+'://'+domain+'/users/'+nickname+'/outbox?page=true',
 | 
			
		||||
                    'first': httpPrefix+'://'+domain+'/users/'+nickname+'/outbox?page=true',
 | 
			
		||||
                    'id': httpPrefix+'://'+domain+'/users/'+nickname+'/outbox',
 | 
			
		||||
                    'last': httpPrefix+'://'+domain+'/users/'+nickname+'/outbox?page=true',
 | 
			
		||||
                    'totalItems': 0,
 | 
			
		||||
                    'type': 'OrderedCollection'}
 | 
			
		||||
    outboxItems = {'@context': 'https://www.w3.org/ns/activitystreams',
 | 
			
		||||
                   'id': prefix+'://'+domain+'/users/'+nickname+'/outbox'+pageStr,
 | 
			
		||||
                   'id': httpPrefix+'://'+domain+'/users/'+nickname+'/outbox'+pageStr,
 | 
			
		||||
                   'orderedItems': [
 | 
			
		||||
                   ],
 | 
			
		||||
                   'partOf': prefix+'://'+domain+'/users/'+nickname+'/outbox',
 | 
			
		||||
                   'partOf': httpPrefix+'://'+domain+'/users/'+nickname+'/outbox',
 | 
			
		||||
                   'type': 'OrderedCollectionPage'}
 | 
			
		||||
 | 
			
		||||
    # counter for posts loop
 | 
			
		||||
| 
						 | 
				
			
			@ -513,7 +498,7 @@ def createOutbox(baseDir: str,nickname: str,domain: str,port: int,https: bool, \
 | 
			
		|||
        if lastPage<1:
 | 
			
		||||
            lastPage=1
 | 
			
		||||
        outboxHeader['last']= \
 | 
			
		||||
            prefix+'://'+domain+'/users/'+nickname+'/outbox?page='+str(lastPage)
 | 
			
		||||
            httpPrefix+'://'+domain+'/users/'+nickname+'/outbox?page='+str(lastPage)
 | 
			
		||||
 | 
			
		||||
    # Insert posts
 | 
			
		||||
    currPage=1
 | 
			
		||||
| 
						 | 
				
			
			@ -524,7 +509,7 @@ def createOutbox(baseDir: str,nickname: str,domain: str,port: int,https: bool, \
 | 
			
		|||
            # update the prev entry for the last message id
 | 
			
		||||
            postId = prevPostFilename.split('#statuses#')[1].replace('#activity','')
 | 
			
		||||
            outboxHeader['prev']= \
 | 
			
		||||
                prefix+'://'+domain+'/users/'+nickname+'/outbox?min_id='+postId+'&page=true'
 | 
			
		||||
                httpPrefix+'://'+domain+'/users/'+nickname+'/outbox?min_id='+postId+'&page=true'
 | 
			
		||||
        # get the full path of the post file
 | 
			
		||||
        filePath = os.path.join(outboxDir, postFilename)
 | 
			
		||||
        try:
 | 
			
		||||
| 
						 | 
				
			
			@ -542,7 +527,7 @@ def createOutbox(baseDir: str,nickname: str,domain: str,port: int,https: bool, \
 | 
			
		|||
                            if '/statuses/' in p['id']:
 | 
			
		||||
                                postId = p['id'].split('/statuses/')[1].replace('/activity','')
 | 
			
		||||
                                outboxHeader['next']= \
 | 
			
		||||
                                    prefix+'://'+domain+'/users/'+ \
 | 
			
		||||
                                    httpPrefix+'://'+domain+'/users/'+ \
 | 
			
		||||
                                    nickname+'/outbox?max_id='+ \
 | 
			
		||||
                                    postId+'&page=true'
 | 
			
		||||
                        postsOnPageCtr += 1
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										52
									
								
								tests.py
								
								
								
								
							
							
						
						
									
										52
									
								
								tests.py
								
								
								
								
							| 
						 | 
				
			
			@ -43,10 +43,10 @@ def testHttpsigBase(withDigest):
 | 
			
		|||
    print('testHttpsig(' + str(withDigest) + ')')
 | 
			
		||||
    nickname='socrates'
 | 
			
		||||
    domain='argumentative.social'
 | 
			
		||||
    https=True
 | 
			
		||||
    httpPrefix='https'
 | 
			
		||||
    port=5576
 | 
			
		||||
    baseDir=os.getcwd()
 | 
			
		||||
    privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(baseDir,nickname,domain,port,https,False)
 | 
			
		||||
    privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(baseDir,nickname,domain,port,httpPrefix,False)
 | 
			
		||||
    messageBodyJsonStr = '{"a key": "a value", "another key": "A string"}'
 | 
			
		||||
 | 
			
		||||
    headersDomain=domain
 | 
			
		||||
| 
						 | 
				
			
			@ -60,11 +60,11 @@ def testHttpsigBase(withDigest):
 | 
			
		|||
        headers = {'host': headersDomain, 'digest': f'SHA-256={bodyDigest}'}
 | 
			
		||||
 | 
			
		||||
    path='/inbox'
 | 
			
		||||
    signatureHeader = signPostHeaders(privateKeyPem, nickname, domain, port, path, https, None)
 | 
			
		||||
    signatureHeader = signPostHeaders(privateKeyPem, nickname, domain, port, path, httpPrefix, None)
 | 
			
		||||
    headers['signature'] = signatureHeader
 | 
			
		||||
    assert verifyPostHeaders(https, publicKeyPem, headers, '/inbox' ,False, messageBodyJsonStr)
 | 
			
		||||
    assert verifyPostHeaders(https, publicKeyPem, headers, '/parambulator/inbox', False , messageBodyJsonStr) == False
 | 
			
		||||
    assert verifyPostHeaders(https, publicKeyPem, headers, '/inbox', True, messageBodyJsonStr) == False
 | 
			
		||||
    assert verifyPostHeaders(httpPrefix, publicKeyPem, headers, '/inbox' ,False, messageBodyJsonStr)
 | 
			
		||||
    assert verifyPostHeaders(httpPrefix, publicKeyPem, headers, '/parambulator/inbox', False , messageBodyJsonStr) == False
 | 
			
		||||
    assert verifyPostHeaders(httpPrefix, publicKeyPem, headers, '/inbox', True, messageBodyJsonStr) == False
 | 
			
		||||
    if not withDigest:
 | 
			
		||||
        # fake domain
 | 
			
		||||
        headers = {'host': 'bogon.domain'}
 | 
			
		||||
| 
						 | 
				
			
			@ -74,7 +74,7 @@ def testHttpsigBase(withDigest):
 | 
			
		|||
        bodyDigest = base64.b64encode(SHA256.new(messageBodyJsonStr.encode()).digest())
 | 
			
		||||
        headers = {'host': domain, 'digest': f'SHA-256={bodyDigest}'}        
 | 
			
		||||
    headers['signature'] = signatureHeader
 | 
			
		||||
    assert verifyPostHeaders(https, publicKeyPem, headers, '/inbox', True, messageBodyJsonStr) == False
 | 
			
		||||
    assert verifyPostHeaders(httpPrefix, publicKeyPem, headers, '/inbox', True, messageBodyJsonStr) == False
 | 
			
		||||
 | 
			
		||||
def testHttpsig():
 | 
			
		||||
    testHttpsigBase(False)
 | 
			
		||||
| 
						 | 
				
			
			@ -111,20 +111,20 @@ def createServerAlice(path: str,domain: str,port: int,federationList: []):
 | 
			
		|||
    os.mkdir(path)
 | 
			
		||||
    os.chdir(path)
 | 
			
		||||
    nickname='alice'
 | 
			
		||||
    https=False
 | 
			
		||||
    httpPrefix=False
 | 
			
		||||
    useTor=False
 | 
			
		||||
    clientToServer=False
 | 
			
		||||
    privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(path,nickname,domain,port,https,True)
 | 
			
		||||
    privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(path,nickname,domain,port,httpPrefix,True)
 | 
			
		||||
    deleteAllPosts(path,nickname,domain)
 | 
			
		||||
    followPerson(path,nickname,domain,'bob','127.0.0.100:61936',federationList)
 | 
			
		||||
    followerOfPerson(path,nickname,domain,'bob','127.0.0.100:61936',federationList)
 | 
			
		||||
    createPublicPost(path,nickname, domain, port,https, "No wise fish would go anywhere without a porpoise", False, True, clientToServer)
 | 
			
		||||
    createPublicPost(path,nickname, domain, port,https, "Curiouser and curiouser!", False, True, clientToServer)
 | 
			
		||||
    createPublicPost(path,nickname, domain, port,https, "In the gardens of memory, in the palace of dreams, that is where you and I shall meet", False, True, clientToServer)
 | 
			
		||||
    createPublicPost(path,nickname, domain, port,httpPrefix, "No wise fish would go anywhere without a porpoise", False, True, clientToServer)
 | 
			
		||||
    createPublicPost(path,nickname, domain, port,httpPrefix, "Curiouser and curiouser!", False, True, clientToServer)
 | 
			
		||||
    createPublicPost(path,nickname, domain, port,httpPrefix, "In the gardens of memory, in the palace of dreams, that is where you and I shall meet", False, True, clientToServer)
 | 
			
		||||
    global testServerAliceRunning
 | 
			
		||||
    testServerAliceRunning = True
 | 
			
		||||
    print('Server running: Alice')
 | 
			
		||||
    runDaemon(domain,port,https,federationList,useTor,True)
 | 
			
		||||
    runDaemon(domain,port,httpPrefix,federationList,useTor,True)
 | 
			
		||||
 | 
			
		||||
def createServerBob(path: str,domain: str,port: int,federationList: []):
 | 
			
		||||
    print('Creating test server: Bob on port '+str(port))
 | 
			
		||||
| 
						 | 
				
			
			@ -133,20 +133,20 @@ def createServerBob(path: str,domain: str,port: int,federationList: []):
 | 
			
		|||
    os.mkdir(path)
 | 
			
		||||
    os.chdir(path)
 | 
			
		||||
    nickname='bob'
 | 
			
		||||
    https=False
 | 
			
		||||
    httpPrefix='http'
 | 
			
		||||
    useTor=False
 | 
			
		||||
    clientToServer=False
 | 
			
		||||
    privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(path,nickname,domain,port,https,True)
 | 
			
		||||
    privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(path,nickname,domain,port,httpPrefix,True)
 | 
			
		||||
    deleteAllPosts(path,nickname,domain)
 | 
			
		||||
    followPerson(path,nickname,domain,'alice','127.0.0.50:61935',federationList)
 | 
			
		||||
    followerOfPerson(path,nickname,domain,'alice','127.0.0.50:61935',federationList)
 | 
			
		||||
    createPublicPost(path,nickname, domain, port,https, "It's your life, live it your way.", False, True, clientToServer)
 | 
			
		||||
    createPublicPost(path,nickname, domain, port,https, "One of the things I've realised is that I am very simple", False, True, clientToServer)
 | 
			
		||||
    createPublicPost(path,nickname, domain, port,https, "Quantum physics is a bit of a passion of mine", False, True, clientToServer)
 | 
			
		||||
    createPublicPost(path,nickname, domain, port,httpPrefix, "It's your life, live it your way.", False, True, clientToServer)
 | 
			
		||||
    createPublicPost(path,nickname, domain, port,httpPrefix, "One of the things I've realised is that I am very simple", False, True, clientToServer)
 | 
			
		||||
    createPublicPost(path,nickname, domain, port,httpPrefix, "Quantum physics is a bit of a passion of mine", False, True, clientToServer)
 | 
			
		||||
    global testServerBobRunning
 | 
			
		||||
    testServerBobRunning = True
 | 
			
		||||
    print('Server running: Bob')
 | 
			
		||||
    runDaemon(domain,port,https,federationList,useTor,True)
 | 
			
		||||
    runDaemon(domain,port,httpPrefix,federationList,useTor,True)
 | 
			
		||||
 | 
			
		||||
def testPostMessageBetweenServers():
 | 
			
		||||
    print('Testing sending message from one server to the inbox of another')
 | 
			
		||||
| 
						 | 
				
			
			@ -156,7 +156,7 @@ def testPostMessageBetweenServers():
 | 
			
		|||
    testServerAliceRunning = False
 | 
			
		||||
    testServerBobRunning = False
 | 
			
		||||
 | 
			
		||||
    https=False
 | 
			
		||||
    httpPrefix='http'
 | 
			
		||||
    useTor=False
 | 
			
		||||
    federationList=['127.0.0.50','127.0.0.100']
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -200,7 +200,7 @@ def testPostMessageBetweenServers():
 | 
			
		|||
    ccUrl=None
 | 
			
		||||
    alicePersonCache={}
 | 
			
		||||
    aliceCachedWebfingers={}
 | 
			
		||||
    sendResult = sendPost(sessionAlice,aliceDir,'alice', aliceDomain, alicePort, 'bob', bobDomain, bobPort, ccUrl, https, 'Why is a mouse when it spins?', followersOnly, saveToFile, clientToServer, federationList, aliceSendThreads, alicePostLog, aliceCachedWebfingers,alicePersonCache,inReplyTo, inReplyToAtomUri, subject)
 | 
			
		||||
    sendResult = sendPost(sessionAlice,aliceDir,'alice', aliceDomain, alicePort, 'bob', bobDomain, bobPort, ccUrl, httpPrefix, 'Why is a mouse when it spins?', followersOnly, saveToFile, clientToServer, federationList, aliceSendThreads, alicePostLog, aliceCachedWebfingers,alicePersonCache,inReplyTo, inReplyToAtomUri, subject)
 | 
			
		||||
    print('sendResult: '+str(sendResult))
 | 
			
		||||
 | 
			
		||||
    for i in range(10):
 | 
			
		||||
| 
						 | 
				
			
			@ -221,14 +221,14 @@ def testFollows():
 | 
			
		|||
    nickname='test529'
 | 
			
		||||
    domain='testdomain.com'
 | 
			
		||||
    port=80
 | 
			
		||||
    https=True
 | 
			
		||||
    httpPrefix='https'
 | 
			
		||||
    federationList=['wild.com','mesh.com']
 | 
			
		||||
    baseDir=currDir+'/.tests_testfollows'
 | 
			
		||||
    if os.path.isdir(baseDir):
 | 
			
		||||
        shutil.rmtree(baseDir)
 | 
			
		||||
    os.mkdir(baseDir)
 | 
			
		||||
    os.chdir(baseDir)
 | 
			
		||||
    createPerson(baseDir,nickname,domain,port,https,True)
 | 
			
		||||
    createPerson(baseDir,nickname,domain,port,httpPrefix,True)
 | 
			
		||||
 | 
			
		||||
    clearFollows(baseDir,nickname,domain)
 | 
			
		||||
    followPerson(baseDir,nickname,domain,'badger','wild.com',federationList)
 | 
			
		||||
| 
						 | 
				
			
			@ -280,7 +280,7 @@ def testCreatePerson():
 | 
			
		|||
    nickname='test382'
 | 
			
		||||
    domain='badgerdomain.com'
 | 
			
		||||
    port=80
 | 
			
		||||
    https=True
 | 
			
		||||
    httpPrefix='https'
 | 
			
		||||
    clientToServer=False
 | 
			
		||||
    baseDir=currDir+'/.tests_createperson'
 | 
			
		||||
    if os.path.isdir(baseDir):
 | 
			
		||||
| 
						 | 
				
			
			@ -288,12 +288,12 @@ def testCreatePerson():
 | 
			
		|||
    os.mkdir(baseDir)
 | 
			
		||||
    os.chdir(baseDir)
 | 
			
		||||
    
 | 
			
		||||
    privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(baseDir,nickname,domain,port,https,True)
 | 
			
		||||
    privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(baseDir,nickname,domain,port,httpPrefix,True)
 | 
			
		||||
    deleteAllPosts(baseDir,nickname,domain)
 | 
			
		||||
    setPreferredNickname(baseDir,nickname,domain,'badger')
 | 
			
		||||
    setBio(baseDir,nickname,domain,'Randomly roaming in your backyard')
 | 
			
		||||
    archivePosts(nickname,domain,baseDir,4)
 | 
			
		||||
    createPublicPost(baseDir,nickname, domain, port,https, "G'day world!", False, True, clientToServer, None, None, 'Not suitable for Vogons')
 | 
			
		||||
    createPublicPost(baseDir,nickname, domain, port,httpPrefix, "G'day world!", False, True, clientToServer, None, None, 'Not suitable for Vogons')
 | 
			
		||||
 | 
			
		||||
    os.chdir(currDir)
 | 
			
		||||
    shutil.rmtree(baseDir)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										31
									
								
								webfinger.py
								
								
								
								
							
							
						
						
									
										31
									
								
								webfinger.py
								
								
								
								
							| 
						 | 
				
			
			@ -22,11 +22,11 @@ def parseHandle(handle: str) -> (str,str):
 | 
			
		|||
        return None, None
 | 
			
		||||
    if '/@' in handle:
 | 
			
		||||
        domain, nickname = \
 | 
			
		||||
            handle.replace('https://','').replace('http://','').split('/@')
 | 
			
		||||
            handle.replace('https://','').replace('http://','').replace('dat://','').split('/@')
 | 
			
		||||
    else:
 | 
			
		||||
        if '/users/' in handle:
 | 
			
		||||
            domain, nickname = \
 | 
			
		||||
                handle.replace('https://','').replace('http://','').split('/users/')
 | 
			
		||||
                handle.replace('https://','').replace('http://','').replace('dat://','').split('/users/')
 | 
			
		||||
        else:
 | 
			
		||||
            if '@' in handle:
 | 
			
		||||
                nickname, domain = handle.split('@')
 | 
			
		||||
| 
						 | 
				
			
			@ -36,7 +36,7 @@ def parseHandle(handle: str) -> (str,str):
 | 
			
		|||
    return nickname, domain
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def webfingerHandle(session,handle: str,https: bool,cachedWebfingers: {}) -> {}:
 | 
			
		||||
def webfingerHandle(session,handle: str,httpPrefix: str,cachedWebfingers: {}) -> {}:
 | 
			
		||||
    nickname, domain = parseHandle(handle)
 | 
			
		||||
    if not nickname:
 | 
			
		||||
        return None
 | 
			
		||||
| 
						 | 
				
			
			@ -47,10 +47,7 @@ def webfingerHandle(session,handle: str,https: bool,cachedWebfingers: {}) -> {}:
 | 
			
		|||
    wf=getWebfingerFromCache(nickname+'@'+wfDomain,cachedWebfingers)
 | 
			
		||||
    if wf:
 | 
			
		||||
        return wf
 | 
			
		||||
    prefix='https'
 | 
			
		||||
    if not https:
 | 
			
		||||
        prefix='http'
 | 
			
		||||
    url = '{}://{}/.well-known/webfinger'.format(prefix,domain)
 | 
			
		||||
    url = '{}://{}/.well-known/webfinger'.format(httpPrefix,domain)
 | 
			
		||||
    par = {'resource': 'acct:{}'.format(nickname+'@'+wfDomain)}
 | 
			
		||||
    hdr = {'Accept': 'application/jrd+json'}
 | 
			
		||||
    #try:
 | 
			
		||||
| 
						 | 
				
			
			@ -83,39 +80,35 @@ def storeWebfingerEndpoint(nickname: str,domain: str,baseDir: str, \
 | 
			
		|||
    return True
 | 
			
		||||
 | 
			
		||||
def createWebfingerEndpoint(nickname: str,domain: str,port: int, \
 | 
			
		||||
                            https: bool,publicKeyPem) -> {}:
 | 
			
		||||
                            httpPrefix: str,publicKeyPem) -> {}:
 | 
			
		||||
    """Creates a webfinger endpoint for a user
 | 
			
		||||
    """
 | 
			
		||||
    prefix='https'
 | 
			
		||||
    if not https:
 | 
			
		||||
        prefix='http'
 | 
			
		||||
        
 | 
			
		||||
    if port!=80 and port!=443:
 | 
			
		||||
        domain=domain+':'+str(port)
 | 
			
		||||
 | 
			
		||||
    account = {
 | 
			
		||||
        "aliases": [
 | 
			
		||||
            prefix+"://"+domain+"/@"+nickname,
 | 
			
		||||
            prefix+"://"+domain+"/users/"+nickname
 | 
			
		||||
            httpPrefix+"://"+domain+"/@"+nickname,
 | 
			
		||||
            httpPrefix+"://"+domain+"/users/"+nickname
 | 
			
		||||
        ],
 | 
			
		||||
        "links": [
 | 
			
		||||
            {
 | 
			
		||||
                "href": prefix+"://"+domain+"/@"+nickname,
 | 
			
		||||
                "href": httpPrefix+"://"+domain+"/@"+nickname,
 | 
			
		||||
                "rel": "http://webfinger.net/rel/profile-page",
 | 
			
		||||
                "type": "text/html"
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "href": prefix+"://"+domain+"/users/"+nickname+".atom",
 | 
			
		||||
                "href": httpPrefix+"://"+domain+"/users/"+nickname+".atom",
 | 
			
		||||
                "rel": "http://schemas.google.com/g/2010#updates-from",
 | 
			
		||||
                "type": "application/atom+xml"
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "href": prefix+"://"+domain+"/users/"+nickname,
 | 
			
		||||
                "href": httpPrefix+"://"+domain+"/users/"+nickname,
 | 
			
		||||
                "rel": "self",
 | 
			
		||||
                "type": "application/activity+json"
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "href": prefix+"://"+domain+"/api/salmon/1",
 | 
			
		||||
                "href": httpPrefix+"://"+domain+"/api/salmon/1",
 | 
			
		||||
                "rel": "salmon"
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
| 
						 | 
				
			
			@ -124,7 +117,7 @@ def createWebfingerEndpoint(nickname: str,domain: str,port: int, \
 | 
			
		|||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "rel": "http://ostatus.org/schema/1.0/subscribe",
 | 
			
		||||
                "template": prefix+"://"+domain+"/authorize_interaction?uri={uri}"
 | 
			
		||||
                "template": httpPrefix+"://"+domain+"/authorize_interaction?uri={uri}"
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "subject": "acct:"+nickname+"@"+domain
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue