Implement continue on verify magic link
Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
@@ -21,6 +21,7 @@ import (
|
||||
"go.probo.inc/probo/pkg/baseurl"
|
||||
"go.probo.inc/probo/pkg/esign"
|
||||
"go.probo.inc/probo/pkg/iam"
|
||||
"go.probo.inc/probo/pkg/saferedirect"
|
||||
"go.probo.inc/probo/pkg/securecookie"
|
||||
"go.probo.inc/probo/pkg/server/api/authn"
|
||||
"go.probo.inc/probo/pkg/server/api/trust/v1/schema"
|
||||
@@ -38,6 +39,7 @@ func NewGraphQLHandler(iamSvc *iam.Service, trustSvc *trust.Service, esignSvc *e
|
||||
logger: logger,
|
||||
baseURL: baseURL,
|
||||
sessionCookie: authn.NewCookie(&cookieConfig),
|
||||
safeRedirect: &saferedirect.SafeRedirect{AllowedHost: baseURL.Host()},
|
||||
},
|
||||
Directives: schema.DirectiveRoot{
|
||||
Session: session.Directive,
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"go.probo.inc/probo/pkg/esign"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/iam"
|
||||
"go.probo.inc/probo/pkg/saferedirect"
|
||||
"go.probo.inc/probo/pkg/securecookie"
|
||||
"go.probo.inc/probo/pkg/server/api/authn"
|
||||
"go.probo.inc/probo/pkg/server/api/compliancepage"
|
||||
@@ -52,6 +53,7 @@ type (
|
||||
iam *iam.Service
|
||||
sessionCookie *authn.Cookie
|
||||
baseURL *baseurl.BaseURL
|
||||
safeRedirect *saferedirect.SafeRedirect
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -553,6 +553,7 @@ type TrustCenterAccess implements Node {
|
||||
|
||||
input SendMagicLinkInput {
|
||||
email: EmailAddr!
|
||||
continue: String
|
||||
}
|
||||
|
||||
type SendMagicLinkPayload {
|
||||
@@ -564,7 +565,7 @@ input VerifyMagicLinkInput {
|
||||
}
|
||||
|
||||
type VerifyMagicLinkPayload {
|
||||
success: Boolean!
|
||||
continue: String
|
||||
}
|
||||
|
||||
type RequestAccessesPayload {
|
||||
|
||||
@@ -277,7 +277,7 @@ type ComplexityRoot struct {
|
||||
}
|
||||
|
||||
VerifyMagicLinkPayload struct {
|
||||
Success func(childComplexity int) int
|
||||
Continue func(childComplexity int) int
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1205,12 +1205,12 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
||||
|
||||
return e.ComplexityRoot.VendorEdge.Node(childComplexity), true
|
||||
|
||||
case "VerifyMagicLinkPayload.success":
|
||||
if e.ComplexityRoot.VerifyMagicLinkPayload.Success == nil {
|
||||
case "VerifyMagicLinkPayload.continue":
|
||||
if e.ComplexityRoot.VerifyMagicLinkPayload.Continue == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.ComplexityRoot.VerifyMagicLinkPayload.Success(childComplexity), true
|
||||
return e.ComplexityRoot.VerifyMagicLinkPayload.Continue(childComplexity), true
|
||||
|
||||
}
|
||||
return 0, false
|
||||
@@ -1860,6 +1860,7 @@ type TrustCenterAccess implements Node {
|
||||
|
||||
input SendMagicLinkInput {
|
||||
email: EmailAddr!
|
||||
continue: String
|
||||
}
|
||||
|
||||
type SendMagicLinkPayload {
|
||||
@@ -1871,7 +1872,7 @@ input VerifyMagicLinkInput {
|
||||
}
|
||||
|
||||
type VerifyMagicLinkPayload {
|
||||
success: Boolean!
|
||||
continue: String
|
||||
}
|
||||
|
||||
type RequestAccessesPayload {
|
||||
@@ -3796,8 +3797,8 @@ func (ec *executionContext) fieldContext_Mutation_verifyMagicLink(ctx context.Co
|
||||
IsResolver: true,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
switch field.Name {
|
||||
case "success":
|
||||
return ec.fieldContext_VerifyMagicLinkPayload_success(ctx, field)
|
||||
case "continue":
|
||||
return ec.fieldContext_VerifyMagicLinkPayload_continue(ctx, field)
|
||||
}
|
||||
return nil, fmt.Errorf("no field named %q was found under type VerifyMagicLinkPayload", field.Name)
|
||||
},
|
||||
@@ -6855,30 +6856,30 @@ func (ec *executionContext) fieldContext_VendorEdge_node(_ context.Context, fiel
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _VerifyMagicLinkPayload_success(ctx context.Context, field graphql.CollectedField, obj *types.VerifyMagicLinkPayload) (ret graphql.Marshaler) {
|
||||
func (ec *executionContext) _VerifyMagicLinkPayload_continue(ctx context.Context, field graphql.CollectedField, obj *types.VerifyMagicLinkPayload) (ret graphql.Marshaler) {
|
||||
return graphql.ResolveField(
|
||||
ctx,
|
||||
ec.OperationContext,
|
||||
field,
|
||||
ec.fieldContext_VerifyMagicLinkPayload_success,
|
||||
ec.fieldContext_VerifyMagicLinkPayload_continue,
|
||||
func(ctx context.Context) (any, error) {
|
||||
return obj.Success, nil
|
||||
return obj.Continue, nil
|
||||
},
|
||||
nil,
|
||||
ec.marshalNBoolean2bool,
|
||||
true,
|
||||
ec.marshalOString2ᚖstring,
|
||||
true,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_VerifyMagicLinkPayload_success(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
func (ec *executionContext) fieldContext_VerifyMagicLinkPayload_continue(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "VerifyMagicLinkPayload",
|
||||
Field: field,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type Boolean does not have child fields")
|
||||
return nil, errors.New("field of type String does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
@@ -8559,7 +8560,7 @@ func (ec *executionContext) unmarshalInputSendMagicLinkInput(ctx context.Context
|
||||
asMap[k] = v
|
||||
}
|
||||
|
||||
fieldsInOrder := [...]string{"email"}
|
||||
fieldsInOrder := [...]string{"email", "continue"}
|
||||
for _, k := range fieldsInOrder {
|
||||
v, ok := asMap[k]
|
||||
if !ok {
|
||||
@@ -8573,6 +8574,13 @@ func (ec *executionContext) unmarshalInputSendMagicLinkInput(ctx context.Context
|
||||
return it, err
|
||||
}
|
||||
it.Email = data
|
||||
case "continue":
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("continue"))
|
||||
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
it.Continue = data
|
||||
}
|
||||
}
|
||||
return it, nil
|
||||
@@ -11243,11 +11251,8 @@ func (ec *executionContext) _VerifyMagicLinkPayload(ctx context.Context, sel ast
|
||||
switch field.Name {
|
||||
case "__typename":
|
||||
out.Values[i] = graphql.MarshalString("VerifyMagicLinkPayload")
|
||||
case "success":
|
||||
out.Values[i] = ec._VerifyMagicLinkPayload_success(ctx, field, obj)
|
||||
if out.Values[i] == graphql.Null {
|
||||
out.Invalids++
|
||||
}
|
||||
case "continue":
|
||||
out.Values[i] = ec._VerifyMagicLinkPayload_continue(ctx, field, obj)
|
||||
default:
|
||||
panic("unknown field " + strconv.Quote(field.Name))
|
||||
}
|
||||
|
||||
@@ -194,7 +194,8 @@ type RequestTrustCenterFileAccessInput struct {
|
||||
}
|
||||
|
||||
type SendMagicLinkInput struct {
|
||||
Email mail.Addr `json:"email"`
|
||||
Email mail.Addr `json:"email"`
|
||||
Continue *string `json:"continue,omitempty"`
|
||||
}
|
||||
|
||||
type SendMagicLinkPayload struct {
|
||||
@@ -296,5 +297,5 @@ type VerifyMagicLinkInput struct {
|
||||
}
|
||||
|
||||
type VerifyMagicLinkPayload struct {
|
||||
Success bool `json:"success"`
|
||||
Continue *string `json:"continue,omitempty"`
|
||||
}
|
||||
|
||||
@@ -157,11 +157,22 @@ func (r *frameworkResolver) DarkLogoURL(ctx context.Context, obj *types.Framewor
|
||||
func (r *mutationResolver) SendMagicLink(ctx context.Context, input types.SendMagicLinkInput) (*types.SendMagicLinkPayload, error) {
|
||||
trustCenter := compliancepage.CompliancePageFromContext(ctx)
|
||||
|
||||
var continueURLString *string
|
||||
if input.Continue != nil {
|
||||
safeURL, ok := r.safeRedirect.Validate(*input.Continue)
|
||||
if !ok {
|
||||
return nil, gqlutils.Invalidf(ctx, "invalid continue URL")
|
||||
}
|
||||
|
||||
continueURLString = &safeURL
|
||||
}
|
||||
|
||||
req := &iam.SendMagicLinkRequest{
|
||||
Email: input.Email,
|
||||
CompliancePageID: &trustCenter.ID,
|
||||
OrganizationID: trustCenter.OrganizationID,
|
||||
URLPath: "verify-magic-link",
|
||||
Continue: continueURLString,
|
||||
}
|
||||
|
||||
if err := r.iam.AuthService.SendMagicLink(ctx, req); err != nil {
|
||||
@@ -174,7 +185,7 @@ func (r *mutationResolver) SendMagicLink(ctx context.Context, input types.SendMa
|
||||
|
||||
// VerifyMagicLink is the resolver for the verifyMagicLink field.
|
||||
func (r *mutationResolver) VerifyMagicLink(ctx context.Context, input types.VerifyMagicLinkInput) (*types.VerifyMagicLinkPayload, error) {
|
||||
identity, session, err := r.iam.AuthService.OpenSessionWithMagicLink(ctx, input.Token)
|
||||
identity, session, continueURL, err := r.iam.AuthService.OpenSessionWithMagicLink(ctx, input.Token)
|
||||
if err != nil {
|
||||
var errInvalidToken *iam.ErrInvalidToken
|
||||
if errors.As(err, &errInvalidToken) {
|
||||
@@ -196,7 +207,7 @@ func (r *mutationResolver) VerifyMagicLink(ctx context.Context, input types.Veri
|
||||
r.sessionCookie.Set(w, session)
|
||||
|
||||
return &types.VerifyMagicLinkPayload{
|
||||
Success: true,
|
||||
Continue: continueURL,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user