initial site
This commit is contained in:
commit
da5b259d06
167 files changed
+34157
No files matched your search
@@ -0,0 +1,62 @@
|
||||
"""Разовая утилита: задать ВСЕМ действующим учёткам 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()
|
||||
Reference in new issue
Block a user