Path: blob/dev/pkg/core/workflow_execute_test.go
2070 views
package core12import (3"context"4"testing"56"github.com/projectdiscovery/nuclei/v3/pkg/model/types/stringslice"7"github.com/projectdiscovery/nuclei/v3/pkg/operators"8"github.com/projectdiscovery/nuclei/v3/pkg/output"9"github.com/projectdiscovery/nuclei/v3/pkg/progress"10"github.com/projectdiscovery/nuclei/v3/pkg/protocols"11"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"12"github.com/projectdiscovery/nuclei/v3/pkg/scan"13"github.com/projectdiscovery/nuclei/v3/pkg/types"14"github.com/projectdiscovery/nuclei/v3/pkg/workflows"15"github.com/stretchr/testify/require"16)1718func TestWorkflowsSimple(t *testing.T) {19progressBar, _ := progress.NewStatsTicker(0, false, false, false, 0)2021workflow := &workflows.Workflow{Options: &protocols.ExecutorOptions{Options: &types.Options{TemplateThreads: 10}}, Workflows: []*workflows.WorkflowTemplate{22{Executers: []*workflows.ProtocolExecuterPair{{23Executer: &mockExecuter{result: true}, Options: &protocols.ExecutorOptions{Progress: progressBar}},24}},25}}2627engine := &Engine{}28input := contextargs.NewWithInput(context.Background(), "https://test.com")29ctx := scan.NewScanContext(context.Background(), input)30matched := engine.executeWorkflow(ctx, workflow)31require.True(t, matched, "could not get correct match value")32}3334func TestWorkflowsSimpleMultiple(t *testing.T) {35progressBar, _ := progress.NewStatsTicker(0, false, false, false, 0)3637var firstInput, secondInput string38workflow := &workflows.Workflow{Options: &protocols.ExecutorOptions{Options: &types.Options{TemplateThreads: 10}}, Workflows: []*workflows.WorkflowTemplate{39{Executers: []*workflows.ProtocolExecuterPair{{40Executer: &mockExecuter{result: true, executeHook: func(input *contextargs.MetaInput) {41firstInput = input.Input42}}, Options: &protocols.ExecutorOptions{Progress: progressBar}},43}},44{Executers: []*workflows.ProtocolExecuterPair{{45Executer: &mockExecuter{result: true, executeHook: func(input *contextargs.MetaInput) {46secondInput = input.Input47}}, Options: &protocols.ExecutorOptions{Progress: progressBar}},48}},49}}5051engine := &Engine{}52input := contextargs.NewWithInput(context.Background(), "https://test.com")53ctx := scan.NewScanContext(context.Background(), input)54matched := engine.executeWorkflow(ctx, workflow)55require.True(t, matched, "could not get correct match value")5657require.Equal(t, "https://test.com", firstInput, "could not get correct first input")58require.Equal(t, "https://test.com", secondInput, "could not get correct second input")59}6061func TestWorkflowsSubtemplates(t *testing.T) {62progressBar, _ := progress.NewStatsTicker(0, false, false, false, 0)6364var firstInput, secondInput string65workflow := &workflows.Workflow{Options: &protocols.ExecutorOptions{Options: &types.Options{TemplateThreads: 10}}, Workflows: []*workflows.WorkflowTemplate{66{Executers: []*workflows.ProtocolExecuterPair{{67Executer: &mockExecuter{result: true, executeHook: func(input *contextargs.MetaInput) {68firstInput = input.Input69}, outputs: []*output.InternalWrappedEvent{70{OperatorsResult: &operators.Result{}, Results: []*output.ResultEvent{{}}},71}}, Options: &protocols.ExecutorOptions{Progress: progressBar}},72}, Subtemplates: []*workflows.WorkflowTemplate{{Executers: []*workflows.ProtocolExecuterPair{{73Executer: &mockExecuter{result: true, executeHook: func(input *contextargs.MetaInput) {74secondInput = input.Input75}}, Options: &protocols.ExecutorOptions{Progress: progressBar}},76}}}},77}}7879engine := &Engine{}80input := contextargs.NewWithInput(context.Background(), "https://test.com")81ctx := scan.NewScanContext(context.Background(), input)82matched := engine.executeWorkflow(ctx, workflow)83require.True(t, matched, "could not get correct match value")8485require.Equal(t, "https://test.com", firstInput, "could not get correct first input")86require.Equal(t, "https://test.com", secondInput, "could not get correct second input")87}8889func TestWorkflowsSubtemplatesNoMatch(t *testing.T) {90progressBar, _ := progress.NewStatsTicker(0, false, false, false, 0)9192var firstInput, secondInput string93workflow := &workflows.Workflow{Options: &protocols.ExecutorOptions{Options: &types.Options{TemplateThreads: 10}}, Workflows: []*workflows.WorkflowTemplate{94{Executers: []*workflows.ProtocolExecuterPair{{95Executer: &mockExecuter{result: false, executeHook: func(input *contextargs.MetaInput) {96firstInput = input.Input97}}, Options: &protocols.ExecutorOptions{Progress: progressBar}},98}, Subtemplates: []*workflows.WorkflowTemplate{{Executers: []*workflows.ProtocolExecuterPair{{99Executer: &mockExecuter{result: true, executeHook: func(input *contextargs.MetaInput) {100secondInput = input.Input101}}, Options: &protocols.ExecutorOptions{Progress: progressBar}},102}}}},103}}104105engine := &Engine{}106input := contextargs.NewWithInput(context.Background(), "https://test.com")107ctx := scan.NewScanContext(context.Background(), input)108matched := engine.executeWorkflow(ctx, workflow)109require.False(t, matched, "could not get correct match value")110111require.Equal(t, "https://test.com", firstInput, "could not get correct first input")112require.Equal(t, "", secondInput, "could not get correct second input")113}114115func TestWorkflowsSubtemplatesWithMatcher(t *testing.T) {116progressBar, _ := progress.NewStatsTicker(0, false, false, false, 0)117118var firstInput, secondInput string119workflow := &workflows.Workflow{Options: &protocols.ExecutorOptions{Options: &types.Options{TemplateThreads: 10}}, Workflows: []*workflows.WorkflowTemplate{120{Executers: []*workflows.ProtocolExecuterPair{{121Executer: &mockExecuter{result: true, executeHook: func(input *contextargs.MetaInput) {122firstInput = input.Input123}, outputs: []*output.InternalWrappedEvent{124{OperatorsResult: &operators.Result{125Matches: map[string][]string{"tomcat": {}},126Extracts: map[string][]string{},127}},128}}, Options: &protocols.ExecutorOptions{Progress: progressBar}},129}, Matchers: []*workflows.Matcher{{Name: stringslice.StringSlice{Value: "tomcat"}, Subtemplates: []*workflows.WorkflowTemplate{{Executers: []*workflows.ProtocolExecuterPair{{130Executer: &mockExecuter{result: true, executeHook: func(input *contextargs.MetaInput) {131secondInput = input.Input132}}, Options: &protocols.ExecutorOptions{Progress: progressBar}},133}}}}}},134}}135136engine := &Engine{}137input := contextargs.NewWithInput(context.Background(), "https://test.com")138ctx := scan.NewScanContext(context.Background(), input)139matched := engine.executeWorkflow(ctx, workflow)140require.True(t, matched, "could not get correct match value")141142require.Equal(t, "https://test.com", firstInput, "could not get correct first input")143require.Equal(t, "https://test.com", secondInput, "could not get correct second input")144}145146func TestWorkflowsSubtemplatesWithMatcherNoMatch(t *testing.T) {147progressBar, _ := progress.NewStatsTicker(0, false, false, false, 0)148149var firstInput, secondInput string150workflow := &workflows.Workflow{Options: &protocols.ExecutorOptions{Options: &types.Options{TemplateThreads: 10}}, Workflows: []*workflows.WorkflowTemplate{151{Executers: []*workflows.ProtocolExecuterPair{{152Executer: &mockExecuter{result: true, executeHook: func(input *contextargs.MetaInput) {153firstInput = input.Input154}, outputs: []*output.InternalWrappedEvent{155{OperatorsResult: &operators.Result{156Matches: map[string][]string{"tomcat": {}},157Extracts: map[string][]string{},158}},159}}, Options: &protocols.ExecutorOptions{Progress: progressBar}},160}, Matchers: []*workflows.Matcher{{Name: stringslice.StringSlice{Value: "apache"}, Subtemplates: []*workflows.WorkflowTemplate{{Executers: []*workflows.ProtocolExecuterPair{{161Executer: &mockExecuter{result: true, executeHook: func(input *contextargs.MetaInput) {162secondInput = input.Input163}}, Options: &protocols.ExecutorOptions{Progress: progressBar}},164}}}}}},165}}166167engine := &Engine{}168input := contextargs.NewWithInput(context.Background(), "https://test.com")169ctx := scan.NewScanContext(context.Background(), input)170matched := engine.executeWorkflow(ctx, workflow)171require.False(t, matched, "could not get correct match value")172173require.Equal(t, "https://test.com", firstInput, "could not get correct first input")174require.Equal(t, "", secondInput, "could not get correct second input")175}176177type mockExecuter struct {178result bool179executeHook func(input *contextargs.MetaInput)180outputs []*output.InternalWrappedEvent181}182183// Compile compiles the execution generators preparing any requests possible.184func (m *mockExecuter) Compile() error {185return nil186}187188// Requests returns the total number of requests the rule will perform189func (m *mockExecuter) Requests() int {190return 1191}192193// Execute executes the protocol group and returns true or false if results were found.194func (m *mockExecuter) Execute(ctx *scan.ScanContext) (bool, error) {195if m.executeHook != nil {196m.executeHook(ctx.Input.MetaInput)197}198return m.result, nil199}200201// ExecuteWithResults executes the protocol requests and returns results instead of writing them.202func (m *mockExecuter) ExecuteWithResults(ctx *scan.ScanContext) ([]*output.ResultEvent, error) {203if m.executeHook != nil {204m.executeHook(ctx.Input.MetaInput)205}206for _, output := range m.outputs {207ctx.LogEvent(output)208}209return ctx.GenerateResult(), nil210}211212213