Files
probo/pkg/server/api/trust/v1/auth_resolvers.go
Sacha Al Himdani 88242eed87 Restore MCP cross-origin protection after go-sdk v1.6.0 bump
The go-sdk v1.6.0 release no longer applies a default
CrossOriginProtection when the field is nil in StreamableHTTPOptions,
silently removing Origin header verification. Wrap the streamable
handler with http.NewCrossOriginProtection().Handler(...) (the
recommended replacement, since the SDK field is deprecated).

Also regenerate gqlgen resolvers to track v0.17.90.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-05 14:46:04 +02:00

180 lines
5.7 KiB
Go

package trust_v1
// This file will be automatically regenerated based on the schema, any resolver
// implementations
// will be copied through when generating and any unknown code will be moved to the end.
// Code generated by github.com/99designs/gqlgen version v0.17.90
import (
"context"
"errors"
"go.gearno.de/kit/log"
"go.probo.inc/probo/pkg/baseurl"
"go.probo.inc/probo/pkg/coredata"
"go.probo.inc/probo/pkg/iam"
"go.probo.inc/probo/pkg/saferedirect"
"go.probo.inc/probo/pkg/server/api/authn"
"go.probo.inc/probo/pkg/server/api/compliancepage"
"go.probo.inc/probo/pkg/server/api/trust/v1/types"
"go.probo.inc/probo/pkg/server/gqlutils"
)
// SendMagicLink is the resolver for the sendMagicLink field.
func (r *mutationResolver) SendMagicLink(ctx context.Context, input types.SendMagicLinkInput) (*types.SendMagicLinkPayload, error) {
trustCenter := compliancepage.CompliancePageFromContext(ctx)
baseURL := compliancepage.CompliancePageBaseURLFromContext(ctx)
safeRedirect := saferedirect.New(saferedirect.StaticHosts(baseurl.MustParse(*baseURL).Host()))
if input.Continue != nil {
_, ok := safeRedirect.Validate(ctx, *input.Continue)
if !ok {
return nil, gqlutils.Invalidf(ctx, "invalid continue URL")
}
}
req := &iam.SendMagicLinkRequest{
Email: input.Email,
CompliancePageID: &trustCenter.ID,
OrganizationID: trustCenter.OrganizationID,
URLPath: "verify-magic-link",
Continue: input.Continue,
}
if err := r.iam.AuthService.SendMagicLink(ctx, req); err != nil {
r.logger.ErrorCtx(ctx, "cannot send magic link", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return nil, nil
}
// VerifyMagicLink is the resolver for the verifyMagicLink field.
func (r *mutationResolver) VerifyMagicLink(ctx context.Context, input types.VerifyMagicLinkInput) (*types.VerifyMagicLinkPayload, error) {
session := authn.SessionFromContext(ctx)
identity := authn.IdentityFromContext(ctx)
email, err := r.iam.AuthService.GetMagicLinkEmail(ctx, input.Token)
if err != nil {
var errExpiredToken *iam.ErrExpiredToken
if errors.As(err, &errExpiredToken) {
return nil, gqlutils.Invalid(ctx, err)
}
var errInvalidToken *iam.ErrInvalidToken
if errors.As(err, &errInvalidToken) {
return nil, gqlutils.Invalid(ctx, err)
}
r.logger.ErrorCtx(ctx, "cannot get magic link email", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
var continueURL *string
switch {
case session == nil:
var err error
identity, session, continueURL, err = r.iam.AuthService.OpenSessionWithMagicLink(ctx, input.Token)
if err != nil {
var errExpiredToken *iam.ErrExpiredToken
if errors.As(err, &errExpiredToken) {
return nil, gqlutils.Invalid(ctx, err)
}
var errInvalidToken *iam.ErrInvalidToken
if errors.As(err, &errInvalidToken) {
return nil, gqlutils.Invalid(ctx, err)
}
r.logger.ErrorCtx(ctx, "cannot open session with magic link", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
case identity.EmailAddress != email:
if err := r.iam.SessionService.CloseSession(ctx, session.ID); err != nil {
r.logger.ErrorCtx(ctx, "cannot close session", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
var err error
identity, session, continueURL, err = r.iam.AuthService.OpenSessionWithMagicLink(ctx, input.Token)
if err != nil {
var errExpiredToken *iam.ErrExpiredToken
if errors.As(err, &errExpiredToken) {
return nil, gqlutils.Invalid(ctx, err)
}
var errInvalidToken *iam.ErrInvalidToken
if errors.As(err, &errInvalidToken) {
return nil, gqlutils.Invalid(ctx, err)
}
r.logger.ErrorCtx(ctx, "cannot open session with magic link", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
}
trustCenter := compliancepage.CompliancePageFromContext(ctx)
if _, err := r.trust.ProvisionMember(ctx, trustCenter.ID, identity.ID); err != nil {
r.logger.ErrorCtx(ctx, "cannot provision member", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
w := gqlutils.HTTPResponseWriterFromContext(ctx)
r.sessionCookie.Set(w, session)
return &types.VerifyMagicLinkPayload{
Continue: continueURL,
}, nil
}
// UpdateFullName is the resolver for the updateFullName field.
func (r *mutationResolver) UpdateFullName(ctx context.Context, input types.UpdateFullNameInput) (*types.UpdateFullNamePayload, error) {
identity := authn.IdentityFromContext(ctx)
if identity == nil {
return nil, gqlutils.Unauthenticatedf(ctx, "authentication is required to request access")
}
identity, err := r.iam.AccountService.UpdateIdentity(
ctx,
identity.ID,
&iam.UpdateIdentityRequest{
FullName: input.FullName,
},
)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot update identity", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
compliancePage := compliancepage.CompliancePageFromContext(ctx)
profile, err := r.iam.OrganizationService.GetProfileForIdentityAndOrganization(ctx, identity.ID, compliancePage.OrganizationID)
if err != nil {
if _, ok := errors.AsType[*iam.ErrProfileNotFound](err); !ok {
r.logger.ErrorCtx(ctx, "cannot get profile", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
}
if profile.Source == coredata.ProfileSourceManual {
if _, err := r.iam.OrganizationService.UpdateUser(ctx, &iam.UpdateUserRequest{
ID: profile.ID,
FullName: identity.FullName,
AdditionalEmailAddresses: profile.AdditionalEmailAddresses,
Kind: profile.Kind,
Position: profile.Position,
ContractStartDate: &profile.ContractStartDate,
ContractEndDate: &profile.ContractEndDate,
}); err != nil {
r.logger.ErrorCtx(ctx, "cannot update profile", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
}
return &types.UpdateFullNamePayload{Success: true}, nil
}