From 3e6f43b0d358da37fb56db7a4d8026344505b8f6 Mon Sep 17 00:00:00 2001 From: meskio <meskio@sindominio.net> Date: Tue, 13 Oct 2020 13:09:09 +0200 Subject: [PATCH] Use login name and allow changing password --- api/api.go | 1 + api/auth.go | 10 ++--- api/auth_test.go | 4 +- api/member.go | 100 +++++++++++++++++++++++++++++++++++---------- api/member_test.go | 49 +++++++++++++++++----- setup.sh | 4 +- src/SignIn.js | 4 +- 7 files changed, 128 insertions(+), 44 deletions(-) diff --git a/api/api.go b/api/api.go index e072e36..a9f5069 100644 --- a/api/api.go +++ b/api/api.go @@ -42,6 +42,7 @@ func Init(dbPath string, signKey string, r *mux.Router) error { r.HandleFunc("/member", a.authAdmin(a.ListMembers)).Methods("GET") r.HandleFunc("/member", a.authAdmin(a.AddMember)).Methods("POST") r.HandleFunc("/member/me", a.authNum(a.getMemberNum)).Methods("GET") + r.HandleFunc("/member/me", a.authNum(a.UpdateMemberMe)).Methods("PUT") r.HandleFunc("/member/{num:[0-9]+}", a.authAdmin(a.GetMember)).Methods("GET") r.HandleFunc("/member/{num:[0-9]+}", a.authAdmin(a.UpdateMember)).Methods("PUT") r.HandleFunc("/member/{num:[0-9]+}", a.authAdmin(a.DeleteMember)).Methods("DELETE") diff --git a/api/auth.go b/api/auth.go index a31bea5..b6881e7 100644 --- a/api/auth.go +++ b/api/auth.go @@ -13,7 +13,7 @@ import ( ) type creds struct { - Name string `json:"name"` + Login string `json:"login"` Password string `json:"password"` NoExpire bool `json:"noExpire"` } @@ -27,21 +27,21 @@ func (a *api) SignIn(w http.ResponseWriter, req *http.Request) { return } var member Member - err = a.db.Where("name = ?", c.Name).First(&member).Error + err = a.db.Where("login = ?", c.Login).First(&member).Error if err != nil { - log.Printf("Can't locate user %s: %v", c.Name, err) + log.Printf("Can't locate user %s: %v", c.Login, err) w.WriteHeader(http.StatusBadRequest) return } hash := hashPass(c.Password, member.Salt) if subtle.ConstantTimeCompare(hash, member.PassHash) == 0 { - log.Printf("Invalid pass for %s", c.Name) + log.Printf("Invalid pass for %s", c.Login) w.WriteHeader(http.StatusBadRequest) return } - log.Printf("Logged in as %s", c.Name) + log.Printf("Logged in as %s", c.Login) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) diff --git a/api/auth_test.go b/api/auth_test.go index 6f70a08..5c49308 100644 --- a/api/auth_test.go +++ b/api/auth_test.go @@ -21,14 +21,14 @@ func TestSignIn(t *testing.T) { Member Member `json:"member"` } jsonAuth := creds{ - Name: testMemberAdmin.Name, + Login: testMemberAdmin.Login, Password: testMemberAdmin.Password, } resp = tapi.do("POST", "/signin", jsonAuth, &respMember) if resp.StatusCode != http.StatusOK { t.Fatal("Can't sign in:", resp.Status) } - if respMember.Member.Name != testMemberAdmin.Name { + if respMember.Member.Login != testMemberAdmin.Login { t.Fatal("Unexpected member:", respMember) } tapi.token = respMember.Token diff --git a/api/member.go b/api/member.go index 353e92d..2a72b31 100644 --- a/api/member.go +++ b/api/member.go @@ -14,7 +14,8 @@ import ( type Member struct { gorm.Model `json:"-"` Num int `json:"num" gorm:"unique;index"` - Name string `json:"name" gorm:"unique;index"` + Login string `json:"login" gorm:"unique;index"` + Name string `json:"name"` Email string `json:"email"` Phone string `json:"phone"` Balance int `json:"balance"` @@ -23,11 +24,13 @@ type Member struct { Salt []byte `json:"-"` } +type MemberReq struct { + Member + Password string `json:"password"` +} + func (a *api) AddMember(w http.ResponseWriter, req *http.Request) { - var memberReq struct { - Member - Password string `json:"password"` - } + var memberReq MemberReq err := json.NewDecoder(req.Body).Decode(&memberReq) if err != nil { log.Printf("Can't create member: %v", err) @@ -36,8 +39,10 @@ func (a *api) AddMember(w http.ResponseWriter, req *http.Request) { } member := Member{ Num: memberReq.Num, + Login: memberReq.Login, Name: memberReq.Name, Email: memberReq.Email, + Phone: memberReq.Phone, Balance: memberReq.Balance, Role: memberReq.Role, } @@ -122,7 +127,7 @@ func (a *api) DeleteMember(w http.ResponseWriter, req *http.Request) { } func (a *api) UpdateMember(w http.ResponseWriter, req *http.Request) { - var member Member + var member MemberReq err := json.NewDecoder(req.Body).Decode(&member) if err != nil { log.Printf("Can't decode memeber: %v", err) @@ -131,43 +136,94 @@ func (a *api) UpdateMember(w http.ResponseWriter, req *http.Request) { } vars := mux.Vars(req) - var dbMember Member - err = a.db.Where("num = ?", vars["num"]).First(&dbMember).Error + num, err := strconv.Atoi(vars["num"]) + if err != nil { + log.Printf("Invalid member num %s: %v", vars["num"], err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + m, err := a.updateMember(num, member) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { w.WriteHeader(http.StatusNotFound) return } - log.Printf("Can't get member %s: %v", vars["num"], err) + log.Printf("Can't update member %d: %v", num, err) w.WriteHeader(http.StatusInternalServerError) return } - if member.Num != 0 { - dbMember.Num = member.Num - } - if member.Name != "" { - dbMember.Name = member.Name - } - if member.Email != "" { - dbMember.Email = member.Email + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusAccepted) + err = json.NewEncoder(w).Encode(m) + if err != nil { + log.Printf("Can't encode updated memeber: %v", err) + w.WriteHeader(http.StatusInternalServerError) + return } - if member.Balance >= 0 { - dbMember.Balance = member.Balance +} + +func (a *api) UpdateMemberMe(num int, w http.ResponseWriter, req *http.Request) { + var member MemberReq + err := json.NewDecoder(req.Body).Decode(&member) + if err != nil { + log.Printf("Can't decode memeber: %v", err) + w.WriteHeader(http.StatusInternalServerError) + return } - err = a.db.Save(&dbMember).Error + + member.Num = 0 + member.Balance = -1 + m, err := a.updateMember(num, member) if err != nil { - log.Printf("Can't update member %s: %v %v", vars["num"], err, member) + if errors.Is(err, gorm.ErrRecordNotFound) { + w.WriteHeader(http.StatusNotFound) + return + } + log.Printf("Can't update member %d: %v", num, err) w.WriteHeader(http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - err = json.NewEncoder(w).Encode(dbMember) + err = json.NewEncoder(w).Encode(m) if err != nil { log.Printf("Can't encode updated memeber: %v", err) w.WriteHeader(http.StatusInternalServerError) return } } + +func (a *api) updateMember(num int, member MemberReq) (Member, error) { + var dbMember Member + err := a.db.Where("num = ?", num).First(&dbMember).Error + if err != nil { + return dbMember, err + } + + if member.Num != 0 { + dbMember.Num = member.Num + } + if member.Login != "" { + dbMember.Login = member.Login + } + if member.Name != "" { + dbMember.Name = member.Name + } + if member.Email != "" { + dbMember.Email = member.Email + } + if member.Balance >= 0 { + dbMember.Balance = member.Balance + } + if member.Password != "" { + dbMember.PassHash, dbMember.Salt, err = newHashPass(member.Password) + if err != nil { + return dbMember, err + } + } + err = a.db.Save(&dbMember).Error + return dbMember, err +} diff --git a/api/member_test.go b/api/member_test.go index 2712ab4..7758fa4 100644 --- a/api/member_test.go +++ b/api/member_test.go @@ -5,13 +5,11 @@ import ( "testing" ) -var testMember = struct { - Member - Password string `json:"password"` -}{ +var testMember = MemberReq{ Member: Member{ Num: 10, - Name: "foo", + Login: "foo", + Name: "Foo Baz", Email: "foo@example.com", Role: "", Balance: 10000, @@ -19,13 +17,11 @@ var testMember = struct { Password: "password", } -var testMemberAdmin = struct { - Member - Password string `json:"password"` -}{ +var testMemberAdmin = MemberReq{ Member: Member{ Num: 20, - Name: "bar", + Login: "bar", + Name: "Bar Baz", Email: "bar@example.com", Role: "admin", Balance: 15000, @@ -47,7 +43,7 @@ func TestMemberAddList(t *testing.T) { if len(members) != 2 { t.Fatal("Wrong number of members", len(members), members) } - if members[0].Name != "foo" { + if members[0].Name != testMember.Name { t.Error("Wrong name:", members[0].Name) } if members[0].Email != "foo@example.com" { @@ -106,6 +102,37 @@ func TestMemberUpdate(t *testing.T) { } } +func TestMemberUpdateMe(t *testing.T) { + tapi := newTestAPI(t) + defer tapi.close() + + tapi.addTestMember() + member := testMember + member.Password = "foobar" + member.Email = "other@example.com" + resp := tapi.do("PUT", "/member/me", member, nil) + if resp.StatusCode != http.StatusAccepted { + t.Fatal("Can't update member:", resp.Status) + } + + var gotMember Member + resp = tapi.doAdmin("GET", "/member/10", nil, &gotMember) + if resp.StatusCode != http.StatusOK { + t.Error("Can't find the member:", resp.Status) + } + if gotMember.Email != member.Email { + t.Error("Wrong email:", gotMember) + } + jsonAuth := creds{ + Login: testMember.Login, + Password: member.Password, + } + resp = tapi.do("POST", "/signin", jsonAuth, nil) + if resp.StatusCode != http.StatusOK { + t.Fatal("Can't sign in:", resp.Status) + } +} + func (tapi *testAPI) addTestMember() { resp := tapi.doAdmin("POST", "/member", testMember, nil) if resp.StatusCode != http.StatusCreated { diff --git a/setup.sh b/setup.sh index abace7d..5e3d79b 100755 --- a/setup.sh +++ b/setup.sh @@ -4,8 +4,8 @@ TOKEN="$1" ADDR="localhost:8080" # set up members -curl -H "x-authentication: $TOKEN" -X "POST" -d '{"num": 900, "name": "admin", "email": "admin@example.com", "phone": "654321123", "password": "admin", "role": "admin", "balance": 10000}' $ADDR/api/member -curl -H "x-authentication: $TOKEN" -X "POST" -d '{"num": 901, "name": "socia", "email": "socia@example.com", "phone": "678900123", "password": "socia", "balance": 10000}' $ADDR/api/member +curl -H "x-authentication: $TOKEN" -X "POST" -d '{"num": 900, "login": "admin", "name": "Administradora", "email": "admin@example.com", "phone": "654321123", "password": "admin", "role": "admin", "balance": 10000}' $ADDR/api/member +curl -H "x-authentication: $TOKEN" -X "POST" -d '{"num": 901, "login": "socia", "name": "Socia Aicos", "email": "socia@example.com", "phone": "678900123", "password": "socia", "balance": 10000}' $ADDR/api/member # set up products curl -H "x-authentication: $TOKEN" -X "POST" -d '{"code": 234, "name": "aceite", "price": 1700, "stock": 35}' $ADDR/api/product diff --git a/src/SignIn.js b/src/SignIn.js index 41157b6..8f2dbbb 100644 --- a/src/SignIn.js +++ b/src/SignIn.js @@ -22,7 +22,7 @@ class SignIn extends React.Component { this.setState({ isLoading: true, error: null }); const body = JSON.stringify({ - name: this.state.name, + login: this.state.name, password: this.state.password, noExpire: this.state.noExpire, }); @@ -57,7 +57,7 @@ class SignIn extends React.Component { let form = ( <Form onSubmit={this.onFormSubmit}> <Form.Group> - <Form.Label>Nombre</Form.Label> + <Form.Label>Nombre de acceso</Form.Label> <Form.Control placeholder="Nombre" value={this.state.name} -- GitLab