all repos — quartzgun @ 31f42d90ff01f59f851ed1f63f93b2f83a61ed41

lightweight web framework in go

IndentalUserDB: use RWMutex; update test file; gofmt
Iris Lightshard nilix@nilfm.cc
PGP Signature
-----BEGIN PGP SIGNATURE-----

iQIzBAABCAAdFiEEkFh6dA+k/6CXFXU4O3+8IhROY5gFAmSwiUgACgkQO3+8IhRO
Y5iOSA/9FJzT79ZoD2VHy8Kq7B3aJhTOnClmaXn2QTdbA17nwcuEGdKqOhzXjbfz
0ppy+4s7+a5RCqFyLGeUJmRPtPG4mJp4frnK7brtZmLlrSAszVot2wJKd1CVDQYK
w0zLWr3heLTfdEIByeGE4etLyNfjVWwAeNirn0e/l07Mf8wz5oYuJa8Oh/VrnGEk
6Rj2esfZXzkcJZkwLsuJ94+XZufvIFWzx88dAy9xKUiYHL7DYYbC0dMkV14o4P3w
qKdKpwSvQY+q+9V/rmX9ccDUVnQ4jQIjDFgpWOGVIYeP4EI/S7+LQWYB4FikV7o3
1Ye20EK8uTa//6CHpSHOt1ic7eBflt/+fP/vq6pD3cjXFLuUv0n3CwmZXgI92k24
OG7rqcnTCA5Hz5z561TziD4lyD1q+Ux1f7XURaMmqbIAzbSGQlrijFlmWDpxaSsA
V/P8rRjeFSrZh8CiPWByblXwUe/hISmSLgF1UAy69CE1cc1tlomoj5YMByDzCQCM
Yte3QvnuabF0XA17T59j0g/0RcXiqxtrqGrHJ0EpT3e7LMOBcOnyfc03REJJpNib
qqXW5O+9c5MFp5NohgRo1SMz8CckH+Cyq17TXho+16Wb3UqSEGZ55us2dRGDkAp5
XbbU77hTZJhPepVgNaETD8It7piSvpGg13ErpslOgkb2fQoyPhk=
=qfKe
-----END PGP SIGNATURE-----
commit

31f42d90ff01f59f851ed1f63f93b2f83a61ed41

parent

d456892299486eed4f03edcea2163c63609d873e

4 files changed, 69 insertions(+), 34 deletions(-)

jump to
M auth/auth.goauth/auth.go

@@ -1,8 +1,8 @@

package auth import ( - "net/http" "hacklab.nilfm.cc/quartzgun/cookie" + "net/http" "time" )
M indentalUserDB/indentalUserDB.goindentalUserDB/indentalUserDB.go

@@ -8,16 +8,16 @@ "golang.org/x/crypto/bcrypt"

"hacklab.nilfm.cc/quartzgun/auth" "hacklab.nilfm.cc/quartzgun/cookie" "os" - "strings" "strconv" - "time" + "strings" "sync" + "time" ) type IndentalUserDB struct { Users map[string]*auth.User Basis string - mtx sync.Mutex + mtx sync.RWMutex } func CreateIndentalUserDB(filePath string) *IndentalUserDB {

@@ -36,12 +36,16 @@ }

} func (self *IndentalUserDB) InitiateSession(user string, password string, ttl int) (string, error) { + self.mtx.RLock() if _, exists := self.Users[user]; !exists { + self.mtx.RUnlock() return "", errors.New("User not in DB") } if bcrypt.CompareHashAndPassword([]byte(self.Users[user].Pass), []byte(password)) != nil { + self.mtx.RUnlock() return "", errors.New("Incorrect password") } + self.mtx.RUnlock() sessionId := cookie.GenToken(64) self.mtx.Lock() self.Users[user].Session = sessionId

@@ -54,12 +58,16 @@ return sessionId, nil

} func (self *IndentalUserDB) GrantToken(user, password string, ttl int) (string, error) { + self.mtx.RLock() if _, exists := self.Users[user]; !exists { + self.mtx.RUnlock() return "", errors.New("User not in DB") } if bcrypt.CompareHashAndPassword([]byte(self.Users[user].Pass), []byte(password)) != nil { + self.mtx.RUnlock() return "", errors.New("Incorrect password") } + self.mtx.RUnlock() sessionId := cookie.GenToken(64) self.mtx.Lock() self.Users[user].Session = sessionId

@@ -72,24 +80,30 @@ return base64.StdEncoding.EncodeToString([]byte(user + "\n" + sessionId)), nil

} func (self *IndentalUserDB) ValidateUser(user string, sessionId string) (bool, error) { + self.mtx.RLock() if _, exists := self.Users[user]; !exists { + self.mtx.RUnlock() return false, errors.New("User not in DB") } validated := self.Users[user].Session == sessionId + self.mtx.RUnlock() + // GetData takes RLock expiry, err3 := self.GetData(user, "token_expiry") expiryInt, err4 := strconv.ParseInt(expiry.(string), 10, 64) + self.mtx.RLock() expiryTime := self.Users[user].LastSeen.Add(time.Minute * time.Duration(expiryInt)) + self.mtx.RUnlock() if validated { - if err3 == nil && err4 == nil && time.Now().After(expiryTime) { - self.EndSession(user) - return true, errors.New("Cookie or token expired") - } else { - self.mtx.Lock() - defer self.mtx.Unlock() - self.Users[user].LastSeen = time.Now() - writeDB(self.Basis, self.Users) - } + if err3 == nil && err4 == nil && time.Now().After(expiryTime) { + self.EndSession(user) + return true, errors.New("Cookie or token expired") + } else { + self.mtx.Lock() + defer self.mtx.Unlock() + self.Users[user].LastSeen = time.Now() + writeDB(self.Basis, self.Users) + } } return validated, nil

@@ -100,7 +114,7 @@ data, err := base64.StdEncoding.DecodeString(token)

if err == nil { parts := strings.Split(string(data), "\n") if len(parts) == 2 { - return self.ValidateUser(parts[0], parts[1]) + return self.ValidateUser(parts[0], parts[1]) } } return false, errors.New("Token was not in a valid format: b64(USER\nSESSION)")

@@ -132,12 +146,15 @@ return false, err

} func (self *IndentalUserDB) EndSession(user string) error { + self.mtx.RLock() if _, exists := self.Users[user]; !exists { + self.mtx.RUnlock() return errors.New("User not in DB") } + self.mtx.RUnlock() - self.mtx.Lock() - defer self.mtx.Unlock() + self.mtx.Lock() + defer self.mtx.Unlock() self.Users[user].Session = "" self.Users[user].LastSeen = time.Now() writeDB(self.Basis, self.Users)

@@ -145,24 +162,31 @@ return nil

} func (self *IndentalUserDB) DeleteUser(user string) error { + self.mtx.RLock() if _, exists := self.Users[user]; !exists { + self.mtx.RUnlock() return errors.New("User not in DB") } + self.mtx.RUnlock() - self.mtx.Lock() - defer self.mtx.Unlock() + self.mtx.Lock() + defer self.mtx.Unlock() delete(self.Users, user) writeDB(self.Basis, self.Users) return nil } func (self *IndentalUserDB) ChangePassword(user string, password string, oldPassword string) error { + self.mtx.RLock() if _, exists := self.Users[user]; !exists { + self.mtx.RUnlock() return errors.New("User not in DB") } if bcrypt.CompareHashAndPassword([]byte(self.Users[user].Pass), []byte(oldPassword)) != nil { + self.mtx.RUnlock() return errors.New("Incorrect password") } + self.mtx.RUnlock() hash, _ := bcrypt.GenerateFromPassword([]byte(password), 10) self.mtx.Lock()

@@ -173,60 +197,71 @@ return nil

} func (self *IndentalUserDB) AddUser(user string, password string) error { + self.mtx.RLock() if _, exists := self.Users[user]; exists { + self.mtx.RUnlock() return errors.New("User already in DB") } + self.mtx.RUnlock() hash, _ := bcrypt.GenerateFromPassword([]byte(password), 10) - self.mtx.Lock() - defer self.mtx.Unlock() + self.mtx.Lock() + defer self.mtx.Unlock() self.Users[user] = &auth.User{ Name: user, Pass: string(hash[:]), LastSeen: time.UnixMicro(0), LoginTime: time.UnixMicro(0), Session: "", - Data: map[string]interface{}{}, + Data: map[string]interface{}{}, } writeDB(self.Basis, self.Users) return nil } func (self *IndentalUserDB) GetLastLoginTime(user string) (time.Time, error) { + self.mtx.RLock() + self.mtx.RUnlock() if usr, exists := self.Users[user]; exists { return usr.LoginTime, nil } - + return time.UnixMicro(0), errors.New("User not in DB") } func (self *IndentalUserDB) GetLastTimeSeen(user string) (time.Time, error) { + self.mtx.RLock() + self.mtx.RUnlock() if usr, exists := self.Users[user]; exists { return usr.LastSeen, nil } - + return time.UnixMicro(0), errors.New("User not in DB") } func (self *IndentalUserDB) SetData(user string, key string, value interface{}) error { - + self.mtx.RLock() if _, exists := self.Users[user]; !exists { + self.mtx.RUnlock() return errors.New("User not in DB") } + self.mtx.RUnlock() - self.mtx.Lock() - defer self.mtx.Unlock() + self.mtx.Lock() + defer self.mtx.Unlock() self.Users[user].Data[key] = value writeDB(self.Basis, self.Users) return nil } func (self *IndentalUserDB) GetData(user string, key string) (interface{}, error) { + self.mtx.RLock() + defer self.mtx.RUnlock() if _, usrExists := self.Users[user]; !usrExists { return nil, errors.New("User not in DB") } - + data, exists := self.Users[user].Data[key] if !exists { return nil, errors.New("Key not found in user data")
M middleware/middleware.gomiddleware/middleware.go

@@ -3,11 +3,11 @@

import ( "context" "fmt" - "net/http" "hacklab.nilfm.cc/quartzgun/auth" "hacklab.nilfm.cc/quartzgun/cookie" "hacklab.nilfm.cc/quartzgun/renderer" "hacklab.nilfm.cc/quartzgun/util" + "net/http" "strings" )
M quartzgun_test.goquartzgun_test.go

@@ -3,12 +3,12 @@

import ( "context" "fmt" + "hacklab.nilfm.cc/quartzgun/indentalUserDB" + "hacklab.nilfm.cc/quartzgun/middleware" + "hacklab.nilfm.cc/quartzgun/renderer" + "hacklab.nilfm.cc/quartzgun/router" "html/template" "net/http" - "nilfm.cc/git/quartzgun/indentalUserDB" - "nilfm.cc/git/quartzgun/middleware" - "nilfm.cc/git/quartzgun/renderer" - "nilfm.cc/git/quartzgun/router" "testing" )

@@ -49,8 +49,8 @@ "testData/templates/login.html"))

rtr.Post("/login", middleware.Authorize("/", udb, "/login?tryagain=1", 120)) - rtr.Post("/provision", middleware.Provision(udb, 60)) - rtr.Get("/protected", middleware.Validate(renderer.Template("testData/templates/test.html"), udb, map[string]string{})) + rtr.Post("/provision", middleware.Provision(udb, 60)) + rtr.Get("/protected", middleware.Validate(renderer.Template("testData/templates/test.html"), udb, map[string]string{})) rtr.Get("/", middleware.Protected( renderer.Template(