Made some changes. Figured out the rf_enable thing.

This commit is contained in:
Michael Woods
2025-12-21 20:51:05 -05:00
parent 0e88677dad
commit 2b4c8b56ba
3 changed files with 88 additions and 3 deletions

View File

@@ -10,6 +10,14 @@ import string
from persistent.mapping import PersistentMapping from persistent.mapping import PersistentMapping
from persistent.list import PersistentList from persistent.list import PersistentList
# Pre-compiled regex for performance
_AX25_CALLSIGN_REGEX = re.compile(
r'^[A-Z0-9]{1,6}(-[0-9]{1,2})?$'
)
# Regex for base callsign only (no SSID)
_BASE_CALLSIGN_REGEX = re.compile(r'^[A-Z][A-Z0-9]{0,5}$')
def email_valid(email: str) -> bool: def email_valid(email: str) -> bool:
"""Taken from https://www.geeksforgeeks.org/check-if-email-address-valid-or-not-in-python/""" """Taken from https://www.geeksforgeeks.org/check-if-email-address-valid-or-not-in-python/"""
regex = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,7}\b' regex = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,7}\b'
@@ -172,4 +180,70 @@ def convert_from_persistent(data):
elif isinstance(data, PersistentList): elif isinstance(data, PersistentList):
return [convert_from_persistent(item) for item in data] return [convert_from_persistent(item) for item in data]
else: else:
return data return data
def is_valid_ax25_callsign(callsign: str) -> bool:
"""
Validate an AX.25 callsign (with optional SSID).
Rules:
- Base: 1-6 uppercase alphanumeric, must start with letter (A-Z)
- Optional: single '-' followed by 1-2 digits (0-15)
- No spaces, lowercase, or other characters
Examples:
W1AW → True
W1AW-1 → True
W1AW-15 → True
1A2BCD → False (starts with digit)
w1aw → False (lowercase)
W1AW- → False (no SSID digits)
W1AW--1 → False (double dash)
W1AW-16 → False (SSID >15)
"""
if not callsign:
return False
callsign = callsign.strip().upper()
if not _AX25_CALLSIGN_REGEX.match(callsign):
return False
# Extra check: base must start with letter (not digit)
base = callsign.split('-')[0]
if not base[0].isalpha():
return False
# If SSID present, ensure 0-15
if '-' in callsign:
ssid_str = callsign.split('-')[1]
if int(ssid_str) > 15:
return False
return True
def is_valid_base_ax25_callsign(base_call: str) -> bool:
"""
Validate an AX.25 **base** callsign (without SSID).
Rules:
- 16 characters total
- Must start with an uppercase letter (AZ)
- Remaining characters: uppercase letters AZ or digits 09
- No hyphen, no SSID, no other characters
Examples:
W1AW → True
M0XYZ → True
K9ABC → True (6 chars)
1ABC → False (starts with digit)
W1AW- → False (has hyphen)
W1AW-1 → False (has SSID)
w1aw → False (lowercase)
A → True (single letter)
ABC1234 → False (7 chars)
Use this when you specifically need the base portion (e.g., before adding SSID).
"""
if not base_call:
return False
base_call = base_call.strip().upper()
return bool(_BASE_CALLSIGN_REGEX.match(base_call))

View File

@@ -3,6 +3,8 @@ from persistent import Persistent
from argon2 import PasswordHasher from argon2 import PasswordHasher
from argon2.exceptions import VerifyMismatchError from argon2.exceptions import VerifyMismatchError
import time import time
from persistent.mapping import PersistentMapping
from persistent.list import PersistentList
ph = PasswordHasher() ph = PasswordHasher()
@@ -64,7 +66,7 @@ class HttpUser(Persistent):
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 import transaction
from packetserver.utils import is_valid_ax25_callsign # assuming you have this helper from packetserver.common.util import is_valid_ax25_callsign # assuming you have this helper
root = transaction.get().db().root() root = transaction.get().db().root()
config = root.setdefault('config', PersistentMapping()) config = root.setdefault('config', PersistentMapping())

View File

@@ -13,6 +13,7 @@ import argparse
import sys import sys
import time import time
from getpass import getpass from getpass import getpass
import ax25
import ZODB.FileStorage import ZODB.FileStorage
import ZODB.DB import ZODB.DB
@@ -102,7 +103,14 @@ def main():
upper_callsign = lambda c: c.upper() upper_callsign = lambda c: c.upper()
if args.command == "add": if args.command == "add":
from packetserver.common.util import is_valid_ax25_callsign
callsign = upper_callsign(args.callsign) callsign = upper_callsign(args.callsign)
if is_valid_ax25_callsign(callsign):
base = ax25.Address(callsign).call.upper()
if base != callsign:
print(f"Error: Trying to add valid callsign + ssid. Remove -<num> and add again.")
sys.exit(1)
if callsign in users_mapping: if callsign in users_mapping:
print(f"Error: HTTP user {callsign} already exists") print(f"Error: HTTP user {callsign} already exists")
sys.exit(1) sys.exit(1)
@@ -121,7 +129,8 @@ def main():
main_users = root.setdefault('users', PersistentMapping()) main_users = root.setdefault('users', PersistentMapping())
if callsign not in main_users: if callsign not in main_users:
User.write_new(main_users, args.callsign) new_user = User(callsign)
new_user.write_new(root)
print(f" → Also created regular BBS user {callsign} (with UUID)") print(f" → Also created regular BBS user {callsign} (with UUID)")
else: else:
print(f" → Regular BBS user {callsign} already exists") print(f" → Regular BBS user {callsign} already exists")