add nested template support in renderer and IndentalUserDB UserStore implementation

This commit is contained in:
Iris Lightshard 2022-01-07 22:52:37 -07:00
parent b17fa798b7
commit 8179aee263
Signed by: Iris Lightshard
GPG key ID: 3B7FBC22144E6398
5 changed files with 220 additions and 12 deletions

View file

@ -2,12 +2,26 @@ package auth
import (
//nilfm.cc/git/goldbug/cookie
"time"
)
type User struct {
Name string
Pass string
Session string
LoginTime time.Time
LastSeen time.Time
Data map[string]interface{}
}
type UserStore interface {
InitiateSession(user string, sessionId string) error
ValidateUser(user string, password string, sessionId string) (bool, error)
InitiateSession(user string, password string) (string, error)
ValidateUser(user string, sessionId string) (bool, error)
EndSession(user string) error
AddUser(user string, password string) error
DeleteUser(user string) error
ChangePassword(user string, oldPassword string, newPassword string) error
}
func Login(user string, password string, userStore UserStore) (string, error) {

View file

@ -0,0 +1,189 @@
package indentalUserDB
import (
"time"
"nilfm.cc/git/goldbug/cookie"
"nilfm.cc/git/goldbug/auth"
"golang.org/x/crypto/bcrypt"
//"io"
"os"
"strings"
"fmt"
"errors"
)
type IndentalUserDB struct {
Users map[string]*auth.User
Basis string
}
func CreateIndentalUserDB(filePath string) *IndentalUserDB {
u, err := readDB(filePath)
if err == nil {
uMap := map[string]*auth.User{}
for _, usr := range u {
uMap[usr.Name] = usr
}
return &IndentalUserDB{
Users: uMap,
Basis: filePath,
}
} else {
return &IndentalUserDB{
Users: map[string]*auth.User{},
Basis: filePath,
}
}
}
func (self *IndentalUserDB) InitiateSession(user string, password string) (string, error) {
if _, exists := self.Users[user]; !exists {
return "", errors.New("User not in DB")
}
if bcrypt.CompareHashAndPassword([]byte(self.Users[user].Pass), []byte(password)) != nil {
return "", errors.New("Incorrect password")
}
sessionId := cookie.GenToken(64)
self.Users[user].Session = sessionId
writeDB(self.Basis, self.Users)
return sessionId, nil
}
func (self *IndentalUserDB) ValidateUser(user string, sessionId string) (bool, error) {
if _, exists := self.Users[user]; !exists {
return false, errors.New("User not in DB")
}
validated := self.Users[user].Session == sessionId
if validated {
self.Users[user].LastSeen = time.Now()
writeDB(self.Basis, self.Users)
}
return validated, nil
}
func (self *IndentalUserDB) EndSession(user string) error {
if _, exists := self.Users[user]; !exists {
return errors.New("User not in DB")
}
self.Users[user].Session = ""
self.Users[user].LastSeen = time.Now()
writeDB(self.Basis, self.Users)
return nil
}
func (self *IndentalUserDB) DeleteUser(user string) error {
if _, exists := self.Users[user]; !exists {
return errors.New("User not in DB")
}
delete(self.Users, user)
writeDB(self.Basis, self.Users)
return nil
}
func (self *IndentalUserDB) ChangePassword(user string, password string, oldPassword string) error {
if _, exists := self.Users[user]; !exists {
return errors.New("User not in DB")
}
if bcrypt.CompareHashAndPassword([]byte(self.Users[user].Pass), []byte(oldPassword)) != nil {
return errors.New("Incorrect password")
}
hash, _ := bcrypt.GenerateFromPassword([]byte(password), 10)
self.Users[user].Pass = string(hash[:])
writeDB(self.Basis, self.Users)
return nil
}
func (self *IndentalUserDB) AddUser(user string, password string) error{
if _, exists := self.Users[user]; exists {
return errors.New("User already in DB")
}
hash, _ := bcrypt.GenerateFromPassword([]byte(password), 10)
self.Users[user] = &auth.User{
Name: user,
Pass: string(hash[:]),
LastSeen: time.UnixMicro(0),
LoginTime: time.UnixMicro(0),
Session: "",
}
writeDB(self.Basis, self.Users)
return nil;
}
const timeFmt = "2006-01-02T15:04Z"
func readDB(filePath string) (map[string]*auth.User, error) {
f, err := os.ReadFile(filePath)
if err != nil {
return nil, err
}
data := string(f[:])
users := map[string]*auth.User{}
lines := strings.Split(data, "\n")
var name string
var pass string
var session string
var loginTime time.Time
var lastSeen time.Time
procFields := 0
for _, l := range lines {
if !strings.HasPrefix(l, " ") {
name = l
procFields++
} else {
kvp := strings.Split(l, ":")
k := strings.TrimSpace(kvp[0])
v := strings.TrimSpace(kvp[1])
switch k {
case "pass":
pass = v
case "session":
session = v
case "loginTime":
loginTime, _ = time.Parse(timeFmt, v)
case "lastSeen":
lastSeen, _ = time.Parse(timeFmt, v)
}
procFields++
if procFields == 5 {
users[name] = &auth.User{
Name: name,
Pass: pass,
Session: session,
LoginTime: loginTime,
LastSeen: lastSeen,
}
procFields = 0
}
}
}
return users, nil
}
func writeDB(filePath string, users map[string]*auth.User) error {
f, err := os.Create(filePath)
if err != nil {
return err
}
defer f.Close()
for _, user := range users {
f.WriteString(fmt.Sprintf("%s:\n pass: %s\n session: %s\n loginTime: %s\n lastSeen: %s\n",
user.Name,
user.Pass,
user.Session,
user.LoginTime,
user.LastSeen));
}
f.Sync()
return nil
}

View file

@ -7,8 +7,8 @@ import (
"encoding/xml"
)
func Template(t string) http.Handler {
tmpl := template.Must(template.ParseFiles(t))
func Template(t ...string) http.Handler {
tmpl := template.Must(template.ParseFiles(t...))
handlerFunc := func(w http.ResponseWriter, req *http.Request) {
tmpl.Execute(w, req)

View file

@ -10,6 +10,7 @@ import (
"path"
"os"
"errors"
"context"
)
type Router struct {
@ -24,7 +25,6 @@ type Router struct {
StaticPaths map[string]string
}
type Route struct {
path *regexp.Regexp
handlerMap map[string]http.Handler
@ -125,7 +125,7 @@ func (self *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
}
for method, handler := range r.handlerMap {
if method == req.Method {
/* Parse the form and add the params to it */
/* Parse the form and add the params to the context */
req.ParseForm()
ProcessParams(req, params)
/* handle the request! */
@ -142,9 +142,7 @@ func (self *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
*******************/
func ProcessParams(req *http.Request, params map[string]string) {
for key, value := range params {
req.Form.Add(key, value)
}
*req = *req.WithContext(context.WithValue(req.Context(), "params", params))
}
func (self *Route) Match(r *http.Request) map[string]string {
@ -165,8 +163,10 @@ func (self *Route) Match(r *http.Request) map[string]string {
func (self *Router) ErrorPage(w http.ResponseWriter, req *http.Request, code int, errMsg string) {
w.WriteHeader(code)
req.ParseForm()
req.Form.Add("ErrorCode", strconv.Itoa(code))
req.Form.Add("ErrorMessage", errMsg)
params := map[string]string{
"ErrorCode": strconv.Itoa(code),
"ErrorMessage": errMsg,
}
ProcessParams(req, params)
self.Fallback.Execute(w, req)
}

5
userDB.ndtl Normal file
View file

@ -0,0 +1,5 @@
nilix:
pass: $2a$10$.Y59TRn/.qBjT8KwleyrBePsC34EuPzrRlQr014bjEKuLoUCWDMtO
session: eMOrLtCvjo_DTV_NqDLicJOugUALtiCIjdvPuzY@O!TOAAzunOs!jnCvCv#sQFxR
loginTime: 1969-12-31 17:00:00 -0700 MST
lastSeen: 1969-12-31 17:00:00 -0700 MST