add .gitattributes, default deny foreign addresses

This commit is contained in:
James Taylor 2018-07-01 21:34:49 -07:00
parent 98157bf1bf
commit 2696fb30c2
2 changed files with 171 additions and 141 deletions

30
.gitattributes vendored Normal file
View File

@ -0,0 +1,30 @@
# Basic .gitattributes for a python repo.
# Source files
# ============
*.pxd text
*.py text
*.py3 text
*.pyw text
*.pyx text
*.html text
*.xml text
*.xhtml text
*.htm text
*.css text
*.txt text
# Binary files
# ============
*.db binary
*.p binary
*.pkl binary
*.pyc binary
*.pyd binary
*.pyo binary
# Note: .db, .p, and .pkl files are associated
# with the python modules ``pickle``, ``dbm.*``,
# ``shelve``, ``marshal``, ``anydbm``, & ``bsddb``
# (among others).

282
server.py
View File

@ -1,141 +1,141 @@
from gevent import monkey from gevent import monkey
monkey.patch_all() monkey.patch_all()
import gevent.socket import gevent.socket
from gevent.pywsgi import WSGIServer from gevent.pywsgi import WSGIServer
from youtube.youtube import youtube from youtube.youtube import youtube
import urllib import urllib
import socket import socket
import socks import socks
import subprocess import subprocess
import re import re
ROUTE_TOR = True ROUTE_TOR = True
TOR_PATH = ***REMOVED*** TOR_PATH = ***REMOVED***
PORT_NUMBER=80 PORT_NUMBER=80
ALLOW_FOREIGN_ADDRESSES=True ALLOW_FOREIGN_ADDRESSES=False
BAN_FILE = "banned_addresses.txt" BAN_FILE = "banned_addresses.txt"
with open(BAN_FILE, 'r') as f: with open(BAN_FILE, 'r') as f:
banned_addresses = f.read().splitlines() banned_addresses = f.read().splitlines()
def ban_address(address): def ban_address(address):
banned_addresses.append(address) banned_addresses.append(address)
with open(BAN_FILE, 'a') as f: with open(BAN_FILE, 'a') as f:
f.write(address + "\n") f.write(address + "\n")
def youtu_be(env, start_response): def youtu_be(env, start_response):
id = env['PATH_INFO'][1:] id = env['PATH_INFO'][1:]
env['PATH_INFO'] = '/watch' env['PATH_INFO'] = '/watch'
env['QUERY_STRING'] = 'v=' + id env['QUERY_STRING'] = 'v=' + id
return youtube(env, start_response) return youtube(env, start_response)
def proxy_site(env, start_response): def proxy_site(env, start_response):
headers = { headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64)', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64)',
'Accept': '*/*', 'Accept': '*/*',
} }
url = "https://" + env['SERVER_NAME'] + env['PATH_INFO'] url = "https://" + env['SERVER_NAME'] + env['PATH_INFO']
if env['QUERY_STRING']: if env['QUERY_STRING']:
url += '?' + env['QUERY_STRING'] url += '?' + env['QUERY_STRING']
req = urllib.request.Request(url, headers=headers) req = urllib.request.Request(url, headers=headers)
response = urllib.request.urlopen(req, timeout = 10) response = urllib.request.urlopen(req, timeout = 10)
start_response('200 OK', () ) start_response('200 OK', () )
return response.read() return response.read()
site_handlers = { site_handlers = {
'youtube.com':youtube, 'youtube.com':youtube,
'youtu.be':youtu_be, 'youtu.be':youtu_be,
'ytimg.com': proxy_site, 'ytimg.com': proxy_site,
'yt3.ggpht.com': proxy_site, 'yt3.ggpht.com': proxy_site,
'lh3.googleusercontent.com': proxy_site, 'lh3.googleusercontent.com': proxy_site,
} }
def split_url(url): def split_url(url):
''' Split https://sub.example.com/foo/bar.html into ('sub.example.com', '/foo/bar.html')''' ''' Split https://sub.example.com/foo/bar.html into ('sub.example.com', '/foo/bar.html')'''
# XXX: Is this regex safe from REDOS? # XXX: Is this regex safe from REDOS?
# python STILL doesn't have a proper regular expression engine like grep uses built in... # python STILL doesn't have a proper regular expression engine like grep uses built in...
match = re.match(r'(?:https?://)?([\w-]+(?:\.[\w-]+)+?)(/.*|$)', url) match = re.match(r'(?:https?://)?([\w-]+(?:\.[\w-]+)+?)(/.*|$)', url)
if match is None: if match is None:
raise ValueError('Invalid or unsupported url: ' + url) raise ValueError('Invalid or unsupported url: ' + url)
return match.group(1), match.group(2) return match.group(1), match.group(2)
def error_code(code, start_response): def error_code(code, start_response):
start_response(code, ()) start_response(code, ())
return code.encode() return code.encode()
def site_dispatch(env, start_response): def site_dispatch(env, start_response):
client_address = env['REMOTE_ADDR'] client_address = env['REMOTE_ADDR']
try: try:
method = env['REQUEST_METHOD'] method = env['REQUEST_METHOD']
path = env['PATH_INFO'] path = env['PATH_INFO']
if client_address in banned_addresses: if client_address in banned_addresses:
yield error_code('403 Fuck Off', start_response) yield error_code('403 Fuck Off', start_response)
return return
if method=="POST" and client_address not in ('127.0.0.1', '::1'): if method=="POST" and client_address not in ('127.0.0.1', '::1'):
yield error_code('403 Forbidden', start_response) yield error_code('403 Forbidden', start_response)
return return
if "phpmyadmin" in path or (path == "/" and method == "HEAD"): if "phpmyadmin" in path or (path == "/" and method == "HEAD"):
ban_address(client_address) ban_address(client_address)
start_response('403 Fuck Off', ()) start_response('403 Fuck Off', ())
yield b'403 Fuck Off' yield b'403 Fuck Off'
return return
'''if env['QUERY_STRING']: '''if env['QUERY_STRING']:
path += '?' + env['QUERY_STRING']''' path += '?' + env['QUERY_STRING']'''
#path_parts = urllib.parse.urlparse(path) #path_parts = urllib.parse.urlparse(path)
try: try:
env['SERVER_NAME'], env['PATH_INFO'] = split_url(path[1:]) env['SERVER_NAME'], env['PATH_INFO'] = split_url(path[1:])
except ValueError: except ValueError:
yield error_code('404 Not Found', start_response) yield error_code('404 Not Found', start_response)
return return
base_name = '' base_name = ''
for domain in reversed(env['SERVER_NAME'].split('.')): for domain in reversed(env['SERVER_NAME'].split('.')):
if base_name == '': if base_name == '':
base_name = domain base_name = domain
else: else:
base_name = domain + '.' + base_name base_name = domain + '.' + base_name
try: try:
handler = site_handlers[base_name] handler = site_handlers[base_name]
except KeyError: except KeyError:
continue continue
else: else:
yield handler(env, start_response) yield handler(env, start_response)
break break
else: # did not break else: # did not break
yield error_code('404 Not Found', start_response) yield error_code('404 Not Found', start_response)
return return
except (socket.error, ConnectionAbortedError) as e: except (socket.error, ConnectionAbortedError) as e:
start_response('500 Internal Server Error', ()) start_response('500 Internal Server Error', ())
print(str(e)) print(str(e))
yield b'500 Internal Server Error' yield b'500 Internal Server Error'
except Exception: except Exception:
start_response('500 Internal Server Error', ()) start_response('500 Internal Server Error', ())
raise raise
return return
if ROUTE_TOR: if ROUTE_TOR:
#subprocess.Popen(TOR_PATH) #subprocess.Popen(TOR_PATH)
socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, '127.0.0.1', 9150) socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, '127.0.0.1', 9150)
socket.socket = socks.socksocket socket.socket = socks.socksocket
gevent.socket.socket = socks.socksocket gevent.socket.socket = socks.socksocket
if ALLOW_FOREIGN_ADDRESSES: if ALLOW_FOREIGN_ADDRESSES:
server = WSGIServer(('0.0.0.0', PORT_NUMBER), site_dispatch) server = WSGIServer(('0.0.0.0', PORT_NUMBER), site_dispatch)
else: else:
server = WSGIServer(('127.0.0.1', PORT_NUMBER), site_dispatch) server = WSGIServer(('127.0.0.1', PORT_NUMBER), site_dispatch)
print('Started httpserver on port ' , PORT_NUMBER) print('Started httpserver on port ' , PORT_NUMBER)
server.serve_forever() server.serve_forever()