add nested template support in renderer and IndentalUserDB UserStore implementation
This commit is contained in:
parent
b17fa798b7
commit
8179aee263
5 changed files with 220 additions and 12 deletions
18
auth/auth.go
18
auth/auth.go
|
@ -2,12 +2,26 @@ package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
//nilfm.cc/git/goldbug/cookie
|
//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 {
|
type UserStore interface {
|
||||||
InitiateSession(user string, sessionId string) error
|
InitiateSession(user string, password string) (string, error)
|
||||||
ValidateUser(user string, password string, sessionId string) (bool, error)
|
ValidateUser(user string, sessionId string) (bool, error)
|
||||||
EndSession(user string) 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) {
|
func Login(user string, password string, userStore UserStore) (string, error) {
|
||||||
|
|
189
indentalUserDB/indentalUserDB.go
Normal file
189
indentalUserDB/indentalUserDB.go
Normal 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
|
||||||
|
}
|
|
@ -7,8 +7,8 @@ import (
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Template(t string) http.Handler {
|
func Template(t ...string) http.Handler {
|
||||||
tmpl := template.Must(template.ParseFiles(t))
|
tmpl := template.Must(template.ParseFiles(t...))
|
||||||
|
|
||||||
handlerFunc := func(w http.ResponseWriter, req *http.Request) {
|
handlerFunc := func(w http.ResponseWriter, req *http.Request) {
|
||||||
tmpl.Execute(w, req)
|
tmpl.Execute(w, req)
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"os"
|
"os"
|
||||||
"errors"
|
"errors"
|
||||||
|
"context"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Router struct {
|
type Router struct {
|
||||||
|
@ -24,7 +25,6 @@ type Router struct {
|
||||||
StaticPaths map[string]string
|
StaticPaths map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type Route struct {
|
type Route struct {
|
||||||
path *regexp.Regexp
|
path *regexp.Regexp
|
||||||
handlerMap map[string]http.Handler
|
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 {
|
for method, handler := range r.handlerMap {
|
||||||
if method == req.Method {
|
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()
|
req.ParseForm()
|
||||||
ProcessParams(req, params)
|
ProcessParams(req, params)
|
||||||
/* handle the request! */
|
/* 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) {
|
func ProcessParams(req *http.Request, params map[string]string) {
|
||||||
for key, value := range params {
|
*req = *req.WithContext(context.WithValue(req.Context(), "params", params))
|
||||||
req.Form.Add(key, value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Route) Match(r *http.Request) map[string]string {
|
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) {
|
func (self *Router) ErrorPage(w http.ResponseWriter, req *http.Request, code int, errMsg string) {
|
||||||
w.WriteHeader(code)
|
w.WriteHeader(code)
|
||||||
req.ParseForm()
|
params := map[string]string{
|
||||||
req.Form.Add("ErrorCode", strconv.Itoa(code))
|
"ErrorCode": strconv.Itoa(code),
|
||||||
req.Form.Add("ErrorMessage", errMsg)
|
"ErrorMessage": errMsg,
|
||||||
|
}
|
||||||
|
ProcessParams(req, params)
|
||||||
self.Fallback.Execute(w, req)
|
self.Fallback.Execute(w, req)
|
||||||
}
|
}
|
||||||
|
|
5
userDB.ndtl
Normal file
5
userDB.ndtl
Normal 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
|
Loading…
Reference in a new issue