diff --git a/.gitignore b/.gitignore index c295232..318c9f1 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,5 @@ build/* data/* .bak/* !.gitkeep +.claude/ + diff --git a/backend/pkg/server/auth/auth_middleware.go b/backend/pkg/server/auth/auth_middleware.go index b713731..de26058 100644 --- a/backend/pkg/server/auth/auth_middleware.go +++ b/backend/pkg/server/auth/auth_middleware.go @@ -5,6 +5,7 @@ import ( "fmt" "slices" "strings" + "time" "pentagi/pkg/server/models" "pentagi/pkg/server/response" @@ -104,6 +105,14 @@ func (p *AuthMiddleware) tryUserCookieAuthentication(c *gin.Context) (authResult return authResultFail, errors.New("no pemissions granted") } + expVal, ok := exp.(int64) + if !ok { + return authResultFail, errors.New("token claim invalid") + } + if time.Now().Unix() > expVal { + return authResultFail, errors.New("session expired") + } + c.Set("prm", prms) c.Set("uid", uid.(uint64)) c.Set("uhash", uhash.(string)) diff --git a/backend/pkg/server/services/auth.go b/backend/pkg/server/services/auth.go index a2ac454..53a27d5 100644 --- a/backend/pkg/server/services/auth.go +++ b/backend/pkg/server/services/auth.go @@ -155,6 +155,7 @@ func (s *AuthService) AuthLogin(c *gin.Context) { session.Options(sessions.Options{ HttpOnly: true, Secure: c.Request.TLS != nil, + SameSite: http.SameSiteLaxMode, Path: s.cfg.BaseURL, MaxAge: int(expires), }) @@ -195,6 +196,7 @@ func (s *AuthService) refreshCookie(c *gin.Context, resp *info, privs []string) session.Options(sessions.Options{ HttpOnly: true, Secure: c.Request.TLS != nil, + SameSite: http.SameSiteLaxMode, Path: s.cfg.BaseURL, MaxAge: expires, }) @@ -325,6 +327,12 @@ func (s *AuthService) AuthLoginGetCallback(c *gin.Context) { return } + if queryState := c.Query("state"); queryState != "" && queryState != state.Value { + logger.FromContext(c).Errorf("error matching received state to stored one") + response.Error(c, response.ErrAuthInvalidAuthorizationState, nil) + return + } + stateData, err := s.parseState(c, state.Value) if err != nil { return @@ -546,6 +554,7 @@ func (s *AuthService) authLoginCallback(c *gin.Context, stateData map[string]str session.Options(sessions.Options{ HttpOnly: true, Secure: c.Request.TLS != nil, + SameSite: http.SameSiteLaxMode, Path: s.cfg.BaseURL, MaxAge: expires, }) @@ -597,13 +606,13 @@ func (s *AuthService) parseState(c *gin.Context, state string) (map[string]strin } signatureLen := 32 - stateSignature := stateJSON[:signatureLen] if len(stateJSON) <= signatureLen { logger.FromContext(c).Errorf("error on parsing state from json data") err := fmt.Errorf("unexpected state length") response.Error(c, response.ErrAuthInvalidAuthorizationState, err) return nil, err } + stateSignature := stateJSON[:signatureLen] stateJSON = stateJSON[signatureLen:] mac := hmac.New(sha256.New, s.key) @@ -646,6 +655,7 @@ func (s *AuthService) setCallbackCookie(w http.ResponseWriter, r *http.Request, Value: value, HttpOnly: true, Secure: r.TLS != nil, + SameSite: http.SameSiteLaxMode, Path: path.Join(s.cfg.BaseURL, s.cfg.LoginCallbackURL), MaxAge: maxAge, } @@ -660,6 +670,7 @@ func (s *AuthService) resetSession(c *gin.Context) { session.Options(sessions.Options{ HttpOnly: true, Secure: c.Request.TLS != nil, + SameSite: http.SameSiteLaxMode, Path: s.cfg.BaseURL, MaxAge: -1, }) diff --git a/backend/pkg/server/services/roles.go b/backend/pkg/server/services/roles.go index 7888623..3674524 100644 --- a/backend/pkg/server/services/roles.go +++ b/backend/pkg/server/services/roles.go @@ -63,7 +63,7 @@ func (s *RoleService) GetRoles(c *gin.Context) { rid := c.GetUint64("rid") privs := c.GetStringSlice("prm") scope := func(db *gorm.DB) *gorm.DB { - if !slices.Contains(privs, "roles.view'") { + if !slices.Contains(privs, "roles.view") { return db.Where("role_id = ?", rid) } return db @@ -128,7 +128,7 @@ func (s *RoleService) GetRole(c *gin.Context) { rid := c.GetUint64("rid") privs := c.GetStringSlice("prm") scope := func(db *gorm.DB) *gorm.DB { - if !slices.Contains(privs, "roles.view'") { + if !slices.Contains(privs, "roles.view") { return db.Where("role_id = ?", rid) } return db diff --git a/backend/pkg/server/services/users.go b/backend/pkg/server/services/users.go index 3586a9f..625c575 100644 --- a/backend/pkg/server/services/users.go +++ b/backend/pkg/server/services/users.go @@ -181,7 +181,7 @@ func (s *UserService) GetUsers(c *gin.Context) { uid := c.GetUint64("uid") privs := c.GetStringSlice("prm") scope := func(db *gorm.DB) *gorm.DB { - if !slices.Contains(privs, "users.view'") { + if !slices.Contains(privs, "users.view") { return db.Where("id = ?", uid) } return db @@ -257,7 +257,7 @@ func (s *UserService) GetUser(c *gin.Context) { uhash := c.GetString("uhash") privs := c.GetStringSlice("prm") - if !slices.Contains(privs, "users.view'") && uhash != hash { + if !slices.Contains(privs, "users.view") && uhash != hash { logger.FromContext(c).Errorf("error filtering user role permissions: permission not found") response.Error(c, response.ErrNotPermitted, nil) return @@ -318,7 +318,7 @@ func (s *UserService) CreateUser(c *gin.Context) { rid := c.GetUint64("rid") privs := c.GetStringSlice("prm") - if !slices.Contains(privs, "users.create'") { + if !slices.Contains(privs, "users.create") { logger.FromContext(c).Errorf("error filtering user role permissions: permission not found") response.Error(c, response.ErrNotPermitted, nil) return @@ -423,13 +423,13 @@ func (s *UserService) PatchUser(c *gin.Context) { uhash := c.GetString("uhash") privs := c.GetStringSlice("prm") scope := func(db *gorm.DB) *gorm.DB { - if slices.Contains(privs, "users.edit'") { + if slices.Contains(privs, "users.edit") { return db.Where("hash = ?", hash) } else { return db.Where("hash = ? AND id = ?", hash, uid) } } - if !slices.Contains(privs, "users.edit'") && uhash != hash { + if !slices.Contains(privs, "users.edit") && uhash != hash { logger.FromContext(c).Errorf("error filtering user role permissions: permission not found") response.Error(c, response.ErrNotPermitted, nil) return @@ -510,13 +510,13 @@ func (s *UserService) DeleteUser(c *gin.Context) { uhash := c.GetString("uhash") privs := c.GetStringSlice("prm") scope := func(db *gorm.DB) *gorm.DB { - if slices.Contains(privs, "users.delete'") { + if slices.Contains(privs, "users.delete") { return db.Where("hash = ?", hash) } else { return db.Where("hash = ? AND id = ?", hash, uid) } } - if !slices.Contains(privs, "users.delete'") && uhash != hash { + if !slices.Contains(privs, "users.delete") && uhash != hash { logger.FromContext(c).Errorf("error filtering user role permissions: permission not found") response.Error(c, response.ErrNotPermitted, nil) return diff --git a/backend/pkg/tools/browser.go b/backend/pkg/tools/browser.go index 26f6aee..b2d0bcb 100644 --- a/backend/pkg/tools/browser.go +++ b/backend/pkg/tools/browser.go @@ -422,9 +422,12 @@ func (b *browser) getScreenshot(targetURL string) (string, error) { } func (b *browser) callScraper(url string) ([]byte, error) { - client := &http.Client{Transport: &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - }} + client := &http.Client{ + Timeout: 65 * time.Second, + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }, + } resp, err := client.Get(url) if err != nil { return nil, fmt.Errorf("failed to fetch data by scraper '%s': %w", url, err)