"""Разовая утилита: задать ВСЕМ действующим учёткам CRM один пароль. Использование: python set_all_passwords.py neon2026 Обновляет dev-базу SQLite (crm/data/crm.db) и, если контейнер neon-db запущен, базу PostgreSQL в docker-стеке. Только для тестового стенда: на живом сервере пароли меняют в панели (свой — кнопка 🔑, чужой — владелец в разделе «Сотрудники»). После смены пароля в .env не забудь: он действует только при ПЕРВОМ создании учётки. """ import hashlib import secrets import sqlite3 import subprocess import sys from pathlib import Path def hash_password(password: str) -> str: # тот же формат, что storage.hash_password: pbkdf2_sha256$iter$salt$hex salt = secrets.token_hex(16) digest = hashlib.pbkdf2_hmac("sha256", password.encode(), bytes.fromhex(salt), 200_000) return f"pbkdf2_sha256$200000${salt}${digest.hex()}" def main() -> None: if len(sys.argv) != 2 or len(sys.argv[1]) < 8: print("Использование: python set_all_passwords.py <пароль-минимум-8-символов>") sys.exit(2) password = sys.argv[1] new_hash = hash_password(password) # 1) dev-база SQLite рядом со скриптом sqlite_path = Path(__file__).resolve().parent / "data" / "crm.db" if sqlite_path.exists(): with sqlite3.connect(sqlite_path) as conn: cur = conn.execute( "UPDATE crm_users SET password_hash = ? WHERE NOT deleted", (new_hash,) ) print(f"SQLite ({sqlite_path.name}): пароль изменён у {cur.rowcount} учёток") else: print(f"SQLite не найдена ({sqlite_path}) — пропускаю") # 2) PostgreSQL в docker-стеке (контейнер neon-db) sql = f"UPDATE crm_users SET password_hash = '{new_hash}' WHERE NOT deleted;" try: proc = subprocess.run( ["docker", "exec", "neon-db", "psql", "-U", "neon", "-d", "neon_crm", "-c", sql], capture_output=True, text=True, timeout=30, ) except (FileNotFoundError, subprocess.TimeoutExpired): print("docker или контейнер neon-db недоступен — postgres-базу не трогал") return if proc.returncode == 0: print("PostgreSQL (neon-db): пароль изменён у всех действующих учёток") else: print(f"postgres UPDATE не прошёл:\n{proc.stderr.strip()}") if __name__ == "__main__": main()