From 994f4ee64ab92c4540e5b5c8cac02461437364ab Mon Sep 17 00:00:00 2001 From: Teajey <21069848+Teajey@users.noreply.github.com> Date: Thu, 21 Nov 2024 09:10:14 +0900 Subject: [PATCH] feat: json login support --- server/api/login.go | 85 +++++++++++++++++++++++++++++++++++++++++ server/main.go | 3 +- server/router/router.go | 7 ++-- server/routing/login.go | 62 ++++-------------------------- 4 files changed, 98 insertions(+), 59 deletions(-) create mode 100644 server/api/login.go diff --git a/server/api/login.go b/server/api/login.go new file mode 100644 index 0000000..4aed299 --- /dev/null +++ b/server/api/login.go @@ -0,0 +1,85 @@ +package api + +import ( + "lishwist/db" + "lishwist/templates" + "log" + + "golang.org/x/crypto/bcrypt" +) + +type LoginProps struct { + GeneralError string + SuccessfulRegistration bool + Username templates.InputProps + Password templates.InputProps +} + +func NewLoginProps(username, password string) *LoginProps { + return &LoginProps{ + Username: templates.InputProps{ + Name: "username", + Required: true, + Value: username, + }, + Password: templates.InputProps{ + Name: "password", + Type: "password", + Required: true, + Value: password, + }, + } +} + +func (p *LoginProps) Validate() (valid bool) { + valid = true + + if !p.Username.Validate() { + valid = false + } + + if !p.Password.Validate() { + valid = false + } + + return +} + +func Login(username, password string) *LoginProps { + props := NewLoginProps(username, password) + + valid := props.Validate() + props.Password.Value = "" + if !valid { + log.Printf("Invalid props: %#v\n", props) + return props + } + + user, err := db.GetUserByName(username) + if err != nil { + log.Printf("Failed to fetch user: %s\n", err) + props.GeneralError = "Username or password invalid" + return props + } + if user == nil { + log.Printf("User not found by name: %q\n", username) + props.GeneralError = "Username or password invalid" + return props + } + + passHash, err := user.GetPassHash() + if err != nil { + log.Println("Failed to get password hash: " + err.Error()) + props.GeneralError = "Something went wrong. Error code: Momo" + return props + } + + err = bcrypt.CompareHashAndPassword(passHash, []byte(password)) + if err != nil { + log.Println("Username or password invalid: " + err.Error()) + props.GeneralError = "Username or password invalid" + return props + } + + return nil +} diff --git a/server/main.go b/server/main.go index d5d280d..8e36c9d 100644 --- a/server/main.go +++ b/server/main.go @@ -14,7 +14,7 @@ import ( func main() { gob.Register(&api.RegisterProps{}) - gob.Register(&routing.LoginProps{}) + gob.Register(&api.LoginProps{}) err := db.Open() if err != nil { @@ -55,6 +55,7 @@ func main() { r.Json.Public.HandleFunc("GET /", routing.NotFoundJson) r.Json.Private.Handle("GET /users", route.ExpectUser(route.UsersJson)) + r.Json.Private.HandleFunc("GET /", routing.NotFoundJson) http.Handle("/", r) diff --git a/server/router/router.go b/server/router/router.go index 27e5fe0..a90662b 100644 --- a/server/router/router.go +++ b/server/router/router.go @@ -2,6 +2,7 @@ package router import ( "net/http" + "strings" "github.com/Teajey/sqlstore" ) @@ -29,10 +30,10 @@ type Router struct { } func (s *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) { - contentType := r.Header.Get("Content-Type") + accept := r.Header.Get("Accept") - switch contentType { - case "application/json": + switch { + case strings.HasPrefix(accept, "application/json"): s.Json.ServeHTTP(w, r) default: s.Html.ServeHTTP(w, r) diff --git a/server/routing/login.go b/server/routing/login.go index 3094a48..27acdea 100644 --- a/server/routing/login.go +++ b/server/routing/login.go @@ -1,40 +1,18 @@ package routing import ( - "lishwist/db" + "encoding/json" + "lishwist/api" sesh "lishwist/session" "lishwist/templates" "log" "net/http" - - "golang.org/x/crypto/bcrypt" ) -type LoginProps struct { - GeneralError string - SuccessfulRegistration bool - Username templates.InputProps - Password templates.InputProps -} - -func NewLoginProps() LoginProps { - return LoginProps{ - Username: templates.InputProps{ - Name: "username", - Required: true, - }, - Password: templates.InputProps{ - Name: "password", - Type: "password", - Required: true, - }, - } -} - func (ctx *Context) Login(w http.ResponseWriter, r *http.Request) { session, _ := ctx.store.Get(r, "lishwist_user") - props := NewLoginProps() + props := api.NewLoginProps("", "") flash, err := sesh.GetFirstFlash(w, r, session, "login_props") if err != nil { @@ -42,7 +20,7 @@ func (ctx *Context) Login(w http.ResponseWriter, r *http.Request) { return } - flashProps, ok := flash.(*LoginProps) + flashProps, ok := flash.(*api.LoginProps) if ok { props.Username.Value = flashProps.Username.Value @@ -74,36 +52,10 @@ func (ctx *Context) LoginPost(w http.ResponseWriter, r *http.Request) { username := r.Form.Get("username") password := r.Form.Get("password") - props := NewLoginProps() - props.Username.Value = username - - user, err := db.GetUserByName(username) - if err != nil { - log.Printf("Failed to fetch user: %s\n", err) - props.GeneralError = "Username or password invalid" - ctx.RedirectWithFlash(w, r, "/", "login_props", &props) - return - } - if user == nil { - log.Printf("User not found by name: %q\n", username) - props.GeneralError = "Username or password invalid" - ctx.RedirectWithFlash(w, r, "/", "login_props", &props) - return - } - - passHash, err := user.GetPassHash() - if err != nil { - log.Println("Failed to get password hash: " + err.Error()) - props.GeneralError = "Something went wrong. Error code: Momo" - ctx.RedirectWithFlash(w, r, "/", "login_props", &props) - return - } - - err = bcrypt.CompareHashAndPassword(passHash, []byte(password)) - if err != nil { - log.Println("Username or password invalid: " + err.Error()) - props.GeneralError = "Username or password invalid" + props := api.Login(username, password) + if props != nil { ctx.RedirectWithFlash(w, r, "/", "login_props", &props) + _ = json.NewEncoder(w).Encode(props) return }