Skip to content

Commit

Permalink
Added request validation filtering
Browse files Browse the repository at this point in the history
  • Loading branch information
jacobm-splunk authored and daveshanley committed Apr 12, 2024
1 parent 3c27d94 commit c05b7e8
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 59 deletions.
10 changes: 10 additions & 0 deletions cmd/root_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,16 @@ var (
printLoadedWebsockets(config.WebsocketConfigs)
}

if len(config.ValidationAllowList) > 0 {
config.CompileIgnoreValidations()
// TODO: add print command
}

if len(config.IgnoreValidation) > 0 {
config.CompileIgnoreValidations()
// TODO: add print command
}

// static headers
if config.Headers != nil && len(config.Headers.DropHeaders) > 0 {
pterm.Info.Printf("Dropping the following %d %s globally:\n", len(config.Headers.DropHeaders),
Expand Down
18 changes: 18 additions & 0 deletions config/paths.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,24 @@ func PathRedirectAllowListed(path string, configuration *shared.WiretapConfigura
return false
}

func IgnoreValidationOnPath(path string, configuration *shared.WiretapConfiguration) bool {
for _, redirectPath := range configuration.CompiledIgnoreValidations {
if redirectPath.CompiledPath.Match(path) {
return true
}
}
return false
}

func PathValidationAllowListed(path string, configuration *shared.WiretapConfiguration) bool {
for _, redirectPath := range configuration.CompiledIgnoreValidations {
if redirectPath.CompiledPath.Match(path) {
return true
}
}
return false
}

func RewritePath(path string, configuration *shared.WiretapConfiguration) string {
paths := FindPaths(path, configuration)
var replaced string = path
Expand Down
2 changes: 2 additions & 0 deletions config/paths_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,3 +308,5 @@ func TestRedirectAllowList_NoPathsRegistered(t *testing.T) {
assert.False(t, ignore)

}

// TODO: add tests for new validation functions
14 changes: 9 additions & 5 deletions daemon/handle_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,17 +131,21 @@ func (ws *WiretapService) handleHttpRequest(request *model.Request) {

ws.config.Logger.Info("[wiretap] handling API request", "url", request.HttpRequest.URL.String())

// check if we're going to fail hard on validation errors. (default is to skip this)
if ws.config.HardErrors && !ws.config.MockMode {
if ws.config.MockMode {
// TODO: Add logging

} else if configModel.IgnoreValidationOnPath(apiRequest.URL.Path, ws.config) && !configModel.PathValidationAllowListed(apiRequest.URL.Path, ws.config) {
// TODO: Add logging

// check if we're going to fail hard on validation errors. (default is to skip this)
} else if ws.config.HardErrors {

// validate the request synchronously
requestErrors = ws.ValidateRequest(request, newReq)

} else {
// validate the request asynchronously
if !ws.config.MockMode {
go ws.ValidateRequest(request, newReq)
}
go ws.ValidateRequest(request, newReq)
}

// short-circuit if we're using mock mode, there is no API call to make.
Expand Down
12 changes: 2 additions & 10 deletions daemon/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,8 @@ func (ws *WiretapService) ValidateRequest(
_, validationErrors = validator.ValidateHttpRequest(httpRequest)
}

pm := false
for i := range validationErrors {
if validationErrors[i].IsPathMissingError() {
if !pm {
cleanedErrors = append(cleanedErrors, validationErrors[i])
pm = true
}
} else {
cleanedErrors = append(cleanedErrors, validationErrors[i])
}
for _, validationError := range validationErrors {
cleanedErrors = append(cleanedErrors, validationError)
}
// record results
buildTransConfig := HttpTransactionConfig{
Expand Down
112 changes: 68 additions & 44 deletions shared/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,51 +13,55 @@ import (
)

type WiretapConfiguration struct {
Contract string `json:"-" yaml:"-"`
RedirectHost string `json:"redirectHost,omitempty" yaml:"redirectHost,omitempty"`
RedirectPort string `json:"redirectPort,omitempty" yaml:"redirectPort,omitempty"`
RedirectBasePath string `json:"redirectBasePath,omitempty" yaml:"redirectBasePath,omitempty"`
RedirectProtocol string `json:"redirectProtocol,omitempty" yaml:"redirectProtocol,omitempty"`
RedirectURL string `json:"redirectURL,omitempty" yaml:"redirectURL,omitempty"`
Port string `json:"port,omitempty" yaml:"port,omitempty"`
MonitorPort string `json:"monitorPort,omitempty" yaml:"monitorPort,omitempty"`
WebSocketHost string `json:"webSocketHost,omitempty" yaml:"webSocketHost,omitempty"`
WebSocketPort string `json:"webSocketPort,omitempty" yaml:"webSocketPort,omitempty"`
GlobalAPIDelay int `json:"globalAPIDelay,omitempty" yaml:"globalAPIDelay,omitempty"`
StaticDir string `json:"staticDir,omitempty" yaml:"staticDir,omitempty"`
StaticIndex string `json:"staticIndex,omitempty" yaml:"staticIndex,omitempty"`
PathConfigurations map[string]*WiretapPathConfig `json:"paths,omitempty" yaml:"paths,omitempty"`
Headers *WiretapHeaderConfig `json:"headers,omitempty" yaml:"headers,omitempty"`
StaticPaths []string `json:"staticPaths,omitempty" yaml:"staticPaths,omitempty"`
Variables map[string]string `json:"variables,omitempty" yaml:"variables,omitempty"`
Spec string `json:"contract,omitempty" yaml:"contract,omitempty"`
Certificate string `json:"certificate,omitempty" yaml:"certificate,omitempty"`
CertificateKey string `json:"certificateKey,omitempty" yaml:"certificateKey,omitempty"`
HardErrors bool `json:"hardValidation,omitempty" yaml:"hardValidation,omitempty"`
HardErrorCode int `json:"hardValidationCode,omitempty" yaml:"hardValidationCode,omitempty"`
HardErrorReturnCode int `json:"hardValidationReturnCode,omitempty" yaml:"hardValidationReturnCode,omitempty"`
PathDelays map[string]int `json:"pathDelays,omitempty" yaml:"pathDelays,omitempty"`
MockMode bool `json:"mockMode,omitempty" yaml:"mockMode,omitempty"`
MockModePretty bool `json:"mockModePretty,omitempty" yaml:"mockModePretty,omitempty"`
Base string `json:"base,omitempty" yaml:"base,omitempty"`
HAR string `json:"har,omitempty" yaml:"har,omitempty"`
HARValidate bool `json:"harValidate,omitempty" yaml:"harValidate,omitempty"`
HARPathAllowList []string `json:"harPathAllowList,omitempty" yaml:"harPathAllowList,omitempty"`
StreamReport bool `json:"streamReport,omitempty" yaml:"streamReport,omitempty"`
ReportFile string `json:"reportFilename,omitempty" yaml:"reportFilename,omitempty"`
IgnoreRedirects []string `json:"ignoreRedirects,omitempty" yaml:"ignoreRedirects,omitempty"`
RedirectAllowList []string `json:"redirectAllowList,omitempty" yaml:"redirectAllowList,omitempty"`
Contract string `json:"-" yaml:"-"`
RedirectHost string `json:"redirectHost,omitempty" yaml:"redirectHost,omitempty"`
RedirectPort string `json:"redirectPort,omitempty" yaml:"redirectPort,omitempty"`
RedirectBasePath string `json:"redirectBasePath,omitempty" yaml:"redirectBasePath,omitempty"`
RedirectProtocol string `json:"redirectProtocol,omitempty" yaml:"redirectProtocol,omitempty"`
RedirectURL string `json:"redirectURL,omitempty" yaml:"redirectURL,omitempty"`
Port string `json:"port,omitempty" yaml:"port,omitempty"`
MonitorPort string `json:"monitorPort,omitempty" yaml:"monitorPort,omitempty"`
WebSocketHost string `json:"webSocketHost,omitempty" yaml:"webSocketHost,omitempty"`
WebSocketPort string `json:"webSocketPort,omitempty" yaml:"webSocketPort,omitempty"`
GlobalAPIDelay int `json:"globalAPIDelay,omitempty" yaml:"globalAPIDelay,omitempty"`
StaticDir string `json:"staticDir,omitempty" yaml:"staticDir,omitempty"`
StaticIndex string `json:"staticIndex,omitempty" yaml:"staticIndex,omitempty"`
PathConfigurations map[string]*WiretapPathConfig `json:"paths,omitempty" yaml:"paths,omitempty"`
Headers *WiretapHeaderConfig `json:"headers,omitempty" yaml:"headers,omitempty"`
StaticPaths []string `json:"staticPaths,omitempty" yaml:"staticPaths,omitempty"`
Variables map[string]string `json:"variables,omitempty" yaml:"variables,omitempty"`
Spec string `json:"contract,omitempty" yaml:"contract,omitempty"`
Certificate string `json:"certificate,omitempty" yaml:"certificate,omitempty"`
CertificateKey string `json:"certificateKey,omitempty" yaml:"certificateKey,omitempty"`
HardErrors bool `json:"hardValidation,omitempty" yaml:"hardValidation,omitempty"`
HardErrorCode int `json:"hardValidationCode,omitempty" yaml:"hardValidationCode,omitempty"`
HardErrorReturnCode int `json:"hardValidationReturnCode,omitempty" yaml:"hardValidationReturnCode,omitempty"`
PathDelays map[string]int `json:"pathDelays,omitempty" yaml:"pathDelays,omitempty"`
MockMode bool `json:"mockMode,omitempty" yaml:"mockMode,omitempty"`
MockModePretty bool `json:"mockModePretty,omitempty" yaml:"mockModePretty,omitempty"`
Base string `json:"base,omitempty" yaml:"base,omitempty"`
HAR string `json:"har,omitempty" yaml:"har,omitempty"`
HARValidate bool `json:"harValidate,omitempty" yaml:"harValidate,omitempty"`
HARPathAllowList []string `json:"harPathAllowList,omitempty" yaml:"harPathAllowList,omitempty"`
StreamReport bool `json:"streamReport,omitempty" yaml:"streamReport,omitempty"`
ReportFile string `json:"reportFilename,omitempty" yaml:"reportFilename,omitempty"`
IgnoreRedirects []string `json:"ignoreRedirects,omitempty" yaml:"ignoreRedirects,omitempty"`
RedirectAllowList []string `json:"redirectAllowList,omitempty" yaml:"redirectAllowList,omitempty"`
WebsocketConfigs map[string]*WiretapWebsocketConfig `json:"websockets" yaml:"websockets"`
HARFile *harhar.HAR `json:"-" yaml:"-"`
CompiledPathDelays map[string]*CompiledPathDelay `json:"-" yaml:"-"`
CompiledVariables map[string]*CompiledVariable `json:"-" yaml:"-"`
Version string `json:"-" yaml:"-"`
StaticPathsCompiled []glob.Glob `json:"-" yaml:"-"`
CompiledPaths map[string]*CompiledPath `json:"-"`
CompiledIgnoreRedirects []*CompiledRedirect `json:"-" yaml:"-"`
CompiledRedirectAllowList []*CompiledRedirect `json:"-" yaml:"-"`
FS embed.FS `json:"-"`
Logger *slog.Logger
IgnoreValidation []string `json:"ignoreValidation,omitempty" yaml:"ignoreValidation,omitempty"`
ValidationAllowList []string `json:"validationAllowList,omitempty" yaml:"validationAllowList,omitempty"`
HARFile *harhar.HAR `json:"-" yaml:"-"`
CompiledPathDelays map[string]*CompiledPathDelay `json:"-" yaml:"-"`
CompiledVariables map[string]*CompiledVariable `json:"-" yaml:"-"`
Version string `json:"-" yaml:"-"`
StaticPathsCompiled []glob.Glob `json:"-" yaml:"-"`
CompiledPaths map[string]*CompiledPath `json:"-"`
CompiledIgnoreRedirects []*CompiledRedirect `json:"-" yaml:"-"`
CompiledRedirectAllowList []*CompiledRedirect `json:"-" yaml:"-"`
CompiledIgnoreValidations []*CompiledRedirect `json:"-" yaml:"-"`
CompiledValidationAllowList []*CompiledRedirect `json:"-" yaml:"-"`
FS embed.FS `json:"-"`
Logger *slog.Logger
}

func (wtc *WiretapConfiguration) CompilePaths() {
Expand Down Expand Up @@ -116,6 +120,26 @@ func (wtc *WiretapConfiguration) CompileRedirectAllowList() {
}
}

func (wtc *WiretapConfiguration) CompileIgnoreValidations() {
wtc.CompiledIgnoreValidations = make([]*CompiledRedirect, 0)
for _, x := range wtc.IgnoreValidation {
compiled := &CompiledRedirect{
CompiledPath: glob.MustCompile(wtc.ReplaceWithVariables(x)),
}
wtc.CompiledIgnoreValidations = append(wtc.CompiledIgnoreValidations, compiled)
}
}

func (wtc *WiretapConfiguration) CompileValidationAllowList() {
wtc.CompiledValidationAllowList = make([]*CompiledRedirect, 0)
for _, x := range wtc.ValidationAllowList {
compiled := &CompiledRedirect{
CompiledPath: glob.MustCompile(wtc.ReplaceWithVariables(x)),
}
wtc.CompiledValidationAllowList = append(wtc.CompiledValidationAllowList, compiled)
}
}

func (wtc *WiretapConfiguration) ReplaceWithVariables(input string) string {
for x := range wtc.Variables {
if wtc.Variables[x] != "" && wtc.CompiledVariables[x] != nil {
Expand Down

0 comments on commit c05b7e8

Please sign in to comment.