From 22c02df1183ef31cb6801c205261d3c5523e06e5 Mon Sep 17 00:00:00 2001 From: zakhaev26 Date: Sun, 25 Feb 2024 03:03:46 +0530 Subject: [PATCH] feat/fix: adds email auth --- auth/internal/handlers/signup_handler.go | 15 ++++-- auth/internal/render_engine.go | 59 ++++++++++++++++++++++++ auth/internal/router/routes.go | 1 + auth/internal/sendMail.go | 38 +++++++++++++++ auth/pkg/security/rbac.go | 5 -- auth/pkg/security/rbac.md | 8 ++++ go.mod | 1 + go.sum | 3 ++ mail/pkg/sender.go | 6 +-- sendMail.txt | 0 10 files changed, 123 insertions(+), 13 deletions(-) create mode 100644 auth/internal/render_engine.go create mode 100644 auth/internal/sendMail.go create mode 100644 auth/pkg/security/rbac.md create mode 100644 sendMail.txt diff --git a/auth/internal/handlers/signup_handler.go b/auth/internal/handlers/signup_handler.go index 55d19f6..6138aef 100644 --- a/auth/internal/handlers/signup_handler.go +++ b/auth/internal/handlers/signup_handler.go @@ -7,6 +7,7 @@ import ( "time" "github.com/golang-jwt/jwt" + "github.com/p-society/gc-server/auth/internal" "github.com/p-society/gc-server/auth/internal/utils" "github.com/p-society/gc-server/auth/pkg/security" model "github.com/p-society/gc-server/schemas/pkg/models" @@ -17,15 +18,15 @@ func SignUpHandler(w http.ResponseWriter, r *http.Request) { var p model.Player w.Header().Set("Content-Type", "application/json") + err := json.NewDecoder(r.Body).Decode(&p) defer r.Body.Close() - if err != nil { json.NewEncoder(w).Encode(err) return } - err = p.Valid() + err = p.Valid() if err != nil { json.NewEncoder(w).Encode(map[string]interface{}{ "error": err.Error(), @@ -33,7 +34,6 @@ func SignUpHandler(w http.ResponseWriter, r *http.Request) { return } - fmt.Println("p.Email @signup", p.Email) err = utils.IsUniqueInDB(p.Email) if err != nil { json.NewEncoder(w).Encode(map[string]interface{}{ @@ -42,16 +42,21 @@ func SignUpHandler(w http.ResponseWriter, r *http.Request) { return } - // TODO:Send OTP Mail - p.StandardClaims = jwt.StandardClaims{ IssuedAt: time.Now().Unix(), ExpiresAt: time.Now().Add(5 * time.Minute).Unix(), } // TODO : Check password to be + p.OTP = utils.GenerateOTP(6) fmt.Println(p.OTP) + + if err := internal.SendEmail(&p); err != nil { + json.NewEncoder(w).Encode(err.Error()) + } + hashedPass, err := bcrypt.GenerateFromPassword([]byte(p.Password), 10) + if err != nil { panic(err) } diff --git a/auth/internal/render_engine.go b/auth/internal/render_engine.go new file mode 100644 index 0000000..230bc7f --- /dev/null +++ b/auth/internal/render_engine.go @@ -0,0 +1,59 @@ +package internal + +func RenderEngine(OTP int) string { + return ` + + + + + + + Grand Championship Sports Fest OTP Verification + + + +
+

In order to finalize your participation and confirm your registration for the Grand Championship Sports Fest, we require you to undergo a one-time verification process. This verification will be conducted through the use of a unique One-Time Password (OTP) sent to your registered email address.

+

This is your OTP: ` + string(OTP) + `

+

Please note that this OTP is valid for 5 minutes. Kindly complete the verification process within this timeframe to ensure successful registration.

+ + +
+ P-Society IIIT-Bh Logo +

Open Source Software Wing, Programming Society, IIIT-Bh

+
+
+ + +` +} diff --git a/auth/internal/router/routes.go b/auth/internal/router/routes.go index 463ad02..a77a364 100644 --- a/auth/internal/router/routes.go +++ b/auth/internal/router/routes.go @@ -12,4 +12,5 @@ func AuthRouter() *mux.Router { r.HandleFunc("/v0/auth/callback/signup", handlers.CallbackVerification).Methods("post") r.HandleFunc("/v0/auth/login", handlers.Login).Methods("POST") return r + } diff --git a/auth/internal/sendMail.go b/auth/internal/sendMail.go new file mode 100644 index 0000000..f618bf7 --- /dev/null +++ b/auth/internal/sendMail.go @@ -0,0 +1,38 @@ +package internal + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + + model "github.com/p-society/gc-server/schemas/pkg/models" +) + +func SendEmail(p *model.Player) error { + var ( + url = "http://localhost:6969/v0/mails" + requestBody = map[string]interface{}{ + "subject": "Grand Championship Player Verification", + "content": RenderEngine(p.OTP), + "to": []string{p.Email}, + } + ) + + requestBodyBytes, err := json.Marshal(requestBody) + if err != nil { + return fmt.Errorf("error encoding JSON: %v", err) + } + + resp, err := http.Post(url, "application/json", bytes.NewBuffer(requestBodyBytes)) + if err != nil { + return fmt.Errorf("error sending request: %v", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("unexpected response status: %s", resp.Status) + } + + return nil +} diff --git a/auth/pkg/security/rbac.go b/auth/pkg/security/rbac.go index 5186b44..3b51a23 100644 --- a/auth/pkg/security/rbac.go +++ b/auth/pkg/security/rbac.go @@ -6,13 +6,11 @@ import ( "github.com/p-society/gc-server/auth/internal/utils" ) -// RoleGuard is a middleware for role-based access control type RoleGuard struct { AllowedRoles []string Handler http.Handler } -// ServeHTTP implements the http.Handler interface for RoleGuard func (rg *RoleGuard) ServeHTTP(w http.ResponseWriter, r *http.Request) { var ( token string @@ -28,18 +26,15 @@ func (rg *RoleGuard) ServeHTTP(w http.ResponseWriter, r *http.Request) { p := ParseAccessToken(token) - // Check if user's role is allowed if !contains(rg.AllowedRoles, p.Role) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusForbidden) return } - // Call the next handler in the chain rg.Handler.ServeHTTP(w, r) } -// contains checks if a string is present in a slice of strings func contains(roles []string, role string) bool { for _, r := range roles { if r == role { diff --git a/auth/pkg/security/rbac.md b/auth/pkg/security/rbac.md new file mode 100644 index 0000000..0782865 --- /dev/null +++ b/auth/pkg/security/rbac.md @@ -0,0 +1,8 @@ +# Protected route with role-based access control + +``` +r.Handle("/v0/auth/login", &security.RoleGuard{ + AllowedRoles: []string{security.RoleSuperAdmin, security.RoleAdmin}, + Handler: http.HandlerFunc(handlers.Login), + }).Methods("POST") +``` \ No newline at end of file diff --git a/go.mod b/go.mod index f53f996..5d88e7f 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( ) require ( + github.com/a-h/templ v0.2.543 // indirect github.com/golang/snappy v0.0.1 // indirect github.com/klauspost/compress v1.13.6 // indirect github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect diff --git a/go.sum b/go.sum index b82cc27..0437523 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/a-h/templ v0.2.543 h1:8YyLvyUtf0/IE2nIwZ62Z/m2o2NqwhnMynzOL78Lzbk= +github.com/a-h/templ v0.2.543/go.mod h1:jP908DQCwI08IrnTalhzSEH9WJqG/Q94+EODQcJGFUA= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= @@ -6,6 +8,7 @@ github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= diff --git a/mail/pkg/sender.go b/mail/pkg/sender.go index 4c981fe..91ddc2c 100644 --- a/mail/pkg/sender.go +++ b/mail/pkg/sender.go @@ -1,6 +1,7 @@ package sender import ( + "fmt" "os" mailConfig "github.com/p-society/gc-server/mail/internal" @@ -8,13 +9,12 @@ import ( ) func SendMail(subject string, content string, to []string) error { - + fmt.Println("called,to = ", to) senderName := os.Getenv("EMAIL_SENDER_NAME") senderAddress := os.Getenv("EMAIL_SENDER_ADDRESS") senderPassword := os.Getenv("EMAIL_SENDER_PASSWORD") - + fmt.Println("sn = ",senderName) sender := mailConfig.NewGmailSender(senderName, senderAddress, senderPassword) - paramInstance := models.MailingParams{ Subject: subject, Content: content, diff --git a/sendMail.txt b/sendMail.txt new file mode 100644 index 0000000..e69de29