Enha: input check; hash passwords

This commit is contained in:
Grail Finder
2026-02-20 09:15:14 +03:00
parent f61de5645d
commit 83d4f88eb5
4 changed files with 136 additions and 4 deletions

View File

@@ -2,8 +2,10 @@ package handlers
import (
"crypto/hmac"
"crypto/md5"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"fmt"
"gralias/models"
"gralias/utils"
@@ -65,7 +67,7 @@ func HandleFrontLogin(w http.ResponseWriter, r *http.Request) {
return
}
username := r.PostFormValue("username")
if username == "" {
if username == "" || !utils.IsInputSane(username) {
msg := "username not provided"
log.Error(msg)
abortWithError(w, msg)
@@ -77,6 +79,9 @@ func HandleFrontLogin(w http.ResponseWriter, r *http.Request) {
// make sure username does not exists
cleanName := utils.RemoveSpacesFromStr(username)
clearPass := utils.RemoveSpacesFromStr(password)
// hash the password with md5
hash := md5.Sum([]byte(clearPass))
hashedPass := hex.EncodeToString(hash[:])
// check if that user was already in db
userstate, err := repo.PlayerGetByName(r.Context(), cleanName)
if err != nil || userstate == nil {
@@ -84,8 +89,8 @@ func HandleFrontLogin(w http.ResponseWriter, r *http.Request) {
userstate = models.InitPlayer(cleanName)
makeplayer = true
} else {
if userstate.Password != clearPass {
log.Error("wrong password", "username", cleanName, "password", clearPass)
if userstate.Password != hashedPass {
log.Error("wrong password", "username", cleanName)
abortWithError(w, "wrong password")
return
}
@@ -126,7 +131,7 @@ func HandleFrontLogin(w http.ResponseWriter, r *http.Request) {
}
// save state to cache
if makeplayer {
userstate.Password = clearPass
userstate.Password = hashedPass
if err := repo.PlayerAdd(r.Context(), userstate); err != nil {
log.Error("failed to save state", "error", err)
abortWithError(w, err.Error())

113
scripts/migrate_passwords.py Executable file
View File

@@ -0,0 +1,113 @@
#!/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()

View File

@@ -5,6 +5,10 @@ import (
"unicode"
)
const (
SaneLengthMax = 20
)
func RemoveSpacesFromStr(origin string) string {
return strings.Map(func(r rune) rune {
if unicode.IsSpace(r) {
@@ -35,3 +39,13 @@ func RemoveFromSlice(key string, sl []string) []string {
}
return resp
}
func IsInputSane(s string) bool {
if len(s) > SaneLengthMax {
return false
}
if strings.ContainsAny(s, "{}?!$&:/[]~") {
return false
}
return true
}