233 lines
12 KiB
Python
233 lines
12 KiB
Python
from datetime import datetime
|
|
|
|
from sqlalchemy import BigInteger, Boolean, DateTime, Integer, String, func
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
from .database import Base
|
|
|
|
|
|
class Admin(Base):
|
|
"""An admin-portal login. `is_admin` grants user/API-key/log management."""
|
|
|
|
__tablename__ = "radadmin_admins"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
username: Mapped[str] = mapped_column(String(64), nullable=False, unique=True)
|
|
password_hash: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
is_admin: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
|
must_change_password: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
|
created_at: Mapped[datetime | None] = mapped_column(
|
|
DateTime, nullable=True, server_default=func.current_timestamp()
|
|
)
|
|
|
|
|
|
class Session(Base):
|
|
"""An opaque login token handed to the browser (Authorization: Bearer)."""
|
|
|
|
__tablename__ = "radadmin_sessions"
|
|
|
|
token: Mapped[str] = mapped_column(String(64), primary_key=True)
|
|
admin_id: Mapped[int] = mapped_column(Integer, nullable=False)
|
|
created_at: Mapped[datetime | None] = mapped_column(
|
|
DateTime, nullable=True, server_default=func.current_timestamp()
|
|
)
|
|
expires_at: Mapped[datetime] = mapped_column(DateTime, nullable=False)
|
|
|
|
|
|
class ApiKey(Base):
|
|
"""A programmatic key (X-API-Key). Only the hash is stored."""
|
|
|
|
__tablename__ = "radadmin_api_keys"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
name: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
key_prefix: Mapped[str] = mapped_column(String(16), nullable=False)
|
|
key_hash: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
created_by: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
created_at: Mapped[datetime | None] = mapped_column(
|
|
DateTime, nullable=True, server_default=func.current_timestamp()
|
|
)
|
|
last_used_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
revoked: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
|
|
|
|
|
class LogEntry(Base):
|
|
"""One activity-log row per state-changing action or auth event."""
|
|
|
|
__tablename__ = "radadmin_logs"
|
|
|
|
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
|
username: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
action: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
detail: Mapped[str | None] = mapped_column(String(512), nullable=True)
|
|
ip_address: Mapped[str | None] = mapped_column(String(45), nullable=True)
|
|
created_at: Mapped[datetime | None] = mapped_column(
|
|
DateTime, nullable=True, server_default=func.current_timestamp()
|
|
)
|
|
|
|
|
|
class Customer(Base):
|
|
__tablename__ = "customers"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
username: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
mac_address: Mapped[str] = mapped_column(String(17), nullable=False)
|
|
status: Mapped[str] = mapped_column(String(10), nullable=False, default="new")
|
|
created_at: Mapped[datetime | None] = mapped_column(
|
|
DateTime, nullable=True, server_default=func.current_timestamp()
|
|
)
|
|
|
|
|
|
class RadadminClient(Base):
|
|
"""Human-only client metadata (name/phone/alias), keyed by MAC. RADIUS ignores this."""
|
|
|
|
__tablename__ = "radadmin_clients"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
# Not DB-unique on its own — uniqueness is enforced only among live rows by the
|
|
# generated `active_mac` column (see radadmin_schema.sql). Soft-deleted rows
|
|
# (deleted_at set) may share a mac_address with the live row and each other.
|
|
mac_address: Mapped[str] = mapped_column(String(17), nullable=False)
|
|
name: Mapped[str | None] = mapped_column(String(128), nullable=True)
|
|
phone: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
alias: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
# Mirror of the client's group (radusergroup) and billing status (customers):
|
|
# set on add, synced on edit, and kept frozen on the row after soft-delete so
|
|
# the deleted client's group/status survive their hard-deleted source rows.
|
|
groupname: Mapped[str | None] = mapped_column(String(64), nullable=True, default=None)
|
|
status: Mapped[str | None] = mapped_column(String(10), nullable=True, default=None)
|
|
created_at: Mapped[datetime | None] = mapped_column(
|
|
DateTime, nullable=True, server_default=func.current_timestamp()
|
|
)
|
|
# Soft delete: NULL = live, a timestamp = deleted. Deleted rows are never
|
|
# returned by the API and are kept only for restore/reference.
|
|
deleted_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, default=None)
|
|
|
|
|
|
class RadadminDevice(Base):
|
|
"""Human alias for a NAS/AP box, keyed by its AP MAC. RADIUS never reads this."""
|
|
|
|
__tablename__ = "radadmin_devices"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
mac_address: Mapped[str] = mapped_column(String(17), nullable=False, unique=True)
|
|
alias: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
created_at: Mapped[datetime | None] = mapped_column(
|
|
DateTime, nullable=True, server_default=func.current_timestamp()
|
|
)
|
|
|
|
|
|
class Nas(Base):
|
|
__tablename__ = "nas"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
nasname: Mapped[str] = mapped_column(String(128), nullable=False)
|
|
shortname: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
type: Mapped[str | None] = mapped_column(String(30), nullable=True, default="other")
|
|
ports: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
|
secret: Mapped[str] = mapped_column(String(60), nullable=False, default="secret")
|
|
server: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
community: Mapped[str | None] = mapped_column(String(50), nullable=True)
|
|
description: Mapped[str | None] = mapped_column(String(200), nullable=True, default="RADIUS Client")
|
|
|
|
|
|
class NasReload(Base):
|
|
__tablename__ = "nasreload"
|
|
|
|
nasipaddress: Mapped[str] = mapped_column(String(15), primary_key=True)
|
|
reloadtime: Mapped[datetime] = mapped_column(DateTime, nullable=False)
|
|
|
|
|
|
class RadCheck(Base):
|
|
__tablename__ = "radcheck"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
username: Mapped[str] = mapped_column(String(64), nullable=False, default="")
|
|
attribute: Mapped[str] = mapped_column(String(64), nullable=False, default="")
|
|
op: Mapped[str] = mapped_column(String(2), nullable=False, default="==")
|
|
value: Mapped[str] = mapped_column(String(253), nullable=False, default="")
|
|
|
|
|
|
class RadReply(Base):
|
|
__tablename__ = "radreply"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
username: Mapped[str] = mapped_column(String(64), nullable=False, default="")
|
|
attribute: Mapped[str] = mapped_column(String(64), nullable=False, default="")
|
|
op: Mapped[str] = mapped_column(String(2), nullable=False, default="=")
|
|
value: Mapped[str] = mapped_column(String(253), nullable=False, default="")
|
|
|
|
|
|
class RadGroupCheck(Base):
|
|
__tablename__ = "radgroupcheck"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
groupname: Mapped[str] = mapped_column(String(64), nullable=False, default="")
|
|
attribute: Mapped[str] = mapped_column(String(64), nullable=False, default="")
|
|
op: Mapped[str] = mapped_column(String(2), nullable=False, default="==")
|
|
value: Mapped[str] = mapped_column(String(253), nullable=False, default="")
|
|
|
|
|
|
class RadGroupReply(Base):
|
|
__tablename__ = "radgroupreply"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
groupname: Mapped[str] = mapped_column(String(64), nullable=False, default="")
|
|
attribute: Mapped[str] = mapped_column(String(64), nullable=False, default="")
|
|
op: Mapped[str] = mapped_column(String(2), nullable=False, default="=")
|
|
value: Mapped[str] = mapped_column(String(253), nullable=False, default="")
|
|
|
|
|
|
class RadUserGroup(Base):
|
|
__tablename__ = "radusergroup"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
username: Mapped[str] = mapped_column(String(64), nullable=False, default="")
|
|
groupname: Mapped[str] = mapped_column(String(64), nullable=False, default="")
|
|
priority: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
|
|
|
|
|
|
class RadAcct(Base):
|
|
__tablename__ = "radacct"
|
|
|
|
radacctid: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
|
acctsessionid: Mapped[str] = mapped_column(String(64), nullable=False, default="")
|
|
acctuniqueid: Mapped[str] = mapped_column(String(32), nullable=False, default="")
|
|
username: Mapped[str] = mapped_column(String(64), nullable=False, default="")
|
|
realm: Mapped[str | None] = mapped_column(String(64), nullable=True, default="")
|
|
nasipaddress: Mapped[str] = mapped_column(String(15), nullable=False, default="")
|
|
nasportid: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
nasporttype: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
acctstarttime: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
acctupdatetime: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
acctstoptime: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
acctinterval: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
|
acctsessiontime: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
|
acctauthentic: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
connectinfo_start: Mapped[str | None] = mapped_column(String(128), nullable=True)
|
|
connectinfo_stop: Mapped[str | None] = mapped_column(String(128), nullable=True)
|
|
acctinputoctets: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
|
|
acctoutputoctets: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
|
|
calledstationid: Mapped[str] = mapped_column(String(50), nullable=False, default="")
|
|
callingstationid: Mapped[str] = mapped_column(String(50), nullable=False, default="")
|
|
acctterminatecause: Mapped[str] = mapped_column(String(32), nullable=False, default="")
|
|
servicetype: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
framedprotocol: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
framedipaddress: Mapped[str] = mapped_column(String(15), nullable=False, default="")
|
|
framedipv6address: Mapped[str] = mapped_column(String(45), nullable=False, default="")
|
|
framedipv6prefix: Mapped[str] = mapped_column(String(45), nullable=False, default="")
|
|
framedinterfaceid: Mapped[str] = mapped_column(String(44), nullable=False, default="")
|
|
delegatedipv6prefix: Mapped[str] = mapped_column(String(45), nullable=False, default="")
|
|
class_: Mapped[str | None] = mapped_column("class", String(64), nullable=True)
|
|
|
|
|
|
class RadPostAuth(Base):
|
|
__tablename__ = "radpostauth"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
username: Mapped[str] = mapped_column(String(64), nullable=False, default="")
|
|
pass_: Mapped[str] = mapped_column("pass", String(64), nullable=False, default="")
|
|
reply: Mapped[str] = mapped_column(String(32), nullable=False, default="")
|
|
authdate: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
class_: Mapped[str | None] = mapped_column("class", String(64), nullable=True)
|