Apply five style rules: convert iota string enums to typed string constants, replace errors.As with errors.AsType, merge three-group imports into two groups, fix multiline parameter/argument formatting, and replace fmt.Sprintf URL construction with net/url. Signed-off-by: Émile Ré <emile@probo.com>
267 lines
7.9 KiB
Go
267 lines
7.9 KiB
Go
package connect_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"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/99designs/gqlgen/graphql"
|
|
"go.gearno.de/kit/log"
|
|
"go.probo.inc/probo/pkg/coredata"
|
|
"go.probo.inc/probo/pkg/gid"
|
|
"go.probo.inc/probo/pkg/iam"
|
|
"go.probo.inc/probo/pkg/iam/oauth2server"
|
|
"go.probo.inc/probo/pkg/mail"
|
|
"go.probo.inc/probo/pkg/server/api/authn"
|
|
"go.probo.inc/probo/pkg/server/api/connect/v1/schema"
|
|
"go.probo.inc/probo/pkg/server/api/connect/v1/types"
|
|
"go.probo.inc/probo/pkg/server/gqlutils"
|
|
)
|
|
|
|
// Node is the resolver for the node field.
|
|
func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
var (
|
|
loadNode func(ctx context.Context, id gid.GID) (types.Node, error)
|
|
action string
|
|
)
|
|
|
|
switch id.EntityType() {
|
|
case coredata.OAuth2ConsentEntityType:
|
|
action = iam.ActionOAuth2ConsentGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
consent, err := r.iam.OAuth2ServerService.GetConsentByID(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return types.NewConsent(consent), nil
|
|
}
|
|
case coredata.OrganizationEntityType:
|
|
action = iam.ActionOrganizationGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
organization, err := r.iam.OrganizationService.GetOrganization(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return types.NewOrganization(organization), nil
|
|
}
|
|
case coredata.IdentityEntityType:
|
|
action = iam.ActionIdentityGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
identity, err := r.iam.AccountService.GetIdentity(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return types.NewIdentity(identity), nil
|
|
}
|
|
case coredata.SessionEntityType:
|
|
action = iam.ActionSessionGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
session, err := r.iam.GetSession(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return types.NewSession(session), nil
|
|
}
|
|
case coredata.MembershipProfileEntityType:
|
|
action = iam.ActionMembershipGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
profile, err := r.iam.OrganizationService.GetProfile(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return types.NewProfile(profile), nil
|
|
}
|
|
case coredata.MembershipEntityType:
|
|
action = iam.ActionMembershipGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
membership, err := r.iam.GetMembership(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return types.NewMembership(membership), nil
|
|
}
|
|
case coredata.InvitationEntityType:
|
|
action = iam.ActionInvitationGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
invitation, err := r.iam.GetInvitation(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return types.NewInvitation(invitation), nil
|
|
}
|
|
case coredata.SAMLConfigurationEntityType:
|
|
action = iam.ActionSAMLConfigurationGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
samlConfiguration, err := r.iam.GetSAMLconfiguration(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return types.NewSAMLConfiguration(samlConfiguration), nil
|
|
}
|
|
case coredata.PersonalAPIKeyEntityType:
|
|
action = iam.ActionPersonalAPIKeyGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
personalAPIKey, err := r.iam.GetPersonalAPIKey(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return types.NewPersonalAPIKey(personalAPIKey), nil
|
|
}
|
|
case coredata.SCIMConfigurationEntityType:
|
|
action = iam.ActionSCIMConfigurationGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
scimConfiguration, err := r.iam.GetSCIMConfiguration(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return types.NewSCIMConfiguration(scimConfiguration), nil
|
|
}
|
|
case coredata.SCIMEventEntityType:
|
|
action = iam.ActionSCIMEventGet
|
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
|
scimEvent, err := r.iam.GetSCIMEvent(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return types.NewSCIMEvent(scimEvent), nil
|
|
}
|
|
default:
|
|
return nil, fmt.Errorf("unsupported entity type: %d", id.EntityType())
|
|
}
|
|
|
|
if err := r.authorize(ctx, id, action); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
node, err := loadNode(ctx, id)
|
|
if err != nil {
|
|
if _, ok := errors.AsType[*iam.ErrOrganizationNotFound](err); ok {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
if _, ok := errors.AsType[*iam.ErrIdentityNotFound](err); ok {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
if _, ok := errors.AsType[*iam.ErrSessionNotFound](err); ok {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
if _, ok := errors.AsType[*iam.ErrProfileNotFound](err); ok {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
if _, ok := errors.AsType[*iam.ErrMembershipNotFound](err); ok {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
if _, ok := errors.AsType[*iam.ErrInvitationNotFound](err); ok {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
if oauthErr, ok := errors.AsType[*oauth2server.OAuth2Error](err); ok {
|
|
return nil, gqlutils.Invalidf(ctx, "%s", oauthErr.Description())
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot load node", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return node, nil
|
|
}
|
|
|
|
// Viewer is the resolver for the viewer field.
|
|
func (r *queryResolver) Viewer(ctx context.Context) (*types.Identity, error) {
|
|
identity := authn.IdentityFromContext(ctx)
|
|
|
|
return &types.Identity{
|
|
ID: identity.ID,
|
|
Email: identity.EmailAddress,
|
|
EmailVerified: identity.EmailAddressVerified,
|
|
FullName: identity.FullName,
|
|
CreatedAt: identity.CreatedAt,
|
|
UpdatedAt: identity.UpdatedAt,
|
|
}, nil
|
|
}
|
|
|
|
// SsoLoginURL is the resolver for the ssoLoginURL field.
|
|
func (r *queryResolver) SsoLoginURL(ctx context.Context, email mail.Addr) (*string, error) {
|
|
count, err := r.iam.AccountService.CountSAMLConfigurationsForEmail(ctx, email)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count SAML configurations for email", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
if count != 1 {
|
|
if count == 0 {
|
|
return nil, graphql.ErrorOnPath(
|
|
ctx,
|
|
fmt.Errorf("no SAML configuration for email"),
|
|
)
|
|
}
|
|
|
|
return nil, graphql.ErrorOnPath(
|
|
ctx,
|
|
fmt.Errorf("multiple SSO configurations found for this domain. Please use your organization-specific SSO login URL"),
|
|
)
|
|
}
|
|
|
|
samlConfigs, err := r.iam.AccountService.ListSAMLConfigurationsForEmail(ctx, email)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list SAML configurations for email", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
samlConfig := samlConfigs[0]
|
|
loginURL := r.SSOLoginURL(samlConfig.ID)
|
|
|
|
return &loginURL, nil
|
|
}
|
|
|
|
// OidcProviders is the resolver for the oidcProviders field.
|
|
func (r *queryResolver) OidcProviders(ctx context.Context) ([]*types.OIDCProviderInfo, error) {
|
|
providers := r.iam.OIDCService.EnabledProviders()
|
|
result := make([]*types.OIDCProviderInfo, 0, len(providers))
|
|
|
|
for _, p := range providers {
|
|
result = append(result, &types.OIDCProviderInfo{
|
|
Name: strings.ToLower(p.String()),
|
|
LoginURL: r.baseURL.WithPath("/api/connect/v1/oidc/" + strings.ToLower(p.String()) + "/login").MustString(),
|
|
})
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// SignUpEnabled is the resolver for the signUpEnabled field.
|
|
func (r *queryResolver) SignUpEnabled(ctx context.Context) (bool, error) {
|
|
return r.iam.IsSignUpEnabled(), nil
|
|
}
|
|
|
|
// Mutation returns schema.MutationResolver implementation.
|
|
func (r *Resolver) Mutation() schema.MutationResolver { return &mutationResolver{r} }
|
|
|
|
// Query returns schema.QueryResolver implementation.
|
|
func (r *Resolver) Query() schema.QueryResolver { return &queryResolver{r} }
|
|
|
|
type mutationResolver struct{ *Resolver }
|
|
type queryResolver struct{ *Resolver }
|