From 1cd7242a7b3d01caa8295e2190a22f4f47b4d922 Mon Sep 17 00:00:00 2001 From: Michael Woods Date: Sun, 21 Dec 2025 21:25:50 -0500 Subject: [PATCH] Updated user manager. --- packetserver/http/auth.py | 16 ++++++++++++---- packetserver/runners/http_user_manager.py | 6 +++--- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/packetserver/http/auth.py b/packetserver/http/auth.py index 59356b2..274cf08 100644 --- a/packetserver/http/auth.py +++ b/packetserver/http/auth.py @@ -1,10 +1,12 @@ # packetserver/http/auth.py +import ax25 from persistent import Persistent from argon2 import PasswordHasher from argon2.exceptions import VerifyMismatchError import time from persistent.mapping import PersistentMapping from persistent.list import PersistentList +from packetserver.common.util import is_valid_ax25_callsign ph = PasswordHasher() @@ -22,6 +24,12 @@ class HttpUser(Persistent): self.last_login = None self.failed_attempts = 0 + # Check to make sure we're not storing a SSID + if is_valid_ax25_callsign(self.username): + base = ax25.Address(self.username).call + if base.upper() != self.username: + raise ValueError(f"'{self.username}' is a callsign with an SSID appended. Please use base callsign.") + # New fields self._enabled = True # HTTP access enabled by default # rf_enabled is a @property – no direct storage needed @@ -30,11 +38,11 @@ class HttpUser(Persistent): # Simple enabled flag (admin can disable HTTP login entirely) # ------------------------------------------------------------------ @property - def enabled(self) -> bool: + def http_enabled(self) -> bool: return getattr(self, '_enabled', True) - @enabled.setter - def enabled(self, value: bool): + @http_enabled.setter + def http_enabled(self, value: bool): self._enabled = bool(value) self._p_changed = True @@ -57,7 +65,7 @@ class HttpUser(Persistent): Requires an open ZODB connection (inside a transaction). Only allows enabling if the username is a valid AX.25 callsign. """ - from packetserver.utils import is_valid_ax25_callsign # our validator + from packetserver.common.util import is_valid_ax25_callsign # our validator root = connection.root() config = root.setdefault('config', PersistentMapping()) diff --git a/packetserver/runners/http_user_manager.py b/packetserver/runners/http_user_manager.py index 17bc8cd..712f66f 100644 --- a/packetserver/runners/http_user_manager.py +++ b/packetserver/runners/http_user_manager.py @@ -214,14 +214,14 @@ def main(): if not users_mapping: print("No HTTP users configured") else: - print(f"{'Callsign':<12} {'Enabled':<8} {'RF Enabled':<11} {'Created':<20} Last Login") - print("-" * 70) + print(f"{'Callsign':<12} {'HTTP Enabled':<13} {'RF Enabled':<11} {'Created':<20} Last Login") + print("-" * 75) for user in sorted(users_mapping.values(), key=lambda u: u.username): created = time.strftime("%Y-%m-%d %H:%M", time.localtime(user.created_at)) last = (time.strftime("%Y-%m-%d %H:%M", time.localtime(user.last_login)) if user.last_login else "-") rf_status = "True" if user.is_rf_enabled(connection) else "False" - print(f"{user.username:<12} {str(user.enabled):<8} {rf_status:<11} {created:<20} {last}") + print(f"{user.username:<12} {str(user.http_enabled):<13} {rf_status:<11} {created:<20} {last}") finally: