Files
catalyst/app/auth/server_local.go
2025-09-02 21:58:08 +02:00

100 lines
2.3 KiB
Go

package auth
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"time"
"golang.org/x/crypto/bcrypt"
"github.com/SecurityBrewery/catalyst/app/database/sqlc"
"github.com/SecurityBrewery/catalyst/app/settings"
)
var ErrUserInactive = errors.New("user is inactive")
func handleLogin(queries *sqlc.Queries) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
type loginData struct {
Email string `json:"email"`
Password string `json:"password"`
}
var data loginData
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
unauthorizedJSON(w, "Invalid request")
return
}
user, err := loginWithMail(r.Context(), data.Email, data.Password, queries)
if err != nil {
if errors.Is(err, ErrUserInactive) {
unauthorizedJSON(w, "User is inactive")
return
}
unauthorizedJSON(w, "Login failed")
return
}
permissions, err := queries.ListUserPermissions(r.Context(), user.ID)
if err != nil {
errorJSON(w, http.StatusInternalServerError, "Failed to get user permissions")
return
}
settings, err := settings.Load(r.Context(), queries)
if err != nil {
errorJSON(w, http.StatusInternalServerError, "Failed to load settings")
return
}
duration := time.Duration(settings.RecordAuthToken.Duration) * time.Second
token, err := CreateAccessToken(r.Context(), user, permissions, duration, queries)
if err != nil {
errorJSON(w, http.StatusInternalServerError, "Failed to create login token")
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
response := map[string]string{
"token": token,
}
if err := json.NewEncoder(w).Encode(response); err != nil {
errorJSON(w, http.StatusInternalServerError, "Failed to encode response")
return
}
}
}
func loginWithMail(ctx context.Context, mail, password string, queries *sqlc.Queries) (*sqlc.User, error) {
user, err := queries.UserByEmail(ctx, &mail)
if err != nil {
return nil, fmt.Errorf("failed to find user by email %q: %w", mail, err)
}
if !user.Active {
return nil, ErrUserInactive
}
if err := bcrypt.CompareHashAndPassword([]byte(user.Passwordhash), []byte(password)); err != nil {
return nil, fmt.Errorf("invalid credentials: %w", err)
}
return &user, nil
}