mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-07-12 17:04:21 +00:00
a4df5a08e3
Group-scoped agents could read sessions from other groups via session tools (sessions_list, sessions_history, session_status, sessions_send) because they only checked agent_key, not group context. This caused cron jobs to leak data from unrelated groups into reports. Add isSessionInScope() guard to all 4 session tools with colon-bounded chatID matching. New share_sessions setting (default false) controls cross-group visibility, following the same pattern as share_memory and share_knowledge_graph. Web UI toggle and i18n strings included. 63 test cases covering guild/DM/group users, realistic Zalo IDs, boundary exactness, multi-colon chatIDs, and the exact bug scenario.
54 lines
1.5 KiB
Go
54 lines
1.5 KiB
Go
package tools
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
"github.com/nextlevelbuilder/goclaw/internal/store"
|
|
)
|
|
|
|
// isSessionInScope checks whether a target session key falls within
|
|
// the current execution scope. Group-scoped runs can only access
|
|
// sessions belonging to the same group, unless share_sessions is enabled.
|
|
func isSessionInScope(ctx context.Context, targetKey, currentKey string) bool {
|
|
// Shared sessions mode — all sessions visible.
|
|
if store.IsSharedSessions(ctx) {
|
|
return true
|
|
}
|
|
|
|
// Always allow own session.
|
|
if targetKey == currentKey {
|
|
return true
|
|
}
|
|
|
|
// Extract group chat ID from user context.
|
|
userID := store.UserIDFromContext(ctx)
|
|
chatID := extractGroupChatID(userID)
|
|
if chatID == "" {
|
|
return true // DM or non-group scope — no restriction.
|
|
}
|
|
|
|
// Allow sessions containing this group's chat ID.
|
|
// Colon-bounded match prevents partial numeric collisions.
|
|
// Matches patterns like:
|
|
// agent:X:channel:group:{chatID}
|
|
// agent:X:channel:group:{chatID}:topic:N
|
|
marker := ":" + chatID
|
|
return strings.HasSuffix(targetKey, marker) ||
|
|
strings.Contains(targetKey, marker+":")
|
|
}
|
|
|
|
// extractGroupChatID extracts the chat ID from a group-scoped userID.
|
|
// Format: "group:channel:chatID" -> "chatID".
|
|
// Returns "" for non-group users (DM, guild, etc.).
|
|
func extractGroupChatID(userID string) string {
|
|
if !strings.HasPrefix(userID, "group:") {
|
|
return ""
|
|
}
|
|
parts := strings.SplitN(userID, ":", 3)
|
|
if len(parts) < 3 {
|
|
return ""
|
|
}
|
|
return parts[2]
|
|
}
|