Added basic authentication (#51)

Username/password can be set either as Dockerfile build arguments or
passed into the run script as "--userpass <username:password>"
main
Ben Busby 2020-05-18 10:30:32 -06:00 committed by GitHub
parent 0e39b8f97b
commit 38b7b19e2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 37 additions and 0 deletions

View File

@ -10,6 +10,11 @@ RUN mkdir -p $config_dir
VOLUME $config_dir VOLUME $config_dir
ENV CONFIG_VOLUME=$config_dir ENV CONFIG_VOLUME=$config_dir
ARG username=''
ENV WHOOGLE_USER=$username
ARG password=''
ENV WHOOGLE_PASS=$password
ARG use_https='' ARG use_https=''
ENV HTTPS_ONLY=$use_https ENV HTTPS_ONLY=$use_https

View File

@ -6,6 +6,7 @@ import argparse
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from cryptography.fernet import Fernet, InvalidToken from cryptography.fernet import Fernet, InvalidToken
from flask import g, make_response, request, redirect, render_template, send_file from flask import g, make_response, request, redirect, render_template, send_file
from functools import wraps
import io import io
import json import json
import os import os
@ -18,6 +19,21 @@ app.config['STATIC_FOLDER'] = os.getenv('STATIC_FOLDER', os.path.join(app.config
CONFIG_PATH = os.getenv('CONFIG_VOLUME', app.config['STATIC_FOLDER']) + '/config.json' CONFIG_PATH = os.getenv('CONFIG_VOLUME', app.config['STATIC_FOLDER']) + '/config.json'
def auth_required(f):
@wraps(f)
def decorated(*args, **kwargs):
auth = request.authorization
# Skip if username/password not set
whoogle_user = os.getenv('WHOOGLE_USER', '')
whoogle_pass = os.getenv('WHOOGLE_PASS', '')
if (not whoogle_user or not whoogle_pass) or (auth and whoogle_user == auth.username and whoogle_pass == auth.password):
return f(*args, **kwargs)
else:
return make_response('Not logged in', 401, {'WWW-Authenticate': 'Basic realm="Login Required"'})
return decorated
@app.before_request @app.before_request
def before_request_func(): def before_request_func():
# Always redirect to https if HTTPS_ONLY is set (otherwise default to false) # Always redirect to https if HTTPS_ONLY is set (otherwise default to false)
@ -44,6 +60,7 @@ def unknown_page(e):
@app.route('/', methods=['GET']) @app.route('/', methods=['GET'])
@auth_required
def index(): def index():
bg = '#000' if g.user_config.dark else '#fff' bg = '#000' if g.user_config.dark else '#fff'
return render_template('index.html', return render_template('index.html',
@ -55,6 +72,7 @@ def index():
@app.route('/opensearch.xml', methods=['GET']) @app.route('/opensearch.xml', methods=['GET'])
@auth_required
def opensearch(): def opensearch():
opensearch_url = g.app_location opensearch_url = g.app_location
if opensearch_url.endswith('/'): if opensearch_url.endswith('/'):
@ -69,6 +87,7 @@ def opensearch():
@app.route('/search', methods=['GET', 'POST']) @app.route('/search', methods=['GET', 'POST'])
@auth_required
def search(): def search():
request_params = request.args if request.method == 'GET' else request.form request_params = request.args if request.method == 'GET' else request.form
q = request_params.get('q') q = request_params.get('q')
@ -109,6 +128,7 @@ def search():
@app.route('/config', methods=['GET', 'POST']) @app.route('/config', methods=['GET', 'POST'])
@auth_required
def config(): def config():
if request.method == 'GET': if request.method == 'GET':
return json.dumps(g.user_config.__dict__) return json.dumps(g.user_config.__dict__)
@ -125,6 +145,7 @@ def config():
@app.route('/url', methods=['GET']) @app.route('/url', methods=['GET'])
@auth_required
def url(): def url():
if 'url' in request.args: if 'url' in request.args:
return redirect(request.args.get('url')) return redirect(request.args.get('url'))
@ -137,11 +158,13 @@ def url():
@app.route('/imgres') @app.route('/imgres')
@auth_required
def imgres(): def imgres():
return redirect(request.args.get('imgurl')) return redirect(request.args.get('imgurl'))
@app.route('/tmp') @app.route('/tmp')
@auth_required
def tmp(): def tmp():
cipher_suite = Fernet(app.secret_key) cipher_suite = Fernet(app.secret_key)
img_url = cipher_suite.decrypt(request.args.get('image_url').encode()).decode() img_url = cipher_suite.decrypt(request.args.get('image_url').encode()).decode()
@ -159,6 +182,7 @@ def tmp():
@app.route('/window') @app.route('/window')
@auth_required
def window(): def window():
get_body = g.user_request.send(base_url=request.args.get('location')) get_body = g.user_request.send(base_url=request.args.get('location'))
get_body = get_body.replace('src="/', 'src="' + request.args.get('location') + '"') get_body = get_body.replace('src="/', 'src="' + request.args.get('location') + '"')
@ -185,7 +209,15 @@ def run_app():
help='Activates debug mode for the server (default False)') help='Activates debug mode for the server (default False)')
parser.add_argument('--https-only', default=False, action='store_true', parser.add_argument('--https-only', default=False, action='store_true',
help='Enforces HTTPS redirects for all requests') help='Enforces HTTPS redirects for all requests')
parser.add_argument('--userpass', default='', metavar='<username:password>',
help='Sets a username/password basic auth combo (default None)')
args = parser.parse_args() args = parser.parse_args()
if args.userpass:
user_pass = args.userpass.split(':')
os.environ['WHOOGLE_USER'] = user_pass[0]
os.environ['WHOOGLE_PASS'] = user_pass[1]
os.environ['HTTPS_ONLY'] = '1' if args.https_only else '' os.environ['HTTPS_ONLY'] = '1' if args.https_only else ''
if args.debug: if args.debug: