Skip to content

Commit

Permalink
feat: add disable (#6)
Browse files Browse the repository at this point in the history
* feat: add disable

* ci: run on ubuntu latest
  • Loading branch information
aeneasr authored Nov 3, 2021
1 parent a79786e commit 2dc2119
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ on:
push:
jobs:
build:
runs-on: ubuntu-16.04
runs-on: ubuntu-latest
strategy:
matrix:
go: [ '1.15', '1.14', '1.13' ]
Expand Down
33 changes: 33 additions & 0 deletions contract.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package nosurf

import "net/http"

type Handler interface {
http.Handler
// RegenerateToken regenerates a CSRF token and sets the cookie.
RegenerateToken(w http.ResponseWriter, r *http.Request) string

// ExemptPath will not require CSRF validation but will still set the
// cookie if it has not yet been set.
ExemptPath(string)

// IgnorePath will not require CSRF validation and also not set the CSRF
// cookie, but it will set the CSRF token (if available) in the request context.
IgnorePath(string)

// IgnoreGlob behaves similar to IgnorePath but allows defining a glob.
IgnoreGlob(string)

// IgnoreGlobs behaves similar to IgnorePath but allows defining globs.
IgnoreGlobs(...string)

// DisablePath will not require CSRF validation and also not set the CSRF
// cookie, and it will also not set the CSRF token in the request context.
DisablePath(string)

// DisableGlob behaves similar to DisablePath but allows defining a glob.
DisableGlob(string)

// DisableGlobs behaves similar to DisablePath but allows defining globs.
DisableGlobs(...string)
}
39 changes: 39 additions & 0 deletions disable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package nosurf

import (
"net/http"
pathModule "path"
)

// Disables the CSRF middleware for an exact path
// With this you should take note that Go's paths
// include a leading slash.
func (h *CSRFHandler) DisablePath(path string) {
h.disablePaths = append(h.disablePaths, path)
}

// Checks if the given request disables this middleware
func (h *CSRFHandler) IsDisabled(r *http.Request) bool {
path := r.URL.Path
if sContains(h.disablePaths, path) {
return true
}

// then the globs
for _, glob := range h.disableGlobs {
matched, err := pathModule.Match(glob, path)
if matched && err == nil {
return true
}
}

return false
}

func (h *CSRFHandler) DisableGlob(pattern string) {
h.disableGlobs = append(h.disableGlobs, pattern)
}

func (h *CSRFHandler) DisableGlobs(patterns ...string) {
h.disableGlobs = append(h.disableGlobs, patterns...)
}
45 changes: 45 additions & 0 deletions disable_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package nosurf

import (
"net/http"
"testing"
)

func TestDisablePath(t *testing.T) {
// the handler doesn't matter here, let's use nil
hand := New(nil)
path := "/home"
exempt, _ := http.NewRequest("GET", path, nil)

hand.DisablePath(path)
if !hand.IsDisabled(exempt) {
t.Errorf("%v is not exempt, but it should be", exempt.URL.Path)
}

other, _ := http.NewRequest("GET", "/faq", nil)
if hand.IsDisabled(other) {
t.Errorf("%v is exempt, but it shouldn't be", other.URL.Path)
}
}

func TestDisableGlob(t *testing.T) {
hand := New(nil)
glob := "/nail/*"

hand.DisableGlob(glob)

test, _ := http.NewRequest("GET", "/nail/foo", nil)
if !hand.IsDisabled(test) {
t.Errorf("%v should be exempt, but it isn't.", test)
}

test, _ = http.NewRequest("GET", "/nail/foo/bar", nil)
if hand.IsDisabled(test) {
t.Errorf("%v should not be exempt, but it is.", test)
}

test, _ = http.NewRequest("GET", "/not-nail/foo", nil)
if hand.IsDisabled(test) {
t.Errorf("%v should not be exempt, but it is.", test)
}
}
11 changes: 11 additions & 0 deletions handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ type CSRFHandler struct {
// ...or a glob (as used by path.Match()).
ignoreGlobs []string

// Slices of paths that completely disable this middleware.
disablePaths []string
// ...or a glob (as used by path.Match()).
disableGlobs []string

// All of those will be matched against Request.URL.Path,
// So they should take the leading slash into account
}
Expand Down Expand Up @@ -121,6 +126,11 @@ func (h CSRFHandler) getCookieName(w http.ResponseWriter, r *http.Request) strin
}

func (h *CSRFHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if h.IsDisabled(r) {
h.handleSuccess(w, r)
return
}

r = addNosurfContext(r)
defer ctxClear(r)

Expand Down Expand Up @@ -148,6 +158,7 @@ func (h *CSRFHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
} else {
ctxSetToken(r, realToken)
}

if h.IsIgnored(r) {
h.handleSuccess(w, r)
return
Expand Down

0 comments on commit 2dc2119

Please sign in to comment.