Tidying of authorized fetch

merge-requests/30/head
Bob Mottram 2021-09-02 10:46:18 +01:00
parent 243b4bc310
commit 72b7ea6977
2 changed files with 50 additions and 39 deletions

View File

@ -586,20 +586,28 @@ class PubServer(BaseHTTPRequestHandler):
return False return False
return True return True
def _fetchAuthenticated(self) -> bool: def _authorizedFetch(self) -> bool:
"""http authentication of GET requests for json """http authentication of GET requests for json
""" """
if not self.server.authenticatedFetch: if not self.server.authorizedFetch:
return True return True
signature = None
if self.headers.get('signature'):
signature = self.headers['signature']
elif self.headers.get('Signature'):
signature = self.headers['Signature']
# check that the headers are signed # check that the headers are signed
if not self.headers.get('signature'): if not signature:
if self.server.debug: if self.server.debug:
print('WARN: authenticated fetch, ' + print('WARN: authorized fetch, ' +
'GET has no signature in headers') 'GET has no signature in headers')
return False return False
# get the keyId
# get the keyId, which is typically the instance actor
keyId = None keyId = None
signatureParams = self.headers['signature'].split(',') signatureParams = signature.split(',')
for signatureItem in signatureParams: for signatureItem in signatureParams:
if signatureItem.startswith('keyId='): if signatureItem.startswith('keyId='):
if '"' in signatureItem: if '"' in signatureItem:
@ -607,23 +615,30 @@ class PubServer(BaseHTTPRequestHandler):
break break
if not keyId: if not keyId:
if self.server.debug: if self.server.debug:
print('WARN: authenticated fetch, ' + print('WARN: authorized fetch, ' +
'failed to obtain keyId from signature') 'failed to obtain keyId from signature')
return False return False
# remove #main-key
if '#' in keyId:
keyId = keyId.split('#')[0]
# is the keyId (actor) valid? # is the keyId (actor) valid?
if not urlPermitted(keyId, self.server.federationList): if not urlPermitted(keyId, self.server.federationList):
if self.server.debug: if self.server.debug:
print('Authorized fetch failed: ' + keyId + print('Authorized fetch failed: ' + keyId +
' is not permitted') ' is not permitted')
return False return False
# make sure we have a session # make sure we have a session
if not self.server.session: if not self.server.session:
print('DEBUG: creating new session during authenticated fetch') print('DEBUG: creating new session during authorized fetch')
self.server.session = createSession(self.server.proxyType) self.server.session = createSession(self.server.proxyType)
if not self.server.session: if not self.server.session:
print('ERROR: GET failed to create session during ' + print('ERROR: GET failed to create session during ' +
'authenticated fetch') 'authorized fetch')
return False return False
# obtain the public key # obtain the public key
pubKey = \ pubKey = \
getPersonPubKey(self.server.baseDir, self.server.session, keyId, getPersonPubKey(self.server.baseDir, self.server.session, keyId,
@ -633,21 +648,17 @@ class PubServer(BaseHTTPRequestHandler):
self.server.signingPrivateKeyPem) self.server.signingPrivateKeyPem)
if not pubKey: if not pubKey:
if self.server.debug: if self.server.debug:
print('DEBUG: Authenticated fetch failed to ' + print('DEBUG: Authorized fetch failed to ' +
'obtain public key for ' + keyId) 'obtain public key for ' + keyId)
return False return False
# it is assumed that there will be no message body on
# authenticated fetches and also consequently no digest
GETrequestBody = ''
GETrequestDigest = None
# verify the GET request without any digest # verify the GET request without any digest
if verifyPostHeaders(self.server.httpPrefix, if verifyPostHeaders(self.server.httpPrefix, pubKey, self.headers,
pubKey, self.headers, self.path, True, None, '', self.server.debug):
self.path, True,
GETrequestDigest,
GETrequestBody,
self.server.debug):
return True return True
if self.server.debug:
print('Authorized fetch failed for ' + keyId)
return False return False
def _login_headers(self, fileFormat: str, length: int, def _login_headers(self, fileFormat: str, length: int,
@ -7720,7 +7731,7 @@ class PubServer(BaseHTTPRequestHandler):
cookie, callingDomain, False) cookie, callingDomain, False)
self._write(msg) self._write(msg)
else: else:
if self._fetchAuthenticated(): if self._authorizedFetch():
msg = json.dumps(repliesJson, ensure_ascii=False) msg = json.dumps(repliesJson, ensure_ascii=False)
msg = msg.encode('utf-8') msg = msg.encode('utf-8')
protocolStr = 'application/json' protocolStr = 'application/json'
@ -7814,7 +7825,7 @@ class PubServer(BaseHTTPRequestHandler):
'individual post done', 'individual post done',
'post replies done') 'post replies done')
else: else:
if self._fetchAuthenticated(): if self._authorizedFetch():
msg = json.dumps(repliesJson, msg = json.dumps(repliesJson,
ensure_ascii=False) ensure_ascii=False)
msg = msg.encode('utf-8') msg = msg.encode('utf-8')
@ -7917,7 +7928,7 @@ class PubServer(BaseHTTPRequestHandler):
'post replies done', 'post replies done',
'show roles') 'show roles')
else: else:
if self._fetchAuthenticated(): if self._authorizedFetch():
rolesList = getActorRolesList(actorJson) rolesList = getActorRolesList(actorJson)
msg = json.dumps(rolesList, msg = json.dumps(rolesList,
ensure_ascii=False) ensure_ascii=False)
@ -8025,7 +8036,7 @@ class PubServer(BaseHTTPRequestHandler):
'post roles done', 'post roles done',
'show skills') 'show skills')
else: else:
if self._fetchAuthenticated(): if self._authorizedFetch():
actorSkillsList = \ actorSkillsList = \
getOccupationSkills(actorJson) getOccupationSkills(actorJson)
skills = getSkillsFromList(actorSkillsList) skills = getSkillsFromList(actorSkillsList)
@ -8161,7 +8172,7 @@ class PubServer(BaseHTTPRequestHandler):
'done', 'done',
'show status') 'show status')
else: else:
if self._fetchAuthenticated(): if self._authorizedFetch():
msg = json.dumps(postJsonObject, msg = json.dumps(postJsonObject,
ensure_ascii=False) ensure_ascii=False)
msg = msg.encode('utf-8') msg = msg.encode('utf-8')
@ -9635,7 +9646,7 @@ class PubServer(BaseHTTPRequestHandler):
'show events done', 'show events done',
'show outbox') 'show outbox')
else: else:
if self._fetchAuthenticated(): if self._authorizedFetch():
msg = json.dumps(outboxFeed, msg = json.dumps(outboxFeed,
ensure_ascii=False) ensure_ascii=False)
msg = msg.encode('utf-8') msg = msg.encode('utf-8')
@ -9879,7 +9890,7 @@ class PubServer(BaseHTTPRequestHandler):
self.server.GETbusy = False self.server.GETbusy = False
return True return True
else: else:
if self._fetchAuthenticated(): if self._authorizedFetch():
msg = json.dumps(shares, msg = json.dumps(shares,
ensure_ascii=False) ensure_ascii=False)
msg = msg.encode('utf-8') msg = msg.encode('utf-8')
@ -9996,7 +10007,7 @@ class PubServer(BaseHTTPRequestHandler):
'show profile 3') 'show profile 3')
return True return True
else: else:
if self._fetchAuthenticated(): if self._authorizedFetch():
msg = json.dumps(following, msg = json.dumps(following,
ensure_ascii=False).encode('utf-8') ensure_ascii=False).encode('utf-8')
msglen = len(msg) msglen = len(msg)
@ -10113,7 +10124,7 @@ class PubServer(BaseHTTPRequestHandler):
'show profile 4') 'show profile 4')
return True return True
else: else:
if self._fetchAuthenticated(): if self._authorizedFetch():
msg = json.dumps(followers, msg = json.dumps(followers,
ensure_ascii=False).encode('utf-8') ensure_ascii=False).encode('utf-8')
msglen = len(msg) msglen = len(msg)
@ -10249,7 +10260,7 @@ class PubServer(BaseHTTPRequestHandler):
'show profile 4 done', 'show profile 4 done',
'show profile posts') 'show profile posts')
else: else:
if self._fetchAuthenticated(): if self._authorizedFetch():
acceptStr = self.headers['Accept'] acceptStr = self.headers['Accept']
msgStr = json.dumps(actorJson, ensure_ascii=False) msgStr = json.dumps(actorJson, ensure_ascii=False)
msg = msgStr.encode('utf-8') msg = msgStr.encode('utf-8')
@ -13846,16 +13857,16 @@ class PubServer(BaseHTTPRequestHandler):
self.server.GETbusy = False self.server.GETbusy = False
return return
if not self._fetchAuthenticated(): if not self._authorizedFetch():
if self.server.debug: if self.server.debug:
print('WARN: Unauthenticated GET') print('WARN: Unauthorized GET')
self._404() self._404()
self.server.GETbusy = False self.server.GETbusy = False
return return
self._benchmarkGETtimings(GETstartTime, GETtimings, self._benchmarkGETtimings(GETstartTime, GETtimings,
'show profile posts done', 'show profile posts done',
'authenticated fetch') 'authorized fetch')
# check that the file exists # check that the file exists
filename = self.server.baseDir + self.path filename = self.server.baseDir + self.path
@ -15829,7 +15840,7 @@ def runDaemon(lowBandwidth: bool,
httpPrefix: str = 'https', httpPrefix: str = 'https',
fedList: [] = [], fedList: [] = [],
maxMentions: int = 10, maxEmoji: int = 10, maxMentions: int = 10, maxEmoji: int = 10,
authenticatedFetch: bool = False, authorizedFetch: bool = False,
proxyType: str = None, maxReplies: int = 64, proxyType: str = None, maxReplies: int = 64,
domainMaxPostsPerDay: int = 8640, domainMaxPostsPerDay: int = 8640,
accountMaxPostsPerDay: int = 864, accountMaxPostsPerDay: int = 864,
@ -16050,7 +16061,7 @@ def runDaemon(lowBandwidth: bool,
httpd.outboxThread = {} httpd.outboxThread = {}
httpd.newPostThread = {} httpd.newPostThread = {}
httpd.projectVersion = projectVersion httpd.projectVersion = projectVersion
httpd.authenticatedFetch = authenticatedFetch httpd.authorizedFetch = authorizedFetch
# max POST size of 30M # max POST size of 30M
httpd.maxPostLength = 1024 * 1024 * 30 httpd.maxPostLength = 1024 * 1024 * 30
httpd.maxMediaSize = httpd.maxPostLength httpd.maxMediaSize = httpd.maxPostLength

View File

@ -407,10 +407,10 @@ parser.add_argument("--debug", type=str2bool, nargs='?',
parser.add_argument("--notificationSounds", type=str2bool, nargs='?', parser.add_argument("--notificationSounds", type=str2bool, nargs='?',
const=True, default=True, const=True, default=True,
help="Play notification sounds") help="Play notification sounds")
parser.add_argument("--authenticatedFetch", type=str2bool, nargs='?', parser.add_argument("--authorizedFetch", type=str2bool, nargs='?',
const=True, default=False, const=True, default=False,
help="Enable authentication on GET requests" + help="Enable authorization on GET requests" +
" for json (authenticated fetch)") " for json (authorized fetch)")
parser.add_argument("--instanceOnlySkillsSearch", type=str2bool, nargs='?', parser.add_argument("--instanceOnlySkillsSearch", type=str2bool, nargs='?',
const=True, default=False, const=True, default=False,
help="Skills searches only return " + help="Skills searches only return " +
@ -2993,7 +2993,7 @@ if __name__ == "__main__":
args.YTReplacementDomain, args.YTReplacementDomain,
port, proxyPort, httpPrefix, port, proxyPort, httpPrefix,
federationList, args.maxMentions, federationList, args.maxMentions,
args.maxEmoji, args.authenticatedFetch, args.maxEmoji, args.authorizedFetch,
proxyType, args.maxReplies, proxyType, args.maxReplies,
args.domainMaxPostsPerDay, args.domainMaxPostsPerDay,
args.accountMaxPostsPerDay, args.accountMaxPostsPerDay,