// Copyright (c) 2024 Zeni Kim // Use of this source code is governed by MIT-style // license that can be found in the LICENSE file. package utils import ( "crypto/md5" "errors" "fmt" "sync" "time" "encoding/json" "git.smarteching.com/goffee/core" "git.smarteching.com/goffee/cup/models" "gorm.io/gorm" ) type SessionUser struct { mu sync.RWMutex context *core.Context userID uint hashedSessionKey string authenticated bool sessionStart time.Time values map[string]interface{} } // start the struct func (s *SessionUser) Init(c *core.Context) bool { // check session cookie pass := true token := "" s.context = c payload := make(map[string]interface{}) usercookie, err := c.GetCookie() if err != nil { } token = usercookie.Token if token == "" { pass = false } else { payload, err = c.GetJWT().DecodeToken(token) if err != nil { pass = false } else { userID := uint(c.CastToInt(payload["userID"])) userAgent := c.GetUserAgent() hashedCacheKey := CreateAuthTokenHashedCacheKey(userID, userAgent) cachedToken, err := c.GetCache().Get(hashedCacheKey) if err != nil { pass = false } else if cachedToken != token { pass = false } else { var user models.User res := c.GetGorm().Where("id = ?", userID).First(&user) if res.Error != nil && !errors.Is(res.Error, gorm.ErrRecordNotFound) { pass = false } // if have session start the struct if pass { userAgent := c.GetUserAgent() sessionKey := fmt.Sprintf("session%v_%v", userID, userAgent) s.hashedSessionKey = fmt.Sprintf("%v", fmt.Sprintf("%x", md5.Sum([]byte(sessionKey)))) value, err := c.GetCache().Get(s.hashedSessionKey) if err != nil { s.values = make(map[string]interface{}) s.authenticated = true s.userID = userID if len(value) > 0 { err := json.Unmarshal([]byte(value), &s.values) if err != nil { } } else { } } return true } else { s.hashedSessionKey = "" s.authenticated = false s.userID = 0 return false } } } } return false } func (s *SessionUser) Set(key string, value interface{}) error { s.mu.Lock() s.values[key] = value s.mu.Unlock() return s.Save() } func (s *SessionUser) Get(key string) (interface{}, bool) { s.mu.RLock() defer s.mu.RUnlock() val, ok := s.values[key] return val, ok } func (s *SessionUser) Delete(key string) interface{} { s.mu.RLock() v, ok := s.values[key] s.mu.RUnlock() if ok { s.mu.Lock() delete(s.values, key) s.mu.Unlock() } s.Save() return v } func (s *SessionUser) Flush() error { s.mu.Lock() s.values = make(map[string]interface{}) s.mu.Unlock() return s.Save() } func (s *SessionUser) Save() error { var value string s.mu.RLock() if len(s.values) > 0 { buf, err := json.Marshal(&s.values) if err != nil { s.mu.RUnlock() return err } value = string(buf) } s.mu.RUnlock() if len(value) > 0 { s.context.GetCache().Set(s.hashedSessionKey, value) } return nil } func (s *SessionUser) GetUserID() uint { return s.userID }