- Web app (Flask): status, config, firewall, logs, users, restart - Docs: AT commands, deploy, DNS, quickstart, web GUI - Scripts: connect, deploy, diag, healthcheck, modem-status, speedtest, status, troubleshoot - Init and iptables: 5g-router, 5g-webgui, rules.v4 - CHANGELOG, TODO, REVISION; config and README updates
120 lines
2.9 KiB
Python
120 lines
2.9 KiB
Python
"""User storage and auth for Alpine 5G Web GUI. Uses SQLite (db.py)."""
|
|
|
|
import json
|
|
from pathlib import Path
|
|
from werkzeug.security import check_password_hash, generate_password_hash
|
|
|
|
from db import (
|
|
init_db,
|
|
user_add as db_user_add,
|
|
user_delete as db_user_delete,
|
|
user_get as db_user_get,
|
|
user_list as db_user_list,
|
|
user_set_password as db_user_set_password,
|
|
user_verify as db_user_verify,
|
|
)
|
|
|
|
DATA_DIR = Path(__file__).resolve().parent / "data"
|
|
USERS_FILE = DATA_DIR / "users.json"
|
|
|
|
ROLES = ("admin", "support")
|
|
|
|
|
|
def can_access_config(role):
|
|
return role == "admin"
|
|
|
|
|
|
def can_access_firewall(role):
|
|
return role == "admin"
|
|
|
|
|
|
def can_access_routes(role):
|
|
return role == "admin"
|
|
|
|
|
|
def can_manage_users(role):
|
|
return role == "admin"
|
|
|
|
|
|
def can_restart_5g(role):
|
|
return role in ("admin", "support")
|
|
|
|
|
|
def can_view_logs(role):
|
|
return role in ("admin", "support")
|
|
|
|
|
|
def can_view_status(role):
|
|
return role in ("admin", "support")
|
|
|
|
|
|
def _migrate_users_from_json():
|
|
"""One-time: copy users from users.json into SQLite if DB has no users."""
|
|
if not USERS_FILE.exists():
|
|
return
|
|
try:
|
|
data = json.loads(USERS_FILE.read_text())
|
|
users = data.get("users", [])
|
|
except (json.JSONDecodeError, IOError):
|
|
return
|
|
for u in users:
|
|
username = u.get("username")
|
|
password_hash = u.get("password_hash")
|
|
role = u.get("role", "support")
|
|
if not username or not password_hash:
|
|
continue
|
|
existing = db_user_get(username)
|
|
if not existing:
|
|
db_user_add(username, password_hash, role)
|
|
# Optionally rename so we don't migrate again
|
|
try:
|
|
USERS_FILE.rename(USERS_FILE.with_suffix(".json.bak"))
|
|
except OSError:
|
|
pass
|
|
|
|
|
|
def init_default_users():
|
|
"""Ensure DB exists and has at least default admin/support if empty."""
|
|
init_db()
|
|
if db_user_list():
|
|
return
|
|
_migrate_users_from_json()
|
|
if db_user_list():
|
|
return
|
|
db_user_add("admin", generate_password_hash("admin"), "admin")
|
|
db_user_add("support", generate_password_hash("support"), "support")
|
|
|
|
|
|
def verify_user(username: str, password: str):
|
|
def check(ph):
|
|
return check_password_hash(ph, password)
|
|
return db_user_verify(username, check)
|
|
|
|
|
|
def get_user(username: str):
|
|
return db_user_get(username)
|
|
|
|
|
|
def list_users():
|
|
return db_user_list()
|
|
|
|
|
|
def set_password(username: str, new_password: str):
|
|
return db_user_set_password(username, generate_password_hash(new_password))
|
|
|
|
|
|
def add_user(username: str, password: str, role: str):
|
|
if role not in ROLES:
|
|
return False, "Invalid role"
|
|
ok, err = db_user_add(username, generate_password_hash(password), role)
|
|
return ok, err
|
|
|
|
|
|
def delete_user(username: str):
|
|
if username == "admin":
|
|
return False, "Cannot delete admin"
|
|
if not db_user_get(username):
|
|
return False, "User not found"
|
|
db_user_delete(username)
|
|
return True, None
|