Spaces:
Building
Building
Update admin_routes.py
Browse files- admin_routes.py +53 -17
admin_routes.py
CHANGED
@@ -4,10 +4,12 @@ Flare Admin API Routes
|
|
4 |
Admin UI için gerekli tüm endpoint'ler
|
5 |
"""
|
6 |
|
|
|
7 |
import json
|
8 |
import hashlib
|
9 |
import secrets
|
10 |
import commentjson
|
|
|
11 |
from datetime import datetime, timedelta
|
12 |
from typing import Dict, List, Optional, Any
|
13 |
from pathlib import Path
|
@@ -19,21 +21,31 @@ import jwt
|
|
19 |
|
20 |
from utils import log
|
21 |
from config_provider import ConfigProvider
|
22 |
-
import os
|
23 |
-
from dotenv import load_dotenv
|
24 |
|
25 |
-
#
|
26 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
|
28 |
# ===================== Constants & Config =====================
|
29 |
-
JWT_SECRET = os.getenv("JWT_SECRET", "flare-admin-secret-key-change-in-production")
|
30 |
-
JWT_ALGORITHM = os.getenv("JWT_ALGORITHM", "HS256")
|
31 |
-
JWT_EXPIRATION_HOURS = int(os.getenv("JWT_EXPIRATION_HOURS", "24"))
|
32 |
-
|
33 |
-
# Production check
|
34 |
-
if os.getenv("ENVIRONMENT") == "production" and JWT_SECRET == "flare-admin-secret-key-change-in-production":
|
35 |
-
raise ValueError("JWT_SECRET must be changed in production!")
|
36 |
-
|
37 |
router = APIRouter(prefix="/api")
|
38 |
security = HTTPBearer()
|
39 |
|
@@ -113,6 +125,25 @@ class TestRequest(BaseModel):
|
|
113 |
test_type: str # "all", "ui", "backend", "integration", "spark"
|
114 |
|
115 |
# ===================== Helpers =====================
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
116 |
def hash_password(password: str, salt: str = None) -> tuple[str, str]:
|
117 |
"""Hash password with bcrypt. Returns (hash, salt)"""
|
118 |
if salt is None:
|
@@ -173,6 +204,7 @@ def add_activity_log(config: Dict[str, Any], user: str, action: str, entity_type
|
|
173 |
async def login(request: LoginRequest):
|
174 |
"""User login"""
|
175 |
config = load_config()
|
|
|
176 |
|
177 |
# Find user
|
178 |
users = config.get("config", {}).get("users", [])
|
@@ -182,18 +214,22 @@ async def login(request: LoginRequest):
|
|
182 |
raise HTTPException(status_code=401, detail="Invalid credentials")
|
183 |
|
184 |
# Verify password with bcrypt
|
185 |
-
if
|
186 |
-
#
|
187 |
-
if
|
|
|
|
|
|
|
|
|
188 |
raise HTTPException(status_code=401, detail="Invalid credentials")
|
189 |
|
190 |
# Create JWT token
|
191 |
-
expire = datetime.utcnow() + timedelta(hours=
|
192 |
payload = {
|
193 |
"sub": request.username,
|
194 |
"exp": expire
|
195 |
}
|
196 |
-
token = jwt.encode(payload,
|
197 |
|
198 |
log(f"✅ User '{request.username}' logged in")
|
199 |
return LoginResponse(token=token, username=request.username)
|
|
|
4 |
Admin UI için gerekli tüm endpoint'ler
|
5 |
"""
|
6 |
|
7 |
+
import os
|
8 |
import json
|
9 |
import hashlib
|
10 |
import secrets
|
11 |
import commentjson
|
12 |
+
import bcrypt
|
13 |
from datetime import datetime, timedelta
|
14 |
from typing import Dict, List, Optional, Any
|
15 |
from pathlib import Path
|
|
|
21 |
|
22 |
from utils import log
|
23 |
from config_provider import ConfigProvider
|
|
|
|
|
24 |
|
25 |
+
# ===================== Dynamic Config Loading =====================
|
26 |
+
def get_jwt_config():
|
27 |
+
"""Get JWT configuration based on work_mode"""
|
28 |
+
cfg = ConfigProvider.get()
|
29 |
+
|
30 |
+
if cfg.global_config.is_cloud_mode():
|
31 |
+
# Cloud mode - use HuggingFace Secrets
|
32 |
+
jwt_secret = os.getenv("JWT_SECRET")
|
33 |
+
if not jwt_secret:
|
34 |
+
log("❌ JWT_SECRET not found in HuggingFace Secrets!")
|
35 |
+
jwt_secret = "flare-admin-secret-key-change-in-production" # Fallback
|
36 |
+
else:
|
37 |
+
# On-premise mode - use .env file
|
38 |
+
from dotenv import load_dotenv
|
39 |
+
load_dotenv()
|
40 |
+
jwt_secret = os.getenv("JWT_SECRET", "flare-admin-secret-key-change-in-production")
|
41 |
+
|
42 |
+
return {
|
43 |
+
"secret": jwt_secret,
|
44 |
+
"algorithm": os.getenv("JWT_ALGORITHM", "HS256"),
|
45 |
+
"expiration_hours": int(os.getenv("JWT_EXPIRATION_HOURS", "24"))
|
46 |
+
}
|
47 |
|
48 |
# ===================== Constants & Config =====================
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
router = APIRouter(prefix="/api")
|
50 |
security = HTTPBearer()
|
51 |
|
|
|
125 |
test_type: str # "all", "ui", "backend", "integration", "spark"
|
126 |
|
127 |
# ===================== Helpers =====================
|
128 |
+
def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)) -> str:
|
129 |
+
"""Verify JWT token and return username"""
|
130 |
+
jwt_config = get_jwt_config()
|
131 |
+
|
132 |
+
try:
|
133 |
+
payload = jwt.decode(
|
134 |
+
credentials.credentials,
|
135 |
+
jwt_config["secret"],
|
136 |
+
algorithms=[jwt_config["algorithm"]]
|
137 |
+
)
|
138 |
+
username = payload.get("sub")
|
139 |
+
if username is None:
|
140 |
+
raise HTTPException(status_code=401, detail="Invalid token")
|
141 |
+
return username
|
142 |
+
except jwt.ExpiredSignatureError:
|
143 |
+
raise HTTPException(status_code=401, detail="Token expired")
|
144 |
+
except jwt.JWTError:
|
145 |
+
raise HTTPException(status_code=401, detail="Invalid token")
|
146 |
+
|
147 |
def hash_password(password: str, salt: str = None) -> tuple[str, str]:
|
148 |
"""Hash password with bcrypt. Returns (hash, salt)"""
|
149 |
if salt is None:
|
|
|
204 |
async def login(request: LoginRequest):
|
205 |
"""User login"""
|
206 |
config = load_config()
|
207 |
+
jwt_config = get_jwt_config()
|
208 |
|
209 |
# Find user
|
210 |
users = config.get("config", {}).get("users", [])
|
|
|
214 |
raise HTTPException(status_code=401, detail="Invalid credentials")
|
215 |
|
216 |
# Verify password with bcrypt
|
217 |
+
if user.get("salt"):
|
218 |
+
# New bcrypt format
|
219 |
+
if not verify_password(request.password, user["password_hash"], user["salt"]):
|
220 |
+
raise HTTPException(status_code=401, detail="Invalid credentials")
|
221 |
+
else:
|
222 |
+
# Legacy SHA256 format
|
223 |
+
if hashlib.sha256(request.password.encode()).hexdigest() != user["password_hash"]:
|
224 |
raise HTTPException(status_code=401, detail="Invalid credentials")
|
225 |
|
226 |
# Create JWT token
|
227 |
+
expire = datetime.utcnow() + timedelta(hours=jwt_config["expiration_hours"])
|
228 |
payload = {
|
229 |
"sub": request.username,
|
230 |
"exp": expire
|
231 |
}
|
232 |
+
token = jwt.encode(payload, jwt_config["secret"], algorithm=jwt_config["algorithm"])
|
233 |
|
234 |
log(f"✅ User '{request.username}' logged in")
|
235 |
return LoginResponse(token=token, username=request.username)
|