diff --git a/api/api.go b/api/api.go index 07b7328..d4623eb 100644 --- a/api/api.go +++ b/api/api.go @@ -53,7 +53,14 @@ func Start() { r.Use(UserCtx) // Load user r.Get("/", GetUser) }) - r.Post("/new", NewUser) + }) + + r.Route("/login", func(r chi.Router) { + r.Post("/", Login) + }) + + r.Route("/register", func(r chi.Router) { + r.Post("/", NewUser) }) if *routes { diff --git a/api/db.go b/api/db.go index 7cad316..918c17a 100644 --- a/api/db.go +++ b/api/db.go @@ -19,8 +19,29 @@ func dbGetUser(id string) (*User, error) { user := u.(map[string]interface{}) if user["ID"].(string) == id { return &User{ - ID: user["ID"].(string), - Name: user["Name"].(string), + ID: user["ID"].(string), + Name: user["Name"].(string), + Password: user["Password"].(string), + }, nil + } + } + return nil, errors.New("User not found") +} + +func dbGetUserByName(username string) (*User, error) { + data := db.ExecDB("users") + if data == nil { + return nil, errors.New("failed to load users database") + } + + users := data["users"].([]interface{}) + for _, u := range users { + user := u.(map[string]interface{}) + if user["Name"].(string) == username { + return &User{ + ID: user["ID"].(string), + Name: user["Name"].(string), + Password: user["Password"].(string), }, nil } } @@ -133,8 +154,9 @@ func dbAddUser(user *User) error { } dbUser := map[string]interface{}{ - "ID": user.ID, - "Name": user.Name, + "ID": user.ID, + "Name": user.Name, + "Password": user.Password, } users = append(users, dbUser) diff --git a/api/user.go b/api/user.go index 1bac250..ca151c0 100644 --- a/api/user.go +++ b/api/user.go @@ -7,6 +7,7 @@ import ( "github.com/go-chi/chi/v5" "github.com/go-chi/render" "github.com/google/uuid" + "golang.org/x/crypto/bcrypt" ) func UserCtx(next http.Handler) http.Handler { @@ -67,10 +68,17 @@ func NewUser(w http.ResponseWriter, r *http.Request) { } newUserName := r.FormValue("name") + password := r.FormValue("password") + if newUserName == "" || password == "" { + http.Error(w, "Username and password cannot be empty", http.StatusBadRequest) + return + } + hashedPassword, err := hashPassword(password) newUser := User{ - ID: newUserID(), - Name: newUserName, + ID: newUserID(), + Name: newUserName, + Password: hashedPassword, } err = dbAddUser(&newUser) @@ -82,15 +90,54 @@ func NewUser(w http.ResponseWriter, r *http.Request) { render.Render(w, r, NewUserPayloadResponse(&newUser)) } +func Login(w http.ResponseWriter, r *http.Request) { + err := r.ParseMultipartForm(64 << 10) + if err != nil { + http.Error(w, "Unable to parse form", http.StatusBadRequest) + return + } + + username := r.FormValue("name") + password := r.FormValue("password") + if username == "" || password == "" { + http.Error(w, "Username and password cannot be empty", http.StatusBadRequest) + return + } + + user, err := dbGetUserByName(username) + if err != nil { + http.Error(w, "Invalid username or password", http.StatusUnauthorized) + return + } + + err = validatePassword(user.Password, password) + if err != nil { + http.Error(w, "Invalid username or password", http.StatusUnauthorized) + return + } + + w.Write([]byte("Login successful")) +} + func (u *UserPayload) Render(w http.ResponseWriter, r *http.Request) error { return nil } +func hashPassword(password string) (string, error) { + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + return string(hashedPassword), err +} + +func validatePassword(hashedPassword, password string) error { + return bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password)) +} + type userKey struct{} type User struct { - ID string `json:"id"` - Name string `json:"name"` + ID string `json:"id"` + Name string `json:"name"` + Password string `json:"-"` } type UserPayload struct { diff --git a/test_data/users.json b/test_data/users.json index c304e1e..97ed1f9 100644 --- a/test_data/users.json +++ b/test_data/users.json @@ -1,10 +1,12 @@ [ - { - "ID": "user_8d7cd2ed-0aa2-4810-a172-42dd58563a54", - "Name": "duby" - }, - { - "ID": "user_63dac6ad-f255-4af8-a057-4b064a982a84", - "Name": "astolfo" - } + { + "ID": "user_8d7cd2ed-0aa2-4810-a172-42dd58563a54", + "Name": "duby", + "Password": "$2a$10$fYKgHJRgR6hJl9VAAu4HPeeyTbDP3UCxiAxZMMKDL8A0ya0Sdg.pq" + }, + { + "ID": "user_63dac6ad-f255-4af8-a057-4b064a982a84", + "Name": "astolfo", + "Password": "$2a$10$ryzbb6l/hkZH6wwtdLdbYew3R1ug4O3tdHi4581WQHui8JKSPFqSu" + } ] \ No newline at end of file