diff --git a/.gitignore b/.gitignore index ea6b22e..23e1857 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,7 @@ *.db # Build -*.exe \ No newline at end of file +*.exe + +# Environment +.env \ No newline at end of file diff --git a/README.md b/README.md index f26d173..9fec0fd 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,7 @@ Don't forget to setup the [Environment variables](#environment-variables)! ### Use with Docker -To **run** the app, run the command - -```shell -docker-compose up -``` +TODO (or is it...) ### Build and run it yourself @@ -22,10 +18,10 @@ TODO ### Environment variables -| Name | Type | Description | Comment | -|------|------|-------------|---------| -| | | | | - +| Name | Type | Description | Comment | +|-------------|--------|---------------------------------------|-----------------------------------------| +| PORT | int | The port the API will use | required | +| ENVIRONMENT | string | The environment the API is running in | required, `development` or `production` | ## API Usage diff --git a/api/auth.go b/api/auth.go index 5f1eda7..ebb8aff 100644 --- a/api/auth.go +++ b/api/auth.go @@ -7,6 +7,7 @@ import ( "github.com/go-chi/jwtauth/v5" "golang.org/x/crypto/bcrypt" "net/http" + "os" "time" ) @@ -21,6 +22,7 @@ type UserLogin struct { Password string `json:"password" validate:"required,min=8"` } +var shouldCookieBeSecure = os.Getenv("ENVIRONMENT") == "production" var TokenAuth *jwtauth.JWTAuth // TODO Move into its own file or package that handles api errors @@ -36,14 +38,14 @@ func SetJwtCookie(w *http.ResponseWriter, userId uint32) error { Name: "jwt", Value: tokenString, Expires: time.Now().Add(24 * time.Hour), - Secure: false, // TODO false in dev, true in prod + Secure: shouldCookieBeSecure, HttpOnly: true, Path: "/", }) return nil } -func isAllowedToCreateUser() bool { +func isUserTableEmpty() bool { users := container.ListUsersUseCase.ListUsers() return len(users) == 0 } @@ -92,7 +94,7 @@ func login(w http.ResponseWriter, r *http.Request) { } func register(w http.ResponseWriter, r *http.Request) { - if !IsLoggedIn(r) && !isAllowedToCreateUser() { + if !IsLoggedIn(r) && !isUserTableEmpty() { http.Error(w, "You are not allowed to create a user. Log in or reset database.", http.StatusForbidden) return } @@ -132,7 +134,7 @@ func removeJwtCookie(w http.ResponseWriter) { Value: "", Expires: time.Now(), MaxAge: -1, - Secure: false, // TODO false in dev, true in prod + Secure: shouldCookieBeSecure, HttpOnly: true, Path: "/", }) diff --git a/api/page.go b/api/page.go index e4570db..37baf48 100644 --- a/api/page.go +++ b/api/page.go @@ -6,6 +6,7 @@ import ( "github.com/go-chi/chi/v5" "html/template" "net/http" + "os" "path/filepath" "strings" ) @@ -78,9 +79,11 @@ func postLoginPage(w http.ResponseWriter, r *http.Request) { return } - // TODO replace url with som env variable - response, err := http.Post("http://localhost:8080/v1/auth/login", "application/json", bytes.NewBuffer(credentials)) - // TODO handle possible errors in separate file (api package) + response, err := http.Post( + "http://localhost:"+os.Getenv("PORT")+"/v1/auth/login", + "application/json", + bytes.NewBuffer(credentials)) + if err != nil || response.StatusCode != http.StatusOK { r.Method = http.MethodGet getLoginPageHandler(NewLoginPage("Invalid username or password.", r.FormValue("username")))(w, r) diff --git a/cmd/main.go b/cmd/main.go index 43adcde..4a9881a 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -8,9 +8,14 @@ import ( "github.com/go-chi/chi/v5" "github.com/go-chi/cors" "github.com/go-chi/jwtauth/v5" + "github.com/joho/godotenv" + "log" "net/http" + "os" ) +var envVarsToLoad = []string{"PORT", "ENVIRONMENT"} + func jsonContentTypeMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") @@ -80,15 +85,27 @@ func initRoutes() *chi.Mux { return apiRouter } +func initEnvVariables() { + err := godotenv.Load() + if err != nil { + log.Fatal("Error loading .env file") + } + for _, envVar := range envVarsToLoad { + if _, ok := os.LookupEnv(envVar); !ok { + panic(fmt.Sprintf("Environment variable %s is not set", envVar)) + } + } +} + func main() { + initEnvVariables() api.InitContainer() api.InitValidator() initJwt() - router := initRoutes() - fmt.Println("Server starting on port 8080") - err := http.ListenAndServe(":8080", router) + fmt.Println("Server starting on port " + os.Getenv("PORT")) + err := http.ListenAndServe(":"+os.Getenv("PORT"), router) if err != nil { panic(err) } diff --git a/go.mod b/go.mod index a50a12f..2cfe2f5 100644 --- a/go.mod +++ b/go.mod @@ -26,6 +26,7 @@ require ( github.com/google/uuid v1.3.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect + github.com/joho/godotenv v1.5.1 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/lestrrat-go/blackmagic v1.0.1 // indirect github.com/lestrrat-go/httpcc v1.0.1 // indirect diff --git a/go.sum b/go.sum index 9a9f1e1..16f0a1c 100644 --- a/go.sum +++ b/go.sum @@ -41,6 +41,8 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/lestrrat-go/blackmagic v1.0.1 h1:lS5Zts+5HIC/8og6cGHb0uCcNCa3OUt1ygh3Qz2Fe80=