feat(backend): public /api/system/identity for pairing + site_id/lan_ip in status
GET /api/system/identity (unauthenticated, license-exempt) returns
{app: 'xenia-pos', site_id, venue_name, version, api_version: 1} so a phone
can confirm which venue a server is when pairing and when rediscovering the
server after an IP change. No secrets: SITE_KEY never leaves the server.
/api/system/status now also returns site_id and lan_ip (HOST_IP only - in
Docker any auto-detected address is the unreachable bridge IP).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import asyncio
|
||||
import ipaddress
|
||||
import json
|
||||
import os
|
||||
import socket
|
||||
import time
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
@@ -13,6 +14,7 @@ from models.printer import Printer
|
||||
from schemas.printer import PrinterCreate, PrinterUpdate, PrinterOut
|
||||
from routers.deps import get_current_user, require_manager, require_sysadmin
|
||||
from models.user import User
|
||||
from models.settings import PosSettings
|
||||
from models.product import Category, Product
|
||||
from models.table import Table, TableGroup
|
||||
from services import printer_service
|
||||
@@ -30,6 +32,32 @@ def health():
|
||||
return {"status": "ok", "version": settings.VERSION}
|
||||
|
||||
|
||||
# Bump when the waiter app <-> backend contract changes incompatibly, so native
|
||||
# apps (which ship their own UI) can tell they're talking to a server they don't support.
|
||||
API_VERSION = 1
|
||||
|
||||
|
||||
def _lan_ip() -> str | None:
|
||||
"""The address phones should use. Only HOST_IP is trusted: inside Docker any
|
||||
auto-detection returns the container's bridge IP, which phones can't reach."""
|
||||
return os.environ.get("HOST_IP", "").strip() or None
|
||||
|
||||
|
||||
@router.get("/identity")
|
||||
def identity(db: Session = Depends(get_db)):
|
||||
"""Public, unauthenticated. Lets a phone confirm which venue a server is
|
||||
(pairing, and rediscovery after the server's IP changes). No secrets here:
|
||||
site_id is an identifier — the secret is SITE_KEY, which never leaves the server."""
|
||||
venue = db.query(PosSettings).filter(PosSettings.key == "venue.name").first()
|
||||
return {
|
||||
"app": "xenia-pos",
|
||||
"site_id": settings.SITE_ID or None,
|
||||
"venue_name": (venue.value if venue and venue.value else None),
|
||||
"version": settings.VERSION,
|
||||
"api_version": API_VERSION,
|
||||
}
|
||||
|
||||
|
||||
@router.get("/status")
|
||||
def system_status(db: Session = Depends(get_db), user: User = Depends(get_current_user)):
|
||||
from datetime import datetime, timezone
|
||||
@@ -82,6 +110,8 @@ def system_status(db: Session = Depends(get_db), user: User = Depends(get_curren
|
||||
"sync_failed": license_state.get("sync_failed", False),
|
||||
"last_sync": license_state.get("last_sync"),
|
||||
"waiter_domain": license_state.get("waiter_domain"),
|
||||
"site_id": settings.SITE_ID or None,
|
||||
"lan_ip": _lan_ip(),
|
||||
"printers": printer_statuses,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user