mirror of
https://github.com/rommapp/romm.git
synced 2026-06-28 06:46:00 +00:00
Long-lived, revocable, scope-restricted tokens for external clients (mobile apps, retro handhelds, third-party tools). Includes: - Backend: model, migration, DB handler, auth integration (rmm_ prefix routing in HybridAuthBackend), CRUD + pairing + exchange endpoints, rate limiting, scope intersection enforcement, admin oversight - Frontend: settings page with token management table, stepped create/deliver dialog (config -> copy/pair), QR code with RomM logo, admin token table, standalone /pair page for QR scan landing - /pair page supports custom-scheme callbacks for app deep linking, falls back to displaying code for manual entry - 33 backend tests across 5 classes (CRUD, auth, isolation, pairing, admin)
28 lines
986 B
Python
28 lines
986 B
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
from typing import TYPE_CHECKING
|
|
|
|
from sqlalchemy import TIMESTAMP, ForeignKey, String
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from models.base import BaseModel
|
|
|
|
if TYPE_CHECKING:
|
|
from models.user import User
|
|
|
|
|
|
class ClientToken(BaseModel):
|
|
__tablename__ = "client_tokens"
|
|
__table_args__ = {"extend_existing": True}
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
|
user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"))
|
|
name: Mapped[str] = mapped_column(String(255))
|
|
hashed_token: Mapped[str] = mapped_column(String(64), unique=True, index=True)
|
|
scopes: Mapped[str] = mapped_column(String(1000))
|
|
expires_at: Mapped[datetime | None] = mapped_column(TIMESTAMP(timezone=True))
|
|
last_used_at: Mapped[datetime | None] = mapped_column(TIMESTAMP(timezone=True))
|
|
|
|
user: Mapped[User] = relationship(lazy="joined")
|