diff --git a/.changeset/brave-coats-give.md b/.changeset/brave-coats-give.md new file mode 100644 index 000000000..7def22685 --- /dev/null +++ b/.changeset/brave-coats-give.md @@ -0,0 +1,6 @@ +--- +"github.com/livekit/protocol": patch +"@livekit/protocol": patch +--- + +Fix recursive call to CreateSIPInboundTrunkRequest.ValidateResult. diff --git a/livekit/sip.go b/livekit/sip.go index b461feac4..79f076c95 100644 --- a/livekit/sip.go +++ b/livekit/sip.go @@ -365,15 +365,18 @@ func ValidationFailure(err error) ValidationResult { } func validateHeaders(headers map[string]string) ValidationResult { + ret := ValidationResult{} for headerName, headerValue := range headers { if err := ValidateHeaderName(headerName, true); err != nil { - return ValidationFailure(fmt.Errorf("invalid header name: %w", err)) + return ret.WithError(fmt.Errorf("invalid header name: %w", err)) } - if err := ValidateHeaderValue(headerName, headerValue); err != nil { - return ValidationFailure(fmt.Errorf("invalid header value for %s: %w", headerName, err)) + result := ValidateHeaderValueResult(headerName, headerValue) + if !result.OK() { + return ret.WithError(fmt.Errorf("invalid header value for %s: %w", headerName, result.Error())) } + ret = ret.Combine(result) } - return ValidationResult{} + return ret } // validateHeaderNames Makes sure the values of the given map correspond to valid SIP header names @@ -441,7 +444,7 @@ func (p *CreateSIPInboundTrunkRequest) ValidateResult() ValidationResult { if p.Trunk.SipTrunkId != "" { return ValidationFailure(errors.New("trunk id must not be set")) } - return p.ValidateResult() + return p.Trunk.ValidateResult() } func (p *UpdateSIPOutboundTrunkRequest) Validate() error { diff --git a/livekit/sip_test.go b/livekit/sip_test.go index 20838ffdb..cfda9ac38 100644 --- a/livekit/sip_test.go +++ b/livekit/sip_test.go @@ -1,7 +1,8 @@ package livekit import ( - errors "errors" + "errors" + "fmt" "slices" "testing" "time" @@ -50,11 +51,16 @@ func TestSIPValidate(t *testing.T) { type validateable interface { Validate() error } + type resultValidateable interface { + ValidateResult() ValidationResult + } type validateTestCase struct { - name string - req validateable - exp bool + name string + req validateable + exp bool + wantSoftErrs bool } + cases := map[string][]validateTestCase{ "SIPInboundTrunkInfo": { { @@ -114,6 +120,17 @@ func TestSIPValidate(t *testing.T) { }, exp: false, }, + { + name: "inbound invalid header value", + req: &SIPInboundTrunkInfo{ + Numbers: []string{"+1111"}, + Headers: map[string]string{ + "Referred-By": " 0 + if c.wantSoftErrs { + require.Equal(t, c.wantSoftErrs, hasSoftErrs, "got zero soft validation errors; want at least one") + } else { + require.Equal(t, c.wantSoftErrs, hasSoftErrs, "got at least one soft validation error; want zero; %v", result.SoftErrors()) + } + } }) } }) } + + wantResultValidateableTypes := map[string]bool{ + "*livekit.CreateSIPInboundTrunkRequest": true, + "*livekit.CreateSIPOutboundTrunkRequest": true, + "*livekit.CreateSIPParticipantRequest": true, + "*livekit.SIPInboundTrunkInfo": true, + "*livekit.SIPOutboundTrunkInfo": true, + "*livekit.TransferSIPParticipantRequest": true, + "*livekit.UpdateSIPInboundTrunkRequest": true, + "*livekit.UpdateSIPOutboundTrunkRequest": true, + } + require.Equal(t, wantResultValidateableTypes, resultValidatableTypes) } func TestSIPInboundTrunkFilter(t *testing.T) { @@ -1132,3 +1459,57 @@ func TestValidationResultCombine(t *testing.T) { }) } } + +func errMsgs(errs []error) []string { + ret := make([]string, 0, len(errs)) + for _, err := range errs { + ret = append(ret, err.Error()) + } + return ret +} + +func TestValidateHeaders(t *testing.T) { + type testCase struct { + name string + headers map[string]string + expected ValidationResult + } + + testCases := []testCase{ + { + name: "empty headers", + headers: map[string]string{}, + expected: ValidationResult{}, + }, + { + name: "valid header", + headers: map[string]string{ + "Reffered-By": "