From 8c640f7b6b35e5a7721265bb63ffd627e35d5f16 Mon Sep 17 00:00:00 2001 From: Bronku Date: Wed, 6 Aug 2025 19:24:23 +0200 Subject: [PATCH] simpler --- auth/auth.go | 84 --------------------------------------- auth/get.go | 17 -------- auth/session.go | 81 ------------------------------------- auth/templates/login.html | 16 -------- config.default.toml | 5 --- crypto/crypto.go | 25 ------------ go.mod | 2 - go.sum | 4 -- logging/error.go | 13 ------ logging/logger.go | 15 ------- main.go | 38 +----------------- server/template.go | 9 ++--- store/store.go | 31 +++++++++++++++ 13 files changed, 37 insertions(+), 303 deletions(-) delete mode 100644 auth/auth.go delete mode 100644 auth/get.go delete mode 100644 auth/session.go delete mode 100644 auth/templates/login.html delete mode 100644 crypto/crypto.go delete mode 100644 logging/error.go delete mode 100644 logging/logger.go create mode 100644 store/store.go diff --git a/auth/auth.go b/auth/auth.go deleted file mode 100644 index b711692..0000000 --- a/auth/auth.go +++ /dev/null @@ -1,84 +0,0 @@ -package auth - -import ( - "errors" - "log" - "net/http" - "time" - - "github.com/Bronku/iroon/crypto" - "github.com/Bronku/iroon/models" - "gorm.io/gorm" -) - -type Config struct { - SessionExpiration time.Duration -} - -type Authenticator struct { - db *gorm.DB - config Config -} - -func New(db *gorm.DB, config Config) Authenticator { - err := db.AutoMigrate(&models.User{}, &models.Token{}) - if err != nil { - log.Fatal("failed to initialize authenticator", err) - } - return Authenticator{db, config} -} - -var ErrUserNotFound = errors.New("user with this login doesn't exist") -var ErrWrongCredentials = errors.New("wrong credentials") - -// #todo only used once, maybe remove it entirely later -func (a *Authenticator) verifyCredentials(login, password string) error { - var user models.User - - result := a.db.First(&user, "login = ?", login) - if result.Error != nil { - return ErrUserNotFound - } - - hash := crypto.PasswordHash(password, user.Salt) - if hash == user.Password { - return nil - } - - return ErrWrongCredentials -} - -func (a *Authenticator) Middleware(inner http.Handler) http.Handler { - handler := http.NewServeMux() - handler.HandleFunc("GET /login", getLogin) - handler.HandleFunc("POST /login", a.login) - handler.HandleFunc("GET /logout", a.logout) - handler.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - _, err := a.getSession(r) - if err != nil { - http.Redirect(w, r, "/login", http.StatusSeeOther) - return - } - inner.ServeHTTP(w, r) - }) - - return handler -} - -var ErrUsernameTaken = errors.New("username taken") - -func (a *Authenticator) AddUser(login, password string) error { - var user models.User - - result := a.db.First(&user, "login = ?", login) - if !errors.Is(result.Error, gorm.ErrRecordNotFound) { - return ErrUsernameTaken - } - - salt := crypto.GenerateKey() - hash := crypto.PasswordHash(password, salt) - - result = a.db.Save(&models.User{Login: login, Password: hash, Salt: salt}) - - return result.Error -} diff --git a/auth/get.go b/auth/get.go deleted file mode 100644 index 07621a4..0000000 --- a/auth/get.go +++ /dev/null @@ -1,17 +0,0 @@ -package auth - -import ( - "fmt" - "net/http" - - _ "embed" -) - -//go:embed templates/login.html -var loginHTML string - -// returns a simple login page -func getLogin(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("content-type", "text/html") - _, _ = fmt.Fprint(w, loginHTML) -} diff --git a/auth/session.go b/auth/session.go deleted file mode 100644 index 175afa3..0000000 --- a/auth/session.go +++ /dev/null @@ -1,81 +0,0 @@ -package auth - -import ( - "errors" - "net/http" - "time" - - "github.com/Bronku/iroon/crypto" - "github.com/Bronku/iroon/models" -) - -var ErrNoCookie = errors.New("session cookie not found") -var ErrSessionNotFound = errors.New("session not found") -var ErrSessionExpired = errors.New("session has expired") - -func (a *Authenticator) getSession(r *http.Request) (models.Token, error) { - cookie, err := r.Cookie("token") - if err != nil { - return models.Token{}, ErrNoCookie - } - var session models.Token - result := a.db.First(&session, "token = ?", cookie.Value) - if result.Error != nil { - return models.Token{}, ErrSessionNotFound - } - if time.Since(session.Expiration) > 0 { - a.db.Delete(&session) - return models.Token{}, ErrSessionExpired - } - return session, nil -} - -func (a *Authenticator) login(w http.ResponseWriter, r *http.Request) { - _ = r.ParseForm() - login := r.PostFormValue("login") - password := r.PostFormValue("password") - if a.verifyCredentials(login, password) != nil { - http.Redirect(w, r, "/login", http.StatusSeeOther) - return - } - cookie := a.newSession(login) - http.SetCookie(w, &cookie) - http.Redirect(w, r, "/", http.StatusFound) -} - -func (a *Authenticator) logout(w http.ResponseWriter, r *http.Request) { - cookie := http.Cookie{ - Name: "Token", - Value: "nil", - HttpOnly: true, - SameSite: http.SameSiteStrictMode, - Path: "/", - } - http.SetCookie(w, &cookie) - http.Redirect(w, r, "/", http.StatusFound) - c, err := r.Cookie("token") - if err != nil { - return - } - a.db.Delete(&models.Token{}, c.Value) -} - -func (a *Authenticator) newSession(user string) http.Cookie { - key := crypto.GenerateKey() - session := models.Token{ - User: user, - Expiration: time.Now().Add(a.config.SessionExpiration), - Token: key, - } - a.db.Create(&session) - - cookie := http.Cookie{ - Name: "token", - Value: key, - HttpOnly: true, - SameSite: http.SameSiteStrictMode, - Path: "/", - // Secure: true, #todo - } - return cookie -} diff --git a/auth/templates/login.html b/auth/templates/login.html deleted file mode 100644 index b92c576..0000000 --- a/auth/templates/login.html +++ /dev/null @@ -1,16 +0,0 @@ -
-

Login

-
-
-
- - - - - -
-
diff --git a/config.default.toml b/config.default.toml index 712f569..6216c16 100644 --- a/config.default.toml +++ b/config.default.toml @@ -1,11 +1,6 @@ [Database] File = "foo.db" -[Authentication] -DefaultLogin = "admin" -DefaultPassword = "secret" -SessionExpiration = "24h" - [Server] Addr = ":8080" ReadHeaderTimeout = "3s" diff --git a/crypto/crypto.go b/crypto/crypto.go deleted file mode 100644 index 7af21d0..0000000 --- a/crypto/crypto.go +++ /dev/null @@ -1,25 +0,0 @@ -package crypto - -import ( - "crypto/rand" - "encoding/base64" - - "golang.org/x/crypto/argon2" -) - -func PasswordHash(password, salt string) string { - var time uint32 = 3 - var memory uint32 = 32 * 1024 - var threads uint8 = 4 - var length uint32 = 32 - - return string(argon2.Key([]byte(password), []byte(salt), time, memory, threads, length)) -} - -func GenerateKey() string { - key := [32]byte{} - // rand.Read always panics when encountering an error, so checking it is pointless, as the program has already panicked - _, _ = rand.Read(key[:]) - - return base64.StdEncoding.EncodeToString(key[:]) -} diff --git a/go.mod b/go.mod index 3a14f02..c48b048 100644 --- a/go.mod +++ b/go.mod @@ -12,8 +12,6 @@ require ( ) require ( - golang.org/x/crypto v0.36.0 - golang.org/x/sys v0.31.0 // indirect gorm.io/driver/sqlite v1.6.0 gorm.io/gorm v1.30.0 ) diff --git a/go.sum b/go.sum index c88890c..8e03882 100644 --- a/go.sum +++ b/go.sum @@ -6,10 +6,6 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ= diff --git a/logging/error.go b/logging/error.go deleted file mode 100644 index a633018..0000000 --- a/logging/error.go +++ /dev/null @@ -1,13 +0,0 @@ -package logging - -import ( - "fmt" - "net/http" -) - -func ErrorPage(err error, status int) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(status) - _, _ = fmt.Fprint(w, err.Error()) - } -} diff --git a/logging/logger.go b/logging/logger.go deleted file mode 100644 index 271a9d9..0000000 --- a/logging/logger.go +++ /dev/null @@ -1,15 +0,0 @@ -package logging - -import ( - "log" - "net/http" - "time" -) - -func Middleware(in http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - start := time.Now() - in.ServeHTTP(w, r) - log.Println(r.Method, r.URL.String(), time.Since(start)) - }) -} diff --git a/main.go b/main.go index 9b11130..984724a 100644 --- a/main.go +++ b/main.go @@ -2,20 +2,12 @@ package main import ( _ "embed" - "errors" "log" "net/http" - "os" "time" - "github.com/Bronku/iroon/auth" - "github.com/Bronku/iroon/logging" - "github.com/Bronku/iroon/models" "github.com/Bronku/iroon/server" "github.com/BurntSushi/toml" - "gorm.io/driver/sqlite" - "gorm.io/gorm" - "gorm.io/gorm/logger" ) type config struct { @@ -23,12 +15,6 @@ type config struct { File string } - Authentication struct { - auth.Config - DefaultLogin string - DefaultPassword string - } - Server struct { Addr string ReadHeaderTimeout time.Duration @@ -51,34 +37,14 @@ func main() { } // load database - newLogger := logger.New( - log.New(os.Stdout, "\r\n", log.LstdFlags), - logger.Config{ - IgnoreRecordNotFoundError: true}, - ) - db, err := gorm.Open(sqlite.Open(conf.Database.File), &gorm.Config{ - Logger: newLogger, - }) + db, err := store.loadStore(conf.Database.File) if err != nil { - log.Fatal("failed to connect database") - } - err = db.AutoMigrate(&models.Order{}, &models.OrderItem{}, &models.Product{}) - if err != nil { - log.Fatal("couldn't migrate database") - } - - // load auth - authenticator := auth.New(db, conf.Authentication.Config) - err = authenticator.AddUser(conf.Authentication.DefaultLogin, conf.Authentication.DefaultPassword) - if err != nil && !errors.Is(err, auth.ErrUsernameTaken) { - log.Println("add user:", err) + log.Panic(err) } // load server h := server.New(db) var handler http.Handler = h - handler = authenticator.Middleware(handler) - handler = logging.Middleware(handler) log.Println("starting server") // start server diff --git a/server/template.go b/server/template.go index 79197ee..189bc99 100644 --- a/server/template.go +++ b/server/template.go @@ -2,11 +2,10 @@ package server import ( "embed" + "fmt" "html/template" "log" "net/http" - - "github.com/Bronku/iroon/logging" ) //go:embed templates/* @@ -28,14 +27,14 @@ func (h *Server) loadTemplates() { func (h *Server) render(fetch fetcher, templateFile string, templateEntry string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - data, code, err := fetch(r) + data, _, err := fetch(r) if err != nil { - logging.ErrorPage(err, code).ServeHTTP(w, r) + fmt.Fprint(w, err) return } err = h.tmpl[templateFile].ExecuteTemplate(w, templateEntry, data) if err != nil { - logging.ErrorPage(err, http.StatusInternalServerError).ServeHTTP(w, r) + fmt.Fprint(w, err) return } w.Header().Set("content-type", "text/html") diff --git a/store/store.go b/store/store.go new file mode 100644 index 0000000..ebf4028 --- /dev/null +++ b/store/store.go @@ -0,0 +1,31 @@ +package store + +import ( + "fmt" + "log" + "os" + + "github.com/Bronku/iroon/models" + "gorm.io/driver/sqlite" + "gorm.io/gorm" + "gorm.io/gorm/logger" +) + +func loadStore(dsn string) (*gorm.DB, error) { + newLogger := logger.New( + log.New(os.Stdout, "\r\n", log.LstdFlags), + logger.Config{ + IgnoreRecordNotFoundError: true}, + ) + db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{ + Logger: newLogger, + }) + if err != nil { + return db, fmt.Errorf("error connecting to database %w", err) + } + err = db.AutoMigrate(&models.Order{}, &models.OrderItem{}, &models.Product{}) + if err != nil { + return db, fmt.Errorf("error migrating database %w", err) + } + return db, nil +}