diff --git a/.gitea/workflows/main.yml b/.gitea/workflows/main.yml index 3744b44..be542a9 100644 --- a/.gitea/workflows/main.yml +++ b/.gitea/workflows/main.yml @@ -19,7 +19,7 @@ jobs: run: echo "::set-output name=branch::$(echo ${GITHUB_REF##*/})" - name: Push to dokku for main branch - if: steps.branch_name.outputs.branch == 'mailgun' + if: steps.branch_name.outputs.branch == 'mailgun' uses: dokku/github-action@master with: branch: 'main' @@ -32,4 +32,5 @@ jobs: with: branch: 'main' git_remote_url: 'ssh://dokku@staging.discours.io:22/authorizer' - ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }} \ No newline at end of file + ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }} + git_push_flags: '--force' \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..4c1b698 --- /dev/null +++ b/go.mod @@ -0,0 +1,20 @@ +module server + +go 1.21.5 + +require ( + github.com/99designs/gqlgen v0.17.43 // indirect + github.com/agnivade/levenshtein v1.1.1 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/sosodev/duration v1.1.0 // indirect + github.com/urfave/cli/v2 v2.25.5 // indirect + github.com/vektah/gqlparser/v2 v2.5.11 // indirect + github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect + golang.org/x/mod v0.10.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect + golang.org/x/tools v0.9.3 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..c7b9fc6 --- /dev/null +++ b/go.sum @@ -0,0 +1,31 @@ +github.com/99designs/gqlgen v0.17.43 h1:I4SYg6ahjowErAQcHFVKy5EcWuwJ3+Xw9z2fLpuFCPo= +github.com/99designs/gqlgen v0.17.43/go.mod h1:lO0Zjy8MkZgBdv4T1U91x09r0e0WFOdhVUutlQs1Rsc= +github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8= +github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= +github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= +github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sosodev/duration v1.1.0 h1:kQcaiGbJaIsRqgQy7VGlZrVw1giWO+lDoX3MCPnpVO4= +github.com/sosodev/duration v1.1.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg= +github.com/urfave/cli/v2 v2.25.5 h1:d0NIAyhh5shGscroL7ek/Ya9QYQE0KNabJgiUinIQkc= +github.com/urfave/cli/v2 v2.25.5/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= +github.com/vektah/gqlparser/v2 v2.5.11 h1:JJxLtXIoN7+3x6MBdtIP59TP1RANnY7pXOaDnADQSf8= +github.com/vektah/gqlparser/v2 v2.5.11/go.mod h1:1rCcfwB2ekJofmluGWXMSEnPMZgbxzwj6FaZ/4OT8Cc= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM= +golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/server/go.mod b/server/go.mod index 08e4744..0f9343a 100644 --- a/server/go.mod +++ b/server/go.mod @@ -19,6 +19,7 @@ require ( github.com/google/uuid v1.3.1 github.com/guregu/dynamo v1.20.2 github.com/joho/godotenv v1.5.1 + github.com/mailgun/mailgun-go/v4 v4.12.0 github.com/pquerna/otp v1.4.0 github.com/redis/go-redis/v9 v9.2.1 github.com/robertkrimen/otto v0.2.1 @@ -83,7 +84,6 @@ require ( github.com/leodido/go-urn v1.2.4 // indirect github.com/libsql/libsql-client-go v0.0.0-20231026052543-fce76c0f39a7 // indirect github.com/libsql/sqlite-antlr4-parser v0.0.0-20230802215326-5cb5bb604475 // indirect - github.com/mailgun/mailgun-go/v4 v4.12.0 // indirect github.com/maruel/rs v1.1.0 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/microsoft/go-mssqldb v1.6.0 // indirect diff --git a/server/go.sum b/server/go.sum index 4351793..4364aa0 100644 --- a/server/go.sum +++ b/server/go.sum @@ -81,8 +81,11 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/ekristen/gorm-libsql v0.0.0-20231101204708-6e113112bcc2 h1:3f6DAUkYKbZSJ1bBM0/RiX5NHVt7YgmB0BWzKWUd45g= github.com/ekristen/gorm-libsql v0.0.0-20231101204708-6e113112bcc2/go.mod h1:5g9wSYpR/MvkR6W7SumX9zdha7Yt1iM4nxOAWfRfcPA= +github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= +github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= +github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= diff --git a/server/graph/generated/generated.go b/server/graph/generated/generated.go index 3ed5ffe..7ab6fc6 100644 --- a/server/graph/generated/generated.go +++ b/server/graph/generated/generated.go @@ -236,6 +236,7 @@ type ComplexityRoot struct { AdminSession func(childComplexity int) int EmailTemplates func(childComplexity int, params *model.PaginatedInput) int Env func(childComplexity int) int + IsRegistered func(childComplexity int, email string) int Meta func(childComplexity int) int Profile func(childComplexity int) int Session func(childComplexity int, params *model.SessionQueryInput) int @@ -392,6 +393,7 @@ type QueryResolver interface { Meta(ctx context.Context) (*model.Meta, error) Session(ctx context.Context, params *model.SessionQueryInput) (*model.AuthResponse, error) Profile(ctx context.Context) (*model.User, error) + IsRegistered(ctx context.Context, email string) (*model.Response, error) ValidateJwtToken(ctx context.Context, params model.ValidateJWTTokenInput) (*model.ValidateJWTTokenResponse, error) ValidateSession(ctx context.Context, params *model.ValidateSessionInput) (*model.ValidateSessionResponse, error) Users(ctx context.Context, params *model.PaginatedInput) (*model.Users, error) @@ -1666,6 +1668,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Query.Env(childComplexity), true + case "Query.is_registered": + if e.complexity.Query.IsRegistered == nil { + break + } + + args, err := ec.field_Query_is_registered_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.IsRegistered(childComplexity, args["email"].(string)), true + case "Query.meta": if e.complexity.Query.Meta == nil { break @@ -3036,6 +3050,7 @@ type Query { meta: Meta! session(params: SessionQueryInput): AuthResponse! profile: User! + is_registered(email: String!): Response! # custom api validate_jwt_token(params: ValidateJWTTokenInput!): ValidateJWTTokenResponse! validate_session(params: ValidateSessionInput): ValidateSessionResponse! # admin only apis @@ -3612,6 +3627,21 @@ func (ec *executionContext) field_Query__webhooks_args(ctx context.Context, rawA return args, nil } +func (ec *executionContext) field_Query_is_registered_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["email"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("email")) + arg0, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["email"] = arg0 + return args, nil +} + func (ec *executionContext) field_Query_session_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -11208,6 +11238,65 @@ func (ec *executionContext) fieldContext_Query_profile(ctx context.Context, fiel return fc, nil } +func (ec *executionContext) _Query_is_registered(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_is_registered(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().IsRegistered(rctx, fc.Args["email"].(string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.Response) + fc.Result = res + return ec.marshalNResponse2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐResponse(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_is_registered(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "message": + return ec.fieldContext_Response_message(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Response", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_is_registered_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + func (ec *executionContext) _Query_validate_jwt_token(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Query_validate_jwt_token(ctx, field) if err != nil { @@ -20511,6 +20600,28 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "is_registered": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_is_registered(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "validate_jwt_token": field := field diff --git a/server/graph/schema.graphqls b/server/graph/schema.graphqls index 9fc5919..9ad1b4b 100644 --- a/server/graph/schema.graphqls +++ b/server/graph/schema.graphqls @@ -610,7 +610,6 @@ input GetUserRequest { } type Mutation { - is_registered(email: String): AuthResponse! # custom api signup(params: SignUpInput!): AuthResponse! # Deprecated from v1.2.0 mobile_signup(params: MobileSignUpInput): AuthResponse! @@ -652,6 +651,7 @@ type Query { meta: Meta! session(params: SessionQueryInput): AuthResponse! profile: User! + is_registered(email: String!): Response! # custom api validate_jwt_token(params: ValidateJWTTokenInput!): ValidateJWTTokenResponse! validate_session(params: ValidateSessionInput): ValidateSessionResponse! # admin only apis diff --git a/server/graph/schema.resolvers.go b/server/graph/schema.resolvers.go index bec4ae3..e23a074 100644 --- a/server/graph/schema.resolvers.go +++ b/server/graph/schema.resolvers.go @@ -12,11 +12,6 @@ import ( "github.com/authorizerdev/authorizer/server/resolvers" ) -// Signup is the resolver for the signup field. -func (r *queryResolver) IsRegistered(ctx context.Context, email string) (*model.AuthResponse, error) { - return resolvers.IsRegisteredResolver(ctx, email) -} - // Signup is the resolver for the signup field. func (r *mutationResolver) Signup(ctx context.Context, params model.SignUpInput) (*model.AuthResponse, error) { return resolvers.SignupResolver(ctx, params) @@ -192,6 +187,11 @@ func (r *queryResolver) Profile(ctx context.Context) (*model.User, error) { return resolvers.ProfileResolver(ctx) } +// IsRegistered is the resolver for the signup field. +func (r *queryResolver) IsRegistered(ctx context.Context, email string) (*model.Response, error) { + return resolvers.IsRegisteredResolver(ctx, email) +} + // ValidateJwtToken is the resolver for the validate_jwt_token field. func (r *queryResolver) ValidateJwtToken(ctx context.Context, params model.ValidateJWTTokenInput) (*model.ValidateJWTTokenResponse, error) { return resolvers.ValidateJwtTokenResolver(ctx, params) diff --git a/server/memorystore/providers/inmemory/store.go b/server/memorystore/providers/inmemory/store.go index b20fb62..a92fcff 100644 --- a/server/memorystore/providers/inmemory/store.go +++ b/server/memorystore/providers/inmemory/store.go @@ -3,8 +3,11 @@ package inmemory import ( "fmt" "os" + "errors" + log "github.com/sirupsen/logrus" "github.com/authorizerdev/authorizer/server/constants" + "github.com/authorizerdev/authorizer/server/memorystore/providers/redis" ) // SetUserSession sets the user session for given user identifier in form recipe:user_id @@ -119,3 +122,25 @@ func (c *provider) GetBoolStoreEnvVariable(key string) (bool, error) { } return res.(bool), nil } + +// GetUserAppDataFromRedis retrieves user profile and follows from Redis, combines them into a JSON format, +// and assigns the JSON string to the provided user's ID. +func (c *provider) GetUserAppDataFromRedis(userId string) (string, error) { + redisURL := os.Getenv(constants.EnvKeyRedisURL) + if redisURL == "" { + return "", errors.New("Redis URL not found") + } + + log.Info("Initializing Redis provider") + red, err := redis.NewRedisProvider(redisURL) + if err != nil { + return "", fmt.Errorf("failed to initialize Redis provider: %w", err) + } + + combinedData, err := red.GetUserAppDataFromRedis(userId) + if err != nil { + return "", fmt.Errorf("failed to get Redis app data: %w", err) + } + + return combinedData, nil +} diff --git a/server/memorystore/providers/providers.go b/server/memorystore/providers/providers.go index 331e34a..b1e7153 100644 --- a/server/memorystore/providers/providers.go +++ b/server/memorystore/providers/providers.go @@ -38,4 +38,6 @@ type Provider interface { GetStringStoreEnvVariable(key string) (string, error) // GetBoolStoreEnvVariable to get the bool env variable from env store GetBoolStoreEnvVariable(key string) (bool, error) + + GetUserAppDataFromRedis(userId string) (string, error) } diff --git a/server/memorystore/providers/redis/store.go b/server/memorystore/providers/redis/store.go index a1b21db..4ed66c4 100644 --- a/server/memorystore/providers/redis/store.go +++ b/server/memorystore/providers/redis/store.go @@ -218,3 +218,16 @@ func (c *provider) GetBoolStoreEnvVariable(key string) (bool, error) { return data == "1", nil } + +// GetUserAppDataFromRedis retrieves user profile and follows from Redis, combines them into a JSON format, +// and assigns the JSON string to the provided user's ID. +func (c *provider) GetUserAppDataFromRedis(userId string) (string, error) { + // Retrieve user data from Redis + userProfile := c.store.Get(c.ctx, fmt.Sprintf(`user:%s:author`, userId)) + userFollows := c.store.Get(c.ctx, fmt.Sprintf(`user:%s:follows`, userId)) + + // Combine user data into a JSON string + combinedData := fmt.Sprintf(`{"profile": %s, "follows": %s}`, userProfile, userFollows) + + return combinedData, nil +} diff --git a/server/resolvers/forgot_password.go b/server/resolvers/forgot_password.go index 624955e..cd156b8 100644 --- a/server/resolvers/forgot_password.go +++ b/server/resolvers/forgot_password.go @@ -83,6 +83,16 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu log.Debug("Failed to get user: ", err) return nil, fmt.Errorf(`bad user credentials`) } + + if user.SignupMethods == "magic_link_login" { + user.SignupMethods = "basic_auth" + + user, err = db.Provider.UpdateUser(ctx, user) + if err != nil { + log.Debug("Failed to update user signup method: ", err) + } + } + hostname := parsers.GetHost(gc) _, nonceHash, err := utils.GenerateNonce() if err != nil { diff --git a/server/resolvers/is_registered.go b/server/resolvers/is_registered.go index 92bd8ec..69e19ac 100644 --- a/server/resolvers/is_registered.go +++ b/server/resolvers/is_registered.go @@ -11,32 +11,43 @@ import ( ) // IsRegisteredResolver is a resolver for registered checkup query -func IsRegisteredResolver(ctx context.Context, email string) (*model.AuthResponse, error) { - var res *model.AuthResponse - email = strings.TrimSpace(refs.StringValue(&email)) +func IsRegisteredResolver(ctx context.Context, email string) (*model.Response, error) { + // Initialize the response object + res := &model.Response{} + res.Message = "" + + // Convert email to lowercase + email = strings.ToLower(strings.TrimSpace(refs.StringValue(&email))) if email == "" { log.Debug("Email is required") - return res, fmt.Errorf(`email is required`) + return res, fmt.Errorf("email is required") } + // Initialize logger with a field log := log.WithField("email", email) - // find user with email + // Find user with email existingUser, err := db.Provider.GetUserByEmail(ctx, email) if err != nil { log.Debug("Failed to get user by email: ", err) - } - - if existingUser != nil { - res.Message = "registered" - if existingUser.EmailVerifiedAt != nil { - res.Message = "verified" - log.Debug("Email is already verified and signed up.") - return res, fmt.Errorf(`%s has already signed up`, email) - } else if existingUser.ID != "" && existingUser.EmailVerifiedAt == nil { - res.Message = "not verified" - log.Debug("Email is already signed up. Verification pending...") - return res, fmt.Errorf("%s has already signed up. please complete the email verification process or reset the password", email) + } else { + log.Debug("Found user by email: ", existingUser) + if existingUser != nil { + if existingUser.SignupMethods == "magic_link_login" { + res.Message = "registered" + } else if existingUser.EmailVerifiedAt != nil { + res.Message = "verified" + log.Debug("Email is already verified and signed up.") + return res, nil + } else if existingUser.ID != "" && existingUser.EmailVerifiedAt == nil { + res.Message = "not verified" + log.Debug("Email is already signed up. Verification pending...") + return res, nil + } else { + res.Message = "unknown" + log.Debug("Unknown signup method.") + return res, nil + } } } diff --git a/server/resolvers/login.go b/server/resolvers/login.go index fa5d409..b79ddfe 100644 --- a/server/resolvers/login.go +++ b/server/resolvers/login.go @@ -316,6 +316,12 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes expiresIn = 1 } + appData, err := memorystore.Provider.GetUserAppDataFromRedis(user.ID) + if err == nil { + // Assign the combined data to the provided pointer + user.AppData = &appData + } + res = &model.AuthResponse{ Message: `Logged in successfully`, AccessToken: &authToken.AccessToken.Token, diff --git a/server/resolvers/session.go b/server/resolvers/session.go index 964d1b5..f359782 100644 --- a/server/resolvers/session.go +++ b/server/resolvers/session.go @@ -90,6 +90,12 @@ func SessionResolver(ctx context.Context, params *model.SessionQueryInput) (*mod expiresIn = 1 } + appData, err := memorystore.Provider.GetUserAppDataFromRedis(user.ID) + if err == nil { + // Assign the combined data to the provided pointer + user.AppData = &appData + } + res = &model.AuthResponse{ Message: `Session token refreshed`, AccessToken: &authToken.AccessToken.Token, @@ -102,6 +108,7 @@ func SessionResolver(ctx context.Context, params *model.SessionQueryInput) (*mod memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash, authToken.SessionTokenExpiresAt) memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token, authToken.AccessToken.ExpiresAt) + if authToken.RefreshToken != nil { res.RefreshToken = &authToken.RefreshToken.Token memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token, authToken.RefreshToken.ExpiresAt)