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 aiohttp.web import Application
|
||||||
|
|
||||||
from . import set_app
|
from . import set_app
|
||||||
from . import views
|
|
||||||
from .middleware import http_signatures_middleware
|
|
||||||
|
|
||||||
|
|
||||||
app = Application(middlewares=[
|
app = Application()
|
||||||
http_signatures_middleware
|
|
||||||
])
|
|
||||||
|
|
||||||
set_app(app)
|
set_app(app)
|
||||||
|
|
|
@ -189,7 +189,10 @@ class RelayConfig(DotDict):
|
||||||
|
|
||||||
|
|
||||||
def is_banned_software(self, software):
|
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):
|
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 logging
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import traceback
|
||||||
|
|
||||||
from aiohttp.web import HTTPForbidden, HTTPUnauthorized, Response, json_response
|
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 .application import app
|
||||||
from .http_debug import STATS
|
from .http_debug import STATS
|
||||||
from .misc import request
|
|
||||||
from .processors import run_processor
|
from .processors import run_processor
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,31 +78,65 @@ async def inbox(request):
|
||||||
config = app['config']
|
config = app['config']
|
||||||
database = app['database']
|
database = app['database']
|
||||||
|
|
||||||
if len(config.blocked_software):
|
## reject if missing signature header
|
||||||
software = await fetch_nodeinfo(request['actor_domain'])
|
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:
|
## read message and get actor id and domain
|
||||||
logging.verbose(f'Rejected actor for using specific software: {software}')
|
try:
|
||||||
raise HTTPForbidden(body='access denied', content_type='text/plain')
|
data = await request.json()
|
||||||
|
actor_id = data['actor']
|
||||||
|
actor_domain = urlparse(actor_id).hostname
|
||||||
|
|
||||||
## reject if no post data or signature failed validation
|
except KeyError:
|
||||||
if not request['data'] or not request['validated']:
|
logging.verbose('actor not in data')
|
||||||
logging.verbose('Rejected actor for missing post data')
|
raise HTTPUnauthorized(body='no actor in message')
|
||||||
raise HTTPUnauthorized(body='access denied', content_type='text/plain')
|
|
||||||
|
|
||||||
## reject if activity type isn't 'Follow' and the actor isn't following
|
## reject if there is no actor in the message
|
||||||
if request['data']['type'] != 'Follow' and not database.get_inbox(request['actor_domain']):
|
except:
|
||||||
logging.verbose(f'Rejected actor for trying to post while not following: {request["actor"]["id"]}')
|
traceback.print_exc()
|
||||||
raise HTTPUnauthorized(body='access denied', content_type='text/plain')
|
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
|
## 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']):
|
elif config.whitelist_enabled and not config.is_whitelisted(actor_id):
|
||||||
logging.verbose(f'Rejected actor for not being in the whitelist: {request["actor"]["id"]}')
|
logging.verbose(f'Rejected actor for not being in the whitelist: {actor_id}')
|
||||||
raise HTTPForbidden(body='access denied', content_type='text/plain')
|
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')
|
return Response(body=b'{}', content_type='application/activity+json')
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue