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 }