poolcoach / app /qr.py
masterdanh's picture
deploy: snapshot for HF Space
78738de
Raw
History Blame Contribute Delete
1.84 kB
"""Token QR bàn — ký `itsdangerous`, payload (tenant_id, table_id).
Token KHÔNG có hạn dùng, cố ý: QR in ra dán lên bàn là vật lý vĩnh viễn,
"hết hạn" thuộc về guest_session (TTL 24h, bảng `guest_sessions`), không
thuộc về token. Thu hồi QR = đổi POOLCOACH_SECRET (mọi token cũ chết cùng lúc).
Secret từ env `POOLCOACH_SECRET`; không set → default dev + warning lúc boot
(main.py in). Default dev để chạy local không cần cấu hình gì — nhưng token
ký bằng nó KHÔNG có giá trị bảo mật.
"""
from __future__ import annotations
import os
from itsdangerous import BadSignature, URLSafeSerializer
DEV_SECRET = "poolcoach-dev-secret-khong-dung-cho-prod"
_SALT = "poolcoach-table-qr"
def secret_is_default() -> bool:
return not os.environ.get("POOLCOACH_SECRET")
def _serializer() -> URLSafeSerializer:
# Đọc env MỖI LẦN thay vì cache lúc import: test đổi secret bằng
# monkeypatch.setenv phải có tác dụng ngay.
secret = os.environ.get("POOLCOACH_SECRET") or DEV_SECRET
return URLSafeSerializer(secret, salt=_SALT)
def make_table_token(tenant_id: int, table_id: int) -> str:
return _serializer().dumps([tenant_id, table_id])
def read_table_token(token: str) -> tuple[int, int] | None:
"""Trả (tenant_id, table_id), hoặc None nếu chữ ký sai / payload lạ."""
try:
data = _serializer().loads(token)
except BadSignature:
return None
# Chữ ký đúng nhưng payload không đúng shape vẫn là token rác (ví dụ
# token ký cho mục đích khác cùng secret) — từ chối nốt.
if (not isinstance(data, (list, tuple)) or len(data) != 2
or not all(isinstance(v, int) for v in data)):
return None
return int(data[0]), int(data[1])