Skip to content

Commit db38d2c

Browse files
committed
Merge remote-tracking branch 'origin/release/v11.2.6' into backlog/compliance-evaluation
2 parents 8436126 + 19d04b0 commit db38d2c

1,327 files changed

Lines changed: 27517 additions & 33129 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

agent-manager/agent/agent_imp.go

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,20 @@ type AgentService struct {
2929
AgentStreamMap map[uint]AgentService_AgentStreamServer
3030
AgentStreamMutex sync.Mutex
3131
CacheAgentKey map[uint]string
32-
CacheAgentKeyMutex sync.Mutex
32+
CacheAgentKeyMutex sync.RWMutex
3333
CommandResultChannel map[string]chan *CommandResult
3434
CommandResultChannelM sync.Mutex
3535

3636
DBConnection *database.DB
3737
}
3838

39+
func (s *AgentService) ValidateAgentKey(key string, id uint) bool {
40+
s.CacheAgentKeyMutex.RLock()
41+
defer s.CacheAgentKeyMutex.RUnlock()
42+
_, valid := utils.IsKeyPairValid(key, id, s.CacheAgentKey)
43+
return valid
44+
}
45+
3946
func InitAgentService() error {
4047
var err error
4148
agentServOnce.Do(func() {
@@ -338,20 +345,35 @@ func (s *AgentService) ProcessCommand(stream PanelService_ProcessCommandServer)
338345
return status.Errorf(codes.Internal, "failed to send command to agent: %v", err)
339346
}
340347

341-
result := <-s.CommandResultChannel[cmdID]
342-
err = s.DBConnection.Upsert(
343-
&models.AgentCommand{},
344-
"agent_id = ? AND cmd_id = ?",
345-
map[string]interface{}{"command_status": models.Executed, "result": result.Result},
346-
cmd.AgentId, cmdID,
347-
)
348-
if err != nil {
349-
catcher.Error("failed to update command status", err, map[string]any{"process": "agent-manager"})
350-
}
348+
select {
349+
case result := <-s.CommandResultChannel[cmdID]:
350+
err = s.DBConnection.Upsert(
351+
&models.AgentCommand{},
352+
"agent_id = ? AND cmd_id = ?",
353+
map[string]interface{}{"command_status": models.Executed, "result": result.Result},
354+
cmd.AgentId, cmdID,
355+
)
356+
if err != nil {
357+
catcher.Error("failed to update command status", err, map[string]any{"process": "agent-manager"})
358+
}
351359

352-
err = stream.Send(result)
353-
if err != nil {
354-
return err
360+
err = stream.Send(result)
361+
if err != nil {
362+
return err
363+
}
364+
case <-time.After(5 * time.Minute):
365+
s.CommandResultChannelM.Lock()
366+
delete(s.CommandResultChannel, cmdID)
367+
s.CommandResultChannelM.Unlock()
368+
369+
_ = s.DBConnection.Upsert(
370+
&models.AgentCommand{},
371+
"agent_id = ? AND cmd_id = ?",
372+
map[string]interface{}{"command_status": models.Error, "result": "command timed out after 5 minutes"},
373+
cmd.AgentId, cmdID,
374+
)
375+
376+
return status.Errorf(codes.DeadlineExceeded, "agent did not respond within 5 minutes")
355377
}
356378

357379
s.CommandResultChannelM.Lock()

agent-manager/agent/collector_imp.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,20 @@ type CollectorService struct {
4343
CollectorConfigsCache map[uint][]*CollectorConfigGroup
4444
CollectorConfigsCacheM sync.Mutex
4545
CacheCollectorKey map[uint]string
46-
CacheCollectorKeyMutex sync.Mutex
46+
CacheCollectorKeyMutex sync.RWMutex
4747
CollectorPendigConfigChan chan *CollectorConfig
4848
CollectorTypes []enum.UTMModule
4949

5050
DBConnection *database.DB
5151
}
5252

53+
func (s *CollectorService) ValidateCollectorKey(key string, id uint) bool {
54+
s.CacheCollectorKeyMutex.RLock()
55+
defer s.CacheCollectorKeyMutex.RUnlock()
56+
_, valid := utils.IsKeyPairValid(key, id, s.CacheCollectorKey)
57+
return valid
58+
}
59+
5360
func InitCollectorService() {
5461
collectorServOnce.Do(func() {
5562
CollectorServ = &CollectorService{

agent-manager/agent/interceptor.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package agent
22

33
import (
44
"context"
5-
_ "errors"
5+
"crypto/subtle"
66
"fmt"
77
"strconv"
88
"strings"
@@ -79,11 +79,11 @@ func authHeaders(md metadata.MD, fullMethod string) error {
7979
typ := strings.ToLower(connectorType[0])
8080
switch typ {
8181
case "agent":
82-
if _, isValid := utils.IsKeyPairValid(key, uint(id), AgentServ.CacheAgentKey); !isValid {
82+
if !AgentServ.ValidateAgentKey(key, uint(id)) {
8383
return status.Error(codes.PermissionDenied, "invalid key")
8484
}
8585
case "collector":
86-
if _, isValid := utils.IsKeyPairValid(key, uint(id), CollectorServ.CacheCollectorKey); !isValid {
86+
if !CollectorServ.ValidateCollectorKey(key, uint(id)) {
8787
return status.Error(codes.PermissionDenied, "invalid key")
8888
}
8989
default:
@@ -102,7 +102,7 @@ func authHeaders(md metadata.MD, fullMethod string) error {
102102
}
103103

104104
func isInternalKeyValid(token string) bool {
105-
return token == config.InternalKey
105+
return subtle.ConstantTimeCompare([]byte(token), []byte(config.InternalKey)) == 1
106106
}
107107

108108
func isInRoute(route string, list []string) bool {

agent-manager/agent/parser.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,11 @@ func replaceSecretValues(input string) string {
100100
return match
101101
}
102102
encryptedValue := matches[2]
103-
decryptedValue, _ := utils.DecryptValue(config.EncryptionKey, encryptedValue)
103+
decryptedValue, err := utils.DecryptValue(config.EncryptionKey, encryptedValue)
104+
if err != nil {
105+
catcher.Error("failed to decrypt secret value in command", err, map[string]any{"process": "agent-manager"})
106+
return match
107+
}
104108
return decryptedValue
105109
})
106110
}

agent-manager/utils/auth.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package utils
22

33
import (
4+
"crypto/subtle"
45
"crypto/tls"
56
"net/http"
67
"strings"
@@ -19,10 +20,12 @@ func IsConnectionKeyValid(panelUrl string, token string) bool {
1920
}
2021

2122
func IsKeyPairValid(key string, id uint, cache map[uint]string) (string, bool) {
22-
for agentId, agentKey := range cache {
23-
if key == agentKey && id == agentId {
24-
return agentKey, true
25-
}
23+
agentKey, ok := cache[id]
24+
if !ok {
25+
return "", false
26+
}
27+
if subtle.ConstantTimeCompare([]byte(key), []byte(agentKey)) == 1 {
28+
return agentKey, true
2629
}
2730
return "", false
2831
}

agent-manager/utils/filter.go

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package utils
22

33
import (
44
"fmt"
5+
"regexp"
56
"strings"
67

78
"gorm.io/gorm"
@@ -24,14 +25,14 @@ type Filter struct {
2425
Value interface{}
2526
}
2627

27-
func NewFilter(searchQuery string) []Filter {
28-
defer func() {
29-
if r := recover(); r != nil {
30-
// Handle the panic here
31-
fmt.Println("Panic occurred:", r)
32-
}
33-
}()
28+
// validFieldName ensures the field name only contains safe characters (letters, digits, underscores)
29+
var validFieldName = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`)
3430

31+
func IsValidFieldName(field string) bool {
32+
return validFieldName.MatchString(field)
33+
}
34+
35+
func NewFilter(searchQuery string) []Filter {
3536
filters := make([]Filter, 0)
3637
if searchQuery == "" {
3738
return filters
@@ -42,11 +43,27 @@ func NewFilter(searchQuery string) []Filter {
4243
}
4344
for _, v := range query {
4445
filter := strings.Split(v, "=")
46+
if len(filter) != 2 {
47+
continue
48+
}
4549
filerQuery := strings.Split(filter[0], ".")
50+
if len(filerQuery) != 2 {
51+
continue
52+
}
53+
field := filerQuery[0]
54+
if !IsValidFieldName(field) {
55+
fmt.Printf("Rejected invalid filter field: %s\n", field)
56+
continue
57+
}
58+
op := resolveOperator(filerQuery[1])
59+
if op == "" {
60+
continue
61+
}
4662
filters = append(filters, Filter{
47-
Field: filerQuery[0],
48-
Op: resolveOperator(filerQuery[1]),
49-
Value: filter[1]})
63+
Field: field,
64+
Op: op,
65+
Value: filter[1],
66+
})
5067
}
5168
return filters
5269
}

agent-manager/utils/paginator.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,19 @@ func NewPaginator(limit int, page int, sort string) Pagination {
2828
if len(sort) > 0 {
2929
srt := make([]string, 0)
3030
for _, s := range strings.Split(sort, "&") {
31-
srt = append(srt, strings.Replace(s, ",", " ", 1))
31+
parts := strings.SplitN(s, ",", 2)
32+
field := parts[0]
33+
if !IsValidFieldName(field) {
34+
continue
35+
}
36+
direction := "asc"
37+
if len(parts) == 2 {
38+
d := strings.ToLower(strings.TrimSpace(parts[1]))
39+
if d == "desc" {
40+
direction = "desc"
41+
}
42+
}
43+
srt = append(srt, field+" "+direction)
3244
}
3345
p.Sort = strings.Join(srt, ",")
3446
}

backend/src/main/java/com/park/utmstack/config/Constants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ public final class Constants {
161161

162162
public static final String CONF_TYPE_PASSWORD = "password";
163163
public static final String CONF_TYPE_FILE = "file";
164+
public static final String MASKED_VALUE = "*****";
164165

165166
public static final String API_KEY_HEADER = "Utm-Api-Key";
166167
public static final List<String> API_ENDPOINT_IGNORE = Collections.emptyList();

backend/src/main/java/com/park/utmstack/domain/UtmServerModule.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
package com.park.utmstack.domain;
22

33

4+
import com.park.utmstack.service.dto.auditable.AuditableDTO;
5+
46
import javax.persistence.*;
57
import java.io.Serializable;
8+
import java.util.Map;
69

710
/**
811
* A UtmServerModule.
912
*/
1013
@Entity
1114
@Table(name = "utm_server_module")
12-
public class UtmServerModule implements Serializable {
15+
public class UtmServerModule implements Serializable, AuditableDTO {
1316

1417
private static final long serialVersionUID = 1L;
1518

@@ -100,4 +103,12 @@ public UtmServer getServer() {
100103
public void setServer(UtmServer server) {
101104
this.server = server;
102105
}
106+
107+
@Override
108+
public Map<String, Object> toAuditMap() {
109+
return Map.of(
110+
"moduleName", moduleName != null ? moduleName : "",
111+
"prettyName", prettyName != null ? prettyName : ""
112+
);
113+
}
103114
}

backend/src/main/java/com/park/utmstack/domain/alert_response_rule/UtmAlertResponseRule.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ public class UtmAlertResponseRule implements Serializable {
6464
@Column(name = "last_modified_date")
6565
private Instant lastModifiedDate;
6666

67+
@Size(max = 20)
68+
@Column(name = "rule_shell", length = 20)
69+
private String ruleShell;
70+
6771
@Column(name = "system_owner", nullable = false)
6872
private Boolean systemOwner;
6973

@@ -92,6 +96,7 @@ public UtmAlertResponseRule(UtmAlertResponseRuleDTO dto) {
9296
this.ruleActive = dto.getActive();
9397
this.agentPlatform = dto.getAgentPlatform();
9498
this.defaultAgent = dto.getDefaultAgent();
99+
this.ruleShell = dto.getShell();
95100
this.systemOwner = dto.getSystemOwner();
96101
if (!CollectionUtils.isEmpty(dto.getExcludedAgents()))
97102
this.excludedAgents = String.join(",", dto.getExcludedAgents());

0 commit comments

Comments
 (0)