Giter VIP home page Giter VIP logo

shield's Introduction

Build Status codecov GoDoc Go Report Card

Shield

Shield is a net/http compatible middleware which blocks or allows requests based on a predicate. Shield replies back with a user defined response when the request is blocked.

Usage

Below you can find a example of how to configure the Shield middleware in order to allow only requests with GET method, and reply back with 405 Method Not Allowed in any other case.

package main

import (
	"net/http"

	"github.com/psampaz/shield"
)

func main() {

	shieldMiddleware := shield.New(shield.Options{
		Block: func(r *http.Request) bool {
			return r.Method != "GET"
		},
		Code:    http.StatusMethodNotAllowed,
		Headers: http.Header{"Content-Type": {"text/plain"}},
		Body:    []byte(http.StatusText(http.StatusMethodNotAllowed)),
	})
    
	helloWorldHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hello world"))
	})
    
	http.ListenAndServe(":8080", shieldMiddleware.Handler(helloWorldHandler))
}
$ curl -i -X GET localhost:8080

HTTP/1.1 200 OK
Date: Sat, 22 Feb 2020 10:03:35 GMT
Content-Length: 11
Content-Type: text/plain; charset=utf-8

hello world
$ curl -i -X POST localhost:8080

HTTP/1.1 400 Bad Request
Content-Type: text/plain
Date: Sat, 22 Feb 2020 10:02:31 GMT
Content-Length: 11

Bad Request

Passing a func as Block option, gives you access only in the current request. If there is a need to to use non request related data and functionality, you can you a stuct method with the same signature.

package main

import (
	"net/http"

	"github.com/psampaz/shield"
)

type BlockLogic struct {
	ShouldBLock bool
}

func (b *BlockLogic) Block(r *http.Request) bool {
	return b.ShouldBLock
}

func main() {
	blockLogic := BlockLogic{true}
	shieldMiddleware := shield.New(shield.Options{
		Block:   blockLogic.Block,
		Code:    http.StatusBadRequest,
		Headers: http.Header{"Content-Type": {"text/plain"}},
		Body:    []byte(http.StatusText(http.StatusBadRequest)),
	})

	helloWorldHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hello world"))
	})

	http.ListenAndServe(":8080", shieldMiddleware.Handler(helloWorldHandler))
}

Options

Shield middleware can be configured with the following options:

type Options struct {
	// Block is a predicate responsible for blocking the request.
	// Return true when the request should be blocked, false otherwise
	Block func(r *http.Request) bool
	// Code  is the status code of the response, sent when the request is blocked
	Code int
	// Headers are the headers of the response, sent when the request is blocked
	Headers http.Header
	// Body is the body of the response, sent when the request is blocked
	Body []byte
}

List of predefined block methods

Block based on a list of query param regexes

	queryBlock := blocker.NewQuery(map[string]string{
		"op":       "search",
		"page":     `\d+`,
		"v":        `[a-zA-Z]+`,
		"optional": `^$|\d`,
	})
	shieldMiddleware := shield.New(shield.Options{
		Block:   queryBlock.Block,
		Code:    http.StatusBadRequest,
		Headers: http.Header{"Content-Type": {"text/plain"}},
		Body:    []byte(http.StatusText(http.StatusBadRequest)),
	})

Block based on a list of HTTP Method

	methodBlock := blocker.NewMethod([]string{http.MethodGet, http.MethodPost})
	shieldMiddleware := shield.New(shield.Options{
		Block:   methodBlock.Block,
		Code:    http.StatusBadRequest,
		Headers: http.Header{"Content-Type": {"text/plain"}},
		Body:    []byte(http.StatusText(http.StatusBadRequest)),
	})

Block based on a list of HTTP Scheme

	schemeBlock := blocker.NewScheme([]string{"https"})
	shieldMiddleware := shield.New(shield.Options{
		Block:   schemeBlock.Block,
		Code:    http.StatusBadRequest,
		Headers: http.Header{"Content-Type": {"text/plain"}},
		Body:    []byte(http.StatusText(http.StatusBadRequest)),
	})

Integration with popular routers

Gorilla Mux

package main

import (
	"net/http"

	"github.com/psampaz/shield"

	"github.com/gorilla/mux"
)

func main() {
	shieldMiddleware := shield.New(shield.Options{
		Block: func(r *http.Request) bool {
			return true
		},
		Code:    http.StatusMethodNotAllowed,
		Headers: http.Header{"Content-Type": {"text/plain"}},
		Body:    []byte(http.StatusText(http.StatusMethodNotAllowed)),
	})

	r := mux.NewRouter()
	r.Use(shieldMiddleware.Handler)
	r.HandleFunc("/", HelloHandler)

	http.ListenAndServe(":8080", r)
}

func HelloHandler(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("hello world"))
}

Chi

package main

import (
	"net/http"

	"github.com/psampaz/shield"

	"github.com/go-chi/chi"
)

func main() {
	shieldMiddleware := shield.New(shield.Options{
		Block: func(r *http.Request) bool {
			return true
		},
		Code:    http.StatusMethodNotAllowed,
		Headers: http.Header{"Content-Type": {"text/plain"}},
		Body:    []byte(http.StatusText(http.StatusMethodNotAllowed)),
	})

	r := chi.NewRouter()
	r.Use(shieldMiddleware.Handler)
	r.Get("/", HelloHandler)

	http.ListenAndServe(":8080", r)
}

func HelloHandler(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("hello world"))
}

Echo

package main

import (
	"net/http"

	"github.com/psampaz/shield"

	"github.com/labstack/echo"
)

func main() {
	shieldMiddleware := shield.New(shield.Options{
		Block: func(r *http.Request) bool {
			return true
		},
		Code:    http.StatusMethodNotAllowed,
		Headers: http.Header{"Content-Type": {"text/plain"}},
		Body:    []byte(http.StatusText(http.StatusMethodNotAllowed)),
	})

	e := echo.New()
	e.Use(echo.WrapMiddleware(shieldMiddleware.Handler))

	e.GET("/", func(c echo.Context) error {
		return c.String(http.StatusOK, "Hello world")
	})

	e.Start((":8080"))
}

shield's People

Contributors

psampaz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.