feat: harden query read-only workflow

This commit is contained in:
Logan.Li committed 2026-07-07 17:20:44 +08:00
1 parent 58bbc394e9
commit 617c15dbfe
29 files changed
+1417 -395

No files matched your search

+27 -25
View File
@@ -840,6 +840,10 @@ func executeRedisQuery(instance *model.Instance, dbSelect string, command string
}
cmd := strings.ToUpper(parts[0])
keyName := ""
if len(parts) > 1 {
keyName = parts[1]
}
readOnly := map[string]bool{
"GET": true, "MGET": true, "HGET": true, "HGETALL": true,
"LRANGE": true, "SMEMBERS": true, "ZRANGE": true,
@@ -967,6 +971,21 @@ func executeRedisQuery(instance *model.Instance, dbSelect string, command string
return nil, fmt.Errorf("command failed: %v", err)
}
keyMeta := gin.H{}
if keyName != "" && cmd != "TYPE" && cmd != "TTL" && cmd != "PTTL" && cmd != "EXISTS" && cmd != "DBSIZE" && cmd != "INFO" {
keyMeta["raw_key"] = keyName
if t, err := client.Type(ctx, keyName).Result(); err == nil {
keyMeta["raw_type"] = t
}
if ttl, err := client.TTL(ctx, keyName).Result(); err == nil {
if ttl < 0 {
keyMeta["raw_ttl"] = "-1"
} else {
keyMeta["raw_ttl"] = fmt.Sprintf("%d", int(ttl.Seconds()))
}
}
}
// Format result into rows/columns for frontend table display
columns := []string{"key", "value"}
var rows []interface{}
@@ -1128,10 +1147,6 @@ func executeRedisQuery(instance *model.Instance, dbSelect string, command string
columns = []string{"field", "value"}
} else {
// Single value result (GET, HGET, TYPE, TTL, etc.)
keyName := ""
if len(parts) > 1 {
keyName = parts[1]
}
rawValue := fmt.Sprintf("%v", v)
// Try to pretty-format JSON with Chinese characters preserved
var prettyJSON string
@@ -1147,20 +1162,6 @@ func executeRedisQuery(instance *model.Instance, dbSelect string, command string
prettyJSON = strings.TrimRight(buf.String(), "\n")
}
}
// ARDM-style: auto-fetch key type and TTL for KeyHeader
var keyType, keyTTL string
if keyName != "" && cmd != "TYPE" && cmd != "TTL" && cmd != "PTTL" && cmd != "EXISTS" && cmd != "DBSIZE" && cmd != "INFO" {
if t, err := client.Type(ctx, keyName).Result(); err == nil {
keyType = t
}
if ttl, err := client.TTL(ctx, keyName).Result(); err == nil {
if ttl < 0 {
keyTTL = "永不过期"
} else {
keyTTL = fmt.Sprintf("%vs", int(ttl.Seconds()))
}
}
}
result := gin.H{
"columns": []string{},
"rows": []interface{}{},
@@ -1169,22 +1170,23 @@ func executeRedisQuery(instance *model.Instance, dbSelect string, command string
"raw_key": keyName,
"raw_text": rawValue,
}
if keyType != "" {
result["raw_type"] = keyType
}
if keyTTL != "" {
result["raw_ttl"] = keyTTL
for k, v := range keyMeta {
result[k] = v
}
return result, nil
}
}
return gin.H{
response := gin.H{
"columns": columns,
"rows": rowsOrDefault(rows),
"total": len(rows),
"count": len(rows),
}, nil
}
for k, v := range keyMeta {
response[k] = v
}
return response, nil
}
// executeMongoQuery — MongoDB query with pagination