Skip to content

Commit

Permalink
feat: added logger
Browse files Browse the repository at this point in the history
  • Loading branch information
proffapt committed Jul 5, 2024
1 parent e81a474 commit cf61218
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 30 deletions.
1 change: 1 addition & 0 deletions backend/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/metakgp/naarad/backend
go 1.22.4

require (
github.com/joho/godotenv v1.5.1
github.com/mattn/go-sqlite3 v1.14.22
github.com/rs/cors v1.11.0
golang.org/x/oauth2 v0.21.0
Expand Down
2 changes: 2 additions & 0 deletions backend/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfF
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
github.com/googleapis/gax-go/v2 v2.12.5 h1:8gw9KZK8TiVKB6q3zHY3SBzLnrGp6HQjyfYBYGmXdxA=
github.com/googleapis/gax-go/v2 v2.12.5/go.mod h1:BUDKcWo+RaKq5SC9vVYL0wLADa3VcfswbOMMRmB9H3E=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand Down
101 changes: 71 additions & 30 deletions backend/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import (
"database/sql"
"encoding/json"
"fmt"
"log"
"math/rand"
"net/http"
"os"
"strconv"
"strings"
"time"

"github.com/joho/godotenv"
_ "github.com/mattn/go-sqlite3"
"github.com/rs/cors"
)
Expand Down Expand Up @@ -38,7 +40,39 @@ var jwtValidateResp struct {
}

var healthResponse struct {
Healthy bool `json:"healthy"`
Healthy bool `json:"healthy"`
}

type responseRecorder struct {
http.ResponseWriter
status int
size int
}

func (r *responseRecorder) WriteHeader(status int) {
r.status = status
r.ResponseWriter.WriteHeader(status)
}

func LoggerMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
recorder := &responseRecorder{w, http.StatusOK, 0}
next.ServeHTTP(recorder, r)

logLevel := "INFO"
if recorder.status >= 400 {
logLevel = "ERROR"
}

log.Printf("%s:\t%s - %q %s %d %s\n",
logLevel,
r.Header.Get("X-Real-IP"),
r.Method,
r.RequestURI,
recorder.status,
http.StatusText(recorder.status),
)
})
}

func PasswordGenerator(passwordLength int) string {
Expand Down Expand Up @@ -70,8 +104,8 @@ func PasswordGenerator(passwordLength int) string {
func register(res http.ResponseWriter, req *http.Request) {
cookie, err := req.Cookie("heimdall")
if err != nil {
fmt.Println("Cookie Error (Heimdall token not found): ", err.Error())
http.Error(res, "No Heimdall session token received", http.StatusUnauthorized)
fmt.Println("[ERROR] ~ Retrieving Heimdall Token: ", err.Error())
http.Error(res, "[ERROR] ~ Retrieving Heimdall Token", http.StatusUnauthorized)
return
}
tokenString := cookie.Value
Expand All @@ -82,14 +116,14 @@ func register(res http.ResponseWriter, req *http.Request) {
client := &http.Client{}
resp, err := client.Do(reqEmail)
if err != nil {
fmt.Println("heimdall/validate-jwt Error: ", err.Error())
http.Error(res, "Failed to validate Heimdall session", http.StatusInternalServerError)
fmt.Println("[ERROR] ~ Validating Heimdall Token ~", tokenString, ": ", err.Error())
http.Error(res, "[ERROR] ~ Validating Heimdall Token", http.StatusInternalServerError)
return
}
defer resp.Body.Close()
if err := json.NewDecoder(resp.Body).Decode(&jwtValidateResp); err != nil {
fmt.Println("Heimdall Response | Email Decoder Error: ", err.Error())
http.Error(res, "Failed to retrieve user email", http.StatusInternalServerError)
fmt.Println("[ERROR] ~ Parsing Heimdall Token ~", tokenString, ": ", err.Error())
http.Error(res, "[ERROR] ~ Parsing Heimdall Token", http.StatusInternalServerError)
return
}

Expand All @@ -102,59 +136,59 @@ func register(res http.ResponseWriter, req *http.Request) {
signupData := fmt.Sprintf(`{"username": "%s", "password": "%s"}`, username, password)
reqNtfy, _ := http.NewRequest("POST", ntfyServerAddr+"/v1/account", strings.NewReader(signupData))
for name, values := range req.Header {
reqNtfy.Header[name] = values
}
reqNtfy.Header[name] = values
}
resp, err = client.Do(reqNtfy)
if err != nil {
fmt.Println("NTFY User Registration API Error: ", err.Error())
http.Error(res, "Failed to request user registration for Naarad", http.StatusInternalServerError)
fmt.Println("[ERROR] ~ Requesting User Registration ~", username, ": ", err.Error())
http.Error(res, "[ERROR] ~ Requesting User Registration", http.StatusInternalServerError)
return
}
defer resp.Body.Close()
if resp.StatusCode == 409 {
fmt.Println("User already registered")
http.Error(res, "User already registered", resp.StatusCode)
fmt.Println("[INFO] ~ User Already Registered: ", username)
http.Error(res, "[INFO] ~ User Already Registered", resp.StatusCode)
return
} else if resp.StatusCode != 200 {
fmt.Println("User registeration failed")
http.Error(res, "Failed to register user", resp.StatusCode)
fmt.Println("[ERROR] ~ Registering User: ", username)
http.Error(res, "[ERROR] ~ Registering User", resp.StatusCode)
return
}

// Get the userid from sqlite db
rowD := db.QueryRow(`SELECT id FROM user WHERE user=?`, username)
if err = rowD.Scan(&userId); err != nil {
fmt.Println("Database Error | Get User ID: ", err.Error())
http.Error(res, "Internal Server Error (DB: Fetch UserID)", http.StatusInternalServerError)
fmt.Println("[ERROR] ~ Fetching UserId ~", username, ": ", err.Error())
http.Error(res, "Internal Server Error", http.StatusInternalServerError)
return
}

// Provide read-only access for kgp-* channels to the user
queryGenAccess := fmt.Sprintf(`INSERT INTO user_access VALUES("%s", "kgp-%%", 1, 0, "")`, userId)
if _, err = db.Exec(queryGenAccess); err != nil {
fmt.Println("Granting Access Error (kgp-*): ", err.Error())
http.Error(res, "Internal Server Error (DB: Access Grant)", http.StatusInternalServerError)
fmt.Println("[ERROR] ~ Granting Access to (kgp-*) ~", username, ": ", err.Error())
http.Error(res, "Internal Server Error", http.StatusInternalServerError)
return
}

// Provide read-only access for kgp-* channels to the user
queryGenAccess = fmt.Sprintf(`INSERT INTO user_access VALUES("%s", "st_%%", 1, 0, "")`, userId)
if _, err = db.Exec(queryGenAccess); err != nil {
fmt.Println("Granting Access Error (st_*): ", err.Error())
http.Error(res, "Internal Server Error (DB: Access Grant)", http.StatusInternalServerError)
fmt.Println("[ERROR] ~ Granting Access to (st_*) ~", username, ": ", err.Error())
http.Error(res, "Internal Server Error", http.StatusInternalServerError)
return
}

// Sending user credentials over mail
emailBody := fmt.Sprintf("Here are the credentials to sign in into Naarad.\n\nUsername: %s\nPassword: %s", username, password)
if sent, err := sendMail(userEmail, "Naarad Login Credentials | Metakgp", emailBody); err != nil || !sent {
fmt.Println("Sending Credentials Error: ", err.Error())
http.Error(res, "Failed to send user credentials", http.StatusInternalServerError)
fmt.Println("[ERROR] ~ Sending Credentials ~", username, ": ", err.Error())
http.Error(res, "[ERROR] ~ Sending Credentials", http.StatusInternalServerError)
return
}

http.Header.Add(res.Header(), "content-type", "application/json")
resStruct.Msg = "User created successfully!"
resStruct.Msg = "[INFO] ~ User " + "(" + username + ")" + "Created Successfully!"

if err = json.NewEncoder(res).Encode(&resStruct); err != nil {
http.Error(res, err.Error(), http.StatusInternalServerError)
Expand All @@ -163,7 +197,7 @@ func register(res http.ResponseWriter, req *http.Request) {
}

func healthCheck(res http.ResponseWriter, req *http.Request) {
res.Header().Set("Content-Type", "application/json")
res.Header().Set("Content-Type", "application/json")

// Check database connection
err := db.Ping()
Expand All @@ -179,10 +213,11 @@ func healthCheck(res http.ResponseWriter, req *http.Request) {
res.WriteHeader(http.StatusOK)
}

json.NewEncoder(res).Encode(healthResponse)
json.NewEncoder(res).Encode(healthResponse)
}

func main() {
godotenv.Load()
initMailer()

passwordSize, err := strconv.Atoi(os.Getenv("PASSWORD_SIZE"))
Expand All @@ -208,15 +243,21 @@ func main() {
panic(err)
}

http.HandleFunc("GET /health", healthCheck)
http.HandleFunc("GET /register", register)
mux := http.NewServeMux()
mux.HandleFunc("GET /health", healthCheck)
mux.HandleFunc("GET /register", register)

c := cors.New(cors.Options{
AllowedOrigins: []string{"https://naarad.metakgp.org", "https://naarad-signup.metakgp.org", "http://localhost:3000"},
AllowCredentials: true,
})
fmt.Println("Naarad Backend Server running on port : 5173")
if err = http.ListenAndServe(":5173", c.Handler(http.DefaultServeMux)); err != nil {

handler := c.Handler(mux)
loggedHandler := LoggerMiddleware(handler)
if err := http.ListenAndServe(":5173", loggedHandler); err != nil {
fmt.Printf("error starting server: %s\n", err)
panic(err)
} else {
fmt.Println("Naarad Backend Server running on port : 5173")
}
}

0 comments on commit cf61218

Please sign in to comment.