process inbox data in bg, fix sig validation, and use latest izzylib
This commit is contained in:
parent
7852ddc95b
commit
896d2d60ff
3
Makefile
3
Makefile
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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}'
|
||||
}],
|
||||
}
|
||||
})
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in a new issue