mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-10-12 18:51:36 +08:00
204 lines
4.8 KiB
Go
204 lines
4.8 KiB
Go
package impluser
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/SigNoz/signoz/pkg/errors"
|
|
"github.com/SigNoz/signoz/pkg/http/render"
|
|
"github.com/SigNoz/signoz/pkg/modules/user"
|
|
"github.com/SigNoz/signoz/pkg/modules/user/impluser"
|
|
"github.com/SigNoz/signoz/pkg/types"
|
|
"github.com/gorilla/mux"
|
|
)
|
|
|
|
// EnterpriseHandler embeds the base handler implementation
|
|
type Handler struct {
|
|
user.Handler // Embed the base handler interface
|
|
module user.Module
|
|
}
|
|
|
|
func NewHandler(module user.Module) user.Handler {
|
|
baseHandler := impluser.NewHandler(module)
|
|
return &Handler{
|
|
Handler: baseHandler,
|
|
module: module,
|
|
}
|
|
}
|
|
|
|
func (h *Handler) Login(w http.ResponseWriter, r *http.Request) {
|
|
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
var req types.PostableLoginRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
render.Error(w, err)
|
|
return
|
|
}
|
|
|
|
if req.RefreshToken == "" {
|
|
// the EE handler wrapper passes the feature flag value in context
|
|
ssoAvailable, ok := ctx.Value(types.SSOAvailable).(bool)
|
|
if !ok {
|
|
render.Error(w, errors.New(errors.TypeInternal, errors.CodeInternal, "failed to retrieve SSO availability"))
|
|
return
|
|
}
|
|
|
|
if ssoAvailable {
|
|
_, err := h.module.CanUsePassword(ctx, req.Email)
|
|
if err != nil {
|
|
render.Error(w, err)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
user, err := h.module.GetAuthenticatedUser(ctx, req.OrgID, req.Email, req.Password, req.RefreshToken)
|
|
if err != nil {
|
|
render.Error(w, err)
|
|
return
|
|
}
|
|
|
|
jwt, err := h.module.GetJWTForUser(ctx, user)
|
|
if err != nil {
|
|
render.Error(w, err)
|
|
return
|
|
}
|
|
|
|
gettableLoginResponse := &types.GettableLoginResponse{
|
|
GettableUserJwt: jwt,
|
|
UserID: user.ID.String(),
|
|
}
|
|
|
|
render.Success(w, http.StatusOK, gettableLoginResponse)
|
|
}
|
|
|
|
// Override only the methods you need with enterprise-specific implementations
|
|
func (h *Handler) LoginPrecheck(w http.ResponseWriter, r *http.Request) {
|
|
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
// assume user is valid unless proven otherwise and assign default values for rest of the fields
|
|
|
|
email := r.URL.Query().Get("email")
|
|
sourceUrl := r.URL.Query().Get("ref")
|
|
orgID := r.URL.Query().Get("orgID")
|
|
|
|
resp, err := h.module.LoginPrecheck(ctx, orgID, email, sourceUrl)
|
|
if err != nil {
|
|
render.Error(w, err)
|
|
return
|
|
}
|
|
|
|
render.Success(w, http.StatusOK, resp)
|
|
|
|
}
|
|
|
|
func (h *Handler) AcceptInvite(w http.ResponseWriter, r *http.Request) {
|
|
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
req := new(types.PostableAcceptInvite)
|
|
if err := json.NewDecoder(r.Body).Decode(req); err != nil {
|
|
render.Error(w, errors.Wrapf(err, errors.TypeInvalidInput, errors.CodeInvalidInput, "failed to decode user"))
|
|
return
|
|
}
|
|
|
|
// get invite object
|
|
invite, err := h.module.GetInviteByToken(ctx, req.InviteToken)
|
|
if err != nil {
|
|
render.Error(w, err)
|
|
return
|
|
}
|
|
|
|
orgDomain, err := h.module.GetAuthDomainByEmail(ctx, invite.Email)
|
|
if err != nil && !errors.Ast(err, errors.TypeNotFound) {
|
|
render.Error(w, err)
|
|
return
|
|
}
|
|
|
|
precheckResp := &types.GettableLoginPrecheck{
|
|
SSO: false,
|
|
IsUser: false,
|
|
}
|
|
|
|
if invite.Name == "" && req.DisplayName != "" {
|
|
invite.Name = req.DisplayName
|
|
}
|
|
|
|
user, err := types.NewUser(invite.Name, invite.Email, invite.Role, invite.OrgID)
|
|
if err != nil {
|
|
render.Error(w, err)
|
|
return
|
|
}
|
|
|
|
if orgDomain != nil && orgDomain.SsoEnabled {
|
|
// sso is enabled, create user and respond precheck data
|
|
err = h.module.CreateUser(ctx, user)
|
|
if err != nil {
|
|
render.Error(w, err)
|
|
return
|
|
}
|
|
|
|
// check if sso is enforced for the org
|
|
precheckResp, err = h.module.LoginPrecheck(ctx, invite.OrgID, user.Email, req.SourceURL)
|
|
if err != nil {
|
|
render.Error(w, err)
|
|
return
|
|
}
|
|
|
|
} else {
|
|
password, err := types.NewFactorPassword(req.Password)
|
|
if err != nil {
|
|
render.Error(w, err)
|
|
return
|
|
}
|
|
|
|
user, err = h.module.CreateUserWithPassword(ctx, user, password)
|
|
if err != nil {
|
|
render.Error(w, err)
|
|
return
|
|
}
|
|
|
|
precheckResp.IsUser = true
|
|
}
|
|
|
|
// delete the invite
|
|
if err := h.module.DeleteInvite(ctx, invite.OrgID, invite.ID); err != nil {
|
|
render.Error(w, err)
|
|
return
|
|
}
|
|
|
|
render.Success(w, http.StatusOK, precheckResp)
|
|
}
|
|
|
|
func (h *Handler) GetInvite(w http.ResponseWriter, r *http.Request) {
|
|
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
token := mux.Vars(r)["token"]
|
|
sourceUrl := r.URL.Query().Get("ref")
|
|
invite, err := h.module.GetInviteByToken(ctx, token)
|
|
if err != nil {
|
|
render.Error(w, err)
|
|
return
|
|
}
|
|
|
|
// precheck the user
|
|
precheckResp, err := h.module.LoginPrecheck(ctx, invite.OrgID, invite.Email, sourceUrl)
|
|
if err != nil {
|
|
render.Error(w, err)
|
|
return
|
|
}
|
|
|
|
gettableInvite := &types.GettableEEInvite{
|
|
GettableInvite: *invite,
|
|
PreCheck: precheckResp,
|
|
}
|
|
|
|
render.Success(w, http.StatusOK, gettableInvite)
|
|
return
|
|
}
|