IMPROVE: cho phép lưu dự án và phục hồi dự án vừa tắt
This commit is contained in:
+24
-9
@@ -5,25 +5,40 @@ import time
|
||||
import base64
|
||||
import uuid
|
||||
import os
|
||||
import secrets
|
||||
from typing import Optional, Dict, Any
|
||||
from app.models.user import get_db_connection
|
||||
from app.config import settings
|
||||
|
||||
SECRET_KEY = os.getenv("SECRET_KEY", "sonicforge_secret_key_super_secure_2026")
|
||||
|
||||
def hash_password(password: str) -> str:
|
||||
def hash_password(password: str, salt: Optional[str] = None) -> str:
|
||||
"""
|
||||
Hash password using PBKDF2 HMAC SHA-256 with salt.
|
||||
Hash password using PBKDF2 HMAC SHA-256 with a per-user random salt.
|
||||
Guarantees raw passwords are NEVER stored or exposed in plaintext.
|
||||
Returns format: 'salt_hex:hashed_key_hex' (colon-delimited, stores both values).
|
||||
If salt is provided, uses that salt (for verification).
|
||||
If salt is None, generates a new 32-byte random salt.
|
||||
"""
|
||||
salt = b"sonicforge_crypto_salt_2026_secure_"
|
||||
key = hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), salt, 100000)
|
||||
return key.hex()
|
||||
if salt is None:
|
||||
salt = secrets.token_hex(32)
|
||||
key = hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), salt.encode('utf-8'), 600000)
|
||||
return f"{salt}:{key.hex()}"
|
||||
|
||||
def verify_password(plain_password: str, hashed_password: str) -> bool:
|
||||
"""Verify plain password against PBKDF2 hashed password using constant-time comparison."""
|
||||
computed_hash = hash_password(plain_password)
|
||||
return hmac.compare_digest(computed_hash, hashed_password)
|
||||
def verify_password(plain_password: str, stored_value: str) -> bool:
|
||||
"""Verify plain password against stored 'salt:hash' using constant-time comparison.
|
||||
Also supports legacy-format hash (hex only, without salt) for backward compatibility."""
|
||||
if ':' in stored_value:
|
||||
parts = stored_value.split(':', 1)
|
||||
salt = parts[0]
|
||||
expected_hash = parts[1]
|
||||
computed = hash_password(plain_password, salt)
|
||||
computed_hash = computed.split(':', 1)[1]
|
||||
return hmac.compare_digest(computed_hash, expected_hash)
|
||||
else:
|
||||
expected_hash = stored_value
|
||||
computed_hash = hashlib.pbkdf2_hmac('sha256', plain_password.encode('utf-8'), b"sonicforge_crypto_salt_2026_secure_", 600000).hex()
|
||||
return hmac.compare_digest(computed_hash, expected_hash)
|
||||
|
||||
def create_token(user_id: str, username: str, role: str, must_change_password: bool) -> str:
|
||||
payload = {
|
||||
|
||||
Reference in New Issue
Block a user