Skip to content

Commit

Permalink
Update and rename env vars; Add debug check to overwrite error message
Browse files Browse the repository at this point in the history
  • Loading branch information
daison12006013 committed Jun 2, 2024
1 parent 75b1bfd commit ed62f1e
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 50 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
!.gitignore
coverage.out
11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,17 @@ dbstop:
goose:
GOOSE_DRIVER=postgres GOOSE_DBSTRING="postgres://postgres:YourPostgresPassword@localhost:5432/acme_dev" goose -dir=migrations $(filter-out $@,$(MAKECMDGOALS))

ci:
go mod tidy
go mod verify

test:
go test -v ./...

coverage:
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out

%:
@:

42 changes: 31 additions & 11 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -26,26 +26,46 @@ The project also integrates with LOG_SENTRY_LEVEL (default: "warn") and includes
## ENV Vars

```
# app
APP_KEY="YourAPPKeyHere"
CORS_ORIGIN=api.acme.com
DB_STRING="postgres://postgres:YourPostgresPassword@localhost:5432/your_database_dev?sslmode=disable"
ENABLE_CAPTURE_ERRORS=true
ENABLE_CORS_MIDDLEWARE=true
ENABLE_LOG_REQUEST=true
IP_CLIENT_HEADER_KEY="CF-Connecting-IP"
APP_DEBUG=true
APP_PORT="8080"
# jwt
JWT_EXP="1h"
JWT_REFRESH_EXP="168d"
JWT_KEY="YourJWTKeyHere"
LOG_APP_LEVEL="warn"
LOG_SENTRY_LEVEL="warn"
# database
DB_STRING="postgres://postgres:YourPostgresPassword@localhost:5432/your_database_dev?sslmode=disable"
DB_MAX_OPEN_CONNS=20
# mailgun
MAIL_FROM="[email protected]"
MAILGUN_API_KEY="YourMailgunAPIKey"
MAILGUN_DOMAIN="mailer.acme.com"
PORT="8080"
RATE_LIMIT="5"
REJECT_NON_SPECIFIC_DOMAIN="acme.com"
# sentry
SENTRY_DSN=""
SENTRY_LEVEL="warn"
# log
LOG_APP_LEVEL="warn"
LOG_SENTRY_LEVEL="warn"
LOG_REQUEST_ENABLED=true
# web application firewall
WAF_ENABLED=true
WAF_RATE_LIMIT="5"
WAF_REJECT_REQUESTS_EXCEPT="acme.com"
# get requestor's ip
IP_CLIENT_HEADER_KEY="CF-Connecting-IP"
# cross origin resource
CORS_ORIGIN="*"
CORS_METHODS="POST, GET, OPTIONS, PUT, DELETE"
CORS_HEADERS="Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, X-API-KEY"
```

## Prebuilt Endpoints
Expand Down
2 changes: 1 addition & 1 deletion cmd/http/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func init() {
flag.StringVar(&appKey, "appKey", "", "Application Key")
flag.Parse()

port = utils.GetEnvWithDefault("PORT", port)
port = utils.GetEnvWithDefault("APP_PORT", port)
utils.InitializeSentry(utils.GetEnvWithDefault("SENTRY_DSN", dsn))
utils.InitializeAppKey(utils.GetEnvWithDefault("APP_KEY", appKey))
}
Expand Down
23 changes: 22 additions & 1 deletion pkg/db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"net/url"
"os"
"strconv"

"web-golang-101/sqlc/queries"
)
Expand All @@ -26,12 +27,32 @@ func NewConnection() (*DBC, error) {

db, err := sql.Open(u.Scheme, connStr)
if err != nil {
return nil, fmt.Errorf("500 | %w", err)
return nil, err
}

maxConn, err := defaultMaxOpenConns()
if err != nil {
return nil, err
}
db.SetMaxOpenConns(*maxConn)

return &DBC{DB: db}, nil
}

func (d *DBC) NewQuery() *queries.Queries {
return queries.New(d.DB)
}

func defaultMaxOpenConns() (*int, error) {
maxConn := os.Getenv("DB_MAX_OPEN_CONNS")
if maxConn == "" {
maxConn = "20"
}

maxConnInt, err := strconv.Atoi(maxConn)
if err != nil {
return nil, err
}

return &maxConnInt, nil
}
43 changes: 21 additions & 22 deletions pkg/utils/middlewares.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import (

func EnableCors(w *http.ResponseWriter) {
(*w).Header().Set("Access-Control-Allow-Origin", GetEnvWithDefault("CORS_ORIGIN", "*"))
(*w).Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
(*w).Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
(*w).Header().Set("Access-Control-Allow-Methods", GetEnvWithDefault("CORS_METHODS", "POST, GET, OPTIONS, PUT, DELETE"))
(*w).Header().Set("Access-Control-Allow-Headers", GetEnvWithDefault("CORS_HEADERS", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, X-API-KEY"))
}

func CorsMiddleware(next http.Handler) http.Handler {
Expand Down Expand Up @@ -178,29 +178,28 @@ func RequireApiKeyMiddleware(next http.Handler) http.Handler {
}

func SetDefaultMiddlewares(r *chi.Mux) {
rejectNonSpecificDomain := os.Getenv("REJECT_NON_SPECIFIC_DOMAIN") // Reject requests from non-specific domains
if rejectNonSpecificDomain != "" {
r.Use(RejectNonSpecificDomain(rejectNonSpecificDomain))
}
r.Use(CaptureErrors)
r.Use(CorsMiddleware)

rateLimitStr := GetEnvWithDefault("RATE_LIMIT", "5") // Rate limit in requests per second
if rateLimitStr != "" {
rateLimit, err := strconv.Atoi(rateLimitStr)
if err != nil {
log.Fatal("Invalid rate limit value:", err)
if GetEnvWithDefault("WAF_ENABLED", "true") == "true" {
rejectNonSpecificDomain := os.Getenv("WAF_REJECT_REQUESTS_EXCEPT") // Reject requests from non-specific domains
if rejectNonSpecificDomain != "" {
r.Use(RejectNonSpecificDomain(rejectNonSpecificDomain))
}
r.Use(RateLimit(rateLimit))
}

if GetEnvWithDefault("ENABLE_CAPTURE_ERRORS", "true") == "true" {
r.Use(CaptureErrors)
}
r.Use(WebFirewallMiddleware)

if GetEnvWithDefault("ENABLE_CORS_MIDDLEWARE", "true") == "true" {
r.Use(CorsMiddleware)
rateLimitStr := GetEnvWithDefault("WAF_RATE_LIMIT", "5") // Rate limit in requests per second
if rateLimitStr != "" {
rateLimit, err := strconv.Atoi(rateLimitStr)
if err != nil {
log.Fatal("Invalid rate limit value:", err)
}
r.Use(RateLimit(rateLimit))
}
}

if GetEnvWithDefault("ENABLE_LOG_REQUEST", "true") == "true" {
if GetEnvWithDefault("LOG_REQUEST_ENABLED", "true") == "true" {
r.Use(LogRequest)
}
}
Expand All @@ -215,8 +214,8 @@ func RateLimit(rateLimit int) func(http.Handler) http.Handler {
)
}

func WafMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
func WebFirewallMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
resp := NewResponse(w)

sqlInjectionPattern := regexp.MustCompile(`(?i)(?:'|\b)(?:--|select\b|update\b|drop\b|insert\b|delete\b|or\b|and\b|exec\b|execute\b|union\b|truncate\b|declare\b)`)
Expand All @@ -234,5 +233,5 @@ func WafMiddleware(next http.HandlerFunc) http.HandlerFunc {
}

next.ServeHTTP(w, r)
}
})
}
36 changes: 21 additions & 15 deletions pkg/utils/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package utils
import (
"encoding/json"
"net/http"
"os"

ec "web-golang-101/pkg/errorcodes"

Expand All @@ -22,6 +23,20 @@ func NewResponse(w http.ResponseWriter) *Response {
return &Response{w: w}
}

func (r *Response) WriteSuccessResponse(message string, data interface{}) {
r.Success = true
r.Message = message
r.Data = data
r.writeResponse(http.StatusOK)
}

func (r *Response) WriteValidationResponse(message string, data interface{}) {
r.Success = false
r.Message = message
r.Data = data
r.writeResponse(http.StatusBadRequest)
}

func (r *Response) HandleErrorCode(errc *ec.Error) {
if ok := r.WriteValidationError(errc); ok {
return
Expand All @@ -37,19 +52,17 @@ func (r *Response) HandleErrorCode(errc *ec.Error) {
}

func (r *Response) WriteErrorResponse(message string, statusCode int) {
if os.Getenv("APP_DEBUG") == "true" {
r.Message = message
} else {
r.Message = "Internal Server Error"
}

r.Success = false
r.Message = message
r.Data = nil
r.writeResponse(statusCode)
}

func (r *Response) WriteSuccessResponse(message string, data interface{}) {
r.Success = true
r.Message = message
r.Data = data
r.writeResponse(http.StatusOK)
}

func (r *Response) WriteValidationError(errc *ec.Error) bool {
err := errc.OriginalError()

Expand Down Expand Up @@ -81,13 +94,6 @@ func (r *Response) WriteValidationError(errc *ec.Error) bool {
return false
}

func (r *Response) WriteValidationResponse(message string, data interface{}) {
r.Success = false
r.Message = message
r.Data = data
r.writeResponse(http.StatusBadRequest)
}

func (r *Response) writeResponse(statusCode int) {
js, err := json.Marshal(r)
if err != nil {
Expand Down

0 comments on commit ed62f1e

Please sign in to comment.