fix: side peek des bases repasse en vanilla JS + largeur 1100px standard (v7.49.0)
- Panneau peek: les bindings Alpine (x-data absent du conteneur) rendaient loovverture et le redimensionnement inoperants -> cblage direct sur le document. - Helper unique window.fdWirePeekResize (app.js): pointer capture, 300px-90vw, clic=fermer, largeur persiste fd_peek_width partagee entre les 4 peeks. - database-table-container margin:0 (tableau colle a gauche, marge Library). - .lib-container remonte dans app.css (trash etait pleine largeur), .db-index 1100px. - ObsiGate verifie sans code: creation .xlsx OK (openpyxl, #186).
This commit is contained in:
@@ -11,6 +11,17 @@ from app.services.http_client import shared_client
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Valeurs de substitution livrées dans app/config.py : elles sont NON VIDES,
|
||||
# donc un simple `bool(client_id and client_secret)` les considérait comme
|
||||
# configurées et /auth/login redirigeait vers Gitea avec client_id=test-id
|
||||
# (échec d'authentification garanti). Un placeholder == provider non configuré.
|
||||
_PLACEHOLDER_CREDS = {"test-id", "test-secret", "change-me", "changeme", "your-client-id"}
|
||||
|
||||
|
||||
def _real(value: str | None) -> bool:
|
||||
"""True when ``value`` is a real credential (not empty, not a placeholder)."""
|
||||
return bool(value) and value.strip().lower() not in _PLACEHOLDER_CREDS
|
||||
|
||||
|
||||
class OAuthProvider(ABC):
|
||||
"""Abstract OAuth2 provider interface."""
|
||||
@@ -52,7 +63,7 @@ class GiteaProvider(OAuthProvider):
|
||||
self.redirect_uri = redirect_uri
|
||||
|
||||
def is_enabled(self) -> bool:
|
||||
return bool(self.client_id and self.client_secret)
|
||||
return _real(self.client_id) and _real(self.client_secret)
|
||||
|
||||
def get_authorize_url(self, state: str, redirect_uri: str | None = None, force_login: bool = False) -> str:
|
||||
params = {
|
||||
@@ -144,7 +155,7 @@ class GitHubProvider(OAuthProvider):
|
||||
self.api_url = "https://api.github.com"
|
||||
|
||||
def is_enabled(self) -> bool:
|
||||
return bool(self.client_id and self.client_secret)
|
||||
return _real(self.client_id) and _real(self.client_secret)
|
||||
|
||||
def get_authorize_url(self, state: str, redirect_uri: str | None = None, force_login: bool = False) -> str:
|
||||
return (
|
||||
|
||||
+15
-2
@@ -13,6 +13,19 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
_serializer = URLSafeTimedSerializer(settings.app_secret_key)
|
||||
|
||||
# Colonnes de la table ``users`` qui ne doivent JAMAIS quitter le serveur :
|
||||
# le cookie de session est signé (HMAC) mais pas chiffré — son payload est
|
||||
# lisible en base64 par quiconque détient le cookie, et ``/auth/user`` le
|
||||
# renvoyait tel quel au client.
|
||||
_SECRET_USER_FIELDS = ("password_hash",)
|
||||
|
||||
|
||||
def public_user(user_data: dict | None) -> dict | None:
|
||||
"""Return a copy of ``user_data`` stripped of credential material."""
|
||||
if user_data is None:
|
||||
return None
|
||||
return {k: v for k, v in user_data.items() if k not in _SECRET_USER_FIELDS}
|
||||
|
||||
|
||||
class SessionManager:
|
||||
"""Manages user sessions via signed cookies (v5.2.0: revocable).
|
||||
@@ -30,7 +43,7 @@ class SessionManager:
|
||||
``user_sessions`` table (ip + user agent) and becomes revocable.
|
||||
"""
|
||||
payload = {
|
||||
"user": user_data,
|
||||
"user": public_user(user_data),
|
||||
"created_at": datetime.now(UTC).replace(tzinfo=None).isoformat(),
|
||||
}
|
||||
user_id = user_data.get("id")
|
||||
@@ -93,7 +106,7 @@ class SessionManager:
|
||||
"""Re-sign a cookie keeping its session id (used after profile edits)."""
|
||||
sid = SessionManager.session_id(cookie) if cookie else None
|
||||
payload = {
|
||||
"user": user_data,
|
||||
"user": public_user(user_data),
|
||||
"created_at": datetime.now(UTC).replace(tzinfo=None).isoformat(),
|
||||
}
|
||||
user_id = user_data.get("id")
|
||||
|
||||
Reference in New Issue
Block a user