IndentalUserDB: use RWMutex; update test file; gofmt

This commit is contained in:
Iris Lightshard 2023-07-13 17:31:20 -06:00
parent d456892299
commit 31f42d90ff
Signed by: Iris Lightshard
GPG key ID: 3B7FBC22144E6398
4 changed files with 69 additions and 34 deletions

View file

@ -1,8 +1,8 @@
package auth
import (
"net/http"
"hacklab.nilfm.cc/quartzgun/cookie"
"net/http"
"time"
)

View file

@ -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")

View file

@ -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"
)

View file

@ -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(