process inbox data in bg, fix sig validation, and use latest izzylib

This commit is contained in:
Izalia Mae 2021-09-22 13:34:06 -04:00
parent 7852ddc95b
commit 896d2d60ff
7 changed files with 73 additions and 73 deletions

View file

@ -5,6 +5,7 @@ PYTHON_SYS := `which python3`
install: setupvenv
install-dev: setupvenv setupdev
install-nodeb: setupvenv
reinstall: clean setupenv
uninstall: clean
update: update-deps
@ -27,8 +28,6 @@ setupdev:
$(PYTHON) -m pip install "git+https://git.barkshark.xyz/izaliamae/reload.git"
update-deps:
git reset HEAD --hard
git pull
$(PYTHON) -m pip install -U -r requirements.txt
run:

View file

@ -1,4 +1,3 @@
izzylib[hasher,http_server,http_urllib_client,sql,template] @ https://git.barkshark.xyz/izaliamae/izzylib/archive/0.7.0.tar.gz
izzylib[hasher,http_server,http_signatures,http_urllib_client,sql,template] @ git+https://git.barkshark.xyz/izaliamae/izzylib@864849feb860299ae142b867d8c782d65e769f2e
pyyaml==5.4.1
pg8000==1.21.2

View file

@ -28,16 +28,18 @@ def fetch_actor(url):
if cached:
return cached
data = fetch(url, sign=True, cache=False)
try:
data = fetch(url, cache=False)
error = data.get('error')
except:
data = None
error = None
if not data:
data = fetch(url, sign=True, cache=False)
if error:
logging.debug(f'Failed to fetch actor with error: {error}')
if not data or data.get('error'):
if not data or error:
return
s.put.actor(url, data)

View file

@ -3,19 +3,19 @@ from urllib.parse import urlparse
from uuid import uuid4
from .config import config
from .functions import push_message
from .functions import fetch_actor, push_message
class Message:
def __init__(self, name, *args):
self.message = getattr(self, name)(*args)
self.message = getattr(self, f'msg_{name}')(*args)
def send(self, inbox):
return push_message(inbox, self.message)
def accept(self, followid, actor):
def msg_accept(self, followid, actor):
message = DotDict({
'@context': 'https://www.w3.org/ns/activitystreams',
'type': 'Accept',
@ -35,7 +35,7 @@ class Message:
return message
def reject(self, followid, actor):
def msg_reject(self, followid, actor):
message = DotDict({
'@context': 'https://www.w3.org/ns/activitystreams',
'type': 'Reject',
@ -55,7 +55,7 @@ class Message:
return message
def announce(self, object_id):
def msg_announce(self, object_id):
data = DotDict({
'@context': 'https://www.w3.org/ns/activitystreams',
'type': 'Announce',
@ -68,9 +68,21 @@ class Message:
return data
def note(self, user_handle, user_inbox, user_actor, actor, message):
actor_domain = urlparse(actor).netloc
user_domain = urlparse(user_inbox).netloc
def msg_create(self, inbox, object_id):
data = DotDict({
'@context': 'https://www.w3.org/ns/activitystreams',
'type': 'Create',
'to': [inbox],
'actor': f'https://{config.host}/actor',
'object': object_id,
'id': f'https://{config.host}/activities/{str(uuid4())}'
})
# needs to be redone
def msg_note(self, handle, actor, message):
domain = urlparse(user_inbox).netloc
inbox = fetch_actor(actor)
data = DotDict({
"@context": "https://www.w3.org/ns/activitystreams",
"id": f"https://{config.host}/activities/{str(uuid4())}",
@ -82,11 +94,11 @@ class Message:
"published": ap_date(),
"attributedTo": f"https://{config.host}/actor",
"content": message,
'to': [user_inbox],
'to': [inbox],
'tag': [{
'type': 'Mention',
'href': user_actor,
'name': f'@{user_handle}@{user_domain}'
'href': actor,
'name': f'@{handle}@{domain}'
}],
}
})

View file

@ -1,6 +1,6 @@
from izzylib import logging
from izzylib.http_urllib_client import parse_signature, verify_request, verify_headers
from izzylib.http_server import MiddlewareBase
from izzylib.http_signatures import parse_signature, verify_request, verify_headers
from izzylib.sql.rows import Row
@ -43,16 +43,16 @@ class AuthCheck(MiddlewareBase):
token = request.headers.get('token')
with db.session as s:
request.ctx.token = s.fetch('token', code=token)
request.ctx.user = s.fetch('user', id=request.ctx.token.id) if request.token else None
request.ctx.signature = parse_signature(request.headers.get('signature'))
request.ctx.instance = None
request.ctx.actor = None
request.token = s.fetch('token', code=token)
request.user = s.fetch('user', id=request.token.id) if request.token else None
request.signature = parse_signature(request.headers.get('signature'))
request.instance = None
request.actor = None
if request.ctx.signature:
domain = request.ctx.signature.domain
top_domain = request.ctx.signature.top_domain
actor = request.ctx.signature.actor
if request.signature:
domain = request.signature.domain
top_domain = request.signature.top_domain
actor = request.signature.actor
if top_domain in blocked_instances:
return response.text(f'This teapot kills fascists', status=418)
@ -60,11 +60,11 @@ class AuthCheck(MiddlewareBase):
if any(map(s.get.ban, [None], [domain, top_domain])):
return response.text('no', status=403)
request.ctx.instance = s.get.instance(domain)
request.ctx.actor = fetch_actor(actor)
request.instance = s.get.instance(domain)
request.actor = fetch_actor(actor)
if request.path in ['/inbox', '/actor'] and request.method.lower() == 'post':
if not request.ctx.actor:
if not request.actor:
return response.text('Could not get actor', status=400)
try:
@ -74,30 +74,18 @@ class AuthCheck(MiddlewareBase):
logging.verbose('Failed to parse post data')
return response.text(f'Invalid data', status=400)
try:
if type(request.ctx.actor).__name__ == 'Row':
logging.warning('Actor data is a db row:', actor)
logging.debug(request.ctx.actor.keys())
return response.text(f'An unknown error happened', status=500)
if type(request.actor).__name__ == 'Row':
logging.warning('Actor data is a db row:', actor)
return response.text(f'An unknown error happened', status=500)
validated = verify_headers(
request.Headers.to_dict(),
request.method,
request.path,
actor = request.ctx.actor,
body = request.body
)
except AssertionError as e:
logging.debug(f'Failed sig check: {e}')
return response.text(f'Failed signature check: {e}', status=401)
validated = verify_request(request, request.actor)
if not validated:
logging.debug(f'Not validated: {actor}')
return response.text(f'Failed signature check: {e}', status=401)
return response.text(f'Failed signature check', status=401)
if not request.ctx.instance and data and data.type.lower() != 'follow':
if not request.instance and data and data.type.lower() != 'follow':
return response.text(f'Follow the relay first', status=401)
if any(map(request.path.startswith, auth_paths)) and not request.ctx.user:
if any(map(request.path.startswith, auth_paths)) and not request.user:
return response.redir('/login')

View file

@ -16,23 +16,25 @@ class ProcessData:
def __init__(self, request, response, data):
self.request = request
self.response = response
self.signature = request.ctx.signature
self.instance = request.ctx.instance
self.actor = request.ctx.actor
self.signature = request.signature
self.instance = request.instance
self.actor = request.actor
self.type = data.type.lower()
self.data = data
@property
def func(self):
return getattr(self, f'cmd_{self.type}')
async def __call__(self):
return await getattr(self, f'cmd_{self.type}')()
def error(self, message, status=500):
return self.response.json({'error': message}, status=status)
def valid_type(self):
if getattr(self, f'cmd_{self.type}', None):
return True
return False
def cmd_follow(self):
async def cmd_follow(self):
if self.actor.type.lower() != 'application':
#return self.response.json('No', status=403)
@ -56,7 +58,7 @@ class ProcessData:
if not self.instance:
logging.error(f'Something messed up when inserting "{self.signature.domain}" into the database')
return self.error('Internal error', 500)
return
message = Message('accept', self.data.id, self.instance.actor)
resp = message.send(self.instance.inbox)
@ -67,7 +69,7 @@ class ProcessData:
logging.verbose(f'Instance joined the relay: {self.instance.domain}')
def cmd_undo(self):
async def cmd_undo(self):
if self.actor.type.lower() != 'application':
return
@ -81,7 +83,7 @@ class ProcessData:
logging.debug(f'Removed instance from relay: {self.instance.domain}')
def cmd_announce(self):
async def cmd_announce(self):
if isinstance(self.data.object, dict):
object = self.data.object
object_id = self.data.object.id
@ -123,11 +125,8 @@ class ProcessData:
logging.verbose(f'Failed to send object announce to {instance.domain}: {object.id}')
logging.debug(f'Server error {response.status}: {response.text}')
else:
logging.verbose(f'Sent "{object.id}" to {instance.domain}')
def cmd_create(self):
async def cmd_create(self):
return self.cmd_announce()

View file

@ -1,3 +1,5 @@
import asyncio
from izzylib import DotDict, logging
from izzylib.http_server import View
@ -127,18 +129,17 @@ class UnciaActor(View):
async def post(self, request, response):
if not request.ctx.actor:
if not request.actor:
logging.verbose(f'Failed to fetch actor')
return response.json({'error': 'Failed to fetch actor'})
processor = ProcessData(request, response, request.data.json)
try:
data = processor.func()
except AttributeError:
if not processor.valid_type():
return processor.error(f'Message type unhandled: {processor.type}', 401)
return data or response.text('UvU', status=202)
asyncio.ensure_future(processor())
return response.text('UvU', status=202)
class UnciaNodeinfo(View):