Skip to content

Commit

Permalink
feat: add factories for creating new objects
Browse files Browse the repository at this point in the history
Signed-off-by: Felipe Zipitria <felipe.zipitria@owasp.org>
  • Loading branch information
fzipi committed Sep 23, 2024
1 parent 503bb77 commit b3232d5
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 143 deletions.
5 changes: 5 additions & 0 deletions experimental/corpus/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type Type string

const (
Leipzig Type = "leipzig"
NoType Type = "none"
)

func (t *Type) String() string {
Expand Down Expand Up @@ -112,6 +113,10 @@ type Iterator interface {
type Payload interface {
// LineNumber returns the payload given a line from the Corpus Iterator
LineNumber() int
// SetLineNumber sets the line number of the payload
SetLineNumber(line int)
// Content returns the payload given a line from the Corpus Iterator
Content() string
// SetContent sets the content of the payload
SetContent(content string)
}
27 changes: 27 additions & 0 deletions internal/quantitative/factories.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package quantitative

import (
"fmt"
"github.com/coreruleset/go-ftw/experimental/corpus"
"github.com/coreruleset/go-ftw/internal/quantitative/leipzig"
)

// CorpusFactory creates a new corpus
func CorpusFactory(t corpus.Type) (corpus.Corpus, error) {
switch t {
case corpus.Leipzig:
return leipzig.NewLeipzigCorpus(), nil
default:
return nil, fmt.Errorf("unsupported corpus type: %s", t)
}
}

// PayloadFactory creates a new Payload based on the corpus.Type
func PayloadFactory(t corpus.Type) (corpus.Payload, error) {
switch t {
case corpus.Leipzig:
return &leipzig.Payload{}, nil
default:
return nil, fmt.Errorf("unsupported corpus type: %s", t)
}
}
15 changes: 13 additions & 2 deletions internal/quantitative/leipzig/payload.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package leipzig

import (
"github.com/coreruleset/go-ftw/experimental/corpus"
"strconv"
"strings"
)
Expand All @@ -14,8 +15,8 @@ type Payload struct {
payload string
}

// NewPayload returns a new Payload
func NewPayload(line string) *Payload {
// NewPayload returns a new Payload from a line in the corpus.
func NewPayload(line string) corpus.Payload {
split := strings.Split(line, "\t")
// convert to int
num, err := strconv.Atoi(split[0])
Expand All @@ -35,7 +36,17 @@ func (p *Payload) LineNumber() int {
return p.line
}

// SetLineNumber sets the line number of the payload
func (p *Payload) SetLineNumber(line int) {
p.line = line
}

// Content returns the payload given a line from the Corpus Iterator
func (p *Payload) Content() string {
return p.payload
}

// SetContent sets the content of the payload
func (p *Payload) SetContent(content string) {
p.payload = content
}
129 changes: 14 additions & 115 deletions internal/quantitative/leipzig/payload_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
package leipzig

import (
"reflect"
"testing"

"github.com/stretchr/testify/suite"
Expand All @@ -19,120 +18,20 @@ func TestPayloadTestSuite(t *testing.T) {
}

func (s *payloadTestSuite) TestNewPayload() {
type args struct {
line string
}
tests := []struct {
name string
args args
want *Payload
}{
{
name: "TestNewPayload",
args: args{
line: "1\t$156,834 for The Pathway to Excellence in Practice program through Neighborhood Place of Puna.",
},
want: &Payload{
line: 1,
payload: "$156,834 for The Pathway to Excellence in Practice program through Neighborhood Place of Puna.",
},
},
{
name: "TestAdditional",
args: args{
line: "2000\tThis is an additional payload",
},
want: &Payload{
line: 2000,
payload: "This is an additional payload",
},
},
}
for _, tt := range tests {
s.Run(tt.name, func() {
if got := NewPayload(tt.args.line); !reflect.DeepEqual(got, tt.want) {
s.Require().Equal(got, tt.want)
}
})
}
line := "1\t$156,834 for The Pathway to Excellence in Practice program through Neighborhood Place of Puna."
p := NewPayload(line)
s.Require().Equal(1, p.LineNumber())
s.Require().Equal("$156,834 for The Pathway to Excellence in Practice program through Neighborhood Place of Puna.", p.Content())
line2 := "2000\tThis is an additional payload"
p2 := NewPayload(line2)
s.Require().Equal(2000, p2.LineNumber())
s.Require().Equal("This is an additional payload", p2.Content())
}

func (s *payloadTestSuite) TestPayload_Content() {
type fields struct {
line int
payload string
}
tests := []struct {
name string
fields fields
want string
}{
{
name: "TestContent",
fields: fields{
line: 1,
payload: "$156,834 for The Pathway to Excellence in Practice program through Neighborhood Place of Puna.",
},
want: "$156,834 for The Pathway to Excellence in Practice program through Neighborhood Place of Puna.",
},
{
name: "TestContent2",
fields: fields{
line: 2000,
payload: "This is another test payload",
},
want: "This is another test payload",
},
}
for _, tt := range tests {
s.Run(tt.name, func() {
p := &Payload{
line: tt.fields.line,
payload: tt.fields.payload,
}
if got := p.Content(); got != tt.want {
s.Require().Equal(got, tt.want)
}
})
}
}

func (s *payloadTestSuite) TestPayload_LineNumber() {
type fields struct {
line int
payload string
}
tests := []struct {
name string
fields fields
want int
}{
{
name: "TestLineNumber",
fields: fields{
line: 1,
payload: "This is a test payload",
},
want: 1,
},
{
name: "TestLineNumber2",
fields: fields{
line: 2000,
payload: "This is another test payload",
},
want: 2000,
},
}
for _, tt := range tests {
s.Run(tt.name, func() {
p := &Payload{
line: tt.fields.line,
payload: tt.fields.payload,
}
if got := p.LineNumber(); got != tt.want {
s.Require().Equal(got, tt.want)
}
})
}
func (s *payloadTestSuite) TestPayloadSetters() {
p := &Payload{}
p.SetLineNumber(1)
s.Require().Equal(1, p.LineNumber())
p.SetContent("test")
s.Require().Equal("test", p.Content())
}
4 changes: 2 additions & 2 deletions internal/quantitative/local_engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ func crsWAF(prefix string, paranoiaLevel int) coraza.WAF {
vars := map[string]interface{}{
"ParanoiaLevel": paranoiaLevel,
}
log.Debug().Msgf("Using paranoia level: %d\n", paranoiaLevel)
log.Debug().Msgf("Using paranoia level: %d", paranoiaLevel)
// set up configuration from template
configTmpl, err := template.New("crs-config").Parse(testingConfigTmpl)
if err != nil {
Expand Down Expand Up @@ -163,7 +163,7 @@ func obtainStatusCodeFromInterruptionOrDefault(it *types.Interruption, defaultSt
if it.Action == "deny" {
statusCode := it.Status
if statusCode == 0 {
statusCode = 403
statusCode = http.StatusForbidden
}

return statusCode
Expand Down
44 changes: 22 additions & 22 deletions internal/quantitative/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"github.com/rs/zerolog/log"

"github.com/coreruleset/go-ftw/experimental/corpus"
"github.com/coreruleset/go-ftw/internal/quantitative/leipzig"
"github.com/coreruleset/go-ftw/output"
)

Expand Down Expand Up @@ -42,19 +41,9 @@ type Params struct {
CorpusSource string
}

// NewCorpus creates a new corpus
func NewCorpus(corpusType corpus.Type) corpus.Corpus {
switch corpusType {
case corpus.Leipzig:
return leipzig.NewLeipzigCorpus()
default:
log.Fatal().Msgf("Unknown corpus implementation: %s", corpusType)
return nil
}
}

// RunQuantitativeTests runs all quantitative tests
func RunQuantitativeTests(params Params, out *output.Output) error {
var lc corpus.File
out.Println(":hourglass: Running quantitative tests")

log.Trace().Msgf("Lines: %d", params.Lines)
Expand All @@ -70,32 +59,43 @@ func RunQuantitativeTests(params Params, out *output.Output) error {

startTime := time.Now()
// create a new corpusRunner
corpusRunner := NewCorpus(params.Corpus).
corpusRunner, err := CorpusFactory(params.Corpus)
if err != nil {
return err
}
corpusRunner = corpusRunner.
WithSize(params.CorpusSize).
WithYear(params.CorpusYear).
WithSource(params.CorpusSource).
WithLanguage(params.CorpusLang)

// download the corpusRunner file
lc := corpusRunner.FetchCorpusFile()
// download the corpusRunner file if no payload is provided
if params.Payload == "" {
lc = corpusRunner.FetchCorpusFile()
}
// create the results
stats := NewQuantitativeStats()

var engine LocalEngine = &localEngine{}
runner := engine.Create(params.Directory, params.ParanoiaLevel)

// Are we using the corpus at all?
// TODO: this could be moved to a generic "file" iterator (instead of "corpus), with a Factory method
if params.Payload != "" {
log.Trace().Msgf("Payload received from cmdline: %s", params.Payload)
p, err := PayloadFactory(params.Corpus)
if err != nil {
return err
}
// CrsCall with payload
doEngineCall(runner, params.Payload, params.Rule, stats)
doEngineCall(runner, p, params.Rule, stats)
} else { // iterate over the corpus
log.Trace().Msgf("Iterating over corpus")
for iter := corpusRunner.GetIterator(lc); iter.HasNext(); {
p := iter.Next()
payload := iter.Next()
stats.incrementRun()
payload := p.Content()
log.Trace().Msgf("Line: %s", payload)
content := payload.Content()
log.Trace().Msgf("Line: %s", content)
// check if we are looking for a specific payload line #
if needSpecificPayload(params.Number, stats.Count()) {
continue
Expand Down Expand Up @@ -130,8 +130,8 @@ func wantSpecificRuleResults(specific int, rule int) bool {
}

// doEngineCall
func doEngineCall(engine LocalEngine, payload string, specificRule int, stats *QuantitativeRunStats) {
status, matchedRules := engine.CrsCall(payload)
func doEngineCall(engine LocalEngine, payload corpus.Payload, specificRule int, stats *QuantitativeRunStats) {
status, matchedRules := engine.CrsCall(payload.Content())
log.Trace().Msgf("Status: %d", status)
log.Trace().Msgf("Rules: %v", matchedRules)
if status == http.StatusForbidden {
Expand All @@ -144,7 +144,7 @@ func doEngineCall(engine LocalEngine, payload string, specificRule int, stats *Q
continue
}
stats.addFalsePositive(rule)
log.Debug().Msgf("**> rule %d => %s", rule, data)
log.Debug().Msgf("**> rule %d with payload %d => %s", rule, payload.LineNumber(), data)
}
}
}
9 changes: 7 additions & 2 deletions internal/quantitative/runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,15 @@ func (s *runnerTestSuite) TeardownTest() {
s.Require().NoError(err)
}

func (s *runnerTestSuite) TestNewCorpus() {
s.c = NewCorpus(corpus.Leipzig)
func (s *runnerTestSuite) TestCorpusFactory() {
var err error
s.c, err = CorpusFactory(corpus.Leipzig)
s.Require().NoError(err)
s.Require().NotNil(s.c)
s.Require().Equal(s.c.URL(), "https://downloads.wortschatz-leipzig.de/corpora")

s.c, err = CorpusFactory(corpus.NoType)
s.Require().Error(err)
}

func (s *runnerTestSuite) TestRunQuantitativeTests() {
Expand Down

0 comments on commit b3232d5

Please sign in to comment.