114 lines
2.9 KiB
Python
Executable File
114 lines
2.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
One-time script to migrate player passwords from plaintext to MD5 hashes.
|
|
|
|
This script:
|
|
1. Connects to the SQLite database
|
|
2. Retrieves all players with their passwords
|
|
3. Skips passwords that already look like MD5 hashes (32 hex chars)
|
|
4. Hashes plaintext passwords with MD5
|
|
5. Updates the database with hashed passwords
|
|
|
|
Usage:
|
|
python scripts/migrate_passwords.py [path_to_db]
|
|
|
|
If no path is provided, defaults to 'gralias.db' in the current directory.
|
|
"""
|
|
|
|
import hashlib
|
|
import re
|
|
import sqlite3
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
def is_md5_hash(password: str) -> bool:
|
|
"""Check if password looks like an MD5 hash (32 hex characters)."""
|
|
return bool(re.match(r"^[a-fA-F0-9]{32}$", password))
|
|
|
|
|
|
def hash_password(password: str) -> str:
|
|
"""Hash password with MD5."""
|
|
return hashlib.md5(password.encode("utf-8")).hexdigest()
|
|
|
|
|
|
def migrate_passwords(db_path: str) -> None:
|
|
"""Migrate all player passwords to MD5 hashes."""
|
|
print(f"Connecting to database: {db_path}")
|
|
|
|
if not Path(db_path).exists():
|
|
print(f"Error: Database file not found: {db_path}")
|
|
sys.exit(1)
|
|
|
|
conn = sqlite3.connect(db_path)
|
|
cursor = conn.cursor()
|
|
|
|
try:
|
|
# Get all players
|
|
cursor.execute("SELECT username, password FROM players;")
|
|
players = cursor.fetchall()
|
|
|
|
if not players:
|
|
print("No players found in database.")
|
|
return
|
|
|
|
print(f"Found {len(players)} player(s)")
|
|
print("-" * 60)
|
|
|
|
migrated = 0
|
|
skipped = 0
|
|
errors = 0
|
|
|
|
for username, password in players:
|
|
if not password:
|
|
print(f"[SKIP] {username}: empty password")
|
|
skipped += 1
|
|
continue
|
|
|
|
if is_md5_hash(password):
|
|
print(f"[SKIP] {username}: already MD5 hashed")
|
|
skipped += 1
|
|
continue
|
|
|
|
# Hash the password
|
|
hashed = hash_password(password)
|
|
|
|
try:
|
|
cursor.execute(
|
|
"UPDATE players SET password = ? WHERE username = ?;",
|
|
(hashed, username),
|
|
)
|
|
print(f"[MIGRATED] {username}: '{password}' -> '{hashed}'")
|
|
migrated += 1
|
|
except sqlite3.Error as e:
|
|
print(f"[ERROR] {username}: {e}")
|
|
errors += 1
|
|
|
|
print("-" * 60)
|
|
print(f"Summary: {migrated} migrated, {skipped} skipped, {errors} errors")
|
|
|
|
# Commit changes
|
|
conn.commit()
|
|
print("Changes committed to database.")
|
|
|
|
except sqlite3.Error as e:
|
|
print(f"Database error: {e}")
|
|
conn.rollback()
|
|
sys.exit(1)
|
|
finally:
|
|
conn.close()
|
|
|
|
|
|
def main():
|
|
# Get database path from command line or use default
|
|
if len(sys.argv) > 1:
|
|
db_path = sys.argv[1]
|
|
else:
|
|
db_path = "gralias.db"
|
|
|
|
migrate_passwords(db_path)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|