package graphql import ( "context" "fmt" "github.com/Nerzal/gocloak/v12" "github.com/golang-jwt/jwt/v4" "github.com/gshopify/service-wrapper/auth" "github.com/gshopify/service-wrapper/config" "gshopper.com/gshopify/customer/graphql/generated" m "gshopper.com/gshopify/customer/model" "time" ) type Resolver struct { conf *auth.Config client *gocloak.GoCloak } func NewResolver() (*Resolver, error) { r := &Resolver{ conf: auth.New(), } if err := config.Instance().Load(context.Background(), r.conf); err != nil { return nil, err } r.client = gocloak.NewClient(r.conf.Endpoint, gocloak.SetLegacyWildFlySupport()) return r, nil } func (r *Resolver) decodeAccessToken(ctx context.Context, t string) (*jwt.Token, *m.Claims, error) { if t == "" { return nil, nil, fmt.Errorf("could not decode accessToken: Token is empty") } token, claim, err := r.client.DecodeAccessToken(ctx, t, r.conf.Cli.Realm) if err != nil { return nil, nil, err } if !token.Valid { return nil, nil, fmt.Errorf("could not decode accessToken: Token is NOT valid") } claims := &m.Claims{} if err = claims.Unmarshall(*claim); err != nil { return nil, nil, err } return token, claims, nil } func (r *Resolver) customer(ctx context.Context, uid string) (*generated.Customer, error) { var ( admin *gocloak.JWT user *gocloak.User err error ) admin, err = r.conf.Admin.Token(r.client, ctx) if err != nil { return nil, err } user, err = r.client.GetUserByID(ctx, admin.AccessToken, r.conf.Cli.Realm, uid) if err != nil { return nil, err } return User2Customer(user), nil } func (r *Resolver) saveSession(ctx context.Context, token *gocloak.JWT) error { return auth.SessionManager().PutToken( ctx, token.SessionState, token.RefreshToken, time.Duration(token.RefreshExpiresIn)*time.Second) } func (r *Resolver) setPassword(ctx context.Context, uid, password string, shouldValidate bool) error { if shouldValidate { o := generated.CustomerCreateInput{Password: password} if err := o.ValidatePassword(minPasswordEntropy); err != nil { return fmt.Errorf(err.Message) } } admin, err := r.conf.Admin.Token(r.client, ctx) if err != nil { return err } return r.client.SetPassword(ctx, admin.AccessToken, uid, r.conf.Cli.Realm, password, false) } // Mutation returns generated.MutationResolver implementation. func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResolver{r} } // Query returns generated.QueryResolver implementation. func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} } type mutationResolver struct{ *Resolver } type queryResolver struct{ *Resolver }