From 7a3a73f2a7f2498c61c71f3242a0fcd6c56dfb69 Mon Sep 17 00:00:00 2001 From: Grail Finder Date: Sat, 29 Mar 2025 14:09:42 +0300 Subject: Fix: code cleaning --- cmd/start.go | 6 +- internal/handlers/auth.go | 297 ++++++++++++++++++++-------------------- internal/handlers/main.go | 3 - internal/handlers/middleware.go | 137 +++++++++--------- internal/server/router.go | 9 +- pkg/cache/interface.go | 9 -- pkg/cache/main.go | 146 -------------------- 7 files changed, 222 insertions(+), 385 deletions(-) delete mode 100644 pkg/cache/interface.go delete mode 100644 pkg/cache/main.go diff --git a/cmd/start.go b/cmd/start.go index af46d79..429ed8c 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -2,11 +2,9 @@ package cmd import ( "demoon/config" - "demoon/internal/crons" "demoon/internal/database/repos" database "demoon/internal/database/sql" "demoon/internal/server" - "context" "os" "log/slog" @@ -39,8 +37,8 @@ var startCmd = &cobra.Command{ } repo := repos.NewProvider(db.Conn) srv := server.NewServer(cfg, log, repo) - cron := crons.NewCron(context.Background(), repo) - cron.StartCronJobs() + // cron := crons.NewCron(context.Background(), repo) + // cron.StartCronJobs() // listen for new messages srv.Listen() }, diff --git a/internal/handlers/auth.go b/internal/handlers/auth.go index d0ccdff..cdd55d3 100644 --- a/internal/handlers/auth.go +++ b/internal/handlers/auth.go @@ -1,162 +1,167 @@ package handlers import ( - "crypto/hmac" - "crypto/sha256" - "demoon/internal/models" - "demoon/pkg/utils" - "encoding/base64" - "encoding/json" "html/template" "net/http" - "strings" - "time" - - "golang.org/x/crypto/bcrypt" ) +// import ( +// "crypto/hmac" +// "crypto/sha256" +// "demoon/internal/models" +// "demoon/pkg/utils" +// "encoding/base64" +// "encoding/json" +// "html/template" +// "net/http" +// "strings" +// "time" + +// "golang.org/x/crypto/bcrypt" +// ) + func abortWithError(w http.ResponseWriter, msg string) { tmpl := template.Must(template.ParseGlob("components/*.html")) tmpl.ExecuteTemplate(w, "error", msg) } -func (h *Handlers) HandleSignup(w http.ResponseWriter, r *http.Request) { - r.ParseForm() - username := r.PostFormValue("username") - if username == "" { - msg := "username not provided" - h.log.Error(msg) - abortWithError(w, msg) - return - } - password := r.PostFormValue("password") - if password == "" { - msg := "password not provided" - h.log.Error(msg) - abortWithError(w, msg) - return - } - // make sure username does not exists - cleanName := utils.RemoveSpacesFromStr(username) - hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), 8) - // create user in db - now := time.Now() - nextMidnight := time.Date(now.Year(), now.Month(), now.Day(), - 0, 0, 0, 0, time.UTC).Add(time.Hour * 24) - newUser := &models.UserScore{ - Username: cleanName, Password: string(hashedPassword), - BurnTime: nextMidnight, CreatedAt: now, - } - // login user - cookie, err := h.makeCookie(cleanName, r.RemoteAddr) - if err != nil { - h.log.Error("failed to login", "error", err) - abortWithError(w, err.Error()) - return - } - http.SetCookie(w, cookie) - // http.Redirect(w, r, "/", 302) - tmpl, err := template.ParseGlob("components/*.html") - if err != nil { - abortWithError(w, err.Error()) - return - } - tmpl.ExecuteTemplate(w, "main", newUser) -} +// func (h *Handlers) HandleSignup(w http.ResponseWriter, r *http.Request) { +// r.ParseForm() +// username := r.PostFormValue("username") +// if username == "" { +// msg := "username not provided" +// h.log.Error(msg) +// abortWithError(w, msg) +// return +// } +// password := r.PostFormValue("password") +// if password == "" { +// msg := "password not provided" +// h.log.Error(msg) +// abortWithError(w, msg) +// return +// } +// // make sure username does not exists +// cleanName := utils.RemoveSpacesFromStr(username) +// hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), 8) +// // create user in db +// now := time.Now() +// nextMidnight := time.Date(now.Year(), now.Month(), now.Day(), +// 0, 0, 0, 0, time.UTC).Add(time.Hour * 24) +// newUser := &models.UserScore{ +// Username: cleanName, Password: string(hashedPassword), +// BurnTime: nextMidnight, CreatedAt: now, +// } +// // login user +// cookie, err := h.makeCookie(cleanName, r.RemoteAddr) +// if err != nil { +// h.log.Error("failed to login", "error", err) +// abortWithError(w, err.Error()) +// return +// } +// http.SetCookie(w, cookie) +// // http.Redirect(w, r, "/", 302) +// tmpl, err := template.ParseGlob("components/*.html") +// if err != nil { +// abortWithError(w, err.Error()) +// return +// } +// tmpl.ExecuteTemplate(w, "main", newUser) +// } -func (h *Handlers) HandleLogin(w http.ResponseWriter, r *http.Request) { - r.ParseForm() - username := r.PostFormValue("username") - if username == "" { - msg := "username not provided" - h.log.Error(msg) - abortWithError(w, msg) - return - } - password := r.PostFormValue("password") - if password == "" { - msg := "password not provided" - h.log.Error(msg) - abortWithError(w, msg) - return - } - cleanName := utils.RemoveSpacesFromStr(username) - tmpl, err := template.ParseGlob("components/*.html") - if err != nil { - abortWithError(w, err.Error()) - return - } - cookie, err := h.makeCookie(cleanName, r.RemoteAddr) - if err != nil { - h.log.Error("failed to login", "error", err) - abortWithError(w, err.Error()) - return - } - http.SetCookie(w, cookie) - tmpl.ExecuteTemplate(w, "main", nil) -} +// func (h *Handlers) HandleLogin(w http.ResponseWriter, r *http.Request) { +// r.ParseForm() +// username := r.PostFormValue("username") +// if username == "" { +// msg := "username not provided" +// h.log.Error(msg) +// abortWithError(w, msg) +// return +// } +// password := r.PostFormValue("password") +// if password == "" { +// msg := "password not provided" +// h.log.Error(msg) +// abortWithError(w, msg) +// return +// } +// cleanName := utils.RemoveSpacesFromStr(username) +// tmpl, err := template.ParseGlob("components/*.html") +// if err != nil { +// abortWithError(w, err.Error()) +// return +// } +// cookie, err := h.makeCookie(cleanName, r.RemoteAddr) +// if err != nil { +// h.log.Error("failed to login", "error", err) +// abortWithError(w, err.Error()) +// return +// } +// http.SetCookie(w, cookie) +// tmpl.ExecuteTemplate(w, "main", nil) +// } -func (h *Handlers) makeCookie(username string, remote string) (*http.Cookie, error) { - // secret - // Create a new random session token - // sessionToken := xid.New().String() - sessionToken := "token" - expiresAt := time.Now().Add(time.Duration(h.cfg.SessionLifetime) * time.Second) - // Set the token in the session map, along with the session information - session := &models.Session{ - Username: username, - Expiry: expiresAt, - } - cookieName := "session_token" - // hmac to protect cookies - hm := hmac.New(sha256.New, []byte(h.cfg.CookieSecret)) - hm.Write([]byte(cookieName)) - hm.Write([]byte(sessionToken)) - signature := hm.Sum(nil) - // b64 enc to avoid non-ascii - cookieValue := base64.URLEncoding.EncodeToString([]byte( - string(signature) + sessionToken)) - cookie := &http.Cookie{ - Name: cookieName, - Value: cookieValue, - Secure: true, - HttpOnly: true, - SameSite: http.SameSiteNoneMode, - Domain: h.cfg.ServerConfig.Host, - } - h.log.Info("check remote addr for cookie set", - "remote", remote, "session", session) - if strings.Contains(remote, "192.168.0") { - // no idea what is going on - cookie.Domain = "192.168.0.101" - } - // set ctx? - // set user in session - if err := h.cacheSetSession(sessionToken, session); err != nil { - return nil, err - } - return cookie, nil -} +// func (h *Handlers) makeCookie(username string, remote string) (*http.Cookie, error) { +// // secret +// // Create a new random session token +// // sessionToken := xid.New().String() +// sessionToken := "token" +// expiresAt := time.Now().Add(time.Duration(h.cfg.SessionLifetime) * time.Second) +// // Set the token in the session map, along with the session information +// session := &models.Session{ +// Username: username, +// Expiry: expiresAt, +// } +// cookieName := "session_token" +// // hmac to protect cookies +// hm := hmac.New(sha256.New, []byte(h.cfg.CookieSecret)) +// hm.Write([]byte(cookieName)) +// hm.Write([]byte(sessionToken)) +// signature := hm.Sum(nil) +// // b64 enc to avoid non-ascii +// cookieValue := base64.URLEncoding.EncodeToString([]byte( +// string(signature) + sessionToken)) +// cookie := &http.Cookie{ +// Name: cookieName, +// Value: cookieValue, +// Secure: true, +// HttpOnly: true, +// SameSite: http.SameSiteNoneMode, +// Domain: h.cfg.ServerConfig.Host, +// } +// h.log.Info("check remote addr for cookie set", +// "remote", remote, "session", session) +// if strings.Contains(remote, "192.168.0") { +// // no idea what is going on +// cookie.Domain = "192.168.0.101" +// } +// // set ctx? +// // set user in session +// if err := h.cacheSetSession(sessionToken, session); err != nil { +// return nil, err +// } +// return cookie, nil +// } -func (h *Handlers) cacheGetSession(key string) (*models.Session, error) { - userSessionB, err := h.mc.Get(key) - if err != nil { - return nil, err - } - var us *models.Session - if err := json.Unmarshal(userSessionB, &us); err != nil { - return nil, err - } - return us, nil -} +// func (h *Handlers) cacheGetSession(key string) (*models.Session, error) { +// userSessionB, err := h.mc.Get(key) +// if err != nil { +// return nil, err +// } +// var us *models.Session +// if err := json.Unmarshal(userSessionB, &us); err != nil { +// return nil, err +// } +// return us, nil +// } -func (h *Handlers) cacheSetSession(key string, session *models.Session) error { - sesb, err := json.Marshal(session) - if err != nil { - return err - } - h.mc.Set(key, sesb) - // expire in 10 min - h.mc.Expire(key, 10*60) - return nil -} +// func (h *Handlers) cacheSetSession(key string, session *models.Session) error { +// sesb, err := json.Marshal(session) +// if err != nil { +// return err +// } +// h.mc.Set(key, sesb) +// // expire in 10 min +// h.mc.Expire(key, 10*60) +// return nil +// } diff --git a/internal/handlers/main.go b/internal/handlers/main.go index 960b26d..86f5b09 100644 --- a/internal/handlers/main.go +++ b/internal/handlers/main.go @@ -4,7 +4,6 @@ import ( "demoon/config" "demoon/internal/database/repos" "demoon/internal/models" - "demoon/pkg/cache" "html/template" "log/slog" "net/http" @@ -18,7 +17,6 @@ type Handlers struct { cfg config.Config log *slog.Logger repo repos.FullRepo - mc cache.Cache } // NewHandlers constructor @@ -32,7 +30,6 @@ func NewHandlers( cfg: cfg, log: l, repo: repo, - mc: cache.MemCache, } return h } diff --git a/internal/handlers/middleware.go b/internal/handlers/middleware.go index 8b871a2..242dfb8 100644 --- a/internal/handlers/middleware.go +++ b/internal/handlers/middleware.go @@ -1,75 +1,66 @@ package handlers -import ( - "context" - "crypto/hmac" - "crypto/sha256" - "encoding/base64" - "errors" - "net/http" -) - -func (h *Handlers) GetSession(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - cookieName := "session_token" - sessionCookie, err := r.Cookie(cookieName) - if err != nil { - msg := "auth failed; failed to get session token from cookies" - h.log.Debug(msg, "error", err) - next.ServeHTTP(w, r) - return - } - cookieValueB, err := base64.URLEncoding. - DecodeString(sessionCookie.Value) - if err != nil { - msg := "auth failed; failed to decode b64 cookie" - h.log.Debug(msg, "error", err) - next.ServeHTTP(w, r) - return - } - cookieValue := string(cookieValueB) - if len(cookieValue) < sha256.Size { - h.log.Warn("small cookie", "size", len(cookieValue)) - next.ServeHTTP(w, r) - return - } - // Split apart the signature and original cookie value. - signature := cookieValue[:sha256.Size] - sessionToken := cookieValue[sha256.Size:] - //verify signature - mac := hmac.New(sha256.New, []byte(h.cfg.CookieSecret)) - mac.Write([]byte(cookieName)) - mac.Write([]byte(sessionToken)) - expectedSignature := mac.Sum(nil) - if !hmac.Equal([]byte(signature), expectedSignature) { - h.log.Debug("cookie with an invalid sign") - next.ServeHTTP(w, r) - return - } - userSession, err := h.cacheGetSession(sessionToken) - if err != nil { - msg := "auth failed; session does not exists" - err = errors.New(msg) - h.log.Debug(msg, "error", err) - next.ServeHTTP(w, r) - return - } - if userSession.IsExpired() { - h.mc.RemoveKey(sessionToken) - msg := "session is expired" - h.log.Debug(msg, "error", err, "token", sessionToken) - next.ServeHTTP(w, r) - return - } - ctx := context.WithValue(r.Context(), - "username", userSession.Username) - if err := h.cacheSetSession(sessionToken, - userSession); err != nil { - msg := "failed to marshal user session" - h.log.Warn(msg, "error", err) - next.ServeHTTP(w, r) - return - } - next.ServeHTTP(w, r.WithContext(ctx)) - }) -} +//func (h *Handlers) GetSession(next http.Handler) http.Handler { +// return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +// cookieName := "session_token" +// sessionCookie, err := r.Cookie(cookieName) +// if err != nil { +// msg := "auth failed; failed to get session token from cookies" +// h.log.Debug(msg, "error", err) +// next.ServeHTTP(w, r) +// return +// } +// cookieValueB, err := base64.URLEncoding. +// DecodeString(sessionCookie.Value) +// if err != nil { +// msg := "auth failed; failed to decode b64 cookie" +// h.log.Debug(msg, "error", err) +// next.ServeHTTP(w, r) +// return +// } +// cookieValue := string(cookieValueB) +// if len(cookieValue) < sha256.Size { +// h.log.Warn("small cookie", "size", len(cookieValue)) +// next.ServeHTTP(w, r) +// return +// } +// // Split apart the signature and original cookie value. +// signature := cookieValue[:sha256.Size] +// sessionToken := cookieValue[sha256.Size:] +// //verify signature +// mac := hmac.New(sha256.New, []byte(h.cfg.CookieSecret)) +// mac.Write([]byte(cookieName)) +// mac.Write([]byte(sessionToken)) +// expectedSignature := mac.Sum(nil) +// if !hmac.Equal([]byte(signature), expectedSignature) { +// h.log.Debug("cookie with an invalid sign") +// next.ServeHTTP(w, r) +// return +// } +// userSession, err := h.cacheGetSession(sessionToken) +// if err != nil { +// msg := "auth failed; session does not exists" +// err = errors.New(msg) +// h.log.Debug(msg, "error", err) +// next.ServeHTTP(w, r) +// return +// } +// if userSession.IsExpired() { +// h.mc.RemoveKey(sessionToken) +// msg := "session is expired" +// h.log.Debug(msg, "error", err, "token", sessionToken) +// next.ServeHTTP(w, r) +// return +// } +// ctx := context.WithValue(r.Context(), +// "username", userSession.Username) +// if err := h.cacheSetSession(sessionToken, +// userSession); err != nil { +// msg := "failed to marshal user session" +// h.log.Warn(msg, "error", err) +// next.ServeHTTP(w, r) +// return +// } +// next.ServeHTTP(w, r.WithContext(ctx)) +// }) +//} diff --git a/internal/server/router.go b/internal/server/router.go index 989766c..7034103 100644 --- a/internal/server/router.go +++ b/internal/server/router.go @@ -10,8 +10,9 @@ func (srv *server) ListenToRequests() { h := srv.actions mux := http.NewServeMux() server := &http.Server{ - Addr: fmt.Sprintf("localhost:%s", srv.config.ServerConfig.Port), - Handler: h.GetSession(mux), + Addr: fmt.Sprintf("localhost:%s", srv.config.ServerConfig.Port), + // Handler: h.GetSession(mux), + Handler: mux, ReadTimeout: time.Second * 5, WriteTimeout: time.Second * 5, } @@ -21,8 +22,8 @@ func (srv *server) ListenToRequests() { mux.HandleFunc("GET /ping", h.Ping) mux.HandleFunc("GET /", h.MainPage) - mux.HandleFunc("POST /login", h.HandleLogin) - mux.HandleFunc("POST /signup", h.HandleSignup) + // mux.HandleFunc("POST /login", h.HandleLogin) + // mux.HandleFunc("POST /signup", h.HandleSignup) // ====== elements ====== diff --git a/pkg/cache/interface.go b/pkg/cache/interface.go deleted file mode 100644 index 606f50f..0000000 --- a/pkg/cache/interface.go +++ /dev/null @@ -1,9 +0,0 @@ -package cache - -type Cache interface { - Get(key string) ([]byte, error) - Set(key string, value []byte) - Expire(key string, exp int64) - GetAll() (resp map[string][]byte) - RemoveKey(key string) -} diff --git a/pkg/cache/main.go b/pkg/cache/main.go deleted file mode 100644 index 2aac109..0000000 --- a/pkg/cache/main.go +++ /dev/null @@ -1,146 +0,0 @@ -package cache - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "log/slog" - "os" - "sync" - "time" -) - -const storeFileName = "store.json" - -// var MemCache Cache -var ( - MemCache *MemoryCache - log = slog.New(slog.NewJSONHandler(os.Stdout, nil)) -) - -func readJSON(fileName string) (map[string][]byte, error) { - data := make(map[string][]byte) - file, err := os.Open(fileName) - if err != nil { - return data, err - } - defer file.Close() - decoder := json.NewDecoder(file) - if err := decoder.Decode(&data); err != nil { - return data, err - } - return data, nil -} - -func init() { - data, err := readJSON(storeFileName) - if err != nil { - log.Warn("failed to load store from file", "error", err) - } - MemCache = &MemoryCache{ - data: data, - timeMap: make(map[string]time.Time), - lock: &sync.RWMutex{}, - } - MemCache.StartExpiryRoutine(time.Hour * 24 * 30) - MemCache.StartBackupRoutine(time.Minute) -} - -type MemoryCache struct { - data map[string][]byte - timeMap map[string]time.Time - lock *sync.RWMutex -} - -// Get a value by key from the cache -func (mc *MemoryCache) Get(key string) (value []byte, err error) { - var ok bool - mc.lock.RLock() - if value, ok = mc.data[key]; !ok { - err = fmt.Errorf("not found data in mc for the key: %v", key) - } - mc.lock.RUnlock() - return value, err -} - -// Update a single value in the cache -func (mc *MemoryCache) Set(key string, value []byte) { - // no async writing - mc.lock.Lock() - mc.data[key] = value - mc.lock.Unlock() -} - -func (mc *MemoryCache) Expire(key string, exp int64) { - mc.lock.RLock() - mc.timeMap[key] = time.Now().Add(time.Duration(exp) * time.Second) - mc.lock.RUnlock() -} - -func (mc *MemoryCache) GetAll() (resp map[string][]byte) { - resp = make(map[string][]byte) - mc.lock.RLock() - for k, v := range mc.data { - resp[k] = v - } - mc.lock.RUnlock() - return -} - -func (mc *MemoryCache) GetAllTime() (resp map[string]time.Time) { - resp = make(map[string]time.Time) - mc.lock.RLock() - for k, v := range mc.timeMap { - resp[k] = v - } - mc.lock.RUnlock() - return -} - -func (mc *MemoryCache) RemoveKey(key string) { - mc.lock.RLock() - delete(mc.data, key) - delete(mc.timeMap, key) - mc.lock.RUnlock() -} - -func (mc *MemoryCache) StartExpiryRoutine(n time.Duration) { - ticker := time.NewTicker(n) - go func() { - for { - <-ticker.C - // get all - timeData := mc.GetAllTime() - // check time - currentTS := time.Now() - for k, ts := range timeData { - if ts.Before(currentTS) { - // delete exp keys - mc.RemoveKey(k) - log.Info("remove by expiry", "key", k) - } - } - } - }() -} - -func (mc *MemoryCache) StartBackupRoutine(n time.Duration) { - ticker := time.NewTicker(n) - go func() { - for { - <-ticker.C - // get all - data := mc.GetAll() - jsonString, err := json.Marshal(data) - if err != nil { - log.Warn("failed to marshal kv store", "error", err) - continue - } - err = ioutil.WriteFile(storeFileName, jsonString, os.ModePerm) - if err != nil { - log.Warn("failed to write to json file", "error", err) - continue - } - } - }() -} -- cgit v1.2.3