Files
warmbly/internal/api/handler/auth_setup.go

68 lines
1.6 KiB
Go

package handler
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/warmbly/warmbly/internal/app/token"
"github.com/warmbly/warmbly/internal/errx"
)
type setupClaimRequest struct {
Token string `json:"token"`
Email string `json:"email"`
Password string `json:"password"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
}
// SetupClaim exchanges the one-time link printed at first boot for the owner
// account, and signs them straight in.
//
// Public by necessity: there is no account to authenticate as yet. The token is
// the protection, and it is consumed atomically, refused once any user exists,
// and covered by the same per-IP limiter as the rest of the auth group.
func (h *Handler) SetupClaim(c *gin.Context) {
if h.BootstrapService == nil {
errx.Handle(c, errx.New(errx.NotFound, "Setup is not available on this deployment."))
return
}
var req setupClaimRequest
if err := c.ShouldBindJSON(&req); err != nil {
errx.Handle(c, errx.ErrInvalid)
return
}
u, xerr := h.BootstrapService.Claim(
c.Request.Context(),
req.Token,
req.Email,
req.Password,
req.FirstName,
req.LastName,
)
if xerr != nil {
errx.Handle(c, xerr)
return
}
// Hand back a session rather than bouncing them to the login screen. They
// just proved ownership of the instance; asking them to type the password
// again immediately is friction with no security value.
session, terr := h.TokenService.GenerateSession(
c.Request.Context(),
u.ID,
u.Email,
c.ClientIP(),
c.Request.UserAgent(),
token.AuthProviderEmail,
)
if terr != nil {
errx.Handle(c, terr)
return
}
c.JSON(http.StatusOK, session)
}