merge middleware into views.inbox

This commit is contained in:
Izalia Mae 2022-04-09 22:50:20 -04:00
parent d9fbb8ddd4
commit a5dd6f1abd
4 changed files with 60 additions and 79 deletions

View file

@ -1,16 +1,8 @@
import asyncio
import logging
import sys
from aiohttp.web import Application
from . import set_app
from . import views
from .middleware import http_signatures_middleware
app = Application(middlewares=[
http_signatures_middleware
])
app = Application()
set_app(app)

View file

@ -189,7 +189,10 @@ class RelayConfig(DotDict):
def is_banned_software(self, software):
return software in self.blocked_software
if not software:
return False
return software.lower() in self.blocked_software
def is_whitelisted(self, instance):

View file

@ -1,49 +0,0 @@
import logging
from aiohttp.web import HTTPUnauthorized
from json.decoder import JSONDecodeError
from urllib.parse import urlparse
from . import misc
# This will probably get merged into views.inbox
async def http_signatures_middleware(app, handler):
async def http_signatures_handler(request):
request['validated'] = False
request['actor'] = None
request['actor_domain'] = None
try:
request['data'] = await request.json()
except JSONDecodeError:
request['data'] = None
if 'signature' in request.headers and request.method == 'POST':
if 'actor' not in request['data']:
logging.verbose('Actor not in data')
raise HTTPUnauthorized(body='signature check failed, no actor in message')
if app['config'].is_banned(request['data']['actor']):
logging.verbose(f'Ignored request from banned actor: {request["actor"]["id"]}')
raise HTTPUnauthorized(body='banned')
request['actor'] = await misc.request(request['data']['actor'])
if not request['actor']:
logging.verbose(f'Failed to fetch actor: {request["actor"]["id"]}')
raise HTTPUnauthorized('failed to fetch actor')
actor_id = request['actor']['id']
request['actor_domain'] = urlparse(actor_id).hostname
if not (await misc.validate_signature(actor_id, request)):
logging.verbose(f'signature validation failed for: {actor_id}')
raise HTTPUnauthorized(body='signature check failed, signature did not match key')
return (await handler(request))
return (await handler(request))
return http_signatures_handler

View file

@ -1,12 +1,13 @@
import logging
import subprocess
import traceback
from aiohttp.web import HTTPForbidden, HTTPUnauthorized, Response, json_response
from urllib.parse import urlparse
from . import __version__
from . import __version__, misc
from .application import app
from .http_debug import STATS
from .misc import request
from .processors import run_processor
@ -77,31 +78,65 @@ async def inbox(request):
config = app['config']
database = app['database']
if len(config.blocked_software):
software = await fetch_nodeinfo(request['actor_domain'])
## reject if missing signature header
if 'signature' not in request.headers:
logging.verbose('Actor missing signature header')
raise HTTPUnauthorized(body='missing signature')
if software and software.lower() in config.blocked_software:
logging.verbose(f'Rejected actor for using specific software: {software}')
raise HTTPForbidden(body='access denied', content_type='text/plain')
## read message and get actor id and domain
try:
data = await request.json()
actor_id = data['actor']
actor_domain = urlparse(actor_id).hostname
## reject if no post data or signature failed validation
if not request['data'] or not request['validated']:
logging.verbose('Rejected actor for missing post data')
raise HTTPUnauthorized(body='access denied', content_type='text/plain')
except KeyError:
logging.verbose('actor not in data')
raise HTTPUnauthorized(body='no actor in message')
## reject if activity type isn't 'Follow' and the actor isn't following
if request['data']['type'] != 'Follow' and not database.get_inbox(request['actor_domain']):
logging.verbose(f'Rejected actor for trying to post while not following: {request["actor"]["id"]}')
raise HTTPUnauthorized(body='access denied', content_type='text/plain')
## reject if there is no actor in the message
except:
traceback.print_exc()
logging.verbose('Failed to parse inbox message')
raise HTTPUnauthorized(body='failed to parse message')
actor = await misc.request(actor_id)
## reject if actor is empty
if not actor:
logging.verbose(f'Failed to fetch actor: {actor_id}')
raise HTTPUnauthorized('failed to fetch actor')
## reject if the actor isn't whitelisted while the whiltelist is enabled
elif config.whitelist_enabled and not request['data'].is_whitelisted(request['actor']['id']):
logging.verbose(f'Rejected actor for not being in the whitelist: {request["actor"]["id"]}')
raise HTTPForbidden(body='access denied', content_type='text/plain')
elif config.whitelist_enabled and not config.is_whitelisted(actor_id):
logging.verbose(f'Rejected actor for not being in the whitelist: {actor_id}')
raise HTTPForbidden(body='access denied')
logging.debug(f">> payload {request['data']}")
## reject if actor is banned
if app['config'].is_banned(actor_id):
logging.verbose(f'Ignored request from banned actor: {actor_id}')
raise HTTPForbidden(body='access denied')
await run_processor(request, request['data'], request['actor'])
## reject if software used by actor is banned
if len(config.blocked_software):
software = await fetch_nodeinfo(actor_domain)
if config.is_banned_software(software):
logging.verbose(f'Rejected actor for using specific software: {software}')
raise HTTPForbidden(body='access denied')
## reject if the signature is invalid
if not (await misc.validate_signature(actor_id, request)):
logging.verbose(f'signature validation failed for: {actor_id}')
raise HTTPUnauthorized(body='signature check failed, signature did not match key')
## reject if activity type isn't 'Follow' and the actor isn't following
if data['type'] != 'Follow' and not database.get_inbox(actor_domain):
logging.verbose(f'Rejected actor for trying to post while not following: {actor_id}')
raise HTTPUnauthorized(body='access denied')
logging.debug(f">> payload {data}")
await run_processor(request, data, actor)
return Response(body=b'{}', content_type='application/activity+json')