diff --git a/Dockerfile b/Dockerfile index 5c7aab14..9d0c17c2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.16-alpine as build +FROM golang:1.22-alpine as build RUN apk add --no-cache \ git \ @@ -18,7 +18,7 @@ ENV GODEBUG="netdns=go http2server=0" RUN make build BUILD_VERSION=${BUILD_VERSION} -FROM alpine:3.13.4 +FROM alpine:3.20.0 LABEL maintainer="github.com/subspacecommunity/subspace" COPY --from=build /src/subspace /usr/bin/subspace diff --git a/Makefile b/Makefile index e7ceb7aa..9c2c0ee3 100644 --- a/Makefile +++ b/Makefile @@ -8,21 +8,14 @@ BUILD_VERSION?=unknown help: ## Display this help message and exit @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' -build: clean bindata.go ## Build the binary +# GOOS=linux GOARCH=amd64 +build: @echo "Compiling subspace..." - @CGO_ENABLED=0 \ - go build -v --compiler gc --ldflags "-extldflags -static -s -w -X main.version=${BUILD_VERSION}" -o subspace ./cmd/subspace \ - && rm cmd/subspace/bindata.go + cd web \ + && go run github.com/jteeuwen/go-bindata/go-bindata --pkg main static/... templates/... email/.. \ + && mv bindata.go ../cmd/subspace/ \ + && cd - \ + && CGO_ENABLED=0 \ + go build -v --compiler gc --ldflags "-extldflags -static -s -w -X main.version=${BUILD_VERSION}" -o subspace ./cmd/subspace + rm cmd/subspace/bindata.go @echo "+++ subspace compiled" - -clean: ## Remove old binaries - rm -f subspace cmd/subspace/bindata.go - -bindata.go: $(BINDATA) - @echo "Creating bindata.go..." - @go-bindata -o cmd/subspace/bindata.go --prefix "web/" --pkg main web/... - @echo "+++ bindata.go created" - -$(BINDATA): - go get github.com/kevinburke/go-bindata/go-bindata - diff --git a/cmd/subspace/config.go b/cmd/subspace/config.go index 73b2230c..9e1e5c9a 100644 --- a/cmd/subspace/config.go +++ b/cmd/subspace/config.go @@ -9,7 +9,6 @@ import ( "encoding/pem" "errors" "fmt" - "io/ioutil" "math/big" "os" "path/filepath" @@ -97,12 +96,12 @@ type Config struct { func NewConfig(filename string) (*Config, error) { filename = filepath.Join(datadir, filename) c := &Config{filename: filename} - b, err := ioutil.ReadFile(filename) + b, err := os.ReadFile(filename) // Create new config with defaults if os.IsNotExist(err) { c.Info = &Info{ - Email: "null", + Email: "null", HashKey: RandomString(32), BlockKey: RandomString(32), } diff --git a/cmd/subspace/handlers.go b/cmd/subspace/handlers.go index ae7ff25e..72dbada8 100644 --- a/cmd/subspace/handlers.go +++ b/cmd/subspace/handlers.go @@ -4,11 +4,11 @@ import ( "bytes" "fmt" "image/png" - "io/ioutil" "net/http" "os" "regexp" "strings" + "time" "github.com/crewjam/saml/samlsp" "github.com/julienschmidt/httprouter" @@ -25,13 +25,6 @@ var ( maxProfiles = 250 ) -func getEnv(key, fallback string) string { - if value, ok := os.LookupEnv(key); ok { - return value - } - return fallback -} - // Handles the sign in part separately from the SAML func ssoHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { session, err := samlSP.Session.GetSession(r) @@ -47,7 +40,6 @@ func ssoHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { logger.Debugf("SSO: unable to get session") samlSP.OnError(w, r, err) - return } // Handles the SAML part separately from sign in @@ -72,7 +64,7 @@ func wireguardQRConfigHandler(w *Web) { return } - b, err := ioutil.ReadFile(profile.WireGuardConfigPath()) + b, err := os.ReadFile(profile.WireGuardConfigPath()) if err != nil { Error(w.w, err) return @@ -103,7 +95,7 @@ func wireguardConfigHandler(w *Web) { return } - b, err := ioutil.ReadFile(profile.WireGuardConfigPath()) + b, err := os.ReadFile(profile.WireGuardConfigPath()) if err != nil { Error(w.w, err) return @@ -143,12 +135,16 @@ func configureHandler(w *Web) { w.Redirect("/forgot?error=bcrypt") return } - config.UpdateInfo(func(i *Info) error { + err = config.UpdateInfo(func(i *Info) error { i.Email = email i.Password = hashedPassword i.Configured = true return nil }) + if err != nil { + w.Redirect("/configure?error=invalid") + return + } if err := w.SigninSession(true, ""); err != nil { Error(w.w, err) @@ -189,12 +185,16 @@ func forgotHandler(w *Web) { secret = config.FindInfo().Secret if secret == "" { secret = RandomString(32) - config.UpdateInfo(func(i *Info) error { + err := config.UpdateInfo(func(i *Info) error { if i.Secret == "" { i.Secret = secret } return nil }) + if err != nil { + w.Redirect("/configure?error=invalid") + return + } } go func() { @@ -217,11 +217,15 @@ func forgotHandler(w *Web) { w.Redirect("/forgot?error=bcrypt") return } - config.UpdateInfo(func(i *Info) error { + err = config.UpdateInfo(func(i *Info) error { i.Password = hashedPassword i.Secret = "" return nil }) + if err != nil { + w.Redirect("/configure?error=invalid") + return + } if err := w.SigninSession(true, ""); err != nil { Error(w.w, err) @@ -251,6 +255,7 @@ func signinHandler(w *Web) { } if err := bcrypt.CompareHashAndPassword(config.FindInfo().Password, []byte(password)); err != nil { + time.Sleep(3 * time.Second) // Prevent brute force w.Redirect("/signin?error=invalid") return } @@ -288,7 +293,11 @@ func totpQRHandler(w *Web) { return } - png.Encode(&buf, img) + err = png.Encode(&buf, img) + if err != nil { + Error(w.w, err) + return + } w.w.Header().Set("Content-Type", "image/png") w.w.Header().Set("Content-Length", fmt.Sprintf("%d", len(buf.Bytes()))) @@ -328,11 +337,14 @@ func userEditHandler(w *Web) { admin := w.r.FormValue("admin") == "yes" - config.UpdateUser(user.ID, func(u *User) error { + err = config.UpdateUser(user.ID, func(u *User) error { u.Admin = admin return nil }) - + if err != nil { + w.Redirect("/configure?error=invalid") + return + } w.Redirect("/user/edit/%s?success=edituser", user.ID) } @@ -414,58 +426,19 @@ func profileAddHandler(w *Web) { return } - ipv4Pref := "10.99.97." - if pref := getEnv("SUBSPACE_IPV4_PREF", "nil"); pref != "nil" { - ipv4Pref = pref - } - ipv4Gw := "10.99.97.1" - if gw := getEnv("SUBSPACE_IPV4_GW", "nil"); gw != "nil" { - ipv4Gw = gw - } - ipv4Cidr := "24" - if cidr := getEnv("SUBSPACE_IPV4_CIDR", "nil"); cidr != "nil" { - ipv4Cidr = cidr - } - ipv6Pref := "fd00::10:97:" - if pref := getEnv("SUBSPACE_IPV6_PREF", "nil"); pref != "nil" { - ipv6Pref = pref - } - ipv6Gw := "fd00::10:97:1" - if gw := getEnv("SUBSPACE_IPV6_GW", "nil"); gw != "nil" { - ipv6Gw = gw - } - ipv6Cidr := "64" - if cidr := getEnv("SUBSPACE_IPV6_CIDR", "nil"); cidr != "nil" { - ipv6Cidr = cidr - } - listenport := "51820" - if port := getEnv("SUBSPACE_LISTENPORT", "nil"); port != "nil" { - listenport = port - } - endpointHost := httpHost - if eh := getEnv("SUBSPACE_ENDPOINT_HOST", "nil"); eh != "nil" { - endpointHost = eh - } - allowedips := "0.0.0.0/0, ::/0" - if ips := getEnv("SUBSPACE_ALLOWED_IPS", "nil"); ips != "nil" { - allowedips = ips - } - ipv4Enabled := true - if enable := getEnv("SUBSPACE_IPV4_NAT_ENABLED", "1"); enable == "0" { - ipv4Enabled = false - } - ipv6Enabled := true - if enable := getEnv("SUBSPACE_IPV6_NAT_ENABLED", "1"); enable == "0" { - ipv6Enabled = false - } - disableDNS := false - if shouldDisableDNS := getEnv("SUBSPACE_DISABLE_DNS", "0"); shouldDisableDNS == "1" { - disableDNS = true - } - persistentKeepalive := "0" - if keepalive := getEnv("SUBSPACE_PERSISTENT_KEEPALIVE", "nil"); keepalive != "nil" { - persistentKeepalive = keepalive - } + ipv4Pref := getEnv("SUBSPACE_IPV4_PREF", "10.99.97.") + ipv4Gw := getEnv("SUBSPACE_IPV4_GW", "10.99.97.1") + ipv4Cidr := getEnv("SUBSPACE_IPV4_CIDR", "24") + ipv6Pref := getEnv("SUBSPACE_IPV6_PREF", "fd00::10:97:") + ipv6Gw := getEnv("SUBSPACE_IPV6_GW", "fd00::10:97:1") + ipv6Cidr := getEnv("SUBSPACE_IPV6_CIDR", "64") + listenport := getEnv("SUBSPACE_LISTENPORT", "51820") + endpointHost := getEnv("SUBSPACE_ENDPOINT_HOST", httpHost) + allowedips := getEnv("SUBSPACE_ALLOWED_IPS", "0.0.0.0/0, ::/0") + ipv4Enabled := getEnvAsBool("SUBSPACE_IPV4_NAT_ENABLED", true) + ipv6Enabled := getEnvAsBool("SUBSPACE_IPV6_NAT_ENABLED", true) + disableDNS := getEnvAsBool("SUBSPACE_DISABLE_DNS", false) + persistentKeepalive := getEnv("SUBSPACE_PERSISTENT_KEEPALIVE", "0") script := ` cd {{$.Datadir}}/wireguard @@ -487,6 +460,7 @@ PrivateKey = ${wg_private_key} DNS = {{if .Ipv4Enabled}}{{$.IPv4Gw}}{{end}}{{if .Ipv6Enabled}}{{if .Ipv4Enabled}},{{end}}{{$.IPv6Gw}}{{end}} {{- end }} Address = {{if .Ipv4Enabled}}{{$.IPv4Pref}}{{$.Profile.Number}}/{{$.IPv4Cidr}}{{end}}{{if .Ipv6Enabled}}{{if .Ipv4Enabled}},{{end}}{{$.IPv6Pref}}{{$.Profile.Number}}/{{$.IPv6Cidr}}{{end}} +MTU = 1280 [Peer] PublicKey = $(cat server.public) @@ -497,20 +471,20 @@ PersistentKeepalive = {{$.PersistentKeepalive}} WGCLIENT ` _, err = bash(script, struct { - Profile Profile - EndpointHost string - Datadir string - IPv4Gw string - IPv6Gw string - IPv4Pref string - IPv6Pref string - IPv4Cidr string - IPv6Cidr string - Listenport string - AllowedIPS string - Ipv4Enabled bool - Ipv6Enabled bool - DisableDNS bool + Profile Profile + EndpointHost string + Datadir string + IPv4Gw string + IPv6Gw string + IPv4Pref string + IPv6Pref string + IPv4Cidr string + IPv6Cidr string + Listenport string + AllowedIPS string + Ipv4Enabled bool + Ipv6Enabled bool + DisableDNS bool PersistentKeepalive string }{ profile, @@ -533,7 +507,10 @@ WGCLIENT logger.Warn(err) f, _ := os.Create("/tmp/error.txt") errstr := fmt.Sprintln(err) - f.WriteString(errstr) + _, err = f.WriteString(errstr) + if err != nil { + logger.Warn(err) + } w.Redirect("/?error=addprofile") return } @@ -620,11 +597,15 @@ func settingsHandler(w *Web) { resetTotp := w.r.FormValue("reset_totp") totpCode := w.r.FormValue("totp_code") - config.UpdateInfo(func(i *Info) error { + err := config.UpdateInfo(func(i *Info) error { i.SAML.IDPMetadata = samlMetadata i.Email = email return nil }) + if err != nil { + w.Redirect("/configure?error=invalid") + return + } // Configure SAML if metadata is present. if len(samlMetadata) > 0 { @@ -653,10 +634,14 @@ func settingsHandler(w *Web) { return } - config.UpdateInfo(func(i *Info) error { + err = config.UpdateInfo(func(i *Info) error { i.Password = hashedPassword return nil }) + if err != nil { + w.Redirect("/configure?error=invalid") + return + } } if resetTotp == "true" { @@ -676,7 +661,12 @@ func settingsHandler(w *Web) { return } config.Info.TotpKey = tempTotpKey.Secret() - config.save() + err = config.save() + if err != nil { + logger.Warnf("failed to save totp key: %s", err) + w.Redirect("/settings?error=totp") + return + } } w.Redirect("/settings?success=settings") @@ -686,9 +676,7 @@ func helpHandler(w *Web) { w.HTML() } -// // Helpers -// func deleteProfile(profile Profile) error { script := ` # WireGuard diff --git a/cmd/subspace/mailer.go b/cmd/subspace/mailer.go index d3683a53..6dcf1a4c 100644 --- a/cmd/subspace/mailer.go +++ b/cmd/subspace/mailer.go @@ -14,7 +14,7 @@ import ( ) func init() { - rand.Seed(time.Now().Unix()) + rand.New(rand.NewSource(time.Now().UnixNano())) } type Mailer struct{} diff --git a/cmd/subspace/main.go b/cmd/subspace/main.go index 1956ac9d..149d24c6 100644 --- a/cmd/subspace/main.go +++ b/cmd/subspace/main.go @@ -99,9 +99,10 @@ func init() { } func main() { - var err error - - cli.Parse(os.Args[1:]) + err := cli.Parse(os.Args[1:]) + if err != nil { + logger.Warn("error parsing flags: ", err) + } usage := func(msg string) { if msg != "" { fmt.Fprintf(os.Stderr, "ERROR: %s\n", msg) @@ -332,8 +333,14 @@ func (l tcpKeepAliveListener) Accept() (c net.Conn, err error) { if err != nil { return } - tc.SetKeepAlive(true) - tc.SetKeepAlivePeriod(10 * time.Minute) + err = tc.SetKeepAlive(true) + if err != nil { + logger.Warn("failed to set keep alive: ", err) + } + err = tc.SetKeepAlivePeriod(10 * time.Minute) + if err != nil { + logger.Warn("failed to set keep alive period: ", err) + } return tc, nil } @@ -390,9 +397,6 @@ func configureSAML() error { Certificate: keyPair.Leaf, IDPMetadata: entity, CookieName: SessionCookieNameSSO, - CookieDomain: httpHost, // TODO: this will break if using a custom domain. - CookieSecure: !httpInsecure, - Logger: logger, AllowIDPInitiated: true, }) if err != nil { diff --git a/cmd/subspace/utils.go b/cmd/subspace/utils.go index 4f34348c..9eff3bd3 100644 --- a/cmd/subspace/utils.go +++ b/cmd/subspace/utils.go @@ -6,10 +6,10 @@ import ( "crypto/rand" "encoding/base64" "fmt" - "io/ioutil" "os" "os/exec" "path/filepath" + "strconv" "text/template" "time" ) @@ -23,7 +23,7 @@ func RandomString(n int) string { } func Overwrite(filename string, data []byte, perm os.FileMode) error { - f, err := ioutil.TempFile(filepath.Dir(filename), filepath.Base(filename)+".tmp") + f, err := os.CreateTemp(filepath.Dir(filename), filepath.Base(filename)+".tmp") if err != nil { return err } @@ -62,9 +62,29 @@ set -o xtrace ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) defer cancel() - output, err := exec.CommandContext(ctx, "/bin/bash", "-c", string(script.Bytes())).CombinedOutput() + output, err := exec.CommandContext(ctx, "/bin/bash", "-c", script.String()).CombinedOutput() if err != nil { return string(output), fmt.Errorf("command failed: %s\n%s", err, string(output)) } return string(output), nil } + +func getEnv(key, defaultValue string) string { + if value, exists := os.LookupEnv(key); exists { + return value + } + return defaultValue +} + +// getEnvAsBool retrieves the value of the environment variable named by the key and converts it to a boolean. +// If the variable is present in the environment, the value is converted to a boolean and returned. +// Otherwise, it returns the specified default boolean value. +func getEnvAsBool(key string, defaultValue bool) bool { + if value, exists := os.LookupEnv(key); exists { + boolValue, err := strconv.ParseBool(value) + if err == nil { + return boolValue + } + } + return defaultValue +} diff --git a/cmd/subspace/web.go b/cmd/subspace/web.go index 81c55686..8ec1d4e1 100644 --- a/cmd/subspace/web.go +++ b/cmd/subspace/web.go @@ -16,6 +16,8 @@ import ( "github.com/pquerna/otp" "golang.org/x/net/publicsuffix" + "golang.org/x/text/cases" + "golang.org/x/text/language" humanize "github.com/dustin/go-humanize" httprouter "github.com/julienschmidt/httprouter" @@ -106,7 +108,7 @@ func (w *Web) HTML() { if icann { suffix = "." + suffix } - return strings.Title(strings.TrimSuffix(domain, suffix)) + return cases.Title(language.English).String(strings.TrimSuffix(domain, suffix)) }, }) @@ -200,11 +202,11 @@ func WebHandler(h func(*Web), section string) httprouter.Handle { } if session != nil { - r = r.WithContext(samlsp.ContextWithSession(r.Context(), session)) + web.r = r.WithContext(samlsp.ContextWithSession(r.Context(), session)) jwtSessionClaims, ok := session.(samlsp.JWTSessionClaims) if !ok { - Error(w, fmt.Errorf("Unable to decode session into JWTSessionClaims")) + Error(w, fmt.Errorf("unable to decode session into JWTSessionClaims")) return } @@ -325,7 +327,7 @@ func (w *Web) SignoutSession() { } func (w *Web) SigninSession(admin bool, userID string) error { - expires := time.Now().Add(12 * time.Hour) + expires := time.Now().Add(1 * time.Hour) encoded, err := securetoken.Encode(SessionCookieName, Session{ Admin: admin, diff --git a/entrypoint.sh b/entrypoint.sh index 2d6cb8ab..ca2cd271 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -69,23 +69,16 @@ else export SUBSPACE_IPV4_NAT_ENABLED=0 fi -# DNS server is disabled if the flag is not ommited and set to anything other than 0. -if ! [ -z "${SUBSPACE_DISABLE_DNS-}" ] && [ "${SUBSPACE_DISABLE_DNS}" != "0" ]; then - export SUBSPACE_DISABLE_DNS=1 -else - export SUBSPACE_DISABLE_DNS=0 -fi - if [ "$SUBSPACE_IPV6_NAT_ENABLED" == "0" ] && [ "$SUBSPACE_IPV4_NAT_ENABLED" == "0" ]; then echo "One of envionment variables SUBSPACE_IPV6_NAT_ENABLED, SUBSPACE_IPV4_NAT_ENABLED must be set to 1." echo "Got SUBSPACE_IPV6_NAT_ENABLED=$SUBSPACE_IPV6_NAT_ENABLED, SUBSPACE_IPV4_NAT_ENABLED=$SUBSPACE_IPV4_NAT_ENABLED" exit 1 fi -# Empty out inherited nameservers -echo "" >/etc/resolv.conf -# Set DNS servers -echo ${SUBSPACE_NAMESERVERS} | tr "," "\n" | while read -r ns; do echo "nameserver ${ns}" >>/etc/resolv.conf; done +## Empty out inherited nameservers +#echo "" > /etc/resolv.conf +## Set DNS servers +#echo ${SUBSPACE_NAMESERVERS} | tr "," "\n" | while read -r ns; do echo "nameserver ${ns}" >>/etc/resolv.conf; done if [ -z "${SUBSPACE_DISABLE_MASQUERADE-}" ]; then if [[ ${SUBSPACE_IPV4_NAT_ENABLED} -ne 0 ]]; then @@ -155,7 +148,7 @@ if ! test -d /data/wireguard; then touch peers/null.conf # So you can cat *.conf safely # Generate public/private server keys. - wg genkey | tee server.private | wg pubkey >server.public + wg genkey | tee server.private | wg pubkey > server.public fi cat </data/wireguard/server.conf @@ -184,17 +177,16 @@ wg setconf wg0 /data/wireguard/server.conf ip link set wg0 up # dnsmasq service -if [[ ${SUBSPACE_DISABLE_DNS} == "0" ]]; then - DNSMASQ_LISTEN_ADDRESS="127.0.0.1" - if [[ ${SUBSPACE_IPV4_NAT_ENABLED} -ne 0 ]]; then - DNSMASQ_LISTEN_ADDRESS="${DNSMASQ_LISTEN_ADDRESS},${SUBSPACE_IPV4_GW}" - fi - if [[ ${SUBSPACE_IPV6_NAT_ENABLED} -ne 0 ]]; then - DNSMASQ_LISTEN_ADDRESS="${DNSMASQ_LISTEN_ADDRESS},${SUBSPACE_IPV6_GW}" - fi +DNSMASQ_LISTEN_ADDRESS="127.0.0.1" +if [[ ${SUBSPACE_IPV4_NAT_ENABLED} -ne 0 ]]; then + DNSMASQ_LISTEN_ADDRESS="${DNSMASQ_LISTEN_ADDRESS},${SUBSPACE_IPV4_GW}" +fi +if [[ ${SUBSPACE_IPV6_NAT_ENABLED} -ne 0 ]]; then + DNSMASQ_LISTEN_ADDRESS="${DNSMASQ_LISTEN_ADDRESS},${SUBSPACE_IPV6_GW}" +fi - if ! test -d /etc/service/dnsmasq; then - cat </etc/dnsmasq.conf +if ! test -d /etc/service/dnsmasq; then + cat </etc/dnsmasq.conf # Only listen on necessary addresses. listen-address=${DNSMASQ_LISTEN_ADDRESS} @@ -203,26 +195,22 @@ if [[ ${SUBSPACE_DISABLE_DNS} == "0" ]]; then # Never forward addresses in the non-routed address spaces. bogus-priv - - # Allow extending dnsmasq by providing custom configurations. - conf-dir=/etc/dnsmasq.d DNSMASQ - mkdir -p /etc/service/dnsmasq - cat </etc/service/dnsmasq/run + mkdir -p /etc/service/dnsmasq + cat </etc/service/dnsmasq/run #!/bin/sh -exec /usr/sbin/dnsmasq --keep-in-foreground +exec /usr/sbin/dnsmasq --no-daemon RUNIT - chmod +x /etc/service/dnsmasq/run + chmod +x /etc/service/dnsmasq/run - # dnsmasq service log - mkdir -p /etc/service/dnsmasq/log/main - cat </etc/service/dnsmasq/log/run + # dnsmasq service log + mkdir -p /etc/service/dnsmasq/log/main + cat </etc/service/dnsmasq/log/run #!/bin/sh exec svlogd -tt ./main RUNIT - chmod +x /etc/service/dnsmasq/log/run - fi + chmod +x /etc/service/dnsmasq/log/run fi # subspace service @@ -251,4 +239,4 @@ RUNIT chmod +x /etc/service/subspace/log/run fi -exec $@ +exec $@ \ No newline at end of file diff --git a/go.mod b/go.mod index 1dcf240e..26433e4a 100644 --- a/go.mod +++ b/go.mod @@ -1,20 +1,31 @@ module github.com/subspacecommunity/subspace -go 1.14 +go 1.22 require ( - github.com/crewjam/saml v0.4.5 - github.com/dustin/go-humanize v1.0.0 - github.com/gorilla/securecookie v1.1.1 + github.com/crewjam/saml v0.4.14 + github.com/dustin/go-humanize v1.0.1 + github.com/gorilla/securecookie v1.1.2 github.com/jteeuwen/go-bindata v3.0.8-0.20180305030458-6025e8de665b+incompatible github.com/julienschmidt/httprouter v1.3.0 - github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect - github.com/pquerna/otp v1.2.0 // indirect - github.com/sirupsen/logrus v1.6.0 - github.com/skip2/go-qrcode v0.0.0-20200519171959-a3b48390827e - golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 - golang.org/x/net v0.0.0-20200519113804-d87ec0cfa476 - gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect - gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect + github.com/pquerna/otp v1.4.0 + github.com/sirupsen/logrus v1.9.3 + github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e + golang.org/x/crypto v0.24.0 + golang.org/x/net v0.26.0 + golang.org/x/text v0.16.0 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df ) + +require ( + github.com/beevik/etree v1.4.0 // indirect + github.com/boombuler/barcode v1.0.1 // indirect + github.com/crewjam/httperr v0.2.0 // indirect + github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/jonboulle/clockwork v0.4.0 // indirect + github.com/mattermost/xml-roundtrip-validator v0.1.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/russellhaering/goxmldsig v1.4.0 // indirect + golang.org/x/sys v0.21.0 // indirect + gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect +) diff --git a/go.sum b/go.sum index aa7bd6e4..a54cd765 100644 --- a/go.sum +++ b/go.sum @@ -1,94 +1,86 @@ -github.com/beevik/etree v1.0.1 h1:lWzdj5v/Pj1X360EV7bUudox5SRipy4qZLjY0rhb0ck= -github.com/beevik/etree v1.0.1/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= -github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= -github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= -github.com/crewjam/httperr v0.0.0-20190612203328-a946449404da h1:WXnT88cFG2davqSFqvaFfzkSMC0lqh/8/rKZ+z7tYvI= -github.com/crewjam/httperr v0.0.0-20190612203328-a946449404da/go.mod h1:+rmNIXRvYMqLQeR4DHyTvs6y0MEMymTz4vyFpFkKTPs= -github.com/crewjam/saml v0.4.5 h1:H9u+6CZAESUKHxMyxUbVn0IawYvKZn4nt3d4ccV4O/M= -github.com/crewjam/saml v0.4.5/go.mod h1:qCJQpUtZte9R1ZjUBcW8qtCNlinbO363ooNl02S68bk= +github.com/beevik/etree v1.4.0 h1:oz1UedHRepuY3p4N5OjE0nK1WLCqtzHf25bxplKOHLs= +github.com/beevik/etree v1.4.0/go.mod h1:cyWiXwGoasx60gHvtnEh5x8+uIjUVnjWqBvEnhnqKDA= +github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs= +github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/crewjam/httperr v0.2.0 h1:b2BfXR8U3AlIHwNeFFvZ+BV1LFvKLlzMjzaTnZMybNo= +github.com/crewjam/httperr v0.2.0/go.mod h1:Jlz+Sg/XqBQhyMjdDiC+GNNRzZTD7x39Gu3pglZ5oH4= +github.com/crewjam/saml v0.4.14 h1:g9FBNx62osKusnFzs3QTN5L9CVA/Egfgm+stJShzw/c= +github.com/crewjam/saml v0.4.14/go.mod h1:UVSZCf18jJkk6GpWNVqcyQJMD5HsRugBPf4I1nl2mME= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dchest/uniuri v0.0.0-20160212164326-8902c56451e9/go.mod h1:GgB8SF9nRG+GqaDtLcwJZsQFhcogVCJ79j4EdT0c2V4= -github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= -github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= -github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/jonboulle/clockwork v0.2.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= -github.com/jonboulle/clockwork v0.2.1 h1:S/EaQvW6FpWMYAvYvY+OBDvpaM+izu0oiwo5y0MH7U0= -github.com/jonboulle/clockwork v0.2.1/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= +github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= +github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= github.com/jteeuwen/go-bindata v3.0.8-0.20180305030458-6025e8de665b+incompatible h1:eX6cWzw+KSwhN430wwbdWPgqnlbnK5ux76/q5ko+Qu8= github.com/jteeuwen/go-bindata v3.0.8-0.20180305030458-6025e8de665b+incompatible/go.mod h1:JVvhzYOiGBnFSYRyV00iY8q7/0PThjIYav1p9h5dmKs= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/mattermost/xml-roundtrip-validator v0.0.0-20201213122252-bcd7e1b9601e h1:qqXczln0qwkVGcpQ+sQuPOVntt2FytYarXXxYSNJkgw= -github.com/mattermost/xml-roundtrip-validator v0.0.0-20201213122252-bcd7e1b9601e/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattermost/xml-roundtrip-validator v0.1.0 h1:RXbVD2UAl7A7nOTR4u7E3ILa4IbtvKBHw64LDsmu9hU= +github.com/mattermost/xml-roundtrip-validator v0.1.0/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= -github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= -github.com/russellhaering/goxmldsig v0.0.0-20180430223755-7acd5e4a6ef7 h1:J4AOUcOh/t1XbQcJfkEqhzgvMJ2tDxdCVvmHxW5QXao= -github.com/russellhaering/goxmldsig v0.0.0-20180430223755-7acd5e4a6ef7/go.mod h1:Oz4y6ImuOQZxynhbSXk7btjEfNBtGlj2dcaOvXl2FSM= -github.com/russellhaering/goxmldsig v1.1.0 h1:lK/zeJie2sqG52ZAlPNn1oBBqsIsEKypUUBGpYYF6lk= -github.com/russellhaering/goxmldsig v1.1.0/go.mod h1:QK8GhXPB3+AfuCrfo0oRISa9NfzeCpWmxeGnqEpDF9o= -github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/skip2/go-qrcode v0.0.0-20200519171959-a3b48390827e h1:xVeSA6fTG0og2KsF+Jh9vzx8gYRtBfLmpXzp3L1eThY= -github.com/skip2/go-qrcode v0.0.0-20200519171959-a3b48390827e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= +github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg= +github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/russellhaering/goxmldsig v1.4.0 h1:8UcDh/xGyQiyrW+Fq5t8f+l2DLB1+zlhYzkPUJ7Qhys= +github.com/russellhaering/goxmldsig v1.4.0/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= +github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/zenazn/goji v0.9.1-0.20160507202103-64eb34159fe5/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= -golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw= -golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20200519113804-d87ec0cfa476 h1:E7ct1C6/33eOdrGZKMoyntcEvs2dwZnDe30crG5vpYU= -golang.org/x/net v0.0.0-20200519113804-d87ec0cfa476/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= 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-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/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-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=