Changes grok suggested.
This commit is contained in:
@@ -38,61 +38,47 @@ class HttpUser(Persistent):
|
||||
self._enabled = bool(value)
|
||||
self._p_changed = True
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# rf_enabled property – tied directly to the main server's blacklist
|
||||
# ------------------------------------------------------------------
|
||||
@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 checks..
|
||||
#
|
||||
|
||||
@rf_enabled.setter
|
||||
def rf_enabled(self, allow: bool):
|
||||
def is_rf_enabled(self, connection) -> 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.
|
||||
"""
|
||||
import transaction
|
||||
from packetserver.common.util import is_valid_ax25_callsign # assuming you have this helper
|
||||
from packetserver.utils import is_valid_ax25_callsign # our validator
|
||||
|
||||
root = transaction.get().db().root()
|
||||
root = connection.root()
|
||||
config = root.setdefault('config', PersistentMapping())
|
||||
blacklist = config.setdefault('blacklist', PersistentList())
|
||||
|
||||
upper_name = self.username
|
||||
|
||||
if allow:
|
||||
# Trying to enable RF access
|
||||
if not is_valid_ax25_callsign(upper_name):
|
||||
raise ValueError(f"{upper_name} is not a valid AX.25 callsign – cannot enable RF access")
|
||||
|
||||
if upper_name in blacklist:
|
||||
blacklist.remove(upper_name)
|
||||
config['blacklist'] = blacklist
|
||||
self._p_changed = True
|
||||
blacklist._p_changed = True
|
||||
else:
|
||||
# Disable RF access
|
||||
if upper_name not in blacklist:
|
||||
blacklist.append(upper_name)
|
||||
config['blacklist'] = blacklist
|
||||
self._p_changed = True
|
||||
blacklist._p_changed = True
|
||||
|
||||
# Ensure changes are marked
|
||||
root._p_changed = True
|
||||
config._p_changed = True
|
||||
root._p_changed = True
|
||||
# Caller should commit the transaction
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Password handling (unchanged)
|
||||
|
||||
@@ -19,11 +19,12 @@ async def profile(current_user: HttpUser = Depends(get_current_http_user)):
|
||||
main_users = root.get('users', {})
|
||||
bbs_user = main_users.get(username)
|
||||
safe_profile = bbs_user.to_safe_dict() if bbs_user else {}
|
||||
rf_enabled = current_user.is_rf_enabled(conn)
|
||||
|
||||
return {
|
||||
**safe_profile,
|
||||
"http_enabled": current_user.enabled,
|
||||
"rf_enabled": current_user.rf_enabled,
|
||||
"rf_enabled": rf_enabled,
|
||||
"http_created_at": current_user.created_at,
|
||||
"http_last_login": current_user.last_login,
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from pydantic import BaseModel, Field, validator
|
||||
from typing import List
|
||||
from persistent.list import PersistentList
|
||||
from persistent.mapping import PersistentMapping
|
||||
from datetime import datetime
|
||||
import uuid
|
||||
|
||||
@@ -32,7 +34,9 @@ async def send_message(
|
||||
payload: SendMessageRequest,
|
||||
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(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="RF gateway access required to send messages"
|
||||
@@ -54,8 +58,6 @@ async def send_message(
|
||||
msg_from=username,
|
||||
msg_to=to_tuple,
|
||||
text=payload.text,
|
||||
subject=payload.subject, # if Message supports it; otherwise drop
|
||||
sent_at=datetime.utcnow(),
|
||||
attachments=() # empty for now
|
||||
)
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@ def main():
|
||||
print(f"Error: User {callsign} not found")
|
||||
sys.exit(1)
|
||||
try:
|
||||
user.rf_enabled = True
|
||||
user.set_rf_enabled(connection, True)
|
||||
transaction.commit()
|
||||
print(f"RF gateway enabled for {callsign}")
|
||||
except ValueError as e:
|
||||
@@ -206,7 +206,7 @@ def main():
|
||||
if not user:
|
||||
print(f"Error: User {callsign} not found")
|
||||
sys.exit(1)
|
||||
user.rf_enabled = False
|
||||
user.set_rf_enabled(connection, False)
|
||||
transaction.commit()
|
||||
print(f"RF gateway disabled for {callsign}")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user