fix webfinger, move functions, and handle other methods
This commit is contained in:
parent
e04dd99dc1
commit
c3efd9adc1
|
@ -1,11 +1,13 @@
|
|||
import re
|
||||
import json
|
||||
import logging
|
||||
import socket
|
||||
|
||||
import aiohttp
|
||||
import validators
|
||||
|
||||
from http import client as http
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from colour import Color
|
||||
from aiohttp_jinja2 import render_template as render
|
||||
|
@ -94,6 +96,42 @@ def user_check(path):
|
|||
return False
|
||||
|
||||
|
||||
def parse_sig(signature, short=False):
|
||||
if not signature:
|
||||
return
|
||||
|
||||
for line in signature.split(','):
|
||||
if 'keyid' in line.lower():
|
||||
actor = line.split('=')[1].split('#')[0].replace('"', '')
|
||||
return urlparse(actor).netloc if short else actor
|
||||
|
||||
|
||||
def parse_ua(agent):
|
||||
if not agent:
|
||||
return
|
||||
|
||||
url = re.findall('https?://(?:[-\w.]|(?:%[\da-fA-F]))+', agent)
|
||||
|
||||
if not url:
|
||||
if 'mozilla' not in agent.lower():
|
||||
logging.debug('Failed to find url in user agent')
|
||||
|
||||
return 'unknown'
|
||||
|
||||
return urlparse(url[0]).netloc
|
||||
|
||||
|
||||
def dig(domain):
|
||||
if not domain or domain == 'unknown':
|
||||
return
|
||||
|
||||
try:
|
||||
return socket.gethostbyname(domain)
|
||||
|
||||
except socket.gaierror as e:
|
||||
logging.info(f'Failed to resolve IP: {e}')
|
||||
|
||||
|
||||
class color:
|
||||
def __init__(self):
|
||||
self.check = lambda color: Color(f'#{str(color)}' if re.search(r'^(?:[0-9a-fA-F]{3}){1,2}$', color) else color)
|
||||
|
|
|
@ -4,12 +4,10 @@ import logging
|
|||
import binascii
|
||||
import base64
|
||||
import traceback
|
||||
import socket
|
||||
|
||||
import aiohttp
|
||||
|
||||
from urllib.parse import urlparse, quote_plus
|
||||
from http import client as http
|
||||
from random import choice
|
||||
|
||||
from aiohttp_jinja2 import render_template as render
|
||||
|
@ -18,7 +16,7 @@ from aiohttp.client_exceptions import *
|
|||
from Crypto.PublicKey import RSA
|
||||
|
||||
from .signature import validate, pass_hash, sign_headers
|
||||
from .functions import error, user_check, domain_check
|
||||
from .functions import error, user_check, domain_check, parse_sig, parse_ua, dig
|
||||
from .config import MASTOCONFIG, PAWSCONFIG, VERSION, script_path
|
||||
from .database import pawsdb, query, trans, ban_check, user_ban_check, banned_user_check, wl_check, keys
|
||||
|
||||
|
@ -47,81 +45,19 @@ auth_paths = [
|
|||
]
|
||||
|
||||
|
||||
def parse_sig(signature, short=False):
|
||||
if not signature:
|
||||
return
|
||||
|
||||
for line in signature.split(','):
|
||||
if 'keyid' in line.lower():
|
||||
actor = line.split('=')[1].split('#')[0].replace('"', '')
|
||||
return urlparse(actor).netloc if short else actor
|
||||
|
||||
|
||||
def parse_ua(agent):
|
||||
if not agent:
|
||||
return
|
||||
|
||||
ua1 = agent.split('https://')
|
||||
|
||||
if len(ua1) < 2:
|
||||
logging.debug(f'No url in user-agent: {agent}')
|
||||
return 'unknown'
|
||||
|
||||
if 'mastodon' in agent:
|
||||
ua2 = ua1[1].split('/')
|
||||
|
||||
elif 'pleroma' in agent:
|
||||
ua2 = ua1[1].split(' <')
|
||||
|
||||
elif 'misskey' in agent or 'barksharkrelay' in agent:
|
||||
ua2 = ua1[1].split(')')
|
||||
|
||||
elif 'friendica' in agent or 'microblog.pub' in agent or 'paws' in agent:
|
||||
return ua1[1]
|
||||
|
||||
else:
|
||||
logging.warning(f'Unhandled user-agent: {agent}')
|
||||
return 'unknown'
|
||||
|
||||
if len(ua2) > 1:
|
||||
logging.debug(f'domain: {ua2}')
|
||||
return ua2[0]
|
||||
|
||||
logging.warning(f'Invalid user-agent: {ua2}')
|
||||
|
||||
|
||||
def dig(domain):
|
||||
if not domain or domain == 'unknown':
|
||||
return
|
||||
|
||||
try:
|
||||
return socket.gethostbyname(domain)
|
||||
|
||||
except socket.gaierror as e:
|
||||
logging.info(f'Failed to resolve IP: {e}')
|
||||
|
||||
|
||||
async def raise_auth_error(request, auth_realm):
|
||||
raise aiohttp.web.HTTPUnauthorized(
|
||||
headers={aiohttp.hdrs.WWW_AUTHENTICATE: f'Basic realm={auth_realm}'},
|
||||
body=open(f'{script_path}/templates/unauthorized.html').read(),
|
||||
content_type='text/html'
|
||||
)
|
||||
|
||||
|
||||
async def passthrough(path, headers, urlquery=None, is_json=False):
|
||||
async def passthrough(request, headers, urlquery=None, is_json=False):
|
||||
QUERY = urlquery if urlquery else ''
|
||||
|
||||
try:
|
||||
# I don't think I need this, but I'll leave it here just in case
|
||||
#async with aiohttp.request(reqtype, f'https://{MASTOCONFIG["domain"]}/{path}{query}', headers=headers, data=post) as resp:
|
||||
|
||||
async with aiohttp.request('GET', f'http://localhost:3000{path}?{urlquery}', headers=headers) as resp:
|
||||
async with aiohttp.request(request.method, f'http://localhost:3000{request.path}?{urlquery}', headers=headers) as resp:
|
||||
data = await resp.read()
|
||||
|
||||
if resp.status != 200:
|
||||
logging.debug(data)
|
||||
logging.info(f'Recieved error {resp.status} from Mastodon')
|
||||
logging.warning(data)
|
||||
logging.warning(f'Recieved error {resp.status} from Mastodon')
|
||||
return error(resp.status, f'Failed to forward request. Recieved error {resp.status} from Mastodon')
|
||||
|
||||
return aiohttp.web.HTTPOk(body=data, content_type=resp.content_type)
|
||||
|
@ -214,7 +150,7 @@ async def http_filter(app, handler):
|
|||
urlquery = rawquery if rawquery != '?' else None
|
||||
|
||||
# This is supposed to sign whitelisted unsigned GETs, but it didn't work
|
||||
if not signature and real_ip == ua_ip and wl_check(domain):
|
||||
if not signature and real_ip == ua_ip and wl_check(domain) and request.method == 'GET':
|
||||
logging.info(f'Trying to sign headers for {domain}')
|
||||
|
||||
host = MASTOCONFIG['domain']
|
||||
|
@ -225,10 +161,10 @@ async def http_filter(app, handler):
|
|||
'Accept': 'application/json',
|
||||
'User-Agent': f'PAWS/{VERSION}; https://{host}',
|
||||
'Host': host,
|
||||
'X-Forwarded-For': request.headers.get('X-Forwarded-For', 'localhost'),
|
||||
'X-Forwarded-For': request.headers.get('X-Forwarded-For', request.remote),
|
||||
'X-Forwarded-Port': '443',
|
||||
'X-Forwarded-Proto': 'https',
|
||||
'X-Real-Ip': request.headers.get('X-Real-Ip', 'localhost')
|
||||
'X-Real-Ip': request.headers.get('X-Real-Ip', request.remote)
|
||||
}
|
||||
HEADERS['signature'] = sign_headers(HEADERS, 'default', f'https://{paws_host}/paws/actor#main-key')
|
||||
HEADERS.pop('(request-target)')
|
||||
|
@ -238,7 +174,7 @@ async def http_filter(app, handler):
|
|||
|
||||
is_json = True if request.get('reqtype') == 'json' else False
|
||||
|
||||
get_data = await passthrough(request.path, HEADERS, urlquery=urlquery, is_json=is_json)
|
||||
get_data = await passthrough(request, HEADERS, urlquery=urlquery, is_json=is_json)
|
||||
return get_data
|
||||
|
||||
return (await handler(request))
|
||||
|
|
|
@ -23,6 +23,7 @@ REDIR_URI = f'https://{MASTOCONFIG["domain"]}/paws/auth'
|
|||
WEBSITE = 'https://git.barkshark.xyz/izaliamae/paws'
|
||||
|
||||
|
||||
# some instances use a different domain for federation
|
||||
def get_webhost(domain):
|
||||
try:
|
||||
conn = http.HTTPSConnection(domain)
|
||||
|
|
|
@ -34,7 +34,6 @@ async def post_login(request):
|
|||
return aiohttp.web.HTTPFound('https://www.youtube.com/watch?v=dQw4w9WgXcQ')
|
||||
|
||||
domain = domain_check(domain)
|
||||
print(domain)
|
||||
|
||||
if not domain:
|
||||
return http_error(request, 200, 'Invalid domain')
|
||||
|
@ -117,6 +116,7 @@ async def get_style(request):
|
|||
|
||||
|
||||
async def get_paws(request):
|
||||
'heck'
|
||||
return aiohttp.web.json_response('UvU', status=200)
|
||||
|
||||
|
||||
|
@ -124,41 +124,31 @@ async def post_paws(request):
|
|||
return aiohttp.web.json_response('UvU', status=200)
|
||||
|
||||
|
||||
async def get_json(request):
|
||||
user = request.match_info['user'].replace('.json', '')
|
||||
toot = request.match_info['toot'].replace('.json', '')
|
||||
domain = MASTOCONFIG['domain']
|
||||
|
||||
|
||||
|
||||
return aiohttp.web.json_response(data)
|
||||
|
||||
|
||||
async def get_webfinger(request):
|
||||
domain = PAWSCONFIG['domain']
|
||||
res = request.rel_url.query.get('resource')
|
||||
|
||||
if not res or res != 'paws':
|
||||
if not res or res != f'acct:paws@{domain}':
|
||||
data = {}
|
||||
|
||||
else:
|
||||
data = {
|
||||
"aliases": [
|
||||
"https://{domain}/paws/actor"
|
||||
f"https://{domain}/paws/actor"
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"href": "https://{domain}/paws/actor",
|
||||
"href": f"https://{domain}/paws/actor",
|
||||
"rel": "self",
|
||||
"type": "application/activity+json"
|
||||
},
|
||||
{
|
||||
"href": "https://{domain}/paws/actor",
|
||||
"href": f"https://{domain}/paws/actor",
|
||||
"rel": "self",
|
||||
"type": "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
|
||||
}
|
||||
],
|
||||
"subject": "acct:paws@{domain}"
|
||||
"subject": f"acct:paws@{domain}"
|
||||
}
|
||||
|
||||
return aiohttp.web.json_response(data)
|
||||
|
|
Loading…
Reference in a new issue