From 9412d8ec28df16f5a244aa2e5bcad3789e98fcf4 Mon Sep 17 00:00:00 2001 From: grumbulon Date: Sat, 28 Jan 2023 23:39:26 -0500 Subject: [PATCH 1/5] added user creation, login, and logout test. Linted. Go mod. Adding http.StatusOK const in a few places I noticed it was not in. --- go.mod | 3 + go.sum | 2 - internal/api/api_test.go | 142 +++++++++++++++++++++++++++++++++++++++ internal/api/auth.go | 4 +- 4 files changed, 147 insertions(+), 4 deletions(-) create mode 100644 internal/api/api_test.go diff --git a/go.mod b/go.mod index 5124810..a6b3308 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( require ( github.com/KyleBanks/depth v1.2.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/go-openapi/spec v0.20.6 // indirect @@ -23,6 +24,7 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.7.6 // indirect github.com/mattn/go-colorable v0.1.12 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rs/zerolog v1.27.0 // indirect github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe // indirect gopkg.in/yaml.v2 v2.4.0 // indirect @@ -45,6 +47,7 @@ require ( github.com/lestrrat-go/option v1.0.1 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect + github.com/stretchr/testify v1.8.1 github.com/swaggo/http-swagger v1.3.3 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/net v0.5.0 // indirect diff --git a/go.sum b/go.sum index 4a0864d..b02d0dc 100644 --- a/go.sum +++ b/go.sum @@ -112,8 +112,6 @@ github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe h1:K8pHPVoTgxFJt1lXuI github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w= github.com/swaggo/http-swagger v1.3.3 h1:Hu5Z0L9ssyBLofaama21iYaF2VbWyA8jdohaaCGpHsc= github.com/swaggo/http-swagger v1.3.3/go.mod h1:sE+4PjD89IxMPm77FnkDz0sdO+p5lbXzrVWT6OTVVGo= -github.com/swaggo/swag v1.8.9 h1:kHtaBe/Ob9AZzAANfcn5c6RyCke9gG9QpH0jky0I/sA= -github.com/swaggo/swag v1.8.9/go.mod h1:ezQVUUhly8dludpVk+/PuwJWvLLanB13ygV5Pr9enSk= github.com/swaggo/swag v1.8.10 h1:eExW4bFa52WOjqRzRD58bgWsWfdFJso50lpbeTcmTfo= github.com/swaggo/swag v1.8.10/go.mod h1:ezQVUUhly8dludpVk+/PuwJWvLLanB13ygV5Pr9enSk= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= diff --git a/internal/api/api_test.go b/internal/api/api_test.go new file mode 100644 index 0000000..1e61007 --- /dev/null +++ b/internal/api/api_test.go @@ -0,0 +1,142 @@ +package api + +import ( + "encoding/json" + "io" + "log" + "net/http" + "net/url" + "strings" + "testing" + + "git.freecumextremist.com/grumbulon/pomme/internal" + "git.freecumextremist.com/grumbulon/pomme/internal/db" + "github.com/stretchr/testify/assert" +) + +type response struct { + Username string `json:"username"` + Message string `json:"message"` + Status int `json:"status"` +} + +type accountTest struct { + username string + password string +} + +func TestInit(t *testing.T) { + tester := accountTest{ + username: autoUname(), + password: "merde", + } + + tester.TestMakeAccount(t) + tester.TestLogin(t) + tester.TestLogout(t) + tester.CleanUpDb() +} + +func (a *accountTest) TestMakeAccount(t *testing.T) { + var target response + + client := http.Client{} + + form := url.Values{} + + form.Add("username", a.username) + + form.Add("password", "test") + + if req, err := http.NewRequest(http.MethodPost, "http://localhost:3010/api/create", strings.NewReader(form.Encode())); err == nil { + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + + resp, err := client.Do(req) + if err != nil { + assert.NotNil(t, err) + } + + respBody, _ := io.ReadAll(resp.Body) + + err = json.Unmarshal(respBody, &target) + if err != nil { + assert.NotNil(t, err) + } + + log.Println(target) + assert.Equal(t, http.StatusCreated, target.Status) + } +} + +func (a *accountTest) TestLogin(t *testing.T) { + var target response + + client := http.Client{} + + form := url.Values{} + + form.Add("username", a.username) + + form.Add("password", "test") + + if req, err := http.NewRequest(http.MethodPost, "http://localhost:3010/api/login", strings.NewReader(form.Encode())); err == nil { + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + + resp, err := client.Do(req) + if err != nil { + assert.NotNil(t, err) + } + + respBody, _ := io.ReadAll(resp.Body) + + err = json.Unmarshal(respBody, &target) + if err != nil { + assert.NotNil(t, err) + } + + log.Println(target) + assert.Equal(t, http.StatusOK, target.Status) + } +} + +func (a *accountTest) TestLogout(t *testing.T) { + var target response + + client := http.Client{} + + form := url.Values{} + + form.Add("username", a.username) + + if req, err := http.NewRequest(http.MethodPost, "http://localhost:3010/api/logout", strings.NewReader(form.Encode())); err == nil { + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + + resp, err := client.Do(req) + if err != nil { + assert.NotNil(t, err) + } + + respBody, _ := io.ReadAll(resp.Body) + + err = json.Unmarshal(respBody, &target) + if err != nil { + assert.NotNil(t, err) + } + + log.Println(target) + assert.Equal(t, http.StatusOK, target.Status) + } +} + +// currently does not work. +func (a *accountTest) CleanUpDb() { + var user internal.User + + db := db.InitDb() + + db.Where("username = ?", a.username).First(&user) + + if user.Username != "" { + db.Delete(&user, user.ID) + } +} diff --git a/internal/api/auth.go b/internal/api/auth.go index 39aa347..0b863f8 100644 --- a/internal/api/auth.go +++ b/internal/api/auth.go @@ -120,7 +120,7 @@ func Login(w http.ResponseWriter, r *http.Request) { err = json.NewEncoder(w).Encode( internal.Response{ Message: "Successfully logged in", - HTTPResponse: 200, + HTTPResponse: http.StatusOK, }) if err != nil { @@ -148,7 +148,7 @@ func Logout(w http.ResponseWriter, r *http.Request) { err := json.NewEncoder(w).Encode( internal.Response{ Message: "Successfully logged out", - HTTPResponse: 200, + HTTPResponse: http.StatusOK, }) if err != nil { internalServerError(w, "internal server error") From 849f5d28faaa7377ff2abfed6a62609c22a35679 Mon Sep 17 00:00:00 2001 From: grumbulon Date: Sat, 28 Jan 2023 23:41:53 -0500 Subject: [PATCH 2/5] small oops --- internal/api/api_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/api/api_test.go b/internal/api/api_test.go index 1e61007..fd0bf2c 100644 --- a/internal/api/api_test.go +++ b/internal/api/api_test.go @@ -46,7 +46,7 @@ func (a *accountTest) TestMakeAccount(t *testing.T) { form.Add("username", a.username) - form.Add("password", "test") + form.Add("password", a.password) if req, err := http.NewRequest(http.MethodPost, "http://localhost:3010/api/create", strings.NewReader(form.Encode())); err == nil { req.Header.Add("Content-Type", "application/x-www-form-urlencoded") @@ -77,7 +77,7 @@ func (a *accountTest) TestLogin(t *testing.T) { form.Add("username", a.username) - form.Add("password", "test") + form.Add("password", a.password) if req, err := http.NewRequest(http.MethodPost, "http://localhost:3010/api/login", strings.NewReader(form.Encode())); err == nil { req.Header.Add("Content-Type", "application/x-www-form-urlencoded") From 5e8ba819bc0dd0f4c4d938e7c48685b04bb7d323 Mon Sep 17 00:00:00 2001 From: grumbulon Date: Mon, 30 Jan 2023 19:49:52 -0500 Subject: [PATCH 3/5] added read DB path from config, add DB paths to sample config, added render library for JSON responses, removed plaintext password from User struct, made error handler funcs return json and their calls to include http.Request, and made API tests use httptest server --- .gitignore | 1 + config.sample.yaml | 2 + go.mod | 2 + go.sum | 4 ++ internal/api/api.go | 43 ++++++++++++++++---- internal/api/api_test.go | 82 +++++++++++++++++++++++++++------------ internal/api/auth.go | 57 +++++++++++---------------- internal/api/users.go | 16 ++++---- internal/api/zone.go | 20 +++++----- internal/configuration.go | 3 +- internal/db/db.go | 4 +- 11 files changed, 146 insertions(+), 88 deletions(-) diff --git a/.gitignore b/.gitignore index d46b0b2..6c5e775 100644 --- a/.gitignore +++ b/.gitignore @@ -24,5 +24,6 @@ go.work pomme test.db test.sqlite +pomme.sqlite .dccache config.yaml \ No newline at end of file diff --git a/config.sample.yaml b/config.sample.yaml index eef7035..94d008c 100644 --- a/config.sample.yaml +++ b/config.sample.yaml @@ -1,3 +1,5 @@ server: example.com # does nothing yet hashingsecret: PasswordHashingSecret port: 3008 # port the server runs on +db: pomme.sqlite +testdb: test.sqlite \ No newline at end of file diff --git a/go.mod b/go.mod index a6b3308..2fe0bfb 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( require ( github.com/KyleBanks/depth v1.2.1 // indirect + github.com/ajg/form v1.5.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect @@ -35,6 +36,7 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect github.com/glebarez/go-sqlite v1.20.0 // indirect github.com/go-chi/httplog v0.2.5 + github.com/go-chi/render v1.0.2 github.com/goccy/go-json v0.10.0 // indirect github.com/google/uuid v1.3.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect diff --git a/go.sum b/go.sum index b02d0dc..4017746 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls= github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E= +github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= +github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= @@ -29,6 +31,8 @@ github.com/go-chi/httprate v0.7.1 h1:d5kXARdms2PREQfU4pHvq44S6hJ1hPu4OXLeBKmCKWs github.com/go-chi/httprate v0.7.1/go.mod h1:6GOYBSwnpra4CQfAKXu8sQZg+nZ0M1g9QnyFvxrAB8A= github.com/go-chi/jwtauth/v5 v5.1.0 h1:wJyf2YZ/ohPvNJBwPOzZaQbyzwgMZZceE1m8FOzXLeA= github.com/go-chi/jwtauth/v5 v5.1.0/go.mod h1:MA93hc1au3tAQwCKry+fI4LqJ5MIVN4XSsglOo+lSc8= +github.com/go-chi/render v1.0.2 h1:4ER/udB0+fMWB2Jlf15RV3F4A2FDuYi/9f+lFttR/Lg= +github.com/go-chi/render v1.0.2/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= diff --git a/internal/api/api.go b/internal/api/api.go index d1068f6..b8f3f73 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "log" "net/http" "time" @@ -13,6 +14,8 @@ import ( "github.com/go-chi/httplog" "github.com/go-chi/httprate" "github.com/go-chi/jwtauth/v5" + "github.com/go-chi/render" + "gorm.io/gorm" ) type key int @@ -24,32 +27,56 @@ const ( // setDBMiddleware is the http Handler func for the GORM middleware with context. func setDBMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - db := db.InitDb() + var pommeDB *gorm.DB + c, err := internal.ReadConfig() + if err != nil { + log.Printf("No config file defined: %v", err) + } + + switch r.Header.Get("User-Agent") { + case "pomme-api-test-slave": + pommeDB = db.InitDb(c.TestDB) + default: + pommeDB = db.InitDb(c.DB) + } + timeoutContext, cancelContext := context.WithTimeout(context.Background(), time.Second) - ctx := context.WithValue(r.Context(), keyPrincipalContextID, db.WithContext(timeoutContext)) + ctx := context.WithValue(r.Context(), keyPrincipalContextID, pommeDB.WithContext(timeoutContext)) defer cancelContext() next.ServeHTTP(w, r.WithContext(ctx)) }) } // handlers for very common errors. -func authFailed(w http.ResponseWriter, realm string) { +func authFailed(w http.ResponseWriter, r *http.Request, realm string) { w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.Header().Set("X-Content-Type-Options", "nosniff") w.Header().Add("WWW-Authenticate", fmt.Sprintf(`Realm="%s"`, realm)) - w.WriteHeader(http.StatusUnauthorized) + + resp := internal.Response{ + Message: fmt.Sprintf(`Login failed -- Realm="%s"`, realm), + HTTPResponse: http.StatusUnauthorized, + } + + render.JSON(w, r, resp) } -func internalServerError(w http.ResponseWriter, errMsg string) { +func internalServerError(w http.ResponseWriter, r *http.Request, errMsg string) { logger := httplog.NewLogger("Pomme", httplog.Options{ JSON: true, }) - w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.Header().Set("X-Content-Type-Options", "nosniff") w.Header().Add("Internal Server Error", errMsg) w.WriteHeader(http.StatusInternalServerError) + resp := internal.Response{ + Message: errMsg, + HTTPResponse: http.StatusInternalServerError, + } + + render.JSON(w, r, resp) + logger.Error().Msg(errMsg) } @@ -72,7 +99,7 @@ func API() http.Handler { Message: "API rate limit exceded", }) if err != nil { - internalServerError(w, "internal server error") + internalServerError(w, r, "internal server error") return } @@ -100,7 +127,7 @@ func API() http.Handler { Message: "API rate limit exceded", }) if err != nil { - internalServerError(w, "internal server error") + internalServerError(w, r, "internal server error") return } diff --git a/internal/api/api_test.go b/internal/api/api_test.go index fd0bf2c..44aafcb 100644 --- a/internal/api/api_test.go +++ b/internal/api/api_test.go @@ -3,15 +3,18 @@ package api import ( "encoding/json" "io" - "log" "net/http" + "net/http/httptest" "net/url" "strings" "testing" + "time" "git.freecumextremist.com/grumbulon/pomme/internal" "git.freecumextremist.com/grumbulon/pomme/internal/db" + "github.com/go-chi/chi/v5" "github.com/stretchr/testify/assert" + "golang.org/x/crypto/bcrypt" ) type response struct { @@ -23,18 +26,59 @@ type response struct { type accountTest struct { username string password string + url string } -func TestInit(t *testing.T) { - tester := accountTest{ - username: autoUname(), - password: "merde", +func TestAPI(t *testing.T) { + config, err := internal.ReadConfig() + if err != nil { + panic(err) } + pomme := chi.NewRouter() + + pomme.Mount("/api", API()) + + s := &http.Server{ + ReadTimeout: 3 * time.Second, + WriteTimeout: 15 * time.Second, + Addr: ":" + config.Port, + Handler: pomme, + } + + ts := httptest.NewUnstartedServer(pomme) + ts.Config = s + ts.Start() + + defer ts.Close() + + tester := Init(ts.URL) + + c, err := internal.ReadConfig() + if err != nil { + assert.NotNil(t, err) + } + + db := db.InitDb(c.TestDB) + + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(tester.password), bcrypt.DefaultCost) + if err != nil { + return + } + + db.Create(&internal.User{Username: tester.username, HashedPassword: string(hashedPassword)}) + tester.TestMakeAccount(t) tester.TestLogin(t) tester.TestLogout(t) - tester.CleanUpDb() +} + +func Init(url string) accountTest { + return accountTest{ + username: autoUname(), + password: "merde", + url: url, + } } func (a *accountTest) TestMakeAccount(t *testing.T) { @@ -48,9 +92,11 @@ func (a *accountTest) TestMakeAccount(t *testing.T) { form.Add("password", a.password) - if req, err := http.NewRequest(http.MethodPost, "http://localhost:3010/api/create", strings.NewReader(form.Encode())); err == nil { + if req, err := http.NewRequest(http.MethodPost, a.url+`api/create`, strings.NewReader(form.Encode())); err == nil { req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + req.Header.Add("User-Agent", "pomme-api-test-slave") + resp, err := client.Do(req) if err != nil { assert.NotNil(t, err) @@ -63,7 +109,6 @@ func (a *accountTest) TestMakeAccount(t *testing.T) { assert.NotNil(t, err) } - log.Println(target) assert.Equal(t, http.StatusCreated, target.Status) } } @@ -79,8 +124,9 @@ func (a *accountTest) TestLogin(t *testing.T) { form.Add("password", a.password) - if req, err := http.NewRequest(http.MethodPost, "http://localhost:3010/api/login", strings.NewReader(form.Encode())); err == nil { + if req, err := http.NewRequest(http.MethodPost, a.url+`/api/login`, strings.NewReader(form.Encode())); err == nil { req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + req.Header.Add("User-Agent", "pomme-api-test-slave") resp, err := client.Do(req) if err != nil { @@ -94,7 +140,6 @@ func (a *accountTest) TestLogin(t *testing.T) { assert.NotNil(t, err) } - log.Println(target) assert.Equal(t, http.StatusOK, target.Status) } } @@ -108,8 +153,9 @@ func (a *accountTest) TestLogout(t *testing.T) { form.Add("username", a.username) - if req, err := http.NewRequest(http.MethodPost, "http://localhost:3010/api/logout", strings.NewReader(form.Encode())); err == nil { + if req, err := http.NewRequest(http.MethodPost, a.url+`/api/logout`, strings.NewReader(form.Encode())); err == nil { req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + req.Header.Add("User-Agent", "pomme-api-test-slave") resp, err := client.Do(req) if err != nil { @@ -123,20 +169,6 @@ func (a *accountTest) TestLogout(t *testing.T) { assert.NotNil(t, err) } - log.Println(target) assert.Equal(t, http.StatusOK, target.Status) } } - -// currently does not work. -func (a *accountTest) CleanUpDb() { - var user internal.User - - db := db.InitDb() - - db.Where("username = ?", a.username).First(&user) - - if user.Username != "" { - db.Delete(&user, user.ID) - } -} diff --git a/internal/api/auth.go b/internal/api/auth.go index 0b863f8..ee6fce1 100644 --- a/internal/api/auth.go +++ b/internal/api/auth.go @@ -1,11 +1,11 @@ package api import ( - "encoding/json" "net/http" "time" "git.freecumextremist.com/grumbulon/pomme/internal" + "github.com/go-chi/render" "golang.org/x/crypto/bcrypt" "gorm.io/gorm" ) @@ -48,14 +48,20 @@ func Login(w http.ResponseWriter, r *http.Request) { var result internal.User if _, err := r.Cookie("jwt"); err == nil { - http.Error(w, "Logged in", http.StatusCreated) + w.Header().Set("Content-Type", "application/json") + + resp := internal.Response{ + Message: "Already logged in", + HTTPResponse: http.StatusOK, + } + render.JSON(w, r, resp) return } err := r.ParseForm() if err != nil { - internalServerError(w, "unable to parse request") + internalServerError(w, r, "unable to parse request") return } @@ -65,20 +71,20 @@ func Login(w http.ResponseWriter, r *http.Request) { password := r.Form.Get("password") if username == "" { - internalServerError(w, "no username provided") // this should prob be handled by the frontend + internalServerError(w, r, "no username provided") // this should prob be handled by the frontend return } if password == "" { - internalServerError(w, "no password provided") // this should prob be handled by the frontend + internalServerError(w, r, "no password provided") // this should prob be handled by the frontend return } db, ok := r.Context().Value(keyPrincipalContextID).(*gorm.DB) if !ok { - internalServerError(w, "DB connection failed") + internalServerError(w, r, "DB connection failed") return } @@ -86,7 +92,7 @@ func Login(w http.ResponseWriter, r *http.Request) { db.Where("username = ?", username).First(&result) if result.Username == "" { - authFailed(w, "login") + authFailed(w, r, "authentication") return } @@ -94,14 +100,14 @@ func Login(w http.ResponseWriter, r *http.Request) { err = bcrypt.CompareHashAndPassword([]byte(result.HashedPassword), []byte(password)) if err != nil { - authFailed(w, "login") + authFailed(w, r, "authentication") return } token, err := makeToken(username) if err != nil { - internalServerError(w, err.Error()) + internalServerError(w, r, err.Error()) return } @@ -116,20 +122,12 @@ func Login(w http.ResponseWriter, r *http.Request) { Name: "jwt", // Must be named "jwt" or else the token cannot be searched for by jwtauth.Verifier. Value: token, }) - w.Header().Set("Content-Type", "application/json") - err = json.NewEncoder(w).Encode( - internal.Response{ - Message: "Successfully logged in", - HTTPResponse: http.StatusOK, - }) - if err != nil { - internalServerError(w, "internal server error") - - return + resp := internal.Response{ + Message: "Successfully logged in", + HTTPResponse: http.StatusOK, } - - http.Redirect(w, r, "/", http.StatusSeeOther) + render.JSON(w, r, resp) } // Logout destroys a users JWT cookie. @@ -143,18 +141,9 @@ func Logout(w http.ResponseWriter, r *http.Request) { Value: "", }) - w.Header().Set("Content-Type", "application/json") - - err := json.NewEncoder(w).Encode( - internal.Response{ - Message: "Successfully logged out", - HTTPResponse: http.StatusOK, - }) - if err != nil { - internalServerError(w, "internal server error") - - return + resp := internal.Response{ + Message: "Successfully logged out", + HTTPResponse: http.StatusOK, } - - http.Redirect(w, r, "/", http.StatusSeeOther) + render.JSON(w, r, resp) } diff --git a/internal/api/users.go b/internal/api/users.go index f91ec5e..fbbe9c2 100644 --- a/internal/api/users.go +++ b/internal/api/users.go @@ -17,14 +17,14 @@ import ( func NewUser(w http.ResponseWriter, r *http.Request) { db, ok := r.Context().Value(keyPrincipalContextID).(*gorm.DB) if !ok { - internalServerError(w, "internal server error") + internalServerError(w, r, "internal server error") } var result internal.User err := r.ParseForm() if err != nil { - internalServerError(w, "unable to parse request") + internalServerError(w, r, "unable to parse request") return } @@ -38,7 +38,7 @@ func NewUser(w http.ResponseWriter, r *http.Request) { password := r.Form.Get("password") if password == "" { - internalServerError(w, "no password provided") + internalServerError(w, r, "no password provided") return } @@ -46,14 +46,14 @@ func NewUser(w http.ResponseWriter, r *http.Request) { db.Where("username = ?", username).First(&result) if result.Username != "" { - internalServerError(w, "user already exists") + internalServerError(w, r, "user already exists") return } hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { - authFailed(w, "login") + authFailed(w, r, "login") return } @@ -62,7 +62,7 @@ func NewUser(w http.ResponseWriter, r *http.Request) { token, err := makeToken(username) if err != nil { - internalServerError(w, "internal server error") + internalServerError(w, r, "internal server error") return } @@ -79,7 +79,7 @@ func NewUser(w http.ResponseWriter, r *http.Request) { }) w.WriteHeader(http.StatusCreated) - w.Header().Set("Content-Type", "application/json") + err = json.NewEncoder(w).Encode( internal.Response{ Username: username, @@ -88,7 +88,7 @@ func NewUser(w http.ResponseWriter, r *http.Request) { }) if err != nil { - internalServerError(w, "internal server error") + internalServerError(w, r, "internal server error") return } diff --git a/internal/api/zone.go b/internal/api/zone.go index e1512d4..dee1f8a 100644 --- a/internal/api/zone.go +++ b/internal/api/zone.go @@ -60,7 +60,7 @@ func ReceiveFile(w http.ResponseWriter, r *http.Request) { file, header, err := r.FormFile("file") if err != nil { - internalServerError(w, fmt.Sprintf("file upload failed: %v", err)) + internalServerError(w, r, fmt.Sprintf("file upload failed: %v", err)) return } @@ -77,20 +77,20 @@ func ReceiveFile(w http.ResponseWriter, r *http.Request) { name := strings.Split(header.Filename, ".") if _, err = io.Copy(&buf, file); err != nil { - internalServerError(w, "internal server error") + internalServerError(w, r, "internal server error") return } if err = util.MakeLocal(name[0], claims["username"].(string), buf); err != nil { - internalServerError(w, err.Error()) + internalServerError(w, r, err.Error()) return } db, ok := r.Context().Value(keyPrincipalContextID).(*gorm.DB) if !ok { - internalServerError(w, "internal server error") + internalServerError(w, r, "internal server error") return } @@ -115,7 +115,7 @@ func ReceiveFile(w http.ResponseWriter, r *http.Request) { }) if err != nil { - internalServerError(w, "internal server error") + internalServerError(w, r, "internal server error") return } @@ -147,7 +147,7 @@ func ZoneFiles(w http.ResponseWriter, r *http.Request) { err := r.ParseForm() if err != nil { - internalServerError(w, "unable to parse request") + internalServerError(w, r, "unable to parse request") return } @@ -155,14 +155,14 @@ func ZoneFiles(w http.ResponseWriter, r *http.Request) { filename := r.Form.Get("filename") if filename == "" { - internalServerError(w, "no filename parsed") + internalServerError(w, r, "no filename parsed") return } db, ok := r.Context().Value(keyPrincipalContextID).(*gorm.DB) if !ok { - internalServerError(w, "internal server error") + internalServerError(w, r, "internal server error") return } @@ -175,7 +175,7 @@ func ZoneFiles(w http.ResponseWriter, r *http.Request) { }).First(&result) if result == (internal.ZoneRequest{}) { - internalServerError(w, "internal server error") + internalServerError(w, r, "internal server error") return } @@ -183,7 +183,7 @@ func ZoneFiles(w http.ResponseWriter, r *http.Request) { zoneFile := newZoneRequest(result.RawFileName, claims["username"].(string)) if err := zoneFile.Parse(); err != nil { - internalServerError(w, fmt.Sprintf("unable to parse zonefile: %v", err)) + internalServerError(w, r, fmt.Sprintf("unable to parse zonefile: %v", err)) return } diff --git a/internal/configuration.go b/internal/configuration.go index 189bd67..834794a 100644 --- a/internal/configuration.go +++ b/internal/configuration.go @@ -14,7 +14,6 @@ import ( type User struct { gorm.Model Username string - Password string HashedPassword string } @@ -44,6 +43,8 @@ type Config struct { Server string HashingSecret string Port string + DB string + TestDB string } var config Config diff --git a/internal/db/db.go b/internal/db/db.go index 7a6aa5d..5209b55 100644 --- a/internal/db/db.go +++ b/internal/db/db.go @@ -7,8 +7,8 @@ import ( ) // InitDb is the init function for the database. -func InitDb() *gorm.DB { - db, err := gorm.Open(sqlite.Open("test.sqlite"), &gorm.Config{}) +func InitDb(path string) *gorm.DB { + db, err := gorm.Open(sqlite.Open(path), &gorm.Config{}) if err != nil { panic("failed to connect database") } From 78671549c3c7e15e06f44861db35f23c2efe11ea Mon Sep 17 00:00:00 2001 From: grumbulon Date: Mon, 30 Jan 2023 23:23:35 -0500 Subject: [PATCH 4/5] I <3 TESTS --- internal/api/api.go | 2 +- internal/api/api_test.go | 181 ++++++++++++++++++++++++++++++++++++- internal/api/testhelper.go | 5 + internal/api/zone.go | 9 +- 4 files changed, 192 insertions(+), 5 deletions(-) create mode 100644 internal/api/testhelper.go diff --git a/internal/api/api.go b/internal/api/api.go index b8f3f73..6e92894 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -109,7 +109,7 @@ func API() http.Handler { api.Use(jwtauth.Authenticator) api.With(setDBMiddleware).Post("/upload", ReceiveFile) - api.With(setDBMiddleware).Post("/parse", ZoneFiles) + api.With(setDBMiddleware).Post("/parse", ParseZoneFiles) }) // Open routes diff --git a/internal/api/api_test.go b/internal/api/api_test.go index 44aafcb..970f4c8 100644 --- a/internal/api/api_test.go +++ b/internal/api/api_test.go @@ -1,11 +1,16 @@ package api import ( + "bytes" "encoding/json" + "fmt" "io" + "mime/multipart" "net/http" "net/http/httptest" "net/url" + "os" + "path/filepath" "strings" "testing" "time" @@ -13,6 +18,7 @@ import ( "git.freecumextremist.com/grumbulon/pomme/internal" "git.freecumextremist.com/grumbulon/pomme/internal/db" "github.com/go-chi/chi/v5" + "github.com/go-chi/jwtauth/v5" "github.com/stretchr/testify/assert" "golang.org/x/crypto/bcrypt" ) @@ -26,9 +32,22 @@ type response struct { type accountTest struct { username string password string + token string url string } +func makeTestToken(username string) (tokenString string, err error) { + claim := map[string]interface{}{"username": username, "admin": false} + + jwtauth.SetExpiry(claim, time.Now().Add(time.Hour)) + + if _, tokenString, err = tokenAuth.Encode(claim); err == nil { + return + } + + return "", fmt.Errorf("unable to generate JWT: %w", err) +} + func TestAPI(t *testing.T) { config, err := internal.ReadConfig() if err != nil { @@ -63,7 +82,7 @@ func TestAPI(t *testing.T) { hashedPassword, err := bcrypt.GenerateFromPassword([]byte(tester.password), bcrypt.DefaultCost) if err != nil { - return + assert.NotNil(t, err) } db.Create(&internal.User{Username: tester.username, HashedPassword: string(hashedPassword)}) @@ -71,14 +90,25 @@ func TestAPI(t *testing.T) { tester.TestMakeAccount(t) tester.TestLogin(t) tester.TestLogout(t) + tester.TestUpload(t) } func Init(url string) accountTest { - return accountTest{ - username: autoUname(), + user := autoUname() + + token, err := makeTestToken(user) + if err != nil { + return accountTest{} + } + + test := accountTest{ + username: user, password: "merde", url: url, + token: token, } + + return test } func (a *accountTest) TestMakeAccount(t *testing.T) { @@ -172,3 +202,148 @@ func (a *accountTest) TestLogout(t *testing.T) { assert.Equal(t, http.StatusOK, target.Status) } } + +type expectedValues struct { + response int +} + +func (a *accountTest) TestUpload(t *testing.T) { + testCases := []struct { + name string + file string + contentType string + fileContents []byte + expected expectedValues + }{ + { + name: "Should fail to upload an empty file", + file: "badzonefile", + contentType: "audio/aac", + expected: expectedValues{ + response: http.StatusInternalServerError, + }, + }, + { + name: "Should upload a valid file", + file: "zonefile", + contentType: "multipart/form-data", + fileContents: []byte{}, + expected: expectedValues{ + response: http.StatusCreated, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + var ( + f *os.File + target response + err error + buf = new(bytes.Buffer) + w = multipart.NewWriter(buf) + ) + + switch tc.name { + case "Should fail to upload an empty file": + f, err = os.CreateTemp(".", tc.file) + if err != nil { + assert.NotNil(t, err) + } + default: + f, err = os.CreateTemp(".", "zonefile") + if err != nil { + assert.NotNil(t, err) + } + + if err = os.WriteFile(f.Name(), zonebytes, 0o600); err != nil { + assert.NotNil(t, err) + } + } + + defer os.Remove(f.Name()) //nolint: errcheck + + client := http.Client{} + + part, err := w.CreateFormFile("file", filepath.Base(f.Name())) + if err != nil { + assert.NotNil(t, err) + } + + b, err := os.ReadFile(f.Name()) + if err != nil { + assert.NotNil(t, err) + } + + _, err = part.Write(b) + if err != nil { + assert.NotNil(t, err) + } + + err = w.Close() + if err != nil { + assert.NotNil(t, err) + } + + if req, err := http.NewRequest(http.MethodPost, a.url+`/api/upload`, buf); err == nil { + switch tc.name { + case "Should fail to upload an empty file": + req.Header.Add("Content-Type", tc.contentType) + default: + req.Header.Add("Content-Type", w.FormDataContentType()) + } + + req.Header.Add("Authorization", `Bearer:`+a.token) + req.Header.Add("User-Agent", "pomme-api-test-slave") + + resp, err := client.Do(req) + if err != nil { + assert.NotNil(t, err) + } + + respBody, _ := io.ReadAll(resp.Body) + + err = json.Unmarshal(respBody, &target) + if err != nil { + assert.NotNil(t, err) + } + + assert.Equal(t, tc.expected.response, target.Status) + } + + if tc.name == "Should upload a valid file" { + parse(t, f.Name(), a) + } + }) + } +} + +func parse(t *testing.T, fname string, a *accountTest) { + var target response + + client := http.Client{} + + form := url.Values{} + + form.Add("filename", filepath.Clean(fname)) + + if req, err := http.NewRequest(http.MethodPost, a.url+`/api/parse`, strings.NewReader(form.Encode())); err == nil { + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + req.Header.Add("Authorization", `Bearer:`+a.token) + req.Header.Add("User-Agent", "pomme-api-test-slave") + + resp, err := client.Do(req) + if err != nil { + assert.NotNil(t, err) + } + + respBody, _ := io.ReadAll(resp.Body) + + err = json.Unmarshal(respBody, &target) + if err != nil { + assert.NotNil(t, err) + } + + assert.Equal(t, http.StatusOK, target.Status) + } +} diff --git a/internal/api/testhelper.go b/internal/api/testhelper.go new file mode 100644 index 0000000..858f3a8 --- /dev/null +++ b/internal/api/testhelper.go @@ -0,0 +1,5 @@ +package api + +// you have made a gave mistake opening this file + +var zonebytes []uint8 = []uint8([]byte{0x24, 0x4f, 0x52, 0x49, 0x47, 0x49, 0x4e, 0x20, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0xa, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x33, 0x36, 0x30, 0x30, 0x20, 0x53, 0x4f, 0x41, 0x20, 0x20, 0x20, 0x6e, 0x73, 0x31, 0x2e, 0x70, 0x33, 0x30, 0x2e, 0x64, 0x79, 0x6e, 0x65, 0x63, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x20, 0x28, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7a, 0x6f, 0x6e, 0x65, 0x2d, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x64, 0x79, 0x6e, 0x64, 0x6e, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x20, 0x70, 0x61, 0x72, 0x74, 0x79, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x32, 0x30, 0x31, 0x36, 0x30, 0x37, 0x32, 0x37, 0x30, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x20, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x33, 0x36, 0x30, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x20, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x36, 0x30, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x20, 0x72, 0x65, 0x74, 0x72, 0x79, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x36, 0x30, 0x34, 0x38, 0x30, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3b, 0x20, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x20, 0x74, 0x69, 0x6d, 0x65, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x38, 0x30, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x3b, 0x20, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x20, 0x74, 0x74, 0x6c, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x36, 0x34, 0x30, 0x30, 0x20, 0x4e, 0x53, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x73, 0x31, 0x2e, 0x70, 0x33, 0x30, 0x2e, 0x64, 0x79, 0x6e, 0x65, 0x63, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x36, 0x34, 0x30, 0x30, 0x20, 0x4e, 0x53, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x73, 0x32, 0x2e, 0x70, 0x33, 0x30, 0x2e, 0x64, 0x79, 0x6e, 0x65, 0x63, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x36, 0x34, 0x30, 0x30, 0x20, 0x4e, 0x53, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x73, 0x33, 0x2e, 0x70, 0x33, 0x30, 0x2e, 0x64, 0x79, 0x6e, 0x65, 0x63, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x36, 0x34, 0x30, 0x30, 0x20, 0x4e, 0x53, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x73, 0x34, 0x2e, 0x70, 0x33, 0x30, 0x2e, 0x64, 0x79, 0x6e, 0x65, 0x63, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x33, 0x36, 0x30, 0x30, 0x20, 0x4d, 0x58, 0x20, 0x20, 0x20, 0x20, 0x31, 0x30, 0x20, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x33, 0x36, 0x30, 0x30, 0x20, 0x4d, 0x58, 0x20, 0x20, 0x20, 0x20, 0x32, 0x30, 0x20, 0x76, 0x70, 0x6e, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x33, 0x36, 0x30, 0x30, 0x20, 0x4d, 0x58, 0x20, 0x20, 0x20, 0x20, 0x33, 0x30, 0x20, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x36, 0x30, 0x20, 0x41, 0x20, 0x20, 0x20, 0x20, 0x20, 0x32, 0x30, 0x34, 0x2e, 0x31, 0x33, 0x2e, 0x32, 0x34, 0x38, 0x2e, 0x31, 0x30, 0x36, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x33, 0x36, 0x30, 0x30, 0x20, 0x54, 0x58, 0x54, 0x20, 0x20, 0x20, 0x22, 0x76, 0x3d, 0x73, 0x70, 0x66, 0x31, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x70, 0x66, 0x2e, 0x64, 0x79, 0x6e, 0x65, 0x63, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x20, 0x7e, 0x61, 0x6c, 0x6c, 0x22, 0xa, 0x6d, 0x61, 0x69, 0x6c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x34, 0x34, 0x30, 0x30, 0x20, 0x41, 0x20, 0x20, 0x20, 0x20, 0x20, 0x32, 0x30, 0x34, 0x2e, 0x31, 0x33, 0x2e, 0x32, 0x34, 0x38, 0x2e, 0x31, 0x30, 0x36, 0xa, 0x76, 0x70, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x36, 0x30, 0x20, 0x41, 0x20, 0x20, 0x20, 0x20, 0x20, 0x32, 0x31, 0x36, 0x2e, 0x31, 0x34, 0x36, 0x2e, 0x34, 0x35, 0x2e, 0x32, 0x34, 0x30, 0xa, 0x77, 0x65, 0x62, 0x61, 0x70, 0x70, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x36, 0x30, 0x20, 0x41, 0x20, 0x20, 0x20, 0x20, 0x20, 0x32, 0x31, 0x36, 0x2e, 0x31, 0x34, 0x36, 0x2e, 0x34, 0x36, 0x2e, 0x31, 0x30, 0xa, 0x77, 0x65, 0x62, 0x61, 0x70, 0x70, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x36, 0x30, 0x20, 0x41, 0x20, 0x20, 0x20, 0x20, 0x20, 0x32, 0x31, 0x36, 0x2e, 0x31, 0x34, 0x36, 0x2e, 0x34, 0x36, 0x2e, 0x31, 0x31, 0xa, 0x77, 0x77, 0x77, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x34, 0x33, 0x32, 0x30, 0x30, 0x20, 0x43, 0x4e, 0x41, 0x4d, 0x45, 0x20, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0xa}) diff --git a/internal/api/zone.go b/internal/api/zone.go index dee1f8a..f028623 100644 --- a/internal/api/zone.go +++ b/internal/api/zone.go @@ -13,6 +13,7 @@ import ( "git.freecumextremist.com/grumbulon/pomme/internal" "git.freecumextremist.com/grumbulon/pomme/internal/util" "github.com/go-chi/jwtauth/v5" + "github.com/go-chi/render" "github.com/miekg/dns" "gorm.io/gorm" ) @@ -140,7 +141,7 @@ func ReceiveFile(w http.ResponseWriter, r *http.Request) { // @Security Bearer // // @Router /api/parse [post] -func ZoneFiles(w http.ResponseWriter, r *http.Request) { +func ParseZoneFiles(w http.ResponseWriter, r *http.Request) { var result internal.ZoneRequest _, claims, _ := jwtauth.FromContext(r.Context()) @@ -187,6 +188,12 @@ func ZoneFiles(w http.ResponseWriter, r *http.Request) { return } + + resp := internal.Response{ + Message: "Successfully parsed zonefile", + HTTPResponse: http.StatusOK, + } + render.JSON(w, r, resp) } func newZoneRequest(filename string, user string) *ZoneRequest { From b4af648156fba3753865c7654eb26a6ab09ea06e Mon Sep 17 00:00:00 2001 From: grumbulon Date: Mon, 30 Jan 2023 23:24:44 -0500 Subject: [PATCH 5/5] make test JWT expire in a minute --- internal/api/api_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/api/api_test.go b/internal/api/api_test.go index 970f4c8..a4126f3 100644 --- a/internal/api/api_test.go +++ b/internal/api/api_test.go @@ -39,7 +39,7 @@ type accountTest struct { func makeTestToken(username string) (tokenString string, err error) { claim := map[string]interface{}{"username": username, "admin": false} - jwtauth.SetExpiry(claim, time.Now().Add(time.Hour)) + jwtauth.SetExpiry(claim, time.Now().Add(time.Minute)) if _, tokenString, err = tokenAuth.Encode(claim); err == nil { return