diff --git a/run_ui.py b/run_ui.py index 442feee2d..d96ad70bd 100644 --- a/run_ui.py +++ b/run_ui.py @@ -6,8 +6,7 @@ import socket import struct from functools import wraps import threading -from flask import Flask, request, Response, session -from flask_basicauth import BasicAuth +from flask import Flask, request, Response, session, redirect, url_for, render_template_string import initialize from python.helpers import files, git, mcp_server, fasta2a_server from python.helpers.files import get_abs_path @@ -43,7 +42,7 @@ webapp.config.update( lock = threading.Lock() # Set up basic authentication for UI and API but not MCP -basic_auth = BasicAuth(webapp) +# basic_auth = BasicAuth(webapp) def is_loopback_address(address): @@ -79,7 +78,6 @@ def is_loopback_address(address): return False return True - def requires_api_key(f): @wraps(f) async def decorated(*args, **kwargs): @@ -121,21 +119,17 @@ def requires_auth(f): @wraps(f) async def decorated(*args, **kwargs): user = dotenv.get_dotenv_value("AUTH_LOGIN") - password = dotenv.get_dotenv_value("AUTH_PASSWORD") - if user and password: - auth = request.authorization - if not auth or not (auth.username == user and auth.password == password): - return Response( - "Could not verify your access level for that URL.\n" - "You have to login with proper credentials", - 401, - {"WWW-Authenticate": 'Basic realm="Login Required"'}, - ) + # If no auth is configured, just proceed + if not user: + return await f(*args, **kwargs) + + if not session.get('authenticated'): + return redirect(url_for('login')) + return await f(*args, **kwargs) return decorated - def csrf_protect(f): @wraps(f) async def decorated(*args, **kwargs): @@ -149,6 +143,26 @@ def csrf_protect(f): return decorated +@webapp.route("/login", methods=["GET", "POST"]) +async def login(): + error = None + if request.method == 'POST': + user = dotenv.get_dotenv_value("AUTH_LOGIN") + password = dotenv.get_dotenv_value("AUTH_PASSWORD") + + if request.form['username'] == user and request.form['password'] == password: + session['authenticated'] = True + return redirect(url_for('serve_index')) + else: + error = 'Invalid Credentials. Please try again.' + + login_page_content = files.read_file("webui/login.html") + return render_template_string(login_page_content, error=error) + +@webapp.route("/logout") +async def logout(): + session.pop('authenticated', None) + return redirect(url_for('login')) # handle default address, load index @webapp.route("/", methods=["GET"]) @@ -170,7 +184,6 @@ async def serve_index(): ) return index - def run(): PrintStyle().print("Initializing framework...") @@ -267,4 +280,4 @@ def init_a0(): if __name__ == "__main__": runtime.initialize() dotenv.load_dotenv() - run() + run() \ No newline at end of file diff --git a/webui/login.css b/webui/login.css new file mode 100644 index 000000000..997bfe3de --- /dev/null +++ b/webui/login.css @@ -0,0 +1,81 @@ +body { + background-color: #131313; + color: #d4d4d4; + font-family: "Rubik", Arial, Helvetica, sans-serif; + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + margin: 0; +} + +.login-container { + display: flex; + justify-content: center; + align-items: center; + width: 100%; +} + +.login-form { + background-color: #1a1a1a; + padding: 2rem; + border-radius: 1.125rem; + box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3); + width: 100%; + max-width: 400px; + text-align: center; +} + +.logo { + width: 80px; + height: 80px; + border-radius: 0.3125rem; /* Match the main page logo style */ + margin-bottom: 1rem; +} + +h2 { + margin-bottom: 2rem; +} + +.input-group { + margin-bottom: 1.5rem; + text-align: left; +} + +.input-group label { + display: block; + margin-bottom: 0.5rem; + color: #737a81; +} + +.input-group input { + width: 100%; + padding: 0.75rem; + border: 1px solid #444444a8; + border-radius: 0.5rem; + background-color: #131313; + color: #d4d4d4; + font-size: 1rem; + box-sizing: border-box; /* Added for consistent padding */ +} + +button { + width: 100%; + padding: 0.75rem; + border: none; + border-radius: 0.5rem; + background-color: #4248f1; + color: white; + font-size: 1rem; + cursor: pointer; + transition: background-color 0.3s ease; +} + +button:hover { + background-color: #353bc5; +} + +.error { + color: #cf6679; + margin-top: 1rem; +} diff --git a/webui/login.html b/webui/login.html new file mode 100644 index 000000000..74c714388 --- /dev/null +++ b/webui/login.html @@ -0,0 +1,30 @@ + + +
+ + +