add whitelist management
This commit is contained in:
parent
c3efd9adc1
commit
545a68eeb1
|
@ -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()
|
||||
|
|
|
@ -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']
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
|
62
paws/templates/components/logo.svg
Normal file
62
paws/templates/components/logo.svg
Normal 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 |
|
@ -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 {
|
||||
|
|
|
@ -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 %}
|
42
paws/templates/pages/panel.html
Normal file
42
paws/templates/pages/panel.html
Normal 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 %}
|
|
@ -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')
|
||||
|
|
Loading…
Reference in a new issue