Changes grok suggested.

This commit is contained in:
Michael Woods
2025-12-21 21:10:11 -05:00
parent 2b4c8b56ba
commit b671e49e69
4 changed files with 30 additions and 41 deletions

View File

@@ -38,61 +38,47 @@ class HttpUser(Persistent):
self._enabled = bool(value) self._enabled = bool(value)
self._p_changed = True self._p_changed = True
# ------------------------------------------------------------------ #
# rf_enabled property tied directly to the main server's blacklist # rf enabled checks..
# ------------------------------------------------------------------ #
@property
def rf_enabled(self) -> bool:
"""
True if the callsign is NOT in the global blacklist.
This allows HTTP users to act as RF gateways only if explicitly allowed.
"""
from ZODB import DB # deferred import to avoid circular issues
# We'll get the db from the transaction in most contexts
# But for safety, we'll reach into the current connection's root
import transaction
try:
root = transaction.get().db().root()
blacklist = root.get('config', {}).get('blacklist', [])
return self.username not in blacklist
except Exception:
# If we're outside a transaction (e.g. during tests), default safe
return False
@rf_enabled.setter def is_rf_enabled(self, connection) -> bool:
def rf_enabled(self, allow: bool):
""" """
Enable/disable RF gateway capability by adding/removing from the global blacklist. Check if RF gateway is enabled (i.e., callsign NOT in global blacklist).
Requires an open ZODB connection.
"""
root = connection.root()
blacklist = root.get('config', {}).get('blacklist', [])
return self.username not in blacklist
def set_rf_enabled(self, connection, allow: bool):
"""
Enable/disable RF gateway by adding/removing from global blacklist.
Requires an open ZODB connection (inside a transaction).
Only allows enabling if the username is a valid AX.25 callsign. Only allows enabling if the username is a valid AX.25 callsign.
""" """
import transaction from packetserver.utils import is_valid_ax25_callsign # our validator
from packetserver.common.util import is_valid_ax25_callsign # assuming you have this helper
root = transaction.get().db().root() root = connection.root()
config = root.setdefault('config', PersistentMapping()) config = root.setdefault('config', PersistentMapping())
blacklist = config.setdefault('blacklist', PersistentList()) blacklist = config.setdefault('blacklist', PersistentList())
upper_name = self.username upper_name = self.username
if allow: if allow:
# Trying to enable RF access
if not is_valid_ax25_callsign(upper_name): if not is_valid_ax25_callsign(upper_name):
raise ValueError(f"{upper_name} is not a valid AX.25 callsign cannot enable RF access") raise ValueError(f"{upper_name} is not a valid AX.25 callsign cannot enable RF access")
if upper_name in blacklist: if upper_name in blacklist:
blacklist.remove(upper_name) blacklist.remove(upper_name)
config['blacklist'] = blacklist blacklist._p_changed = True
self._p_changed = True
else: else:
# Disable RF access
if upper_name not in blacklist: if upper_name not in blacklist:
blacklist.append(upper_name) blacklist.append(upper_name)
config['blacklist'] = blacklist blacklist._p_changed = True
self._p_changed = True
# Ensure changes are marked
root._p_changed = True
config._p_changed = True config._p_changed = True
root._p_changed = True
# Caller should commit the transaction
# ------------------------------------------------------------------ # ------------------------------------------------------------------
# Password handling (unchanged) # Password handling (unchanged)

View File

@@ -19,11 +19,12 @@ async def profile(current_user: HttpUser = Depends(get_current_http_user)):
main_users = root.get('users', {}) main_users = root.get('users', {})
bbs_user = main_users.get(username) bbs_user = main_users.get(username)
safe_profile = bbs_user.to_safe_dict() if bbs_user else {} safe_profile = bbs_user.to_safe_dict() if bbs_user else {}
rf_enabled = current_user.is_rf_enabled(conn)
return { return {
**safe_profile, **safe_profile,
"http_enabled": current_user.enabled, "http_enabled": current_user.enabled,
"rf_enabled": current_user.rf_enabled, "rf_enabled": rf_enabled,
"http_created_at": current_user.created_at, "http_created_at": current_user.created_at,
"http_last_login": current_user.last_login, "http_last_login": current_user.last_login,
} }

View File

@@ -2,6 +2,8 @@
from fastapi import APIRouter, Depends, HTTPException, status from fastapi import APIRouter, Depends, HTTPException, status
from pydantic import BaseModel, Field, validator from pydantic import BaseModel, Field, validator
from typing import List from typing import List
from persistent.list import PersistentList
from persistent.mapping import PersistentMapping
from datetime import datetime from datetime import datetime
import uuid import uuid
@@ -32,7 +34,9 @@ async def send_message(
payload: SendMessageRequest, payload: SendMessageRequest,
current_user: HttpUser = Depends(get_current_http_user) current_user: HttpUser = Depends(get_current_http_user)
): ):
if not current_user.rf_enabled: from packetserver.runners.http_server import get_db_connection
conn = get_db_connection()
if not current_user.is_rf_enabled(conn):
raise HTTPException( raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN, status_code=status.HTTP_403_FORBIDDEN,
detail="RF gateway access required to send messages" detail="RF gateway access required to send messages"
@@ -54,8 +58,6 @@ async def send_message(
msg_from=username, msg_from=username,
msg_to=to_tuple, msg_to=to_tuple,
text=payload.text, text=payload.text,
subject=payload.subject, # if Message supports it; otherwise drop
sent_at=datetime.utcnow(),
attachments=() # empty for now attachments=() # empty for now
) )

View File

@@ -193,7 +193,7 @@ def main():
print(f"Error: User {callsign} not found") print(f"Error: User {callsign} not found")
sys.exit(1) sys.exit(1)
try: try:
user.rf_enabled = True user.set_rf_enabled(connection, True)
transaction.commit() transaction.commit()
print(f"RF gateway enabled for {callsign}") print(f"RF gateway enabled for {callsign}")
except ValueError as e: except ValueError as e:
@@ -206,7 +206,7 @@ def main():
if not user: if not user:
print(f"Error: User {callsign} not found") print(f"Error: User {callsign} not found")
sys.exit(1) sys.exit(1)
user.rf_enabled = False user.set_rf_enabled(connection, False)
transaction.commit() transaction.commit()
print(f"RF gateway disabled for {callsign}") print(f"RF gateway disabled for {callsign}")