summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/labstack/echo/middleware
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/labstack/echo/middleware')
-rw-r--r--vendor/github.com/labstack/echo/middleware/basic_auth.go86
-rw-r--r--vendor/github.com/labstack/echo/middleware/body_limit.go116
-rw-r--r--vendor/github.com/labstack/echo/middleware/compress.go121
-rw-r--r--vendor/github.com/labstack/echo/middleware/cors.go139
-rw-r--r--vendor/github.com/labstack/echo/middleware/csrf.go210
-rw-r--r--vendor/github.com/labstack/echo/middleware/jwt.go189
-rw-r--r--vendor/github.com/labstack/echo/middleware/key_auth.go133
-rw-r--r--vendor/github.com/labstack/echo/middleware/logger.go191
-rw-r--r--vendor/github.com/labstack/echo/middleware/method_override.go88
-rw-r--r--vendor/github.com/labstack/echo/middleware/middleware.go14
-rw-r--r--vendor/github.com/labstack/echo/middleware/recover.go85
-rw-r--r--vendor/github.com/labstack/echo/middleware/redirect.go215
-rw-r--r--vendor/github.com/labstack/echo/middleware/secure.go116
-rw-r--r--vendor/github.com/labstack/echo/middleware/slash.go119
-rw-r--r--vendor/github.com/labstack/echo/middleware/static.go118
15 files changed, 1940 insertions, 0 deletions
diff --git a/vendor/github.com/labstack/echo/middleware/basic_auth.go b/vendor/github.com/labstack/echo/middleware/basic_auth.go
new file mode 100644
index 00000000..e98a87e3
--- /dev/null
+++ b/vendor/github.com/labstack/echo/middleware/basic_auth.go
@@ -0,0 +1,86 @@
+package middleware
+
+import (
+ "encoding/base64"
+
+ "github.com/labstack/echo"
+)
+
+type (
+ // BasicAuthConfig defines the config for BasicAuth middleware.
+ BasicAuthConfig struct {
+ // Skipper defines a function to skip middleware.
+ Skipper Skipper
+
+ // Validator is a function to validate BasicAuth credentials.
+ // Required.
+ Validator BasicAuthValidator
+ }
+
+ // BasicAuthValidator defines a function to validate BasicAuth credentials.
+ BasicAuthValidator func(string, string, echo.Context) bool
+)
+
+const (
+ basic = "Basic"
+)
+
+var (
+ // DefaultBasicAuthConfig is the default BasicAuth middleware config.
+ DefaultBasicAuthConfig = BasicAuthConfig{
+ Skipper: DefaultSkipper,
+ }
+)
+
+// BasicAuth returns an BasicAuth middleware.
+//
+// For valid credentials it calls the next handler.
+// For missing or invalid credentials, it sends "401 - Unauthorized" response.
+func BasicAuth(fn BasicAuthValidator) echo.MiddlewareFunc {
+ c := DefaultBasicAuthConfig
+ c.Validator = fn
+ return BasicAuthWithConfig(c)
+}
+
+// BasicAuthWithConfig returns an BasicAuth middleware with config.
+// See `BasicAuth()`.
+func BasicAuthWithConfig(config BasicAuthConfig) echo.MiddlewareFunc {
+ // Defaults
+ if config.Validator == nil {
+ panic("basic-auth middleware requires a validator function")
+ }
+ if config.Skipper == nil {
+ config.Skipper = DefaultBasicAuthConfig.Skipper
+ }
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ if config.Skipper(c) {
+ return next(c)
+ }
+
+ auth := c.Request().Header.Get(echo.HeaderAuthorization)
+ l := len(basic)
+
+ if len(auth) > l+1 && auth[:l] == basic {
+ b, err := base64.StdEncoding.DecodeString(auth[l+1:])
+ if err != nil {
+ return err
+ }
+ cred := string(b)
+ for i := 0; i < len(cred); i++ {
+ if cred[i] == ':' {
+ // Verify credentials
+ if config.Validator(cred[:i], cred[i+1:], c) {
+ return next(c)
+ }
+ }
+ }
+ }
+
+ // Need to return `401` for browsers to pop-up login box.
+ c.Response().Header().Set(echo.HeaderWWWAuthenticate, basic+" realm=Restricted")
+ return echo.ErrUnauthorized
+ }
+ }
+}
diff --git a/vendor/github.com/labstack/echo/middleware/body_limit.go b/vendor/github.com/labstack/echo/middleware/body_limit.go
new file mode 100644
index 00000000..a2ff8d62
--- /dev/null
+++ b/vendor/github.com/labstack/echo/middleware/body_limit.go
@@ -0,0 +1,116 @@
+package middleware
+
+import (
+ "fmt"
+ "io"
+ "sync"
+
+ "github.com/labstack/echo"
+ "github.com/labstack/gommon/bytes"
+)
+
+type (
+ // BodyLimitConfig defines the config for BodyLimit middleware.
+ BodyLimitConfig struct {
+ // Skipper defines a function to skip middleware.
+ Skipper Skipper
+
+ // Maximum allowed size for a request body, it can be specified
+ // as `4x` or `4xB`, where x is one of the multiple from K, M, G, T or P.
+ Limit string `json:"limit"`
+ limit int64
+ }
+
+ limitedReader struct {
+ BodyLimitConfig
+ reader io.ReadCloser
+ read int64
+ context echo.Context
+ }
+)
+
+var (
+ // DefaultBodyLimitConfig is the default Gzip middleware config.
+ DefaultBodyLimitConfig = BodyLimitConfig{
+ Skipper: DefaultSkipper,
+ }
+)
+
+// BodyLimit returns a BodyLimit middleware.
+//
+// BodyLimit middleware sets the maximum allowed size for a request body, if the
+// size exceeds the configured limit, it sends "413 - Request Entity Too Large"
+// response. The BodyLimit is determined based on both `Content-Length` request
+// header and actual content read, which makes it super secure.
+// Limit can be specified as `4x` or `4xB`, where x is one of the multiple from K, M,
+// G, T or P.
+func BodyLimit(limit string) echo.MiddlewareFunc {
+ c := DefaultBodyLimitConfig
+ c.Limit = limit
+ return BodyLimitWithConfig(c)
+}
+
+// BodyLimitWithConfig returns a BodyLimit middleware with config.
+// See: `BodyLimit()`.
+func BodyLimitWithConfig(config BodyLimitConfig) echo.MiddlewareFunc {
+ // Defaults
+ if config.Skipper == nil {
+ config.Skipper = DefaultBodyLimitConfig.Skipper
+ }
+
+ limit, err := bytes.Parse(config.Limit)
+ if err != nil {
+ panic(fmt.Errorf("invalid body-limit=%s", config.Limit))
+ }
+ config.limit = limit
+ pool := limitedReaderPool(config)
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ if config.Skipper(c) {
+ return next(c)
+ }
+
+ req := c.Request()
+
+ // Based on content length
+ if req.ContentLength > config.limit {
+ return echo.ErrStatusRequestEntityTooLarge
+ }
+
+ // Based on content read
+ r := pool.Get().(*limitedReader)
+ r.Reset(req.Body, c)
+ defer pool.Put(r)
+ req.Body = r
+
+ return next(c)
+ }
+ }
+}
+
+func (r *limitedReader) Read(b []byte) (n int, err error) {
+ n, err = r.reader.Read(b)
+ r.read += int64(n)
+ if r.read > r.limit {
+ return n, echo.ErrStatusRequestEntityTooLarge
+ }
+ return
+}
+
+func (r *limitedReader) Close() error {
+ return r.reader.Close()
+}
+
+func (r *limitedReader) Reset(reader io.ReadCloser, context echo.Context) {
+ r.reader = reader
+ r.context = context
+}
+
+func limitedReaderPool(c BodyLimitConfig) sync.Pool {
+ return sync.Pool{
+ New: func() interface{} {
+ return &limitedReader{BodyLimitConfig: c}
+ },
+ }
+}
diff --git a/vendor/github.com/labstack/echo/middleware/compress.go b/vendor/github.com/labstack/echo/middleware/compress.go
new file mode 100644
index 00000000..eee67b37
--- /dev/null
+++ b/vendor/github.com/labstack/echo/middleware/compress.go
@@ -0,0 +1,121 @@
+package middleware
+
+import (
+ "bufio"
+ "compress/gzip"
+ "io"
+ "io/ioutil"
+ "net"
+ "net/http"
+ "strings"
+
+ "github.com/labstack/echo"
+)
+
+type (
+ // GzipConfig defines the config for Gzip middleware.
+ GzipConfig struct {
+ // Skipper defines a function to skip middleware.
+ Skipper Skipper
+
+ // Gzip compression level.
+ // Optional. Default value -1.
+ Level int `json:"level"`
+ }
+
+ gzipResponseWriter struct {
+ io.Writer
+ http.ResponseWriter
+ }
+)
+
+const (
+ gzipScheme = "gzip"
+)
+
+var (
+ // DefaultGzipConfig is the default Gzip middleware config.
+ DefaultGzipConfig = GzipConfig{
+ Skipper: DefaultSkipper,
+ Level: -1,
+ }
+)
+
+// Gzip returns a middleware which compresses HTTP response using gzip compression
+// scheme.
+func Gzip() echo.MiddlewareFunc {
+ return GzipWithConfig(DefaultGzipConfig)
+}
+
+// GzipWithConfig return Gzip middleware with config.
+// See: `Gzip()`.
+func GzipWithConfig(config GzipConfig) echo.MiddlewareFunc {
+ // Defaults
+ if config.Skipper == nil {
+ config.Skipper = DefaultGzipConfig.Skipper
+ }
+ if config.Level == 0 {
+ config.Level = DefaultGzipConfig.Level
+ }
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ if config.Skipper(c) {
+ return next(c)
+ }
+
+ res := c.Response()
+ res.Header().Add(echo.HeaderVary, echo.HeaderAcceptEncoding)
+ if strings.Contains(c.Request().Header.Get(echo.HeaderAcceptEncoding), gzipScheme) {
+ res.Header().Add(echo.HeaderContentEncoding, gzipScheme) // Issue #806
+ rw := res.Writer
+ w, err := gzip.NewWriterLevel(rw, config.Level)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ if res.Size == 0 {
+ if res.Header().Get(echo.HeaderContentEncoding) == gzipScheme {
+ res.Header().Del(echo.HeaderContentEncoding)
+ }
+ // We have to reset response to it's pristine state when
+ // nothing is written to body or error is returned.
+ // See issue #424, #407.
+ res.Writer = rw
+ w.Reset(ioutil.Discard)
+ }
+ w.Close()
+ }()
+ grw := &gzipResponseWriter{Writer: w, ResponseWriter: rw}
+ res.Writer = grw
+ }
+ return next(c)
+ }
+ }
+}
+
+func (w *gzipResponseWriter) WriteHeader(code int) {
+ if code == http.StatusNoContent { // Issue #489
+ w.ResponseWriter.Header().Del(echo.HeaderContentEncoding)
+ }
+ w.ResponseWriter.WriteHeader(code)
+}
+
+func (w *gzipResponseWriter) Write(b []byte) (int, error) {
+ if w.Header().Get(echo.HeaderContentType) == "" {
+ w.Header().Set(echo.HeaderContentType, http.DetectContentType(b))
+ }
+ return w.Writer.Write(b)
+}
+
+func (w *gzipResponseWriter) Flush() error {
+ return w.Writer.(*gzip.Writer).Flush()
+}
+
+func (w *gzipResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return w.ResponseWriter.(http.Hijacker).Hijack()
+}
+
+func (w *gzipResponseWriter) CloseNotify() <-chan bool {
+ return w.ResponseWriter.(http.CloseNotifier).CloseNotify()
+}
diff --git a/vendor/github.com/labstack/echo/middleware/cors.go b/vendor/github.com/labstack/echo/middleware/cors.go
new file mode 100644
index 00000000..c35fc36c
--- /dev/null
+++ b/vendor/github.com/labstack/echo/middleware/cors.go
@@ -0,0 +1,139 @@
+package middleware
+
+import (
+ "net/http"
+ "strconv"
+ "strings"
+
+ "github.com/labstack/echo"
+)
+
+type (
+ // CORSConfig defines the config for CORS middleware.
+ CORSConfig struct {
+ // Skipper defines a function to skip middleware.
+ Skipper Skipper
+
+ // AllowOrigin defines a list of origins that may access the resource.
+ // Optional. Default value []string{"*"}.
+ AllowOrigins []string `json:"allow_origins"`
+
+ // AllowMethods defines a list methods allowed when accessing the resource.
+ // This is used in response to a preflight request.
+ // Optional. Default value DefaultCORSConfig.AllowMethods.
+ AllowMethods []string `json:"allow_methods"`
+
+ // AllowHeaders defines a list of request headers that can be used when
+ // making the actual request. This in response to a preflight request.
+ // Optional. Default value []string{}.
+ AllowHeaders []string `json:"allow_headers"`
+
+ // AllowCredentials indicates whether or not the response to the request
+ // can be exposed when the credentials flag is true. When used as part of
+ // a response to a preflight request, this indicates whether or not the
+ // actual request can be made using credentials.
+ // Optional. Default value false.
+ AllowCredentials bool `json:"allow_credentials"`
+
+ // ExposeHeaders defines a whitelist headers that clients are allowed to
+ // access.
+ // Optional. Default value []string{}.
+ ExposeHeaders []string `json:"expose_headers"`
+
+ // MaxAge indicates how long (in seconds) the results of a preflight request
+ // can be cached.
+ // Optional. Default value 0.
+ MaxAge int `json:"max_age"`
+ }
+)
+
+var (
+ // DefaultCORSConfig is the default CORS middleware config.
+ DefaultCORSConfig = CORSConfig{
+ Skipper: DefaultSkipper,
+ AllowOrigins: []string{"*"},
+ AllowMethods: []string{echo.GET, echo.HEAD, echo.PUT, echo.PATCH, echo.POST, echo.DELETE},
+ }
+)
+
+// CORS returns a Cross-Origin Resource Sharing (CORS) middleware.
+// See: https://developer.mozilla.org/en/docs/Web/HTTP/Access_control_CORS
+func CORS() echo.MiddlewareFunc {
+ return CORSWithConfig(DefaultCORSConfig)
+}
+
+// CORSWithConfig returns a CORS middleware with config.
+// See: `CORS()`.
+func CORSWithConfig(config CORSConfig) echo.MiddlewareFunc {
+ // Defaults
+ if config.Skipper == nil {
+ config.Skipper = DefaultCORSConfig.Skipper
+ }
+ if len(config.AllowOrigins) == 0 {
+ config.AllowOrigins = DefaultCORSConfig.AllowOrigins
+ }
+ if len(config.AllowMethods) == 0 {
+ config.AllowMethods = DefaultCORSConfig.AllowMethods
+ }
+
+ allowMethods := strings.Join(config.AllowMethods, ",")
+ allowHeaders := strings.Join(config.AllowHeaders, ",")
+ exposeHeaders := strings.Join(config.ExposeHeaders, ",")
+ maxAge := strconv.Itoa(config.MaxAge)
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ if config.Skipper(c) {
+ return next(c)
+ }
+
+ req := c.Request()
+ res := c.Response()
+ origin := req.Header.Get(echo.HeaderOrigin)
+ allowOrigin := ""
+
+ // Check allowed origins
+ for _, o := range config.AllowOrigins {
+ if o == "*" || o == origin {
+ allowOrigin = o
+ break
+ }
+ }
+
+ // Simple request
+ if req.Method != echo.OPTIONS {
+ res.Header().Add(echo.HeaderVary, echo.HeaderOrigin)
+ res.Header().Set(echo.HeaderAccessControlAllowOrigin, allowOrigin)
+ if config.AllowCredentials {
+ res.Header().Set(echo.HeaderAccessControlAllowCredentials, "true")
+ }
+ if exposeHeaders != "" {
+ res.Header().Set(echo.HeaderAccessControlExposeHeaders, exposeHeaders)
+ }
+ return next(c)
+ }
+
+ // Preflight request
+ res.Header().Add(echo.HeaderVary, echo.HeaderOrigin)
+ res.Header().Add(echo.HeaderVary, echo.HeaderAccessControlRequestMethod)
+ res.Header().Add(echo.HeaderVary, echo.HeaderAccessControlRequestHeaders)
+ res.Header().Set(echo.HeaderAccessControlAllowOrigin, allowOrigin)
+ res.Header().Set(echo.HeaderAccessControlAllowMethods, allowMethods)
+ if config.AllowCredentials {
+ res.Header().Set(echo.HeaderAccessControlAllowCredentials, "true")
+ }
+ if allowHeaders != "" {
+ res.Header().Set(echo.HeaderAccessControlAllowHeaders, allowHeaders)
+ } else {
+ h := req.Header.Get(echo.HeaderAccessControlRequestHeaders)
+ if h != "" {
+ res.Header().Set(echo.HeaderAccessControlAllowHeaders, h)
+ }
+ }
+ if config.MaxAge > 0 {
+ res.Header().Set(echo.HeaderAccessControlMaxAge, maxAge)
+ }
+ return c.NoContent(http.StatusNoContent)
+ }
+ }
+}
diff --git a/vendor/github.com/labstack/echo/middleware/csrf.go b/vendor/github.com/labstack/echo/middleware/csrf.go
new file mode 100644
index 00000000..5bbeecb4
--- /dev/null
+++ b/vendor/github.com/labstack/echo/middleware/csrf.go
@@ -0,0 +1,210 @@
+package middleware
+
+import (
+ "crypto/subtle"
+ "errors"
+ "net/http"
+ "strings"
+ "time"
+
+ "github.com/labstack/echo"
+ "github.com/labstack/gommon/random"
+)
+
+type (
+ // CSRFConfig defines the config for CSRF middleware.
+ CSRFConfig struct {
+ // Skipper defines a function to skip middleware.
+ Skipper Skipper
+
+ // TokenLength is the length of the generated token.
+ TokenLength uint8 `json:"token_length"`
+ // Optional. Default value 32.
+
+ // TokenLookup is a string in the form of "<source>:<key>" that is used
+ // to extract token from the request.
+ // Optional. Default value "header:X-CSRF-Token".
+ // Possible values:
+ // - "header:<name>"
+ // - "form:<name>"
+ // - "query:<name>"
+ TokenLookup string `json:"token_lookup"`
+
+ // Context key to store generated CSRF token into context.
+ // Optional. Default value "csrf".
+ ContextKey string `json:"context_key"`
+
+ // Name of the CSRF cookie. This cookie will store CSRF token.
+ // Optional. Default value "csrf".
+ CookieName string `json:"cookie_name"`
+
+ // Domain of the CSRF cookie.
+ // Optional. Default value none.
+ CookieDomain string `json:"cookie_domain"`
+
+ // Path of the CSRF cookie.
+ // Optional. Default value none.
+ CookiePath string `json:"cookie_path"`
+
+ // Max age (in seconds) of the CSRF cookie.
+ // Optional. Default value 86400 (24hr).
+ CookieMaxAge int `json:"cookie_max_age"`
+
+ // Indicates if CSRF cookie is secure.
+ // Optional. Default value false.
+ CookieSecure bool `json:"cookie_secure"`
+
+ // Indicates if CSRF cookie is HTTP only.
+ // Optional. Default value false.
+ CookieHTTPOnly bool `json:"cookie_http_only"`
+ }
+
+ // csrfTokenExtractor defines a function that takes `echo.Context` and returns
+ // either a token or an error.
+ csrfTokenExtractor func(echo.Context) (string, error)
+)
+
+var (
+ // DefaultCSRFConfig is the default CSRF middleware config.
+ DefaultCSRFConfig = CSRFConfig{
+ Skipper: DefaultSkipper,
+ TokenLength: 32,
+ TokenLookup: "header:" + echo.HeaderXCSRFToken,
+ ContextKey: "csrf",
+ CookieName: "_csrf",
+ CookieMaxAge: 86400,
+ }
+)
+
+// CSRF returns a Cross-Site Request Forgery (CSRF) middleware.
+// See: https://en.wikipedia.org/wiki/Cross-site_request_forgery
+func CSRF() echo.MiddlewareFunc {
+ c := DefaultCSRFConfig
+ return CSRFWithConfig(c)
+}
+
+// CSRFWithConfig returns a CSRF middleware with config.
+// See `CSRF()`.
+func CSRFWithConfig(config CSRFConfig) echo.MiddlewareFunc {
+ // Defaults
+ if config.Skipper == nil {
+ config.Skipper = DefaultCSRFConfig.Skipper
+ }
+ if config.TokenLength == 0 {
+ config.TokenLength = DefaultCSRFConfig.TokenLength
+ }
+ if config.TokenLookup == "" {
+ config.TokenLookup = DefaultCSRFConfig.TokenLookup
+ }
+ if config.ContextKey == "" {
+ config.ContextKey = DefaultCSRFConfig.ContextKey
+ }
+ if config.CookieName == "" {
+ config.CookieName = DefaultCSRFConfig.CookieName
+ }
+ if config.CookieMaxAge == 0 {
+ config.CookieMaxAge = DefaultCSRFConfig.CookieMaxAge
+ }
+
+ // Initialize
+ parts := strings.Split(config.TokenLookup, ":")
+ extractor := csrfTokenFromHeader(parts[1])
+ switch parts[0] {
+ case "form":
+ extractor = csrfTokenFromForm(parts[1])
+ case "query":
+ extractor = csrfTokenFromQuery(parts[1])
+ }
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ if config.Skipper(c) {
+ return next(c)
+ }
+
+ req := c.Request()
+ k, err := c.Cookie(config.CookieName)
+ token := ""
+
+ if err != nil {
+ // Generate token
+ token = random.String(config.TokenLength)
+ } else {
+ // Reuse token
+ token = k.Value
+ }
+
+ switch req.Method {
+ case echo.GET, echo.HEAD, echo.OPTIONS, echo.TRACE:
+ default:
+ // Validate token only for requests which are not defined as 'safe' by RFC7231
+ clientToken, err := extractor(c)
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, err.Error())
+ }
+ if !validateCSRFToken(token, clientToken) {
+ return echo.NewHTTPError(http.StatusForbidden, "Invalid csrf token")
+ }
+ }
+
+ // Set CSRF cookie
+ cookie := new(http.Cookie)
+ cookie.Name = config.CookieName
+ cookie.Value = token
+ if config.CookiePath != "" {
+ cookie.Path = config.CookiePath
+ }
+ if config.CookieDomain != "" {
+ cookie.Domain = config.CookieDomain
+ }
+ cookie.Expires = time.Now().Add(time.Duration(config.CookieMaxAge) * time.Second)
+ cookie.Secure = config.CookieSecure
+ cookie.HttpOnly = config.CookieHTTPOnly
+ c.SetCookie(cookie)
+
+ // Store token in the context
+ c.Set(config.ContextKey, token)
+
+ // Protect clients from caching the response
+ c.Response().Header().Add(echo.HeaderVary, echo.HeaderCookie)
+
+ return next(c)
+ }
+ }
+}
+
+// csrfTokenFromForm returns a `csrfTokenExtractor` that extracts token from the
+// provided request header.
+func csrfTokenFromHeader(header string) csrfTokenExtractor {
+ return func(c echo.Context) (string, error) {
+ return c.Request().Header.Get(header), nil
+ }
+}
+
+// csrfTokenFromForm returns a `csrfTokenExtractor` that extracts token from the
+// provided form parameter.
+func csrfTokenFromForm(param string) csrfTokenExtractor {
+ return func(c echo.Context) (string, error) {
+ token := c.FormValue(param)
+ if token == "" {
+ return "", errors.New("Missing csrf token in the form parameter")
+ }
+ return token, nil
+ }
+}
+
+// csrfTokenFromQuery returns a `csrfTokenExtractor` that extracts token from the
+// provided query parameter.
+func csrfTokenFromQuery(param string) csrfTokenExtractor {
+ return func(c echo.Context) (string, error) {
+ token := c.QueryParam(param)
+ if token == "" {
+ return "", errors.New("Missing csrf token in the query string")
+ }
+ return token, nil
+ }
+}
+
+func validateCSRFToken(token, clientToken string) bool {
+ return subtle.ConstantTimeCompare([]byte(token), []byte(clientToken)) == 1
+}
diff --git a/vendor/github.com/labstack/echo/middleware/jwt.go b/vendor/github.com/labstack/echo/middleware/jwt.go
new file mode 100644
index 00000000..b2658739
--- /dev/null
+++ b/vendor/github.com/labstack/echo/middleware/jwt.go
@@ -0,0 +1,189 @@
+package middleware
+
+import (
+ "errors"
+ "fmt"
+ "net/http"
+ "reflect"
+ "strings"
+
+ "github.com/dgrijalva/jwt-go"
+ "github.com/labstack/echo"
+)
+
+type (
+ // JWTConfig defines the config for JWT middleware.
+ JWTConfig struct {
+ // Skipper defines a function to skip middleware.
+ Skipper Skipper
+
+ // Signing key to validate token.
+ // Required.
+ SigningKey interface{}
+
+ // Signing method, used to check token signing method.
+ // Optional. Default value HS256.
+ SigningMethod string
+
+ // Context key to store user information from the token into context.
+ // Optional. Default value "user".
+ ContextKey string
+
+ // Claims are extendable claims data defining token content.
+ // Optional. Default value jwt.MapClaims
+ Claims jwt.Claims
+
+ // TokenLookup is a string in the form of "<source>:<name>" that is used
+ // to extract token from the request.
+ // Optional. Default value "header:Authorization".
+ // Possible values:
+ // - "header:<name>"
+ // - "query:<name>"
+ // - "cookie:<name>"
+ TokenLookup string
+
+ // AuthScheme to be used in the Authorization header.
+ // Optional. Default value "Bearer".
+ AuthScheme string
+
+ keyFunc jwt.Keyfunc
+ }
+
+ jwtExtractor func(echo.Context) (string, error)
+)
+
+// Algorithms
+const (
+ AlgorithmHS256 = "HS256"
+)
+
+var (
+ // DefaultJWTConfig is the default JWT auth middleware config.
+ DefaultJWTConfig = JWTConfig{
+ Skipper: DefaultSkipper,
+ SigningMethod: AlgorithmHS256,
+ ContextKey: "user",
+ TokenLookup: "header:" + echo.HeaderAuthorization,
+ AuthScheme: "Bearer",
+ Claims: jwt.MapClaims{},
+ }
+)
+
+// JWT returns a JSON Web Token (JWT) auth middleware.
+//
+// For valid token, it sets the user in context and calls next handler.
+// For invalid token, it returns "401 - Unauthorized" error.
+// For missing token, it returns "400 - Bad Request" error.
+//
+// See: https://jwt.io/introduction
+// See `JWTConfig.TokenLookup`
+func JWT(key []byte) echo.MiddlewareFunc {
+ c := DefaultJWTConfig
+ c.SigningKey = key
+ return JWTWithConfig(c)
+}
+
+// JWTWithConfig returns a JWT auth middleware with config.
+// See: `JWT()`.
+func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
+ // Defaults
+ if config.Skipper == nil {
+ config.Skipper = DefaultJWTConfig.Skipper
+ }
+ if config.SigningKey == nil {
+ panic("jwt middleware requires signing key")
+ }
+ if config.SigningMethod == "" {
+ config.SigningMethod = DefaultJWTConfig.SigningMethod
+ }
+ if config.ContextKey == "" {
+ config.ContextKey = DefaultJWTConfig.ContextKey
+ }
+ if config.Claims == nil {
+ config.Claims = DefaultJWTConfig.Claims
+ }
+ if config.TokenLookup == "" {
+ config.TokenLookup = DefaultJWTConfig.TokenLookup
+ }
+ if config.AuthScheme == "" {
+ config.AuthScheme = DefaultJWTConfig.AuthScheme
+ }
+ config.keyFunc = func(t *jwt.Token) (interface{}, error) {
+ // Check the signing method
+ if t.Method.Alg() != config.SigningMethod {
+ return nil, fmt.Errorf("Unexpected jwt signing method=%v", t.Header["alg"])
+ }
+ return config.SigningKey, nil
+ }
+
+ // Initialize
+ parts := strings.Split(config.TokenLookup, ":")
+ extractor := jwtFromHeader(parts[1], config.AuthScheme)
+ switch parts[0] {
+ case "query":
+ extractor = jwtFromQuery(parts[1])
+ case "cookie":
+ extractor = jwtFromCookie(parts[1])
+ }
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ if config.Skipper(c) {
+ return next(c)
+ }
+
+ auth, err := extractor(c)
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, err.Error())
+ }
+ token := new(jwt.Token)
+ // Issue #647, #656
+ if _, ok := config.Claims.(jwt.MapClaims); ok {
+ token, err = jwt.Parse(auth, config.keyFunc)
+ } else {
+ claims := reflect.ValueOf(config.Claims).Interface().(jwt.Claims)
+ token, err = jwt.ParseWithClaims(auth, claims, config.keyFunc)
+ }
+ if err == nil && token.Valid {
+ // Store user information from token into context.
+ c.Set(config.ContextKey, token)
+ return next(c)
+ }
+ return echo.ErrUnauthorized
+ }
+ }
+}
+
+// jwtFromHeader returns a `jwtExtractor` that extracts token from the request header.
+func jwtFromHeader(header string, authScheme string) jwtExtractor {
+ return func(c echo.Context) (string, error) {
+ auth := c.Request().Header.Get(header)
+ l := len(authScheme)
+ if len(auth) > l+1 && auth[:l] == authScheme {
+ return auth[l+1:], nil
+ }
+ return "", errors.New("Missing or invalid jwt in the request header")
+ }
+}
+
+// jwtFromQuery returns a `jwtExtractor` that extracts token from the query string.
+func jwtFromQuery(param string) jwtExtractor {
+ return func(c echo.Context) (string, error) {
+ token := c.QueryParam(param)
+ if token == "" {
+ return "", errors.New("Missing jwt in the query string")
+ }
+ return token, nil
+ }
+}
+
+// jwtFromCookie returns a `jwtExtractor` that extracts token from the named cookie.
+func jwtFromCookie(name string) jwtExtractor {
+ return func(c echo.Context) (string, error) {
+ cookie, err := c.Cookie(name)
+ if err != nil {
+ return "", errors.New("Missing jwt in the cookie")
+ }
+ return cookie.Value, nil
+ }
+}
diff --git a/vendor/github.com/labstack/echo/middleware/key_auth.go b/vendor/github.com/labstack/echo/middleware/key_auth.go
new file mode 100644
index 00000000..4d4cb940
--- /dev/null
+++ b/vendor/github.com/labstack/echo/middleware/key_auth.go
@@ -0,0 +1,133 @@
+package middleware
+
+import (
+ "errors"
+ "net/http"
+ "strings"
+
+ "github.com/labstack/echo"
+)
+
+type (
+ // KeyAuthConfig defines the config for KeyAuth middleware.
+ KeyAuthConfig struct {
+ // Skipper defines a function to skip middleware.
+ Skipper Skipper
+
+ // KeyLookup is a string in the form of "<source>:<name>" that is used
+ // to extract key from the request.
+ // Optional. Default value "header:Authorization".
+ // Possible values:
+ // - "header:<name>"
+ // - "query:<name>"
+ KeyLookup string `json:"key_lookup"`
+
+ // AuthScheme to be used in the Authorization header.
+ // Optional. Default value "Bearer".
+ AuthScheme string
+
+ // Validator is a function to validate key.
+ // Required.
+ Validator KeyAuthValidator
+ }
+
+ // KeyAuthValidator defines a function to validate KeyAuth credentials.
+ KeyAuthValidator func(string, echo.Context) bool
+
+ keyExtractor func(echo.Context) (string, error)
+)
+
+var (
+ // DefaultKeyAuthConfig is the default KeyAuth middleware config.
+ DefaultKeyAuthConfig = KeyAuthConfig{
+ Skipper: DefaultSkipper,
+ KeyLookup: "header:" + echo.HeaderAuthorization,
+ AuthScheme: "Bearer",
+ }
+)
+
+// KeyAuth returns an KeyAuth middleware.
+//
+// For valid key it calls the next handler.
+// For invalid key, it sends "401 - Unauthorized" response.
+// For missing key, it sends "400 - Bad Request" response.
+func KeyAuth(fn KeyAuthValidator) echo.MiddlewareFunc {
+ c := DefaultKeyAuthConfig
+ c.Validator = fn
+ return KeyAuthWithConfig(c)
+}
+
+// KeyAuthWithConfig returns an KeyAuth middleware with config.
+// See `KeyAuth()`.
+func KeyAuthWithConfig(config KeyAuthConfig) echo.MiddlewareFunc {
+ // Defaults
+ if config.Skipper == nil {
+ config.Skipper = DefaultKeyAuthConfig.Skipper
+ }
+ // Defaults
+ if config.AuthScheme == "" {
+ config.AuthScheme = DefaultKeyAuthConfig.AuthScheme
+ }
+ if config.KeyLookup == "" {
+ config.KeyLookup = DefaultKeyAuthConfig.KeyLookup
+ }
+ if config.Validator == nil {
+ panic("key-auth middleware requires a validator function")
+ }
+
+ // Initialize
+ parts := strings.Split(config.KeyLookup, ":")
+ extractor := keyFromHeader(parts[1], config.AuthScheme)
+ switch parts[0] {
+ case "query":
+ extractor = keyFromQuery(parts[1])
+ }
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ if config.Skipper(c) {
+ return next(c)
+ }
+
+ // Extract and verify key
+ key, err := extractor(c)
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, err.Error())
+ }
+ if config.Validator(key, c) {
+ return next(c)
+ }
+
+ return echo.ErrUnauthorized
+ }
+ }
+}
+
+// keyFromHeader returns a `keyExtractor` that extracts key from the request header.
+func keyFromHeader(header string, authScheme string) keyExtractor {
+ return func(c echo.Context) (string, error) {
+ auth := c.Request().Header.Get(header)
+ if auth == "" {
+ return "", errors.New("Missing key in request header")
+ }
+ if header == echo.HeaderAuthorization {
+ l := len(authScheme)
+ if len(auth) > l+1 && auth[:l] == authScheme {
+ return auth[l+1:], nil
+ }
+ return "", errors.New("Invalid key in the request header")
+ }
+ return auth, nil
+ }
+}
+
+// keyFromQuery returns a `keyExtractor` that extracts key from the query string.
+func keyFromQuery(param string) keyExtractor {
+ return func(c echo.Context) (string, error) {
+ key := c.QueryParam(param)
+ if key == "" {
+ return "", errors.New("Missing key in the query string")
+ }
+ return key, nil
+ }
+}
diff --git a/vendor/github.com/labstack/echo/middleware/logger.go b/vendor/github.com/labstack/echo/middleware/logger.go
new file mode 100644
index 00000000..e26b5496
--- /dev/null
+++ b/vendor/github.com/labstack/echo/middleware/logger.go
@@ -0,0 +1,191 @@
+package middleware
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/labstack/echo"
+ "github.com/labstack/gommon/color"
+ "github.com/valyala/fasttemplate"
+)
+
+type (
+ // LoggerConfig defines the config for Logger middleware.
+ LoggerConfig struct {
+ // Skipper defines a function to skip middleware.
+ Skipper Skipper
+
+ // Tags to constructed the logger format.
+ //
+ // - time_unix
+ // - time_unix_nano
+ // - time_rfc3339
+ // - time_rfc3339_nano
+ // - id (Request ID - Not implemented)
+ // - remote_ip
+ // - uri
+ // - host
+ // - method
+ // - path
+ // - referer
+ // - user_agent
+ // - status
+ // - latency (In nanoseconds)
+ // - latency_human (Human readable)
+ // - bytes_in (Bytes received)
+ // - bytes_out (Bytes sent)
+ // - header:<NAME>
+ // - query:<NAME>
+ // - form:<NAME>
+ //
+ // Example "${remote_ip} ${status}"
+ //
+ // Optional. Default value DefaultLoggerConfig.Format.
+ Format string `json:"format"`
+
+ // Output is a writer where logs in JSON format are written.
+ // Optional. Default value os.Stdout.
+ Output io.Writer
+
+ template *fasttemplate.Template
+ colorer *color.Color
+ pool *sync.Pool
+ }
+)
+
+var (
+ // DefaultLoggerConfig is the default Logger middleware config.
+ DefaultLoggerConfig = LoggerConfig{
+ Skipper: DefaultSkipper,
+ Format: `{"time":"${time_rfc3339_nano}","remote_ip":"${remote_ip}","host":"${host}",` +
+ `"method":"${method}","uri":"${uri}","status":${status}, "latency":${latency},` +
+ `"latency_human":"${latency_human}","bytes_in":${bytes_in},` +
+ `"bytes_out":${bytes_out}}` + "\n",
+ Output: os.Stdout,
+ colorer: color.New(),
+ }
+)
+
+// Logger returns a middleware that logs HTTP requests.
+func Logger() echo.MiddlewareFunc {
+ return LoggerWithConfig(DefaultLoggerConfig)
+}
+
+// LoggerWithConfig returns a Logger middleware with config.
+// See: `Logger()`.
+func LoggerWithConfig(config LoggerConfig) echo.MiddlewareFunc {
+ // Defaults
+ if config.Skipper == nil {
+ config.Skipper = DefaultLoggerConfig.Skipper
+ }
+ if config.Format == "" {
+ config.Format = DefaultLoggerConfig.Format
+ }
+ if config.Output == nil {
+ config.Output = DefaultLoggerConfig.Output
+ }
+
+ config.template = fasttemplate.New(config.Format, "${", "}")
+ config.colorer = color.New()
+ config.colorer.SetOutput(config.Output)
+ config.pool = &sync.Pool{
+ New: func() interface{} {
+ return bytes.NewBuffer(make([]byte, 256))
+ },
+ }
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) (err error) {
+ if config.Skipper(c) {
+ return next(c)
+ }
+
+ req := c.Request()
+ res := c.Response()
+ start := time.Now()
+ if err = next(c); err != nil {
+ c.Error(err)
+ }
+ stop := time.Now()
+ buf := config.pool.Get().(*bytes.Buffer)
+ buf.Reset()
+ defer config.pool.Put(buf)
+
+ if _, err = config.template.ExecuteFunc(buf, func(w io.Writer, tag string) (int, error) {
+ switch tag {
+ case "time_unix":
+ return buf.WriteString(strconv.FormatInt(time.Now().Unix(), 10))
+ case "time_unix_nano":
+ return buf.WriteString(strconv.FormatInt(time.Now().UnixNano(), 10))
+ case "time_rfc3339":
+ return buf.WriteString(time.Now().Format(time.RFC3339))
+ case "time_rfc3339_nano":
+ return buf.WriteString(time.Now().Format(time.RFC3339Nano))
+ case "remote_ip":
+ return buf.WriteString(c.RealIP())
+ case "host":
+ return buf.WriteString(req.Host)
+ case "uri":
+ return buf.WriteString(req.RequestURI)
+ case "method":
+ return buf.WriteString(req.Method)
+ case "path":
+ p := req.URL.Path
+ if p == "" {
+ p = "/"
+ }
+ return buf.WriteString(p)
+ case "referer":
+ return buf.WriteString(req.Referer())
+ case "user_agent":
+ return buf.WriteString(req.UserAgent())
+ case "status":
+ n := res.Status
+ s := config.colorer.Green(n)
+ switch {
+ case n >= 500:
+ s = config.colorer.Red(n)
+ case n >= 400:
+ s = config.colorer.Yellow(n)
+ case n >= 300:
+ s = config.colorer.Cyan(n)
+ }
+ return buf.WriteString(s)
+ case "latency":
+ l := stop.Sub(start)
+ return buf.WriteString(strconv.FormatInt(int64(l), 10))
+ case "latency_human":
+ return buf.WriteString(stop.Sub(start).String())
+ case "bytes_in":
+ cl := req.Header.Get(echo.HeaderContentLength)
+ if cl == "" {
+ cl = "0"
+ }
+ return buf.WriteString(cl)
+ case "bytes_out":
+ return buf.WriteString(strconv.FormatInt(res.Size, 10))
+ default:
+ switch {
+ case strings.HasPrefix(tag, "header:"):
+ return buf.Write([]byte(c.Request().Header.Get(tag[7:])))
+ case strings.HasPrefix(tag, "query:"):
+ return buf.Write([]byte(c.QueryParam(tag[6:])))
+ case strings.HasPrefix(tag, "form:"):
+ return buf.Write([]byte(c.FormValue(tag[5:])))
+ }
+ }
+ return 0, nil
+ }); err != nil {
+ return
+ }
+
+ _, err = config.Output.Write(buf.Bytes())
+ return
+ }
+ }
+}
diff --git a/vendor/github.com/labstack/echo/middleware/method_override.go b/vendor/github.com/labstack/echo/middleware/method_override.go
new file mode 100644
index 00000000..955fd11e
--- /dev/null
+++ b/vendor/github.com/labstack/echo/middleware/method_override.go
@@ -0,0 +1,88 @@
+package middleware
+
+import "github.com/labstack/echo"
+
+type (
+ // MethodOverrideConfig defines the config for MethodOverride middleware.
+ MethodOverrideConfig struct {
+ // Skipper defines a function to skip middleware.
+ Skipper Skipper
+
+ // Getter is a function that gets overridden method from the request.
+ // Optional. Default values MethodFromHeader(echo.HeaderXHTTPMethodOverride).
+ Getter MethodOverrideGetter
+ }
+
+ // MethodOverrideGetter is a function that gets overridden method from the request
+ MethodOverrideGetter func(echo.Context) string
+)
+
+var (
+ // DefaultMethodOverrideConfig is the default MethodOverride middleware config.
+ DefaultMethodOverrideConfig = MethodOverrideConfig{
+ Skipper: DefaultSkipper,
+ Getter: MethodFromHeader(echo.HeaderXHTTPMethodOverride),
+ }
+)
+
+// MethodOverride returns a MethodOverride middleware.
+// MethodOverride middleware checks for the overridden method from the request and
+// uses it instead of the original method.
+//
+// For security reasons, only `POST` method can be overridden.
+func MethodOverride() echo.MiddlewareFunc {
+ return MethodOverrideWithConfig(DefaultMethodOverrideConfig)
+}
+
+// MethodOverrideWithConfig returns a MethodOverride middleware with config.
+// See: `MethodOverride()`.
+func MethodOverrideWithConfig(config MethodOverrideConfig) echo.MiddlewareFunc {
+ // Defaults
+ if config.Skipper == nil {
+ config.Skipper = DefaultMethodOverrideConfig.Skipper
+ }
+ if config.Getter == nil {
+ config.Getter = DefaultMethodOverrideConfig.Getter
+ }
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ if config.Skipper(c) {
+ return next(c)
+ }
+
+ req := c.Request()
+ if req.Method == echo.POST {
+ m := config.Getter(c)
+ if m != "" {
+ req.Method = m
+ }
+ }
+ return next(c)
+ }
+ }
+}
+
+// MethodFromHeader is a `MethodOverrideGetter` that gets overridden method from
+// the request header.
+func MethodFromHeader(header string) MethodOverrideGetter {
+ return func(c echo.Context) string {
+ return c.Request().Header.Get(header)
+ }
+}
+
+// MethodFromForm is a `MethodOverrideGetter` that gets overridden method from the
+// form parameter.
+func MethodFromForm(param string) MethodOverrideGetter {
+ return func(c echo.Context) string {
+ return c.FormValue(param)
+ }
+}
+
+// MethodFromQuery is a `MethodOverrideGetter` that gets overridden method from
+// the query parameter.
+func MethodFromQuery(param string) MethodOverrideGetter {
+ return func(c echo.Context) string {
+ return c.QueryParam(param)
+ }
+}
diff --git a/vendor/github.com/labstack/echo/middleware/middleware.go b/vendor/github.com/labstack/echo/middleware/middleware.go
new file mode 100644
index 00000000..7edccc1d
--- /dev/null
+++ b/vendor/github.com/labstack/echo/middleware/middleware.go
@@ -0,0 +1,14 @@
+package middleware
+
+import "github.com/labstack/echo"
+
+type (
+ // Skipper defines a function to skip middleware. Returning true skips processing
+ // the middleware.
+ Skipper func(c echo.Context) bool
+)
+
+// DefaultSkipper returns false which processes the middleware.
+func DefaultSkipper(c echo.Context) bool {
+ return false
+}
diff --git a/vendor/github.com/labstack/echo/middleware/recover.go b/vendor/github.com/labstack/echo/middleware/recover.go
new file mode 100644
index 00000000..96fa62c9
--- /dev/null
+++ b/vendor/github.com/labstack/echo/middleware/recover.go
@@ -0,0 +1,85 @@
+package middleware
+
+import (
+ "fmt"
+ "runtime"
+
+ "github.com/labstack/echo"
+ "github.com/labstack/gommon/color"
+)
+
+type (
+ // RecoverConfig defines the config for Recover middleware.
+ RecoverConfig struct {
+ // Skipper defines a function to skip middleware.
+ Skipper Skipper
+
+ // Size of the stack to be printed.
+ // Optional. Default value 4KB.
+ StackSize int `json:"stack_size"`
+
+ // DisableStackAll disables formatting stack traces of all other goroutines
+ // into buffer after the trace for the current goroutine.
+ // Optional. Default value false.
+ DisableStackAll bool `json:"disable_stack_all"`
+
+ // DisablePrintStack disables printing stack trace.
+ // Optional. Default value as false.
+ DisablePrintStack bool `json:"disable_print_stack"`
+ }
+)
+
+var (
+ // DefaultRecoverConfig is the default Recover middleware config.
+ DefaultRecoverConfig = RecoverConfig{
+ Skipper: DefaultSkipper,
+ StackSize: 4 << 10, // 4 KB
+ DisableStackAll: false,
+ DisablePrintStack: false,
+ }
+)
+
+// Recover returns a middleware which recovers from panics anywhere in the chain
+// and handles the control to the centralized HTTPErrorHandler.
+func Recover() echo.MiddlewareFunc {
+ return RecoverWithConfig(DefaultRecoverConfig)
+}
+
+// RecoverWithConfig returns a Recover middleware with config.
+// See: `Recover()`.
+func RecoverWithConfig(config RecoverConfig) echo.MiddlewareFunc {
+ // Defaults
+ if config.Skipper == nil {
+ config.Skipper = DefaultRecoverConfig.Skipper
+ }
+ if config.StackSize == 0 {
+ config.StackSize = DefaultRecoverConfig.StackSize
+ }
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ if config.Skipper(c) {
+ return next(c)
+ }
+
+ defer func() {
+ if r := recover(); r != nil {
+ var err error
+ switch r := r.(type) {
+ case error:
+ err = r
+ default:
+ err = fmt.Errorf("%v", r)
+ }
+ stack := make([]byte, config.StackSize)
+ length := runtime.Stack(stack, !config.DisableStackAll)
+ if !config.DisablePrintStack {
+ c.Logger().Printf("[%s] %s %s\n", color.Red("PANIC RECOVER"), err, stack[:length])
+ }
+ c.Error(err)
+ }
+ }()
+ return next(c)
+ }
+ }
+}
diff --git a/vendor/github.com/labstack/echo/middleware/redirect.go b/vendor/github.com/labstack/echo/middleware/redirect.go
new file mode 100644
index 00000000..b87dab09
--- /dev/null
+++ b/vendor/github.com/labstack/echo/middleware/redirect.go
@@ -0,0 +1,215 @@
+package middleware
+
+import (
+ "net/http"
+
+ "github.com/labstack/echo"
+)
+
+type (
+ // RedirectConfig defines the config for Redirect middleware.
+ RedirectConfig struct {
+ // Skipper defines a function to skip middleware.
+ Skipper Skipper
+
+ // Status code to be used when redirecting the request.
+ // Optional. Default value http.StatusMovedPermanently.
+ Code int `json:"code"`
+ }
+)
+
+const (
+ www = "www"
+)
+
+var (
+ // DefaultRedirectConfig is the default Redirect middleware config.
+ DefaultRedirectConfig = RedirectConfig{
+ Skipper: DefaultSkipper,
+ Code: http.StatusMovedPermanently,
+ }
+)
+
+// HTTPSRedirect redirects http requests to https.
+// For example, http://labstack.com will be redirect to https://labstack.com.
+//
+// Usage `Echo#Pre(HTTPSRedirect())`
+func HTTPSRedirect() echo.MiddlewareFunc {
+ return HTTPSRedirectWithConfig(DefaultRedirectConfig)
+}
+
+// HTTPSRedirectWithConfig returns an HTTPSRedirect middleware with config.
+// See `HTTPSRedirect()`.
+func HTTPSRedirectWithConfig(config RedirectConfig) echo.MiddlewareFunc {
+ // Defaults
+ if config.Skipper == nil {
+ config.Skipper = DefaultTrailingSlashConfig.Skipper
+ }
+ if config.Code == 0 {
+ config.Code = DefaultRedirectConfig.Code
+ }
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ if config.Skipper(c) {
+ return next(c)
+ }
+
+ req := c.Request()
+ host := req.Host
+ uri := req.RequestURI
+ if !c.IsTLS() {
+ return c.Redirect(config.Code, "https://"+host+uri)
+ }
+ return next(c)
+ }
+ }
+}
+
+// HTTPSWWWRedirect redirects http requests to https www.
+// For example, http://labstack.com will be redirect to https://www.labstack.com.
+//
+// Usage `Echo#Pre(HTTPSWWWRedirect())`
+func HTTPSWWWRedirect() echo.MiddlewareFunc {
+ return HTTPSWWWRedirectWithConfig(DefaultRedirectConfig)
+}
+
+// HTTPSWWWRedirectWithConfig returns an HTTPSRedirect middleware with config.
+// See `HTTPSWWWRedirect()`.
+func HTTPSWWWRedirectWithConfig(config RedirectConfig) echo.MiddlewareFunc {
+ // Defaults
+ if config.Skipper == nil {
+ config.Skipper = DefaultTrailingSlashConfig.Skipper
+ }
+ if config.Code == 0 {
+ config.Code = DefaultRedirectConfig.Code
+ }
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ if config.Skipper(c) {
+ return next(c)
+ }
+
+ req := c.Request()
+ host := req.Host
+ uri := req.RequestURI
+ if !c.IsTLS() && host[:3] != www {
+ return c.Redirect(config.Code, "https://www."+host+uri)
+ }
+ return next(c)
+ }
+ }
+}
+
+// HTTPSNonWWWRedirect redirects http requests to https non www.
+// For example, http://www.labstack.com will be redirect to https://labstack.com.
+//
+// Usage `Echo#Pre(HTTPSNonWWWRedirect())`
+func HTTPSNonWWWRedirect() echo.MiddlewareFunc {
+ return HTTPSNonWWWRedirectWithConfig(DefaultRedirectConfig)
+}
+
+// HTTPSNonWWWRedirectWithConfig returns an HTTPSRedirect middleware with config.
+// See `HTTPSNonWWWRedirect()`.
+func HTTPSNonWWWRedirectWithConfig(config RedirectConfig) echo.MiddlewareFunc {
+ // Defaults
+ if config.Skipper == nil {
+ config.Skipper = DefaultTrailingSlashConfig.Skipper
+ }
+ if config.Code == 0 {
+ config.Code = DefaultRedirectConfig.Code
+ }
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ if config.Skipper(c) {
+ return next(c)
+ }
+
+ req := c.Request()
+ host := req.Host
+ uri := req.RequestURI
+ if !c.IsTLS() {
+ if host[:3] == www {
+ return c.Redirect(config.Code, "https://"+host[4:]+uri)
+ }
+ return c.Redirect(config.Code, "https://"+host+uri)
+ }
+ return next(c)
+ }
+ }
+}
+
+// WWWRedirect redirects non www requests to www.
+// For example, http://labstack.com will be redirect to http://www.labstack.com.
+//
+// Usage `Echo#Pre(WWWRedirect())`
+func WWWRedirect() echo.MiddlewareFunc {
+ return WWWRedirectWithConfig(DefaultRedirectConfig)
+}
+
+// WWWRedirectWithConfig returns an HTTPSRedirect middleware with config.
+// See `WWWRedirect()`.
+func WWWRedirectWithConfig(config RedirectConfig) echo.MiddlewareFunc {
+ // Defaults
+ if config.Skipper == nil {
+ config.Skipper = DefaultTrailingSlashConfig.Skipper
+ }
+ if config.Code == 0 {
+ config.Code = DefaultRedirectConfig.Code
+ }
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ if config.Skipper(c) {
+ return next(c)
+ }
+
+ req := c.Request()
+ scheme := c.Scheme()
+ host := req.Host
+ if host[:3] != www {
+ uri := req.RequestURI
+ return c.Redirect(config.Code, scheme+"://www."+host+uri)
+ }
+ return next(c)
+ }
+ }
+}
+
+// NonWWWRedirect redirects www requests to non www.
+// For example, http://www.labstack.com will be redirect to http://labstack.com.
+//
+// Usage `Echo#Pre(NonWWWRedirect())`
+func NonWWWRedirect() echo.MiddlewareFunc {
+ return NonWWWRedirectWithConfig(DefaultRedirectConfig)
+}
+
+// NonWWWRedirectWithConfig returns an HTTPSRedirect middleware with config.
+// See `NonWWWRedirect()`.
+func NonWWWRedirectWithConfig(config RedirectConfig) echo.MiddlewareFunc {
+ if config.Skipper == nil {
+ config.Skipper = DefaultTrailingSlashConfig.Skipper
+ }
+ if config.Code == 0 {
+ config.Code = DefaultRedirectConfig.Code
+ }
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ if config.Skipper(c) {
+ return next(c)
+ }
+
+ req := c.Request()
+ scheme := c.Scheme()
+ host := req.Host
+ if host[:3] == www {
+ uri := req.RequestURI
+ return c.Redirect(config.Code, scheme+"://"+host[4:]+uri)
+ }
+ return next(c)
+ }
+ }
+}
diff --git a/vendor/github.com/labstack/echo/middleware/secure.go b/vendor/github.com/labstack/echo/middleware/secure.go
new file mode 100644
index 00000000..0125e74a
--- /dev/null
+++ b/vendor/github.com/labstack/echo/middleware/secure.go
@@ -0,0 +1,116 @@
+package middleware
+
+import (
+ "fmt"
+
+ "github.com/labstack/echo"
+)
+
+type (
+ // SecureConfig defines the config for Secure middleware.
+ SecureConfig struct {
+ // Skipper defines a function to skip middleware.
+ Skipper Skipper
+
+ // XSSProtection provides protection against cross-site scripting attack (XSS)
+ // by setting the `X-XSS-Protection` header.
+ // Optional. Default value "1; mode=block".
+ XSSProtection string `json:"xss_protection"`
+
+ // ContentTypeNosniff provides protection against overriding Content-Type
+ // header by setting the `X-Content-Type-Options` header.
+ // Optional. Default value "nosniff".
+ ContentTypeNosniff string `json:"content_type_nosniff"`
+
+ // XFrameOptions can be used to indicate whether or not a browser should
+ // be allowed to render a page in a <frame>, <iframe> or <object> .
+ // Sites can use this to avoid clickjacking attacks, by ensuring that their
+ // content is not embedded into other sites.provides protection against
+ // clickjacking.
+ // Optional. Default value "SAMEORIGIN".
+ // Possible values:
+ // - "SAMEORIGIN" - The page can only be displayed in a frame on the same origin as the page itself.
+ // - "DENY" - The page cannot be displayed in a frame, regardless of the site attempting to do so.
+ // - "ALLOW-FROM uri" - The page can only be displayed in a frame on the specified origin.
+ XFrameOptions string `json:"x_frame_options"`
+
+ // HSTSMaxAge sets the `Strict-Transport-Security` header to indicate how
+ // long (in seconds) browsers should remember that this site is only to
+ // be accessed using HTTPS. This reduces your exposure to some SSL-stripping
+ // man-in-the-middle (MITM) attacks.
+ // Optional. Default value 0.
+ HSTSMaxAge int `json:"hsts_max_age"`
+
+ // HSTSExcludeSubdomains won't include subdomains tag in the `Strict Transport Security`
+ // header, excluding all subdomains from security policy. It has no effect
+ // unless HSTSMaxAge is set to a non-zero value.
+ // Optional. Default value false.
+ HSTSExcludeSubdomains bool `json:"hsts_exclude_subdomains"`
+
+ // ContentSecurityPolicy sets the `Content-Security-Policy` header providing
+ // security against cross-site scripting (XSS), clickjacking and other code
+ // injection attacks resulting from execution of malicious content in the
+ // trusted web page context.
+ // Optional. Default value "".
+ ContentSecurityPolicy string `json:"content_security_policy"`
+ }
+)
+
+var (
+ // DefaultSecureConfig is the default Secure middleware config.
+ DefaultSecureConfig = SecureConfig{
+ Skipper: DefaultSkipper,
+ XSSProtection: "1; mode=block",
+ ContentTypeNosniff: "nosniff",
+ XFrameOptions: "SAMEORIGIN",
+ }
+)
+
+// Secure returns a Secure middleware.
+// Secure middleware provides protection against cross-site scripting (XSS) attack,
+// content type sniffing, clickjacking, insecure connection and other code injection
+// attacks.
+func Secure() echo.MiddlewareFunc {
+ return SecureWithConfig(DefaultSecureConfig)
+}
+
+// SecureWithConfig returns a Secure middleware with config.
+// See: `Secure()`.
+func SecureWithConfig(config SecureConfig) echo.MiddlewareFunc {
+ // Defaults
+ if config.Skipper == nil {
+ config.Skipper = DefaultSecureConfig.Skipper
+ }
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ if config.Skipper(c) {
+ return next(c)
+ }
+
+ req := c.Request()
+ res := c.Response()
+
+ if config.XSSProtection != "" {
+ res.Header().Set(echo.HeaderXXSSProtection, config.XSSProtection)
+ }
+ if config.ContentTypeNosniff != "" {
+ res.Header().Set(echo.HeaderXContentTypeOptions, config.ContentTypeNosniff)
+ }
+ if config.XFrameOptions != "" {
+ res.Header().Set(echo.HeaderXFrameOptions, config.XFrameOptions)
+ }
+ if (c.IsTLS() || (req.Header.Get(echo.HeaderXForwardedProto) == "https")) && config.HSTSMaxAge != 0 {
+ subdomains := ""
+ if !config.HSTSExcludeSubdomains {
+ subdomains = "; includeSubdomains"
+ }
+ res.Header().Set(echo.HeaderStrictTransportSecurity, fmt.Sprintf("max-age=%d%s", config.HSTSMaxAge, subdomains))
+ }
+ if config.ContentSecurityPolicy != "" {
+ res.Header().Set(echo.HeaderContentSecurityPolicy, config.ContentSecurityPolicy)
+ }
+ return next(c)
+ }
+ }
+}
diff --git a/vendor/github.com/labstack/echo/middleware/slash.go b/vendor/github.com/labstack/echo/middleware/slash.go
new file mode 100644
index 00000000..1114d722
--- /dev/null
+++ b/vendor/github.com/labstack/echo/middleware/slash.go
@@ -0,0 +1,119 @@
+package middleware
+
+import (
+ "github.com/labstack/echo"
+)
+
+type (
+ // TrailingSlashConfig defines the config for TrailingSlash middleware.
+ TrailingSlashConfig struct {
+ // Skipper defines a function to skip middleware.
+ Skipper Skipper
+
+ // Status code to be used when redirecting the request.
+ // Optional, but when provided the request is redirected using this code.
+ RedirectCode int `json:"redirect_code"`
+ }
+)
+
+var (
+ // DefaultTrailingSlashConfig is the default TrailingSlash middleware config.
+ DefaultTrailingSlashConfig = TrailingSlashConfig{
+ Skipper: DefaultSkipper,
+ }
+)
+
+// AddTrailingSlash returns a root level (before router) middleware which adds a
+// trailing slash to the request `URL#Path`.
+//
+// Usage `Echo#Pre(AddTrailingSlash())`
+func AddTrailingSlash() echo.MiddlewareFunc {
+ return AddTrailingSlashWithConfig(DefaultTrailingSlashConfig)
+}
+
+// AddTrailingSlashWithConfig returns a AddTrailingSlash middleware with config.
+// See `AddTrailingSlash()`.
+func AddTrailingSlashWithConfig(config TrailingSlashConfig) echo.MiddlewareFunc {
+ // Defaults
+ if config.Skipper == nil {
+ config.Skipper = DefaultTrailingSlashConfig.Skipper
+ }
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ if config.Skipper(c) {
+ return next(c)
+ }
+
+ req := c.Request()
+ url := req.URL
+ path := url.Path
+ qs := c.QueryString()
+ if path != "/" && path[len(path)-1] != '/' {
+ path += "/"
+ uri := path
+ if qs != "" {
+ uri += "?" + qs
+ }
+
+ // Redirect
+ if config.RedirectCode != 0 {
+ return c.Redirect(config.RedirectCode, uri)
+ }
+
+ // Forward
+ req.RequestURI = uri
+ url.Path = path
+ }
+ return next(c)
+ }
+ }
+}
+
+// RemoveTrailingSlash returns a root level (before router) middleware which removes
+// a trailing slash from the request URI.
+//
+// Usage `Echo#Pre(RemoveTrailingSlash())`
+func RemoveTrailingSlash() echo.MiddlewareFunc {
+ return RemoveTrailingSlashWithConfig(TrailingSlashConfig{})
+}
+
+// RemoveTrailingSlashWithConfig returns a RemoveTrailingSlash middleware with config.
+// See `RemoveTrailingSlash()`.
+func RemoveTrailingSlashWithConfig(config TrailingSlashConfig) echo.MiddlewareFunc {
+ // Defaults
+ if config.Skipper == nil {
+ config.Skipper = DefaultTrailingSlashConfig.Skipper
+ }
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ if config.Skipper(c) {
+ return next(c)
+ }
+
+ req := c.Request()
+ url := req.URL
+ path := url.Path
+ qs := c.QueryString()
+ l := len(path) - 1
+ if l >= 0 && path != "/" && path[l] == '/' {
+ path = path[:l]
+ uri := path
+ if qs != "" {
+ uri += "?" + qs
+ }
+
+ // Redirect
+ if config.RedirectCode != 0 {
+ return c.Redirect(config.RedirectCode, uri)
+ }
+
+ // Forward
+ req.RequestURI = uri
+ url.Path = path
+ }
+ return next(c)
+ }
+ }
+}
diff --git a/vendor/github.com/labstack/echo/middleware/static.go b/vendor/github.com/labstack/echo/middleware/static.go
new file mode 100644
index 00000000..793c1445
--- /dev/null
+++ b/vendor/github.com/labstack/echo/middleware/static.go
@@ -0,0 +1,118 @@
+package middleware
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+
+ "github.com/labstack/echo"
+)
+
+type (
+ // StaticConfig defines the config for Static middleware.
+ StaticConfig struct {
+ // Skipper defines a function to skip middleware.
+ Skipper Skipper
+
+ // Root directory from where the static content is served.
+ // Required.
+ Root string `json:"root"`
+
+ // Index file for serving a directory.
+ // Optional. Default value "index.html".
+ Index string `json:"index"`
+
+ // Enable HTML5 mode by forwarding all not-found requests to root so that
+ // SPA (single-page application) can handle the routing.
+ // Optional. Default value false.
+ HTML5 bool `json:"html5"`
+
+ // Enable directory browsing.
+ // Optional. Default value false.
+ Browse bool `json:"browse"`
+ }
+)
+
+var (
+ // DefaultStaticConfig is the default Static middleware config.
+ DefaultStaticConfig = StaticConfig{
+ Skipper: DefaultSkipper,
+ Index: "index.html",
+ }
+)
+
+// Static returns a Static middleware to serves static content from the provided
+// root directory.
+func Static(root string) echo.MiddlewareFunc {
+ c := DefaultStaticConfig
+ c.Root = root
+ return StaticWithConfig(c)
+}
+
+// StaticWithConfig returns a Static middleware with config.
+// See `Static()`.
+func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc {
+ // Defaults
+ if config.Skipper == nil {
+ config.Skipper = DefaultStaticConfig.Skipper
+ }
+ if config.Index == "" {
+ config.Index = DefaultStaticConfig.Index
+ }
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ p := c.Param("*")
+ name := filepath.Join(config.Root, p)
+ fi, err := os.Stat(name)
+
+ if err != nil {
+ if os.IsNotExist(err) {
+ if config.HTML5 {
+ return c.File(filepath.Join(config.Root, config.Index))
+ }
+ return echo.ErrNotFound
+ }
+ return err
+ }
+
+ if fi.IsDir() {
+ if config.Browse {
+ return listDir(name, c.Response())
+ }
+ return c.File(filepath.Join(name, config.Index))
+ }
+ return c.File(name)
+ }
+ }
+}
+
+func listDir(name string, res *echo.Response) error {
+ dir, err := os.Open(name)
+ if err != nil {
+ return err
+ }
+ dirs, err := dir.Readdir(-1)
+ if err != nil {
+ return err
+ }
+
+ // Create a directory index
+ res.Header().Set(echo.HeaderContentType, echo.MIMETextHTMLCharsetUTF8)
+ if _, err = fmt.Fprintf(res, "<pre>\n"); err != nil {
+ return err
+ }
+ for _, d := range dirs {
+ name := d.Name()
+ color := "#212121"
+ if d.IsDir() {
+ color = "#e91e63"
+ name += "/"
+ }
+ if _, err = fmt.Fprintf(res, "<a href=\"%s\" style=\"color: %s;\">%s</a>\n", name, color, name); err != nil {
+ return err
+ }
+ }
+ _, err = fmt.Fprintf(res, "</pre>\n")
+ return err
+}