import hashlib, secrets, functools, os from datetime import datetime, timedelta from flask import request, redirect, session def hash_password(password: str) -> str: """Bezpieczne hashowanie: PBKDF2-SHA256 z solą.""" salt = secrets.token_hex(32) dk = hashlib.pbkdf2_hmac('sha256', password.encode(), salt.encode(), 600000) return f"pbkdf2:sha256:600000${salt}${dk.hex()}" def verify_password(password: str, hash_: str) -> bool: if hash_.startswith("pbkdf2:sha256:"): # Format: pbkdf2:sha256:600000$SALT$DK_HEX try: meta, salt, stored = hash_.split("$", 2) _, _, iters_str = meta.split(":", 2) iters = int(iters_str) dk = hashlib.pbkdf2_hmac('sha256', password.encode(), salt.encode(), iters) return secrets.compare_digest(dk.hex(), stored) except Exception: return False # Stary format (SHA256 plain) – automatyczna migracja przy logowaniu old = hashlib.sha256(password.encode()).hexdigest() if secrets.compare_digest(old, hash_): # Migruj do nowego formatu (tylko jeśli hash w DB to stary format) try: from database import get_db db = get_db() new_hash = hash_password(password) db.execute("UPDATE users SET password_hash=? WHERE password_hash=?", (new_hash, hash_)) db.commit() db.close() except Exception: pass return True return False def login_required(f): @functools.wraps(f) def wrap(*a, **kw): if not session.get("username"): return redirect("/login?next=" + request.path) return f(*a, **kw) return wrap def build_auth_required(f): @functools.wraps(f) def wrap(*a, **kw): from config.settings import BUILD_PASSWORD if request.cookies.get("build_auth") != BUILD_PASSWORD: return redirect("/build/login") return f(*a, **kw) return wrap def can_edit_repo(username, repo_name): if not username: return False from database import get_db db = get_db() row = db.execute("SELECT role FROM repo_permissions WHERE repo_name=? AND username=?", (repo_name, username)).fetchone() db.close() return row is not None def get_section(): """Wykrywa aktywną sekcję na podstawie domeny.""" host = request.host.split(":")[0] from config.settings import DOMAINS return DOMAINS.get(host, "main")