Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions blackwords.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ import (

// BlackWords middleware doesn't allow some words in the request body
func BlackWords(words ...string) func(http.Handler) http.Handler {
return blackWords(func() []string { return words })
}

// BlackWordsFn middleware uses func to get the list and doesn't allow some words in the request body.
// The func is called for every request, so the list can be changed at runtime.
func BlackWordsFn(fn func() []string) func(http.Handler) http.Handler {
return blackWords(fn)
}

func blackWords(wordsFn func() []string) func(http.Handler) http.Handler {

return func(h http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
Expand All @@ -23,7 +33,7 @@ func BlackWords(words ...string) func(http.Handler) http.Handler {

body := strings.ToLower(string(content))
if body != "" {
for _, word := range words {
for _, word := range wordsFn() {
if strings.Contains(body, strings.ToLower(word)) {
_ = EncodeJSON(w, http.StatusForbidden, JSON{"error": "one of blacklisted words detected"})
return
Expand All @@ -35,8 +45,3 @@ func BlackWords(words ...string) func(http.Handler) http.Handler {
return http.HandlerFunc(fn)
}
}

// BlackWordsFn middleware uses func to get the list and doesn't allow some words in the request body
func BlackWordsFn(fn func() []string) func(http.Handler) http.Handler {
return BlackWords(fn()...)
}
35 changes: 35 additions & 0 deletions blackwords_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import (
"fmt"
"net/http"
"net/http/httptest"
"sync"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestBlackwords(t *testing.T) {
Expand Down Expand Up @@ -124,3 +126,36 @@ func TestBlackwordsUnreadableBody(t *testing.T) {
assert.Equal(t, http.StatusBadRequest, w.Code)
assert.False(t, called, "handler must not run on a body that can't be inspected")
}

func TestBlackwordsFnDynamic(t *testing.T) {
var mu sync.Mutex
words := []string{"bad1"}
bwMiddleware := BlackWordsFn(func() []string {
mu.Lock()
defer mu.Unlock()
return words
})

ts := httptest.NewServer(bwMiddleware(getTestHandlerBlah()))
defer ts.Close()

send := func(body string) int {
req, err := http.NewRequest("POST", ts.URL+"/something", bytes.NewBufferString(body))
require.NoError(t, err)
resp, err := http.DefaultClient.Do(req)
require.NoError(t, err)
defer resp.Body.Close()
return resp.StatusCode
}

assert.Equal(t, http.StatusForbidden, send("has bad1 in it"))
assert.Equal(t, http.StatusOK, send("has bad2 in it"))

// the list is changed after the middleware was created, it should be picked up by the next request
mu.Lock()
words = []string{"bad2"}
mu.Unlock()

assert.Equal(t, http.StatusOK, send("has bad1 in it"))
assert.Equal(t, http.StatusForbidden, send("has bad2 in it"))
}