basic greylist functionality

This commit is contained in:
Izalia Mae 2020-04-28 00:57:46 -04:00
parent 67efd787c7
commit ada71fb7d7
12 changed files with 404 additions and 182 deletions

View file

@ -28,18 +28,24 @@ if not isfile(f'{stor_path}/production.env'):
logging.error(f'PAWS environment file doesn\'t exist: {stor_path}/production.env')
logging.info('Creating a new config file. Be sure to edit it and restart PAWS')
new_config = '''
### Uncomment and adjust any values as necessary
new_config = '''###
# Uncomment and adjust any values as necessary
###
### Port and host PAWS will listen on
#PAWS_HOST=127.0.0.1
#PAWS_PORT=3001
#PAWS_DOMAIN=bappypaws.example.com
#PAWS_NORSS=true
### Require approval for unknown instances. Set to true for all AP servers or a comma-separated list for specific server software
### Ex: mastodon,pleroma,miskey,activityrelay,unciarelay,other,unidentified
### Require approval for unknown instances. They can be accepted or denied at {{MASTODOMAIN}}/paws/list/requests
#PAWS_REQ_APPROVAL=false
### Override domain in mastodon's config
#MASTODOMAIN=mastodon.example.com
###
#MASTOPATH=/home/mastodon/glitch-soc
#MASTOHOST=localhost:3000
'''
@ -53,10 +59,7 @@ else:
load_envbash(f'{stor_path}/production.env')
req_approval = boolean(env.get('PAWS_REQ_APPROVAL', False), False)
if not isinstance(req_approval, bool):
req_approval = [sw.strip() for sw in req_approval.split(',')]
req_approval = boolean(env.get('PAWS_REQ_APPROVAL'), False)
PAWSCONFIG = {
@ -64,7 +67,7 @@ PAWSCONFIG = {
'port': int(env.get('PAWS_PORT', 3001)),
'domain': env.get('PAWS_DOMAIN', 'bappypaws.example.com'),
'disable_rss': boolean(env.get('PAWS_DISABLE_RSS', True)),
'req_approval': req_approval,
'require_approval': req_approval,
'mastopath': env.get('MASTOPATH', os.getcwd()),
'mastohost': env.get('MASTOHOST', 'localhost:3000'),
}
@ -79,7 +82,7 @@ else:
load_envbash(f'{masto_path}/.env.production')
MASTOCONFIG={
'domain': env.get('WEB_DOMAIN', env.get('LOCAL_DOMAIN', 'localhost:3000')),
'domain': env.get('MASTODOMAIN', env.get('WEB_DOMAIN', env.get('LOCAL_DOMAIN', 'localhost:3000'))),
'auth_fetch': boolean(env.get('AUTHORIZED_FETCH')),
'dbhost': env.get('DB_HOST', '/var/run/postgresql'),
'dbport': int(env.get('DB_PORT', 5432)),
@ -87,4 +90,3 @@ MASTOCONFIG={
'dbuser': env.get('DB_USER', env.get('USER')),
'dbpass': env.get('DB_PASS')
}

View file

@ -17,7 +17,7 @@ from Crypto.PublicKey import RSA
from mastodon import Mastodon
from mastodon.Mastodon import MastodonUnauthorizedError, MastodonBadGatewayError, MastodonNetworkError
from .config import stor_path, MASTOCONFIG as mdb
from .config import stor_path, PAWSCONFIG, MASTOCONFIG as mdb
from .functions import fetch, get_nodeinfo
@ -36,6 +36,7 @@ def jsondb():
instances = db.table('instances')
users = db.table('users')
whitelist = db.table('whitelist')
request = db.table('request')
return table
@ -223,51 +224,77 @@ def whitelist(action, instance):
def get_instances(domain=None, state=None):
if domain:
rows = table.instances.get(query.domain == domain)
rows = pawsdb.instances.get(query.domain == domain)
elif state:
rows = table.instances.search(query.state == state)
rows = pawsdb.instances.search(query.state == state)
else:
rows = table.instances.all()
rows = pawsdb.instances.all()
return rows
def instances(action, instance, state=None):
def instances(action, instance, state='request'):
logging.debug(', '.join([action, instance, state]))
if None in [action, instance, state]:
return False
domain = urlparse(instance).netloc if instance.startswith('http') else instance
req_data = table.requests.get(query.domain == domain)
instance_data = pawsdb.instances.get(query.domain == domain)
state = state.lower()
if action == 'add':
if not state:
logging.debug('Instance state not specified')
return
if instance_data:
logging.debug(f'Updating instance state: {domain}, {state}')
with trans(pawsdb.instances) as tr:
tr.update({'state': state}, doc_ids=[instance_data.doc_id])
if req_data:
logging.debug(f'Domain already in request list: {domain}')
return
ni_software = get_nodeinfo(domain)
if not ni_software:
logging.debug(f'Failed to get nodeinfo data from instance: {domain}')
return
data = {
'instance': domain,
'domain': domain,
'software': ni_software['name'],
'state': state,
'timestamp': datetime.timestamp(datetime.now())
}
with trans(table.instances) as tr:
with trans(pawsdb.instances) as tr:
tr.insert(data)
elif action == 'remove':
if not req_data:
if not instance_data:
logging.debug(f'Domain not in request list: {domain}')
with trans(table.instances) as tr:
tr.remove(doc_ids=[req_data.doc_id])
with trans(pawsdb.instances) as tr:
tr.remove(doc_ids=[instance_data.doc_id])
def instance_check(domain):
timestamp = datetime.timestamp(datetime.now())
instance = pawsdb.instances.get(query.domain == domain)
state = instance.get('state') if instance else None
if not domain:
return False
if state == 'accept' or domain == mdb['domain']:
return True
elif state == 'deny':
return False
elif not state:
result = instances('add', domain)
return
def cleanup_users(invalid_check=None):

View file

@ -54,7 +54,7 @@ def get_nodeinfo(instance):
nodeinfo = fetch(f'https://{domain}/nodeinfo/2.0.json')
if not nodeinfo:
if not nodeinfo or (isinstance(nodeinfo, dict) and nodeinfo.get('error')):
logging.debug('Wrong nodeinfo url. Finding correct one...')
wk_url = f'https://{domain}/.well-known/nodeinfo'
well_known = fetch(wk_url)

View file

@ -1,13 +1,9 @@
import asyncio
import json
import binascii
import base64
import traceback
import asyncio, json, binascii, base64, traceback, aiohttp
import aiohttp
from urllib.parse import urlparse, quote_plus
from urllib.parse import urlparse, quote_plus, unquote_plus
from random import choice
from os.path import isfile
from http import client as HTTP
from IzzyLib import logging
from IzzyLib.misc import boolean
@ -18,17 +14,12 @@ from Crypto.PublicKey import RSA
from .signature import validate, pass_hash, sign_headers
from .functions import error, user_check, domain_check, parse_sig, parse_ua, dig, distill_query, get_nodeinfo, httpclient
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, user_domain_ban_check, admin_check
from .database import pawsdb, query, trans, ban_check, user_ban_check, banned_user_check, wl_check, keys, user_domain_ban_check, admin_check, instance_check, instances
paws_host = PAWSCONFIG['domain']
masto_host = MASTOCONFIG['domain']
# I'm a little teapot :3
class HTTPTeapot(aiohttp.web.HTTPError):
status_code = 418
masto_path = PAWSCONFIG['mastopath']
blocked_agents = [
'gabsocial',
@ -40,7 +31,9 @@ blocked_agents = [
'baraag',
'gameliberty',
'neckbeard',
'soapbox'
'soapbox',
'qoto',
'archive'
]
auth_paths = [
@ -48,6 +41,66 @@ auth_paths = [
'/users'
]
admin_paths = [
'/paws/action',
'/paws/list'
]
error_msgs = {
404: 'Not found',
500: 'Server did an oopsie'
}
def parse_headers(headers, enc=True):
new_headers = {}
for header in headers:
key, value = [item.decode() for item in header]
if key.lower() in ['content-encoding', 'transfer-encoding'] and not enc:
continue
if key in new_headers:
new_headers[key] + '; ' + value
else:
new_headers[key] = value
return new_headers
async def passthrough2(request, headers):
mastohost = PAWSCONFIG['mastohost']
raw_data = await request.read()
is_json = request.get('jsonreq', False)
Headers = parse_headers(request.raw_headers)
Headers['Proxy'] = ''
try:
timeout = aiohttp.ClientTimeout(total=5)
async with aiohttp.request(request.method, f'http://{mastohost}{request.path}?{request.query_string}', headers=Headers, data=raw_data, timeout=timeout, allow_redirects=False) as resp:
data = await resp.read()
if resp.status not in [200, 202, 301, 302]:
if data in [b'Request not signed', 'Request not signed']:
err_msg = 'Missing signature'
logging.debug(err_msg)
else:
err_msg = f'Recieved error {resp.status} from Mastodon'
logging.debug(err_msg)
return error(request, resp.status, f'Failed to forward request')
resp_headers = parse_headers(resp.raw_headers, False)
return aiohttp.web.Response(body=data, headers=resp_headers, status=resp.status)
except Exception as e:
traceback.print_exc()
return error(request, 504, f'Failed to connect to Mastodon')
async def passthrough(request, headers):
mastohost = PAWSCONFIG['mastohost']
@ -56,10 +109,9 @@ async def passthrough(request, headers):
try:
resp = httpclient.request(request.method, f'http://{mastohost}{request.path}?{request.query_string}', body=req_data, headers=headers, redirect=False)
#async with aiohttp.request(request.method, f'http://{mastohost}{request.path}?{request.query_string}', headers=headers, data=data) as resp:
data = resp.data
if resp.status not in [200, 202, 301]:
if resp.status not in [200, 202, 301, 302]:
if data in [b'Request not signed', 'Request not signed']:
err_msg = 'Missing signature'
logging.debug(err_msg)
@ -88,41 +140,46 @@ async def passthrough(request, headers):
async def http_filter(app, handler):
async def http_filter_handler(request):
signature = request.headers.get('signature')
ua = request.headers.get('user-agent').lower()
sig_domain = parse_sig(signature, short=True)
ua = request.headers.get('user-agent').lower()
ua_domain = parse_ua(ua)
domain = ua_domain if not sig_domain else sig_domain
token = request.cookies.get('paws_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
user = (user_data['handle'], user_data['instance']) if user_data and user_data.get('instance') else (None, None)
real_ip = request.headers.get('X-Real-Ip', request.remote)
ua_ip = dig(ua_domain)
nodeinfo = get_nodeinfo(domain)
software = nodeinfo['name'] if nodeinfo else None
software = nodeinfo.get('name') if nodeinfo else None
instance = domain if domain != 'unknown' else user[1]
allow = instance_check(instance)
request['jsonreq'] = True if 'json' in request.headers.get('Accept', '') or request.path.endswith('.json') else False
# Disable rss feeds
if PAWSCONFIG['disable_rss'] and request.path.endswith('.rss'):
return error(request, 403, 'RSS feeds disabled')
# add logged in user data to the request for the frontend
request['user'] = user_data
request['admin'] = admin_check(user_data['handle']) if user_data else None
if request.path in ['/paws/actor', '/paws/inbox', '/.well-known/webfinger'] and request.host != paws_host:
return aiohttp.web.HTTPFound('/paws')
# try to find the domain for the request
if not domain:
return error(request, 401, 'Can\'t find instance domain')
# block nazis and general garbage
for agent in blocked_agents:
if agent in ua:
logging.debug(f'Blocked garbage: {domain}')
return error(request, 418, '418 This teapot kills fascists')
return error(request, 418, 'This teapot kills fascists')
# Disable rss feeds
if PAWSCONFIG['disable_rss'] and request.path.endswith('.rss'):
return error(request, 403, 'RSS feeds disabled')
if request.path in ['/paws/actor', '/paws/inbox', '/.well-known/webfinger'] and request.host != paws_host:
return aiohttp.web.HTTPFound('/paws')
# give up if a domain can't be found'
if not domain:
return error(request, 401, 'Can\'t find instance domain')
# block any suspended instances
if ban_check(domain):
@ -134,7 +191,21 @@ async def http_filter(app, handler):
logging.debug(f'Blocked user: {domain}')
return error(request, 403, 'Access Denied')
# prevent unauthed users from accessing the instance lists
if any(map(request.path.startswith, admin_paths)) and not request['admin']:
return aiohttp.web.HTTPFound('/paws/login')
if any(map(request.path.startswith, auth_paths)) and request.method == 'GET':
if PAWSCONFIG['require_approval'] and not allow:
if allow != False:
status, message = (401, 'Instance awaiting approval or rejection')
instances('add', instance)
else:
status, message = (403, 'Rejected')
return error(request, status, message)
# Check signatures if auth fetches are off
if not user_check(request.path) and not MASTOCONFIG['auth_fetch']:
if signature:
@ -162,7 +233,7 @@ async def http_filter(app, handler):
if user_ban_check(user.lower(), (user_data['handle'].lower(), user_data['instance'])) or user_domain_ban_check(user.lower(), user_data['instance']):
return error(request, 403, 'Access Denied')
if signature and wl_check(domain):
if signature and wl_check(domain) and request.method == 'GET':
logging.warning(f'{domain} has started signing requests and can be removed from the whitelist')
if not signature and real_ip == ua_ip and wl_check(domain) and request.method == 'GET':
@ -185,6 +256,11 @@ async def http_filter(app, handler):
HEADERS = request.headers
if not request.path.startswith('/paws'):
masto_file = f'{masto_path}/public{request.path}'
if isfile(masto_file):
return aiohttp.web.FileResponse(masto_file, headers=HEADERS)
return_data = await passthrough(request, HEADERS)
return return_data
@ -202,6 +278,29 @@ async def http_trailing_slash(app, handler):
return http_trailing_slash_handler
# Custom error handler
async def http_error(app, handler):
async def http_error_handler(request):
try:
response = await handler(request)
#except aiohttp.web.HTTPException as ex:
# message = error_msgs.get(ex.status, 'Server did an oopsie')
# response = error(request, ex.status, message)
except Exception as e:
if getattr(e, 'status', None):
message = error_msgs.get(e.status, 'Server did an oopsie')
response = error(request, e.status, message)
else:
traceback.print_exc()
response = error(request, 500, e)
return response
return http_error_handler
async def http_server_header(request, response):
response.headers['Server'] = f'PAWS/{VERSION}'
@ -221,10 +320,8 @@ async def http_server_header(request, response):
async def http_access_log(request, response):
uagent = request.headers.get('user-agent')
client_ip = request.headers.get('X-Real-IP', request.remote)
if not request.path.endswith(('js', 'css', 'png', 'jpg', 'gif')):
uagent = request.headers.get('user-agent')
client_ip = request.headers.get('X-Real-IP', request.remote)
logging.info(f'{client_ip} {request.method} {request.path_qs} {response.status} "{uagent}"')
__all__ = ['http_signatures_middleware', 'http_auth_middleware', 'http_filter_middleware', 'http_trailing_slash', 'http_server_header']
logging.info(f'{client_ip} {request.method} {request.path_qs} {response.status} "{uagent}"')

View file

@ -103,5 +103,3 @@ def login(user, code):
return ('error', msg)
return (token, fetch_user)

View file

@ -15,7 +15,8 @@ from . import middleware, views, stor_path
def webserver():
web = aiohttp.web.Application(middlewares=[
middleware.http_filter,
middleware.http_trailing_slash
middleware.http_trailing_slash,
middleware.http_error
])
web.on_response_prepare.append(middleware.http_server_header)
@ -25,8 +26,8 @@ def webserver():
aiohttp.web.route('GET', '/paws', views.get_paws),
aiohttp.web.route('GET', '/paws/imgay', views.get_gay),
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.view('/paws/list/{list}', views.lists),
aiohttp.web.view('/paws/login', views.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-{timestamp}.css', views.get_style),

View file

@ -22,8 +22,8 @@ summary:hover {
}
#paw_logo_container {
width: 50px;
height: 50px;
width: 25px;
height: 25px;
}
#content {
@ -150,16 +150,16 @@ input[type=text]:hover {
}
input[type=text]:focus {
width: 90%;
width: 50%;
}
/* Admin */
#whitelist .col1 {
/* lists */
.list .col1 {
text-align: left;
}
#whitelist .col2 {
.list .col2 {
text-align: center;
width: 75px;
}

View file

@ -29,9 +29,11 @@
-if request.user
-if request.admin
.item
%a{'href': '/paws/whitelist', 'target': '_self'} Whitelist
%a{'href': '/paws/list/whitelist', 'target': '_self'} Whitelist
.item
%a{'href': '/paws/instances', 'target': '_self'} Instances
%a{'href': '/paws/list/signlist', 'target': '_self'} Signlist
.item
%a{'href': '/paws/list/instances', 'target': '_self'} Instances
.item
%a{'href': '/paws/logout', 'target': '_self'} Logout
-else

View file

@ -0,0 +1,106 @@
-extends 'base.html'
-set page = 'Home'
-block content
#panel{'class': 'section'}
-if listtype == 'signlist'
%center
%h2{'class': 'title'} Signlist
%table{'id': 'signlist', 'class': 'list'}
%tr{'class': 'header'}
%td
%td
-if len(signlist) > 0
-for instance in signlist
%tr{'class': 'instance'}
%td{'class': 'col1'}
%a{'href': 'https://{{instance}}/about', 'target': '_new'}= instance
%td{'class': 'col2'}
%form{'action': '/paws/action/remove', 'method': 'post'}
%input{'name': 'name', 'value': '{{instance}}', 'hidden': None}
%input{'type': 'submit', 'value': 'Remove'}
-else
%tr{'class': 'instance'}
%td none
%td
%tr{'class': 'instance'}
%form{'action': '/paws/action/add', 'method': 'post'}
%td{'class': 'col1'}
%input{'type': 'text', 'name': 'name', 'placeholder': 'mastodon.social'}
%td{'class': 'col2'}
%input{'type': 'submit', 'value': 'Add'}
-if listtype == 'requests'
%center
%h2{'class': 'title'} Requests
%table{'id': 'request', 'class': 'list'}
%tr{'class': 'header'}
%td
%td
-if len(requests) > 0
-for instance in requests
%tr{'class': 'instance'}
%td{'class': 'col1'}
%a{'href': 'https://{{instance.domain}}/about', 'target': '_new'}= instance.domain
%td{'class': 'col2'}
%form{'action': '/paws/action/add', 'method': 'post'}
%input{'name': 'name', 'value': '{{instance.domain}}', 'hidden': None}
%input{'type': 'submit', 'name': 'action', 'value': 'Deny'}
%input{'type': 'submit', 'name': 'action', 'value': 'Accept'}
%form{'action': '/paws/action/remove', 'method': 'post'}
%input{'name': 'name', 'value': '{{instance.domain}}', 'hidden': None}
%input{'type': 'submit', 'value': 'Remove'}
-else
%tr{'class': 'instance'}
%td none
%td
-if listtype == 'instances'
%center
%h2{'class': 'title'} Instances
%table{'id': 'accept', 'class': 'list'}
%tr{'class': 'header'}
%td
%td
-if len(instances) > 0
-for instance in instances
%tr{'class': 'instance'}
%td{'class': 'col1'}
%a{'href': 'https://{{instance.domain}}/about', 'target': '_new'}= instance.domain
%td{'class': 'col2'}
%form{'action': '/paws/action/add', 'method': 'post'}
%input{'name': 'name', 'value': '{{instance.domain}}', 'hidden': None}
-if instance.state == 'accept'
%input{'type': 'submit', 'name': 'action', 'value': 'Deny'}
-elif instance.state == 'deny'
%input{'type': 'submit', 'name': 'action', 'value': 'Accept'}
%form{'action': '/paws/action/remove', 'method': 'post'}
%input{'name': 'name', 'value': '{{instance.domain}}', 'hidden': None}
%input{'type': 'submit', 'value': 'Remove'}
-else
%tr{'class': 'instance'}
%td none
%td
%tr{'class': 'instance'}
%form{'action': '/paws/action/add', 'method': 'post'}
%td{'class': 'col1'}
%input{'type': 'text', 'name': 'name', 'placeholder': 'mastodon.social'}
%td{'class': 'col2'}
%input{'type': 'submit', 'name': 'action', 'value': 'Accept'}
%input{'type': 'submit', 'name': 'action', 'value': 'Deny'}

View file

@ -6,34 +6,3 @@
%h2{'class': 'title'} PAWS
%p
PAWS is an extra auth layer for public profiles and posts. The main purpose is to prevent web scrapers from hoarding posts, but it also prevents banned users from viewing toots they shouldn't see
-if admin
%center
%h2 Whitelist
%table{'id': 'whitelist'}
%tr{'class': 'header'}
%td
%td
-if len(whitelist) > 0
-for instance in whitelist
%tr{'class': 'instance'}
%td{'class': 'col1'}
%a{'href': 'https://{{instance}}/about', 'target': '_new'}= instance
%td{'class': 'col2'}
%form{'action': '/paws/action/remove', 'method': 'post'}
%input{'name': 'name', 'value': '{{instance}}', 'hidden': None}
%input{'type': 'submit', 'value': 'Remove'}
-else
%tr{'class': 'instance'}
%td none
%td
%tr{'class': 'instance'}
%form{'action': '/paws/action/add', 'method': 'post'}
%td{'class': 'col1'}
%input{'type': 'text', 'name': 'name', 'placeholder': 'mastodon.social'}
%td{'class': 'col2'}
%input{'type': 'submit', 'value': 'Add'}

View file

@ -8,9 +8,9 @@ from IzzyLib.template import aiohttpTemplate
from urllib.parse import quote_plus, unquote_plus, urlparse
from datetime import datetime
from .database import pawsdb, trans, query, where, keys, ban_check, get_user, get_toot, admin_check, whitelist
from . import oauth
from .database import pawsdb, trans, query, where, keys, ban_check, get_user, get_toot, admin_check, whitelist, instances
from .functions import error, fed_domain, domain_check, css_ts
from .oauth import create_app, login
from .config import MASTOCONFIG, PAWSCONFIG
@ -18,19 +18,92 @@ paws_host = PAWSCONFIG['domain']
masto_host = MASTOCONFIG['domain']
class login(aiohttp.web.View):
async def get(self):
parms = self.request.rel_url.query
redir = parms.get('redir')
numid = random.randint(1*1000000, 10*1000000-1)
if self.request['user']:
return aiohttp.web.HTTPFound('/paws')
data = {'redir': redir, 'numid': numid}
return aiohttpTemplate('login.html', data, self.request)
async def post(self):
data = await self.request.post()
domain = data.get('domain')
redir = data.get('redir')
numid = data.get('numid')
if 'DROP ' in domain:
return aiohttp.web.HTTPFound('https://www.youtube.com/watch?v=dQw4w9WgXcQ')
domain = domain_check(domain)
if not domain:
return error(self.request, 400, 'Invalid domain')
if ban_check(domain):
return error(self.request, 403, 'Instance banned')
appid, appsecret, redir_url = oauth.create_app(domain)
if appid == 'error':
return error(self.request, 500, appsecret)
with trans(pawsdb.users) as tr:
tr.insert({
'handle': data['numid'],
'domain': data['domain'].lower(),
'appid': appid,
'appsecret': appsecret,
'token': None,
'timestamp': datetime.timestamp(datetime.now())
})
response = aiohttp.web.HTTPFound(redir_url)
response.set_cookie('paws_numid', numid, max_age=60*60, path='/paws')
if redir not in ['', None]:
response.set_cookie('paws_redir', redir, max_age=60*60, path='/paws')
return response
class lists(aiohttp.web.View):
async def get(self):
request = self.request
listtype = request.match_info['list']
if request['admin']:
data = {
'listtype': listtype,
'signlist': [line['domain'] for line in pawsdb.whitelist.all()],
'requests': pawsdb.instances.search(query.state == 'request'),
'instances': pawsdb.instances.search(query.state != 'request')
}
else:
data = {}
if listtype not in data.keys():
return error(request, 404, 'Invalid list type')
return aiohttpTemplate('lists.html', data, request)
async def post(self):
pass
async def get_home(request):
return aiohttpTemplate('home.html', {}, request)
async def get_paws(request):
if request['admin']:
whitelist = [line['domain'] for line in pawsdb.whitelist.all()]
whitelist.sort()
else:
whitelist = None
data = {'whitelist': whitelist}
data = {}
return aiohttpTemplate('panel.html', data, request)
@ -38,8 +111,8 @@ async def post_paws(request):
data = await request.post()
user_data = request['user']
domain = data.get('name')
action = request.match_info['action']
action = request.match_info['action'].lower()
action = 'add' if action == 'update' else action
admin = admin_check(user_data['handle']) if user_data else None
if not admin:
@ -54,63 +127,10 @@ async def post_paws(request):
if action not in ['add', 'remove']:
error(request, 400, 'Invalid action')
whitelist(action, parsed_domain)
result = instances(action, parsed_domain, data.get('action', 'request'))
print(result)
return aiohttp.web.HTTPFound('/paws')
async def get_login(request):
parms = request.rel_url.query
redir = parms.get('redir')
numid = random.randint(1*1000000, 10*1000000-1)
if request['user']:
return aiohttp.web.HTTPFound('/paws')
data = {'redir': redir, 'numid': numid}
return aiohttpTemplate('login.html', data, request)
async def post_login(request):
data = await request.post()
domain = data.get('domain')
redir = data.get('redir')
numid = data.get('numid')
if 'DROP ' in domain:
return aiohttp.web.HTTPFound('https://www.youtube.com/watch?v=dQw4w9WgXcQ')
domain = domain_check(domain)
if not domain:
return error(request, 400, 'Invalid domain')
if ban_check(domain):
return error(request, 403, 'Instance banned')
appid, appsecret, redir_url = create_app(domain)
if appid == 'error':
return error(request, 500, appsecret)
with trans(pawsdb.users) as tr:
tr.insert({
'handle': data['numid'],
'domain': data['domain'].lower(),
'appid': appid,
'appsecret': appsecret,
'token': None,
'timestamp': datetime.timestamp(datetime.now())
})
response = aiohttp.web.HTTPFound(redir_url)
response.set_cookie('paws_numid', numid, max_age=60*60, path='/paws')
if redir not in ['', None]:
response.set_cookie('paws_redir', redir, max_age=60*60, path='/paws')
return response
return aiohttp.web.HTTPFound('/paws/list/instances')
async def get_auth(request):
@ -127,7 +147,7 @@ async def get_auth(request):
redir = '/paws'
user = pawsdb.users.get(query.handle == str(numid))
token, userinfo = login(user, code)
token, userinfo = oauth.login(user, code)
if token == 'error':
return error(request, 500, userinfo)

View file

@ -1,5 +1,5 @@
exec = python3 -m paws
watch_ext = py, env
ignore_dirs = build, data
ignore_dirs = build
ignore_files = reload.py, test.py, heck.py
log_level = INFO