Files
storage-appliance/internal/auth/user.go

103 lines
2.5 KiB
Go

package auth
import (
"context"
"database/sql"
"errors"
)
type User struct {
ID string
Username string
PasswordHash string
Role string // Legacy field, kept for backward compatibility
CreatedAt string
}
type UserStore struct {
DB *sql.DB
}
func NewUserStore(db *sql.DB) *UserStore {
return &UserStore{DB: db}
}
// GetUserByUsername retrieves a user by username
func (s *UserStore) GetUserByUsername(ctx context.Context, username string) (*User, error) {
var user User
err := s.DB.QueryRowContext(ctx,
`SELECT id, username, password_hash, role, created_at FROM users WHERE username = ?`,
username).Scan(&user.ID, &user.Username, &user.PasswordHash, &user.Role, &user.CreatedAt)
if err != nil {
if err == sql.ErrNoRows {
return nil, errors.New("user not found")
}
return nil, err
}
return &user, nil
}
// GetUserByID retrieves a user by ID
func (s *UserStore) GetUserByID(ctx context.Context, userID string) (*User, error) {
var user User
err := s.DB.QueryRowContext(ctx,
`SELECT id, username, password_hash, role, created_at FROM users WHERE id = ?`,
userID).Scan(&user.ID, &user.Username, &user.PasswordHash, &user.Role, &user.CreatedAt)
if err != nil {
if err == sql.ErrNoRows {
return nil, errors.New("user not found")
}
return nil, err
}
return &user, nil
}
// CreateUser creates a new user
func (s *UserStore) CreateUser(ctx context.Context, username, password string) (*User, error) {
passwordHash, err := HashPassword(password)
if err != nil {
return nil, err
}
userID := username // Using username as ID for simplicity, could use UUID
_, err = s.DB.ExecContext(ctx,
`INSERT INTO users (id, username, password_hash) VALUES (?, ?, ?)`,
userID, username, passwordHash)
if err != nil {
return nil, err
}
return s.GetUserByID(ctx, userID)
}
// UpdatePassword updates a user's password
func (s *UserStore) UpdatePassword(ctx context.Context, userID, newPassword string) error {
passwordHash, err := HashPassword(newPassword)
if err != nil {
return err
}
_, err = s.DB.ExecContext(ctx,
`UPDATE users SET password_hash = ? WHERE id = ?`,
passwordHash, userID)
return err
}
// Authenticate verifies username and password
func (s *UserStore) Authenticate(ctx context.Context, username, password string) (*User, error) {
user, err := s.GetUserByUsername(ctx, username)
if err != nil {
return nil, err
}
valid, err := VerifyPassword(password, user.PasswordHash)
if err != nil {
return nil, err
}
if !valid {
return nil, errors.New("invalid password")
}
return user, nil
}