threadr-rewritten/models/user.go

161 lines
5.2 KiB
Go

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
}