merge middleware into views.inbox
This commit is contained in:
parent
d9fbb8ddd4
commit
a5dd6f1abd
4 changed files with 60 additions and 79 deletions
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
|
@ -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')
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue