diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index e5c4d46..201d293 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -43,16 +43,12 @@ jobs: - name: Extract metadata (tags, labels) for Docker id: meta - uses: docker/metadata-action@v5.5.1 + uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - tags: | - # set latest tag for master branch - type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'master') }} - - name: Build and push Docker image - uses: docker/build-push-action@v6.0.0 + uses: docker/build-push-action@v6 with: context: . push: true diff --git a/Dockerfile b/Dockerfile index 4869f54..d8a611c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,6 +13,7 @@ RUN go mod download COPY *.go ./ COPY internal ./internal/ +COPY handlers ./handlers/ RUN go build -o /goboard diff --git a/goboard.go b/goboard.go index 93a9708..a1b824a 100644 --- a/goboard.go +++ b/goboard.go @@ -14,11 +14,16 @@ import ( "github.com/gorilla/handlers" "github.com/gorilla/mux" - bolt "go.etcd.io/bbolt" + "go.etcd.io/bbolt" "gopkg.in/yaml.v2" + + admin "github.com/dguihal/goboard/handlers/admin" + backend "github.com/dguihal/goboard/handlers/backend" + template "github.com/dguihal/goboard/handlers/template" + user "github.com/dguihal/goboard/handlers/user" ) -const goBoardVer = 0.03 +const goBoardVer = "0.0.4" // Config holds the configuration of the process type Config struct { @@ -35,23 +40,6 @@ type Config struct { AdminToken string `yaml:"AdminToken"` } -// RESTEndpointHandler defines a handler function for a REST Endpoint -type RESTEndpointHandler func(http.ResponseWriter, *http.Request) - -// SupportedOp Defines a REST endpoint with its path, method and endpoint -type SupportedOp struct { - PathBase string - RestPath string - Method string - handler RESTEndpointHandler -} - -// GoBoardHandler Base Class for endpoint handlers -type GoBoardHandler struct { - Db *bolt.DB - supportedOps []SupportedOp -} - // Command line arguments management var configFilePath string var showHelp bool @@ -120,7 +108,7 @@ func main() { } // Open database - db, err := bolt.Open(config.GoBoardDBFile, config.GoBoardDBFileMode, &bolt.Options{Timeout: 1 * time.Second}) + db, err := bbolt.Open(config.GoBoardDBFile, config.GoBoardDBFileMode, &bbolt.Options{Timeout: 1 * time.Second}) if err != nil { log.Fatalf("error: %v", err) } @@ -130,27 +118,27 @@ func main() { r := mainRouter // Backend operations - backendHandler := NewBackendHandler(config.MaxHistorySize, config.BackendTimeZone) + backendHandler := backend.NewBackendHandler(config.MaxHistorySize, config.BackendTimeZone) backendHandler.Db = db - for _, op := range backendHandler.supportedOps { + for _, op := range backendHandler.SupportedOps { r.Handle(op.RestPath, backendHandler).Methods(op.Method) } // User operations - userHandler := NewUserHandler(config.CookieDuration) + userHandler := user.NewUserHandler(config.CookieDuration) userHandler.Db = db - for _, op := range userHandler.supportedOps { + for _, op := range userHandler.SupportedOps { r.Handle(op.RestPath, userHandler).Methods(op.Method) } // Admin operations - adminHandler := NewAdminHandler(config.AdminToken) + adminHandler := admin.NewAdminHandler(config.AdminToken) adminHandler.Db = db - for _, op := range adminHandler.supportedOps { + for _, op := range adminHandler.SupportedOps { r.Handle(op.RestPath, adminHandler).Methods(op.Method) } - templateHandler := NewTemplateHandler() + templateHandler := template.NewTemplateHandler() // Swagger operations if len(config.SwaggerPath) > 0 { @@ -164,7 +152,7 @@ func main() { } else { templateHandler.SetSwaggerBaseDir(realPath) swaggerOp := templateHandler.GetSwaggerOp() - r.HandleFunc(swaggerOp.RestPath, swaggerOp.handler).Methods(swaggerOp.Method) + r.HandleFunc(swaggerOp.RestPath, swaggerOp.Handler).Methods(swaggerOp.Method) r.PathPrefix("/swagger/").Handler(http.StripPrefix("/swagger/", http.FileServer(http.Dir(realPath)))) r.Handle("/swagger", http.RedirectHandler("/swagger/", http.StatusMovedPermanently)) @@ -181,14 +169,14 @@ func main() { } else if _, err := os.Stat(strings.Join([]string{realPath, "/index.html"}, "")); os.IsNotExist(err) { log.Println(strings.Join([]string{realPath, "/index.html"}, ""), "Not found: Disabling webui capabilities") } else { - templateHandler.setWebUIBaseDir(realPath) + templateHandler.SetWebUIBaseDir(realPath) r.PathPrefix("/webui/").Handler(http.StripPrefix("/webui/", http.FileServer(http.Dir(realPath)))) r.Handle("/webui", http.RedirectHandler("/webui/", http.StatusMovedPermanently)) r.Handle("/", http.RedirectHandler("/webui/", http.StatusMovedPermanently)) } } - fmt.Println("GoBoard version ", goBoardVer, " starting on port", config.ListenPort) + fmt.Println("GoBoard version", goBoardVer, "starting on port", config.ListenPort) var handler http.Handler if fiAccessLog != nil { @@ -228,7 +216,7 @@ func main() { //https://github.com/golang/go/wiki/LearnServerProgramming //https://astaxie.gitbooks.io/build-web-application-with-golang/ -//https://github.com/boltdb/bolt : Backend -//https://github.com/skyec/boltdb-server/blob/master/server.go +//https://github.com/etcd-io/bbolt : Backend +//https://github.com/skyec/boltdb-server : Example //https://blog.golang.org/error-handling-and-go diff --git a/adminhandler.go b/handlers/admin/adminhandler.go similarity index 85% rename from adminhandler.go rename to handlers/admin/adminhandler.go index 615140e..31c81a3 100644 --- a/adminhandler.go +++ b/handlers/admin/adminhandler.go @@ -1,4 +1,4 @@ -package main +package admin import ( "encoding/json" @@ -8,6 +8,7 @@ import ( "strconv" "strings" + "github.com/dguihal/goboard/handlers" goboardbackend "github.com/dguihal/goboard/internal/backend" goboardcookie "github.com/dguihal/goboard/internal/cookie" goboarduser "github.com/dguihal/goboard/internal/user" @@ -19,7 +20,7 @@ const tokenWarnLen int = 12 // AdminHandler represents the handler of admin URLs type AdminHandler struct { - GoBoardHandler + handlers.GoBoardHandler adminToken string } @@ -28,10 +29,10 @@ type AdminHandler struct { func NewAdminHandler(adminToken string) (a *AdminHandler) { a = &AdminHandler{} - a.supportedOps = []SupportedOp{ - {"/admin/user/", "/admin/user/{login}", "DELETE", a.deleteUser}, // Delete a user - {"/admin/user/", "/admin/user/{login}", "GET", a.getUser}, // Get a user info - {"/admin/post/", "/admin/post/{id}", "DELETE", a.deletePost}, // Delete a post + a.SupportedOps = []handlers.SupportedOp{ + {PathBase: "/admin/user/", RestPath: "/admin/user/{login}", Method: "DELETE", Handler: a.deleteUser}, // Delete a user + {PathBase: "/admin/user/", RestPath: "/admin/user/{login}", Method: "GET", Handler: a.getUser}, // Get a user info + {PathBase: "/admin/post/", RestPath: "/admin/post/{id}", Method: "DELETE", Handler: a.deletePost}, // Delete a post } if len(adminToken) <= tokenMinLen { @@ -51,10 +52,10 @@ func (a *AdminHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } - for _, op := range a.supportedOps { + for _, op := range a.SupportedOps { if r.Method == op.Method && strings.HasPrefix(r.URL.Path, op.PathBase) { // Call specific handling method - op.handler(w, r) + op.Handler(w, r) return } } diff --git a/backendhandler.go b/handlers/backend/backendhandler.go similarity index 87% rename from backendhandler.go rename to handlers/backend/backendhandler.go index 1878e5b..aa31fab 100644 --- a/backendhandler.go +++ b/handlers/backend/backendhandler.go @@ -1,4 +1,4 @@ -package main +package backend import ( "bytes" @@ -10,6 +10,7 @@ import ( "strings" "time" + "github.com/dguihal/goboard/handlers" goboardbackend "github.com/dguihal/goboard/internal/backend" goboardcookie "github.com/dguihal/goboard/internal/cookie" "github.com/gorilla/mux" @@ -31,7 +32,7 @@ var knownHeaders = map[string]string{ // BackendHandler represents the handler of backend URLs type BackendHandler struct { - GoBoardHandler + handlers.GoBoardHandler historySize int } @@ -40,12 +41,12 @@ type BackendHandler struct { func NewBackendHandler(historySize int, frontLocation string) (b *BackendHandler) { b = &BackendHandler{} - b.supportedOps = []SupportedOp{ - {"/backend", "/backend", "GET", b.getBackend}, // Get backend (in xml) - {"/backend", "/backend/{format}", "GET", b.getBackend}, // Get backend (in specific format) - {"/post", "/post", "POST", b.post}, // Post new message - {"/post/", "/post/{id}", "GET", b.getPost}, // Get a specific message (in xml) - {"/post/", "/post/{id}/{format}", "GET", b.getPost}, // Get a specific message (in specific format) + b.SupportedOps = []handlers.SupportedOp{ + {PathBase: "/backend", RestPath: "/backend", Method: "GET", Handler: b.getBackend}, // Get backend (in xml) + {PathBase: "/backend", RestPath: "/backend/{format}", Method: "GET", Handler: b.getBackend}, // Get backend (in specific format) + {PathBase: "/post", RestPath: "/post", Method: "POST", Handler: b.post}, // Post new message + {PathBase: "/post/", RestPath: "/post/{id}", Method: "GET", Handler: b.getPost}, // Get a specific message (in xml) + {PathBase: "/post/", RestPath: "/post/{id}/{format}", Method: "GET", Handler: b.getPost}, // Get a specific message (in specific format) } if location, err := time.LoadLocation(frontLocation); err == nil { @@ -61,10 +62,10 @@ func NewBackendHandler(historySize int, frontLocation string) (b *BackendHandler func (b *BackendHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - for _, op := range b.supportedOps { + for _, op := range b.SupportedOps { if r.Method == op.Method && strings.HasPrefix(r.URL.Path, op.PathBase) { // Call specific handling method - op.handler(w, r) + op.Handler(w, r) return } } @@ -114,7 +115,8 @@ func (b *BackendHandler) getBackend(w http.ResponseWriter, r *http.Request) { } // TODO : Manage returning an original posted data for a specific id as text -// Maybe consider allowing this only for admins (not sure it is relevant) +// +// Maybe consider allowing this only for admins (not sure it is relevant) func (b *BackendHandler) getPost(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) @@ -258,6 +260,10 @@ func guessFormat(formatAttr string, acceptHeader string) (format string) { func postsToXML(posts []goboardbackend.Post, backendLocation string) []byte { var b = goboardbackend.Board{} + var outputBuffer bytes.Buffer + + outputBuffer.WriteString("\n") + if (len(backendLocation)) > 0 { b.Site = "http://" + backendLocation } else { @@ -279,7 +285,9 @@ func postsToXML(posts []goboardbackend.Post, backendLocation string) []byte { if err != nil { return []byte(err.Error()) } - return s + outputBuffer.Write(s) + + return outputBuffer.Bytes() } func postsToJSON(posts []goboardbackend.Post) []byte { diff --git a/handlers/goboardhandler.go b/handlers/goboardhandler.go new file mode 100644 index 0000000..e4747b9 --- /dev/null +++ b/handlers/goboardhandler.go @@ -0,0 +1,24 @@ +package handlers + +import ( + "net/http" + + "go.etcd.io/bbolt" +) + +// RESTEndpointHandler defines a handler function for a REST Endpoint +type RESTEndpointHandler func(http.ResponseWriter, *http.Request) + +// SupportedOp Defines a REST endpoint with its path, method and endpoint +type SupportedOp struct { + PathBase string + RestPath string + Method string + Handler RESTEndpointHandler +} + +// GoBoardHandler Base Class for endpoint handlers +type GoBoardHandler struct { + Db *bbolt.DB + SupportedOps []SupportedOp +} diff --git a/templatehandler.go b/handlers/template/templatehandler.go similarity index 86% rename from templatehandler.go rename to handlers/template/templatehandler.go index d44b9f2..410a3f2 100644 --- a/templatehandler.go +++ b/handlers/template/templatehandler.go @@ -1,10 +1,12 @@ -package main +package template import ( "bytes" "html/template" "net/http" "os" + + "github.com/dguihal/goboard/handlers" ) // TemplateHandler represents the handler of swagger URLs @@ -33,12 +35,12 @@ func (s *TemplateHandler) SetSwaggerBaseDir(swaggerBaseDir string) { } // GetSwaggerOp GET swagger content -func (s *TemplateHandler) GetSwaggerOp() SupportedOp { - return SupportedOp{"/swagger/swagger.yaml", "/swagger/swagger.yaml", "GET", s.ServeSwagger} +func (s *TemplateHandler) GetSwaggerOp() handlers.SupportedOp { + return handlers.SupportedOp{PathBase: "/swagger/swagger.yaml", RestPath: "/swagger/swagger.yaml", Method: "GET", Handler: s.ServeSwagger} } // SetSwaggerBaseDir configures webui base dir -func (s *TemplateHandler) setWebUIBaseDir(webuiBaseDir string) { +func (s *TemplateHandler) SetWebUIBaseDir(webuiBaseDir string) { s.webuiBaseDir = http.Dir(webuiBaseDir) s.webuiBaseDirSet = true diff --git a/userhandler.go b/handlers/user/userhandler.go similarity index 82% rename from userhandler.go rename to handlers/user/userhandler.go index f99ab63..b50fc09 100644 --- a/userhandler.go +++ b/handlers/user/userhandler.go @@ -1,4 +1,4 @@ -package main +package user import ( "encoding/json" @@ -7,13 +7,14 @@ import ( "os" "strings" + "github.com/dguihal/goboard/handlers" goboardcookie "github.com/dguihal/goboard/internal/cookie" goboarduser "github.com/dguihal/goboard/internal/user" ) // UserHandler represents the handler of user URLs type UserHandler struct { - GoBoardHandler + handlers.GoBoardHandler cookieDurationD int logger *log.Logger @@ -25,11 +26,11 @@ func NewUserHandler(cookieDuration int) (u *UserHandler) { u.logger = log.New(os.Stdout, "", log.Ldate|log.Ltime|log.Lshortfile) - u.supportedOps = []SupportedOp{ - {"/user/add", "/user/add", "POST", u.addUser}, // Add a user - {"/user/login", "/user/login", "POST", u.authUser}, // Authenticate a user - {"/user/logout", "/user/logout", "GET", u.unAuthUser}, // Unauthenticate a user - {"/user/whoami", "/user/whoami", "GET", u.whoAmI}, // Get self account infos + u.SupportedOps = []handlers.SupportedOp{ + {PathBase: "/user/add", RestPath: "/user/add", Method: "POST", Handler: u.addUser}, // Add a user + {PathBase: "/user/login", RestPath: "/user/login", Method: "POST", Handler: u.authUser}, // Authenticate a user + {PathBase: "/user/logout", RestPath: "/user/logout", Method: "GET", Handler: u.unAuthUser}, // Unauthenticate a user + {PathBase: "/user/whoami", RestPath: "/user/whoami", Method: "GET", Handler: u.whoAmI}, // Get self account infos } u.cookieDurationD = cookieDuration @@ -39,10 +40,10 @@ func NewUserHandler(cookieDuration int) (u *UserHandler) { func (u *UserHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - for _, op := range u.supportedOps { + for _, op := range u.SupportedOps { if r.Method == op.Method && strings.HasPrefix(r.URL.Path, op.PathBase) { // Call specific handling method - op.handler(w, r) + op.Handler(w, r) return } } @@ -51,13 +52,14 @@ func (u *UserHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (u *UserHandler) addUser(w http.ResponseWriter, r *http.Request) { r.ParseForm() - var login, passwd string = "", "" + var login string if login = r.FormValue("login"); len(login) == 0 { w.WriteHeader(http.StatusBadRequest) w.Write([]byte("Login can't be empty")) return } + var passwd string if passwd = r.FormValue("password"); len(passwd) == 0 { w.WriteHeader(http.StatusBadRequest) w.Write([]byte("Password can't be empty")) @@ -68,9 +70,10 @@ func (u *UserHandler) addUser(w http.ResponseWriter, r *http.Request) { if err == nil { // User created : Send him a cookie - if cookie, err := goboardcookie.ForUser(u.Db, login, u.cookieDurationD); err == nil { + var cookie http.Cookie + if cookie, err = goboardcookie.ForUser(u.Db, login, u.cookieDurationD); err == nil { http.SetCookie(w, &cookie) - w.WriteHeader(http.StatusOK) + w.WriteHeader(http.StatusCreated) return } } else { @@ -89,13 +92,14 @@ func (u *UserHandler) addUser(w http.ResponseWriter, r *http.Request) { func (u *UserHandler) authUser(w http.ResponseWriter, r *http.Request) { r.ParseForm() - var login, passwd string = "", "" + var login string if login = r.FormValue("login"); len(login) == 0 { w.WriteHeader(http.StatusBadRequest) w.Write([]byte("Login can't be empty")) return } + var passwd string if passwd = r.FormValue("password"); len(passwd) == 0 { w.WriteHeader(http.StatusBadRequest) w.Write([]byte("Password can't be empty")) @@ -129,8 +133,6 @@ func (u *UserHandler) authUser(w http.ResponseWriter, r *http.Request) { } } - u.logger.Println(cookie) - u.logger.Println(err) if err == nil { http.SetCookie(w, &cookie) w.WriteHeader(http.StatusOK) diff --git a/handlers/user/userhandler_test.go b/handlers/user/userhandler_test.go new file mode 100644 index 0000000..0a6ac48 --- /dev/null +++ b/handlers/user/userhandler_test.go @@ -0,0 +1,127 @@ +package user + +import ( + "net/http" + "net/http/httptest" + "net/url" + "os" + "strings" + "testing" + + "go.etcd.io/bbolt" +) + +type UserTestEnv struct { + DB *bbolt.DB +} + +// setupTestEnv create temporary test env +func setupTestEnv(t *testing.T) (*UserTestEnv, func()) { + tmpFile := "test_auth.db" + db, err := bbolt.Open(tmpFile, 0600, nil) + if err != nil { + t.Fatalf("Erreur d'ouverture BoltDB : %v", err) + } + + // Initialise les buckets nécessaires + err = db.Update(func(tx *bbolt.Tx) error { + _, err := tx.CreateBucketIfNotExists([]byte("users")) + return err + }) + if err != nil { + t.Fatalf("Erreur d'init bucket : %v", err) + } + + env := &UserTestEnv{DB: db} + + // Fonction de nettoyage + cleanup := func() { + db.Close() + os.Remove(tmpFile) + } + + return env, cleanup +} + +func TestUserHandlerWhoami403(t *testing.T) { + + env, cleanup := setupTestEnv(t) + defer cleanup() + + req := httptest.NewRequest(http.MethodGet, "/user/whoami", nil) + + // Response recorder to capture handler's response + rr := httptest.NewRecorder() + + userHandler := NewUserHandler(30) + userHandler.Db = env.DB + + userHandler.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusForbidden { + t.Errorf("Wrong response status code: got %v, expected %v", status, http.StatusForbidden) + } + + expected := "You need to be authenticated" + if rr.Body.String() != expected { + t.Errorf("Wrong response body: got %v, expected %v", rr.Body.String(), expected) + } +} + +func TestUserHandlerRegisterLogin(t *testing.T) { + + env, cleanup := setupTestEnv(t) + defer cleanup() + + // Step 1: Create user + form := url.Values{} + form.Add("login", "alice") + form.Add("password", "secure123") + + userAddReq := httptest.NewRequest(http.MethodPost, "/user/add", strings.NewReader(form.Encode())) + userAddReq.Header.Set("Content-Type", "application/x-www-form-urlencoded") + userAddRes := httptest.NewRecorder() + + userHandler := NewUserHandler(30) + userHandler.Db = env.DB + + userHandler.ServeHTTP(userAddRes, userAddReq) + + if userAddRes.Code != http.StatusCreated { + t.Fatalf("User creation failed: %d - %s", userAddRes.Code, userAddRes.Body.String()) + } + + // Step 2: Authenticate user + loginReq := httptest.NewRequest(http.MethodPost, "/user/login", strings.NewReader(form.Encode())) + loginReq.Header.Set("Content-Type", "application/x-www-form-urlencoded") + loginRes := httptest.NewRecorder() + + userHandler.ServeHTTP(loginRes, loginReq) + + if loginRes.Code != http.StatusOK { + t.Fatalf("Authentification failed: %d - %s", loginRes.Code, loginRes.Body.String()) + } + + // Check cookie in response + cookies := loginRes.Result().Cookies() + found := false + + if len(cookies) == 0 { + t.Fatalf("No cookies returned") + } + + for _, cookie := range cookies { + if cookie.Name == "goboard_id" { + found = true + if cookie.Value == "" { + t.Errorf("Cookie 'goboard_id' present but empty") + } + break + } + } + + if !found { + t.Errorf("Cookie 'goboard_id' not found") + } + +} diff --git a/internal/backend/backend.go b/internal/backend/backend.go index 4600915..9c2f1c0 100644 --- a/internal/backend/backend.go +++ b/internal/backend/backend.go @@ -6,7 +6,7 @@ import ( "time" goboardutils "github.com/dguihal/goboard/internal/utils" - bolt "go.etcd.io/bbolt" + "go.etcd.io/bbolt" ) const backendBucketName string = "Backend" @@ -47,9 +47,9 @@ type Board struct { } // DeletePost is a method for deleting a post from the history -func DeletePost(db *bolt.DB, id uint64) (err error) { +func DeletePost(db *bbolt.DB, id uint64) (err error) { - err = db.Update(func(tx *bolt.Tx) error { + err = db.Update(func(tx *bbolt.Tx) error { b, err := tx.CreateBucketIfNotExists([]byte(backendBucketName)) if err != nil { return err @@ -61,11 +61,11 @@ func DeletePost(db *bolt.DB, id uint64) (err error) { } // GetBackend returns the last posts from the history -func GetBackend(db *bolt.DB, historySize int, last uint64) (posts []Post, err error) { +func GetBackend(db *bbolt.DB, historySize int, last uint64) (posts []Post, err error) { posts = make([]Post, historySize) - err = db.View(func(tx *bolt.Tx) error { + err = db.View(func(tx *bbolt.Tx) error { b := tx.Bucket([]byte(backendBucketName)) if b == nil { @@ -95,11 +95,11 @@ func GetBackend(db *bolt.DB, historySize int, last uint64) (posts []Post, err er } // GetPost returns a post from its id -func GetPost(db *bolt.DB, id uint64) (post Post, err error) { +func GetPost(db *bbolt.DB, id uint64) (post Post, err error) { post = Post{} - err = db.View(func(tx *bolt.Tx) error { + err = db.View(func(tx *bbolt.Tx) error { b := tx.Bucket([]byte(backendBucketName)) if b == nil { @@ -120,9 +120,9 @@ func GetPost(db *bolt.DB, id uint64) (post Post, err error) { } // PostMessage adds a new message to the history -func PostMessage(db *bolt.DB, post Post) (postID uint64, err error) { +func PostMessage(db *bbolt.DB, post Post) (postID uint64, err error) { - err = db.Update(func(tx *bolt.Tx) error { + err = db.Update(func(tx *bbolt.Tx) error { b, err := tx.CreateBucketIfNotExists([]byte(backendBucketName)) if err != nil { return err diff --git a/internal/backend/backendsanitizer.go b/internal/backend/backendsanitizer.go index 56ea612..f0cd1d9 100644 --- a/internal/backend/backendsanitizer.go +++ b/internal/backend/backendsanitizer.go @@ -84,10 +84,10 @@ L: for { tt := z.Next() - switch { - case tt == html.ErrorToken: + switch tt { + case html.ErrorToken: break L - case tt == html.StartTagToken: + case html.StartTagToken: tn, hasAttrs := z.TagName() tnStr := string(tn) @@ -122,7 +122,7 @@ L: txt: sanitizeChars(string(z.Raw())), tokenType: html.TextToken}) } - case tt == html.EndTagToken: + case html.EndTagToken: tn, _ := z.TagName() tnStr := string(tn) diff --git a/internal/cookie/cookie.go b/internal/cookie/cookie.go index 8bdfb93..b4f17d8 100644 --- a/internal/cookie/cookie.go +++ b/internal/cookie/cookie.go @@ -8,7 +8,7 @@ import ( "time" "github.com/dchest/uniuri" - bolt "go.etcd.io/bbolt" + "go.etcd.io/bbolt" ) const goboardCookieName string = "goboard_id" @@ -36,7 +36,7 @@ type UserCookieError struct { func (e *UserCookieError) Error() string { return e.error.Error() } // ForUser returns a valid cookie (already existing or new) for a user -func ForUser(db *bolt.DB, login string, cookieDurationD int) (cookie http.Cookie, err error) { +func ForUser(db *bbolt.DB, login string, cookieDurationD int) (cookie http.Cookie, err error) { if cookie, err = fetchCookieForUser(db, login); err != nil { if ucerr, ok := err.(*UserCookieError); ok { @@ -51,7 +51,7 @@ func ForUser(db *bolt.DB, login string, cookieDurationD int) (cookie http.Cookie } // createAndStoreCookie creates a new cookie and stores it in database -func createAndStoreCookie(db *bolt.DB, login string, cookieDurationD int) (cookie http.Cookie, err error) { +func createAndStoreCookie(db *bbolt.DB, login string, cookieDurationD int) (cookie http.Cookie, err error) { expiration := time.Now().Add(time.Duration(cookieDurationD) * 24 * time.Hour) cookie = http.Cookie{ @@ -72,7 +72,7 @@ func createAndStoreCookie(db *bolt.DB, login string, cookieDurationD int) (cooki return cookie, ucerr } - err = db.Update(func(tx *bolt.Tx) error { + err = db.Update(func(tx *bbolt.Tx) error { b, err := tx.CreateBucketIfNotExists([]byte(usersCookieBucketName)) if err != nil { ucerr := &UserCookieError{error: err, ErrCode: DatabaseError} @@ -96,9 +96,9 @@ func createAndStoreCookie(db *bolt.DB, login string, cookieDurationD int) (cooki } // DeleteCookiesForUser delete stored cookies for user -func DeleteCookiesForUser(db *bolt.DB, login string) (err error) { +func DeleteCookiesForUser(db *bbolt.DB, login string) (err error) { - err = db.Batch(func(tx *bolt.Tx) error { + err = db.Batch(func(tx *bbolt.Tx) error { b, err := tx.CreateBucketIfNotExists([]byte(usersCookieBucketName)) if err != nil { uerr := &UserCookieError{error: err, ErrCode: DatabaseError} @@ -126,11 +126,11 @@ func DeleteCookiesForUser(db *bolt.DB, login string) (err error) { } // fetchCookieForUser retreive a valid stored cookie for a user (if any in database) -func fetchCookieForUser(db *bolt.DB, login string) (cookie http.Cookie, err error) { +func fetchCookieForUser(db *bbolt.DB, login string) (cookie http.Cookie, err error) { cookie = http.Cookie{} - err = db.Update(func(tx *bolt.Tx) error { + err = db.Update(func(tx *bbolt.Tx) error { // Find if non expired cookie already exists b, err := tx.CreateBucketIfNotExists([]byte(usersCookieBucketName)) if err != nil { @@ -174,7 +174,7 @@ func fetchCookieForUser(db *bolt.DB, login string) (cookie http.Cookie, err erro } // LoginForCookie get the user associated with a cookie -func LoginForCookie(db *bolt.DB, cookie *http.Cookie) (login string, err error) { +func LoginForCookie(db *bbolt.DB, cookie *http.Cookie) (login string, err error) { var uc = UserCookie{} login = "" @@ -182,7 +182,7 @@ func LoginForCookie(db *bolt.DB, cookie *http.Cookie) (login string, err error) return } - err = db.View(func(tx *bolt.Tx) error { + err = db.View(func(tx *bbolt.Tx) error { b := tx.Bucket([]byte(usersCookieBucketName)) @@ -201,7 +201,7 @@ func LoginForCookie(db *bolt.DB, cookie *http.Cookie) (login string, err error) login = uc.Login if err == nil && uc.Cookie.Expires.Before(time.Now()) { - err = db.Update(func(tx *bolt.Tx) error { + err = db.Update(func(tx *bbolt.Tx) error { b := tx.Bucket([]byte(usersCookieBucketName)) if b == nil { return nil diff --git a/internal/user/user.go b/internal/user/user.go index dd30b39..8b4fec3 100644 --- a/internal/user/user.go +++ b/internal/user/user.go @@ -6,7 +6,7 @@ import ( "fmt" "time" - bolt "go.etcd.io/bbolt" + "go.etcd.io/bbolt" "golang.org/x/crypto/bcrypt" ) @@ -33,9 +33,9 @@ type User struct { HashedPassword []byte `json:"HashedPassword,omitempty"` } -func AddUser(db *bolt.DB, login string, password string) (uerr error) { +func AddUser(db *bbolt.DB, login string, password string) (uerr error) { - db.Batch(func(tx *bolt.Tx) error { + db.Batch(func(tx *bbolt.Tx) error { b, err := tx.CreateBucketIfNotExists([]byte(usersBucketName)) if err != nil { uerr = &Error{error: err, ErrCode: DatabaseError} @@ -75,9 +75,9 @@ func AddUser(db *bolt.DB, login string, password string) (uerr error) { return } -func AuthUser(db *bolt.DB, login string, password string) (uerr error) { +func AuthUser(db *bbolt.DB, login string, password string) (uerr error) { - db.View(func(tx *bolt.Tx) error { + db.View(func(tx *bbolt.Tx) error { b := tx.Bucket([]byte(usersBucketName)) var v []byte @@ -107,9 +107,9 @@ func AuthUser(db *bolt.DB, login string, password string) (uerr error) { return } -func DeleteUser(db *bolt.DB, login string) (uerr error) { +func DeleteUser(db *bbolt.DB, login string) (uerr error) { - db.Batch(func(tx *bolt.Tx) error { + db.Batch(func(tx *bbolt.Tx) error { b, err := tx.CreateBucketIfNotExists([]byte(usersBucketName)) if err != nil { uerr = &Error{error: err, ErrCode: DatabaseError} @@ -121,11 +121,10 @@ func DeleteUser(db *bolt.DB, login string) (uerr error) { if v == nil { // User does not exists uerr = &Error{error: fmt.Errorf("User does not exists"), ErrCode: UserDoesNotExistsError} return uerr - } else { - if err = b.Delete([]byte(login)); err != nil { - uerr = &Error{error: err, ErrCode: DatabaseError} - return err - } + } + if err = b.Delete([]byte(login)); err != nil { + uerr = &Error{error: err, ErrCode: DatabaseError} + return err } return nil @@ -134,9 +133,9 @@ func DeleteUser(db *bolt.DB, login string) (uerr error) { return } -func GetUser(db *bolt.DB, login string) (user User, uerr error) { +func GetUser(db *bbolt.DB, login string) (user User, uerr error) { - db.View(func(tx *bolt.Tx) error { + db.View(func(tx *bbolt.Tx) error { b := tx.Bucket([]byte(usersBucketName)) var v []byte diff --git a/web/package-lock.json b/web/package-lock.json index 56cbe26..7c28b6d 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,12 +1,12 @@ { "name": "goboard-ui", - "version": "0.0.3", + "version": "0.0.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "goboard-ui", - "version": "0.0.3", + "version": "0.0.4", "hasInstallScript": true, "devDependencies": { "bower": "^1.8.14", diff --git a/web/package.json b/web/package.json index 1ecdf9e..8127ca6 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "goboard-ui", - "version": "0.0.3", + "version": "0.0.4", "private": true, "devDependencies": { "bower": "^1.8.14",