mirror of
https://github.com/teamhanko/hanko.git
synced 2025-10-27 14:17:56 +08:00
134 lines
3.6 KiB
Go
134 lines
3.6 KiB
Go
package handler
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"github.com/gobuffalo/pop/v6"
|
|
"github.com/gofrs/uuid"
|
|
"github.com/labstack/echo/v4"
|
|
"github.com/lestrrat-go/jwx/v2/jwt"
|
|
"github.com/teamhanko/hanko/backend/audit_log"
|
|
"github.com/teamhanko/hanko/backend/dto"
|
|
"github.com/teamhanko/hanko/backend/persistence"
|
|
"github.com/teamhanko/hanko/backend/persistence/models"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
type UserHandler struct {
|
|
persister persistence.Persister
|
|
auditLogger auditlog.Logger
|
|
}
|
|
|
|
func NewUserHandler(persister persistence.Persister, auditLogger auditlog.Logger) *UserHandler {
|
|
return &UserHandler{
|
|
persister: persister,
|
|
auditLogger: auditLogger,
|
|
}
|
|
}
|
|
|
|
type UserCreateBody struct {
|
|
Email string `json:"email" validate:"required,email"`
|
|
}
|
|
|
|
func (h *UserHandler) Create(c echo.Context) error {
|
|
var body UserCreateBody
|
|
if err := (&echo.DefaultBinder{}).BindBody(c, &body); err != nil {
|
|
return dto.ToHttpError(err)
|
|
}
|
|
|
|
if err := c.Validate(body); err != nil {
|
|
return dto.ToHttpError(err)
|
|
}
|
|
|
|
body.Email = strings.ToLower(body.Email)
|
|
|
|
return h.persister.Transaction(func(tx *pop.Connection) error {
|
|
user, err := h.persister.GetUserPersisterWithConnection(tx).GetByEmail(body.Email)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get user: %w", err)
|
|
}
|
|
|
|
if user != nil {
|
|
return dto.NewHTTPError(http.StatusConflict).SetInternal(errors.New(fmt.Sprintf("user with email %s already exists", user.Email)))
|
|
}
|
|
|
|
newUser := models.NewUser(body.Email)
|
|
err = h.persister.GetUserPersisterWithConnection(tx).Create(newUser)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to store user: %w", err)
|
|
}
|
|
|
|
_ = h.auditLogger.Create(c, models.AuditLogUserCreated, &newUser, nil) // TODO: what to do on error
|
|
|
|
return c.JSON(http.StatusOK, newUser)
|
|
})
|
|
}
|
|
|
|
func (h *UserHandler) Get(c echo.Context) error {
|
|
userId := c.Param("id")
|
|
|
|
sessionToken, ok := c.Get("session").(jwt.Token)
|
|
if !ok {
|
|
return errors.New("missing or malformed jwt")
|
|
}
|
|
|
|
if sessionToken.Subject() != userId {
|
|
return dto.NewHTTPError(http.StatusForbidden).SetInternal(errors.New(fmt.Sprintf("user %s tried to get user %s", sessionToken.Subject(), userId)))
|
|
}
|
|
|
|
user, err := h.persister.GetUserPersister().Get(uuid.FromStringOrNil(userId))
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get user: %w", err)
|
|
}
|
|
|
|
if user == nil {
|
|
return dto.NewHTTPError(http.StatusNotFound).SetInternal(errors.New("user not found"))
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, user)
|
|
}
|
|
|
|
type UserGetByEmailBody struct {
|
|
Email string `json:"email" validate:"required,email"`
|
|
}
|
|
|
|
func (h *UserHandler) GetUserIdByEmail(c echo.Context) error {
|
|
var request UserGetByEmailBody
|
|
if err := (&echo.DefaultBinder{}).BindBody(c, &request); err != nil {
|
|
return dto.ToHttpError(err)
|
|
}
|
|
|
|
if err := c.Validate(request); err != nil {
|
|
return dto.ToHttpError(err)
|
|
}
|
|
|
|
user, err := h.persister.GetUserPersister().GetByEmail(strings.ToLower(request.Email))
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get user: %w", err)
|
|
}
|
|
|
|
if user == nil {
|
|
return dto.NewHTTPError(http.StatusNotFound).SetInternal(errors.New("user not found"))
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, struct {
|
|
UserId string `json:"id"`
|
|
Verified bool `json:"verified"`
|
|
HasWebauthnCredential bool `json:"has_webauthn_credential"`
|
|
}{
|
|
UserId: user.ID.String(),
|
|
Verified: user.Verified,
|
|
HasWebauthnCredential: len(user.WebauthnCredentials) > 0,
|
|
})
|
|
}
|
|
|
|
func (h *UserHandler) Me(c echo.Context) error {
|
|
sessionToken, ok := c.Get("session").(jwt.Token)
|
|
if !ok {
|
|
return errors.New("failed to cast session object")
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, map[string]string{"id": sessionToken.Subject()})
|
|
}
|