feat(rt+auth): batched input publish boi so 4 (het crackle) + auto-login loopback khong can mat khau
- fx_realtime: write_input gom FXRT_IN_SLOTS(4) frame vao _in_pending, flush ghi 1 lan + h.in_write += n (publish atomic -> bridge take=4 luon, het deficit) - plugins pump: flush_input_stale(0.004) dau vong lap -> input le khong ket - auth: _is_loopback(127.*/::1/localhost) -> get_current_user khong token = admin tu DB (must_change_password=False); POST /auth/local auto-login loopback, LAN 403 - ws fx-realtime: loopback khong token cho phep, remote thieu token -> close 4401 - UI: checkAuthStatus khong savedToken -> thu localLogin, thanh cong vao DAW, that bai -> modal login nhu cu; cache-buster v=202608212400
This commit is contained in:
@@ -52,6 +52,30 @@ def _record_login_success(ip: str):
|
||||
with _LOGIN_LOCK:
|
||||
_LOGIN_FAILURES.pop(ip, None)
|
||||
|
||||
def _is_loopback(host: Optional[str]) -> bool:
|
||||
"""Standalone: request từ chính máy (127.0.0.1/::1/localhost) → bỏ qua
|
||||
đăng nhập. Client LAN (IP khác) → vẫn cần mật khẩu."""
|
||||
if not host:
|
||||
return False
|
||||
host = host.lower()
|
||||
return host in ("127.0.0.1", "::1", "localhost") or host.startswith("127.")
|
||||
|
||||
def _loopback_admin_user() -> dict:
|
||||
"""Identity admin cho loopback — real user_id từ DB; không bắt buộc đổi
|
||||
mật khẩu (standalone tự vào thẳng DAW)."""
|
||||
try:
|
||||
conn = get_db_connection()
|
||||
try:
|
||||
cur = conn.execute("SELECT id, username, role FROM users WHERE username = ?", ("admin",))
|
||||
row = cur.fetchone()
|
||||
finally:
|
||||
conn.close()
|
||||
if row:
|
||||
return {"user_id": row["id"], "username": row["username"], "role": row["role"], "must_change_password": False}
|
||||
except Exception:
|
||||
pass
|
||||
return {"user_id": "local", "username": "admin", "role": "admin", "must_change_password": False}
|
||||
|
||||
def _set_auth_cookie(response: Response, token: str):
|
||||
response.set_cookie(
|
||||
COOKIE_NAME, token,
|
||||
@@ -68,6 +92,10 @@ def get_current_user(request: Request, authorization: Optional[str] = Header(Non
|
||||
elif request.cookies.get(COOKIE_NAME):
|
||||
token = request.cookies.get(COOKIE_NAME)
|
||||
if not token:
|
||||
# Standalone (loopback): không cần mật khẩu — auto admin. LAN vẫn 401.
|
||||
host = request.client.host if request.client else None
|
||||
if _is_loopback(host):
|
||||
return _loopback_admin_user()
|
||||
raise HTTPException(status_code=401, detail="Thiếu Token xác thực hoặc Token không hợp lệ")
|
||||
payload = decode_token(token)
|
||||
if not payload:
|
||||
@@ -135,6 +163,22 @@ async def login(req: LoginRequest, request: Request):
|
||||
_set_auth_cookie(resp, token)
|
||||
return resp
|
||||
|
||||
@router.post("/local")
|
||||
async def local_login(request: Request, response: Response):
|
||||
"""Auto-login standalone: chỉ cho phép từ loopback (máy chạy engine).
|
||||
Client LAN nhận 403 → buộc đăng nhập mật khẩu qua /login."""
|
||||
host = request.client.host if request.client else None
|
||||
if not _is_loopback(host):
|
||||
raise HTTPException(status_code=403, detail="Truy cập từ xa — cần đăng nhập")
|
||||
u = _loopback_admin_user()
|
||||
token = create_token(u["user_id"], u["username"], u["role"], False)
|
||||
resp = JSONResponse({
|
||||
"access_token": token,
|
||||
"user": {"id": u["user_id"], "username": u["username"], "role": u["role"], "must_change_password": False},
|
||||
})
|
||||
_set_auth_cookie(resp, token)
|
||||
return resp
|
||||
|
||||
def _validate_password_strength(password: str):
|
||||
"""Minimal strength policy: >= 8 chars and not trivially common."""
|
||||
if len(password) < 8:
|
||||
|
||||
Reference in New Issue
Block a user