summaryrefslogtreecommitdiff
path: root/models/user.go
blob: f2b4e22098f95445ef30a6ef64748d0bbaa56080 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package models

import (
	"auth-proxy/database"
	"auth-proxy/types"
	"database/sql"

	"golang.org/x/crypto/bcrypt"
)

// HashPassword generates a bcrypt hash of the password
func HashPassword(password string) (string, error) {
	bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
	return string(bytes), err
}

// CheckPasswordHash compares a password with a hash
func CheckPasswordHash(password, hash string) bool {
	err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
	return err == nil
}

// CreateUser creates a new user in the database
func CreateUser(username, password, role string) (*types.User, error) {
	passwordHash, err := HashPassword(password)
	if err != nil {
		return nil, err
	}

	query := database.Rebind("INSERT INTO users(username, password_hash, role) VALUES(?, ?, ?)")
	stmt, err := database.DB.Prepare(query)
	if err != nil {
		return nil, err
	}
	defer stmt.Close() //nolint:errcheck

	_, err = stmt.Exec(username, passwordHash, role)
	if err != nil {
		return nil, err
	}

	return GetUserByUsername(username) // Return the full user object
}

// baseSelectQuery is the common set of columns for user queries
const baseSelectQuery = "SELECT id, username, password_hash, role, is_active, failed_logins, last_login_at, created_at, updated_at FROM users"

// scanUser scans a row into a User struct
func scanUser(row *sql.Row) (*types.User, error) {
	user := &types.User{}
	err := row.Scan(&user.ID, &user.Username, &user.PasswordHash, &user.Role, &user.IsActive, &user.FailedLogins, &user.LastLoginAt, &user.CreatedAt, &user.UpdatedAt)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, nil // User not found
		}
		return nil, err
	}
	return user, nil
}

// GetUserByUsername retrieves a user by their username
func GetUserByUsername(username string) (*types.User, error) {
	query := database.Rebind(baseSelectQuery + " WHERE username = ?")
	row := database.DB.QueryRow(query, username)
	return scanUser(row)
}

// GetUserByID retrieves a user by their ID
func GetUserByID(id int64) (*types.User, error) {
	query := database.Rebind(baseSelectQuery + " WHERE id = ?")
	row := database.DB.QueryRow(query, id)
	return scanUser(row)
}

// GetAllUsers retrieves all users from the database
func GetAllUsers() ([]types.User, error) {
	rows, err := database.DB.Query(baseSelectQuery)
	if err != nil {
		return nil, err
	}
	defer rows.Close() //nolint:errcheck

	var users []types.User
	for rows.Next() {
		var user types.User
		if err := rows.Scan(&user.ID, &user.Username, &user.PasswordHash, &user.Role, &user.IsActive, &user.FailedLogins, &user.LastLoginAt, &user.CreatedAt, &user.UpdatedAt); err != nil {
			return nil, err
		}
		users = append(users, user)
	}
	return users, nil
}

// UpdateUserRole updates a user's role
func UpdateUserRole(id int64, role string) error {
	query := database.Rebind("UPDATE users SET role = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?")
	_, err := database.DB.Exec(query, role, id)
	return err
}

// DeleteUser deletes a user from the database
func DeleteUser(id int64) error {
	query := database.Rebind("DELETE FROM users WHERE id = ?")
	_, err := database.DB.Exec(query, id)
	return err
}

// UpdateUserPassword updates a user's password hash
func UpdateUserPassword(id int64, passwordHash string) error {
	query := database.Rebind("UPDATE users SET password_hash = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?")
	_, err := database.DB.Exec(query, passwordHash, id)
	return err
}

// RecordLoginSuccess resets failed login attempts and updates last login time
func RecordLoginSuccess(id int64) error {
	query := database.Rebind("UPDATE users SET failed_logins = 0, last_login_at = CURRENT_TIMESTAMP, updated_at = CURRENT_TIMESTAMP WHERE id = ?")
	_, err := database.DB.Exec(query, id)
	return err
}

// RecordLoginFailure increments the failed login counter
func RecordLoginFailure(id int64) error {
	query := database.Rebind("UPDATE users SET failed_logins = failed_logins + 1, updated_at = CURRENT_TIMESTAMP WHERE id = ?")
	_, err := database.DB.Exec(query, id)
	return err
}

// SetUserActiveStatus updates the is_active flag for a user
func SetUserActiveStatus(id int64, isActive bool) error {
	query := database.Rebind("UPDATE users SET is_active = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?")
	_, err := database.DB.Exec(query, isActive, id)
	return err
}