Skip to content

Commit 2c5fea8

Browse files
committed
Added new header drop feature
cleaned up regex handling for case sensitivity (had to remove viper) and also added query param to all rewrites. Signed-off-by: Dave Shanley <[email protected]>
1 parent e05f703 commit 2c5fea8

File tree

11 files changed

+273
-207
lines changed

11 files changed

+273
-207
lines changed

README.md

+11
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,17 @@ paths:
2727
'^/pb33f/(\w+)/test/': ''
2828
```
2929
30+
## Dropping certain headers
31+
32+
To prevent certain headers from being proxies, you can drop them using the `headers` config property and the `drop` property
33+
which is an array of headers to drop from all outbound requests..
34+
35+
```yaml
36+
headers:
37+
drop:
38+
- Origin
39+
```
40+
3041
## Command Line Interface
3142

3243
### Available Flags

cmd/root_command.go

+77-115
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@ package cmd
55

66
import (
77
"embed"
8-
"github.com/mitchellh/mapstructure"
8+
"gopkg.in/yaml.v3"
99
"net/url"
1010
"os"
1111

1212
"github.com/pb33f/wiretap/shared"
1313
"github.com/pterm/pterm"
1414
"github.com/spf13/cobra"
15-
"github.com/spf13/viper"
1615
)
1716

1817
var (
@@ -33,89 +32,24 @@ var (
3332

3433
configFlag, _ := cmd.Flags().GetString("config")
3534

36-
if configFlag == "" {
37-
pterm.Info.Println("Attempting to locate wiretap configuration...")
38-
viper.SetConfigFile(".wiretap")
39-
viper.SetConfigType("env")
40-
viper.AddConfigPath("$HOME/.wiretap")
41-
viper.AddConfigPath(".")
42-
} else {
43-
viper.SetConfigFile(configFlag)
44-
}
45-
46-
cerr := viper.ReadInConfig()
47-
if cerr != nil && configFlag != "" {
48-
pterm.Error.Printf("No wiretap configuration located. Using defaults: %s\n", cerr.Error())
49-
}
50-
if cerr != nil && configFlag == "" {
51-
pterm.Info.Println("No wiretap configuration located. Using defaults.")
52-
}
53-
if cerr == nil {
54-
pterm.Info.Printf("Located configuration file at: %s\n", viper.ConfigFileUsed())
55-
}
56-
5735
var spec string
5836
var port string
5937
var monitorPort string
6038
var wsPort string
6139
var staticDir string
62-
var pathConfigurations map[string]*shared.WiretapPathConfig
40+
6341
var redirectHost string
6442
var redirectPort string
6543
var redirectScheme string
6644
var redirectBasePath string
6745
var redirectURL string
6846
var globalAPIDelay int
6947

70-
// extract from wiretap environment variables.
71-
if viper.IsSet("PORT") {
72-
port = viper.GetString("PORT")
73-
}
74-
75-
if viper.IsSet("SPEC") {
76-
spec = viper.GetString("SPEC")
77-
}
78-
79-
if viper.IsSet("MONITOR_PORT") {
80-
monitorPort = viper.GetString("MONITOR_PORT")
81-
}
82-
83-
if viper.IsSet("WEBSOCKET_PORT") {
84-
wsPort = viper.GetString("WEBSOCKET_PORT")
85-
}
86-
87-
if viper.IsSet("STATIC_DIR") {
88-
staticDir = viper.GetString("STATIC_DIR")
89-
}
90-
91-
if viper.IsSet("PATHS") {
92-
paths := viper.Get("PATHS")
93-
var pc map[string]*shared.WiretapPathConfig
94-
err := mapstructure.Decode(paths, &pc)
95-
if err != nil {
96-
pterm.Error.Printf("Unable to decode paths from configuration: %s\n", err.Error())
97-
} else {
98-
// print out the path configurations.
99-
printLoadedPathConfigurations(pc)
100-
pathConfigurations = pc
101-
}
102-
}
103-
104-
if viper.IsSet("REDIRECT_URL") {
105-
redirectURL = viper.GetString("REDIRECT_URL")
106-
}
107-
108-
if viper.IsSet("GLOBAL_API_DELAY") {
109-
globalAPIDelay = viper.GetInt("GLOBAL_API_DELAY")
110-
}
111-
11248
portFlag, _ := cmd.Flags().GetString("port")
11349
if portFlag != "" {
11450
port = portFlag
11551
} else {
116-
if port == "" {
117-
port = "9090" // default
118-
}
52+
port = "9090" // default
11953
}
12054

12155
specFlag, _ := cmd.Flags().GetString("spec")
@@ -127,9 +61,7 @@ var (
12761
if monitorPortFlag != "" {
12862
monitorPort = monitorPortFlag
12963
} else {
130-
if monitorPort == "" {
131-
monitorPort = "9091" // default
132-
}
64+
monitorPort = "9091" // default
13365
}
13466

13567
staticDirFlag, _ := cmd.Flags().GetString("static")
@@ -141,18 +73,11 @@ var (
14173
if wsPortFlag != "" {
14274
wsPort = wsPortFlag
14375
} else {
144-
if wsPort == "" {
145-
wsPort = "9092" // default
146-
}
76+
wsPort = "9092" // default
14777
}
14878

14979
redirectURLFlag, _ := cmd.Flags().GetString("url")
15080
if redirectURLFlag != "" {
151-
152-
if pathConfigurations != nil {
153-
// warn the user that the path configurations will trump the switch
154-
pterm.Warning.Println("Using the --url flag will be *overridden* by the path configuration 'target' setting")
155-
}
15681
redirectURL = redirectURLFlag
15782
}
15883

@@ -161,6 +86,27 @@ var (
16186
globalAPIDelay = globalAPIDelayFlag
16287
}
16388

89+
var config shared.WiretapConfiguration
90+
if configFlag != "" {
91+
92+
cBytes, err := os.ReadFile(configFlag)
93+
if err != nil {
94+
pterm.Error.Printf("Failed to read wiretap configuration '%s': %s\n", configFlag, err.Error())
95+
return err
96+
}
97+
err = yaml.Unmarshal(cBytes, &config)
98+
if err != nil {
99+
pterm.Error.Printf("Failed to parse wiretap configuration '%s': %s\n", configFlag, err.Error())
100+
return err
101+
}
102+
pterm.Info.Printf("Loaded wiretap configuration '%s'...\n\n", configFlag)
103+
if config.RedirectURL != "" {
104+
redirectURL = config.RedirectURL
105+
}
106+
} else {
107+
pterm.Info.Println("No wiretap configuration located. Using defaults")
108+
}
109+
164110
if spec == "" {
165111
pterm.Warning.Println("No OpenAPI specification provided. " +
166112
"Please provide a path to an OpenAPI specification using the --spec or -s flags.")
@@ -177,48 +123,64 @@ var (
177123
return nil
178124
}
179125

180-
if redirectURL != "" {
181-
parsedURL, e := url.Parse(redirectURL)
182-
if e != nil {
183-
pterm.Println()
184-
pterm.Error.Printf("URL is not valid. "+
185-
"Please provide a valid URL to redirect to. %s cannot be parsed\n\n", redirectURL)
186-
pterm.Println()
187-
return nil
188-
}
189-
if parsedURL.Scheme == "" || parsedURL.Host == "" {
190-
pterm.Println()
191-
pterm.Error.Printf("URL is not valid. "+
192-
"Please provide a valid URL to redirect to. %s cannot be parsed\n\n", redirectURL)
193-
pterm.Println()
194-
return nil
195-
}
196-
redirectHost = parsedURL.Hostname()
197-
redirectPort = parsedURL.Port()
198-
redirectScheme = parsedURL.Scheme
199-
redirectBasePath = parsedURL.Path
126+
parsedURL, e := url.Parse(redirectURL)
127+
if e != nil {
128+
pterm.Println()
129+
pterm.Error.Printf("URL is not valid. "+
130+
"Please provide a valid URL to redirect to. %s cannot be parsed\n\n", redirectURL)
131+
pterm.Println()
132+
return nil
200133
}
134+
if parsedURL.Scheme == "" || parsedURL.Host == "" {
135+
pterm.Println()
136+
pterm.Error.Printf("URL is not valid. "+
137+
"Please provide a valid URL to redirect to. %s cannot be parsed\n\n", redirectURL)
138+
pterm.Println()
139+
return nil
140+
}
141+
redirectHost = parsedURL.Hostname()
142+
redirectPort = parsedURL.Port()
143+
redirectScheme = parsedURL.Scheme
144+
redirectBasePath = parsedURL.Path
201145

202-
config := shared.WiretapConfiguration{
203-
Contract: spec,
204-
RedirectURL: redirectURL,
205-
RedirectHost: redirectHost,
206-
RedirectBasePath: redirectBasePath,
207-
RedirectPort: redirectPort,
208-
RedirectProtocol: redirectScheme,
209-
Port: port,
210-
MonitorPort: monitorPort,
211-
GlobalAPIDelay: globalAPIDelay,
212-
WebSocketPort: wsPort,
213-
StaticDir: staticDir,
214-
PathConfigurations: pathConfigurations,
215-
FS: FS,
146+
config.Contract = spec
147+
config.RedirectURL = redirectURL
148+
config.RedirectHost = redirectHost
149+
config.RedirectBasePath = redirectBasePath
150+
config.RedirectPort = redirectPort
151+
config.RedirectProtocol = redirectScheme
152+
if config.Port == "" {
153+
config.Port = port
154+
}
155+
if config.MonitorPort == "" {
156+
config.MonitorPort = monitorPort
157+
}
158+
if config.WebSocketPort == "" {
159+
config.WebSocketPort = wsPort
216160
}
161+
if config.GlobalAPIDelay == 0 {
162+
config.GlobalAPIDelay = globalAPIDelay
163+
}
164+
if config.StaticDir == "" {
165+
config.StaticDir = staticDir
166+
}
167+
config.FS = FS
217168

218-
if len(pathConfigurations) > 0 {
169+
if len(config.PathConfigurations) > 0 {
170+
printLoadedPathConfigurations(config.PathConfigurations)
219171
config.CompilePaths()
220172
}
221173

174+
if config.Headers != nil && len(config.Headers.DropHeaders) > 0 {
175+
176+
pterm.Info.Printf("Dropping the following %d %s:\n", len(config.Headers.DropHeaders),
177+
shared.Pluralize(len(config.Headers.DropHeaders), "header", "headers"))
178+
for _, header := range config.Headers.DropHeaders {
179+
pterm.Printf("🗑️ %s\n", pterm.LightMagenta(header))
180+
}
181+
pterm.Println()
182+
}
183+
222184
// ready to boot, let's go!
223185
_, pErr := runWiretapService(&config)
224186

config/paths_test.go

+47-4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/pb33f/wiretap/shared"
99
"github.com/spf13/viper"
1010
"github.com/stretchr/testify/assert"
11+
"gopkg.in/yaml.v3"
1112
"strings"
1213
"testing"
1314
)
@@ -36,7 +37,6 @@ paths:
3637
PathConfigurations: pc,
3738
}
3839

39-
// compile paths
4040
wcConfig.CompilePaths()
4141

4242
res := FindPaths("/pb33f/test/123", wcConfig)
@@ -74,7 +74,6 @@ paths:
7474
PathConfigurations: pc,
7575
}
7676

77-
// compile paths
7877
wcConfig.CompilePaths()
7978

8079
path := RewritePath("/pb33f/test/123/slap/a/chap", wcConfig)
@@ -106,7 +105,6 @@ paths:
106105
PathConfigurations: pc,
107106
}
108107

109-
// compile paths
110108
wcConfig.CompilePaths()
111109

112110
path := RewritePath("/pb33f/cakes/test/123/smelly/jelly", wcConfig)
@@ -138,10 +136,55 @@ paths:
138136
PathConfigurations: pc,
139137
}
140138

141-
// compile paths
142139
wcConfig.CompilePaths()
143140

144141
path := RewritePath("/pb33f/cakes/test/lemons/321/smelly/jelly", wcConfig)
145142
assert.Equal(t, "https://localhost:9093/slippy/cakes/whip/321/lemons/smelly/jelly", path)
146143

147144
}
145+
146+
func TestRewritePath_Secure_With_Variables_CaseSensitive(t *testing.T) {
147+
148+
config := `
149+
paths:
150+
/en-US/burgerd/__raw/*:
151+
target: localhost:80
152+
pathRewrite:
153+
'^/en-US/burgerd/__raw/(\w+)/nobody/': '$1/-/'
154+
/en-US/burgerd/services/*:
155+
target: locahost:80
156+
pathRewrite:
157+
'^/en-US/burgerd/services': '/services'`
158+
159+
var c shared.WiretapConfiguration
160+
_ = yaml.Unmarshal([]byte(config), &c)
161+
162+
c.CompilePaths()
163+
164+
path := RewritePath("/en-US/burgerd/__raw/noKetchupPlease/nobody/", &c)
165+
assert.Equal(t, "http://localhost:80/noKetchupPlease/-/", path)
166+
167+
}
168+
169+
func TestRewritePath_Secure_With_Variables_CaseSensitive_AndQuery(t *testing.T) {
170+
171+
config := `
172+
paths:
173+
/en-US/burgerd/__raw/*:
174+
target: localhost:80
175+
pathRewrite:
176+
'^/en-US/burgerd/__raw/(\w+)/nobody/': '$1/-/'
177+
/en-US/burgerd/services/*:
178+
target: locahost:80
179+
pathRewrite:
180+
'^/en-US/burgerd/services': '/services'`
181+
182+
var c shared.WiretapConfiguration
183+
_ = yaml.Unmarshal([]byte(config), &c)
184+
185+
c.CompilePaths()
186+
187+
path := RewritePath("/en-US/burgerd/__raw/noKetchupPlease/nobody/yummy/yum?onions=true", &c)
188+
assert.Equal(t, "http://localhost:80/noKetchupPlease/-/yummy/yum?onions=true", path)
189+
190+
}

daemon/api.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ func (ws *WiretapService) callAPI(req *http.Request) (*http.Response, error) {
5151
replaced := config.RewritePath(req.URL.Path, wiretapConfig)
5252
if replaced != "" {
5353
newUrl, _ := url.Parse(replaced)
54-
pterm.Info.Printf("[wiretap] Re-writing path '%s' to '%s'\n", req.URL.Path, replaced)
54+
if req.URL.RawQuery != "" {
55+
newUrl.RawQuery = req.URL.RawQuery
56+
}
57+
pterm.Info.Printf("[wiretap] Re-writing path '%s' to '%s'\n", req.URL.String(), newUrl.String())
5558
req.URL = newUrl
5659
}
5760

0 commit comments

Comments
 (0)