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" "github.com/gshopify/service-wrapper/model" "github.com/mitchellh/mapstructure" "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, string, error) { if t == "" { return 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, "", err } if !token.Valid { return nil, "", fmt.Errorf("could not decode accessToken: Token is NOT valid") } var sessionId string if claimed, ok := (*claim)["sid"]; ok { if s, ok := claimed.(string); ok { sessionId = s } } if sessionId == "" { return nil, "", fmt.Errorf("could not claim session id") } return token, sessionId, nil } func (r *Resolver) customer(ctx context.Context, t string) (*generated.Customer, error) { var ( customer = generated.Customer{} udata map[string]any phone *m.Phone err error ) udata, err = r.client.GetRawUserInfo(ctx, t, r.conf.Cli.Realm) if err != nil { return nil, err } if err = mapstructure.Decode(udata, &customer); err != nil { return nil, err } customer.Phone = nil phone, err = m.ParsePhoneNumber(udata) if err != nil { return nil, err } customer.Phone = gocloak.StringP(phone.String()) customer.Metafields = append(customer.Metafields, NewMetafield("phone_region", phone.PhoneRegion, model.MetafieldTypeSingleLineTextField), NewMetafield("phone_verified", phone.Verified, model.MetafieldTypeBoolean)) return &customer, 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) } // 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 }