diff --git a/re/golang.go b/re/golang.go index 5ee8acecc..e2db6fa28 100644 --- a/re/golang.go +++ b/re/golang.go @@ -20,7 +20,10 @@ import ( const logicFunction = "main.logicFunction" -var goKeywordRegex = regexp.MustCompile(`\bgo\s+func\s*\(|^\s*go\s+\w+\(|[;\s{]go\s+func\s*\(|[;\s{]go\s+\w+\(`) +var ( + goKeywordRegex = regexp.MustCompile(`\bgo\s+func\s*\(|^\s*go\s+\w+\(|[;\s{]go\s+func\s*\(|[;\s{]go\s+\w+\(`) + panicRegex = regexp.MustCompile(`\bpanic\s*\(`) +) // Type message is an SMQ message with payload replaces by JSON deserialized payload. type message struct { diff --git a/re/service.go b/re/service.go index 09d5e9c62..153df304d 100644 --- a/re/service.go +++ b/re/service.go @@ -21,7 +21,10 @@ import ( "github.com/absmach/supermq/pkg/roles" ) -var ErrGoroutinesNotAllowed = errors.New("goroutines are not allowed in Go scripts") +var ( + ErrGoroutinesNotAllowed = errors.New("goroutines are not allowed in Go scripts") + ErrPanicNotAllowed = errors.New("panic is not allowed in Go scripts") +) type re struct { repo Repository @@ -59,6 +62,9 @@ func (re *re) AddRule(ctx context.Context, session authn.Session, r Rule) (retRu if r.Logic.Type == GoType && goKeywordRegex.MatchString(r.Logic.Value) { return Rule{}, errors.Wrap(svcerr.ErrMalformedEntity, ErrGoroutinesNotAllowed) } + if r.Logic.Type == GoType && panicRegex.MatchString(r.Logic.Value) { + return Rule{}, errors.Wrap(svcerr.ErrMalformedEntity, ErrPanicNotAllowed) + } id, err := re.idp.ID() if err != nil { @@ -131,6 +137,9 @@ func (re *re) UpdateRule(ctx context.Context, session authn.Session, r Rule) (Ru if r.Logic.Type == GoType && goKeywordRegex.MatchString(r.Logic.Value) { return Rule{}, errors.Wrap(svcerr.ErrMalformedEntity, ErrGoroutinesNotAllowed) } + if r.Logic.Type == GoType && panicRegex.MatchString(r.Logic.Value) { + return Rule{}, errors.Wrap(svcerr.ErrMalformedEntity, ErrPanicNotAllowed) + } r.UpdatedAt = time.Now().UTC() r.UpdatedBy = session.UserID diff --git a/re/service_test.go b/re/service_test.go index 97ba1c2de..cd08f59f1 100644 --- a/re/service_test.go +++ b/re/service_test.go @@ -335,6 +335,30 @@ func TestAddRule(t *testing.T) { addRoleErr: nil, deleteErr: nil, }, + { + desc: "Add rule with Go script containing panic", + session: authn.Session{ + UserID: userID, + DomainID: domainID, + }, + rule: re.Rule{ + Name: ruleName, + InputChannel: inputChannel, + Logic: re.Script{ + Type: re.GoType, + Value: `func logicFunction() any { panic("error"); return true }`, + }, + Schedule: pkgSch.Schedule{ + Recurring: pkgSch.Daily, + RecurringPeriod: 1, + Time: now, + }, + }, + err: re.ErrPanicNotAllowed, + addPoliciesErr: nil, + addRoleErr: nil, + deleteErr: nil, + }, { desc: "Add rule with failed to add roles and failed to delete policies", session: authn.Session{ @@ -640,6 +664,31 @@ func TestUpdateRule(t *testing.T) { }, err: re.ErrGoroutinesNotAllowed, }, + { + desc: "Update rule with Go script containing panic", + session: authn.Session{ + UserID: userID, + DomainID: domainID, + }, + rule: re.Rule{ + Name: ruleName, + ID: ruleID, + InputChannel: inputChannel, + Logic: re.Script{ + Type: re.GoType, + Value: `func logicFunction() any { panic("test panic"); return true }`, + }, + Schedule: pkgSch.Schedule{ + Recurring: pkgSch.Daily, + RecurringPeriod: 1, + Time: now, + }, + Status: re.EnabledStatus, + CreatedBy: userID, + DomainID: domainID, + }, + err: re.ErrPanicNotAllowed, + }, } for _, tc := range cases {