add whitelist management

This commit is contained in:
Izalia Mae 2020-01-20 03:44:17 -05:00
parent c3efd9adc1
commit 545a68eeb1
10 changed files with 262 additions and 30 deletions

View file

@ -171,6 +171,38 @@ def wl_check(domain):
return pawsdb.whitelist.get(query.domain == domain)
def admin_check(handle):
user = get_user(handle)
if not user:
return
userid = user['id']
user_data = mastodb.query(f'SELECT * FROM public.users WHERE account_id = \'{userid}\'').dictresult()
if not user_data or not user_data[0]['admin']:
return
return True
def whitelist(action, instance):
domain = pawsdb.whitelist.get(query.domain == instance)
if action == 'add':
if not domain:
with trans(pawsdb.whitelist) as tr:
tr.insert({'domain': instance})
elif action == 'remove':
if domain:
with trans(pawsdb.whitelist) as tr:
tr.remove(query.domain == instance)
else:
return 'InvalidAction'
pawsdb = jsondb()
query = Query()
mastodb = pgdb()

View file

@ -75,19 +75,23 @@ async def http_filter(app, handler):
ua_domain = parse_ua(ua)
domain = ua_domain if not sig_domain else sig_domain
token = request.cookies.get('paws_token')
user_data = pawsdb.users.get(query.token == token)
user_data = None if not token else pawsdb.users.get(query.token == token)
user = (user_data['handle'], user_data['instance']) if user_data and user_data.get('instance') else None
real_ip = request.headers.get('X-Real-Ip')
ua_ip = dig(ua_domain)
# add logged in user data to the request for the frontend
request['user'] = user_data
# try to find the domain for the request
if not domain:
raise error(401, 'Can\'t find instance domain')
# block nazis and general garbage
if [agent for agent in blocked_agents if agent in domain]:
logging.info(f'Blocked garbage: {domain}')
raise HTTPTeapot(body='418 This teapot kills fascists', content_type='text/plain')
for agent in blocked_agents:
if agent in ua:
logging.info(f'Blocked garbage: {domain}')
raise HTTPTeapot(body='418 This teapot kills fascists', content_type='text/plain')
# block any suspended instances
if ban_check(domain):
@ -120,22 +124,19 @@ async def http_filter(app, handler):
logging.warning(msg)
raise error(401, msg)
elif not request.path.startswith('/paws/'):
else:
logging.error('heck')
request['reqtype'] = 'html'
token = request.cookies.get('paws_token')
access_user = pawsdb.users.get(query.token == token)
if not token or not access_user:
if not token or not user_data:
return aiohttp.web.HTTPFound(f'/paws/login?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.lower(), (access_user['handle'].lower(), access_user['instance'])):
if user_ban_check(user.lower(), (user_data['handle'].lower(), user_data['instance'])):
return http_error(request, 403, 'Access Denied')
querydata = request.query
rawquery = ''
@ -151,7 +152,7 @@ async def http_filter(app, handler):
# 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) and request.method == 'GET':
logging.info(f'Trying to sign headers for {domain}')
logging.info(f'Signing fetch for whitelisted instance: {domain}')
host = MASTOCONFIG['domain']
paws_host = PAWSCONFIG['domain']

View file

@ -24,9 +24,9 @@ def webserver():
web.on_response_prepare.append(middleware.http_server_header)
web.add_routes([
aiohttp.web.route('GET', '/', views.get_paws),
aiohttp.web.route('GET', '/', views.get_home),
aiohttp.web.route('GET', '/paws', views.get_paws),
aiohttp.web.route('POST', '/paws', views.post_paws),
aiohttp.web.route('POST', '/paws/action/{action}', 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),

View file

@ -1,4 +1,7 @@
{% set default_open = 'open' %}
{% set logo_svg %}
{% include 'components/logo.svg' %}
{% endset %}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
@ -9,7 +12,7 @@
<body>
<div id="content">
<div id="header">
<h1 id="name">PAWS</h1>
<h1 id="name">{{logo_svg}}</h1>
</div>
{% block content %}{% endblock %}
@ -18,6 +21,13 @@
<p><a href="https://{{domain}}/about">{{domain}}</a></p>
</div>
<div class="grid-item col2">
{% if request.user %}
<p>{{request.user.handle}} [<a href="/paws/logout">logout</a>]</p>
{% else %}
<p>Guest [<a href="/paws/login">login</a>]</p>
{% endif %}
</div>
<div class="grid-item col3">
<p><a href="https://git.barkshark.xyz/izaliamae/paws" target="_new">PAWS/{{VERSION}}</a></p>
</div>
</div>

View file

@ -22,7 +22,7 @@
/* general */
*:not(#content) {
input, a {
transition-property: color, background-color, border, width, height;
transition-timing-function: ease-in-out;
transition-duration: 0.35s;
@ -65,6 +65,10 @@ a:hover {
color: {{saturate(primary, 0.8)}};
}
#paw_logo circle {
fill: var(--text)
}
#content {
background-color: var(--bg-color);
box-shadow: var(--shadow);

View file

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
width="200"
height="200"
viewBox="0 0 52.916666 52.916666"
version="1.1"
id="paw_logo_container">
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="paw_logo"
transform="translate(0,-244.08334)">
<circle
id="pawpad"
cx="26.458332"
cy="277.15625"
r="13.229166"
style="stroke-width:0.26458332" />
<circle
id="toebean1"
cx="18.520826"
cy="255.98961"
r="5.2916665"
style="stroke-width:0.26458332" />
<circle
id="toebean2"
cx="34.395836"
cy="255.98961"
r="5.2916665"
style="stroke-width:0.26458332" />
<circle
id="tobean3"
cx="46.566689"
cy="266.57306"
r="5.2916665"
style="stroke-width:0.26458332" />
<circle
id="toebean4"
cx="6.3499994"
cy="266.57306"
r="5.2916665"
style="stroke-width:0.26458332" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -21,6 +21,11 @@ summary:hover {
cursor: pointer;
}
#paw_logo_container {
width: 50px;
height: 50px;
}
#content {
width: 1000px;
margin: 0 auto;
@ -40,11 +45,15 @@ summary:hover {
}
#footer {
grid-template-columns: auto auto;
grid-template-columns: 100px auto 100px;
font-size: 12px;
}
#footer .col2 {
text-align: center;
}
#footer .col3 {
text-align: right;
}
@ -122,16 +131,37 @@ tr:last-child .col2 {
display: inline-grid;
}
.msg, .error {
margin-bottom: 10px;
}
/* Login */
#auth {
text-align: center;
}
.msg, .error {
margin-bottom: 10px;
#auth input[type=text] {
width: 25%;
min-width: 200px;
}
#auth input[type=text]:hover{
width: 35%;
}
#auth input[type=text]:focus {
width: 80%;
}
/* Admin */
#whitelist .col1 {
text-align: left;
}
/* Errors */
#error .msg {
text-align: center;
}
@ -140,6 +170,7 @@ tr:last-child .col2 {
font-size: 48px;
}
/* mobile/small screen */
@media (max-width : 1000px) {
#content {

View file

@ -0,0 +1,11 @@
{% extends "base.html" %}
{% set page = 'Home' %}
{% block content %}
<div class="section" id="auth">
<h2 class="title">PAWS</h2>
UvU
</div>
{% endblock %}

View file

@ -0,0 +1,42 @@
{% extends "base.html" %}
{% set page = 'Control Panel' %}
{% block content %}
<div class="section" id="auth">
<h2 class="title">Control Panel</h2>
UvU<br /><br />
{% if admin %}
<table id="whitelist">
<tr class="header">
<td class="col1">Instance</td>
<td>Remove</td>
</tr>
{% if len(whitelist) > 0 %}
{% for instance in whitelist %}
<tr class="instance">
<td class="col1"><a href="https://{{instance}}/about">{{instance}}</a></td>
<td>
<form action="https://{{domain}}/paws/action/remove" method="post">
<input name="name" value="{{instance}}" hidden>
<input type="submit" value="X">
</form>
</td>
{% endfor %}
</tr>
{% else %}
<tr><td>none</td><td></td></tr>
{% endif %}
<tr class="instance">
<form action="https://{{domain}}/paws/action/add" method="post">
<td class="col1"><input type="text" name="name" placeholder="bofa.lol"></td>
<td>
<input type="submit" value="Add">
</td>
</form>
</table>
{% endif %}
</div>
{% endblock %}

View file

@ -1,17 +1,65 @@
import aiohttp
import random
import traceback
import logging
from aiohttp_jinja2 import render_template as render
from urllib.parse import quote_plus, unquote_plus
from urllib.parse import quote_plus, unquote_plus, urlparse
from .database import pawsdb, trans, query, where, keys, ban_check, get_user, get_toot
from .database import pawsdb, trans, query, where, keys, ban_check, get_user, get_toot, admin_check, whitelist
from .functions import error, http_error, fed_domain, domain_check
from .oauth import create_app, login
from .config import MASTOCONFIG, PAWSCONFIG
from .cache import TTLCache
async def get_home(request):
'heck2'
return render('pages/home.html', request, {})
async def get_paws(request):
token = request.cookies.get('paws_token')
user_data = pawsdb.users.get(query.token == token)
admin = admin_check(user_data['handle']) if user_data else None
if admin:
whitelist = [line['domain'] for line in pawsdb.whitelist.all()]
else:
whitelist = None
return render('pages/panel.html', request, {'admin': admin, 'whitelist': whitelist})
async def post_paws(request):
data = await request.post()
token = request.cookies.get('paws_token')
user_data = pawsdb.users.get(query.token == token)
domain = data.get('name')
action = request.match_info['action']
admin = admin_check(user_data['handle']) if user_data else None
if not admin:
return http_error(request, 403, 'Not an admin')
if None in [action, domain]:
return http_error(request, 400, 'Missing action or doamin')
domain = urlparse(domain.replace(' ', ''))
parsed_domain = domain.netloc if domain.netloc != '' else domain.path
if action not in ['add', 'remove']:
http_error(request, 400, 'Invalid action')
whitelist(action, parsed_domain)
return aiohttp.web.HTTPFound('/paws')
async def get_login(request):
parms = request.rel_url.query
redir = parms.get('redir')
@ -115,15 +163,6 @@ async def get_style(request):
return response
async def get_paws(request):
'heck'
return aiohttp.web.json_response('UvU', status=200)
async def post_paws(request):
return aiohttp.web.json_response('UvU', status=200)
async def get_webfinger(request):
domain = PAWSCONFIG['domain']
res = request.rel_url.query.get('resource')