using bcrypt

jocadbz
Joca 2025-12-07 21:30:23 -03:00
parent 7b934e00a6
commit 876ac33d1b
Signed by: jocadbz
GPG Key ID: B1836DCE2F50BDF7
1 changed files with 46 additions and 23 deletions

View File

@ -1,27 +1,36 @@
package models package models
import ( import (
"crypto/rand"
"crypto/sha256" "crypto/sha256"
"database/sql" "database/sql"
"fmt" "fmt"
"time" "time"
"golang.org/x/crypto/bcrypt"
) )
type User struct { type User struct {
ID int ID int
Username string Username string
DisplayName string DisplayName string
PfpFileID sql.NullInt64 PfpFileID sql.NullInt64
Bio string Bio string
AuthenticationString string AuthenticationString string
AuthenticationSalt string AuthenticationSalt string
AuthenticationAlgorithm string AuthenticationAlgorithm string
CreatedAt time.Time CreatedAt time.Time
UpdatedAt time.Time UpdatedAt time.Time
Verified bool Verified bool
Permissions int64 Permissions int64
} }
const (
// bcryptCost defines the work factor for bcrypt password hashing.
// 12 is a reasonable default; increase for stronger machines.
bcryptCost = 12
)
func GetUserByID(db *sql.DB, id int) (*User, error) { func GetUserByID(db *sql.DB, id int) (*User, error) {
query := "SELECT id, username, display_name, pfp_file_id, bio, authentication_string, authentication_salt, authentication_algorithm, created_at, updated_at, verified, permissions FROM users WHERE id = ?" query := "SELECT id, username, display_name, pfp_file_id, bio, authentication_string, authentication_salt, authentication_algorithm, created_at, updated_at, verified, permissions FROM users WHERE id = ?"
row := db.QueryRow(query, id) row := db.QueryRow(query, id)
@ -108,28 +117,42 @@ func GetUserByUsername(db *sql.DB, username string) (*User, error) {
} }
func CheckPassword(password, salt, algorithm, hash string) bool { func CheckPassword(password, salt, algorithm, hash string) bool {
if algorithm != "sha256" { switch algorithm {
case "bcrypt":
return bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) == nil
case "sha256":
computedHash := HashPassword(password, salt, algorithm)
return computedHash == hash
default:
return false return false
} }
computedHash := HashPassword(password, salt, algorithm)
return computedHash == hash
} }
func HashPassword(password, salt, algorithm string) string { func HashPassword(password, salt, algorithm string) string {
if algorithm != "sha256" { switch algorithm {
case "sha256":
data := password + salt
hash := sha256.Sum256([]byte(data))
return fmt.Sprintf("%x", hash)
default:
return "" return ""
} }
data := password + salt
hash := sha256.Sum256([]byte(data))
return fmt.Sprintf("%x", hash)
} }
func CreateUser(db *sql.DB, username, password string) error { func CreateUser(db *sql.DB, username, password string) error {
salt := "random-salt" // Replace with secure random generation hash, err := bcrypt.GenerateFromPassword([]byte(password), bcryptCost)
algorithm := "sha256" if err != nil {
hash := HashPassword(password, salt, algorithm) return err
}
// Keep salt column for backward compatibility, or else this apparently shits itself
var saltBytes [16]byte
if _, err := rand.Read(saltBytes[:]); err != nil {
return fmt.Errorf("failed to generate salt: %w", err)
}
salt := fmt.Sprintf("%x", saltBytes)
query := "INSERT INTO users (username, authentication_string, authentication_salt, authentication_algorithm, created_at, updated_at, verified, permissions) VALUES (?, ?, ?, ?, NOW(), NOW(), ?, 0)" query := "INSERT INTO users (username, authentication_string, authentication_salt, authentication_algorithm, created_at, updated_at, verified, permissions) VALUES (?, ?, ?, ?, NOW(), NOW(), ?, 0)"
_, err := db.Exec(query, username, hash, salt, algorithm, false) _, err = db.Exec(query, username, string(hash), salt, "bcrypt", false)
return err return err
} }
@ -176,4 +199,4 @@ func GetUsernamesInBoard(db *sql.DB, boardID int) ([]string, error) {
usernames = append(usernames, username) usernames = append(usernames, username)
} }
return usernames, nil return usernames, nil
} }