check personal user bans
This commit is contained in:
parent
69cb899a93
commit
3c3f49c110
|
@ -107,5 +107,5 @@ class LRUCache:
|
|||
if key in self.items:
|
||||
return self.items[key]
|
||||
|
||||
return None
|
||||
return
|
||||
|
||||
|
|
|
@ -53,9 +53,8 @@ else:
|
|||
PAWSCONFIG = {
|
||||
'host': env.get('PAWS_HOST', '127.0.0.1'),
|
||||
'port': int(env.get('PAWS_PORT', 3001)),
|
||||
'user': env.get('PAWS_USER', 'admin'),
|
||||
'pass': env.get('PAWS_PASS', 'password'),
|
||||
'mastopath': env.get('MASTOPATH', os.getcwd())
|
||||
'admin': env.get('PAWS_ADMIN', None),
|
||||
'mastopath': env.get('MASTOPATH', os.getcwd()),
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
import sys
|
||||
|
||||
from DBUtils.PooledPg import PooledPg as DB
|
||||
from datetime import datetime
|
||||
from urllib.parse import urlparse
|
||||
from json.decoder import JSONDecodeError
|
||||
|
||||
from DBUtils.PooledPg import PooledPg as DB
|
||||
from tinydb import TinyDB, Query, where
|
||||
from tinydb_smartcache import SmartCacheTable
|
||||
from tinyrecord import transaction as trans
|
||||
from tldextract import extract
|
||||
from urllib.parse import urlparse
|
||||
from json.decoder import JSONDecodeError
|
||||
from Crypto.PublicKey import RSA
|
||||
|
||||
from .config import stor_path, logging, MASTOCONFIG as mdb
|
||||
from .functions import bool_check
|
||||
from .cache import LRUCache
|
||||
|
||||
|
||||
def jsondb():
|
||||
|
@ -24,7 +27,7 @@ def jsondb():
|
|||
db.table_class = SmartCacheTable
|
||||
|
||||
class table:
|
||||
bans = db.table('bans')
|
||||
keys = db.table('keys')
|
||||
follows = db.table('follows')
|
||||
users = db.table('users')
|
||||
|
||||
|
@ -44,6 +47,34 @@ def pgdb():
|
|||
sys.exit()
|
||||
|
||||
|
||||
def keys(actor):
|
||||
if pawsdb.keys.get(query.actor == actor) == None:
|
||||
logging.info(f'No RSA key. Generating one for {actor}...')
|
||||
PRIV = RSA.generate(4096)
|
||||
PUB = PRIV.publickey()
|
||||
|
||||
keydata = {
|
||||
'actor': actor,
|
||||
'pubkey': PUB.exportKey('PEM').decode('utf-8'),
|
||||
'privkey': PRIV.exportKey('PEM').decode('utf-8')
|
||||
}
|
||||
|
||||
with trans(pawsdb.keys) as tr:
|
||||
tr.insert(keydata)
|
||||
|
||||
|
||||
return pawsdb.keys.get(query.actor == actor)
|
||||
|
||||
|
||||
def get_handle(userid):
|
||||
user_data = mastodb.query(f'SELECT * FROM public.accounts WHERE id = \'{userid}\'').dictresult()
|
||||
|
||||
if len(user_data) < 1:
|
||||
return
|
||||
|
||||
return (user_data[0]['username'].lower(), user_data[0]['domain'].lower())
|
||||
|
||||
|
||||
def get_bans(suspend=True, details=False):
|
||||
domains = mastodb.query('SELECT * FROM public.domain_blocks;').dictresult()
|
||||
banlist = {} if details else []
|
||||
|
@ -84,6 +115,32 @@ def ban_check(url):
|
|||
logging.debug(f'{parsed} not in blocklist')
|
||||
|
||||
|
||||
def user_ban_check(user, access_user):
|
||||
user_data = mastodb.query(f'SELECT * FROM public.accounts WHERE username = \'{user}\'').dictresult()
|
||||
|
||||
if len(user_data) < 1:
|
||||
return
|
||||
|
||||
userid = user_data[0]['id']
|
||||
userban_query = mastodb.query(f'SELECT * FROM public.blocks WHERE account_id = \'{userid}\'').dictresult()
|
||||
userbans = []
|
||||
|
||||
for ban in userban_query:
|
||||
acct_id = ban['target_account_id']
|
||||
user = get_handle(acct_id)
|
||||
|
||||
if user:
|
||||
userbans.append(user)
|
||||
|
||||
else:
|
||||
logging.warning(f'Invalid userid: {acct_id}')
|
||||
|
||||
if access_user in userbans:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
pawsdb = jsondb()
|
||||
query = Query()
|
||||
mastodb = pgdb()
|
||||
|
|
|
@ -3,6 +3,8 @@ import re
|
|||
import json
|
||||
import logging
|
||||
|
||||
from http import client as http
|
||||
|
||||
from colour import Color
|
||||
from aiohttp_jinja2 import render_template as render
|
||||
|
||||
|
@ -46,6 +48,27 @@ def error(code, error):
|
|||
raise eval('aiohttp.web.HTTP'+error_codes[code]+'(body=error_body, content_type=cont_type)')
|
||||
|
||||
|
||||
def fed_domain(user, domain):
|
||||
headers = {'Accept': 'application/json'}
|
||||
conn = http.HTTPSConnection(domain)
|
||||
conn.request('GET', f'/.well-known/webfinger?resource=acct:{user}@{domain}', headers=headers)
|
||||
response = conn.getresponse()
|
||||
|
||||
if response.status != 200:
|
||||
return
|
||||
|
||||
try:
|
||||
data = json.loads(response.read())
|
||||
|
||||
except:
|
||||
logging.debug(f'Invalid user: {user}@{domain}')
|
||||
|
||||
wf_data = data.get('subject')
|
||||
user_data = wf_data.replace('acct:', '').split('@')
|
||||
|
||||
return user_data[1]
|
||||
|
||||
|
||||
def user_check(path):
|
||||
parsed = path.replace('.json', '').split('/')
|
||||
|
||||
|
|
|
@ -7,13 +7,14 @@ import base64
|
|||
import traceback
|
||||
|
||||
from urllib.parse import urlparse, quote_plus
|
||||
from aiohttp_jinja2 import render_template as render
|
||||
from aiohttp.http_exceptions import *
|
||||
from aiohttp.client_exceptions import *
|
||||
|
||||
from .signature import validate, pass_hash
|
||||
from .functions import error, user_check
|
||||
from .config import MASTOCONFIG, PAWSCONFIG, VERSION, script_path
|
||||
from .database import pawsdb, query, trans, ban_check
|
||||
from .database import pawsdb, query, trans, ban_check, user_ban_check
|
||||
|
||||
|
||||
# I'm a little teapot :3
|
||||
|
@ -94,7 +95,10 @@ async def passthrough(path, headers, post=None, query=None):
|
|||
querydata = query if query else ''
|
||||
|
||||
try:
|
||||
async with aiohttp.request(reqtype, f'https://{MASTOCONFIG["domain"]}/{path}{query}', headers=headers, data=post) as resp:
|
||||
# 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(reqtype, f'http://localhost:3000/{path}{query}', headers=headers, data=post) as resp:
|
||||
data = await resp.read()
|
||||
|
||||
if resp.status not in [200, 202]:
|
||||
|
@ -163,9 +167,16 @@ async def http_signatures(app, handler):
|
|||
request['reqtype'] = 'html'
|
||||
|
||||
token = request.cookies.get('paws_token')
|
||||
access_user = pawsdb.users.get(query.token == token)
|
||||
|
||||
if not token or not pawsdb.users.get(query.token == token):
|
||||
return aiohttp.web.HTTPFound(f'/paws/login?redir={quote_plus(request.path)}')
|
||||
if not token or not access_user:
|
||||
return aiohttp.web.HTTPFound(f'/paws/login?msg=InvalidToken&redir={quote_plus(request.path)}')
|
||||
|
||||
split_path = request.path.split('/')
|
||||
user = split_path[1].replace('@', '') if request.path.startswith('/@') else split_path[2]
|
||||
|
||||
if user_ban_check(user, (access_user['handle'].lower(), access_user['instance'])):
|
||||
return render('pages/error.html', request, {'msg': 'Access Denied', 'code': '403'}, status=403)
|
||||
|
||||
return (await handler(request))
|
||||
return http_signatures_handler
|
||||
|
@ -208,7 +219,7 @@ async def http_trailing_slash(app, handler):
|
|||
|
||||
|
||||
async def http_server_header(request, response):
|
||||
response.headers['SErver'] = f'PAWS/{VERSION}'
|
||||
response.headers['Server'] = f'PAWS/{VERSION}'
|
||||
response.headers['trans_rights'] = 'are human rights'
|
||||
|
||||
|
||||
|
|
|
@ -25,11 +25,15 @@ def webserver():
|
|||
web.on_response_prepare.append(middleware.http_server_header)
|
||||
|
||||
web.add_routes([
|
||||
aiohttp.web.route('GET', '/paws', views.get_paws),
|
||||
aiohttp.web.route('POST', '/paws', views.post_paws),
|
||||
aiohttp.web.route('GET', '/paws/login', views.get_login),
|
||||
aiohttp.web.route('POST', '/paws/login', views.post_login),
|
||||
aiohttp.web.route('GET', '/paws/logout', views.get_logout),
|
||||
aiohttp.web.route('GET', '/paws/auth', views.get_auth),
|
||||
aiohttp.web.route('GET', '/paws/style.css', views.get_style)
|
||||
aiohttp.web.route('GET', '/paws/style.css', views.get_style),
|
||||
aiohttp.web.route('POST', '/paws/inbox', views.post_inbox),
|
||||
aiohttp.web.route('GET', '/paws/actor', views.get_actor)
|
||||
])
|
||||
|
||||
async def global_vars(request):
|
||||
|
|
|
@ -4,16 +4,21 @@ import random
|
|||
from aiohttp_jinja2 import render_template as render
|
||||
from urllib.parse import quote_plus, unquote_plus
|
||||
|
||||
from .database import pawsdb, trans, query, where
|
||||
from .functions import error
|
||||
from .database import pawsdb, trans, query, where, keys
|
||||
from .functions import error, fed_domain
|
||||
from .oauth import create_app, login
|
||||
from .config import MASTOCONFIG
|
||||
|
||||
|
||||
async def get_login(request):
|
||||
parms = request.rel_url.query
|
||||
redir = parms.get('redir')
|
||||
token = request.cookies.get('paws_token')
|
||||
numid = random.randint(1*1000000, 10*1000000-1)
|
||||
|
||||
if pawsdb.users.get(query.token == token):
|
||||
return aiohttp.web.HTTPFound(f'/about')
|
||||
|
||||
return render('pages/login.html', request, {'redir': redir, 'numid': numid})
|
||||
|
||||
|
||||
|
@ -26,13 +31,15 @@ async def post_login(request):
|
|||
if domain in ['', None]:
|
||||
return render('pages/login.html', request, {'msg': 'Missing domain'})
|
||||
|
||||
if ban_check(domain):
|
||||
return render('pages/error.html', request, {'msg': 'Instance banned', 'code': '403'}, status=403)
|
||||
|
||||
appid, appsecret, redir_url = create_app(domain)
|
||||
|
||||
with trans(pawsdb.users) as tr:
|
||||
tr.insert({
|
||||
'handle': data['numid'],
|
||||
'domain': data['domain'],
|
||||
'icon': None,
|
||||
'appid': appid,
|
||||
'appsecret': appsecret,
|
||||
'token': None
|
||||
|
@ -55,13 +62,17 @@ async def get_auth(request):
|
|||
code = parms.get('code')
|
||||
|
||||
if None in [numid, code]:
|
||||
response = render('pages/error.html', request, {'msg': 'Missing temporary userid or auth code', 'code': 500}, status=500)
|
||||
return render('pages/error.html', request, {'msg': 'Missing temporary userid or auth code', 'code': '500'}, status=500)
|
||||
|
||||
if redir in ['', None]:
|
||||
redir = '/about'
|
||||
|
||||
user = pawsdb.users.get(query.handle == str(numid))
|
||||
token, userinfo = login(user, code)
|
||||
instance = fed_domain(userinfo['username'], user['domain'])
|
||||
|
||||
with trans(pawsdb.users) as tr:
|
||||
tr.update({'handle': userinfo['username'], 'icon': userinfo['avatar_static'], 'token': token}, where('handle') == numid)
|
||||
tr.update({'handle': userinfo['username'], 'instance': instance, 'token': token}, where('handle') == numid)
|
||||
|
||||
print(user)
|
||||
|
||||
|
@ -90,3 +101,50 @@ async def get_style(request):
|
|||
|
||||
return response
|
||||
|
||||
|
||||
async def get_actor(request):
|
||||
rsakey = keys('default')
|
||||
HOST = MASTOCONFIG['domain']
|
||||
|
||||
if not rsakey:
|
||||
render('pages/error.html', request, {'msg': 'Missing actor keys', 'code': 500}, status=500)
|
||||
|
||||
PUBKEY = rsakey['pubkey']
|
||||
|
||||
data = {
|
||||
'@context': [
|
||||
'https://www.w3.org/ns/activitystreams'
|
||||
],
|
||||
'endpoints': {
|
||||
'sharedInbox': f'https://{HOST}/inbox'
|
||||
},
|
||||
'inbox': f'https://{HOST}/paws/inbox',
|
||||
'name': f'PAWS @ {HOST}',
|
||||
'type': 'Application',
|
||||
'id': f'https://{HOST}/paws/actor',
|
||||
'publicKey': {
|
||||
'id': f'https://{HOST}/paws/actor#main-key',
|
||||
'owner': f'https://{HOST}/paws/actor',
|
||||
'publicKeyPem': PUBKEY
|
||||
},
|
||||
'summary': 'PAWS Actor',
|
||||
'preferredUsername': 'paws',
|
||||
'url': f'https://{HOST}/paws/actor'
|
||||
}
|
||||
|
||||
return aiohttp.web.json_response(data)
|
||||
|
||||
|
||||
async def post_inbox(request):
|
||||
return aiohttp.web.json_response('UvU', status=202)
|
||||
|
||||
|
||||
async def get_paws(request):
|
||||
return aiohttp.web.json_response('UvU', status=202)
|
||||
|
||||
|
||||
async def post_paws(request):
|
||||
return aiohttp.web.json_response('UvU', status=202)
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue