summaryrefslogtreecommitdiff
path: root/teleirc/matterbridge/vendor/github.com/labstack/echo
diff options
context:
space:
mode:
authorMistivia <i@mistivia.com>2025-11-02 15:27:18 +0800
committerMistivia <i@mistivia.com>2025-11-02 15:27:18 +0800
commite9c24f4af7ed56760f6db7941827d09f6db9020b (patch)
tree62128c43b883ce5e3148113350978755779bb5de /teleirc/matterbridge/vendor/github.com/labstack/echo
parent58d5e7cfda4781d8a57ec52aefd02983835c301a (diff)
add matterbridge
Diffstat (limited to 'teleirc/matterbridge/vendor/github.com/labstack/echo')
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/.editorconfig25
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/.gitattributes20
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/.gitignore8
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/.travis.yml21
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/CHANGELOG.md352
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/LICENSE21
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/Makefile36
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/README.md138
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/bind.go340
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/binder.go1331
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/codecov.yml11
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/context.go647
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/context_fs.go49
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/echo.go980
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/echo_fs.go159
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/group.go126
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/group_fs.go30
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/ip.go268
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/json.go31
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/log.go41
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/basic_auth.go110
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/body_dump.go106
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/body_limit.go117
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/compress.go144
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/cors.go282
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/csrf.go219
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/decompress.go99
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/extractor.go204
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/jwt.go304
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/key_auth.go180
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/logger.go245
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/method_override.go92
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/middleware.go89
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/proxy.go318
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/rate_limiter.go271
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/recover.go122
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/redirect.go152
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/request_id.go77
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/request_logger.go364
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/rewrite.go81
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/secure.go145
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/slash.go130
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/static.go277
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/timeout.go220
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/util.go54
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/response.go104
-rw-r--r--teleirc/matterbridge/vendor/github.com/labstack/echo/v4/router.go744
47 files changed, 9884 insertions, 0 deletions
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/.editorconfig b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/.editorconfig
new file mode 100644
index 0000000..17ae50d
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/.editorconfig
@@ -0,0 +1,25 @@
+# EditorConfig coding styles definitions. For more information about the
+# properties used in this file, please see the EditorConfig documentation:
+# http://editorconfig.org/
+
+# indicate this is the root of the project
+root = true
+
+[*]
+charset = utf-8
+
+end_of_line = LF
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+indent_style = space
+indent_size = 2
+
+[Makefile]
+indent_style = tab
+
+[*.md]
+trim_trailing_whitespace = false
+
+[*.go]
+indent_style = tab
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/.gitattributes b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/.gitattributes
new file mode 100644
index 0000000..49b63e5
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/.gitattributes
@@ -0,0 +1,20 @@
+# Automatically normalize line endings for all text-based files
+# http://git-scm.com/docs/gitattributes#_end_of_line_conversion
+* text=auto
+
+# For the following file types, normalize line endings to LF on checking and
+# prevent conversion to CRLF when they are checked out (this is required in
+# order to prevent newline related issues)
+.* text eol=lf
+*.go text eol=lf
+*.yml text eol=lf
+*.html text eol=lf
+*.css text eol=lf
+*.js text eol=lf
+*.json text eol=lf
+LICENSE text eol=lf
+
+# Exclude `website` and `cookbook` from GitHub's language statistics
+# https://github.com/github/linguist#using-gitattributes
+cookbook/* linguist-documentation
+website/* linguist-documentation
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/.gitignore b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/.gitignore
new file mode 100644
index 0000000..dbadf3b
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/.gitignore
@@ -0,0 +1,8 @@
+.DS_Store
+coverage.txt
+_test
+vendor
+.idea
+*.iml
+*.out
+.vscode
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/.travis.yml b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/.travis.yml
new file mode 100644
index 0000000..67d45ad
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/.travis.yml
@@ -0,0 +1,21 @@
+arch:
+ - amd64
+ - ppc64le
+
+language: go
+go:
+ - 1.14.x
+ - 1.15.x
+ - tip
+env:
+ - GO111MODULE=on
+install:
+ - go get -v golang.org/x/lint/golint
+script:
+ - golint -set_exit_status ./...
+ - go test -race -coverprofile=coverage.txt -covermode=atomic ./...
+after_success:
+ - bash <(curl -s https://codecov.io/bash)
+matrix:
+ allow_failures:
+ - go: tip
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/CHANGELOG.md b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/CHANGELOG.md
new file mode 100644
index 0000000..c1c3c10
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/CHANGELOG.md
@@ -0,0 +1,352 @@
+# Changelog
+
+## v4.10.0 - 2022-12-27
+
+**Security**
+
+* We are deprecating JWT middleware in this repository. Please use https://github.com/labstack/echo-jwt instead.
+
+ JWT middleware is moved to separate repository to allow us to bump/upgrade version of JWT implementation (`github.com/golang-jwt/jwt`) we are using
+which we can not do in Echo core because this would break backwards compatibility guarantees we try to maintain.
+
+* This minor version bumps minimum Go version to 1.17 (from 1.16) due `golang.org/x/` packages we depend on. There are
+ several vulnerabilities fixed in these libraries.
+
+ Echo still tries to support last 4 Go versions but there are occasions we can not guarantee this promise.
+
+
+**Enhancements**
+
+* Bump x/text to 0.3.8 [#2305](https://github.com/labstack/echo/pull/2305)
+* Bump dependencies and add notes about Go releases we support [#2336](https://github.com/labstack/echo/pull/2336)
+* Add helper interface for ProxyBalancer interface [#2316](https://github.com/labstack/echo/pull/2316)
+* Expose `middleware.CreateExtractors` function so we can use it from echo-contrib repository [#2338](https://github.com/labstack/echo/pull/2338)
+* Refactor func(Context) error to HandlerFunc [#2315](https://github.com/labstack/echo/pull/2315)
+* Improve function comments [#2329](https://github.com/labstack/echo/pull/2329)
+* Add new method HTTPError.WithInternal [#2340](https://github.com/labstack/echo/pull/2340)
+* Replace io/ioutil package usages [#2342](https://github.com/labstack/echo/pull/2342)
+* Add staticcheck to CI flow [#2343](https://github.com/labstack/echo/pull/2343)
+* Replace relative path determination from proprietary to std [#2345](https://github.com/labstack/echo/pull/2345)
+* Remove square brackets from ipv6 addresses in XFF (X-Forwarded-For header) [#2182](https://github.com/labstack/echo/pull/2182)
+* Add testcases for some BodyLimit middleware configuration options [#2350](https://github.com/labstack/echo/pull/2350)
+* Additional configuration options for RequestLogger and Logger middleware [#2341](https://github.com/labstack/echo/pull/2341)
+* Add route to request log [#2162](https://github.com/labstack/echo/pull/2162)
+* GitHub Workflows security hardening [#2358](https://github.com/labstack/echo/pull/2358)
+* Add govulncheck to CI and bump dependencies [#2362](https://github.com/labstack/echo/pull/2362)
+* Fix rate limiter docs [#2366](https://github.com/labstack/echo/pull/2366)
+* Refactor how `e.Routes()` work and introduce `e.OnAddRouteHandler` callback [#2337](https://github.com/labstack/echo/pull/2337)
+
+
+## v4.9.1 - 2022-10-12
+
+**Fixes**
+
+* Fix logger panicing (when template is set to empty) by bumping dependency version [#2295](https://github.com/labstack/echo/issues/2295)
+
+**Enhancements**
+
+* Improve CORS documentation [#2272](https://github.com/labstack/echo/pull/2272)
+* Update readme about supported Go versions [#2291](https://github.com/labstack/echo/pull/2291)
+* Tests: improve error handling on closing body [#2254](https://github.com/labstack/echo/pull/2254)
+* Tests: refactor some of the assertions in tests [#2275](https://github.com/labstack/echo/pull/2275)
+* Tests: refactor assertions [#2301](https://github.com/labstack/echo/pull/2301)
+
+## v4.9.0 - 2022-09-04
+
+**Security**
+
+* Fix open redirect vulnerability in handlers serving static directories (e.Static, e.StaticFs, echo.StaticDirectoryHandler) [#2260](https://github.com/labstack/echo/pull/2260)
+
+**Enhancements**
+
+* Allow configuring ErrorHandler in CSRF middleware [#2257](https://github.com/labstack/echo/pull/2257)
+* Replace HTTP method constants in tests with stdlib constants [#2247](https://github.com/labstack/echo/pull/2247)
+
+
+## v4.8.0 - 2022-08-10
+
+**Most notable things**
+
+You can now add any arbitrary HTTP method type as a route [#2237](https://github.com/labstack/echo/pull/2237)
+```go
+e.Add("COPY", "/*", func(c echo.Context) error
+ return c.String(http.StatusOK, "OK COPY")
+})
+```
+
+You can add custom 404 handler for specific paths [#2217](https://github.com/labstack/echo/pull/2217)
+```go
+e.RouteNotFound("/*", func(c echo.Context) error { return c.NoContent(http.StatusNotFound) })
+
+g := e.Group("/images")
+g.RouteNotFound("/*", func(c echo.Context) error { return c.NoContent(http.StatusNotFound) })
+```
+
+**Enhancements**
+
+* Add new value binding methods (UnixTimeMilli,TextUnmarshaler,JSONUnmarshaler) to Valuebinder [#2127](https://github.com/labstack/echo/pull/2127)
+* Refactor: body_limit middleware unit test [#2145](https://github.com/labstack/echo/pull/2145)
+* Refactor: Timeout mw: rework how test waits for timeout. [#2187](https://github.com/labstack/echo/pull/2187)
+* BasicAuth middleware returns 500 InternalServerError on invalid base64 strings but should return 400 [#2191](https://github.com/labstack/echo/pull/2191)
+* Refactor: duplicated findStaticChild process at findChildWithLabel [#2176](https://github.com/labstack/echo/pull/2176)
+* Allow different param names in different methods with same path scheme [#2209](https://github.com/labstack/echo/pull/2209)
+* Add support for registering handlers for different 404 routes [#2217](https://github.com/labstack/echo/pull/2217)
+* Middlewares should use errors.As() instead of type assertion on HTTPError [#2227](https://github.com/labstack/echo/pull/2227)
+* Allow arbitrary HTTP method types to be added as routes [#2237](https://github.com/labstack/echo/pull/2237)
+
+## v4.7.2 - 2022-03-16
+
+**Fixes**
+
+* Fix nil pointer exception when calling Start again after address binding error [#2131](https://github.com/labstack/echo/pull/2131)
+* Fix CSRF middleware not being able to extract token from multipart/form-data form [#2136](https://github.com/labstack/echo/pull/2136)
+* Fix Timeout middleware write race [#2126](https://github.com/labstack/echo/pull/2126)
+
+**Enhancements**
+
+* Recover middleware should not log panic for aborted handler [#2134](https://github.com/labstack/echo/pull/2134)
+
+
+## v4.7.1 - 2022-03-13
+
+**Fixes**
+
+* Fix `e.Static`, `.File()`, `c.Attachment()` being picky with paths starting with `./`, `../` and `/` after 4.7.0 introduced echo.Filesystem support (Go1.16+) [#2123](https://github.com/labstack/echo/pull/2123)
+
+**Enhancements**
+
+* Remove some unused code [#2116](https://github.com/labstack/echo/pull/2116)
+
+
+## v4.7.0 - 2022-03-01
+
+**Enhancements**
+
+* Add JWT, KeyAuth, CSRF multivalue extractors [#2060](https://github.com/labstack/echo/pull/2060)
+* Add LogErrorFunc to recover middleware [#2072](https://github.com/labstack/echo/pull/2072)
+* Add support for HEAD method query params binding [#2027](https://github.com/labstack/echo/pull/2027)
+* Improve filesystem support with echo.FileFS, echo.StaticFS, group.FileFS, group.StaticFS [#2064](https://github.com/labstack/echo/pull/2064)
+
+**Fixes**
+
+* Fix X-Real-IP bug, improve tests [#2007](https://github.com/labstack/echo/pull/2007)
+* Minor syntax fixes [#1994](https://github.com/labstack/echo/pull/1994), [#2102](https://github.com/labstack/echo/pull/2102), [#2102](https://github.com/labstack/echo/pull/2102)
+
+**General**
+
+* Add cache-control and connection headers [#2103](https://github.com/labstack/echo/pull/2103)
+* Add Retry-After header constant [#2078](https://github.com/labstack/echo/pull/2078)
+* Upgrade `go` directive in `go.mod` to 1.17 [#2049](https://github.com/labstack/echo/pull/2049)
+* Add Pagoda [#2077](https://github.com/labstack/echo/pull/2077) and Souin [#2069](https://github.com/labstack/echo/pull/2069) to 3rd-party middlewares in README
+
+## v4.6.3 - 2022-01-10
+
+**Fixes**
+
+* Fixed Echo version number in greeting message which was not incremented to `4.6.2` [#2066](https://github.com/labstack/echo/issues/2066)
+
+
+## v4.6.2 - 2022-01-08
+
+**Fixes**
+
+* Fixed route containing escaped colon should be matchable but is not matched to request path [#2047](https://github.com/labstack/echo/pull/2047)
+* Fixed a problem that returned wrong content-encoding when the gzip compressed content was empty. [#1921](https://github.com/labstack/echo/pull/1921)
+* Update (test) dependencies [#2021](https://github.com/labstack/echo/pull/2021)
+
+
+**Enhancements**
+
+* Add support for configurable target header for the request_id middleware [#2040](https://github.com/labstack/echo/pull/2040)
+* Change decompress middleware to use stream decompression instead of buffering [#2018](https://github.com/labstack/echo/pull/2018)
+* Documentation updates
+
+
+## v4.6.1 - 2021-09-26
+
+**Enhancements**
+
+* Add start time to request logger middleware values [#1991](https://github.com/labstack/echo/pull/1991)
+
+## v4.6.0 - 2021-09-20
+
+Introduced a new [request logger](https://github.com/labstack/echo/blob/master/middleware/request_logger.go) middleware
+to help with cases when you want to use some other logging library in your application.
+
+**Fixes**
+
+* fix timeout middleware warning: superfluous response.WriteHeader [#1905](https://github.com/labstack/echo/issues/1905)
+
+**Enhancements**
+
+* Add Cookie to KeyAuth middleware's KeyLookup [#1929](https://github.com/labstack/echo/pull/1929)
+* JWT middleware should ignore case of auth scheme in request header [#1951](https://github.com/labstack/echo/pull/1951)
+* Refactor default error handler to return first if response is already committed [#1956](https://github.com/labstack/echo/pull/1956)
+* Added request logger middleware which helps to use custom logger library for logging requests. [#1980](https://github.com/labstack/echo/pull/1980)
+* Allow escaping of colon in route path so Google Cloud API "custom methods" could be implemented [#1988](https://github.com/labstack/echo/pull/1988)
+
+## v4.5.0 - 2021-08-01
+
+**Important notes**
+
+A **BREAKING CHANGE** is introduced for JWT middleware users.
+The JWT library used for the JWT middleware had to be changed from [github.com/dgrijalva/jwt-go](https://github.com/dgrijalva/jwt-go) to
+[github.com/golang-jwt/jwt](https://github.com/golang-jwt/jwt) due former library being unmaintained and affected by security
+issues.
+The [github.com/golang-jwt/jwt](https://github.com/golang-jwt/jwt) project is a drop-in replacement, but supports only the latest 2 Go versions.
+So for JWT middleware users Go 1.15+ is required. For detailed information please read [#1940](https://github.com/labstack/echo/discussions/)
+
+To change the library imports in all .go files in your project replace all occurrences of `dgrijalva/jwt-go` with `golang-jwt/jwt`.
+
+For Linux CLI you can use:
+```bash
+find -type f -name "*.go" -exec sed -i "s/dgrijalva\/jwt-go/golang-jwt\/jwt/g" {} \;
+go mod tidy
+```
+
+**Fixes**
+
+* Change JWT library to `github.com/golang-jwt/jwt` [#1946](https://github.com/labstack/echo/pull/1946)
+
+## v4.4.0 - 2021-07-12
+
+**Fixes**
+
+* Split HeaderXForwardedFor header only by comma [#1878](https://github.com/labstack/echo/pull/1878)
+* Fix Timeout middleware Context propagation [#1910](https://github.com/labstack/echo/pull/1910)
+
+**Enhancements**
+
+* Bind data using headers as source [#1866](https://github.com/labstack/echo/pull/1866)
+* Adds JWTConfig.ParseTokenFunc to JWT middleware to allow different libraries implementing JWT parsing. [#1887](https://github.com/labstack/echo/pull/1887)
+* Adding tests for Echo#Host [#1895](https://github.com/labstack/echo/pull/1895)
+* Adds RequestIDHandler function to RequestID middleware [#1898](https://github.com/labstack/echo/pull/1898)
+* Allow for custom JSON encoding implementations [#1880](https://github.com/labstack/echo/pull/1880)
+
+## v4.3.0 - 2021-05-08
+
+**Important notes**
+
+* Route matching has improvements for following cases:
+ 1. Correctly match routes with parameter part as last part of route (with trailing backslash)
+ 2. Considering handlers when resolving routes and search for matching http method handler
+* Echo minimal Go version is now 1.13.
+
+**Fixes**
+
+* When url ends with slash first param route is the match [#1804](https://github.com/labstack/echo/pull/1812)
+* Router should check if node is suitable as matching route by path+method and if not then continue search in tree [#1808](https://github.com/labstack/echo/issues/1808)
+* Fix timeout middleware not writing response correctly when handler panics [#1864](https://github.com/labstack/echo/pull/1864)
+* Fix binder not working with embedded pointer structs [#1861](https://github.com/labstack/echo/pull/1861)
+* Add Go 1.16 to CI and drop 1.12 specific code [#1850](https://github.com/labstack/echo/pull/1850)
+
+**Enhancements**
+
+* Make KeyFunc public in JWT middleware [#1756](https://github.com/labstack/echo/pull/1756)
+* Add support for optional filesystem to the static middleware [#1797](https://github.com/labstack/echo/pull/1797)
+* Add a custom error handler to key-auth middleware [#1847](https://github.com/labstack/echo/pull/1847)
+* Allow JWT token to be looked up from multiple sources [#1845](https://github.com/labstack/echo/pull/1845)
+
+## v4.2.2 - 2021-04-07
+
+**Fixes**
+
+* Allow proxy middleware to use query part in rewrite (#1802)
+* Fix timeout middleware not sending status code when handler returns an error (#1805)
+* Fix Bind() when target is array/slice and path/query params complains bind target not being struct (#1835)
+* Fix panic in redirect middleware on short host name (#1813)
+* Fix timeout middleware docs (#1836)
+
+## v4.2.1 - 2021-03-08
+
+**Important notes**
+
+Due to a datarace the config parameters for the newly added timeout middleware required a change.
+See the [docs](https://echo.labstack.com/middleware/timeout).
+A performance regression has been fixed, even bringing better performance than before for some routing scenarios.
+
+**Fixes**
+
+* Fix performance regression caused by path escaping (#1777, #1798, #1799, aldas)
+* Avoid context canceled errors (#1789, clwluvw)
+* Improve router to use on stack backtracking (#1791, aldas, stffabi)
+* Fix panic in timeout middleware not being not recovered and cause application crash (#1794, aldas)
+* Fix Echo.Serve() not serving on HTTP port correctly when TLSListener is used (#1785, #1793, aldas)
+* Apply go fmt (#1788, Le0tk0k)
+* Uses strings.Equalfold (#1790, rkilingr)
+* Improve code quality (#1792, withshubh)
+
+This release was made possible by our **contributors**:
+aldas, clwluvw, lammel, Le0tk0k, maciej-jezierski, rkilingr, stffabi, withshubh
+
+## v4.2.0 - 2021-02-11
+
+**Important notes**
+
+The behaviour for binding data has been reworked for compatibility with echo before v4.1.11 by
+enforcing `explicit tagging` for processing parameters. This **may break** your code if you
+expect combined handling of query/path/form params.
+Please see the updated documentation for [request](https://echo.labstack.com/guide/request) and [binding](https://echo.labstack.com/guide/request)
+
+The handling for rewrite rules has been slightly adjusted to expand `*` to a non-greedy `(.*?)` capture group. This is only relevant if multiple asterisks are used in your rules.
+Please see [rewrite](https://echo.labstack.com/middleware/rewrite) and [proxy](https://echo.labstack.com/middleware/proxy) for details.
+
+**Security**
+
+* Fix directory traversal vulnerability for Windows (#1718, little-cui)
+* Fix open redirect vulnerability with trailing slash (#1771,#1775 aldas,GeoffreyFrogeye)
+
+**Enhancements**
+
+* Add Echo#ListenerNetwork as configuration (#1667, pafuent)
+* Add ability to change the status code using response beforeFuncs (#1706, RashadAnsari)
+* Echo server startup to allow data race free access to listener address
+* Binder: Restore pre v4.1.11 behaviour for c.Bind() to use query params only for GET or DELETE methods (#1727, aldas)
+* Binder: Add separate methods to bind only query params, path params or request body (#1681, aldas)
+* Binder: New fluent binder for query/path/form parameter binding (#1717, #1736, aldas)
+* Router: Performance improvements for missed routes (#1689, pafuent)
+* Router: Improve performance for Real-IP detection using IndexByte instead of Split (#1640, imxyb)
+* Middleware: Support real regex rules for rewrite and proxy middleware (#1767)
+* Middleware: New rate limiting middleware (#1724, iambenkay)
+* Middleware: New timeout middleware implementation for go1.13+ (#1743, )
+* Middleware: Allow regex pattern for CORS middleware (#1623, KlotzAndrew)
+* Middleware: Add IgnoreBase parameter to static middleware (#1701, lnenad, iambenkay)
+* Middleware: Add an optional custom function to CORS middleware to validate origin (#1651, curvegrid)
+* Middleware: Support form fields in JWT middleware (#1704, rkfg)
+* Middleware: Use sync.Pool for (de)compress middleware to improve performance (#1699, #1672, pafuent)
+* Middleware: Add decompress middleware to support gzip compressed requests (#1687, arun0009)
+* Middleware: Add ErrJWTInvalid for JWT middleware (#1627, juanbelieni)
+* Middleware: Add SameSite mode for CSRF cookies to support iframes (#1524, pr0head)
+
+**Fixes**
+
+* Fix handling of special trailing slash case for partial prefix (#1741, stffabi)
+* Fix handling of static routes with trailing slash (#1747)
+* Fix Static files route not working (#1671, pwli0755, lammel)
+* Fix use of caret(^) in regex for rewrite middleware (#1588, chotow)
+* Fix Echo#Reverse for Any type routes (#1695, pafuent)
+* Fix Router#Find panic with infinite loop (#1661, pafuent)
+* Fix Router#Find panic fails on Param paths (#1659, pafuent)
+* Fix DefaultHTTPErrorHandler with Debug=true (#1477, lammel)
+* Fix incorrect CORS headers (#1669, ulasakdeniz)
+* Fix proxy middleware rewritePath to use url with updated tests (#1630, arun0009)
+* Fix rewritePath for proxy middleware to use escaped path in (#1628, arun0009)
+* Remove unless defer (#1656, imxyb)
+
+**General**
+
+* New maintainers for Echo: Roland Lammel (@lammel) and Pablo Andres Fuente (@pafuent)
+* Add GitHub action to compare benchmarks (#1702, pafuent)
+* Binding query/path params and form fields to struct only works for explicit tags (#1729,#1734, aldas)
+* Add support for Go 1.15 in CI (#1683, asahasrabuddhe)
+* Add test for request id to remain unchanged if provided (#1719, iambenkay)
+* Refactor echo instance listener access and startup to speed up testing (#1735, aldas)
+* Refactor and improve various tests for binding and routing
+* Run test workflow only for relevant changes (#1637, #1636, pofl)
+* Update .travis.yml (#1662, santosh653)
+* Update README.md with an recents framework benchmark (#1679, pafuent)
+
+This release was made possible by **over 100 commits** from more than **20 contributors**:
+asahasrabuddhe, aldas, AndrewKlotz, arun0009, chotow, curvegrid, iambenkay, imxyb,
+juanbelieni, lammel, little-cui, lnenad, pafuent, pofl, pr0head, pwli, RashadAnsari,
+rkfg, santosh653, segfiner, stffabi, ulasakdeniz
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/LICENSE b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/LICENSE
new file mode 100644
index 0000000..c46d010
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2021 LabStack
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/Makefile b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/Makefile
new file mode 100644
index 0000000..6aff6a8
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/Makefile
@@ -0,0 +1,36 @@
+PKG := "github.com/labstack/echo"
+PKG_LIST := $(shell go list ${PKG}/...)
+
+tag:
+ @git tag `grep -P '^\tversion = ' echo.go|cut -f2 -d'"'`
+ @git tag|grep -v ^v
+
+.DEFAULT_GOAL := check
+check: lint vet race ## Check project
+
+init:
+ @go install golang.org/x/lint/golint@latest
+ @go install honnef.co/go/tools/cmd/staticcheck@latest
+
+lint: ## Lint the files
+ @staticcheck ${PKG_LIST}
+ @golint -set_exit_status ${PKG_LIST}
+
+vet: ## Vet the files
+ @go vet ${PKG_LIST}
+
+test: ## Run tests
+ @go test -short ${PKG_LIST}
+
+race: ## Run tests with data race detector
+ @go test -race ${PKG_LIST}
+
+benchmark: ## Run benchmarks
+ @go test -run="-" -bench=".*" ${PKG_LIST}
+
+help: ## Display this help screen
+ @grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
+
+goversion ?= "1.17"
+test_version: ## Run tests inside Docker with given version (defaults to 1.17 oldest supported). Example: make test_version goversion=1.17
+ @docker run --rm -it -v $(shell pwd):/project golang:$(goversion) /bin/sh -c "cd /project && make init check"
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/README.md b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/README.md
new file mode 100644
index 0000000..509b973
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/README.md
@@ -0,0 +1,138 @@
+<a href="https://echo.labstack.com"><img height="80" src="https://cdn.labstack.com/images/echo-logo.svg"></a>
+
+[![Sourcegraph](https://sourcegraph.com/github.com/labstack/echo/-/badge.svg?style=flat-square)](https://sourcegraph.com/github.com/labstack/echo?badge)
+[![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](https://pkg.go.dev/github.com/labstack/echo/v4)
+[![Go Report Card](https://goreportcard.com/badge/github.com/labstack/echo?style=flat-square)](https://goreportcard.com/report/github.com/labstack/echo)
+[![Build Status](http://img.shields.io/travis/labstack/echo.svg?style=flat-square)](https://travis-ci.org/labstack/echo)
+[![Codecov](https://img.shields.io/codecov/c/github/labstack/echo.svg?style=flat-square)](https://codecov.io/gh/labstack/echo)
+[![Forum](https://img.shields.io/badge/community-forum-00afd1.svg?style=flat-square)](https://github.com/labstack/echo/discussions)
+[![Twitter](https://img.shields.io/badge/twitter-@labstack-55acee.svg?style=flat-square)](https://twitter.com/labstack)
+[![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://raw.githubusercontent.com/labstack/echo/master/LICENSE)
+
+## Supported Go versions
+
+Latest version of Echo supports last four Go major [releases](https://go.dev/doc/devel/release) and might work with older versions.
+
+As of version 4.0.0, Echo is available as a [Go module](https://github.com/golang/go/wiki/Modules).
+Therefore a Go version capable of understanding /vN suffixed imports is required:
+
+
+Any of these versions will allow you to import Echo as `github.com/labstack/echo/v4` which is the recommended
+way of using Echo going forward.
+
+For older versions, please use the latest v3 tag.
+
+## Feature Overview
+
+- Optimized HTTP router which smartly prioritize routes
+- Build robust and scalable RESTful APIs
+- Group APIs
+- Extensible middleware framework
+- Define middleware at root, group or route level
+- Data binding for JSON, XML and form payload
+- Handy functions to send variety of HTTP responses
+- Centralized HTTP error handling
+- Template rendering with any template engine
+- Define your format for the logger
+- Highly customizable
+- Automatic TLS via Let’s Encrypt
+- HTTP/2 support
+
+## Benchmarks
+
+Date: 2020/11/11<br>
+Source: https://github.com/vishr/web-framework-benchmark<br>
+Lower is better!
+
+<img src="https://i.imgur.com/qwPNQbl.png">
+<img src="https://i.imgur.com/s8yKQjx.png">
+
+The benchmarks above were run on an Intel(R) Core(TM) i7-6820HQ CPU @ 2.70GHz
+
+## [Guide](https://echo.labstack.com/guide)
+
+### Installation
+
+```sh
+// go get github.com/labstack/echo/{version}
+go get github.com/labstack/echo/v4
+```
+
+### Example
+
+```go
+package main
+
+import (
+ "github.com/labstack/echo/v4"
+ "github.com/labstack/echo/v4/middleware"
+ "net/http"
+)
+
+func main() {
+ // Echo instance
+ e := echo.New()
+
+ // Middleware
+ e.Use(middleware.Logger())
+ e.Use(middleware.Recover())
+
+ // Routes
+ e.GET("/", hello)
+
+ // Start server
+ e.Logger.Fatal(e.Start(":1323"))
+}
+
+// Handler
+func hello(c echo.Context) error {
+ return c.String(http.StatusOK, "Hello, World!")
+}
+```
+
+# Third-party middlewares
+
+| Repository | Description |
+|------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| [github.com/labstack/echo-contrib](https://github.com/labstack/echo-contrib) | (by Echo team) [casbin](https://github.com/casbin/casbin), [gorilla/sessions](https://github.com/gorilla/sessions), [jaegertracing](github.com/uber/jaeger-client-go), [prometheus](https://github.com/prometheus/client_golang/), [pprof](https://pkg.go.dev/net/http/pprof), [zipkin](https://github.com/openzipkin/zipkin-go) middlewares |
+| [deepmap/oapi-codegen](https://github.com/deepmap/oapi-codegen) | Automatically generate RESTful API documentation with [OpenAPI](https://swagger.io/specification/) Client and Server Code Generator |
+| [github.com/swaggo/echo-swagger](https://github.com/swaggo/echo-swagger) | Automatically generate RESTful API documentation with [Swagger](https://swagger.io/) 2.0. |
+| [github.com/ziflex/lecho](https://github.com/ziflex/lecho) | [Zerolog](https://github.com/rs/zerolog) logging library wrapper for Echo logger interface. |
+| [github.com/brpaz/echozap](https://github.com/brpaz/echozap) | Uber´s [Zap](https://github.com/uber-go/zap) logging library wrapper for Echo logger interface. |
+| [github.com/darkweak/souin/plugins/echo](https://github.com/darkweak/souin/tree/master/plugins/echo) | HTTP cache system based on [Souin](https://github.com/darkweak/souin) to automatically get your endpoints cached. It supports some distributed and non-distributed storage systems depending your needs. |
+| [github.com/mikestefanello/pagoda](https://github.com/mikestefanello/pagoda) | Rapid, easy full-stack web development starter kit built with Echo. |
+| [github.com/go-woo/protoc-gen-echo](https://github.com/go-woo/protoc-gen-echo) | ProtoBuf generate Echo server side code |
+
+Please send a PR to add your own library here.
+
+## Help
+
+- [Forum](https://github.com/labstack/echo/discussions)
+
+## Contribute
+
+**Use issues for everything**
+
+- For a small change, just send a PR.
+- For bigger changes open an issue for discussion before sending a PR.
+- PR should have:
+ - Test case
+ - Documentation
+ - Example (If it makes sense)
+- You can also contribute by:
+ - Reporting issues
+ - Suggesting new features or enhancements
+ - Improve/fix documentation
+
+## Credits
+
+- [Vishal Rana](https://github.com/vishr) (Author)
+- [Nitin Rana](https://github.com/nr17) (Consultant)
+- [Roland Lammel](https://github.com/lammel) (Maintainer)
+- [Martti T.](https://github.com/aldas) (Maintainer)
+- [Pablo Andres Fuente](https://github.com/pafuent) (Maintainer)
+- [Contributors](https://github.com/labstack/echo/graphs/contributors)
+
+## License
+
+[MIT](https://github.com/labstack/echo/blob/master/LICENSE)
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/bind.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/bind.go
new file mode 100644
index 0000000..c841ca0
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/bind.go
@@ -0,0 +1,340 @@
+package echo
+
+import (
+ "encoding"
+ "encoding/xml"
+ "errors"
+ "fmt"
+ "net/http"
+ "reflect"
+ "strconv"
+ "strings"
+)
+
+type (
+ // Binder is the interface that wraps the Bind method.
+ Binder interface {
+ Bind(i interface{}, c Context) error
+ }
+
+ // DefaultBinder is the default implementation of the Binder interface.
+ DefaultBinder struct{}
+
+ // BindUnmarshaler is the interface used to wrap the UnmarshalParam method.
+ // Types that don't implement this, but do implement encoding.TextUnmarshaler
+ // will use that interface instead.
+ BindUnmarshaler interface {
+ // UnmarshalParam decodes and assigns a value from an form or query param.
+ UnmarshalParam(param string) error
+ }
+)
+
+// BindPathParams binds path params to bindable object
+func (b *DefaultBinder) BindPathParams(c Context, i interface{}) error {
+ names := c.ParamNames()
+ values := c.ParamValues()
+ params := map[string][]string{}
+ for i, name := range names {
+ params[name] = []string{values[i]}
+ }
+ if err := b.bindData(i, params, "param"); err != nil {
+ return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
+ }
+ return nil
+}
+
+// BindQueryParams binds query params to bindable object
+func (b *DefaultBinder) BindQueryParams(c Context, i interface{}) error {
+ if err := b.bindData(i, c.QueryParams(), "query"); err != nil {
+ return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
+ }
+ return nil
+}
+
+// BindBody binds request body contents to bindable object
+// NB: then binding forms take note that this implementation uses standard library form parsing
+// which parses form data from BOTH URL and BODY if content type is not MIMEMultipartForm
+// See non-MIMEMultipartForm: https://golang.org/pkg/net/http/#Request.ParseForm
+// See MIMEMultipartForm: https://golang.org/pkg/net/http/#Request.ParseMultipartForm
+func (b *DefaultBinder) BindBody(c Context, i interface{}) (err error) {
+ req := c.Request()
+ if req.ContentLength == 0 {
+ return
+ }
+
+ ctype := req.Header.Get(HeaderContentType)
+ switch {
+ case strings.HasPrefix(ctype, MIMEApplicationJSON):
+ if err = c.Echo().JSONSerializer.Deserialize(c, i); err != nil {
+ switch err.(type) {
+ case *HTTPError:
+ return err
+ default:
+ return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
+ }
+ }
+ case strings.HasPrefix(ctype, MIMEApplicationXML), strings.HasPrefix(ctype, MIMETextXML):
+ if err = xml.NewDecoder(req.Body).Decode(i); err != nil {
+ if ute, ok := err.(*xml.UnsupportedTypeError); ok {
+ return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unsupported type error: type=%v, error=%v", ute.Type, ute.Error())).SetInternal(err)
+ } else if se, ok := err.(*xml.SyntaxError); ok {
+ return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Syntax error: line=%v, error=%v", se.Line, se.Error())).SetInternal(err)
+ }
+ return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
+ }
+ case strings.HasPrefix(ctype, MIMEApplicationForm), strings.HasPrefix(ctype, MIMEMultipartForm):
+ params, err := c.FormParams()
+ if err != nil {
+ return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
+ }
+ if err = b.bindData(i, params, "form"); err != nil {
+ return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
+ }
+ default:
+ return ErrUnsupportedMediaType
+ }
+ return nil
+}
+
+// BindHeaders binds HTTP headers to a bindable object
+func (b *DefaultBinder) BindHeaders(c Context, i interface{}) error {
+ if err := b.bindData(i, c.Request().Header, "header"); err != nil {
+ return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
+ }
+ return nil
+}
+
+// Bind implements the `Binder#Bind` function.
+// Binding is done in following order: 1) path params; 2) query params; 3) request body. Each step COULD override previous
+// step binded values. For single source binding use their own methods BindBody, BindQueryParams, BindPathParams.
+func (b *DefaultBinder) Bind(i interface{}, c Context) (err error) {
+ if err := b.BindPathParams(c, i); err != nil {
+ return err
+ }
+ // Only bind query parameters for GET/DELETE/HEAD to avoid unexpected behavior with destination struct binding from body.
+ // For example a request URL `&id=1&lang=en` with body `{"id":100,"lang":"de"}` would lead to precedence issues.
+ // The HTTP method check restores pre-v4.1.11 behavior to avoid these problems (see issue #1670)
+ method := c.Request().Method
+ if method == http.MethodGet || method == http.MethodDelete || method == http.MethodHead {
+ if err = b.BindQueryParams(c, i); err != nil {
+ return err
+ }
+ }
+ return b.BindBody(c, i)
+}
+
+// bindData will bind data ONLY fields in destination struct that have EXPLICIT tag
+func (b *DefaultBinder) bindData(destination interface{}, data map[string][]string, tag string) error {
+ if destination == nil || len(data) == 0 {
+ return nil
+ }
+ typ := reflect.TypeOf(destination).Elem()
+ val := reflect.ValueOf(destination).Elem()
+
+ // Map
+ if typ.Kind() == reflect.Map {
+ for k, v := range data {
+ val.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v[0]))
+ }
+ return nil
+ }
+
+ // !struct
+ if typ.Kind() != reflect.Struct {
+ if tag == "param" || tag == "query" || tag == "header" {
+ // incompatible type, data is probably to be found in the body
+ return nil
+ }
+ return errors.New("binding element must be a struct")
+ }
+
+ for i := 0; i < typ.NumField(); i++ {
+ typeField := typ.Field(i)
+ structField := val.Field(i)
+ if typeField.Anonymous {
+ if structField.Kind() == reflect.Ptr {
+ structField = structField.Elem()
+ }
+ }
+ if !structField.CanSet() {
+ continue
+ }
+ structFieldKind := structField.Kind()
+ inputFieldName := typeField.Tag.Get(tag)
+ if typeField.Anonymous && structField.Kind() == reflect.Struct && inputFieldName != "" {
+ // if anonymous struct with query/param/form tags, report an error
+ return errors.New("query/param/form tags are not allowed with anonymous struct field")
+ }
+
+ if inputFieldName == "" {
+ // If tag is nil, we inspect if the field is a not BindUnmarshaler struct and try to bind data into it (might contains fields with tags).
+ // structs that implement BindUnmarshaler are binded only when they have explicit tag
+ if _, ok := structField.Addr().Interface().(BindUnmarshaler); !ok && structFieldKind == reflect.Struct {
+ if err := b.bindData(structField.Addr().Interface(), data, tag); err != nil {
+ return err
+ }
+ }
+ // does not have explicit tag and is not an ordinary struct - so move to next field
+ continue
+ }
+
+ inputValue, exists := data[inputFieldName]
+ if !exists {
+ // Go json.Unmarshal supports case insensitive binding. However the
+ // url params are bound case sensitive which is inconsistent. To
+ // fix this we must check all of the map values in a
+ // case-insensitive search.
+ for k, v := range data {
+ if strings.EqualFold(k, inputFieldName) {
+ inputValue = v
+ exists = true
+ break
+ }
+ }
+ }
+
+ if !exists {
+ continue
+ }
+
+ // Call this first, in case we're dealing with an alias to an array type
+ if ok, err := unmarshalField(typeField.Type.Kind(), inputValue[0], structField); ok {
+ if err != nil {
+ return err
+ }
+ continue
+ }
+
+ numElems := len(inputValue)
+ if structFieldKind == reflect.Slice && numElems > 0 {
+ sliceOf := structField.Type().Elem().Kind()
+ slice := reflect.MakeSlice(structField.Type(), numElems, numElems)
+ for j := 0; j < numElems; j++ {
+ if err := setWithProperType(sliceOf, inputValue[j], slice.Index(j)); err != nil {
+ return err
+ }
+ }
+ val.Field(i).Set(slice)
+ } else if err := setWithProperType(typeField.Type.Kind(), inputValue[0], structField); err != nil {
+ return err
+
+ }
+ }
+ return nil
+}
+
+func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value) error {
+ // But also call it here, in case we're dealing with an array of BindUnmarshalers
+ if ok, err := unmarshalField(valueKind, val, structField); ok {
+ return err
+ }
+
+ switch valueKind {
+ case reflect.Ptr:
+ return setWithProperType(structField.Elem().Kind(), val, structField.Elem())
+ case reflect.Int:
+ return setIntField(val, 0, structField)
+ case reflect.Int8:
+ return setIntField(val, 8, structField)
+ case reflect.Int16:
+ return setIntField(val, 16, structField)
+ case reflect.Int32:
+ return setIntField(val, 32, structField)
+ case reflect.Int64:
+ return setIntField(val, 64, structField)
+ case reflect.Uint:
+ return setUintField(val, 0, structField)
+ case reflect.Uint8:
+ return setUintField(val, 8, structField)
+ case reflect.Uint16:
+ return setUintField(val, 16, structField)
+ case reflect.Uint32:
+ return setUintField(val, 32, structField)
+ case reflect.Uint64:
+ return setUintField(val, 64, structField)
+ case reflect.Bool:
+ return setBoolField(val, structField)
+ case reflect.Float32:
+ return setFloatField(val, 32, structField)
+ case reflect.Float64:
+ return setFloatField(val, 64, structField)
+ case reflect.String:
+ structField.SetString(val)
+ default:
+ return errors.New("unknown type")
+ }
+ return nil
+}
+
+func unmarshalField(valueKind reflect.Kind, val string, field reflect.Value) (bool, error) {
+ switch valueKind {
+ case reflect.Ptr:
+ return unmarshalFieldPtr(val, field)
+ default:
+ return unmarshalFieldNonPtr(val, field)
+ }
+}
+
+func unmarshalFieldNonPtr(value string, field reflect.Value) (bool, error) {
+ fieldIValue := field.Addr().Interface()
+ if unmarshaler, ok := fieldIValue.(BindUnmarshaler); ok {
+ return true, unmarshaler.UnmarshalParam(value)
+ }
+ if unmarshaler, ok := fieldIValue.(encoding.TextUnmarshaler); ok {
+ return true, unmarshaler.UnmarshalText([]byte(value))
+ }
+
+ return false, nil
+}
+
+func unmarshalFieldPtr(value string, field reflect.Value) (bool, error) {
+ if field.IsNil() {
+ // Initialize the pointer to a nil value
+ field.Set(reflect.New(field.Type().Elem()))
+ }
+ return unmarshalFieldNonPtr(value, field.Elem())
+}
+
+func setIntField(value string, bitSize int, field reflect.Value) error {
+ if value == "" {
+ value = "0"
+ }
+ intVal, err := strconv.ParseInt(value, 10, bitSize)
+ if err == nil {
+ field.SetInt(intVal)
+ }
+ return err
+}
+
+func setUintField(value string, bitSize int, field reflect.Value) error {
+ if value == "" {
+ value = "0"
+ }
+ uintVal, err := strconv.ParseUint(value, 10, bitSize)
+ if err == nil {
+ field.SetUint(uintVal)
+ }
+ return err
+}
+
+func setBoolField(value string, field reflect.Value) error {
+ if value == "" {
+ value = "false"
+ }
+ boolVal, err := strconv.ParseBool(value)
+ if err == nil {
+ field.SetBool(boolVal)
+ }
+ return err
+}
+
+func setFloatField(value string, bitSize int, field reflect.Value) error {
+ if value == "" {
+ value = "0.0"
+ }
+ floatVal, err := strconv.ParseFloat(value, bitSize)
+ if err == nil {
+ field.SetFloat(floatVal)
+ }
+ return err
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/binder.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/binder.go
new file mode 100644
index 0000000..5a6cf9d
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/binder.go
@@ -0,0 +1,1331 @@
+package echo
+
+import (
+ "encoding"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "strconv"
+ "strings"
+ "time"
+)
+
+/**
+ Following functions provide handful of methods for binding to Go native types from request query or path parameters.
+ * QueryParamsBinder(c) - binds query parameters (source URL)
+ * PathParamsBinder(c) - binds path parameters (source URL)
+ * FormFieldBinder(c) - binds form fields (source URL + body)
+
+ Example:
+ ```go
+ var length int64
+ err := echo.QueryParamsBinder(c).Int64("length", &length).BindError()
+ ```
+
+ For every supported type there are following methods:
+ * <Type>("param", &destination) - if parameter value exists then binds it to given destination of that type i.e Int64(...).
+ * Must<Type>("param", &destination) - parameter value is required to exist, binds it to given destination of that type i.e MustInt64(...).
+ * <Type>s("param", &destination) - (for slices) if parameter values exists then binds it to given destination of that type i.e Int64s(...).
+ * Must<Type>s("param", &destination) - (for slices) parameter value is required to exist, binds it to given destination of that type i.e MustInt64s(...).
+
+ for some slice types `BindWithDelimiter("param", &dest, ",")` supports splitting parameter values before type conversion is done
+ i.e. URL `/api/search?id=1,2,3&id=1` can be bind to `[]int64{1,2,3,1}`
+
+ `FailFast` flags binder to stop binding after first bind error during binder call chain. Enabled by default.
+ `BindError()` returns first bind error from binder and resets errors in binder. Useful along with `FailFast()` method
+ to do binding and returns on first problem
+ `BindErrors()` returns all bind errors from binder and resets errors in binder.
+
+ Types that are supported:
+ * bool
+ * float32
+ * float64
+ * int
+ * int8
+ * int16
+ * int32
+ * int64
+ * uint
+ * uint8/byte (does not support `bytes()`. Use BindUnmarshaler/CustomFunc to convert value from base64 etc to []byte{})
+ * uint16
+ * uint32
+ * uint64
+ * string
+ * time
+ * duration
+ * BindUnmarshaler() interface
+ * TextUnmarshaler() interface
+ * JSONUnmarshaler() interface
+ * UnixTime() - converts unix time (integer) to time.Time
+ * UnixTimeMilli() - converts unix time with millisecond precision (integer) to time.Time
+ * UnixTimeNano() - converts unix time with nanosecond precision (integer) to time.Time
+ * CustomFunc() - callback function for your custom conversion logic. Signature `func(values []string) []error`
+*/
+
+// BindingError represents an error that occurred while binding request data.
+type BindingError struct {
+ // Field is the field name where value binding failed
+ Field string `json:"field"`
+ // Values of parameter that failed to bind.
+ Values []string `json:"-"`
+ *HTTPError
+}
+
+// NewBindingError creates new instance of binding error
+func NewBindingError(sourceParam string, values []string, message interface{}, internalError error) error {
+ return &BindingError{
+ Field: sourceParam,
+ Values: values,
+ HTTPError: &HTTPError{
+ Code: http.StatusBadRequest,
+ Message: message,
+ Internal: internalError,
+ },
+ }
+}
+
+// Error returns error message
+func (be *BindingError) Error() string {
+ return fmt.Sprintf("%s, field=%s", be.HTTPError.Error(), be.Field)
+}
+
+// ValueBinder provides utility methods for binding query or path parameter to various Go built-in types
+type ValueBinder struct {
+ // failFast is flag for binding methods to return without attempting to bind when previous binding already failed
+ failFast bool
+ errors []error
+
+ // ValueFunc is used to get single parameter (first) value from request
+ ValueFunc func(sourceParam string) string
+ // ValuesFunc is used to get all values for parameter from request. i.e. `/api/search?ids=1&ids=2`
+ ValuesFunc func(sourceParam string) []string
+ // ErrorFunc is used to create errors. Allows you to use your own error type, that for example marshals to your specific json response
+ ErrorFunc func(sourceParam string, values []string, message interface{}, internalError error) error
+}
+
+// QueryParamsBinder creates query parameter value binder
+func QueryParamsBinder(c Context) *ValueBinder {
+ return &ValueBinder{
+ failFast: true,
+ ValueFunc: c.QueryParam,
+ ValuesFunc: func(sourceParam string) []string {
+ values, ok := c.QueryParams()[sourceParam]
+ if !ok {
+ return nil
+ }
+ return values
+ },
+ ErrorFunc: NewBindingError,
+ }
+}
+
+// PathParamsBinder creates path parameter value binder
+func PathParamsBinder(c Context) *ValueBinder {
+ return &ValueBinder{
+ failFast: true,
+ ValueFunc: c.Param,
+ ValuesFunc: func(sourceParam string) []string {
+ // path parameter should not have multiple values so getting values does not make sense but lets not error out here
+ value := c.Param(sourceParam)
+ if value == "" {
+ return nil
+ }
+ return []string{value}
+ },
+ ErrorFunc: NewBindingError,
+ }
+}
+
+// FormFieldBinder creates form field value binder
+// For all requests, FormFieldBinder parses the raw query from the URL and uses query params as form fields
+//
+// For POST, PUT, and PATCH requests, it also reads the request body, parses it
+// as a form and uses query params as form fields. Request body parameters take precedence over URL query
+// string values in r.Form.
+//
+// NB: when binding forms take note that this implementation uses standard library form parsing
+// which parses form data from BOTH URL and BODY if content type is not MIMEMultipartForm
+// See https://golang.org/pkg/net/http/#Request.ParseForm
+func FormFieldBinder(c Context) *ValueBinder {
+ vb := &ValueBinder{
+ failFast: true,
+ ValueFunc: func(sourceParam string) string {
+ return c.Request().FormValue(sourceParam)
+ },
+ ErrorFunc: NewBindingError,
+ }
+ vb.ValuesFunc = func(sourceParam string) []string {
+ if c.Request().Form == nil {
+ // this is same as `Request().FormValue()` does internally
+ _ = c.Request().ParseMultipartForm(32 << 20)
+ }
+ values, ok := c.Request().Form[sourceParam]
+ if !ok {
+ return nil
+ }
+ return values
+ }
+
+ return vb
+}
+
+// FailFast set internal flag to indicate if binding methods will return early (without binding) when previous bind failed
+// NB: call this method before any other binding methods as it modifies binding methods behaviour
+func (b *ValueBinder) FailFast(value bool) *ValueBinder {
+ b.failFast = value
+ return b
+}
+
+func (b *ValueBinder) setError(err error) {
+ if b.errors == nil {
+ b.errors = []error{err}
+ return
+ }
+ b.errors = append(b.errors, err)
+}
+
+// BindError returns first seen bind error and resets/empties binder errors for further calls
+func (b *ValueBinder) BindError() error {
+ if b.errors == nil {
+ return nil
+ }
+ err := b.errors[0]
+ b.errors = nil // reset errors so next chain will start from zero
+ return err
+}
+
+// BindErrors returns all bind errors and resets/empties binder errors for further calls
+func (b *ValueBinder) BindErrors() []error {
+ if b.errors == nil {
+ return nil
+ }
+ errors := b.errors
+ b.errors = nil // reset errors so next chain will start from zero
+ return errors
+}
+
+// CustomFunc binds parameter values with Func. Func is called only when parameter values exist.
+func (b *ValueBinder) CustomFunc(sourceParam string, customFunc func(values []string) []error) *ValueBinder {
+ return b.customFunc(sourceParam, customFunc, false)
+}
+
+// MustCustomFunc requires parameter values to exist to bind with Func. Returns error when value does not exist.
+func (b *ValueBinder) MustCustomFunc(sourceParam string, customFunc func(values []string) []error) *ValueBinder {
+ return b.customFunc(sourceParam, customFunc, true)
+}
+
+func (b *ValueBinder) customFunc(sourceParam string, customFunc func(values []string) []error, valueMustExist bool) *ValueBinder {
+ if b.failFast && b.errors != nil {
+ return b
+ }
+
+ values := b.ValuesFunc(sourceParam)
+ if len(values) == 0 {
+ if valueMustExist {
+ b.setError(b.ErrorFunc(sourceParam, []string{}, "required field value is empty", nil))
+ }
+ return b
+ }
+ if errs := customFunc(values); errs != nil {
+ b.errors = append(b.errors, errs...)
+ }
+ return b
+}
+
+// String binds parameter to string variable
+func (b *ValueBinder) String(sourceParam string, dest *string) *ValueBinder {
+ if b.failFast && b.errors != nil {
+ return b
+ }
+
+ value := b.ValueFunc(sourceParam)
+ if value == "" {
+ return b
+ }
+ *dest = value
+ return b
+}
+
+// MustString requires parameter value to exist to bind to string variable. Returns error when value does not exist
+func (b *ValueBinder) MustString(sourceParam string, dest *string) *ValueBinder {
+ if b.failFast && b.errors != nil {
+ return b
+ }
+
+ value := b.ValueFunc(sourceParam)
+ if value == "" {
+ b.setError(b.ErrorFunc(sourceParam, []string{value}, "required field value is empty", nil))
+ return b
+ }
+ *dest = value
+ return b
+}
+
+// Strings binds parameter values to slice of string
+func (b *ValueBinder) Strings(sourceParam string, dest *[]string) *ValueBinder {
+ if b.failFast && b.errors != nil {
+ return b
+ }
+
+ value := b.ValuesFunc(sourceParam)
+ if value == nil {
+ return b
+ }
+ *dest = value
+ return b
+}
+
+// MustStrings requires parameter values to exist to bind to slice of string variables. Returns error when value does not exist
+func (b *ValueBinder) MustStrings(sourceParam string, dest *[]string) *ValueBinder {
+ if b.failFast && b.errors != nil {
+ return b
+ }
+
+ value := b.ValuesFunc(sourceParam)
+ if value == nil {
+ b.setError(b.ErrorFunc(sourceParam, []string{}, "required field value is empty", nil))
+ return b
+ }
+ *dest = value
+ return b
+}
+
+// BindUnmarshaler binds parameter to destination implementing BindUnmarshaler interface
+func (b *ValueBinder) BindUnmarshaler(sourceParam string, dest BindUnmarshaler) *ValueBinder {
+ if b.failFast && b.errors != nil {
+ return b
+ }
+
+ tmp := b.ValueFunc(sourceParam)
+ if tmp == "" {
+ return b
+ }
+
+ if err := dest.UnmarshalParam(tmp); err != nil {
+ b.setError(b.ErrorFunc(sourceParam, []string{tmp}, "failed to bind field value to BindUnmarshaler interface", err))
+ }
+ return b
+}
+
+// MustBindUnmarshaler requires parameter value to exist to bind to destination implementing BindUnmarshaler interface.
+// Returns error when value does not exist
+func (b *ValueBinder) MustBindUnmarshaler(sourceParam string, dest BindUnmarshaler) *ValueBinder {
+ if b.failFast && b.errors != nil {
+ return b
+ }
+
+ value := b.ValueFunc(sourceParam)
+ if value == "" {
+ b.setError(b.ErrorFunc(sourceParam, []string{value}, "required field value is empty", nil))
+ return b
+ }
+
+ if err := dest.UnmarshalParam(value); err != nil {
+ b.setError(b.ErrorFunc(sourceParam, []string{value}, "failed to bind field value to BindUnmarshaler interface", err))
+ }
+ return b
+}
+
+// JSONUnmarshaler binds parameter to destination implementing json.Unmarshaler interface
+func (b *ValueBinder) JSONUnmarshaler(sourceParam string, dest json.Unmarshaler) *ValueBinder {
+ if b.failFast && b.errors != nil {
+ return b
+ }
+
+ tmp := b.ValueFunc(sourceParam)
+ if tmp == "" {
+ return b
+ }
+
+ if err := dest.UnmarshalJSON([]byte(tmp)); err != nil {
+ b.setError(b.ErrorFunc(sourceParam, []string{tmp}, "failed to bind field value to json.Unmarshaler interface", err))
+ }
+ return b
+}
+
+// MustJSONUnmarshaler requires parameter value to exist to bind to destination implementing json.Unmarshaler interface.
+// Returns error when value does not exist
+func (b *ValueBinder) MustJSONUnmarshaler(sourceParam string, dest json.Unmarshaler) *ValueBinder {
+ if b.failFast && b.errors != nil {
+ return b
+ }
+
+ tmp := b.ValueFunc(sourceParam)
+ if tmp == "" {
+ b.setError(b.ErrorFunc(sourceParam, []string{tmp}, "required field value is empty", nil))
+ return b
+ }
+
+ if err := dest.UnmarshalJSON([]byte(tmp)); err != nil {
+ b.setError(b.ErrorFunc(sourceParam, []string{tmp}, "failed to bind field value to json.Unmarshaler interface", err))
+ }
+ return b
+}
+
+// TextUnmarshaler binds parameter to destination implementing encoding.TextUnmarshaler interface
+func (b *ValueBinder) TextUnmarshaler(sourceParam string, dest encoding.TextUnmarshaler) *ValueBinder {
+ if b.failFast && b.errors != nil {
+ return b
+ }
+
+ tmp := b.ValueFunc(sourceParam)
+ if tmp == "" {
+ return b
+ }
+
+ if err := dest.UnmarshalText([]byte(tmp)); err != nil {
+ b.setError(b.ErrorFunc(sourceParam, []string{tmp}, "failed to bind field value to encoding.TextUnmarshaler interface", err))
+ }
+ return b
+}
+
+// MustTextUnmarshaler requires parameter value to exist to bind to destination implementing encoding.TextUnmarshaler interface.
+// Returns error when value does not exist
+func (b *ValueBinder) MustTextUnmarshaler(sourceParam string, dest encoding.TextUnmarshaler) *ValueBinder {
+ if b.failFast && b.errors != nil {
+ return b
+ }
+
+ tmp := b.ValueFunc(sourceParam)
+ if tmp == "" {
+ b.setError(b.ErrorFunc(sourceParam, []string{tmp}, "required field value is empty", nil))
+ return b
+ }
+
+ if err := dest.UnmarshalText([]byte(tmp)); err != nil {
+ b.setError(b.ErrorFunc(sourceParam, []string{tmp}, "failed to bind field value to encoding.TextUnmarshaler interface", err))
+ }
+ return b
+}
+
+// BindWithDelimiter binds parameter to destination by suitable conversion function.
+// Delimiter is used before conversion to split parameter value to separate values
+func (b *ValueBinder) BindWithDelimiter(sourceParam string, dest interface{}, delimiter string) *ValueBinder {
+ return b.bindWithDelimiter(sourceParam, dest, delimiter, false)
+}
+
+// MustBindWithDelimiter requires parameter value to exist to bind destination by suitable conversion function.
+// Delimiter is used before conversion to split parameter value to separate values
+func (b *ValueBinder) MustBindWithDelimiter(sourceParam string, dest interface{}, delimiter string) *ValueBinder {
+ return b.bindWithDelimiter(sourceParam, dest, delimiter, true)
+}
+
+func (b *ValueBinder) bindWithDelimiter(sourceParam string, dest interface{}, delimiter string, valueMustExist bool) *ValueBinder {
+ if b.failFast && b.errors != nil {
+ return b
+ }
+ values := b.ValuesFunc(sourceParam)
+ if len(values) == 0 {
+ if valueMustExist {
+ b.setError(b.ErrorFunc(sourceParam, []string{}, "required field value is empty", nil))
+ }
+ return b
+ }
+ tmpValues := make([]string, 0, len(values))
+ for _, v := range values {
+ tmpValues = append(tmpValues, strings.Split(v, delimiter)...)
+ }
+
+ switch d := dest.(type) {
+ case *[]string:
+ *d = tmpValues
+ return b
+ case *[]bool:
+ return b.bools(sourceParam, tmpValues, d)
+ case *[]int64, *[]int32, *[]int16, *[]int8, *[]int:
+ return b.ints(sourceParam, tmpValues, d)
+ case *[]uint64, *[]uint32, *[]uint16, *[]uint8, *[]uint: // *[]byte is same as *[]uint8
+ return b.uints(sourceParam, tmpValues, d)
+ case *[]float64, *[]float32:
+ return b.floats(sourceParam, tmpValues, d)
+ case *[]time.Duration:
+ return b.durations(sourceParam, tmpValues, d)
+ default:
+ // support only cases when destination is slice
+ // does not support time.Time as it needs argument (layout) for parsing or BindUnmarshaler
+ b.setError(b.ErrorFunc(sourceParam, []string{}, "unsupported bind type", nil))
+ return b
+ }
+}
+
+// Int64 binds parameter to int64 variable
+func (b *ValueBinder) Int64(sourceParam string, dest *int64) *ValueBinder {
+ return b.intValue(sourceParam, dest, 64, false)
+}
+
+// MustInt64 requires parameter value to exist to bind to int64 variable. Returns error when value does not exist
+func (b *ValueBinder) MustInt64(sourceParam string, dest *int64) *ValueBinder {
+ return b.intValue(sourceParam, dest, 64, true)
+}
+
+// Int32 binds parameter to int32 variable
+func (b *ValueBinder) Int32(sourceParam string, dest *int32) *ValueBinder {
+ return b.intValue(sourceParam, dest, 32, false)
+}
+
+// MustInt32 requires parameter value to exist to bind to int32 variable. Returns error when value does not exist
+func (b *ValueBinder) MustInt32(sourceParam string, dest *int32) *ValueBinder {
+ return b.intValue(sourceParam, dest, 32, true)
+}
+
+// Int16 binds parameter to int16 variable
+func (b *ValueBinder) Int16(sourceParam string, dest *int16) *ValueBinder {
+ return b.intValue(sourceParam, dest, 16, false)
+}
+
+// MustInt16 requires parameter value to exist to bind to int16 variable. Returns error when value does not exist
+func (b *ValueBinder) MustInt16(sourceParam string, dest *int16) *ValueBinder {
+ return b.intValue(sourceParam, dest, 16, true)
+}
+
+// Int8 binds parameter to int8 variable
+func (b *ValueBinder) Int8(sourceParam string, dest *int8) *ValueBinder {
+ return b.intValue(sourceParam, dest, 8, false)
+}
+
+// MustInt8 requires parameter value to exist to bind to int8 variable. Returns error when value does not exist
+func (b *ValueBinder) MustInt8(sourceParam string, dest *int8) *ValueBinder {
+ return b.intValue(sourceParam, dest, 8, true)
+}
+
+// Int binds parameter to int variable
+func (b *ValueBinder) Int(sourceParam string, dest *int) *ValueBinder {
+ return b.intValue(sourceParam, dest, 0, false)
+}
+
+// MustInt requires parameter value to exist to bind to int variable. Returns error when value does not exist
+func (b *ValueBinder) MustInt(sourceParam string, dest *int) *ValueBinder {
+ return b.intValue(sourceParam, dest, 0, true)
+}
+
+func (b *ValueBinder) intValue(sourceParam string, dest interface{}, bitSize int, valueMustExist bool) *ValueBinder {
+ if b.failFast && b.errors != nil {
+ return b
+ }
+
+ value := b.ValueFunc(sourceParam)
+ if value == "" {
+ if valueMustExist {
+ b.setError(b.ErrorFunc(sourceParam, []string{}, "required field value is empty", nil))
+ }
+ return b
+ }
+
+ return b.int(sourceParam, value, dest, bitSize)
+}
+
+func (b *ValueBinder) int(sourceParam string, value string, dest interface{}, bitSize int) *ValueBinder {
+ n, err := strconv.ParseInt(value, 10, bitSize)
+ if err != nil {
+ if bitSize == 0 {
+ b.setError(b.ErrorFunc(sourceParam, []string{value}, "failed to bind field value to int", err))
+ } else {
+ b.setError(b.ErrorFunc(sourceParam, []string{value}, fmt.Sprintf("failed to bind field value to int%v", bitSize), err))
+ }
+ return b
+ }
+
+ switch d := dest.(type) {
+ case *int64:
+ *d = n
+ case *int32:
+ *d = int32(n)
+ case *int16:
+ *d = int16(n)
+ case *int8:
+ *d = int8(n)
+ case *int:
+ *d = int(n)
+ }
+ return b
+}
+
+func (b *ValueBinder) intsValue(sourceParam string, dest interface{}, valueMustExist bool) *ValueBinder {
+ if b.failFast && b.errors != nil {
+ return b
+ }
+
+ values := b.ValuesFunc(sourceParam)
+ if len(values) == 0 {
+ if valueMustExist {
+ b.setError(b.ErrorFunc(sourceParam, values, "required field value is empty", nil))
+ }
+ return b
+ }
+ return b.ints(sourceParam, values, dest)
+}
+
+func (b *ValueBinder) ints(sourceParam string, values []string, dest interface{}) *ValueBinder {
+ switch d := dest.(type) {
+ case *[]int64:
+ tmp := make([]int64, len(values))
+ for i, v := range values {
+ b.int(sourceParam, v, &tmp[i], 64)
+ if b.failFast && b.errors != nil {
+ return b
+ }
+ }
+ if b.errors == nil {
+ *d = tmp
+ }
+ case *[]int32:
+ tmp := make([]int32, len(values))
+ for i, v := range values {
+ b.int(sourceParam, v, &tmp[i], 32)
+ if b.failFast && b.errors != nil {
+ return b
+ }
+ }
+ if b.errors == nil {
+ *d = tmp
+ }
+ case *[]int16:
+ tmp := make([]int16, len(values))
+ for i, v := range values {
+ b.int(sourceParam, v, &tmp[i], 16)
+ if b.failFast && b.errors != nil {
+ return b
+ }
+ }
+ if b.errors == nil {
+ *d = tmp
+ }
+ case *[]int8:
+ tmp := make([]int8, len(values))
+ for i, v := range values {
+ b.int(sourceParam, v, &tmp[i], 8)
+ if b.failFast && b.errors != nil {
+ return b
+ }
+ }
+ if b.errors == nil {
+ *d = tmp
+ }
+ case *[]int:
+ tmp := make([]int, len(values))
+ for i, v := range values {
+ b.int(sourceParam, v, &tmp[i], 0)
+ if b.failFast && b.errors != nil {
+ return b
+ }
+ }
+ if b.errors == nil {
+ *d = tmp
+ }
+ }
+ return b
+}
+
+// Int64s binds parameter to slice of int64
+func (b *ValueBinder) Int64s(sourceParam string, dest *[]int64) *ValueBinder {
+ return b.intsValue(sourceParam, dest, false)
+}
+
+// MustInt64s requires parameter value to exist to bind to int64 slice variable. Returns error when value does not exist
+func (b *ValueBinder) MustInt64s(sourceParam string, dest *[]int64) *ValueBinder {
+ return b.intsValue(sourceParam, dest, true)
+}
+
+// Int32s binds parameter to slice of int32
+func (b *ValueBinder) Int32s(sourceParam string, dest *[]int32) *ValueBinder {
+ return b.intsValue(sourceParam, dest, false)
+}
+
+// MustInt32s requires parameter value to exist to bind to int32 slice variable. Returns error when value does not exist
+func (b *ValueBinder) MustInt32s(sourceParam string, dest *[]int32) *ValueBinder {
+ return b.intsValue(sourceParam, dest, true)
+}
+
+// Int16s binds parameter to slice of int16
+func (b *ValueBinder) Int16s(sourceParam string, dest *[]int16) *ValueBinder {
+ return b.intsValue(sourceParam, dest, false)
+}
+
+// MustInt16s requires parameter value to exist to bind to int16 slice variable. Returns error when value does not exist
+func (b *ValueBinder) MustInt16s(sourceParam string, dest *[]int16) *ValueBinder {
+ return b.intsValue(sourceParam, dest, true)
+}
+
+// Int8s binds parameter to slice of int8
+func (b *ValueBinder) Int8s(sourceParam string, dest *[]int8) *ValueBinder {
+ return b.intsValue(sourceParam, dest, false)
+}
+
+// MustInt8s requires parameter value to exist to bind to int8 slice variable. Returns error when value does not exist
+func (b *ValueBinder) MustInt8s(sourceParam string, dest *[]int8) *ValueBinder {
+ return b.intsValue(sourceParam, dest, true)
+}
+
+// Ints binds parameter to slice of int
+func (b *ValueBinder) Ints(sourceParam string, dest *[]int) *ValueBinder {
+ return b.intsValue(sourceParam, dest, false)
+}
+
+// MustInts requires parameter value to exist to bind to int slice variable. Returns error when value does not exist
+func (b *ValueBinder) MustInts(sourceParam string, dest *[]int) *ValueBinder {
+ return b.intsValue(sourceParam, dest, true)
+}
+
+// Uint64 binds parameter to uint64 variable
+func (b *ValueBinder) Uint64(sourceParam string, dest *uint64) *ValueBinder {
+ return b.uintValue(sourceParam, dest, 64, false)
+}
+
+// MustUint64 requires parameter value to exist to bind to uint64 variable. Returns error when value does not exist
+func (b *ValueBinder) MustUint64(sourceParam string, dest *uint64) *ValueBinder {
+ return b.uintValue(sourceParam, dest, 64, true)
+}
+
+// Uint32 binds parameter to uint32 variable
+func (b *ValueBinder) Uint32(sourceParam string, dest *uint32) *ValueBinder {
+ return b.uintValue(sourceParam, dest, 32, false)
+}
+
+// MustUint32 requires parameter value to exist to bind to uint32 variable. Returns error when value does not exist
+func (b *ValueBinder) MustUint32(sourceParam string, dest *uint32) *ValueBinder {
+ return b.uintValue(sourceParam, dest, 32, true)
+}
+
+// Uint16 binds parameter to uint16 variable
+func (b *ValueBinder) Uint16(sourceParam string, dest *uint16) *ValueBinder {
+ return b.uintValue(sourceParam, dest, 16, false)
+}
+
+// MustUint16 requires parameter value to exist to bind to uint16 variable. Returns error when value does not exist
+func (b *ValueBinder) MustUint16(sourceParam string, dest *uint16) *ValueBinder {
+ return b.uintValue(sourceParam, dest, 16, true)
+}
+
+// Uint8 binds parameter to uint8 variable
+func (b *ValueBinder) Uint8(sourceParam string, dest *uint8) *ValueBinder {
+ return b.uintValue(sourceParam, dest, 8, false)
+}
+
+// MustUint8 requires parameter value to exist to bind to uint8 variable. Returns error when value does not exist
+func (b *ValueBinder) MustUint8(sourceParam string, dest *uint8) *ValueBinder {
+ return b.uintValue(sourceParam, dest, 8, true)
+}
+
+// Byte binds parameter to byte variable
+func (b *ValueBinder) Byte(sourceParam string, dest *byte) *ValueBinder {
+ return b.uintValue(sourceParam, dest, 8, false)
+}
+
+// MustByte requires parameter value to exist to bind to byte variable. Returns error when value does not exist
+func (b *ValueBinder) MustByte(sourceParam string, dest *byte) *ValueBinder {
+ return b.uintValue(sourceParam, dest, 8, true)
+}
+
+// Uint binds parameter to uint variable
+func (b *ValueBinder) Uint(sourceParam string, dest *uint) *ValueBinder {
+ return b.uintValue(sourceParam, dest, 0, false)
+}
+
+// MustUint requires parameter value to exist to bind to uint variable. Returns error when value does not exist
+func (b *ValueBinder) MustUint(sourceParam string, dest *uint) *ValueBinder {
+ return b.uintValue(sourceParam, dest, 0, true)
+}
+
+func (b *ValueBinder) uintValue(sourceParam string, dest interface{}, bitSize int, valueMustExist bool) *ValueBinder {
+ if b.failFast && b.errors != nil {
+ return b
+ }
+
+ value := b.ValueFunc(sourceParam)
+ if value == "" {
+ if valueMustExist {
+ b.setError(b.ErrorFunc(sourceParam, []string{}, "required field value is empty", nil))
+ }
+ return b
+ }
+
+ return b.uint(sourceParam, value, dest, bitSize)
+}
+
+func (b *ValueBinder) uint(sourceParam string, value string, dest interface{}, bitSize int) *ValueBinder {
+ n, err := strconv.ParseUint(value, 10, bitSize)
+ if err != nil {
+ if bitSize == 0 {
+ b.setError(b.ErrorFunc(sourceParam, []string{value}, "failed to bind field value to uint", err))
+ } else {
+ b.setError(b.ErrorFunc(sourceParam, []string{value}, fmt.Sprintf("failed to bind field value to uint%v", bitSize), err))
+ }
+ return b
+ }
+
+ switch d := dest.(type) {
+ case *uint64:
+ *d = n
+ case *uint32:
+ *d = uint32(n)
+ case *uint16:
+ *d = uint16(n)
+ case *uint8: // byte is alias to uint8
+ *d = uint8(n)
+ case *uint:
+ *d = uint(n)
+ }
+ return b
+}
+
+func (b *ValueBinder) uintsValue(sourceParam string, dest interface{}, valueMustExist bool) *ValueBinder {
+ if b.failFast && b.errors != nil {
+ return b
+ }
+
+ values := b.ValuesFunc(sourceParam)
+ if len(values) == 0 {
+ if valueMustExist {
+ b.setError(b.ErrorFunc(sourceParam, values, "required field value is empty", nil))
+ }
+ return b
+ }
+ return b.uints(sourceParam, values, dest)
+}
+
+func (b *ValueBinder) uints(sourceParam string, values []string, dest interface{}) *ValueBinder {
+ switch d := dest.(type) {
+ case *[]uint64:
+ tmp := make([]uint64, len(values))
+ for i, v := range values {
+ b.uint(sourceParam, v, &tmp[i], 64)
+ if b.failFast && b.errors != nil {
+ return b
+ }
+ }
+ if b.errors == nil {
+ *d = tmp
+ }
+ case *[]uint32:
+ tmp := make([]uint32, len(values))
+ for i, v := range values {
+ b.uint(sourceParam, v, &tmp[i], 32)
+ if b.failFast && b.errors != nil {
+ return b
+ }
+ }
+ if b.errors == nil {
+ *d = tmp
+ }
+ case *[]uint16:
+ tmp := make([]uint16, len(values))
+ for i, v := range values {
+ b.uint(sourceParam, v, &tmp[i], 16)
+ if b.failFast && b.errors != nil {
+ return b
+ }
+ }
+ if b.errors == nil {
+ *d = tmp
+ }
+ case *[]uint8: // byte is alias to uint8
+ tmp := make([]uint8, len(values))
+ for i, v := range values {
+ b.uint(sourceParam, v, &tmp[i], 8)
+ if b.failFast && b.errors != nil {
+ return b
+ }
+ }
+ if b.errors == nil {
+ *d = tmp
+ }
+ case *[]uint:
+ tmp := make([]uint, len(values))
+ for i, v := range values {
+ b.uint(sourceParam, v, &tmp[i], 0)
+ if b.failFast && b.errors != nil {
+ return b
+ }
+ }
+ if b.errors == nil {
+ *d = tmp
+ }
+ }
+ return b
+}
+
+// Uint64s binds parameter to slice of uint64
+func (b *ValueBinder) Uint64s(sourceParam string, dest *[]uint64) *ValueBinder {
+ return b.uintsValue(sourceParam, dest, false)
+}
+
+// MustUint64s requires parameter value to exist to bind to uint64 slice variable. Returns error when value does not exist
+func (b *ValueBinder) MustUint64s(sourceParam string, dest *[]uint64) *ValueBinder {
+ return b.uintsValue(sourceParam, dest, true)
+}
+
+// Uint32s binds parameter to slice of uint32
+func (b *ValueBinder) Uint32s(sourceParam string, dest *[]uint32) *ValueBinder {
+ return b.uintsValue(sourceParam, dest, false)
+}
+
+// MustUint32s requires parameter value to exist to bind to uint32 slice variable. Returns error when value does not exist
+func (b *ValueBinder) MustUint32s(sourceParam string, dest *[]uint32) *ValueBinder {
+ return b.uintsValue(sourceParam, dest, true)
+}
+
+// Uint16s binds parameter to slice of uint16
+func (b *ValueBinder) Uint16s(sourceParam string, dest *[]uint16) *ValueBinder {
+ return b.uintsValue(sourceParam, dest, false)
+}
+
+// MustUint16s requires parameter value to exist to bind to uint16 slice variable. Returns error when value does not exist
+func (b *ValueBinder) MustUint16s(sourceParam string, dest *[]uint16) *ValueBinder {
+ return b.uintsValue(sourceParam, dest, true)
+}
+
+// Uint8s binds parameter to slice of uint8
+func (b *ValueBinder) Uint8s(sourceParam string, dest *[]uint8) *ValueBinder {
+ return b.uintsValue(sourceParam, dest, false)
+}
+
+// MustUint8s requires parameter value to exist to bind to uint8 slice variable. Returns error when value does not exist
+func (b *ValueBinder) MustUint8s(sourceParam string, dest *[]uint8) *ValueBinder {
+ return b.uintsValue(sourceParam, dest, true)
+}
+
+// Uints binds parameter to slice of uint
+func (b *ValueBinder) Uints(sourceParam string, dest *[]uint) *ValueBinder {
+ return b.uintsValue(sourceParam, dest, false)
+}
+
+// MustUints requires parameter value to exist to bind to uint slice variable. Returns error when value does not exist
+func (b *ValueBinder) MustUints(sourceParam string, dest *[]uint) *ValueBinder {
+ return b.uintsValue(sourceParam, dest, true)
+}
+
+// Bool binds parameter to bool variable
+func (b *ValueBinder) Bool(sourceParam string, dest *bool) *ValueBinder {
+ return b.boolValue(sourceParam, dest, false)
+}
+
+// MustBool requires parameter value to exist to bind to bool variable. Returns error when value does not exist
+func (b *ValueBinder) MustBool(sourceParam string, dest *bool) *ValueBinder {
+ return b.boolValue(sourceParam, dest, true)
+}
+
+func (b *ValueBinder) boolValue(sourceParam string, dest *bool, valueMustExist bool) *ValueBinder {
+ if b.failFast && b.errors != nil {
+ return b
+ }
+
+ value := b.ValueFunc(sourceParam)
+ if value == "" {
+ if valueMustExist {
+ b.setError(b.ErrorFunc(sourceParam, []string{}, "required field value is empty", nil))
+ }
+ return b
+ }
+ return b.bool(sourceParam, value, dest)
+}
+
+func (b *ValueBinder) bool(sourceParam string, value string, dest *bool) *ValueBinder {
+ n, err := strconv.ParseBool(value)
+ if err != nil {
+ b.setError(b.ErrorFunc(sourceParam, []string{value}, "failed to bind field value to bool", err))
+ return b
+ }
+
+ *dest = n
+ return b
+}
+
+func (b *ValueBinder) boolsValue(sourceParam string, dest *[]bool, valueMustExist bool) *ValueBinder {
+ if b.failFast && b.errors != nil {
+ return b
+ }
+
+ values := b.ValuesFunc(sourceParam)
+ if len(values) == 0 {
+ if valueMustExist {
+ b.setError(b.ErrorFunc(sourceParam, []string{}, "required field value is empty", nil))
+ }
+ return b
+ }
+ return b.bools(sourceParam, values, dest)
+}
+
+func (b *ValueBinder) bools(sourceParam string, values []string, dest *[]bool) *ValueBinder {
+ tmp := make([]bool, len(values))
+ for i, v := range values {
+ b.bool(sourceParam, v, &tmp[i])
+ if b.failFast && b.errors != nil {
+ return b
+ }
+ }
+ if b.errors == nil {
+ *dest = tmp
+ }
+ return b
+}
+
+// Bools binds parameter values to slice of bool variables
+func (b *ValueBinder) Bools(sourceParam string, dest *[]bool) *ValueBinder {
+ return b.boolsValue(sourceParam, dest, false)
+}
+
+// MustBools requires parameter values to exist to bind to slice of bool variables. Returns error when values does not exist
+func (b *ValueBinder) MustBools(sourceParam string, dest *[]bool) *ValueBinder {
+ return b.boolsValue(sourceParam, dest, true)
+}
+
+// Float64 binds parameter to float64 variable
+func (b *ValueBinder) Float64(sourceParam string, dest *float64) *ValueBinder {
+ return b.floatValue(sourceParam, dest, 64, false)
+}
+
+// MustFloat64 requires parameter value to exist to bind to float64 variable. Returns error when value does not exist
+func (b *ValueBinder) MustFloat64(sourceParam string, dest *float64) *ValueBinder {
+ return b.floatValue(sourceParam, dest, 64, true)
+}
+
+// Float32 binds parameter to float32 variable
+func (b *ValueBinder) Float32(sourceParam string, dest *float32) *ValueBinder {
+ return b.floatValue(sourceParam, dest, 32, false)
+}
+
+// MustFloat32 requires parameter value to exist to bind to float32 variable. Returns error when value does not exist
+func (b *ValueBinder) MustFloat32(sourceParam string, dest *float32) *ValueBinder {
+ return b.floatValue(sourceParam, dest, 32, true)
+}
+
+func (b *ValueBinder) floatValue(sourceParam string, dest interface{}, bitSize int, valueMustExist bool) *ValueBinder {
+ if b.failFast && b.errors != nil {
+ return b
+ }
+
+ value := b.ValueFunc(sourceParam)
+ if value == "" {
+ if valueMustExist {
+ b.setError(b.ErrorFunc(sourceParam, []string{}, "required field value is empty", nil))
+ }
+ return b
+ }
+
+ return b.float(sourceParam, value, dest, bitSize)
+}
+
+func (b *ValueBinder) float(sourceParam string, value string, dest interface{}, bitSize int) *ValueBinder {
+ n, err := strconv.ParseFloat(value, bitSize)
+ if err != nil {
+ b.setError(b.ErrorFunc(sourceParam, []string{value}, fmt.Sprintf("failed to bind field value to float%v", bitSize), err))
+ return b
+ }
+
+ switch d := dest.(type) {
+ case *float64:
+ *d = n
+ case *float32:
+ *d = float32(n)
+ }
+ return b
+}
+
+func (b *ValueBinder) floatsValue(sourceParam string, dest interface{}, valueMustExist bool) *ValueBinder {
+ if b.failFast && b.errors != nil {
+ return b
+ }
+
+ values := b.ValuesFunc(sourceParam)
+ if len(values) == 0 {
+ if valueMustExist {
+ b.setError(b.ErrorFunc(sourceParam, []string{}, "required field value is empty", nil))
+ }
+ return b
+ }
+ return b.floats(sourceParam, values, dest)
+}
+
+func (b *ValueBinder) floats(sourceParam string, values []string, dest interface{}) *ValueBinder {
+ switch d := dest.(type) {
+ case *[]float64:
+ tmp := make([]float64, len(values))
+ for i, v := range values {
+ b.float(sourceParam, v, &tmp[i], 64)
+ if b.failFast && b.errors != nil {
+ return b
+ }
+ }
+ if b.errors == nil {
+ *d = tmp
+ }
+ case *[]float32:
+ tmp := make([]float32, len(values))
+ for i, v := range values {
+ b.float(sourceParam, v, &tmp[i], 32)
+ if b.failFast && b.errors != nil {
+ return b
+ }
+ }
+ if b.errors == nil {
+ *d = tmp
+ }
+ }
+ return b
+}
+
+// Float64s binds parameter values to slice of float64 variables
+func (b *ValueBinder) Float64s(sourceParam string, dest *[]float64) *ValueBinder {
+ return b.floatsValue(sourceParam, dest, false)
+}
+
+// MustFloat64s requires parameter values to exist to bind to slice of float64 variables. Returns error when values does not exist
+func (b *ValueBinder) MustFloat64s(sourceParam string, dest *[]float64) *ValueBinder {
+ return b.floatsValue(sourceParam, dest, true)
+}
+
+// Float32s binds parameter values to slice of float32 variables
+func (b *ValueBinder) Float32s(sourceParam string, dest *[]float32) *ValueBinder {
+ return b.floatsValue(sourceParam, dest, false)
+}
+
+// MustFloat32s requires parameter values to exist to bind to slice of float32 variables. Returns error when values does not exist
+func (b *ValueBinder) MustFloat32s(sourceParam string, dest *[]float32) *ValueBinder {
+ return b.floatsValue(sourceParam, dest, true)
+}
+
+// Time binds parameter to time.Time variable
+func (b *ValueBinder) Time(sourceParam string, dest *time.Time, layout string) *ValueBinder {
+ return b.time(sourceParam, dest, layout, false)
+}
+
+// MustTime requires parameter value to exist to bind to time.Time variable. Returns error when value does not exist
+func (b *ValueBinder) MustTime(sourceParam string, dest *time.Time, layout string) *ValueBinder {
+ return b.time(sourceParam, dest, layout, true)
+}
+
+func (b *ValueBinder) time(sourceParam string, dest *time.Time, layout string, valueMustExist bool) *ValueBinder {
+ if b.failFast && b.errors != nil {
+ return b
+ }
+
+ value := b.ValueFunc(sourceParam)
+ if value == "" {
+ if valueMustExist {
+ b.setError(b.ErrorFunc(sourceParam, []string{value}, "required field value is empty", nil))
+ }
+ return b
+ }
+ t, err := time.Parse(layout, value)
+ if err != nil {
+ b.setError(b.ErrorFunc(sourceParam, []string{value}, "failed to bind field value to Time", err))
+ return b
+ }
+ *dest = t
+ return b
+}
+
+// Times binds parameter values to slice of time.Time variables
+func (b *ValueBinder) Times(sourceParam string, dest *[]time.Time, layout string) *ValueBinder {
+ return b.times(sourceParam, dest, layout, false)
+}
+
+// MustTimes requires parameter values to exist to bind to slice of time.Time variables. Returns error when values does not exist
+func (b *ValueBinder) MustTimes(sourceParam string, dest *[]time.Time, layout string) *ValueBinder {
+ return b.times(sourceParam, dest, layout, true)
+}
+
+func (b *ValueBinder) times(sourceParam string, dest *[]time.Time, layout string, valueMustExist bool) *ValueBinder {
+ if b.failFast && b.errors != nil {
+ return b
+ }
+
+ values := b.ValuesFunc(sourceParam)
+ if len(values) == 0 {
+ if valueMustExist {
+ b.setError(b.ErrorFunc(sourceParam, []string{}, "required field value is empty", nil))
+ }
+ return b
+ }
+
+ tmp := make([]time.Time, len(values))
+ for i, v := range values {
+ t, err := time.Parse(layout, v)
+ if err != nil {
+ b.setError(b.ErrorFunc(sourceParam, []string{v}, "failed to bind field value to Time", err))
+ if b.failFast {
+ return b
+ }
+ continue
+ }
+ tmp[i] = t
+ }
+ if b.errors == nil {
+ *dest = tmp
+ }
+ return b
+}
+
+// Duration binds parameter to time.Duration variable
+func (b *ValueBinder) Duration(sourceParam string, dest *time.Duration) *ValueBinder {
+ return b.duration(sourceParam, dest, false)
+}
+
+// MustDuration requires parameter value to exist to bind to time.Duration variable. Returns error when value does not exist
+func (b *ValueBinder) MustDuration(sourceParam string, dest *time.Duration) *ValueBinder {
+ return b.duration(sourceParam, dest, true)
+}
+
+func (b *ValueBinder) duration(sourceParam string, dest *time.Duration, valueMustExist bool) *ValueBinder {
+ if b.failFast && b.errors != nil {
+ return b
+ }
+
+ value := b.ValueFunc(sourceParam)
+ if value == "" {
+ if valueMustExist {
+ b.setError(b.ErrorFunc(sourceParam, []string{value}, "required field value is empty", nil))
+ }
+ return b
+ }
+ t, err := time.ParseDuration(value)
+ if err != nil {
+ b.setError(b.ErrorFunc(sourceParam, []string{value}, "failed to bind field value to Duration", err))
+ return b
+ }
+ *dest = t
+ return b
+}
+
+// Durations binds parameter values to slice of time.Duration variables
+func (b *ValueBinder) Durations(sourceParam string, dest *[]time.Duration) *ValueBinder {
+ return b.durationsValue(sourceParam, dest, false)
+}
+
+// MustDurations requires parameter values to exist to bind to slice of time.Duration variables. Returns error when values does not exist
+func (b *ValueBinder) MustDurations(sourceParam string, dest *[]time.Duration) *ValueBinder {
+ return b.durationsValue(sourceParam, dest, true)
+}
+
+func (b *ValueBinder) durationsValue(sourceParam string, dest *[]time.Duration, valueMustExist bool) *ValueBinder {
+ if b.failFast && b.errors != nil {
+ return b
+ }
+
+ values := b.ValuesFunc(sourceParam)
+ if len(values) == 0 {
+ if valueMustExist {
+ b.setError(b.ErrorFunc(sourceParam, []string{}, "required field value is empty", nil))
+ }
+ return b
+ }
+ return b.durations(sourceParam, values, dest)
+}
+
+func (b *ValueBinder) durations(sourceParam string, values []string, dest *[]time.Duration) *ValueBinder {
+ tmp := make([]time.Duration, len(values))
+ for i, v := range values {
+ t, err := time.ParseDuration(v)
+ if err != nil {
+ b.setError(b.ErrorFunc(sourceParam, []string{v}, "failed to bind field value to Duration", err))
+ if b.failFast {
+ return b
+ }
+ continue
+ }
+ tmp[i] = t
+ }
+ if b.errors == nil {
+ *dest = tmp
+ }
+ return b
+}
+
+// UnixTime binds parameter to time.Time variable (in local Time corresponding to the given Unix time).
+//
+// Example: 1609180603 bind to 2020-12-28T18:36:43.000000000+00:00
+//
+// Note:
+// * time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
+func (b *ValueBinder) UnixTime(sourceParam string, dest *time.Time) *ValueBinder {
+ return b.unixTime(sourceParam, dest, false, time.Second)
+}
+
+// MustUnixTime requires parameter value to exist to bind to time.Duration variable (in local time corresponding
+// to the given Unix time). Returns error when value does not exist.
+//
+// Example: 1609180603 bind to 2020-12-28T18:36:43.000000000+00:00
+//
+// Note:
+// * time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
+func (b *ValueBinder) MustUnixTime(sourceParam string, dest *time.Time) *ValueBinder {
+ return b.unixTime(sourceParam, dest, true, time.Second)
+}
+
+// UnixTimeMilli binds parameter to time.Time variable (in local time corresponding to the given Unix time in millisecond precision).
+//
+// Example: 1647184410140 bind to 2022-03-13T15:13:30.140000000+00:00
+//
+// Note:
+// * time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
+func (b *ValueBinder) UnixTimeMilli(sourceParam string, dest *time.Time) *ValueBinder {
+ return b.unixTime(sourceParam, dest, false, time.Millisecond)
+}
+
+// MustUnixTimeMilli requires parameter value to exist to bind to time.Duration variable (in local time corresponding
+// to the given Unix time in millisecond precision). Returns error when value does not exist.
+//
+// Example: 1647184410140 bind to 2022-03-13T15:13:30.140000000+00:00
+//
+// Note:
+// * time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
+func (b *ValueBinder) MustUnixTimeMilli(sourceParam string, dest *time.Time) *ValueBinder {
+ return b.unixTime(sourceParam, dest, true, time.Millisecond)
+}
+
+// UnixTimeNano binds parameter to time.Time variable (in local time corresponding to the given Unix time in nanosecond precision).
+//
+// Example: 1609180603123456789 binds to 2020-12-28T18:36:43.123456789+00:00
+// Example: 1000000000 binds to 1970-01-01T00:00:01.000000000+00:00
+// Example: 999999999 binds to 1970-01-01T00:00:00.999999999+00:00
+//
+// Note:
+// * time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
+// * Javascript's Number type only has about 53 bits of precision (Number.MAX_SAFE_INTEGER = 9007199254740991). Compare it to 1609180603123456789 in example.
+func (b *ValueBinder) UnixTimeNano(sourceParam string, dest *time.Time) *ValueBinder {
+ return b.unixTime(sourceParam, dest, false, time.Nanosecond)
+}
+
+// MustUnixTimeNano requires parameter value to exist to bind to time.Duration variable (in local Time corresponding
+// to the given Unix time value in nano second precision). Returns error when value does not exist.
+//
+// Example: 1609180603123456789 binds to 2020-12-28T18:36:43.123456789+00:00
+// Example: 1000000000 binds to 1970-01-01T00:00:01.000000000+00:00
+// Example: 999999999 binds to 1970-01-01T00:00:00.999999999+00:00
+//
+// Note:
+// * time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
+// * Javascript's Number type only has about 53 bits of precision (Number.MAX_SAFE_INTEGER = 9007199254740991). Compare it to 1609180603123456789 in example.
+func (b *ValueBinder) MustUnixTimeNano(sourceParam string, dest *time.Time) *ValueBinder {
+ return b.unixTime(sourceParam, dest, true, time.Nanosecond)
+}
+
+func (b *ValueBinder) unixTime(sourceParam string, dest *time.Time, valueMustExist bool, precision time.Duration) *ValueBinder {
+ if b.failFast && b.errors != nil {
+ return b
+ }
+
+ value := b.ValueFunc(sourceParam)
+ if value == "" {
+ if valueMustExist {
+ b.setError(b.ErrorFunc(sourceParam, []string{value}, "required field value is empty", nil))
+ }
+ return b
+ }
+
+ n, err := strconv.ParseInt(value, 10, 64)
+ if err != nil {
+ b.setError(b.ErrorFunc(sourceParam, []string{value}, "failed to bind field value to Time", err))
+ return b
+ }
+
+ switch precision {
+ case time.Second:
+ *dest = time.Unix(n, 0)
+ case time.Millisecond:
+ *dest = time.Unix(n/1e3, (n%1e3)*1e6) // TODO: time.UnixMilli(n) exists since Go1.17 switch to that when min version allows
+ case time.Nanosecond:
+ *dest = time.Unix(0, n)
+ }
+ return b
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/codecov.yml b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/codecov.yml
new file mode 100644
index 0000000..0fa3a3f
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/codecov.yml
@@ -0,0 +1,11 @@
+coverage:
+ status:
+ project:
+ default:
+ threshold: 1%
+ patch:
+ default:
+ threshold: 1%
+
+comment:
+ require_changes: true \ No newline at end of file
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/context.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/context.go
new file mode 100644
index 0000000..b3a7ce8
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/context.go
@@ -0,0 +1,647 @@
+package echo
+
+import (
+ "bytes"
+ "encoding/xml"
+ "fmt"
+ "io"
+ "mime/multipart"
+ "net"
+ "net/http"
+ "net/url"
+ "strings"
+ "sync"
+)
+
+type (
+ // Context represents the context of the current HTTP request. It holds request and
+ // response objects, path, path parameters, data and registered handler.
+ Context interface {
+ // Request returns `*http.Request`.
+ Request() *http.Request
+
+ // SetRequest sets `*http.Request`.
+ SetRequest(r *http.Request)
+
+ // SetResponse sets `*Response`.
+ SetResponse(r *Response)
+
+ // Response returns `*Response`.
+ Response() *Response
+
+ // IsTLS returns true if HTTP connection is TLS otherwise false.
+ IsTLS() bool
+
+ // IsWebSocket returns true if HTTP connection is WebSocket otherwise false.
+ IsWebSocket() bool
+
+ // Scheme returns the HTTP protocol scheme, `http` or `https`.
+ Scheme() string
+
+ // RealIP returns the client's network address based on `X-Forwarded-For`
+ // or `X-Real-IP` request header.
+ // The behavior can be configured using `Echo#IPExtractor`.
+ RealIP() string
+
+ // Path returns the registered path for the handler.
+ Path() string
+
+ // SetPath sets the registered path for the handler.
+ SetPath(p string)
+
+ // Param returns path parameter by name.
+ Param(name string) string
+
+ // ParamNames returns path parameter names.
+ ParamNames() []string
+
+ // SetParamNames sets path parameter names.
+ SetParamNames(names ...string)
+
+ // ParamValues returns path parameter values.
+ ParamValues() []string
+
+ // SetParamValues sets path parameter values.
+ SetParamValues(values ...string)
+
+ // QueryParam returns the query param for the provided name.
+ QueryParam(name string) string
+
+ // QueryParams returns the query parameters as `url.Values`.
+ QueryParams() url.Values
+
+ // QueryString returns the URL query string.
+ QueryString() string
+
+ // FormValue returns the form field value for the provided name.
+ FormValue(name string) string
+
+ // FormParams returns the form parameters as `url.Values`.
+ FormParams() (url.Values, error)
+
+ // FormFile returns the multipart form file for the provided name.
+ FormFile(name string) (*multipart.FileHeader, error)
+
+ // MultipartForm returns the multipart form.
+ MultipartForm() (*multipart.Form, error)
+
+ // Cookie returns the named cookie provided in the request.
+ Cookie(name string) (*http.Cookie, error)
+
+ // SetCookie adds a `Set-Cookie` header in HTTP response.
+ SetCookie(cookie *http.Cookie)
+
+ // Cookies returns the HTTP cookies sent with the request.
+ Cookies() []*http.Cookie
+
+ // Get retrieves data from the context.
+ Get(key string) interface{}
+
+ // Set saves data in the context.
+ Set(key string, val interface{})
+
+ // Bind binds the request body into provided type `i`. The default binder
+ // does it based on Content-Type header.
+ Bind(i interface{}) error
+
+ // Validate validates provided `i`. It is usually called after `Context#Bind()`.
+ // Validator must be registered using `Echo#Validator`.
+ Validate(i interface{}) error
+
+ // Render renders a template with data and sends a text/html response with status
+ // code. Renderer must be registered using `Echo.Renderer`.
+ Render(code int, name string, data interface{}) error
+
+ // HTML sends an HTTP response with status code.
+ HTML(code int, html string) error
+
+ // HTMLBlob sends an HTTP blob response with status code.
+ HTMLBlob(code int, b []byte) error
+
+ // String sends a string response with status code.
+ String(code int, s string) error
+
+ // JSON sends a JSON response with status code.
+ JSON(code int, i interface{}) error
+
+ // JSONPretty sends a pretty-print JSON with status code.
+ JSONPretty(code int, i interface{}, indent string) error
+
+ // JSONBlob sends a JSON blob response with status code.
+ JSONBlob(code int, b []byte) error
+
+ // JSONP sends a JSONP response with status code. It uses `callback` to construct
+ // the JSONP payload.
+ JSONP(code int, callback string, i interface{}) error
+
+ // JSONPBlob sends a JSONP blob response with status code. It uses `callback`
+ // to construct the JSONP payload.
+ JSONPBlob(code int, callback string, b []byte) error
+
+ // XML sends an XML response with status code.
+ XML(code int, i interface{}) error
+
+ // XMLPretty sends a pretty-print XML with status code.
+ XMLPretty(code int, i interface{}, indent string) error
+
+ // XMLBlob sends an XML blob response with status code.
+ XMLBlob(code int, b []byte) error
+
+ // Blob sends a blob response with status code and content type.
+ Blob(code int, contentType string, b []byte) error
+
+ // Stream sends a streaming response with status code and content type.
+ Stream(code int, contentType string, r io.Reader) error
+
+ // File sends a response with the content of the file.
+ File(file string) error
+
+ // Attachment sends a response as attachment, prompting client to save the
+ // file.
+ Attachment(file string, name string) error
+
+ // Inline sends a response as inline, opening the file in the browser.
+ Inline(file string, name string) error
+
+ // NoContent sends a response with no body and a status code.
+ NoContent(code int) error
+
+ // Redirect redirects the request to a provided URL with status code.
+ Redirect(code int, url string) error
+
+ // Error invokes the registered global HTTP error handler. Generally used by middleware.
+ // A side-effect of calling global error handler is that now Response has been committed (sent to the client) and
+ // middlewares up in chain can not change Response status code or Response body anymore.
+ //
+ // Avoid using this method in handlers as no middleware will be able to effectively handle errors after that.
+ Error(err error)
+
+ // Handler returns the matched handler by router.
+ Handler() HandlerFunc
+
+ // SetHandler sets the matched handler by router.
+ SetHandler(h HandlerFunc)
+
+ // Logger returns the `Logger` instance.
+ Logger() Logger
+
+ // SetLogger Set the logger
+ SetLogger(l Logger)
+
+ // Echo returns the `Echo` instance.
+ Echo() *Echo
+
+ // Reset resets the context after request completes. It must be called along
+ // with `Echo#AcquireContext()` and `Echo#ReleaseContext()`.
+ // See `Echo#ServeHTTP()`
+ Reset(r *http.Request, w http.ResponseWriter)
+ }
+
+ context struct {
+ request *http.Request
+ response *Response
+ path string
+ pnames []string
+ pvalues []string
+ query url.Values
+ handler HandlerFunc
+ store Map
+ echo *Echo
+ logger Logger
+ lock sync.RWMutex
+ }
+)
+
+const (
+ // ContextKeyHeaderAllow is set by Router for getting value for `Allow` header in later stages of handler call chain.
+ // Allow header is mandatory for status 405 (method not found) and useful for OPTIONS method requests.
+ // It is added to context only when Router does not find matching method handler for request.
+ ContextKeyHeaderAllow = "echo_header_allow"
+)
+
+const (
+ defaultMemory = 32 << 20 // 32 MB
+ indexPage = "index.html"
+ defaultIndent = " "
+)
+
+func (c *context) writeContentType(value string) {
+ header := c.Response().Header()
+ if header.Get(HeaderContentType) == "" {
+ header.Set(HeaderContentType, value)
+ }
+}
+
+func (c *context) Request() *http.Request {
+ return c.request
+}
+
+func (c *context) SetRequest(r *http.Request) {
+ c.request = r
+}
+
+func (c *context) Response() *Response {
+ return c.response
+}
+
+func (c *context) SetResponse(r *Response) {
+ c.response = r
+}
+
+func (c *context) IsTLS() bool {
+ return c.request.TLS != nil
+}
+
+func (c *context) IsWebSocket() bool {
+ upgrade := c.request.Header.Get(HeaderUpgrade)
+ return strings.EqualFold(upgrade, "websocket")
+}
+
+func (c *context) Scheme() string {
+ // Can't use `r.Request.URL.Scheme`
+ // See: https://groups.google.com/forum/#!topic/golang-nuts/pMUkBlQBDF0
+ if c.IsTLS() {
+ return "https"
+ }
+ if scheme := c.request.Header.Get(HeaderXForwardedProto); scheme != "" {
+ return scheme
+ }
+ if scheme := c.request.Header.Get(HeaderXForwardedProtocol); scheme != "" {
+ return scheme
+ }
+ if ssl := c.request.Header.Get(HeaderXForwardedSsl); ssl == "on" {
+ return "https"
+ }
+ if scheme := c.request.Header.Get(HeaderXUrlScheme); scheme != "" {
+ return scheme
+ }
+ return "http"
+}
+
+func (c *context) RealIP() string {
+ if c.echo != nil && c.echo.IPExtractor != nil {
+ return c.echo.IPExtractor(c.request)
+ }
+ // Fall back to legacy behavior
+ if ip := c.request.Header.Get(HeaderXForwardedFor); ip != "" {
+ i := strings.IndexAny(ip, ",")
+ if i > 0 {
+ xffip := strings.TrimSpace(ip[:i])
+ xffip = strings.TrimPrefix(xffip, "[")
+ xffip = strings.TrimSuffix(xffip, "]")
+ return xffip
+ }
+ return ip
+ }
+ if ip := c.request.Header.Get(HeaderXRealIP); ip != "" {
+ ip = strings.TrimPrefix(ip, "[")
+ ip = strings.TrimSuffix(ip, "]")
+ return ip
+ }
+ ra, _, _ := net.SplitHostPort(c.request.RemoteAddr)
+ return ra
+}
+
+func (c *context) Path() string {
+ return c.path
+}
+
+func (c *context) SetPath(p string) {
+ c.path = p
+}
+
+func (c *context) Param(name string) string {
+ for i, n := range c.pnames {
+ if i < len(c.pvalues) {
+ if n == name {
+ return c.pvalues[i]
+ }
+ }
+ }
+ return ""
+}
+
+func (c *context) ParamNames() []string {
+ return c.pnames
+}
+
+func (c *context) SetParamNames(names ...string) {
+ c.pnames = names
+
+ l := len(names)
+ if *c.echo.maxParam < l {
+ *c.echo.maxParam = l
+ }
+
+ if len(c.pvalues) < l {
+ // Keeping the old pvalues just for backward compatibility, but it sounds that doesn't make sense to keep them,
+ // probably those values will be overriden in a Context#SetParamValues
+ newPvalues := make([]string, l)
+ copy(newPvalues, c.pvalues)
+ c.pvalues = newPvalues
+ }
+}
+
+func (c *context) ParamValues() []string {
+ return c.pvalues[:len(c.pnames)]
+}
+
+func (c *context) SetParamValues(values ...string) {
+ // NOTE: Don't just set c.pvalues = values, because it has to have length c.echo.maxParam at all times
+ // It will brake the Router#Find code
+ limit := len(values)
+ if limit > *c.echo.maxParam {
+ limit = *c.echo.maxParam
+ }
+ for i := 0; i < limit; i++ {
+ c.pvalues[i] = values[i]
+ }
+}
+
+func (c *context) QueryParam(name string) string {
+ if c.query == nil {
+ c.query = c.request.URL.Query()
+ }
+ return c.query.Get(name)
+}
+
+func (c *context) QueryParams() url.Values {
+ if c.query == nil {
+ c.query = c.request.URL.Query()
+ }
+ return c.query
+}
+
+func (c *context) QueryString() string {
+ return c.request.URL.RawQuery
+}
+
+func (c *context) FormValue(name string) string {
+ return c.request.FormValue(name)
+}
+
+func (c *context) FormParams() (url.Values, error) {
+ if strings.HasPrefix(c.request.Header.Get(HeaderContentType), MIMEMultipartForm) {
+ if err := c.request.ParseMultipartForm(defaultMemory); err != nil {
+ return nil, err
+ }
+ } else {
+ if err := c.request.ParseForm(); err != nil {
+ return nil, err
+ }
+ }
+ return c.request.Form, nil
+}
+
+func (c *context) FormFile(name string) (*multipart.FileHeader, error) {
+ f, fh, err := c.request.FormFile(name)
+ if err != nil {
+ return nil, err
+ }
+ f.Close()
+ return fh, nil
+}
+
+func (c *context) MultipartForm() (*multipart.Form, error) {
+ err := c.request.ParseMultipartForm(defaultMemory)
+ return c.request.MultipartForm, err
+}
+
+func (c *context) Cookie(name string) (*http.Cookie, error) {
+ return c.request.Cookie(name)
+}
+
+func (c *context) SetCookie(cookie *http.Cookie) {
+ http.SetCookie(c.Response(), cookie)
+}
+
+func (c *context) Cookies() []*http.Cookie {
+ return c.request.Cookies()
+}
+
+func (c *context) Get(key string) interface{} {
+ c.lock.RLock()
+ defer c.lock.RUnlock()
+ return c.store[key]
+}
+
+func (c *context) Set(key string, val interface{}) {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ if c.store == nil {
+ c.store = make(Map)
+ }
+ c.store[key] = val
+}
+
+func (c *context) Bind(i interface{}) error {
+ return c.echo.Binder.Bind(i, c)
+}
+
+func (c *context) Validate(i interface{}) error {
+ if c.echo.Validator == nil {
+ return ErrValidatorNotRegistered
+ }
+ return c.echo.Validator.Validate(i)
+}
+
+func (c *context) Render(code int, name string, data interface{}) (err error) {
+ if c.echo.Renderer == nil {
+ return ErrRendererNotRegistered
+ }
+ buf := new(bytes.Buffer)
+ if err = c.echo.Renderer.Render(buf, name, data, c); err != nil {
+ return
+ }
+ return c.HTMLBlob(code, buf.Bytes())
+}
+
+func (c *context) HTML(code int, html string) (err error) {
+ return c.HTMLBlob(code, []byte(html))
+}
+
+func (c *context) HTMLBlob(code int, b []byte) (err error) {
+ return c.Blob(code, MIMETextHTMLCharsetUTF8, b)
+}
+
+func (c *context) String(code int, s string) (err error) {
+ return c.Blob(code, MIMETextPlainCharsetUTF8, []byte(s))
+}
+
+func (c *context) jsonPBlob(code int, callback string, i interface{}) (err error) {
+ indent := ""
+ if _, pretty := c.QueryParams()["pretty"]; c.echo.Debug || pretty {
+ indent = defaultIndent
+ }
+ c.writeContentType(MIMEApplicationJavaScriptCharsetUTF8)
+ c.response.WriteHeader(code)
+ if _, err = c.response.Write([]byte(callback + "(")); err != nil {
+ return
+ }
+ if err = c.echo.JSONSerializer.Serialize(c, i, indent); err != nil {
+ return
+ }
+ if _, err = c.response.Write([]byte(");")); err != nil {
+ return
+ }
+ return
+}
+
+func (c *context) json(code int, i interface{}, indent string) error {
+ c.writeContentType(MIMEApplicationJSONCharsetUTF8)
+ c.response.Status = code
+ return c.echo.JSONSerializer.Serialize(c, i, indent)
+}
+
+func (c *context) JSON(code int, i interface{}) (err error) {
+ indent := ""
+ if _, pretty := c.QueryParams()["pretty"]; c.echo.Debug || pretty {
+ indent = defaultIndent
+ }
+ return c.json(code, i, indent)
+}
+
+func (c *context) JSONPretty(code int, i interface{}, indent string) (err error) {
+ return c.json(code, i, indent)
+}
+
+func (c *context) JSONBlob(code int, b []byte) (err error) {
+ return c.Blob(code, MIMEApplicationJSONCharsetUTF8, b)
+}
+
+func (c *context) JSONP(code int, callback string, i interface{}) (err error) {
+ return c.jsonPBlob(code, callback, i)
+}
+
+func (c *context) JSONPBlob(code int, callback string, b []byte) (err error) {
+ c.writeContentType(MIMEApplicationJavaScriptCharsetUTF8)
+ c.response.WriteHeader(code)
+ if _, err = c.response.Write([]byte(callback + "(")); err != nil {
+ return
+ }
+ if _, err = c.response.Write(b); err != nil {
+ return
+ }
+ _, err = c.response.Write([]byte(");"))
+ return
+}
+
+func (c *context) xml(code int, i interface{}, indent string) (err error) {
+ c.writeContentType(MIMEApplicationXMLCharsetUTF8)
+ c.response.WriteHeader(code)
+ enc := xml.NewEncoder(c.response)
+ if indent != "" {
+ enc.Indent("", indent)
+ }
+ if _, err = c.response.Write([]byte(xml.Header)); err != nil {
+ return
+ }
+ return enc.Encode(i)
+}
+
+func (c *context) XML(code int, i interface{}) (err error) {
+ indent := ""
+ if _, pretty := c.QueryParams()["pretty"]; c.echo.Debug || pretty {
+ indent = defaultIndent
+ }
+ return c.xml(code, i, indent)
+}
+
+func (c *context) XMLPretty(code int, i interface{}, indent string) (err error) {
+ return c.xml(code, i, indent)
+}
+
+func (c *context) XMLBlob(code int, b []byte) (err error) {
+ c.writeContentType(MIMEApplicationXMLCharsetUTF8)
+ c.response.WriteHeader(code)
+ if _, err = c.response.Write([]byte(xml.Header)); err != nil {
+ return
+ }
+ _, err = c.response.Write(b)
+ return
+}
+
+func (c *context) Blob(code int, contentType string, b []byte) (err error) {
+ c.writeContentType(contentType)
+ c.response.WriteHeader(code)
+ _, err = c.response.Write(b)
+ return
+}
+
+func (c *context) Stream(code int, contentType string, r io.Reader) (err error) {
+ c.writeContentType(contentType)
+ c.response.WriteHeader(code)
+ _, err = io.Copy(c.response, r)
+ return
+}
+
+func (c *context) Attachment(file, name string) error {
+ return c.contentDisposition(file, name, "attachment")
+}
+
+func (c *context) Inline(file, name string) error {
+ return c.contentDisposition(file, name, "inline")
+}
+
+func (c *context) contentDisposition(file, name, dispositionType string) error {
+ c.response.Header().Set(HeaderContentDisposition, fmt.Sprintf("%s; filename=%q", dispositionType, name))
+ return c.File(file)
+}
+
+func (c *context) NoContent(code int) error {
+ c.response.WriteHeader(code)
+ return nil
+}
+
+func (c *context) Redirect(code int, url string) error {
+ if code < 300 || code > 308 {
+ return ErrInvalidRedirectCode
+ }
+ c.response.Header().Set(HeaderLocation, url)
+ c.response.WriteHeader(code)
+ return nil
+}
+
+func (c *context) Error(err error) {
+ c.echo.HTTPErrorHandler(err, c)
+}
+
+func (c *context) Echo() *Echo {
+ return c.echo
+}
+
+func (c *context) Handler() HandlerFunc {
+ return c.handler
+}
+
+func (c *context) SetHandler(h HandlerFunc) {
+ c.handler = h
+}
+
+func (c *context) Logger() Logger {
+ res := c.logger
+ if res != nil {
+ return res
+ }
+ return c.echo.Logger
+}
+
+func (c *context) SetLogger(l Logger) {
+ c.logger = l
+}
+
+func (c *context) Reset(r *http.Request, w http.ResponseWriter) {
+ c.request = r
+ c.response.reset(w)
+ c.query = nil
+ c.handler = NotFoundHandler
+ c.store = nil
+ c.path = ""
+ c.pnames = nil
+ c.logger = nil
+ // NOTE: Don't reset because it has to have length c.echo.maxParam at all times
+ for i := 0; i < *c.echo.maxParam; i++ {
+ c.pvalues[i] = ""
+ }
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/context_fs.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/context_fs.go
new file mode 100644
index 0000000..1038f89
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/context_fs.go
@@ -0,0 +1,49 @@
+package echo
+
+import (
+ "errors"
+ "io"
+ "io/fs"
+ "net/http"
+ "path/filepath"
+)
+
+func (c *context) File(file string) error {
+ return fsFile(c, file, c.echo.Filesystem)
+}
+
+// FileFS serves file from given file system.
+//
+// When dealing with `embed.FS` use `fs := echo.MustSubFS(fs, "rootDirectory") to create sub fs which uses necessary
+// prefix for directory path. This is necessary as `//go:embed assets/images` embeds files with paths
+// including `assets/images` as their prefix.
+func (c *context) FileFS(file string, filesystem fs.FS) error {
+ return fsFile(c, file, filesystem)
+}
+
+func fsFile(c Context, file string, filesystem fs.FS) error {
+ f, err := filesystem.Open(file)
+ if err != nil {
+ return ErrNotFound
+ }
+ defer f.Close()
+
+ fi, _ := f.Stat()
+ if fi.IsDir() {
+ file = filepath.ToSlash(filepath.Join(file, indexPage)) // ToSlash is necessary for Windows. fs.Open and os.Open are different in that aspect.
+ f, err = filesystem.Open(file)
+ if err != nil {
+ return ErrNotFound
+ }
+ defer f.Close()
+ if fi, err = f.Stat(); err != nil {
+ return err
+ }
+ }
+ ff, ok := f.(io.ReadSeeker)
+ if !ok {
+ return errors.New("file does not implement io.ReadSeeker")
+ }
+ http.ServeContent(c.Response(), c.Request(), fi.Name(), fi.ModTime(), ff)
+ return nil
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/echo.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/echo.go
new file mode 100644
index 0000000..f6d89b9
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/echo.go
@@ -0,0 +1,980 @@
+/*
+Package echo implements high performance, minimalist Go web framework.
+
+Example:
+
+ package main
+
+ import (
+ "net/http"
+
+ "github.com/labstack/echo/v4"
+ "github.com/labstack/echo/v4/middleware"
+ )
+
+ // Handler
+ func hello(c echo.Context) error {
+ return c.String(http.StatusOK, "Hello, World!")
+ }
+
+ func main() {
+ // Echo instance
+ e := echo.New()
+
+ // Middleware
+ e.Use(middleware.Logger())
+ e.Use(middleware.Recover())
+
+ // Routes
+ e.GET("/", hello)
+
+ // Start server
+ e.Logger.Fatal(e.Start(":1323"))
+ }
+
+Learn more at https://echo.labstack.com
+*/
+package echo
+
+import (
+ stdContext "context"
+ "crypto/tls"
+ "errors"
+ "fmt"
+ "io"
+ stdLog "log"
+ "net"
+ "net/http"
+ "os"
+ "reflect"
+ "runtime"
+ "sync"
+ "time"
+
+ "github.com/labstack/gommon/color"
+ "github.com/labstack/gommon/log"
+ "golang.org/x/crypto/acme"
+ "golang.org/x/crypto/acme/autocert"
+ "golang.org/x/net/http2"
+ "golang.org/x/net/http2/h2c"
+)
+
+type (
+ // Echo is the top-level framework instance.
+ //
+ // Goroutine safety: Do not mutate Echo instance fields after server has started. Accessing these
+ // fields from handlers/middlewares and changing field values at the same time leads to data-races.
+ // Adding new routes after the server has been started is also not safe!
+ Echo struct {
+ filesystem
+ common
+ // startupMutex is mutex to lock Echo instance access during server configuration and startup. Useful for to get
+ // listener address info (on which interface/port was listener binded) without having data races.
+ startupMutex sync.RWMutex
+ colorer *color.Color
+
+ // premiddleware are middlewares that are run before routing is done. In case a pre-middleware returns
+ // an error the router is not executed and the request will end up in the global error handler.
+ premiddleware []MiddlewareFunc
+ middleware []MiddlewareFunc
+ maxParam *int
+ router *Router
+ routers map[string]*Router
+ pool sync.Pool
+
+ StdLogger *stdLog.Logger
+ Server *http.Server
+ TLSServer *http.Server
+ Listener net.Listener
+ TLSListener net.Listener
+ AutoTLSManager autocert.Manager
+ DisableHTTP2 bool
+ Debug bool
+ HideBanner bool
+ HidePort bool
+ HTTPErrorHandler HTTPErrorHandler
+ Binder Binder
+ JSONSerializer JSONSerializer
+ Validator Validator
+ Renderer Renderer
+ Logger Logger
+ IPExtractor IPExtractor
+ ListenerNetwork string
+
+ // OnAddRouteHandler is called when Echo adds new route to specific host router.
+ OnAddRouteHandler func(host string, route Route, handler HandlerFunc, middleware []MiddlewareFunc)
+ }
+
+ // Route contains a handler and information for matching against requests.
+ Route struct {
+ Method string `json:"method"`
+ Path string `json:"path"`
+ Name string `json:"name"`
+ }
+
+ // HTTPError represents an error that occurred while handling a request.
+ HTTPError struct {
+ Code int `json:"-"`
+ Message interface{} `json:"message"`
+ Internal error `json:"-"` // Stores the error returned by an external dependency
+ }
+
+ // MiddlewareFunc defines a function to process middleware.
+ MiddlewareFunc func(next HandlerFunc) HandlerFunc
+
+ // HandlerFunc defines a function to serve HTTP requests.
+ HandlerFunc func(c Context) error
+
+ // HTTPErrorHandler is a centralized HTTP error handler.
+ HTTPErrorHandler func(err error, c Context)
+
+ // Validator is the interface that wraps the Validate function.
+ Validator interface {
+ Validate(i interface{}) error
+ }
+
+ // JSONSerializer is the interface that encodes and decodes JSON to and from interfaces.
+ JSONSerializer interface {
+ Serialize(c Context, i interface{}, indent string) error
+ Deserialize(c Context, i interface{}) error
+ }
+
+ // Renderer is the interface that wraps the Render function.
+ Renderer interface {
+ Render(io.Writer, string, interface{}, Context) error
+ }
+
+ // Map defines a generic map of type `map[string]interface{}`.
+ Map map[string]interface{}
+
+ // Common struct for Echo & Group.
+ common struct{}
+)
+
+// HTTP methods
+// NOTE: Deprecated, please use the stdlib constants directly instead.
+const (
+ CONNECT = http.MethodConnect
+ DELETE = http.MethodDelete
+ GET = http.MethodGet
+ HEAD = http.MethodHead
+ OPTIONS = http.MethodOptions
+ PATCH = http.MethodPatch
+ POST = http.MethodPost
+ // PROPFIND = "PROPFIND"
+ PUT = http.MethodPut
+ TRACE = http.MethodTrace
+)
+
+// MIME types
+const (
+ MIMEApplicationJSON = "application/json"
+ MIMEApplicationJSONCharsetUTF8 = MIMEApplicationJSON + "; " + charsetUTF8
+ MIMEApplicationJavaScript = "application/javascript"
+ MIMEApplicationJavaScriptCharsetUTF8 = MIMEApplicationJavaScript + "; " + charsetUTF8
+ MIMEApplicationXML = "application/xml"
+ MIMEApplicationXMLCharsetUTF8 = MIMEApplicationXML + "; " + charsetUTF8
+ MIMETextXML = "text/xml"
+ MIMETextXMLCharsetUTF8 = MIMETextXML + "; " + charsetUTF8
+ MIMEApplicationForm = "application/x-www-form-urlencoded"
+ MIMEApplicationProtobuf = "application/protobuf"
+ MIMEApplicationMsgpack = "application/msgpack"
+ MIMETextHTML = "text/html"
+ MIMETextHTMLCharsetUTF8 = MIMETextHTML + "; " + charsetUTF8
+ MIMETextPlain = "text/plain"
+ MIMETextPlainCharsetUTF8 = MIMETextPlain + "; " + charsetUTF8
+ MIMEMultipartForm = "multipart/form-data"
+ MIMEOctetStream = "application/octet-stream"
+)
+
+const (
+ charsetUTF8 = "charset=UTF-8"
+ // PROPFIND Method can be used on collection and property resources.
+ PROPFIND = "PROPFIND"
+ // REPORT Method can be used to get information about a resource, see rfc 3253
+ REPORT = "REPORT"
+ // RouteNotFound is special method type for routes handling "route not found" (404) cases
+ RouteNotFound = "echo_route_not_found"
+)
+
+// Headers
+const (
+ HeaderAccept = "Accept"
+ HeaderAcceptEncoding = "Accept-Encoding"
+ // HeaderAllow is the name of the "Allow" header field used to list the set of methods
+ // advertised as supported by the target resource. Returning an Allow header is mandatory
+ // for status 405 (method not found) and useful for the OPTIONS method in responses.
+ // See RFC 7231: https://datatracker.ietf.org/doc/html/rfc7231#section-7.4.1
+ HeaderAllow = "Allow"
+ HeaderAuthorization = "Authorization"
+ HeaderContentDisposition = "Content-Disposition"
+ HeaderContentEncoding = "Content-Encoding"
+ HeaderContentLength = "Content-Length"
+ HeaderContentType = "Content-Type"
+ HeaderCookie = "Cookie"
+ HeaderSetCookie = "Set-Cookie"
+ HeaderIfModifiedSince = "If-Modified-Since"
+ HeaderLastModified = "Last-Modified"
+ HeaderLocation = "Location"
+ HeaderRetryAfter = "Retry-After"
+ HeaderUpgrade = "Upgrade"
+ HeaderVary = "Vary"
+ HeaderWWWAuthenticate = "WWW-Authenticate"
+ HeaderXForwardedFor = "X-Forwarded-For"
+ HeaderXForwardedProto = "X-Forwarded-Proto"
+ HeaderXForwardedProtocol = "X-Forwarded-Protocol"
+ HeaderXForwardedSsl = "X-Forwarded-Ssl"
+ HeaderXUrlScheme = "X-Url-Scheme"
+ HeaderXHTTPMethodOverride = "X-HTTP-Method-Override"
+ HeaderXRealIP = "X-Real-Ip"
+ HeaderXRequestID = "X-Request-Id"
+ HeaderXCorrelationID = "X-Correlation-Id"
+ HeaderXRequestedWith = "X-Requested-With"
+ HeaderServer = "Server"
+ HeaderOrigin = "Origin"
+ HeaderCacheControl = "Cache-Control"
+ HeaderConnection = "Connection"
+
+ // Access control
+ HeaderAccessControlRequestMethod = "Access-Control-Request-Method"
+ HeaderAccessControlRequestHeaders = "Access-Control-Request-Headers"
+ HeaderAccessControlAllowOrigin = "Access-Control-Allow-Origin"
+ HeaderAccessControlAllowMethods = "Access-Control-Allow-Methods"
+ HeaderAccessControlAllowHeaders = "Access-Control-Allow-Headers"
+ HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials"
+ HeaderAccessControlExposeHeaders = "Access-Control-Expose-Headers"
+ HeaderAccessControlMaxAge = "Access-Control-Max-Age"
+
+ // Security
+ HeaderStrictTransportSecurity = "Strict-Transport-Security"
+ HeaderXContentTypeOptions = "X-Content-Type-Options"
+ HeaderXXSSProtection = "X-XSS-Protection"
+ HeaderXFrameOptions = "X-Frame-Options"
+ HeaderContentSecurityPolicy = "Content-Security-Policy"
+ HeaderContentSecurityPolicyReportOnly = "Content-Security-Policy-Report-Only"
+ HeaderXCSRFToken = "X-CSRF-Token"
+ HeaderReferrerPolicy = "Referrer-Policy"
+)
+
+const (
+ // Version of Echo
+ Version = "4.10.0"
+ website = "https://echo.labstack.com"
+ // http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo
+ banner = `
+ ____ __
+ / __/___/ / ___
+ / _// __/ _ \/ _ \
+/___/\__/_//_/\___/ %s
+High performance, minimalist Go web framework
+%s
+____________________________________O/_______
+ O\
+`
+)
+
+var (
+ methods = [...]string{
+ http.MethodConnect,
+ http.MethodDelete,
+ http.MethodGet,
+ http.MethodHead,
+ http.MethodOptions,
+ http.MethodPatch,
+ http.MethodPost,
+ PROPFIND,
+ http.MethodPut,
+ http.MethodTrace,
+ REPORT,
+ }
+)
+
+// Errors
+var (
+ ErrUnsupportedMediaType = NewHTTPError(http.StatusUnsupportedMediaType)
+ ErrNotFound = NewHTTPError(http.StatusNotFound)
+ ErrUnauthorized = NewHTTPError(http.StatusUnauthorized)
+ ErrForbidden = NewHTTPError(http.StatusForbidden)
+ ErrMethodNotAllowed = NewHTTPError(http.StatusMethodNotAllowed)
+ ErrStatusRequestEntityTooLarge = NewHTTPError(http.StatusRequestEntityTooLarge)
+ ErrTooManyRequests = NewHTTPError(http.StatusTooManyRequests)
+ ErrBadRequest = NewHTTPError(http.StatusBadRequest)
+ ErrBadGateway = NewHTTPError(http.StatusBadGateway)
+ ErrInternalServerError = NewHTTPError(http.StatusInternalServerError)
+ ErrRequestTimeout = NewHTTPError(http.StatusRequestTimeout)
+ ErrServiceUnavailable = NewHTTPError(http.StatusServiceUnavailable)
+ ErrValidatorNotRegistered = errors.New("validator not registered")
+ ErrRendererNotRegistered = errors.New("renderer not registered")
+ ErrInvalidRedirectCode = errors.New("invalid redirect status code")
+ ErrCookieNotFound = errors.New("cookie not found")
+ ErrInvalidCertOrKeyType = errors.New("invalid cert or key type, must be string or []byte")
+ ErrInvalidListenerNetwork = errors.New("invalid listener network")
+)
+
+// Error handlers
+var (
+ NotFoundHandler = func(c Context) error {
+ return ErrNotFound
+ }
+
+ MethodNotAllowedHandler = func(c Context) error {
+ // See RFC 7231 section 7.4.1: An origin server MUST generate an Allow field in a 405 (Method Not Allowed)
+ // response and MAY do so in any other response. For disabled resources an empty Allow header may be returned
+ routerAllowMethods, ok := c.Get(ContextKeyHeaderAllow).(string)
+ if ok && routerAllowMethods != "" {
+ c.Response().Header().Set(HeaderAllow, routerAllowMethods)
+ }
+ return ErrMethodNotAllowed
+ }
+)
+
+// New creates an instance of Echo.
+func New() (e *Echo) {
+ e = &Echo{
+ filesystem: createFilesystem(),
+ Server: new(http.Server),
+ TLSServer: new(http.Server),
+ AutoTLSManager: autocert.Manager{
+ Prompt: autocert.AcceptTOS,
+ },
+ Logger: log.New("echo"),
+ colorer: color.New(),
+ maxParam: new(int),
+ ListenerNetwork: "tcp",
+ }
+ e.Server.Handler = e
+ e.TLSServer.Handler = e
+ e.HTTPErrorHandler = e.DefaultHTTPErrorHandler
+ e.Binder = &DefaultBinder{}
+ e.JSONSerializer = &DefaultJSONSerializer{}
+ e.Logger.SetLevel(log.ERROR)
+ e.StdLogger = stdLog.New(e.Logger.Output(), e.Logger.Prefix()+": ", 0)
+ e.pool.New = func() interface{} {
+ return e.NewContext(nil, nil)
+ }
+ e.router = NewRouter(e)
+ e.routers = map[string]*Router{}
+ return
+}
+
+// NewContext returns a Context instance.
+func (e *Echo) NewContext(r *http.Request, w http.ResponseWriter) Context {
+ return &context{
+ request: r,
+ response: NewResponse(w, e),
+ store: make(Map),
+ echo: e,
+ pvalues: make([]string, *e.maxParam),
+ handler: NotFoundHandler,
+ }
+}
+
+// Router returns the default router.
+func (e *Echo) Router() *Router {
+ return e.router
+}
+
+// Routers returns the map of host => router.
+func (e *Echo) Routers() map[string]*Router {
+ return e.routers
+}
+
+// DefaultHTTPErrorHandler is the default HTTP error handler. It sends a JSON response
+// with status code.
+//
+// NOTE: In case errors happens in middleware call-chain that is returning from handler (which did not return an error).
+// When handler has already sent response (ala c.JSON()) and there is error in middleware that is returning from
+// handler. Then the error that global error handler received will be ignored because we have already "commited" the
+// response and status code header has been sent to the client.
+func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
+
+ if c.Response().Committed {
+ return
+ }
+
+ he, ok := err.(*HTTPError)
+ if ok {
+ if he.Internal != nil {
+ if herr, ok := he.Internal.(*HTTPError); ok {
+ he = herr
+ }
+ }
+ } else {
+ he = &HTTPError{
+ Code: http.StatusInternalServerError,
+ Message: http.StatusText(http.StatusInternalServerError),
+ }
+ }
+
+ // Issue #1426
+ code := he.Code
+ message := he.Message
+ if m, ok := he.Message.(string); ok {
+ if e.Debug {
+ message = Map{"message": m, "error": err.Error()}
+ } else {
+ message = Map{"message": m}
+ }
+ }
+
+ // Send response
+ if c.Request().Method == http.MethodHead { // Issue #608
+ err = c.NoContent(he.Code)
+ } else {
+ err = c.JSON(code, message)
+ }
+ if err != nil {
+ e.Logger.Error(err)
+ }
+}
+
+// Pre adds middleware to the chain which is run before router.
+func (e *Echo) Pre(middleware ...MiddlewareFunc) {
+ e.premiddleware = append(e.premiddleware, middleware...)
+}
+
+// Use adds middleware to the chain which is run after router.
+func (e *Echo) Use(middleware ...MiddlewareFunc) {
+ e.middleware = append(e.middleware, middleware...)
+}
+
+// CONNECT registers a new CONNECT route for a path with matching handler in the
+// router with optional route-level middleware.
+func (e *Echo) CONNECT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return e.Add(http.MethodConnect, path, h, m...)
+}
+
+// DELETE registers a new DELETE route for a path with matching handler in the router
+// with optional route-level middleware.
+func (e *Echo) DELETE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return e.Add(http.MethodDelete, path, h, m...)
+}
+
+// GET registers a new GET route for a path with matching handler in the router
+// with optional route-level middleware.
+func (e *Echo) GET(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return e.Add(http.MethodGet, path, h, m...)
+}
+
+// HEAD registers a new HEAD route for a path with matching handler in the
+// router with optional route-level middleware.
+func (e *Echo) HEAD(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return e.Add(http.MethodHead, path, h, m...)
+}
+
+// OPTIONS registers a new OPTIONS route for a path with matching handler in the
+// router with optional route-level middleware.
+func (e *Echo) OPTIONS(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return e.Add(http.MethodOptions, path, h, m...)
+}
+
+// PATCH registers a new PATCH route for a path with matching handler in the
+// router with optional route-level middleware.
+func (e *Echo) PATCH(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return e.Add(http.MethodPatch, path, h, m...)
+}
+
+// POST registers a new POST route for a path with matching handler in the
+// router with optional route-level middleware.
+func (e *Echo) POST(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return e.Add(http.MethodPost, path, h, m...)
+}
+
+// PUT registers a new PUT route for a path with matching handler in the
+// router with optional route-level middleware.
+func (e *Echo) PUT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return e.Add(http.MethodPut, path, h, m...)
+}
+
+// TRACE registers a new TRACE route for a path with matching handler in the
+// router with optional route-level middleware.
+func (e *Echo) TRACE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return e.Add(http.MethodTrace, path, h, m...)
+}
+
+// RouteNotFound registers a special-case route which is executed when no other route is found (i.e. HTTP 404 cases)
+// for current request URL.
+// Path supports static and named/any parameters just like other http method is defined. Generally path is ended with
+// wildcard/match-any character (`/*`, `/download/*` etc).
+//
+// Example: `e.RouteNotFound("/*", func(c echo.Context) error { return c.NoContent(http.StatusNotFound) })`
+func (e *Echo) RouteNotFound(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return e.Add(RouteNotFound, path, h, m...)
+}
+
+// Any registers a new route for all HTTP methods (supported by Echo) and path with matching handler
+// in the router with optional route-level middleware.
+//
+// Note: this method only adds specific set of supported HTTP methods as handler and is not true
+// "catch-any-arbitrary-method" way of matching requests.
+func (e *Echo) Any(path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
+ routes := make([]*Route, len(methods))
+ for i, m := range methods {
+ routes[i] = e.Add(m, path, handler, middleware...)
+ }
+ return routes
+}
+
+// Match registers a new route for multiple HTTP methods and path with matching
+// handler in the router with optional route-level middleware.
+func (e *Echo) Match(methods []string, path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
+ routes := make([]*Route, len(methods))
+ for i, m := range methods {
+ routes[i] = e.Add(m, path, handler, middleware...)
+ }
+ return routes
+}
+
+func (common) file(path, file string, get func(string, HandlerFunc, ...MiddlewareFunc) *Route,
+ m ...MiddlewareFunc) *Route {
+ return get(path, func(c Context) error {
+ return c.File(file)
+ }, m...)
+}
+
+// File registers a new route with path to serve a static file with optional route-level middleware.
+func (e *Echo) File(path, file string, m ...MiddlewareFunc) *Route {
+ return e.file(path, file, e.GET, m...)
+}
+
+func (e *Echo) add(host, method, path string, handler HandlerFunc, middlewares ...MiddlewareFunc) *Route {
+ router := e.findRouter(host)
+ //FIXME: when handler+middleware are both nil ... make it behave like handler removal
+ name := handlerName(handler)
+ route := router.add(method, path, name, func(c Context) error {
+ h := applyMiddleware(handler, middlewares...)
+ return h(c)
+ })
+
+ if e.OnAddRouteHandler != nil {
+ e.OnAddRouteHandler(host, *route, handler, middlewares)
+ }
+
+ return route
+}
+
+// Add registers a new route for an HTTP method and path with matching handler
+// in the router with optional route-level middleware.
+func (e *Echo) Add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) *Route {
+ return e.add("", method, path, handler, middleware...)
+}
+
+// Host creates a new router group for the provided host and optional host-level middleware.
+func (e *Echo) Host(name string, m ...MiddlewareFunc) (g *Group) {
+ e.routers[name] = NewRouter(e)
+ g = &Group{host: name, echo: e}
+ g.Use(m...)
+ return
+}
+
+// Group creates a new router group with prefix and optional group-level middleware.
+func (e *Echo) Group(prefix string, m ...MiddlewareFunc) (g *Group) {
+ g = &Group{prefix: prefix, echo: e}
+ g.Use(m...)
+ return
+}
+
+// URI generates an URI from handler.
+func (e *Echo) URI(handler HandlerFunc, params ...interface{}) string {
+ name := handlerName(handler)
+ return e.Reverse(name, params...)
+}
+
+// URL is an alias for `URI` function.
+func (e *Echo) URL(h HandlerFunc, params ...interface{}) string {
+ return e.URI(h, params...)
+}
+
+// Reverse generates an URL from route name and provided parameters.
+func (e *Echo) Reverse(name string, params ...interface{}) string {
+ return e.router.Reverse(name, params...)
+}
+
+// Routes returns the registered routes for default router.
+// In case when Echo serves multiple hosts/domains use `e.Routers()["domain2.site"].Routes()` to get specific host routes.
+func (e *Echo) Routes() []*Route {
+ return e.router.Routes()
+}
+
+// AcquireContext returns an empty `Context` instance from the pool.
+// You must return the context by calling `ReleaseContext()`.
+func (e *Echo) AcquireContext() Context {
+ return e.pool.Get().(Context)
+}
+
+// ReleaseContext returns the `Context` instance back to the pool.
+// You must call it after `AcquireContext()`.
+func (e *Echo) ReleaseContext(c Context) {
+ e.pool.Put(c)
+}
+
+// ServeHTTP implements `http.Handler` interface, which serves HTTP requests.
+func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ // Acquire context
+ c := e.pool.Get().(*context)
+ c.Reset(r, w)
+ var h HandlerFunc
+
+ if e.premiddleware == nil {
+ e.findRouter(r.Host).Find(r.Method, GetPath(r), c)
+ h = c.Handler()
+ h = applyMiddleware(h, e.middleware...)
+ } else {
+ h = func(c Context) error {
+ e.findRouter(r.Host).Find(r.Method, GetPath(r), c)
+ h := c.Handler()
+ h = applyMiddleware(h, e.middleware...)
+ return h(c)
+ }
+ h = applyMiddleware(h, e.premiddleware...)
+ }
+
+ // Execute chain
+ if err := h(c); err != nil {
+ e.HTTPErrorHandler(err, c)
+ }
+
+ // Release context
+ e.pool.Put(c)
+}
+
+// Start starts an HTTP server.
+func (e *Echo) Start(address string) error {
+ e.startupMutex.Lock()
+ e.Server.Addr = address
+ if err := e.configureServer(e.Server); err != nil {
+ e.startupMutex.Unlock()
+ return err
+ }
+ e.startupMutex.Unlock()
+ return e.Server.Serve(e.Listener)
+}
+
+// StartTLS starts an HTTPS server.
+// If `certFile` or `keyFile` is `string` the values are treated as file paths.
+// If `certFile` or `keyFile` is `[]byte` the values are treated as the certificate or key as-is.
+func (e *Echo) StartTLS(address string, certFile, keyFile interface{}) (err error) {
+ e.startupMutex.Lock()
+ var cert []byte
+ if cert, err = filepathOrContent(certFile); err != nil {
+ e.startupMutex.Unlock()
+ return
+ }
+
+ var key []byte
+ if key, err = filepathOrContent(keyFile); err != nil {
+ e.startupMutex.Unlock()
+ return
+ }
+
+ s := e.TLSServer
+ s.TLSConfig = new(tls.Config)
+ s.TLSConfig.Certificates = make([]tls.Certificate, 1)
+ if s.TLSConfig.Certificates[0], err = tls.X509KeyPair(cert, key); err != nil {
+ e.startupMutex.Unlock()
+ return
+ }
+
+ e.configureTLS(address)
+ if err := e.configureServer(s); err != nil {
+ e.startupMutex.Unlock()
+ return err
+ }
+ e.startupMutex.Unlock()
+ return s.Serve(e.TLSListener)
+}
+
+func filepathOrContent(fileOrContent interface{}) (content []byte, err error) {
+ switch v := fileOrContent.(type) {
+ case string:
+ return os.ReadFile(v)
+ case []byte:
+ return v, nil
+ default:
+ return nil, ErrInvalidCertOrKeyType
+ }
+}
+
+// StartAutoTLS starts an HTTPS server using certificates automatically installed from https://letsencrypt.org.
+func (e *Echo) StartAutoTLS(address string) error {
+ e.startupMutex.Lock()
+ s := e.TLSServer
+ s.TLSConfig = new(tls.Config)
+ s.TLSConfig.GetCertificate = e.AutoTLSManager.GetCertificate
+ s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, acme.ALPNProto)
+
+ e.configureTLS(address)
+ if err := e.configureServer(s); err != nil {
+ e.startupMutex.Unlock()
+ return err
+ }
+ e.startupMutex.Unlock()
+ return s.Serve(e.TLSListener)
+}
+
+func (e *Echo) configureTLS(address string) {
+ s := e.TLSServer
+ s.Addr = address
+ if !e.DisableHTTP2 {
+ s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, "h2")
+ }
+}
+
+// StartServer starts a custom http server.
+func (e *Echo) StartServer(s *http.Server) (err error) {
+ e.startupMutex.Lock()
+ if err := e.configureServer(s); err != nil {
+ e.startupMutex.Unlock()
+ return err
+ }
+ if s.TLSConfig != nil {
+ e.startupMutex.Unlock()
+ return s.Serve(e.TLSListener)
+ }
+ e.startupMutex.Unlock()
+ return s.Serve(e.Listener)
+}
+
+func (e *Echo) configureServer(s *http.Server) error {
+ // Setup
+ e.colorer.SetOutput(e.Logger.Output())
+ s.ErrorLog = e.StdLogger
+ s.Handler = e
+ if e.Debug {
+ e.Logger.SetLevel(log.DEBUG)
+ }
+
+ if !e.HideBanner {
+ e.colorer.Printf(banner, e.colorer.Red("v"+Version), e.colorer.Blue(website))
+ }
+
+ if s.TLSConfig == nil {
+ if e.Listener == nil {
+ l, err := newListener(s.Addr, e.ListenerNetwork)
+ if err != nil {
+ return err
+ }
+ e.Listener = l
+ }
+ if !e.HidePort {
+ e.colorer.Printf("⇨ http server started on %s\n", e.colorer.Green(e.Listener.Addr()))
+ }
+ return nil
+ }
+ if e.TLSListener == nil {
+ l, err := newListener(s.Addr, e.ListenerNetwork)
+ if err != nil {
+ return err
+ }
+ e.TLSListener = tls.NewListener(l, s.TLSConfig)
+ }
+ if !e.HidePort {
+ e.colorer.Printf("⇨ https server started on %s\n", e.colorer.Green(e.TLSListener.Addr()))
+ }
+ return nil
+}
+
+// ListenerAddr returns net.Addr for Listener
+func (e *Echo) ListenerAddr() net.Addr {
+ e.startupMutex.RLock()
+ defer e.startupMutex.RUnlock()
+ if e.Listener == nil {
+ return nil
+ }
+ return e.Listener.Addr()
+}
+
+// TLSListenerAddr returns net.Addr for TLSListener
+func (e *Echo) TLSListenerAddr() net.Addr {
+ e.startupMutex.RLock()
+ defer e.startupMutex.RUnlock()
+ if e.TLSListener == nil {
+ return nil
+ }
+ return e.TLSListener.Addr()
+}
+
+// StartH2CServer starts a custom http/2 server with h2c (HTTP/2 Cleartext).
+func (e *Echo) StartH2CServer(address string, h2s *http2.Server) error {
+ e.startupMutex.Lock()
+ // Setup
+ s := e.Server
+ s.Addr = address
+ e.colorer.SetOutput(e.Logger.Output())
+ s.ErrorLog = e.StdLogger
+ s.Handler = h2c.NewHandler(e, h2s)
+ if e.Debug {
+ e.Logger.SetLevel(log.DEBUG)
+ }
+
+ if !e.HideBanner {
+ e.colorer.Printf(banner, e.colorer.Red("v"+Version), e.colorer.Blue(website))
+ }
+
+ if e.Listener == nil {
+ l, err := newListener(s.Addr, e.ListenerNetwork)
+ if err != nil {
+ e.startupMutex.Unlock()
+ return err
+ }
+ e.Listener = l
+ }
+ if !e.HidePort {
+ e.colorer.Printf("⇨ http server started on %s\n", e.colorer.Green(e.Listener.Addr()))
+ }
+ e.startupMutex.Unlock()
+ return s.Serve(e.Listener)
+}
+
+// Close immediately stops the server.
+// It internally calls `http.Server#Close()`.
+func (e *Echo) Close() error {
+ e.startupMutex.Lock()
+ defer e.startupMutex.Unlock()
+ if err := e.TLSServer.Close(); err != nil {
+ return err
+ }
+ return e.Server.Close()
+}
+
+// Shutdown stops the server gracefully.
+// It internally calls `http.Server#Shutdown()`.
+func (e *Echo) Shutdown(ctx stdContext.Context) error {
+ e.startupMutex.Lock()
+ defer e.startupMutex.Unlock()
+ if err := e.TLSServer.Shutdown(ctx); err != nil {
+ return err
+ }
+ return e.Server.Shutdown(ctx)
+}
+
+// NewHTTPError creates a new HTTPError instance.
+func NewHTTPError(code int, message ...interface{}) *HTTPError {
+ he := &HTTPError{Code: code, Message: http.StatusText(code)}
+ if len(message) > 0 {
+ he.Message = message[0]
+ }
+ return he
+}
+
+// Error makes it compatible with `error` interface.
+func (he *HTTPError) Error() string {
+ if he.Internal == nil {
+ return fmt.Sprintf("code=%d, message=%v", he.Code, he.Message)
+ }
+ return fmt.Sprintf("code=%d, message=%v, internal=%v", he.Code, he.Message, he.Internal)
+}
+
+// SetInternal sets error to HTTPError.Internal
+func (he *HTTPError) SetInternal(err error) *HTTPError {
+ he.Internal = err
+ return he
+}
+
+// WithInternal returns clone of HTTPError with err set to HTTPError.Internal field
+func (he *HTTPError) WithInternal(err error) *HTTPError {
+ return &HTTPError{
+ Code: he.Code,
+ Message: he.Message,
+ Internal: err,
+ }
+}
+
+// Unwrap satisfies the Go 1.13 error wrapper interface.
+func (he *HTTPError) Unwrap() error {
+ return he.Internal
+}
+
+// WrapHandler wraps `http.Handler` into `echo.HandlerFunc`.
+func WrapHandler(h http.Handler) HandlerFunc {
+ return func(c Context) error {
+ h.ServeHTTP(c.Response(), c.Request())
+ return nil
+ }
+}
+
+// WrapMiddleware wraps `func(http.Handler) http.Handler` into `echo.MiddlewareFunc`
+func WrapMiddleware(m func(http.Handler) http.Handler) MiddlewareFunc {
+ return func(next HandlerFunc) HandlerFunc {
+ return func(c Context) (err error) {
+ m(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ c.SetRequest(r)
+ c.SetResponse(NewResponse(w, c.Echo()))
+ err = next(c)
+ })).ServeHTTP(c.Response(), c.Request())
+ return
+ }
+ }
+}
+
+// GetPath returns RawPath, if it's empty returns Path from URL
+// Difference between RawPath and Path is:
+// - Path is where request path is stored. Value is stored in decoded form: /%47%6f%2f becomes /Go/.
+// - RawPath is an optional field which only gets set if the default encoding is different from Path.
+func GetPath(r *http.Request) string {
+ path := r.URL.RawPath
+ if path == "" {
+ path = r.URL.Path
+ }
+ return path
+}
+
+func (e *Echo) findRouter(host string) *Router {
+ if len(e.routers) > 0 {
+ if r, ok := e.routers[host]; ok {
+ return r
+ }
+ }
+ return e.router
+}
+
+func handlerName(h HandlerFunc) string {
+ t := reflect.ValueOf(h).Type()
+ if t.Kind() == reflect.Func {
+ return runtime.FuncForPC(reflect.ValueOf(h).Pointer()).Name()
+ }
+ return t.String()
+}
+
+// // PathUnescape is wraps `url.PathUnescape`
+// func PathUnescape(s string) (string, error) {
+// return url.PathUnescape(s)
+// }
+
+// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
+// connections. It's used by ListenAndServe and ListenAndServeTLS so
+// dead TCP connections (e.g. closing laptop mid-download) eventually
+// go away.
+type tcpKeepAliveListener struct {
+ *net.TCPListener
+}
+
+func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
+ if c, err = ln.AcceptTCP(); err != nil {
+ return
+ } else if err = c.(*net.TCPConn).SetKeepAlive(true); err != nil {
+ return
+ }
+ // Ignore error from setting the KeepAlivePeriod as some systems, such as
+ // OpenBSD, do not support setting TCP_USER_TIMEOUT on IPPROTO_TCP
+ _ = c.(*net.TCPConn).SetKeepAlivePeriod(3 * time.Minute)
+ return
+}
+
+func newListener(address, network string) (*tcpKeepAliveListener, error) {
+ if network != "tcp" && network != "tcp4" && network != "tcp6" {
+ return nil, ErrInvalidListenerNetwork
+ }
+ l, err := net.Listen(network, address)
+ if err != nil {
+ return nil, err
+ }
+ return &tcpKeepAliveListener{l.(*net.TCPListener)}, nil
+}
+
+func applyMiddleware(h HandlerFunc, middleware ...MiddlewareFunc) HandlerFunc {
+ for i := len(middleware) - 1; i >= 0; i-- {
+ h = middleware[i](h)
+ }
+ return h
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/echo_fs.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/echo_fs.go
new file mode 100644
index 0000000..9f83a03
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/echo_fs.go
@@ -0,0 +1,159 @@
+package echo
+
+import (
+ "fmt"
+ "io/fs"
+ "net/http"
+ "net/url"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+type filesystem struct {
+ // Filesystem is file system used by Static and File handlers to access files.
+ // Defaults to os.DirFS(".")
+ //
+ // When dealing with `embed.FS` use `fs := echo.MustSubFS(fs, "rootDirectory") to create sub fs which uses necessary
+ // prefix for directory path. This is necessary as `//go:embed assets/images` embeds files with paths
+ // including `assets/images` as their prefix.
+ Filesystem fs.FS
+}
+
+func createFilesystem() filesystem {
+ return filesystem{
+ Filesystem: newDefaultFS(),
+ }
+}
+
+// Static registers a new route with path prefix to serve static files from the provided root directory.
+func (e *Echo) Static(pathPrefix, fsRoot string) *Route {
+ subFs := MustSubFS(e.Filesystem, fsRoot)
+ return e.Add(
+ http.MethodGet,
+ pathPrefix+"*",
+ StaticDirectoryHandler(subFs, false),
+ )
+}
+
+// StaticFS registers a new route with path prefix to serve static files from the provided file system.
+//
+// When dealing with `embed.FS` use `fs := echo.MustSubFS(fs, "rootDirectory") to create sub fs which uses necessary
+// prefix for directory path. This is necessary as `//go:embed assets/images` embeds files with paths
+// including `assets/images` as their prefix.
+func (e *Echo) StaticFS(pathPrefix string, filesystem fs.FS) *Route {
+ return e.Add(
+ http.MethodGet,
+ pathPrefix+"*",
+ StaticDirectoryHandler(filesystem, false),
+ )
+}
+
+// StaticDirectoryHandler creates handler function to serve files from provided file system
+// When disablePathUnescaping is set then file name from path is not unescaped and is served as is.
+func StaticDirectoryHandler(fileSystem fs.FS, disablePathUnescaping bool) HandlerFunc {
+ return func(c Context) error {
+ p := c.Param("*")
+ if !disablePathUnescaping { // when router is already unescaping we do not want to do is twice
+ tmpPath, err := url.PathUnescape(p)
+ if err != nil {
+ return fmt.Errorf("failed to unescape path variable: %w", err)
+ }
+ p = tmpPath
+ }
+
+ // fs.FS.Open() already assumes that file names are relative to FS root path and considers name with prefix `/` as invalid
+ name := filepath.ToSlash(filepath.Clean(strings.TrimPrefix(p, "/")))
+ fi, err := fs.Stat(fileSystem, name)
+ if err != nil {
+ return ErrNotFound
+ }
+
+ // If the request is for a directory and does not end with "/"
+ p = c.Request().URL.Path // path must not be empty.
+ if fi.IsDir() && len(p) > 0 && p[len(p)-1] != '/' {
+ // Redirect to ends with "/"
+ return c.Redirect(http.StatusMovedPermanently, sanitizeURI(p+"/"))
+ }
+ return fsFile(c, name, fileSystem)
+ }
+}
+
+// FileFS registers a new route with path to serve file from the provided file system.
+func (e *Echo) FileFS(path, file string, filesystem fs.FS, m ...MiddlewareFunc) *Route {
+ return e.GET(path, StaticFileHandler(file, filesystem), m...)
+}
+
+// StaticFileHandler creates handler function to serve file from provided file system
+func StaticFileHandler(file string, filesystem fs.FS) HandlerFunc {
+ return func(c Context) error {
+ return fsFile(c, file, filesystem)
+ }
+}
+
+// defaultFS exists to preserve pre v4.7.0 behaviour where files were open by `os.Open`.
+// v4.7 introduced `echo.Filesystem` field which is Go1.16+ `fs.Fs` interface.
+// Difference between `os.Open` and `fs.Open` is that FS does not allow opening path that start with `.`, `..` or `/`
+// etc. For example previously you could have `../images` in your application but `fs := os.DirFS("./")` would not
+// allow you to use `fs.Open("../images")` and this would break all old applications that rely on being able to
+// traverse up from current executable run path.
+// NB: private because you really should use fs.FS implementation instances
+type defaultFS struct {
+ prefix string
+ fs fs.FS
+}
+
+func newDefaultFS() *defaultFS {
+ dir, _ := os.Getwd()
+ return &defaultFS{
+ prefix: dir,
+ fs: nil,
+ }
+}
+
+func (fs defaultFS) Open(name string) (fs.File, error) {
+ if fs.fs == nil {
+ return os.Open(name)
+ }
+ return fs.fs.Open(name)
+}
+
+func subFS(currentFs fs.FS, root string) (fs.FS, error) {
+ root = filepath.ToSlash(filepath.Clean(root)) // note: fs.FS operates only with slashes. `ToSlash` is necessary for Windows
+ if dFS, ok := currentFs.(*defaultFS); ok {
+ // we need to make exception for `defaultFS` instances as it interprets root prefix differently from fs.FS.
+ // fs.Fs.Open does not like relative paths ("./", "../") and absolute paths at all but prior echo.Filesystem we
+ // were able to use paths like `./myfile.log`, `/etc/hosts` and these would work fine with `os.Open` but not with fs.Fs
+ if !filepath.IsAbs(root) {
+ root = filepath.Join(dFS.prefix, root)
+ }
+ return &defaultFS{
+ prefix: root,
+ fs: os.DirFS(root),
+ }, nil
+ }
+ return fs.Sub(currentFs, root)
+}
+
+// MustSubFS creates sub FS from current filesystem or panic on failure.
+// Panic happens when `fsRoot` contains invalid path according to `fs.ValidPath` rules.
+//
+// MustSubFS is helpful when dealing with `embed.FS` because for example `//go:embed assets/images` embeds files with
+// paths including `assets/images` as their prefix. In that case use `fs := echo.MustSubFS(fs, "rootDirectory") to
+// create sub fs which uses necessary prefix for directory path.
+func MustSubFS(currentFs fs.FS, fsRoot string) fs.FS {
+ subFs, err := subFS(currentFs, fsRoot)
+ if err != nil {
+ panic(fmt.Errorf("can not create sub FS, invalid root given, err: %w", err))
+ }
+ return subFs
+}
+
+func sanitizeURI(uri string) string {
+ // double slash `\\`, `//` or even `\/` is absolute uri for browsers and by redirecting request to that uri
+ // we are vulnerable to open redirect attack. so replace all slashes from the beginning with single slash
+ if len(uri) > 1 && (uri[0] == '\\' || uri[0] == '/') && (uri[1] == '\\' || uri[1] == '/') {
+ uri = "/" + strings.TrimLeft(uri, `/\`)
+ }
+ return uri
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/group.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/group.go
new file mode 100644
index 0000000..28ce0dd
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/group.go
@@ -0,0 +1,126 @@
+package echo
+
+import (
+ "net/http"
+)
+
+type (
+ // Group is a set of sub-routes for a specified route. It can be used for inner
+ // routes that share a common middleware or functionality that should be separate
+ // from the parent echo instance while still inheriting from it.
+ Group struct {
+ common
+ host string
+ prefix string
+ middleware []MiddlewareFunc
+ echo *Echo
+ }
+)
+
+// Use implements `Echo#Use()` for sub-routes within the Group.
+func (g *Group) Use(middleware ...MiddlewareFunc) {
+ g.middleware = append(g.middleware, middleware...)
+ if len(g.middleware) == 0 {
+ return
+ }
+ // Allow all requests to reach the group as they might get dropped if router
+ // doesn't find a match, making none of the group middleware process.
+ g.Any("", NotFoundHandler)
+ g.Any("/*", NotFoundHandler)
+}
+
+// CONNECT implements `Echo#CONNECT()` for sub-routes within the Group.
+func (g *Group) CONNECT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return g.Add(http.MethodConnect, path, h, m...)
+}
+
+// DELETE implements `Echo#DELETE()` for sub-routes within the Group.
+func (g *Group) DELETE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return g.Add(http.MethodDelete, path, h, m...)
+}
+
+// GET implements `Echo#GET()` for sub-routes within the Group.
+func (g *Group) GET(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return g.Add(http.MethodGet, path, h, m...)
+}
+
+// HEAD implements `Echo#HEAD()` for sub-routes within the Group.
+func (g *Group) HEAD(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return g.Add(http.MethodHead, path, h, m...)
+}
+
+// OPTIONS implements `Echo#OPTIONS()` for sub-routes within the Group.
+func (g *Group) OPTIONS(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return g.Add(http.MethodOptions, path, h, m...)
+}
+
+// PATCH implements `Echo#PATCH()` for sub-routes within the Group.
+func (g *Group) PATCH(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return g.Add(http.MethodPatch, path, h, m...)
+}
+
+// POST implements `Echo#POST()` for sub-routes within the Group.
+func (g *Group) POST(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return g.Add(http.MethodPost, path, h, m...)
+}
+
+// PUT implements `Echo#PUT()` for sub-routes within the Group.
+func (g *Group) PUT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return g.Add(http.MethodPut, path, h, m...)
+}
+
+// TRACE implements `Echo#TRACE()` for sub-routes within the Group.
+func (g *Group) TRACE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return g.Add(http.MethodTrace, path, h, m...)
+}
+
+// Any implements `Echo#Any()` for sub-routes within the Group.
+func (g *Group) Any(path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
+ routes := make([]*Route, len(methods))
+ for i, m := range methods {
+ routes[i] = g.Add(m, path, handler, middleware...)
+ }
+ return routes
+}
+
+// Match implements `Echo#Match()` for sub-routes within the Group.
+func (g *Group) Match(methods []string, path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
+ routes := make([]*Route, len(methods))
+ for i, m := range methods {
+ routes[i] = g.Add(m, path, handler, middleware...)
+ }
+ return routes
+}
+
+// Group creates a new sub-group with prefix and optional sub-group-level middleware.
+func (g *Group) Group(prefix string, middleware ...MiddlewareFunc) (sg *Group) {
+ m := make([]MiddlewareFunc, 0, len(g.middleware)+len(middleware))
+ m = append(m, g.middleware...)
+ m = append(m, middleware...)
+ sg = g.echo.Group(g.prefix+prefix, m...)
+ sg.host = g.host
+ return
+}
+
+// File implements `Echo#File()` for sub-routes within the Group.
+func (g *Group) File(path, file string) {
+ g.file(path, file, g.GET)
+}
+
+// RouteNotFound implements `Echo#RouteNotFound()` for sub-routes within the Group.
+//
+// Example: `g.RouteNotFound("/*", func(c echo.Context) error { return c.NoContent(http.StatusNotFound) })`
+func (g *Group) RouteNotFound(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return g.Add(RouteNotFound, path, h, m...)
+}
+
+// Add implements `Echo#Add()` for sub-routes within the Group.
+func (g *Group) Add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) *Route {
+ // Combine into a new slice to avoid accidentally passing the same slice for
+ // multiple routes, which would lead to later add() calls overwriting the
+ // middleware from earlier calls.
+ m := make([]MiddlewareFunc, 0, len(g.middleware)+len(middleware))
+ m = append(m, g.middleware...)
+ m = append(m, middleware...)
+ return g.echo.add(g.host, method, g.prefix+path, handler, m...)
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/group_fs.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/group_fs.go
new file mode 100644
index 0000000..aedc4c6
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/group_fs.go
@@ -0,0 +1,30 @@
+package echo
+
+import (
+ "io/fs"
+ "net/http"
+)
+
+// Static implements `Echo#Static()` for sub-routes within the Group.
+func (g *Group) Static(pathPrefix, fsRoot string) {
+ subFs := MustSubFS(g.echo.Filesystem, fsRoot)
+ g.StaticFS(pathPrefix, subFs)
+}
+
+// StaticFS implements `Echo#StaticFS()` for sub-routes within the Group.
+//
+// When dealing with `embed.FS` use `fs := echo.MustSubFS(fs, "rootDirectory") to create sub fs which uses necessary
+// prefix for directory path. This is necessary as `//go:embed assets/images` embeds files with paths
+// including `assets/images` as their prefix.
+func (g *Group) StaticFS(pathPrefix string, filesystem fs.FS) {
+ g.Add(
+ http.MethodGet,
+ pathPrefix+"*",
+ StaticDirectoryHandler(filesystem, false),
+ )
+}
+
+// FileFS implements `Echo#FileFS()` for sub-routes within the Group.
+func (g *Group) FileFS(path, file string, filesystem fs.FS, m ...MiddlewareFunc) *Route {
+ return g.GET(path, StaticFileHandler(file, filesystem), m...)
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/ip.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/ip.go
new file mode 100644
index 0000000..1bcd756
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/ip.go
@@ -0,0 +1,268 @@
+package echo
+
+import (
+ "net"
+ "net/http"
+ "strings"
+)
+
+/**
+By: https://github.com/tmshn (See: https://github.com/labstack/echo/pull/1478 , https://github.com/labstack/echox/pull/134 )
+Source: https://echo.labstack.com/guide/ip-address/
+
+IP address plays fundamental role in HTTP; it's used for access control, auditing, geo-based access analysis and more.
+Echo provides handy method [`Context#RealIP()`](https://godoc.org/github.com/labstack/echo#Context) for that.
+
+However, it is not trivial to retrieve the _real_ IP address from requests especially when you put L7 proxies before the application.
+In such situation, _real_ IP needs to be relayed on HTTP layer from proxies to your app, but you must not trust HTTP headers unconditionally.
+Otherwise, you might give someone a chance of deceiving you. **A security risk!**
+
+To retrieve IP address reliably/securely, you must let your application be aware of the entire architecture of your infrastructure.
+In Echo, this can be done by configuring `Echo#IPExtractor` appropriately.
+This guides show you why and how.
+
+> Note: if you dont' set `Echo#IPExtractor` explicitly, Echo fallback to legacy behavior, which is not a good choice.
+
+Let's start from two questions to know the right direction:
+
+1. Do you put any HTTP (L7) proxy in front of the application?
+ - It includes both cloud solutions (such as AWS ALB or GCP HTTP LB) and OSS ones (such as Nginx, Envoy or Istio ingress gateway).
+2. If yes, what HTTP header do your proxies use to pass client IP to the application?
+
+## Case 1. With no proxy
+
+If you put no proxy (e.g.: directory facing to the internet), all you need to (and have to) see is IP address from network layer.
+Any HTTP header is untrustable because the clients have full control what headers to be set.
+
+In this case, use `echo.ExtractIPDirect()`.
+
+```go
+e.IPExtractor = echo.ExtractIPDirect()
+```
+
+## Case 2. With proxies using `X-Forwarded-For` header
+
+[`X-Forwared-For` (XFF)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) is the popular header
+to relay clients' IP addresses.
+At each hop on the proxies, they append the request IP address at the end of the header.
+
+Following example diagram illustrates this behavior.
+
+```text
+┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
+│ "Origin" │───────────>│ Proxy 1 │───────────>│ Proxy 2 │───────────>│ Your app │
+│ (IP: a) │ │ (IP: b) │ │ (IP: c) │ │ │
+└──────────┘ └──────────┘ └──────────┘ └──────────┘
+
+Case 1.
+XFF: "" "a" "a, b"
+ ~~~~~~
+Case 2.
+XFF: "x" "x, a" "x, a, b"
+ ~~~~~~~~~
+ ↑ What your app will see
+```
+
+In this case, use **first _untrustable_ IP reading from right**. Never use first one reading from left, as it is
+configurable by client. Here "trustable" means "you are sure the IP address belongs to your infrastructre".
+In above example, if `b` and `c` are trustable, the IP address of the client is `a` for both cases, never be `x`.
+
+In Echo, use `ExtractIPFromXFFHeader(...TrustOption)`.
+
+```go
+e.IPExtractor = echo.ExtractIPFromXFFHeader()
+```
+
+By default, it trusts internal IP addresses (loopback, link-local unicast, private-use and unique local address
+from [RFC6890](https://tools.ietf.org/html/rfc6890), [RFC4291](https://tools.ietf.org/html/rfc4291) and
+[RFC4193](https://tools.ietf.org/html/rfc4193)).
+To control this behavior, use [`TrustOption`](https://godoc.org/github.com/labstack/echo#TrustOption)s.
+
+E.g.:
+
+```go
+e.IPExtractor = echo.ExtractIPFromXFFHeader(
+ TrustLinkLocal(false),
+ TrustIPRanges(lbIPRange),
+)
+```
+
+- Ref: https://godoc.org/github.com/labstack/echo#TrustOption
+
+## Case 3. With proxies using `X-Real-IP` header
+
+`X-Real-IP` is another HTTP header to relay clients' IP addresses, but it carries only one address unlike XFF.
+
+If your proxies set this header, use `ExtractIPFromRealIPHeader(...TrustOption)`.
+
+```go
+e.IPExtractor = echo.ExtractIPFromRealIPHeader()
+```
+
+Again, it trusts internal IP addresses by default (loopback, link-local unicast, private-use and unique local address
+from [RFC6890](https://tools.ietf.org/html/rfc6890), [RFC4291](https://tools.ietf.org/html/rfc4291) and
+[RFC4193](https://tools.ietf.org/html/rfc4193)).
+To control this behavior, use [`TrustOption`](https://godoc.org/github.com/labstack/echo#TrustOption)s.
+
+- Ref: https://godoc.org/github.com/labstack/echo#TrustOption
+
+> **Never forget** to configure the outermost proxy (i.e.; at the edge of your infrastructure) **not to pass through incoming headers**.
+> Otherwise there is a chance of fraud, as it is what clients can control.
+
+## About default behavior
+
+In default behavior, Echo sees all of first XFF header, X-Real-IP header and IP from network layer.
+
+As you might already notice, after reading this article, this is not good.
+Sole reason this is default is just backward compatibility.
+
+## Private IP ranges
+
+See: https://en.wikipedia.org/wiki/Private_network
+
+Private IPv4 address ranges (RFC 1918):
+* 10.0.0.0 – 10.255.255.255 (24-bit block)
+* 172.16.0.0 – 172.31.255.255 (20-bit block)
+* 192.168.0.0 – 192.168.255.255 (16-bit block)
+
+Private IPv6 address ranges:
+* fc00::/7 address block = RFC 4193 Unique Local Addresses (ULA)
+
+*/
+
+type ipChecker struct {
+ trustLoopback bool
+ trustLinkLocal bool
+ trustPrivateNet bool
+ trustExtraRanges []*net.IPNet
+}
+
+// TrustOption is config for which IP address to trust
+type TrustOption func(*ipChecker)
+
+// TrustLoopback configures if you trust loopback address (default: true).
+func TrustLoopback(v bool) TrustOption {
+ return func(c *ipChecker) {
+ c.trustLoopback = v
+ }
+}
+
+// TrustLinkLocal configures if you trust link-local address (default: true).
+func TrustLinkLocal(v bool) TrustOption {
+ return func(c *ipChecker) {
+ c.trustLinkLocal = v
+ }
+}
+
+// TrustPrivateNet configures if you trust private network address (default: true).
+func TrustPrivateNet(v bool) TrustOption {
+ return func(c *ipChecker) {
+ c.trustPrivateNet = v
+ }
+}
+
+// TrustIPRange add trustable IP ranges using CIDR notation.
+func TrustIPRange(ipRange *net.IPNet) TrustOption {
+ return func(c *ipChecker) {
+ c.trustExtraRanges = append(c.trustExtraRanges, ipRange)
+ }
+}
+
+func newIPChecker(configs []TrustOption) *ipChecker {
+ checker := &ipChecker{trustLoopback: true, trustLinkLocal: true, trustPrivateNet: true}
+ for _, configure := range configs {
+ configure(checker)
+ }
+ return checker
+}
+
+// Go1.16+ added `ip.IsPrivate()` but until that use this implementation
+func isPrivateIPRange(ip net.IP) bool {
+ if ip4 := ip.To4(); ip4 != nil {
+ return ip4[0] == 10 ||
+ ip4[0] == 172 && ip4[1]&0xf0 == 16 ||
+ ip4[0] == 192 && ip4[1] == 168
+ }
+ return len(ip) == net.IPv6len && ip[0]&0xfe == 0xfc
+}
+
+func (c *ipChecker) trust(ip net.IP) bool {
+ if c.trustLoopback && ip.IsLoopback() {
+ return true
+ }
+ if c.trustLinkLocal && ip.IsLinkLocalUnicast() {
+ return true
+ }
+ if c.trustPrivateNet && isPrivateIPRange(ip) {
+ return true
+ }
+ for _, trustedRange := range c.trustExtraRanges {
+ if trustedRange.Contains(ip) {
+ return true
+ }
+ }
+ return false
+}
+
+// IPExtractor is a function to extract IP addr from http.Request.
+// Set appropriate one to Echo#IPExtractor.
+// See https://echo.labstack.com/guide/ip-address for more details.
+type IPExtractor func(*http.Request) string
+
+// ExtractIPDirect extracts IP address using actual IP address.
+// Use this if your server faces to internet directory (i.e.: uses no proxy).
+func ExtractIPDirect() IPExtractor {
+ return extractIP
+}
+
+func extractIP(req *http.Request) string {
+ ra, _, _ := net.SplitHostPort(req.RemoteAddr)
+ return ra
+}
+
+// ExtractIPFromRealIPHeader extracts IP address using x-real-ip header.
+// Use this if you put proxy which uses this header.
+func ExtractIPFromRealIPHeader(options ...TrustOption) IPExtractor {
+ checker := newIPChecker(options)
+ return func(req *http.Request) string {
+ realIP := req.Header.Get(HeaderXRealIP)
+ if realIP != "" {
+ realIP = strings.TrimPrefix(realIP, "[")
+ realIP = strings.TrimSuffix(realIP, "]")
+ if ip := net.ParseIP(realIP); ip != nil && checker.trust(ip) {
+ return realIP
+ }
+ }
+ return extractIP(req)
+ }
+}
+
+// ExtractIPFromXFFHeader extracts IP address using x-forwarded-for header.
+// Use this if you put proxy which uses this header.
+// This returns nearest untrustable IP. If all IPs are trustable, returns furthest one (i.e.: XFF[0]).
+func ExtractIPFromXFFHeader(options ...TrustOption) IPExtractor {
+ checker := newIPChecker(options)
+ return func(req *http.Request) string {
+ directIP := extractIP(req)
+ xffs := req.Header[HeaderXForwardedFor]
+ if len(xffs) == 0 {
+ return directIP
+ }
+ ips := append(strings.Split(strings.Join(xffs, ","), ","), directIP)
+ for i := len(ips) - 1; i >= 0; i-- {
+ ips[i] = strings.TrimSpace(ips[i])
+ ips[i] = strings.TrimPrefix(ips[i], "[")
+ ips[i] = strings.TrimSuffix(ips[i], "]")
+ ip := net.ParseIP(ips[i])
+ if ip == nil {
+ // Unable to parse IP; cannot trust entire records
+ return directIP
+ }
+ if !checker.trust(ip) {
+ return ip.String()
+ }
+ }
+ // All of the IPs are trusted; return first element because it is furthest from server (best effort strategy).
+ return strings.TrimSpace(ips[0])
+ }
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/json.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/json.go
new file mode 100644
index 0000000..16b2d05
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/json.go
@@ -0,0 +1,31 @@
+package echo
+
+import (
+ "encoding/json"
+ "fmt"
+ "net/http"
+)
+
+// DefaultJSONSerializer implements JSON encoding using encoding/json.
+type DefaultJSONSerializer struct{}
+
+// Serialize converts an interface into a json and writes it to the response.
+// You can optionally use the indent parameter to produce pretty JSONs.
+func (d DefaultJSONSerializer) Serialize(c Context, i interface{}, indent string) error {
+ enc := json.NewEncoder(c.Response())
+ if indent != "" {
+ enc.SetIndent("", indent)
+ }
+ return enc.Encode(i)
+}
+
+// Deserialize reads a JSON from a request body and converts it into an interface.
+func (d DefaultJSONSerializer) Deserialize(c Context, i interface{}) error {
+ err := json.NewDecoder(c.Request().Body).Decode(i)
+ if ute, ok := err.(*json.UnmarshalTypeError); ok {
+ return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unmarshal type error: expected=%v, got=%v, field=%v, offset=%v", ute.Type, ute.Value, ute.Field, ute.Offset)).SetInternal(err)
+ } else if se, ok := err.(*json.SyntaxError); ok {
+ return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Syntax error: offset=%v, error=%v", se.Offset, se.Error())).SetInternal(err)
+ }
+ return err
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/log.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/log.go
new file mode 100644
index 0000000..3f8de59
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/log.go
@@ -0,0 +1,41 @@
+package echo
+
+import (
+ "io"
+
+ "github.com/labstack/gommon/log"
+)
+
+type (
+ // Logger defines the logging interface.
+ Logger interface {
+ Output() io.Writer
+ SetOutput(w io.Writer)
+ Prefix() string
+ SetPrefix(p string)
+ Level() log.Lvl
+ SetLevel(v log.Lvl)
+ SetHeader(h string)
+ Print(i ...interface{})
+ Printf(format string, args ...interface{})
+ Printj(j log.JSON)
+ Debug(i ...interface{})
+ Debugf(format string, args ...interface{})
+ Debugj(j log.JSON)
+ Info(i ...interface{})
+ Infof(format string, args ...interface{})
+ Infoj(j log.JSON)
+ Warn(i ...interface{})
+ Warnf(format string, args ...interface{})
+ Warnj(j log.JSON)
+ Error(i ...interface{})
+ Errorf(format string, args ...interface{})
+ Errorj(j log.JSON)
+ Fatal(i ...interface{})
+ Fatalj(j log.JSON)
+ Fatalf(format string, args ...interface{})
+ Panic(i ...interface{})
+ Panicj(j log.JSON)
+ Panicf(format string, args ...interface{})
+ }
+)
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/basic_auth.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/basic_auth.go
new file mode 100644
index 0000000..52ef104
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/basic_auth.go
@@ -0,0 +1,110 @@
+package middleware
+
+import (
+ "encoding/base64"
+ "strconv"
+ "strings"
+ "net/http"
+
+ "github.com/labstack/echo/v4"
+)
+
+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
+
+ // Realm is a string to define realm attribute of BasicAuth.
+ // Default value "Restricted".
+ Realm string
+ }
+
+ // BasicAuthValidator defines a function to validate BasicAuth credentials.
+ BasicAuthValidator func(string, string, echo.Context) (bool, error)
+)
+
+const (
+ basic = "basic"
+ defaultRealm = "Restricted"
+)
+
+var (
+ // DefaultBasicAuthConfig is the default BasicAuth middleware config.
+ DefaultBasicAuthConfig = BasicAuthConfig{
+ Skipper: DefaultSkipper,
+ Realm: defaultRealm,
+ }
+)
+
+// 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("echo: basic-auth middleware requires a validator function")
+ }
+ if config.Skipper == nil {
+ config.Skipper = DefaultBasicAuthConfig.Skipper
+ }
+ if config.Realm == "" {
+ config.Realm = defaultRealm
+ }
+
+ 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 && strings.EqualFold(auth[:l], basic) {
+ // Invalid base64 shouldn't be treated as error
+ // instead should be treated as invalid client input
+ b, err := base64.StdEncoding.DecodeString(auth[l+1:])
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest).SetInternal(err)
+ }
+
+ cred := string(b)
+ for i := 0; i < len(cred); i++ {
+ if cred[i] == ':' {
+ // Verify credentials
+ valid, err := config.Validator(cred[:i], cred[i+1:], c)
+ if err != nil {
+ return err
+ } else if valid {
+ return next(c)
+ }
+ break
+ }
+ }
+ }
+
+ realm := defaultRealm
+ if config.Realm != defaultRealm {
+ realm = strconv.Quote(config.Realm)
+ }
+
+ // Need to return `401` for browsers to pop-up login box.
+ c.Response().Header().Set(echo.HeaderWWWAuthenticate, basic+" realm="+realm)
+ return echo.ErrUnauthorized
+ }
+ }
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/body_dump.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/body_dump.go
new file mode 100644
index 0000000..fa7891b
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/body_dump.go
@@ -0,0 +1,106 @@
+package middleware
+
+import (
+ "bufio"
+ "bytes"
+ "io"
+ "net"
+ "net/http"
+
+ "github.com/labstack/echo/v4"
+)
+
+type (
+ // BodyDumpConfig defines the config for BodyDump middleware.
+ BodyDumpConfig struct {
+ // Skipper defines a function to skip middleware.
+ Skipper Skipper
+
+ // Handler receives request and response payload.
+ // Required.
+ Handler BodyDumpHandler
+ }
+
+ // BodyDumpHandler receives the request and response payload.
+ BodyDumpHandler func(echo.Context, []byte, []byte)
+
+ bodyDumpResponseWriter struct {
+ io.Writer
+ http.ResponseWriter
+ }
+)
+
+var (
+ // DefaultBodyDumpConfig is the default BodyDump middleware config.
+ DefaultBodyDumpConfig = BodyDumpConfig{
+ Skipper: DefaultSkipper,
+ }
+)
+
+// BodyDump returns a BodyDump middleware.
+//
+// BodyDump middleware captures the request and response payload and calls the
+// registered handler.
+func BodyDump(handler BodyDumpHandler) echo.MiddlewareFunc {
+ c := DefaultBodyDumpConfig
+ c.Handler = handler
+ return BodyDumpWithConfig(c)
+}
+
+// BodyDumpWithConfig returns a BodyDump middleware with config.
+// See: `BodyDump()`.
+func BodyDumpWithConfig(config BodyDumpConfig) echo.MiddlewareFunc {
+ // Defaults
+ if config.Handler == nil {
+ panic("echo: body-dump middleware requires a handler function")
+ }
+ if config.Skipper == nil {
+ config.Skipper = DefaultBodyDumpConfig.Skipper
+ }
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) (err error) {
+ if config.Skipper(c) {
+ return next(c)
+ }
+
+ // Request
+ reqBody := []byte{}
+ if c.Request().Body != nil { // Read
+ reqBody, _ = io.ReadAll(c.Request().Body)
+ }
+ c.Request().Body = io.NopCloser(bytes.NewBuffer(reqBody)) // Reset
+
+ // Response
+ resBody := new(bytes.Buffer)
+ mw := io.MultiWriter(c.Response().Writer, resBody)
+ writer := &bodyDumpResponseWriter{Writer: mw, ResponseWriter: c.Response().Writer}
+ c.Response().Writer = writer
+
+ if err = next(c); err != nil {
+ c.Error(err)
+ }
+
+ // Callback
+ config.Handler(c, reqBody, resBody.Bytes())
+
+ return
+ }
+ }
+}
+
+func (w *bodyDumpResponseWriter) WriteHeader(code int) {
+ w.ResponseWriter.WriteHeader(code)
+}
+
+func (w *bodyDumpResponseWriter) Write(b []byte) (int, error) {
+ return w.Writer.Write(b)
+}
+
+func (w *bodyDumpResponseWriter) Flush() {
+ w.ResponseWriter.(http.Flusher).Flush()
+}
+
+func (w *bodyDumpResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return w.ResponseWriter.(http.Hijacker).Hijack()
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/body_limit.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/body_limit.go
new file mode 100644
index 0000000..b436bd5
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/body_limit.go
@@ -0,0 +1,117 @@
+package middleware
+
+import (
+ "fmt"
+ "io"
+ "sync"
+
+ "github.com/labstack/echo/v4"
+ "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 `yaml:"limit"`
+ limit int64
+ }
+
+ limitedReader struct {
+ BodyLimitConfig
+ reader io.ReadCloser
+ read int64
+ context echo.Context
+ }
+)
+
+var (
+ // DefaultBodyLimitConfig is the default BodyLimit 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("echo: 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
+ r.read = 0
+}
+
+func limitedReaderPool(c BodyLimitConfig) sync.Pool {
+ return sync.Pool{
+ New: func() interface{} {
+ return &limitedReader{BodyLimitConfig: c}
+ },
+ }
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/compress.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/compress.go
new file mode 100644
index 0000000..9e5f610
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/compress.go
@@ -0,0 +1,144 @@
+package middleware
+
+import (
+ "bufio"
+ "compress/gzip"
+ "io"
+ "net"
+ "net/http"
+ "strings"
+ "sync"
+
+ "github.com/labstack/echo/v4"
+)
+
+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 `yaml:"level"`
+ }
+
+ gzipResponseWriter struct {
+ io.Writer
+ http.ResponseWriter
+ wroteBody bool
+ }
+)
+
+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
+ }
+
+ pool := gzipCompressPool(config)
+
+ 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().Set(echo.HeaderContentEncoding, gzipScheme) // Issue #806
+ i := pool.Get()
+ w, ok := i.(*gzip.Writer)
+ if !ok {
+ return echo.NewHTTPError(http.StatusInternalServerError, i.(error).Error())
+ }
+ rw := res.Writer
+ w.Reset(rw)
+ grw := &gzipResponseWriter{Writer: w, ResponseWriter: rw}
+ defer func() {
+ if !grw.wroteBody {
+ 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(io.Discard)
+ }
+ w.Close()
+ pool.Put(w)
+ }()
+ res.Writer = grw
+ }
+ return next(c)
+ }
+ }
+}
+
+func (w *gzipResponseWriter) WriteHeader(code int) {
+ w.Header().Del(echo.HeaderContentLength) // Issue #444
+ 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))
+ }
+ w.wroteBody = true
+ return w.Writer.Write(b)
+}
+
+func (w *gzipResponseWriter) Flush() {
+ w.Writer.(*gzip.Writer).Flush()
+ if flusher, ok := w.ResponseWriter.(http.Flusher); ok {
+ flusher.Flush()
+ }
+}
+
+func (w *gzipResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return w.ResponseWriter.(http.Hijacker).Hijack()
+}
+
+func (w *gzipResponseWriter) Push(target string, opts *http.PushOptions) error {
+ if p, ok := w.ResponseWriter.(http.Pusher); ok {
+ return p.Push(target, opts)
+ }
+ return http.ErrNotSupported
+}
+
+func gzipCompressPool(config GzipConfig) sync.Pool {
+ return sync.Pool{
+ New: func() interface{} {
+ w, err := gzip.NewWriterLevel(io.Discard, config.Level)
+ if err != nil {
+ return err
+ }
+ return w
+ },
+ }
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/cors.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/cors.go
new file mode 100644
index 0000000..25cf983
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/cors.go
@@ -0,0 +1,282 @@
+package middleware
+
+import (
+ "net/http"
+ "regexp"
+ "strconv"
+ "strings"
+
+ "github.com/labstack/echo/v4"
+)
+
+type (
+ // CORSConfig defines the config for CORS middleware.
+ CORSConfig struct {
+ // Skipper defines a function to skip middleware.
+ Skipper Skipper
+
+ // AllowOrigins determines the value of the Access-Control-Allow-Origin
+ // response header. This header defines a list of origins that may access the
+ // resource. The wildcard characters '*' and '?' are supported and are
+ // converted to regex fragments '.*' and '.' accordingly.
+ //
+ // Security: use extreme caution when handling the origin, and carefully
+ // validate any logic. Remember that attackers may register hostile domain names.
+ // See https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
+ //
+ // Optional. Default value []string{"*"}.
+ //
+ // See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
+ AllowOrigins []string `yaml:"allow_origins"`
+
+ // AllowOriginFunc is a custom function to validate the origin. It takes the
+ // origin as an argument and returns true if allowed or false otherwise. If
+ // an error is returned, it is returned by the handler. If this option is
+ // set, AllowOrigins is ignored.
+ //
+ // Security: use extreme caution when handling the origin, and carefully
+ // validate any logic. Remember that attackers may register hostile domain names.
+ // See https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
+ //
+ // Optional.
+ AllowOriginFunc func(origin string) (bool, error) `yaml:"allow_origin_func"`
+
+ // AllowMethods determines the value of the Access-Control-Allow-Methods
+ // response header. This header specified the list of methods allowed when
+ // accessing the resource. This is used in response to a preflight request.
+ //
+ // Optional. Default value DefaultCORSConfig.AllowMethods.
+ // If `allowMethods` is left empty, this middleware will fill for preflight
+ // request `Access-Control-Allow-Methods` header value
+ // from `Allow` header that echo.Router set into context.
+ //
+ // See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods
+ AllowMethods []string `yaml:"allow_methods"`
+
+ // AllowHeaders determines the value of the Access-Control-Allow-Headers
+ // response header. This header is used in response to a preflight request to
+ // indicate which HTTP headers can be used when making the actual request.
+ //
+ // Optional. Default value []string{}.
+ //
+ // See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
+ AllowHeaders []string `yaml:"allow_headers"`
+
+ // AllowCredentials determines the value of the
+ // Access-Control-Allow-Credentials response header. This header indicates
+ // whether or not the response to the request can be exposed when the
+ // credentials mode (Request.credentials) 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. See also
+ // [MDN: Access-Control-Allow-Credentials].
+ //
+ // Optional. Default value false, in which case the header is not set.
+ //
+ // Security: avoid using `AllowCredentials = true` with `AllowOrigins = *`.
+ // See "Exploiting CORS misconfigurations for Bitcoins and bounties",
+ // https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
+ //
+ // See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
+ AllowCredentials bool `yaml:"allow_credentials"`
+
+ // ExposeHeaders determines the value of Access-Control-Expose-Headers, which
+ // defines a list of headers that clients are allowed to access.
+ //
+ // Optional. Default value []string{}, in which case the header is not set.
+ //
+ // See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Header
+ ExposeHeaders []string `yaml:"expose_headers"`
+
+ // MaxAge determines the value of the Access-Control-Max-Age response header.
+ // This header indicates how long (in seconds) the results of a preflight
+ // request can be cached.
+ //
+ // Optional. Default value 0. The header is set only if MaxAge > 0.
+ //
+ // See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age
+ MaxAge int `yaml:"max_age"`
+ }
+)
+
+var (
+ // DefaultCORSConfig is the default CORS middleware config.
+ DefaultCORSConfig = CORSConfig{
+ Skipper: DefaultSkipper,
+ AllowOrigins: []string{"*"},
+ AllowMethods: []string{http.MethodGet, http.MethodHead, http.MethodPut, http.MethodPatch, http.MethodPost, http.MethodDelete},
+ }
+)
+
+// CORS returns a Cross-Origin Resource Sharing (CORS) middleware.
+// See also [MDN: Cross-Origin Resource Sharing (CORS)].
+//
+// Security: Poorly configured CORS can compromise security because it allows
+// relaxation of the browser's Same-Origin policy. See [Exploiting CORS
+// misconfigurations for Bitcoins and bounties] and [Portswigger: Cross-origin
+// resource sharing (CORS)] for more details.
+//
+// [MDN: Cross-Origin Resource Sharing (CORS)]: https://developer.mozilla.org/en/docs/Web/HTTP/Access_control_CORS
+// [Exploiting CORS misconfigurations for Bitcoins and bounties]: https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
+// [Portswigger: Cross-origin resource sharing (CORS)]: https://portswigger.net/web-security/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
+ }
+ hasCustomAllowMethods := true
+ if len(config.AllowMethods) == 0 {
+ hasCustomAllowMethods = false
+ config.AllowMethods = DefaultCORSConfig.AllowMethods
+ }
+
+ allowOriginPatterns := []string{}
+ for _, origin := range config.AllowOrigins {
+ pattern := regexp.QuoteMeta(origin)
+ pattern = strings.Replace(pattern, "\\*", ".*", -1)
+ pattern = strings.Replace(pattern, "\\?", ".", -1)
+ pattern = "^" + pattern + "$"
+ allowOriginPatterns = append(allowOriginPatterns, pattern)
+ }
+
+ 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 := ""
+
+ res.Header().Add(echo.HeaderVary, echo.HeaderOrigin)
+
+ // Preflight request is an OPTIONS request, using three HTTP request headers: Access-Control-Request-Method,
+ // Access-Control-Request-Headers, and the Origin header. See: https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request
+ // For simplicity we just consider method type and later `Origin` header.
+ preflight := req.Method == http.MethodOptions
+
+ // Although router adds special handler in case of OPTIONS method we avoid calling next for OPTIONS in this middleware
+ // as CORS requests do not have cookies / authentication headers by default, so we could get stuck in auth
+ // middlewares by calling next(c).
+ // But we still want to send `Allow` header as response in case of Non-CORS OPTIONS request as router default
+ // handler does.
+ routerAllowMethods := ""
+ if preflight {
+ tmpAllowMethods, ok := c.Get(echo.ContextKeyHeaderAllow).(string)
+ if ok && tmpAllowMethods != "" {
+ routerAllowMethods = tmpAllowMethods
+ c.Response().Header().Set(echo.HeaderAllow, routerAllowMethods)
+ }
+ }
+
+ // No Origin provided. This is (probably) not request from actual browser - proceed executing middleware chain
+ if origin == "" {
+ if !preflight {
+ return next(c)
+ }
+ return c.NoContent(http.StatusNoContent)
+ }
+
+ if config.AllowOriginFunc != nil {
+ allowed, err := config.AllowOriginFunc(origin)
+ if err != nil {
+ return err
+ }
+ if allowed {
+ allowOrigin = origin
+ }
+ } else {
+ // Check allowed origins
+ for _, o := range config.AllowOrigins {
+ if o == "*" && config.AllowCredentials {
+ allowOrigin = origin
+ break
+ }
+ if o == "*" || o == origin {
+ allowOrigin = o
+ break
+ }
+ if matchSubdomain(origin, o) {
+ allowOrigin = origin
+ break
+ }
+ }
+
+ checkPatterns := false
+ if allowOrigin == "" {
+ // to avoid regex cost by invalid (long) domains (253 is domain name max limit)
+ if len(origin) <= (253+3+5) && strings.Contains(origin, "://") {
+ checkPatterns = true
+ }
+ }
+ if checkPatterns {
+ for _, re := range allowOriginPatterns {
+ if match, _ := regexp.MatchString(re, origin); match {
+ allowOrigin = origin
+ break
+ }
+ }
+ }
+ }
+
+ // Origin not allowed
+ if allowOrigin == "" {
+ if !preflight {
+ return next(c)
+ }
+ return c.NoContent(http.StatusNoContent)
+ }
+
+ res.Header().Set(echo.HeaderAccessControlAllowOrigin, allowOrigin)
+ if config.AllowCredentials {
+ res.Header().Set(echo.HeaderAccessControlAllowCredentials, "true")
+ }
+
+ // Simple request
+ if !preflight {
+ if exposeHeaders != "" {
+ res.Header().Set(echo.HeaderAccessControlExposeHeaders, exposeHeaders)
+ }
+ return next(c)
+ }
+
+ // Preflight request
+ res.Header().Add(echo.HeaderVary, echo.HeaderAccessControlRequestMethod)
+ res.Header().Add(echo.HeaderVary, echo.HeaderAccessControlRequestHeaders)
+
+ if !hasCustomAllowMethods && routerAllowMethods != "" {
+ res.Header().Set(echo.HeaderAccessControlAllowMethods, routerAllowMethods)
+ } else {
+ res.Header().Set(echo.HeaderAccessControlAllowMethods, allowMethods)
+ }
+
+ 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/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/csrf.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/csrf.go
new file mode 100644
index 0000000..8661c9f
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/csrf.go
@@ -0,0 +1,219 @@
+package middleware
+
+import (
+ "crypto/subtle"
+ "net/http"
+ "time"
+
+ "github.com/labstack/echo/v4"
+ "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 `yaml:"token_length"`
+ // Optional. Default value 32.
+
+ // TokenLookup is a string in the form of "<source>:<name>" or "<source>:<name>,<source>:<name>" that is used
+ // to extract token from the request.
+ // Optional. Default value "header:X-CSRF-Token".
+ // Possible values:
+ // - "header:<name>" or "header:<name>:<cut-prefix>"
+ // - "query:<name>"
+ // - "form:<name>"
+ // Multiple sources example:
+ // - "header:X-CSRF-Token,query:csrf"
+ TokenLookup string `yaml:"token_lookup"`
+
+ // Context key to store generated CSRF token into context.
+ // Optional. Default value "csrf".
+ ContextKey string `yaml:"context_key"`
+
+ // Name of the CSRF cookie. This cookie will store CSRF token.
+ // Optional. Default value "csrf".
+ CookieName string `yaml:"cookie_name"`
+
+ // Domain of the CSRF cookie.
+ // Optional. Default value none.
+ CookieDomain string `yaml:"cookie_domain"`
+
+ // Path of the CSRF cookie.
+ // Optional. Default value none.
+ CookiePath string `yaml:"cookie_path"`
+
+ // Max age (in seconds) of the CSRF cookie.
+ // Optional. Default value 86400 (24hr).
+ CookieMaxAge int `yaml:"cookie_max_age"`
+
+ // Indicates if CSRF cookie is secure.
+ // Optional. Default value false.
+ CookieSecure bool `yaml:"cookie_secure"`
+
+ // Indicates if CSRF cookie is HTTP only.
+ // Optional. Default value false.
+ CookieHTTPOnly bool `yaml:"cookie_http_only"`
+
+ // Indicates SameSite mode of the CSRF cookie.
+ // Optional. Default value SameSiteDefaultMode.
+ CookieSameSite http.SameSite `yaml:"cookie_same_site"`
+
+ // ErrorHandler defines a function which is executed for returning custom errors.
+ ErrorHandler CSRFErrorHandler
+ }
+
+ // CSRFErrorHandler is a function which is executed for creating custom errors.
+ CSRFErrorHandler func(err error, c echo.Context) error
+)
+
+// ErrCSRFInvalid is returned when CSRF check fails
+var ErrCSRFInvalid = echo.NewHTTPError(http.StatusForbidden, "invalid csrf token")
+
+var (
+ // DefaultCSRFConfig is the default CSRF middleware config.
+ DefaultCSRFConfig = CSRFConfig{
+ Skipper: DefaultSkipper,
+ TokenLength: 32,
+ TokenLookup: "header:" + echo.HeaderXCSRFToken,
+ ContextKey: "csrf",
+ CookieName: "_csrf",
+ CookieMaxAge: 86400,
+ CookieSameSite: http.SameSiteDefaultMode,
+ }
+)
+
+// 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
+ }
+ if config.CookieSameSite == http.SameSiteNoneMode {
+ config.CookieSecure = true
+ }
+
+ extractors, err := CreateExtractors(config.TokenLookup)
+ if err != nil {
+ panic(err)
+ }
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ if config.Skipper(c) {
+ return next(c)
+ }
+
+ token := ""
+ if k, err := c.Cookie(config.CookieName); err != nil {
+ token = random.String(config.TokenLength) // Generate token
+ } else {
+ token = k.Value // Reuse token
+ }
+
+ switch c.Request().Method {
+ case http.MethodGet, http.MethodHead, http.MethodOptions, http.MethodTrace:
+ default:
+ // Validate token only for requests which are not defined as 'safe' by RFC7231
+ var lastExtractorErr error
+ var lastTokenErr error
+ outer:
+ for _, extractor := range extractors {
+ clientTokens, err := extractor(c)
+ if err != nil {
+ lastExtractorErr = err
+ continue
+ }
+
+ for _, clientToken := range clientTokens {
+ if validateCSRFToken(token, clientToken) {
+ lastTokenErr = nil
+ lastExtractorErr = nil
+ break outer
+ }
+ lastTokenErr = ErrCSRFInvalid
+ }
+ }
+ var finalErr error
+ if lastTokenErr != nil {
+ finalErr = lastTokenErr
+ } else if lastExtractorErr != nil {
+ // ugly part to preserve backwards compatible errors. someone could rely on them
+ if lastExtractorErr == errQueryExtractorValueMissing {
+ lastExtractorErr = echo.NewHTTPError(http.StatusBadRequest, "missing csrf token in the query string")
+ } else if lastExtractorErr == errFormExtractorValueMissing {
+ lastExtractorErr = echo.NewHTTPError(http.StatusBadRequest, "missing csrf token in the form parameter")
+ } else if lastExtractorErr == errHeaderExtractorValueMissing {
+ lastExtractorErr = echo.NewHTTPError(http.StatusBadRequest, "missing csrf token in request header")
+ } else {
+ lastExtractorErr = echo.NewHTTPError(http.StatusBadRequest, lastExtractorErr.Error())
+ }
+ finalErr = lastExtractorErr
+ }
+
+ if finalErr != nil {
+ if config.ErrorHandler != nil {
+ return config.ErrorHandler(finalErr, c)
+ }
+ return finalErr
+ }
+ }
+
+ // 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
+ }
+ if config.CookieSameSite != http.SameSiteDefaultMode {
+ cookie.SameSite = config.CookieSameSite
+ }
+ 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)
+ }
+ }
+}
+
+func validateCSRFToken(token, clientToken string) bool {
+ return subtle.ConstantTimeCompare([]byte(token), []byte(clientToken)) == 1
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/decompress.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/decompress.go
new file mode 100644
index 0000000..88ec709
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/decompress.go
@@ -0,0 +1,99 @@
+package middleware
+
+import (
+ "compress/gzip"
+ "io"
+ "net/http"
+ "sync"
+
+ "github.com/labstack/echo/v4"
+)
+
+type (
+ // DecompressConfig defines the config for Decompress middleware.
+ DecompressConfig struct {
+ // Skipper defines a function to skip middleware.
+ Skipper Skipper
+
+ // GzipDecompressPool defines an interface to provide the sync.Pool used to create/store Gzip readers
+ GzipDecompressPool Decompressor
+ }
+)
+
+//GZIPEncoding content-encoding header if set to "gzip", decompress body contents.
+const GZIPEncoding string = "gzip"
+
+// Decompressor is used to get the sync.Pool used by the middleware to get Gzip readers
+type Decompressor interface {
+ gzipDecompressPool() sync.Pool
+}
+
+var (
+ //DefaultDecompressConfig defines the config for decompress middleware
+ DefaultDecompressConfig = DecompressConfig{
+ Skipper: DefaultSkipper,
+ GzipDecompressPool: &DefaultGzipDecompressPool{},
+ }
+)
+
+// DefaultGzipDecompressPool is the default implementation of Decompressor interface
+type DefaultGzipDecompressPool struct {
+}
+
+func (d *DefaultGzipDecompressPool) gzipDecompressPool() sync.Pool {
+ return sync.Pool{New: func() interface{} { return new(gzip.Reader) }}
+}
+
+//Decompress decompresses request body based if content encoding type is set to "gzip" with default config
+func Decompress() echo.MiddlewareFunc {
+ return DecompressWithConfig(DefaultDecompressConfig)
+}
+
+//DecompressWithConfig decompresses request body based if content encoding type is set to "gzip" with config
+func DecompressWithConfig(config DecompressConfig) echo.MiddlewareFunc {
+ // Defaults
+ if config.Skipper == nil {
+ config.Skipper = DefaultGzipConfig.Skipper
+ }
+ if config.GzipDecompressPool == nil {
+ config.GzipDecompressPool = DefaultDecompressConfig.GzipDecompressPool
+ }
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ pool := config.GzipDecompressPool.gzipDecompressPool()
+
+ return func(c echo.Context) error {
+ if config.Skipper(c) {
+ return next(c)
+ }
+
+ if c.Request().Header.Get(echo.HeaderContentEncoding) != GZIPEncoding {
+ return next(c)
+ }
+
+ i := pool.Get()
+ gr, ok := i.(*gzip.Reader)
+ if !ok || gr == nil {
+ return echo.NewHTTPError(http.StatusInternalServerError, i.(error).Error())
+ }
+ defer pool.Put(gr)
+
+ b := c.Request().Body
+ defer b.Close()
+
+ if err := gr.Reset(b); err != nil {
+ if err == io.EOF { //ignore if body is empty
+ return next(c)
+ }
+ return err
+ }
+
+ // only Close gzip reader if it was set to a proper gzip source otherwise it will panic on close.
+ defer gr.Close()
+
+ c.Request().Body = gr
+
+ return next(c)
+ }
+ }
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/extractor.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/extractor.go
new file mode 100644
index 0000000..5d9cee6
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/extractor.go
@@ -0,0 +1,204 @@
+package middleware
+
+import (
+ "errors"
+ "fmt"
+ "github.com/labstack/echo/v4"
+ "net/textproto"
+ "strings"
+)
+
+const (
+ // extractorLimit is arbitrary number to limit values extractor can return. this limits possible resource exhaustion
+ // attack vector
+ extractorLimit = 20
+)
+
+var errHeaderExtractorValueMissing = errors.New("missing value in request header")
+var errHeaderExtractorValueInvalid = errors.New("invalid value in request header")
+var errQueryExtractorValueMissing = errors.New("missing value in the query string")
+var errParamExtractorValueMissing = errors.New("missing value in path params")
+var errCookieExtractorValueMissing = errors.New("missing value in cookies")
+var errFormExtractorValueMissing = errors.New("missing value in the form")
+
+// ValuesExtractor defines a function for extracting values (keys/tokens) from the given context.
+type ValuesExtractor func(c echo.Context) ([]string, error)
+
+// CreateExtractors creates ValuesExtractors from given lookups.
+// Lookups is a string in the form of "<source>:<name>" or "<source>:<name>,<source>:<name>" that is used
+// to extract key from the request.
+// Possible values:
+// - "header:<name>" or "header:<name>:<cut-prefix>"
+// `<cut-prefix>` is argument value to cut/trim prefix of the extracted value. This is useful if header
+// value has static prefix like `Authorization: <auth-scheme> <authorisation-parameters>` where part that we
+// want to cut is `<auth-scheme> ` note the space at the end.
+// In case of basic authentication `Authorization: Basic <credentials>` prefix we want to remove is `Basic `.
+// - "query:<name>"
+// - "param:<name>"
+// - "form:<name>"
+// - "cookie:<name>"
+//
+// Multiple sources example:
+// - "header:Authorization,header:X-Api-Key"
+func CreateExtractors(lookups string) ([]ValuesExtractor, error) {
+ return createExtractors(lookups, "")
+}
+
+func createExtractors(lookups string, authScheme string) ([]ValuesExtractor, error) {
+ if lookups == "" {
+ return nil, nil
+ }
+ sources := strings.Split(lookups, ",")
+ var extractors = make([]ValuesExtractor, 0)
+ for _, source := range sources {
+ parts := strings.Split(source, ":")
+ if len(parts) < 2 {
+ return nil, fmt.Errorf("extractor source for lookup could not be split into needed parts: %v", source)
+ }
+
+ switch parts[0] {
+ case "query":
+ extractors = append(extractors, valuesFromQuery(parts[1]))
+ case "param":
+ extractors = append(extractors, valuesFromParam(parts[1]))
+ case "cookie":
+ extractors = append(extractors, valuesFromCookie(parts[1]))
+ case "form":
+ extractors = append(extractors, valuesFromForm(parts[1]))
+ case "header":
+ prefix := ""
+ if len(parts) > 2 {
+ prefix = parts[2]
+ } else if authScheme != "" && parts[1] == echo.HeaderAuthorization {
+ // backwards compatibility for JWT and KeyAuth:
+ // * we only apply this fix to Authorization as header we use and uses prefixes like "Bearer <token-value>" etc
+ // * previously header extractor assumed that auth-scheme/prefix had a space as suffix we need to retain that
+ // behaviour for default values and Authorization header.
+ prefix = authScheme
+ if !strings.HasSuffix(prefix, " ") {
+ prefix += " "
+ }
+ }
+ extractors = append(extractors, valuesFromHeader(parts[1], prefix))
+ }
+ }
+ return extractors, nil
+}
+
+// valuesFromHeader returns a functions that extracts values from the request header.
+// valuePrefix is parameter to remove first part (prefix) of the extracted value. This is useful if header value has static
+// prefix like `Authorization: <auth-scheme> <authorisation-parameters>` where part that we want to remove is `<auth-scheme> `
+// note the space at the end. In case of basic authentication `Authorization: Basic <credentials>` prefix we want to remove
+// is `Basic `. In case of JWT tokens `Authorization: Bearer <token>` prefix is `Bearer `.
+// If prefix is left empty the whole value is returned.
+func valuesFromHeader(header string, valuePrefix string) ValuesExtractor {
+ prefixLen := len(valuePrefix)
+ // standard library parses http.Request header keys in canonical form but we may provide something else so fix this
+ header = textproto.CanonicalMIMEHeaderKey(header)
+ return func(c echo.Context) ([]string, error) {
+ values := c.Request().Header.Values(header)
+ if len(values) == 0 {
+ return nil, errHeaderExtractorValueMissing
+ }
+
+ result := make([]string, 0)
+ for i, value := range values {
+ if prefixLen == 0 {
+ result = append(result, value)
+ if i >= extractorLimit-1 {
+ break
+ }
+ continue
+ }
+ if len(value) > prefixLen && strings.EqualFold(value[:prefixLen], valuePrefix) {
+ result = append(result, value[prefixLen:])
+ if i >= extractorLimit-1 {
+ break
+ }
+ }
+ }
+
+ if len(result) == 0 {
+ if prefixLen > 0 {
+ return nil, errHeaderExtractorValueInvalid
+ }
+ return nil, errHeaderExtractorValueMissing
+ }
+ return result, nil
+ }
+}
+
+// valuesFromQuery returns a function that extracts values from the query string.
+func valuesFromQuery(param string) ValuesExtractor {
+ return func(c echo.Context) ([]string, error) {
+ result := c.QueryParams()[param]
+ if len(result) == 0 {
+ return nil, errQueryExtractorValueMissing
+ } else if len(result) > extractorLimit-1 {
+ result = result[:extractorLimit]
+ }
+ return result, nil
+ }
+}
+
+// valuesFromParam returns a function that extracts values from the url param string.
+func valuesFromParam(param string) ValuesExtractor {
+ return func(c echo.Context) ([]string, error) {
+ result := make([]string, 0)
+ paramVales := c.ParamValues()
+ for i, p := range c.ParamNames() {
+ if param == p {
+ result = append(result, paramVales[i])
+ if i >= extractorLimit-1 {
+ break
+ }
+ }
+ }
+ if len(result) == 0 {
+ return nil, errParamExtractorValueMissing
+ }
+ return result, nil
+ }
+}
+
+// valuesFromCookie returns a function that extracts values from the named cookie.
+func valuesFromCookie(name string) ValuesExtractor {
+ return func(c echo.Context) ([]string, error) {
+ cookies := c.Cookies()
+ if len(cookies) == 0 {
+ return nil, errCookieExtractorValueMissing
+ }
+
+ result := make([]string, 0)
+ for i, cookie := range cookies {
+ if name == cookie.Name {
+ result = append(result, cookie.Value)
+ if i >= extractorLimit-1 {
+ break
+ }
+ }
+ }
+ if len(result) == 0 {
+ return nil, errCookieExtractorValueMissing
+ }
+ return result, nil
+ }
+}
+
+// valuesFromForm returns a function that extracts values from the form field.
+func valuesFromForm(name string) ValuesExtractor {
+ return func(c echo.Context) ([]string, error) {
+ if c.Request().Form == nil {
+ _ = c.Request().ParseMultipartForm(32 << 20) // same what `c.Request().FormValue(name)` does
+ }
+ values := c.Request().Form[name]
+ if len(values) == 0 {
+ return nil, errFormExtractorValueMissing
+ }
+ if len(values) > extractorLimit-1 {
+ values = values[:extractorLimit]
+ }
+ result := append([]string{}, values...)
+ return result, nil
+ }
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/jwt.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/jwt.go
new file mode 100644
index 0000000..bd62826
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/jwt.go
@@ -0,0 +1,304 @@
+//go:build go1.15
+// +build go1.15
+
+package middleware
+
+import (
+ "errors"
+ "fmt"
+ "github.com/golang-jwt/jwt"
+ "github.com/labstack/echo/v4"
+ "net/http"
+ "reflect"
+)
+
+type (
+ // JWTConfig defines the config for JWT middleware.
+ JWTConfig struct {
+ // Skipper defines a function to skip middleware.
+ Skipper Skipper
+
+ // BeforeFunc defines a function which is executed just before the middleware.
+ BeforeFunc BeforeFunc
+
+ // SuccessHandler defines a function which is executed for a valid token before middleware chain continues with next
+ // middleware or handler.
+ SuccessHandler JWTSuccessHandler
+
+ // ErrorHandler defines a function which is executed for an invalid token.
+ // It may be used to define a custom JWT error.
+ ErrorHandler JWTErrorHandler
+
+ // ErrorHandlerWithContext is almost identical to ErrorHandler, but it's passed the current context.
+ ErrorHandlerWithContext JWTErrorHandlerWithContext
+
+ // ContinueOnIgnoredError allows the next middleware/handler to be called when ErrorHandlerWithContext decides to
+ // ignore the error (by returning `nil`).
+ // This is useful when parts of your site/api allow public access and some authorized routes provide extra functionality.
+ // In that case you can use ErrorHandlerWithContext to set a default public JWT token value in the request context
+ // and continue. Some logic down the remaining execution chain needs to check that (public) token value then.
+ ContinueOnIgnoredError bool
+
+ // Signing key to validate token.
+ // This is one of the three options to provide a token validation key.
+ // The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey.
+ // Required if neither user-defined KeyFunc nor SigningKeys is provided.
+ SigningKey interface{}
+
+ // Map of signing keys to validate token with kid field usage.
+ // This is one of the three options to provide a token validation key.
+ // The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey.
+ // Required if neither user-defined KeyFunc nor SigningKey is provided.
+ SigningKeys map[string]interface{}
+
+ // Signing method used to check the token's signing algorithm.
+ // 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. Used by default ParseTokenFunc implementation.
+ // Not used if custom ParseTokenFunc is set.
+ // Optional. Default value jwt.MapClaims
+ Claims jwt.Claims
+
+ // TokenLookup is a string in the form of "<source>:<name>" or "<source>:<name>,<source>:<name>" that is used
+ // to extract token from the request.
+ // Optional. Default value "header:Authorization".
+ // Possible values:
+ // - "header:<name>" or "header:<name>:<cut-prefix>"
+ // `<cut-prefix>` is argument value to cut/trim prefix of the extracted value. This is useful if header
+ // value has static prefix like `Authorization: <auth-scheme> <authorisation-parameters>` where part that we
+ // want to cut is `<auth-scheme> ` note the space at the end.
+ // In case of JWT tokens `Authorization: Bearer <token>` prefix we cut is `Bearer `.
+ // If prefix is left empty the whole value is returned.
+ // - "query:<name>"
+ // - "param:<name>"
+ // - "cookie:<name>"
+ // - "form:<name>"
+ // Multiple sources example:
+ // - "header:Authorization,cookie:myowncookie"
+ TokenLookup string
+
+ // TokenLookupFuncs defines a list of user-defined functions that extract JWT token from the given context.
+ // This is one of the two options to provide a token extractor.
+ // The order of precedence is user-defined TokenLookupFuncs, and TokenLookup.
+ // You can also provide both if you want.
+ TokenLookupFuncs []ValuesExtractor
+
+ // AuthScheme to be used in the Authorization header.
+ // Optional. Default value "Bearer".
+ AuthScheme string
+
+ // KeyFunc defines a user-defined function that supplies the public key for a token validation.
+ // The function shall take care of verifying the signing algorithm and selecting the proper key.
+ // A user-defined KeyFunc can be useful if tokens are issued by an external party.
+ // Used by default ParseTokenFunc implementation.
+ //
+ // When a user-defined KeyFunc is provided, SigningKey, SigningKeys, and SigningMethod are ignored.
+ // This is one of the three options to provide a token validation key.
+ // The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey.
+ // Required if neither SigningKeys nor SigningKey is provided.
+ // Not used if custom ParseTokenFunc is set.
+ // Default to an internal implementation verifying the signing algorithm and selecting the proper key.
+ KeyFunc jwt.Keyfunc
+
+ // ParseTokenFunc defines a user-defined function that parses token from given auth. Returns an error when token
+ // parsing fails or parsed token is invalid.
+ // Defaults to implementation using `github.com/golang-jwt/jwt` as JWT implementation library
+ ParseTokenFunc func(auth string, c echo.Context) (interface{}, error)
+ }
+
+ // JWTSuccessHandler defines a function which is executed for a valid token.
+ JWTSuccessHandler func(c echo.Context)
+
+ // JWTErrorHandler defines a function which is executed for an invalid token.
+ JWTErrorHandler func(err error) error
+
+ // JWTErrorHandlerWithContext is almost identical to JWTErrorHandler, but it's passed the current context.
+ JWTErrorHandlerWithContext func(err error, c echo.Context) error
+)
+
+// Algorithms
+const (
+ AlgorithmHS256 = "HS256"
+)
+
+// Errors
+var (
+ ErrJWTMissing = echo.NewHTTPError(http.StatusBadRequest, "missing or malformed jwt")
+ ErrJWTInvalid = echo.NewHTTPError(http.StatusUnauthorized, "invalid or expired jwt")
+)
+
+var (
+ // DefaultJWTConfig is the default JWT auth middleware config.
+ DefaultJWTConfig = JWTConfig{
+ Skipper: DefaultSkipper,
+ SigningMethod: AlgorithmHS256,
+ ContextKey: "user",
+ TokenLookup: "header:" + echo.HeaderAuthorization,
+ TokenLookupFuncs: nil,
+ AuthScheme: "Bearer",
+ Claims: jwt.MapClaims{},
+ KeyFunc: nil,
+ }
+)
+
+// 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`
+//
+// Deprecated: Please use https://github.com/labstack/echo-jwt instead
+func JWT(key interface{}) echo.MiddlewareFunc {
+ c := DefaultJWTConfig
+ c.SigningKey = key
+ return JWTWithConfig(c)
+}
+
+// JWTWithConfig returns a JWT auth middleware with config.
+// See: `JWT()`.
+//
+// Deprecated: Please use https://github.com/labstack/echo-jwt instead
+func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
+ // Defaults
+ if config.Skipper == nil {
+ config.Skipper = DefaultJWTConfig.Skipper
+ }
+ if config.SigningKey == nil && len(config.SigningKeys) == 0 && config.KeyFunc == nil && config.ParseTokenFunc == nil {
+ panic("echo: 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 == "" && len(config.TokenLookupFuncs) == 0 {
+ config.TokenLookup = DefaultJWTConfig.TokenLookup
+ }
+ if config.AuthScheme == "" {
+ config.AuthScheme = DefaultJWTConfig.AuthScheme
+ }
+ if config.KeyFunc == nil {
+ config.KeyFunc = config.defaultKeyFunc
+ }
+ if config.ParseTokenFunc == nil {
+ config.ParseTokenFunc = config.defaultParseToken
+ }
+
+ extractors, err := createExtractors(config.TokenLookup, config.AuthScheme)
+ if err != nil {
+ panic(err)
+ }
+ if len(config.TokenLookupFuncs) > 0 {
+ extractors = append(config.TokenLookupFuncs, extractors...)
+ }
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ if config.Skipper(c) {
+ return next(c)
+ }
+
+ if config.BeforeFunc != nil {
+ config.BeforeFunc(c)
+ }
+
+ var lastExtractorErr error
+ var lastTokenErr error
+ for _, extractor := range extractors {
+ auths, err := extractor(c)
+ if err != nil {
+ lastExtractorErr = ErrJWTMissing // backwards compatibility: all extraction errors are same (unlike KeyAuth)
+ continue
+ }
+ for _, auth := range auths {
+ token, err := config.ParseTokenFunc(auth, c)
+ if err != nil {
+ lastTokenErr = err
+ continue
+ }
+ // Store user information from token into context.
+ c.Set(config.ContextKey, token)
+ if config.SuccessHandler != nil {
+ config.SuccessHandler(c)
+ }
+ return next(c)
+ }
+ }
+ // we are here only when we did not successfully extract or parse any of the tokens
+ err := lastTokenErr
+ if err == nil { // prioritize token errors over extracting errors
+ err = lastExtractorErr
+ }
+ if config.ErrorHandler != nil {
+ return config.ErrorHandler(err)
+ }
+ if config.ErrorHandlerWithContext != nil {
+ tmpErr := config.ErrorHandlerWithContext(err, c)
+ if config.ContinueOnIgnoredError && tmpErr == nil {
+ return next(c)
+ }
+ return tmpErr
+ }
+
+ // backwards compatible errors codes
+ if lastTokenErr != nil {
+ return &echo.HTTPError{
+ Code: ErrJWTInvalid.Code,
+ Message: ErrJWTInvalid.Message,
+ Internal: err,
+ }
+ }
+ return err // this is lastExtractorErr value
+ }
+ }
+}
+
+func (config *JWTConfig) defaultParseToken(auth string, c echo.Context) (interface{}, error) {
+ var token *jwt.Token
+ var err error
+ // Issue #647, #656
+ if _, ok := config.Claims.(jwt.MapClaims); ok {
+ token, err = jwt.Parse(auth, config.KeyFunc)
+ } else {
+ t := reflect.ValueOf(config.Claims).Type().Elem()
+ claims := reflect.New(t).Interface().(jwt.Claims)
+ token, err = jwt.ParseWithClaims(auth, claims, config.KeyFunc)
+ }
+ if err != nil {
+ return nil, err
+ }
+ if !token.Valid {
+ return nil, errors.New("invalid token")
+ }
+ return token, nil
+}
+
+// defaultKeyFunc returns a signing key of the given token.
+func (config *JWTConfig) defaultKeyFunc(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"])
+ }
+ if len(config.SigningKeys) > 0 {
+ if kid, ok := t.Header["kid"].(string); ok {
+ if key, ok := config.SigningKeys[kid]; ok {
+ return key, nil
+ }
+ }
+ return nil, fmt.Errorf("unexpected jwt key id=%v", t.Header["kid"])
+ }
+
+ return config.SigningKey, nil
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/key_auth.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/key_auth.go
new file mode 100644
index 0000000..e8a6b08
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/key_auth.go
@@ -0,0 +1,180 @@
+package middleware
+
+import (
+ "errors"
+ "github.com/labstack/echo/v4"
+ "net/http"
+)
+
+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>" or "<source>:<name>,<source>:<name>" that is used
+ // to extract key from the request.
+ // Optional. Default value "header:Authorization".
+ // Possible values:
+ // - "header:<name>" or "header:<name>:<cut-prefix>"
+ // `<cut-prefix>` is argument value to cut/trim prefix of the extracted value. This is useful if header
+ // value has static prefix like `Authorization: <auth-scheme> <authorisation-parameters>` where part that we
+ // want to cut is `<auth-scheme> ` note the space at the end.
+ // In case of basic authentication `Authorization: Basic <credentials>` prefix we want to remove is `Basic `.
+ // - "query:<name>"
+ // - "form:<name>"
+ // - "cookie:<name>"
+ // Multiple sources example:
+ // - "header:Authorization,header:X-Api-Key"
+ KeyLookup string
+
+ // AuthScheme to be used in the Authorization header.
+ // Optional. Default value "Bearer".
+ AuthScheme string
+
+ // Validator is a function to validate key.
+ // Required.
+ Validator KeyAuthValidator
+
+ // ErrorHandler defines a function which is executed for an invalid key.
+ // It may be used to define a custom error.
+ ErrorHandler KeyAuthErrorHandler
+
+ // ContinueOnIgnoredError allows the next middleware/handler to be called when ErrorHandler decides to
+ // ignore the error (by returning `nil`).
+ // This is useful when parts of your site/api allow public access and some authorized routes provide extra functionality.
+ // In that case you can use ErrorHandler to set a default public key auth value in the request context
+ // and continue. Some logic down the remaining execution chain needs to check that (public) key auth value then.
+ ContinueOnIgnoredError bool
+ }
+
+ // KeyAuthValidator defines a function to validate KeyAuth credentials.
+ KeyAuthValidator func(auth string, c echo.Context) (bool, error)
+
+ // KeyAuthErrorHandler defines a function which is executed for an invalid key.
+ KeyAuthErrorHandler func(err error, c echo.Context) error
+)
+
+var (
+ // DefaultKeyAuthConfig is the default KeyAuth middleware config.
+ DefaultKeyAuthConfig = KeyAuthConfig{
+ Skipper: DefaultSkipper,
+ KeyLookup: "header:" + echo.HeaderAuthorization,
+ AuthScheme: "Bearer",
+ }
+)
+
+// ErrKeyAuthMissing is error type when KeyAuth middleware is unable to extract value from lookups
+type ErrKeyAuthMissing struct {
+ Err error
+}
+
+// Error returns errors text
+func (e *ErrKeyAuthMissing) Error() string {
+ return e.Err.Error()
+}
+
+// Unwrap unwraps error
+func (e *ErrKeyAuthMissing) Unwrap() error {
+ return e.Err
+}
+
+// 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("echo: key-auth middleware requires a validator function")
+ }
+
+ extractors, err := createExtractors(config.KeyLookup, config.AuthScheme)
+ if err != nil {
+ panic(err)
+ }
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ if config.Skipper(c) {
+ return next(c)
+ }
+
+ var lastExtractorErr error
+ var lastValidatorErr error
+ for _, extractor := range extractors {
+ keys, err := extractor(c)
+ if err != nil {
+ lastExtractorErr = err
+ continue
+ }
+ for _, key := range keys {
+ valid, err := config.Validator(key, c)
+ if err != nil {
+ lastValidatorErr = err
+ continue
+ }
+ if valid {
+ return next(c)
+ }
+ lastValidatorErr = errors.New("invalid key")
+ }
+ }
+
+ // we are here only when we did not successfully extract and validate any of keys
+ err := lastValidatorErr
+ if err == nil { // prioritize validator errors over extracting errors
+ // ugly part to preserve backwards compatible errors. someone could rely on them
+ if lastExtractorErr == errQueryExtractorValueMissing {
+ err = errors.New("missing key in the query string")
+ } else if lastExtractorErr == errCookieExtractorValueMissing {
+ err = errors.New("missing key in cookies")
+ } else if lastExtractorErr == errFormExtractorValueMissing {
+ err = errors.New("missing key in the form")
+ } else if lastExtractorErr == errHeaderExtractorValueMissing {
+ err = errors.New("missing key in request header")
+ } else if lastExtractorErr == errHeaderExtractorValueInvalid {
+ err = errors.New("invalid key in the request header")
+ } else {
+ err = lastExtractorErr
+ }
+ err = &ErrKeyAuthMissing{Err: err}
+ }
+
+ if config.ErrorHandler != nil {
+ tmpErr := config.ErrorHandler(err, c)
+ if config.ContinueOnIgnoredError && tmpErr == nil {
+ return next(c)
+ }
+ return tmpErr
+ }
+ if lastValidatorErr != nil { // prioritize validator errors over extracting errors
+ return &echo.HTTPError{
+ Code: http.StatusUnauthorized,
+ Message: "Unauthorized",
+ Internal: lastValidatorErr,
+ }
+ }
+ return echo.NewHTTPError(http.StatusBadRequest, err.Error())
+ }
+ }
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/logger.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/logger.go
new file mode 100644
index 0000000..7958d87
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/logger.go
@@ -0,0 +1,245 @@
+package middleware
+
+import (
+ "bytes"
+ "encoding/json"
+ "io"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/labstack/echo/v4"
+ "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 construct the logger format.
+ //
+ // - time_unix
+ // - time_unix_milli
+ // - time_unix_micro
+ // - time_unix_nano
+ // - time_rfc3339
+ // - time_rfc3339_nano
+ // - time_custom
+ // - id (Request ID)
+ // - remote_ip
+ // - uri
+ // - host
+ // - method
+ // - path
+ // - route
+ // - protocol
+ // - referer
+ // - user_agent
+ // - status
+ // - error
+ // - latency (In nanoseconds)
+ // - latency_human (Human readable)
+ // - bytes_in (Bytes received)
+ // - bytes_out (Bytes sent)
+ // - header:<NAME>
+ // - query:<NAME>
+ // - form:<NAME>
+ // - custom (see CustomTagFunc field)
+ //
+ // Example "${remote_ip} ${status}"
+ //
+ // Optional. Default value DefaultLoggerConfig.Format.
+ Format string `yaml:"format"`
+
+ // Optional. Default value DefaultLoggerConfig.CustomTimeFormat.
+ CustomTimeFormat string `yaml:"custom_time_format"`
+
+ // CustomTagFunc is function called for `${custom}` tag to output user implemented text by writing it to buf.
+ // Make sure that outputted text creates valid JSON string with other logged tags.
+ // Optional.
+ CustomTagFunc func(c echo.Context, buf *bytes.Buffer) (int, error)
+
+ // 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}","id":"${id}","remote_ip":"${remote_ip}",` +
+ `"host":"${host}","method":"${method}","uri":"${uri}","user_agent":"${user_agent}",` +
+ `"status":${status},"error":"${error}","latency":${latency},"latency_human":"${latency_human}"` +
+ `,"bytes_in":${bytes_in},"bytes_out":${bytes_out}}` + "\n",
+ CustomTimeFormat: "2006-01-02 15:04:05.00000",
+ 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 "custom":
+ if config.CustomTagFunc == nil {
+ return 0, nil
+ }
+ return config.CustomTagFunc(c, buf)
+ case "time_unix":
+ return buf.WriteString(strconv.FormatInt(time.Now().Unix(), 10))
+ case "time_unix_milli":
+ // go 1.17 or later, it supports time#UnixMilli()
+ return buf.WriteString(strconv.FormatInt(time.Now().UnixNano()/1000000, 10))
+ case "time_unix_micro":
+ // go 1.17 or later, it supports time#UnixMicro()
+ return buf.WriteString(strconv.FormatInt(time.Now().UnixNano()/1000, 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 "time_custom":
+ return buf.WriteString(time.Now().Format(config.CustomTimeFormat))
+ case "id":
+ id := req.Header.Get(echo.HeaderXRequestID)
+ if id == "" {
+ id = res.Header().Get(echo.HeaderXRequestID)
+ }
+ return buf.WriteString(id)
+ 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 "route":
+ return buf.WriteString(c.Path())
+ case "protocol":
+ return buf.WriteString(req.Proto)
+ 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 "error":
+ if err != nil {
+ // Error may contain invalid JSON e.g. `"`
+ b, _ := json.Marshal(err.Error())
+ b = b[1 : len(b)-1]
+ return buf.Write(b)
+ }
+ 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:])))
+ case strings.HasPrefix(tag, "cookie:"):
+ cookie, err := c.Cookie(tag[7:])
+ if err == nil {
+ return buf.Write([]byte(cookie.Value))
+ }
+ }
+ }
+ return 0, nil
+ }); err != nil {
+ return
+ }
+
+ if config.Output == nil {
+ _, err = c.Logger().Output().Write(buf.Bytes())
+ return
+ }
+ _, err = config.Output.Write(buf.Bytes())
+ return
+ }
+ }
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/method_override.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/method_override.go
new file mode 100644
index 0000000..92b14d2
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/method_override.go
@@ -0,0 +1,92 @@
+package middleware
+
+import (
+ "net/http"
+
+ "github.com/labstack/echo/v4"
+)
+
+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 == http.MethodPost {
+ 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/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/middleware.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/middleware.go
new file mode 100644
index 0000000..f250ca4
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/middleware.go
@@ -0,0 +1,89 @@
+package middleware
+
+import (
+ "net/http"
+ "regexp"
+ "strconv"
+ "strings"
+
+ "github.com/labstack/echo/v4"
+)
+
+type (
+ // Skipper defines a function to skip middleware. Returning true skips processing
+ // the middleware.
+ Skipper func(c echo.Context) bool
+
+ // BeforeFunc defines a function which is executed just before the middleware.
+ BeforeFunc func(c echo.Context)
+)
+
+func captureTokens(pattern *regexp.Regexp, input string) *strings.Replacer {
+ groups := pattern.FindAllStringSubmatch(input, -1)
+ if groups == nil {
+ return nil
+ }
+ values := groups[0][1:]
+ replace := make([]string, 2*len(values))
+ for i, v := range values {
+ j := 2 * i
+ replace[j] = "$" + strconv.Itoa(i+1)
+ replace[j+1] = v
+ }
+ return strings.NewReplacer(replace...)
+}
+
+func rewriteRulesRegex(rewrite map[string]string) map[*regexp.Regexp]string {
+ // Initialize
+ rulesRegex := map[*regexp.Regexp]string{}
+ for k, v := range rewrite {
+ k = regexp.QuoteMeta(k)
+ k = strings.Replace(k, `\*`, "(.*?)", -1)
+ if strings.HasPrefix(k, `\^`) {
+ k = strings.Replace(k, `\^`, "^", -1)
+ }
+ k = k + "$"
+ rulesRegex[regexp.MustCompile(k)] = v
+ }
+ return rulesRegex
+}
+
+func rewriteURL(rewriteRegex map[*regexp.Regexp]string, req *http.Request) error {
+ if len(rewriteRegex) == 0 {
+ return nil
+ }
+
+ // Depending how HTTP request is sent RequestURI could contain Scheme://Host/path or be just /path.
+ // We only want to use path part for rewriting and therefore trim prefix if it exists
+ rawURI := req.RequestURI
+ if rawURI != "" && rawURI[0] != '/' {
+ prefix := ""
+ if req.URL.Scheme != "" {
+ prefix = req.URL.Scheme + "://"
+ }
+ if req.URL.Host != "" {
+ prefix += req.URL.Host // host or host:port
+ }
+ if prefix != "" {
+ rawURI = strings.TrimPrefix(rawURI, prefix)
+ }
+ }
+
+ for k, v := range rewriteRegex {
+ if replacer := captureTokens(k, rawURI); replacer != nil {
+ url, err := req.URL.Parse(replacer.Replace(v))
+ if err != nil {
+ return err
+ }
+ req.URL = url
+
+ return nil // rewrite only once
+ }
+ }
+ return nil
+}
+
+// DefaultSkipper returns false which processes the middleware.
+func DefaultSkipper(echo.Context) bool {
+ return false
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/proxy.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/proxy.go
new file mode 100644
index 0000000..d2cd2aa
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/proxy.go
@@ -0,0 +1,318 @@
+package middleware
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "math/rand"
+ "net"
+ "net/http"
+ "net/http/httputil"
+ "net/url"
+ "regexp"
+ "strings"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "github.com/labstack/echo/v4"
+)
+
+// TODO: Handle TLS proxy
+
+type (
+ // ProxyConfig defines the config for Proxy middleware.
+ ProxyConfig struct {
+ // Skipper defines a function to skip middleware.
+ Skipper Skipper
+
+ // Balancer defines a load balancing technique.
+ // Required.
+ Balancer ProxyBalancer
+
+ // Rewrite defines URL path rewrite rules. The values captured in asterisk can be
+ // retrieved by index e.g. $1, $2 and so on.
+ // Examples:
+ // "/old": "/new",
+ // "/api/*": "/$1",
+ // "/js/*": "/public/javascripts/$1",
+ // "/users/*/orders/*": "/user/$1/order/$2",
+ Rewrite map[string]string
+
+ // RegexRewrite defines rewrite rules using regexp.Rexexp with captures
+ // Every capture group in the values can be retrieved by index e.g. $1, $2 and so on.
+ // Example:
+ // "^/old/[0.9]+/": "/new",
+ // "^/api/.+?/(.*)": "/v2/$1",
+ RegexRewrite map[*regexp.Regexp]string
+
+ // Context key to store selected ProxyTarget into context.
+ // Optional. Default value "target".
+ ContextKey string
+
+ // To customize the transport to remote.
+ // Examples: If custom TLS certificates are required.
+ Transport http.RoundTripper
+
+ // ModifyResponse defines function to modify response from ProxyTarget.
+ ModifyResponse func(*http.Response) error
+ }
+
+ // ProxyTarget defines the upstream target.
+ ProxyTarget struct {
+ Name string
+ URL *url.URL
+ Meta echo.Map
+ }
+
+ // ProxyBalancer defines an interface to implement a load balancing technique.
+ ProxyBalancer interface {
+ AddTarget(*ProxyTarget) bool
+ RemoveTarget(string) bool
+ Next(echo.Context) *ProxyTarget
+ }
+
+ // TargetProvider defines an interface that gives the opportunity for balancer to return custom errors when selecting target.
+ TargetProvider interface {
+ NextTarget(echo.Context) (*ProxyTarget, error)
+ }
+
+ commonBalancer struct {
+ targets []*ProxyTarget
+ mutex sync.RWMutex
+ }
+
+ // RandomBalancer implements a random load balancing technique.
+ randomBalancer struct {
+ *commonBalancer
+ random *rand.Rand
+ }
+
+ // RoundRobinBalancer implements a round-robin load balancing technique.
+ roundRobinBalancer struct {
+ *commonBalancer
+ i uint32
+ }
+)
+
+var (
+ // DefaultProxyConfig is the default Proxy middleware config.
+ DefaultProxyConfig = ProxyConfig{
+ Skipper: DefaultSkipper,
+ ContextKey: "target",
+ }
+)
+
+func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ in, _, err := c.Response().Hijack()
+ if err != nil {
+ c.Set("_error", fmt.Sprintf("proxy raw, hijack error=%v, url=%s", t.URL, err))
+ return
+ }
+ defer in.Close()
+
+ out, err := net.Dial("tcp", t.URL.Host)
+ if err != nil {
+ c.Set("_error", echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, dial error=%v, url=%s", t.URL, err)))
+ return
+ }
+ defer out.Close()
+
+ // Write header
+ err = r.Write(out)
+ if err != nil {
+ c.Set("_error", echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, request header copy error=%v, url=%s", t.URL, err)))
+ return
+ }
+
+ errCh := make(chan error, 2)
+ cp := func(dst io.Writer, src io.Reader) {
+ _, err = io.Copy(dst, src)
+ errCh <- err
+ }
+
+ go cp(out, in)
+ go cp(in, out)
+ err = <-errCh
+ if err != nil && err != io.EOF {
+ c.Set("_error", fmt.Errorf("proxy raw, copy body error=%v, url=%s", t.URL, err))
+ }
+ })
+}
+
+// NewRandomBalancer returns a random proxy balancer.
+func NewRandomBalancer(targets []*ProxyTarget) ProxyBalancer {
+ b := &randomBalancer{commonBalancer: new(commonBalancer)}
+ b.targets = targets
+ return b
+}
+
+// NewRoundRobinBalancer returns a round-robin proxy balancer.
+func NewRoundRobinBalancer(targets []*ProxyTarget) ProxyBalancer {
+ b := &roundRobinBalancer{commonBalancer: new(commonBalancer)}
+ b.targets = targets
+ return b
+}
+
+// AddTarget adds an upstream target to the list.
+func (b *commonBalancer) AddTarget(target *ProxyTarget) bool {
+ for _, t := range b.targets {
+ if t.Name == target.Name {
+ return false
+ }
+ }
+ b.mutex.Lock()
+ defer b.mutex.Unlock()
+ b.targets = append(b.targets, target)
+ return true
+}
+
+// RemoveTarget removes an upstream target from the list.
+func (b *commonBalancer) RemoveTarget(name string) bool {
+ b.mutex.Lock()
+ defer b.mutex.Unlock()
+ for i, t := range b.targets {
+ if t.Name == name {
+ b.targets = append(b.targets[:i], b.targets[i+1:]...)
+ return true
+ }
+ }
+ return false
+}
+
+// Next randomly returns an upstream target.
+func (b *randomBalancer) Next(c echo.Context) *ProxyTarget {
+ if b.random == nil {
+ b.random = rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
+ }
+ b.mutex.RLock()
+ defer b.mutex.RUnlock()
+ return b.targets[b.random.Intn(len(b.targets))]
+}
+
+// Next returns an upstream target using round-robin technique.
+func (b *roundRobinBalancer) Next(c echo.Context) *ProxyTarget {
+ b.i = b.i % uint32(len(b.targets))
+ t := b.targets[b.i]
+ atomic.AddUint32(&b.i, 1)
+ return t
+}
+
+// Proxy returns a Proxy middleware.
+//
+// Proxy middleware forwards the request to upstream server using a configured load balancing technique.
+func Proxy(balancer ProxyBalancer) echo.MiddlewareFunc {
+ c := DefaultProxyConfig
+ c.Balancer = balancer
+ return ProxyWithConfig(c)
+}
+
+// ProxyWithConfig returns a Proxy middleware with config.
+// See: `Proxy()`
+func ProxyWithConfig(config ProxyConfig) echo.MiddlewareFunc {
+ // Defaults
+ if config.Skipper == nil {
+ config.Skipper = DefaultProxyConfig.Skipper
+ }
+ if config.Balancer == nil {
+ panic("echo: proxy middleware requires balancer")
+ }
+
+ if config.Rewrite != nil {
+ if config.RegexRewrite == nil {
+ config.RegexRewrite = make(map[*regexp.Regexp]string)
+ }
+ for k, v := range rewriteRulesRegex(config.Rewrite) {
+ config.RegexRewrite[k] = v
+ }
+ }
+
+ provider, isTargetProvider := config.Balancer.(TargetProvider)
+ 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()
+
+ var tgt *ProxyTarget
+ if isTargetProvider {
+ tgt, err = provider.NextTarget(c)
+ if err != nil {
+ return err
+ }
+ } else {
+ tgt = config.Balancer.Next(c)
+ }
+ c.Set(config.ContextKey, tgt)
+
+ if err := rewriteURL(config.RegexRewrite, req); err != nil {
+ return err
+ }
+
+ // Fix header
+ // Basically it's not good practice to unconditionally pass incoming x-real-ip header to upstream.
+ // However, for backward compatibility, legacy behavior is preserved unless you configure Echo#IPExtractor.
+ if req.Header.Get(echo.HeaderXRealIP) == "" || c.Echo().IPExtractor != nil {
+ req.Header.Set(echo.HeaderXRealIP, c.RealIP())
+ }
+ if req.Header.Get(echo.HeaderXForwardedProto) == "" {
+ req.Header.Set(echo.HeaderXForwardedProto, c.Scheme())
+ }
+ if c.IsWebSocket() && req.Header.Get(echo.HeaderXForwardedFor) == "" { // For HTTP, it is automatically set by Go HTTP reverse proxy.
+ req.Header.Set(echo.HeaderXForwardedFor, c.RealIP())
+ }
+
+ // Proxy
+ switch {
+ case c.IsWebSocket():
+ proxyRaw(tgt, c).ServeHTTP(res, req)
+ case req.Header.Get(echo.HeaderAccept) == "text/event-stream":
+ default:
+ proxyHTTP(tgt, c, config).ServeHTTP(res, req)
+ }
+ if e, ok := c.Get("_error").(error); ok {
+ err = e
+ }
+
+ return
+ }
+ }
+}
+
+// StatusCodeContextCanceled is a custom HTTP status code for situations
+// where a client unexpectedly closed the connection to the server.
+// As there is no standard error code for "client closed connection", but
+// various well-known HTTP clients and server implement this HTTP code we use
+// 499 too instead of the more problematic 5xx, which does not allow to detect this situation
+const StatusCodeContextCanceled = 499
+
+func proxyHTTP(tgt *ProxyTarget, c echo.Context, config ProxyConfig) http.Handler {
+ proxy := httputil.NewSingleHostReverseProxy(tgt.URL)
+ proxy.ErrorHandler = func(resp http.ResponseWriter, req *http.Request, err error) {
+ desc := tgt.URL.String()
+ if tgt.Name != "" {
+ desc = fmt.Sprintf("%s(%s)", tgt.Name, tgt.URL.String())
+ }
+ // If the client canceled the request (usually by closing the connection), we can report a
+ // client error (4xx) instead of a server error (5xx) to correctly identify the situation.
+ // The Go standard library (at of late 2020) wraps the exported, standard
+ // context.Canceled error with unexported garbage value requiring a substring check, see
+ // https://github.com/golang/go/blob/6965b01ea248cabb70c3749fd218b36089a21efb/src/net/net.go#L416-L430
+ if err == context.Canceled || strings.Contains(err.Error(), "operation was canceled") {
+ httpError := echo.NewHTTPError(StatusCodeContextCanceled, fmt.Sprintf("client closed connection: %v", err))
+ httpError.Internal = err
+ c.Set("_error", httpError)
+ } else {
+ httpError := echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("remote %s unreachable, could not forward: %v", desc, err))
+ httpError.Internal = err
+ c.Set("_error", httpError)
+ }
+ }
+ proxy.Transport = config.Transport
+ proxy.ModifyResponse = config.ModifyResponse
+ return proxy
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/rate_limiter.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/rate_limiter.go
new file mode 100644
index 0000000..f7fae83
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/rate_limiter.go
@@ -0,0 +1,271 @@
+package middleware
+
+import (
+ "net/http"
+ "sync"
+ "time"
+
+ "github.com/labstack/echo/v4"
+ "golang.org/x/time/rate"
+)
+
+type (
+ // RateLimiterStore is the interface to be implemented by custom stores.
+ RateLimiterStore interface {
+ // Stores for the rate limiter have to implement the Allow method
+ Allow(identifier string) (bool, error)
+ }
+)
+
+type (
+ // RateLimiterConfig defines the configuration for the rate limiter
+ RateLimiterConfig struct {
+ Skipper Skipper
+ BeforeFunc BeforeFunc
+ // IdentifierExtractor uses echo.Context to extract the identifier for a visitor
+ IdentifierExtractor Extractor
+ // Store defines a store for the rate limiter
+ Store RateLimiterStore
+ // ErrorHandler provides a handler to be called when IdentifierExtractor returns an error
+ ErrorHandler func(context echo.Context, err error) error
+ // DenyHandler provides a handler to be called when RateLimiter denies access
+ DenyHandler func(context echo.Context, identifier string, err error) error
+ }
+ // Extractor is used to extract data from echo.Context
+ Extractor func(context echo.Context) (string, error)
+)
+
+// errors
+var (
+ // ErrRateLimitExceeded denotes an error raised when rate limit is exceeded
+ ErrRateLimitExceeded = echo.NewHTTPError(http.StatusTooManyRequests, "rate limit exceeded")
+ // ErrExtractorError denotes an error raised when extractor function is unsuccessful
+ ErrExtractorError = echo.NewHTTPError(http.StatusForbidden, "error while extracting identifier")
+)
+
+// DefaultRateLimiterConfig defines default values for RateLimiterConfig
+var DefaultRateLimiterConfig = RateLimiterConfig{
+ Skipper: DefaultSkipper,
+ IdentifierExtractor: func(ctx echo.Context) (string, error) {
+ id := ctx.RealIP()
+ return id, nil
+ },
+ ErrorHandler: func(context echo.Context, err error) error {
+ return &echo.HTTPError{
+ Code: ErrExtractorError.Code,
+ Message: ErrExtractorError.Message,
+ Internal: err,
+ }
+ },
+ DenyHandler: func(context echo.Context, identifier string, err error) error {
+ return &echo.HTTPError{
+ Code: ErrRateLimitExceeded.Code,
+ Message: ErrRateLimitExceeded.Message,
+ Internal: err,
+ }
+ },
+}
+
+/*
+RateLimiter returns a rate limiting middleware
+
+ e := echo.New()
+
+ limiterStore := middleware.NewRateLimiterMemoryStore(20)
+
+ e.GET("/rate-limited", func(c echo.Context) error {
+ return c.String(http.StatusOK, "test")
+ }, RateLimiter(limiterStore))
+*/
+func RateLimiter(store RateLimiterStore) echo.MiddlewareFunc {
+ config := DefaultRateLimiterConfig
+ config.Store = store
+
+ return RateLimiterWithConfig(config)
+}
+
+/*
+RateLimiterWithConfig returns a rate limiting middleware
+
+ e := echo.New()
+
+ config := middleware.RateLimiterConfig{
+ Skipper: DefaultSkipper,
+ Store: middleware.NewRateLimiterMemoryStore(
+ middleware.RateLimiterMemoryStoreConfig{Rate: 10, Burst: 30, ExpiresIn: 3 * time.Minute}
+ )
+ IdentifierExtractor: func(ctx echo.Context) (string, error) {
+ id := ctx.RealIP()
+ return id, nil
+ },
+ ErrorHandler: func(context echo.Context, err error) error {
+ return context.JSON(http.StatusTooManyRequests, nil)
+ },
+ DenyHandler: func(context echo.Context, identifier string) error {
+ return context.JSON(http.StatusForbidden, nil)
+ },
+ }
+
+ e.GET("/rate-limited", func(c echo.Context) error {
+ return c.String(http.StatusOK, "test")
+ }, middleware.RateLimiterWithConfig(config))
+*/
+func RateLimiterWithConfig(config RateLimiterConfig) echo.MiddlewareFunc {
+ if config.Skipper == nil {
+ config.Skipper = DefaultRateLimiterConfig.Skipper
+ }
+ if config.IdentifierExtractor == nil {
+ config.IdentifierExtractor = DefaultRateLimiterConfig.IdentifierExtractor
+ }
+ if config.ErrorHandler == nil {
+ config.ErrorHandler = DefaultRateLimiterConfig.ErrorHandler
+ }
+ if config.DenyHandler == nil {
+ config.DenyHandler = DefaultRateLimiterConfig.DenyHandler
+ }
+ if config.Store == nil {
+ panic("Store configuration must be provided")
+ }
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ if config.Skipper(c) {
+ return next(c)
+ }
+ if config.BeforeFunc != nil {
+ config.BeforeFunc(c)
+ }
+
+ identifier, err := config.IdentifierExtractor(c)
+ if err != nil {
+ c.Error(config.ErrorHandler(c, err))
+ return nil
+ }
+
+ if allow, err := config.Store.Allow(identifier); !allow {
+ c.Error(config.DenyHandler(c, identifier, err))
+ return nil
+ }
+ return next(c)
+ }
+ }
+}
+
+type (
+ // RateLimiterMemoryStore is the built-in store implementation for RateLimiter
+ RateLimiterMemoryStore struct {
+ visitors map[string]*Visitor
+ mutex sync.Mutex
+ rate rate.Limit // for more info check out Limiter docs - https://pkg.go.dev/golang.org/x/time/rate#Limit.
+
+ burst int
+ expiresIn time.Duration
+ lastCleanup time.Time
+ }
+ // Visitor signifies a unique user's limiter details
+ Visitor struct {
+ *rate.Limiter
+ lastSeen time.Time
+ }
+)
+
+/*
+NewRateLimiterMemoryStore returns an instance of RateLimiterMemoryStore with
+the provided rate (as req/s).
+for more info check out Limiter docs - https://pkg.go.dev/golang.org/x/time/rate#Limit.
+
+Burst and ExpiresIn will be set to default values.
+
+Note that if the provided rate is a float number and Burst is zero, Burst will be treated as the rounded down value of the rate.
+
+Example (with 20 requests/sec):
+
+ limiterStore := middleware.NewRateLimiterMemoryStore(20)
+*/
+func NewRateLimiterMemoryStore(rate rate.Limit) (store *RateLimiterMemoryStore) {
+ return NewRateLimiterMemoryStoreWithConfig(RateLimiterMemoryStoreConfig{
+ Rate: rate,
+ })
+}
+
+/*
+NewRateLimiterMemoryStoreWithConfig returns an instance of RateLimiterMemoryStore
+with the provided configuration. Rate must be provided. Burst will be set to the rounded down value of
+the configured rate if not provided or set to 0.
+
+The build-in memory store is usually capable for modest loads. For higher loads other
+store implementations should be considered.
+
+Characteristics:
+* Concurrency above 100 parallel requests may causes measurable lock contention
+* A high number of different IP addresses (above 16000) may be impacted by the internally used Go map
+* A high number of requests from a single IP address may cause lock contention
+
+Example:
+
+ limiterStore := middleware.NewRateLimiterMemoryStoreWithConfig(
+ middleware.RateLimiterMemoryStoreConfig{Rate: 50, Burst: 200, ExpiresIn: 5 * time.Minute},
+ )
+*/
+func NewRateLimiterMemoryStoreWithConfig(config RateLimiterMemoryStoreConfig) (store *RateLimiterMemoryStore) {
+ store = &RateLimiterMemoryStore{}
+
+ store.rate = config.Rate
+ store.burst = config.Burst
+ store.expiresIn = config.ExpiresIn
+ if config.ExpiresIn == 0 {
+ store.expiresIn = DefaultRateLimiterMemoryStoreConfig.ExpiresIn
+ }
+ if config.Burst == 0 {
+ store.burst = int(config.Rate)
+ }
+ store.visitors = make(map[string]*Visitor)
+ store.lastCleanup = now()
+ return
+}
+
+// RateLimiterMemoryStoreConfig represents configuration for RateLimiterMemoryStore
+type RateLimiterMemoryStoreConfig struct {
+ Rate rate.Limit // Rate of requests allowed to pass as req/s. For more info check out Limiter docs - https://pkg.go.dev/golang.org/x/time/rate#Limit.
+ Burst int // Burst is maximum number of requests to pass at the same moment. It additionally allows a number of requests to pass when rate limit is reached.
+ ExpiresIn time.Duration // ExpiresIn is the duration after that a rate limiter is cleaned up
+}
+
+// DefaultRateLimiterMemoryStoreConfig provides default configuration values for RateLimiterMemoryStore
+var DefaultRateLimiterMemoryStoreConfig = RateLimiterMemoryStoreConfig{
+ ExpiresIn: 3 * time.Minute,
+}
+
+// Allow implements RateLimiterStore.Allow
+func (store *RateLimiterMemoryStore) Allow(identifier string) (bool, error) {
+ store.mutex.Lock()
+ limiter, exists := store.visitors[identifier]
+ if !exists {
+ limiter = new(Visitor)
+ limiter.Limiter = rate.NewLimiter(store.rate, store.burst)
+ store.visitors[identifier] = limiter
+ }
+ limiter.lastSeen = now()
+ if now().Sub(store.lastCleanup) > store.expiresIn {
+ store.cleanupStaleVisitors()
+ }
+ store.mutex.Unlock()
+ return limiter.AllowN(now(), 1), nil
+}
+
+/*
+cleanupStaleVisitors helps manage the size of the visitors map by removing stale records
+of users who haven't visited again after the configured expiry time has elapsed
+*/
+func (store *RateLimiterMemoryStore) cleanupStaleVisitors() {
+ for id, visitor := range store.visitors {
+ if now().Sub(visitor.lastSeen) > store.expiresIn {
+ delete(store.visitors, id)
+ }
+ }
+ store.lastCleanup = now()
+}
+
+/*
+actual time method which is mocked in test file
+*/
+var now = time.Now
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/recover.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/recover.go
new file mode 100644
index 0000000..7b61285
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/recover.go
@@ -0,0 +1,122 @@
+package middleware
+
+import (
+ "fmt"
+ "net/http"
+ "runtime"
+
+ "github.com/labstack/echo/v4"
+ "github.com/labstack/gommon/log"
+)
+
+type (
+ // LogErrorFunc defines a function for custom logging in the middleware.
+ LogErrorFunc func(c echo.Context, err error, stack []byte) error
+
+ // 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 `yaml:"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 `yaml:"disable_stack_all"`
+
+ // DisablePrintStack disables printing stack trace.
+ // Optional. Default value as false.
+ DisablePrintStack bool `yaml:"disable_print_stack"`
+
+ // LogLevel is log level to printing stack trace.
+ // Optional. Default value 0 (Print).
+ LogLevel log.Lvl
+
+ // LogErrorFunc defines a function for custom logging in the middleware.
+ // If it's set you don't need to provide LogLevel for config.
+ LogErrorFunc LogErrorFunc
+ }
+)
+
+var (
+ // DefaultRecoverConfig is the default Recover middleware config.
+ DefaultRecoverConfig = RecoverConfig{
+ Skipper: DefaultSkipper,
+ StackSize: 4 << 10, // 4 KB
+ DisableStackAll: false,
+ DisablePrintStack: false,
+ LogLevel: 0,
+ LogErrorFunc: nil,
+ }
+)
+
+// 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 {
+ if r == http.ErrAbortHandler {
+ panic(r)
+ }
+ err, ok := r.(error)
+ if !ok {
+ err = fmt.Errorf("%v", r)
+ }
+ var stack []byte
+ var length int
+
+ if !config.DisablePrintStack {
+ stack = make([]byte, config.StackSize)
+ length = runtime.Stack(stack, !config.DisableStackAll)
+ stack = stack[:length]
+ }
+
+ if config.LogErrorFunc != nil {
+ err = config.LogErrorFunc(c, err, stack)
+ } else if !config.DisablePrintStack {
+ msg := fmt.Sprintf("[PANIC RECOVER] %v %s\n", err, stack[:length])
+ switch config.LogLevel {
+ case log.DEBUG:
+ c.Logger().Debug(msg)
+ case log.INFO:
+ c.Logger().Info(msg)
+ case log.WARN:
+ c.Logger().Warn(msg)
+ case log.ERROR:
+ c.Logger().Error(msg)
+ case log.OFF:
+ // None.
+ default:
+ c.Logger().Print(msg)
+ }
+ }
+ c.Error(err)
+ }
+ }()
+ return next(c)
+ }
+ }
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/redirect.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/redirect.go
new file mode 100644
index 0000000..13877db
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/redirect.go
@@ -0,0 +1,152 @@
+package middleware
+
+import (
+ "net/http"
+ "strings"
+
+ "github.com/labstack/echo/v4"
+)
+
+// RedirectConfig defines the config for Redirect middleware.
+type RedirectConfig struct {
+ // Skipper defines a function to skip middleware.
+ Skipper
+
+ // Status code to be used when redirecting the request.
+ // Optional. Default value http.StatusMovedPermanently.
+ Code int `yaml:"code"`
+}
+
+// redirectLogic represents a function that given a scheme, host and uri
+// can both: 1) determine if redirect is needed (will set ok accordingly) and
+// 2) return the appropriate redirect url.
+type redirectLogic func(scheme, host, uri string) (ok bool, url string)
+
+const www = "www."
+
+// DefaultRedirectConfig is the default Redirect middleware config.
+var 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 {
+ return redirect(config, func(scheme, host, uri string) (bool, string) {
+ if scheme != "https" {
+ return true, "https://" + host + uri
+ }
+ return false, ""
+ })
+}
+
+// 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 {
+ return redirect(config, func(scheme, host, uri string) (bool, string) {
+ if scheme != "https" && !strings.HasPrefix(host, www) {
+ return true, "https://www." + host + uri
+ }
+ return false, ""
+ })
+}
+
+// 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 {
+ return redirect(config, func(scheme, host, uri string) (ok bool, url string) {
+ if scheme != "https" {
+ host = strings.TrimPrefix(host, www)
+ return true, "https://" + host + uri
+ }
+ return false, ""
+ })
+}
+
+// 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 {
+ return redirect(config, func(scheme, host, uri string) (bool, string) {
+ if !strings.HasPrefix(host, www) {
+ return true, scheme + "://www." + host + uri
+ }
+ return false, ""
+ })
+}
+
+// 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 {
+ return redirect(config, func(scheme, host, uri string) (bool, string) {
+ if strings.HasPrefix(host, www) {
+ return true, scheme + "://" + host[4:] + uri
+ }
+ return false, ""
+ })
+}
+
+func redirect(config RedirectConfig, cb redirectLogic) echo.MiddlewareFunc {
+ if config.Skipper == nil {
+ config.Skipper = DefaultRedirectConfig.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, scheme := c.Request(), c.Scheme()
+ host := req.Host
+ if ok, url := cb(scheme, host, req.RequestURI); ok {
+ return c.Redirect(config.Code, url)
+ }
+
+ return next(c)
+ }
+ }
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/request_id.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/request_id.go
new file mode 100644
index 0000000..8c5ff66
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/request_id.go
@@ -0,0 +1,77 @@
+package middleware
+
+import (
+ "github.com/labstack/echo/v4"
+ "github.com/labstack/gommon/random"
+)
+
+type (
+ // RequestIDConfig defines the config for RequestID middleware.
+ RequestIDConfig struct {
+ // Skipper defines a function to skip middleware.
+ Skipper Skipper
+
+ // Generator defines a function to generate an ID.
+ // Optional. Default value random.String(32).
+ Generator func() string
+
+ // RequestIDHandler defines a function which is executed for a request id.
+ RequestIDHandler func(echo.Context, string)
+
+ // TargetHeader defines what header to look for to populate the id
+ TargetHeader string
+ }
+)
+
+var (
+ // DefaultRequestIDConfig is the default RequestID middleware config.
+ DefaultRequestIDConfig = RequestIDConfig{
+ Skipper: DefaultSkipper,
+ Generator: generator,
+ TargetHeader: echo.HeaderXRequestID,
+ }
+)
+
+// RequestID returns a X-Request-ID middleware.
+func RequestID() echo.MiddlewareFunc {
+ return RequestIDWithConfig(DefaultRequestIDConfig)
+}
+
+// RequestIDWithConfig returns a X-Request-ID middleware with config.
+func RequestIDWithConfig(config RequestIDConfig) echo.MiddlewareFunc {
+ // Defaults
+ if config.Skipper == nil {
+ config.Skipper = DefaultRequestIDConfig.Skipper
+ }
+ if config.Generator == nil {
+ config.Generator = generator
+ }
+ if config.TargetHeader == "" {
+ config.TargetHeader = echo.HeaderXRequestID
+ }
+
+ 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()
+ rid := req.Header.Get(config.TargetHeader)
+ if rid == "" {
+ rid = config.Generator()
+ }
+ res.Header().Set(config.TargetHeader, rid)
+ if config.RequestIDHandler != nil {
+ config.RequestIDHandler(c, rid)
+ }
+
+ return next(c)
+ }
+ }
+}
+
+func generator() string {
+ return random.String(32)
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/request_logger.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/request_logger.go
new file mode 100644
index 0000000..b9e3692
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/request_logger.go
@@ -0,0 +1,364 @@
+package middleware
+
+import (
+ "errors"
+ "net/http"
+ "time"
+
+ "github.com/labstack/echo/v4"
+)
+
+// Example for `fmt.Printf`
+// e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
+// LogStatus: true,
+// LogURI: true,
+// LogError: true,
+// HandleError: true, // forwards error to the global error handler, so it can decide appropriate status code
+// LogValuesFunc: func(c echo.Context, v middleware.RequestLoggerValues) error {
+// if v.Error == nil {
+// fmt.Printf("REQUEST: uri: %v, status: %v\n", v.URI, v.Status)
+// } else {
+// fmt.Printf("REQUEST_ERROR: uri: %v, status: %v, err: %v\n", v.URI, v.Status, v.Error)
+// }
+// return nil
+// },
+// }))
+//
+// Example for Zerolog (https://github.com/rs/zerolog)
+// logger := zerolog.New(os.Stdout)
+// e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
+// LogURI: true,
+// LogStatus: true,
+// LogError: true,
+// HandleError: true, // forwards error to the global error handler, so it can decide appropriate status code
+// LogValuesFunc: func(c echo.Context, v middleware.RequestLoggerValues) error {
+// if v.Error == nil {
+// logger.Info().
+// Str("URI", v.URI).
+// Int("status", v.Status).
+// Msg("request")
+// } else {
+// logger.Error().
+// Err(v.Error).
+// Str("URI", v.URI).
+// Int("status", v.Status).
+// Msg("request error")
+// }
+// return nil
+// },
+// }))
+//
+// Example for Zap (https://github.com/uber-go/zap)
+// logger, _ := zap.NewProduction()
+// e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
+// LogURI: true,
+// LogStatus: true,
+// LogError: true,
+// HandleError: true, // forwards error to the global error handler, so it can decide appropriate status code
+// LogValuesFunc: func(c echo.Context, v middleware.RequestLoggerValues) error {
+// if v.Error == nil {
+// logger.Info("request",
+// zap.String("URI", v.URI),
+// zap.Int("status", v.Status),
+// )
+// } else {
+// logger.Error("request error",
+// zap.String("URI", v.URI),
+// zap.Int("status", v.Status),
+// zap.Error(v.Error),
+// )
+// }
+// return nil
+// },
+// }))
+//
+// Example for Logrus (https://github.com/sirupsen/logrus)
+// log := logrus.New()
+// e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
+// LogURI: true,
+// LogStatus: true,
+// LogError: true,
+// HandleError: true, // forwards error to the global error handler, so it can decide appropriate status code
+// LogValuesFunc: func(c echo.Context, v middleware.RequestLoggerValues) error {
+// if v.Error == nil {
+// log.WithFields(logrus.Fields{
+// "URI": v.URI,
+// "status": v.Status,
+// }).Info("request")
+// } else {
+// log.WithFields(logrus.Fields{
+// "URI": v.URI,
+// "status": v.Status,
+// "error": v.Error,
+// }).Error("request error")
+// }
+// return nil
+// },
+// }))
+
+// RequestLoggerConfig is configuration for Request Logger middleware.
+type RequestLoggerConfig struct {
+ // Skipper defines a function to skip middleware.
+ Skipper Skipper
+
+ // BeforeNextFunc defines a function that is called before next middleware or handler is called in chain.
+ BeforeNextFunc func(c echo.Context)
+ // LogValuesFunc defines a function that is called with values extracted by logger from request/response.
+ // Mandatory.
+ LogValuesFunc func(c echo.Context, v RequestLoggerValues) error
+
+ // HandleError instructs logger to call global error handler when next middleware/handler returns an error.
+ // This is useful when you have custom error handler that can decide to use different status codes.
+ //
+ // A side-effect of calling global error handler is that now Response has been committed and sent to the client
+ // and middlewares up in chain can not change Response status code or response body.
+ HandleError bool
+
+ // LogLatency instructs logger to record duration it took to execute rest of the handler chain (next(c) call).
+ LogLatency bool
+ // LogProtocol instructs logger to extract request protocol (i.e. `HTTP/1.1` or `HTTP/2`)
+ LogProtocol bool
+ // LogRemoteIP instructs logger to extract request remote IP. See `echo.Context.RealIP()` for implementation details.
+ LogRemoteIP bool
+ // LogHost instructs logger to extract request host value (i.e. `example.com`)
+ LogHost bool
+ // LogMethod instructs logger to extract request method value (i.e. `GET` etc)
+ LogMethod bool
+ // LogURI instructs logger to extract request URI (i.e. `/list?lang=en&page=1`)
+ LogURI bool
+ // LogURIPath instructs logger to extract request URI path part (i.e. `/list`)
+ LogURIPath bool
+ // LogRoutePath instructs logger to extract route path part to which request was matched to (i.e. `/user/:id`)
+ LogRoutePath bool
+ // LogRequestID instructs logger to extract request ID from request `X-Request-ID` header or response if request did not have value.
+ LogRequestID bool
+ // LogReferer instructs logger to extract request referer values.
+ LogReferer bool
+ // LogUserAgent instructs logger to extract request user agent values.
+ LogUserAgent bool
+ // LogStatus instructs logger to extract response status code. If handler chain returns an echo.HTTPError,
+ // the status code is extracted from the echo.HTTPError returned
+ LogStatus bool
+ // LogError instructs logger to extract error returned from executed handler chain.
+ LogError bool
+ // LogContentLength instructs logger to extract content length header value. Note: this value could be different from
+ // actual request body size as it could be spoofed etc.
+ LogContentLength bool
+ // LogResponseSize instructs logger to extract response content length value. Note: when used with Gzip middleware
+ // this value may not be always correct.
+ LogResponseSize bool
+ // LogHeaders instructs logger to extract given list of headers from request. Note: request can contain more than
+ // one header with same value so slice of values is been logger for each given header.
+ //
+ // Note: header values are converted to canonical form with http.CanonicalHeaderKey as this how request parser converts header
+ // names to. For example, the canonical key for "accept-encoding" is "Accept-Encoding".
+ LogHeaders []string
+ // LogQueryParams instructs logger to extract given list of query parameters from request URI. Note: request can
+ // contain more than one query parameter with same name so slice of values is been logger for each given query param name.
+ LogQueryParams []string
+ // LogFormValues instructs logger to extract given list of form values from request body+URI. Note: request can
+ // contain more than one form value with same name so slice of values is been logger for each given form value name.
+ LogFormValues []string
+
+ timeNow func() time.Time
+}
+
+// RequestLoggerValues contains extracted values from logger.
+type RequestLoggerValues struct {
+ // StartTime is time recorded before next middleware/handler is executed.
+ StartTime time.Time
+ // Latency is duration it took to execute rest of the handler chain (next(c) call).
+ Latency time.Duration
+ // Protocol is request protocol (i.e. `HTTP/1.1` or `HTTP/2`)
+ Protocol string
+ // RemoteIP is request remote IP. See `echo.Context.RealIP()` for implementation details.
+ RemoteIP string
+ // Host is request host value (i.e. `example.com`)
+ Host string
+ // Method is request method value (i.e. `GET` etc)
+ Method string
+ // URI is request URI (i.e. `/list?lang=en&page=1`)
+ URI string
+ // URIPath is request URI path part (i.e. `/list`)
+ URIPath string
+ // RoutePath is route path part to which request was matched to (i.e. `/user/:id`)
+ RoutePath string
+ // RequestID is request ID from request `X-Request-ID` header or response if request did not have value.
+ RequestID string
+ // Referer is request referer values.
+ Referer string
+ // UserAgent is request user agent values.
+ UserAgent string
+ // Status is response status code. Then handler returns an echo.HTTPError then code from there.
+ Status int
+ // Error is error returned from executed handler chain.
+ Error error
+ // ContentLength is content length header value. Note: this value could be different from actual request body size
+ // as it could be spoofed etc.
+ ContentLength string
+ // ResponseSize is response content length value. Note: when used with Gzip middleware this value may not be always correct.
+ ResponseSize int64
+ // Headers are list of headers from request. Note: request can contain more than one header with same value so slice
+ // of values is been logger for each given header.
+ // Note: header values are converted to canonical form with http.CanonicalHeaderKey as this how request parser converts header
+ // names to. For example, the canonical key for "accept-encoding" is "Accept-Encoding".
+ Headers map[string][]string
+ // QueryParams are list of query parameters from request URI. Note: request can contain more than one query parameter
+ // with same name so slice of values is been logger for each given query param name.
+ QueryParams map[string][]string
+ // FormValues are list of form values from request body+URI. Note: request can contain more than one form value with
+ // same name so slice of values is been logger for each given form value name.
+ FormValues map[string][]string
+}
+
+// RequestLoggerWithConfig returns a RequestLogger middleware with config.
+func RequestLoggerWithConfig(config RequestLoggerConfig) echo.MiddlewareFunc {
+ mw, err := config.ToMiddleware()
+ if err != nil {
+ panic(err)
+ }
+ return mw
+}
+
+// ToMiddleware converts RequestLoggerConfig into middleware or returns an error for invalid configuration.
+func (config RequestLoggerConfig) ToMiddleware() (echo.MiddlewareFunc, error) {
+ if config.Skipper == nil {
+ config.Skipper = DefaultSkipper
+ }
+ now = time.Now
+ if config.timeNow != nil {
+ now = config.timeNow
+ }
+
+ if config.LogValuesFunc == nil {
+ return nil, errors.New("missing LogValuesFunc callback function for request logger middleware")
+ }
+
+ logHeaders := len(config.LogHeaders) > 0
+ headers := append([]string(nil), config.LogHeaders...)
+ for i, v := range headers {
+ headers[i] = http.CanonicalHeaderKey(v)
+ }
+
+ logQueryParams := len(config.LogQueryParams) > 0
+ logFormValues := len(config.LogFormValues) > 0
+
+ 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()
+ start := now()
+
+ if config.BeforeNextFunc != nil {
+ config.BeforeNextFunc(c)
+ }
+ err := next(c)
+ if config.HandleError {
+ c.Error(err)
+ }
+
+ v := RequestLoggerValues{
+ StartTime: start,
+ }
+ if config.LogLatency {
+ v.Latency = now().Sub(start)
+ }
+ if config.LogProtocol {
+ v.Protocol = req.Proto
+ }
+ if config.LogRemoteIP {
+ v.RemoteIP = c.RealIP()
+ }
+ if config.LogHost {
+ v.Host = req.Host
+ }
+ if config.LogMethod {
+ v.Method = req.Method
+ }
+ if config.LogURI {
+ v.URI = req.RequestURI
+ }
+ if config.LogURIPath {
+ p := req.URL.Path
+ if p == "" {
+ p = "/"
+ }
+ v.URIPath = p
+ }
+ if config.LogRoutePath {
+ v.RoutePath = c.Path()
+ }
+ if config.LogRequestID {
+ id := req.Header.Get(echo.HeaderXRequestID)
+ if id == "" {
+ id = res.Header().Get(echo.HeaderXRequestID)
+ }
+ v.RequestID = id
+ }
+ if config.LogReferer {
+ v.Referer = req.Referer()
+ }
+ if config.LogUserAgent {
+ v.UserAgent = req.UserAgent()
+ }
+ if config.LogStatus {
+ v.Status = res.Status
+ if err != nil && !config.HandleError {
+ // this block should not be executed in case of HandleError=true as the global error handler will decide
+ // the status code. In that case status code could be different from what err contains.
+ var httpErr *echo.HTTPError
+ if errors.As(err, &httpErr) {
+ v.Status = httpErr.Code
+ }
+ }
+ }
+ if config.LogError && err != nil {
+ v.Error = err
+ }
+ if config.LogContentLength {
+ v.ContentLength = req.Header.Get(echo.HeaderContentLength)
+ }
+ if config.LogResponseSize {
+ v.ResponseSize = res.Size
+ }
+ if logHeaders {
+ v.Headers = map[string][]string{}
+ for _, header := range headers {
+ if values, ok := req.Header[header]; ok {
+ v.Headers[header] = values
+ }
+ }
+ }
+ if logQueryParams {
+ queryParams := c.QueryParams()
+ v.QueryParams = map[string][]string{}
+ for _, param := range config.LogQueryParams {
+ if values, ok := queryParams[param]; ok {
+ v.QueryParams[param] = values
+ }
+ }
+ }
+ if logFormValues {
+ v.FormValues = map[string][]string{}
+ for _, formValue := range config.LogFormValues {
+ if values, ok := req.Form[formValue]; ok {
+ v.FormValues[formValue] = values
+ }
+ }
+ }
+
+ if errOnLog := config.LogValuesFunc(c, v); errOnLog != nil {
+ return errOnLog
+ }
+
+ // in case of HandleError=true we are returning the error that we already have handled with global error handler
+ // this is deliberate as this error could be useful for upstream middlewares and default global error handler
+ // will ignore that error when it bubbles up in middleware chain.
+ return err
+ }
+ }, nil
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/rewrite.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/rewrite.go
new file mode 100644
index 0000000..e5b0a6b
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/rewrite.go
@@ -0,0 +1,81 @@
+package middleware
+
+import (
+ "regexp"
+
+ "github.com/labstack/echo/v4"
+)
+
+type (
+ // RewriteConfig defines the config for Rewrite middleware.
+ RewriteConfig struct {
+ // Skipper defines a function to skip middleware.
+ Skipper Skipper
+
+ // Rules defines the URL path rewrite rules. The values captured in asterisk can be
+ // retrieved by index e.g. $1, $2 and so on.
+ // Example:
+ // "/old": "/new",
+ // "/api/*": "/$1",
+ // "/js/*": "/public/javascripts/$1",
+ // "/users/*/orders/*": "/user/$1/order/$2",
+ // Required.
+ Rules map[string]string `yaml:"rules"`
+
+ // RegexRules defines the URL path rewrite rules using regexp.Rexexp with captures
+ // Every capture group in the values can be retrieved by index e.g. $1, $2 and so on.
+ // Example:
+ // "^/old/[0.9]+/": "/new",
+ // "^/api/.+?/(.*)": "/v2/$1",
+ RegexRules map[*regexp.Regexp]string `yaml:"regex_rules"`
+ }
+)
+
+var (
+ // DefaultRewriteConfig is the default Rewrite middleware config.
+ DefaultRewriteConfig = RewriteConfig{
+ Skipper: DefaultSkipper,
+ }
+)
+
+// Rewrite returns a Rewrite middleware.
+//
+// Rewrite middleware rewrites the URL path based on the provided rules.
+func Rewrite(rules map[string]string) echo.MiddlewareFunc {
+ c := DefaultRewriteConfig
+ c.Rules = rules
+ return RewriteWithConfig(c)
+}
+
+// RewriteWithConfig returns a Rewrite middleware with config.
+// See: `Rewrite()`.
+func RewriteWithConfig(config RewriteConfig) echo.MiddlewareFunc {
+ // Defaults
+ if config.Rules == nil && config.RegexRules == nil {
+ panic("echo: rewrite middleware requires url path rewrite rules or regex rules")
+ }
+
+ if config.Skipper == nil {
+ config.Skipper = DefaultBodyDumpConfig.Skipper
+ }
+
+ if config.RegexRules == nil {
+ config.RegexRules = make(map[*regexp.Regexp]string)
+ }
+ for k, v := range rewriteRulesRegex(config.Rules) {
+ config.RegexRules[k] = v
+ }
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) (err error) {
+ if config.Skipper(c) {
+ return next(c)
+ }
+
+ if err := rewriteURL(config.RegexRules, c.Request()); err != nil {
+ return err
+ }
+ return next(c)
+ }
+ }
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/secure.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/secure.go
new file mode 100644
index 0000000..6c40517
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/secure.go
@@ -0,0 +1,145 @@
+package middleware
+
+import (
+ "fmt"
+
+ "github.com/labstack/echo/v4"
+)
+
+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 `yaml:"xss_protection"`
+
+ // ContentTypeNosniff provides protection against overriding Content-Type
+ // header by setting the `X-Content-Type-Options` header.
+ // Optional. Default value "nosniff".
+ ContentTypeNosniff string `yaml:"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 `yaml:"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 `yaml:"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 `yaml:"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 `yaml:"content_security_policy"`
+
+ // CSPReportOnly would use the `Content-Security-Policy-Report-Only` header instead
+ // of the `Content-Security-Policy` header. This allows iterative updates of the
+ // content security policy by only reporting the violations that would
+ // have occurred instead of blocking the resource.
+ // Optional. Default value false.
+ CSPReportOnly bool `yaml:"csp_report_only"`
+
+ // HSTSPreloadEnabled will add the preload tag in the `Strict Transport Security`
+ // header, which enables the domain to be included in the HSTS preload list
+ // maintained by Chrome (and used by Firefox and Safari): https://hstspreload.org/
+ // Optional. Default value false.
+ HSTSPreloadEnabled bool `yaml:"hsts_preload_enabled"`
+
+ // ReferrerPolicy sets the `Referrer-Policy` header providing security against
+ // leaking potentially sensitive request paths to third parties.
+ // Optional. Default value "".
+ ReferrerPolicy string `yaml:"referrer_policy"`
+ }
+)
+
+var (
+ // DefaultSecureConfig is the default Secure middleware config.
+ DefaultSecureConfig = SecureConfig{
+ Skipper: DefaultSkipper,
+ XSSProtection: "1; mode=block",
+ ContentTypeNosniff: "nosniff",
+ XFrameOptions: "SAMEORIGIN",
+ HSTSPreloadEnabled: false,
+ }
+)
+
+// 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"
+ }
+ if config.HSTSPreloadEnabled {
+ subdomains = fmt.Sprintf("%s; preload", subdomains)
+ }
+ res.Header().Set(echo.HeaderStrictTransportSecurity, fmt.Sprintf("max-age=%d%s", config.HSTSMaxAge, subdomains))
+ }
+ if config.ContentSecurityPolicy != "" {
+ if config.CSPReportOnly {
+ res.Header().Set(echo.HeaderContentSecurityPolicyReportOnly, config.ContentSecurityPolicy)
+ } else {
+ res.Header().Set(echo.HeaderContentSecurityPolicy, config.ContentSecurityPolicy)
+ }
+ }
+ if config.ReferrerPolicy != "" {
+ res.Header().Set(echo.HeaderReferrerPolicy, config.ReferrerPolicy)
+ }
+ return next(c)
+ }
+ }
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/slash.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/slash.go
new file mode 100644
index 0000000..a3bf807
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/slash.go
@@ -0,0 +1,130 @@
+package middleware
+
+import (
+ "strings"
+
+ "github.com/labstack/echo/v4"
+)
+
+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 `yaml:"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 an 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 !strings.HasSuffix(path, "/") {
+ path += "/"
+ uri := path
+ if qs != "" {
+ uri += "?" + qs
+ }
+
+ // Redirect
+ if config.RedirectCode != 0 {
+ return c.Redirect(config.RedirectCode, sanitizeURI(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 && strings.HasSuffix(path, "/") {
+ path = path[:l]
+ uri := path
+ if qs != "" {
+ uri += "?" + qs
+ }
+
+ // Redirect
+ if config.RedirectCode != 0 {
+ return c.Redirect(config.RedirectCode, sanitizeURI(uri))
+ }
+
+ // Forward
+ req.RequestURI = uri
+ url.Path = path
+ }
+ return next(c)
+ }
+ }
+}
+
+func sanitizeURI(uri string) string {
+ // double slash `\\`, `//` or even `\/` is absolute uri for browsers and by redirecting request to that uri
+ // we are vulnerable to open redirect attack. so replace all slashes from the beginning with single slash
+ if len(uri) > 1 && (uri[0] == '\\' || uri[0] == '/') && (uri[1] == '\\' || uri[1] == '/') {
+ uri = "/" + strings.TrimLeft(uri, `/\`)
+ }
+ return uri
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/static.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/static.go
new file mode 100644
index 0000000..27ccf41
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/static.go
@@ -0,0 +1,277 @@
+package middleware
+
+import (
+ "errors"
+ "fmt"
+ "html/template"
+ "net/http"
+ "net/url"
+ "os"
+ "path"
+ "path/filepath"
+ "strings"
+
+ "github.com/labstack/echo/v4"
+ "github.com/labstack/gommon/bytes"
+)
+
+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 `yaml:"root"`
+
+ // Index file for serving a directory.
+ // Optional. Default value "index.html".
+ Index string `yaml:"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 `yaml:"html5"`
+
+ // Enable directory browsing.
+ // Optional. Default value false.
+ Browse bool `yaml:"browse"`
+
+ // Enable ignoring of the base of the URL path.
+ // Example: when assigning a static middleware to a non root path group,
+ // the filesystem path is not doubled
+ // Optional. Default value false.
+ IgnoreBase bool `yaml:"ignoreBase"`
+
+ // Filesystem provides access to the static content.
+ // Optional. Defaults to http.Dir(config.Root)
+ Filesystem http.FileSystem `yaml:"-"`
+ }
+)
+
+const html = `
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta http-equiv="X-UA-Compatible" content="ie=edge">
+ <title>{{ .Name }}</title>
+ <style>
+ body {
+ font-family: Menlo, Consolas, monospace;
+ padding: 48px;
+ }
+ header {
+ padding: 4px 16px;
+ font-size: 24px;
+ }
+ ul {
+ list-style-type: none;
+ margin: 0;
+ padding: 20px 0 0 0;
+ display: flex;
+ flex-wrap: wrap;
+ }
+ li {
+ width: 300px;
+ padding: 16px;
+ }
+ li a {
+ display: block;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ text-decoration: none;
+ transition: opacity 0.25s;
+ }
+ li span {
+ color: #707070;
+ font-size: 12px;
+ }
+ li a:hover {
+ opacity: 0.50;
+ }
+ .dir {
+ color: #E91E63;
+ }
+ .file {
+ color: #673AB7;
+ }
+ </style>
+</head>
+<body>
+ <header>
+ {{ .Name }}
+ </header>
+ <ul>
+ {{ range .Files }}
+ <li>
+ {{ if .Dir }}
+ {{ $name := print .Name "/" }}
+ <a class="dir" href="{{ $name }}">{{ $name }}</a>
+ {{ else }}
+ <a class="file" href="{{ .Name }}">{{ .Name }}</a>
+ <span>{{ .Size }}</span>
+ {{ end }}
+ </li>
+ {{ end }}
+ </ul>
+</body>
+</html>
+`
+
+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.Root == "" {
+ config.Root = "." // For security we want to restrict to CWD.
+ }
+ if config.Skipper == nil {
+ config.Skipper = DefaultStaticConfig.Skipper
+ }
+ if config.Index == "" {
+ config.Index = DefaultStaticConfig.Index
+ }
+ if config.Filesystem == nil {
+ config.Filesystem = http.Dir(config.Root)
+ config.Root = "."
+ }
+
+ // Index template
+ t, err := template.New("index").Parse(html)
+ if err != nil {
+ panic(fmt.Sprintf("echo: %v", err))
+ }
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) (err error) {
+ if config.Skipper(c) {
+ return next(c)
+ }
+
+ p := c.Request().URL.Path
+ if strings.HasSuffix(c.Path(), "*") { // When serving from a group, e.g. `/static*`.
+ p = c.Param("*")
+ }
+ p, err = url.PathUnescape(p)
+ if err != nil {
+ return
+ }
+ name := filepath.Join(config.Root, filepath.Clean("/"+p)) // "/"+ for security
+
+ if config.IgnoreBase {
+ routePath := path.Base(strings.TrimRight(c.Path(), "/*"))
+ baseURLPath := path.Base(p)
+ if baseURLPath == routePath {
+ i := strings.LastIndex(name, routePath)
+ name = name[:i] + strings.Replace(name[i:], routePath, "", 1)
+ }
+ }
+
+ file, err := openFile(config.Filesystem, name)
+ if err != nil {
+ if !os.IsNotExist(err) {
+ return err
+ }
+
+ if err = next(c); err == nil {
+ return err
+ }
+
+ var he *echo.HTTPError
+ if !(errors.As(err, &he) && config.HTML5 && he.Code == http.StatusNotFound) {
+ return err
+ }
+
+ file, err = openFile(config.Filesystem, filepath.Join(config.Root, config.Index))
+ if err != nil {
+ return err
+ }
+ }
+
+ defer file.Close()
+
+ info, err := file.Stat()
+ if err != nil {
+ return err
+ }
+
+ if info.IsDir() {
+ index, err := openFile(config.Filesystem, filepath.Join(name, config.Index))
+ if err != nil {
+ if config.Browse {
+ return listDir(t, name, file, c.Response())
+ }
+
+ if os.IsNotExist(err) {
+ return next(c)
+ }
+ }
+
+ defer index.Close()
+
+ info, err = index.Stat()
+ if err != nil {
+ return err
+ }
+
+ return serveFile(c, index, info)
+ }
+
+ return serveFile(c, file, info)
+ }
+ }
+}
+
+func openFile(fs http.FileSystem, name string) (http.File, error) {
+ pathWithSlashes := filepath.ToSlash(name)
+ return fs.Open(pathWithSlashes)
+}
+
+func serveFile(c echo.Context, file http.File, info os.FileInfo) error {
+ http.ServeContent(c.Response(), c.Request(), info.Name(), info.ModTime(), file)
+ return nil
+}
+
+func listDir(t *template.Template, name string, dir http.File, res *echo.Response) (err error) {
+ files, err := dir.Readdir(-1)
+ if err != nil {
+ return
+ }
+
+ // Create directory index
+ res.Header().Set(echo.HeaderContentType, echo.MIMETextHTMLCharsetUTF8)
+ data := struct {
+ Name string
+ Files []interface{}
+ }{
+ Name: name,
+ }
+ for _, f := range files {
+ data.Files = append(data.Files, struct {
+ Name string
+ Dir bool
+ Size string
+ }{f.Name(), f.IsDir(), bytes.Format(f.Size())})
+ }
+ return t.Execute(res, data)
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/timeout.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/timeout.go
new file mode 100644
index 0000000..4e8836c
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/timeout.go
@@ -0,0 +1,220 @@
+package middleware
+
+import (
+ "context"
+ "github.com/labstack/echo/v4"
+ "net/http"
+ "sync"
+ "time"
+)
+
+// ---------------------------------------------------------------------------------------------------------------
+// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+// WARNING: Timeout middleware causes more problems than it solves.
+// WARNING: This middleware should be first middleware as it messes with request Writer and could cause data race if
+// it is in other position
+//
+// Depending on out requirements you could be better of setting timeout to context and
+// check its deadline from handler.
+//
+// For example: create middleware to set timeout to context
+// func RequestTimeout(timeout time.Duration) echo.MiddlewareFunc {
+// return func(next echo.HandlerFunc) echo.HandlerFunc {
+// return func(c echo.Context) error {
+// timeoutCtx, cancel := context.WithTimeout(c.Request().Context(), timeout)
+// c.SetRequest(c.Request().WithContext(timeoutCtx))
+// defer cancel()
+// return next(c)
+// }
+// }
+//}
+//
+// Create handler that checks for context deadline and runs actual task in separate coroutine
+// Note: separate coroutine may not be even if you do not want to process continue executing and
+// just want to stop long-running handler to stop and you are using "context aware" methods (ala db queries with ctx)
+// e.GET("/", func(c echo.Context) error {
+//
+// doneCh := make(chan error)
+// go func(ctx context.Context) {
+// doneCh <- myPossiblyLongRunningBackgroundTaskWithCtx(ctx)
+// }(c.Request().Context())
+//
+// select { // wait for task to finish or context to timeout/cancelled
+// case err := <-doneCh:
+// if err != nil {
+// return err
+// }
+// return c.String(http.StatusOK, "OK")
+// case <-c.Request().Context().Done():
+// if c.Request().Context().Err() == context.DeadlineExceeded {
+// return c.String(http.StatusServiceUnavailable, "timeout")
+// }
+// return c.Request().Context().Err()
+// }
+//
+// })
+//
+
+// TimeoutConfig defines the config for Timeout middleware.
+type TimeoutConfig struct {
+ // Skipper defines a function to skip middleware.
+ Skipper Skipper
+
+ // ErrorMessage is written to response on timeout in addition to http.StatusServiceUnavailable (503) status code
+ // It can be used to define a custom timeout error message
+ ErrorMessage string
+
+ // OnTimeoutRouteErrorHandler is an error handler that is executed for error that was returned from wrapped route after
+ // request timeouted and we already had sent the error code (503) and message response to the client.
+ // NB: do not write headers/body inside this handler. The response has already been sent to the client and response writer
+ // will not accept anything no more. If you want to know what actual route middleware timeouted use `c.Path()`
+ OnTimeoutRouteErrorHandler func(err error, c echo.Context)
+
+ // Timeout configures a timeout for the middleware, defaults to 0 for no timeout
+ // NOTE: when difference between timeout duration and handler execution time is almost the same (in range of 100microseconds)
+ // the result of timeout does not seem to be reliable - could respond timeout, could respond handler output
+ // difference over 500microseconds (0.5millisecond) response seems to be reliable
+ Timeout time.Duration
+}
+
+var (
+ // DefaultTimeoutConfig is the default Timeout middleware config.
+ DefaultTimeoutConfig = TimeoutConfig{
+ Skipper: DefaultSkipper,
+ Timeout: 0,
+ ErrorMessage: "",
+ }
+)
+
+// Timeout returns a middleware which returns error (503 Service Unavailable error) to client immediately when handler
+// call runs for longer than its time limit. NB: timeout does not stop handler execution.
+func Timeout() echo.MiddlewareFunc {
+ return TimeoutWithConfig(DefaultTimeoutConfig)
+}
+
+// TimeoutWithConfig returns a Timeout middleware with config or panics on invalid configuration.
+func TimeoutWithConfig(config TimeoutConfig) echo.MiddlewareFunc {
+ mw, err := config.ToMiddleware()
+ if err != nil {
+ panic(err)
+ }
+ return mw
+}
+
+// ToMiddleware converts Config to middleware or returns an error for invalid configuration
+func (config TimeoutConfig) ToMiddleware() (echo.MiddlewareFunc, error) {
+ if config.Skipper == nil {
+ config.Skipper = DefaultTimeoutConfig.Skipper
+ }
+
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ if config.Skipper(c) || config.Timeout == 0 {
+ return next(c)
+ }
+
+ errChan := make(chan error, 1)
+ handlerWrapper := echoHandlerFuncWrapper{
+ writer: &ignorableWriter{ResponseWriter: c.Response().Writer},
+ ctx: c,
+ handler: next,
+ errChan: errChan,
+ errHandler: config.OnTimeoutRouteErrorHandler,
+ }
+ handler := http.TimeoutHandler(handlerWrapper, config.Timeout, config.ErrorMessage)
+ handler.ServeHTTP(handlerWrapper.writer, c.Request())
+
+ select {
+ case err := <-errChan:
+ return err
+ default:
+ return nil
+ }
+ }
+ }, nil
+}
+
+type echoHandlerFuncWrapper struct {
+ writer *ignorableWriter
+ ctx echo.Context
+ handler echo.HandlerFunc
+ errHandler func(err error, c echo.Context)
+ errChan chan error
+}
+
+func (t echoHandlerFuncWrapper) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
+ // replace echo.Context Request with the one provided by TimeoutHandler to let later middlewares/handler on the chain
+ // handle properly it's cancellation
+ t.ctx.SetRequest(r)
+
+ // replace writer with TimeoutHandler custom one. This will guarantee that
+ // `writes by h to its ResponseWriter will return ErrHandlerTimeout.`
+ originalWriter := t.ctx.Response().Writer
+ t.ctx.Response().Writer = rw
+
+ // in case of panic we restore original writer and call panic again
+ // so it could be handled with global middleware Recover()
+ defer func() {
+ if err := recover(); err != nil {
+ t.ctx.Response().Writer = originalWriter
+ panic(err)
+ }
+ }()
+
+ err := t.handler(t.ctx)
+ if ctxErr := r.Context().Err(); ctxErr == context.DeadlineExceeded {
+ if err != nil && t.errHandler != nil {
+ t.errHandler(err, t.ctx)
+ }
+ return // on timeout we can not send handler error to client because `http.TimeoutHandler` has already sent headers
+ }
+ if err != nil {
+ // This is needed as `http.TimeoutHandler` will write status code by itself on error and after that our tries to write
+ // status code will not work anymore as Echo.Response thinks it has been already "committed" and further writes
+ // create errors in log about `superfluous response.WriteHeader call from`
+ t.writer.Ignore(true)
+ t.ctx.Response().Writer = originalWriter // make sure we restore writer before we signal original coroutine about the error
+ // we pass error from handler to middlewares up in handler chain to act on it if needed.
+ t.errChan <- err
+ return
+ }
+ // we restore original writer only for cases we did not timeout. On timeout we have already sent response to client
+ // and should not anymore send additional headers/data
+ // so on timeout writer stays what http.TimeoutHandler uses and prevents writing headers/body
+ t.ctx.Response().Writer = originalWriter
+}
+
+// ignorableWriter is ResponseWriter implementations that allows us to mark writer to ignore further write calls. This
+// is handy in cases when you do not have direct control of code being executed (3rd party middleware) but want to make
+// sure that external code will not be able to write response to the client.
+// Writer is coroutine safe for writes.
+type ignorableWriter struct {
+ http.ResponseWriter
+
+ lock sync.Mutex
+ ignoreWrites bool
+}
+
+func (w *ignorableWriter) Ignore(ignore bool) {
+ w.lock.Lock()
+ w.ignoreWrites = ignore
+ w.lock.Unlock()
+}
+
+func (w *ignorableWriter) WriteHeader(code int) {
+ w.lock.Lock()
+ defer w.lock.Unlock()
+ if w.ignoreWrites {
+ return
+ }
+ w.ResponseWriter.WriteHeader(code)
+}
+
+func (w *ignorableWriter) Write(b []byte) (int, error) {
+ w.lock.Lock()
+ defer w.lock.Unlock()
+ if w.ignoreWrites {
+ return len(b), nil
+ }
+ return w.ResponseWriter.Write(b)
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/util.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/util.go
new file mode 100644
index 0000000..ab951a0
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/middleware/util.go
@@ -0,0 +1,54 @@
+package middleware
+
+import (
+ "strings"
+)
+
+func matchScheme(domain, pattern string) bool {
+ didx := strings.Index(domain, ":")
+ pidx := strings.Index(pattern, ":")
+ return didx != -1 && pidx != -1 && domain[:didx] == pattern[:pidx]
+}
+
+// matchSubdomain compares authority with wildcard
+func matchSubdomain(domain, pattern string) bool {
+ if !matchScheme(domain, pattern) {
+ return false
+ }
+ didx := strings.Index(domain, "://")
+ pidx := strings.Index(pattern, "://")
+ if didx == -1 || pidx == -1 {
+ return false
+ }
+ domAuth := domain[didx+3:]
+ // to avoid long loop by invalid long domain
+ if len(domAuth) > 253 {
+ return false
+ }
+ patAuth := pattern[pidx+3:]
+
+ domComp := strings.Split(domAuth, ".")
+ patComp := strings.Split(patAuth, ".")
+ for i := len(domComp)/2 - 1; i >= 0; i-- {
+ opp := len(domComp) - 1 - i
+ domComp[i], domComp[opp] = domComp[opp], domComp[i]
+ }
+ for i := len(patComp)/2 - 1; i >= 0; i-- {
+ opp := len(patComp) - 1 - i
+ patComp[i], patComp[opp] = patComp[opp], patComp[i]
+ }
+
+ for i, v := range domComp {
+ if len(patComp) <= i {
+ return false
+ }
+ p := patComp[i]
+ if p == "*" {
+ return true
+ }
+ if p != v {
+ return false
+ }
+ }
+ return false
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/response.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/response.go
new file mode 100644
index 0000000..84f7c9e
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/response.go
@@ -0,0 +1,104 @@
+package echo
+
+import (
+ "bufio"
+ "net"
+ "net/http"
+)
+
+type (
+ // Response wraps an http.ResponseWriter and implements its interface to be used
+ // by an HTTP handler to construct an HTTP response.
+ // See: https://golang.org/pkg/net/http/#ResponseWriter
+ Response struct {
+ echo *Echo
+ beforeFuncs []func()
+ afterFuncs []func()
+ Writer http.ResponseWriter
+ Status int
+ Size int64
+ Committed bool
+ }
+)
+
+// NewResponse creates a new instance of Response.
+func NewResponse(w http.ResponseWriter, e *Echo) (r *Response) {
+ return &Response{Writer: w, echo: e}
+}
+
+// Header returns the header map for the writer that will be sent by
+// WriteHeader. Changing the header after a call to WriteHeader (or Write) has
+// no effect unless the modified headers were declared as trailers by setting
+// the "Trailer" header before the call to WriteHeader (see example)
+// To suppress implicit response headers, set their value to nil.
+// Example: https://golang.org/pkg/net/http/#example_ResponseWriter_trailers
+func (r *Response) Header() http.Header {
+ return r.Writer.Header()
+}
+
+// Before registers a function which is called just before the response is written.
+func (r *Response) Before(fn func()) {
+ r.beforeFuncs = append(r.beforeFuncs, fn)
+}
+
+// After registers a function which is called just after the response is written.
+// If the `Content-Length` is unknown, none of the after function is executed.
+func (r *Response) After(fn func()) {
+ r.afterFuncs = append(r.afterFuncs, fn)
+}
+
+// WriteHeader sends an HTTP response header with status code. If WriteHeader is
+// not called explicitly, the first call to Write will trigger an implicit
+// WriteHeader(http.StatusOK). Thus explicit calls to WriteHeader are mainly
+// used to send error codes.
+func (r *Response) WriteHeader(code int) {
+ if r.Committed {
+ r.echo.Logger.Warn("response already committed")
+ return
+ }
+ r.Status = code
+ for _, fn := range r.beforeFuncs {
+ fn()
+ }
+ r.Writer.WriteHeader(r.Status)
+ r.Committed = true
+}
+
+// Write writes the data to the connection as part of an HTTP reply.
+func (r *Response) Write(b []byte) (n int, err error) {
+ if !r.Committed {
+ if r.Status == 0 {
+ r.Status = http.StatusOK
+ }
+ r.WriteHeader(r.Status)
+ }
+ n, err = r.Writer.Write(b)
+ r.Size += int64(n)
+ for _, fn := range r.afterFuncs {
+ fn()
+ }
+ return
+}
+
+// Flush implements the http.Flusher interface to allow an HTTP handler to flush
+// buffered data to the client.
+// See [http.Flusher](https://golang.org/pkg/net/http/#Flusher)
+func (r *Response) Flush() {
+ r.Writer.(http.Flusher).Flush()
+}
+
+// Hijack implements the http.Hijacker interface to allow an HTTP handler to
+// take over the connection.
+// See [http.Hijacker](https://golang.org/pkg/net/http/#Hijacker)
+func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return r.Writer.(http.Hijacker).Hijack()
+}
+
+func (r *Response) reset(w http.ResponseWriter) {
+ r.beforeFuncs = nil
+ r.afterFuncs = nil
+ r.Writer = w
+ r.Size = 0
+ r.Status = http.StatusOK
+ r.Committed = false
+}
diff --git a/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/router.go b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/router.go
new file mode 100644
index 0000000..86a986a
--- /dev/null
+++ b/teleirc/matterbridge/vendor/github.com/labstack/echo/v4/router.go
@@ -0,0 +1,744 @@
+package echo
+
+import (
+ "bytes"
+ "fmt"
+ "net/http"
+)
+
+type (
+ // Router is the registry of all registered routes for an `Echo` instance for
+ // request matching and URL path parameter parsing.
+ Router struct {
+ tree *node
+ routes map[string]*Route
+ echo *Echo
+ }
+ node struct {
+ kind kind
+ label byte
+ prefix string
+ parent *node
+ staticChildren children
+ originalPath string
+ methods *routeMethods
+ paramChild *node
+ anyChild *node
+ paramsCount int
+ // isLeaf indicates that node does not have child routes
+ isLeaf bool
+ // isHandler indicates that node has at least one handler registered to it
+ isHandler bool
+
+ // notFoundHandler is handler registered with RouteNotFound method and is executed for 404 cases
+ notFoundHandler *routeMethod
+ }
+ kind uint8
+ children []*node
+ routeMethod struct {
+ ppath string
+ pnames []string
+ handler HandlerFunc
+ }
+ routeMethods struct {
+ connect *routeMethod
+ delete *routeMethod
+ get *routeMethod
+ head *routeMethod
+ options *routeMethod
+ patch *routeMethod
+ post *routeMethod
+ propfind *routeMethod
+ put *routeMethod
+ trace *routeMethod
+ report *routeMethod
+ anyOther map[string]*routeMethod
+ allowHeader string
+ }
+)
+
+const (
+ staticKind kind = iota
+ paramKind
+ anyKind
+
+ paramLabel = byte(':')
+ anyLabel = byte('*')
+)
+
+func (m *routeMethods) isHandler() bool {
+ return m.connect != nil ||
+ m.delete != nil ||
+ m.get != nil ||
+ m.head != nil ||
+ m.options != nil ||
+ m.patch != nil ||
+ m.post != nil ||
+ m.propfind != nil ||
+ m.put != nil ||
+ m.trace != nil ||
+ m.report != nil ||
+ len(m.anyOther) != 0
+ // RouteNotFound/404 is not considered as a handler
+}
+
+func (m *routeMethods) updateAllowHeader() {
+ buf := new(bytes.Buffer)
+ buf.WriteString(http.MethodOptions)
+
+ if m.connect != nil {
+ buf.WriteString(", ")
+ buf.WriteString(http.MethodConnect)
+ }
+ if m.delete != nil {
+ buf.WriteString(", ")
+ buf.WriteString(http.MethodDelete)
+ }
+ if m.get != nil {
+ buf.WriteString(", ")
+ buf.WriteString(http.MethodGet)
+ }
+ if m.head != nil {
+ buf.WriteString(", ")
+ buf.WriteString(http.MethodHead)
+ }
+ if m.patch != nil {
+ buf.WriteString(", ")
+ buf.WriteString(http.MethodPatch)
+ }
+ if m.post != nil {
+ buf.WriteString(", ")
+ buf.WriteString(http.MethodPost)
+ }
+ if m.propfind != nil {
+ buf.WriteString(", PROPFIND")
+ }
+ if m.put != nil {
+ buf.WriteString(", ")
+ buf.WriteString(http.MethodPut)
+ }
+ if m.trace != nil {
+ buf.WriteString(", ")
+ buf.WriteString(http.MethodTrace)
+ }
+ if m.report != nil {
+ buf.WriteString(", REPORT")
+ }
+ for method := range m.anyOther { // for simplicity, we use map and therefore order is not deterministic here
+ buf.WriteString(", ")
+ buf.WriteString(method)
+ }
+ m.allowHeader = buf.String()
+}
+
+// NewRouter returns a new Router instance.
+func NewRouter(e *Echo) *Router {
+ return &Router{
+ tree: &node{
+ methods: new(routeMethods),
+ },
+ routes: map[string]*Route{},
+ echo: e,
+ }
+}
+
+// Routes returns the registered routes.
+func (r *Router) Routes() []*Route {
+ routes := make([]*Route, 0, len(r.routes))
+ for _, v := range r.routes {
+ routes = append(routes, v)
+ }
+ return routes
+}
+
+// Reverse generates an URL from route name and provided parameters.
+func (r *Router) Reverse(name string, params ...interface{}) string {
+ uri := new(bytes.Buffer)
+ ln := len(params)
+ n := 0
+ for _, route := range r.routes {
+ if route.Name == name {
+ for i, l := 0, len(route.Path); i < l; i++ {
+ if (route.Path[i] == ':' || route.Path[i] == '*') && n < ln {
+ for ; i < l && route.Path[i] != '/'; i++ {
+ }
+ uri.WriteString(fmt.Sprintf("%v", params[n]))
+ n++
+ }
+ if i < l {
+ uri.WriteByte(route.Path[i])
+ }
+ }
+ break
+ }
+ }
+ return uri.String()
+}
+
+func (r *Router) add(method, path, name string, h HandlerFunc) *Route {
+ r.Add(method, path, h)
+
+ route := &Route{
+ Method: method,
+ Path: path,
+ Name: name,
+ }
+ r.routes[method+path] = route
+ return route
+}
+
+// Add registers a new route for method and path with matching handler.
+func (r *Router) Add(method, path string, h HandlerFunc) {
+ // Validate path
+ if path == "" {
+ path = "/"
+ }
+ if path[0] != '/' {
+ path = "/" + path
+ }
+ pnames := []string{} // Param names
+ ppath := path // Pristine path
+
+ if h == nil && r.echo.Logger != nil {
+ // FIXME: in future we should return error
+ r.echo.Logger.Errorf("Adding route without handler function: %v:%v", method, path)
+ }
+
+ for i, lcpIndex := 0, len(path); i < lcpIndex; i++ {
+ if path[i] == ':' {
+ if i > 0 && path[i-1] == '\\' {
+ path = path[:i-1] + path[i:]
+ i--
+ lcpIndex--
+ continue
+ }
+ j := i + 1
+
+ r.insert(method, path[:i], staticKind, routeMethod{})
+ for ; i < lcpIndex && path[i] != '/'; i++ {
+ }
+
+ pnames = append(pnames, path[j:i])
+ path = path[:j] + path[i:]
+ i, lcpIndex = j, len(path)
+
+ if i == lcpIndex {
+ // path node is last fragment of route path. ie. `/users/:id`
+ r.insert(method, path[:i], paramKind, routeMethod{ppath, pnames, h})
+ } else {
+ r.insert(method, path[:i], paramKind, routeMethod{})
+ }
+ } else if path[i] == '*' {
+ r.insert(method, path[:i], staticKind, routeMethod{})
+ pnames = append(pnames, "*")
+ r.insert(method, path[:i+1], anyKind, routeMethod{ppath, pnames, h})
+ }
+ }
+
+ r.insert(method, path, staticKind, routeMethod{ppath, pnames, h})
+}
+
+func (r *Router) insert(method, path string, t kind, rm routeMethod) {
+ // Adjust max param
+ paramLen := len(rm.pnames)
+ if *r.echo.maxParam < paramLen {
+ *r.echo.maxParam = paramLen
+ }
+
+ currentNode := r.tree // Current node as root
+ if currentNode == nil {
+ panic("echo: invalid method")
+ }
+ search := path
+
+ for {
+ searchLen := len(search)
+ prefixLen := len(currentNode.prefix)
+ lcpLen := 0
+
+ // LCP - Longest Common Prefix (https://en.wikipedia.org/wiki/LCP_array)
+ max := prefixLen
+ if searchLen < max {
+ max = searchLen
+ }
+ for ; lcpLen < max && search[lcpLen] == currentNode.prefix[lcpLen]; lcpLen++ {
+ }
+
+ if lcpLen == 0 {
+ // At root node
+ currentNode.label = search[0]
+ currentNode.prefix = search
+ if rm.handler != nil {
+ currentNode.kind = t
+ currentNode.addMethod(method, &rm)
+ currentNode.paramsCount = len(rm.pnames)
+ currentNode.originalPath = rm.ppath
+ }
+ currentNode.isLeaf = currentNode.staticChildren == nil && currentNode.paramChild == nil && currentNode.anyChild == nil
+ } else if lcpLen < prefixLen {
+ // Split node into two before we insert new node.
+ // This happens when we are inserting path that is submatch of any existing inserted paths.
+ // For example, we have node `/test` and now are about to insert `/te/*`. In that case
+ // 1. overlapping part is `/te` that is used as parent node
+ // 2. `st` is part from existing node that is not matching - it gets its own node (child to `/te`)
+ // 3. `/*` is the new part we are about to insert (child to `/te`)
+ n := newNode(
+ currentNode.kind,
+ currentNode.prefix[lcpLen:],
+ currentNode,
+ currentNode.staticChildren,
+ currentNode.originalPath,
+ currentNode.methods,
+ currentNode.paramsCount,
+ currentNode.paramChild,
+ currentNode.anyChild,
+ currentNode.notFoundHandler,
+ )
+ // Update parent path for all children to new node
+ for _, child := range currentNode.staticChildren {
+ child.parent = n
+ }
+ if currentNode.paramChild != nil {
+ currentNode.paramChild.parent = n
+ }
+ if currentNode.anyChild != nil {
+ currentNode.anyChild.parent = n
+ }
+
+ // Reset parent node
+ currentNode.kind = staticKind
+ currentNode.label = currentNode.prefix[0]
+ currentNode.prefix = currentNode.prefix[:lcpLen]
+ currentNode.staticChildren = nil
+ currentNode.originalPath = ""
+ currentNode.methods = new(routeMethods)
+ currentNode.paramsCount = 0
+ currentNode.paramChild = nil
+ currentNode.anyChild = nil
+ currentNode.isLeaf = false
+ currentNode.isHandler = false
+ currentNode.notFoundHandler = nil
+
+ // Only Static children could reach here
+ currentNode.addStaticChild(n)
+
+ if lcpLen == searchLen {
+ // At parent node
+ currentNode.kind = t
+ if rm.handler != nil {
+ currentNode.addMethod(method, &rm)
+ currentNode.paramsCount = len(rm.pnames)
+ currentNode.originalPath = rm.ppath
+ }
+ } else {
+ // Create child node
+ n = newNode(t, search[lcpLen:], currentNode, nil, "", new(routeMethods), 0, nil, nil, nil)
+ if rm.handler != nil {
+ n.addMethod(method, &rm)
+ n.paramsCount = len(rm.pnames)
+ n.originalPath = rm.ppath
+ }
+ // Only Static children could reach here
+ currentNode.addStaticChild(n)
+ }
+ currentNode.isLeaf = currentNode.staticChildren == nil && currentNode.paramChild == nil && currentNode.anyChild == nil
+ } else if lcpLen < searchLen {
+ search = search[lcpLen:]
+ c := currentNode.findChildWithLabel(search[0])
+ if c != nil {
+ // Go deeper
+ currentNode = c
+ continue
+ }
+ // Create child node
+ n := newNode(t, search, currentNode, nil, rm.ppath, new(routeMethods), 0, nil, nil, nil)
+ if rm.handler != nil {
+ n.addMethod(method, &rm)
+ n.paramsCount = len(rm.pnames)
+ }
+
+ switch t {
+ case staticKind:
+ currentNode.addStaticChild(n)
+ case paramKind:
+ currentNode.paramChild = n
+ case anyKind:
+ currentNode.anyChild = n
+ }
+ currentNode.isLeaf = currentNode.staticChildren == nil && currentNode.paramChild == nil && currentNode.anyChild == nil
+ } else {
+ // Node already exists
+ if rm.handler != nil {
+ currentNode.addMethod(method, &rm)
+ currentNode.paramsCount = len(rm.pnames)
+ currentNode.originalPath = rm.ppath
+ }
+ }
+ return
+ }
+}
+
+func newNode(
+ t kind,
+ pre string,
+ p *node,
+ sc children,
+ originalPath string,
+ methods *routeMethods,
+ paramsCount int,
+ paramChildren,
+ anyChildren *node,
+ notFoundHandler *routeMethod,
+) *node {
+ return &node{
+ kind: t,
+ label: pre[0],
+ prefix: pre,
+ parent: p,
+ staticChildren: sc,
+ originalPath: originalPath,
+ methods: methods,
+ paramsCount: paramsCount,
+ paramChild: paramChildren,
+ anyChild: anyChildren,
+ isLeaf: sc == nil && paramChildren == nil && anyChildren == nil,
+ isHandler: methods.isHandler(),
+ notFoundHandler: notFoundHandler,
+ }
+}
+
+func (n *node) addStaticChild(c *node) {
+ n.staticChildren = append(n.staticChildren, c)
+}
+
+func (n *node) findStaticChild(l byte) *node {
+ for _, c := range n.staticChildren {
+ if c.label == l {
+ return c
+ }
+ }
+ return nil
+}
+
+func (n *node) findChildWithLabel(l byte) *node {
+ if c := n.findStaticChild(l); c != nil {
+ return c
+ }
+ if l == paramLabel {
+ return n.paramChild
+ }
+ if l == anyLabel {
+ return n.anyChild
+ }
+ return nil
+}
+
+func (n *node) addMethod(method string, h *routeMethod) {
+ switch method {
+ case http.MethodConnect:
+ n.methods.connect = h
+ case http.MethodDelete:
+ n.methods.delete = h
+ case http.MethodGet:
+ n.methods.get = h
+ case http.MethodHead:
+ n.methods.head = h
+ case http.MethodOptions:
+ n.methods.options = h
+ case http.MethodPatch:
+ n.methods.patch = h
+ case http.MethodPost:
+ n.methods.post = h
+ case PROPFIND:
+ n.methods.propfind = h
+ case http.MethodPut:
+ n.methods.put = h
+ case http.MethodTrace:
+ n.methods.trace = h
+ case REPORT:
+ n.methods.report = h
+ case RouteNotFound:
+ n.notFoundHandler = h
+ return // RouteNotFound/404 is not considered as a handler so no further logic needs to be executed
+ default:
+ if n.methods.anyOther == nil {
+ n.methods.anyOther = make(map[string]*routeMethod)
+ }
+ if h.handler == nil {
+ delete(n.methods.anyOther, method)
+ } else {
+ n.methods.anyOther[method] = h
+ }
+ }
+
+ n.methods.updateAllowHeader()
+ n.isHandler = true
+}
+
+func (n *node) findMethod(method string) *routeMethod {
+ switch method {
+ case http.MethodConnect:
+ return n.methods.connect
+ case http.MethodDelete:
+ return n.methods.delete
+ case http.MethodGet:
+ return n.methods.get
+ case http.MethodHead:
+ return n.methods.head
+ case http.MethodOptions:
+ return n.methods.options
+ case http.MethodPatch:
+ return n.methods.patch
+ case http.MethodPost:
+ return n.methods.post
+ case PROPFIND:
+ return n.methods.propfind
+ case http.MethodPut:
+ return n.methods.put
+ case http.MethodTrace:
+ return n.methods.trace
+ case REPORT:
+ return n.methods.report
+ default: // RouteNotFound/404 is not considered as a handler
+ return n.methods.anyOther[method]
+ }
+}
+
+func optionsMethodHandler(allowMethods string) func(c Context) error {
+ return func(c Context) error {
+ // Note: we are not handling most of the CORS headers here. CORS is handled by CORS middleware
+ // 'OPTIONS' method RFC: https://httpwg.org/specs/rfc7231.html#OPTIONS
+ // 'Allow' header RFC: https://datatracker.ietf.org/doc/html/rfc7231#section-7.4.1
+ c.Response().Header().Add(HeaderAllow, allowMethods)
+ return c.NoContent(http.StatusNoContent)
+ }
+}
+
+// Find lookup a handler registered for method and path. It also parses URL for path
+// parameters and load them into context.
+//
+// For performance:
+//
+// - Get context from `Echo#AcquireContext()`
+// - Reset it `Context#Reset()`
+// - Return it `Echo#ReleaseContext()`.
+func (r *Router) Find(method, path string, c Context) {
+ ctx := c.(*context)
+ ctx.path = path
+ currentNode := r.tree // Current node as root
+
+ var (
+ previousBestMatchNode *node
+ matchedRouteMethod *routeMethod
+ // search stores the remaining path to check for match. By each iteration we move from start of path to end of the path
+ // and search value gets shorter and shorter.
+ search = path
+ searchIndex = 0
+ paramIndex int // Param counter
+ paramValues = ctx.pvalues // Use the internal slice so the interface can keep the illusion of a dynamic slice
+ )
+
+ // Backtracking is needed when a dead end (leaf node) is reached in the router tree.
+ // To backtrack the current node will be changed to the parent node and the next kind for the
+ // router logic will be returned based on fromKind or kind of the dead end node (static > param > any).
+ // For example if there is no static node match we should check parent next sibling by kind (param).
+ // Backtracking itself does not check if there is a next sibling, this is done by the router logic.
+ backtrackToNextNodeKind := func(fromKind kind) (nextNodeKind kind, valid bool) {
+ previous := currentNode
+ currentNode = previous.parent
+ valid = currentNode != nil
+
+ // Next node type by priority
+ if previous.kind == anyKind {
+ nextNodeKind = staticKind
+ } else {
+ nextNodeKind = previous.kind + 1
+ }
+
+ if fromKind == staticKind {
+ // when backtracking is done from static kind block we did not change search so nothing to restore
+ return
+ }
+
+ // restore search to value it was before we move to current node we are backtracking from.
+ if previous.kind == staticKind {
+ searchIndex -= len(previous.prefix)
+ } else {
+ paramIndex--
+ // for param/any node.prefix value is always `:` so we can not deduce searchIndex from that and must use pValue
+ // for that index as it would also contain part of path we cut off before moving into node we are backtracking from
+ searchIndex -= len(paramValues[paramIndex])
+ paramValues[paramIndex] = ""
+ }
+ search = path[searchIndex:]
+ return
+ }
+
+ // Router tree is implemented by longest common prefix array (LCP array) https://en.wikipedia.org/wiki/LCP_array
+ // Tree search is implemented as for loop where one loop iteration is divided into 3 separate blocks
+ // Each of these blocks checks specific kind of node (static/param/any). Order of blocks reflex their priority in routing.
+ // Search order/priority is: static > param > any.
+ //
+ // Note: backtracking in tree is implemented by replacing/switching currentNode to previous node
+ // and hoping to (goto statement) next block by priority to check if it is the match.
+ for {
+ prefixLen := 0 // Prefix length
+ lcpLen := 0 // LCP (longest common prefix) length
+
+ if currentNode.kind == staticKind {
+ searchLen := len(search)
+ prefixLen = len(currentNode.prefix)
+
+ // LCP - Longest Common Prefix (https://en.wikipedia.org/wiki/LCP_array)
+ max := prefixLen
+ if searchLen < max {
+ max = searchLen
+ }
+ for ; lcpLen < max && search[lcpLen] == currentNode.prefix[lcpLen]; lcpLen++ {
+ }
+ }
+
+ if lcpLen != prefixLen {
+ // No matching prefix, let's backtrack to the first possible alternative node of the decision path
+ nk, ok := backtrackToNextNodeKind(staticKind)
+ if !ok {
+ return // No other possibilities on the decision path, handler will be whatever context is reset to.
+ } else if nk == paramKind {
+ goto Param
+ // NOTE: this case (backtracking from static node to previous any node) can not happen by current any matching logic. Any node is end of search currently
+ //} else if nk == anyKind {
+ // goto Any
+ } else {
+ // Not found (this should never be possible for static node we are looking currently)
+ break
+ }
+ }
+
+ // The full prefix has matched, remove the prefix from the remaining search
+ search = search[lcpLen:]
+ searchIndex = searchIndex + lcpLen
+
+ // Finish routing if is no request path remaining to search
+ if search == "" {
+ // in case of node that is handler we have exact method type match or something for 405 to use
+ if currentNode.isHandler {
+ // check if current node has handler registered for http method we are looking for. we store currentNode as
+ // best matching in case we do no find no more routes matching this path+method
+ if previousBestMatchNode == nil {
+ previousBestMatchNode = currentNode
+ }
+ if h := currentNode.findMethod(method); h != nil {
+ matchedRouteMethod = h
+ break
+ }
+ } else if currentNode.notFoundHandler != nil {
+ matchedRouteMethod = currentNode.notFoundHandler
+ break
+ }
+ }
+
+ // Static node
+ if search != "" {
+ if child := currentNode.findStaticChild(search[0]); child != nil {
+ currentNode = child
+ continue
+ }
+ }
+
+ Param:
+ // Param node
+ if child := currentNode.paramChild; search != "" && child != nil {
+ currentNode = child
+ i := 0
+ l := len(search)
+ if currentNode.isLeaf {
+ // when param node does not have any children (path param is last piece of route path) then param node should
+ // act similarly to any node - consider all remaining search as match
+ i = l
+ } else {
+ for ; i < l && search[i] != '/'; i++ {
+ }
+ }
+
+ paramValues[paramIndex] = search[:i]
+ paramIndex++
+ search = search[i:]
+ searchIndex = searchIndex + i
+ continue
+ }
+
+ Any:
+ // Any node
+ if child := currentNode.anyChild; child != nil {
+ // If any node is found, use remaining path for paramValues
+ currentNode = child
+ paramValues[currentNode.paramsCount-1] = search
+
+ // update indexes/search in case we need to backtrack when no handler match is found
+ paramIndex++
+ searchIndex += +len(search)
+ search = ""
+
+ if h := currentNode.findMethod(method); h != nil {
+ matchedRouteMethod = h
+ break
+ }
+ // we store currentNode as best matching in case we do not find more routes matching this path+method. Needed for 405
+ if previousBestMatchNode == nil {
+ previousBestMatchNode = currentNode
+ }
+ if currentNode.notFoundHandler != nil {
+ matchedRouteMethod = currentNode.notFoundHandler
+ break
+ }
+ }
+
+ // Let's backtrack to the first possible alternative node of the decision path
+ nk, ok := backtrackToNextNodeKind(anyKind)
+ if !ok {
+ break // No other possibilities on the decision path
+ } else if nk == paramKind {
+ goto Param
+ } else if nk == anyKind {
+ goto Any
+ } else {
+ // Not found
+ break
+ }
+ }
+
+ if currentNode == nil && previousBestMatchNode == nil {
+ return // nothing matched at all
+ }
+
+ // matchedHandler could be method+path handler that we matched or notFoundHandler from node with matching path
+ // user provided not found (404) handler has priority over generic method not found (405) handler or global 404 handler
+ var rPath string
+ var rPNames []string
+ if matchedRouteMethod != nil {
+ rPath = matchedRouteMethod.ppath
+ rPNames = matchedRouteMethod.pnames
+ ctx.handler = matchedRouteMethod.handler
+ } else {
+ // use previous match as basis. although we have no matching handler we have path match.
+ // so we can send http.StatusMethodNotAllowed (405) instead of http.StatusNotFound (404)
+ currentNode = previousBestMatchNode
+
+ rPath = currentNode.originalPath
+ rPNames = nil // no params here
+ ctx.handler = NotFoundHandler
+ if currentNode.notFoundHandler != nil {
+ rPath = currentNode.notFoundHandler.ppath
+ rPNames = currentNode.notFoundHandler.pnames
+ ctx.handler = currentNode.notFoundHandler.handler
+ } else if currentNode.isHandler {
+ ctx.Set(ContextKeyHeaderAllow, currentNode.methods.allowHeader)
+ ctx.handler = MethodNotAllowedHandler
+ if method == http.MethodOptions {
+ ctx.handler = optionsMethodHandler(currentNode.methods.allowHeader)
+ }
+ }
+ }
+ ctx.path = rPath
+ ctx.pnames = rPNames
+}