IndentalUserDB: use RWMutex; update test file; gofmt
This commit is contained in:
parent
d456892299
commit
31f42d90ff
4 changed files with 69 additions and 34 deletions
|
@ -1,8 +1,8 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"hacklab.nilfm.cc/quartzgun/cookie"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
|
|
@ -8,16 +8,16 @@ import (
|
|||
"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 CreateIndentalUserDB(filePath string) *IndentalUserDB {
|
|||
}
|
||||
|
||||
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 @@ func (self *IndentalUserDB) InitiateSession(user string, password string, ttl in
|
|||
}
|
||||
|
||||
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 @@ func (self *IndentalUserDB) GrantToken(user, password string, ttl int) (string,
|
|||
}
|
||||
|
||||
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 @@ func (self *IndentalUserDB) ValidateToken(token string) (bool, error) {
|
|||
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 @@ func (self *IndentalUserDB) ValidateTokenWithScopes(token string, scopes map[str
|
|||
}
|
||||
|
||||
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 @@ func (self *IndentalUserDB) EndSession(user string) error {
|
|||
}
|
||||
|
||||
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 @@ func (self *IndentalUserDB) ChangePassword(user string, password string, oldPass
|
|||
}
|
||||
|
||||
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")
|
||||
|
|
|
@ -3,11 +3,11 @@ package middleware
|
|||
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"
|
||||
)
|
||||
|
||||
|
|
|
@ -3,12 +3,12 @@ package main
|
|||
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 @@ func TestMain(m *testing.M) {
|
|||
|
||||
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(
|
||||
|
|
Loading…
Reference in a new issue