Implement basic authentication
Initial working implementation, would require more polishing, but at least it works for now.
This commit is contained in:
		
							parent
							
								
									b4d5146fdc
								
							
						
					
					
						commit
						cf694a0d61
					
				| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
name = "Folder share"
 | 
					name = "Folder share"
 | 
				
			||||||
base_path = "/path/to/folder"
 | 
					base_path = "/path/to/folder"
 | 
				
			||||||
favicon = "/.favicon.png"
 | 
					favicon = "/.favicon.png"
 | 
				
			||||||
 | 
					password = "publicpass"
 | 
				
			||||||
 | 
					admin_password = "verysecurepass"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[qbittorrent]
 | 
					[qbittorrent]
 | 
				
			||||||
base_url = "http://127.0.0.1:8080"
 | 
					base_url = "http://127.0.0.1:8080"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,10 +2,11 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from flask import Flask, render_template, send_file, request
 | 
					from flask import Flask, Response, render_template, send_file, request
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from . import file
 | 
					from . import file
 | 
				
			||||||
from . import config
 | 
					from . import config
 | 
				
			||||||
 | 
					from . import auth
 | 
				
			||||||
 | 
					
 | 
				
			||||||
app = Flask(
 | 
					app = Flask(
 | 
				
			||||||
    __name__,
 | 
					    __name__,
 | 
				
			||||||
| 
						 | 
					@ -21,6 +22,7 @@ app.jinja_env.globals.update(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@app.route('/', defaults={'path': ''})
 | 
					@app.route('/', defaults={'path': ''})
 | 
				
			||||||
@app.route('/<path:path>')
 | 
					@app.route('/<path:path>')
 | 
				
			||||||
 | 
					@auth.requires_auth
 | 
				
			||||||
def index(path):
 | 
					def index(path):
 | 
				
			||||||
    internal_path = os.path.join(config.get('base_path'), path)
 | 
					    internal_path = os.path.join(config.get('base_path'), path)
 | 
				
			||||||
    path = '/' + path
 | 
					    path = '/' + path
 | 
				
			||||||
| 
						 | 
					@ -62,6 +64,7 @@ def index(path):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@app.route('/search')
 | 
					@app.route('/search')
 | 
				
			||||||
 | 
					@auth.requires_auth
 | 
				
			||||||
def search():
 | 
					def search():
 | 
				
			||||||
    q = request.args.get('q', '')
 | 
					    q = request.args.get('q', '')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -85,3 +88,27 @@ def search():
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        200,
 | 
					        200,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@app.route('/auth', methods=['POST'])
 | 
				
			||||||
 | 
					def auth_handle():
 | 
				
			||||||
 | 
					    expected_pass = config.get('password')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if expected_pass is None:
 | 
				
			||||||
 | 
					        return "You shouldn't be here.", 405
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if request.form.get("pass", None) != expected_pass:
 | 
				
			||||||
 | 
					        return render_template(
 | 
				
			||||||
 | 
					            'auth.html',
 | 
				
			||||||
 | 
					            path=request.form.get("location", "/"),
 | 
				
			||||||
 | 
					            error_msg="Incorrect password",
 | 
				
			||||||
 | 
					        ), 403
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return Response(
 | 
				
			||||||
 | 
					        "Redirecting...",
 | 
				
			||||||
 | 
					        303,
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            'Location': request.form.get("location", "/"),
 | 
				
			||||||
 | 
					            'Set-Cookie': 'film_session=To be changed',
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,31 @@
 | 
				
			||||||
 | 
					from functools import wraps
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from flask import request, render_template
 | 
				
			||||||
 | 
					from . import config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# FIXME: EVERYTHING is under the auth now, even files (makes sense)
 | 
				
			||||||
 | 
					#        but that means that even the favicon requires authentication.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def auth_page(*args, **kwargs):
 | 
				
			||||||
 | 
					    # TODO: Is there a better way of doing this?
 | 
				
			||||||
 | 
					    path = f"{request.path}?{request.query_string.decode('utf-8')}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return render_template("auth.html", path=path), 403
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def requires_auth(f):
 | 
				
			||||||
 | 
					    @wraps(f)
 | 
				
			||||||
 | 
					    def decorated(*args, **kwargs):
 | 
				
			||||||
 | 
					        if config.get('password') in [False, None, ""]:
 | 
				
			||||||
 | 
					            return f(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if request.cookies.get('film_session', None) != 'To be changed':
 | 
				
			||||||
 | 
					            # Not authenticated
 | 
				
			||||||
 | 
					            return auth_page()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # User properly authenticated
 | 
				
			||||||
 | 
					        print(request.cookies['film_session'])
 | 
				
			||||||
 | 
					        return f(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return decorated
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,13 @@
 | 
				
			||||||
 | 
					{% extends 'base.html' %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block title %}Secret required{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block body %}
 | 
				
			||||||
 | 
					<h1>Secret required</h1>
 | 
				
			||||||
 | 
					<form method="POST" action="/auth">
 | 
				
			||||||
 | 
					    <input type="hidden" name="location" value="{{ path }}">
 | 
				
			||||||
 | 
					    <input type="text" name="pass" />
 | 
				
			||||||
 | 
					    <input type="submit" />
 | 
				
			||||||
 | 
					</form>
 | 
				
			||||||
 | 
					<p style="color:red;">{{ error_msg|default('') }}</p>
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue