chore: initialize insar management system v2
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
import base64
|
||||
import hashlib
|
||||
import hmac
|
||||
import re
|
||||
import secrets
|
||||
from typing import Tuple
|
||||
|
||||
from .config import settings
|
||||
|
||||
|
||||
_USERNAME_RE = re.compile(r"^[a-zA-Z0-9_.-]{3,64}$")
|
||||
_PBKDF2_ITERATIONS = int(settings.AUTH_PBKDF2_ITERATIONS)
|
||||
|
||||
|
||||
def normalize_username(username: str) -> str:
|
||||
return (username or "").strip().lower()
|
||||
|
||||
|
||||
def validate_username(username: str) -> Tuple[bool, str]:
|
||||
normalized = normalize_username(username)
|
||||
if not normalized:
|
||||
return False, "用户名不能为空。"
|
||||
if not _USERNAME_RE.match(normalized):
|
||||
return False, "用户名仅支持 3-64 位字母、数字、下划线、点和短横线。"
|
||||
return True, ""
|
||||
|
||||
|
||||
def validate_password(password: str) -> Tuple[bool, str]:
|
||||
password = password or ""
|
||||
if len(password) < 8:
|
||||
return False, "密码长度至少 8 位。"
|
||||
if not re.search(r"[A-Z]", password):
|
||||
return False, "密码需包含至少一个大写字母。"
|
||||
if not re.search(r"[a-z]", password):
|
||||
return False, "密码需包含至少一个小写字母。"
|
||||
if not re.search(r"[0-9]", password):
|
||||
return False, "密码需包含至少一个数字。"
|
||||
return True, ""
|
||||
|
||||
|
||||
def hash_password(password: str, iterations: int = _PBKDF2_ITERATIONS) -> str:
|
||||
salt = secrets.token_bytes(16)
|
||||
dk = hashlib.pbkdf2_hmac("sha256", password.encode("utf-8"), salt, iterations)
|
||||
salt_b64 = base64.b64encode(salt).decode("utf-8")
|
||||
hash_b64 = base64.b64encode(dk).decode("utf-8")
|
||||
return f"pbkdf2_sha256${iterations}${salt_b64}${hash_b64}"
|
||||
|
||||
|
||||
def verify_password(password: str, encoded: str) -> bool:
|
||||
try:
|
||||
algo, iteration_str, salt_b64, hash_b64 = (encoded or "").split("$", 3)
|
||||
if algo != "pbkdf2_sha256":
|
||||
return False
|
||||
iterations = int(iteration_str)
|
||||
salt = base64.b64decode(salt_b64.encode("utf-8"))
|
||||
expected = base64.b64decode(hash_b64.encode("utf-8"))
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
actual = hashlib.pbkdf2_hmac("sha256", (password or "").encode("utf-8"), salt, iterations)
|
||||
return hmac.compare_digest(actual, expected)
|
||||
|
||||
|
||||
def generate_session_token() -> str:
|
||||
return secrets.token_urlsafe(48)
|
||||
|
||||
|
||||
def hash_session_token(token: str) -> str:
|
||||
return hashlib.sha256((token or "").encode("utf-8")).hexdigest()
|
||||
Reference in New Issue
Block a user