From c0979f16f2a7b15eb772f06f4feeb73a62a1df02 Mon Sep 17 00:00:00 2001 From: Jon Ander Oribe Date: Sun, 11 Jan 2026 17:54:43 +0100 Subject: [PATCH] Implement user authentication with hashed passwords Replaces hardcoded admin credentials with a users table in the database, storing hashed passwords and user roles. Updates the login logic in app.py to authenticate against the database using Werkzeug's password hashing utilities. Adds admin credential configuration to config.py and ensures a default admin user is created during database initialization. --- app.py | 25 +++++++++++++++++++++---- config.py | 3 +++ pyproject.toml | 1 + utils/database.py | 27 +++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 4 deletions(-) diff --git a/app.py b/app.py index 1c487f7..f6038b2 100644 --- a/app.py +++ b/app.py @@ -9,6 +9,8 @@ from __future__ import annotations import sys import site +from utils.database import get_db + # Ensure user site-packages is available (may be disabled when running as root/sudo) if not site.ENABLE_USER_SITE: user_site = site.getusersitepackages() @@ -24,7 +26,7 @@ import subprocess from typing import Any from flask import Flask, render_template, jsonify, send_file, Response, request,redirect, url_for, flash, session - +from werkzeug.security import check_password_hash from config import VERSION from utils.dependencies import check_tool, check_all_dependencies, TOOL_DEPENDENCIES from utils.process import cleanup_stale_processes @@ -36,11 +38,11 @@ from utils.constants import ( MAX_BT_DEVICE_AGE_SECONDS, QUEUE_MAX_SIZE, ) - +import logging # Track application start time for uptime calculation import time as _time _app_start_time = _time.time() - +logger = logging.getLogger('intercept.database') # Create Flask app app = Flask(__name__) @@ -162,10 +164,25 @@ def login(): username = request.form.get('username') password = request.form.get('password') - if username == "admin" and password == "intercept2026": + # 1. Conectar a la DB y buscar al usuario + with get_db() as conn: + cursor = conn.execute( + 'SELECT password_hash, role FROM users WHERE username = ?', + (username,) + ) + user = cursor.fetchone() + + # 2. Verificar si el usuario existe y la contraseña es correcta + if user and check_password_hash(user['password_hash'], password): + # Guardamos datos en la sesión session['logged_in'] = True + session['username'] = username + session['role'] = user['role'] + + logger.info(f"User '{username}' logged in successfully.") return redirect(url_for('index')) else: + logger.warning(f"Failed login attempt for username: {username}") flash("ACCESS DENIED: INVALID CREDENTIALS", "error") return render_template('login.html', version=VERSION) diff --git a/config.py b/config.py index 5bd4ec8..93d3eaa 100644 --- a/config.py +++ b/config.py @@ -81,6 +81,9 @@ SATELLITE_UPDATE_INTERVAL = _get_env_int('SATELLITE_UPDATE_INTERVAL', 30) SATELLITE_TRAJECTORY_POINTS = _get_env_int('SATELLITE_TRAJECTORY_POINTS', 30) SATELLITE_ORBIT_MINUTES = _get_env_int('SATELLITE_ORBIT_MINUTES', 45) +# Admin credentials +ADMIN_USERNAME = _get_env('ADMIN_USERNAME', 'admin') +ADMIN_PASSWORD = _get_env('ADMIN_PASSWORD', 'intercept') def configure_logging() -> None: """Configure application logging.""" diff --git a/pyproject.toml b/pyproject.toml index 9ea365b..05c8d65 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,6 +29,7 @@ dependencies = [ "flask>=2.0.0", "skyfield>=1.45", "pyserial>=3.5", + "Werkzeug>=3.1.5", ] [project.urls] diff --git a/utils/database.py b/utils/database.py index 1534849..2d52109 100644 --- a/utils/database.py +++ b/utils/database.py @@ -12,6 +12,8 @@ from contextlib import contextmanager from datetime import datetime from pathlib import Path from typing import Any +from werkzeug.security import generate_password_hash +from config import ADMIN_USERNAME, ADMIN_PASSWORD logger = logging.getLogger('intercept.database') @@ -100,6 +102,31 @@ def init_db() -> None: ) ''') + # Users table for authentication + conn.execute(''' + CREATE TABLE IF NOT EXISTS users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username TEXT UNIQUE NOT NULL, + password_hash TEXT NOT NULL, + role TEXT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + ''') + + cursor = conn.execute('SELECT COUNT(*) FROM users') + if cursor.fetchone()[0] == 0: + from config import ADMIN_USERNAME, ADMIN_PASSWORD + + logger.info(f"Creating default admin user: {ADMIN_USERNAME}") + + # Password hashing + hashed_pw = generate_password_hash(ADMIN_PASSWORD) + + conn.execute(''' + INSERT INTO users (username, password_hash, role) + VALUES (?, ?, ?) + ''', (ADMIN_USERNAME, hashed_pw, 'admin')) + logger.info("Database initialized successfully")