diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7354317..1bc2372 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,7 +18,7 @@ jobs: run: shell: bash steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions/setup-go@v2 with: @@ -47,7 +47,7 @@ jobs: release-test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 0 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index cc259d1..7f29041 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fe726c4..d18f7b2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,7 +9,7 @@ jobs: goreleaser: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 0 diff --git a/README.md b/README.md index 6d13079..1de388c 100644 --- a/README.md +++ b/README.md @@ -20,49 +20,49 @@ To execute the full build pipeline, run `make`; to build the docker images, run You'll need to set some environment variables to tell Fluitans how to assign names and how to connect to a ZeroTier network controller. Specifically, you'll need to set: -- FLUITANS_DOMAIN_NAME, which should be the parent domain name under which network domain names will be assigned, for example `fluitans.org` or `prakashlab.dedyn.io`. For web security reasons, the Fluitans app itself should be hosted on a separate domain name (for example `fluitans.sargassum.world`). -- FLUITANS_ZT_CONTROLLER_SERVER, which should be the URL for the ZeroTier network controller's HTTP API. It needs to include the scheme `http://` or `https://`, for example `http://localhost:9993` or `https://zerotier-test.cloud.fluitans.sargassumworld`. -- FLUITANS_ZT_CONTROLLER_AUTHTOKEN, which should be the contents of the authtoken.secret file saved by ZeroTier One in its working directory (more details [in ZeroTier's documentation](https://docs.zerotier.com/zerotier/zerotier.conf/)). -- FLUITANS_DNS_SERVER, which should be the URL for the deSEC HTTP API. It needs to include the scheme `https://`, for example `https://desec.io`. -- FLUITANS_DNS_AUTHTOKEN, which should be an authentication token for the deSEC HTTP API. -- FLUITANS_SESSIONS_COOKIE_NOHTTPSONLY, which should be `true` if you are running Fluitans locally (as `localhost`) without HTTPS. If you are running Fluitans over the web, you should run it behind an HTTPS reverse proxy and you should leave FLUITANS_SESSION_COOKIE_NOHTTPSONLY unset. -- FLUITANS_SESSIONS_AUTH_KEY, which should be set to a session key generated by running Fluitans without the FLUITANS_SESSION_AUTH_KEY set. -- FLUITANS_AUTHN_ADMIN_PW_HASH, which should be set to the password hash generated by running Fluitans with a password set as FLUITANS_AUTHN_ADMIN_PW. +- ZT_CONTROLLER_SERVER, which should be the URL for the ZeroTier network controller's HTTP API. It needs to include the scheme `http://` or `https://`, for example `http://localhost:9993` or `https://zerotier-test.cloud.fluitans.sargassumworld`. +- ZT_CONTROLLER_AUTHTOKEN, which should be the contents of the authtoken.secret file saved by ZeroTier One in its working directory (more details [in ZeroTier's documentation](https://docs.zerotier.com/zerotier/zerotier.conf/)). +- DNS_DOMAIN_NAME, which should be the parent domain name under which network domain names will be assigned, for example `fluitans.org` or `prakashlab.dedyn.io`. For web security reasons, the Fluitans app itself should be hosted on a separate domain name (for example `fluitans.sargassum.world`). +- DNS_SERVER, which should be the URL for the deSEC HTTP API. It needs to include the scheme `https://`, for example `https://desec.io`. +- DNS_AUTHTOKEN, which should be an authentication token for the deSEC HTTP API. +- SESSIONS_COOKIE_NOHTTPSONLY, which should be `true` if you are running Fluitans locally (as `localhost`) without HTTPS. If you are running Fluitans over the web, you should run it behind an HTTPS reverse proxy and you should leave SESSION_COOKIE_NOHTTPSONLY unset. +- SESSIONS_AUTH_KEY, which should be set to a session key generated by running Fluitans without the SESSION_AUTH_KEY set. +- AUTHN_ADMIN_PW_HASH, which should be set to the password hash generated by running Fluitans with a password set as AUTHN_ADMIN_PW. For example, you could generate the password and session key using: ``` -FLUITANS_AUTHN_ADMIN_PW='mypassword' make run +AUTHN_ADMIN_PW='mypassword' make run ``` which will print a message like: ``` -Record this admin password hash for future use as FLUITANS_AUTHN_ADMIN_PW_HASH +Record this admin password hash for future use as AUTHN_ADMIN_PW_HASH (use single-quotes from shell to avoid string substitution with dollar-signs): $argon2id$v=19$m=65536,t=1,p=2$EIV/HJ0DILHeNf2IC+qsGQ$BvBCCEsKUCKuAPI+pzM+sbCy/pdQdOF/FmHwx/yIusU -Record this key for future use as FLUITANS_SESSIONS_AUTH_KEY: +Record this key for future use as SESSIONS_AUTH_KEY: QVG4y5EPPoDZjAzYc6j7I09iJum3w+hXNrB3O4HQvSc= ``` And then you could run the server in development mode (which you can log into with username `admin` and password `mypassword`) using: ``` -FLUITANS_DOMAIN_NAME='fluitans.org' \ -FLUITANS_ZT_CONTROLLER_SERVER='http://localhost:9993' \ -FLUITANS_ZT_CONTROLLER_AUTHTOKEN='0123456789abcdefghijklmn' \ -FLUITANS_DNS_SERVER='https://desec.io' \ -FLUITANS_DNS_AUTHTOKEN='abcdefghijklmn0123456789' \ -FLUITANS_SESSION_AUTH_KEY='QVG4y5EPPoDZjAzYc6j7I09iJum3w+hXNrB3O4HQvSc=' \ -FLUITANS_AUTHN_ADMIN_PW_HASH='$argon2id$v=19$m=65536,t=1,p=2$EIV/HJ0DILHeNf2IC+qsGQ$BvBCCEsKUCKuAPI+pzM+sbCy/pdQdOF/FmHwx/yIusU' \ +ZTCONTROLLER_SERVER='http://localhost:9993' \ +ZTCONTROLLER_AUTHTOKEN='0123456789abcdefghijklmn' \ +DNS_DOMAIN_NAME='fluitans.org' \ +DNS_SERVER='https://desec.io' \ +DNS_AUTHTOKEN='abcdefghijklmn0123456789' \ +SESSION_AUTH_KEY='QVG4y5EPPoDZjAzYc6j7I09iJum3w+hXNrB3O4HQvSc=' \ +AUTHN_ADMIN_PW_HASH='$argon2id$v=19$m=65536,t=1,p=2$EIV/HJ0DILHeNf2IC+qsGQ$BvBCCEsKUCKuAPI+pzM+sbCy/pdQdOF/FmHwx/yIusU' \ make run ``` Or you could run the built binary using: ``` -FLUITANS_DOMAIN_NAME='fluitans.org' \ -FLUITANS_ZT_CONTROLLER_SERVER='http://localhost:9993' \ -FLUITANS_ZT_CONTROLLER_AUTHTOKEN='0123456789abcdefghijklmn' \ -FLUITANS_DNS_SERVER='https://desec.io' \ -FLUITANS_DNS_AUTHTOKEN='abcdefghijklmn0123456789' \ -FLUITANS_SESSION_AUTH_KEY='QVG4y5EPPoDZjAzYc6j7I09iJum3w+hXNrB3O4HQvSc=' \ -FLUITANS_AUTHN_ADMIN_PW_HASH='$argon2id$v=19$m=65536,t=1,p=2$EIV/HJ0DILHeNf2IC+qsGQ$BvBCCEsKUCKuAPI+pzM+sbCy/pdQdOF/FmHwx/yIusU' \ +ZTCONTROLLER_SERVER='http://localhost:9993' \ +ZTCONTROLLER_AUTHTOKEN='0123456789abcdefghijklmn' \ +DNS_DOMAIN_NAME='fluitans.org' \ +DNS_SERVER='https://desec.io' \ +DNS_AUTHTOKEN='abcdefghijklmn0123456789' \ +SESSION_AUTH_KEY='QVG4y5EPPoDZjAzYc6j7I09iJum3w+hXNrB3O4HQvSc=' \ +AUTHN_ADMIN_PW_HASH='$argon2id$v=19$m=65536,t=1,p=2$EIV/HJ0DILHeNf2IC+qsGQ$BvBCCEsKUCKuAPI+pzM+sbCy/pdQdOF/FmHwx/yIusU' \ ./fluitans ``` diff --git a/go.mod b/go.mod index a06f2c9..7338cfc 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/gorilla/sessions v1.2.1 github.com/huandu/xstrings v1.3.2 // indirect github.com/imdario/mergo v0.3.12 // indirect - github.com/labstack/echo/v4 v4.6.3 + github.com/labstack/echo/v4 v4.7.0 github.com/labstack/gommon v0.3.1 github.com/mattn/go-colorable v0.1.12 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect @@ -28,9 +28,9 @@ require ( github.com/twmb/murmur3 v1.1.6 github.com/unrolled/secure v1.10.0 github.com/vmihailenco/msgpack/v5 v5.3.5 - golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect + golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70 // indirect golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 // indirect + golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 // indirect golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect ) diff --git a/go.sum b/go.sum index d0b1a02..18d1d60 100644 --- a/go.sum +++ b/go.sum @@ -78,8 +78,9 @@ github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NB github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/labstack/echo/v4 v4.6.3 h1:VhPuIZYxsbPmo4m9KAkMU/el2442eB7EBFFhNTTT9ac= github.com/labstack/echo/v4 v4.6.3/go.mod h1:Hk5OiHj0kDqmFq7aHe7eDqI7CUhuCrfpupQtLGGLm7A= +github.com/labstack/echo/v4 v4.7.0 h1:8wHgZhoE9OT1NSLw6sfrX7ZGpWMtO5Zlfr68+BIo180= +github.com/labstack/echo/v4 v4.7.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks= github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o= github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= @@ -159,8 +160,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE= -golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70 h1:syTAU9FwmvzEoIYMqcPHOcVm4H3U5u90WsvuYgwpETU= +golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -169,6 +170,7 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210913180222-943fd674d43e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= @@ -191,8 +193,8 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 h1:y/woIyUBFbpQGKS0u1aHF/40WUDnek3fPOyD08H5Vng= +golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/internal/app/fluitans/auth/authz.go b/internal/app/fluitans/auth/authz.go index 2231c72..e357b33 100644 --- a/internal/app/fluitans/auth/authz.go +++ b/internal/app/fluitans/auth/authz.go @@ -5,7 +5,7 @@ import ( "github.com/labstack/echo/v4" - "github.com/sargassum-world/fluitans/internal/clients/sessions" + "github.com/sargassum-world/fluitans/pkg/godest/session" ) // Authorization @@ -28,10 +28,10 @@ func (a Auth) RequireAuthorized() error { return echo.NewHTTPError(http.StatusNotFound, "unauthorized") } -func RequireAuthz(sc *sessions.Client) echo.MiddlewareFunc { +func RequireAuthz(sc *session.Client) echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { - a, _, err := GetWithSession(c, sc) + a, _, err := GetWithSession(c.Request(), sc, c.Logger()) if err != nil { return err } diff --git a/internal/app/fluitans/auth/middleware.go b/internal/app/fluitans/auth/middleware.go new file mode 100644 index 0000000..794f2a8 --- /dev/null +++ b/internal/app/fluitans/auth/middleware.go @@ -0,0 +1,89 @@ +package auth + +import ( + "github.com/gorilla/sessions" + "github.com/labstack/echo/v4" + "github.com/pkg/errors" + + "github.com/sargassum-world/fluitans/pkg/godest" + "github.com/sargassum-world/fluitans/pkg/godest/session" +) + +type ( + Handler func(c echo.Context, a Auth) error + HandlerWithSession func(c echo.Context, a Auth, sess *sessions.Session) error +) + +func Handle(h Handler, sc *session.Client) echo.HandlerFunc { + return func(c echo.Context) error { + a, sess, err := GetWithSession(c.Request(), sc, c.Logger()) + // We don't expect the handler to write to the session, so we save it now + if serr := sess.Save(c.Request(), c.Response()); serr != nil { + return errors.Wrap(err, "couldn't save new session to replace invalid session") + } + if err != nil { + return err + } + return h(c, a) + } +} + +func HandleWithSession(h HandlerWithSession, sc *session.Client) echo.HandlerFunc { + return func(c echo.Context) error { + a, sess, err := GetWithSession(c.Request(), sc, c.Logger()) + if err != nil { + return err + } + return h(c, a, sess) + } +} + +// Router is a routing adapter between echo.Handler and this package's Handler, by +// automatically extracting auth data from the session of the request. +type Router struct { + er godest.EchoRouter + sc *session.Client +} + +func NewRouter(er godest.EchoRouter, sc *session.Client) Router { + return Router{ + er: er, + sc: sc, + } +} + +func (r *Router) CONNECT(path string, h Handler, m ...echo.MiddlewareFunc) *echo.Route { + return r.er.CONNECT(path, Handle(h, r.sc), m...) +} + +func (r *Router) DELETE(path string, h Handler, m ...echo.MiddlewareFunc) *echo.Route { + return r.er.DELETE(path, Handle(h, r.sc), m...) +} + +func (r *Router) GET(path string, h Handler, m ...echo.MiddlewareFunc) *echo.Route { + return r.er.GET(path, Handle(h, r.sc), m...) +} + +func (r *Router) HEAD(path string, h Handler, m ...echo.MiddlewareFunc) *echo.Route { + return r.er.HEAD(path, Handle(h, r.sc), m...) +} + +func (r *Router) OPTIONS(path string, h Handler, m ...echo.MiddlewareFunc) *echo.Route { + return r.er.OPTIONS(path, Handle(h, r.sc), m...) +} + +func (r *Router) PATCH(path string, h Handler, m ...echo.MiddlewareFunc) *echo.Route { + return r.er.PATCH(path, Handle(h, r.sc), m...) +} + +func (r *Router) POST(path string, h Handler, m ...echo.MiddlewareFunc) *echo.Route { + return r.er.POST(path, Handle(h, r.sc), m...) +} + +func (r *Router) PUT(path string, h Handler, m ...echo.MiddlewareFunc) *echo.Route { + return r.er.PUT(path, Handle(h, r.sc), m...) +} + +func (r *Router) TRACE(path string, h Handler, m ...echo.MiddlewareFunc) *echo.Route { + return r.er.TRACE(path, Handle(h, r.sc), m...) +} diff --git a/internal/app/fluitans/auth/models.go b/internal/app/fluitans/auth/models.go index b246aed..fd2ce65 100644 --- a/internal/app/fluitans/auth/models.go +++ b/internal/app/fluitans/auth/models.go @@ -2,10 +2,7 @@ package auth import ( - "github.com/labstack/echo/v4" - - "github.com/sargassum-world/fluitans/internal/clients/sessions" - "github.com/sargassum-world/fluitans/pkg/godest" + "github.com/sargassum-world/fluitans/pkg/godest/session" ) type Identity struct { @@ -18,7 +15,7 @@ type CSRFBehavior struct { } type CSRF struct { - Config sessions.CSRFOptions + Config session.CSRFOptions Behavior CSRFBehavior Token string } @@ -27,85 +24,3 @@ type Auth struct { Identity Identity CSRF CSRF } - -// Middleware & Routing Adapter - -type AuthAwareHandler func(c echo.Context, a Auth) error - -func HandleWithAuth(h AuthAwareHandler, sc *sessions.Client) echo.HandlerFunc { - return func(c echo.Context) error { - a, _, err := GetWithSession(c, sc) - if err != nil { - return err - } - return h(c, a) - } -} - -// AuthAwareRouter is a routing adapter between echo.Handler and AuthAwareHandler, by automatically -// extracting auth data from the session of the request. -type AuthAwareRouter struct { - er godest.EchoRouter - sc *sessions.Client -} - -func NewAuthAwareRouter(er godest.EchoRouter, sc *sessions.Client) AuthAwareRouter { - return AuthAwareRouter{ - er: er, - sc: sc, - } -} - -func (r *AuthAwareRouter) CONNECT( - path string, h AuthAwareHandler, m ...echo.MiddlewareFunc, -) *echo.Route { - return r.er.CONNECT(path, HandleWithAuth(h, r.sc), m...) -} - -func (r *AuthAwareRouter) DELETE( - path string, h AuthAwareHandler, m ...echo.MiddlewareFunc, -) *echo.Route { - return r.er.DELETE(path, HandleWithAuth(h, r.sc), m...) -} - -func (r *AuthAwareRouter) GET( - path string, h AuthAwareHandler, m ...echo.MiddlewareFunc, -) *echo.Route { - return r.er.GET(path, HandleWithAuth(h, r.sc), m...) -} - -func (r *AuthAwareRouter) HEAD( - path string, h AuthAwareHandler, m ...echo.MiddlewareFunc, -) *echo.Route { - return r.er.HEAD(path, HandleWithAuth(h, r.sc), m...) -} - -func (r *AuthAwareRouter) OPTIONS( - path string, h AuthAwareHandler, m ...echo.MiddlewareFunc, -) *echo.Route { - return r.er.OPTIONS(path, HandleWithAuth(h, r.sc), m...) -} - -func (r *AuthAwareRouter) PATCH( - path string, h AuthAwareHandler, m ...echo.MiddlewareFunc, -) *echo.Route { - return r.er.PATCH(path, HandleWithAuth(h, r.sc), m...) -} - -func (r *AuthAwareRouter) POST( - path string, h AuthAwareHandler, m ...echo.MiddlewareFunc, -) *echo.Route { - return r.er.POST(path, HandleWithAuth(h, r.sc), m...) -} - -func (r *AuthAwareRouter) PUT( - path string, h AuthAwareHandler, m ...echo.MiddlewareFunc, -) *echo.Route { - return r.er.PUT(path, HandleWithAuth(h, r.sc), m...) -} - -func (r *AuthAwareRouter) TRACE( - path string, h AuthAwareHandler, m ...echo.MiddlewareFunc, -) *echo.Route { - return r.er.TRACE(path, HandleWithAuth(h, r.sc), m...) -} diff --git a/internal/app/fluitans/auth/sessions.go b/internal/app/fluitans/auth/sessions.go index 5b81d92..1c8402a 100644 --- a/internal/app/fluitans/auth/sessions.go +++ b/internal/app/fluitans/auth/sessions.go @@ -2,14 +2,14 @@ package auth import ( "encoding/gob" - "fmt" "net/http" "github.com/gorilla/csrf" "github.com/gorilla/sessions" - "github.com/labstack/echo/v4" + "github.com/pkg/errors" - sessionsc "github.com/sargassum-world/fluitans/internal/clients/sessions" + "github.com/sargassum-world/fluitans/pkg/godest" + "github.com/sargassum-world/fluitans/pkg/godest/session" ) // Identity @@ -25,20 +25,19 @@ func SetIdentity(s *sessions.Session, username string) { func GetIdentity(s sessions.Session) (identity Identity, err error) { if s.IsNew { - return + return Identity{}, nil } rawIdentity, ok := s.Values["identity"] if !ok { // A zero value for Identity indicates that the session has no identity associated with it - return + return Identity{}, nil } identity, ok = rawIdentity.(Identity) if !ok { - err = fmt.Errorf("unexpected type for field identity in session") - return + return Identity{}, errors.Errorf("unexpected type for field identity in session") } - return + return identity, nil } // CSRF @@ -53,7 +52,7 @@ func SetCSRFBehavior(s *sessions.Session, inlineToken bool) { func GetCSRFBehavior(s sessions.Session) (behavior CSRFBehavior, err error) { if s.IsNew { - return + return CSRFBehavior{}, nil } rawBehavior, ok := s.Values["csrfBehavior"] @@ -61,14 +60,13 @@ func GetCSRFBehavior(s sessions.Session) (behavior CSRFBehavior, err error) { // By default, HTML responses won't inline the CSRF input fields (so responses can be cached), // because the app only allows POST requests after user authentication. This default behavior // can be overridden, e.g. on the login form for user authentication, with OverrideCSRFInlining. - return + return CSRFBehavior{}, nil } behavior, ok = rawBehavior.(CSRFBehavior) if !ok { - err = fmt.Errorf("unexpected type for field csrfBehavior in session") - return + return CSRFBehavior{}, errors.Errorf("unexpected type for field csrfBehavior in session") } - return + return behavior, nil } func (c *CSRF) SetInlining(r *http.Request, inlineToken bool) { @@ -82,36 +80,42 @@ func (c *CSRF) SetInlining(r *http.Request, inlineToken bool) { // Access -func Get(c echo.Context, s sessions.Session, sc *sessionsc.Client) (a Auth, err error) { - return GetFromRequest(c.Request(), s, sc) +func Get(r *http.Request, s sessions.Session, sc *session.Client) (a Auth, err error) { + return GetFromRequest(r, s, sc) } -func GetFromRequest(r *http.Request, s sessions.Session, sc *sessionsc.Client) (a Auth, err error) { +func GetFromRequest(r *http.Request, s sessions.Session, sc *session.Client) (a Auth, err error) { a.Identity, err = GetIdentity(s) if err != nil { - return + return Auth{}, err } a.CSRF.Config = sc.Config.CSRFOptions a.CSRF.Behavior, err = GetCSRFBehavior(s) if err != nil { - return + return Auth{}, err } if a.CSRF.Behavior.InlineToken { a.CSRF.Token = csrf.Token(r) } - return + return a, nil } -func GetWithSession(c echo.Context, sc *sessionsc.Client) (a Auth, s *sessions.Session, err error) { - s, err = sc.Get(c) +func GetWithSession( + r *http.Request, sc *session.Client, l godest.Logger, +) (a Auth, s *sessions.Session, err error) { + s, err = sc.Get(r) if err != nil { - return Auth{}, nil, err + // If the user doesn't have a valid session, create one + if s, err = sc.New(r); err != nil { + // When an error is returned, a new (valid) session is still created + l.Warnf("created new session to replace invalid session") + } + // We let the caller save the new session } - a, err = Get(c, *s, sc) + a, err = Get(r, *s, sc) if err != nil { return Auth{}, s, err } - - return + return a, s, nil } diff --git a/internal/app/fluitans/client/globals.go b/internal/app/fluitans/client/globals.go index 86a454d..0d5aff1 100644 --- a/internal/app/fluitans/client/globals.go +++ b/internal/app/fluitans/client/globals.go @@ -5,72 +5,68 @@ import ( "github.com/pkg/errors" "github.com/sargassum-world/fluitans/internal/app/fluitans/conf" - "github.com/sargassum-world/fluitans/internal/clients/authn" "github.com/sargassum-world/fluitans/internal/clients/desec" - "github.com/sargassum-world/fluitans/internal/clients/sessions" "github.com/sargassum-world/fluitans/internal/clients/zerotier" "github.com/sargassum-world/fluitans/internal/clients/ztcontrollers" "github.com/sargassum-world/fluitans/pkg/godest" + "github.com/sargassum-world/fluitans/pkg/godest/authn" "github.com/sargassum-world/fluitans/pkg/godest/clientcache" + "github.com/sargassum-world/fluitans/pkg/godest/session" ) type Clients struct { Authn *authn.Client Desec *desec.Client - Sessions *sessions.Client + Sessions *session.Client Zerotier *zerotier.Client ZTControllers *ztcontrollers.Client } type Globals struct { Config conf.Config + Cache clientcache.Cache Clients *Clients } -func NewGlobals(l godest.Logger) (*Globals, error) { - config, err := conf.GetConfig() - if err != nil { +func NewGlobals(l godest.Logger) (g *Globals, err error) { + g = &Globals{} + if g.Config, err = conf.GetConfig(); err != nil { return nil, errors.Wrap(err, "couldn't set up application config") } - - cache, err := clientcache.NewRistrettoCache(config.Cache) - if err != nil { + if g.Cache, err = clientcache.NewRistrettoCache(g.Config.Cache); err != nil { return nil, errors.Wrap(err, "couldn't set up client cache") } + g.Clients = &Clients{} - authnClient, err := authn.NewClient(l) + authnConfig, err := authn.GetConfig() if err != nil { - return nil, errors.Wrap(err, "couldn't set up authn client") + return nil, errors.Wrap(err, "couldn't set up authn config") } + g.Clients.Authn = authn.NewClient(authnConfig) - desecClient, err := desec.NewClient(config.DomainName, cache, l) + desecConfig, err := desec.GetConfig(g.Config.DomainName) if err != nil { - return nil, errors.Wrap(err, "couldn't set up desec client") + return nil, errors.Wrap(err, "couldn't set up desec config") } + g.Clients.Desec = desec.NewClient(desecConfig, g.Cache, l) - sessionsClient, err := sessions.NewMemStoreClient(l) + sessionsConfig, err := session.GetConfig() if err != nil { - return nil, errors.Wrap(err, "couldn't set up sessions client") + return nil, errors.Wrap(err, "couldn't set up sessions config") } + g.Clients.Sessions = session.NewMemStoreClient(sessionsConfig) - ztClient, err := zerotier.NewClient(cache, l) + ztConfig, err := zerotier.GetConfig() if err != nil { - return nil, errors.Wrap(err, "couldn't set up zerotier client") + return nil, errors.Wrap(err, "couldn't set up zerotier config") } + g.Clients.Zerotier = zerotier.NewClient(ztConfig, g.Cache, l) - ztcClient, err := ztcontrollers.NewClient(cache, l) + ztcConfig, err := ztcontrollers.GetConfig() if err != nil { - return nil, errors.Wrap(err, "couldn't set up zerotier controllers client") + return nil, errors.Wrap(err, "couldn't set up zerotier controllers config") } + g.Clients.ZTControllers = ztcontrollers.NewClient(ztcConfig, g.Cache, l) - return &Globals{ - Config: config, - Clients: &Clients{ - Authn: authnClient, - Desec: desecClient, - Sessions: sessionsClient, - Zerotier: ztClient, - ZTControllers: ztcClient, - }, - }, nil + return g, nil } diff --git a/internal/app/fluitans/conf/cache.go b/internal/app/fluitans/conf/cache.go index 2f7f081..4aae766 100644 --- a/internal/app/fluitans/conf/cache.go +++ b/internal/app/fluitans/conf/cache.go @@ -7,33 +7,30 @@ import ( "github.com/sargassum-world/fluitans/pkg/godest/env" ) +const cacheEnvPrefix = "CACHE_" + func getCacheConfig() (c ristretto.Config, err error) { const defaultNumCounters = 3e6 // default: 300k items, ~9 MB of counters - c.NumCounters, err = env.GetInt64("FLUITANS_CACHE_NUMCOUNTERS", defaultNumCounters) + c.NumCounters, err = env.GetInt64(cacheEnvPrefix+"CACHE_NUMCOUNTERS", defaultNumCounters) if err != nil { - err = errors.Wrap(err, "couldn't make numCounters config") - return + return ristretto.Config{}, errors.Wrap(err, "couldn't make numCounters config") } const defaultMaxCost = 3e7 // default: up to 30 MB total with min cost weight of 1 - c.MaxCost, err = env.GetInt64("FLUITANS_CACHE_MAXCOST", defaultMaxCost) + c.MaxCost, err = env.GetInt64(cacheEnvPrefix+"MAXCOST", defaultMaxCost) if err != nil { - err = errors.Wrap(err, "couldn't make maxCost config") - return + return ristretto.Config{}, errors.Wrap(err, "couldn't make maxCost config") } const defaultBufferItems = 64 // default: ristretto's recommended value - c.BufferItems, err = env.GetInt64("FLUITANS_CACHE_BUFFERITEMS", defaultBufferItems) + c.BufferItems, err = env.GetInt64(cacheEnvPrefix+"BUFFERITEMS", defaultBufferItems) if err != nil { - err = errors.Wrap(err, "couldn't make bufferItems config") - return + return ristretto.Config{}, errors.Wrap(err, "couldn't make bufferItems config") } - c.Metrics, err = env.GetBool("FLUITANS_CACHE_METRICS") + c.Metrics, err = env.GetBool(cacheEnvPrefix + "METRICS") if err != nil { - err = errors.Wrap(err, "couldn't make metrics config") - return + return ristretto.Config{}, errors.Wrap(err, "couldn't make metrics config") } - - return + return c, nil } diff --git a/internal/app/fluitans/conf/conf.go b/internal/app/fluitans/conf/conf.go index b77762f..8ede67c 100644 --- a/internal/app/fluitans/conf/conf.go +++ b/internal/app/fluitans/conf/conf.go @@ -15,17 +15,14 @@ type Config struct { func GetConfig() (c Config, err error) { c.Cache, err = getCacheConfig() if err != nil { - err = errors.Wrap(err, "couldn't make cache config") - return + return Config{}, errors.Wrap(err, "couldn't make cache config") } c.DomainName = getDomainName() c.HTTP, err = getHTTPConfig() if err != nil { - err = errors.Wrap(err, "couldn't make http config") - return + return Config{}, errors.Wrap(err, "couldn't make http config") } - - return + return c, nil } diff --git a/internal/app/fluitans/conf/dns.go b/internal/app/fluitans/conf/dns.go index 5df262e..bde424a 100644 --- a/internal/app/fluitans/conf/dns.go +++ b/internal/app/fluitans/conf/dns.go @@ -4,6 +4,8 @@ import ( "os" ) +const dnsEnvPrefix = "DNS_" // note: this overlaps with the prefix for the desec client + func getDomainName() string { - return os.Getenv("FLUITANS_DOMAIN_NAME") + return os.Getenv(dnsEnvPrefix + "DOMAIN_NAME") } diff --git a/internal/app/fluitans/conf/http.go b/internal/app/fluitans/conf/http.go index 8295dcf..6d24e51 100644 --- a/internal/app/fluitans/conf/http.go +++ b/internal/app/fluitans/conf/http.go @@ -6,18 +6,18 @@ import ( "github.com/sargassum-world/fluitans/pkg/godest/env" ) +const httpEnvPrefix = "HTTP_" + type HTTPConfig struct { GzipLevel int } func getHTTPConfig() (c HTTPConfig, err error) { const defaultGzipLevel = 1 - rawGzipLevel, err := env.GetInt64("FLUITANS_HTTP_GZIPLEVEL", defaultGzipLevel) + rawGzipLevel, err := env.GetInt64(httpEnvPrefix+"GZIPLEVEL", defaultGzipLevel) if err != nil { - err = errors.Wrap(err, "couldn't make gzip level config") - return + return HTTPConfig{}, errors.Wrap(err, "couldn't make gzip level config") } c.GzipLevel = int(rawGzipLevel) - - return + return c, nil } diff --git a/internal/app/fluitans/httperr.go b/internal/app/fluitans/httperr.go index 62f4927..5be1af8 100644 --- a/internal/app/fluitans/httperr.go +++ b/internal/app/fluitans/httperr.go @@ -1,4 +1,3 @@ -// Package fluitans provides the Fluitans server. package fluitans import ( @@ -10,7 +9,6 @@ import ( "github.com/pkg/errors" "github.com/sargassum-world/fluitans/internal/app/fluitans/auth" - "github.com/sargassum-world/fluitans/internal/clients/sessions" "github.com/sargassum-world/fluitans/pkg/godest" "github.com/sargassum-world/fluitans/pkg/godest/httperr" "github.com/sargassum-world/fluitans/pkg/godest/session" @@ -22,15 +20,15 @@ type ErrorData struct { Messages []string } -func NewHTTPErrorHandler(tr godest.TemplateRenderer, sc *sessions.Client) echo.HTTPErrorHandler { +func NewHTTPErrorHandler(tr godest.TemplateRenderer, sc *session.Client) echo.HTTPErrorHandler { tr.MustHave("app/httperr.page.tmpl") return func(err error, c echo.Context) { c.Logger().Error(err) // Check authentication & authorization - a, sess, serr := auth.GetWithSession(c, sc) + a, sess, serr := auth.GetWithSession(c.Request(), sc, c.Logger()) if serr != nil { - c.Logger().Error(errors.Wrap(serr, "couldn't get session+auth in error handler")) + c.Logger().Error(errors.Wrap(serr, "couldn't get auth in error handler")) } // Process error code @@ -44,21 +42,19 @@ func NewHTTPErrorHandler(tr godest.TemplateRenderer, sc *sessions.Client) echo.H } // Consume & save session - if sess != nil { - messages, merr := session.GetErrorMessages(sess) - if merr != nil { - c.Logger().Error(errors.Wrap( - merr, "couldn't get error messages from session in error handler", - )) - } - errorData.Messages = messages - if err := sess.Save(c.Request(), c.Response()); err != nil { - c.Logger().Error(errors.Wrap(serr, "couldn't save session in error handler")) - } + messages, merr := session.GetErrorMessages(sess) + if merr != nil { + c.Logger().Error(errors.Wrap( + merr, "couldn't get error messages from session in error handler", + )) + } + errorData.Messages = messages + if err := sess.Save(c.Request(), c.Response()); err != nil { + c.Logger().Error(errors.Wrap(serr, "couldn't save session in error handler")) } // Produce output - tr.SetUncacheable(c.Response().Header()) + godest.SetUncacheable(c.Response().Header()) if perr := tr.Page( c.Response(), c.Request(), code, "app/httperr.page.tmpl", errorData, a, ); perr != nil { @@ -68,22 +64,19 @@ func NewHTTPErrorHandler(tr godest.TemplateRenderer, sc *sessions.Client) echo.H } func NewCSRFErrorHandler( - tr godest.TemplateRenderer, l echo.Logger, sc *sessions.Client, + tr godest.TemplateRenderer, l echo.Logger, sc *session.Client, ) http.HandlerFunc { tr.MustHave("app/httperr.page.tmpl") return func(w http.ResponseWriter, r *http.Request) { l.Error(csrf.FailureReason(r)) // Check authentication & authorization - sess, serr := session.Get(r, sc.Config.CookieName, sc.Store) + a, sess, serr := auth.GetWithSession(r, sc, l) if serr != nil { - l.Error(errors.Wrap(serr, "couldn't get session in error handler")) + l.Error(errors.Wrap(serr, "couldn't get auth in error handler")) } - var a auth.Auth - if sess != nil { - a, serr = auth.GetFromRequest(r, *sess, sc) - if serr != nil { - l.Error(errors.Wrap(serr, "couldn't get auth in error handler")) - } + // Save the session in case it was freshly generated + if err := sess.Save(r, w); err != nil { + l.Error(errors.Wrap(serr, "couldn't save session in error handler")) } // Generate error code @@ -101,7 +94,7 @@ func NewCSRFErrorHandler( } // Produce output - tr.SetUncacheable(w.Header()) + godest.SetUncacheable(w.Header()) if rerr := tr.Page(w, r, code, "app/httperr.page.tmpl", errorData, a); rerr != nil { l.Error(errors.Wrap(rerr, "couldn't render error page in error handler")) } diff --git a/internal/app/fluitans/routes/auth/routes.go b/internal/app/fluitans/routes/auth/routes.go index 02a33c3..8262e47 100644 --- a/internal/app/fluitans/routes/auth/routes.go +++ b/internal/app/fluitans/routes/auth/routes.go @@ -3,18 +3,18 @@ package auth import ( "github.com/sargassum-world/fluitans/internal/app/fluitans/auth" - "github.com/sargassum-world/fluitans/internal/clients/authn" - "github.com/sargassum-world/fluitans/internal/clients/sessions" "github.com/sargassum-world/fluitans/pkg/godest" + "github.com/sargassum-world/fluitans/pkg/godest/authn" + "github.com/sargassum-world/fluitans/pkg/godest/session" ) type Handlers struct { r godest.TemplateRenderer ac *authn.Client - sc *sessions.Client + sc *session.Client } -func New(r godest.TemplateRenderer, ac *authn.Client, sc *sessions.Client) *Handlers { +func New(r godest.TemplateRenderer, ac *authn.Client, sc *session.Client) *Handlers { return &Handlers{ r: r, ac: ac, @@ -23,8 +23,7 @@ func New(r godest.TemplateRenderer, ac *authn.Client, sc *sessions.Client) *Hand } func (h *Handlers) Register(er godest.EchoRouter) { - ar := auth.NewAuthAwareRouter(er, h.sc) er.GET("/csrf", h.HandleCSRFGet()) - ar.GET("/login", h.HandleLoginGet()) + er.GET("/login", auth.HandleWithSession(h.HandleLoginGet(), h.sc)) er.POST("/sessions", h.HandleSessionsPost()) } diff --git a/internal/app/fluitans/routes/auth/sessions.go b/internal/app/fluitans/routes/auth/sessions.go index 062fff1..d5bb175 100644 --- a/internal/app/fluitans/routes/auth/sessions.go +++ b/internal/app/fluitans/routes/auth/sessions.go @@ -7,10 +7,11 @@ import ( "strings" "github.com/gorilla/csrf" + "github.com/gorilla/sessions" "github.com/labstack/echo/v4" "github.com/sargassum-world/fluitans/internal/app/fluitans/auth" - "github.com/sargassum-world/fluitans/internal/clients/sessions" + "github.com/sargassum-world/fluitans/pkg/godest" "github.com/sargassum-world/fluitans/pkg/godest/session" ) @@ -22,17 +23,8 @@ type CSRFData struct { func (h *Handlers) HandleCSRFGet() echo.HandlerFunc { return func(c echo.Context) error { - // Get session - sess, err := h.sc.Get(c) - if err != nil { - return err - } - if err := sess.Save(c.Request(), c.Response()); err != nil { - return err - } - // Produce output - h.r.SetUncacheable(c.Response().Header()) + godest.SetUncacheable(c.Response().Header()) return c.JSON(http.StatusOK, CSRFData{ HeaderName: h.sc.Config.CSRFOptions.HeaderName, FieldName: h.sc.Config.CSRFOptions.FieldName, @@ -47,16 +39,10 @@ type LoginData struct { ErrorMessages []string } -func (h *Handlers) HandleLoginGet() auth.AuthAwareHandler { +func (h *Handlers) HandleLoginGet() auth.HandlerWithSession { t := "auth/login.page.tmpl" h.r.MustHave(t) - return func(c echo.Context, a auth.Auth) error { - // Check authentication & authorization - sess, err := h.sc.Get(c) - if err != nil { - return err - } - + return func(c echo.Context, a auth.Auth, sess *sessions.Session) error { // Consume & save session errorMessages, err := session.GetErrorMessages(sess) if err != nil { @@ -88,13 +74,14 @@ func sanitizeReturnURL(returnURL string) (*url.URL, error) { } func handleAuthenticationSuccess( - c echo.Context, username, returnURL string, omitCSRFToken bool, sc *sessions.Client, + c echo.Context, username, returnURL string, omitCSRFToken bool, sc *session.Client, ) error { // Update session - sess, err := sc.Regenerate(c) + sess, err := sc.Get(c.Request()) if err != nil { return err } + session.Regenerate(sess) auth.SetIdentity(sess, username) // This allows client-side Javascript to specify for server-side session data that we only need // to provide CSRF tokens through the /csrf route and we can omit them from HTML response @@ -113,9 +100,9 @@ func handleAuthenticationSuccess( return c.Redirect(http.StatusSeeOther, u.String()) } -func handleAuthenticationFailure(c echo.Context, returnURL string, sc *sessions.Client) error { +func handleAuthenticationFailure(c echo.Context, returnURL string, sc *session.Client) error { // Update session - sess, serr := sc.Get(c) + sess, serr := sc.Get(c.Request()) if serr != nil { return serr } @@ -170,10 +157,11 @@ func (h *Handlers) HandleSessionsPost() echo.HandlerFunc { case "unauthenticated": // TODO: add a client-side controller to automatically submit a logout request after the // idle timeout expires, and display an inactivity logout message - sess, err := h.sc.Invalidate(c) + sess, err := h.sc.Get(c.Request()) if err != nil { return err } + session.Invalidate(sess) if err := sess.Save(c.Request(), c.Response()); err != nil { return err } diff --git a/internal/app/fluitans/routes/controllers/controller.go b/internal/app/fluitans/routes/controllers/controller.go index 85131a4..844a0ce 100644 --- a/internal/app/fluitans/routes/controllers/controller.go +++ b/internal/app/fluitans/routes/controllers/controller.go @@ -53,7 +53,7 @@ func getControllerData( }, nil } -func (h *Handlers) HandleControllerGet() auth.AuthAwareHandler { +func (h *Handlers) HandleControllerGet() auth.Handler { t := "controllers/controller.page.tmpl" h.r.MustHave(t) return func(c echo.Context, a auth.Auth) error { diff --git a/internal/app/fluitans/routes/controllers/controllers.go b/internal/app/fluitans/routes/controllers/controllers.go index 2ad9ed1..80ceb07 100644 --- a/internal/app/fluitans/routes/controllers/controllers.go +++ b/internal/app/fluitans/routes/controllers/controllers.go @@ -6,7 +6,7 @@ import ( "github.com/sargassum-world/fluitans/internal/app/fluitans/auth" ) -func (h *Handlers) HandleControllersGet() auth.AuthAwareHandler { +func (h *Handlers) HandleControllersGet() auth.Handler { t := "controllers/controllers.page.tmpl" h.r.MustHave(t) return func(c echo.Context, a auth.Auth) error { diff --git a/internal/app/fluitans/routes/controllers/routes.go b/internal/app/fluitans/routes/controllers/routes.go index 803ff39..55ddaca 100644 --- a/internal/app/fluitans/routes/controllers/routes.go +++ b/internal/app/fluitans/routes/controllers/routes.go @@ -3,33 +3,30 @@ package controllers import ( "github.com/sargassum-world/fluitans/internal/app/fluitans/auth" - "github.com/sargassum-world/fluitans/internal/clients/sessions" "github.com/sargassum-world/fluitans/internal/clients/zerotier" "github.com/sargassum-world/fluitans/internal/clients/ztcontrollers" "github.com/sargassum-world/fluitans/pkg/godest" + "github.com/sargassum-world/fluitans/pkg/godest/session" ) type Handlers struct { r godest.TemplateRenderer ztcc *ztcontrollers.Client ztc *zerotier.Client - sc *sessions.Client } func New( - r godest.TemplateRenderer, - ztcc *ztcontrollers.Client, ztc *zerotier.Client, sc *sessions.Client, + r godest.TemplateRenderer, ztcc *ztcontrollers.Client, ztc *zerotier.Client, ) *Handlers { return &Handlers{ r: r, ztcc: ztcc, ztc: ztc, - sc: sc, } } -func (h *Handlers) Register(er godest.EchoRouter) { - ar := auth.NewAuthAwareRouter(er, h.sc) +func (h *Handlers) Register(er godest.EchoRouter, sc *session.Client) { + ar := auth.NewRouter(er, sc) ar.GET("/controllers", h.HandleControllersGet()) ar.GET("/controllers/:name", h.HandleControllerGet()) } diff --git a/internal/app/fluitans/routes/dns/routes.go b/internal/app/fluitans/routes/dns/routes.go index 039acb8..ecee4ec 100644 --- a/internal/app/fluitans/routes/dns/routes.go +++ b/internal/app/fluitans/routes/dns/routes.go @@ -4,10 +4,10 @@ package dns import ( "github.com/sargassum-world/fluitans/internal/app/fluitans/auth" "github.com/sargassum-world/fluitans/internal/clients/desec" - "github.com/sargassum-world/fluitans/internal/clients/sessions" "github.com/sargassum-world/fluitans/internal/clients/zerotier" "github.com/sargassum-world/fluitans/internal/clients/ztcontrollers" "github.com/sargassum-world/fluitans/pkg/godest" + "github.com/sargassum-world/fluitans/pkg/godest/session" ) type Handlers struct { @@ -15,24 +15,23 @@ type Handlers struct { dc *desec.Client ztc *zerotier.Client ztcc *ztcontrollers.Client - sc *sessions.Client } func New( r godest.TemplateRenderer, - dc *desec.Client, ztc *zerotier.Client, ztcc *ztcontrollers.Client, sc *sessions.Client, + dc *desec.Client, ztc *zerotier.Client, ztcc *ztcontrollers.Client, ) *Handlers { return &Handlers{ r: r, dc: dc, ztc: ztc, ztcc: ztcc, - sc: sc, } } -func (h *Handlers) Register(er godest.EchoRouter) { - ar := auth.NewAuthAwareRouter(er, h.sc) - ar.GET("/dns", h.HandleServerGet(), auth.RequireAuthz(h.sc)) - er.POST("/dns/:subname/:type", h.HandleRRsetPost(), auth.RequireAuthz(h.sc)) +func (h *Handlers) Register(er godest.EchoRouter, sc *session.Client) { + ar := auth.NewRouter(er, sc) + az := auth.RequireAuthz(sc) + ar.GET("/dns", h.HandleServerGet(), az) + er.POST("/dns/:subname/:type", h.HandleRRsetPost(), az) } diff --git a/internal/app/fluitans/routes/dns/server.go b/internal/app/fluitans/routes/dns/server.go index 8058115..830d4e6 100644 --- a/internal/app/fluitans/routes/dns/server.go +++ b/internal/app/fluitans/routes/dns/server.go @@ -71,7 +71,7 @@ func getServerData( }, nil } -func (h *Handlers) HandleServerGet() auth.AuthAwareHandler { +func (h *Handlers) HandleServerGet() auth.Handler { t := "dns/server.page.tmpl" h.r.MustHave(t) return func(c echo.Context, a auth.Auth) error { diff --git a/internal/app/fluitans/routes/home/routes.go b/internal/app/fluitans/routes/home/routes.go index 8cdd912..811aa0f 100644 --- a/internal/app/fluitans/routes/home/routes.go +++ b/internal/app/fluitans/routes/home/routes.go @@ -5,28 +5,26 @@ import ( "github.com/labstack/echo/v4" "github.com/sargassum-world/fluitans/internal/app/fluitans/auth" - "github.com/sargassum-world/fluitans/internal/clients/sessions" "github.com/sargassum-world/fluitans/pkg/godest" + "github.com/sargassum-world/fluitans/pkg/godest/session" ) type Handlers struct { - r godest.TemplateRenderer - sc *sessions.Client + r godest.TemplateRenderer } -func New(r godest.TemplateRenderer, sc *sessions.Client) *Handlers { +func New(r godest.TemplateRenderer) *Handlers { return &Handlers{ - r: r, - sc: sc, + r: r, } } -func (h *Handlers) Register(er godest.EchoRouter) { - ar := auth.NewAuthAwareRouter(er, h.sc) +func (h *Handlers) Register(er godest.EchoRouter, sc *session.Client) { + ar := auth.NewRouter(er, sc) ar.GET("/", h.HandleHomeGet()) } -func (h *Handlers) HandleHomeGet() auth.AuthAwareHandler { +func (h *Handlers) HandleHomeGet() auth.Handler { t := "home/home.page.tmpl" h.r.MustHave(t) return func(c echo.Context, a auth.Auth) error { diff --git a/internal/app/fluitans/routes/networks/devices.go b/internal/app/fluitans/routes/networks/devices.go index c160c79..b492b36 100644 --- a/internal/app/fluitans/routes/networks/devices.go +++ b/internal/app/fluitans/routes/networks/devices.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/labstack/echo/v4" + "github.com/pkg/errors" "github.com/sargassum-world/fluitans/internal/clients/desec" ztc "github.com/sargassum-world/fluitans/internal/clients/zerotier" @@ -78,7 +79,7 @@ func confirmMemberNameManageable( return "", err } if !named { - return "", fmt.Errorf("network does not have a valid domain name for naming members") + return "", errors.Errorf("network does not have a valid domain name for naming members") } hasMember := false for _, address := range memberAddresses { @@ -88,7 +89,7 @@ func confirmMemberNameManageable( } } if !hasMember { - return "", fmt.Errorf( + return "", errors.Errorf( "cannot set domain name for device which is not a network member", ) } diff --git a/internal/app/fluitans/routes/networks/network.go b/internal/app/fluitans/routes/networks/network.go index 11fa94d..bbbd41a 100644 --- a/internal/app/fluitans/routes/networks/network.go +++ b/internal/app/fluitans/routes/networks/network.go @@ -31,7 +31,7 @@ func getRecordsOfType( for subname, rrsets := range subnameRRsets { filtered := desecc.FilterAndSortRRsets(rrsets, []string{rrsetType}) if len(filtered) > 1 { - return nil, fmt.Errorf("unexpected number of RRsets for record") + return nil, errors.Errorf("unexpected number of RRsets for record") } if len(filtered) == 1 { records[subname] = filtered[0].Records @@ -54,7 +54,7 @@ func identifyMemberDomainNames( for memberAddress, member := range zerotierMembers { for _, ipAddress := range *member.IpAssignments { for _, subname := range addressDomainNames[ipAddress] { - domainName := fmt.Sprintf("%s.%s", subname, zoneDomainName) + domainName := subname + "." + zoneDomainName memberDomainNames[memberAddress] = append(memberDomainNames[memberAddress], domainName) } } @@ -124,7 +124,7 @@ func getMemberRecords( func checkNamedByDNS( ctx context.Context, networkName, networkID string, c *desecc.Client, ) (bool, error) { - domainSuffix := fmt.Sprintf(".%s", c.Config.DomainName) + domainSuffix := "." + c.Config.DomainName if !strings.HasSuffix(networkName, domainSuffix) { return false, nil } @@ -178,15 +178,15 @@ func getNetworkDNSRecords( ) (networkDNS NetworkDNS, err error) { namedByDNS, err := checkNamedByDNS(ctx, networkName, networkID, dc) if err != nil || !namedByDNS { - return + return NetworkDNS{}, err } networkDNS.Named = true txtRecords, err := getRecordsOfType(subnameRRsets, "TXT") if err != nil { - return + return NetworkDNS{}, err } - confirmedSubname := strings.TrimSuffix(networkName, fmt.Sprintf(".%s", dc.Config.DomainName)) + confirmedSubname := strings.TrimSuffix(networkName, "."+dc.Config.DomainName) networkDNS.Aliases = identifyNetworkAliases(networkID, confirmedSubname, txtRecords) aliases := make(map[string]bool, len(networkDNS.Aliases)) for _, alias := range networkDNS.Aliases { @@ -195,19 +195,19 @@ func getNetworkDNSRecords( subdomains, err := client.GetSubdomains(ctx, subnameRRsets, dc, c, cc) if err != nil { - return + return NetworkDNS{}, err } - networkSubname := strings.TrimSuffix(networkName, fmt.Sprintf(".%s", dc.Config.DomainName)) + networkSubname := strings.TrimSuffix(networkName, "."+dc.Config.DomainName) networkDNS.DeviceSubdomains = make(map[string]client.Subdomain) for _, subdomain := range subdomains { if subdomain.Subname != networkSubname && !strings.HasSuffix( - subdomain.Subname, fmt.Sprintf(".%s", networkSubname), + subdomain.Subname, "."+networkSubname, ) && !aliases[subdomain.Subname] { // Subdomain is unrelated to this network continue } - if strings.HasSuffix(subdomain.Subname, fmt.Sprintf(".d.%s", networkSubname)) { + if strings.HasSuffix(subdomain.Subname, ".d."+networkSubname) { // Subdomain is for a device networkDNS.DeviceSubdomains[subdomain.Subname] = subdomain continue @@ -215,8 +215,7 @@ func getNetworkDNSRecords( networkDNS.OtherSubdomains = append(networkDNS.OtherSubdomains, subdomain) } - - return + return networkDNS, nil } type NetworkData struct { @@ -243,11 +242,11 @@ func getNetworkData( var subnameRRsets map[string][]desec.RRset eg.Go(func() (err error) { network, memberAddresses, err = c.GetNetworkInfo(ctx, *controller, id) - return + return err }) eg.Go(func() (err error) { subnameRRsets, err = dc.GetRRsets(ctx) - return + return err }) if err = eg.Wait(); err != nil { return nil, err @@ -266,14 +265,14 @@ func getNetworkData( members, err = getMemberRecords( ctx, dc.Config.DomainName, *controller, *network, memberAddresses, subnameRRsets, c, ) - return + return err }) var networkDNS NetworkDNS eg.Go(func() (err error) { networkDNS, err = getNetworkDNSRecords( egctx, *network.Id, *network.Name, subnameRRsets, c, cc, dc, ) - return + return err }) if err := eg.Wait(); err != nil { return nil, err @@ -289,7 +288,7 @@ func getNetworkData( }, nil } -func (h *Handlers) HandleNetworkGet() auth.AuthAwareHandler { +func (h *Handlers) HandleNetworkGet() auth.Handler { t := "networks/network.page.tmpl" h.r.MustHave(t) return func(c echo.Context, a auth.Auth) error { @@ -317,12 +316,12 @@ func nameNetwork( } // Check to see if the network was already named by DNS - fqdn := fmt.Sprintf("%s.%s", name, dc.Config.DomainName) + fqdn := name + "." + dc.Config.DomainName txtRRset, err := dc.GetRRset(ctx, name, "TXT") if err != nil { - return errors.Wrap(err, fmt.Sprintf( - "couldn't check cache for DNS TXT RRset at %s for network %s", fqdn, id, - )) + return errors.Wrapf( + err, "couldn't check cache for DNS TXT RRset at %s for network %s", fqdn, id, + ) } if txtRRset != nil { if _, hasID := client.GetNetworkID(txtRRset.Records); hasID { @@ -338,9 +337,7 @@ func nameNetwork( // zerotier-net-id=... record (but we should have a global lock on a get-and-patch to avoid // data races) // TODO: if the returned error code was an HTTP error, preserve the status code - return errors.Wrap(err, fmt.Sprintf( - "couldn't create a DNS TXT RRset at %s for network %s", fqdn, id, - )) + return errors.Wrapf(err, "couldn't create a DNS TXT RRset at %s for network %s", fqdn, id) } return c.UpdateNetwork( ctx, controller, id, zerotier.SetControllerNetworkJSONRequestBody{Name: &fqdn}, diff --git a/internal/app/fluitans/routes/networks/networks.go b/internal/app/fluitans/routes/networks/networks.go index 2384c26..7fe3a73 100644 --- a/internal/app/fluitans/routes/networks/networks.go +++ b/internal/app/fluitans/routes/networks/networks.go @@ -44,7 +44,7 @@ func getNetworksData( return networksData, nil } -func (h *Handlers) HandleNetworksGet() auth.AuthAwareHandler { +func (h *Handlers) HandleNetworksGet() auth.Handler { t := "networks/networks.page.tmpl" h.r.MustHave(t) return func(c echo.Context, a auth.Auth) error { diff --git a/internal/app/fluitans/routes/networks/routes.go b/internal/app/fluitans/routes/networks/routes.go index fbd0dea..28409ea 100644 --- a/internal/app/fluitans/routes/networks/routes.go +++ b/internal/app/fluitans/routes/networks/routes.go @@ -4,10 +4,10 @@ package networks import ( "github.com/sargassum-world/fluitans/internal/app/fluitans/auth" "github.com/sargassum-world/fluitans/internal/clients/desec" - "github.com/sargassum-world/fluitans/internal/clients/sessions" "github.com/sargassum-world/fluitans/internal/clients/zerotier" "github.com/sargassum-world/fluitans/internal/clients/ztcontrollers" "github.com/sargassum-world/fluitans/pkg/godest" + "github.com/sargassum-world/fluitans/pkg/godest/session" ) type Handlers struct { @@ -15,34 +15,30 @@ type Handlers struct { dc *desec.Client ztc *zerotier.Client ztcc *ztcontrollers.Client - sc *sessions.Client } func New( r godest.TemplateRenderer, - dc *desec.Client, ztc *zerotier.Client, ztcc *ztcontrollers.Client, sc *sessions.Client, + dc *desec.Client, ztc *zerotier.Client, ztcc *ztcontrollers.Client, ) *Handlers { return &Handlers{ r: r, dc: dc, ztc: ztc, ztcc: ztcc, - sc: sc, } } -func (h *Handlers) Register(er godest.EchoRouter) { - ar := auth.NewAuthAwareRouter(er, h.sc) +func (h *Handlers) Register(er godest.EchoRouter, sc *session.Client) { + ar := auth.NewRouter(er, sc) + az := auth.RequireAuthz(sc) ar.GET("/networks", h.HandleNetworksGet()) - er.POST("/networks", h.HandleNetworksPost(), auth.RequireAuthz(h.sc)) + er.POST("/networks", h.HandleNetworksPost(), az) ar.GET("/networks/:id", h.HandleNetworkGet()) - er.POST("/networks/:id", h.HandleNetworkPost(), auth.RequireAuthz(h.sc)) - er.POST("/networks/:id/name", h.HandleNetworkNamePost(), auth.RequireAuthz(h.sc)) - er.POST("/networks/:id/rules", h.HandleNetworkRulesPost(), auth.RequireAuthz(h.sc)) - er.POST("/networks/:id/devices", h.HandleDevicesPost(), auth.RequireAuthz(h.sc)) - er.POST( - "/networks/:id/devices/:address/authorization", h.HandleDeviceAuthorizationPost(), - auth.RequireAuthz(h.sc), - ) - er.POST("/networks/:id/devices/:address/name", h.HandleDeviceNamePost(), auth.RequireAuthz(h.sc)) + er.POST("/networks/:id", h.HandleNetworkPost(), az) + er.POST("/networks/:id/name", h.HandleNetworkNamePost(), az) + er.POST("/networks/:id/rules", h.HandleNetworkRulesPost(), az) + er.POST("/networks/:id/devices", h.HandleDevicesPost(), az) + er.POST("/networks/:id/devices/:address/authorization", h.HandleDeviceAuthorizationPost(), az) + er.POST("/networks/:id/devices/:address/name", h.HandleDeviceNamePost(), az) } diff --git a/internal/app/fluitans/routes/routes.go b/internal/app/fluitans/routes/routes.go index c32897c..8213118 100644 --- a/internal/app/fluitans/routes/routes.go +++ b/internal/app/fluitans/routes/routes.go @@ -27,13 +27,13 @@ func New(r godest.TemplateRenderer, clients *client.Clients) *Handlers { func (h *Handlers) Register(er godest.EchoRouter, em godest.Embeds) { assets.RegisterStatic(er, em) assets.NewTemplated(h.r).Register(er) - home.New(h.r, h.clients.Sessions).Register(er) + home.New(h.r).Register(er, h.clients.Sessions) auth.New(h.r, h.clients.Authn, h.clients.Sessions).Register(er) - controllers.New(h.r, h.clients.ZTControllers, h.clients.Zerotier, h.clients.Sessions).Register(er) + controllers.New(h.r, h.clients.ZTControllers, h.clients.Zerotier).Register(er, h.clients.Sessions) networks.New( - h.r, h.clients.Desec, h.clients.Zerotier, h.clients.ZTControllers, h.clients.Sessions, - ).Register(er) + h.r, h.clients.Desec, h.clients.Zerotier, h.clients.ZTControllers, + ).Register(er, h.clients.Sessions) dns.New( - h.r, h.clients.Desec, h.clients.Zerotier, h.clients.ZTControllers, h.clients.Sessions, - ).Register(er) + h.r, h.clients.Desec, h.clients.Zerotier, h.clients.ZTControllers, + ).Register(er, h.clients.Sessions) } diff --git a/internal/app/fluitans/server.go b/internal/app/fluitans/server.go index e32359c..478fc3c 100644 --- a/internal/app/fluitans/server.go +++ b/internal/app/fluitans/server.go @@ -20,6 +20,7 @@ import ( imw "github.com/sargassum-world/fluitans/internal/middleware" "github.com/sargassum-world/fluitans/pkg/godest" gmw "github.com/sargassum-world/fluitans/pkg/godest/middleware" + "github.com/sargassum-world/fluitans/pkg/godest/session" "github.com/sargassum-world/fluitans/web" ) @@ -41,20 +42,16 @@ func NewServer(e *echo.Echo) (s *Server, err error) { ), ) if err != nil { - s = nil - err = errors.Wrap(err, "couldn't make template renderer") - return + return nil, errors.Wrap(err, "couldn't make template renderer") } s.Globals, err = client.NewGlobals(e.Logger) if err != nil { - s = nil - err = errors.Wrap(err, "couldn't make app globals") - return + return nil, errors.Wrap(err, "couldn't make app globals") } s.Handlers = routes.New(s.Renderer, s.Globals.Clients) - return + return s, nil } func (s *Server) Register(e *echo.Echo) { @@ -102,9 +99,10 @@ func (s *Server) Register(e *echo.Echo) { // Other Middleware e.Pre(middleware.RemoveTrailingSlash()) - e.Use(s.Globals.Clients.Sessions.NewCSRFMiddleware( + e.Use(echo.WrapMiddleware(session.NewCSRFMiddleware( + s.Globals.Clients.Sessions.Config, csrf.ErrorHandler(NewCSRFErrorHandler(s.Renderer, e.Logger, s.Globals.Clients.Sessions)), - )) + ))) e.Use(imw.RequireContentTypes(echo.MIMEApplicationForm)) // TODO: enable Prometheus and rate-limiting diff --git a/internal/clients/desec/cache.go b/internal/clients/desec/cache.go index 17de13f..334455d 100644 --- a/internal/clients/desec/cache.go +++ b/internal/clients/desec/cache.go @@ -98,9 +98,9 @@ func (c *Cache) SetRRsetsByName(domainName, subname string, rrsets []desec.RRset err := c.SetRRsetByNameAndType(domainName, subname, recordType, rrset) if err != nil { - return errors.Wrap(err, fmt.Sprintf( - "couldn't set cache entry for the %s RRset for %s.%s", recordType, subname, domainName, - )) + return errors.Wrapf( + err, "couldn't set cache entry for the %s RRset for %s.%s", recordType, subname, domainName, + ) } } return nil @@ -113,9 +113,9 @@ func (c *Cache) GetRRsetsByName(domainName, subname string) ([]desec.RRset, erro var value desec.RRset keyExists, valueExists, err := c.Cache.GetEntry(key, &value) if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf( - "couldn't get cache entry for the %s RRset for %s.%s", recordType, subname, domainName, - )) + return nil, errors.Wrapf( + err, "couldn't get cache entry for the %s RRset for %s.%s", recordType, subname, domainName, + ) } if !keyExists { diff --git a/internal/clients/desec/client.go b/internal/clients/desec/client.go index a34d2ed..852da2e 100644 --- a/internal/clients/desec/client.go +++ b/internal/clients/desec/client.go @@ -24,6 +24,23 @@ type Client struct { WriteLimiter *slidingwindows.MultiLimiter } +func NewClient(c Config, cache clientcache.Cache, l godest.Logger) *Client { + clientCache := Cache{ + Cache: cache, + CostWeight: c.DNSServer.NetworkCostWeight, + TTL: c.APISettings.ReadCacheTTL, + RecordTypes: c.RecordTypes, + } + readLimiter := desec.NewReadLimiter(0) + return &Client{ + Config: c, + Logger: l, + Cache: &clientCache, + ReadLimiter: readLimiter, + WriteLimiter: desec.NewRRSetWriteLimiter(0), + } +} + func (c *Client) handleDesecMissingDomainError(res http.Response) error { if res.StatusCode == http.StatusNotFound { c.Cache.SetNonexistentDomainByName(c.Config.DomainName) @@ -75,28 +92,6 @@ func (c *Client) tryAddLimitedRead() error { return nil } -func NewClient(domainName string, cache clientcache.Cache, l godest.Logger) (*Client, error) { - config, err := GetConfig(domainName) - if err != nil { - return nil, errors.Wrap(err, "couldn't set up desec client config") - } - - clientCache := Cache{ - Cache: cache, - CostWeight: config.DNSServer.NetworkCostWeight, - TTL: config.APISettings.ReadCacheTTL, - RecordTypes: config.RecordTypes, - } - readLimiter := desec.NewReadLimiter(0) - return &Client{ - Config: config, - Logger: l, - Cache: &clientCache, - ReadLimiter: readLimiter, - WriteLimiter: desec.NewRRSetWriteLimiter(0), - }, nil -} - // Rate-Limiting func CalculateBatchWaitDuration( diff --git a/internal/clients/desec/conf.go b/internal/clients/desec/conf.go index 9dbcb02..1cb7c35 100644 --- a/internal/clients/desec/conf.go +++ b/internal/clients/desec/conf.go @@ -11,6 +11,8 @@ import ( "github.com/sargassum-world/fluitans/pkg/godest/env" ) +const envPrefix = "DNS_" + type Config struct { DomainName string DNSServer models.DNSServer @@ -22,56 +24,49 @@ func GetConfig(domainName string) (c Config, err error) { c.DomainName = domainName c.DNSServer, err = getDNSServer() if err != nil { - err = errors.Wrap(err, "couldn't make DNS server config") - return + return Config{}, errors.Wrap(err, "couldn't make DNS server config") } c.APISettings, err = GetAPISettings() if err != nil { - err = errors.Wrap(err, "couldn't make deSEC API settings") - return + return Config{}, errors.Wrap(err, "couldn't make deSEC API settings") } c.RecordTypes = getRecordTypes() - return + return c, nil } func getDNSServer() (s models.DNSServer, err error) { - url, err := env.GetURLOrigin("FLUITANS_DNS_SERVER", "", "https") + url, err := env.GetURLOrigin(envPrefix+"SERVER", "", "https") if err != nil { - err = errors.Wrap(err, "couldn't make server url config") - return + return models.DNSServer{}, errors.Wrap(err, "couldn't make server url config") } s.Server = url.String() if len(s.Server) == 0 { - s = models.DNSServer{} - return + return models.DNSServer{}, nil } - s.API = strings.ToLower(env.GetString("FLUITANS_DNS_API", "desec")) + s.API = strings.ToLower(env.GetString(envPrefix+"API", "desec")) if len(s.API) == 0 { - s = models.DNSServer{} - return + return models.DNSServer{}, nil } - s.Authtoken = os.Getenv("FLUITANS_DNS_AUTHTOKEN") + s.Authtoken = os.Getenv(envPrefix + "AUTHTOKEN") if len(s.Authtoken) == 0 { - s = models.DNSServer{} - return + return models.DNSServer{}, nil } - s.Name = env.GetString("FLUITANS_DNS_NAME", url.Host) + s.Name = env.GetString(envPrefix+"NAME", url.Host) s.Description = env.GetString( - "FLUITANS_DNS_DESC", + envPrefix+"DESC", "The default deSEC DNS server account specified in the environment variables.", ) const defaultNetworkCost = 2.0 - s.NetworkCostWeight, err = env.GetFloat32("FLUITANS_DNS_NETWORKCOST", defaultNetworkCost) + s.NetworkCostWeight, err = env.GetFloat32(envPrefix+"NETWORKCOST", defaultNetworkCost) if err != nil { - err = errors.Wrap(err, "couldn't make network cost config") - return + return models.DNSServer{}, errors.Wrap(err, "couldn't make network cost config") } - return + return s, nil } func getReadCacheTTL() (time.Duration, error) { @@ -80,7 +75,7 @@ func getReadCacheTTL() (time.Duration, error) { // API read requests. The cache will be consistent with the API at an infinite TTL (the default // TTL) if we promise to only modify DNS records through Fluitans, and not independently through // the deSEC server. - rawTTL, err := env.GetFloat32("FLUITANS_DESEC_READ_CACHE_TTL", -1) + rawTTL, err := env.GetFloat32(envPrefix+"READ_CACHE_TTL", -1) var ttl time.Duration = -1 if rawTTL >= 0 { durationReadCacheTTL := time.Duration(rawTTL) * time.Second @@ -96,17 +91,15 @@ func getReadCacheTTL() (time.Duration, error) { func GetAPISettings() (s DesecAPISettings, err error) { s.ReadCacheTTL, err = getReadCacheTTL() if err != nil { - err = errors.Wrap(err, "couldn't make readCacheTTL config") - return + return DesecAPISettings{}, errors.Wrap(err, "couldn't make readCacheTTL config") } // The write limiter fill ratio above which RRset writes, rather than being executed immediately, // will first be batched into groups based on the nearest rate limit const defaultWriteSoftQuota = 0.34 - s.WriteSoftQuota, err = env.GetFloat32("FLUITANS_DESEC_WRITE_SOFT_QUOTA", defaultWriteSoftQuota) + s.WriteSoftQuota, err = env.GetFloat32(envPrefix+"WRITE_SOFT_QUOTA", defaultWriteSoftQuota) if err != nil { - err = errors.Wrap(err, "couldn't make writeSoftQuota config") - return + return DesecAPISettings{}, errors.Wrap(err, "couldn't make writeSoftQuota config") } if s.WriteSoftQuota < 0 { s.WriteSoftQuota = 0 @@ -114,8 +107,7 @@ func GetAPISettings() (s DesecAPISettings, err error) { if s.WriteSoftQuota > 1 { s.WriteSoftQuota = 1 } - - return + return s, nil } func getRecordTypes() []string { diff --git a/internal/clients/desec/domain.go b/internal/clients/desec/domain.go index 9c37b69..b86f01c 100644 --- a/internal/clients/desec/domain.go +++ b/internal/clients/desec/domain.go @@ -2,7 +2,6 @@ package desec import ( "context" - "fmt" "github.com/pkg/errors" @@ -16,9 +15,9 @@ func (c *Client) getDomainFromCache() (*desec.Domain, bool) { domain, cacheHit, err := c.Cache.GetDomainByName(domainName) if err != nil { // Log the error but return as a cache miss so we can manually query the domain - c.Logger.Error(errors.Wrap(err, fmt.Sprintf( - "couldn't get the cache entry for the domain with name %s", domainName, - ))) + c.Logger.Error(errors.Wrapf( + err, "couldn't get the cache entry for the domain with name %s", domainName, + )) return nil, false // treat an unparseable cache entry like a cache miss } return domain, cacheHit // cache hit with nil domain indicates nonexistent domain diff --git a/internal/clients/desec/rrsets.go b/internal/clients/desec/rrsets.go index 0c40c6e..4707adb 100644 --- a/internal/clients/desec/rrsets.go +++ b/internal/clients/desec/rrsets.go @@ -2,7 +2,6 @@ package desec import ( "context" - "fmt" "strings" "github.com/pkg/errors" @@ -45,9 +44,9 @@ func (c *Client) getRRsetsFromCache() map[string][]desec.RRset { subnames, err := c.Cache.GetSubnames(domainName) if err != nil { // Log the error but return as a cache miss so we can manually query the RRsets - c.Logger.Error(errors.Wrap(err, fmt.Sprintf( - "couldn't get the cache entry for the RRsets for %s", domainName, - ))) + c.Logger.Error(errors.Wrapf( + err, "couldn't get the cache entry for the RRsets for %s", domainName, + )) return nil // treat an unparseable cache entry like a cache miss } @@ -129,9 +128,9 @@ func (c *Client) getSubnameRRsetsFromCache(subname string) []desec.RRset { rrsets, err := c.Cache.GetRRsetsByName(domainName, subname) if err != nil { // Log the error but return as a cache miss so we can manually query the RRsets - c.Logger.Error(errors.Wrap(err, fmt.Sprintf( - "couldn't get the cache entry for one of the RRsets for %s.%s", subname, domainName, - ))) + c.Logger.Error(errors.Wrapf( + err, "couldn't get the cache entry for one of the RRsets for %s.%s", subname, domainName, + )) return nil // treat an unparseable cache entry like a cache miss } @@ -187,9 +186,10 @@ func (c *Client) getRRsetFromCache(subname, recordType string) (*desec.RRset, bo rrset, cacheHit, err := c.Cache.GetRRsetByNameAndType(domainName, subname, recordType) if err != nil { // Log the error but return as a cache miss so we can manually query the RRsets - c.Logger.Error(errors.Wrap(err, fmt.Sprintf( - "couldn't get the cache entry for the %s RRsets for %s.%s", recordType, subname, domainName, - ))) + c.Logger.Error(errors.Wrapf( + err, "couldn't get the cache entry for the %s RRsets for %s.%s", + recordType, subname, domainName, + )) return nil, false // treat an unparseable cache entry like a cache miss } diff --git a/internal/clients/sessions/client.go b/internal/clients/sessions/client.go deleted file mode 100644 index 16c554a..0000000 --- a/internal/clients/sessions/client.go +++ /dev/null @@ -1,74 +0,0 @@ -// Package sessions provides a high-level client for session management -package sessions - -import ( - "net/http" - - "github.com/gorilla/csrf" - "github.com/gorilla/sessions" - "github.com/labstack/echo/v4" - "github.com/pkg/errors" - "github.com/quasoft/memstore" - - "github.com/sargassum-world/fluitans/pkg/godest" - "github.com/sargassum-world/fluitans/pkg/godest/session" -) - -type Client struct { - Config Config - Logger godest.Logger - // TODO: allow configuration to use sqlite for a persistent session store - Store sessions.Store -} - -func (sc *Client) Get(c echo.Context) (*sessions.Session, error) { - return session.Get(c.Request(), sc.Config.CookieName, sc.Store) -} - -func (sc *Client) Regenerate(c echo.Context) (*sessions.Session, error) { - return session.Regenerate(c.Request(), sc.Config.CookieName, sc.Store) -} - -func (sc *Client) Invalidate(c echo.Context) (*sessions.Session, error) { - return session.Invalidate(c.Request(), sc.Config.CookieName, sc.Store) -} - -func (sc *Client) NewCSRFMiddleware(opts ...csrf.Option) echo.MiddlewareFunc { - sameSite := csrf.SameSiteDefaultMode - switch sc.Config.CookieOptions.SameSite { - case http.SameSiteLaxMode: - sameSite = csrf.SameSiteLaxMode - case http.SameSiteStrictMode: - sameSite = csrf.SameSiteStrictMode - case http.SameSiteNoneMode: - sameSite = csrf.SameSiteNoneMode - } - options := []csrf.Option{ - csrf.Path(sc.Config.CookieOptions.Path), - csrf.Domain(sc.Config.CookieOptions.Domain), - csrf.MaxAge(sc.Config.CookieOptions.MaxAge), - csrf.Secure(sc.Config.CookieOptions.Secure), - csrf.HttpOnly(sc.Config.CookieOptions.HttpOnly), - csrf.SameSite(sameSite), - csrf.RequestHeader(sc.Config.CSRFOptions.HeaderName), - csrf.FieldName(sc.Config.CSRFOptions.FieldName), - } - options = append(options, opts...) - return echo.WrapMiddleware(csrf.Protect(sc.Config.AuthKey, options...)) -} - -func NewMemStoreClient(l godest.Logger) (*Client, error) { - config, err := GetConfig() - if err != nil { - return nil, errors.Wrap(err, "couldn't set up sessions client config") - } - - store := memstore.NewMemStore(config.AuthKey) - store.Options = &config.CookieOptions - - return &Client{ - Config: config, - Logger: l, - Store: store, - }, nil -} diff --git a/internal/clients/zerotier/client.go b/internal/clients/zerotier/client.go index de1a3b1..d4c06a2 100644 --- a/internal/clients/zerotier/client.go +++ b/internal/clients/zerotier/client.go @@ -2,8 +2,6 @@ package zerotier import ( - "github.com/pkg/errors" - "github.com/sargassum-world/fluitans/pkg/godest" "github.com/sargassum-world/fluitans/pkg/godest/clientcache" ) @@ -14,17 +12,12 @@ type Client struct { Cache *Cache } -func NewClient(cache clientcache.Cache, l godest.Logger) (*Client, error) { - config, err := GetConfig() - if err != nil { - return nil, errors.Wrap(err, "couldn't set up zerotier client config") - } - +func NewClient(c Config, cache clientcache.Cache, l godest.Logger) *Client { return &Client{ - Config: config, + Config: c, Logger: l, Cache: &Cache{ Cache: cache, }, - }, nil + } } diff --git a/internal/clients/zerotier/conf.go b/internal/clients/zerotier/conf.go index 152f41c..9444e12 100644 --- a/internal/clients/zerotier/conf.go +++ b/internal/clients/zerotier/conf.go @@ -6,6 +6,8 @@ import ( "github.com/sargassum-world/fluitans/pkg/godest/env" ) +const envPrefix = "ZEROTIER_" + type Config struct { DNS ZTDNSSettings } @@ -13,34 +15,31 @@ type Config struct { func GetConfig() (c Config, err error) { c.DNS, err = GetDNSSettings() if err != nil { - err = errors.Wrap(err, "couldn't make Zerotier DNS settings") - return + return Config{}, errors.Wrap(err, "couldn't make Zerotier DNS settings") } - return + return c, nil } func getNetworkTTL() (int64, error) { const defaultTTL = 24 * 60 * 60 // default: 24 hours - return env.GetInt64("FLUITANS_ZEROTIER_DNS_NETWORKTTL", defaultTTL) + return env.GetInt64(envPrefix+"DNS_NETWORKTTL", defaultTTL) } func getDeviceTTL() (int64, error) { const defaultTTL = 1 * 60 * 60 // default: 1 hour - return env.GetInt64("FLUITANS_ZEROTIER_DNS_DEVICETTL", defaultTTL) + return env.GetInt64(envPrefix+"DNS_DEVICETTL", defaultTTL) } func GetDNSSettings() (s ZTDNSSettings, err error) { s.NetworkTTL, err = getNetworkTTL() if err != nil { - err = errors.Wrap(err, "couldn't make network record TTL config") - return + return ZTDNSSettings{}, errors.Wrap(err, "couldn't make network record TTL config") } s.DeviceTTL, err = getDeviceTTL() if err != nil { - err = errors.Wrap(err, "couldn't make device record TTL config") - return + return ZTDNSSettings{}, errors.Wrap(err, "couldn't make device record TTL config") } - return + return s, nil } diff --git a/internal/clients/zerotier/networks.go b/internal/clients/zerotier/networks.go index 94822a0..ba5d558 100644 --- a/internal/clients/zerotier/networks.go +++ b/internal/clients/zerotier/networks.go @@ -3,7 +3,6 @@ package zerotier import ( "context" "encoding/json" - "fmt" "net/http" "github.com/pkg/errors" @@ -26,9 +25,9 @@ func (c *Client) getNetworkIDsFromCache( networkIDs, err := cc.Cache.GetNetworkIDsByServer(controller.Server) if err != nil { // Log the error but return as a cache miss so we can manually query the network IDs - c.Logger.Error(errors.Wrap(err, fmt.Sprintf( - "couldn't get the cache entry for the network IDs controlled by %s", controller.Name, - ))) + c.Logger.Error(errors.Wrapf( + err, "couldn't get the cache entry for the network IDs controlled by %s", controller.Name, + )) return nil // treat an unparseable cache entry like a cache miss } @@ -85,7 +84,7 @@ func (c *Client) GetAllNetworkIDs( eg.Go(func(i int, controller ztcontrollers.Controller) func() error { return func() (err error) { allNetworkIDs[i], err = c.GetNetworkIDs(ctx, controller, cc) - return + return err } }(i, controller)) } @@ -104,7 +103,7 @@ func (c *Client) GetNetworks( eg.Go(func(i int, id string) func() error { return func() (err error) { networks[i], err = c.GetNetwork(ctx, controller, id) - return + return err } }(i, id)) } @@ -126,7 +125,7 @@ func (c *Client) GetAllNetworks( ctx context.Context, controllers []ztcontrollers.Controller, ids [][]string, ) ([]map[string]zerotier.ControllerNetwork, error) { if len(controllers) != len(ids) { - return nil, fmt.Errorf("lists of controllers and ids must have the same length") + return nil, errors.Errorf("lists of controllers and ids must have the same length") } eg, ctx := errgroup.WithContext(ctx) @@ -135,7 +134,7 @@ func (c *Client) GetAllNetworks( eg.Go(func(i int, controller ztcontrollers.Controller, someIDs []string) func() error { return func() (err error) { allNetworks[i], err = c.GetNetworks(ctx, controller, someIDs) - return + return err } }(i, controller, ids[i])) } @@ -152,9 +151,7 @@ func (c *Client) getNetworkFromCache(id string) (*zerotier.ControllerNetwork, bo network, cacheHit, err := c.Cache.GetNetworkByID(id) if err != nil { // Log the error but return as a cache miss so we can manually query the network - c.Logger.Error(errors.Wrap(err, fmt.Sprintf( - "couldn't get the cache entry for the network with id %s", id, - ))) + c.Logger.Error(errors.Wrapf(err, "couldn't get the cache entry for the network with id %s", id)) return nil, false // treat an unparseable cache entry like a cache miss } return network, cacheHit // cache hit with nil rrset indicates nonexistent RRset @@ -197,9 +194,9 @@ func (c *Client) getNetworkMemberAddressesFromCache(networkID string) []string { addresses, err := c.Cache.GetNetworkMembersByID(networkID) if err != nil { // Log the error but return as a cache miss so we can manually query the member addresses - c.Logger.Error(errors.Wrap(err, fmt.Sprintf( - "couldn't get the cache entry for the member addresses of network %s", networkID, - ))) + c.Logger.Error(errors.Wrapf( + err, "couldn't get the cache entry for the member addresses of network %s", networkID, + )) return nil // treat an unparseable cache entry like a cache miss } @@ -253,11 +250,11 @@ func (c *Client) GetNetworkInfo( var addresses []string eg.Go(func() (err error) { network, err = c.GetNetwork(ctx, controller, id) - return + return err }) eg.Go(func() (err error) { addresses, err = c.GetNetworkMemberAddresses(ctx, controller, id) - return + return err }) if err := eg.Wait(); err != nil { return nil, nil, err diff --git a/internal/clients/zerotier/status.go b/internal/clients/zerotier/status.go index 9078947..252e5fa 100644 --- a/internal/clients/zerotier/status.go +++ b/internal/clients/zerotier/status.go @@ -52,11 +52,11 @@ func (c *Client) GetControllerInfo( var networkIDs []string eg.Go(func() (err error) { status, controllerStatus, err = c.GetControllerStatuses(ctx, controller, cc) - return + return err }) eg.Go(func() (err error) { networkIDs, err = c.GetNetworkIDs(ctx, controller, cc) - return + return err }) if err := eg.Wait(); err != nil { return nil, nil, nil, err diff --git a/internal/clients/ztcontrollers/client.go b/internal/clients/ztcontrollers/client.go index 0de022d..1745670 100644 --- a/internal/clients/ztcontrollers/client.go +++ b/internal/clients/ztcontrollers/client.go @@ -3,8 +3,6 @@ package ztcontrollers import ( - "github.com/pkg/errors" - "github.com/sargassum-world/fluitans/pkg/godest" "github.com/sargassum-world/fluitans/pkg/godest/clientcache" ) @@ -15,17 +13,12 @@ type Client struct { Cache *Cache } -func NewClient(cache clientcache.Cache, l godest.Logger) (*Client, error) { - config, err := GetConfig() - if err != nil { - return nil, errors.Wrap(err, "couldn't set up zerotier controllers client config") - } - +func NewClient(c Config, cache clientcache.Cache, l godest.Logger) *Client { return &Client{ - Config: config, + Config: c, Logger: l, Cache: &Cache{ Cache: cache, }, - }, nil + } } diff --git a/internal/clients/ztcontrollers/conf.go b/internal/clients/ztcontrollers/conf.go index e37a341..82ef5de 100644 --- a/internal/clients/ztcontrollers/conf.go +++ b/internal/clients/ztcontrollers/conf.go @@ -8,6 +8,8 @@ import ( "github.com/sargassum-world/fluitans/pkg/godest/env" ) +const envPrefix = "ZTCONTROLLER_" + type Config struct { Controller Controller } @@ -15,43 +17,36 @@ type Config struct { func GetConfig() (c Config, err error) { c.Controller, err = GetController() if err != nil { - err = errors.Wrap(err, "couldn't make Zerotier controller config") - return + return Config{}, errors.Wrap(err, "couldn't make Zerotier controller config") } - - return + return c, nil } func GetController() (c Controller, err error) { - url, err := env.GetURLOrigin("FLUITANS_ZT_CONTROLLER_SERVER", "", "http") + url, err := env.GetURLOrigin(envPrefix+"SERVER", "", "http") if err != nil { - err = errors.Wrap(err, "couldn't make server url config") - return + return Controller{}, errors.Wrap(err, "couldn't make server url config") } c.Server = url.String() if len(c.Server) == 0 { - c = Controller{} - return + return Controller{}, nil } - c.Authtoken = os.Getenv("FLUITANS_ZT_CONTROLLER_AUTHTOKEN") + c.Authtoken = os.Getenv(envPrefix + "AUTHTOKEN") if len(c.Authtoken) == 0 { - c = Controller{} - return + return Controller{}, nil } - c.Name = env.GetString("FLUITANS_ZT_CONTROLLER_NAME", url.Host) + c.Name = env.GetString(envPrefix+"NAME", url.Host) c.Description = env.GetString( - "FLUITANS_ZT_CONTROLLER_DESC", + envPrefix+"DESC", "The default ZeroTier network controller specified in the environment variables.", ) const defaultNetworkCost = 1.0 - c.NetworkCostWeight, err = env.GetFloat32("FLUITANS_ZT_CONTROLLER_NETWORKCOST", defaultNetworkCost) + c.NetworkCostWeight, err = env.GetFloat32(envPrefix+"NETWORKCOST", defaultNetworkCost) if err != nil { - err = errors.Wrap(err, "couldn't make network cost config") - return + return Controller{}, errors.Wrap(err, "couldn't make network cost config") } - - return + return c, nil } diff --git a/internal/clients/ztcontrollers/controllers.go b/internal/clients/ztcontrollers/controllers.go index aa30a43..9c51fb6 100644 --- a/internal/clients/ztcontrollers/controllers.go +++ b/internal/clients/ztcontrollers/controllers.go @@ -119,9 +119,9 @@ func (c *Client) FindControllerByAddress(ctx context.Context, address string) (* controller, err := c.checkCachedController(ctx, address) if err != nil { // Log the error and proceed to manually query all controllers - c.Logger.Error(err, errors.Wrap(err, fmt.Sprintf( - "couldn't handle the cache entry for the zerotier controller with address %s", address, - ))) + c.Logger.Error(err, errors.Wrapf( + err, "couldn't handle the cache entry for the zerotier controller with address %s", address, + )) } else if controller != nil { return controller, nil } @@ -155,9 +155,9 @@ func (c *Client) getAddressFromCache(controller Controller) (string, bool) { address, cacheHit, err := c.Cache.GetAddressByServer(controller.Server) if err != nil { // Log the error but return as a cache miss so we can manually query the RRsets - c.Logger.Error(errors.Wrap(err, fmt.Sprintf( - "couldn't get the cache entry for the Zerotier address for %s", controller.Server, - ))) + c.Logger.Error(errors.Wrapf( + err, "couldn't get the cache entry for the Zerotier address for %s", controller.Server, + )) return "", false // treat an unparseable cache entry like a cache miss } diff --git a/internal/clients/authn/client.go b/pkg/godest/authn/client.go similarity index 75% rename from internal/clients/authn/client.go rename to pkg/godest/authn/client.go index d42baa0..b671a22 100644 --- a/internal/clients/authn/client.go +++ b/pkg/godest/authn/client.go @@ -5,26 +5,16 @@ import ( "crypto/subtle" "github.com/alexedwards/argon2id" - "github.com/pkg/errors" - - "github.com/sargassum-world/fluitans/pkg/godest" ) type Client struct { Config Config - Logger godest.Logger } -func NewClient(l godest.Logger) (*Client, error) { - config, err := GetConfig() - if err != nil { - return nil, errors.Wrap(err, "couldn't set up sessions client config") - } - +func NewClient(c Config) *Client { return &Client{ - Config: *config, - Logger: l, - }, nil + Config: c, + } } func (c *Client) CheckCredentials(username, password string) (bool, error) { diff --git a/internal/clients/authn/conf.go b/pkg/godest/authn/conf.go similarity index 57% rename from internal/clients/authn/conf.go rename to pkg/godest/authn/conf.go index 326d8d0..47eb965 100644 --- a/internal/clients/authn/conf.go +++ b/pkg/godest/authn/conf.go @@ -9,6 +9,8 @@ import ( "github.com/sargassum-world/fluitans/pkg/godest/env" ) +const envPrefix = "AUTHN_" + type Config struct { NoAuth bool Argon2idParams argon2id.Params @@ -16,50 +18,47 @@ type Config struct { AdminPasswordHash string } -func GetConfig() (*Config, error) { - noAuth, err := getNoAuth() +func GetConfig() (c Config, err error) { + c.NoAuth, err = getNoAuth() if err != nil { - return nil, errors.Wrap(err, "couldn't make authentication config") + return Config{}, errors.Wrap(err, "couldn't make authentication config") } - argon2idParams, err := getArgon2idParams() + c.Argon2idParams, err = getArgon2idParams() if err != nil { - return nil, errors.Wrap(err, "couldn't make password hashing config") + return Config{}, errors.Wrap(err, "couldn't make password hashing config") } - adminPasswordHash, err := getAdminPasswordHash(argon2idParams, noAuth) + c.AdminUsername = getAdminUsername() + + c.AdminPasswordHash, err = getAdminPasswordHash(c.Argon2idParams, c.NoAuth) if err != nil { - return nil, errors.Wrap(err, "couldn't make admin password hash config") + return Config{}, errors.Wrap(err, "couldn't make admin password hash config") } - return &Config{ - NoAuth: noAuth, - Argon2idParams: argon2idParams, - AdminUsername: getAdminUsername(), - AdminPasswordHash: adminPasswordHash, - }, nil + return c, nil } func getNoAuth() (bool, error) { - return env.GetBool("FLUITANS_AUTHN_NOAUTH") + return env.GetBool(envPrefix + "NOAUTH") } func getArgon2idParams() (argon2id.Params, error) { var defaultMemorySize uint64 = 64 // default: 64 MiB - memorySize, err := env.GetUint64("FLUITANS_AUTHN_ARGON2ID_M", defaultMemorySize) + memorySize, err := env.GetUint64(envPrefix+"ARGON2ID_M", defaultMemorySize) if err != nil { return argon2id.Params{}, errors.Wrap(err, "couldn't make memorySize config") } memorySize *= 1024 var defaultIterations uint64 = 1 // default: 1 iteration over the memory - iterations, err := env.GetUint64("FLUITANS_AUTHN_ARGON2ID_T", defaultIterations) + iterations, err := env.GetUint64(envPrefix+"ARGON2ID_T", defaultIterations) if err != nil { return argon2id.Params{}, errors.Wrap(err, "couldn't make iterations config") } var defaultParallelism uint64 = 2 // default: 2 threads/lanes - parallelism, err := env.GetUint64("FLUITANS_AUTHN_ARGON2ID_P", defaultParallelism) + parallelism, err := env.GetUint64(envPrefix+"ARGON2ID_P", defaultParallelism) if err != nil { return argon2id.Params{}, errors.Wrap(err, "couldn't make parallelism config") } @@ -76,16 +75,16 @@ func getArgon2idParams() (argon2id.Params, error) { } func getAdminUsername() string { - return env.GetString("FLUITANS_AUTHN_ADMIN_USERNAME", "admin") + return env.GetString(envPrefix+"ADMIN_USERNAME", "admin") } func getAdminPasswordHash(argon2idParams argon2id.Params, noAuth bool) (hash string, err error) { - hash = env.GetString("FLUITANS_AUTHN_ADMIN_PW_HASH", "") + hash = env.GetString(envPrefix+"ADMIN_PW_HASH", "") if len(hash) == 0 && !noAuth { - password := env.GetString("FLUITANS_AUTHN_ADMIN_PW", "") + password := env.GetString(envPrefix+"ADMIN_PW", "") if len(password) == 0 { - return "", fmt.Errorf( - "must provide a password for the admin account with FLUITANS_AUTHN_ADMIN_PW", + return "", errors.Errorf( + "must provide a password for the admin account with %sADMIN_PW", envPrefix, ) } @@ -94,9 +93,9 @@ func getAdminPasswordHash(argon2idParams argon2id.Params, noAuth bool) (hash str return "", err } fmt.Printf( - "Record this admin password hash for future use as FLUITANS_AUTHN_ADMIN_PW_HASH "+ + "Record this admin password hash for future use as %sADMIN_PW_HASH "+ "(use single-quotes from shell to avoid string substitution with dollar-signs): %s\n", - hash, + envPrefix, hash, ) } diff --git a/pkg/godest/clientcache/marshalling.go b/pkg/godest/clientcache/marshalling.go index 5c10fb4..c948c8a 100644 --- a/pkg/godest/clientcache/marshalling.go +++ b/pkg/godest/clientcache/marshalling.go @@ -3,7 +3,6 @@ package clientcache import ( "bytes" "encoding/gob" - "fmt" "github.com/pkg/errors" "github.com/vmihailenco/msgpack/v5" @@ -29,7 +28,7 @@ func (m *GobMarshaller) Marshal(value interface{}) ([]byte, error) { var buf bytes.Buffer enc := gob.NewEncoder(&buf) if err := enc.Encode(value); err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("couldn't gob-encode value %#v", value)) + return nil, errors.Wrapf(err, "couldn't gob-encode value %#v", value) } return buf.Bytes(), nil } @@ -38,9 +37,7 @@ func (m *GobMarshaller) Unmarshal(marshaled []byte, result interface{}) error { buf := bytes.NewBuffer(marshaled) dec := gob.NewDecoder(buf) if err := dec.Decode(result); err != nil { - return errors.Wrap(err, fmt.Sprintf( - "couldn't gob-decode type %T from bytes %+v", result, marshaled, - )) + return errors.Wrapf(err, "couldn't gob-decode type %T from bytes %+v", result, marshaled) } return nil } @@ -58,7 +55,7 @@ func (m *MsgPackMarshaller) Marshal(value interface{}) ([]byte, error) { enc := msgpack.NewEncoder(&buf) enc.SetCustomStructTag("json") if err := enc.Encode(value); err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("couldn't msgpack-encode value %#v", value)) + return nil, errors.Wrapf(err, "couldn't msgpack-encode value %#v", value) } return buf.Bytes(), nil } @@ -68,9 +65,7 @@ func (m *MsgPackMarshaller) Unmarshal(marshaled []byte, result interface{}) erro dec := msgpack.NewDecoder(buf) dec.SetCustomStructTag("json") if err := dec.Decode(result); err != nil { - return errors.Wrap(err, fmt.Sprintf( - "couldn't msgpack-decode type %T from bytes %+v", result, marshaled, - )) + return errors.Wrapf(err, "couldn't msgpack-decode type %T from bytes %+v", result, marshaled) } return nil } diff --git a/pkg/godest/clientcache/ristretto.go b/pkg/godest/clientcache/ristretto.go index 7f3ddf4..0cfe84c 100644 --- a/pkg/godest/clientcache/ristretto.go +++ b/pkg/godest/clientcache/ristretto.go @@ -1,7 +1,6 @@ package clientcache import ( - "fmt" "time" "github.com/dgraph-io/ristretto" @@ -36,7 +35,7 @@ func (c *RistrettoCache) SetEntry( ) error { marshaled, err := c.marshaller.Marshal(value) if err != nil { - return errors.Wrap(err, fmt.Sprintf("couldn't marshal value for key %s", key)) + return errors.Wrapf(err, "couldn't marshal value for key %s", key) } if ttl < 0 { @@ -71,12 +70,12 @@ func (c *RistrettoCache) GetEntry(key string, value interface{}) (bool, bool, er switch marshaledBytes := entryRaw.(type) { default: - return true, false, fmt.Errorf("invalid cache entry %s has unexpected type %T", key, entryRaw) + return true, false, errors.Errorf("cache entry %s has unexpected type %T", key, entryRaw) case nonexistentValue: return true, false, nil case []byte: if err := c.marshaller.Unmarshal(marshaledBytes, value); err != nil { - return true, true, errors.Wrap(err, fmt.Sprintf("couldn't unmarshal value for key %s", key)) + return true, true, errors.Wrapf(err, "couldn't unmarshal value for key %s", key) } return true, true, nil diff --git a/pkg/godest/embeds.go b/pkg/godest/embeds.go index a6ef427..73c58b7 100644 --- a/pkg/godest/embeds.go +++ b/pkg/godest/embeds.go @@ -10,20 +10,16 @@ import ( "github.com/benbjohnson/hashfs" "github.com/pkg/errors" - - "github.com/sargassum-world/fluitans/pkg/godest/fingerprint" - "github.com/sargassum-world/fluitans/pkg/godest/fsutil" - tp "github.com/sargassum-world/fluitans/pkg/godest/template" ) -func ComputeCSPHash(resource []byte) string { +func computeCSPHash(resource []byte) string { rawHash := sha512.Sum512(resource) encodedHash := base64.StdEncoding.EncodeToString(rawHash[:]) return fmt.Sprintf("'sha512-%s'", encodedHash) } func identifyModuleNonpageFiles(templates fs.FS) (map[string][]string, error) { - modules, err := fsutil.ListDirectories(templates, tp.FilterModule) + modules, err := listDirectories(templates, filterTemplateModule) if err != nil { return nil, errors.Wrap(err, "couldn't list template modules") } @@ -37,19 +33,19 @@ func identifyModuleNonpageFiles(templates fs.FS) (map[string][]string, error) { subfs, err = fs.Sub(templates, module) } if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("couldn't list template module %s", module)) + return nil, errors.Wrapf(err, "couldn't list template module %s", module) } - moduleSubfiles, err := fsutil.ListFiles(subfs, tp.FilterNonpage) + moduleSubfiles, err := listFiles(subfs, filterNonpageTemplate) moduleFiles[module] = make([]string, len(moduleSubfiles)) for i, subfile := range moduleSubfiles { if module == "" { moduleFiles[module][i] = subfile } else { - moduleFiles[module][i] = fmt.Sprintf("%s/%s", module, subfile) + moduleFiles[module][i] = module + "/" + subfile } } if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("couldn't list template files in module %s", module)) + return nil, errors.Wrapf(err, "couldn't list template files in module %s", module) } } return moduleFiles, nil @@ -60,16 +56,16 @@ func identifyModuleNonpageFiles(templates fs.FS) (map[string][]string, error) { func computeAppFingerprint( appAssets, sharedTemplates []string, templates, app fs.FS, ) (string, error) { - appConcatenated, err := fsutil.ReadConcatenated(appAssets, app) + appConcatenated, err := readConcatenated(appAssets, app) if err != nil { return "", errors.Wrap(err, "couldn't load all app assets together for fingerprinting") } - sharedConcatenated, err := fsutil.ReadConcatenated(sharedTemplates, templates) + sharedConcatenated, err := readConcatenated(sharedTemplates, templates) if err != nil { return "", errors.Wrap(err, "couldn't load all shared templates together for fingerprinting") } - return fingerprint.Compute(append(appConcatenated, sharedConcatenated...)), nil + return computeFingerprint(append(appConcatenated, sharedConcatenated...)), nil } func computePageFingerprints( @@ -77,22 +73,20 @@ func computePageFingerprints( ) (map[string]string, error) { moduleNonpages := make(map[string][]byte) for module, files := range moduleNonpageFiles { - loadedNonpages, err := fsutil.ReadConcatenated(files, templates) + loadedNonpages, err := readConcatenated(files, templates) if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf( - "couldn't load non-page template files in template module %s for fingerprinting", module, - )) + return nil, errors.Wrapf( + err, "couldn't load non-page template files in module %s for fingerprinting", module, + ) } moduleNonpages[module] = loadedNonpages } pages := make(map[string][]byte) for _, file := range pageFiles { - loadedPage, err := fsutil.ReadFile(file, templates) + loadedPage, err := readFile(file, templates) if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf( - "couldn't load page template %s for fingerprinting", file, - )) + return nil, errors.Wrapf(err, "couldn't load page template %s for fingerprinting", file) } pages[file] = loadedPage } @@ -100,7 +94,7 @@ func computePageFingerprints( pageFingerprints := make(map[string]string) for _, pageFile := range pageFiles { module := path.Dir(pageFile) - pageFingerprints[pageFile] = fingerprint.Compute(append( + pageFingerprints[pageFile] = computeFingerprint(append( // Each page's fingerprint is computed from the page template itself as well as any non-page // files (e.g. partials) within its module, recursively including all non-page files in // submodules (i.e. subdirectories) @@ -121,63 +115,48 @@ type Embeds struct { FontsFS fs.FS } -func (e Embeds) ComputeAppFingerprint() (fingerprint string, err error) { - appAssetFiles, err := fsutil.ListFiles(e.AppFS, tp.FilterAsset) +func (e Embeds) computeAppFingerprint() (fingerprint string, err error) { + appAssetFiles, err := listFiles(e.AppFS, filterAsset) if err != nil { - err = errors.Wrap(err, "couldn't list app assets") - return + return "", errors.Wrap(err, "couldn't list app assets") } - sharedFiles, err := fsutil.ListFiles(e.TemplatesFS, tp.FilterShared) + sharedFiles, err := listFiles(e.TemplatesFS, filterSharedTemplate) if err != nil { - err = errors.Wrap(err, "couldn't list shared templates") - return + return "", errors.Wrap(err, "couldn't list shared templates") } fingerprint, err = computeAppFingerprint(appAssetFiles, sharedFiles, e.TemplatesFS, e.AppFS) if err != nil { - err = errors.Wrap(err, "couldn't compute fingerprint for app") - return + return "", errors.Wrap(err, "couldn't compute fingerprint for app") } - return + return fingerprint, nil } -func (e Embeds) ComputePageFingerprints() (fingerprints map[string]string, err error) { +func (e Embeds) computePageFingerprints() (fingerprints map[string]string, err error) { moduleNonpageFiles, err := identifyModuleNonpageFiles(e.TemplatesFS) if err != nil { - err = errors.Wrap(err, "couldn't list template module non-page template files") - return + return nil, errors.Wrap(err, "couldn't list template module non-page template files") } - pageFiles, err := fsutil.ListFiles(e.TemplatesFS, tp.FilterPage) + pageFiles, err := listFiles(e.TemplatesFS, filterPageTemplate) if err != nil { - err = errors.Wrap(err, "couldn't list template pages") - return + return nil, errors.Wrap(err, "couldn't list template pages") } fingerprints, err = computePageFingerprints(moduleNonpageFiles, pageFiles, e.TemplatesFS) if err != nil { - err = errors.Wrap(err, "couldn't compute fingerprint for page/module templates") - return - } - return -} - -func (e Embeds) NewTemplates(funcs ...template.FuncMap) (r tp.Templates, err error) { - pageFiles, err := fsutil.ListFiles(e.TemplatesFS, tp.FilterPage) - if err != nil { - err = errors.Wrap(err, "couldn't list template pages") + return nil, errors.Wrap(err, "couldn't compute fingerprint for page/module templates") } - r = tp.NewTemplates(e.TemplatesFS, pageFiles, funcs...) - return + return fingerprints, nil } func (e Embeds) GetAppHashedNamer(urlPrefix string) func(string) string { return func(unhashedFilename string) string { - return fmt.Sprintf(urlPrefix + e.AppHFS.HashName(unhashedFilename)) + return urlPrefix + e.AppHFS.HashName(unhashedFilename) } } func (e Embeds) GetStaticHashedNamer(urlPrefix string) func(string) string { return func(unhashedFilename string) string { - return fmt.Sprintf(urlPrefix + e.StaticHFS.HashName(unhashedFilename)) + return urlPrefix + e.StaticHFS.HashName(unhashedFilename) } } @@ -195,15 +174,15 @@ type Inlines struct { func (i Inlines) ComputeCSSHashesForCSP() (hashes []string) { hashes = make([]string, 0, len(i.CSS)) for _, inline := range i.CSS { - hashes = append(hashes, ComputeCSPHash([]byte(inline))) + hashes = append(hashes, computeCSPHash([]byte(inline))) } - return + return hashes } func (i Inlines) ComputeJSHashesForCSP() (hashes []string) { hashes = make([]string, 0, len(i.CSS)) for _, inline := range i.JS { - hashes = append(hashes, ComputeCSPHash([]byte(inline))) + hashes = append(hashes, computeCSPHash([]byte(inline))) } - return + return hashes } diff --git a/pkg/godest/env/parsing.go b/pkg/godest/env/parsing.go index cfc57ff..ff16abf 100644 --- a/pkg/godest/env/parsing.go +++ b/pkg/godest/env/parsing.go @@ -3,7 +3,6 @@ package env import ( "encoding/base64" - "fmt" "net/url" "os" "strconv" @@ -41,9 +40,9 @@ func GetUint64(varName string, defaultValue uint64) (uint64, error) { ) parsed, err := strconv.ParseUint(value, base, width) if err != nil { - return 0, errors.Wrap(err, fmt.Sprintf( - "unparseable value %s for uint64 environment variable %s", value, varName, - )) + return 0, errors.Wrapf( + err, "unparseable value %s for uint64 environment variable %s", value, varName, + ) } return parsed, nil @@ -61,9 +60,9 @@ func GetInt64(varName string, defaultValue int64) (int64, error) { ) parsed, err := strconv.ParseInt(value, base, width) if err != nil { - return 0, errors.Wrap(err, fmt.Sprintf( - "unparseable value %s for int64 environment variable %s", value, varName, - )) + return 0, errors.Wrapf( + err, "unparseable value %s for int64 environment variable %s", value, varName, + ) } return parsed, nil @@ -78,9 +77,9 @@ func GetFloat32(varName string, defaultValue float32) (float32, error) { const width = 32 // bits parsed, err := strconv.ParseFloat(value, width) if err != nil { - return 0, errors.Wrap(err, fmt.Sprintf( - "unparseable value %s for float32 environment variable %s", value, varName, - )) + return 0, errors.Wrapf( + err, "unparseable value %s for float32 environment variable %s", value, varName, + ) } return float32(parsed), nil @@ -116,9 +115,9 @@ func GetURL(varName string, defaultValue string) (*url.URL, error) { func GetURLOrigin(varName, defaultValue, defaultScheme string) (*url.URL, error) { url, err := GetURL(varName, defaultValue) if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf( - "unparseable value %s for URL environment variable %s", os.Getenv(varName), varName, - )) + return nil, errors.Wrapf( + err, "unparseable value %s for URL environment variable %s", os.Getenv(varName), varName, + ) } if len(url.Scheme) == 0 { diff --git a/pkg/godest/etags.go b/pkg/godest/etags.go new file mode 100644 index 0000000..e4a7655 --- /dev/null +++ b/pkg/godest/etags.go @@ -0,0 +1,44 @@ +package godest + +import ( + "fmt" + "net/http" + "strings" +) + +// Etag Assembly + +const etagSegmentDelimiter = " " + +func makeEtag(segments ...string) string { + return fmt.Sprintf("W/\"%s\"", strings.Join(segments, etagSegmentDelimiter)) +} + +// Headers for Etags + +func SetUncacheable(resh http.Header) { + // Don't cache cookies - see the "Web Content Caching" subsection of + // https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html + resh.Set("Cache-Control", "no-cache=\"Set-Cookie, Set-Cookie2\", no-store, max-age=0") +} + +func setEtag(resh http.Header, etag string) { + resh.Set("Cache-Control", "private, no-cache") + resh.Set("Etag", etag) +} + +func checkEtagMatch(reqh http.Header, etag string) (matches bool) { + matchQuery := reqh.Get("If-None-Match") + if matchQuery == "" || etag == "" { + return false + } + return matchQuery == etag +} + +func setAndCheckEtag( + w http.ResponseWriter, r *http.Request, etagSegments ...string, +) (noContent bool) { + etag := makeEtag(etagSegments...) + setEtag(w.Header(), etag) + return checkEtagMatch(r.Header, etag) +} diff --git a/pkg/godest/fingerprint.go b/pkg/godest/fingerprint.go new file mode 100644 index 0000000..dcddd18 --- /dev/null +++ b/pkg/godest/fingerprint.go @@ -0,0 +1,18 @@ +package godest + +import ( + "encoding/base64" + "encoding/binary" + "fmt" + + "github.com/twmb/murmur3" +) + +const fingerprintSize = 8 + +func computeFingerprint(data []byte) string { + hash := murmur3.Sum64(data) + hashBytes := make([]byte, fingerprintSize) + binary.LittleEndian.PutUint64(hashBytes, hash) + return fmt.Sprintf("%x:%s", len(data), base64.StdEncoding.EncodeToString(hashBytes)) +} diff --git a/pkg/godest/fingerprint/fingerprint.go b/pkg/godest/fingerprint/fingerprint.go deleted file mode 100644 index 669747c..0000000 --- a/pkg/godest/fingerprint/fingerprint.go +++ /dev/null @@ -1,35 +0,0 @@ -// Package fingerprint contains utilities for fingerprinting files from -// fs.FS filesystems, for Etag-based caching of template-based resources. -package fingerprint - -import ( - "encoding/base64" - "encoding/binary" - "fmt" - "io/fs" - - "github.com/twmb/murmur3" - - "github.com/sargassum-world/fluitans/pkg/godest/fsutil" -) - -const FingerprintSize = 8 - -func Compute(data []byte) string { - hash := murmur3.Sum64(data) - hashBytes := make([]byte, FingerprintSize) - binary.LittleEndian.PutUint64(hashBytes, hash) - return fmt.Sprintf("%x:%s", len(data), base64.StdEncoding.EncodeToString(hashBytes)) -} - -func ComputeFiles(filenames []string, f fs.FS) (map[string]string, error) { - fingerprints := make(map[string]string) - for _, name := range filenames { - data, err := fsutil.ReadFile(name, f) - if err != nil { - return nil, err - } - fingerprints[name] = Compute(data) - } - return fingerprints, nil -} diff --git a/pkg/godest/fsutil.go b/pkg/godest/fsutil.go new file mode 100644 index 0000000..7759906 --- /dev/null +++ b/pkg/godest/fsutil.go @@ -0,0 +1,85 @@ +package godest + +import ( + "io/fs" + "io/ioutil" +) + +// Directories + +func listDirectories(f fs.FS, filter func(path string) bool) ([]string, error) { + dirs := []string{} + err := fs.WalkDir(f, ".", func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if !d.IsDir() { + return nil + } + if filter == nil || filter(path) { + if path == "." { + dirs = append(dirs, "") + } else { + dirs = append(dirs, path) + } + } + return nil + }) + if err != nil { + return nil, err + } + return dirs, nil +} + +func listFiles(f fs.FS, filter func(path string) bool) ([]string, error) { + files := []string{} + err := fs.WalkDir(f, ".", func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if d.IsDir() { + return nil + } + if filter == nil || filter(path) { + files = append(files, path) + } + return nil + }) + if err != nil { + return nil, err + } + return files, nil +} + +// File Reading + +func readFile(filename string, f fs.FS) ([]byte, error) { + file, err := f.Open(filename) + if err != nil { + return nil, err + } + defer func() { + if cerr := file.Close(); cerr != nil && err == nil { + err = cerr + } + }() + + data, err := ioutil.ReadAll(file) + if err != nil { + return nil, err + } + return data, err +} + +func readConcatenated(filenames []string, f fs.FS) ([]byte, error) { + var concatenated []byte + for _, name := range filenames { + data, err := readFile(name, f) + if err != nil { + return nil, err + } + concatenated = append(concatenated, data...) + } + + return concatenated, nil +} diff --git a/pkg/godest/fsutil/dir.go b/pkg/godest/fsutil/dir.go deleted file mode 100644 index 8d61b46..0000000 --- a/pkg/godest/fsutil/dir.go +++ /dev/null @@ -1,49 +0,0 @@ -package fsutil - -import ( - "io/fs" -) - -func ListDirectories(f fs.FS, filter func(path string) bool) ([]string, error) { - dirs := []string{} - err := fs.WalkDir(f, ".", func(path string, d fs.DirEntry, err error) error { - if err != nil { - return err - } - if !d.IsDir() { - return nil - } - if filter == nil || filter(path) { - if path == "." { - dirs = append(dirs, "") - } else { - dirs = append(dirs, path) - } - } - return nil - }) - if err != nil { - return nil, err - } - return dirs, nil -} - -func ListFiles(f fs.FS, filter func(path string) bool) ([]string, error) { - files := []string{} - err := fs.WalkDir(f, ".", func(path string, d fs.DirEntry, err error) error { - if err != nil { - return err - } - if d.IsDir() { - return nil - } - if filter == nil || filter(path) { - files = append(files, path) - } - return nil - }) - if err != nil { - return nil, err - } - return files, nil -} diff --git a/pkg/godest/fsutil/reading.go b/pkg/godest/fsutil/reading.go deleted file mode 100644 index 23927c0..0000000 --- a/pkg/godest/fsutil/reading.go +++ /dev/null @@ -1,38 +0,0 @@ -// Package fsutil contains utilities for working with fs.FS filesystems. -package fsutil - -import ( - "io/fs" - "io/ioutil" -) - -func ReadFile(filename string, f fs.FS) ([]byte, error) { - file, err := f.Open(filename) - if err != nil { - return nil, err - } - defer func() { - if cerr := file.Close(); cerr != nil && err == nil { - err = cerr - } - }() - - data, err := ioutil.ReadAll(file) - if err != nil { - return nil, err - } - return data, err -} - -func ReadConcatenated(filenames []string, f fs.FS) ([]byte, error) { - var concatenated []byte - for _, name := range filenames { - data, err := ReadFile(name, f) - if err != nil { - return nil, err - } - concatenated = append(concatenated, data...) - } - - return concatenated, nil -} diff --git a/pkg/godest/httpcache/etag.go b/pkg/godest/httpcache/etag.go deleted file mode 100644 index ce6cb10..0000000 --- a/pkg/godest/httpcache/etag.go +++ /dev/null @@ -1,50 +0,0 @@ -package httpcache - -import ( - "fmt" - "net/http" - "strings" -) - -// Etag Assembly - -const etagSegmentDelimiter = " " - -func JoinEtagSegments(segments ...string) string { - return strings.Join(segments, etagSegmentDelimiter) -} - -func MakeEtag(segments ...string) string { - return fmt.Sprintf("W/\"%s\"", JoinEtagSegments(segments...)) -} - -// Headers for Etags - -func SetNoEtag(resh http.Header) { - // Don't cache cookies - see the "Web Content Caching" subsection of - // https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html - resh.Set("Cache-Control", "no-cache=\"Set-Cookie, Set-Cookie2\", no-store, max-age=0") -} - -func SetEtag(resh http.Header, etag string) { - resh.Set("Cache-Control", "private, no-cache") - resh.Set("Etag", etag) -} - -func CheckEtagMatch(reqh http.Header, etag string) bool { - match := reqh.Get("If-None-Match") - if match == "" || etag == "" { - return false - } - return match == etag -} - -func SetAndCheckEtag(w http.ResponseWriter, r *http.Request, etagSegments ...string) bool { - etag := MakeEtag(etagSegments...) - SetEtag(w.Header(), etag) - if !CheckEtagMatch(r.Header, etag) { - return false - } - w.WriteHeader(http.StatusNotModified) - return true -} diff --git a/pkg/godest/httpcache/filerevving.go b/pkg/godest/httpcache/filerevving.go deleted file mode 100644 index 3af4779..0000000 --- a/pkg/godest/httpcache/filerevving.go +++ /dev/null @@ -1,14 +0,0 @@ -// Package httpcache provides utilities for working with HTTP caching in Echo -package httpcache - -import ( - "fmt" - "net/http" -) - -func WrapStaticHeader(h http.Handler, age int) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Cache-Control", fmt.Sprintf("public, max-age=%d", age)) - h.ServeHTTP(w, r) - }) -} diff --git a/pkg/godest/session/client.go b/pkg/godest/session/client.go new file mode 100644 index 0000000..837bb0f --- /dev/null +++ b/pkg/godest/session/client.go @@ -0,0 +1,60 @@ +package session + +import ( + "net/http" + + "github.com/gorilla/csrf" + "github.com/gorilla/sessions" + "github.com/pkg/errors" + "github.com/quasoft/memstore" +) + +type Client struct { + Config Config + // TODO: allow configuration to use sqlite for a persistent session store + Store sessions.Store +} + +func NewMemStoreClient(c Config) *Client { + store := memstore.NewMemStore(c.AuthKey) + store.Options = &c.CookieOptions + + return &Client{ + Config: c, + Store: store, + } +} + +func (sc *Client) New(r *http.Request) (sess *sessions.Session, err error) { + sess, err = sc.Store.New(r, sc.Config.CookieName) + return sess, errors.Wrap(err, "couldn't make session") +} + +func (sc *Client) Get(r *http.Request) (sess *sessions.Session, err error) { + sess, err = sc.Store.Get(r, sc.Config.CookieName) + return sess, errors.Wrap(err, "couldn't get session") +} + +func NewCSRFMiddleware(config Config, opts ...csrf.Option) func(http.Handler) http.Handler { + sameSite := csrf.SameSiteDefaultMode + switch config.CookieOptions.SameSite { + case http.SameSiteLaxMode: + sameSite = csrf.SameSiteLaxMode + case http.SameSiteStrictMode: + sameSite = csrf.SameSiteStrictMode + case http.SameSiteNoneMode: + sameSite = csrf.SameSiteNoneMode + } + options := []csrf.Option{ + csrf.Path(config.CookieOptions.Path), + csrf.Domain(config.CookieOptions.Domain), + csrf.MaxAge(config.CookieOptions.MaxAge), + csrf.Secure(config.CookieOptions.Secure), + csrf.HttpOnly(config.CookieOptions.HttpOnly), + csrf.SameSite(sameSite), + csrf.RequestHeader(config.CSRFOptions.HeaderName), + csrf.FieldName(config.CSRFOptions.FieldName), + } + options = append(options, opts...) + return csrf.Protect(config.AuthKey, options...) +} diff --git a/internal/clients/sessions/conf.go b/pkg/godest/session/conf.go similarity index 64% rename from internal/clients/sessions/conf.go rename to pkg/godest/session/conf.go index ebba348..5cf2aa7 100644 --- a/internal/clients/sessions/conf.go +++ b/pkg/godest/session/conf.go @@ -1,4 +1,4 @@ -package sessions +package session import ( "encoding/base64" @@ -13,6 +13,8 @@ import ( "github.com/sargassum-world/fluitans/pkg/godest/env" ) +const envPrefix = "SESSIONS_" + type Timeouts struct { Absolute time.Duration // TODO: add idle timeout @@ -35,21 +37,18 @@ type Config struct { func GetConfig() (c Config, err error) { c.AuthKey, err = getAuthKey() if err != nil { - err = errors.Wrap(err, "couldn't make session key config") - return + return Config{}, errors.Wrap(err, "couldn't make session key config") } c.Timeouts, err = getTimeouts() if err != nil { - err = errors.Wrap(err, "couldn't make session timeouts config") - return + return Config{}, errors.Wrap(err, "couldn't make session timeouts config") } // TODO: when we implement idle timeout, pass that instead of absolute timeout c.CookieOptions, err = getCookieOptions(c.Timeouts.Absolute) if err != nil { - err = errors.Wrap(err, "couldn't make cookie options config") - return + return Config{}, errors.Wrap(err, "couldn't make cookie options config") } if c.CookieOptions.Secure { @@ -60,13 +59,13 @@ func GetConfig() (c Config, err error) { } c.CSRFOptions = getCSRFOptions() - return + return c, nil } func getAuthKey() (authKey []byte, err error) { - authKey, err = env.GetBase64("FLUITANS_SESSIONS_AUTH_KEY") + authKey, err = env.GetBase64(envPrefix + "AUTH_KEY") if err != nil { - return + return nil, err } if authKey == nil { @@ -74,44 +73,41 @@ func getAuthKey() (authKey []byte, err error) { authKey = securecookie.GenerateRandomKey(authKeySize) // TODO: print to the logger instead? fmt.Printf( - "Record this key for future use as FLUITANS_SESSIONS_AUTH_KEY: %s\n", - base64.StdEncoding.EncodeToString(authKey), + "Record this key for future use as %sAUTH_KEY: %s\n", + envPrefix, base64.StdEncoding.EncodeToString(authKey), ) } - return + return authKey, nil } func getTimeouts() (t Timeouts, err error) { const defaultAbsolute = 12 * 60 // default: 12 hours - rawAbsolute, err := env.GetInt64("FLUITANS_SESSIONS_TIMEOUTS_ABSOLUTE", defaultAbsolute) + rawAbsolute, err := env.GetInt64(envPrefix+"TIMEOUTS_ABSOLUTE", defaultAbsolute) if err != nil { - err = errors.Wrap(err, "couldn't make absolute timeout config") - return + return Timeouts{}, errors.Wrap(err, "couldn't make absolute timeout config") } t.Absolute = time.Duration(rawAbsolute) * time.Minute - return + return t, nil } func getCookieOptions(absoluteTimeout time.Duration) (o sessions.Options, err error) { - noHTTPSOnly, err := env.GetBool("FLUITANS_SESSIONS_COOKIE_NOHTTPSONLY") + noHTTPSOnly, err := env.GetBool(envPrefix + "COOKIE_NOHTTPSONLY") if err != nil { - err = errors.Wrap(err, "couldn't make HTTPS-only config") - return + return sessions.Options{}, errors.Wrap(err, "couldn't make HTTPS-only config") } - o = sessions.Options{ + return sessions.Options{ Path: "/", Domain: "", MaxAge: int(absoluteTimeout.Seconds()), Secure: !noHTTPSOnly, HttpOnly: true, SameSite: http.SameSiteLaxMode, - } - return + }, nil } func getCSRFOptions() (o CSRFOptions) { - o.HeaderName = env.GetString("FLUITANS_SESSIONS_CSRF_HEADERNAME", "X-CSRF-Token") - o.FieldName = env.GetString("FLUITANS_SESSIONS_CSRF_FIELDNAME", "csrf-token") - return + o.HeaderName = env.GetString(envPrefix+"CSRF_HEADERNAME", "X-CSRF-Token") + o.FieldName = env.GetString(envPrefix+"CSRF_FIELDNAME", "csrf-token") + return o } diff --git a/pkg/godest/session/flash.go b/pkg/godest/session/flash.go deleted file mode 100644 index 0b0baf9..0000000 --- a/pkg/godest/session/flash.go +++ /dev/null @@ -1,28 +0,0 @@ -package session - -import ( - "fmt" - - "github.com/gorilla/sessions" -) - -// Errors - -const FlashErrorsKey = "_flash_errors" - -func AddErrorMessage(s *sessions.Session, message string) { - s.AddFlash(message, FlashErrorsKey) -} - -func GetErrorMessages(s *sessions.Session) ([]string, error) { - rawFlashes := s.Flashes(FlashErrorsKey) - flashes := make([]string, 0, len(rawFlashes)) - for _, rawFlash := range rawFlashes { - flash, ok := rawFlash.(string) - if !ok { - return nil, fmt.Errorf("session error message is of unexpected non-string type %T", rawFlash) - } - flashes = append(flashes, flash) - } - return flashes, nil -} diff --git a/pkg/godest/session/sessions.go b/pkg/godest/session/sessions.go index 28e71cd..a420b30 100644 --- a/pkg/godest/session/sessions.go +++ b/pkg/godest/session/sessions.go @@ -2,44 +2,41 @@ package session import ( - "net/http" - "github.com/gorilla/sessions" + "github.com/pkg/errors" ) -func Get( - r *http.Request, cookieName string, store sessions.Store, -) (*sessions.Session, error) { - // TODO: implement idle timeout, and implement automatic renewal timeout (if we can). Refer to the - // "Automatic Session Expiration" section of - // https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html - // TODO: regenerate the session upon privilege change - // TODO: log the session life cycle - return store.Get(r, cookieName) -} - -func Regenerate( - r *http.Request, cookieName string, store sessions.Store, -) (*sessions.Session, error) { - s, err := Get(r, cookieName, store) - if err != nil { - return nil, err - } +// Session rotation +func Regenerate(s *sessions.Session) { s.ID = "" s.Values = make(map[interface{}]interface{}) - return s, nil } -func Invalidate( - r *http.Request, cookieName string, store sessions.Store, -) (*sessions.Session, error) { - s, err := Get(r, cookieName, store) - if err != nil { - return nil, err - } - +func Invalidate(s *sessions.Session) { s.Options.MaxAge = 0 s.Values = make(map[interface{}]interface{}) - return s, nil +} + +// Flash messages + +const FlashErrorsKey = "_flash_errors" + +func AddErrorMessage(s *sessions.Session, message string) { + s.AddFlash(message, FlashErrorsKey) +} + +func GetErrorMessages(s *sessions.Session) ([]string, error) { + rawFlashes := s.Flashes(FlashErrorsKey) + flashes := make([]string, 0, len(rawFlashes)) + for _, rawFlash := range rawFlashes { + flash, ok := rawFlash.(string) + if !ok { + return nil, errors.Errorf( + "session error message is of unexpected non-string type %T", rawFlash, + ) + } + flashes = append(flashes, flash) + } + return flashes, nil } diff --git a/pkg/godest/statics.go b/pkg/godest/statics.go index 898c46e..e7b15f2 100644 --- a/pkg/godest/statics.go +++ b/pkg/godest/statics.go @@ -1,17 +1,23 @@ package godest import ( + "fmt" "io/fs" "net/http" "time" "github.com/benbjohnson/hashfs" - - "github.com/sargassum-world/fluitans/pkg/godest/httpcache" ) +func wrapStaticHeader(h http.Handler, age int) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Cache-Control", fmt.Sprintf("public, max-age=%d", age)) + h.ServeHTTP(w, r) + }) +} + func HandleFS(routePrefix string, fsys fs.FS, age time.Duration) http.Handler { - return httpcache.WrapStaticHeader( + return wrapStaticHeader( http.StripPrefix(routePrefix, http.FileServer(http.FS(fsys))), int(age.Seconds()), ) } diff --git a/pkg/godest/template/execution.go b/pkg/godest/template/execution.go deleted file mode 100644 index 6d7a3af..0000000 --- a/pkg/godest/template/execution.go +++ /dev/null @@ -1,42 +0,0 @@ -// Package template preloads a collection of shared template files and page template files for fast -// execution of page templates, and specifies a layout convention to enable this functionality. -package template - -import ( - "fmt" - "html/template" - "io" - "io/fs" -) - -type Templates struct { - allTemplates *template.Template - pageTemplates map[string]*template.Template - templatesFS fs.FS -} - -func NewTemplates(fsys fs.FS, pageFiles []string, functions ...template.FuncMap) Templates { - tmpl := template.New("App") - for _, f := range functions { - tmpl = tmpl.Funcs(f) - } - allTemplates := template.Must(ParseFS(tmpl, fsys, "**/*"+FileExt)) - pageTemplates := make(map[string]*template.Template) - for _, name := range pageFiles { - all := template.Must(allTemplates.Clone()) - pageTemplates[name] = template.Must(ParseFS(all, fsys, name)) - } - return Templates{ - allTemplates: allTemplates, - pageTemplates: pageTemplates, - templatesFS: fsys, - } -} - -func (t *Templates) Execute(w io.Writer, name string, data interface{}) error { - tmpl, ok := t.pageTemplates[name] - if !ok { - return fmt.Errorf("template %s not found", name) - } - return tmpl.ExecuteTemplate(w, name, data) -} diff --git a/pkg/godest/template/filters.go b/pkg/godest/template/filters.go deleted file mode 100644 index 06e6fb5..0000000 --- a/pkg/godest/template/filters.go +++ /dev/null @@ -1,58 +0,0 @@ -package template - -import ( - "strings" -) - -// Template Files - -const ( - FileExt = ".tmpl" - PartialFileExt = ".partial" + FileExt - LayoutFileExt = ".layout" + FileExt - SharedModule = "shared" -) - -func Filter(path string) bool { - return strings.HasSuffix(path, FileExt) -} - -func FilterShared(path string) bool { - return Filter(path) && strings.HasPrefix(path, SharedModule+"/") -} - -func FilterPartial(path string) bool { - return strings.HasSuffix(path, PartialFileExt) -} - -func FilterLayout(path string) bool { - return strings.HasSuffix(path, LayoutFileExt) -} - -func FilterNonpage(path string) bool { - return FilterPartial(path) || FilterLayout(path) -} - -func FilterPage(path string) bool { - // Usually a page ends with ".page.tmpl", but it may end with other things, - // e.g. ".webmanifest.tmpl", ".json.tmpl", etc. - return Filter(path) && !FilterNonpage(path) -} - -func FilterModule(path string) bool { - return path != SharedModule -} - -// Built Asset Files - -func FilterCSSAsset(path string) bool { - return strings.HasSuffix(path, ".css") -} - -func FilterJSAsset(path string) bool { - return strings.HasSuffix(path, ".js") -} - -func FilterAsset(path string) bool { - return FilterCSSAsset(path) || FilterJSAsset(path) -} diff --git a/pkg/godest/template/parsing.go b/pkg/godest/template/parsing.go deleted file mode 100644 index b55c7dd..0000000 --- a/pkg/godest/template/parsing.go +++ /dev/null @@ -1,72 +0,0 @@ -package template - -import ( - "fmt" - "html/template" - "io/fs" - - "github.com/bmatcuk/doublestar/v4" - "github.com/pkg/errors" -) - -// parseFiles is a direct copy of the parseFiles helper function in text/template. -func parseFiles( - t *template.Template, readFile func(string) (string, []byte, error), filenames ...string, -) (*template.Template, error) { - if len(filenames) == 0 { - return nil, errors.Errorf("template: no files named in call to ParseFiles") - } - - for _, filename := range filenames { - name, b, err := readFile(filename) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("couldn't read file %s", filename)) - } - s := string(b) - var tmpl *template.Template - if t == nil { - t = template.New(name) - } - if name == t.Name() { - tmpl = t - } else { - tmpl = t.New(name) - } - _, err = tmpl.Parse(s) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("couldn't parse template %s", filename)) - } - } - return t, nil -} - -// readFileFS is an adaptation of the readFileFS helper function in text/template, except it uses -// the fully-qualified path name of the template file in the filesystem rather than just the -// template file's basename. -func readFileFS(fsys fs.FS) func(string) (string, []byte, error) { - return func(file string) (name string, b []byte, err error) { - name = file - b, err = fs.ReadFile(fsys, file) - return - } -} - -// ParseFS is a direct copy of the parseFS helper function in text/template, except it uses the -// fully-qualified path name of the template file in the filesystem rather than just the template -// file's basename, and it allows double-star globs (e.g. "**/*.txt"). -func ParseFS( - t *template.Template, fsys fs.FS, patterns ...string, -) (*template.Template, error) { - var filenames []string - for _, pattern := range patterns { - list, err := doublestar.Glob(fsys, pattern) - if err != nil { - return nil, err - } - if len(list) == 0 { - return nil, errors.Errorf("template: pattern matches no files: %#q", pattern) - } - filenames = append(filenames, list...) - } - return parseFiles(t, readFileFS(fsys), filenames...) -} diff --git a/pkg/godest/templated.go b/pkg/godest/templated.go deleted file mode 100644 index a1957fc..0000000 --- a/pkg/godest/templated.go +++ /dev/null @@ -1,177 +0,0 @@ -// Package godest provides a mildly opinionated framework for more easily writing web apps with -// modest Javascript approaches such as Hotwire-based apps. It provides support for using templates -// in a clear and structured way. It also makes it easy to embed all templates, static assets -// (e.g. images) and app-related assets (e.g. JS bundles) into the compiled server binary, and it -// takes care of the details of browser caching for assets and templated pages. -// Finally, it provides some standalone utilities for caching data on the server, getting the values -// of environment variables, and using cookies for form-based authentication. -package godest - -import ( - "bytes" - "encoding/json" - "fmt" - "html/template" - "net/http" - - "github.com/pkg/errors" - - "github.com/sargassum-world/fluitans/pkg/godest/fingerprint" - "github.com/sargassum-world/fluitans/pkg/godest/httpcache" - tp "github.com/sargassum-world/fluitans/pkg/godest/template" -) - -// Templated page fingerprinting - -type fingerprints struct { - App string - Page map[string]string -} - -func (f fingerprints) GetEtagSegments(templateName string) ([]string, error) { - if templateName == "" { - return []string{f.App}, nil - } - - pageFingerprint, ok := f.Page[templateName] - if !ok { - return []string{f.App}, errors.Errorf( - "couldn't find page fingerprint for template %s", templateName, - ) - } - - return []string{f.App, pageFingerprint}, nil -} - -func (f fingerprints) MustHave(templateNames ...string) { - for _, name := range templateNames { - if _, err := f.GetEtagSegments(name); err != nil { - panic(errors.Wrap(err, fmt.Sprintf("couldn't find template etag segments for %s", name))) - } - } -} - -func (f fingerprints) SetAndCheckEtag( - w http.ResponseWriter, r *http.Request, templateName string, data interface{}, -) (noContent bool, err error) { - // Look up data-independent etag segments - templateEtagSegments, err := f.GetEtagSegments(templateName) - if err != nil { - return - } - - // Encode data - var buf bytes.Buffer - // github.com/vmihailenco/msgpack has better performance, but we use the JSON encoder because - // the msgpack encoder can only sort the map keys of map[string]string and map[string]interface{} - // maps, and it's too much trouble to convert our maps into map[string]interface{}. If we can - // work around this limitation, we should use msgpack though. - if err = json.NewEncoder(&buf).Encode(data); err != nil { - return - } - encoded := buf.Bytes() - - noContent = httpcache.SetAndCheckEtag( - w, r, append(templateEtagSegments, fingerprint.Compute(encoded))..., - ) - return -} - -// Template rendering - -type Meta struct { - Path string - RequestURI string -} - -type RenderData struct { - Meta Meta - Inlines interface{} - Data interface{} - Auth interface{} -} - -type TemplateRenderer struct { - inlines interface{} - fingerprints fingerprints - templates tp.Templates -} - -func NewTemplateRenderer( - e Embeds, inlines interface{}, funcs ...template.FuncMap, -) (r TemplateRenderer, err error) { - r.inlines = inlines - r.templates, err = e.NewTemplates(funcs...) - if err != nil { - err = errors.Wrap(err, "couldn't make templated pages renderer") - return - } - if r.fingerprints.App, err = e.ComputeAppFingerprint(); err != nil { - err = errors.Wrap(err, "couldn't compute fingerprint for app") - return - } - if r.fingerprints.Page, err = e.ComputePageFingerprints(); err != nil { - err = errors.Wrap(err, "couldn't compute fingerprint for page/module templates") - return - } - return -} - -func (tr TemplateRenderer) MustHave(templateNames ...string) { - tr.fingerprints.MustHave(templateNames...) -} - -func (tr TemplateRenderer) NewRenderData( - r *http.Request, data interface{}, auth interface{}, -) RenderData { - return RenderData{ - Meta: Meta{ - Path: r.URL.Path, - RequestURI: r.URL.RequestURI(), - }, - Inlines: tr.inlines, - Data: data, - Auth: auth, - } -} - -func (tr TemplateRenderer) SetUncacheable(resh http.Header) { - httpcache.SetNoEtag(resh) -} - -func (tr TemplateRenderer) Page( - w http.ResponseWriter, r *http.Request, - status int, templateName string, templateData interface{}, authData interface{}, -) error { - // This is basically a reimplementation of the echo.Context.Render method, but without requiring - // an echo.Context to be provided - buf := new(bytes.Buffer) - if rerr := tr.templates.Execute( - buf, templateName, tr.NewRenderData(r, templateData, authData), - ); rerr != nil { - return rerr - } - - // Write render result - w.Header().Set("Content-Type", "text/html; charset=utf-8") - w.WriteHeader(status) - _, werr := w.Write(buf.Bytes()) - return werr -} - -func (tr TemplateRenderer) CacheablePage( - w http.ResponseWriter, r *http.Request, - templateName string, templateData interface{}, authData interface{}, -) error { - type EtagInputs struct { - Data interface{} - Auth interface{} - } - if noContent, err := tr.fingerprints.SetAndCheckEtag(w, r, templateName, EtagInputs{ - Data: templateData, - Auth: authData, - }); noContent || (err != nil) { - return err - } - return tr.Page(w, r, http.StatusOK, templateName, templateData, authData) -} diff --git a/pkg/godest/templates.go b/pkg/godest/templates.go new file mode 100644 index 0000000..4e40600 --- /dev/null +++ b/pkg/godest/templates.go @@ -0,0 +1,314 @@ +// Package godest provides a mildly opinionated framework for more easily writing web apps with +// modest Javascript approaches such as Hotwire-based apps. It provides support for using templates +// in a clear and structured way. It also makes it easy to embed all templates, static assets +// (e.g. images) and app-related assets (e.g. JS bundles) into the compiled server binary, and it +// takes care of the details of browser caching for assets and templated pages. +// Finally, it provides some standalone utilities for caching data on the server, getting the values +// of environment variables, and using cookies for form-based authentication. +package godest + +import ( + "bytes" + "encoding/json" + "html/template" + "io/fs" + "net/http" + "strings" + + "github.com/bmatcuk/doublestar/v4" + "github.com/pkg/errors" +) + +// Template File Filters + +const ( + templateFileExt = ".tmpl" + partialTemplateFileExt = ".partial" + templateFileExt + layoutTemplateFileExt = ".layout" + templateFileExt + templateSharedModule = "shared" +) + +func filterTemplate(path string) bool { + return strings.HasSuffix(path, templateFileExt) +} + +func filterSharedTemplate(path string) bool { + return filterTemplate(path) && strings.HasPrefix(path, templateSharedModule+"/") +} + +func filterPartialTemplate(path string) bool { + return strings.HasSuffix(path, partialTemplateFileExt) +} + +func filterLayoutTemplate(path string) bool { + return strings.HasSuffix(path, layoutTemplateFileExt) +} + +func filterNonpageTemplate(path string) bool { + return filterPartialTemplate(path) || filterLayoutTemplate(path) +} + +func filterPageTemplate(path string) bool { + // Usually a page ends with ".page.tmpl", but it may end with other things, + // e.g. ".webmanifest.tmpl", ".json.tmpl", etc. + return filterTemplate(path) && !filterNonpageTemplate(path) +} + +func filterTemplateModule(path string) bool { + return path != templateSharedModule +} + +// Built Asset File Filters + +func filterCSSAsset(path string) bool { + return strings.HasSuffix(path, ".css") +} + +func filterJSAsset(path string) bool { + return strings.HasSuffix(path, ".js") +} + +func filterAsset(path string) bool { + return filterCSSAsset(path) || filterJSAsset(path) +} + +// Template File Parsing + +// parseFiles is a direct copy of the parseFiles helper function in text/template. +func parseFiles( + t *template.Template, readFile func(string) (string, []byte, error), filenames ...string, +) (*template.Template, error) { + if len(filenames) == 0 { + return nil, errors.Errorf("template: no files named in call to ParseFiles") + } + + for _, filename := range filenames { + name, b, err := readFile(filename) + if err != nil { + return nil, errors.Wrapf(err, "couldn't read file %s", filename) + } + s := string(b) + var tmpl *template.Template + if t == nil { + t = template.New(name) + } + if name == t.Name() { + tmpl = t + } else { + tmpl = t.New(name) + } + _, err = tmpl.Parse(s) + if err != nil { + return nil, errors.Wrapf(err, "couldn't parse template %s", filename) + } + } + return t, nil +} + +// readFileFS is an adaptation of the readFileFS helper function in text/template, except it uses +// the fully-qualified path name of the template file in the filesystem rather than just the +// template file's basename. +func readFileFS(fsys fs.FS) func(string) (string, []byte, error) { + return func(file string) (name string, b []byte, err error) { + b, err = fs.ReadFile(fsys, file) + return file, b, err + } +} + +// parseFS is a direct copy of the parseFS helper function in text/template, except it uses the +// fully-qualified path name of the template file in the filesystem rather than just the template +// file's basename, and it allows double-star globs (e.g. "**/*.txt"). +func parseFS( + t *template.Template, fsys fs.FS, patterns ...string, +) (*template.Template, error) { + var filenames []string + for _, pattern := range patterns { + list, err := doublestar.Glob(fsys, pattern) + if err != nil { + return nil, err + } + if len(list) == 0 { + return nil, errors.Errorf("template: pattern matches no files: %#q", pattern) + } + filenames = append(filenames, list...) + } + return parseFiles(t, readFileFS(fsys), filenames...) +} + +// Templated Page Fingerprinting + +type fingerprints struct { + app string + page map[string]string +} + +func (f fingerprints) getEtagSegments(templateName string) ([]string, error) { + if templateName == "" { + return []string{f.app}, nil + } + + pageFingerprint, ok := f.page[templateName] + if !ok { + return []string{f.app}, errors.Errorf( + "couldn't find page fingerprint for template %s", templateName, + ) + } + + return []string{f.app, pageFingerprint}, nil +} + +func (f fingerprints) MustHave(templateNames ...string) { + for _, name := range templateNames { + if _, err := f.getEtagSegments(name); err != nil { + panic(errors.Wrapf(err, "couldn't find template etag segments for %s", name)) + } + } +} + +func (f fingerprints) SetAndCheckEtag( + w http.ResponseWriter, r *http.Request, templateName string, data interface{}, +) (noContent bool, err error) { + // Look up data-independent etag segments + templateEtagSegments, err := f.getEtagSegments(templateName) + if err != nil { + return false, err + } + + // Encode data + var buf bytes.Buffer + // github.com/vmihailenco/msgpack has better performance, but we use the JSON encoder because + // the msgpack encoder can only sort the map keys of map[string]string and map[string]interface{} + // maps, and it's too much trouble to convert our maps into map[string]interface{}. If we can + // work around this limitation, we should use msgpack though. + if err = json.NewEncoder(&buf).Encode(data); err != nil { + return false, err + } + encoded := buf.Bytes() + + noContent = setAndCheckEtag( + w, r, append(templateEtagSegments, computeFingerprint(encoded))..., + ) + if noContent { + w.WriteHeader(http.StatusNotModified) + } + return noContent, nil +} + +// Template Rendering + +type Meta struct { + Path string + RequestURI string +} + +type RenderData struct { + Meta Meta + Inlines interface{} + Data interface{} + Auth interface{} +} + +type TemplateRenderer struct { + pageTemplates map[string]*template.Template + inlines interface{} + fingerprints fingerprints +} + +func NewTemplateRenderer( + e Embeds, inlines interface{}, funcs ...template.FuncMap, +) (tr TemplateRenderer, err error) { + tmpl := template.New("App") + for _, f := range funcs { + tmpl = tmpl.Funcs(f) + } + allTemplates, err := parseFS(tmpl, e.TemplatesFS, "**/*"+templateFileExt) + if err != nil { + return TemplateRenderer{}, errors.Wrap(err, "couldn't load templates from filesystem") + } + + tr.pageTemplates = make(map[string]*template.Template) + pageFiles, err := listFiles(e.TemplatesFS, filterPageTemplate) + if err != nil { + return TemplateRenderer{}, errors.Wrap(err, "couldn't list template pages") + } + for _, name := range pageFiles { + all, cerr := allTemplates.Clone() + if cerr != nil { + return TemplateRenderer{}, errors.Wrap(err, "couldn't clone root template set") + } + tr.pageTemplates[name], err = parseFS(all, e.TemplatesFS, name) + if err != nil { + return TemplateRenderer{}, errors.Wrapf(err, "couldn't make template set for %s", name) + } + } + + tr.inlines = inlines + if tr.fingerprints.app, err = e.computeAppFingerprint(); err != nil { + return TemplateRenderer{}, errors.Wrap(err, "couldn't compute fingerprint for app") + } + if tr.fingerprints.page, err = e.computePageFingerprints(); err != nil { + return TemplateRenderer{}, errors.Wrap( + err, "couldn't compute fingerprint for page/module templates", + ) + } + + return tr, nil +} + +func (tr TemplateRenderer) MustHave(templateNames ...string) { + tr.fingerprints.MustHave(templateNames...) +} + +func (tr TemplateRenderer) newRenderData( + r *http.Request, data interface{}, auth interface{}, +) RenderData { + return RenderData{ + Meta: Meta{ + Path: r.URL.Path, + RequestURI: r.URL.RequestURI(), + }, + Inlines: tr.inlines, + Data: data, + Auth: auth, + } +} + +func (tr TemplateRenderer) Page( + w http.ResponseWriter, r *http.Request, + status int, templateName string, templateData interface{}, authData interface{}, +) error { + // This is basically a reimplementation of the echo.Context.Render method, but without requiring + // an echo.Context to be provided + buf := new(bytes.Buffer) + tmpl, ok := tr.pageTemplates[templateName] + if !ok { + return errors.Errorf("teplate %s not found", templateName) + } + if err := tmpl.ExecuteTemplate( + buf, templateName, tr.newRenderData(r, templateData, authData), + ); err != nil { + return errors.Wrapf(err, "couldn't execute template %s", templateName) + } + + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.WriteHeader(status) + _, werr := w.Write(buf.Bytes()) + return werr +} + +func (tr TemplateRenderer) CacheablePage( + w http.ResponseWriter, r *http.Request, + templateName string, templateData interface{}, authData interface{}, +) error { + type EtagInputs struct { + Data interface{} + Auth interface{} + } + if noContent, err := tr.fingerprints.SetAndCheckEtag(w, r, templateName, EtagInputs{ + Data: templateData, + Auth: authData, + }); noContent || (err != nil) { + return err + } + return tr.Page(w, r, http.StatusOK, templateName, templateData, authData) +} diff --git a/tools/go.mod b/tools/go.mod index 1ae76b6..e32b4b3 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -5,6 +5,6 @@ go 1.16 require ( github.com/deepmap/oapi-codegen v1.8.3 github.com/golangci/golangci-lint v1.42.1 - github.com/goreleaser/goreleaser v0.178.0 + github.com/goreleaser/goreleaser v1.6.1 mvdan.cc/gofumpt v0.2.1 ) diff --git a/tools/go.sum b/tools/go.sum index 7b6c237..7e3f44c 100644 --- a/tools/go.sum +++ b/tools/go.sum @@ -5,7 +5,6 @@ bitbucket.org/creachadair/shell v0.0.6/go.mod h1:8Qqi/cYk7vPnsOePHroKXDJYmb5x7EN cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= @@ -24,8 +23,22 @@ cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmW cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0 h1:at8Tk2zUz63cLPR0JPWm5vp77pEZmzxEQBEfRKn1VV8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.82.0/go.mod h1:vlKccHJGuFBFufnAnuB08dfEH9Y3H7dzDzRECFdC2TA= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.88.0/go.mod h1:dnKwfYbP9hQhefiUvpbcAyoGSHUrOxR20JVElLiUvEY= +cloud.google.com/go v0.89.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.92.2/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.92.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.0/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0 h1:y/cM2iqGgGi5D5DQZl6D9STN/3dR/Vx5Mp8s752oJTY= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -36,60 +49,77 @@ cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7 cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/firestore v1.5.0/go.mod h1:c4nNYR1qdq7eaZ+jSc5fonrQN2k3M7sWATcYTiakjEo= +cloud.google.com/go/kms v0.1.0/go.mod h1:8Qp8PCAypHg4FdmlyW1QRAv09BGQ9Uzh7JnmIZxPk+c= +cloud.google.com/go/kms v1.1.0 h1:1yc4rLqCkVDS9Zvc7m+3mJ47kw0Uo5Q5+sMjcmUVUeM= +cloud.google.com/go/kms v1.1.0/go.mod h1:WdbppnCDMDpOvoYBMn1+gNmOeEoZYqAv+HeuKARGCXI= +cloud.google.com/go/monitoring v0.1.0/go.mod h1:Hpm3XfzJv+UTiXzCG5Ffp0wijzHTC7Cv4eR7o3x/fEE= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/pubsub v1.5.0/go.mod h1:ZEwJccE3z93Z2HWvstpri00jOg7oO4UZDtKhwDwqF0w= -cloud.google.com/go/pubsub v1.10.3/go.mod h1:FUcc28GpGxxACoklPsE1sCtbkY4Ix+ro7yvw+h82Jn4= +cloud.google.com/go/pubsub v1.16.0/go.mod h1:6A8EfoWZ/lUvCWStKGwAWauJZSiuV0Mkmu6WilK/TxQ= +cloud.google.com/go/secretmanager v0.1.0/go.mod h1:3nGKHvnzDUVit7U0S9KAKJ4aOsO1xtwRG+7ey5LK1bM= cloud.google.com/go/spanner v1.7.0/go.mod h1:sd3K2gZ9Fd0vMPLXzeCrF6fq4i63Q7aTLW/lBIfBkIk= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.15.0 h1:Ljj+ZXVEhCr/1+4ZhvtteN1ND7UUsNTlduGclLh8GO0= -cloud.google.com/go/storage v1.15.0/go.mod h1:mjjQMoxxyGH7Jr8K5qrx6N2O0AHsczI61sMNn03GIZI= +cloud.google.com/go/storage v1.16.1/go.mod h1:LaNorbty3ehnU3rEjXSNV/NRgQA0O8Y+uh6bPe5UOk4= +cloud.google.com/go/storage v1.18.2 h1:5NQw6tOn3eMm0oE8vTkfjau18kjL79FlMjy/CHTpmoY= +cloud.google.com/go/storage v1.18.2/go.mod h1:AiIj7BWXyhO5gGVmYJ+S8tbkCx3yb0IMjua8Aw4naVM= +cloud.google.com/go/trace v0.1.0/go.mod h1:wxEwsoeRVPbeSkt7ZC9nWCgmoKQRAoySN7XHW2AmI7g= code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE= -code.gitea.io/sdk/gitea v0.15.0 h1:tsNhxDM/2N1Ohv1Xq5UWrht/esg0WmtRj4wsHVHriTg= -code.gitea.io/sdk/gitea v0.15.0/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMVoHRBA= +code.gitea.io/sdk/gitea v0.15.1 h1:WJreC7YYuxbn0UDaPuWIe/mtiNKTvLN8MLkaw71yx/M= +code.gitea.io/sdk/gitea v0.15.1/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMVoHRBA= contrib.go.opencensus.io/exporter/aws v0.0.0-20200617204711-c478e41e60e9/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= -contrib.go.opencensus.io/exporter/stackdriver v0.13.5/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= +contrib.go.opencensus.io/exporter/stackdriver v0.13.8/go.mod h1:huNtlWx75MwO7qMs0KrMxPZXzNNWebav1Sq/pm02JdQ= contrib.go.opencensus.io/integrations/ocsql v0.1.7/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/AlekSi/pointer v1.1.0 h1:SSDMPcXD9jSl8FPy9cRzoRaMJtm9g9ggGTxecRUbQoI= -github.com/AlekSi/pointer v1.1.0/go.mod h1:y7BvfRI3wXPWKXEBhU71nbnIEEZX0QTSB2Bj48UJIZE= +github.com/AlekSi/pointer v1.2.0 h1:glcy/gc4h8HnG2Z3ZECSzZ1IX1x2JxRVuDzaJwQE0+w= +github.com/AlekSi/pointer v1.2.0/go.mod h1:gZGfd3dpW4vEc/UlyfKKi1roIqcCgwOIvb0tSNSBle0= github.com/Antonboom/errname v0.1.4 h1:lGSlI42Gm4bI1e+IITtXJXvxFM8N7naWimVFKcb0McY= github.com/Antonboom/errname v0.1.4/go.mod h1:jRXo3m0E0EuCnK3wbsSVH3X55Z4iTDLl6ZfCxwFj4TM= github.com/Azure/azure-amqp-common-go/v3 v3.1.0/go.mod h1:PBIGdzcO1teYoufTKMcGibdKaYZv4avS+O6LNIp8bq0= +github.com/Azure/azure-amqp-common-go/v3 v3.1.1/go.mod h1:YsDaPfaO9Ub2XeSKdIy2DfwuiQlHQCauHJwSqtrkECI= github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVtCdfBE21U= github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k= github.com/Azure/azure-sdk-for-go v51.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go v54.0.0+incompatible h1:Bq3L9LF0DHCexlT0fccwxgrOMfjHx8LGz+d+L7gGQv4= -github.com/Azure/azure-sdk-for-go v54.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-service-bus-go v0.10.11/go.mod h1:AWw9eTTWZVZyvgpPahD1ybz3a8/vT3GsJDS8KYex55U= -github.com/Azure/azure-storage-blob-go v0.13.0 h1:lgWHvFh+UYBNVQLFHXkvul2f6yOPA9PIH82RTG2cSwc= -github.com/Azure/azure-storage-blob-go v0.13.0/go.mod h1:pA9kNqtjUeQF2zOSu4s//nUdBD+e64lEuc4sVnuOfNs= +github.com/Azure/azure-sdk-for-go v57.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v60.2.0+incompatible h1:twJOQQl3um6o+1q5SSyAdLr2GCX8dJPVRNS1eKOnv54= +github.com/Azure/azure-sdk-for-go v60.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-service-bus-go v0.10.16/go.mod h1:MlkLwGGf1ewcx5jZadn0gUEty+tTg0RaElr6bPf+QhI= +github.com/Azure/azure-storage-blob-go v0.14.0 h1:1BCg74AmVdYwO3dlKwtFU1V0wU2PZdREkXvAmZJRUlM= +github.com/Azure/azure-storage-blob-go v0.14.0/go.mod h1:SMqIBi+SuiQH32bvyjngEewEeXoPfKMgWlBDaYf6fck= github.com/Azure/go-amqp v0.13.0/go.mod h1:qj+o8xPCz9tMSbQ83Vp8boHahuRDl5mkNHyt1xlxUTs= -github.com/Azure/go-amqp v0.13.4/go.mod h1:wbpCKA8tR5MLgRyIu+bb+S6ECdIDdYJ0NlpFE9xsBPI= -github.com/Azure/go-amqp v0.13.7/go.mod h1:wbpCKA8tR5MLgRyIu+bb+S6ECdIDdYJ0NlpFE9xsBPI= +github.com/Azure/go-amqp v0.13.11/go.mod h1:D5ZrjQqB1dyp1A+G73xeL/kNn7D5qHJIIsNNps7YNmk= +github.com/Azure/go-amqp v0.13.12/go.mod h1:D5ZrjQqB1dyp1A+G73xeL/kNn7D5qHJIIsNNps7YNmk= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.11.3/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= github.com/Azure/go-autorest/autorest v0.11.17/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= -github.com/Azure/go-autorest/autorest v0.11.18 h1:90Y4srNYrwOtAgVo3ndrQkTYn6kf1Eg/AjTFJ8Is2aM= github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= +github.com/Azure/go-autorest/autorest v0.11.19/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= +github.com/Azure/go-autorest/autorest v0.11.20/go.mod h1:o3tqFY+QR40VOlk+pV4d77mORO64jOXSgEnPQgLK6JY= +github.com/Azure/go-autorest/autorest v0.11.23 h1:bRQWsW25/YkoxnIqXMPF94JW33qWDcrPMZ3bINaAruU= +github.com/Azure/go-autorest/autorest v0.11.23/go.mod h1:BAWYUWGPEtKPzjVkp0Q6an0MJcJDsoh5Z1BFAEFs4Xs= github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= -github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE= github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= github.com/Azure/go-autorest/autorest/adal v0.9.11/go.mod h1:nBKAnTomx8gDtl+3ZCJv2v0KACFHWTB2drffI1B68Pk= -github.com/Azure/go-autorest/autorest/adal v0.9.13 h1:Mp5hbtOePIzM8pJVRa3YLrWWmZtoxRXqUEzCfJt3+/Q= github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= -github.com/Azure/go-autorest/autorest/azure/auth v0.5.7 h1:8DQB8yl7aLQuP+nuR5e2RO6454OvFlSTXXaNHshc16s= -github.com/Azure/go-autorest/autorest/azure/auth v0.5.7/go.mod h1:AkzUsqkrdmNhfP2i54HqINVQopw0CLDnvHpJ88Zz1eI= -github.com/Azure/go-autorest/autorest/azure/cli v0.4.2 h1:dMOmEJfkLKW/7JsokJqkyoYSgmR08hi9KrhjZb+JALY= +github.com/Azure/go-autorest/autorest/adal v0.9.14/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= +github.com/Azure/go-autorest/autorest/adal v0.9.15/go.mod h1:tGMin8I49Yij6AQ+rvV+Xa/zwxYQB5hmsd6DkfAx2+A= +github.com/Azure/go-autorest/autorest/adal v0.9.18 h1:kLnPsRjzZZUF3K5REu/Kc+qMQrvuza2bwSnNdhmzLfQ= +github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.8/go.mod h1:kxyKZTSfKh8OVFWPAgOgQ/frrJgeYQJPyR5fLFmXko4= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.10 h1:F9A3Z++TtAoFysBsNOIJILoHuYBaYvhVGsMGEqPtIS8= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.10/go.mod h1:zQXYYNX9kXzRMrJNVXWUfNy38oPMF5/2TeZ4Wylc9fE= github.com/Azure/go-autorest/autorest/azure/cli v0.4.2/go.mod h1:7qkJkT+j6b+hIpzMOwPChJhTqS8VbsqqgULzMNRugoM= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.3/go.mod h1:yAQ2b6eP/CmLPnmLvxtT1ALIY3OR1oFcCqVBi8vHiTc= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.4 h1:iuooz5cZL6VRcO7DVSFYxRcouqn6bFVE/e77Wts50Zk= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.4/go.mod h1:yAQ2b6eP/CmLPnmLvxtT1ALIY3OR1oFcCqVBi8vHiTc= github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= @@ -108,9 +138,18 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw= github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/DisgoOrg/disgohook v1.4.4 h1:6xU+nRtyCYX7RyKvRnroJE8JMv+YIrQEMBDGUjBGDlQ= +github.com/DisgoOrg/disgohook v1.4.4/go.mod h1:l7r9dZgfkA3KiV+ErxqweKaknnskmzZO+SRTNHvJTUU= +github.com/DisgoOrg/log v1.1.0/go.mod h1:Qihgz6fax3JCfuO7vxVavL0LyHS0sUdQ9OmykQ2fiQs= +github.com/DisgoOrg/log v1.1.2 h1:tGJS4jaH1PyjPRHybHp8WpYJ/4fR3fYWT4Mv1PoDGBM= +github.com/DisgoOrg/log v1.1.2/go.mod h1:tSMofXaNhQNvzLRoL4tAiCG9yGY1ES5DLvduh7e9GRU= +github.com/DisgoOrg/restclient v1.2.8 h1:0Kv2g2bNYUvAAeIpJ1oNHorRcj5z6qkO2kOlm4R7cAs= +github.com/DisgoOrg/restclient v1.2.8/go.mod h1:2pc/htya/5kjxvWNYya98sb8B4mexobxmWvhTiWPt94= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= -github.com/GoogleCloudPlatform/cloudsql-proxy v1.22.0/go.mod h1:mAm5O/zik2RFmcpigNjg6nMotDL8ZXJaxKzgGVcSMFA= +github.com/GoogleCloudPlatform/cloudsql-proxy v1.24.0/go.mod h1:3tx938GhY4FC+E1KT/jNjDw7Z5qxAEtIiERJ2sXjnII= github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= @@ -125,21 +164,27 @@ github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZC github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.15/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= -github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY= +github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OpenPeeDeeP/depguard v1.0.1 h1:VlW4R6jmBIv3/u1JNlawEvJMM4J+dPORPaZasQee8Us= github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM= +github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= github.com/ProtonMail/go-crypto v0.0.0-20210512092938-c05353c2d58c h1:bNpaLLv2Y4kslsdkdCwAYu8Bak1aGVtxwi8Z/wy4Yuo= github.com/ProtonMail/go-crypto v0.0.0-20210512092938-c05353c2d58c/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= github.com/ProtonMail/go-mime v0.0.0-20190923161245-9b5a4261663a h1:W6RrgN/sTxg1msqzFFb+G80MFmpjMw61IU+slm+wln4= github.com/ProtonMail/go-mime v0.0.0-20190923161245-9b5a4261663a/go.mod h1:NYt+V3/4rEeDuaev/zw1zCq8uqVEuPHzDPo3OZrlGJ4= -github.com/ProtonMail/gopenpgp/v2 v2.2.0 h1:XLsUEY/dQhQcOg8r0ijNvMTJIKM4EBkf3K7zV+kcGj4= -github.com/ProtonMail/gopenpgp/v2 v2.2.0/go.mod h1:ajUlBGvxMH1UBZnaYO3d1FSVzjiC6kK9XlZYGiDCvpM= +github.com/ProtonMail/gopenpgp/v2 v2.2.2 h1:u2m7xt+CZWj88qK1UUNBoXeJCFJwJCZ/Ff4ymGoxEXs= +github.com/ProtonMail/gopenpgp/v2 v2.2.2/go.mod h1:ajUlBGvxMH1UBZnaYO3d1FSVzjiC6kK9XlZYGiDCvpM= github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= +github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= +github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= -github.com/alecthomas/jsonschema v0.0.0-20210526225647-edb03dcab7bc/go.mod h1:/n6+1/DWPltRLWL/VKyUxg6tzsl5kHUCcraimt4vr60= +github.com/alecthomas/jsonschema v0.0.0-20210920000243-787cd8204a0d/go.mod h1:/n6+1/DWPltRLWL/VKyUxg6tzsl5kHUCcraimt4vr60= +github.com/alecthomas/jsonschema v0.0.0-20211209230136-e2b41affa5c1 h1:6mZ7MG/flSahicBVy4GKlWI+dzoR5rgnm7H8e17TAio= +github.com/alecthomas/jsonschema v0.0.0-20211209230136-e2b41affa5c1/go.mod h1:/n6+1/DWPltRLWL/VKyUxg6tzsl5kHUCcraimt4vr60= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -167,14 +212,55 @@ github.com/ashanbrown/forbidigo v1.2.0 h1:RMlEFupPCxQ1IogYOQUnIQwGEUGK8g5vAPMRyJ github.com/ashanbrown/forbidigo v1.2.0/go.mod h1:vVW7PEdqEFqapJe95xHkTfB1+XvZXBFg8t0sG2FIxmI= github.com/ashanbrown/makezero v0.0.0-20210520155254-b6261585ddde h1:YOsoVXsZQPA9aOTy1g0lAJv5VzZUvwQuZqug8XPeqfM= github.com/ashanbrown/makezero v0.0.0-20210520155254-b6261585ddde/go.mod h1:oG9Dnez7/ESBqc4EdrdNlryeo7d0KcW1ftXHm7nU/UU= +github.com/atc0005/go-teams-notify/v2 v2.6.1 h1:t22ybzQuaQs4UJe4ceF5VYGsPhs6ir3nZOId/FBy6Go= +github.com/atc0005/go-teams-notify/v2 v2.6.1/go.mod h1:xo6GejLDHn3tWBA181F8LrllIL0xC1uRsRxq7YNXaaY= github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.36.30/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.38.35 h1:7AlAO0FC+8nFjxiGKEmq0QLpiA8/XFr6eIxgRTwkdTg= -github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.40.34/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= +github.com/aws/aws-sdk-go v1.42.24 h1:pDUeL5+HaEK+CBKsnzmjZCpLmfRek9JLMM/KhjiQorU= +github.com/aws/aws-sdk-go v1.42.24/go.mod h1:gyRszuZ/icHmHAVE4gc/r+cfCmhA1AD+vqfWbgI+eHs= +github.com/aws/aws-sdk-go-v2 v1.9.0/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= +github.com/aws/aws-sdk-go-v2 v1.11.2 h1:SDiCYqxdIYi6HgQfAWRhgdZrdnOuGyLDJVRSWLeHWvs= +github.com/aws/aws-sdk-go-v2 v1.11.2/go.mod h1:SQfA+m2ltnu1cA0soUkj4dRSsmITiVQUJvBIZjzfPyQ= +github.com/aws/aws-sdk-go-v2/config v1.7.0/go.mod h1:w9+nMZ7soXCe5nT46Ri354SNhXDQ6v+V5wqDjnZE+GY= +github.com/aws/aws-sdk-go-v2/config v1.11.0 h1:Czlld5zBB61A3/aoegA9/buZulwL9mHHfizh/Oq+Kqs= +github.com/aws/aws-sdk-go-v2/config v1.11.0/go.mod h1:VrQDJGFBM5yZe+IOeenNZ/DWoErdny+k2MHEIpwDsEY= +github.com/aws/aws-sdk-go-v2/credentials v1.4.0/go.mod h1:dgGR+Qq7Wjcd4AOAW5Rf5Tnv3+x7ed6kETXyS9WCuAY= +github.com/aws/aws-sdk-go-v2/credentials v1.6.4 h1:2hvbUoHufns0lDIsaK8FVCMukT1WngtZPavN+W2FkSw= +github.com/aws/aws-sdk-go-v2/credentials v1.6.4/go.mod h1:tTrhvBPHyPde4pdIPSba4Nv7RYr4wP9jxXEDa1bKn/8= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.5.0/go.mod h1:CpNzHK9VEFUCknu50kkB8z58AH2B5DvPP7ea1LHve/Y= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.8.2 h1:KiN5TPOLrEjbGCvdTQR4t0U4T87vVwALZ5Bg3jpMqPY= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.8.2/go.mod h1:dF2F6tXEOgmW5X1ZFO/EPtWrcm7XkW07KNcJUGNtt4s= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.2 h1:XJLnluKuUxQG255zPNe+04izXl7GSyUVafIsgfv9aw4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.2/go.mod h1:SgKKNBIoDC/E1ZCDhhMW3yalWjwuLjMcpLzsM/QQnWo= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.0.2 h1:EauRoYZVNPlidZSZJDscjJBQ22JhVF2+tdteatax2Ak= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.0.2/go.mod h1:xT4XX6w5Sa3dhg50JrYyy3e4WPYo/+WjY/BXtqXVunU= +github.com/aws/aws-sdk-go-v2/internal/ini v1.2.2/go.mod h1:BQV0agm+JEhqR+2RT5e1XTFIDcAAV0eW6z2trp+iduw= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.2 h1:IQup8Q6lorXeiA/rK72PeToWoWK8h7VAPgHNWdSrtgE= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.2/go.mod h1:VITe/MdW6EMXPb0o0txu/fsonXbMHUU2OC2Qp7ivU4o= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.3.0/go.mod h1:R1KK+vY8AfalhG1AOu5e35pOD2SdoPKQCFLTvnxiohk= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.5.2 h1:CKdUNKmuilw/KNmO2Q53Av8u+ZyXMC2M9aX8Z+c/gzg= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.5.2/go.mod h1:FgR1tCsn8C6+Hf+N5qkfrE4IXvUL1RgW87sunJ+5J4I= +github.com/aws/aws-sdk-go-v2/service/kms v1.5.0/go.mod h1:w7JuP9Oq1IKMFQPkNe3V6s9rOssXzOVEMNEqK1L1bao= +github.com/aws/aws-sdk-go-v2/service/kms v1.11.1 h1:4WsetDYlA3aUYTuQQU76VMi3xH4D/CSbrx9aVqEUwHE= +github.com/aws/aws-sdk-go-v2/service/kms v1.11.1/go.mod h1:e33KkPXn1iEeHHHflmS+Jxx09wbYw2uzAO3sQE1smg0= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.6.0/go.mod h1:B+7C5UKdVq1ylkI/A6O8wcurFtaux0R1njePNPtKwoA= +github.com/aws/aws-sdk-go-v2/service/ssm v1.10.0/go.mod h1:4dXS5YNqI3SNbetQ7X7vfsMlX6ZnboJA2dulBwJx7+g= +github.com/aws/aws-sdk-go-v2/service/sso v1.4.0/go.mod h1:+1fpWnL96DL23aXPpMGbsmKe8jLTEfbjuQoA4WS1VaA= +github.com/aws/aws-sdk-go-v2/service/sso v1.6.2 h1:2IDmvSb86KT44lSg1uU4ONpzgWLOuApRl6Tg54mZ6Dk= +github.com/aws/aws-sdk-go-v2/service/sso v1.6.2/go.mod h1:KnIpszaIdwI33tmc/W/GGXyn22c1USYxA/2KyvoeDY0= +github.com/aws/aws-sdk-go-v2/service/sts v1.7.0/go.mod h1:0qcSMCyASQPN2sk/1KQLQ2Fh6yq8wm0HSDAimPhzCoM= +github.com/aws/aws-sdk-go-v2/service/sts v1.11.1 h1:QKR7wy5e650q70PFKMfGF9sTo0rZgUevSSJ4wxmyWXk= +github.com/aws/aws-sdk-go-v2/service/sts v1.11.1/go.mod h1:UV2N5HaPfdbDpkgkz4sRzWCvQswZjdO1FfqCWl0t7RA= +github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= +github.com/aws/smithy-go v1.9.0 h1:c7FUdEqrQA1/UVKKCNDFQPNKGp4FQg3YW4Ck5SLTG58= +github.com/aws/smithy-go v1.9.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -188,26 +274,35 @@ github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4 github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= github.com/bombsimon/wsl/v3 v3.3.0 h1:Mka/+kRLoQJq7g2rggtgQsjuI/K5Efd87WX96EWFxjM= github.com/bombsimon/wsl/v3 v3.3.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc= +github.com/bradleyfalzon/ghinstallation/v2 v2.0.4/go.mod h1:B40qPqJxWE0jDZgOR1JmaMy+4AY1eBP+IByOvqyAKp0= github.com/caarlos0/ctrlc v1.0.0 h1:2DtF8GSIcajgffDFJzyG15vO+1PuBWOMUdFut7NnXhw= github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGrrHhcQw= -github.com/caarlos0/env/v6 v6.7.0 h1:OftrMgQyETinUI4YU3WxhHeKtCRonDMtnUO14+ZRXdY= -github.com/caarlos0/env/v6 v6.7.0/go.mod h1:FE0jGiAnQqtv2TenJ4KTa8+/T2Ss8kdS5s1VEjasoN0= +github.com/caarlos0/env/v6 v6.9.1 h1:zOkkjM0F6ltnQ5eBX6IPI41UP/KDGEK7rRPwGCNos8k= +github.com/caarlos0/env/v6 v6.9.1/go.mod h1:hvp/ryKXKipEkcuYjs9mI4bBCg+UI0Yhgm5Zu0ddvwc= +github.com/caarlos0/go-reddit/v3 v3.0.1 h1:w8ugvsrHhaE/m4ez0BO/sTBOBWI9WZTjG7VTecHnql4= +github.com/caarlos0/go-reddit/v3 v3.0.1/go.mod h1:QlwgmG5SAqxMeQvg/A2dD1x9cIZCO56BMnMdjXLoisI= +github.com/caarlos0/go-rpmutils v0.2.1-0.20211112020245-2cd62ff89b11 h1:IRrDwVlWQr6kS1U8/EtyA1+EHcc4yl8pndcqXWrEamg= +github.com/caarlos0/go-rpmutils v0.2.1-0.20211112020245-2cd62ff89b11/go.mod h1:je2KZ+LxaCNvCoKg32jtOIULcFogJKcL1ZWUaIBjKj0= github.com/caarlos0/go-shellwords v1.0.12 h1:HWrUnu6lGbWfrDcFiHcZiwOLzHWjjrPVehULaTFgPp8= github.com/caarlos0/go-shellwords v1.0.12/go.mod h1:bYeeX1GrTLPl5cAMYEzdm272qdsQAZiaHgeF0KTk1Gw= -github.com/caarlos0/testfs v0.4.3 h1:q1zEM5hgsssqWanAfevJYYa0So60DdK6wlJeTc/yfUE= -github.com/caarlos0/testfs v0.4.3/go.mod h1:bRN55zgG4XCUVVHZCeU+/Tz1Q6AxEJOEJTliBy+1DMk= -github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e h1:hHg27A0RSSp2Om9lubZpiMgVbvn39bsUmW9U5h0twqc= -github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oDpT4efm8tSYHXV5tHSdRvBet/b/QzxZ+XyyPehvm3A= -github.com/cenkalti/backoff v2.1.1+incompatible h1:tKJnvO2kl0zmb/jA5UKAt4VoEVw1qxKWjE/Bpp46npY= -github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/caarlos0/testfs v0.4.4 h1:3PHvzHi5Lt+g332CiShwS8ogTgS3HjrmzZxCm6JCDr8= +github.com/caarlos0/testfs v0.4.4/go.mod h1:bRN55zgG4XCUVVHZCeU+/Tz1Q6AxEJOEJTliBy+1DMk= +github.com/cavaliergopher/cpio v1.0.1 h1:KQFSeKmZhv0cr+kawA3a0xTQCU4QxXF1vhU7P7av2KM= +github.com/cavaliergopher/cpio v1.0.1/go.mod h1:pBdaqQjnvXxdS/6CvNDwIANIFSP0xRKI16PX4xejRQc= +github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo= +github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0 h1:t/LhUZLVitR1Ow2YOnduCsavhwFUklBMoGVYUCqmCqk= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/charithe/durationcheck v0.0.8 h1:cnZrThioNW9gSV5JsRIXmkyHUbcDH7Y9hkzFDVc9/j0= github.com/charithe/durationcheck v0.0.8/go.mod h1:SSbRIBVfMjCi/kEB6K65XEA83D6prSM8ap1UCpNKtgg= +github.com/charmbracelet/keygen v0.2.1 h1:H1yYTVe6qIDz+UILYXo6q+qLQNkvyXXA5KEhzyuEfzg= +github.com/charmbracelet/keygen v0.2.1/go.mod h1:kFQ3Cvop12fXWX1K29vxDxV9x8ujG4wBSXq//GySSSk= github.com/chavacava/garif v0.0.0-20210405164556-e8a0a408d6af h1:spmv8nSH9h5oCQf40jt/ufBCt9j0/58u4G+rkeMqXGI= github.com/chavacava/garif v0.0.0-20210405164556-e8a0a408d6af/go.mod h1:Qjyv4H3//PWVzTeCezG2b9IRn6myJxJSr4TD/xo6ojU= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -217,6 +312,15 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 h1:hzAQntlaYRkVSFEfj9OTWlVV1H155FMD8BTKktLv0QI= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211216145620-d92e9ce0af51 h1:F6fR7MjvOIk+FLQOeBCAbbKItVgbdj0l9VWPiHeBEiY= +github.com/cncf/xds/go v0.0.0-20211216145620-d92e9ce0af51/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -227,15 +331,15 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190620071333-e64a0ec8b42a/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.3.1/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= @@ -251,12 +355,12 @@ github.com/denis-tingajkin/go-header v0.4.2 h1:jEeSF4sdv8/3cT/WY8AgDHUoItNSoEZ7q github.com/denis-tingajkin/go-header v0.4.2/go.mod h1:eLRHAVXzE5atsKAnNRDB90WHCFFnBUn4RN0nRcs1LJA= github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY= -github.com/dghubble/go-twitter v0.0.0-20210609183100-2fdbf421508e h1:o0sI/cfhAXdtAbiIVeTd4hmwtwgs4cQFwRBhmbx8AKY= -github.com/dghubble/go-twitter v0.0.0-20210609183100-2fdbf421508e/go.mod h1:xfg4uS5LEzOj8PgZV7SQYRHbG7jPUnelEiaAVJxmhJE= -github.com/dghubble/oauth1 v0.7.0 h1:AlpZdbRiJM4XGHIlQ8BuJ/wlpGwFEJNnB4Mc+78tA/w= -github.com/dghubble/oauth1 v0.7.0/go.mod h1:8pFdfPkv/jr8mkChVbNVuJ0suiHe278BtWI4Tk1ujxk= -github.com/dghubble/sling v1.3.0 h1:pZHjCJq4zJvc6qVQ5wN1jo5oNZlNE0+8T/h0XeXBUKU= -github.com/dghubble/sling v1.3.0/go.mod h1:XXShWaBWKzNLhu2OxikSNFrlsvowtz4kyRuXUG7oQKY= +github.com/dghubble/go-twitter v0.0.0-20211115160449-93a8679adecb h1:7ENzkH+O3juL+yj2undESLTaAeRllHwCs/b8z6aWSfc= +github.com/dghubble/go-twitter v0.0.0-20211115160449-93a8679adecb/go.mod h1:qhZBgV9e4WyB1JNjHpcXVkUe3knWUwYuAPB1hITdm50= +github.com/dghubble/oauth1 v0.7.1 h1:JjbOVSVVkms9A4h/sTQy5Jb2nFuAAVb2qVYgenJPyrE= +github.com/dghubble/oauth1 v0.7.1/go.mod h1:0eEzON0UY/OLACQrmnjgJjmvCGXzjBCsZqL1kWDXtF0= +github.com/dghubble/sling v1.4.0 h1:/n8MRosVTthvMbwlNZgLx579OGVjUOy3GNEv5BIqAWY= +github.com/dghubble/sling v1.4.0/go.mod h1:0r40aNsU9EdDUVBNhfCstAtFgutjgJGYbO1oNzkMoM8= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= @@ -272,8 +376,14 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.1 h1:cgDRLG7bs59Zd+apAWuzLQL95obVYAymNJek76W3mgw= +github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= github.com/envoyproxy/protoc-gen-validate v0.0.14/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.6.2 h1:JiO+kJTpmYGjEodY7O1Zk8oZcNz1+f30UtwtXoFUPzE= +github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= github.com/esimonov/ifshort v1.0.2 h1:K5s1W2fGfkoWXsFlxBNqT6J0ZCncPaKrGM5qe0bni68= github.com/esimonov/ifshort v1.0.2/go.mod h1:yZqNJUrNn20K8Q9n2CrjTKYyVEmX209Hgu+M1LBpeZE= github.com/ettle/strcase v0.1.1 h1:htFueZyVeE1XNnMEfbqp5r67qAN/4r6ya1ysq8Q+Zcw= @@ -281,19 +391,20 @@ github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc= github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/fullstorydev/grpcurl v1.6.0/go.mod h1:ZQ+ayqbKMJNhzLmbpCiurTVlaK2M/3nqZCxaQ2Ze/sM= github.com/fzipp/gocyclo v0.3.1 h1:A9UeX3HJSXTBzvHzhqoYVuE0eAhe+aM8XBCCwsPMZOc= github.com/fzipp/gocyclo v0.3.1/go.mod h1:DJHO6AUmbdqj2ET4Z9iArSuwWgYDRryYt2wASxc7x3E= @@ -311,13 +422,15 @@ github.com/go-critic/go-critic v0.5.6/go.mod h1:cVjj0DfqewQVIlIAGexPCaGaZDAqGE29 github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-billy/v5 v5.1.0 h1:4pl5BV4o7ZG/lterP4S6WzJ6xr49Ba5ET9ygheTYahk= -github.com/go-git/go-billy/v5 v5.1.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12 h1:PbKy9zOy4aAKrJ5pibIRpVO2BXnK1Tlcg+caKI7Ox5M= +github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34= +github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= +github.com/go-git/go-git-fixtures/v4 v4.2.1 h1:n9gGL1Ct/yIw+nfsfr8s4+sbhT+Ncu2SubfXjIWgci8= +github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0= github.com/go-git/go-git/v5 v5.2.0/go.mod h1:kh02eMX+wdqqxgNMEyq8YgwlIOsDOa9homkUq1PoTMs= -github.com/go-git/go-git/v5 v5.3.0 h1:8WKMtJR2j8RntEXR/uvTKagfEt4GYlwQ7mntE4+0GWc= -github.com/go-git/go-git/v5 v5.3.0/go.mod h1:xdX4bWJ48aOrdhnl2XqHYstHbbp6+LFS4r4X+lNVprw= +github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4= +github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -341,6 +454,8 @@ github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU= +github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM= github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-toolsmith/astcast v1.0.0 h1:JojxlmI6STnFVG9yOImLeGREv8W2ocNUM+iOhR6jE7g= @@ -376,6 +491,9 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU= +github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -393,6 +511,7 @@ github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -449,23 +568,27 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-github/v35 v35.3.0 h1:fU+WBzuukn0VssbayTT+Zo3/ESKX9JYWjbZTLOTEyho= -github.com/google/go-github/v35 v35.3.0/go.mod h1:yWB7uCcVWaUbUP74Aq3whuMySRMatyRmq5U9FTNlbio= -github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-github/v41 v41.0.0/go.mod h1:XgmCA5H323A9rtgExdTcnDkcqp6S30AVACCBDOonIxg= +github.com/google/go-github/v43 v43.0.0 h1:y+GL7LIsAIF2NZlJ46ZoC/D1W1ivZasT0lnWHMYPZ+U= +github.com/google/go-github/v43 v43.0.0/go.mod h1:ZkTvvmCXBvsfPpTHXnH/d2hP9Y0cTbvN9kr5xqyXOIc= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/go-replayers/grpcreplay v1.0.0 h1:B5kVOzJ1hBgnevTgIWhSTatQ3608yu/2NnU0Ta1d0kY= -github.com/google/go-replayers/grpcreplay v1.0.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE= -github.com/google/go-replayers/httpreplay v0.1.2 h1:HCfx+dQzwN9XbGTHF8qJ+67WN8glL9FTWV5rraCJ/jU= -github.com/google/go-replayers/httpreplay v0.1.2/go.mod h1:YKZViNhiGgqdBlUbI2MwGpq4pXxNmhJLPHQ7cv2b5no= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/go-replayers/grpcreplay v1.1.0 h1:S5+I3zYyZ+GQz68OfbURDdt/+cSMqCK1wrvNx7WBzTE= +github.com/google/go-replayers/grpcreplay v1.1.0/go.mod h1:qzAvJ8/wi57zq7gWqaE6AwLM6miiXUQwP1S+I9icmhk= +github.com/google/go-replayers/httpreplay v1.0.0 h1:8SmT8fUYM4nueF+UnXIX8LJxNTb1vpPuknXz+yTWzL4= +github.com/google/go-replayers/httpreplay v1.0.0/go.mod h1:LJhKoTwS5Wy5Ld/peq8dFFG5OfJyHEz7ft+DsTUv25M= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible h1:xmapqc1AyLoB+ddYT6r04bD9lIjlOqGaREovi0SzFaE= github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0 h1:wCKgOCHuUEVfsaQLpPSJb7VdYCdTVZQAuOdYm1yc/60= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1 h1:d8MncMlErDFTwQGBK1xhv026j9kqhvw1Qv9IbWT1VLQ= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -479,22 +602,30 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210506205249-923b5ab0fc1a/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210715191844-86eeefc3e471/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/rpmpack v0.0.0-20210410105602-e20c988a6f5a h1:XC048Fc/OB2rUl/BxruopEl2u/EP6cJNFveVxI1cvdk= -github.com/google/rpmpack v0.0.0-20210410105602-e20c988a6f5a/go.mod h1:+y9lKiqDhR4zkLl+V9h4q0rdyrYVsWWm6LLCQP33DIk= +github.com/google/rpmpack v0.0.0-20211125064518-d0ed9b1b61b9 h1:ClPt4zdk8fbRqTANpgege8HBktalZaIz32dIGnwcVZI= +github.com/google/rpmpack v0.0.0-20211125064518-d0ed9b1b61b9/go.mod h1:3YnKULqkUnzpgcZS8uQgbTRwcAW4IqYiUzWFy6aVvu0= github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/trillian v1.3.11/go.mod h1:0tPraVHrSDkA3BO6vKX67zgLXs6SsOAbHEivX+9mPgw= github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8= github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1 h1:dp3bWCh+PPO1zjRRiCSczJav13sBvG4UhNyVTa1KqdU= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -503,12 +634,12 @@ github.com/gordonklaus/ineffassign v0.0.0-20210225214923-2e10b2664254 h1:Nb2aRlC github.com/gordonklaus/ineffassign v0.0.0-20210225214923-2e10b2664254/go.mod h1:M9mZEtGIsR1oDaZagNPNG9iq9n2HrhZ17dsXk73V3Lw= github.com/goreleaser/chglog v0.1.2 h1:tdzAb/ILeMnphzI9zQ7Nkq+T8R9qyXli8GydD8plFRY= github.com/goreleaser/chglog v0.1.2/go.mod h1:tTZsFuSZK4epDXfjMkxzcGbrIOXprf0JFp47BjIr3B8= -github.com/goreleaser/fileglob v1.2.0 h1:OErqbdzeg/eibfDGPHDQDN8jL5u1jNyxA5IQzNPLLoU= -github.com/goreleaser/fileglob v1.2.0/go.mod h1:rFyb2pXaK3YdnYnSjn6lifw0h2Q6s8OfOsx6I6bXkKE= -github.com/goreleaser/goreleaser v0.178.0 h1:rc4yBn2vQ2eNMz9mPx+0/2v9R24c4meFqinpl3K8c00= -github.com/goreleaser/goreleaser v0.178.0/go.mod h1:/3Iz1GSJFxAVLAu1gkZoV8mXm6WJ94rtvk+t+81+Uw4= -github.com/goreleaser/nfpm/v2 v2.6.0 h1:bwDU9o4/CVTSpqASJA7+r+rkqpTGamQKYHMRH3wDlRE= -github.com/goreleaser/nfpm/v2 v2.6.0/go.mod h1:qaMnjBaZz/2vInOIWx0IbuKuaZpaVB6O8oLG0u4qH1Y= +github.com/goreleaser/fileglob v1.3.0 h1:/X6J7U8lbDpQtBvGcwwPS6OpzkNVlVEsFUVRx9+k+7I= +github.com/goreleaser/fileglob v1.3.0/go.mod h1:Jx6BoXv3mbYkEzwm9THo7xbr5egkAraxkGorbJb4RxU= +github.com/goreleaser/goreleaser v1.6.1 h1:FzbmxtKCu+/R4dC1Yf3DR/VpBN8jBA2O2X11465LxE4= +github.com/goreleaser/goreleaser v1.6.1/go.mod h1:GNAzFVZsES0XQyspLpg0pYMRTAeC2wmNejmmxF9r90g= +github.com/goreleaser/nfpm/v2 v2.14.0 h1:1xFq1F1Dy3HSdbjUtd+8CCahxLNlQwylcHwoLOg/lW0= +github.com/goreleaser/nfpm/v2 v2.14.0/go.mod h1:46Gk7U5PrLL34NxrsorlkiavoX5gwyGOYQSMaPn5xdw= github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75/go.mod h1:g2644b03hfBX9Ov0ZBDgXXens4rxSxmqFBbhvKv2yVA= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= @@ -540,24 +671,28 @@ github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBt github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.0.0 h1:bkKf0BeBXcSYa7f5Fyi9gMuQ8gNsxeiNpZjR6VxNZeo= +github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-retryablehttp v0.6.8 h1:92lWxgpa+fF3FozM4B3UZtHZMJX8T5XT+TFdCxsPyWs= github.com/hashicorp/go-retryablehttp v0.6.8/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-retryablehttp v0.7.0 h1:eu1EI/mbirUgP5C8hVsTNaGZreBDlYiwC1FZWkvQPQ4= +github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.3.0 h1:McDWVJIU/y+u1BRV06dPaLfLCaT7fUTJLp5r04x7iNw= +github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -574,6 +709,9 @@ github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63 github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA= +github.com/iancoleman/orderedmap v0.2.0 h1:sq1N/TFpYH++aViPcaKjys3bDClUEU7s5B+z6jq8pNA= +github.com/iancoleman/orderedmap v0.2.0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= @@ -584,8 +722,8 @@ github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jarcoal/httpmock v1.0.8 h1:8kI16SoO6LQKgPE7PvQuV+YuD/inwHd7fOOe2zMbo4k= -github.com/jarcoal/httpmock v1.0.8/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= +github.com/jarcoal/httpmock v1.1.0 h1:F47ChZj1Y2zFsCXxNkBPwNNKnAyOATcdQibk0qEdVCE= +github.com/jarcoal/httpmock v1.1.0/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -614,7 +752,6 @@ github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -637,7 +774,12 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.0/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= +github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -672,10 +814,9 @@ github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.1/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= @@ -688,6 +829,7 @@ github.com/maratori/testpackage v1.0.1 h1:QtJ5ZjqapShm0w5DosRjg0PRlSdAdlx+W6cCKo github.com/maratori/testpackage v1.0.1/go.mod h1:ddKdw+XG0Phzhx8BFDTKgpWP4i7MpApTE5fXSKAqwDU= github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 h1:pWxk9e//NbPwfxat7RXkts09K+dEBJWakUWwICVqYbA= github.com/matoous/godox v0.0.0-20210227103229-6504466cf951/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= +github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= @@ -696,8 +838,10 @@ github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcncea github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-ieproxy v0.0.1 h1:qiyop7gCflfhwCzGyeT0gro3sF9AIg9HU98JORTkqfI= github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= @@ -707,8 +851,9 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= @@ -729,10 +874,12 @@ github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3N github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a h1:eU8j/ClY2Ty3qdHnn0TyW3ivFoPC/0F1gQZz8yTxbbE= +github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a/go.mod h1:v8eSC2SMp9/7FTKUncp7fH9IwPfw+ysMObcEz5FWheQ= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= -github.com/mitchellh/copystructure v1.1.2 h1:Th2TIvG1+6ma3e/0/bopBKohOTY7s4dA8V2q4EUcBJ0= -github.com/mitchellh/copystructure v1.1.2/go.mod h1:EBArHfARyrSWO/+Wyr9zwEkc6XMFB9XyNgFNmRkZZU4= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -746,8 +893,9 @@ github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -757,6 +905,16 @@ github.com/moricho/tparallel v0.2.1 h1:95FytivzT6rYzdJLdtfn6m1bfFJylOJK41+lgv/EH github.com/moricho/tparallel v0.2.1/go.mod h1:fXEIZxG2vdfl0ZF8b42f5a78EhjjD5mX8qUplsoSU4k= github.com/mozilla/scribe v0.0.0-20180711195314-fb71baf557c1/go.mod h1:FIczTrinKo8VaLxe6PWTPEXRXDIHz2QAwiaBaP5/4a8= github.com/mozilla/tls-observatory v0.0.0-20210609171429-7bc42856d2e5/go.mod h1:FUqVoUPHSEdDR0MnFM3Dh8AU0pZHLXUD127SAJGER/s= +github.com/muesli/coral v1.0.0 h1:odyqkoEg4aJAINOzvnjN4tUsdp+Zleccs7tRIAkkYzU= +github.com/muesli/coral v1.0.0/go.mod h1:bf91M/dkp7iHQw73HOoR9PekdTJMTD6ihJgWoDitde8= +github.com/muesli/mango v0.1.0 h1:DZQK45d2gGbql1arsYA4vfg4d7I9Hfx5rX/GCmzsAvI= +github.com/muesli/mango v0.1.0/go.mod h1:5XFpbC8jY5UUv89YQciiXNlbi+iJgt29VDC5xbzrLL4= +github.com/muesli/mango-coral v1.0.1 h1:W3nGbUC/q5vLscQ6GPzteHZrJI1Msjw5Hns82o0xRkI= +github.com/muesli/mango-coral v1.0.1/go.mod h1:EPSlYH67AtcxQrxssNw6r/lMFxHTjuDoGfq9Uxxevhg= +github.com/muesli/mango-pflag v0.1.0 h1:UADqbYgpUyRoBja3g6LUL+3LErjpsOwaC9ywvBWe7Sg= +github.com/muesli/mango-pflag v0.1.0/go.mod h1:YEQomTxaCUp8PrbhFh10UfbhbQrM/xJ4i2PB8VTLLW0= +github.com/muesli/roff v0.1.0 h1:YD0lalCotmYuF5HhZliKWlIx7IEhiXeSfq7hNjFqGF8= +github.com/muesli/roff v0.1.0/go.mod h1:pjAHQM9hdUUwm/krAfrLGgJkXJ+YuhtsfZ42kieB2Ig= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007/go.mod h1:m2XC9Qq0AlmmVksL6FktJCdTYyLk7V3fKyp0sl1yWQo= github.com/mwitkow/go-proto-validators v0.2.0/go.mod h1:ZfA1hW+UH/2ZHOWvQ3HnQaU0DtnpXu850MZiy+YUgcc= @@ -790,8 +948,6 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak= github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= -github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88= -github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= @@ -860,8 +1016,9 @@ github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4 github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryancurrah/gomodguard v1.2.3 h1:ww2fsjqocGCAFamzvv/b8IsRduuHHeK2MHTcTxZTQX8= github.com/ryancurrah/gomodguard v1.2.3/go.mod h1:rYbA/4Tg5c54mV1sv4sQTP5WOPBcoLtnBZ7/TEhXAbg= github.com/ryanrolds/sqlclosecheck v0.3.0 h1:AZx+Bixh8zdUBxUA1NxbxVAS78vTPq4rCb8OUZI9xFw= @@ -869,8 +1026,6 @@ github.com/ryanrolds/sqlclosecheck v0.3.0/go.mod h1:1gREqxyTGR3lVtpngyFo3hZAgk0K github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sanposhiho/wastedassign/v2 v2.0.6 h1:+6/hQIHKNJAUixEj6EmOngGIisyeI+T3335lYTyxRoA= github.com/sanposhiho/wastedassign/v2 v2.0.6/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= -github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b h1:+gCnWOZV8Z/8jehJ2CdqB47Z3S+SREmQcuXkRFLNsiI= -github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b/go.mod h1:am+Fp8Bt506lA3Rk3QCmSqmYmLMnPDhdDUcosQCAx+I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/securego/gosec/v2 v2.8.1 h1:Tyy/nsH39TYCOkqf5HAgRE+7B5D8sHDwPdXRgFWokh8= github.com/securego/gosec/v2 v2.8.1/go.mod h1:pUmsq6+VyFEElJMUX+QB3p3LWNHXg1R3xh2ssVJPs8Q= @@ -883,7 +1038,6 @@ github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAx github.com/shirou/gopsutil/v3 v3.21.7/go.mod h1:RGl11Y7XMTQPmHh8F0ayC6haKNBgH4PXMJuTAcMOlz4= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= -github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= @@ -892,8 +1046,8 @@ github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrf github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/slack-go/slack v0.9.4 h1:C+FC3zLxLxUTQjDy2RZeMHYon005zsCROiZNWVo+opQ= -github.com/slack-go/slack v0.9.4/go.mod h1:wWL//kk0ho+FcQXcBTmEafUI5dz4qz5f4mMk8oIkioQ= +github.com/slack-go/slack v0.10.2 h1:KMN/h2sgUninHXvQI8PrR/PHBUuWp2NPvz2Kr66tki4= +github.com/slack-go/slack v0.10.2/go.mod h1:5FLdBRv7VW/d9EBxx/eEktOptWygbA9K2QK/KW7ds1s= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= @@ -908,6 +1062,7 @@ github.com/sourcegraph/go-diff v0.6.1 h1:hmA1LzxW0n1c3Q4YbrFgg4P99GSnebYa3x8gr0H github.com/sourcegraph/go-diff v0.6.1/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.4.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= @@ -951,6 +1106,8 @@ github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tdakkota/asciicheck v0.0.0-20200416200610-e657995f937b h1:HxLVTlqcHhFAz3nWUcuvpH7WuOMv8LQoCWmruLfFH2U= github.com/tdakkota/asciicheck v0.0.0-20200416200610-e657995f937b/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM= +github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM= +github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog= github.com/tetafro/godot v1.4.9 h1:wsNd0RuUxISqqudFqchsSsMqsM188DoZVPBeKl87tP0= github.com/tetafro/godot v1.4.9/go.mod h1:LR3CJpxDVGlYOWn3ZZg1PgNZdTUvzsZWu8xaEohUpn8= github.com/timakin/bodyclose v0.0.0-20200424151742-cb6215831a94 h1:ig99OeTyDwQWhPe2iw9lwfQVF1KB3Q4fpP3X7/2VBG8= @@ -975,7 +1132,6 @@ github.com/tommy-muehle/go-mnd/v2 v2.4.0/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= @@ -995,14 +1151,13 @@ github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52 github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/quicktemplate v1.6.3/go.mod h1:fwPzK2fHuYEODzJ9pkw0ipCPNHZ2tD5KW4lOuSdPKzY= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= -github.com/vartanbeno/go-reddit/v2 v2.0.0 h1:fxYMqx5lhbmJ3yYRN1nnQC/gecRB3xpUS2BbG7GLpsk= -github.com/vartanbeno/go-reddit/v2 v2.0.0/go.mod h1:758/S10hwZSLm43NPtwoNQdZFSg3sjB5745Mwjb0ANI= github.com/viki-org/dnscache v0.0.0-20130720023526-c70c1f23c5d8/go.mod h1:dniwbG03GafCjFohMDmz6Zc6oCuiqgH6tGNyXTkHzXE= -github.com/xanzy/go-gitlab v0.50.3 h1:M7ncgNhCN4jaFNyXxarJhCLa9Qi6fdmCxFFhMTQPZiY= -github.com/xanzy/go-gitlab v0.50.3/go.mod h1:Q+hQhV508bDPoBijv7YjK/Lvlb4PhVhJdKqXVQrUoAE= +github.com/xanzy/go-gitlab v0.56.0 h1:/QHBvk3IKVNwvXB/UOWVb5J6VCN6r2bg9/WxjUbFY/0= +github.com/xanzy/go-gitlab v0.56.0/go.mod h1:F0QEXwmqiBUxCgJm8fE9S+1veX4XC9Z4cfaAbqwk4YM= github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= -github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI= github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= +github.com/xanzy/ssh-agent v0.3.1 h1:AmzO1SSWxw73zxFZPRwaMN1MohDw8UyHnmuxyceTEGo= +github.com/xanzy/ssh-agent v0.3.1/go.mod h1:QIE4lCeL7nkC25x+yA3LBIYfwCc1TFziCtG7cBAac6w= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= @@ -1034,25 +1189,29 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.22.6/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -gocloud.dev v0.23.0 h1:u/6F8slWwaZPgGpjpNp0jzH+1P/M2ri7qEP3lFgbqBE= -gocloud.dev v0.23.0/go.mod h1:zklCCIIo1N9ELkU2S2E7tW8P8eeMU7oGLeQCXdDwx9Q= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +gocloud.dev v0.24.0 h1:cNtHD07zQQiv02OiwwDyVMuHmR7iQt2RLkzoAgz7wBs= +gocloud.dev v0.24.0/go.mod h1:uA+als++iBX5ShuG4upQo/3Zoz49iIPlYUWHV5mM8w8= golang.org/x/crypto v0.0.0-20180501155221-613d6eafa307/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1073,9 +1232,13 @@ golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838 h1:71vQrMauZZhcTVK6KdYM+rklehEEwb3E+ZhaE5jrPrE= +golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1101,7 +1264,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -1116,6 +1278,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1167,13 +1330,18 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= -golang.org/x/net v0.0.0-20210420210106-798c2154c571/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210505214959-0714010a04ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211007125505-59d4e928ea9d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1183,14 +1351,19 @@ golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210126194326-f9ce19ea3013/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 h1:3B43BWw0xEBsLZ/NO1VALz6fppU3481pik+2Ksv45z8= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1273,20 +1446,34 @@ golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210412220455-f1c623a9e750/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827 h1:A0Qkn7Z/n8zC1xd9LTw17AiKlBRK64tw3ejWQiEqca0= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a h1:ppl5mZgokTT8uPkmYOyEUmPTr3ypaKkg5eFOGrAmxxE= +golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1303,8 +1490,10 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M= +golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1400,6 +1589,7 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= @@ -1412,7 +1602,6 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -1431,13 +1620,25 @@ google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSr google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.37.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= -google.golang.org/api v0.45.0/go.mod h1:ISLIJCedJolbZvDfAk+Ctuq5hf+aJ33WgtUsfyFoLXA= -google.golang.org/api v0.46.0 h1:jkDWHOBIoNSD0OQpq4rtBVu+Rh325MPjXG1rakAp8JU= google.golang.org/api v0.46.0/go.mod h1:ceL4oozhkAiTID8XMmJBsIxID/9wMXJVVFXPg4ylg3I= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.52.0/go.mod h1:Him/adpjt0sxtkWViy0b6xyKW/SD71CwdJ7HqJo7SrU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.58.0/go.mod h1:cAbP2FsxoGVNwtgNAmmn3y5G1TWAiVYRmg4yku3lv+E= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0 h1:n2bqqK895ygnBpdPDYetfy23K7fJ22wsrZKCyfuRkkA= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1455,8 +1656,6 @@ google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= @@ -1492,22 +1691,43 @@ google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210413151531-c14fb6ef47c3/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210420162539-3c870d7478d2/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210423144448-3a41ef94ed2b/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210429181445-86c259c2b4ab/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210506142907-4a47615972c2/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210517163617-5e0236093d7a/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210721163202-f1cecdd8b78a/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210825212027-de86158e7fda/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211016002631-37fc39342514/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211018162055-cf77aa76bad2/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= @@ -1529,8 +1749,15 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.43.0 h1:Eeu7bZtDZ2DpRCsLhUlcrLnvYaMK1Gz86a+hMVvELmM= +google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1542,9 +1769,12 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1560,6 +1790,8 @@ gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk= +gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= diff --git a/web/app/.eslintrc.js b/web/app/.eslintrc.js index 68ba9db..3c881ee 100644 --- a/web/app/.eslintrc.js +++ b/web/app/.eslintrc.js @@ -1,12 +1,10 @@ module.exports = { - parser: '@typescript-eslint/parser', extends: [ 'eslint:recommended', ], parserOptions: { - ecmaVersion: 2020, + ecmaVersion: 2022, sourceType: 'module', - project: './tsconfig.json', extraFileExtensions: ['.svelte'] }, env: { @@ -19,25 +17,13 @@ module.exports = { processor: 'svelte3/svelte3', extends: [ 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:@typescript-eslint/recommended-requiring-type-checking', ], - plugins: ['svelte3', '@typescript-eslint'], + plugins: ['svelte3'], settings: { - 'svelte3/typescript': require('typescript') // ignore style tags in Svelte because of Tailwind CSS // See https://github.com/sveltejs/eslint-plugin-svelte3/issues/70 //'svelte3/ignore-styles': () => true }, - }, - { - files: ['**/*.ts'], - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:@typescript-eslint/recommended-requiring-type-checking', - ], - plugins: ['@typescript-eslint'], } ], rules: { diff --git a/web/app/package.json b/web/app/package.json index bb98f26..3e3957f 100644 --- a/web/app/package.json +++ b/web/app/package.json @@ -4,20 +4,17 @@ "private": true, "scripts": { "build": "rollup -c", - "check": "svelte-check --tsconfig ./tsconfig.json", - "format": "prettier --write ./src/**/*.{js,svelte,html,ts}", - "lint": "tsc --noEmit && prettier --write ./src/**/*.{js,svelte,html,ts} && eslint src/**/*.{js,ts,svelte}", - "lint:fix": "tsc --noEmit && prettier --write ./src/**/*.{js,svelte,html,ts} && eslint --fix src/**/*.{js,ts,svelte}" + "check": "svelte-check", + "format": "prettier --write ./src/**/*.{js,svelte,html}", + "lint": "prettier --write ./src/**/*.{js,svelte,html} && eslint src/**/*.{js,svelte}", + "lint:fix": "prettier --write ./src/**/*.{js,svelte,html} && eslint --fix src/**/*.{js,svelte}" }, "devDependencies": { "@rollup/plugin-commonjs": "^17.0.0", "@rollup/plugin-node-resolve": "^11.0.0", - "@rollup/plugin-typescript": "^8.0.0", - "@tsconfig/svelte": "^2.0.1", - "@typescript-eslint/eslint-plugin": "^4.29.3", - "@typescript-eslint/parser": "^4.29.3", + "@sargassum-world/styles": "^0.2.0", "bulma": "^0.9.3", - "eslint": "^7.32.0", + "eslint": "^8.10.0", "eslint-plugin-import": "^2.24.2", "eslint-plugin-svelte3": "^3.2.1", "prettier": "^2.4.1", @@ -33,16 +30,13 @@ "svelte": "^3.0.0", "svelte-check": "^2.0.0", "svelte-dark-mode": "^2.0.0", - "svelte-preprocess": "^4.0.0", - "tslib": "^2.0.0", - "typescript": "^4.0.0" + "svelte-preprocess": "^4.0.0" }, "dependencies": { "@fontsource/atkinson-hyperlegible": "^4.5.1", "@fontsource/oxygen-mono": "^4.5.0", "@hotwired/turbo": "^7.0.1", - "async-mutex": "^0.3.2", - "stimulus": "2.0.0", - "stimulus-use": "^0.41.0" + "@sargassum-world/stimulated": "^0.2.9", + "stimulus": "2.0.0" } } diff --git a/web/app/rollup.config.js b/web/app/rollup.config.js index fb180a8..92325a3 100644 --- a/web/app/rollup.config.js +++ b/web/app/rollup.config.js @@ -3,7 +3,6 @@ import commonjs from '@rollup/plugin-commonjs'; import resolve from '@rollup/plugin-node-resolve'; import { terser } from 'rollup-plugin-terser'; import sveltePreprocess from 'svelte-preprocess'; -import typescript from '@rollup/plugin-typescript'; import css from 'rollup-plugin-css-only'; import scss from 'rollup-plugin-scss'; import { existsSync, mkdirSync, writeFileSync } from 'fs'; @@ -15,7 +14,7 @@ const buildDir = 'public/build'; function themeGenerator(theme) { return { - input: `src/theme-${theme}.ts`, + input: `src/theme-${theme}.js`, output: { sourcemap: !production, format: 'iife', @@ -36,8 +35,9 @@ function themeGenerator(theme) { writeFileSync(`${buildDir}/theme-${theme}.css`, styles); purify( [ + 'node_modules/@sargassum-world/**/*.js', + 'node_modules/@sargassum-world/**/*.svelte', 'src/**/*.js', - 'src/**/*.ts', 'src/**/*.svelte', '../templates/**/*.tmpl', ], @@ -66,7 +66,7 @@ function themeGenerator(theme) { function bundleGenerator(type, appName, context) { return { - input: `src/main-${type}.ts`, + input: `src/main-${type}.js`, output: { sourcemap: !production, format: 'iife', @@ -100,7 +100,7 @@ function bundleGenerator(type, appName, context) { }), // we'll extract any component CSS out into // a separate file - better for performance - css({ output: 'bundle.css' }), + css({ output: `${buildDir}/bundle-${type}.css` }), // If you have external dependencies installed from // npm, you'll most likely need these plugins. In @@ -112,10 +112,6 @@ function bundleGenerator(type, appName, context) { dedupe: ['svelte'] }), commonjs(), - typescript({ - sourceMap: !production, - inlineSources: !production - }), // If we're building for production (npm run build // instead of npm run dev), minify diff --git a/web/app/src/main-deferred.ts b/web/app/src/main-deferred.js similarity index 52% rename from web/app/src/main-deferred.ts rename to web/app/src/main-deferred.js index 8c9547b..c8404c2 100644 --- a/web/app/src/main-deferred.ts +++ b/web/app/src/main-deferred.js @@ -1,23 +1,24 @@ import * as Turbo from '@hotwired/turbo'; +import { + CSRFController, + DefaultScrollableController, + FormSubmissionController, + NavigationLinkController, + NavigationMenuController, + ThemeController, + TurboCacheController, +} from '@sargassum-world/stimulated'; import { Application } from 'stimulus'; -import ThemeController from './sprinkles/theme.controller'; -import NavigationMenuController from './sprinkles/navigation-menu.controller'; -import NavigationLinkController from './sprinkles/navigation-link.controller'; -import FormSubmissionController from './sprinkles/form-submission.controller'; -import CSRFController from './sprinkles/csrf.controller'; -import DefaultScrollableController from './sprinkles/default-scrollable.controller'; -import TurboCacheController from './sprinkles/turbo-cache.controller'; - Turbo.session.drive = true; const Stimulus = Application.start(); -Stimulus.register('theme', ThemeController); -Stimulus.register('navigation-menu', NavigationMenuController); -Stimulus.register('navigation-link', NavigationLinkController); -Stimulus.register('form-submission', FormSubmissionController); Stimulus.register('csrf', CSRFController); Stimulus.register('default-scrollable', DefaultScrollableController); +Stimulus.register('form-submission', FormSubmissionController); +Stimulus.register('navigation-link', NavigationLinkController); +Stimulus.register('navigation-menu', NavigationMenuController); +Stimulus.register('theme', ThemeController); Stimulus.register('turbo-cache', TurboCacheController); export {}; diff --git a/web/app/src/main-eager.js b/web/app/src/main-eager.js new file mode 100644 index 0000000..f442cc7 --- /dev/null +++ b/web/app/src/main-eager.js @@ -0,0 +1,5 @@ +import { ThemeToggle } from '@sargassum-world/stimulated/util'; + +ThemeToggle.onLoad(); + +export {}; diff --git a/web/app/src/main-eager.ts b/web/app/src/main-eager.ts deleted file mode 100644 index 4786ef0..0000000 --- a/web/app/src/main-eager.ts +++ /dev/null @@ -1,5 +0,0 @@ -import * as ThemeToggle from './sprinkles/theme-toggle'; - -ThemeToggle.onLoad(); - -export {}; diff --git a/web/app/src/sprinkles/csrf.controller.js b/web/app/src/sprinkles/csrf.controller.js deleted file mode 100644 index 073dfea..0000000 --- a/web/app/src/sprinkles/csrf.controller.js +++ /dev/null @@ -1,61 +0,0 @@ -import { Controller } from 'stimulus'; -import { Mutex } from 'async-mutex'; - -// These are globals because we only need to fetch a CSRF token once; we can reuse it as long as -// the CSRF cookie (for the Double Submit Cookie pattern) remains valid. -let csrfToken = null; -let fetchMutex = new Mutex(); - -export default class extends Controller { - static targets = ['token', 'route', 'omit', 'submit']; - async connect() { - this.omitTarget.value = true; - if (this.hasValidToken()) { - csrfToken = this.tokenTarget.value; - return; - } - await this.addToken() - } - - async addToken(e) { - if (this.hasValidToken() || this.setToken()) { - return; - } - - if (e !== undefined) { - e.preventDefault(); - } - if (fetchMutex.isLocked()) { - await fetchMutex.waitForUnlock(); - } - if (this.setToken()) { - if (e !== undefined) { - e.target.submit(); - } - return; - } - - await fetchMutex.runExclusive(async () => { - const response = await fetch(this.routeTarget.value); - const responseBody = await response.json(); - csrfToken = responseBody.token; - this.setToken(); - }); - if (e !== undefined) { - // Assumes the controller is mounted on a form! - e.target.submit(); - } - } - - setToken() { - if (csrfToken === null) { - return false - } - this.tokenTarget.value = csrfToken; - return this.hasValidToken() - } - - hasValidToken() { - return this.tokenTarget.value.length > 0 - } -} diff --git a/web/app/src/sprinkles/default-scrollable.controller.js b/web/app/src/sprinkles/default-scrollable.controller.js deleted file mode 100644 index b55c8e7..0000000 --- a/web/app/src/sprinkles/default-scrollable.controller.js +++ /dev/null @@ -1,21 +0,0 @@ -import { Controller } from 'stimulus'; - -export default class extends Controller { - connect() { - this.element.focus(); - var scrollpos = sessionStorage.getItem('scrollpos'); - // TODO: instead of setting scrollTop (which causes a flash of unscrolled content, - // change the HTML element structure of the navbar so that the main container just - // has the window scroll, to let the browser natively keep track of the scroll - // position when the page is refreshed - if (scrollpos) { - this.element.scrollTop = scrollpos; - sessionStorage.removeItem('scrollpos'); - } - - const element = this.element; - window.addEventListener('beforeunload', function () { - sessionStorage.setItem('scrollpos', element.scrollTop); - }) - } -} diff --git a/web/app/src/sprinkles/form-submission.controller.js b/web/app/src/sprinkles/form-submission.controller.js deleted file mode 100644 index 41431a4..0000000 --- a/web/app/src/sprinkles/form-submission.controller.js +++ /dev/null @@ -1,14 +0,0 @@ -import { Controller } from 'stimulus'; - -export default class extends Controller { - static targets = ['submit', 'submitter']; - - submit() { - this.submitTarget.setAttribute('disabled', true); - const progress = document.createElement('progress'); - progress.classList.add('progress'); - progress.classList.add('is-small'); - progress.classList.add('is-info'); - this.submitterTarget.appendChild(progress); - } -} diff --git a/web/app/src/sprinkles/navigation-link.controller.js b/web/app/src/sprinkles/navigation-link.controller.js deleted file mode 100644 index 033758a..0000000 --- a/web/app/src/sprinkles/navigation-link.controller.js +++ /dev/null @@ -1,29 +0,0 @@ -import { Controller } from 'stimulus'; - -export default class extends Controller { - connect() { - this.updateActiveListener = (event) => { - const location = event.path[2].location.href; - if (this.element === undefined) { - return; - } - - if (location.startsWith(this.element.href)) { - this.element.classList.add('is-active'); - } else { - this.element.classList.remove('is-active'); - } - }; - - document.addEventListener('turbo:render', this.updateActiveListener); - } - disconnect() { - if (this.updateActiveListener === undefined) { - return; - } - - document.removeEventListener('turbo:render', this.updateActiveListener); - } - - updateActive; -} diff --git a/web/app/src/sprinkles/navigation-menu.controller.js b/web/app/src/sprinkles/navigation-menu.controller.js deleted file mode 100644 index d4a0f5a..0000000 --- a/web/app/src/sprinkles/navigation-menu.controller.js +++ /dev/null @@ -1,30 +0,0 @@ -import { Controller } from 'stimulus'; - -export default class extends Controller { - static targets = ['toggle', 'close', 'menu']; - connect() { - this.closeTarget.classList.add('is-hidden'); - this.toggleTarget.setAttribute('href', '#'); - } - - open() { - this.menuTarget.classList.add('is-active'); - this.toggleTarget.classList.add('is-active'); - this.toggleTarget.setAttribute('aria-expanded', true); - } - - close() { - this.menuTarget.classList.remove('is-active'); - this.toggleTarget.classList.remove('is-active'); - this.toggleTarget.setAttribute('aria-expanded', false); - } - - toggle(event) { - if (this.menuTarget.classList.contains('is-active')) { - this.close(); - } else { - this.open(); - } - event.preventDefault(); - } -} diff --git a/web/app/src/sprinkles/theme-toggle.ts b/web/app/src/sprinkles/theme-toggle.ts deleted file mode 100644 index 0bee0eb..0000000 --- a/web/app/src/sprinkles/theme-toggle.ts +++ /dev/null @@ -1,51 +0,0 @@ -type Theme = 'dark' | 'light'; - -export function loadThemeSetting(): Theme { - const theme = window.localStorage.getItem('theme'); - switch (theme) { - case 'dark': - return 'dark'; - default: - return 'light'; - } -} -export function storeThemeSetting(theme: Theme): void { - window.localStorage.setItem('theme', theme); -} -export function invert(theme: Theme): Theme { - switch (theme) { - case 'dark': - return 'light'; - default: - return 'dark'; - } -} -function setThemeProperties(stylesheetID: string, theme: Theme): void { - const stylesheet = document.querySelector(`link#${stylesheetID}`); - if (stylesheet === null || !(stylesheet instanceof HTMLLinkElement)) { - return; - } - - const active = stylesheet.id === `${theme}-theme`; - stylesheet.rel = active ? 'stylesheet' : 'stylesheet alternate'; -} -export function setTheme(theme: Theme): void { - setThemeProperties('light-theme', theme); - setThemeProperties('dark-theme', theme); -} - -export function onLoad(): void { - const theme = loadThemeSetting(); - if (theme === 'dark') { - // Set an initial color to prevent a white flash when dark mode has been set - document.documentElement.classList.add('initial-load-dark'); - const darkStylesheet = document.querySelector('link#dark-theme'); - if (darkStylesheet !== null && darkStylesheet instanceof HTMLLinkElement) { - darkStylesheet.addEventListener('load', () => { - document.documentElement.classList.remove('initial-load-dark'); - }); - } - } - setTheme(theme); - storeThemeSetting(theme); -} diff --git a/web/app/src/sprinkles/theme.controller.ts b/web/app/src/sprinkles/theme.controller.ts deleted file mode 100644 index 88ed6db..0000000 --- a/web/app/src/sprinkles/theme.controller.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Controller } from 'stimulus'; - -import { - invert, - loadThemeSetting, - storeThemeSetting, - setTheme, -} from './theme-toggle'; - -export default class extends Controller { - connect(): void { - this.element.classList.remove('is-hidden'); - } - toggle(): void { - const theme = invert(loadThemeSetting()); - setTheme(theme); - storeThemeSetting(theme); - } -} diff --git a/web/app/src/sprinkles/turbo-cache.controller.js b/web/app/src/sprinkles/turbo-cache.controller.js deleted file mode 100644 index 0b5f078..0000000 --- a/web/app/src/sprinkles/turbo-cache.controller.js +++ /dev/null @@ -1,11 +0,0 @@ -import * as Turbo from '@hotwired/turbo'; -import { Controller } from 'stimulus'; - -export default class extends Controller { - clear(e) { - // This assumes the controller is attached to a form! - e.preventDefault(); - Turbo.clearCache(); - e.target.submit(); - } -} diff --git a/web/app/src/styles/app/bulma.scss b/web/app/src/styles/app/bulma.scss deleted file mode 100644 index 1c7c5b1..0000000 --- a/web/app/src/styles/app/bulma.scss +++ /dev/null @@ -1,3 +0,0 @@ -@charset 'utf-8'; - -@import 'node_modules/bulma/bulma.sass'; diff --git a/web/app/src/styles/app/components.scss b/web/app/src/styles/app/components.scss deleted file mode 100644 index 477c961..0000000 --- a/web/app/src/styles/app/components.scss +++ /dev/null @@ -1,14 +0,0 @@ -@charset 'utf-8'; - -@import 'styles/shared/components/accordions.scss'; -@import 'styles/shared/components/cards.scss'; -//@import 'styles/shared/components/modals.scss'; -@import 'styles/shared/components/panels.scss'; -@import 'styles/shared/components/progress.scss'; -@import 'styles/shared/components/scroller.scss'; -@import 'styles/shared/components/sections.scss'; -//@import 'styles/shared/components/toolbars.scss'; -@import 'styles/shared/components/typed-tags.scss'; - -@import 'styles/app/components/accordions.scss'; -@import 'styles/app/components/turbo-progress.scss'; diff --git a/web/app/src/styles/app/components/_all.scss b/web/app/src/styles/app/components/_all.scss new file mode 100644 index 0000000..8dd25e0 --- /dev/null +++ b/web/app/src/styles/app/components/_all.scss @@ -0,0 +1,4 @@ +@charset 'utf-8'; + +@import 'styles/app/components/accordions.scss'; +@import 'styles/app/components/turbo-progress.scss'; diff --git a/web/app/src/styles/app/theme-overrides.scss b/web/app/src/styles/app/theme-overrides.scss deleted file mode 100644 index 89e0468..0000000 --- a/web/app/src/styles/app/theme-overrides.scss +++ /dev/null @@ -1,7 +0,0 @@ -@charset 'utf-8'; - -@import 'styles/shared/theme-overrides/breadcrumbs.scss'; -@import 'styles/shared/theme-overrides/buttons.scss'; -@import 'styles/shared/theme-overrides/forms.scss'; -@import 'styles/shared/theme-overrides/navbar.scss'; -@import 'styles/shared/theme-overrides/tags.scss'; diff --git a/web/app/src/styles/shared/colors-base.vars.scss b/web/app/src/styles/shared/colors-base.vars.scss deleted file mode 100644 index 3a150c8..0000000 --- a/web/app/src/styles/shared/colors-base.vars.scss +++ /dev/null @@ -1,18 +0,0 @@ -@charset 'utf-8'; - -// Grayscale - -$grayscale-hue: 215; -$grayscale-sat: 25%; -$black: hsl($grayscale-hue, $grayscale-sat * 2, 8%); -$black-bis: hsl($grayscale-hue, $grayscale-sat * 1.5, 10%); -$black-ter: hsl($grayscale-hue, $grayscale-sat * 1.25, 12%); -$grey-darker: hsl($grayscale-hue, $grayscale-sat, 20%); -$grey-dark: hsl($grayscale-hue, $grayscale-sat, 29%); -$grey: hsl($grayscale-hue, $grayscale-sat, 48%); -$grey-light: hsl($grayscale-hue, $grayscale-sat, 71%); -$grey-lighter: hsl($grayscale-hue, $grayscale-sat, 82%); -$grey-lightest: hsl($grayscale-hue, $grayscale-sat, 93%); -$white-ter: hsl($grayscale-hue, $grayscale-sat, 95%); -$white-bis: hsl($grayscale-hue, $grayscale-sat, 98%); -$white: hsl($grayscale-hue, $grayscale-sat, 100%); diff --git a/web/app/src/styles/shared/colors-dark.vars.scss b/web/app/src/styles/shared/colors-dark.vars.scss deleted file mode 100644 index 5cd3686..0000000 --- a/web/app/src/styles/shared/colors-dark.vars.scss +++ /dev/null @@ -1,56 +0,0 @@ -@charset 'utf-8'; - -// Theme Colors - -$scheme-main: $black; -$scheme-main-bis: $black-bis; -$scheme-main-ter: $black-ter; -$scheme-main-grey: $grey-darker; -$scheme-main-grey-bis: $grey-dark; -$scheme-main-grey-ter: $grey; -$scheme-invert-grey-ter: $grey-light; -$scheme-invert-grey-bis: $grey-lighter; -$scheme-invert-grey: $grey-lightest; -$scheme-invert-ter: $white-ter; -$scheme-invert-bis: $white-bis; -$scheme-invert: $white; - -$green: hsl(153, 53%, 30%); -$turquoise: hsl(175, 100%, 30%); -$red: hsl(348, 86%, 50%); -$red-light: change-color($red, $lightness: 90%); - -$danger-light: $red-light; - -// Element Colors - -$body-background-color: $scheme-main-ter; -$background: $scheme-main-ter; -$focus-color: change-color($cyan, $lightness: 40%); -$scrollbar-color: $scheme-main-grey-bis; -$scrollbar-hover-color: $scheme-main-grey-ter; - -// Component Colors - -$toolbar-background-color: $scheme-main-bis; - -$navbar-item-color: $scheme-invert-ter; -$navbar-background-color: $scheme-main; -$navbar-button-active-color: $scheme-invert; -$navbar-button-active-background: $scheme-main-grey; - -$card-background-color: $scheme-main; -$card-header-background-color: $scheme-main-grey; -$card-item-border-color: $card-header-background-color; - -$modal-dialog-background: $scheme-main-grey; - -$zerotier-address-tag-color: change-color($cyan, $lightness: 85%); -$zerotier-address-tag-background-color: change-color($cyan, $lightness: 30%); -$zerotier-network-number-tag-color: change-color($green, $lightness: 85%); -$zerotier-network-number-tag-background-color: change-color($green, $lightness: 30%); -$zerotier-unknown-network-tag-color: $background; -$socket-tag-color: change-color($purple, $lightness: 90%); -$socket-tag-background-color: change-color($purple, $lightness: 20%); -$domain-name-tag-color: $white; -$domain-name-tag-background-color: $grey-dark; diff --git a/web/app/src/styles/shared/colors-light.vars.scss b/web/app/src/styles/shared/colors-light.vars.scss deleted file mode 100644 index 6fa5659..0000000 --- a/web/app/src/styles/shared/colors-light.vars.scss +++ /dev/null @@ -1,53 +0,0 @@ -@charset 'utf-8'; - -// Theme Colors - -$scheme-main: $white; -$scheme-main-bis: $white-bis; -$scheme-main-ter: $white-ter; -$scheme-main-grey: $grey-lightest; -$scheme-main-grey-bis: $grey-lighter; -$scheme-main-grey-ter: $grey-light; -$scheme-invert-grey-ter: $grey; -$scheme-invert-grey-bis: $grey-dark; -$scheme-invert-grey: $grey-darker; -$scheme-invert-ter: $black-ter; -$scheme-invert-bis: $black-bis; -$scheme-invert: $black; - -$green: hsl(153, 53%, 40%); -$turquoise: hsl(175, 100%, 35%); -$red: hsl(348, 86%, 61%); - -// Element Colors - -$body-background-color: $scheme-main; -$background: $scheme-main; -$focus-color: change-color($cyan, $lightness: 65%); -$scrollbar-color: $scheme-main-grey-ter; -$scrollbar-hover-color: $scheme-invert-grey-ter; - -// Component Colors - -$toolbar-background-color: $scheme-main-grey; - -$navbar-item-color: $scheme-invert-ter; -$navbar-background-color: $scheme-main-grey-bis; -$navbar-button-active-color: $scheme-invert; -$navbar-button-active-background: $scheme-main-grey-ter; - -$card-background-color: $scheme-main-grey; -$card-header-background-color: $scheme-main-grey-bis; -$card-item-border-color: $card-header-background-color; - -$modal-dialog-background: $scheme-main; - -$zerotier-address-tag-color: $scheme-invert-grey-bis; -$zerotier-address-tag-background-color: change-color($cyan, $lightness: 80%); -$zerotier-network-number-tag-color: $scheme-invert-grey-bis; -$zerotier-network-number-tag-background-color: change-color($green, $lightness: 80%); -$zerotier-unknown-network-tag-color: $background; -$socket-tag-color: $scheme-invert-grey-bis; -$socket-tag-background-color: change-color($purple, $lightness: 90%); -$domain-name-tag-color: $white; -$domain-name-tag-background-color: $grey; diff --git a/web/app/src/styles/shared/components/accordions.scss b/web/app/src/styles/shared/components/accordions.scss deleted file mode 100644 index 6d673c1..0000000 --- a/web/app/src/styles/shared/components/accordions.scss +++ /dev/null @@ -1,55 +0,0 @@ -@charset 'utf-8'; - -ul[data-accordion] { - list-style: none; - margin: 0; -} -ul[data-accordion] li[data-accordion-item] + li[data-accordion-item] { - margin-top: 0; -} -li[data-accordion-item], details[data-accordion-item] { - display: block; - padding: 0; - margin: 0; -} -.panel.entity-panel { - li[data-accordion-item].panel-block, details[data-accordion-item].panel-block { - padding: 0; - } -} -li[data-accordion-item]>button { - @include reset; - - display: block; - width: 100%; - padding-left: $gap; - padding-right: $gap; - padding-top: 0.5 * $gap; - padding-bottom: 0.5 * $gap; - cursor: pointer; - text-align: left; -} -.accordion-header { - h1, h2, h3, h4, h5, h6 { - @include reset; - display: inline; - font-weight: normal; - } -} -.accordion-header.level { - display: flex; - margin-bottom: 0; -} -button[aria-expanded="true"] .accordion-header .icon { - transform: rotate(0.5turn); -} -li[data-accordion-item]>div { - display: unset; -} -.accordion-content { - width: calc(100% - 2 * #{$gap}); - padding-left: $gap; - padding-right: $gap; - padding-top: 0.5 * $gap; - padding-bottom: $gap; -} diff --git a/web/app/src/styles/shared/components/cards.scss b/web/app/src/styles/shared/components/cards.scss deleted file mode 100644 index 9368437..0000000 --- a/web/app/src/styles/shared/components/cards.scss +++ /dev/null @@ -1,52 +0,0 @@ -@charset 'utf-8'; - -.card.section-card { - display: inline-block; - vertical-align: top; - border-radius: 0; - width: 100%; - max-width: 36em; - margin-bottom: $gap; - margin-right: $gap; - - @include from($navside-breakpoint) { - width: calc(100% - #{2 * $gap}); - margin-bottom: 2 * $gap; - margin-right: 2 * $gap; - } - - h4, h5 { - margin-bottom: 0; - } - h4:not(:first-child), h5:not(:first-child) { - margin-top: 0.5em; - } - p:not(:last-child) { - margin-bottom: 0; - } -} - -.info-card-container { - padding-right: $gap; - padding-bottom: $gap; - - @include from($navside-breakpoint) { - padding-right: 2 * $gap; - padding-bottom: 2 * $gap; - } -} -.card.info-card { - display: inline-block; - vertical-align: top; - border-radius: 0; - width: calc(100% - #{$gap}); - max-width: 36em; - margin-top: $gap; - margin-left: $gap; - - @include from($navside-breakpoint) { - width: calc(100% - #{2 * $gap}); - margin-top: 2 * $gap; - margin-left: 2 * $gap; - } -} diff --git a/web/app/src/styles/shared/components/modals.scss b/web/app/src/styles/shared/components/modals.scss deleted file mode 100644 index faed1f1..0000000 --- a/web/app/src/styles/shared/components/modals.scss +++ /dev/null @@ -1,71 +0,0 @@ -@charset 'utf-8'; - -div[data-svelte-dialog-portal] { - position: absolute; - bottom: 0; - left: 0; - right: 0; - top: 0; - z-index: 40; -} -div[data-svelte-dialog-overlay] { - background-color: transparent; - width: 100vw; - height: 100vh; - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - overflow: hidden; - z-index: 41; -} -.modal { - // Bulma's default for "position: fixed" causes the modal to freeze the application - // on the Jetson Nano (aarch64, Ubuntu 18.04), for some reason - position: absolute; -} -.modal-background { - background-color: $modal-overlay-background; -} -.drawer-container { - position: relative; - background-color: $modal-dialog-background; - padding: $gap; - - @include from($navside-breakpoint) { - padding: 2 * $gap; - } -} -.drawer-container.right-drawer { - width: 100%; - max-width: 24em; - margin-left: auto; - margin-right: 0; - margin-top: 0; - margin-bottom: 0; - height: 100vh; -} -.drawer-container.scroller { - scrollbar-color: $scrollbar-color $modal-dialog-background; -} -.drawer-container.scroller::-webkit-scrollbar-track { - background: $modal-dialog-background; -} -.drawer-container.scroller::-webkit-scrollbar-thumb { - border-color: $modal-dialog-background; -} -.drawer-container .modal-title { - margin-bottom: $gap; - - @include from($navside-breakpoint) { - margin-bottom: 2 * $gap; - } -} -.modal-title h2 { - display: inline; -} -.modal-title .delete { - display: block; - float: right; -} diff --git a/web/app/src/styles/shared/components/panels.scss b/web/app/src/styles/shared/components/panels.scss deleted file mode 100644 index 248cc62..0000000 --- a/web/app/src/styles/shared/components/panels.scss +++ /dev/null @@ -1,60 +0,0 @@ -@charset 'utf-8'; - -.panel.entity-panel { - display: inline-block; - vertical-align: top; - width: calc(100% - #{$gap}); - max-width: 36em; - margin-bottom: $gap; - margin-right: $gap; - border-radius: 0.5em; - background-color: $card-background-color; - box-shadow: none; - - @include from($navside-breakpoint) { - width: calc(100% - #{2 * $gap}); - margin-bottom: 2 * $gap; - margin-right: 2 * $gap; - } - - .panel-heading { - padding: $gap; - margin-bottom: 0; - border-radius: 0.5em 0.5em 0 0; - background-color: $card-header-background-color; - box-shadow: none; - - .entity-name { - margin-bottom: 0.25em; - display: inline-flex; - } - .entity-name:last-child { - margin-bottom: 0; - } - .tag { - font-weight: normal; - } - } - - .panel-block { - width: 100%; - padding-left: $gap; - padding-right: $gap; - padding-top: 0.5 * $gap; - padding-bottom: $gap; - - h4, h5 { - margin-bottom: 0; - } - h4:not(:first-child), h5:not(:first-child) { - margin-top: 0.5em; - } - p:not(:last-child) { - margin-bottom: 0; - } - } - - .panel-block:not(:last-child) { - border-bottom: 1px solid $card-item-border-color; - } -} diff --git a/web/app/src/styles/shared/components/progress.scss b/web/app/src/styles/shared/components/progress.scss deleted file mode 100644 index e98d502..0000000 --- a/web/app/src/styles/shared/components/progress.scss +++ /dev/null @@ -1,13 +0,0 @@ -@charset 'utf-8'; - -.progress.is-body-background { - background: $body-background-color; -} - -.progress.is-body-background::-webkit-progress-bar { - background: $body-background-color; -} - -form .control input[type="submit"] + progress { - margin-top: 0.5em; -} diff --git a/web/app/src/styles/shared/components/scroller.scss b/web/app/src/styles/shared/components/scroller.scss deleted file mode 100644 index f709c91..0000000 --- a/web/app/src/styles/shared/components/scroller.scss +++ /dev/null @@ -1,31 +0,0 @@ -@charset 'utf-8'; - -.scroller { - overflow: auto; - scrollbar-width: auto; - scrollbar-color: $scrollbar-color $background; -} -.scroller::-webkit-scrollbar { - -webkit-appearance: none; // don't hide scrollbar without hover - width: 16px; -} -.scroller::-webkit-scrollbar-track { - background: $background; -} -.scroller::-webkit-scrollbar-thumb { - background-color: $scrollbar-color ; - border-radius: 8px; - border: 4px solid $background; -} -.scroller::-webkit-scrollbar-thumb:horizontal:hover { - background-color: $scrollbar-hover-color; -} -.scroller::-webkit-scrollbar-thumb:horizontal:active { - background-color: $scrollbar-hover-color; -} -.scroller::-webkit-scrollbar-thumb:vertical:hover { - background-color: $scrollbar-hover-color; -} -.scroller::-webkit-scrollbar-thumb:vertical:active { - background-color: $scrollbar-hover-color; -} diff --git a/web/app/src/styles/shared/components/sections.scss b/web/app/src/styles/shared/components/sections.scss deleted file mode 100644 index 87da8bc..0000000 --- a/web/app/src/styles/shared/components/sections.scss +++ /dev/null @@ -1,11 +0,0 @@ -@charset 'utf-8'; - -.section-description { - margin-bottom: $gap; -} -.empty-section { - padding-top: 0; - padding-bottom: 0; - transition: padding-top 0.2s ease-out 0.8s; - transition: padding-bottom 0.2s ease-out 0.8s; -} diff --git a/web/app/src/styles/shared/components/toolbars.scss b/web/app/src/styles/shared/components/toolbars.scss deleted file mode 100644 index e2555a5..0000000 --- a/web/app/src/styles/shared/components/toolbars.scss +++ /dev/null @@ -1,22 +0,0 @@ -@charset 'utf-8'; - -.toolbar { - width: 100%; - padding-left: $gap; - padding-right: $gap; - padding-top: $gap; - padding-bottom: $gap; - margin-bottom: $gap; - background-color: $toolbar-background-color; - - @include from($navside-breakpoint) { - padding-left: 2 * $gap; - padding-right: 2 * $gap; - margin-bottom: 2 * $gap; - } -} - -.toolbar .button { - font-weight: bold; - margin-bottom: $gap; -} diff --git a/web/app/src/styles/shared/components/typed-tags.scss b/web/app/src/styles/shared/components/typed-tags.scss deleted file mode 100644 index 2d7b3b2..0000000 --- a/web/app/src/styles/shared/components/typed-tags.scss +++ /dev/null @@ -1,97 +0,0 @@ -@charset 'utf-8'; - -.tag.scoped-name { - display: inline-block; - background-color: transparent; - padding: 0; - border-radius: 1em; - height: unset; -} -.tag.zerotier-address { - font-family: $family-monospace; - color: $zerotier-address-tag-color; - background-color: $zerotier-address-tag-background-color; - padding-left: 0.5em; - padding-right: 0.5em; - border-radius: 0.75em; -} -.zerotier-network-id { - display: inline-block; -} -.tag.zerotier-network-host { - font-family: $family-monospace; - color: $zerotier-address-tag-color; - background-color: $zerotier-address-tag-background-color; - padding-left: 0.5em; - padding-right: 0; - margin-right: 0; - border-radius: 0.75em 0 0 0.75em; -} -.tag.zerotier-network-number { - font-family: $family-monospace; - color: $zerotier-network-number-tag-color; - background-color: $zerotier-network-number-tag-background-color; - padding-left: 0; - padding-right: 0.5em; - margin-left: 0; - border-radius: 0 0.75em 0.75em 0; -} -.tag.zerotier-unknown-network-named { - display: inline-block; - background-color: $zerotier-unknown-network-tag-color; - padding-left: 0.25em; - padding-right: 0.5em; - padding-top: 0.25em; - padding-bottom: 0.25em; - border-radius: 1em; - height: unset; -} -.tag.zerotier-unknown-network-named .tag.zerotier-network-name { - display: inline; - background-color: transparent; - height: unset; - white-space: normal; -} -.tag.socket { - font-family: $family-monospace; - color: $socket-tag-color; - background-color: $socket-tag-background-color; - padding-left: 0.5em; - padding-right: 0.5em; - border-radius: 0.75em; -} -.tag.ip-address { - font-family: $family-monospace; - color: $socket-tag-color; - background-color: $socket-tag-background-color; - padding-left: 0.5em; - padding-right: 0.5em; - border-radius: 0.75em; -} -.tag.ip-subnet { - font-family: $family-monospace; - color: $socket-tag-color; - background-color: $socket-tag-background-color; - padding-left: 0.5em; - padding-right: 0.5em; - border-radius: 0.75em; -} -.tag.domain-name { - font-family: $family-monospace; - color: $domain-name-tag-color; - background-color: $domain-name-tag-background-color; - padding-left: 0.5em; - padding-right: 0.5em; - border-radius: 0.75em; -} -.tag.mac-address { - font-family: $family-monospace; - padding-left: 0.5em; - padding-right: 0.5em; - border-radius: 0.75em; -} - -.tag .delete { - margin-bottom: 4px; - margin-top: 4px; -} diff --git a/web/app/src/styles/shared/global.scss b/web/app/src/styles/shared/global.scss deleted file mode 100644 index c969d44..0000000 --- a/web/app/src/styles/shared/global.scss +++ /dev/null @@ -1,17 +0,0 @@ -html, body { - position: relative; - width: 100%; - height: 100%; -} - -body { - scrollbar-width: none; - scroll-behavior: smooth; - margin: 0; - box-sizing: border-box; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} -body::-webkit-scrollbar { - display: none; -} diff --git a/web/app/src/styles/shared/layout.scss b/web/app/src/styles/shared/layout.scss deleted file mode 100644 index 4a33e61..0000000 --- a/web/app/src/styles/shared/layout.scss +++ /dev/null @@ -1,206 +0,0 @@ -@charset 'utf-8'; - -// Custom Containers - -.main-window { - height: 100%; - overflow: hidden; -} -.main-container { - width: 100%; - height: 100%; - overflow: auto; -} -.pad-gap { - padding: $gap; - - @include from($navside-breakpoint) { - padding: 2 * $gap; - } -} - -// Flexbox Responsive Helpers - -.is-flex-direction-row-mobile { - @include mobile { - flex-direction: row; - } -} -.is-flex-direction-row-tablet-only { - @include tablet-only { - flex-direction: row; - } -} -.is-flex-direction-row-desktop-only { - @include desktop-only { - flex-direction: row; - } -} -.is-flex-direction-row-widescreen-only { - @include widescreen-only { - flex-direction: row; - } -} -.is-flex-direction-row-touch { - @include touch { - flex-direction: row; - } -} -.is-flex-direction-row-tablet { - @include tablet { - flex-direction: row; - } -} -.is-flex-direction-row-desktop { - @include desktop { - flex-direction: row; - } -} -.is-flex-direction-row-widescreen { - @include widescreen { - flex-direction: row; - } -} -.is-flex-direction-row-fullhd { - @include fullhd { - flex-direction: row; - } -} - -.is-flex-direction-row-reverse-mobile { - @include mobile { - flex-direction: row-reverse; - } -} -.is-flex-direction-row-reverse-tablet-only { - @include tablet-only { - flex-direction: row-reverse; - } -} -.is-flex-direction-row-reverse-desktop-only { - @include desktop-only { - flex-direction: row-reverse; - } -} -.is-flex-direction-row-reverse-widescreen-only { - @include widescreen-only { - flex-direction: row-reverse; - } -} -.is-flex-direction-row-reverse-touch { - @include touch { - flex-direction: row-reverse; - } -} -.is-flex-direction-row-reverse-tablet { - @include tablet { - flex-direction: row-reverse; - } -} -.is-flex-direction-row-reverse-desktop { - @include desktop { - flex-direction: row-reverse; - } -} -.is-flex-direction-row-reverse-widescreen { - @include widescreen { - flex-direction: row-reverse; - } -} -.is-flex-direction-row-reverse-fullhd { - @include fullhd { - flex-direction: row-reverse; - } -} - -.is-flex-direction-column-mobile { - @include mobile { - flex-direction: column; - } -} -.is-flex-direction-column-tablet-only { - @include tablet-only { - flex-direction: column; - } -} -.is-flex-direction-column-desktop-only { - @include desktop-only { - flex-direction: column; - } -} -.is-flex-direction-column-widescreen-only { - @include widescreen-only { - flex-direction: column; - } -} -.is-flex-direction-column-touch { - @include touch { - flex-direction: column; - } -} -.is-flex-direction-column-tablet { - @include tablet { - flex-direction: column; - } -} -.is-flex-direction-column-desktop { - @include desktop { - flex-direction: column; - } -} -.is-flex-direction-column-widescreen { - @include widescreen { - flex-direction: column; - } -} -.is-flex-direction-column-fullhd { - @include fullhd { - flex-direction: column; - } -} - -.is-flex-direction-column-reverse-mobile { - @include mobile { - flex-direction: column-reverse; - } -} -.is-flex-direction-column-reverse-tablet-only { - @include tablet-only { - flex-direction: column-reverse; - } -} -.is-flex-direction-column-reverse-desktop-only { - @include desktop-only { - flex-direction: column-reverse; - } -} -.is-flex-direction-column-reverse-widescreen-only { - @include widescreen-only { - flex-direction: column-reverse; - } -} -.is-flex-direction-column-reverse-touch { - @include touch { - flex-direction: column-reverse; - } -} -.is-flex-direction-column-reverse-tablet { - @include tablet { - flex-direction: column-reverse; - } -} -.is-flex-direction-column-reverse-desktop { - @include desktop { - flex-direction: column-reverse; - } -} -.is-flex-direction-column-reverse-widescreen { - @include widescreen { - flex-direction: column-reverse; - } -} -.is-flex-direction-column-reverse-fullhd { - @include fullhd { - flex-direction: column-reverse; - } -} diff --git a/web/app/src/styles/shared/theme-overrides/breadcrumbs.scss b/web/app/src/styles/shared/theme-overrides/breadcrumbs.scss deleted file mode 100644 index 265cb69..0000000 --- a/web/app/src/styles/shared/theme-overrides/breadcrumbs.scss +++ /dev/null @@ -1,12 +0,0 @@ -@charset 'utf-8'; - -.breadcrumb.main-breadcrumb { - padding-left: $gap; - padding-top: $gap; - margin-bottom: 0; - - @include from($navside-breakpoint) { - padding-left: 2 * $gap; - padding-top: 2 * $gap; - } -} diff --git a/web/app/src/styles/shared/theme-overrides/buttons.scss b/web/app/src/styles/shared/theme-overrides/buttons.scss deleted file mode 100644 index dbfabcf..0000000 --- a/web/app/src/styles/shared/theme-overrides/buttons.scss +++ /dev/null @@ -1,16 +0,0 @@ -@charset 'utf-8'; - -:focus, button.button:focus { - outline: 4px solid $focus-color; -} - -button.is-ghost.is-ahref { - padding: 0; - border: none; - border-radius: 0; - height: unset; -} -// For some reason, the Bulma tag color classes ignore $success, $danger, etc. -.button.is-primary { - background-color: $primary; -} diff --git a/web/app/src/styles/shared/theme-overrides/forms.scss b/web/app/src/styles/shared/theme-overrides/forms.scss deleted file mode 100644 index a3eb904..0000000 --- a/web/app/src/styles/shared/theme-overrides/forms.scss +++ /dev/null @@ -1,37 +0,0 @@ -@charset 'utf-8'; - -.field .message { - margin-top: $gap; -} -.field .message .message-body { - padding: $gap; -} -// For some reason, the Bulma tag color classes ignore $success, $danger, etc. -.message.is-danger { - background-color: $danger-light; -} - -input[type="submit"].is-href { - height: unset; - justify-content: unset; - vertical-align: unset; - background-color: unset; - border: unset; - border-radius: unset; - text-decoration: none; - text-rendering: optimizelegibility; - - @include from($navside-breakpoint) { - padding-top: 0.25 * $gap; - width: calc(100% - 2 * 0.75em); - } - - &:hover, &:focus { - text-decoration: none; - color: $navbar-button-active-color; - background-color: $navbar-button-active-background; - } - &:focus { - outline: 4px solid $focus-color; - } -} diff --git a/web/app/src/styles/shared/theme-overrides/navbar.scss b/web/app/src/styles/shared/theme-overrides/navbar.scss deleted file mode 100644 index 40028f3..0000000 --- a/web/app/src/styles/shared/theme-overrides/navbar.scss +++ /dev/null @@ -1,234 +0,0 @@ -@charset 'utf-8'; - -.navbar, .navbar-menu, .navbar-start, .navbar-end { - @include from($navside-breakpoint) { - flex-direction: column; - } -} -.navbar { - min-height: 0.5 * $navbar-height; - height: 10vh; - max-height: $navbar-height; - @include from($navside-breakpoint) { - height: 100%; - max-height: 100%; - flex-grow: 0; - flex-shrink: 0; - flex-basis: fit-content; - } -} -.navbar-brand { - @include until($navside-breakpoint) { - min-height: 0.5 * $navbar-height; - height: 100%; - max-height: $navbar-height; - } - @include from($navside-breakpoint) { - margin-top: 2 * $gap; - min-height: 0; - } - - a.navbar-item { - margin-top: auto; - margin-bottom: auto; - margin-left: 0.25em; - margin-right: 0em; - padding-left: 0.25em; - height: 100%; - max-height: $navbar-height * 0.625; - font-weight: bold; - text-align: center; - - @include from($navbar-breakpoint) { - margin-left: $navbar-margin; - } - - @include from($navside-breakpoint) { - display: block; - margin-top: 0em; - margin-bottom: $navbar-margin; - margin-right: $navbar-margin; - padding-left: 0.5em; - max-height: unset; - height: unset; - width: calc(100% - 2 * 0.75em); - } - } - a.navbar-item.brand-with-logo { - @include from($navside-breakpoint) { - margin-top: -0.75em; - } - } - a.navbar-item.is-active:not(:focus):not(:hover), a.navbar-item:hover, a.navbar-item:focus { - color: $navbar-button-active-color; - background-color: $navbar-button-active-background; - } -} -img.navbar-brand-logo { - padding-top: 0.125em; - padding-bottom: 0.125em; - padding-right: 0.25em; - - @include from($navside-breakpoint) { - display: block; - margin-left: auto; - margin-right: auto; - padding-left: 0em; - padding-right: 0em; - max-height: $navbar-height; - } -} -.navbar-brand.left-burger { - align-items: flex-start; - - .navbar-burger { - margin-left: 0; - margin-right: 0; - } -} -.navbar-burger { - min-width: 0.5 * $navbar-height; - width: 10vh; - max-width: $navbar-height; - height: 100%; - max-height: $navbar-height; - &:hover, &:focus { - color: $navbar-button-active-color; - background-color: $navbar-button-active-background; - } - span { - transition: unset; - height: 0.5px; - } -} -.navbar-menu { - @include until($navbar-breakpoint) { - display: block; - visibility: hidden; - max-height: 0; - padding-top: 0; - padding-bottom: 0; - overflow: hidden; - transition: all 0.2s ease-out; - scrollbar-width: none; - } -} -.navbar-menu::-webkit-scrollbar { - display: none; -} -.navbar-menu.is-active, .navbar-menu:target, .navbar-menu[aria-expanded="true"] { - @include until($navbar-breakpoint) { - display: block; - max-height: 90vh; - visibility: visible; - padding-top: 0.25 * $gap; - padding-bottom: $gap; - overflow: auto; - } - - .navbar-burger { - min-width: unset; - width: 2.5em; - max-width: unset; - height: 2.5em; - max-height: unset; - } -} -.navbar-start, .navbar-end { - @include from($navside-breakpoint) { - width: 100%; - } -} -.navbar-item { - margin: $navbar-margin; - padding: 0.5em; - - @include from($navbar-breakpoint) { - margin-top: auto; - margin-bottom: auto; - margin-right: 0em; - height: 100%; - max-height: $navbar-height * 0.625; - } - @include from($navside-breakpoint) { - margin-top: 0em; - margin-bottom: $navbar-margin; - margin-right: $navbar-margin; - height: unset; - } - .icon img { - height: 1em; - } -} -.navbar-item.end-buttons{ - padding-top: 0; - padding-bottom: 0; - - @include until($navside-breakpoint) { - margin-top: auto; - margin-bottom: auto; - margin-left: 0; - padding-left: 0.75em; - } - @include from($navside-breakpoint) { - margin: $navbar-margin; - height: unset; - } - - .buttons { - margin-left: auto; - margin-right: auto; - @include until($navside-breakpoint) { - margin-top: auto; - margin-bottom: auto; - height: 100%; - } - @include from($navside-breakpoint) { - margin-top: $navbar-margin; - margin-bottom: $navbar-margin; - } - } - .button { - border-radius: 0; - margin-top: auto; - margin-bottom: auto; - @include until($navbar-breakpoint) { - padding-left: calc(0.5em - 1px); - padding-right: calc(0.5em - 1px); - } - @include from($navbar-breakpoint) { - height: 100%; - max-height: $navbar-height * 0.625; - } - } - .icon-button { - @include from($navbar-breakpoint) { - padding-top: 0.25 * $gap; - padding-bottom: 0.25 * $gap; - padding-left: 0.125 * $gap; - padding-right: 0.125 * $gap; - } - .icon:first-child:last-child { - margin-left: auto; - margin-right: auto; - } - } - .button.is-active:not(:hover), .button:hover, .button:focus { - color: $navbar-button-active-color; - background-color: $navbar-button-active-background; - } - .button:focus { - outline: 4px solid $focus-color; - } -} -a.navbar-item.is-active:not(:focus):not(:hover), a.navbar-item:hover, a.navbar-item:focus { - color: $navbar-button-active-color; - background-color: $navbar-button-active-background; -} -.navbar-end { - @include from($navside-breakpoint) { - margin-top: auto; - margin-right: auto; - margin-bottom: $navbar-margin; - } -} diff --git a/web/app/src/styles/shared/theme-overrides/tags.scss b/web/app/src/styles/shared/theme-overrides/tags.scss deleted file mode 100644 index c82f94f..0000000 --- a/web/app/src/styles/shared/theme-overrides/tags.scss +++ /dev/null @@ -1,15 +0,0 @@ -@charset 'utf-8'; - -.tag:not(body) { - padding-left: 0.25em; - padding-right: 0.25em; - font-size: $size-normal; - height: 1.4 * $size-normal; -} -// For some reason, the Bulma tag color classes ignore $success, $danger, etc. -.tag:not(body).is-success { - background-color: $success; -} -.tag:not(body).is-danger { - background-color: $danger; -} diff --git a/web/app/src/styles/shared/theme.vars.scss b/web/app/src/styles/shared/theme.vars.scss deleted file mode 100644 index 77e84c0..0000000 --- a/web/app/src/styles/shared/theme.vars.scss +++ /dev/null @@ -1,24 +0,0 @@ -@charset 'utf-8'; - -// Basic Colors - -$primary: $turquoise; -$success: $green; -$danger: $red; -$border: $scheme-main-grey-bis; -$border-hover: $scheme-main-grey-ter; -$border-light: $scheme-main-grey; -$border-light-hover: $scheme-main-grey-ter; -$text: $scheme-invert-grey; -$text-light: $scheme-invert-grey-bis; -$text-strong: $scheme-invert-grey; -$link-hover: $scheme-invert-ter; -$link-hover-border: $scheme-main-grey-ter; -$link-focus: $scheme-invert-ter; -$link-active: $scheme-main-grey; -$link-active-border: $scheme-main-grey-bis; - -// Component Customizations - -$card-shadow: none; -$modal-overlay-background: rgba(10, 19, 31, 0.75); diff --git a/web/app/src/styles/shared/typography.vars.scss b/web/app/src/styles/shared/typography.vars.scss deleted file mode 100644 index bbb734d..0000000 --- a/web/app/src/styles/shared/typography.vars.scss +++ /dev/null @@ -1,4 +0,0 @@ -@charset 'utf-8'; - -$family-sans-serif: 'Atkinson Hyperlegible', BlinkMacSystemFont, -apple-system, 'Oxygen', 'Segoe UI', 'Ubuntu', 'Fira Sans', sans-serif; -$family-monospace: 'Oxygen Mono', 'Ubuntu Mono', 'Fira Code', 'Fira Mono', monospace; diff --git a/web/app/src/styles/theme-dark.scss b/web/app/src/styles/theme-dark.scss index 369bdf2..a4e5f2c 100644 --- a/web/app/src/styles/theme-dark.scss +++ b/web/app/src/styles/theme-dark.scss @@ -1,8 +1,8 @@ @charset 'utf-8'; // Shared base -@import 'styles/shared/global.scss'; -@import 'styles/shared/typography.vars.scss'; +@import 'node_modules/@sargassum-world/styles/global.scss'; +@import 'node_modules/@sargassum-world/styles/typography.vars.scss'; @import 'node_modules/bulma/sass/utilities/mixins.sass'; // Application-specific parameters @@ -10,25 +10,26 @@ @import 'styles/app/layout.vars.scss'; // Shared -@import 'styles/shared/layout.scss'; -@import 'styles/shared/colors-base.vars.scss'; +@import 'node_modules/@sargassum-world/styles/layout.scss'; +@import 'node_modules/@sargassum-world/styles/colors-base.vars.scss'; @import 'node_modules/bulma/sass/utilities/initial-variables.sass'; // Theme colors -@import 'styles/shared/colors-dark.vars.scss'; +@import 'node_modules/@sargassum-world/styles/colors-dark.vars.scss'; // Shared -@import 'styles/shared/theme.vars.scss'; +@import 'node_modules/@sargassum-world/styles/theme.vars.scss'; -// Application-specific Bulma imports -@import 'styles/app/bulma.scss'; +// Bulma imports +@import 'node_modules/bulma/bulma.sass'; // Anti-FOUC mechanism @import 'styles/app/fouc-post.scss'; // Overrides & components -@import 'styles/app/theme-overrides.scss'; -@import 'styles/app/components.scss'; +@import 'node_modules/@sargassum-world/styles/theme-overrides.scss'; +@import 'node_modules/@sargassum-world/styles/components.scss'; +@import 'styles/app/components/_all.scss'; @import 'styles/app/sprinkles.scss'; // Overrides only for dark mode diff --git a/web/app/src/styles/theme-light.scss b/web/app/src/styles/theme-light.scss index 42fdb72..22e7d7e 100644 --- a/web/app/src/styles/theme-light.scss +++ b/web/app/src/styles/theme-light.scss @@ -1,8 +1,8 @@ @charset 'utf-8'; // Shared base -@import 'styles/shared/global.scss'; -@import 'styles/shared/typography.vars.scss'; +@import 'node_modules/@sargassum-world/styles/global.scss'; +@import 'node_modules/@sargassum-world/styles/typography.vars.scss'; @import 'node_modules/bulma/sass/utilities/mixins.sass'; // Application-specific parameters @@ -10,23 +10,24 @@ @import 'styles/app/layout.vars.scss'; // Shared -@import 'styles/shared/layout.scss'; -@import 'styles/shared/colors-base.vars.scss'; +@import 'node_modules/@sargassum-world/styles/layout.scss'; +@import 'node_modules/@sargassum-world/styles/colors-base.vars.scss'; @import 'node_modules/bulma/sass/utilities/initial-variables.sass'; // Theme colors -@import 'styles/shared/colors-light.vars.scss'; +@import 'node_modules/@sargassum-world/styles/colors-light.vars.scss'; // Shared -@import 'styles/shared/theme.vars.scss'; +@import 'node_modules/@sargassum-world/styles/theme.vars.scss'; -// Application-specific Bulma imports -@import 'styles/app/bulma.scss'; +// Bulma imports +@import 'node_modules/bulma/bulma.sass'; // Anti-FOUC mechanism @import 'styles/app/fouc-post.scss'; // Overrides & components -@import 'styles/app/theme-overrides.scss'; -@import 'styles/app/components.scss'; +@import 'node_modules/@sargassum-world/styles/theme-overrides.scss'; +@import 'node_modules/@sargassum-world/styles/components.scss'; +@import 'styles/app/components/_all.scss'; @import 'styles/app/sprinkles.scss'; diff --git a/web/app/src/theme-dark.ts b/web/app/src/theme-dark.js similarity index 100% rename from web/app/src/theme-dark.ts rename to web/app/src/theme-dark.js diff --git a/web/app/src/theme-eager.ts b/web/app/src/theme-eager.js similarity index 100% rename from web/app/src/theme-eager.ts rename to web/app/src/theme-eager.js diff --git a/web/app/src/theme-light.ts b/web/app/src/theme-light.js similarity index 100% rename from web/app/src/theme-light.ts rename to web/app/src/theme-light.js diff --git a/web/app/tsconfig.json b/web/app/tsconfig.json deleted file mode 100644 index 6a2c4ea..0000000 --- a/web/app/tsconfig.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "es5", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], - "types": ["node", "svelte"], - "allowJs": true, - "skipLibCheck": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "noFallthroughCasesInSwitch": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "importsNotUsedAsValues": "remove", - "outDir": "./public/build" - }, - "include": ["src/**/*"], - "exclude": ["__sapper__/*", "public/*"] -} diff --git a/web/app/yarn.lock b/web/app/yarn.lock index 40a777d..db2e3aa 100644 --- a/web/app/yarn.lock +++ b/web/app/yarn.lock @@ -2,13 +2,6 @@ # yarn lockfile v1 -"@babel/code-frame@7.12.11": - version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" - integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== - dependencies: - "@babel/highlight" "^7.10.4" - "@babel/code-frame@^7.10.4": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" @@ -21,7 +14,7 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== -"@babel/highlight@^7.10.4", "@babel/highlight@^7.16.7": +"@babel/highlight@^7.16.7": version "7.16.10" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== @@ -30,18 +23,18 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@eslint/eslintrc@^0.4.3": - version "0.4.3" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" - integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== +"@eslint/eslintrc@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.2.0.tgz#7ce1547a5c46dfe56e1e45c3c9ed18038c721c6a" + integrity sha512-igm9SjJHNEJRiUnecP/1R5T3wKLEJ7pL6e2P+GUSfCd0dGjPYYZve08uzw8L2J8foVHFz+NGu12JxRcU2gGo6w== dependencies: ajv "^6.12.4" - debug "^4.1.1" - espree "^7.3.0" + debug "^4.3.2" + espree "^9.3.1" globals "^13.9.0" ignore "^4.0.6" import-fresh "^3.2.1" - js-yaml "^3.13.1" + js-yaml "^4.1.0" minimatch "^3.0.4" strip-json-comments "^3.1.1" @@ -60,16 +53,16 @@ resolved "https://registry.yarnpkg.com/@hotwired/turbo/-/turbo-7.1.0.tgz#27e44e0e3dc5bd1d4bda0766d579cf5a14091cd7" integrity sha512-Q8kGjqwPqER+CtpQudbH+3Zgs2X4zb6pBAlr6NsKTXadg45pAOvxI9i4QpuHbwSzR2+x87HUm+rot9F/Pe8rxA== -"@humanwhocodes/config-array@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" - integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== +"@humanwhocodes/config-array@^0.9.2": + version "0.9.5" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7" + integrity sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw== dependencies: - "@humanwhocodes/object-schema" "^1.2.0" + "@humanwhocodes/object-schema" "^1.2.1" debug "^4.1.1" minimatch "^3.0.4" -"@humanwhocodes/object-schema@^1.2.0": +"@humanwhocodes/object-schema@^1.2.1": version "1.2.1" resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== @@ -120,14 +113,6 @@ is-module "^1.0.0" resolve "^1.19.0" -"@rollup/plugin-typescript@^8.0.0": - version "8.3.1" - resolved "https://registry.yarnpkg.com/@rollup/plugin-typescript/-/plugin-typescript-8.3.1.tgz#b7dc75ed6b4876e260b9e80624fab23bc98e4ac1" - integrity sha512-84rExe3ICUBXzqNX48WZV2Jp3OddjTMX97O2Py6D1KJaGSwWp0mDHXj+bCGNJqWHIEKDIT2U0sDjhP4czKi6cA== - dependencies: - "@rollup/pluginutils" "^3.1.0" - resolve "^1.17.0" - "@rollup/pluginutils@4": version "4.1.2" resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.1.2.tgz#ed5821c15e5e05e32816f5fb9ec607cdf5a75751" @@ -145,6 +130,20 @@ estree-walker "^1.0.1" picomatch "^2.2.2" +"@sargassum-world/stimulated@^0.2.9": + version "0.2.9" + resolved "https://registry.yarnpkg.com/@sargassum-world/stimulated/-/stimulated-0.2.9.tgz#02922770aa62312bd49cf46e0c9203980f66d8e7" + integrity sha512-kJ22FwchwDnPd2VdYhObGUfgGAAxVTzZWFkmfG5Iq35KPxosJLDnt+MOCSn5JitnVHFPjZQ4G6ggGFPcIcXhIg== + dependencies: + "@hotwired/turbo" "^7.0.1" + async-mutex "^0.3.2" + stimulus "2.0.0" + +"@sargassum-world/styles@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@sargassum-world/styles/-/styles-0.2.0.tgz#1835b0cc6245f67f00bb0375076f8b18774da5a0" + integrity sha512-/zXKNTKATsj0/zmOoaL8zPFN/eyPmtrgdh2+249dVOJqxmObeWzAnKgH5Nre1D67dSfvBK6VqvX0uDy8mpaACA== + "@stimulus/core@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@stimulus/core/-/core-2.0.0.tgz#140c85318d6a8a8210c0faf182223b8459348877" @@ -169,11 +168,6 @@ resolved "https://registry.yarnpkg.com/@stimulus/webpack-helpers/-/webpack-helpers-2.0.0.tgz#54296d2a2dffd4f962d2e802d99a3fdd84b8845f" integrity sha512-D6tJWsAC024MwGEIKlUVYU8Ln87mlrmiwHvYAjipg+s8H4eLxUMQ3PZkWyPevfipH+oR3leuHsjYsK1gN5ViQA== -"@tsconfig/svelte@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@tsconfig/svelte/-/svelte-2.0.1.tgz#0e8d7caa693e9b2afce5e622c0475bb0fd89c12c" - integrity sha512-aqkICXbM1oX5FfgZd2qSSAGdyo/NRxjWCamxoyi3T8iVQnzGge19HhDYzZ6NrVOW7bhcWNSq9XexWFtMzbB24A== - "@types/estree@*": version "0.0.51" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" @@ -199,11 +193,6 @@ "@types/minimatch" "*" "@types/node" "*" -"@types/json-schema@^7.0.7": - version "7.0.9" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" - integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== - "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" @@ -238,87 +227,12 @@ dependencies: "@types/node" "*" -"@typescript-eslint/eslint-plugin@^4.29.3": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276" - integrity sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg== - dependencies: - "@typescript-eslint/experimental-utils" "4.33.0" - "@typescript-eslint/scope-manager" "4.33.0" - debug "^4.3.1" - functional-red-black-tree "^1.0.1" - ignore "^5.1.8" - regexpp "^3.1.0" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/experimental-utils@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz#6f2a786a4209fa2222989e9380b5331b2810f7fd" - integrity sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q== - dependencies: - "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.33.0" - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/typescript-estree" "4.33.0" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" - -"@typescript-eslint/parser@^4.29.3": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.33.0.tgz#dfe797570d9694e560528d18eecad86c8c744899" - integrity sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA== - dependencies: - "@typescript-eslint/scope-manager" "4.33.0" - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/typescript-estree" "4.33.0" - debug "^4.3.1" - -"@typescript-eslint/scope-manager@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz#d38e49280d983e8772e29121cf8c6e9221f280a3" - integrity sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ== - dependencies: - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/visitor-keys" "4.33.0" - -"@typescript-eslint/types@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" - integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== - -"@typescript-eslint/typescript-estree@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609" - integrity sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA== - dependencies: - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/visitor-keys" "4.33.0" - debug "^4.3.1" - globby "^11.0.3" - is-glob "^4.0.1" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/visitor-keys@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd" - integrity sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg== - dependencies: - "@typescript-eslint/types" "4.33.0" - eslint-visitor-keys "^2.0.0" - acorn-jsx@^5.3.1: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^7.4.0: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - -acorn@^8.5.0: +acorn@^8.5.0, acorn@^8.7.0: version "8.7.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== @@ -333,21 +247,6 @@ ajv@^6.10.0, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.1: - version "8.10.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.10.0.tgz#e573f719bd3af069017e3b66538ab968d040e54d" - integrity sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - -ansi-colors@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== - ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" @@ -370,7 +269,7 @@ ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -ansi-styles@^4.0.0, ansi-styles@^4.1.0: +ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== @@ -385,12 +284,10 @@ anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== array-includes@^3.1.4: version "3.1.4" @@ -417,11 +314,6 @@ array.prototype.flat@^1.2.5: define-properties "^1.1.3" es-abstract "^1.19.0" -astral-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" - integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== - async-mutex@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/async-mutex/-/async-mutex-0.3.2.tgz#1485eda5bda1b0ec7c8df1ac2e815757ad1831df" @@ -641,7 +533,7 @@ debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.0.1, debug@^4.1.1, debug@^4.3.1: +debug@^4.1.1, debug@^4.3.2: version "4.3.3" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== @@ -701,18 +593,6 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -enquirer@^2.3.5: - version "2.3.6" - resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" - integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== - dependencies: - ansi-colors "^4.1.1" - error-ex@^1.2.0: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" @@ -810,20 +690,13 @@ eslint-plugin-svelte3@^3.2.1: resolved "https://registry.yarnpkg.com/eslint-plugin-svelte3/-/eslint-plugin-svelte3-3.4.1.tgz#3618700333c8f8f12e28aec93bf18440d44a61fd" integrity sha512-7p59WG8qV8L6wLdl4d/c3mdjkgVglQCdv5XOTk/iNPBKXuuV+Q0eFP5Wa6iJd/G2M1qR3BkLPEzaANOqKAZczw== -eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== +eslint-scope@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== dependencies: esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-utils@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== - dependencies: - eslint-visitor-keys "^1.1.0" + estraverse "^5.2.0" eslint-utils@^3.0.0: version "3.0.0" @@ -832,75 +705,65 @@ eslint-utils@^3.0.0: dependencies: eslint-visitor-keys "^2.0.0" -eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - eslint-visitor-keys@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint@^7.32.0: - version "7.32.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" - integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== +eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== + +eslint@^8.10.0: + version "8.10.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.10.0.tgz#931be395eb60f900c01658b278e05b6dae47199d" + integrity sha512-tcI1D9lfVec+R4LE1mNDnzoJ/f71Kl/9Cv4nG47jOueCMBrCCKYXr4AUVS7go6mWYGFD4+EoN6+eXSrEbRzXVw== dependencies: - "@babel/code-frame" "7.12.11" - "@eslint/eslintrc" "^0.4.3" - "@humanwhocodes/config-array" "^0.5.0" + "@eslint/eslintrc" "^1.2.0" + "@humanwhocodes/config-array" "^0.9.2" ajv "^6.10.0" chalk "^4.0.0" cross-spawn "^7.0.2" - debug "^4.0.1" + debug "^4.3.2" doctrine "^3.0.0" - enquirer "^2.3.5" escape-string-regexp "^4.0.0" - eslint-scope "^5.1.1" - eslint-utils "^2.1.0" - eslint-visitor-keys "^2.0.0" - espree "^7.3.1" + eslint-scope "^7.1.1" + eslint-utils "^3.0.0" + eslint-visitor-keys "^3.3.0" + espree "^9.3.1" esquery "^1.4.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" file-entry-cache "^6.0.1" functional-red-black-tree "^1.0.1" - glob-parent "^5.1.2" + glob-parent "^6.0.1" globals "^13.6.0" - ignore "^4.0.6" + ignore "^5.2.0" import-fresh "^3.0.0" imurmurhash "^0.1.4" is-glob "^4.0.0" - js-yaml "^3.13.1" + js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" lodash.merge "^4.6.2" minimatch "^3.0.4" natural-compare "^1.4.0" optionator "^0.9.1" - progress "^2.0.0" - regexpp "^3.1.0" - semver "^7.2.1" - strip-ansi "^6.0.0" + regexpp "^3.2.0" + strip-ansi "^6.0.1" strip-json-comments "^3.1.0" - table "^6.0.9" text-table "^0.2.0" v8-compile-cache "^2.0.3" -espree@^7.3.0, espree@^7.3.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" - integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== +espree@^9.3.1: + version "9.3.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.1.tgz#8793b4bc27ea4c778c19908e0719e7b8f4115bcd" + integrity sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ== dependencies: - acorn "^7.4.0" + acorn "^8.7.0" acorn-jsx "^5.3.1" - eslint-visitor-keys "^1.3.0" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + eslint-visitor-keys "^3.3.0" esquery@^1.4.0: version "1.4.0" @@ -916,11 +779,6 @@ esrecurse@^4.3.0: dependencies: estraverse "^5.2.0" -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - estraverse@^5.1.0, estraverse@^5.2.0: version "5.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" @@ -964,7 +822,7 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.0.3, fast-glob@^3.2.7, fast-glob@^3.2.9: +fast-glob@^3.0.3, fast-glob@^3.2.7: version "3.2.11" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== @@ -1089,6 +947,13 @@ glob-parent@^5.1.2, glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" +glob-parent@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + glob@^7.1.1, glob@^7.1.3, glob@^7.1.6: version "7.2.0" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" @@ -1122,18 +987,6 @@ globby@10.0.1: merge2 "^1.2.3" slash "^3.0.0" -globby@^11.0.3: - version "11.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.2.9" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^3.0.0" - graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.9" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" @@ -1178,17 +1031,12 @@ hosted-git-info@^2.1.4: resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== -hotkeys-js@>=3: - version "3.8.7" - resolved "https://registry.yarnpkg.com/hotkeys-js/-/hotkeys-js-3.8.7.tgz#c16cab978b53d7242f860ca3932e976b92399981" - integrity sha512-ckAx3EkUr5XjDwjEHDorHxRO2Kb7z6Z2Sxul4MbBkN8Nho7XDslQsgMJT+CiJ5Z4TgRxxvKHEpuLE3imzqy4Lg== - ignore@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -ignore@^5.1.1, ignore@^5.1.8, ignore@^5.2.0: +ignore@^5.1.1, ignore@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== @@ -1301,11 +1149,6 @@ is-fullwidth-code-point@^2.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" @@ -1405,24 +1248,18 @@ js-tokens@^4.0.0: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== dependencies: - argparse "^1.0.7" - esprima "^4.0.0" + argparse "^2.0.1" json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== -json-schema-traverse@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" - integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== - json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" @@ -1480,11 +1317,6 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash.truncate@^4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" - integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= - lru-cache@^4.0.1: version "4.1.5" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" @@ -1493,13 +1325,6 @@ lru-cache@^4.0.1: pseudomap "^1.0.2" yallist "^2.1.2" -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - magic-string@^0.25.7: version "0.25.7" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" @@ -1519,7 +1344,7 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -merge2@^1.2.3, merge2@^1.3.0, merge2@^1.4.1: +merge2@^1.2.3, merge2@^1.3.0: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== @@ -1775,11 +1600,6 @@ prettier@^2.4.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a" integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg== -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" @@ -1837,7 +1657,7 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" -regexpp@^3.1.0: +regexpp@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== @@ -1847,11 +1667,6 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= -require-from-string@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" - integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== - require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" @@ -2008,13 +1823,6 @@ sass@^1.43.2: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@^7.2.1, semver@^7.3.5: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== - dependencies: - lru-cache "^6.0.0" - serialize-javascript@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" @@ -2070,15 +1878,6 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -slice-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" - integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - sorcery@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/sorcery/-/sorcery-0.10.0.tgz#8ae90ad7d7cb05fc59f1ab0c637845d5c15a52b7" @@ -2159,18 +1958,6 @@ spdx-license-ids@^3.0.0: resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz#50c0d8c40a14ec1bf449bae69a0ea4685a9d9f95" integrity sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g== -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -stimulus-use@^0.41.0: - version "0.41.0" - resolved "https://registry.yarnpkg.com/stimulus-use/-/stimulus-use-0.41.0.tgz#afe2559281ebe0504b1d35eb0e8e77df9ebd6fb6" - integrity sha512-d+XWb5YN2L9I+4zQDtE1sJVy1DBO+1qgNcjV0XpMw7KXPJ8m8JA5lcJk3qgbxV86ePHko0CP9F3dzVsapQwzmA== - dependencies: - hotkeys-js ">=3" - stimulus@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/stimulus/-/stimulus-2.0.0.tgz#713c8b91a72ef90914b90955f0e705f004403047" @@ -2196,15 +1983,6 @@ string-width@^2.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - string.prototype.trimend@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" @@ -2235,7 +2013,7 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: +strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -2320,17 +2098,6 @@ svelte@^3.0.0: resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.46.4.tgz#0c46bc4a3e20a2617a1b7dc43a722f9d6c084a38" integrity sha512-qKJzw6DpA33CIa+C/rGp4AUdSfii0DOTCzj/2YpSKKayw5WGSS624Et9L1nU1k2OVRS9vaENQXp2CVZNU+xvIg== -table@^6.0.9: - version "6.8.0" - resolved "https://registry.yarnpkg.com/table/-/table-6.8.0.tgz#87e28f14fa4321c3377ba286f07b79b281a3b3ca" - integrity sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA== - dependencies: - ajv "^8.0.1" - lodash.truncate "^4.4.2" - slice-ansi "^4.0.0" - string-width "^4.2.3" - strip-ansi "^6.0.1" - terser@^5.0.0: version "5.12.0" resolved "https://registry.yarnpkg.com/terser/-/terser-5.12.0.tgz#728c6bff05f7d1dcb687d8eace0644802a9dae8a" @@ -2363,23 +2130,11 @@ tsconfig-paths@^3.12.0: minimist "^1.2.0" strip-bom "^3.0.0" -tslib@^1.8.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tslib@^2.0.0, tslib@^2.3.1: +tslib@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== -tsutils@^3.21.0: - version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" - type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -2392,7 +2147,7 @@ type-fest@^0.20.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== -typescript@*, typescript@^4.0.0: +typescript@*: version "4.6.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.2.tgz#fe12d2727b708f4eef40f51598b3398baa9611d4" integrity sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg== @@ -2500,11 +2255,6 @@ yallist@^2.1.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - yargs-parser@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" diff --git a/web/templates/app/app.webmanifest.tmpl b/web/templates/app/app.webmanifest.tmpl index 99b6ac7..08b951c 100644 --- a/web/templates/app/app.webmanifest.tmpl +++ b/web/templates/app/app.webmanifest.tmpl @@ -1,6 +1,6 @@ { "name": "Fluitans", - "decsription": "An application for managing Sargassum networks, domain names, and organizations.", + "description": "An application for managing Sargassum networks, domain names, and organizations.", "categories": ["utilities"], "short_name": "Fluitans", "lang": "en-US", diff --git a/web/templates/auth/login.page.tmpl b/web/templates/auth/login.page.tmpl index 292f779..0c073eb 100644 --- a/web/templates/auth/login.page.tmpl +++ b/web/templates/auth/login.page.tmpl @@ -12,7 +12,7 @@

Sign In

{{end}} {{range $message := .Data.ErrorMessages}} -
+

Error

@@ -22,7 +22,7 @@
{{end}} {{if .Data.NoAuth}} -
+

Security Warning

@@ -33,7 +33,7 @@
{{end}} {{if .Auth.Identity.Authenticated}} -
+

You are currently signed in as {{.Auth.Identity.User}}.

{{else}} -
+
- - {{template "shared/auth/csrf-input.partial.tmpl" .Auth.CSRF}} - -
- -
- +
+
+ {{template "shared/auth/csrf-input.partial.tmpl" .Auth.CSRF}} + +
+ +
+
+
{{end}}