diff --git a/assets/js/controllers/logout.js b/assets/js/controllers/logout.js new file mode 100644 index 0000000..385570f --- /dev/null +++ b/assets/js/controllers/logout.js @@ -0,0 +1,9 @@ +import { Controller } from "@hotwired/stimulus" + +export default class LogoutController extends Controller { + async logout(ev) { + ev.preventDefault(); + await fetch(`/logout`, { method: 'POST' }); + window.location.href = '/login'; + } +} \ No newline at end of file diff --git a/assets/js/main.js b/assets/js/main.js index a9bcc2a..7cb8e33 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -3,8 +3,10 @@ import { Application } from "@hotwired/stimulus"; import ToastController from "./controllers/toast"; import PostlistController from "./controllers/postlist"; import PosteditController from "./controllers/postedit"; +import LogoutController from "./controllers/logout"; window.Stimulus = Application.start() Stimulus.register("toast", ToastController); Stimulus.register("postlist", PostlistController); Stimulus.register("postedit", PosteditController); +Stimulus.register("logout", LogoutController); diff --git a/handlers/login.go b/handlers/login.go index 291b7ba..d9bfc0c 100644 --- a/handlers/login.go +++ b/handlers/login.go @@ -29,12 +29,21 @@ func (lh *LoginHandler) Login(c fiber.Ctx) error { return nil } +func (lh *LoginHandler) Logout(c fiber.Ctx) error { + sess := session.FromContext(c) + sess.Destroy() + return c.Redirect().To("/login") +} + func (lh *LoginHandler) DoLogin(c fiber.Ctx) error { var req struct { Username string `form:"username"` Password string `form:"password"` LoginChallenge string `form:"_login_challenge"` } + if err := c.Bind().Body(&req); err != nil { + return c.Status(fiber.StatusBadRequest).SendString("Failed to parse request body") + } if req.Username == "" || req.Password == "" { return c.Status(fiber.StatusBadRequest).SendString("Username and password are required") @@ -43,7 +52,7 @@ func (lh *LoginHandler) DoLogin(c fiber.Ctx) error { sess := session.FromContext(c) challenge, _ := sess.Get("_login_challenge").(string) - if challenge == req.LoginChallenge { + if challenge != req.LoginChallenge { return c.Redirect().To("/login") } diff --git a/main.go b/main.go index b3b9ec4..349680e 100644 --- a/main.go +++ b/main.go @@ -2,6 +2,7 @@ package main import ( "context" + "flag" "html" "html/template" "log" @@ -29,6 +30,10 @@ import ( ) func main() { + flagUser := flag.String("user", "", "select user to perform operation on") + flagPasswd := flag.String("passwd", "", "change password for user") + flag.Parse() + cfg, err := config.LoadConfig() if err != nil { log.Fatal(err) @@ -43,9 +48,20 @@ func main() { authSvc := auth.New(dbp) publisherSvc := publisher.New(dbp) publisherQueue := publisher.NewQueue(publisherSvc) - publisherQueue.Start(context.Background()) postService := posts.New(dbp, publisherQueue) + // CLI tools + if *flagPasswd != "" && *flagUser != "" { + user, err := authSvc.SetPassword(context.Background(), *flagUser, *flagPasswd) + if err != nil { + log.Fatal(err) + } + log.Printf("Password changed for user %s\n", user.Username) + return + } + + publisherQueue.Start(context.Background()) + fiberTemplate := fiber_html.New("./views", ".html") fiberTemplate.Funcmap["sub"] = func(x, y int) int { return x - y } fiberTemplate.Funcmap["markdown"] = func() func(s string) template.HTML { @@ -108,7 +124,8 @@ func main() { ph := handlers.PostsHandler{PostService: postService} app.Get("/login", lh.Login) - app.Post("/login", lh.Login) + app.Post("/login", lh.DoLogin) + app.Post("/logout", lh.Logout) siteGroup := app.Group("/sites/:siteID", middleware.AuthUser(authSvc), middleware.RequiresSite(dbp)) diff --git a/services/auth/service.go b/services/auth/service.go index 12417f0..bb958e3 100644 --- a/services/auth/service.go +++ b/services/auth/service.go @@ -34,3 +34,13 @@ func (s *Service) Login(ctx context.Context, username, password string) (models. func (s *Service) GetUser(ctx context.Context, userID int64) (models.User, error) { return s.db.SelectUserByID(ctx, userID) } + +func (s *Service) SetPassword(ctx context.Context, username, password string) (models.User, error) { + user, err := s.db.SelectUserByUsername(ctx, username) + if err != nil { + return models.User{}, err + } + + user.SetPassword(password) + return user, s.db.SaveUser(ctx, &user) +} diff --git a/views/_common/nav.html b/views/_common/nav.html index 6ae9613..8729c09 100644 --- a/views/_common/nav.html +++ b/views/_common/nav.html @@ -18,8 +18,17 @@ --> - - +
diff --git a/views/login/login.html b/views/login/login.html index 5fe8501..62e304a 100644 --- a/views/login/login.html +++ b/views/login/login.html @@ -2,15 +2,15 @@