diff --git a/server/db/db.go b/server/db/db.go index fc3afd4..90ae531 100644 --- a/server/db/db.go +++ b/server/db/db.go @@ -18,9 +18,10 @@ type Manager interface { GetUsers() ([]User, error) GetUserByEmail(email string) (User, error) UpdateVerificationTime(verifiedAt int64, id uint) error - AddVerification(verification Verification) (Verification, error) - GetVerificationByToken(token string) (Verification, error) + AddVerification(verification VerificationRequest) (VerificationRequest, error) + GetVerificationByToken(token string) (VerificationRequest, error) DeleteToken(email string) error + GetVerificationRequests() ([]VerificationRequest, error) } type manager struct { @@ -50,7 +51,7 @@ func init() { if err != nil { log.Fatal("Failed to init db:", err) } else { - db.AutoMigrate(&User{}, &Verification{}) + db.AutoMigrate(&User{}, &VerificationRequest{}) } Mgr = &manager{db: db} diff --git a/server/db/verification.go b/server/db/verificationRequests.go similarity index 67% rename from server/db/verification.go rename to server/db/verificationRequests.go index b019241..e59d6c6 100644 --- a/server/db/verification.go +++ b/server/db/verificationRequests.go @@ -6,7 +6,7 @@ import ( "gorm.io/gorm/clause" ) -type Verification struct { +type VerificationRequest struct { ID uint `gorm:"primaryKey"` Token string `gorm:"index"` Identifier string @@ -17,7 +17,7 @@ type Verification struct { } // AddVerification function to add verification record -func (mgr *manager) AddVerification(verification Verification) (Verification, error) { +func (mgr *manager) AddVerification(verification VerificationRequest) (VerificationRequest, error) { result := mgr.db.Clauses(clause.OnConflict{ Columns: []clause.Column{{Name: "email"}}, DoUpdates: clause.AssignmentColumns([]string{"token", "identifier", "expires_at"}), @@ -29,8 +29,8 @@ func (mgr *manager) AddVerification(verification Verification) (Verification, er return verification, nil } -func (mgr *manager) GetVerificationByToken(token string) (Verification, error) { - var verification Verification +func (mgr *manager) GetVerificationByToken(token string) (VerificationRequest, error) { + var verification VerificationRequest result := mgr.db.Where("token = ?", token).First(&verification) if result.Error != nil { @@ -42,7 +42,7 @@ func (mgr *manager) GetVerificationByToken(token string) (Verification, error) { } func (mgr *manager) DeleteToken(email string) error { - var verification Verification + var verification VerificationRequest result := mgr.db.Where("email = ?", email).Delete(&verification) if result.Error != nil { @@ -52,3 +52,14 @@ func (mgr *manager) DeleteToken(email string) error { return nil } + +// GetUsers function to get all users +func (mgr *manager) GetVerificationRequests() ([]VerificationRequest, error) { + var verificationRequests []VerificationRequest + result := mgr.db.Find(&verificationRequests) + if result.Error != nil { + log.Println(result.Error) + return verificationRequests, result.Error + } + return verificationRequests, nil +} diff --git a/server/graph/generated/generated.go b/server/graph/generated/generated.go index 0de4a42..da666f6 100644 --- a/server/graph/generated/generated.go +++ b/server/graph/generated/generated.go @@ -64,9 +64,10 @@ type ComplexityRoot struct { } Query struct { - Profile func(childComplexity int) int - Token func(childComplexity int) int - Users func(childComplexity int) int + Profile func(childComplexity int) int + Token func(childComplexity int) int + Users func(childComplexity int) int + VerificationRequests func(childComplexity int) int } Response struct { @@ -108,6 +109,7 @@ type QueryResolver interface { Users(ctx context.Context) ([]*model.User, error) Token(ctx context.Context) (*model.LoginResponse, error) Profile(ctx context.Context) (*model.User, error) + VerificationRequests(ctx context.Context) ([]*model.VerificationRequest, error) } type executableSchema struct { @@ -243,6 +245,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Query.Users(childComplexity), true + case "Query.verificationRequests": + if e.complexity.Query.VerificationRequests == nil { + break + } + + return e.complexity.Query.VerificationRequests(childComplexity), true + case "Response.message": if e.complexity.Response.Message == nil { break @@ -517,6 +526,7 @@ type Query { users: [User!]! token: LoginResponse profile: User! + verificationRequests: [VerificationRequest!]! } `, BuiltIn: false}, } @@ -1145,6 +1155,41 @@ func (ec *executionContext) _Query_profile(ctx context.Context, field graphql.Co return ec.marshalNUser2ᚖgithubᚗcomᚋyauthdevᚋyauthᚋserverᚋgraphᚋmodelᚐUser(ctx, field.Selections, res) } +func (ec *executionContext) _Query_verificationRequests(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Query", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().VerificationRequests(rctx) + }) + 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.VerificationRequest) + fc.Result = res + return ec.marshalNVerificationRequest2ᚕᚖgithubᚗcomᚋyauthdevᚋyauthᚋserverᚋgraphᚋmodelᚐVerificationRequestᚄ(ctx, field.Selections, res) +} + func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -3248,6 +3293,20 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr } return res }) + case "verificationRequests": + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_verificationRequests(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + }) case "__type": out.Values[i] = ec._Query___type(ctx, field) case "__schema": @@ -3764,6 +3823,53 @@ func (ec *executionContext) marshalNUser2ᚖgithubᚗcomᚋyauthdevᚋyauthᚋse return ec._User(ctx, sel, v) } +func (ec *executionContext) marshalNVerificationRequest2ᚕᚖgithubᚗcomᚋyauthdevᚋyauthᚋserverᚋgraphᚋmodelᚐVerificationRequestᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.VerificationRequest) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNVerificationRequest2ᚖgithubᚗcomᚋyauthdevᚋyauthᚋserverᚋgraphᚋmodelᚐVerificationRequest(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + return ret +} + +func (ec *executionContext) marshalNVerificationRequest2ᚖgithubᚗcomᚋyauthdevᚋyauthᚋserverᚋgraphᚋmodelᚐVerificationRequest(ctx context.Context, sel ast.SelectionSet, v *model.VerificationRequest) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._VerificationRequest(ctx, sel, v) +} + func (ec *executionContext) unmarshalNVerifyEmailInput2githubᚗcomᚋyauthdevᚋyauthᚋserverᚋgraphᚋmodelᚐVerifyEmailInput(ctx context.Context, v interface{}) (model.VerifyEmailInput, error) { res, err := ec.unmarshalInputVerifyEmailInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) diff --git a/server/graph/schema.graphqls b/server/graph/schema.graphqls index c3360da..0d3add9 100644 --- a/server/graph/schema.graphqls +++ b/server/graph/schema.graphqls @@ -82,4 +82,5 @@ type Query { users: [User!]! token: LoginResponse profile: User! + verificationRequests: [VerificationRequest!]! } diff --git a/server/graph/schema.resolvers.go b/server/graph/schema.resolvers.go index a3bd09c..34914aa 100644 --- a/server/graph/schema.resolvers.go +++ b/server/graph/schema.resolvers.go @@ -43,6 +43,10 @@ func (r *queryResolver) Profile(ctx context.Context) (*model.User, error) { return resolvers.Profile(ctx) } +func (r *queryResolver) VerificationRequests(ctx context.Context) ([]*model.VerificationRequest, error) { + return resolvers.VerificationRequests(ctx) +} + // Mutation returns generated.MutationResolver implementation. func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResolver{r} } diff --git a/server/resolvers/login.go b/server/resolvers/login.go index 6e72a1e..e9fb3fb 100644 --- a/server/resolvers/login.go +++ b/server/resolvers/login.go @@ -34,9 +34,7 @@ func Login(ctx context.Context, params model.LoginInput) (*model.LoginResponse, if user.EmailVerifiedAt <= 0 { return res, fmt.Errorf(`email not verified`) } - // match password - cost, err := bcrypt.Cost([]byte(user.Password)) - log.Println(cost, err) + err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(params.Password)) if err != nil { @@ -68,6 +66,8 @@ func Login(ctx context.Context, params model.LoginInput) (*model.LoginResponse, LastName: &user.LastName, SignupMethod: user.SignupMethod, EmailVerifiedAt: &user.EmailVerifiedAt, + CreatedAt: &user.CreatedAt, + UpdatedAt: &user.UpdatedAt, }, } diff --git a/server/resolvers/profile.go b/server/resolvers/profile.go index c45f155..6cf375b 100644 --- a/server/resolvers/profile.go +++ b/server/resolvers/profile.go @@ -48,6 +48,8 @@ func Profile(ctx context.Context) (*model.User, error) { LastName: &user.LastName, SignupMethod: user.SignupMethod, EmailVerifiedAt: &user.EmailVerifiedAt, + CreatedAt: &user.CreatedAt, + UpdatedAt: &user.UpdatedAt, } return res, nil diff --git a/server/resolvers/signup.go b/server/resolvers/signup.go index 47f6ab3..cc9e1b7 100644 --- a/server/resolvers/signup.go +++ b/server/resolvers/signup.go @@ -62,7 +62,7 @@ func Signup(ctx context.Context, params model.SignUpInput) (*model.Response, err if err != nil { log.Println(`Error generating token`, err) } - db.Mgr.AddVerification(db.Verification{ + db.Mgr.AddVerification(db.VerificationRequest{ Token: token, Identifier: verificationType, ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), diff --git a/server/resolvers/token.go b/server/resolvers/token.go index 963805d..8a67099 100644 --- a/server/resolvers/token.go +++ b/server/resolvers/token.go @@ -58,6 +58,8 @@ func Token(ctx context.Context) (*model.LoginResponse, error) { Image: &user.Image, FirstName: &user.FirstName, LastName: &user.LastName, + CreatedAt: &user.CreatedAt, + UpdatedAt: &user.UpdatedAt, }, } return res, nil diff --git a/server/resolvers/updateProfile.go b/server/resolvers/updateProfile.go index e6acee4..99609af 100644 --- a/server/resolvers/updateProfile.go +++ b/server/resolvers/updateProfile.go @@ -109,7 +109,7 @@ func UpdateProfile(ctx context.Context, params model.UpdateProfileInput) (*model if err != nil { log.Println(`Error generating token`, err) } - db.Mgr.AddVerification(db.Verification{ + db.Mgr.AddVerification(db.VerificationRequest{ Token: token, Identifier: verificationType, ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), diff --git a/server/resolvers/users.go b/server/resolvers/users.go index 06ae7b4..3c0de2d 100644 --- a/server/resolvers/users.go +++ b/server/resolvers/users.go @@ -34,6 +34,8 @@ func Users(ctx context.Context) ([]*model.User, error) { LastName: &user.LastName, Password: &user.Password, EmailVerifiedAt: &user.EmailVerifiedAt, + CreatedAt: &user.CreatedAt, + UpdatedAt: &user.UpdatedAt, }) } diff --git a/server/resolvers/verificationRequests.go b/server/resolvers/verificationRequests.go new file mode 100644 index 0000000..18683bf --- /dev/null +++ b/server/resolvers/verificationRequests.go @@ -0,0 +1,40 @@ +package resolvers + +import ( + "context" + "fmt" + + "github.com/yauthdev/yauth/server/db" + "github.com/yauthdev/yauth/server/graph/model" + "github.com/yauthdev/yauth/server/utils" +) + +func VerificationRequests(ctx context.Context) ([]*model.VerificationRequest, error) { + gc, err := utils.GinContextFromContext(ctx) + var res []*model.VerificationRequest + if err != nil { + return res, err + } + + if !utils.IsSuperAdmin(gc) { + return res, fmt.Errorf("unauthorized") + } + + verificationRequests, err := db.Mgr.GetVerificationRequests() + if err != nil { + return res, err + } + + for _, verificationRequest := range verificationRequests { + res = append(res, &model.VerificationRequest{ + ID: fmt.Sprintf("%d", verificationRequest.ID), + Email: &verificationRequest.Email, + Token: &verificationRequest.Token, + Expires: &verificationRequest.ExpiresAt, + CreatedAt: &verificationRequest.CreatedAt, + UpdatedAt: &verificationRequest.UpdatedAt, + }) + } + + return res, nil +} diff --git a/server/resolvers/verifyEmail.go b/server/resolvers/verifyEmail.go index e381abb..978bf4f 100644 --- a/server/resolvers/verifyEmail.go +++ b/server/resolvers/verifyEmail.go @@ -65,6 +65,8 @@ func VerifyEmail(ctx context.Context, params model.VerifyEmailInput) (*model.Log LastName: &user.LastName, SignupMethod: user.SignupMethod, EmailVerifiedAt: &user.EmailVerifiedAt, + CreatedAt: &user.CreatedAt, + UpdatedAt: &user.UpdatedAt, }, } diff --git a/server/server.go b/server/server.go index 268fc26..7e617d6 100644 --- a/server/server.go +++ b/server/server.go @@ -2,7 +2,6 @@ package main import ( "context" - "log" "github.com/gin-gonic/gin" "github.com/yauthdev/yauth/server/enum" @@ -27,7 +26,6 @@ func main() { r.GET("/login/google", handlers.HandleOAuthLogin(enum.GoogleProvider)) r.GET("/callback/google", handlers.HandleOAuthCallback(enum.GoogleProvider)) } - log.Println(oauth.OAuthProvider.GithubConfig) if oauth.OAuthProvider.GithubConfig != nil { r.GET("/login/github", handlers.HandleOAuthLogin(enum.GithubProvider)) r.GET("/callback/github", handlers.HandleOAuthCallback(enum.GithubProvider))