mirror of
https://github.com/SecurityBrewery/catalyst.git
synced 2025-12-06 07:12:46 +01:00
100 lines
2.3 KiB
Go
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
|
|
}
|