Parameter types

master
Bob Mottram 2019-07-01 12:09:09 +01:00
parent 888e4831f2
commit d160c060c9
10 changed files with 32 additions and 32 deletions

View File

@ -16,7 +16,7 @@ personCache = {}
# cached webfinger endpoints # cached webfinger endpoints
cachedWebfingers = {} cachedWebfingers = {}
def storePersonInCache(personUrl: str,personJson) -> None: def storePersonInCache(personUrl: str,personJson: {}) -> None:
"""Store an actor in the cache """Store an actor in the cache
""" """
currTime=datetime.datetime.utcnow() currTime=datetime.datetime.utcnow()
@ -27,7 +27,7 @@ def storeWebfingerInCache(handle: str,wf) -> None:
""" """
cachedWebfingers[handle]=wf cachedWebfingers[handle]=wf
def getPersonFromCache(personUrl: str): def getPersonFromCache(personUrl: str) -> {}:
"""Get an actor from the cache """Get an actor from the cache
""" """
if personCache.get(personUrl): if personCache.get(personUrl):
@ -40,7 +40,7 @@ def getPersonFromCache(personUrl: str):
return personCache[personUrl]['actor'] return personCache[personUrl]['actor']
return None return None
def getWebfingerFromCache(handle: str): def getWebfingerFromCache(handle: str) -> {}:
"""Get webfinger endpoint from the cache """Get webfinger endpoint from the cache
""" """
if cachedWebfingers.get(handle): if cachedWebfingers.get(handle):

View File

@ -87,7 +87,7 @@ testPostMessageBetweenServers()
#runDaemon(domain,port,https,federationList,useTor) #runDaemon(domain,port,https,federationList,useTor)
#testHttpsig() #testHttpsig()
#sys.exit() sys.exit()
#pprint(person) #pprint(person)
#print('\n') #print('\n')

View File

@ -12,7 +12,7 @@ import os
import sys import sys
from person import validUsername from person import validUsername
def followPerson(baseDir: str,username: str, domain: str, followUsername: str, followDomain: str, federationList, followFile='following.txt') -> bool: def followPerson(baseDir: str,username: str, domain: str, followUsername: str, followDomain: str, federationList: [], followFile='following.txt') -> bool:
"""Adds a person to the follow list """Adds a person to the follow list
""" """
if followDomain.lower().replace('\n','') not in federationList: if followDomain.lower().replace('\n','') not in federationList:
@ -32,7 +32,7 @@ def followPerson(baseDir: str,username: str, domain: str, followUsername: str, f
followfile.write(handleToFollow+'\n') followfile.write(handleToFollow+'\n')
return True return True
def followerOfPerson(baseDir: str,username: str, domain: str, followerUsername: str, followerDomain: str, federationList) -> bool: def followerOfPerson(baseDir: str,username: str, domain: str, followerUsername: str, followerDomain: str, federationList: []) -> bool:
"""Adds a follower of the given person """Adds a follower of the given person
""" """
return followPerson(baseDir,username, domain, followerUsername, followerDomain, federationList, 'followers.txt') return followPerson(baseDir,username, domain, followerUsername, followerDomain, federationList, 'followers.txt')

View File

@ -15,7 +15,7 @@ from requests.auth import AuthBase
import base64 import base64
import json import json
def signPostHeaders(privateKeyPem: str, username: str, domain: str, port: int,path: str, https: bool, messageBodyJson) -> str: def signPostHeaders(privateKeyPem: str, username: str, domain: str, port: int,path: str, https: bool, messageBodyJson: {}) -> str:
"""Returns a raw signature string that can be plugged into a header and """Returns a raw signature string that can be plugged into a header and
used to verify the authenticity of an HTTP transmission. used to verify the authenticity of an HTTP transmission.
""" """
@ -59,7 +59,7 @@ def signPostHeaders(privateKeyPem: str, username: str, domain: str, port: int,pa
[f'{k}="{v}"' for k, v in signatureDict.items()]) [f'{k}="{v}"' for k, v in signatureDict.items()])
return signatureHeader return signatureHeader
def createSignedHeader(privateKeyPem: str,username: str,domain: str,port: int,path: str,https: bool,withDigest: bool,messageBodyJson) -> {}: def createSignedHeader(privateKeyPem: str,username: str,domain: str,port: int,path: str,https: bool,withDigest: bool,messageBodyJson: {}) -> {}:
headerDomain=domain headerDomain=domain
if port!=80 and port!=443: if port!=80 and port!=443:
@ -74,6 +74,7 @@ def createSignedHeader(privateKeyPem: str,username: str,domain: str,port: int,pa
path='/inbox' path='/inbox'
signatureHeader = signPostHeaders(privateKeyPem, username, domain, port, path, https, None) signatureHeader = signPostHeaders(privateKeyPem, username, domain, port, path, https, None)
headers['signature'] = signatureHeader headers['signature'] = signatureHeader
headers['Content-type'] = 'application/json'
return headers return headers
def verifyPostHeaders(https: bool, publicKeyPem: str, headers: dict, path: str, GETmethod: bool, messageBodyJsonStr: str) -> bool: def verifyPostHeaders(https: bool, publicKeyPem: str, headers: dict, path: str, GETmethod: bool, messageBodyJsonStr: str) -> bool:

View File

@ -10,7 +10,7 @@ import json
import os import os
import datetime import datetime
def inboxPermittedMessage(messageJson,federationList) -> bool: def inboxPermittedMessage(messageJson: {},federationList: []) -> bool:
""" check that we are receiving from a permitted domain """ check that we are receiving from a permitted domain
""" """
testParam='actor' testParam='actor'
@ -42,7 +42,7 @@ def inboxPermittedMessage(messageJson,federationList) -> bool:
return True return True
def receivePublicMessage(message) -> bool: def receivePublicMessage(message: {}) -> bool:
print("TODO") print("TODO")
def validPublishedDate(published): def validPublishedDate(published):
@ -53,7 +53,7 @@ def validPublishedDate(published):
return False return False
return True return True
def receiveMessage(message,baseDir: str): def receiveMessage(message: {},baseDir: str):
if not message.get('type'): if not message.get('type'):
return return
if message['type']!='Create': if message['type']!='Create':

View File

@ -106,7 +106,7 @@ def createPerson(baseDir: str,username: str,domain: str,port: int,https: bool, s
return privateKeyPem,publicKeyPem,newPerson,webfingerEndpoint return privateKeyPem,publicKeyPem,newPerson,webfingerEndpoint
def validUsername(username): def validUsername(username: str) -> bool:
forbiddenChars=['.',' ','/','?',':',';','@'] forbiddenChars=['.',' ','/','?',':',';','@']
for c in forbiddenChars: for c in forbiddenChars:
if c in username: if c in username:

View File

@ -44,7 +44,7 @@ def getPersonKey(username: str,domain: str,baseDir: str,keyType='public'):
return '' return ''
return keyPem return keyPem
def permitted(url: str,federationList) -> bool: def permitted(url: str,federationList: []) -> bool:
"""Is a url from one of the permitted domains? """Is a url from one of the permitted domains?
""" """
for domain in federationList: for domain in federationList:
@ -64,7 +64,7 @@ def getUserUrl(wfRequest) -> str:
return link['href'] return link['href']
return None return None
def parseUserFeed(session,feedUrl,asHeader) -> None: def parseUserFeed(session,feedUrl: str,asHeader: {}) -> None:
feedJson = getJson(session,feedUrl,asHeader,None) feedJson = getJson(session,feedUrl,asHeader,None)
pprint(feedJson) pprint(feedJson)
@ -90,7 +90,6 @@ def getPersonBox(session,wfRequest,boxName='inbox') -> (str,str,str,str):
personJson = getPersonFromCache(personUrl) personJson = getPersonFromCache(personUrl)
if not personJson: if not personJson:
personJson = getJson(session,personUrl,asHeader,None) personJson = getJson(session,personUrl,asHeader,None)
pprint(personJson)
if not personJson.get(boxName): if not personJson.get(boxName):
return personPosts return personPosts
personId=None personId=None
@ -108,7 +107,7 @@ def getPersonBox(session,wfRequest,boxName='inbox') -> (str,str,str,str):
return personJson[boxName],pubKeyId,pubKey,personId return personJson[boxName],pubKeyId,pubKey,personId
def getUserPosts(session,wfRequest,maxPosts,maxMentions,maxEmoji,maxAttachments,federationList) -> {}: def getUserPosts(session,wfRequest: {},maxPosts: int,maxMentions: int,maxEmoji: int,maxAttachments: int,federationList: []) -> {}:
userPosts={} userPosts={}
feedUrl,pubKeyId,pubKey,personId = getPersonBox(session,wfRequest,'outbox') feedUrl,pubKeyId,pubKey,personId = getPersonBox(session,wfRequest,'outbox')
if not feedUrl: if not feedUrl:
@ -317,13 +316,13 @@ def createPublicPost(username: str, domain: str, https: bool, content: str, foll
prefix='http' prefix='http'
return createPostBase(username, domain, 'https://www.w3.org/ns/activitystreams#Public', prefix+'://'+domain+'/users/'+username+'/followers', https, content, followersOnly, saveToFile, inReplyTo, inReplyToAtomUri, subject) return createPostBase(username, domain, 'https://www.w3.org/ns/activitystreams#Public', prefix+'://'+domain+'/users/'+username+'/followers', https, content, followersOnly, saveToFile, inReplyTo, inReplyToAtomUri, subject)
def threadSendPost(session,postJsonObject,federationList,inboxUrl: str,baseDir: str,signatureHeader,postLog) -> None: def threadSendPost(session,postJsonObject: {},federationList: [],inboxUrl: str,baseDir: str,signatureHeaderJson: {},postLog: []) -> None:
"""Sends a post with exponential backoff """Sends a post with exponential backoff
""" """
tries=0 tries=0
backoffTime=60 backoffTime=60
for attempt in range(20): for attempt in range(20):
postResult = postJson(session,postJsonObject,federationList,inboxUrl,signatureHeader) postResult = postJson(session,postJsonObject,federationList,inboxUrl,signatureHeaderJson)
if postResult: if postResult:
postLog.append(postJsonObject['published']+' '+postResult+'\n') postLog.append(postJsonObject['published']+' '+postResult+'\n')
# keep the length of the log finite # keep the length of the log finite
@ -340,7 +339,7 @@ def threadSendPost(session,postJsonObject,federationList,inboxUrl: str,baseDir:
time.sleep(backoffTime) time.sleep(backoffTime)
backoffTime *= 2 backoffTime *= 2
def sendPost(session,baseDir,username: str, domain: str, port: int, toUsername: str, toDomain: str, toPort: int, cc: str, https: bool, content: str, followersOnly: bool, saveToFile: bool, federationList, sendThreads, postLog, inReplyTo=None, inReplyToAtomUri=None, subject=None) -> int: def sendPost(session,baseDir: str,username: str, domain: str, port: int, toUsername: str, toDomain: str, toPort: int, cc: str, https: bool, content: str, followersOnly: bool, saveToFile: bool, federationList: [], sendThreads: [], postLog: [], inReplyTo=None, inReplyToAtomUri=None, subject=None) -> int:
"""Post to another inbox """Post to another inbox
""" """
prefix='https' prefix='https'
@ -377,7 +376,6 @@ def sendPost(session,baseDir,username: str, domain: str, port: int, toUsername:
# construct the http header # construct the http header
signatureHeaderJson = createSignedHeader(privateKeyPem, username, domain, port, '/inbox', https, withDigest, postJsonObject) signatureHeaderJson = createSignedHeader(privateKeyPem, username, domain, port, '/inbox', https, withDigest, postJsonObject)
signatureHeaderJson['Content-type'] = 'application/json'
# Keep the number of threads being used small # Keep the number of threads being used small
while len(sendThreads)>10: while len(sendThreads)>10:

View File

@ -19,7 +19,7 @@ def createSession(onionRoute: bool):
session.proxies['https'] = 'socks5h://localhost:9050' session.proxies['https'] = 'socks5h://localhost:9050'
return session return session
def getJson(session,url: str,headers,params): def getJson(session,url: str,headers: {},params: {}) -> {}:
sessionParams={} sessionParams={}
sessionHeaders={} sessionHeaders={}
if headers: if headers:
@ -30,7 +30,7 @@ def getJson(session,url: str,headers,params):
session.cookies.clear() session.cookies.clear()
return session.get(url, headers=sessionHeaders, params=sessionParams).json() return session.get(url, headers=sessionHeaders, params=sessionParams).json()
def postJson(session,postJsonObject,federationList,inboxUrl: str,headers) -> str: def postJson(session,postJsonObject: {},federationList: [],inboxUrl: str,headers: {}) -> str:
"""Post a json message to the inbox of another person """Post a json message to the inbox of another person
""" """
# check that we are posting to a permitted domain # check that we are posting to a permitted domain
@ -44,6 +44,3 @@ def postJson(session,postJsonObject,federationList,inboxUrl: str,headers) -> str
postResult = session.post(url = inboxUrl, data = json.dumps(postJsonObject), headers=headers) postResult = session.post(url = inboxUrl, data = json.dumps(postJsonObject), headers=headers)
return postResult.text return postResult.text
def getBaseDirectory():
baseDirectory = os.getcwd()

View File

@ -23,8 +23,12 @@ from person import createPerson
from posts import deleteAllPosts from posts import deleteAllPosts
from posts import createPublicPost from posts import createPublicPost
from posts import sendPost from posts import sendPost
from follow import clearFollows
from follow import clearFollowers
from follow import followPerson from follow import followPerson
from follow import followerOfPerson from follow import followerOfPerson
from follow import unfollowPerson
from follow import unfollowerOfPerson
testServerAliceRunning = False testServerAliceRunning = False
testServerBobRunning = False testServerBobRunning = False
@ -185,7 +189,7 @@ def testPostMessageBetweenServers():
sendResult = sendPost(sessionAlice,aliceDir,'alice', '127.0.0.1', alicePort, 'bob', '127.0.0.1', bobPort, '', https, 'Why is a mouse when it spins?', False, True, federationList, aliceSendThreads, alicePostLog, inReplyTo, inReplyToAtomUri, subject) sendResult = sendPost(sessionAlice,aliceDir,'alice', '127.0.0.1', alicePort, 'bob', '127.0.0.1', bobPort, '', https, 'Why is a mouse when it spins?', False, True, federationList, aliceSendThreads, alicePostLog, inReplyTo, inReplyToAtomUri, subject)
print('sendResult: '+str(sendResult)) print('sendResult: '+str(sendResult))
time.sleep(5) time.sleep(15)
# stop the servers # stop the servers
thrAlice.kill() thrAlice.kill()

View File

@ -17,7 +17,7 @@ from session import getJson
from cache import storeWebfingerInCache from cache import storeWebfingerInCache
from cache import getWebfingerFromCache from cache import getWebfingerFromCache
def parseHandle(handle): def parseHandle(handle: str) -> (str,str):
if '.' not in handle: if '.' not in handle:
return None, None return None, None
if '/@' in handle: if '/@' in handle:
@ -34,7 +34,7 @@ def parseHandle(handle):
return username, domain return username, domain
def webfingerHandle(session,handle: str,https: bool): def webfingerHandle(session,handle: str,https: bool) -> {}:
username, domain = parseHandle(handle) username, domain = parseHandle(handle)
if not username: if not username:
return None return None
@ -57,7 +57,7 @@ def webfingerHandle(session,handle: str,https: bool):
storeWebfingerInCache(username+'@'+domain, result) storeWebfingerInCache(username+'@'+domain, result)
return result return result
def generateMagicKey(publicKeyPem): def generateMagicKey(publicKeyPem) -> str:
"""See magic_key method in """See magic_key method in
https://github.com/tootsuite/mastodon/blob/707ddf7808f90e3ab042d7642d368c2ce8e95e6f/app/models/account.rb https://github.com/tootsuite/mastodon/blob/707ddf7808f90e3ab042d7642d368c2ce8e95e6f/app/models/account.rb
""" """
@ -66,7 +66,7 @@ def generateMagicKey(publicKeyPem):
pubexp = base64.urlsafe_b64encode(number.long_to_bytes(privkey.e)).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}" return f"data:application/magic-public-key,RSA.{mod}.{pubexp}"
def storeWebfingerEndpoint(username: str,domain: str,baseDir: str,wfJson) -> bool: def storeWebfingerEndpoint(username: str,domain: str,baseDir: str,wfJson: {}) -> bool:
"""Stores webfinger endpoint for a user to a file """Stores webfinger endpoint for a user to a file
""" """
handle=username+'@'+domain handle=username+'@'+domain
@ -78,7 +78,7 @@ def storeWebfingerEndpoint(username: str,domain: str,baseDir: str,wfJson) -> boo
commentjson.dump(wfJson, fp, indent=4, sort_keys=False) commentjson.dump(wfJson, fp, indent=4, sort_keys=False)
return True return True
def createWebfingerEndpoint(username,domain,port,https,publicKeyPem) -> {}: def createWebfingerEndpoint(username: str,domain: str,port: int,https: bool,publicKeyPem) -> {}:
"""Creates a webfinger endpoint for a user """Creates a webfinger endpoint for a user
""" """
prefix='https' prefix='https'
@ -141,7 +141,7 @@ def webfingerMeta() -> str:
" </Link>" \ " </Link>" \
"</XRD>" "</XRD>"
def webfingerLookup(path: str,baseDir: str): def webfingerLookup(path: str,baseDir: str) -> {}:
"""Lookup the webfinger endpoint for an account """Lookup the webfinger endpoint for an account
""" """
if not path.startswith('/.well-known/webfinger?'): if not path.startswith('/.well-known/webfinger?'):