package models import ( "crypto/sha256" "database/sql" "fmt" "time" ) type User struct { ID int Username string DisplayName string PfpURL string Bio string AuthenticationString string AuthenticationSalt string AuthenticationAlgorithm string CreatedAt time.Time UpdatedAt time.Time Verified bool Permissions int64 } func GetUserByID(db *sql.DB, id int) (*User, error) { query := "SELECT id, username, display_name, pfp_url, bio, authentication_string, authentication_salt, authentication_algorithm, created_at, updated_at, verified, permissions FROM users WHERE id = ?" row := db.QueryRow(query, id) user := &User{} var displayName sql.NullString var pfpURL sql.NullString var bio sql.NullString var createdAtString sql.NullString var updatedAtString sql.NullString err := row.Scan(&user.ID, &user.Username, &displayName, &pfpURL, &bio, &user.AuthenticationString, &user.AuthenticationSalt, &user.AuthenticationAlgorithm, &createdAtString, &updatedAtString, &user.Verified, &user.Permissions) if err == sql.ErrNoRows { return nil, nil } if err != nil { return nil, err } if displayName.Valid { user.DisplayName = displayName.String } else { user.DisplayName = "" } if pfpURL.Valid { user.PfpURL = pfpURL.String } else { user.PfpURL = "" } if bio.Valid { user.Bio = bio.String } else { user.Bio = "" } if createdAtString.Valid { user.CreatedAt, err = time.Parse("2006-01-02 15:04:05", createdAtString.String) if err != nil { return nil, fmt.Errorf("error parsing created_at: %v", err) } } else { user.CreatedAt = time.Time{} } if updatedAtString.Valid { user.UpdatedAt, err = time.Parse("2006-01-02 15:04:05", updatedAtString.String) if err != nil { return nil, fmt.Errorf("error parsing updated_at: %v", err) } } else { user.UpdatedAt = time.Time{} } return user, nil } func GetUserByUsername(db *sql.DB, username string) (*User, error) { query := "SELECT id, username, display_name, pfp_url, bio, authentication_string, authentication_salt, authentication_algorithm, created_at, updated_at, verified, permissions FROM users WHERE username = ?" row := db.QueryRow(query, username) user := &User{} var displayName sql.NullString var pfpURL sql.NullString var bio sql.NullString var createdAtString sql.NullString var updatedAtString sql.NullString err := row.Scan(&user.ID, &user.Username, &displayName, &pfpURL, &bio, &user.AuthenticationString, &user.AuthenticationSalt, &user.AuthenticationAlgorithm, &createdAtString, &updatedAtString, &user.Verified, &user.Permissions) if err != nil { return nil, err } if displayName.Valid { user.DisplayName = displayName.String } else { user.DisplayName = "" } if pfpURL.Valid { user.PfpURL = pfpURL.String } else { user.PfpURL = "" } if bio.Valid { user.Bio = bio.String } else { user.Bio = "" } if createdAtString.Valid { user.CreatedAt, err = time.Parse("2006-01-02 15:04:05", createdAtString.String) if err != nil { return nil, fmt.Errorf("error parsing created_at: %v", err) } } else { user.CreatedAt = time.Time{} } if updatedAtString.Valid { user.UpdatedAt, err = time.Parse("2006-01-02 15:04:05", updatedAtString.String) if err != nil { return nil, fmt.Errorf("error parsing updated_at: %v", err) } } else { user.UpdatedAt = time.Time{} } return user, nil } func CheckPassword(password, salt, algorithm, hash string) bool { if algorithm != "sha256" { return false } computedHash := HashPassword(password, salt, algorithm) return computedHash == hash } func HashPassword(password, salt, algorithm string) string { if algorithm != "sha256" { return "" } data := password + salt hash := sha256.Sum256([]byte(data)) return fmt.Sprintf("%x", hash) } func CreateUser(db *sql.DB, username, password string) error { salt := "random-salt" // Replace with secure random generation algorithm := "sha256" hash := HashPassword(password, salt, algorithm) 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) return err } func UpdateUserProfile(db *sql.DB, userID int, displayName, pfpURL, bio string) error { query := "UPDATE users SET display_name = ?, pfp_url = ?, bio = ?, updated_at = NOW() WHERE id = ?" _, err := db.Exec(query, displayName, pfpURL, bio, userID) return err } const ( PermCreateBoard int64 = 1 << 0 PermManageUsers int64 = 1 << 1 ) func HasGlobalPermission(user *User, perm int64) bool { return user.Permissions&perm != 0 }