Skip to content

Commit 3311d0f

Browse files
authored
feat: redesign logger, error and event handling (#65)
Signed-off-by: Kohei Morita <moritakouhei@graffer.jp>
1 parent ba986ab commit 3311d0f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+800
-450
lines changed

action/action.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
package action
22

3-
import (
4-
"fmt"
5-
)
3+
import "errors"
4+
5+
var _ error = (*BlockError)(nil)
66

77
type BlockError struct {
88
RuleID string
99
Inspector string
1010
}
1111

1212
func (e *BlockError) Error() string {
13-
return fmt.Sprintf("blocked by rule %s with inspector %s", e.RuleID, e.Inspector)
13+
return "request blocked by WAF"
14+
}
15+
16+
func IsBlockError(err error) bool {
17+
var blockErr *BlockError
18+
return errors.As(err, &blockErr)
1419
}

action/handler.go

Lines changed: 0 additions & 37 deletions
This file was deleted.

action/handler_test.go

Lines changed: 0 additions & 92 deletions
This file was deleted.

contrib/99designs/gqlgen/waf_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ func TestWafMiddleware(t *testing.T) {
9595
"text": "<script>alert(1)</script>",
9696
},
9797
waffleRule: blockRuleGraphQLRequestVariables,
98-
expectStatus: http.StatusOK,
99-
expectBody: `{"errors":[{"message":"RequestBlocked",`,
98+
expectStatus: http.StatusForbidden,
99+
expectBody: `{"error": "access denied. Sorry, you cannnot access this resource. Please contact the customer support."}`,
100100
},
101101
}
102102

contrib/gin-gonic/gin/waf_test.go

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package gin_test
2+
3+
import (
4+
_ "github.com/mattn/go-sqlite3"
5+
6+
"bytes"
7+
"context"
8+
"net/http"
9+
"net/http/httptest"
10+
"net/url"
11+
"testing"
12+
13+
"github.com/gin-gonic/gin"
14+
"github.com/sitebatch/waffle-go"
15+
"github.com/sitebatch/waffle-go/action"
16+
ginWaf "github.com/sitebatch/waffle-go/contrib/gin-gonic/gin"
17+
waffleOs "github.com/sitebatch/waffle-go/contrib/os"
18+
"github.com/sitebatch/waffle-go/waf"
19+
"github.com/stretchr/testify/assert"
20+
"github.com/stretchr/testify/require"
21+
)
22+
23+
type requestParams struct {
24+
File string `form:"file" json:"file"`
25+
}
26+
27+
type mockEventExporter struct {
28+
events []waf.DetectionEvent
29+
}
30+
31+
func (m *mockEventExporter) Export(_ context.Context, events waf.ReadOnlyDetectionEvents) error {
32+
m.events = append(m.events, events.Events()...)
33+
34+
return nil
35+
}
36+
37+
func TestWafMiddleware(t *testing.T) {
38+
r := setupRouter()
39+
40+
testCases := map[string]struct {
41+
req *http.Request
42+
wantStatusCode int
43+
wantResponseBody string
44+
wantDetectionRuleIDs []string
45+
}{
46+
"Successful read file": {
47+
req: func() *http.Request {
48+
form := url.Values{}
49+
form.Add("file", "README.md")
50+
body := bytes.NewBufferString(form.Encode())
51+
r := httptest.NewRequest("POST", "/file", body)
52+
r.Header.Add("Content-Type", "application/x-www-form-urlencoded")
53+
return r
54+
}(),
55+
wantStatusCode: 200,
56+
wantResponseBody: `file read successful`,
57+
wantDetectionRuleIDs: []string{},
58+
},
59+
"Failed read file": {
60+
req: func() *http.Request {
61+
form := url.Values{}
62+
form.Add("file", "non_existent_file.md")
63+
body := bytes.NewBufferString(form.Encode())
64+
r := httptest.NewRequest("POST", "/file", body)
65+
r.Header.Add("Content-Type", "application/x-www-form-urlencoded")
66+
return r
67+
}(),
68+
wantStatusCode: 500,
69+
wantResponseBody: `file read error`,
70+
wantDetectionRuleIDs: []string{},
71+
},
72+
"Block read sensitive file": {
73+
req: func() *http.Request {
74+
form := url.Values{}
75+
form.Add("file", "/var/run/secrets/path/to/file")
76+
body := bytes.NewBufferString(form.Encode())
77+
r := httptest.NewRequest("POST", "/file", body)
78+
r.Header.Add("Content-Type", "application/x-www-form-urlencoded")
79+
return r
80+
}(),
81+
wantStatusCode: 403,
82+
wantResponseBody: `request blocked`,
83+
wantDetectionRuleIDs: []string{"sensitive-file-opened"},
84+
},
85+
}
86+
87+
for name, tt := range testCases {
88+
t.Run(name, func(t *testing.T) {
89+
eventExporter := &mockEventExporter{}
90+
waffle.SetExporter(eventExporter)
91+
waffle.SetBlockResponseTemplateHTML([]byte("request blocked"))
92+
require.NoError(t, waffle.Start())
93+
94+
w := httptest.NewRecorder()
95+
96+
r.ServeHTTP(w, tt.req)
97+
assert.Equal(t, tt.wantStatusCode, w.Code)
98+
assert.Equal(t, tt.wantResponseBody, w.Body.String())
99+
100+
ruleIDs := make([]string, 0, len(eventExporter.events))
101+
for _, evt := range eventExporter.events {
102+
ruleIDs = append(ruleIDs, evt.Rule.ID)
103+
}
104+
105+
assert.Equal(t, tt.wantDetectionRuleIDs, ruleIDs)
106+
})
107+
}
108+
}
109+
110+
func setupRouter() *gin.Engine {
111+
r := gin.Default()
112+
r.Use(ginWaf.WafMiddleware())
113+
r.POST("/file", func(c *gin.Context) {
114+
readFile(c)
115+
})
116+
return r
117+
}
118+
119+
func readFile(c *gin.Context) {
120+
var req requestParams
121+
if err := c.ShouldBind(&req); err != nil {
122+
c.Data(http.StatusBadRequest, "text/html", []byte("bad request"))
123+
return
124+
}
125+
126+
if _, err := waffleOs.ProtectReadFile(c.Request.Context(), req.File); err != nil {
127+
if action.IsBlockError(err) {
128+
// WAF has already handled the block response.
129+
return
130+
}
131+
132+
c.Data(http.StatusInternalServerError, "text/html", []byte("file read error"))
133+
return
134+
}
135+
136+
c.Data(http.StatusOK, "text/html", []byte("file read successful"))
137+
}

contrib/labstack/echo/waf_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func TestWafMiddleware(t *testing.T) {
5656

5757
if tt.expectErr {
5858
assert.Error(t, actual)
59-
assert.Contains(t, actual.Error(), "blocked by rule sensitive-file-opened")
59+
assert.Contains(t, actual.Error(), "request blocked by WAF")
6060
return
6161
}
6262

contrib/net/http/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ func main() {
1818
mux := http.NewServeMux()
1919
handler := waffleHttp.WafMiddleware(mux)
2020

21-
waffle.Start(waffle.WithDebug())
21+
waffle.Start()
2222

2323
srv := &http.Server{
2424
Addr: ":8000",

0 commit comments

Comments
 (0)